1111publicly available.
1212"""
1313
14- import contextlib
14+ from __future__ import annotations
15+
1516import threading
16- import typing
17- from typing import List
17+ from typing import TYPE_CHECKING , List
1818
19- if typing . TYPE_CHECKING :
19+ if TYPE_CHECKING :
2020 from iris .cube import Cube , CubeList
2121
2222
2323class CombineOptions (threading .local ):
2424 """A container for cube combination options.
2525
26- Controls for generalised merge/concatenate options.
27-
28- Also controls the detection and handling of cases where a hybrid coordinate
29- uses multiple reference fields during loading : for example, a UM file which
30- contains a series of fields describing time-varying orography.
31-
32- Options can be set directly, or via :meth:`~iris.LoadPolicy.set`, or changed for
33- the scope of a code block with :meth:`~iris.LoadPolicy.context`.
34-
35- .. note ::
26+ Controls for generalised merge/concatenate options. These are used as controls for
27+ both the :func:`iris.util.combine_cubes` utility method and the core Iris loading
28+ functions : see also :data:`iris.loading.LoadPolicy`.
3629
37- The default behaviour will "fix" loading for cases like the time-varying
38- orography case described above. However, this is not strictly
39- backwards-compatible. If this causes problems, you can force identical loading
40- behaviour to earlier Iris versions with ``LOAD_POLICY.set("legacy")`` or
41- equivalent.
42-
43- .. testsetup::
44-
45- from iris import LOAD_POLICY
30+ It specifies a number of possible operations which may be applied to a list of
31+ cubes, in a definite sequence, all of which tend to combine cubes into a smaller
32+ number of larger or higher-dimensional cubes.
4633
4734 Notes
4835 -----
4936 The individual configurable options are :
5037
51- * ``support_multiple_references`` = True / False
52- When enabled, the presence of multiple aux-factory reference cubes, which merge
53- to define a extra dimension, will add that dimension to the loaded cubes.
54- This is essential for correct support of time-dependent hybrid coordinates (i.e.
55- aux factories) when loading from fields-based data (e.g. PP or GRIB).
56- For example (notably) time-dependent orography in UM data on hybrid-heights.
38+ * ``merge_concat_sequence`` = "m" / "c" / "cm" / "mc"
39+ Specifies whether to apply :meth:`~iris.cube.CubeList.merge`, or
40+ :meth:`~iris.cube.CubeList.concatenate` operations, or both, in either order.
5741
58- In addition, when such multiple references are detected, an extra concatenate
59- step is added to the 'merge_concat_sequence' (see below), if none is already
60- configured there .
42+ * ``merge_uses_unique`` = True / False
43+ When True, any merge operation will error if its result contains multiple
44+ identical cubes. Otherwise (unique=False), that is a permitted result .
6145
62- * ``merge_concat_sequence`` = "m" / "c" / "cm" / "mc"
63- Specifies whether to merge, or concatenate, or both in either order.
64- This is the "combine" operation which is applied to loaded data.
46+ .. Note::
47+
48+ By default, in a normal :meth:`~iris.cube.CubeList.merge` operation on a
49+ :class:`~iris.cube.CubeList`, ``unique`` defaults to ``True``.
50+ For loading operations, however, the default is ``unique=False``, as this
51+ produces the intended behaviour when loading with multiple constraints.
6552
6653 * ``repeat_until_unchanged`` = True / False
6754 When enabled, the configured "combine" operation will be repeated until the
@@ -102,35 +89,29 @@ class CombineOptions(threading.local):
10289
10390 # Useful constants
10491 #: Valid option names
105- OPTION_KEYS = (
106- "support_multiple_references" ,
92+ OPTION_KEYS = [
10793 "merge_concat_sequence" ,
10894 "repeat_until_unchanged" ,
109- )
95+ ] # this is a list, so we can update it in an inheriting class
11096 _OPTIONS_ALLOWED_VALUES = {
111- "support_multiple_references" : (False , True ),
11297 "merge_concat_sequence" : ("" , "m" , "c" , "mc" , "cm" ),
11398 "repeat_until_unchanged" : (False , True ),
11499 }
115100 #: Settings content
116101 SETTINGS = {
117102 "legacy" : dict (
118- support_multiple_references = False ,
119103 merge_concat_sequence = "m" ,
120104 repeat_until_unchanged = False ,
121105 ),
122106 "default" : dict (
123- support_multiple_references = True ,
124107 merge_concat_sequence = "m" ,
125108 repeat_until_unchanged = False ,
126109 ),
127110 "recommended" : dict (
128- support_multiple_references = True ,
129111 merge_concat_sequence = "mc" ,
130112 repeat_until_unchanged = False ,
131113 ),
132114 "comprehensive" : dict (
133- support_multiple_references = True ,
134115 merge_concat_sequence = "mc" ,
135116 repeat_until_unchanged = True ,
136117 ),
@@ -163,8 +144,8 @@ def set(self, options: str | dict | None = None, **kwargs):
163144 Parameters
164145 ----------
165146 * options : str or dict, optional
166- A dictionary of options values, or the name of one of the
167- :data:`~iris.LoadPolicy.SETTINGS ` standard option sets ,
147+ A dictionary of options values, or one of the
148+ :data:`~iris.LoadPolicy.SETTINGS_NAMES ` standard settings names ,
168149 e.g. "legacy" or "comprehensive".
169150 * kwargs : dict
170151 Individual option settings, from :data:`~iris.LoadPolicy.OPTION_KEYS`.
@@ -183,13 +164,13 @@ def set(self, options: str | dict | None = None, **kwargs):
183164 options_dict = options
184165 else :
185166 msg = (
186- f"'options' arg has unexpected type { type (options )!r} , "
187- "expected (None | str | dict )."
167+ f"arg `options` has unexpected type { type (options )!r} , "
168+ f "expected one of (None | str | dcit )."
188169 )
189- raise ValueError (msg )
170+ raise TypeError (msg )
190171
191172 # Override any options with keywords
192- options_dict = options_dict .copy () # do not modify source (!)
173+ options_dict = options_dict .copy () # don't modify original
193174 options_dict .update (** kwargs )
194175 bad_keys = [key for key in options_dict if key not in self .OPTION_KEYS ]
195176 if bad_keys :
@@ -210,52 +191,6 @@ def __repr__(self):
210191 msg += ")"
211192 return msg
212193
213- @contextlib .contextmanager
214- def context (self , settings : str | dict | None = None , ** kwargs ):
215- """Return a context manager applying given options.
216-
217- Parameters
218- ----------
219- settings : str or dict
220- Options dictionary or name, as for :meth:`~LoadPolicy.set`.
221- kwargs : dict
222- Option values, as for :meth:`~LoadPolicy.set`.
223-
224- Examples
225- --------
226- .. testsetup::
227-
228- import iris
229- from iris import LOAD_POLICY, sample_data_path
230-
231- >>> # Show how a CombineOptions acts in the context of a load operation
232- >>> # (N.B. the LOAD_POLICY actually *is* a CombineOptions type object)
233- >>> path = sample_data_path("time_varying_hybrid_height", "*.pp")
234- >>> # "legacy" load behaviour allows merge but not concatenate
235- >>> with LOAD_POLICY.context("legacy"):
236- ... cubes = iris.load(path, "x_wind")
237- >>> print(cubes)
238- 0: x_wind / (m s-1) (time: 2; model_level_number: 5; latitude: 144; longitude: 192)
239- 1: x_wind / (m s-1) (time: 12; model_level_number: 5; latitude: 144; longitude: 192)
240- 2: x_wind / (m s-1) (model_level_number: 5; latitude: 144; longitude: 192)
241- >>>
242- >>> # "recommended" behaviour enables concatenation
243- >>> with LOAD_POLICY.context("recommended"):
244- ... cubes = iris.load(path, "x_wind")
245- >>> print(cubes)
246- 0: x_wind / (m s-1) (model_level_number: 5; time: 15; latitude: 144; longitude: 192)
247- """
248- # Save the current state
249- saved_settings = self .settings ()
250-
251- # Apply the new options and execute the context
252- try :
253- self .set (settings , ** kwargs )
254- yield
255- finally :
256- # Re-establish the former state
257- self .set (saved_settings )
258-
259194
260195def _combine_cubes (cubes : List [Cube ], options : dict ) -> CubeList :
261196 """Combine cubes as for load, according to "loading policy" options.
0 commit comments