Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add L2 #80

Merged
merged 27 commits into from
Dec 13, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
3749d78
add fns to convert to si + another fn to get these fns
Geet-George Nov 16, 2023
fc4ac28
add convert_to_si fn
Geet-George Nov 16, 2023
0f50128
Merge pull request #79 from Geet-George/convert-to-si
Geet-George Nov 16, 2023
4f6bda7
add only l2 vars from aspen to interim_l2_ds
Geet-George Dec 11, 2023
a4bce7a
Merge pull request #81 from Geet-George/l2-vars
Geet-George Dec 11, 2023
03e1162
create dict as default for creating L2
Geet-George Dec 11, 2023
905368a
get l2 vars with dict
Geet-George Dec 11, 2023
d24783d
add variable attributes to helper l2 vars dict
Geet-George Dec 11, 2023
1141721
add sonde_id variable to l2
Geet-George Dec 11, 2023
49a9f19
add attrs to l2 vars if dictionary contains attrs
Geet-George Dec 11, 2023
0ae7689
change Paths object name to Flight
Geet-George Dec 11, 2023
29096b1
create Platform object
Geet-George Dec 11, 2023
5cde681
add get_platforms function
Geet-George Dec 11, 2023
267b8a2
change Flight object to accommodate new directory structure
Geet-George Dec 11, 2023
4525baf
add flight_id and platform_id attrs to Sonde
Geet-George Dec 11, 2023
d58abfa
remove data_directory arg and get it from config
Geet-George Dec 11, 2023
f0d3928
get all sondes from all flights together
Geet-George Dec 11, 2023
f638883
Merge pull request #85 from Geet-George/multiple-flights
Geet-George Dec 11, 2023
8989930
change tests to account for data_dir structure change from 267b8a2e07…
Geet-George Dec 11, 2023
d69996a
add get_flight_attributes method to Sonde class
Geet-George Dec 11, 2023
b141c60
add fn to get global attrs
Geet-George Dec 11, 2023
fae0f60
check different attr if SondeId not found
Geet-George Dec 11, 2023
b5a5ddd
add fn to include global+flight attrs to interim_l2; remove existing …
Geet-George Dec 11, 2023
3f0f466
add encoding and compression to vars and time
Geet-George Dec 13, 2023
e017465
add L2 filename attr
Geet-George Dec 13, 2023
d9581eb
save L2 file
Geet-George Dec 13, 2023
167f1fc
add L2 functions to pipeline and close #27
Geet-George Dec 13, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
136 changes: 136 additions & 0 deletions src/halodrops/helper/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,115 @@
import numpy as np

# Keys in l2_variables should be variable names in aspen_ds attribute of Sonde object
l2_variables = {
"u_wind": {
"rename_to": "u",
"attributes": {
"standard_name": "eastward_wind",
"long_name": "u component of winds",
"units": "m s-1",
"coordinates": "time lon lat alt",
},
},
"v_wind": {
"rename_to": "v",
"attributes": {
"standard_name": "northward_wind",
"long_name": "v component of winds",
"units": "m s-1",
"coordinates": "time lon lat alt",
},
},
"tdry": {
"rename_to": "ta",
"attributes": {
"standard_name": "air_temperature",
"long_name": "air temperature",
"units": "K",
"coordinates": "time lon lat alt",
},
},
"pres": {
"rename_to": "p",
"attributes": {
"standard_name": "air_pressure",
"long_name": "atmospheric pressure",
"units": "Pa",
"coordinates": "time lon lat alt",
},
},
"rh": {
"attributes": {
"standard_name": "relative_humidity",
"long_name": "relative humidity",
"units": "",
"coordinates": "time lon lat alt",
}
},
"lat": {
"attributes": {
"standard_name": "latitude",
"long_name": "latitude",
"units": "degree_north",
"axis": "Y",
}
},
"lon": {
"attributes": {
"standard_name": "longitude",
"long_name": "longitude",
"units": "degree_east",
"axis": "X",
}
},
"time": {
"attributes": {
"standard_name": "time",
"long_name": "time of recorded measurement",
"axis": "T",
}
},
"gpsalt": {
"attributes": {
"standard_name": "altitude",
"long_name": "gps reported altitude above MSL",
"units": "m",
"axis": "Z",
"positive": "up",
}
},
}

encoding_variables = {
"time": {"units": "seconds since 1970-01-01", "dtype": "float"},
}

variable_compression_properties = dict(
zlib=True,
complevel=4,
fletcher32=True,
_FillValue=np.finfo("float32").max,
)

l2_flight_attributes_map = {
"True Air Speed (m/s)": "true_air_speed_(ms-1)",
"Ground Speed (m/s)": "ground_speed_(ms-1)",
"Software Notes": "AVAPS_software_notes",
"Format Notes": "AVAPS_format_notes",
"True Heading (deg)": "true_heading_(deg)",
"Ground Track (deg)": "ground_track_(deg)",
"Longitude (deg)": "aircraft_longitude_(deg_E)",
"Latitude (deg)": "aircraft_latitude_(deg_N)",
"MSL Altitude (m)": "aircraft_msl_altitude_(m)",
"Geopotential Altitude (m)": "aircraft_geopotential_altitude_(m)",
}


