Skip to content

(vector)field evaluation breaking for fields without time dimension #2735

Description

@erikvansebille

Parcels version

v4

Description

If a fieldset has a combination of fields with and without time (on the same lon/lat grid), then evaluating the field without time fails. This occurs for Fields as well as VectorFields

Code sample

def test_vectorfields_without_time():
    """Test that vector fields without a time dimension can be evaluated."""
    ds1 = datasets_structured["ds_2d_left"][["U_A_grid", "V_A_grid", "grid"]].rename({"U_A_grid": "U", "V_A_grid": "V"})
    ds2 = ds1.isel(time=0).drop_vars("time").rename({"U": "U_const", "V": "V_const"})
    ds = xr.merge([ds1, ds2])

    fset = FieldSet.from_sgrid_conventions(ds, mesh="flat", vector_fields={"UV_const": ("U_const", "V_const")})
    fset.UV_const.eval(time=0, z=0, y=0, x=0)
    fset.U_const.eval(time=0, z=0, y=0, x=0)
______________________________________________________________ test_vectorfields_without_time ______________________________________________________________

    def test_vectorfields_without_time():
        """Test that vector fields can be created from datasets without a time dimension."""
        ds = datasets_structured["ds_2d_left"][["U_A_grid", "V_A_grid", "grid"]].rename({"U_A_grid": "U", "V_A_grid": "V"})
        ds2 = ds.isel(time=0).drop_vars("time").rename({"U": "U_const", "V": "V_const"})
        ds = xr.merge([ds, ds2])
    
        fset = FieldSet.from_sgrid_conventions(ds, mesh="flat", vector_fields={"UV_const": ("U_const", "V_const")})
>       fset.UV_const.eval(time=0, z=0, y=0, x=0)

tests/test_fieldset.py:354: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
src/parcels/_core/field.py:280: in eval
    particle_positions, grid_positions = _get_positions(self.U, time, z, y, x, particles, _ei)
                                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
src/parcels/_core/field.py:394: in _get_positions
    grid_positions.update(_search_time_index(field, time))
                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
src/parcels/_core/index_search.py:88: in _search_time_index
    time_flt = timedelta_to_float(field.data.time.data - field.time_interval.left)
                                  ^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <xarray.DataArray 'U_const' (mockT: 1, ZG: 90, YG: 60, XG: 30)> Size: 1MB
array([[[[0.2756942 , 0.02738098, 0.84066951...074
    lon      (XG) float64 240B 0.0 0.2094 0.4189 0.6283 ... 5.655 5.864 6.074
Dimensions without coordinates: mockT
name = 'time'

    def __getattr__(self, name: str) -> Any:
        if name not in {"__dict__", "__setstate__"}:
            # this avoids an infinite loop when pickle looks for the
            # __setstate__ attribute before the xarray object is initialized
            for source in self._attr_sources:
                with suppress(KeyError):
                    return source[name]
>       raise AttributeError(
            f"{type(self).__name__!r} object has no attribute {name!r}"
        )
E       AttributeError: 'DataArray' object has no attribute 'time'

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    Status
    Backlog

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions