Skip to content

Commit f4f5045

Browse files
committed
Add ability to mimic ocean model data
1 parent 23dfb50 commit f4f5045

File tree

3 files changed

+190
-19
lines changed

3 files changed

+190
-19
lines changed

modelmimic/config/MVKO.toml

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
2+
[pass_b4b]
3+
size = [1, 5, 2]
4+
dims = ["time", "nCells", "nVertLevels"]
5+
variables = [
6+
"timeClimatology_avg_activeTracers_salinity",
7+
"timeClimatology_avg_activeTracers_temperature",
8+
"timeClimatology_avg_ssh",
9+
"timeClimatology_avg_velocityMeridional",
10+
"timeClimatology_avg_velocityZonal",
11+
]
12+
ntimes = 2
13+
timestep = "yearly-year-month-day"
14+
ninst = 30
15+
hist_file_fmt = "mpaso_{inst:04d}.hist.am.timeSeriesStatsClimatology.{time}"
16+
ensembles = ["baseline", "test"]
17+
18+
[pass_b4b.baseline]
19+
ensemble = { seed = true }
20+
name = "mvko_pass_b4b_base"
21+
22+
[pass_b4b.test]
23+
ensemble = { seed = true }
24+
name = "mvko_pass_b4b_test"
25+
26+
[pass_nb4b]
27+
size = [1, 5, 2]
28+
dims = ["time", "nCells", "nVertLevels"]
29+
variables = [
30+
"timeClimatology_avg_activeTracers_salinity",
31+
"timeClimatology_avg_activeTracers_temperature",
32+
"timeClimatology_avg_ssh",
33+
"timeClimatology_avg_velocityMeridional",
34+
"timeClimatology_avg_velocityZonal",
35+
]
36+
37+
ntimes = 2
38+
timestep = "yearly-year-month-day"
39+
ninst = 30
40+
hist_file_fmt = "mpaso_{inst:04d}.hist.am.timeSeriesStatsClimatology.{time}"
41+
ensembles = ["baseline", "test"]
42+
[pass_nb4b.baseline]
43+
ensemble = { seed = false }
44+
name = "mvko_pass_nb4b_base"
45+
[pass_nb4b.test]
46+
ensemble = { seed = false }
47+
name = "mvko_pass_nb4b_test"
48+
49+
[fail]
50+
size = [1, 5, 2]
51+
dims = ["time", "nCells", "nVertLevels"]
52+
variables = [
53+
"timeClimatology_avg_activeTracers_salinity",
54+
"timeClimatology_avg_activeTracers_temperature",
55+
"timeClimatology_avg_ssh",
56+
"timeClimatology_avg_velocityMeridional",
57+
"timeClimatology_avg_velocityZonal",
58+
]
59+
60+
ntimes = 2
61+
timestep = "yearly-year-month-day"
62+
ninst = 30
63+
hist_file_fmt = "mpaso_{inst:04d}.hist.am.timeSeriesStatsClimatology.{time}"
64+
ensembles = ["baseline", "test"]
65+
[fail.baseline]
66+
ensemble = { seed = false, popmean = 1.0 }
67+
name = "mvko_fail_base"
68+
[fail.test]
69+
ensemble = { seed = false, popmean = 2.0 }
70+
name = "mvko_fail_test"