l2_filename_template = (
"HALO-(AC)3_{platform}_{launch_time}_{flight_id}_{serial_id}_Level_2.nc"
)


def get_bool(s):
if isinstance(s, bool):
return s
Expand All @@ -15,3 +127,27 @@ def get_bool(s):
raise ValueError(f"Cannot convert {s} to boolean")
else:
raise ValueError(f"Cannot convert {s} to boolean")


def convert_rh_to_si(value):
"""convert RH from % to fraction"""
return value / 100


def convert_pres_to_si(value):
"""convert pressure from hPa to Pa"""
return value * 100


def convert_tdry_to_si(value):
"""convert temperature from C to K"""
return value + 273.15


def get_si_converter_function_based_on_var(var_name):
"""get the function to convert a variable to SI units based on its name"""
func_name = f"convert_{var_name}_to_si"
func = globals().get(func_name, None)
if func is None:
raise ValueError(f"No function named {func_name} found in the module")
return func
66 changes: 55 additions & 11 deletions src/halodrops/helper/paths.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,49 @@
module_logger = logging.getLogger("halodrops.helper.paths")


class Paths:
class Platform:
"""
Deriving flight paths from the provided platform directory

The input should align in terms of hierarchy and nomenclature
with the {doc}`Directory Structure </handbook/directory_structure>` that `halodrops` expects.
"""

def __init__(
self, data_directory, platform_id, platform_directory_name=None
) -> None:
self.platform_id = platform_id
self.platform_directory_name = platform_directory_name
self.data_directory = data_directory
self.flight_ids = self.get_flight_ids()

def get_flight_ids(self):
"""Returns a list of flight IDs for the given platform directory"""
if self.platform_directory_name is None:
platform_dir = os.path.join(self.data_directory, self.platform_id)
else:
platform_dir = os.path.join(
self.data_directory, self.platform_directory_name
)

flight_ids = []
for flight_dir in os.listdir(platform_dir):
if os.path.isdir(os.path.join(platform_dir, flight_dir)):
flight_ids.append(flight_dir)
return flight_ids


class Flight:
"""
Deriving paths from the provided directory

The input should align in terms of hierarchy and nomenclature
with the {doc}`Directory Structure </handbook/directory_structure>` that `halodrops` expects.
"""

def __init__(self, data_directory, flight_id):
def __init__(
self, data_directory, flight_id, platform_id, platform_directory_name=None
):
"""Creates an instance of Paths object for a given flight

Parameters
Expand All @@ -30,25 +64,33 @@ def __init__(self, data_directory, flight_id):
`flight_id` : `str`
Individual flight directory name

`platform_id` : `str`
Platform name

Attributes
----------
`flight_id`
`flight_idpath`
Path to flight data directory

`flight_idname`
`flight_id`
Name of flight data directory

`l1dir`
Path to Level-1 data directory
"""
self.logger = logging.getLogger("halodrops.helper.paths.Paths")
self.flight_id = os.path.join(data_directory, flight_id)
self.flight_idname = flight_id
self.l0dir = os.path.join(data_directory, flight_id, "Level_0")
self.l1dir = os.path.join(data_directory, flight_id, "Level_1")
if platform_directory_name is None:
platform_directory_name = platform_id
self.flight_idpath = os.path.join(
data_directory, platform_directory_name, flight_id
)
self.flight_id = flight_id
self.platform_id = platform_id
self.l1dir = os.path.join(self.flight_idpath, "Level_1")
self.l0dir = os.path.join(self.flight_idpath, "Level_0")

self.logger.info(
f"Created Path Instance: {self.flight_id=}; {self.flight_idname=}; {self.l1dir=}"
f"Created Path Instance: {self.flight_idpath=}; {self.flight_id=}; {self.l1dir=}"
)

def get_all_afiles(self):
Expand All @@ -69,7 +111,7 @@ def quicklooks_path(self):
`str`
Path to quicklooks directory
"""
quicklooks_path_str = os.path.join(self.flight_id, "Quicklooks")
quicklooks_path_str = os.path.join(self.flight_idpath, "Quicklooks")
if pp(quicklooks_path_str).exists():
self.logger.info(f"Path exists: {quicklooks_path_str=}")
else:
Expand All @@ -80,7 +122,7 @@ def quicklooks_path(self):
return quicklooks_path_str

def populate_sonde_instances(self) -> Dict:
"""Returns a dictionary of `Sonde` class instances for all A-files found in `flight_id`
"""Returns a dictionary of `Sonde` class instances for all A-files found in `flight_idpath`
and also sets the dictionary as value of `Sondes` attribute
"""
afiles = self.get_all_afiles()
Expand All @@ -94,6 +136,8 @@ def populate_sonde_instances(self) -> Dict:

Sondes[sonde_id] = Sonde(sonde_id, launch_time=launch_time)
Sondes[sonde_id].add_launch_detect(launch_detect)
Sondes[sonde_id].add_flight_id(self.flight_id)
Sondes[sonde_id].add_platform_id(self.platform_id)
Sondes[sonde_id].add_afile(a_file)
if launch_detect:
Sondes[sonde_id].add_postaspenfile()
Expand Down
Loading