Skip to content

Commit 79430eb

Browse files
It is possible to create 1d_profile plots and zonalmean plots
1 parent 778b38a commit 79430eb

File tree

2 files changed

+86
-21
lines changed

2 files changed

+86
-21
lines changed

esmvaltool/diag_scripts/lifetime/lifetime.py

Lines changed: 19 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -343,8 +343,7 @@ def __init__(self, config):
343343
'timeseries',
344344
'annual_cycle',
345345
'zonalmean',
346-
'1d_profile'
347-
]
346+
'1d_profile' ]
348347
for (plot_type, plot_options) in self.plots.items():
349348
if plot_type not in self.supported_plot_types:
350349
raise ValueError(
@@ -353,7 +352,7 @@ def __init__(self, config):
353352
if plot_options is None:
354353
self.plots[plot_type] = {}
355354

356-
# Default options for the different plot types
355+
# Default options for the differ N MMNMJHJ JMHTHent plot types
357356
if plot_type == 'timeseries':
358357
self.plots[plot_type].setdefault('annual_mean', False)
359358
self.plots[plot_type].setdefault('annual_mean_kwargs', {})
@@ -371,7 +370,9 @@ def __init__(self, config):
371370

372371
if plot_type == 'zonalmean':
373372
self.plots[plot_type].setdefault(
374-
'cbar_label', '{short_name} [{units}]')
373+
'cbar_label',
374+
f"{chr(964)}({self._get_name('reactant').upper()})"
375+
' [{units}]')
375376
self.plots[plot_type].setdefault(
376377
'cbar_label_bias', 'Δ{short_name} [{units}]')
377378
self.plots[plot_type].setdefault(
@@ -569,20 +570,23 @@ def _calculate_coefficients(self):
569570
z_coord = reaction.coord('air_pressure', dim_coords=True)
570571
z_coord.attributes['positive'] = 'down'
571572
z_coord.convert_units('Pa')
573+
use_z_coord = 'air_pressure'
572574
elif reaction.coords('atmosphere_hybrid_sigma_pressure_coordinate',
573575
dim_coords=True):
574576
self.z_coord = 'atmosphere_hybrid_sigma_pressure_coordinate'
575577
z_coord = reaction.coord(
576578
'atmosphere_hybrid_sigma_pressure_coordinate',
577579
dim_coords=True)
578580
z_coord.attributes['positive'] = 'down'
581+
use_z_coord = 'model_level_number'
579582
else:
580583
raise NotImplementedError(
581584
"Lifetime calculation is not implemented"
582585
" for the present type of vertical coordinate."
583586
)
584587

585-
if not set(['TROP', 'STRA']).isdisjoint(self.cfg['regions']):
588+
if (not set(['TROP', 'STRA']).isdisjoint(self.cfg['regions']) and
589+
not set(['timeseries', 'annual_cycle']).isdisjoint(self.plots)):
586590

587591
# calculate climatological tropopause pressure (tp_clim)
588592
# but only if no tropopause is given by data
@@ -600,16 +604,19 @@ def _calculate_coefficients(self):
600604
# - tp_i and model_level_number
601605
# - ptp and (derived) air_pressure
602606
# - tp_clim and (derived) air_pressure
603-
use_z_coord = 'air_pressure'
604607
if z_coord.name() == 'air_pressure':
605608
tropopause = variables.get('ptp', tropopause)
606609
elif (z_coord.name()
607610
== 'atmosphere_hybrid_sigma_pressure_coordinate'):
608611
if 'tp_i' in variables:
609612
tropopause = variables['tp_i']
610-
use_z_coord = 'model_level_number'
611613
else:
612614
tropopause = variables.get('ptp', tropopause)
615+
# fall back to air_pressure
616+
use_z_coord = 'air_pressure'
617+
618+
input_data_dataset[dataset]['tropopause'] = tropopause
619+
613620

614621
weight = self._define_weight(variables)
615622

@@ -620,7 +627,6 @@ def _calculate_coefficients(self):
620627

621628
input_data_dataset[dataset]['z_coord'] = z_coord
622629
input_data_dataset[dataset]['use_z_coord'] = use_z_coord
623-
input_data_dataset[dataset]['tropopause'] = tropopause
624630
input_data_dataset[dataset]['variables'] = variables
625631
input_data_dataset[dataset]['reaction'] = reaction
626632
input_data_dataset[dataset]['weight'] = weight
@@ -1030,8 +1036,8 @@ def create_timeseries_plot(self, region, input_data, base_datasets):
10301036
slice_dataset['tropopause'] = tp_slice
10311037

10321038
cube_slice = calculate_lifetime(slice_dataset,
1033-
plot_type,
1034-
region)
1039+
plot_type,
1040+
region)
10351041
# make it real to reduce memory demand later
10361042
cube_slice.data
10371043
cube_slices.append(cube_slice)
@@ -1164,7 +1170,7 @@ def create_annual_cycle_plot(self, region, input_data, base_datasets):
11641170
list(base_datasets.values()))
11651171
axes.set_title(f'{self.info["long_name"]} in region {region}')
11661172
axes.set_xlabel('Month')
1167-
axes.set_ylabel(f"$\tau$({self._get_name('reactant').upper()})"
1173+
axes.set_ylabel(f"{chr(964)}({self._get_name('reactant').upper()})"
11681174
" [{self.info['units']}]")
11691175
axes.set_xticks(range(1, 13), [str(m) for m in range(1, 13)])
11701176
gridline_kwargs = self._get_gridline_kwargs(plot_type)
@@ -1329,8 +1335,8 @@ def create_1d_profile_plot(self, region, input_data, base_datasets):
13291335
# Default plot appearance
13301336
multi_dataset_facets = self._get_multi_dataset_facets(
13311337
list(base_datasets.values()))
1332-
axes.set_title(f'{self.info["long_name"]} in region {region}')
1333-
axes.set_xlabel(f"$\tau$({self._get_name('reactant').upper()})"
1338+
axes.set_title(f'{self.info["long_name"]}')
1339+
axes.set_xlabel(f"{chr(964)}({self._get_name('reactant').upper()})"
13341340
f" [{self.info['units']}]")
13351341
z_coord = cube.coord(axis='Z')
13361342
axes.set_ylabel(f'{z_coord.long_name} [{z_coord.units}]')

esmvaltool/diag_scripts/lifetime/lifetime_func.py

Lines changed: 67 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -46,11 +46,14 @@ def calculate_gridmassdry(press, hus, z_coord):
4646
pmin = da.nanmin(press)
4747

4848
# surface air pressure as cube
49-
pmax = press[:, 0, :, :].copy()
49+
surface = press.coord(z_coord)[0].points
50+
pmax = press.extract(iris.Constraint(coord_values={z: surface for z in [z_coord]})).copy()
5051
if 'surface_air_pressure' in press.coords():
5152
pmax.data = press.coord('surface_air_pressure').lazy_points()
5253
else:
53-
pmax.data[:, :, :] = 101525.
54+
pmax.data = da.full_like(
55+
press.extract(iris.Constraint(coord_values={z: surface for z in [z_coord]})),
56+
101525.)
5457

5558
# grid area -> m2
5659
lat_lon_dims = sorted(
@@ -66,10 +69,10 @@ def calculate_gridmassdry(press, hus, z_coord):
6669
)
6770

6871
# delta pressure levels
69-
delta_p = dpres_plevel_4d(press,
70-
pmin,
71-
pmax,
72-
z_coord=z_coord)
72+
delta_p = dpres_plevel(press,
73+
pmin,
74+
pmax,
75+
z_coord=z_coord)
7376

7477
# gridmass of dry air
7578
gridmassdry = deepcopy(press)
@@ -188,6 +191,58 @@ def _number_density_dryair_by_grid(grmassdry, grvol):
188191

189192
return rho
190193

194+
def dpres_plevel(plev, pmin, pmax, z_coord='air_pressure'):
195+
"""
196+
Call the appropriate pressure level calculation with
197+
respect to the given coordinates.
198+
"""
199+
200+
cube_coords = [coord.name() for coord in plev.dim_coords]
201+
202+
if [z_coord, 'latitude', 'longitude'] == cube_coords:
203+
dplev = dpres_plevel_3d(plev, pmin, pmax, z_coord)
204+
elif ['time', z_coord, 'latitude', 'longitude'] == cube_coords:
205+
dplev = dpres_plevel_4d(plev, pmin, pmax, z_coord)
206+
else:
207+
raise NotImplementedError(
208+
"Pressurelevel calculation is not implemented"
209+
" for the present coordinates.")
210+
211+
return dplev
212+
213+
214+
def dpres_plevel_3d(plev, pmin, pmax, z_coord='air_pressure'):
215+
"""Calculate delta pressure levels.
216+
217+
The delta pressure levels are based
218+
on the given pressure as a
219+
four dimensional cube.
220+
"""
221+
axis = plev.coord_dims(z_coord)
222+
223+
# shifted vectors:
224+
# - p_m1: shifted by one index down
225+
# (the value of the last index is the former first)
226+
# - p_p1: shifted by one index up
227+
# (the value of the first index is the former last)
228+
# both vector values are divided by two
229+
p_p1 = da.roll(plev.lazy_data(), 1, axis=axis) / 2.
230+
p_m1 = da.roll(plev.lazy_data(), -1, axis=axis) / 2.
231+
232+
# modify the first entry in p_p1
233+
# note: p_p1[1, :, :] .eq. plev[0, :, :] / 2.
234+
p_p1[0, :, :] = pmax.lazy_data() - p_p1[1, :, :]
235+
236+
# and the last entry in p_m1
237+
# note: p_m1[-2, :, :] .eq. plev[-1, :, :] / 2.
238+
p_m1[-1, :, :] = pmin - p_m1[-2, :, :]
239+
240+
# calculate difference
241+
dplev = deepcopy(plev)
242+
dplev.data = p_p1 - p_m1
243+
244+
return dplev
245+
191246

192247
def dpres_plevel_4d(plev, pmin, pmax, z_coord='air_pressure'):
193248
"""Calculate delta pressure levels.
@@ -225,8 +280,12 @@ def dpres_plevel_4d(plev, pmin, pmax, z_coord='air_pressure'):
225280
def calculate_lifetime(dataset, plot_type, region):
226281
"""Calculate the lifetime for the given plot_type and region."""
227282
# extract region from weights and reaction
228-
reaction = extract_region(dataset, region, case='reaction')
229-
weight = extract_region(dataset, region, case='weight')
283+
if plot_type in ['timeseries', 'annual_cycle']:
284+
reaction = extract_region(dataset, region, case='reaction')
285+
weight = extract_region(dataset, region, case='weight')
286+
else:
287+
reaction = dataset['reaction']
288+
weight = dataset['weight']
230289

231290
# calculate nominator and denominator
232291
# and sum of nominator and denominator via plot_type dimensions

0 commit comments

Comments
 (0)