10 from collections
import defaultdict, OrderedDict
11 from orddicts
import DefaultOrderedDict
17 import ioda_conv_ncio
as iconv
19 __ALL__ = [
'conv_platforms']
61 "aircraft": [230, 231, 233, 235],
62 "sondes": range(220, 223),
63 "satwind": range(240, 261),
65 "windprof": range(227, 230),
66 "sfcship": [280, 282, 284],
73 "aircraft": [130, 131, 133, 135],
74 "sondes": range(120, 123),
76 "sfcship": [180, 183],
78 "gps": [3, 4, 42, 43, 745, 825],
79 "sst": [181, 182, 183, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202],
85 'Station_ID': (
'station_id',
'string'),
86 'Time': (
'datetime',
'string'),
87 'Latitude': (
'latitude',
'float'),
88 'Longitude': (
'longitude',
'float'),
89 'Station_Elevation': (
'station_elevation',
'float'),
90 'Pressure': (
'air_pressure',
'float'),
91 'Height': (
'height',
'float'),
92 'Elevation': (
'height_above_mean_sea_level',
'float'),
93 'Obs_Time': (
'datetime',
'string'),
94 'Scan_Position': (
'scan_position',
'float'),
95 'Sat_Zenith_Angle': (
'sensor_zenith_angle',
'float'),
96 'Sat_Azimuth_Angle': (
'sensor_azimuth_angle',
'float'),
97 'Sol_Zenith_Angle': (
'solar_zenith_angle',
'float'),
98 'Sol_Azimuth_Angle': (
'solar_azimuth_angle',
'float'),
99 'Scan_Angle': (
'sensor_view_angle',
'float'),
100 'Surface_type': (
'surface_type',
'integer'),
101 'MODIS_deep_blue_flag': (
'modis_deep_blue_flag',
'integer'),
102 'Reference_Pressure': (
'air_pressure',
'float'),
103 'Solar_Zenith_Angle': (
'solar_zenith_angle',
'float'),
104 'Row_Anomaly_Index': (
'row_anomaly_index',
'float'),
105 'TopLevelPressure': (
'top_level_pressure',
'float'),
106 'BottomLevelPressure': (
'bottom_level_pressure',
'float'),
107 'Total_Ozone_Error_Flag': (
'total_ozone_error_flag',
'float'),
108 'Profile_Ozone_Error_Flag': (
'profile_ozone_error_flag',
'float'),
109 'XoverR': (
'radar_azimuth',
'float'),
110 'YoverR': (
'radar_tilt',
'float'),
111 'ZoverR': (
'radar_dir3',
'float'),
112 'Vterminal': (
'vterminal',
'float'),
113 'SWCM_spec_type': (
'satwind_spectral_type',
'float'),
114 'SAZA_sat_zen_angle': (
'sensor_zenith_angle',
'float'),
115 'SCCF_chan_wavelen': (
'channel_wavelength',
'float'),
116 'QI_with_FC': (
'satwind_quality_ind_with_fc',
'float'),
117 'QI_without_FC': (
'satwind_quality_ind_no_fc',
'float'),
118 'LaunchTime': (
'LaunchTime',
'float'),
122 "eastward_wind":
"u",
123 "northward_wind":
"v",
127 "tv": [
"virtual_temperature"],
128 "tsen": [
"air_temperature"],
129 "uv": [
"eastward_wind",
"northward_wind"],
130 "ps": [
"surface_pressure"],
131 "q": [
"specific_humidity"],
132 "bend": [
"bending_angle"],
133 "refract": [
"refractivity"],
134 "sst": [
"sea_surface_temperature"],
138 "tv": [
"Observation"],
139 "tsen": [
"Observation"],
140 "uv": [
"u_Observation",
"v_Observation"],
141 "ps": [
"Observation"],
142 "q": [
"Observation"],
143 "bend": [
"Observation"],
144 "refract": [
"Observation"],
145 "sst": [
"Observation"],
148 gsi_add_vars_allsky = {
149 'Observation_Type':
'ObsType',
150 'Prep_Use_Flag':
'PreUseFlag',
151 'Analysis_Use_Flag':
'GsiUseFlag',
152 'Nonlinear_QC_Rel_Wgt':
'GsiQCWeight',
153 'Errinv_Adjust':
'GsiAdjustObsError',
154 'Errinv_Final':
'GsiFinalObsError',
155 'Forecast_adjusted':
'GsiHofXBc',
156 'Forecast_unadjusted':
'GsiHofX',
157 'Forecast_unadjusted_clear':
'GsiHofXClr',
158 'Obs_Minus_Forecast_adjusted':
'GsiHofXBc',
159 'Obs_Minus_Forecast_unadjusted':
'GsiHofX',
160 'Obs_Minus_Forecast_unadjusted_clear':
'GsiHofX',
161 'Inverse_Observation_Error':
'GsiFinalObsError',
162 'Bias_Correction':
'GsiBc',
167 gsi_add_qcvars_allsky = {
168 'ObsBias':
'GsiObsBias',
169 'Inverse_Observation_Error_after_jsfcchk':
'GsiObsError_after_jsfcchk',
170 'Inverse_Observation_Error_after_sdoei':
'GsiObsError_after_sdoei',
171 'Inverse_Observation_Error_after_grosschk':
'GsiObsError_after_grosschk',
172 'Inverse_Observation_Error_sdoei':
'GsiObsError_sdoei',
173 'Inverse_Observation_Error_grosschk':
'GsiObsError_grosschk',
177 'ObsBias':
'GsiObsBias',
178 'Observation_Type':
'ObsType',
179 'Prep_Use_Flag':
'PreUseFlag',
180 'Analysis_Use_Flag':
'GsiUseFlag',
181 'Nonlinear_QC_Rel_Wgt':
'GsiQCWeight',
182 'Errinv_Adjust':
'GsiAdjustObsError',
183 'Errinv_Final':
'GsiFinalObsError',
184 'Obs_Minus_Forecast_adjusted':
'GsiHofXBc',
185 'Obs_Minus_Forecast_unadjusted':
'GsiHofX',
186 'Forecast_adjusted':
'GsiHofXBc',
187 'Forecast_unadjusted':
'GsiHofX',
188 'Inverse_Observation_Error':
'GsiFinalObsError',
189 'Bias_Correction':
'GsiBc',
195 'Bias_Correction':
'GsiObsBias',
196 'Inverse_Observation_Error_jsfc':
'GsiObsError_jsfc',
197 'Inverse_Observation_Error_clddet':
'GsiObsError_clddet',
198 'Inverse_Observation_Error_nsstret':
'GsiObsError_nsstret',
199 'Inverse_Observation_Error_grosschk':
'GsiObsError_grosschk',
200 'Inverse_Observation_Error_after_wavenum':
'GsiObsError_after_wavenum',
201 'Inverse_Observation_Error_after_range':
'GsiObsError_after_rangechk',
202 'Inverse_Observation_Error_after_topo':
'GsiObsError_after_topo',
203 'Inverse_Observation_Error_after_transmittop':
'GsiObsError_after_transmittop',
204 'Inverse_Observation_Error_after_clddet':
'GsiObsError_after_clddet',
205 'Inverse_Observation_Error_after_nsstret':
'GsiObsError_after_nsstret',
206 'Inverse_Observation_Error_after_jsfcchk':
'GsiObsError_after_jsfcchk',
210 'Observation_Type':
'ObsType',
211 'Prep_Use_Flag':
'PreUseFlag',
212 'Analysis_Use_Flag':
'GsiUseFlag',
213 'Nonlinear_QC_Rel_Wgt':
'GsiQCWeight',
214 'Errinv_Adjust':
'GsiAdjustObsError',
215 'Errinv_Final':
'GsiFinalObsError',
216 'Errinv_Input':
'GsiInputObsError',
217 'u_Forecast_adjusted':
'GsiHofXBc',
218 'u_Forecast_unadjusted':
'GsiHofX',
219 'v_Forecast_adjusted':
'GsiHofXBc',
220 'v_Forecast_unadjusted':
'GsiHofX',
221 'u_Obs_Minus_Forecast_adjusted':
'GsiHofXBc',
222 'u_Obs_Minus_Forecast_unadjusted':
'GsiHofX',
223 'v_Obs_Minus_Forecast_adjusted':
'GsiHofXBc',
224 'v_Obs_Minus_Forecast_unadjusted':
'GsiHofX',
233 'obsdbz':
'dbzerror',
245 geovals_metadata_dict = {
246 'Latitude':
'latitude',
247 'Longitude':
'longitude',
252 obsdiag_metadata_dict = {
253 'Latitude':
'latitude',
254 'Longitude':
'longitude',
267 'sndrd1',
'sndrd2',
'sndrd3',
'sndrd4',
284 chan_metadata_dict = {
285 'sensor_chan':
'sensor_channel',
286 'use_flag':
'gsi_use_flag',
287 'frequency':
'sensor_band_central_radiation_frequency',
288 'polarization':
'polarization',
289 'wavenumber':
'sensor_band_central_radiation_wavenumber',
290 'error_variance':
'ObsError',
291 'mean_lapse_rate':
'mean_lapse_rate',
296 'virtual_temperature':
'virtual_temperature',
297 'atmosphere_ln_pressure_coordinate':
'atmosphere_ln_pressure_coordinate',
298 'specific_humidity':
'specific_humidity',
299 'northward_wind':
'northward_wind',
300 'eastward_wind':
'eastward_wind',
301 'geopotential_height':
'geopotential_height',
302 'height':
'height_above_mean_sea_level',
303 'tropopause_pressure':
'tropopause_pressure',
304 'surface_pressure':
'surface_pressure',
305 'surface_air_pressure':
'surface_pressure',
306 'surface_temperature':
'surface_temperature',
307 'sea_surface_temperature':
'sea_surface_temperature',
308 'surface_roughness':
'surface_roughness_length',
309 'surface_height':
'surface_geopotential_height',
310 'surface_geopotential_height':
'surface_geopotential_height',
311 'landmask':
'land_area_fraction',
312 'air_temperature':
'air_temperature',
313 'air_pressure':
'air_pressure',
314 'atmosphere_pressure_coordinate':
'air_pressure',
315 'atmosphere_pressure_coordinate_interface':
'air_pressure_levels',
316 'air_pressure_levels':
'air_pressure_levels',
317 'atmosphere_absorber_01':
'humidity_mixing_ratio',
318 'atmosphere_absorber_02':
'mole_fraction_of_carbon_dioxide_in_air',
319 'mole_fraction_of_ozone_in_air':
'mole_fraction_of_ozone_in_air',
320 'atmosphere_absorber_03':
'mole_fraction_of_ozone_in_air',
321 'atmosphere_mass_content_of_cloud_01':
'mass_content_of_cloud_liquid_water_in_atmosphere_layer',
322 'effective_radius_of_cloud_particle_01':
'effective_radius_of_cloud_liquid_water_particle',
323 'atmosphere_mass_content_of_cloud_02':
'mass_content_of_cloud_ice_in_atmosphere_layer',
324 'effective_radius_of_cloud_particle_02':
'effective_radius_of_cloud_ice_particle',
325 'Water_Fraction':
'water_area_fraction',
326 'Land_Fraction':
'land_area_fraction',
327 'Ice_Fraction':
'ice_area_fraction',
328 'Snow_Fraction':
'surface_snow_area_fraction',
329 'Vegetation_Fraction':
'vegetation_area_fraction',
330 'Water_Temperature':
'surface_temperature_where_sea',
331 'Land_Temperature':
'surface_temperature_where_land',
332 'Ice_Temperature':
'surface_temperature_where_ice',
333 'Snow_Temperature':
'surface_temperature_where_snow',
334 'tsavg5':
'average_surface_temperature_within_field_of_view',
335 'Sfc_Wind_Speed':
'surface_wind_speed',
336 'Sfc_Wind_Direction':
'surface_wind_from_direction',
337 'Lai':
'leaf_area_index',
338 'Soil_Moisture':
'volume_fraction_of_condensed_water_in_soil',
339 'Soil_Temperature':
'soil_temperature',
340 'Land_Type_Index':
'land_type_index',
341 'Vegetation_Type':
'vegetation_type_index',
342 'Soil_Type':
'soil_type',
343 'Snow_Depth':
'surface_snow_thickness',
344 'humidity_mixing_ratio':
'humidity_mixing_ratio',
345 'Sfc_Height':
'surface_geopotential_height',
346 'Wind_Reduction_Factor_at_10m':
'wind_reduction_factor_at_10m',
361 'dbzges':
'equivalent_reflectivity_factor',
362 'upward_air_velocity':
'upward_air_velocity',
366 'Jacobian_Surface_Temperature':
'brightness_temperature_jacobian_surface_temperature',
367 'Jacobian_Surface_Emissivity':
'brightness_temperature_jacobian_surface_emissivity',
368 'Jacobian_Temperature':
'brightness_temperature_jacobian_air_temperature',
369 'Jacobian_Moisture':
'brightness_temperature_jacobian_humidity_mixing_ratio',
370 'Layer_Optical_Depth':
'optical_thickness_of_atmosphere_layer',
371 'Layer_to_Space_Transmittance':
'transmittances_of_atmosphere_layer',
372 'Weighting_Function':
'weightingfunction_of_atmosphere_layer',
373 'Pressure_Level_WeightFuncMax':
'pressure_level_at_peak_of_weightingfunction',
374 'Forecast_unadjusted_clear':
'brightness_temperature_assuming_clear_sky',
396 'virtual_temperature':
'K',
397 'atmosphere_ln_pressure_coordinate':
'1',
398 'specific_humidity':
'1',
399 'northward_wind':
'm s-1',
400 'eastward_wind':
'm s-1',
401 'geopotential_height':
'm',
402 'height_above_mean_sea_level':
'm',
403 'surface_pressure':
'Pa',
404 'sea_surface_temperature':
'K',
405 'surface_temperature':
'K',
406 'surface_roughness_length':
'm',
407 'surface_geopotential_height':
'm',
408 'land_area_fraction':
'1',
409 'air_temperature':
'K',
410 'air_pressure':
'Pa',
411 'air_pressure_levels':
'Pa',
412 'humidity_mixing_ratio':
'1',
413 'mole_fraction_of_carbon_dioxide_in_air':
'1',
414 'mole_fraction_of_ozone_in_air':
'1',
415 'integrated_layer_ozone_in_air':
'DU',
416 'atmosphere_mass_content_of_cloud_liquid_water':
'kg m-2',
417 'effective_radius_of_cloud_liquid_water_particle':
'm',
418 'atmosphere_mass_content_of_cloud_ice':
'kg m-2',
419 'effective_radius_of_cloud_ice_particle':
'm',
420 'water_area_fraction':
'1',
421 'land_area_fraction':
'1',
422 'ice_area_fraction':
'1',
423 'surface_snow_area_fraction':
'1',
424 'vegetation_area_fraction':
'1',
425 'surface_temperature_where_sea':
'K',
426 'surface_temperature_where_land':
'K',
427 'surface_temperature_where_ice':
'K',
428 'surface_temperature_where_snow':
'K',
429 'surface_wind_speed':
'm s-1',
430 'wind_speed':
'm s-1',
431 'surface_wind_from_direction':
'degree',
432 'leaf_area_index':
'1',
433 'volume_fraction_of_condensed_water_in_soil':
'1',
434 'soil_temperature':
'K',
435 'land_type_index':
'1',
436 'vegetation_type_index':
'1',
438 'surface_snow_thickness':
'm',
439 'humidity_mixing_ratio':
'1',
440 'wind_reduction_factor_at_10m':
'1',
455 'latitude':
'degrees_north',
456 'longitude':
'degrees_east',
457 'station_elevation':
'm',
459 'height_above_mean_sea_level':
'm',
460 'scan_position':
'1',
461 'sensor_zenith_angle':
'degree',
462 'sensor_azimuth_angle':
'degree',
463 'solar_zenith_angle':
'degree',
464 'solar_azimuth_angle':
'degree',
465 'modis_deep_blue_flag':
'1',
466 'row_anomaly_index':
'1',
467 'total_ozone_error_flag':
'1',
468 'profile_ozone_error_flag':
'1',
469 'top_level_pressure':
'Pa',
470 'bottom_level_pressure':
'Pa',
471 'tropopause_pressure':
'Pa',
472 'brightness_temperature_jacobian_surface_temperature':
'1',
473 'brightness_temperature_jacobian_surface_emissivity':
'K',
474 'brightness_temperature_jacobian_air_temperature':
'1',
475 'brightness_temperature_jacobian_humidity_mixing_ratio':
'K/g/Kg ',
476 'optical_thickness_of_atmosphere_layer':
'1',
477 'clw_retrieved_from_observation':
'kg/m/m',
478 'clw_retrieved_from_background':
'kg/m/m',
479 'scat_retrieved_from_observation':
'1',
480 'LaunchTime':
'hours',
488 'wind_speed': (
'wind_speed',
'float'),
493 test_fields_allsky = {
494 'clwp_amsua': (
'clw_retrieved_from_observation',
'float'),
495 'clw_guess_retrieval': (
'clw_retrieved_from_background',
'float'),
496 'clw_symmetric_amount': (
'clw_symmetric_amount',
'float'),
497 'scat_amsua': (
'scat_retrieved_from_observation',
'float'),
499 test_fields_with_channels_allsky = {
500 'Hydrometeor_Affected_Channels': (
'Hydrometeor_Affected_Channels',
'float'),
501 'Input_Observation_Error': (
'ObsError',
'float'),
502 'Cloud_Match_Index': (
'Cloud_Match_Index',
'float'),
503 'Error_Inflation_Factor_sdoei': (
'error_inflation_factor_sdoei',
'float'),
505 test_fields_with_channels = {
506 'Error_Inflation_Factor_Topo': (
'error_inflation_factor_topo',
'float'),
507 'Error_Inflation_Factor_Transmittop': (
'error_inflation_factor_transmittop',
'float'),
508 'Error_Inflation_Factor_Wavenum': (
'error_inflation_factor_wavenum',
'float'),
509 'Error_Inflation_Factor_Jsfc': (
'error_inflation_factor_jsfc',
'float'),
510 'Error_Inflation_Factor_Grosschk': (
'error_inflation_factor_grosschk',
'float'),
511 'Transmittance_at_Top': (
'tao_top',
'float'),
512 'Transmittance_at_Sfc': (
'tao_sfc',
'float'),
513 'Cloudy_Channel': (
'cloudy_channel',
'integer'),
514 'Transmittance_at_Cloud_Top': (
'tao_cldtop',
'float'),
515 'NSST_Retrieval_check': (
'nsstret_check',
'integer'),
517 gmi_chan_dep_loc_vars = {
528 FLOAT_FILL = nc.default_fillvals[
'f4']
529 INT_FILL = nc.default_fillvals[
'i4']
533 return np.array(netcdf_var[:])
537 Data array. Return a numpy array based on variable name
539 return self.
_as_array_as_array(self.df[var_name])
544 """ class Conv - conventional observations
546 Use this class to read in conventional observations
547 from GSI netCDF diag files
552 filename - string path to file
553 validtime - datetime object of valid observation time
554 nobs - number of observations
558 splitfname = self.
filenamefilename.split(
'/')[-1].split(
'_')
559 if 'conv' in splitfname:
560 i = splitfname.index(
'conv')
561 self.
obstypeobstype =
"_".join(splitfname[i:i + 2])
563 raise ValueError(
"Observation is not a conventional type...")
566 if self.
obstypeobstype ==
'conv_t':
568 elif self.
obstypeobstype ==
'conv_gps':
569 self.
obsvarsobsvars = [
'bend',
'refract']
571 self.
obsvarsobsvars = [splitfname[i + 1]]
575 df = nc.Dataset(self.
filenamefilename)
576 tstr =
str(df.getncattr(
'date_time'))
577 self.
validtimevalidtime = dt.datetime.strptime(tstr,
"%Y%m%d%H")
579 self.
nobsnobs = len(df[
'Observation_Type'][:])
586 """ toGeovals(OutDir,clobber=True)
587 if model state fields are in the GSI diag file, create
588 GeoVaLs in an output file for use by JEDI/UFO
594 platforms = conv_platforms[self.
obstypeobstype]
595 except BaseException:
596 print(self.
obstypeobstype +
" is not currently supported. Exiting.")
601 outname = OutDir +
'/' + p +
'_' + v +
'_geoval_' + \
602 self.
validtimevalidtime.strftime(
"%Y%m%d%H") +
'.nc4'
604 outname = OutDir +
'/' + v +
'_geoval_' + \
605 self.
validtimevalidtime.strftime(
"%Y%m%d%H") +
'.nc4'
606 if (p ==
'windprof' or p ==
'satwind' or p ==
'scatwind' or p ==
'vadwind'):
607 outname = OutDir +
'/' + p +
'_geoval_' + \
608 self.
validtimevalidtime.strftime(
"%Y%m%d%H") +
'.nc4'
610 if (os.path.exists(outname)):
611 print(
"File exists. Skipping and not overwriting:%s" % outname)
615 for ncv
in self.
dfdf.variables:
616 if ncv
in geovals_vars:
617 OutVars.append(geovals_vars[ncv])
621 if (np.sum(idx) == 0):
622 print(
"No matching observations for Platform:%s Var:%s" % (p, v))
624 print(
"Platform:%s Var:%s #Obs:%d" % (p, v, np.sum(idx)))
626 ncout = nc.Dataset(outname,
'w', format=
'NETCDF4')
628 "date_time", np.int32(
629 self.
validtimevalidtime.strftime(
"%Y%m%d%H")))
632 ncout.createDimension(
"nlocs", nlocs)
635 ncout.createDimension(
636 "nlevs", self.
dfdf.dimensions[
"atmosphere_pressure_coordinate_arr_dim"].size)
637 ncout.createDimension(
638 "ninterfaces", self.
dfdf.dimensions[
"atmosphere_pressure_coordinate_interface_arr_dim"].size)
639 dimname =
"Station_ID_maxstrlen"
640 ncout.createDimension(dimname, self.
dfdf.dimensions[dimname].size)
641 dimname =
"Observation_Class_maxstrlen"
642 ncout.createDimension(dimname, self.
dfdf.dimensions[dimname].size)
643 for var
in self.
dfdf.variables.values():
645 if (vname
in geovals_metadata_dict.keys())
or (
646 vname
in geovals_vars.keys()):
647 vdata = var[...].data
648 dims = tuple([len(self.
dfdf.dimensions[d])
for d
in var.dimensions])
649 vdata = np.frombuffer(vdata, dtype=var.dtype)
650 vdata = np.reshape(vdata, dims)
651 if vname
in geovals_metadata_dict.keys():
652 dims = (
"nlocs",) + var.dimensions[1:]
653 var_out = ncout.createVariable(geovals_metadata_dict[vname], vdata.dtype, dims)
654 var_out[...] = vdata[idx, ...]
655 if vname
in geovals_vars.keys():
656 if (len(var.dimensions) == 1):
659 if vname ==
"atmosphere_pressure_coordinate_interface":
660 dims = (
"nlocs",
"ninterfaces")
662 dims = (
"nlocs",
"nlevs")
663 var_out = ncout.createVariable(geovals_vars[vname], vdata.dtype, dims)
664 var_out[...] = vdata[idx, ...]
667 def toIODAobs(self, OutDir, clobber=True, platforms=None):
668 """ toIODAobs(OutDir,clobber=True)
669 output observations from the specified GSI diag file
670 to the JEDI/IODA observation format
675 platforms = conv_platforms[self.
obstypeobstype]
676 except BaseException:
677 print(self.
obstypeobstype +
" is not currently supported. Exiting.")
683 outname = OutDir +
'/' + p +
'_' + v +
'_obs_' + \
684 self.
validtimevalidtime.strftime(
"%Y%m%d%H") +
'.nc4'
686 outname = OutDir +
'/' + v +
'_obs_' + \
687 self.
validtimevalidtime.strftime(
"%Y%m%d%H") +
'.nc4'
688 if (p ==
'windprof' or p ==
'satwind' or p ==
'scatwind' or p ==
'vadwind'):
689 outname = OutDir +
'/' + p +
'_obs_' + \
690 self.
validtimevalidtime.strftime(
"%Y%m%d%H") +
'.nc4'
692 if (os.path.exists(outname)):
693 print(
"File exists. Skipping and not overwriting: %s" % outname)
700 varDict = defaultdict(
lambda: defaultdict(dict))
705 test_fields_ = test_fields_conv
707 for ncv
in self.
dfdf.variables:
708 if ncv
in all_LocKeyList:
709 LocKeyList.append(all_LocKeyList[ncv])
712 for ncv
in self.
dfdf.variables:
713 if ncv
in test_fields_:
714 TestKeyList.append(test_fields_[ncv])
718 if (np.sum(idx) == 0):
719 print(
"No matching observations for Platform:%s Var:%s" % (p, v))
721 print(
"Platform:%s Var:%s #Obs:%d" % (p, v, np.sum(idx)))
723 writer = iconv.NcWriter(outname, LocKeyList, TestKeyList=TestKeyList)
725 outvars = conv_varnames[v]
726 for value
in outvars:
727 varDict[value][
'valKey'] = value, writer.OvalName()
728 varDict[value][
'errKey'] = value, writer.OerrName()
729 varDict[value][
'qcKey'] = value, writer.OqcName()
731 for o
in range(len(outvars)):
732 obsdata = self.
varvar(conv_gsivarnames[v][o])[idx]
733 if outvars[o] ==
'surface_pressure':
734 if np.max(obsdata) < 1100.:
735 obsdata = obsdata * 100.
736 obserr = self.
varvar(
'Errinv_Input')[idx]
737 mask = obserr < self.
EPSILONEPSILON
738 obserr[~mask] = 1.0 / obserr[~mask]
740 obserr[obserr > 4e8] = self.
FLOAT_FILLFLOAT_FILL
742 obsqc = self.
varvar(
'Prep_QC_Mark')[idx]
743 except BaseException:
744 obsqc = np.ones_like(obsdata) * 2
746 gsivars = gsi_add_vars_uv
748 gsivars = gsi_add_vars
750 for key, value
in gsivars.items():
751 if key
in self.
dfdf.variables:
752 df_key = self.
varvar(key)
753 gvname = outvars[o], value
756 if (
"Forecast" in key)
and (v ==
'uv'):
757 if (checkuv[outvars[o]] != key[0]):
761 mask = tmp < self.
EPSILONEPSILON
762 tmp[~mask] = 1.0 / tmp[~mask]
764 elif "Obs_Minus_" in key:
765 if 'u_Forecast_adjusted' in self.
dfdf.variables:
767 elif 'Forecast_adjusted' in self.
dfdf.variables:
770 if (checkuv[outvars[o]] != key[0]):
773 key1 = key[0]+
'_Observation'
776 tmp = self.
varvar(key1)[idx] - df_key[idx]
780 tmp = tmp.astype(int)
781 tmp[tmp > 4e4] = self.
INT_FILLINT_FILL
784 outdata[gvname] = tmp
786 outdata[varDict[outvars[o]][
'valKey']] = obsdata
787 outdata[varDict[outvars[o]][
'errKey']] = obserr
788 outdata[varDict[outvars[o]][
'qcKey']] = obsqc.astype(int)
791 loc_mdata_name = all_LocKeyList[lvar][0]
792 if lvar ==
'Station_ID':
793 tmp = self.
varvar(lvar)[idx]
794 StationIDs = [bytes((b
''.join(tmp[a])).decode(
'iso-8859-1').
encode(
'utf8'))
for a
in range(len(tmp))]
795 loc_mdata[loc_mdata_name] = writer.FillNcVector(StationIDs,
"string")
797 tmp = self.
varvar(lvar)[idx]
798 obstimes = [self.
validtimevalidtime + dt.timedelta(hours=float(tmp[a]))
for a
in range(len(tmp))]
799 obstimes = [a.strftime(
"%Y-%m-%dT%H:%M:%SZ")
for a
in obstimes]
800 loc_mdata[loc_mdata_name] = writer.FillNcVector(obstimes,
"datetime")
802 elif lvar ==
'Pressure':
803 tmpps = self.
varvar(lvar)[idx]
804 if np.max(tmpps) > 1100.:
805 loc_mdata[loc_mdata_name] = tmpps
807 loc_mdata[loc_mdata_name] = tmpps * 100.
809 elif lvar
in [
'Station_Elevation',
'Height']:
811 tmp = self.
varvar(lvar)[idx]
813 tmp[tmp == 10009.] = self.
FLOAT_FILLFLOAT_FILL
816 if lvar ==
'Height' and self.
obstypeobstype
in [
'conv_t',
'conv_q']:
817 elev = self.
varvar(
'Station_Elevation')[idx]
821 loc_mdata[loc_mdata_name] = tmp
822 elif p ==
'sondes' or p ==
'aircraft' or p ==
'satwind':
823 tmp = self.
varvar(lvar)[idx]
825 loc_mdata[loc_mdata_name] = tmp
827 loc_mdata[loc_mdata_name] = self.
varvar(lvar)[idx]
829 loc_mdata[loc_mdata_name] = self.
varvar(lvar)[idx]
831 for tvar
in TestVars:
832 if tvar
in test_fields_:
833 test_mdata_name = test_fields_[tvar][0]
834 tmp = self.
varvar(tvar)[idx]
836 test_mdata[test_mdata_name] = tmp
838 SIDUnique, idxs, invs = np.unique(StationIDs, return_index=
True, return_inverse=
True, axis=0)
839 loc_mdata[
'record_number'] = invs
842 var_mdata[
'variable_names'] = writer.FillNcVector(outvars,
"string")
844 AttrData[
"date_time_string"] = self.
validtimevalidtime.strftime(
"%Y-%m-%dT%H:%M:%SZ")
848 nlocs = len(StationIDs)
850 writer._nvars = nvars
851 writer._nlocs = nlocs
853 writer.BuildNetcdf(outdata, loc_mdata, var_mdata, AttrData, units_values, test_mdata)
855 print(
"ProcessedL %d Conventional obs processed to: %s" % (len(obsdata), outname))
859 """ grabobsidx(obsdata,platform,var):
860 obsdata - netCDF dataset object
861 platform - string of observation type: 'sondes','sfc',etc.
862 var - string of variable type: 'tsen','tv','q', etc.
864 returns idx - indices of observations to write out
866 code = obsdata[
'Observation_Type'][:]
867 if var
in [
'tsen',
'tv']:
868 iqt = obsdata[
'Setup_QC_Mark'][:]
873 elif var
in [
'bend',
'refract']:
874 igps = obsdata[
'GPS_Type'][:]
877 elif var ==
'refract':
884 codes = uv_bufrtypes[platform]
886 codes = conv_bufrtypes[platform]
887 idx = np.logical_and(np.in1d(code, codes), idx2)
894 """ class Radiances - satellite radiance observations
896 Use this class to read in satellite radiance observations
897 from GSI netCDF diag files
902 filename - string path to file
903 validtime - datetime object of valid observation time
904 nobs - number of observations
911 splitfname = self.
filenamefilename.split(
'/')[-1].split(
'_')
913 for s
in rad_sensors:
915 i = splitfname.index(s)
916 self.
obstypeobstype =
"_".join(splitfname[i:i + 2])
918 raise ValueError(
"Observation is not a radiance type...")
922 df = nc.Dataset(self.
filenamefilename)
923 tstr =
str(df.getncattr(
'date_time'))
924 self.
validtimevalidtime = dt.datetime.strptime(tstr,
"%Y%m%d%H")
926 self.
sensorsensor = df.getncattr(
'Observation_type')
929 self.
nobsnobs = len(df.dimensions[
'nobs'])
930 self.
nchansnchans = len(df.dimensions[
'nchans'])
937 """ toGeovals(OutDir,clobber=True)
938 if model state fields are in the GSI diag file, create
939 GeoVaLs in an output file for use by JEDI/UFO
944 outname = OutDir +
'/' + self.
sensorsensor +
'_' + self.
satellitesatellite + \
945 '_geoval_' + self.
validtimevalidtime.strftime(
"%Y%m%d%H") +
'.nc4'
947 if (os.path.exists(outname)):
948 print(
"File exists. Skipping and not overwriting:")
953 for ncv
in self.
dfdf.variables:
954 if ncv
in geovals_vars:
955 OutVars.append(geovals_vars[ncv])
959 ncout = nc.Dataset(outname,
'w', format=
'NETCDF4')
960 ncout.setncattr(
"date_time", np.int32(self.
validtimevalidtime.strftime(
"%Y%m%d%H")))
961 ncout.setncattr(
"satellite", self.
satellitesatellite)
962 ncout.setncattr(
"sensor", self.
sensorsensor)
965 ncout.createDimension(
"nlocs", nlocs)
967 ncout.createDimension(
"nlevs", self.
dfdf.dimensions[
"air_temperature_arr_dim"].size)
968 ncout.createDimension(
"nlevsp1", self.
dfdf.dimensions[
"air_pressure_levels_arr_dim"].size)
970 for var
in self.
dfdf.variables.values():
972 if vname
in geovals_metadata_dict.keys():
974 var_out = ncout.createVariable(geovals_metadata_dict[vname], var.dtype, dims)
976 vdata = vdata[::self.
nchansnchans]
978 elif vname
in geovals_vars.keys():
979 if (len(var.dimensions) == 1):
981 elif "_levels" in vname:
982 dims = (
"nlocs",
"nlevsp1")
984 dims = (
"nlocs",
"nlevs")
985 var_out = ncout.createVariable(geovals_vars[vname], var.dtype, dims)
987 vdata = vdata[::self.
nchansnchans, ...]
994 """ toObsdiag(OutDir,clobber=True)
995 if model state fields are in the GSI diag file, create
996 Obsdiag in an output file for use by JEDI/UFO
1002 outname = OutDir +
'/' + self.
sensorsensor +
'_' + self.
satellitesatellite + \
1003 '_obsdiag_' + self.
validtimevalidtime.strftime(
"%Y%m%d%H") +
'.nc4'
1005 if (os.path.exists(outname)):
1006 print(
"File exists. Skipping and not overwriting: %s" % outname)
1010 for ncv
in self.
dfdf.variables:
1011 if ncv
in obsdiag_vars:
1012 OutVars.append(obsdiag_vars[ncv])
1016 ncout = nc.Dataset(outname,
'w', format=
'NETCDF4')
1017 ncout.setncattr(
"date_time", np.int32(self.
validtimevalidtime.strftime(
"%Y%m%d%H")))
1018 ncout.setncattr(
"satellite", self.
satellitesatellite)
1019 ncout.setncattr(
"sensor", self.
sensorsensor)
1022 ncout.createDimension(
"nlocs", nlocs)
1024 nlevs = self.
dfdf.dimensions[
"air_pressure_arr_dim"].size
1025 nlevsp1 = self.
dfdf.dimensions[
"air_pressure_levels_arr_dim"].size
1027 ncout.createDimension(
"nlevs", self.
dfdf.dimensions[
"air_pressure_arr_dim"].size)
1030 chan_number = self.darr(
'sensor_chan')
1031 chan_number = chan_number[chan_number >= 0]
1032 chan_indx = self.
varvar(
'Channel_Index')
1033 nchans = len(chan_number)
1034 nlocs =
int(self.
nobsnobs / nchans)
1035 chanlist = chan_number
1038 for var
in self.
dfdf.variables.values():
1040 if vname
in obsdiag_metadata_dict.keys():
1042 var_out = ncout.createVariable(obsdiag_metadata_dict[vname], var.dtype, dims)
1044 vdata = vdata[::self.
nchansnchans]
1046 elif vname
in obsdiag_vars.keys():
1048 if (len(var.dimensions) == 1):
1050 for c
in range(len(chanlist)):
1051 var_name = obsdiag_vars[vname]+
"_"+
"{:d}".format(chanlist[c])
1052 idx = chan_indx == c+1
1053 if (np.sum(idx) == 0):
1054 print(
"No matching observations for: %s" % value)
1056 var_out = ncout.createVariable(var_name, var.dtype, dims)
1060 elif "_levels" in vname:
1061 dims = (
"nlocs",
"nlevsp1")
1063 dims = (
"nlocs",
"nlevs")
1064 for c
in range(len(chanlist)):
1065 var_name = obsdiag_vars[vname]+
"_"+
"{:d}".format(chanlist[c])
1066 idx = chan_indx == c+1
1067 if (np.sum(idx) == 0):
1068 print(
"No matching observations for: %s" % value)
1070 var_out = ncout.createVariable(var_name, var.dtype, dims)
1072 vdata = vdata[idx, ...]
1073 var_out[...] = vdata
1078 def toIODAobs(self, OutDir, ObsBias, QCVars, TestRefs, clobber=True):
1079 """ toIODAobs(OutDir,clobber=True)
1080 output observations from the specified GSI diag file
1081 to the JEDI/IODA observation format
1084 print(
"Input Parameters: ObsBias=%s QCVars=%s TestRefs=%s" % (ObsBias, QCVars, TestRefs))
1086 outname = OutDir +
'/' + self.
sensorsensor +
'_' + self.
satellitesatellite + \
1087 '_obs_' + self.
validtimevalidtime.strftime(
"%Y%m%d%H") +
'.nc4'
1089 if (os.path.exists(outname)):
1090 print(
"File exists. Skipping and not overwriting: %s" % outname)
1097 varDict = defaultdict(
lambda: defaultdict(dict))
1102 if self.
sensorsensor ==
"amsua":
1103 test_fields_ = test_fields_allsky
1104 test_fields_with_channels_ = test_fields_with_channels_allsky
1105 elif self.
sensorsensor ==
"atms":
1106 test_fields_ = test_fields_allsky
1107 test_fields_with_channels_ = test_fields_with_channels_allsky
1109 test_fields_ = test_fields
1110 test_fields_with_channels_ = test_fields_with_channels
1113 for ncv
in self.
dfdf.variables:
1114 if ncv
in all_LocKeyList:
1115 LocKeyList.append(all_LocKeyList[ncv])
1119 for ncv
in self.
dfdf.variables:
1120 if ncv
in test_fields_:
1121 TestKeyList.append(test_fields_[ncv])
1122 TestVars.append(ncv)
1123 if ncv
in test_fields_with_channels_:
1124 TestKeyList.append(test_fields_with_channels_[ncv])
1125 TestVars.append(ncv)
1129 writer = iconv.NcWriter(outname, LocKeyList, TestKeyList=TestKeyList)
1131 writer = iconv.NcWriter(outname, LocKeyList)
1133 chan_number = self.
varvar(
'sensor_chan')
1134 chan_number = chan_number[chan_number >= 0]
1135 chan_indx = self.
varvar(
'Channel_Index')
1136 nchans = len(chan_number)
1137 nlocs =
int(self.
nobsnobs / nchans)
1139 chanlist = chan_number
1141 value =
"brightness_temperature_{:d}".format(a)
1142 varDict[value][
'valKey'] = value, writer.OvalName()
1143 varDict[value][
'errKey'] = value, writer.OerrName()
1144 varDict[value][
'qcKey'] = value, writer.OqcName()
1145 units_values[value] =
'K'
1148 "constant_{:d}".format(a),
1149 "zenith_angle_{:d}".format(a),
1150 "cloud_liquid_water_{:d}".format(a),
1151 "lapse_rate_squared_{:d}".format(a),
1152 "lapse_rate_{:d}".format(a),
1153 "cosine_of_latitude_times_orbit_node_{:d}".format(a),
1154 "sine_of_latitude_{:d}".format(a),
1155 "emissivity_{:d}".format(a),
1156 "scan_angle_order_4_{:d}".format(a),
1157 "scan_angle_order_3_{:d}".format(a),
1158 "scan_angle_order_2_{:d}".format(a),
1159 "scan_angle_{:d}".format(a),
1163 varDict[vbc][
'bctKey'] = vbc, writer.ObiastermName()
1164 varDict[vbc][
'bcpKey'] = vbc, writer.ObiaspredName()
1166 obsdata = self.
varvar(
'Observation')
1168 obserr = self.
varvar(
'Input_Observation_Error')
1170 obserr = 1./self.
varvar(
'Inverse_Observation_Error')
1171 obsqc = self.
varvar(
'QC_Flag').astype(int)
1176 'BC_Cloud_Liquid_Water',
1177 'BC_Lapse_Rate_Squared',
1179 'BC_Cosine_Latitude_times_Node',
1182 'BC_Scan_Angle_4th_order',
1183 'BC_Scan_Angle_3rd_order',
1184 'BC_Scan_Angle_2nd_order',
1185 'BC_Scan_Angle_1st_order',
1189 'BCPred_Scan_Angle',
1190 'BCPred_Cloud_Liquid_Water',
1191 'BCPred_Lapse_Rate_Squared',
1192 'BCPred_Lapse_Rate',
1193 'BCPred_Cosine_Latitude_times_Node',
1194 'BCPred_Sine_Latitude',
1195 'BCPred_Emissivity',
1196 'BCPred_Scan_Angle_4th_order',
1197 'BCPred_Scan_Angle_3rd_order',
1198 'BCPred_Scan_Angle_2nd_order',
1199 'BCPred_Scan_Angle_1st_order',
1204 obsbiasterm.append(self.
varvar(nametbc[ii]))
1210 obsbiaspred.append(self.
varvar(namepbc[ii]))
1212 for lvar
in LocVars:
1213 loc_mdata_name = all_LocKeyList[lvar][0]
1214 if lvar ==
'Obs_Time':
1215 tmp = self.
varvar(lvar)[::nchans]
1216 obstimes = [self.
validtimevalidtime + dt.timedelta(hours=float(tmp[a]))
for a
in range(len(tmp))]
1217 obstimes = [a.strftime(
"%Y-%m-%dT%H:%M:%SZ")
for a
in obstimes]
1218 loc_mdata[loc_mdata_name] = writer.FillNcVector(obstimes,
"datetime")
1219 elif self.
sensorsensor ==
"gmi" and lvar
in gmi_chan_dep_loc_vars:
1221 tmp = self.
varvar(lvar)[::nchans]
1223 loc_mdata[loc_mdata_name] = tmp
1225 tmp = self.
varvar(lvar)[nchans-1::nchans]
1227 loc_mdata[loc_mdata_name+
'1'] = tmp
1229 tmp = self.
varvar(lvar)[::nchans]
1231 loc_mdata[loc_mdata_name] = tmp
1234 for tvar
in TestVars:
1235 if tvar
in test_fields_with_channels_:
1236 for ii, ch
in enumerate(chanlist):
1237 test_mdata_name = test_fields_with_channels_[tvar][0]+
"_{:d}".format(ch)
1238 tmp = self.
varvar(tvar)[:]
1240 idx = chan_indx == ii+1
1242 test_mdata[test_mdata_name] = outvals
1243 if tvar
in test_fields_:
1244 test_mdata_name = test_fields_[tvar][0]
1245 tmp = self.
varvar(tvar)[::nchans]
1247 test_mdata[test_mdata_name] = tmp
1249 gsi_add_radvars = gsi_add_vars
1251 gsi_add_radvars.update(gsi_add_qcvars)
1253 if self.
sensorsensor ==
"amsua":
1254 gsi_add_radvars = gsi_add_vars_allsky
1256 gsi_add_radvars.update(gsi_add_qcvars_allsky)
1258 if self.
sensorsensor ==
"atms":
1259 gsi_add_radvars = gsi_add_vars_allsky
1261 gsi_add_radvars.update(gsi_add_qcvars_allsky)
1264 for gsivar, iodavar
in gsi_add_radvars.items():
1265 if gsivar
in self.
dfdf.variables:
1266 if "Inverse" in gsivar:
1267 tmp = self.
varvar(gsivar)
1269 mask = tmp < self.
EPSILONEPSILON
1270 tmp[~mask] = 1.0 / tmp[~mask]
1272 elif "Obs_Minus_" in gsivar:
1273 if 'Forecast_adjusted' in self.
dfdf.variables:
1275 key1 =
'Observation'
1276 tmp = self.
varvar(key1) - self.
varvar(gsivar)
1278 tmp = self.
varvar(gsivar)
1279 if gsivar
in gsiint:
1280 tmp = tmp.astype(int)
1283 for ii, ch
in enumerate(chanlist):
1284 varname =
"brightness_temperature_{:d}".format(ch)
1285 gvname = varname, iodavar
1286 idx = chan_indx == ii+1
1288 outdata[gvname] = outvals
1292 for c
in range(len(chanlist)):
1293 value =
"brightness_temperature_{:d}".format(chanlist[c])
1294 var_names.append(value)
1295 idx = chan_indx == c+1
1296 if (np.sum(idx) == 0):
1297 print(
"No matching observations for: %s" % value)
1299 obsdatasub = obsdata[idx]
1300 obsdatasub[obsdatasub > 9e5] = self.
FLOAT_FILLFLOAT_FILL
1301 obserrsub = obserr[idx]
1302 obsqcsub = obsqc[idx]
1303 obsqcsub[obsdatasub > 9e5] = self.
INT_FILLINT_FILL
1306 outdata[varDict[value][
'valKey']] = obsdatasub
1307 outdata[varDict[value][
'errKey']] = obserrsub
1308 outdata[varDict[value][
'qcKey']] = obsqcsub.astype(int)
1311 "constant_{:d}".format(chanlist[c]),
1312 "zenith_angle_{:d}".format(chanlist[c]),
1313 "cloud_liquid_water_{:d}".format(chanlist[c]),
1314 "lapse_rate_squared_{:d}".format(chanlist[c]),
1315 "lapse_rate_{:d}".format(chanlist[c]),
1316 "cosine_of_latitude_times_orbit_node_{:d}".format(chanlist[c]),
1317 "sine_of_latitude_{:d}".format(chanlist[c]),
1318 "emissivity_{:d}".format(chanlist[c]),
1319 "scan_angle_order_4_{:d}".format(chanlist[c]),
1320 "scan_angle_order_3_{:d}".format(chanlist[c]),
1321 "scan_angle_order_2_{:d}".format(chanlist[c]),
1322 "scan_angle_{:d}".format(chanlist[c]),
1325 for value
in valuebc:
1326 obsbiastermsub = obsbiasterm[ii][idx]
1327 obsbiaspredsub = obsbiaspred[ii][idx]
1328 obsbiastermsub[obsbiastermsub > 9e5] = self.
FLOAT_FILLFLOAT_FILL
1329 obsbiaspredsub[obsbiaspredsub > 9e5] = self.
FLOAT_FILLFLOAT_FILL
1332 outdata[varDict[value][
'bctKey']] = obsbiastermsub
1333 outdata[varDict[value][
'bcpKey']] = obsbiaspredsub
1336 var_mdata[
'variable_names'] = writer.FillNcVector(var_names,
"string")
1337 for key, value2
in chan_metadata_dict.items():
1339 var_mdata[value2] = self.
varvar(key)
1344 loc_mdata[
'record_number'] = np.full((nlocs), 1, dtype=
'i4')
1348 AttrData[
"date_time_string"] = self.
validtimevalidtime.strftime(
"%Y-%m-%dT%H:%M:%SZ")
1349 AttrData[
"satellite"] = self.
satellitesatellite
1350 AttrData[
"sensor"] = self.
sensorsensor
1354 writer._nvars = nchans
1355 writer._nlocs = nlocs
1357 writer.BuildNetcdf(outdata, loc_mdata, var_mdata,
1358 AttrData, units_values, test_mdata)
1360 writer.BuildNetcdf(outdata, loc_mdata, var_mdata,
1361 AttrData, units_values)
1363 print(
"Satellite radiance obs processed, wrote to: %s" % outname)
1369 """ class AOD - aerosol optical depth satellite observations
1371 Use this class to read in AOD satellite observations
1372 from GSI netCDF diag files
1376 filename - string path to file
1377 validtime - datetime object of valid observation time
1378 nobs - number of observations
1382 splitfname = self.
filenamefilename.split(
'/')[-1].split(
'_')
1384 for s
in aod_sensors:
1386 i = splitfname.index(s)
1389 raise ValueError(
"Observation is not AOD type...")
1396 df = nc.Dataset(self.
filenamefilename)
1397 tstr =
str(df.getncattr(
'date_time'))
1398 self.
validtimevalidtime = dt.datetime.strptime(tstr,
"%Y%m%d%H")
1400 self.
nobsnobs = len(df.dimensions[
'nobs'])
1401 self.
nchansnchans = len(df.dimensions[
'nchans'])
1405 """ toGeovals(OutDir,clobber=True)
1406 if model state fields are in the GSI diag file, create
1407 GeoVaLs in an output file for use by JEDI/UFO
1413 outname = OutDir+
'/'+self.
obstypeobstype+
'_geoval_'+self.
validtimevalidtime.strftime(
"%Y%m%d%H")+
'.nc4'
1415 if (os.path.exists(outname)):
1416 print(
"File exists. Skipping and not overwriting: %s" % outname)
1420 for ncv
in self.
dfdf.variables:
1421 if ncv
in geovals_vars:
1422 OutVars.append(geovals_vars[ncv])
1426 ncout = nc.Dataset(outname,
'w', format=
'NETCDF4')
1427 ncout.setncattr(
"date_time", np.int32(self.
validtimevalidtime.strftime(
"%Y%m%d%H")))
1428 ncout.setncattr(
"satellite", self.
satellitesatellite)
1429 ncout.setncattr(
"sensor", self.
sensorsensor)
1431 nlocs = self.
nobsnobs
1432 ncout.createDimension(
"nlocs", nlocs)
1434 ncout.createDimension(
"nlevs", self.
dfdf.dimensions[
"air_temperature_arr_dim"].size)
1435 ncout.createDimension(
"nlevsp1", self.
dfdf.dimensions[
"air_pressure_levels_arr_dim"].size)
1436 for var
in self.
dfdf.variables.values():
1438 if vname
in geovals_metadata_dict.keys():
1440 var_out = ncout.createVariable(geovals_metadata_dict[vname], var.dtype, dims)
1443 elif vname
in geovals_vars.keys():
1444 if (len(var.dimensions) == 1):
1446 elif "_levels" in vname:
1447 dims = (
"nlocs",
"nlevsp1")
1449 dims = (
"nlocs",
"nlevs")
1450 var_out = ncout.createVariable(geovals_vars[vname], var.dtype, dims)
1452 var_out[...] = vdata
1459 toIODAobs(OutDir,clobber=True)
1460 output observations from the specified GSI diag file
1461 to the JEDI/IODA observation format
1464 outname = OutDir+
'/'+self.
obstypeobstype+
'_obs_'+self.
validtimevalidtime.strftime(
"%Y%m%d%H")+
'.nc4'
1466 if (os.path.exists(outname)):
1467 print(
"File exists. Skipping and not overwriting:%s" % outname)
1472 varDict = defaultdict(
lambda: defaultdict(dict))
1477 for ncv
in self.
dfdf.variables:
1478 if ncv
in all_LocKeyList:
1479 LocKeyList.append(all_LocKeyList[ncv])
1483 writer = iconv.NcWriter(outname, LocKeyList)
1485 chan_number = self.
varvar(
'sensor_chan')
1486 chan_number = chan_number[chan_number >= 0]
1487 chan_indx = self.
varvar(
'Channel_Index')
1488 nchans = len(chan_number)
1489 nlocs = self.
nobsnobs / nchans
1490 chanlist = chan_indx[:nchans]
1492 value =
"aerosol_optical_depth_{:d}".format(a)
1493 varDict[value][
'valKey'] = value, writer.OvalName()
1494 varDict[value][
'errKey'] = value, writer.OerrName()
1495 varDict[value][
'qcKey'] = value, writer.OqcName()
1497 obsdata = self.
varvar(
'Observation')
1498 obserr = 1.0/self.
varvar(
'Observation_Error')
1499 obsqc = self.
varvar(
'QC_Flag').astype(int)
1501 gsivars = gsi_add_vars
1505 for c
in range(len(chanlist)):
1506 value =
"aerosol_optical_depth_{:d}".format(chanlist[c])
1507 var_names.append(value)
1508 idx = chan_indx == chanlist[c]
1509 obsdatasub = obsdata[idx]
1510 obserrsub = obserr[idx]
1511 obsqcsub = obsqc[idx]
1512 for lvar
in LocVars:
1513 loc_mdata_name = all_LocKeyList[lvar][0]
1514 if lvar ==
'Obs_Time':
1515 tmp = self.
varvar(lvar)[idx]
1516 obstimes = [self.
validtimevalidtime+dt.timedelta(hours=float(tmp[a]))
for a
in range(len(tmp))]
1517 obstimes = [a.strftime(
"%Y-%m-%dT%H:%M:%SZ")
for a
in obstimes]
1518 loc_mdata[loc_mdata_name] = writer.FillNcVector(obstimes,
"datetime")
1520 loc_mdata[loc_mdata_name] = self.
varvar(lvar)[idx]
1522 for key, value2
in gsivars.items():
1524 if "Inverse" in key:
1526 gsimeta[key] = 1.0/self.
varvar(key)[idx]
1531 gsimeta[key] = self.
varvar(key)[idx]
1536 outdata[varDict[value][
'valKey']] = obsdatasub
1537 outdata[varDict[value][
'errKey']] = obserrsub
1538 outdata[varDict[value][
'qcKey']] = obsqcsub
1541 for key, value2
in gsivars.items():
1542 gvname = value, value2
1543 if value2
in gsiint:
1545 outdata[gvname] = gsimeta[key].astype(int)
1550 outdata[gvname] = gsimeta[key]
1555 var_mdata[
'variable_names'] = writer.FillNcVector(var_names,
"string")
1556 for key, value2
in chan_metadata_dict.items():
1558 var_mdata[value2] = self.
varvar(key)[:nchans]
1563 loc_mdata[
'record_number'] = np.full((nlocs), 1, dtype=
'i4')
1566 AttrData[
"date_time_string"] = self.
validtimevalidtime.strftime(
"%Y-%m-%dT%H:%M:%SZ")
1567 AttrData[
"satellite"] = self.
satellitesatellite
1568 AttrData[
"sensor"] = self.
sensorsensor
1571 writer._nvars = nchans
1572 writer._nlocs = nlocs
1574 writer.BuildNetcdf(outdata, loc_mdata, var_mdata, AttrData, units_values)
1575 print(
"AOD obs processed, wrote to:%s" % outname)
1579 """ class Ozone - ozone satellite observations
1581 Use this class to read in ozone satellite observations
1582 from GSI netCDF diag files
1587 filename - string path to file
1588 validtime - datetime object of valid observation time
1589 nobs - number of observations
1594 splitfname = self.
filenamefilename.split(
'/')[-1].split(
'_')
1596 for s
in oz_sensors:
1598 i = splitfname.index(s)
1601 raise ValueError(
"Observation is not an ozone type...")
1608 df = nc.Dataset(self.
filenamefilename)
1609 tstr =
str(df.getncattr(
'date_time'))
1610 self.
validtimevalidtime = dt.datetime.strptime(tstr,
"%Y%m%d%H")
1612 self.
nobsnobs = len(df.dimensions[
'nobs'])
1616 """ toGeovals(OutDir,clobber=True)
1617 if model state fields are in the GSI diag file, create
1618 GeoVaLs in an output file for use by JEDI/UFO
1624 outname = OutDir+
'/'+self.
sensorsensor+
'_'+self.
satellitesatellite+
'_geoval_'+self.
validtimevalidtime.strftime(
"%Y%m%d%H")+
'.nc4'
1626 if (os.path.exists(outname)):
1627 print(
"File exists. Skipping and not overwriting: %s" % outname)
1631 for ncv
in self.
dfdf.variables:
1632 if ncv
in geovals_vars:
1633 OutVars.append(geovals_vars[ncv])
1637 ncout = nc.Dataset(outname,
'w', format=
'NETCDF4')
1638 ncout.setncattr(
"date_time", np.int32(self.
validtimevalidtime.strftime(
"%Y%m%d%H")))
1639 ncout.setncattr(
"satellite", self.
satellitesatellite)
1640 ncout.setncattr(
"sensor", self.
sensorsensor)
1642 nlocs = self.
nobsnobs
1643 ncout.createDimension(
"nlocs", nlocs)
1645 ncout.createDimension(
"nlevs", self.
dfdf.dimensions[
"mole_fraction_of_ozone_in_air_arr_dim"].size)
1646 if (self.
sensorsensor
not in [
"ompslp",
"mls55"]):
1647 ncout.createDimension(
"nlevsp1", self.
dfdf.dimensions[
"air_pressure_levels_arr_dim"].size)
1648 for var
in self.
dfdf.variables.values():
1650 if vname
in geovals_metadata_dict.keys():
1652 var_out = ncout.createVariable(geovals_metadata_dict[vname], var.dtype, dims)
1655 elif vname
in geovals_vars.keys():
1656 if (len(var.dimensions) == 1):
1658 elif "_levels" in vname:
1659 dims = (
"nlocs",
"nlevsp1")
1661 dims = (
"nlocs",
"nlevs")
1662 var_out = ncout.createVariable(geovals_vars[vname], var.dtype, dims)
1664 var_out[...] = vdata
1670 """ toIODAobs(OutDir,clobber=True)
1671 output observations from the specified GSI diag file
1672 to the JEDI/IODA observation format
1675 outname = OutDir+
'/'+self.
sensorsensor+
'_'+self.
satellitesatellite+
'_obs_'+self.
validtimevalidtime.strftime(
"%Y%m%d%H")+
'.nc4'
1677 if (os.path.exists(outname)):
1678 print(
"File exists. Skipping and not overwriting: %s" % outname)
1683 varDict = defaultdict(
lambda: defaultdict(dict))
1688 for ncv
in self.
dfdf.variables:
1689 if ncv
in all_LocKeyList:
1690 LocKeyList.append(all_LocKeyList[ncv])
1693 writer = iconv.NcWriter(outname, LocKeyList)
1695 nlocs = self.
nobsnobs
1696 vname =
"integrated_layer_ozone_in_air"
1697 if (self.
sensorsensor
in [
"ompslp",
"mls55"]):
1698 vname =
"mole_fraction_of_ozone_in_air"
1699 varDict[vname][
'valKey'] = vname, writer.OvalName()
1700 varDict[vname][
'errKey'] = vname, writer.OerrName()
1701 varDict[vname][
'qcKey'] = vname, writer.OqcName()
1703 obsdata = self.
varvar(
'Observation')
1705 tmp = self.
varvar(
'Input_Observation_Error')
1707 tmp = 1./self.
varvar(
'Inverse_Observation_Error')
1708 tmp[tmp < self.
EPSILONEPSILON] = 0
1710 obserr[np.isinf(obserr)] = self.
FLOAT_FILLFLOAT_FILL
1711 obsqc = self.
varvar(
'Analysis_Use_Flag').astype(int)
1713 for lvar
in LocVars:
1714 loc_mdata_name = all_LocKeyList[lvar][0]
1716 tmp = self.
varvar(lvar)
1717 obstimes = [self.
validtimevalidtime+dt.timedelta(hours=float(tmp[a]))
for a
in range(len(tmp))]
1718 obstimes = [a.strftime(
"%Y-%m-%dT%H:%M:%SZ")
for a
in obstimes]
1719 loc_mdata[loc_mdata_name] = writer.FillNcVector(obstimes,
"datetime")
1721 tmp = self.
varvar(lvar)
1723 loc_mdata[loc_mdata_name] = tmp
1725 for gsivar, iodavar
in gsi_add_vars.items():
1727 if gsivar
in self.
dfdf.variables:
1728 if "Inverse" in gsivar:
1729 tmp = self.
varvar(gsivar)
1731 mask = tmp < self.
EPSILONEPSILON
1732 tmp[~mask] = 1.0 / tmp[~mask]
1734 elif "Obs_Minus_" in gsivar:
1735 if 'Forecast_adjusted' in self.
dfdf.variables:
1737 key1 =
'Observation'
1738 tmp = self.
varvar(key1) - self.
varvar(gsivar)
1740 tmp = self.
varvar(gsivar)
1741 if gsivar
in gsiint:
1742 tmp = tmp.astype(int)
1745 gvname = vname, iodavar
1746 outdata[gvname] = tmp
1748 outdata[varDict[vname][
'valKey']] = obsdata
1749 outdata[varDict[vname][
'errKey']] = obserr
1750 outdata[varDict[vname][
'qcKey']] = obsqc
1753 loc_mdata[
'record_number'] = np.full((nlocs), 1, dtype=
'i4')
1755 AttrData[
"date_time_string"] = self.
validtimevalidtime.strftime(
"%Y-%m-%dT%H:%M:%SZ")
1756 AttrData[
"satellite"] = self.
satellitesatellite
1757 AttrData[
"sensor"] = self.
sensorsensor
1761 writer._nlocs = nlocs
1763 writer.BuildNetcdf(outdata, loc_mdata, var_mdata, AttrData, units_values)
1764 print(
"Ozone obs processed, wrote to: %s" % outname)
1768 """ class Radar - reflectivity and radial wind observations
1770 Use this class to read in radar observations
1771 from GSI netCDF diag files
1776 filename - string path to file
1777 validtime - datetime object of valid observation time
1778 nobs - number of observations
1783 splitfname = self.
filenamefilename.split(
'/')[-1].split(
'_')
1785 for s
in radar_sensors:
1787 i = splitfname.index(s)
1790 raise ValueError(
"Observation is not a radar type...")
1793 self.
obstypeobstype = splitfname[i+1]
1797 df = nc.Dataset(self.
filenamefilename)
1798 tstr =
str(df.getncattr(
'date_time'))
1799 self.
validtimevalidtime = dt.datetime.strptime(tstr,
"%Y%m%d%H")
1801 self.
nobsnobs = len(df.dimensions[
'nobs'])
1805 """ toGeovals(OutDir,clobber=True)
1806 if model state fields are in the GSI diag file, create
1807 GeoVaLs in an output file for use by JEDI/UFO
1813 outname = OutDir+
'/'+self.
sensorsensor+
'_'+self.
obstypeobstype+
'_geoval_'+self.
validtimevalidtime.strftime(
"%Y%m%d%H")+
'.nc4'
1815 if (os.path.exists(outname)):
1816 print(
"File exists. Skipping and not overwriting: %s" % outname)
1820 for ncv
in self.
dfdf.variables:
1821 if ncv
in geovals_vars:
1822 OutVars.append(geovals_vars[ncv])
1826 ncout = nc.Dataset(outname,
'w', format=
'NETCDF4')
1827 ncout.setncattr(
"date_time", np.int32(self.
validtimevalidtime.strftime(
"%Y%m%d%H")))
1829 nlocs = self.
nobsnobs
1830 ncout.createDimension(
"nlocs", nlocs)
1832 ncout.createDimension(
"nlevs", self.
dfdf.dimensions[
"nlevs"].size)
1834 for var
in self.
dfdf.variables.values():
1836 if vname
in geovals_metadata_dict.keys():
1838 var_out = ncout.createVariable(geovals_metadata_dict[vname], var.dtype, dims)
1841 elif vname
in geovals_vars.keys():
1842 if (len(var.dimensions) == 1):
1844 elif "_levels" in vname:
1845 dims = (
"nlocs",
"nlevsp1")
1847 dims = (
"nlocs",
"nlevs")
1848 var_out = ncout.createVariable(geovals_vars[vname], var.dtype, dims)
1850 var_out[...] = vdata
1856 """ toIODAobs(OutDir,clobber=True)
1857 output observations from the specified GSI diag file
1858 to the JEDI/IODA observation format
1861 outname = OutDir+
'/'+self.
sensorsensor+
'_'+self.
obstypeobstype+
'_obs_'+self.
validtimevalidtime.strftime(
"%Y%m%d%H")+
'.nc4'
1863 if (os.path.exists(outname)):
1864 print(
"File exists. Skipping and not overwriting:%s" % outname)
1869 varDict = defaultdict(
lambda: defaultdict(dict))
1874 for ncv
in self.
dfdf.variables:
1875 if ncv
in all_LocKeyList:
1876 LocKeyList.append(all_LocKeyList[ncv])
1879 writer = iconv.NcWriter(outname, LocKeyList)
1881 nlocs = self.
nobsnobs
1882 if self.
obstypeobstype ==
"dbz":
1884 'obsdbz':
'equivalent_reflectivity_factor',
1886 elif self.
obstypeobstype ==
"rw":
1888 'obsrw':
'radial_velocity',
1891 for key, value
in radar_varnames.items():
1892 varDict[value][
'valKey'] = value, writer.OvalName()
1893 varDict[value][
'errKey'] = value, writer.OerrName()
1894 varDict[value][
'qcKey'] = value, writer.OqcName()
1896 obsdata = self.
varvar(key)
1897 errvarname = radar_err[key]
1898 qcvarname = radar_qc[key]
1899 obserr = self.
varvar(errvarname)
1900 obserr[np.isinf(obserr)] = self.
FLOAT_FILLFLOAT_FILL
1901 obsqc = self.
varvar(qcvarname).astype(int)
1903 outdata[varDict[value][
'valKey']] = obsdata
1904 outdata[varDict[value][
'errKey']] = obserr
1905 outdata[varDict[value][
'qcKey']] = obsqc
1907 for gsivar, iodavar
in gsi_add_vars.items():
1909 if gsivar
in self.
dfdf.variables:
1910 if "Inverse" in gsivar:
1911 tmp = self.
varvar(gsivar)
1913 mask = tmp < self.
EPSILONEPSILON
1914 tmp[~mask] = 1.0 / tmp[~mask]
1917 tmp = self.
varvar(gsivar)[:]
1918 if gsivar
in gsiint:
1919 tmp = tmp.astype(int)
1922 gvname = vname, iodavar
1923 outdata[gvname] = tmp
1925 for lvar
in LocVars:
1926 loc_mdata_name = all_LocKeyList[lvar][0]
1928 tmp = self.
varvar(lvar)[:]
1929 obstimes = [self.
validtimevalidtime+dt.timedelta(hours=float(tmp[a]))
for a
in range(len(tmp))]
1930 obstimes = [a.strftime(
"%Y-%m-%dT%H:%M:%SZ")
for a
in obstimes]
1931 loc_mdata[loc_mdata_name] = writer.FillNcVector(obstimes,
"datetime")
1933 tmp = self.
varvar(lvar)[:]
1935 loc_mdata[loc_mdata_name] = tmp
1938 loc_mdata[
'record_number'] = np.full((nlocs), 1, dtype=
'i4')
1940 AttrData[
"date_time_string"] = self.
validtimevalidtime.strftime(
"%Y-%m-%dT%H:%M:%SZ")
1941 AttrData[
"sensor"] = self.
sensorsensor
1945 writer._nlocs = nlocs
1947 writer.BuildNetcdf(outdata, loc_mdata, var_mdata, AttrData, units_values)
1948 print(
"Radar obs processed, wrote to: %s" % outname)
def __init__(self, filename)
def toIODAobs(self, OutDir, clobber=True)
def toGeovals(self, OutDir, clobber=True)
def _as_array(netcdf_var)
def __init__(self, filename)
def toIODAobs(self, OutDir, clobber=True, platforms=None)
def toGeovals(self, OutDir, clobber=True)
def __init__(self, filename)
def toIODAobs(self, OutDir, clobber=True)
def toGeovals(self, OutDir, clobber=True)
def toIODAobs(self, OutDir, clobber=True)
def toGeovals(self, OutDir, clobber=True)
def __init__(self, filename)
def toIODAobs(self, OutDir, ObsBias, QCVars, TestRefs, clobber=True)
def __init__(self, filename)
def toObsdiag(self, OutDir, clobber=True)
def toGeovals(self, OutDir, clobber=True)
def grabobsidx(obsdata, platform, var)
void encode(DataHandle &out, const std::vector< ColumnInfo > &columns, const std::vector< ConstStridedData > &data, const std::map< std::string, std::string > &properties, size_t maxRowsPerFrame)