Skip to content

Commit

Permalink
Merge pull request #80 from Geet-George/l2data
Browse files Browse the repository at this point in the history
add L2
  • Loading branch information
Geet-George authored Dec 13, 2023
2 parents 8e2554c + 167f1fc commit 2621df7
Show file tree
Hide file tree
Showing 5 changed files with 613 additions and 29 deletions.
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

0 comments on commit 2621df7

Please sign in to comment.