modelmimic/config/MVKxx.toml

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
2+
[pass_b4b]
3+
size = [3, 5]
4+
variables = [
5+
"SW_flux_up_at_model_top",
6+
"LW_flux_up_at_model_top",
7+
"SW_flux_dn_at_model_top",
8+
"LiqWaterPath",
9+
]
10+
ntimes = 12
11+
ninst = 30
12+
hist_file_fmt = "scream_{inst:04d}.h.{time}"
13+
ensembles = ["baseline", "test"]
14+
[pass_b4b.baseline]
15+
ensemble = { seed = true }
16+
name = "mvkxx_pass_b4b_base"
17+
[pass_b4b.test]
18+
ensemble = { seed = true }
19+
name = "mvkxx_pass_b4b_test"
20+
21+
[pass_nb4b]
22+
size = [3, 5]
23+
variables = [
24+
"SW_flux_up_at_model_top",
25+
"LW_flux_up_at_model_top",
26+
"SW_flux_dn_at_model_top",
27+
"LiqWaterPath",
28+
]
29+
ntimes = 12
30+
ninst = 30
31+
hist_file_fmt = "scream_{inst:04d}.h.{time}"
32+
ensembles = ["baseline", "test"]
33+
[pass_nb4b.baseline]
34+
ensemble = { seed = false }
35+
name = "mvkxx_pass_nb4b_base"
36+
[pass_nb4b.test]
37+
ensemble = { seed = false }
38+
name = "mvkxx_pass_nb4b_test"
39+
40+
[fail]
41+
size = [3, 5]
42+
variables = [
43+
"SW_flux_up_at_model_top",
44+
"LW_flux_up_at_model_top",
45+
"SW_flux_dn_at_model_top",
46+
"LiqWaterPath",
47+
]
48+
ntimes = 12
49+
ninst = 30
50+
hist_file_fmt = "scream_{inst:04d}.h.{time}"
51+
ensembles = ["baseline", "test"]
52+
[fail.baseline]
53+
ensemble = { seed = false, popmean = 1.0 }
54+
name = "mvkxx_fail_base"
55+
[fail.test]
56+
ensemble = { seed = false, popmean = 2.0 }
57+
name = "mvkxx_fail_test"

modelmimic/mimic.py

