diff --git a/modules/aeolus/datasource.py b/modules/aeolus/datasource.py new file mode 100644 index 0000000000000000000000000000000000000000..42ea8755a7c303aabc8610460377c2ca9765acd0 --- /dev/null +++ b/modules/aeolus/datasource.py @@ -0,0 +1,211 @@ +import datetime, os +from datetime import timezone +import glob +import numpy as np + +from aeolus.geos_nav import GEOSNavigation +from util.util import GenericException + + +class AMVFiles: + + def __init__(self, files_path, file_time_span, pattern, band='14', elem_name=None, line_name=None, lat_name=None, + lon_name=None, params=None, out_params=None, meta_dict=None): + + self.flist = glob.glob(files_path + pattern) + if len(self.flist) == 0: + raise GenericException('no matching files found in: ' + files_path) + + self.band = band + self.ftimes = [] + self.span_seconds = datetime.timedelta(minutes=file_time_span).seconds + + for pname in self.flist: + dto = self.get_datetime(pname) + dto_start = dto + dto_end = dto + datetime.timedelta(minutes=file_time_span) + self.ftimes.append((dto_start.timestamp(), dto_end.timestamp())) + + self.ftimes = np.array(self.ftimes) + self.flist = np.array(self.flist) + sidxs = np.argsort(self.ftimes[:, 0]) + self.ftimes = self.ftimes[sidxs, :] + self.flist = self.flist[sidxs] + + self.elem_name = elem_name + self.line_name = line_name + self.lon_name = lon_name + self.lat_name = lat_name + self.params = params + self.out_params = params + if out_params is not None: + self.out_params = out_params + self.meta_dict = meta_dict + + def get_datetime(self, pathname): + pass + + def get_navigation(self): + pass + + def get_file_containing_time(self, timestamp): + k = -1 + for i in range(len(self.ftimes.shape[0])): + if (timestamp >= self.ftimes[i, 0]) and (timestamp < self.ftimes[i, 1]): + k = i + break + if k < 0: + return None, None, None + + return self.flist[k], self.ftimes[k, 0], k + + def get_file(self, timestamp): + diff = self.ftimes[:, 0] - timestamp + midx = np.argmin(np.abs(diff)) + if np.abs(self.ftimes[midx, 0] - timestamp) < self.span_seconds: + return self.flist[midx], self.ftimes[midx, 0], midx + else: + return None, None, None + + def get_parameters(self): + return self.params + + def get_out_parameters(self): + return self.out_params + + def get_meta_dict(self): + return self.meta_dict + + +class Framework(AMVFiles): + def __init__(self, files_path, file_time_span, band='14'): + elem_name = 'Element' + line_name = 'Line' + lon_name = 'Longitude' + lat_name = 'Latitude' + params = ['MedianPress', 'Wind_Speed', 'Wind_Dir', 'BestFitPresLvl'] + out_params = ['Lon', 'Lat', 'Element', 'Line', 'pressure', 'wind_speed', 'wind_direction', 'BestFitPresLvl'] + meta_dict = {'Lon': ('degrees east', 'f4'), 'Lat': ('degrees north', 'f4'), 'Element': (None, 'i4'), + 'Line': (None, 'i4'), 'pressure': ('hPa', 'f4'), 'wind_speed': ('m s-1', 'f4'), + 'wind_direction': ('degrees', 'f4'), 'BestFitPresLvl': ('hPa', 'f4')} + + super().__init__(files_path, file_time_span, '*WINDS_AMV_EN-'+band+'*.nc', band=band, elem_name=elem_name, params=params, + line_name=line_name, lat_name=lat_name, lon_name=lon_name, out_params=out_params, meta_dict=meta_dict) + + def get_navigation(self): + return GEOSNavigation(sub_lon=-75.0) + + def get_datetime(self, pathname): + fname = os.path.split(pathname)[1] + toks = fname.split('_') + dstr = toks[4] + tstr = toks[5] + dtstr = dstr + tstr + dto = datetime.datetime.strptime(dtstr, '%Y%j%H%M').replace(tzinfo=timezone.utc) + + return dto + + +class FrameworkCloudHeight(AMVFiles): + def __init__(self, files_path, file_time_span): + elem_name = 'Element' + line_name = 'Line' + lon_name = 'Longitude' + lat_name = 'Latitude' + + out_params = ['CldTopPres', 'CldTopHght', 'CldOptDpth'] + params = ['CldTopPres', 'CldTopHght', 'CldOptDpth'] + meta_dict = {'CldTopPres': ('hPa', 'f4'), 'CldTopHght': ('km', 'f4'), 'CldOptDpth': ('km', 'f4')} + + super().__init__(files_path, file_time_span, '*_CLOUD_HEIGHT_EN'+'*.nc', band=None, elem_name=elem_name, params=params, + line_name=line_name, lat_name=lat_name, lon_name=lon_name, out_params=out_params, meta_dict=meta_dict) + + def get_navigation(self): + return GEOSNavigation(sub_lon=-75.0) + + def get_datetime(self, pathname): + fname = os.path.split(pathname)[1] + toks = fname.split('_') + dstr = toks[4] + tstr = toks[5] + dtstr = dstr + tstr + dto = datetime.datetime.strptime(dtstr, '%Y%j%H%M').replace(tzinfo=timezone.utc) + + return dto + + +class OPS(AMVFiles): + def __init__(self, files_path, file_time_span, band='14'): + elem_name = None + line_name = None + lon_name = 'lon' + lat_name = 'lat' + + out_params = ['Lon', 'Lat', 'Element', 'Line', 'pressure', 'wind_speed', 'wind_direction'] + params = ['pressure', 'wind_speed', 'wind_direction'] + meta_dict = {'Lon': ('degrees east', 'f4'), 'Lat': ('degrees north', 'f4'), 'Element': (None, 'i4'), 'Line': (None, 'i4'), + 'pressure': ('hPa', 'f4'), 'wind_speed': ('m s-1', 'f4'), 'wind_direction': ('degrees', 'f4')} + + super().__init__(files_path, file_time_span, 'OR_ABI-L2-DMWF*'+'C'+band+'*.nc', band=band, elem_name=elem_name, params=params, + line_name=line_name, lat_name=lat_name, lon_name=lon_name, out_params=out_params, meta_dict=meta_dict) + + def get_navigation(self): + # return GEOSNavigation(sub_lon=-75.2) ? + return GEOSNavigation(sub_lon=-75.0) + + def get_datetime(self, pathname): + fname = os.path.split(pathname)[1] + toks = fname.split('_') + dtstr = toks[3] + dtstr = dtstr[:-3] + dto = datetime.datetime.strptime(dtstr, 's%Y%j%H%M').replace(tzinfo=timezone.utc) + + return dto + + +class CarrStereo(AMVFiles): + def __init__(self, files_path, file_time_span, band='14'): + elem_name = 'Element' + line_name = 'Line' + lon_name = 'Lon' + lat_name = 'Lat' + + out_params = ['Lon', 'Lat', 'Element', 'Line', 'V_3D_u', 'V_3D_v', 'H_3D', 'pres', 'Fcst_Spd', 'Fcst_Dir', 'SatZen', + 'InversionFlag', 'CloudPhase', 'CloudType'] + + params = ['V_3D', 'H_3D', 'pres', 'Fcst_Spd', 'Fcst_Dir', 'SatZen', + 'InversionFlag', 'CloudPhase', 'CloudType'] + + meta_dict = {'H_3D': ('m', 'f4'), 'pres': ('hPa', 'f4'), 'Fcst_Spd': ('m s-1', 'f4'), + 'Fcst_Dir': ('degree', 'f4'), + 'SatZen': ('degree', 'f4'), 'InversionFlag': (None, 'u1'), + 'CloudPhase': (None, 'u1'), 'CloudType': (None, 'u1'), + 'V_3D_u': ('m s-1', 'f4'), 'V_3D_v': ('m s-1', 'f4'), 'Lon': ('degrees east', 'f4'), + 'Lat': ('degrees north', 'f4'), 'Element': (None, 'i4'), 'Line': (None, 'i4')} + + super().__init__(files_path, file_time_span, 'tdw_qc_GOES*'+'ch_'+band+'.nc', band=band, elem_name=elem_name, params=params, + line_name=line_name, lat_name=lat_name, lon_name=lon_name, out_params=out_params, meta_dict=meta_dict) + + def get_navigation(self): + return GEOSNavigation(sub_lon=-137.0) + + def get_datetime(self, pathname): + fname = os.path.split(pathname)[1] + toks = fname.split('_') + dtstr = toks[3] + dto = datetime.datetime.strptime(dtstr, '%Y%j.%H%M.ch').replace(tzinfo=timezone.utc) + + return dto + + +def get_datasource(files_path, file_time_span, source, band='14'): + if source == 'OPS': + return OPS(files_path, file_time_span, band=band) + elif source == 'FMWK': + return Framework(files_path, file_time_span, band=band) + elif source == 'CARR': + return CarrStereo(files_path, file_time_span, band=band) + elif source == 'FMWK_CLD_HGT': + return FrameworkCloudHeight(files_path, file_time_span, band=None) + else: + raise GenericException('Unknown data source type') \ No newline at end of file