Skip to content

Commit be4f5d9

Browse files
wyatt-fluidnumericsWyatt Sieminskipre-commit-ci[bot]
authored
Add a warning whenever a _mesh is different for a field when added to a FieldSet, or during Fieldset creation (#2761)
* added a warning whenever added fields use different meshes * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * Added mesh warning to add_constant_field and revised test suite to only combine/create FieldSets with the same underlying mesh --------- Co-authored-by: Wyatt Sieminski <wyatt_sieminski@brown.edu> Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
1 parent fcffbbb commit be4f5d9

2 files changed

Lines changed: 31 additions & 4 deletions

File tree

src/parcels/_core/fieldset.py

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import functools
44
import sys
5+
import warnings
56
from collections.abc import Iterable
67
from typing import IO, TYPE_CHECKING
78

@@ -21,6 +22,7 @@
2122
from parcels._core.utils.string import _assert_str_and_python_varname
2223
from parcels._core.utils.time import get_datetime_type_calendar
2324
from parcels._core.utils.time import is_compatible as datetime_is_compatible
25+
from parcels._core.warnings import FieldSetWarning
2426
from parcels._python import NOTSET, NotSetType
2527
from parcels._reprs import fieldset_describe
2628
from parcels.interpolators import (
@@ -73,6 +75,7 @@ def __init__(self, models: list[ModelData]):
7375
self._fields: dict[str, Field | VectorField] | None = None
7476
self.reconstruct_fields()
7577
self.context: dict[str, float] = {}
78+
_warn_if_fields_use_different_meshes(self.fields.values())
7679

7780
def __setattr__(self, name, value):
7881
"""Set field attribute by name. If context exists and name in context, raise error to prevent overwriting context variable."""
@@ -151,6 +154,7 @@ def add_field(self, field: Field, name: str | None = None):
151154
raise ValueError(f"FieldSet already has a Field with name '{name}'")
152155

153156
self.fields[name] = field
157+
_warn_if_fields_use_different_meshes(self.fields.values())
154158

155159
def to_windowed_arrays(self, *, max_levels: int | None = None):
156160
"""Wrap dask-backed field data in rolling time-window caches.
@@ -215,6 +219,7 @@ def add_constant_field(self, name: str, value, mesh: ptyping.Mesh = "spherical")
215219
self.reconstruct_fields()
216220
field = getattr(self, name)
217221
field.interp_method = XConstantField()
222+
_warn_if_fields_use_different_meshes(self.fields.values())
218223

219224
def add_context(self, name, value):
220225
"""Add context variable to the FieldSet.
@@ -362,6 +367,28 @@ def assert_compatible_fieldsets(left: FieldSet, right: FieldSet) -> None:
362367
)
363368

364369

370+
def _warn_if_fields_use_different_meshes(fields: Iterable[Field | VectorField]):
371+
"""Warn if multiple fields use different meshes on the underlying grids.
372+
373+
Parameters
374+
----------
375+
fields : Iterable[Field | VectorField]
376+
The fields to check for conflicting meshes.
377+
378+
Warns
379+
-----
380+
FieldSetWarning
381+
If the fields have different meshes on the underlying grids.
382+
"""
383+
meshes = {field.grid._mesh for field in fields}
384+
if len(meshes) > 1:
385+
warnings.warn(
386+
f"FieldSet has multiple different meshes: {meshes}. This may lead to unexpected behavior during execution.",
387+
category=FieldSetWarning,
388+
stacklevel=3,
389+
)
390+
391+
365392
class CalendarError(Exception): # TODO: Move to a parcels errors module
366393
"""Exception raised when the calendar of a field is not compatible with the rest of the Fields. The user should ensure that they only add fields to a FieldSet that have compatible CFtime calendars."""
367394

tests/test_fieldset.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ def fieldset_two_models():
3232
fset2 = FieldSet.from_sgrid_conventions(ds2, mesh="flat", vector_fields={"UV_wind": ("U_wind", "V_wind")})
3333
fset2.add_context("my_value", 2.0)
3434
fset2.add_context("my_list", [1, 2, "hello"])
35-
fset2.add_constant_field("constant_field", 3.0)
35+
fset2.add_constant_field("constant_field", 3.0, mesh="flat")
3636
return fset1 + fset2
3737

3838

@@ -69,7 +69,7 @@ def test_fieldset_add_context_invalid_name(fieldset, name):
6969

7070

7171
def test_fieldset_add_constant_field(fieldset):
72-
fieldset.add_constant_field("test_constant_field", 1.0)
72+
fieldset.add_constant_field("test_constant_field", 1.0, mesh="flat")
7373

7474
# Get a point in the domain
7575
time = ds["time"].mean()
@@ -86,7 +86,7 @@ def test_fieldset_gridset(fieldset):
8686
assert fieldset.fields["UV"].grid in fieldset.gridset
8787
assert len(fieldset.gridset) == 1
8888

89-
fieldset.add_constant_field("constant_field", 1.0)
89+
fieldset.add_constant_field("constant_field", 1.0, mesh="flat")
9090
assert len(fieldset.gridset) == 2
9191

9292

@@ -233,7 +233,7 @@ def test_fieldset_time_interval():
233233
field2 = Field("field2", ds2["U_A_grid"], grid2, interp_method=XLinear)
234234

235235
fieldset = FieldSet([field1, field2])
236-
fieldset.add_constant_field("constant_field", 1.0)
236+
fieldset.add_constant_field("constant_field", 1.0, mesh="flat")
237237

238238
assert fieldset.time_interval.left == np.datetime64("2000-01-02")
239239
assert fieldset.time_interval.right == np.datetime64("2001-01-01")

0 commit comments

Comments
 (0)