diff --git a/.circleci/config.yml b/.circleci/config.yml index 5be43d58c6..5957a5e7e3 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -258,7 +258,7 @@ jobs: # Test conda package installation docker: - image: condaforge/mambaforge:latest - resource_class: medium + resource_class: large steps: - run: command: | diff --git a/doc/sphinx/source/recipes/recipe_clouds.rst b/doc/sphinx/source/recipes/recipe_clouds.rst index 3106a616d7..d4497a5d4f 100644 --- a/doc/sphinx/source/recipes/recipe_clouds.rst +++ b/doc/sphinx/source/recipes/recipe_clouds.rst @@ -30,6 +30,9 @@ Four recipes are available to evaluate cloud climatologies from CMIP models. estimated as the relative temporal standard deviation from multi-year timeseries of data with the temporal standard deviations calculated from monthly anomalies after subtracting the climatological mean seasonal cycle. + Note that the satellite observations used in the original recipe (UWisc) is not + maintained anymore and has been superseeded by MAC-LWP (`Elsaesser et al., 2017`_). + We recommend using MAC-LWP. 4) Recipe family recipe_lauer22jclim_*.yml is an extension of recipe_lauer13jclim.yml for evaluation of cloud radiative forcing @@ -49,6 +52,7 @@ Four recipes are available to evaluate cloud climatologies from CMIP models. .. _`Flato et al., 2013`: https://www.ipcc.ch/site/assets/uploads/2018/02/WG1AR5_Chapter09_FINAL.pdf .. _`Lauer and Hamilton (2013)`: https://journals.ametsoc.org/view/journals/clim/26/11/jcli-d-12-00451.1.xml .. _`Lauer et al. (2023)`: https://journals.ametsoc.org/view/journals/clim/36/2/JCLI-D-22-0181.1.xml +.. _`Elsaesser et al., 2017`: https://journals.ametsoc.org/view/journals/clim/30/24/jcli-d-16-0902.1.xml Available recipes and diagnostics diff --git a/esmvaltool/diag_scripts/monitor/multi_datasets.py b/esmvaltool/diag_scripts/monitor/multi_datasets.py index abfed90f9d..9d1834651e 100644 --- a/esmvaltool/diag_scripts/monitor/multi_datasets.py +++ b/esmvaltool/diag_scripts/monitor/multi_datasets.py @@ -946,15 +946,24 @@ def _add_stats(self, plot_type, axes, dim_coords, dataset, mean.data, dataset['units'], ) - axes.text(x_pos, y_pos, f"{mean.data:.2f}{cube.units}", - fontsize=fontsize, transform=axes.transAxes) + if np.abs(mean.data) >= 0.1: + mean_val = f"{mean.data:.2f} {cube.units}" + else: + mean_val = f"{mean.data:.2e} {cube.units}" + axes.text( + x_pos, y_pos, mean_val, fontsize=fontsize, transform=axes.transAxes + ) if ref_cube is None: return # Weighted RMSE rmse = (cube - ref_cube).collapsed(dim_coords, iris.analysis.RMS, weights=weights) - axes.text(x_pos_bias, y_pos, f"RMSE={rmse.data:.2f}{cube.units}", + if np.abs(rmse.data) >= 0.1: + rmse_val = f"{rmse.data:.2f} {cube.units}" + else: + rmse_val = f"{rmse.data:.2e} {cube.units}" + axes.text(x_pos_bias, y_pos, f"RMSE={rmse_val}", fontsize=fontsize, transform=axes.transAxes) logger.info( "Area-weighted RMSE of %s for %s = %f%s", @@ -1193,8 +1202,7 @@ def _plot_map_with_ref(self, plot_func, dataset, ref_dataset): ref_dataset) # Customize plot - fig.suptitle(f"{dataset['long_name']} ({dataset['start_year']}-" - f"{dataset['end_year']})") + fig.suptitle(dataset['long_name']) self._process_pyplot_kwargs(plot_type, dataset) # Rasterization @@ -1249,8 +1257,7 @@ def _plot_map_without_ref(self, plot_func, dataset): # Customize plot axes.set_title(self._get_label(dataset)) - fig.suptitle(f"{dataset['long_name']} ({dataset['start_year']}-" - f"{dataset['end_year']})") + fig.suptitle(dataset['long_name']) self._process_pyplot_kwargs(plot_type, dataset) # Rasterization @@ -1351,8 +1358,7 @@ def _plot_zonal_mean_profile_with_ref(self, plot_func, dataset, ref_dataset) # Customize plot - fig.suptitle(f"{dataset['long_name']} ({dataset['start_year']}-" - f"{dataset['end_year']})") + fig.suptitle(dataset['long_name']) self._process_pyplot_kwargs(plot_type, dataset) # Rasterization @@ -1404,8 +1410,7 @@ def _plot_zonal_mean_profile_without_ref(self, plot_func, dataset): # Customize plot axes.set_title(self._get_label(dataset)) - fig.suptitle(f"{dataset['long_name']} ({dataset['start_year']}-" - f"{dataset['end_year']})") + fig.suptitle(dataset['long_name']) axes.set_xlabel('latitude [°N]') z_coord = cube.coord(axis='Z') axes.set_ylabel(f'{z_coord.long_name} [{z_coord.units}]') @@ -1463,8 +1468,7 @@ def _plot_hovmoeller_z_vs_time_without_ref(self, plot_func, dataset): # Customize plot axes.set_title(self._get_label(dataset)) - fig.suptitle(f"{dataset['long_name']} ({dataset['start_year']}-" - f"{dataset['end_year']})") + fig.suptitle(dataset['long_name']) z_coord = cube.coord(axis='Z') axes.set_ylabel(f'{z_coord.long_name} [{z_coord.units}]') if self.plots[plot_type]['log_y']: @@ -1590,8 +1594,7 @@ def _plot_hovmoeller_z_vs_time_with_ref(self, plot_func, dataset, ref_dataset) # Customize plot - fig.suptitle(f"{dataset['long_name']} ({dataset['start_year']}-" - f"{dataset['end_year']})") + fig.suptitle(dataset['long_name']) self._process_pyplot_kwargs(plot_type, dataset) # Rasterization @@ -1699,8 +1702,7 @@ def _plot_hovmoeller_time_vs_lat_or_lon_with_ref(self, plot_func, dataset, cbar_bias.ax.tick_params(labelsize=fontsize) # Customize plot - fig.suptitle(f"{dataset['long_name']} ({dataset['start_year']}-" - f"{dataset['end_year']})") + fig.suptitle(dataset['long_name']) self._process_pyplot_kwargs(plot_type, dataset) # Rasterization @@ -1752,8 +1754,7 @@ def _plot_hovmoeller_time_vs_lat_or_lon_without_ref(self, plot_func, # Customize plot axes.set_title(self._get_label(dataset)) - fig.suptitle(f"{dataset['long_name']} ({dataset['start_year']}-" - f"{dataset['end_year']})") + fig.suptitle(dataset['long_name']) if 'latitude' in dim_coords_dat: axes.set_xlabel('latitude [°N]') elif 'longitude' in dim_coords_dat: @@ -1842,7 +1843,7 @@ def _get_multi_dataset_facets(datasets): multi_dataset_facets = {} for key in all_keys: if all(d.get(key) == datasets[0].get(key) for d in datasets): - multi_dataset_facets[key] = datasets[0][key] + multi_dataset_facets[key] = datasets[0].get(key) else: multi_dataset_facets[key] = f'ambiguous_{key}' return multi_dataset_facets @@ -2058,8 +2059,7 @@ def create_map_plot(self, datasets): ) caption = ( f"Map plot of {dataset['long_name']} of dataset " - f"{dataset['dataset']} (project {dataset['project']}) " - f"from {dataset['start_year']} to {dataset['end_year']}." + f"{dataset['dataset']} (project {dataset['project']})." ) else: (plot_path, netcdf_paths) = ( @@ -2069,8 +2069,7 @@ def create_map_plot(self, datasets): f"Map plot of {dataset['long_name']} of dataset " f"{dataset['dataset']} (project {dataset['project']}) " f"including bias relative to {ref_dataset['dataset']} " - f"(project {ref_dataset['project']}) from " - f"{dataset['start_year']} to {dataset['end_year']}." + f"(project {ref_dataset['project']})." ) ancestors.append(ref_dataset['filename']) @@ -2135,8 +2134,7 @@ def create_zonal_mean_profile_plot(self, datasets): ) caption = ( f"Zonal mean profile of {dataset['long_name']} of dataset " - f"{dataset['dataset']} (project {dataset['project']}) " - f"from {dataset['start_year']} to {dataset['end_year']}." + f"{dataset['dataset']} (project {dataset['project']})." ) else: (plot_path, netcdf_paths) = ( @@ -2147,8 +2145,7 @@ def create_zonal_mean_profile_plot(self, datasets): f"Zonal mean profile of {dataset['long_name']} of dataset " f"{dataset['dataset']} (project {dataset['project']}) " f"including bias relative to {ref_dataset['dataset']} " - f"(project {ref_dataset['project']}) from " - f"{dataset['start_year']} to {dataset['end_year']}." + f"(project {ref_dataset['project']})." ) ancestors.append(ref_dataset['filename']) @@ -2390,8 +2387,8 @@ def create_hovmoeller_z_vs_time_plot(self, datasets): caption = ( f"Hovmoeller Z vs. time plot of {dataset['long_name']} " f"of dataset " - f"{dataset['dataset']} (project {dataset['project']}) " - f"from {dataset['start_year']} to {dataset['end_year']}.") + f"{dataset['dataset']} (project {dataset['project']})." + ) else: (plot_path, netcdf_paths) = (self._plot_hovmoeller_z_vs_time_with_ref( @@ -2401,8 +2398,8 @@ def create_hovmoeller_z_vs_time_plot(self, datasets): f"of dataset " f"{dataset['dataset']} (project {dataset['project']}) " f"including bias relative to {ref_dataset['dataset']} " - f"(project {ref_dataset['project']}) from " - f"{dataset['start_year']} to {dataset['end_year']}.") + f"(project {ref_dataset['project']})." + ) ancestors.append(ref_dataset['filename']) # If statistics are shown add a brief description to the caption @@ -2467,8 +2464,7 @@ def create_hovmoeller_time_vs_lat_or_lon_plot(self, datasets): ) caption = ( f"Hovmoeller plot of {dataset['long_name']} of dataset " - f"{dataset['dataset']} (project {dataset['project']}) " - f"from {dataset['start_year']} to {dataset['end_year']}." + f"{dataset['dataset']} (project {dataset['project']})." ) else: (plot_path, netcdf_paths) = ( @@ -2479,8 +2475,7 @@ def create_hovmoeller_time_vs_lat_or_lon_plot(self, datasets): f"Hovmoeller plot of {dataset['long_name']} of dataset " f"{dataset['dataset']} (project {dataset['project']}) " f"including bias relative to {ref_dataset['dataset']} " - f"(project {ref_dataset['project']}) from " - f"{dataset['start_year']} to {dataset['end_year']}." + f"(project {ref_dataset['project']})." ) ancestors.append(ref_dataset['filename']) diff --git a/esmvaltool/diag_scripts/seaice_drift/seaice_drift.py b/esmvaltool/diag_scripts/seaice_drift/seaice_drift.py index fd586f6b7e..6791254109 100644 --- a/esmvaltool/diag_scripts/seaice_drift/seaice_drift.py +++ b/esmvaltool/diag_scripts/seaice_drift/seaice_drift.py @@ -540,7 +540,8 @@ def __init__(self, polygon=None, lat=None, lon=None): polygon.append(polygon[0]) self.transformer = Transformer.from_crs("WGS84", - "North_Pole_Stereographic") + "North_Pole_Stereographic", + always_xy=True) transformed = [] for lon_val, lat_val in polygon: diff --git a/esmvaltool/recipes/clouds/recipe_lauer13jclim.yml b/esmvaltool/recipes/clouds/recipe_lauer13jclim.yml index 3d741e485d..9acbcfcbd1 100644 --- a/esmvaltool/recipes/clouds/recipe_lauer13jclim.yml +++ b/esmvaltool/recipes/clouds/recipe_lauer13jclim.yml @@ -142,6 +142,13 @@ diagnostics: mip: Amon derive: true additional_datasets: + # The original recipe uses the UWisc dataset that is not + # maintained anymore by the authors and has been supersided + # by MAC-LWP (Elsaesser et al., 2017) + # https://doi.org/10.1175/JCLI-D-16-0902.1 + # We recommend using MAC-LWP + #- {dataset: MAC-LWP, project: OBS, type: sat, version: v1, + # start_year: 1988, end_year: 2007, tier: 3} - {dataset: UWisc, project: OBS, type: sat, version: v2, start_year: 1988, end_year: 2007, tier: 3} scripts: diff --git a/esmvaltool/recipes/model_evaluation/recipe_model_evaluation_clouds_clim.yml b/esmvaltool/recipes/model_evaluation/recipe_model_evaluation_clouds_clim.yml index fd2d08781f..c45a4971ad 100644 --- a/esmvaltool/recipes/model_evaluation/recipe_model_evaluation_clouds_clim.yml +++ b/esmvaltool/recipes/model_evaluation/recipe_model_evaluation_clouds_clim.yml @@ -3,8 +3,8 @@ documentation: title: Model evaluation with focus on clouds. description: > - Plot climatologies several cloud-related variables of multi-year - simulations. + Plot climatologies and zonal mean profiles of several cloud-related + variables of multi-year simulations. authors: - bonnet_pauline - lauer_axel diff --git a/esmvaltool/recipes/model_evaluation/recipe_model_evaluation_clouds_cycles.yml b/esmvaltool/recipes/model_evaluation/recipe_model_evaluation_clouds_cycles.yml index ed52fd7d3c..8139a04dfc 100644 --- a/esmvaltool/recipes/model_evaluation/recipe_model_evaluation_clouds_cycles.yml +++ b/esmvaltool/recipes/model_evaluation/recipe_model_evaluation_clouds_cycles.yml @@ -3,7 +3,8 @@ documentation: title: Model evaluation with focus on clouds. description: > - Plot annual cycles of several cloud-related variables of multi-year simulations. + Plot annual cycles of several cloud-related variables of multi-year + simulations. authors: - lauer_axel - schlund_manuel diff --git a/esmvaltool/recipes/model_evaluation/recipe_model_evaluation_precip_zonal.yml b/esmvaltool/recipes/model_evaluation/recipe_model_evaluation_precip_zonal.yml index 6bd1231046..97802deb47 100644 --- a/esmvaltool/recipes/model_evaluation/recipe_model_evaluation_precip_zonal.yml +++ b/esmvaltool/recipes/model_evaluation/recipe_model_evaluation_precip_zonal.yml @@ -3,7 +3,7 @@ documentation: title: Model evaluation with focus on precipitation. description: > - Plot zonal mean plots of precipitation. + Plot zonal mean precipitation. authors: - lauer_axel - schlund_manuel diff --git a/esmvaltool/recipes/recipe_autoassess_landsurface_surfrad.yml b/esmvaltool/recipes/recipe_autoassess_landsurface_surfrad.yml index 0ddb86c181..3d77ed02c1 100644 --- a/esmvaltool/recipes/recipe_autoassess_landsurface_surfrad.yml +++ b/esmvaltool/recipes/recipe_autoassess_landsurface_surfrad.yml @@ -42,7 +42,7 @@ diagnostics: force_derivation: false mip: Amon additional_datasets: - - {dataset: CERES-EBAF, project: obs4MIPs, level: L3B, version: Ed2-7, start_year: 2001, end_year: 2012, tier: 1} + - {dataset: CERES-EBAF, project: obs4MIPs, level: L3B, start_year: 2001, end_year: 2012, tier: 1} sftlf: mip: fx rlns: # Surf LW net all sky @@ -50,7 +50,7 @@ diagnostics: force_derivation: false mip: Amon additional_datasets: - - {dataset: CERES-EBAF, project: obs4MIPs, level: L3B, version: Ed2-7, start_year: 2001, end_year: 2012, tier: 1} + - {dataset: CERES-EBAF, project: obs4MIPs, level: L3B, start_year: 2001, end_year: 2012, tier: 1} sftlf: mip: fx scripts: