@@ -10,10 +10,8 @@ def open_mfdataset(
1010 earth_radius = 6370000 ,
1111 convert_to_ppb = True ,
1212 var_list = ["O3" , "NO" , "NO2" , "lat" , "lon" ],
13- scrip_file = "" ,
14- grid_file = None ,
15- ** kwargs
16- ):
13+ scrip_file = None ,
14+ ** kwargs ):
1715 """Method to open multiple (or single) CESM SE netcdf files.
1816 This method extends the xarray.open_mfdataset functionality
1917 It is the main method called by the driver. Other functions defined
@@ -45,22 +43,32 @@ def open_mfdataset(
4543 # check that the files are netcdf format
4644 names , netcdf = _ensure_mfdataset_filenames (fname )
4745
46+ if scrip_file is None :
47+ raise ValueError (
48+ "CESM-SE requires a scrip_file (set 'scrip_file:' in your YAML)." )
49+ ux_grid_path = scrip_file
50+
4851 # open the dataset using xarray
52+ # try:
53+ # if ux_grid_path:
54+ # print(f"Opening unstructured grid with UXArray: {ux_grid_path}")
55+ # dset_load = ux.open_mfdataset(ux_grid_path, fname, **kwargs)
56+ # elif netcdf:
57+ # print("Opening Xarray...")
58+ # dset_load = xr.open_mfdataset(fname, **kwargs)
59+ # else:
60+ # raise ValueError(
61+ # "File format not recognized. Files should be in netcdf format; "
62+ # "do not mix file types."
63+ # )
64+ # except Exception as e:
65+ # print("ERROR while opening dataset:")
66+ # print(repr(e))
67+ # raise
68+
4969 try :
50- if grid_file is not None :
51- print ("Opening unstructured grid with UXArray..." )
52- #uxds = ux.open_dataset(grid_file, fname, **kwargs)
53- #dset_load = uxds
54- dset_load = ux .open_mfdataset (grid_file , fname , ** kwargs )
55- # may need ux.open_dataset later
56- elif netcdf :
57- print ("Opening Xarray..." )
58- dset_load = xr .open_mfdataset (fname , ** kwargs )
59- else :
60- raise ValueError ("File format not recognized. "
61- "Note that files should be in netcdf format. "
62- "Do not mix and match file types." )
63-
70+ print (f"Opening unstructured grid with UXArray: { ux_grid_path } " )
71+ dset_load = ux .open_mfdataset (ux_grid_path , fname , ** kwargs )
6472 except Exception as e :
6573 print ("ERROR while opening dataset:" )
6674 print (repr (e ))
@@ -74,20 +82,89 @@ def open_mfdataset(
7482 if "lev" not in var_list :
7583 var_list .append ("lev" )
7684
85+ # variables for cesm-se specific derivations
86+ _cesm_se_var = []
87+
88+ # Always request the source variables needed for standardized derivations
89+ # Filtered against what's actually present, so a missing one just
90+ # skips the corresponding derivation
91+
92+ for _v in ("hyam" , "hybm" , "PS" , "P0" , "T" , "PDELDRY" ):
93+ if _v not in var_list :
94+ var_list .append (_v )
95+ _cesm_se_var .append (_v )
96+
97+ # filter to vars present and then warn about vars missing rather than generic rename error
98+ _requested = list (var_list )
99+ _present = [v for v in _requested if v in dset_load .variables ]
100+ _missing = [v for v in _requested if v not in dset_load .variables ]
101+
102+ if _missing :
103+ print (
104+ f"CESM-SE: requested variables not found in { names [0 ]!r} : "
105+ f"{ _missing } . Continuing with what's available: { _present } ."
106+ )
107+ dset = dset_load [_present ]
108+
77109 # ===========================
78110 # Process the loaded data
79111 # extract variables of choice
80- dset = dset_load .get (var_list )
112+ # dset = dset_load.get(var_list)
81113 # rename altitude variable to z for monet use
82114 dset = dset .rename ({"lev" : "z" })
83115
84116 # re-order so surface is associated with the first vertical index
85117 dset = dset .sortby ("z" , ascending = False )
86118 # ===========================
87119
120+ # Derive MM-standardized variables from CESM-SE native fields.
121+ # Source vars are optional: missing inputs then derivation skipped,
122+
123+ # pres_pa_mid: hybrid sigma-pressure midpoint (Pa)
124+ # P = hyam*P0 + hybm*PS (standard CAM hybrid coords)
125+ if "pres_pa_mid" not in dset .variables and {"hyam" , "hybm" , "PS" } <= set (dset .variables ):
126+ _P0 = float (dset ["P0" ].values ) if "P0" in dset .variables else 100000.0
127+ dset ["pres_pa_mid" ] = dset ["hyam" ] * _P0 + dset ["hybm" ] * dset ["PS" ]
128+ dset ["pres_pa_mid" ].attrs .update ({
129+ "units" : "Pa" ,
130+ "long_name" : "Pressure at mid-level" ,
131+ "description" : "hyam*P0 + hybm*PS" ,
132+ })
133+
134+ # temperature_k
135+ if "temperature_k" not in dset .variables and "T" in dset .variables :
136+ dset ["temperature_k" ] = dset ["T" ]
137+ dset ["temperature_k" ].attrs .setdefault ("units" , "K" )
138+
139+ # dz_m: layer thickness (m) via hydrostatic + ideal gas
140+ # dz = PDELDRY * Rd * T / (P_mid * g)
141+ if (
142+ "dz_m" not in dset .variables
143+ and "PDELDRY" in dset .variables
144+ and "pres_pa_mid" in dset .variables
145+ and "temperature_k" in dset .variables
146+ ):
147+ _Rd = 287.04 # J/(kg*K), dry air
148+ _g = 9.80665 # m/s^2
149+ dset ["dz_m" ] = (
150+ dset ["PDELDRY" ] * _Rd * dset ["temperature_k" ]
151+ / (dset ["pres_pa_mid" ] * _g )
152+ )
153+ dset ["dz_m" ].attrs .update ({
154+ "units" : "m" ,
155+ "long_name" : "Layer thickness" ,
156+ "description" : "PDELDRY * Rd * T / (P_mid * g)" ,
157+ })
158+
159+ # once derivations are complete, dont keep in returned dataset
160+ for _v in _cesm_se_var :
161+ if _v in dset .variables :
162+ dset = dset .drop_vars (_v )
163+
88164 # Make sure this dataset has unstructured grid
89165 dset .attrs ["mio_has_unstructured_grid" ] = True
90- dset .attrs ["mio_scrip_file" ] = scrip_file
166+ if scrip_file :
167+ dset .attrs ["mio_scrip_file" ] = scrip_file
91168
92169 # convert units
93170 if convert_to_ppb :
@@ -111,7 +188,6 @@ def open_mfdataset(
111188# Below are internal functions to this file
112189# -----------------------------------------
113190
114-
115191def _ensure_mfdataset_filenames (fname ):
116192 """Checks if dataset in netcdf format
117193 Parameters
0 commit comments