Skip to content
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions parcels/_index_search.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
# from .grid import Grid


def _search_time_index(field: Field, time: datetime, allow_time_extrapolation=True):
def _search_time_index(field: Field, time: datetime):
"""Find and return the index and relative coordinate in the time array associated with a given time.

Parameters
Expand All @@ -37,8 +37,12 @@ def _search_time_index(field: Field, time: datetime, allow_time_extrapolation=Tr
Note that we normalize to either the first or the last index
if the sampled value is outside the time value range.
"""
if not allow_time_extrapolation and (time < field.data.time[0] or time > field.data.time[-1]):
if field.time_interval is None:
return 0

if time in field.time_interval:
_raise_time_extrapolation_error(time, field=None)

time_index = field.data.time <= time

if time_index.all():
Expand Down
12 changes: 5 additions & 7 deletions parcels/field.py
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,6 @@ def __init__(
grid: ux.Grid | Grid,
mesh_type: Mesh = "flat",
interp_method: Callable | None = None,
allow_time_extrapolation: bool | None = None,
):
if not isinstance(data, (ux.UxDataArray, xr.DataArray)):
raise ValueError(
Expand Down Expand Up @@ -209,10 +208,9 @@ def __init__(
else:
raise ValueError("Unsupported mesh type in data array attributes. Choose either: 'spherical' or 'flat'")

if allow_time_extrapolation is None:
self.allow_time_extrapolation = True if len(getattr(self.data, "time", [])) == 1 else False
else:
self.allow_time_extrapolation = allow_time_extrapolation
# Check if time is in self.data.dims
Comment thread
fluidnumericsJoe marked this conversation as resolved.
Outdated
if "time" not in self.data.dims:
raise ValueError("Field is missing a 'time' dimension. ")

def __repr__(self):
return field_repr(self)
Expand Down Expand Up @@ -366,7 +364,7 @@ def _search_indices_structured(self, z, y, x, ei=None, search2D=False):
return (zeta, eta, xsi, zi, yi, xi)

def _search_indices(self, time: datetime, z, y, x, ei=None, search2D=False):
tau, ti = _search_time_index(self, time, self.allow_time_extrapolation)
tau, ti = _search_time_index(self, time)

if ei is None:
_ei = None
Expand Down Expand Up @@ -679,7 +677,7 @@ def _assert_compatible_combination(data: xr.DataArray | ux.UxDataArray, grid: ux


def get_time_interval(data: xr.DataArray | ux.UxDataArray) -> TimeInterval | None:
if "time" not in data.dims:
if len(data.time) == 1:
return None

return TimeInterval(data.time.values[0], data.time.values[-1])
Expand Down
3 changes: 2 additions & 1 deletion parcels/fieldset.py
Original file line number Diff line number Diff line change
Expand Up @@ -164,14 +164,15 @@ def add_constant_field(self, name: str, value, mesh: Mesh = "flat"):
"""
da = xr.DataArray(
data=np.full((1, 1, 1, 1), value),
dims=["T", "ZG", "YG", "XG"],
dims=["time", "ZG", "YG", "XG"],
coords={
"ZG": (["ZG"], np.arange(1), {"axis": "Z"}),
"YG": (["YG"], np.arange(1), {"axis": "Y"}),
"XG": (["XG"], np.arange(1), {"axis": "X"}),
"lon": (["XG"], np.arange(1), {"axis": "X"}),
"lat": (["YG"], np.arange(1), {"axis": "Y"}),
"depth": (["ZG"], np.arange(1), {"axis": "Z"}),
"time": (["time"], np.arange(1), {"axis": "T"}),
},
)
grid = Grid(da)
Expand Down
12 changes: 6 additions & 6 deletions parcels/particleset.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,9 @@
from tqdm import tqdm

from parcels._compat import MPI
from parcels._core.utils.time import TimeInterval
from parcels._reprs import particleset_repr
from parcels.application_kernels.advection import AdvectionRK4
from parcels.field import Field
from parcels.grid import GridType
from parcels.interaction.interactionkernel import InteractionKernel
from parcels.interaction.neighborsearch import (
Expand Down Expand Up @@ -162,8 +162,8 @@ def ArrayClass_init(self, *args, **kwargs):
raise NotImplementedError("If fieldset.time_origin is not a date, time of a particle must be a double")
time = np.array([self.time_origin.reltime(t) if _convert_to_reltime(t) else t for t in time])
assert lon.size == time.size, "time and positions (lon, lat, depth) do not have the same lengths."
if isinstance(fieldset.U, Field) and (not fieldset.U.allow_time_extrapolation):
_warn_particle_times_outside_fieldset_time_bounds(time, fieldset.U.grid.time)
if fieldset.time_interval:
_warn_particle_times_outside_fieldset_time_bounds(time, fieldset.time_interval)

if lonlatdepth_dtype is None:
lonlatdepth_dtype = self.lonlatdepth_dtype_from_field_interp_method(fieldset.U)
Expand Down Expand Up @@ -1127,17 +1127,17 @@ def _warn_outputdt_release_desync(outputdt: float, starttime: float, release_tim
)


def _warn_particle_times_outside_fieldset_time_bounds(release_times: np.ndarray, time: np.ndarray):
def _warn_particle_times_outside_fieldset_time_bounds(release_times: np.ndarray, time: np.ndarray | TimeInterval):
if np.any(release_times):
if np.any(release_times < time[0]):
warnings.warn(
"Some particles are set to be released before the fieldset's first time and allow_time_extrapolation is set to False.",
"Some particles are set to be released outside the FieldSet's executable time domain.",
ParticleSetWarning,
stacklevel=2,
)
if np.any(release_times > time[-1]):
warnings.warn(
"Some particles are set to be released after the fieldset's last time and allow_time_extrapolation is set to False.",
"Some particles are set to be released after the fieldset's last time and the fields are not constant in time.",
ParticleSetWarning,
stacklevel=2,
)