Skip to content

Commit 4b8bf66

Browse files
authored
Added option to explicitly not use fx variables in preprocessors (#1416)
* Added option to explicitly not use fx variables in preprocessors * Updated doc * Updated doc * Deprecated always_use_ne_masks for mask_landsea * Always use fx_variables: null in doc * Moved Deprecation warning to dedicated exceptions module
1 parent 2fc6a19 commit 4b8bf66

File tree

6 files changed

+150
-17
lines changed

6 files changed

+150
-17
lines changed

doc/recipe/preprocessor.rst

+12-5
Original file line numberDiff line numberDiff line change
@@ -195,11 +195,11 @@ Preprocessor Default fx variab
195195
:ref:`weighting_landsea_fraction<land/sea fraction weighting>` ``sftlf``, ``sftof``
196196
============================================================== =====================
197197

198-
If no ``fx_variables`` are specified for these preprocessors, the fx variables
199-
in the second column are used. If given, the ``fx_variables`` argument
200-
specifies the fx variables that the user wishes to input to the corresponding
201-
preprocessor function. The user may specify these by simply adding the names of
202-
the variables, e.g.,
198+
If the option ``fx_variables`` is not explicitly specified for these
199+
preprocessors, the default fx variables in the second column are automatically
200+
used. If given, the ``fx_variables`` argument specifies the fx variables that
201+
the user wishes to input to the corresponding preprocessor function. The user
202+
may specify these by simply adding the names of the variables, e.g.,
203203

204204
.. code-block:: yaml
205205
@@ -247,6 +247,13 @@ available tables of the specified project.
247247
a given dataset) fx files are found in more than one table, ``mip`` needs to
248248
be specified, otherwise an error is raised.
249249