Lines changed: 63 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,10 @@ def gen_hybrid_pres(
124124
in the TSC (time step convergence) test
125125
126126
"""
127-
nlev, ncol = size
127+
if len(size) == 2:
128+
nlev, ncol = size
129+
elif len(size) == 3:
130+
_, nlev, ncol = size
128131
p_0 = 100000
129132

130133
if seed is not None:
@@ -262,6 +265,10 @@ def make_ensemble(
262265
_area, _ = gen_field(self.size[-1:])
263266
_area = norm(_area)
264267

268+
# Last dimension of self.size should be number of columns
269+
lat = np.linspace(-np.pi / 2, np.pi / 2, self.size[-1])
270+
lon = np.linspace(0, 2 * np.pi, self.size[-1])
271+
265272
# 2/3 ocean, 1/3 land
266273
_landfrac = np.zeros(self.size[-1])
267274
_landfrac[: self.size[-1] // 3] = 1.0
@@ -288,6 +295,8 @@ def make_ensemble(
288295
ens_data[iinst]["hybi"] = hybi
289296
ens_data[iinst]["LANDFRAC"] = _landfrac
290297
ens_data[iinst]["area"] = _area
298+
ens_data[iinst]["lon"] = lon
299+
ens_data[iinst]["lat"] = lat
291300

292301
self.ens_data = ens_data
293302

@@ -319,6 +328,16 @@ def get_file_times(
319328
f"{sim_start}-{istep:05d}"
320329
for istep in range(0, step_mult * self.ntimes, step_mult)
321330
]
331+
elif timestep.lower() == "yearly-year-month-day":
332+
file_times = pd.date_range(
333+
start=sim_start, periods=self.ntimes, freq="YS", unit="s"
334+
)
335+
file_times = [_time.strftime("%04Y-%m-%d") for _time in file_times]
336+
elif timestep.lower() == "year":
337+
file_times = pd.date_range(
338+
start=sim_start, periods=self.ntimes, freq="YS", unit="s"
339+
)
340+
file_times = [_time.strftime("%04Y") for _time in file_times]
322341
else:
323342
raise NotImplementedError(f"FREQ: {timestep} NOT YET IMPLEMENTED")
324343
return file_times
@@ -330,7 +349,9 @@ def write_to_nc(
330349
timestep: str = "month",
331350
step_mult: int = 1,
332351
hist_file_pattern: str = "eam_{inst:04d}.h0.{time}",
352+
casename: bool = True,
333353
file_suffix: str = None,
354+
**kwargs,
334355
):
335356
"""Write generated data to a netCDF file."""
336357
# Make an xarray.Dataset for each instance so it can be written to a file.
@@ -361,33 +382,46 @@ def write_to_nc(
361382
if file_suffix is not None:
362383
extn = f"{extn}.{file_suffix}"
363384

385+
_time_suffix = kwargs.get("time_suffix", None)
386+
if _time_suffix is None:
387+
_time_suffix = ""
388+
364389
# TODO: Parallelize this
365390
for iinst in self.ens_data:
366391
for itime in range(self.ntimes):
367392
_outfile_name = hist_file_pattern.format(
368-
inst=(iinst + 1), time=file_times[itime]
393+
inst=(iinst + 1), time=file_times[itime], time_suffix=_time_suffix
369394
)
370395
data_vars = {}
371396
for _var in self.vars:
372397
data_vars[_var] = (self.dims, self.ens_data[iinst][_var][itime])
373-
data_vars["PS"] = (self.dims[-1:], self.ens_data[iinst]["PS"])
374-
data_vars["area"] = (self.dims[-1:], self.ens_data[iinst]["area"])
375-
data_vars["LANDFRAC"] = (
376-
("time", self.dims[-1]),
377-
np.expand_dims(self.ens_data[iinst]["LANDFRAC"], 0),
378-
)
379-
380-
data_vars["hyai"] = (self.dims[:1], self.ens_data[iinst]["hyai"])
381-
data_vars["hybi"] = (self.dims[:1], self.ens_data[iinst]["hybi"])
382-
data_vars["P0"] = self.ens_data[iinst]["P0"]
383398

384-
_dset = xr.Dataset(
385-
data_vars=data_vars,
386-
coords=coords,
387-
attrs={**ds_attrs, "inst": iinst},
388-
)
399+
# 1-D variables only x/y
400+
for _var in ["PS", "area", "lon", "lat"]:
401+
data_vars[_var] = (self.dims[-1:], self.ens_data[iinst][_var])
402+
403+
if "mvko" not in self.name:
404+
data_vars["LANDFRAC"] = (
405+
("time", self.dims[-1]),
406+
np.expand_dims(self.ens_data[iinst]["LANDFRAC"], 0),
407+
)
408+
data_vars["hyai"] = (self.dims[:1], self.ens_data[iinst]["hyai"])
409+
data_vars["hybi"] = (self.dims[:1], self.ens_data[iinst]["hybi"])
410+
data_vars["P0"] = self.ens_data[iinst]["P0"]
411+
try:
412+
_dset = xr.Dataset(
413+
data_vars=data_vars,
414+
coords=coords,
415+
attrs={**ds_attrs, "inst": iinst},
416+
)
417+
except ValueError:
418+
breakpoint()
389419
ens_xarray[iinst] = _dset
390-
_out_file = Path(out_path, f"{self.name}.{_outfile_name}.{extn}")
420+
if casename:
421+
_filename = f"{self.name}.{_outfile_name}.{extn}"
422+
else:
423+
_filename = f"{_outfile_name}.{extn}"
424+
_out_file = Path(out_path, _filename)
391425
_dset.to_netcdf(
392426
_out_file,
393427
unlimited_dims="time",
@@ -441,27 +475,37 @@ def main(args):
441475
variables=_test["variables"],
442476
ntimes=_test["ntimes"],
443477
ninst=_test["ninst"],
478+
dims=_test.get("dims", ("nlev", "ncol")),
444479
)
445480
mimic_case.make_ensemble(**_test[case]["ensemble"])
446481

482+
# Defaults for file output
447483
out_path = Path("./data", _testname, mimic_case.name)
448484
file_suffix = None
449485
step_mult = 1
450-
timestep = "month"
486+
# Will be overridden if set in "to_nc" below
487+
timestep = _test.get("timestep", "month")
488+
casename = True
451489

452490
if "to_nc" in _test[case]:
453491
# If the to_nc has variables in config file, use that, otherwise use default
454492
out_path = Path(_test[case]["to_nc"].get("out_path", out_path))
455493
file_suffix = _test[case]["to_nc"].get("file_suffix", file_suffix)
456494
timestep = _test[case]["to_nc"].get("timestep", timestep)
457495
step_mult = _test[case]["to_nc"].get("step_mult", step_mult)
496+
casename = _test[case]["to_nc"].get("casename", casename)
497+
time_suffix = _test[case]["to_nc"].get("time_suffix", None)
498+
else:
499+
time_suffix = ""
458500

459501
mimic_case.write_to_nc(
460502
out_path=out_path,
461503
hist_file_pattern=_test["hist_file_fmt"],
504+
casename=casename,
462505
file_suffix=file_suffix,
463506
timestep=timestep,
464507
step_mult=step_mult,
508+
time_suffix=time_suffix,
465509
)
466510
out_dirs[_testname][case] = out_path
467511

0 commit comments

Comments
 (0)