MPAS-JEDI
var_utils.py
Go to the documentation of this file.
1 #!/usr/bin/env python3
2 
3 from copy import deepcopy
4 from jediApplicationArgs import depbgGroup, depanGroup
5 import numpy as np
6 import os
7 import re
8 import plot_utils as pu
9 
10 miss_f = -88888.8
11 miss_i = -88888
12 miss_s = 'null'
13 csvSEP = ';'
14 
15 #=====================
16 # variable definitions
17 #=====================
18 
19 ## NC variable names for MPAS-JEDI
20 obsVarAlt = 'altitude'
21 obsVarACI = 'asymmetric_cloud_impact'
22 obsVarBT = 'brightness_temperature'
23 obsVarBTClear = obsVarBT+'_assuming_clear_sky'
24 obsVarCldFrac = 'cloud_area_fraction'
25 obsVarDT = 'datetime'
26 obsVarGlint = 'glint'
27 obsVarLT = 'LocalTime'
28 obsVarLandFrac= 'land_area_fraction'
29 obsVarLat = 'latitude'
30 obsVarLon = 'longitude'
31 obsVarNormErr = 'dσ\N{SUPERSCRIPT MINUS}\N{SUPERSCRIPT ONE}'
32 obsVarPrs = 'air_pressure'
33 obsVarQC = 'QCflag'
34 obsVarSCI = 'symmetric_cloud_impact'
35 obsVarSenZen = 'sensor_zenith_angle'
36 obsVarSenAzi = 'sensor_azimuth_angle'
37 obsVarSolZen = 'solar_zenith_angle'
38 obsVarSolAzi = 'solar_azimuth_angle'
39 
40 degree= u'\N{DEGREE SIGN}'
41 
42 # columns: var_name unit_used abbr.
43 varDictObs = {
44  'air_temperature': [ 'K', 'T' ],
45  'bending_angle': [ '%', 'Bnd' ],
46  obsVarBT: [ 'K', 'BT' ],
47  'eastward_wind': [ 'm/s', 'U' ],
48  'northward_wind': [ 'm/s', 'V' ],
49  'refractivity': [ '%', 'Ref' ],
50  'specific_humidity': [ 'kg/kg', 'qv' ],
51  'surface_pressure': [ 'Pa', 'Ps' ],
52  'virtual_temperature': [ 'K', 'Tv' ],
53  obsVarAlt: [ 'm', 'alt' ],
54  obsVarACI: [ 'K', 'ACI' ],
55  obsVarCldFrac: [ miss_s, 'cldfrac' ],
56  obsVarLandFrac: [ miss_s, 'landfrac'],
57  obsVarLat: [ degree, 'lat' ],
58  obsVarLon: [ degree, 'lon' ],
59  obsVarLT: [ 'hr', obsVarLT ],
60  obsVarNormErr: [ miss_s, obsVarNormErr ],
61  obsVarPrs: [ 'hPa', 'P' ],
62  obsVarQC: [ miss_s, obsVarQC ],
63  obsVarSCI: [ 'K', 'SCI' ],
64  obsVarSenZen: [ degree, 'zenith' ],
65  obsVarGlint: [ degree, obsVarGlint ],
66 }
67 #Note, refractivity: we plot RMSE of OMB/O and OMA/O; refractivity unit: N-unit
68 #Note, bending_angle: we plot RMSE of OMB/O and OMA/O; bendibinVar == obsVarAlt:
69 
70 obsRegionBinVar = 'ObsRegion'
71 varDictObs[obsRegionBinVar] = [miss_s, obsRegionBinVar]
72 
73 # IODA observation variable name substitutions
74 vNameStr = 'varName'
75 vChanStr = 'varCHAN'
76 
77 # Dynamic Fixed IODA ObsGroups for observation-type variables
78 hofxGroup = 'hofx'
79 qcGroup = 'EffectiveQC'
80 errorGroup = 'EffectiveError'
81 bgIter = '0'
82 
83 # Fixed IODA ObsGroups for observation-type variables
84 obsGroup = 'ObsValue'
85 metaGroup = 'MetaData'
86 
87 # Dynamic MPAS-Workflow ObsGroups for observation-type variables
88 depGroup = 'depIter'
89 
90 # GeoVaLs ObsGroups only used in post-processing, not in files
91 diagGroup = 'ObsDiag'
92 geoGroup = 'GeoVaLs'
93 
94 # Generic variable names used as baseVar
95 selfObsValue = 'selfObsValue'
96 selfDepValue = 'selfDepValue'
97 selfHofXValue = 'selfHofXValue'
98 selfQCValue = 'selfQCValue'
99 selfErrorValue = 'selfErrorValue'
100 bgHofXValue = 'bgHofXValue'
101 altMeta = 'altMeta'
102 cldfracMeta = 'cldfracMeta'
103 datetimeMeta = 'datetimeMeta'
104 latMeta = 'latMeta'
105 lonMeta = 'lonMeta'
106 prsMeta = 'prsMeta'
107 senzenMeta = 'senzenMeta'
108 senaziMeta = 'senaziMeta'
109 solzenMeta = 'solzenMeta'
110 solaziMeta = 'solaziMeta'
111 landfracGeo = 'landfracGeo'
112 clrskyBTDiag = 'clrskyBTDiag'
113 
114 # Context-dependent (dynamic) IODA variable names
115 ObsGroups = {}
116 ObsVars = {}
117 ObsGroups[selfObsValue] = obsGroup
118 ObsGroups[selfDepValue] = depGroup
119 ObsGroups[selfHofXValue] = hofxGroup
120 ObsGroups[selfQCValue] = qcGroup
121 ObsGroups[selfErrorValue] = errorGroup
122 
123 for key in ObsGroups.keys():
124  ObsVars[key] = vNameStr
125 
126 ObsGroups[bgHofXValue] = hofxGroup+bgIter
127 ObsVars[bgHofXValue] = vNameStr
128 
129 # Fixed IODA variable names (MetaData)
130 ObsVars[altMeta] = obsVarAlt
131 ObsVars[cldfracMeta] = obsVarCldFrac
132 ObsVars[datetimeMeta] = obsVarDT
133 ObsVars[latMeta] = obsVarLat
134 ObsVars[lonMeta] = obsVarLon
135 ObsVars[prsMeta] = obsVarPrs
136 ObsVars[senzenMeta] = obsVarSenZen
137 ObsVars[senaziMeta] = obsVarSenAzi
138 ObsVars[solzenMeta] = obsVarSolZen
139 ObsVars[solaziMeta] = obsVarSolAzi
140 
141 for key in ObsVars.keys():
142  if 'Meta' in key:
143  ObsGroups[key] = metaGroup
144 
145 # separator to be used for channel or other integer suffixes
146 intSufSeparator = '_'
147 
148 
149 # GeoVaLs variable names
150 ObsVars[landfracGeo] = obsVarLandFrac
151 ObsGroups[landfracGeo] = geoGroup
152 
153 ObsVars[clrskyBTDiag] = obsVarBTClear+intSufSeparator+vChanStr
154 ObsGroups[clrskyBTDiag] = diagGroup
155 
156 
157 # ensemble/mean classifiers
158 mean = 'mean'
159 ensemble = 'ensemble'
160 ensSuffixBase = "&&&mem"
161 def ensSuffix(member):
162  if member == 0:
163  return ""
164  else:
165  return ensSuffixBase+str(member)
166 
167 
168 # functions for extracting/combining sub-parts of UFO variable names
169 def splitObsVarGrp(WholeVarGrp):
170  if "@" in WholeVarGrp:
171  var = '@'.join(WholeVarGrp.split('@')[:-1])
172  grp = WholeVarGrp.split('@')[-1]
173  elif "/" in WholeVarGrp:
174  grp = WholeVarGrp.split('/')[0]
175  var = '/'.join(WholeVarGrp.split('/')[1:])
176  else:
177  var = WholeVarGrp
178  grp = miss_s
179  return var, grp
180 
181 
182 def splitIntSuffix(var):
183  # separate integer suffixes (e.g., brightness_temperature_*)
184  obsVarName, grpName = splitObsVarGrp(var)
185  suf = obsVarName.split(intSufSeparator)[-1]
186  if not pu.isint(suf):
187  suf = ''
188  else:
189  obsVarName = intSufSeparator.join(obsVarName.split(intSufSeparator)[:-1])
190  return obsVarName, suf
191 
192 
193 def appendSuffix(var, suf):
194  return var+intSufSeparator+str(suf)
195 
196 
197 def varAttributes(var):
198  # return short name and units
199  dictName, suf = splitIntSuffix(var)
200  varAtt = varDictObs.get(dictName,[miss_s,dictName])
201  varShort = varAtt[1]+suf
202  varUnits = varAtt[0]
203  return varShort, varUnits
204 
205 
206 # FileFormat-dependent variable name constructors
207 def groupSLASHvar(var, group):
208  return group+'/'+var
209 
210 def varATgroup(var, group):
211  return var+'@'+group
212 
213 ncFileFormat = 'nc'
214 hdfFileFormat = 'hdf'
215 IODAVarCtors = {
216  ncFileFormat: varATgroup,
217  hdfFileFormat: groupSLASHvar,
218 }
219 
220 
221 #BaseVars describes the file-format-specific generic variable names
222 BaseVars = {}
223 for fileFormat, ctor in IODAVarCtors.items():
224  BaseVars[fileFormat] = {}
225  for baseVar, ObsVar in ObsVars.items():
226  BaseVars[fileFormat][baseVar] = ctor(ObsVar, ObsGroups[baseVar])
227 
228 def base2dbVar(baseVar, varName, fileFormat, outerIter = None):
229  # converts baseVar to a context-specific variable name to retrieve from a JediDB object
230  dbVar = BaseVars[fileFormat][baseVar]
231 
232  dictName, suf = splitIntSuffix(varName)
233  dbVar = re.sub(vNameStr,varName,dbVar)
234  dbVar = re.sub(vChanStr,suf,dbVar)
235 
236  if outerIter is None:
237  iterStr = ''
238  else:
239  iterStr = str(outerIter)
240  for group in [hofxGroup, errorGroup, qcGroup]:
241  # append iterStr if one is not already appended
242  if group in dbVar.split('@') or group in dbVar.split('/'):
243  dbVar = re.sub(group,group+iterStr,dbVar)
244  if iterStr != '':
245  if iterStr == bgIter:
246  dbVar = re.sub(depGroup,depbgGroup,dbVar)
247  else:
248  dbVar = re.sub(depGroup,depanGroup,dbVar)
249  return dbVar
250 
251 
252 ## NC variable names for MPAS-Model
253 #modVarAlt = 'zgrid' # --> needs to be interpolated to nVertLevels instead of nVertLevelsP1
254 modVarPrs = 'pressure_p'
255 modVarLat = 'latCell'
256 modVarLon = 'lonCell'
257 modVarLev = 'model_level'
258 
259 kgm3 = 'kg/m\N{SUPERSCRIPT THREE}'
260 
261 # columns: var_name unit_used abbr.
262 varDictModel = {
263  modVarLev: [ miss_s, 'ModLev'],
264  modVarLat: [ degree, 'lat' ],
265  modVarLon: [ degree, 'lon' ],
266  modVarPrs: [ 'Pa', 'PP' ],
267  'pressure': [ 'Pa', 'P' ],
268  'q2': [ 'g/kg', 'Q2m' ],
269  'qv': [ 'g/kg', 'Qv' ],
270  'rho': [ kgm3, 'rho' ],
271  'surface_pressure': [ 'Pa', 'Ps' ],
272  't2m': [ 'C', 'T2m' ],
273  'temperature': [ 'C', 'T' ],
274  'theta': [ 'K', 'Theta'],
275  'u': [ 'm/s', 'uedge'],
276  'u10': [ 'm/s', 'U10m' ],
277  'uReconstructZonal': [ 'm/s', 'U' ],
278  'uReconstructMeridional': [ 'm/s', 'V' ],
279  'v10': [ 'm/s', 'V10m' ],
280  'w': [ 'm/s', 'W' ],
281 }
282 #Note, qv unit is kg/kg in original mpas restart file. The unit is converted to g/kg when read qv.
283 
284 ## add dummy variable for no binning
285 noBinVar = 'all'
286 varDictModel[noBinVar] = [miss_s, noBinVar]
287 
288 modelRegionBinVar = 'ModelRegion'
289 varDictModel[modelRegionBinVar] = [miss_s, modelRegionBinVar]
290 
291 modVarNames2d = ['t2m','surface_pressure','q2','u10','v10']
292 modVarNames3d = ['theta','temperature','rho','pressure','uReconstructZonal','uReconstructMeridional','qv','w']
293 
295  # return short name and units
296  dictName, suf = splitIntSuffix(var)
297  varAtt = varDictModel.get(dictName,[miss_s,dictName])
298  varShort = varAtt[1]+suf
299  varUnits = varAtt[0]
300  return varShort, varUnits
301 
302 #misc. constants; TODO: collect into single script
303 deg2rad = np.pi / np.float(180.0)
304 rad2deg = np.float(180.0) / np.pi
305 
306 
307 # dictionary containing all analyzed variables
308 varDictAll = deepcopy(varDictObs)
309 for var, desc in varDictModel.items():
310  if var not in varDictAll:
311  varDictAll[var] = deepcopy(desc)
312  else:
313  assert desc[0] == varDictAll[var][0], var+' units differ between varDictObs and varDictModel'
314  assert desc[1] == varDictAll[var][1], var+' abbreviation differs between varDictObs and varDictModel'
def varAttributes(var)
Definition: var_utils.py:197
def modelVarAttributes(var)
Definition: var_utils.py:294
def ensSuffix(member)
Definition: var_utils.py:161
def appendSuffix(var, suf)
Definition: var_utils.py:193
def base2dbVar(baseVar, varName, fileFormat, outerIter=None)
Definition: var_utils.py:228
def splitIntSuffix(var)
Definition: var_utils.py:182
def splitObsVarGrp(WholeVarGrp)
Definition: var_utils.py:169
def groupSLASHvar(var, group)
Definition: var_utils.py:207
def varATgroup(var, group)
Definition: var_utils.py:210