250+
.. note::
251+
To explicitly **not** use any fx variables in a preprocessor, use
252+
``fx_variables: null``. While some of the preprocessors mentioned above do
253+
work without fx variables (e.g., ``area_statistics`` or ``mask_landsea``
254+
with datasets that have regular latitude/longitude grids), using this option
255+
is **not** recommended.
256+
250257
Internally, the required ``fx_variables`` are automatically loaded by the
251258
preprocessor step ``add_fx_variables`` which also checks them against CMOR
252259
standards and adds them either as ``cell_measure`` (see `CF conventions on cell

esmvalcore/_recipe.py

+14-9
Original file line numberDiff line numberDiff line change
@@ -507,14 +507,12 @@ def _fx_list_to_dict(fx_vars):
507507

508508
def _update_fx_settings(settings, variable, config_user):
509509
"""Update fx settings depending on the needed method."""
510-
511-
# get fx variables either from user defined attribute or fixed
512-
def _get_fx_vars_from_attribute(step_settings, step_name):
513-
user_fx_vars = step_settings.get('fx_variables')
514-
if isinstance(user_fx_vars, list):
515-
user_fx_vars = _fx_list_to_dict(user_fx_vars)
516-
step_settings['fx_variables'] = user_fx_vars
517-
if not user_fx_vars:
510+
# Add default values to the option 'fx_variables' if it is not explicitly
511+
# specified and transform fx variables to dicts
512+
def _update_fx_vars_in_settings(step_settings, step_name):
513+
"""Update fx_variables option in the settings."""
514+
# Add default values for fx_variables
515+
if 'fx_variables' not in step_settings:
518516
default_fx = {
519517
'area_statistics': {
520518
'areacella': None,
@@ -538,13 +536,20 @@ def _get_fx_vars_from_attribute(step_settings, step_name):
538536
default_fx['weighting_landsea_fraction']['sftof'] = None
539537
step_settings['fx_variables'] = default_fx[step_name]
540538

539+
# Transform fx variables to dicts
540+
user_fx_vars = step_settings['fx_variables']
541+
if user_fx_vars is None:
542+
step_settings['fx_variables'] = {}
543+
elif isinstance(user_fx_vars, list):
544+
step_settings['fx_variables'] = _fx_list_to_dict(user_fx_vars)
545+
541546
fx_steps = [
542547
'mask_landsea', 'mask_landseaice', 'weighting_landsea_fraction',
543548
'area_statistics', 'volume_statistics'
544549
]
545550
for step_name in settings:
546551
if step_name in fx_steps:
547-
_get_fx_vars_from_attribute(settings[step_name], step_name)
552+
_update_fx_vars_in_settings(settings[step_name], step_name)
548553
_update_fx_files(step_name, settings, variable, config_user,
549554
settings[step_name]['fx_variables'])
550555
# Remove unused attribute in 'fx_steps' preprocessors.

esmvalcore/exceptions.py

+4
Original file line numberDiff line numberDiff line change
@@ -16,3 +16,7 @@ def __str__(self):
1616

1717
class InputFilesNotFound(RecipeError):
1818
"""Files that are required to run the recipe have not been found."""
19+
20+
21+
class ESMValCoreDeprecationWarning(UserWarning):
22+
"""Custom deprecation warning."""

esmvalcore/preprocessor/_mask.py

+19
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
import logging
99
import os
10+
import warnings
1011

1112
import cartopy.io.shapereader as shpreader
1213
import dask.array as da
@@ -16,6 +17,8 @@
1617
from iris.analysis import Aggregator
1718
from iris.util import rolling_window
1819

20+
from esmvalcore.exceptions import ESMValCoreDeprecationWarning
21+
1922
logger = logging.getLogger(__name__)
2023

2124

@@ -81,6 +84,14 @@ def mask_landsea(cube, mask_out, always_use_ne_mask=False):
8184
always apply Natural Earths mask, regardless if fx files are available
8285
or not.
8386
87+
.. warning::
88+
This option has been deprecated in ESMValCore version 2.5. To
89+
always use Natural Earth masks, either explicitly remove all
90+
``ancillary_variables`` from the input cube (when this function is
91+
used directly) or specify ``fx_variables: null`` as option for this
92+
preprocessor in the recipe (when this function is used as part of
93+
ESMValTool).
94+
8495
Returns
8596
-------
8697
iris.cube.Cube
@@ -132,6 +143,14 @@ def mask_landsea(cube, mask_out, always_use_ne_mask=False):
132143
"yet implemented, land-sea mask not applied.")
133144
raise ValueError(msg)
134145
else:
146+
deprecation_msg = (
147+
"The option ``always_use_ne_masks``' has been deprecated in "
148+
"ESMValCore version 2.5. To always use Natural Earth masks, "
149+
"either explicitly remove all ``ancillary_variables`` from the "
150+
"input cube (when this function is used directly) or specify "
151+
"``fx_variables: null`` as option for this preprocessor in the "
152+
"recipe (when this function is used as part of ESMValTool).")
153+
warnings.warn(deprecation_msg, ESMValCoreDeprecationWarning)
135154
if cube.coord('longitude').points.ndim < 2:
136155
cube = _mask_with_shp(cube, shapefiles[mask_out], [
137156
0,

tests/integration/preprocessor/_mask/test_mask.py

+8-3
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,18 @@
77
"""
88

99
import iris
10+
import iris.fileformats
1011
import numpy as np
1112
import pytest
1213

1314
from esmvalcore.cmor.check import CheckLevels
14-
from esmvalcore.preprocessor import (PreprocessorFile, mask_fillvalues,
15-
mask_landsea, mask_landseaice,
16-
add_fx_variables)
15+
from esmvalcore.preprocessor import (
16+
PreprocessorFile,
17+
add_fx_variables,
18+
mask_fillvalues,
19+
mask_landsea,
20+
mask_landseaice,
21+
)
1722
from tests import assert_array_equal
1823

1924

tests/integration/test_recipe.py

+93
Original file line numberDiff line numberDiff line change
@@ -2116,6 +2116,99 @@ def test_landmask(tmp_path, patched_datafinder, config_user):
21162116
assert len(fx_variables) == 2
21172117

21182118

2119+
def test_empty_fxvar_none(tmp_path, patched_datafinder, config_user):
2120+
"""Test that no fx variables are added if explicitly specified."""
2121+
content = dedent("""
2122+
preprocessors:
2123+
landmask:
2124+
mask_landsea:
2125+
mask_out: sea
2126+
fx_variables: null
2127+
diagnostics:
2128+
diagnostic_name:
2129+
variables:
2130+
gpp:
2131+
preprocessor: landmask
2132+
project: CMIP5
2133+
mip: Lmon
2134+
exp: historical
2135+
start_year: 2000
2136+
end_year: 2005
2137+
ensemble: r1i1p1
2138+
additional_datasets:
2139+
- {dataset: CanESM2}
2140+
scripts: null
2141+
""")
2142+
recipe = get_recipe(tmp_path, content, config_user)
2143+
2144+
# Check that no custom fx variables are present
2145+
task = recipe.tasks.pop()
2146+
product = task.products.pop()
2147+
assert product.settings['add_fx_variables']['fx_variables'] == {}
2148+
2149+
2150+
def test_empty_fxvar_list(tmp_path, patched_datafinder, config_user):
2151+
"""Test that no fx variables are added if explicitly specified."""
2152+
content = dedent("""
2153+
preprocessors:
2154+
landmask:
2155+
mask_landsea:
2156+
mask_out: sea
2157+
fx_variables: []
2158+
diagnostics:
2159+
diagnostic_name:
2160+
variables:
2161+
gpp:
2162+
preprocessor: landmask
2163+
project: CMIP5
2164+
mip: Lmon
2165+
exp: historical
2166+
start_year: 2000
2167+
end_year: 2005
2168+
ensemble: r1i1p1
2169+
additional_datasets:
2170+
- {dataset: CanESM2}
2171+
scripts: null
2172+
""")
2173+
recipe = get_recipe(tmp_path, content, config_user)
2174+
2175+
# Check that no custom fx variables are present
2176+
task = recipe.tasks.pop()
2177+
product = task.products.pop()
2178+
assert product.settings['add_fx_variables']['fx_variables'] == {}
2179+
2180+
2181+
def test_empty_fxvar_dict(tmp_path, patched_datafinder, config_user):
2182+
"""Test that no fx variables are added if explicitly specified."""
2183+
content = dedent("""
2184+
preprocessors:
2185+
landmask:
2186+
mask_landsea:
2187+
mask_out: sea
2188+
fx_variables: {}
2189+
diagnostics:
2190+
diagnostic_name:
2191+
variables:
2192+
gpp:
2193+
preprocessor: landmask
2194+
project: CMIP5
2195+
mip: Lmon
2196+
exp: historical
2197+
start_year: 2000
2198+
end_year: 2005
2199+
ensemble: r1i1p1
2200+
additional_datasets:
2201+
- {dataset: CanESM2}
2202+
scripts: null
2203+
""")
2204+
recipe = get_recipe(tmp_path, content, config_user)
2205+
2206+
# Check that no custom fx variables are present
2207+
task = recipe.tasks.pop()
2208+
product = task.products.pop()
2209+
assert product.settings['add_fx_variables']['fx_variables'] == {}
2210+
2211+
21192212
def test_user_defined_fxvar(tmp_path, patched_datafinder, config_user):
21202213
content = dedent("""
21212214
preprocessors:

0 commit comments

Comments
 (0)