Source code for ppcpy.io.readMeteo


#import netCDF4
import glob
import re
import datetime

import xarray as xr
#from scipy.interpolate import griddata
import numpy as np


[docs] class Meteo: """ % LOADMETEOR read meteorological data. % % USAGE: % [temp, pres, relh, wins, wind, meteorAttri] = loadMeteor(mTime, asl) % % INPUTS: % mTime: array % query time. % asl: array % height above sea level. (m) % % KEYWORDS: % meteorDataSource: str % meteorological data type. % e.g., 'gdas1'(default), 'standard_atmosphere', 'websonde', 'radiosonde', 'nc_cloudnet' % gdas1Site: str % the GDAS1 site for the current campaign. % meteo_folder: str % the main folder of the GDAS1 profiles (or the cloudnet profiles). % radiosondeSitenum: integer % site number, which can be found in % doc/radiosonde-station-list.txt. % radiosondeFolder: str % the folder of the sonding files. % radiosondeType: integer % file type of the radiosonde file. % 1: radiosonde file for MOSAiC (default) % 2: radiosonde file for MUA % flagReadLess: logical % flag to determine whether access meteorological data by certain time % interval. (default: false) % method: char % Interpolation method. (default: 'nearest') % isUseLatestGDAS: logical % whether to search the latest available GDAS profile (default: false). % % OUTPUTS: % temp: matrix (time * height) % temperature for each range bin. [°C] % pres: matrix (time * height) % pressure for each range bin. [hPa] % relh: matrix (time * height) % relative humidity for each range bin. [%] % wins: matrix (time * height) % wind speed. (m/s) % meteorAttri: struct % dataSource: cell % The data source used in the data processing for each cloud-free group. % URL: cell % The data file info for each cloud-free group. % datetime: array % datetime label for the meteorlogical data. % % HISTORY: % - 2021-05-22: first edition by Zhenping % % .. Authors: - zhenping@tropos.de """ """Typical call [temp, pres, relh, ~, ~, data.meteorAttri] = loadMeteor(clFreGrpTimes, data.alt, ... 'meteorDataSource', PollyConfig.meteorDataSource, ... 'gdas1Site', PollyConfig.gdas1Site, ... 'meteo_folder', PollyConfig.meteo_folder, ... 'radiosondeSitenum', PollyConfig.radiosondeSitenum, ... 'radiosondeFolder', PollyConfig.radiosondeFolder, ... 'radiosondeType', PollyConfig.radiosondeType, ... 'method', 'linear', ... 'isUseLatestGDAS', PollyConfig.flagUseLatestGDAS); """ def __init__(self, meteorDataSource, meteo_folder, meteo_file): assert meteorDataSource == 'nc_cloudnet', "Other meteo sources are not implemented yet" self.reader = MeteoNcCloudnet(meteo_folder, meteo_file) return None
[docs] def load(self, times, heights): """load the data and resample to 15 minute intervals """ self.ds = self.reader.load(times, heights) self.ds = self.ds.resample(time='15min').interpolate() return self
[docs] def get_mean_profiles(self, time_slice): """get the mean meteorological profiles """ mean_profiles = [] for t in time_slice: mean_profiles.append(self.ds.sel(time=slice(*t)).mean(dim='time')) return mean_profiles
[docs] class MeteoNcCloudnet: """ TODO for now only one filename define preferred model """ def __init__(self, basepath, filepattern): if not '/' == basepath[-1]: basepath = basepath + '/' self.basepath = basepath self.filepattern = filepattern
[docs] def find_path_for_time(self, time): candidates = glob.glob(self.basepath + "**/*") #print('candidates ', candidates) dt = datetime.datetime.fromtimestamp(time) regex = re.compile(self.filepattern.format(dt)) #print('regex ', regex) filename = [s for s in candidates if regex.search(s) ] #print('filename ', filename) assert len(filename) == 1 return filename[0]
[docs] def load(self, time, height_grid): """ not quite sure on the interface yet ``` met.load(data_cube.retrievals_highres['time'][0]) met.load(datetime.datetime.timestamp(datetime.datetime.strptime(data_cube.date, '%Y%m%d'))) ``` Recipie: - load - select variables? - rename? - regrid from (time, level) to (time, lidar heights) clarify the above ground above sea level issues """ filename = self.find_path_for_time(time) ds = xr.load_dataset(filename) variables_to_select = [ 'height', 'temperature', 'pressure', 'rh', 'q' ] ds = ds[variables_to_select] height_2d = ds.height.values #height_grid = data_cube.retrievals_highres['height'] time = ds.time.values.astype('datetime64[s]').astype(int) # for some reasons this interpolation provides strange results in the lowermost layers # zi = griddata((np.repeat(time, ds_dash.height.shape[1], axis=0), # height_2d.ravel()), # ds_dash['temperature'].values.ravel(), # (time[None,:], height_grid[:,None]), # method='linear') temp = np.zeros((time.shape[0], height_grid.shape[0])) for i in range(time.shape[0]): temp[i,:] = np.interp(height_grid, height_2d[i,:],ds['temperature'].values[i,:]) p = np.zeros((time.shape[0], height_grid.shape[0])) for i in range(time.shape[0]): p[i,:] = np.interp(height_grid, height_2d[i,:],ds['pressure'].values[i,:]) rh = np.zeros((time.shape[0], height_grid.shape[0])) for i in range(time.shape[0]): rh[i,:] = np.interp(height_grid, height_2d[i,:],ds['rh'].values[i,:]) q = np.zeros((time.shape[0], height_grid.shape[0])) for i in range(time.shape[0]): q[i,:] = np.interp(height_grid, height_2d[i,:],ds['q'].values[i,:]) ds_new = xr.Dataset( data_vars=dict( temperature=(["time", "height"], temp, ds['temperature'].attrs), pressure=(["time", "height"], p, ds['pressure'].attrs), rh=(["time", "height"], rh, ds['rh'].attrs), q=(["time", "height"], q, ds['q'].attrs), ), coords=dict( time=("time", ds.time.values), height=("height", height_grid), ), attrs=ds.attrs, ) return ds_new