Skip to content

Commit a732ff4

Browse files
committed
Update support for ocean in OM3 and ESM1-6
1 parent 978d99e commit a732ff4

File tree

2 files changed

+193
-11
lines changed

2 files changed

+193
-11
lines changed

notebooks/Getting_started.ipynb

Lines changed: 64 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -251,7 +251,7 @@
251251
"id": "59b4dedb-aca7-4969-a285-9a07561c3cea",
252252
"metadata": {},
253253
"source": [
254-
"## CMORising files for an Atmosphere variable (zos)\n"
254+
"## CMORising files for an Atmosphere variable (hur)\n"
255255
]
256256
},
257257
{
@@ -299,6 +299,56 @@
299299
" mip_table=\"CMIP6_Amon.json\")"
300300
]
301301
},
302+
{
303+
"cell_type": "markdown",
304+
"id": "158f4c2f-5e1c-4c25-b27d-129bade71078",
305+
"metadata": {},
306+
"source": [
307+
"## CMORising files for an Ocean variable (zos) (ACCESS-OM2 In development)"
308+
]
309+
},
310+
{
311+
"cell_type": "code",
312+
"execution_count": 9,
313+
"id": "7c7708e7-d72c-4000-b4f4-b7afb45c4a6b",
314+
"metadata": {},
315+
"outputs": [],
316+
"source": [
317+
"file_pattern = \"/home/romain/PROJECTS/ACCESS-MOPPeR/Test_data/cj877/history/ocn/ocean-2d-sea_level-1-monthly-mean-ym_0326_01.nc\""
318+
]
319+
},
320+
{
321+
"cell_type": "code",
322+
"execution_count": 11,
323+
"id": "41ea0fec-0315-4be9-8d9d-0dc24b637ed3",
324+
"metadata": {},
325+
"outputs": [
326+
{
327+
"name": "stdout",
328+
"output_type": "stream",
329+
"text": [
330+
"Stored in: MOPPeR_outputs/CMIP6/CMIP/CSIRO/ACCESS-ESM1-5/piControl-spinup/r1i1p1f1/Omon/zos/gn/v20250423/zos_Omon_ACCESS-ESM1-5_piControl-spinup_r1i1p1f1_gn_032601-032606.nc\n"
331+
]
332+
},
333+
{
334+
"name": "stderr",
335+
"output_type": "stream",
336+
"text": [
337+
"\n",
338+
"! ------\n",
339+
"! All files were closed successfully. \n",
340+
"! ------\n",
341+
"! \n"
342+
]
343+
}
344+
],
345+
"source": [
346+
"val = experiment.cmorise_ocean(file_paths=glob.glob(file_pattern),\n",
347+
" compound_name= \"Omon.zos\", \n",
348+
" cmor_dataset_json= \"experiment.json\",\n",
349+
" mip_table=\"CMIP6_Omon.json\")"
350+
]
351+
},
302352
{
303353
"attachments": {},
304354
"cell_type": "markdown",
@@ -310,7 +360,7 @@
310360
},
311361
{
312362
"cell_type": "code",
313-
"execution_count": 11,
363+
"execution_count": 12,
314364
"id": "c7b6beda-3d28-41ce-8bc7-02ce3402dfbc",
315365
"metadata": {},
316366
"outputs": [],
@@ -335,7 +385,7 @@
335385
},
336386
{
337387
"cell_type": "code",
338-
"execution_count": 12,
388+
"execution_count": 13,
339389
"id": "aae20d6a-8ea6-44d6-9e25-ead8f2c93108",
340390
"metadata": {},
341391
"outputs": [
@@ -353,7 +403,7 @@
353403
},
354404
{
355405
"cell_type": "code",
356-
"execution_count": 13,
406+
"execution_count": 14,
357407
"id": "350920e3-7ad0-44e5-98e8-653c4830f4e5",
358408
"metadata": {},
359409
"outputs": [
@@ -380,7 +430,7 @@
380430
},
381431
{
382432
"cell_type": "code",
383-
"execution_count": 14,
433+
"execution_count": 15,
384434
"id": "e228b219-6c5b-4ade-9d7d-fbd5d9e13ddb",
385435
"metadata": {},
386436
"outputs": [],
@@ -390,7 +440,7 @@
390440
},
391441
{
392442
"cell_type": "code",
393-
"execution_count": 15,
443+
"execution_count": 16,
394444
"id": "3d75e6c4-c902-44f0-ba75-7c835483bf85",
395445
"metadata": {},
396446
"outputs": [
@@ -451,6 +501,14 @@
451501
" cmor_dataset_json= \"experiment.json\",\n",
452502
" mip_table=\"CMIP6_Omon.json\")"
453503
]
504+
},
505+
{
506+
"cell_type": "code",
507+
"execution_count": null,
508+
"id": "d4c44a43-ef66-4345-9f51-3c45ab53ae03",
509+
"metadata": {},
510+
"outputs": [],
511+
"source": []
454512
}
455513
],
456514
"metadata": {

src/access_mopper/configurations.py

Lines changed: 129 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
from .calc_atmos import level_to_height
1010
from .calc_land import average_tile, calc_landcover, calc_topsoil, extract_tilefrac
1111
from .dataclasses import CMIP6_Experiment
12-
from .ocean_supergrid import om3_grid
12+
from .ocean_supergrid import om2_grid, om3_grid
1313

1414
# Supported operators
1515
OPERATORS = {
@@ -24,6 +24,7 @@
2424
@dataclass
2525
class ACCESS_ESM16_CMIP6(CMIP6_Experiment):
2626
mapping_file_prefix: str = "Mappings_CMIP6_"
27+
supergrid = om2_grid
2728

2829
def __post_init__(self):
2930
self.initialise("ACCESS-ESM1-5")
@@ -136,6 +137,129 @@ def cmorise(self, file_paths, compound_name, cmor_dataset_json, mip_table):
136137

137138
cmor.close()
138139

140+
def cmorise_ocean(self, file_paths, compound_name, cmor_dataset_json, mip_table):
141+
_, cmor_name = compound_name.split(".")
142+
143+
# Open the matching files with xarray
144+
ds = xr.open_mfdataset(file_paths, combine="by_coords", decode_times=False)
145+
146+
# Extract required variables and coordinates
147+
mapping = self.get_mapping(compound_name=compound_name)
148+
149+
if mapping["calculation"]["type"] == "direct":
150+
access_var = mapping["calculation"]["formula"]
151+
variable_units = mapping["units"]
152+
positive = mapping["positive"]
153+
var = ds[access_var]
154+
else:
155+
raise ValueError("Not implemented")
156+
157+
dim_mapping = mapping["dimensions"]
158+
_ = (
159+
self.supergrid.h_cells()
160+
if "xt_ocean" in var.dims
161+
else self.supergrid.q_cells()
162+
)
163+
axes = {dim_mapping.get(axis, axis): axis for axis in var.dims}
164+
165+
i_axis = axes.pop("longitude")
166+
i_axis = ds[i_axis].values
167+
j_axis = axes.pop("latitude")
168+
j_axis = ds[j_axis].values
169+
x = np.arange(i_axis.size, dtype="float")
170+
x_bnds = np.array([[x_ - 0.5, x_ + 0.5] for x_ in x])
171+
y = np.arange(j_axis.size, dtype="float")
172+
y_bnds = np.array([[y_ - 0.5, y_ + 0.5] for y_ in y])
173+
174+
data = var.values
175+
lat = self.supergrid.lat
176+
lat_bnds = self.supergrid.lat_bnds
177+
178+
lon = self.supergrid.lon
179+
lon_bnds = self.supergrid.lon_bnds
180+
181+
# Convert time to numeric values
182+
time_axis = axes.pop("time")
183+
time_numeric = ds[time_axis].values
184+
time_units = ds[time_axis].attrs["units"]
185+
time_bnds = ds[ds[time_axis].attrs["bounds"]].values
186+
# TODO: Check that the calendar is the same than the one defined in the model.json
187+
# Convert if not.
188+
# calendar = ds[time_axis].attrs["calendar"]
189+
190+
# CMOR setup
191+
ipth = "Test"
192+
cmor.setup(
193+
inpath=ipth,
194+
set_verbosity=cmor.CMOR_NORMAL,
195+
netcdf_file_action=cmor.CMOR_REPLACE,
196+
)
197+
198+
cmor.dataset_json(cmor_dataset_json)
199+
current_dir = os.path.dirname(os.path.abspath(__file__))
200+
grid_table_id = cmor.load_table(
201+
os.path.join(current_dir, "cmor_tables", "CMIP6_grids.json")
202+
)
203+
cmor.set_table(grid_table_id)
204+
205+
cmor_axes = []
206+
# Define CMOR axes
207+
yaxis_id = cmor.axis(
208+
table_entry="j_index", units="1", coord_vals=y, cell_bounds=y_bnds
209+
)
210+
xaxis_id = cmor.axis(
211+
table_entry="i_index", units="1", coord_vals=x, cell_bounds=x_bnds
212+
)
213+
214+
grid_id = cmor.grid(
215+
axis_ids=np.array([yaxis_id, xaxis_id]),
216+
latitude=lat,
217+
longitude=lon,
218+
latitude_vertices=lat_bnds,
219+
longitude_vertices=lon_bnds,
220+
)
221+
cmor_axes.append(grid_id)
222+
223+
# Now, load the Omon table to set up the time axis and variable
224+
current_dir = os.path.dirname(os.path.abspath(__file__))
225+
mip_table = os.path.join(current_dir, "cmor_tables", mip_table)
226+
omon_table_id = cmor.load_table(mip_table)
227+
cmor.set_table(omon_table_id)
228+
229+
cmorTime = cmor.axis(
230+
"time", coord_vals=time_numeric, cell_bounds=time_bnds, units=time_units
231+
)
232+
cmor_axes.append(cmorTime)
233+
234+
if axes:
235+
for axis, dim in axes.items():
236+
coord_vals = var[dim].values
237+
try:
238+
cell_bounds = var[var[dim].attrs["bounds"]].values
239+
except KeyError:
240+
cell_bounds = None
241+
axis_units = var[dim].attrs["units"]
242+
cmor_axis = cmor.axis(
243+
axis,
244+
coord_vals=coord_vals,
245+
cell_bounds=cell_bounds,
246+
units=axis_units,
247+
)
248+
cmor_axes.append(cmor_axis)
249+
250+
# Define CMOR variable
251+
cmorVar = cmor.variable(cmor_name, variable_units, cmor_axes, positive=positive)
252+
253+
# Write data to CMOR
254+
data = np.moveaxis(data, 0, -1)
255+
cmor.write(cmorVar, data, ntimes_passed=len(time_numeric))
256+
257+
# Finalize and save the file
258+
filename = cmor.close(cmorVar, file_name=True)
259+
print("Stored in:", filename)
260+
261+
cmor.close()
262+
139263

140264
@dataclass
141265
class ACCESS_OM3_CMIP6(CMIP6_Experiment):
@@ -176,11 +300,11 @@ def cmorise(self, file_paths, compound_name, cmor_dataset_json, mip_table):
176300
y_bnds = np.array([[y_ - 0.5, y_ + 0.5] for y_ in y])
177301

178302
data = var.values
179-
lat = om3_grid.lat
180-
lat_bnds = om3_grid.lat_bnds
303+
lat = self.supergrid.lat
304+
lat_bnds = self.supergrid.lat_bnds
181305

182-
lon = om3_grid.lon
183-
lon_bnds = om3_grid.lon_bnds
306+
lon = self.supergrid.lon
307+
lon_bnds = self.supergrid.lon_bnds
184308

185309
# Convert time to numeric values
186310
time_axis = axes.pop("time")

0 commit comments

Comments
 (0)