-
Notifications
You must be signed in to change notification settings - Fork 129
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'main' into climate_patterns_only
- Loading branch information
Showing
18 changed files
with
877 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -6,7 +6,6 @@ on: | |
push: | ||
branches: | ||
- main | ||
- fix_recipe_filler_bkwds_incompatibility | ||
schedule: | ||
- cron: '0 0 * * *' | ||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Binary file added
BIN
+224 KB
...aeronet_assess/UKESM1-0-LL_CMIP_AERmon_historical_od440aer_gn_1988_2008_DJF.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added
BIN
+243 KB
...aeronet_assess/UKESM1-0-LL_CMIP_AERmon_historical_od440aer_gn_1988_2008_JJA.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added
BIN
+227 KB
...aeronet_assess/UKESM1-0-LL_CMIP_AERmon_historical_od440aer_gn_1988_2008_MAM.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added
BIN
+232 KB
...aeronet_assess/UKESM1-0-LL_CMIP_AERmon_historical_od440aer_gn_1988_2008_SON.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added
BIN
+105 KB
...net_assess/UKESM1-0-LL_CMIP_AERmon_historical_od440aer_gn_1988_2008_scatter.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added
BIN
+847 KB
...aeronet_assess/UKESM1-0-LL_CMIP_AERmon_historical_od440aer_gn_1994_2014_DJF.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added
BIN
+908 KB
...aeronet_assess/UKESM1-0-LL_CMIP_AERmon_historical_od440aer_gn_1994_2014_JJA.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added
BIN
+850 KB
...aeronet_assess/UKESM1-0-LL_CMIP_AERmon_historical_od440aer_gn_1994_2014_MAM.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added
BIN
+879 KB
...aeronet_assess/UKESM1-0-LL_CMIP_AERmon_historical_od440aer_gn_1994_2014_SON.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added
BIN
+110 KB
...net_assess/UKESM1-0-LL_CMIP_AERmon_historical_od440aer_gn_1994_2014_scatter.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
161 changes: 161 additions & 0 deletions
161
doc/sphinx/source/recipes/recipe_aod_aeronet_assess.rst
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,161 @@ | ||
.. _recipe_aod_aeronet_assess: | ||
|
||
AOD AeroNET Assess | ||
================== | ||
|
||
Overview | ||
-------- | ||
|
||
This diagnostic evaluates model aerosol optical depth (AOD) against ground | ||
based observations from the AeroNET measurement network. Monthly mean AOD | ||
data is downloaded from the AeroNET website and formatted (CMORized) using the | ||
AERONET downloader and formatter within ESMValTool. | ||
|
||
Multiannual seasonal means are calculated from the model output and compared | ||
with a multiannual seasonal mean climatology generated from AeroNET | ||
observational data. At each AeroNET station the data are screened for validity | ||
according to the following default criteria: | ||
|
||
* 1. Monthly means must be generated from at least one AOD observation in that | ||
month. | ||
|
||
* 2. Seasonal means for DJF, MAM, JJA and SON must be calculated from three | ||
monthly means, i.e. a monthly mean from December January and Feburary. | ||
|
||
* 3. For a given year to be valid, there must be a seasonal mean for each climate | ||
season i.e. DJF, MAM, JJA and SON. | ||
|
||
* 4. For a multiannual seasonal means there must be at least five seasonaal means | ||
over the time range of interest. | ||
|
||
NOTE: The code is designed to be flexible and the default criteria can be | ||
changed according to the user's requirements (see the user settings below). | ||
|
||
The evaluation is visualised by plotting model output as 2D filled contours and | ||
overlaying AeroNET observations at model grid cells co-located with the AeroNET | ||
measurement stations. Statistical data (root mean square error) is generated | ||
using AeroNET observations at model grid cells co-located with the AeroNET | ||
measurement stations. | ||
|
||
Available recipes and diagnostics | ||
--------------------------------- | ||
|
||
Recipes are stored in esmvaltool/recipes/ | ||
|
||
* recipe_aod_aeronet_assess.yml | ||
|
||
Diagnostics are stored in esmvaltool/diag_scripts/aerosols/ | ||
|
||
* aod_aeronet_assess.py: Plot the AOD evaluation. | ||
* aero_utils.py: Utility functions commonly used by aerosol assessment routines. | ||
|
||
|
||
User settings in recipe | ||
----------------------- | ||
|
||
#. Script aod_aeronet_assess.py | ||
|
||
*Required settings for script* | ||
|
||
* wavel: The wavelength of interest for the evaluation, currently set up for 440nm | ||
* min_days_per_mon: The minimum number of days used to calculate the AOD monthly mean | ||
* min_mon_per_seas: The minimum number of seasons used to calculate each | ||
seasonal mean. This must be between 1 and 3. | ||
* min_seas_per_year: The minimum number of seasonal means in each year. This | ||
must be between 1 and 4. | ||
* min_seas_per_clim: The minimum number of seasonal means used to calculate | ||
the multiannual seasonal mean. This must be btween 1 and the number of years | ||
of available AeroNET data. | ||
|
||
*Optional settings for script* | ||
|
||
* None | ||
|
||
*Required settings for variables* | ||
|
||
* None | ||
|
||
*Optional settings for variables* | ||
|
||
* None | ||
|
||
*Required settings for preprocessor* | ||
|
||
* None | ||
|
||
*Optional settings for preprocessor* | ||
|
||
* None | ||
|
||
*Color tables* | ||
|
||
* brewer_Spectral_11 | ||
|
||
|
||
Variables | ||
--------- | ||
|
||
* od440aer (atmos, monthly mean, longitude latitude time) | ||
|
||
|
||
Observations and reformat scripts | ||
--------------------------------- | ||
|
||
* Note: (1) obs4MIPs data can be used directly without any preprocessing; (2) | ||
see headers of reformat scripts for non-obs4MIPs data for download | ||
instructions. | ||
|
||
* The AeroNET data is downloaded from the AeroNET website using the downloader: | ||
|
||
.. code-block:: yaml | ||
$ esmvaltool data download AERONET. | ||
* The AeroNET data is formatteed (CMORized) using the formatter: | ||
|
||
.. code-block:: yaml | ||
$ esmvaltool data format AERONET. | ||
References | ||
---------- | ||
* Holben B.N., T.F.Eck, I.Slutsker, D.Tanre, J.P.Buis, A.Setzer, E.Vermote, J.A.Reagan, Y.Kaufman, T.Nakajima, F.Lavenu, I.Jankowiak, and A.Smirnov, 1998: AERONET - A federated instrument network and data archive for aerosol characterization, Rem. Sens. Environ., 66, 1-16. | ||
|
||
* Holben, B.N., D.Tanre, A.Smirnov, T.F.Eck, I.Slutsker, N.Abuhassan, W.W.Newcomb, J.Schafer, B.Chatenet, F.Lavenue, Y.J.Kaufman, J.Vande Castle, A.Setzer, B.Markham, D.Clark, R.Frouin, R.Halthore, A.Karnieli, N.T.O'Neill, C.Pietras, R.T.Pinker, K.Voss, and G.Zibordi, 2001: An emerging ground-based aerosol climatology: Aerosol Optical Depth from AERONET, J. Geophys. Res., 106, 12 067-12 097. | ||
|
||
* Mulcahy, J. P., Johnson, C., Jones, C. G., Povey, A. C., Scott, C. E., Sellar, A., Turnock, S. T., Woodhouse, M. T., Abraham, N. L., Andrews, M. B., Bellouin, N., Browse, J., Carslaw, K. S., Dalvi, M., Folberth, G. A., Glover, M., Grosvenor, D. P., Hardacre, C., Hill, R., Johnson, B., Jones, A., Kipling, Z., Mann, G., Mollard, J., O’Connor, F. M., Palmiéri, J., Reddington, C., Rumbold, S. T., Richardson, M., Schitgens, N. A. J., Stier, P., Stringer, M., Tang, Y., Walton, J., Woodward, S., and Yool. A.: Description and evaluation of aerosol in UKESM1 and HadGEM3-GC3.1 CMIP6 historical simulations, Geosci. Model Dev., 13, 6383–6423, 2020 | ||
|
||
Example plots | ||
------------- | ||
|
||
.. _fig_aod_aeronet_assess_1: | ||
.. figure:: /recipes/figures/aod_aeronet_assess/UKESM1-0-LL_CMIP_AERmon_historical_od440aer_gn_1994_2014_DJF.png | ||
:align: center | ||
|
||
Evaluation of AOD at 440 nm from UKESM1 historical ensemble member r1i1p1f2 against the AeroNET climatology from ground-based observations for Dec-Jan-Feb. The multiannual seasonal mean is calculated for the model data for the period 1994-2014. The model output is overlaid with the observational climatology. | ||
|
||
.. _fig_aod_aeronet_assess_2: | ||
.. figure:: /recipes/figures/aod_aeronet_assess/UKESM1-0-LL_CMIP_AERmon_historical_od440aer_gn_1994_2014_MAM.png | ||
:align: center | ||
|
||
Evaluation of AOD at 440 nm from UKESM1 historical ensemble member r1i1p1f2 against the AeroNET climatology from ground-based observations for Mar_Apr_May. The multiannual seasonal mean is calculated for the model data for the period 1994-2014. The model output is overlaid with the observational climatology. | ||
|
||
.. _fig_aod_aeronet_assess_3: | ||
.. figure:: /recipes/figures/aod_aeronet_assess/UKESM1-0-LL_CMIP_AERmon_historical_od440aer_gn_1994_2014_JJA.png | ||
:align: center | ||
|
||
Evaluation of AOD at 440 nm from UKESM1 historical ensemble member r1i1p1f2 against the AeroNET climatology from ground-based observations for Jun-Jul-Aug. The multiannual seasonal mean is calculated for the model data for the period 1994-2014. The model output is overlaid with the observational climatology. | ||
|
||
.. _fig_aod_aeronet_assess_4: | ||
.. figure:: /recipes/figures/aod_aeronet_assess/UKESM1-0-LL_CMIP_AERmon_historical_od440aer_gn_1994_2014_SON.png | ||
:align: center | ||
|
||
Evaluation of AOD at 440 nm from UKESM1 historical ensemble member r1i1p1f2 against the AeroNET climatology from ground-based observations for Sep-Oct-Nov. The multiannual seasonal mean is calculated for the model data for the period 1994-2014. The model output is overlaid with the observational climatology. | ||
|
||
.. _fig_aod_aeronet_assess_5: | ||
.. figure:: /recipes/figures/aod_aeronet_assess/UKESM1-0-LL_CMIP_AERmon_historical_od440aer_gn_1994_2014_scatter.png | ||
:align: center | ||
|
||
Evaluation of AOD at 440 nm from UKESM1 historical ensemble member r1i1p1f2 against the AeroNET climatology from ground-based observations for Dec-Jan-Feb, Mar_Apr_May, Jun-Jul-Aug and Sep-Oct-Nov. The multiannual seasonal mean is calculated for the model data for the period 1994-2014. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,193 @@ | ||
"""Part of the ESMValTool Aerosol diagnostics. | ||
This module contains utility functions commonly used by aerosol | ||
assessment routines. | ||
""" | ||
|
||
import iris | ||
import numpy as np | ||
|
||
|
||
class AeroAnsError(Exception): | ||
|
||
"""Exception class for errors raised when model data is checked in the | ||
extract_pt module. | ||
""" | ||
|
||
|
||
def add_bounds(cube): | ||
"""Add bounds to a cube's latitude and longitude coordinates. | ||
Parameters | ||
---------- | ||
cube : Iris cube | ||
Iris cube with latitude and longitude coordinates. | ||
Returns | ||
------- | ||
cube : Iris cube. | ||
Iris cube with bounds added to the latitude and longitude coordinates. | ||
""" | ||
|
||
if not cube.coord('latitude').has_bounds(): | ||
cube.coord('latitude').guess_bounds() | ||
if not cube.coord('longitude').has_bounds(): | ||
cube.coord('longitude').guess_bounds() | ||
|
||
return cube | ||
|
||
|
||
def extract_pt(icube, pt_lat, pt_lon, height=None, level=None, nearest=False): | ||
"""Extracts given location(s) (3-D) from a cube. | ||
Method | ||
------ | ||
Uses Iris module Analysis.Interpolate to extract values, | ||
initially based on horizontal coordinates, and then based on | ||
height, if specified. | ||
If height ('altitude') is requested, checks if cube heights | ||
include orography, i.e. HybridHeights have been derived. | ||
Parameters | ||
---------- | ||
icube : Iris cube | ||
pt_lat, pt_lon : Float or list/array of floats. Latitude and longitude | ||
coordinates of desired points. | ||
args: | ||
height : Float or list/array of floats. Altitude (above geoid) of | ||
point. Initialized to None. | ||
level : Integer . Model level or pseudo level or tile number. | ||
Initialized to None, meaning that all available levels in | ||
the cube are used. | ||
nearest : Boolean. Specify whether to use 'nearest neighbour', instead | ||
of 'linear' method while extracting data. Default is False. | ||
Returns | ||
------- | ||
data_out : List | ||
List of single point values, corresponding to each point specified. | ||
Raises | ||
------ | ||
AeroAnsError : If the number of latitude and longitude points are | ||
mismatched. OR if both and level and height are passed as args. | ||
OR if the cube contains a time coordinate. OR if a pseudo level | ||
coordinate is requested, but not present in the cube. OR if the numbers | ||
of latitude/longitude and height points are mismatched. OR if height | ||
is requested but the cube does not contain an altitude coordinate. | ||
""" | ||
|
||
# Check that input data is a (single) cube | ||
if not isinstance(icube, iris.cube.Cube): | ||
raise AeroAnsError('Extract_pt:First argument must be a single cube') | ||
|
||
# Check if the cube contains a time dimension, which is | ||
# currently unsupported. | ||
if icube.coords()[0].name() == 'time': | ||
raise AeroAnsError( | ||
'Extract_pt:Cannot handle time dimension at present') | ||
|
||
# Check that equal number of lat/lon pairs are passed in point coordinates. | ||
# Convert arguments to lists for easier processing if necessary. | ||
pt_lat1 = [] | ||
pt_lon1 = [] | ||
|
||
if not isinstance(pt_lat, list): | ||
pt_lat1.append(pt_lat) | ||
pt_lon1.append(pt_lon) | ||
|
||
else: | ||
for n_lat in np.arange(len(pt_lat)): | ||
pt_lat1.append(pt_lat[n_lat]) | ||
pt_lon1.append(pt_lon[n_lat]) | ||
|
||
if len(pt_lat1) != len(pt_lon1): | ||
raise AeroAnsError('Extract_pt:Mismatch in number of lat/long values') | ||
|
||
# Check that both level and height haven't been requested. | ||
if level is not None and height is not None: | ||
raise AeroAnsError('Extract_pt: Both Level and Height requested') | ||
|
||
# Check that the cube has a level coordinate if level has been requested. | ||
if level is not None and not icube.coord( | ||
'model_level_number') and not icube.coord('pseudo_level'): | ||
raise AeroAnsError('Extract_pt:Level requested, but not found in cube') | ||
|
||
# Check that the number of height points is equal to the number of | ||
# lat/lon pairs. Convert the argument to a list for easier | ||
# processing if necessary. | ||
if height is not None: | ||
pt_hgt = [] | ||
|
||
# if isinstance(height, list): | ||
# pt_hgt.extend(height) | ||
# else: | ||
# pt_hgt.append(height) | ||
pt_hgt.extend(height) if \ | ||
isinstance(height, list) else \ | ||
pt_hgt.append(height) | ||
|
||
if len(pt_lat1) != len(pt_hgt): | ||
raise AeroAnsError( | ||
'Extract_pt:Mismatch in number of points for lat/long/height') | ||
|
||
# Check that heights have been merged with orography. | ||
if not icube.coords('altitude'): | ||
raise AeroAnsError( | ||
'Extract_pt:Height requested but input data does not contain \ | ||
"Altitude" coordinate') | ||
|
||
# Store the min and max altitudes from cube data so that user | ||
# cannot request points located below/ above that. | ||
# Will extract =min/max if beyond limits. | ||
hgt_min = icube.coord('altitude').points.min() | ||
hgt_max = icube.coord('altitude').points.max() | ||
|
||
# ---------- Finished checks -- begin processing ------------------------- | ||
|
||
# If level specified, extract slice first | ||
if level is not None: | ||
|
||
try: | ||
icube = icube.extract( | ||
iris.Constraint(model_level_number=level)) | ||
|
||
except Exception: | ||
print('Model level number not available. Use pseudo level') | ||
|
||
else: | ||
icube = icube.extract( | ||
iris.Constraint(pseudo_level=level)) | ||
|
||
# Extract values for specified points lat/lon | ||
# NOTE: Does not seem to handle multiple points if 3-D | ||
data_out = [] | ||
|
||
# Set lat/lon coordinates for model grid cell interpolation | ||
for n_lat1 in np.arange(len(pt_lat1)): | ||
latlon_coords = [('latitude', pt_lat1[n_lat1]), | ||
('longitude', pt_lon1[n_lat1])] | ||
|
||
if nearest: | ||
tcube = icube.interpolate(latlon_coords, iris.analysis.Nearest()) | ||
else: | ||
tcube = icube.interpolate(latlon_coords, iris.analysis.Linear()) | ||
|
||
# If height specified, interpolate to requested height | ||
if height is not None: | ||
|
||
# Set vertical coordinates for model grid cell interpolation | ||
point = max(pt_hgt[n_lat1], hgt_min) | ||
point = min(pt_hgt[n_lat1], hgt_max) | ||
hgt_coords = [('altitude', point)] | ||
|
||
if nearest: | ||
tcube = tcube.interpolate(hgt_coords, iris.analysis.Nearest()) | ||
else: | ||
tcube = tcube.interpolate(hgt_coords, iris.analysis.Linear()) | ||
|
||
# Append processed data point | ||
data_out.append(tcube.data) | ||
|
||
return data_out |
Oops, something went wrong.