From dc4ba5226b1672a36ea87bfc137c090c81010b6a Mon Sep 17 00:00:00 2001 From: Wyatt Sieminski Date: Mon, 20 Jul 2026 15:25:49 -0400 Subject: [PATCH 1/4] added a warning whenever added fields use different meshes --- src/parcels/_core/fieldset.py | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/src/parcels/_core/fieldset.py b/src/parcels/_core/fieldset.py index 940c98cf2..139487be3 100644 --- a/src/parcels/_core/fieldset.py +++ b/src/parcels/_core/fieldset.py @@ -2,6 +2,7 @@ import functools import sys +import warnings from collections.abc import Iterable from typing import IO, TYPE_CHECKING @@ -21,6 +22,7 @@ from parcels._core.utils.string import _assert_str_and_python_varname from parcels._core.utils.time import get_datetime_type_calendar from parcels._core.utils.time import is_compatible as datetime_is_compatible +from parcels._core.warnings import FieldSetWarning from parcels._python import NOTSET, NotSetType from parcels._reprs import fieldset_describe from parcels.interpolators import ( @@ -73,6 +75,7 @@ def __init__(self, models: list[ModelData]): self._fields: dict[str, Field | VectorField] | None = None self.reconstruct_fields() self.context: dict[str, float] = {} + _warn_if_fields_use_different_meshes(self.fields.values()) def __setattr__(self, name, value): """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): raise ValueError(f"FieldSet already has a Field with name '{name}'") self.fields[name] = field + _warn_if_fields_use_different_meshes(self.fields.values()) def to_windowed_arrays(self, *, max_levels: int | None = None): """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") self.reconstruct_fields() field = getattr(self, name) field.interp_method = XConstantField() + _warn_if_fields_use_different_meshes(self.fields.values()) def add_context(self, name, value): """Add context variable to the FieldSet. @@ -362,6 +367,28 @@ def assert_compatible_fieldsets(left: FieldSet, right: FieldSet) -> None: ) +def _warn_if_fields_use_different_meshes(fields: Iterable[Field | VectorField]): + """Warn if multiple fields use different meshes on the underlying grids. + + Parameters + ---------- + fields : Iterable[Field | VectorField] + The fields to check for conflicting meshes. + + Warns + ------ + FieldSetWarning + If the fields have different meshes on the underlying grids. + """ + meshes = {field.grid._mesh for field in fields} + if len(meshes) > 1: + warnings.warn( + f"FieldSet has multiple different meshes: {meshes}. This may lead to unexpected behavior during execution.", + category=FieldSetWarning, + stacklevel=2, + ) + + class CalendarError(Exception): # TODO: Move to a parcels errors module """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.""" From f314bb8b71749be9201fec39daab30dea99baf56 Mon Sep 17 00:00:00 2001 From: Wyatt Sieminski Date: Mon, 20 Jul 2026 15:43:15 -0400 Subject: [PATCH 2/4] commented out warning in add_constant_field --- src/parcels/_core/fieldset.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/parcels/_core/fieldset.py b/src/parcels/_core/fieldset.py index 139487be3..dca13a2df 100644 --- a/src/parcels/_core/fieldset.py +++ b/src/parcels/_core/fieldset.py @@ -219,7 +219,7 @@ def add_constant_field(self, name: str, value, mesh: ptyping.Mesh = "spherical") self.reconstruct_fields() field = getattr(self, name) field.interp_method = XConstantField() - _warn_if_fields_use_different_meshes(self.fields.values()) + #_warn_if_fields_use_different_meshes(self.fields.values()) def add_context(self, name, value): """Add context variable to the FieldSet. From 3a0b5517bc9a3bfddf15683d8ba4054857e5c2c0 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 20 Jul 2026 20:01:26 +0000 Subject: [PATCH 3/4] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- src/parcels/_core/fieldset.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/parcels/_core/fieldset.py b/src/parcels/_core/fieldset.py index dca13a2df..5d597a00c 100644 --- a/src/parcels/_core/fieldset.py +++ b/src/parcels/_core/fieldset.py @@ -219,7 +219,7 @@ def add_constant_field(self, name: str, value, mesh: ptyping.Mesh = "spherical") self.reconstruct_fields() field = getattr(self, name) field.interp_method = XConstantField() - #_warn_if_fields_use_different_meshes(self.fields.values()) + # _warn_if_fields_use_different_meshes(self.fields.values()) def add_context(self, name, value): """Add context variable to the FieldSet. @@ -376,7 +376,7 @@ def _warn_if_fields_use_different_meshes(fields: Iterable[Field | VectorField]): The fields to check for conflicting meshes. Warns - ------ + ----- FieldSetWarning If the fields have different meshes on the underlying grids. """ From 413b73ad1cd85c3e1c917050e13062a7cb273a9f Mon Sep 17 00:00:00 2001 From: Wyatt Sieminski Date: Tue, 21 Jul 2026 10:48:14 -0400 Subject: [PATCH 4/4] Added mesh warning to add_constant_field and revised test suite to only combine/create FieldSets with the same underlying mesh --- src/parcels/_core/fieldset.py | 4 ++-- tests/test_fieldset.py | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/parcels/_core/fieldset.py b/src/parcels/_core/fieldset.py index 5d597a00c..232ca2724 100644 --- a/src/parcels/_core/fieldset.py +++ b/src/parcels/_core/fieldset.py @@ -219,7 +219,7 @@ def add_constant_field(self, name: str, value, mesh: ptyping.Mesh = "spherical") self.reconstruct_fields() field = getattr(self, name) field.interp_method = XConstantField() - # _warn_if_fields_use_different_meshes(self.fields.values()) + _warn_if_fields_use_different_meshes(self.fields.values()) def add_context(self, name, value): """Add context variable to the FieldSet. @@ -385,7 +385,7 @@ def _warn_if_fields_use_different_meshes(fields: Iterable[Field | VectorField]): warnings.warn( f"FieldSet has multiple different meshes: {meshes}. This may lead to unexpected behavior during execution.", category=FieldSetWarning, - stacklevel=2, + stacklevel=3, ) diff --git a/tests/test_fieldset.py b/tests/test_fieldset.py index 5ec45ac0d..bba2738c7 100644 --- a/tests/test_fieldset.py +++ b/tests/test_fieldset.py @@ -31,7 +31,7 @@ def fieldset_two_models(): fset2 = FieldSet.from_sgrid_conventions(ds2, mesh="flat", vector_fields={"UV_wind": ("U_wind", "V_wind")}) fset2.add_context("my_value", 2.0) fset2.add_context("my_list", [1, 2, "hello"]) - fset2.add_constant_field("constant_field", 3.0) + fset2.add_constant_field("constant_field", 3.0, mesh="flat") return fset1 + fset2 @@ -68,7 +68,7 @@ def test_fieldset_add_context_invalid_name(fieldset, name): def test_fieldset_add_constant_field(fieldset): - fieldset.add_constant_field("test_constant_field", 1.0) + fieldset.add_constant_field("test_constant_field", 1.0, mesh="flat") # Get a point in the domain time = ds["time"].mean() @@ -85,7 +85,7 @@ def test_fieldset_gridset(fieldset): assert fieldset.fields["UV"].grid in fieldset.gridset assert len(fieldset.gridset) == 1 - fieldset.add_constant_field("constant_field", 1.0) + fieldset.add_constant_field("constant_field", 1.0, mesh="flat") assert len(fieldset.gridset) == 2 @@ -232,7 +232,7 @@ def test_fieldset_time_interval(): field2 = Field("field2", ds2["U_A_grid"], grid2, interp_method=XLinear) fieldset = FieldSet([field1, field2]) - fieldset.add_constant_field("constant_field", 1.0) + fieldset.add_constant_field("constant_field", 1.0, mesh="flat") assert fieldset.time_interval.left == np.datetime64("2000-01-02") assert fieldset.time_interval.right == np.datetime64("2001-01-01")