Skip to content

Commit c3c5acf

Browse files
authored
Merge pull request #1375 from DestinE-Climate-DT/icon_healpix
Icon healpix grids update
2 parents 90edfb8 + 0da18a4 commit c3c5acf

15 files changed

+163
-63
lines changed

CHANGELOG.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -9,15 +9,15 @@ Unreleased in the current development version:
99

1010
AQUA core complete list:
1111

12+
- Mixed updates to support data for NextGEMS cycle4 hackathon (#1375)
1213
- Preprocess functionality added to the `Reader` class (#1298)
1314
- The AQUAthon material has been moved under the `notebooks` folder (#1342)
1415
- `aqua` source code has been moved to the `src` folder (#1332)
1516
- A diagnostic module, called `aqua.diagnostics`, has been created under the `src` folder (#1332, #1341)
16-
- LRA generator tool support for multiple relizations (#1357)
17+
- LRA generator tool support for multiple relizations (#1357, #1375)
1718
- LRA generator requires `catalog` as a mandatory argument (#1357)
1819
- AQUA console revisiting, adding `avail` method and `update` method (#1346)
1920
- AQUA install now requires mandatory machine name (#1346)
20-
2121
- Fix to make keyword step optional in request (#1360)
2222

2323
AQUA diagnostic complete list:
+10-6
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,21 @@
11
# These are needed for the AQUA retrieve
2+
catalog: nextgems3
23
model: ICON
3-
exp: historical-1990
4-
source: daily-hpz10-oce3d
5-
var: avg_so
4+
exp: ngc3028
5+
source: P1D
6+
var: tke
67

78
# These are needed for grid conversion with CDO
8-
zoom: 10
9+
zoom: 5
910
nested: True # otherwise ring
1011

1112
# These are extra info:
1213
# model name for saving the grid
1314
model_name: icon
15+
resolution: R02B09
16+
extra: null
17+
1418
# tmp folder for the grid generation
15-
tmp: /pfs/lustrep3/scratch/project_465000454/padavini
19+
tmp: /home/b/b382076/scratch/healpix-icon-ng3/tmp
1620
# target folder for the grid generated
17-
tgt: /pfs/lustrep3/projappl/project_465000454/data/AQUA/grids/HealPix
21+
tgt: /home/b/b382076/scratch/healpix-icon-ng3

cli/grid-from-data/hpx-from-sources.py

+46-16
Original file line numberDiff line numberDiff line change
@@ -11,17 +11,21 @@
1111
from aqua.util import load_yaml, get_arg, create_folder
1212
from aqua.logger import log_configure
1313

14+
reasonable_vert_coords = ['depth_full', 'depth_half', 'level']
15+
1416

1517
def parse_arguments(args):
1618
"""
1719
Parse command line arguments
1820
"""
1921

20-
parser = argparse.ArgumentParser(description='AQUA gribber')
22+
parser = argparse.ArgumentParser(description='AQUA grids from data')
2123
parser.add_argument('-c', '--config', type=str, required=True,
2224
help='yaml file with exp information and directories')
2325
parser.add_argument('-l', '--loglevel', type=str,
2426
help='log level [default: WARNING]')
27+
parser.add_argument('-z', '--zoom', type=str,
28+
help='override zoom: convenient for loop on many zoom levels')
2529

2630
return parser.parse_args(args)
2731

@@ -42,28 +46,44 @@ def parse_arguments(args):
4246
source = config['source']
4347
var = config['var']
4448
resolution = config.get('resolution')
49+
extra = config.get('extra')
4550
logger.info('Retrieving %s from %s %s %s', var, model, exp, source)
4651

4752
# Configuration needed to save the file
4853
tmp = config['tmp']
4954
model_name = config['model_name']
50-
zoom = config['zoom']
55+
zoom = int(get_arg(args, 'zoom', config.get('zoom'))) #HACK for zoom
56+
catalog = config.get('catalog')
5157
nested = config['nested']
5258

59+
# adding zoom if found
60+
mykwargs = {}
61+
if zoom:
62+
mykwargs = {**mykwargs, **{'zoom': zoom}}
63+
if catalog:
64+
mykwargs = {**mykwargs, **{'catalog': catalog}}
65+
66+
5367
# Create Reader object
5468
reader = Reader(model=model, exp=exp, source=source,
55-
areas=False, fix=False, loglevel=loglevel)
69+
areas=False, fix=False, loglevel=loglevel, **mykwargs)
5670
data = reader.retrieve(var=var)
5771

72+
# detect vertical coordinate from a set of plausible values
73+
vert_coord = list(set(reasonable_vert_coords) & set(data.coords))
74+
5875
#automatic detection of 3d
59-
if data['level'] is not None:
76+
if vert_coord:
6077
model3d = True
78+
if len(vert_coord)>1:
79+
raise KeyError("Too many vertical coordinates identified, check the data manually")
80+
vert_coord = vert_coord[0]
6181
else:
6282
model3d = False
6383

6484
if model3d:
6585
logger.debug("Modifying level axis attributes as Z")
66-
data['level'].attrs['axis'] = 'Z'
86+
data[vert_coord].attrs['axis'] = 'Z'
6787

6888
# Save data in a netcdf file on the temporary directory
6989
create_folder(tmp)
@@ -78,28 +98,38 @@ def parse_arguments(args):
7898

7999
# cdo command setup:
80100
nside = 2**zoom
101+
102+
# Setting grid name
81103
if nested:
82-
grid_name = 'hp' + str(nside) + '_nested'
104+
grid_name = f'hp{nside}_nested'
83105
else: # ring
84-
grid_name = 'hp' + str(nside) + '_ring'
106+
grid_name = f'hp{nside}_ring'
85107

86-
# setting output filename
108+
# Setting output filename
87109
tgt = config['tgt']
88110
create_folder(tgt)
89-
filename_tgt = tgt + '/' + model_name
111+
filename_tgt = os.path.join(tgt, model_name)
112+
113+
# add info on original data resolution if available
90114
if resolution:
91-
filename_tgt = filename_tgt + "-" + resolution
115+
filename_tgt = f"{filename_tgt}-{resolution}"
92116

93-
filename_tgt = filename_tgt + '_hpz' + str(zoom)
117+
# add info on hpz zoom
118+
filename_tgt = f"{filename_tgt}_hpz{zoom}"
119+
120+
# options for nested and ringed
94121
if nested:
95-
filename_tgt = filename_tgt + '_nested_oce'
122+
filename_tgt = f"{filename_tgt}_nested_oce"
96123
else:
97-
filename_tgt = filename_tgt + '_ring_oce'
124+
filename_tgt = f"{filename_tgt}_ring_oce"
98125

99126
if model3d:
100-
filename_tgt = filename_tgt + '_level.nc'
101-
else:
102-
filename_tgt = filename_tgt + '.nc'
127+
filename_tgt = f"{filename_tgt}_{vert_coord}"
128+
129+
if extra:
130+
filename_tgt = f"{filename_tgt}_{extra}"
131+
132+
filename_tgt = f'{filename_tgt}.nc'
103133

104134
logger.info('Setting grid %s', grid_name)
105135
logger.info('Saving data in %s', filename_tgt)

cli/lra/auto_LRA_overnight.yaml

+7-3
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,18 @@
22
target:
33
resolution: r100
44
frequency: monthly
5+
catalog: climatedt-phase1
6+
7+
path:
58
outdir: /pfs/lustrep3/projappl/project_465000454/data/AQUA/LRA
69
tmpdir: /pfs/lustrep3/projappl/project_465000454/padavini/tmp
710

8-
loglevel: INFO
911

12+
options:
1013
# Set to True if lra-r100-monthly-zarr should be created and checked
11-
zarr: False
12-
verify_zarr: False
14+
zarr: False
15+
verify_zarr: False
16+
loglevel: INFO
1317

1418
slurm:
1519
partition: small

cli/lra/cli_lra_parallel_slurm.py

+15-7
Original file line numberDiff line numberDiff line change
@@ -66,10 +66,12 @@ def submit_sbatch(model, exp, source, varname, slurm_dict, yaml_file,
6666
]
6767

6868
if dependency is not None:
69+
print(dependency)
6970
sbatch_cmd.append('--dependency=afterany:'+ str(dependency))
7071

7172
# Add script command
72-
sbatch_cmd.append('aqua lra')
73+
sbatch_cmd.append('aqua')
74+
sbatch_cmd.append('lra')
7375
sbatch_cmd.append('--config')
7476
sbatch_cmd.append(yaml_file)
7577
sbatch_cmd.append('--model')
@@ -92,11 +94,17 @@ def submit_sbatch(model, exp, source, varname, slurm_dict, yaml_file,
9294
if overwrite:
9395
sbatch_cmd.append('-o')
9496
sbatch_cmd.append('-d')
95-
result = subprocess.run(sbatch_cmd, capture_output = True, check=True).stdout.decode('utf-8')
96-
jobid = re.findall(r'\b\d+\b', result)[-1]
97-
return jobid
98-
99-
#print(sbatch_cmd)
97+
try:
98+
result = subprocess.run(sbatch_cmd, capture_output = True, check=True).stdout.decode('utf-8')
99+
jobid = re.findall(r'\b\d+\b', result)[-1]
100+
return jobid
101+
except subprocess.CalledProcessError as e:
102+
# Print the error message and stderr if the command fails
103+
print(f"Command failed with return code {e.returncode}")
104+
print(f"stdout: {e.stdout}")
105+
print(f"stderr: {e.stderr}")
106+
107+
print(sbatch_cmd)
100108
return 0
101109

102110

@@ -147,7 +155,7 @@ def parse_arguments(arguments):
147155
varnames = config['data'][model][exp][source]['vars']
148156
for varname in varnames:
149157
if (COUNT % int(parallel)) == 0 and COUNT != 0:
150-
print('Updating parent job to' + jobid)
158+
print('Updating parent job to' + str(jobid))
151159
PARENT_JOB = str(jobid)
152160
COUNT = COUNT + 1
153161
print(' '.join(['Submitting', model, exp, source, varname]))

config/fixes/ICON-default.yaml

+3-1
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,9 @@ fixer_name:
109109
avg_von:
110110
source: v
111111
grib: true
112-
112+
avg_so:
113+
source: so
114+
grib: true
113115
#fixes for NextGems data
114116
cfh_lnd:
115117
source: cfh_lnd

config/fixes/OBS-default.yaml

+8
Original file line numberDiff line numberDiff line change
@@ -80,3 +80,11 @@ fixer_name:
8080
source: sftof
8181
src_units: frac
8282
units: frac
83+
84+
era5-arco:
85+
data_model: false
86+
coords:
87+
lat:
88+
source: latitude
89+
lon:
90+
source: longitude

config/grids/ICON.yaml

+18-7
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
# More info on ICON here: https://easy.gems.dkrz.de/Processing/healpix/index.html
12
grids:
23
# ICON oceanic healpix
34
icon-hpz10-nested:
@@ -8,11 +9,11 @@ grids:
89
level: '{{ grids }}/HealPix/icon_hpz10_nested_oce_level.nc'
910

1011
#ICON
11-
R02B08:
12+
R02B08: # ICON grid R02B08, corresponding to 10km resolution
1213
path: '{{ grids }}/ICON/icon_grid_0033_R02B08_G.nc'
1314
space_coord: ["cell"]
1415
extra: -selname,cell_index
15-
R02B09:
16+
R02B09: # ICON grid R02B09, corresponding to 5km resolution
1617
path: '{{ grids }}/ICON/icon_grid_0015_R02B09_G.nc'
1718
space_coord: ["cell"]
1819
extra: -selname,cell_index
@@ -25,12 +26,22 @@ grids:
2526
path: '{{ grids }}/ICON/icon_grid_0015_R02B09_G.nc'
2627
extra: -selname,cell_index
2728
space_coord: ["ncells"]
28-
icon-healpix:
29+
icon-R02B08-hp-nested: # NG4, from ICON grid R02B08, corresponding to 10km resolution, 72 depth_full levels
2930
path:
30-
2d: '{{ grids }}/HealPix_old/icon_hpx{zoom}_atm_2d.nc' # this is the default 2d grid
31-
2dm: '{{ grids }}/HealPix_old/icon_hpx{zoom}_oce_2d.nc' # this is an additional and optional 2d grid used if data are masked
32-
depth_full: '{{ grids }}/HealPix_old/icon_hpx{zoom}_oce_depth_full.nc'
33-
depth_half: '{{ grids }}/HealPix_old/icon_hpx{zoom}_oce_depth_half.nc'
31+
2d: '{{ grids }}/HealPix/hpz{zoom}_nested_atm.nc' # this is the default 2d grid
32+
2dm: '{{ grids }}/HealPix/icon-R02B08_hpz{zoom}_nested_oce.nc' # this is an additional and optional 2d grid used if data are masked
33+
depth_full: '{{ grids }}/HealPix/icon-R02B08_hpz{zoom}_nested_oce_depth_full.nc'
34+
depth_half: '{{ grids }}/HealPix/icon-R02B08_hpz{zoom}_nested_oce_depth_half.nc'
35+
masked: # This is the attribute used to distinguish variables which should go into the masked category
36+
component: ocean
37+
space_coord: ["cell"]
38+
vert_coord: ["depth_half", "depth_full"]
39+
icon-R02B09-hp-nested: # NG3, from ICON grid R02B09, corresponding to 5km resolution, 128 depth_full levels
40+
path:
41+
2d: '{{ grids }}/HealPix/hpz{zoom}_nested_atm.nc' # this is the default 2d grid
42+
2dm: '{{ grids }}/HealPix/icon-R02B09_hpz{zoom}_nested_oce.nc' # this is an additional and optional 2d grid used if data are masked
43+
depth_full: '{{ grids }}/HealPix/icon-R02B09_hpz{zoom}_nested_oce_depth_full.nc'
44+
depth_half: '{{ grids }}/HealPix/icon-R02B09_hpz{zoom}_nested_oce_depth_half.nc'
3445
masked: # This is the attribute used to distinguish variables which should go into the masked category
3546
component: ocean
3647
space_coord: ["cell"]

config/grids/default.yaml

+12
Original file line numberDiff line numberDiff line change
@@ -22,13 +22,25 @@ grids:
2222
lon-lat-depth:
2323
vert_coord: ["depth"]
2424
space_coord: [lon, lat]
25+
longitude-latitude:
26+
vert_coord: ["2d"]
27+
space_coord: [longitude, latitude]
2528

2629
# target regrid
30+
# rxxxs are staggered grids
31+
r005s: r7200x3601
2732
r005: r7200x3600
33+
r010s: r3600x1801
2834
r010: r3600x1800
35+
r020s: r1800x901
2936
r020: r1800x900
37+
r025s: r1440x721
3038
r025: r1440x720
39+
r050s: r720x361
3140
r050: r720x360
41+
r100s: r360x181
3242
r100: r360x180
43+
r200s: r180x91
3344
r200: r180x90
45+
r250s: r144x73
3446
r250: r144x72

pyproject.toml

+1
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ dependencies = [
4040
"dask_jobqueue",
4141
"eccodes==2.38.0",
4242
"docker",
43+
"gcsfs", # Google Cloud Storage File System
4344
"gribscan",
4445
"pandas",
4546
"intake==0.7.0", # Version 2 is not yet compatible with intake-xarray

src/aqua/cli/lra.py

+3-1
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,8 @@ def lra_parser(parser = None):
5555
help='source to be processed. Use with coherence with --exp and --var')
5656
parser.add_argument('-v', '--var', type=str,
5757
help='var to be processed. Use with coherence with --source')
58+
#parser.add_argument('-r', '--realization', type=str,
59+
# help="realization to be processed. Use with coherence with --var")
5860

5961
#return parser.parse_args(arguments)
6062
return parser
@@ -149,7 +151,7 @@ def lra_cli(args, config, catalog, resolution, frequency, fix, outdir, tmpdir, l
149151
sources = to_list(get_arg(args, 'source', config['data'][model][exp].keys()))
150152
for source in sources:
151153
# get info on potential realizations
152-
realizations = get_arg(args, 'var', config['data'][model][exp][source].get('realizations'))
154+
realizations = config['data'][model][exp][source].get('realizations')
153155
loop_realizations = to_list(realizations) if realizations is not None else [1]
154156

155157
# get info on varlist and workers

src/aqua/exceptions.py

+7
Original file line numberDiff line numberDiff line change
@@ -31,3 +31,10 @@ class NoObservationError(Exception):
3131
def __init__(self, message="No observation available"):
3232
self.message = message
3333
super().__init__(self.message)
34+
35+
class NoRegridError(Exception):
36+
"""Exception raised when no regrid is available"""
37+
38+
def __init__(self, message="No regrid available"):
39+
self.message = message
40+
super().__init__(self.message)

0 commit comments

Comments
 (0)