From 2955bca0b479ecc9bb331a35ebe3f85371ee8c43 Mon Sep 17 00:00:00 2001 From: Joeperdefloep Date: Mon, 8 Feb 2021 21:22:17 +0100 Subject: [PATCH 01/33] added a main_clock with dimension 'mclock' to initialize context, this returns a xr.DataArray. However, I cannot set xs.variables in the initialize step: 'AttributeError: cannot set attribute' --- xsimlab/drivers.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/xsimlab/drivers.py b/xsimlab/drivers.py index 0d8a5d47..afb19a53 100644 --- a/xsimlab/drivers.py +++ b/xsimlab/drivers.py @@ -28,6 +28,7 @@ class RuntimeContext(Mapping[str, Any]): "batch", "sim_start", "sim_end", + "main_clock", "step", "nsteps", "step_start", @@ -155,12 +156,16 @@ def _generate_runtime_datasets(dataset): """ mclock_dim = dataset.xsimlab.master_clock_dim + + # prevent non-index coordinates be included mclock_coord = dataset[mclock_dim].reset_coords(drop=True) init_data_vars = { "_sim_start": mclock_coord[0], "_nsteps": dataset.xsimlab.nsteps, + #since we pass a dataset, we need to set the coords + "mclock": dataset.coords[mclock_dim].data, "_sim_end": mclock_coord[-1], } @@ -327,6 +332,7 @@ def _run( sim_start=ds_init["_sim_start"].values, nsteps=ds_init["_nsteps"].values, sim_end=ds_init["_sim_end"].values, + main_clock=ds_init["mclock"], ) in_vars = _get_input_vars(ds_init, model) From 770d1ec2bb8796e25654f4d67c3301dc678b0847 Mon Sep 17 00:00:00 2001 From: Joeperdefloep Date: Mon, 8 Feb 2021 21:51:43 +0100 Subject: [PATCH 02/33] fixed black --- xsimlab/drivers.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/xsimlab/drivers.py b/xsimlab/drivers.py index afb19a53..7796ce53 100644 --- a/xsimlab/drivers.py +++ b/xsimlab/drivers.py @@ -156,15 +156,13 @@ def _generate_runtime_datasets(dataset): """ mclock_dim = dataset.xsimlab.master_clock_dim - - # prevent non-index coordinates be included mclock_coord = dataset[mclock_dim].reset_coords(drop=True) init_data_vars = { "_sim_start": mclock_coord[0], "_nsteps": dataset.xsimlab.nsteps, - #since we pass a dataset, we need to set the coords + # since we pass a dataset, we need to set the coords "mclock": dataset.coords[mclock_dim].data, "_sim_end": mclock_coord[-1], } From 7b0326eba48694eb6c11ce3dec8476d79bb7a560 Mon Sep 17 00:00:00 2001 From: Joeperdefloep Date: Tue, 9 Feb 2021 00:13:45 +0100 Subject: [PATCH 03/33] changed 'master' to 'main' everywhere except in non-breaking testcases. --- .vscode/settings.json | 3 + doc/api.rst | 4 +- doc/io_storage.rst | 2 +- doc/run_model.rst | 10 +-- xsimlab/drivers.py | 14 +-- xsimlab/ipython.py | 2 +- xsimlab/stores.py | 2 +- xsimlab/tests/fixture_model.py | 2 +- xsimlab/tests/test_drivers.py | 2 +- xsimlab/tests/test_ipython.py | 4 +- xsimlab/tests/test_xr_accessor.py | 32 +++---- xsimlab/xr_accessor.py | 143 +++++++++++++++++------------- 12 files changed, 119 insertions(+), 101 deletions(-) create mode 100644 .vscode/settings.json diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 00000000..233aa52f --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "python.pythonPath": "/home/joempie/miniconda3/envs/simlab-dev/bin/python" +} \ No newline at end of file diff --git a/doc/api.rst b/doc/api.rst index 6b286a80..63733318 100644 --- a/doc/api.rst +++ b/doc/api.rst @@ -42,8 +42,8 @@ properties listed below. Proper use of this accessor should be like: Dataset.xsimlab.clock_coords Dataset.xsimlab.clock_sizes - Dataset.xsimlab.master_clock_dim - Dataset.xsimlab.master_clock_coord + Dataset.xsimlab.main_clock_dim + Dataset.xsimlab.main_clock_coord Dataset.xsimlab.nsteps Dataset.xsimlab.output_vars Dataset.xsimlab.output_vars_by_clock diff --git a/doc/io_storage.rst b/doc/io_storage.rst index 293ee888..6a50a675 100644 --- a/doc/io_storage.rst +++ b/doc/io_storage.rst @@ -43,7 +43,7 @@ one used in Section :doc:`run_model`: 'time': np.linspace(0., 1., 101), 'otime': [0, 0.5, 1] }, - master_clock='time', + main_clock='time', input_vars={ 'grid': {'length': 1.5, 'spacing': 0.01}, 'init': {'loc': 0.3, 'scale': 0.1}, diff --git a/doc/run_model.rst b/doc/run_model.rst index a055f03a..e9910c1f 100644 --- a/doc/run_model.rst +++ b/doc/run_model.rst @@ -52,7 +52,7 @@ create a new setup in a very declarative way: 'time': np.linspace(0., 1., 101), 'otime': [0, 0.5, 1] }, - master_clock='time', + main_clock='time', input_vars={ 'grid': {'length': 1.5, 'spacing': 0.01}, 'init': {'loc': 0.3, 'scale': 0.1}, @@ -72,7 +72,7 @@ A setup consists in: - one or more time dimensions ("clocks") and their given coordinate values ; -- one of these time dimensions, defined as master clock, which will be +- one of these time dimensions, defined as main clock, which will be used to define the simulation time steps (the other time dimensions usually serve to take snapshots during a simulation on a different but synchronized clock) ; @@ -81,7 +81,7 @@ A setup consists in: clocks (time dimension) or just once at the end of the simulation (``None``). -In the example above, we set ``time`` as the master clock dimension +In the example above, we set ``time`` as the main clock dimension and ``otime`` as another dimension for taking snapshots of :math:`u` along the grid at three given times of the simulation (beginning, middle and end). @@ -225,7 +225,7 @@ for the ``otime`` coordinate (which serves to take snapshots of clocks = {'otime': [0, 0.25, 0.5]} with advect_model: out_ds3 = (in_ds.xsimlab.update_clocks(clocks=clocks, - master_clock='time') + main_clock='time') .xsimlab.run()) @savefig run_advect_model_clock.png width=100% out_ds3.profile__u.plot(col='otime', figsize=(9, 3)); @@ -258,7 +258,7 @@ Time-varying input values ------------------------- Except for static variables, all model inputs accept arrays which have a -dimension that corresponds to the master clock. This is useful for adding +dimension that corresponds to the main clock. This is useful for adding external forcing. The example below is based on the last example above, but instead of diff --git a/xsimlab/drivers.py b/xsimlab/drivers.py index 7796ce53..48582bfa 100644 --- a/xsimlab/drivers.py +++ b/xsimlab/drivers.py @@ -111,9 +111,9 @@ def _reset_multi_indexes(dataset): return dataset.reset_index(dims), multi_indexes -def _check_missing_master_clock(dataset): - if dataset.xsimlab.master_clock_dim is None: - raise ValueError("Missing master clock dimension / coordinate") +def _check_missing_main_clock(dataset): + if dataset.xsimlab.main_clock_dim is None: + raise ValueError("Missing main clock dimension / coordinate") def _check_missing_inputs(dataset, model): @@ -154,7 +154,7 @@ def _generate_runtime_datasets(dataset): Runtime data is added to those datasets. """ - mclock_dim = dataset.xsimlab.master_clock_dim + mclock_dim = dataset.xsimlab.main_clock_dim # prevent non-index coordinates be included mclock_coord = dataset[mclock_dim].reset_coords(drop=True) @@ -190,7 +190,7 @@ def _maybe_transpose(dataset, model, check_dims, batch_dim): """Check and maybe re-order the dimensions of model input variables in the input dataset. - Dimensions are re-ordered like this: (, , *model var dims) + Dimensions are re-ordered like this: (,
, *model var dims) Raise an error if dimensions found in the dataset are not valid or could not be transposed. @@ -210,7 +210,7 @@ def _maybe_transpose(dataset, model, check_dims, batch_dim): # all valid dimensions in the right order dims = [list(d) for d in model.cache[var_key]["metadata"]["dims"]] - dims += [[dataset.xsimlab.master_clock_dim] + d for d in dims] + dims += [[dataset.xsimlab.main_clock_dim] + d for d in dims] if batch_dim is not None: dims += [[batch_dim] + d for d in dims] @@ -408,7 +408,7 @@ def __init__( self.dataset, self.multi_indexes = _reset_multi_indexes(dataset) - _check_missing_master_clock(self.dataset) + _check_missing_main_clock(self.dataset) _check_missing_inputs(self.dataset, model) self.batch_dim = batch_dim diff --git a/xsimlab/ipython.py b/xsimlab/ipython.py index 947eecdd..f7177a79 100644 --- a/xsimlab/ipython.py +++ b/xsimlab/ipython.py @@ -41,7 +41,7 @@ def format_var_comment(var, verbose=0): if var_dims: comment += f"# dimensions: {var_dims}\n" if var.metadata["static"]: - comment += f"# static: master clock dimension not supported\n" + comment += f"# static: main clock dimension not supported\n" if verbose > 2: var_attrs = var.metadata.get("attrs", False) diff --git a/xsimlab/stores.py b/xsimlab/stores.py index 353ade7d..7a15402c 100644 --- a/xsimlab/stores.py +++ b/xsimlab/stores.py @@ -139,7 +139,7 @@ def __init__( self.batch_dim = batch_dim self.batch_size = get_batch_size(dataset, batch_dim) - self.mclock_dim = dataset.xsimlab.master_clock_dim + self.mclock_dim = dataset.xsimlab.main_clock_dim self.clock_sizes = dataset.xsimlab.clock_sizes # initialize clock incrementers diff --git a/xsimlab/tests/fixture_model.py b/xsimlab/tests/fixture_model.py index 781c853c..0654dd12 100644 --- a/xsimlab/tests/fixture_model.py +++ b/xsimlab/tests/fixture_model.py @@ -133,7 +133,7 @@ def simple_model_repr(): @pytest.fixture def in_dataset(): clock_key = SimlabAccessor._clock_key - mclock_key = SimlabAccessor._master_clock_key + mclock_key = SimlabAccessor._main_clock_key svars_key = SimlabAccessor._output_vars_key ds = xr.Dataset() diff --git a/xsimlab/tests/test_drivers.py b/xsimlab/tests/test_drivers.py index 90d1ac76..2adec338 100644 --- a/xsimlab/tests/test_drivers.py +++ b/xsimlab/tests/test_drivers.py @@ -86,7 +86,7 @@ def test_get_input_vars_scalar(in_dataset, model, value, is_scalar): class TestXarraySimulationDriver: def test_constructor(self, in_dataset, model): invalid_ds = in_dataset.drop("clock") - with pytest.raises(ValueError, match=r"Missing master clock.*"): + with pytest.raises(ValueError, match=r"Missing main clock.*"): XarraySimulationDriver(invalid_ds, model) invalid_ds = in_dataset.drop("init_profile__n_points") diff --git a/xsimlab/tests/test_ipython.py b/xsimlab/tests/test_ipython.py index 13abfd98..281d12ba 100644 --- a/xsimlab/tests/test_ipython.py +++ b/xsimlab/tests/test_ipython.py @@ -143,7 +143,7 @@ def test_create_setup_magic_error(ip): input_vars={ # v1 description # dimensions: ('x',) - # static: master clock dimension not supported + # static: main clock dimension not supported 'foo__v1': , # v2 description 'foo__v2': , @@ -164,7 +164,7 @@ def test_create_setup_magic_error(ip): input_vars={ # v1 description # dimensions: ('x',) - # static: master clock dimension not supported + # static: main clock dimension not supported 'foo__v1': , # v2 description # units: m diff --git a/xsimlab/tests/test_xr_accessor.py b/xsimlab/tests/test_xr_accessor.py index 2b019ddf..26683cea 100644 --- a/xsimlab/tests/test_xr_accessor.py +++ b/xsimlab/tests/test_xr_accessor.py @@ -113,7 +113,7 @@ def test_flatten_outputs_error(): class TestSimlabAccessor: _clock_key = xr_accessor.SimlabAccessor._clock_key - _master_clock_key = xr_accessor.SimlabAccessor._master_clock_key + _main_clock_key = xr_accessor.SimlabAccessor._main_clock_key _output_vars_key = xr_accessor.SimlabAccessor._output_vars_key def test_clock_coords(self): @@ -122,7 +122,7 @@ def test_clock_coords(self): "mclock": ( "mclock", [0, 1, 2], - {self._clock_key: 1, self._master_clock_key: 1}, + {self._clock_key: 1, self._main_clock_key: 1}, ), "sclock": ("sclock", [0, 2], {self._clock_key: 1}), "no_clock": ("no_clock", [3, 4]), @@ -141,19 +141,19 @@ def test_clock_sizes(self): assert ds.xsimlab.clock_sizes == {"clock1": 3, "clock2": 2} - def test_master_clock_dim(self): - attrs = {self._clock_key: 1, self._master_clock_key: 1} + def test_main_clock_dim(self): + attrs = {self._clock_key: 1, self._main_clock_key: 1} ds = xr.Dataset(coords={"clock": ("clock", [1, 2], attrs)}) - assert ds.xsimlab.master_clock_dim == "clock" - assert ds.xsimlab._master_clock_dim == "clock" # cache - assert ds.xsimlab.master_clock_dim == "clock" # get cached value + assert ds.xsimlab.main_clock_dim == "clock" + assert ds.xsimlab._main_clock_dim == "clock" # cache + assert ds.xsimlab.main_clock_dim == "clock" # get cached value ds = xr.Dataset() - assert ds.xsimlab.master_clock_dim is None + assert ds.xsimlab.main_clock_dim is None def test_nsteps(self): - attrs = {self._clock_key: 1, self._master_clock_key: 1} + attrs = {self._clock_key: 1, self._main_clock_key: 1} ds = xr.Dataset(coords={"clock": ("clock", [1, 2, 3], attrs)}) assert ds.xsimlab.nsteps == 2 @@ -162,7 +162,7 @@ def test_nsteps(self): assert ds.xsimlab.nsteps == 0 def test_get_output_save_steps(self): - attrs = {self._clock_key: 1, self._master_clock_key: 1} + attrs = {self._clock_key: 1, self._main_clock_key: 1} ds = xr.Dataset( coords={ "clock": ("clock", [0, 1, 2, 3, 4], attrs), @@ -228,7 +228,7 @@ def test_update_clocks(self, model): ) ds = xr.Dataset() - with pytest.raises(KeyError, match="Master clock dimension name.*"): + with pytest.raises(KeyError, match="Main clock dimension name.*"): ds.xsimlab.update_clocks( model=model, clocks={"clock": [0, 1, 2]}, @@ -252,7 +252,7 @@ def test_update_clocks(self, model): ds = xr.Dataset() ds = ds.xsimlab.update_clocks(model=model, clocks={"clock": [0, 1, 2]}) - assert ds.xsimlab.master_clock_dim == "clock" + assert ds.xsimlab.main_clock_dim == "clock" ds.clock.attrs[self._output_vars_key] = "profile__u" @@ -275,13 +275,13 @@ def test_update_clocks(self, model): clocks={"clock2": [0, 0.5, 1, 1.5, 2]}, master_clock="clock2", ) - assert new_ds.xsimlab.master_clock_dim == "clock2" + assert new_ds.xsimlab.main_clock_dim == "clock2" new_ds = ds.xsimlab.update_clocks(model=model, clocks={"out2": [0, 2]}) - assert new_ds.xsimlab.master_clock_dim == "clock" + assert new_ds.xsimlab.main_clock_dim == "clock" new_ds = ds.xsimlab.update_clocks(model=model, clocks={"clock": [0, 2, 4]}) - assert new_ds.xsimlab.master_clock_dim == "clock" + assert new_ds.xsimlab.main_clock_dim == "clock" np.testing.assert_array_equal(new_ds.clock.values, [0, 2, 4]) def test_update_vars(self, model, in_dataset): @@ -333,7 +333,7 @@ def test_set_output_vars(self, model): ds["clock"] = ( "clock", [0, 2, 4, 6, 8], - {self._clock_key: 1, self._master_clock_key: 1}, + {self._clock_key: 1, self._main_clock_key: 1}, ) ds["out"] = ("out", [0, 4, 8], {self._clock_key: 1}) ds["not_a_clock"] = ("not_a_clock", [0, 1]) diff --git a/xsimlab/xr_accessor.py b/xsimlab/xr_accessor.py index dbbe2af8..a372e2da 100644 --- a/xsimlab/xr_accessor.py +++ b/xsimlab/xr_accessor.py @@ -128,12 +128,12 @@ class SimlabAccessor: """Simlab extension to :class:`xarray.Dataset`.""" _clock_key = "__xsimlab_output_clock__" - _master_clock_key = "__xsimlab_master_clock__" + _main_clock_key = "__xsimlab_main_clock__" _output_vars_key = "__xsimlab_output_vars__" def __init__(self, ds): self._ds = ds - self._master_clock_dim = None + self._main_clock_dim = None self._clock_coords = None @property @@ -161,9 +161,9 @@ def clock_sizes(self): return Frozen({k: coord.size for k, coord in self.clock_coords.items()}) @property - def master_clock_dim(self): - """Dimension used as master clock for model runs. Returns None - if no dimension is set as master clock. + def main_clock_dim(self): + """Dimension used as main clock for model runs. Returns None + if no dimension is set as main clock. See Also -------- @@ -171,39 +171,39 @@ def master_clock_dim(self): """ # it is fine to cache the value here as inconsistency may appear - # only when deleting the master clock coordinate from the dataset, + # only when deleting the main clock coordinate from the dataset, # which would raise early anyway - if self._master_clock_dim is not None: - return self._master_clock_dim + if self._main_clock_dim is not None: + return self._main_clock_dim else: for c in self._ds.coords.values(): - if c.attrs.get(self._master_clock_key, False): + if c.attrs.get(self._main_clock_key, False): dim = c.dims[0] - self._master_clock_dim = dim + self._main_clock_dim = dim return dim return None @property - def master_clock_coord(self): - """Master clock coordinate (as a :class:`xarray.DataArray` object). + def main_clock_coord(self): + """Main clock coordinate (as a :class:`xarray.DataArray` object). - Returns None if no master clock is defined in the dataset. + Returns None if no main clock is defined in the dataset. """ - return self._ds.get(self.master_clock_dim) + return self._ds.get(self.main_clock_dim) @property def nsteps(self): """Number of simulation steps, computed from the master clock coordinate. - Returns 0 if no master clock is defined in the dataset. + Returns 0 if no main clock is defined in the dataset. """ - if self.master_clock_dim is None: + if self.main_clock_dim is None: return 0 else: - return self._ds[self.master_clock_dim].size - 1 + return self._ds[self.main_clock_dim].size - 1 def get_output_save_steps(self): """Returns save steps for each clock as boolean values. @@ -212,16 +212,16 @@ def get_output_save_steps(self): ------- save_steps : :class:`xarray.Dataset` A new Dataset with boolean data variables for each clock - dimension other than the master clock, where values specify + dimension other than the main clock, where values specify whether or not to save outputs at every step of a simulation. """ - ds = Dataset(coords={self.master_clock_dim: self.master_clock_coord}) + ds = Dataset(coords={self.main_clock_dim: self.main_clock_coord}) for clock, coord in self.clock_coords.items(): - if clock != self.master_clock_dim: - save_steps = np.in1d(self.master_clock_coord.values, coord.values) - ds[clock] = (self.master_clock_dim, save_steps) + if clock != self.main_clock_dim: + save_steps = np.in1d(self.main_clock_coord.values, coord.values) + ds[clock] = (self.main_clock_dim, save_steps) return ds @@ -242,26 +242,26 @@ def _set_clock_coord(self, dim, data): def _uniformize_clock_coords(self, dim=None, units=None, calendar=None): """Ensure consistency across all clock coordinates. - - maybe update master clock dimension + - maybe update main clock dimension - maybe set or update the same units and/or calendar for all coordinates as attributes - - check that all clocks are synchronized with master clock, i.e., - there is no coordinate label that is not present in master clock + - check that all clocks are synchronized with main clock, i.e., + there is no coordinate label that is not present in main clock """ if dim is not None: - if self.master_clock_dim is not None: - old_mclock_coord = self._ds[self.master_clock_dim] - old_mclock_coord.attrs.pop(self._master_clock_key) + if self.main_clock_dim is not None: + old_mclock_coord = self._ds[self.main_clock_dim] + old_mclock_coord.attrs.pop(self._main_clock_key) if dim not in self._ds.coords: raise KeyError( - f"Master clock dimension name {dim} as no " + f"Main clock dimension name {dim} as no " "defined coordinate in Dataset" ) - self._ds[dim].attrs[self._master_clock_key] = np.uint8(True) - self._master_clock_dim = dim + self._ds[dim].attrs[self._main_clock_key] = np.uint8(True) + self._main_clock_dim = dim if units is not None: for coord in self.clock_coords.values(): @@ -271,21 +271,21 @@ def _uniformize_clock_coords(self, dim=None, units=None, calendar=None): for coord in self.clock_coords.values(): coord.attrs["calendar"] = calendar - master_clock_idx = self._ds.indexes.get(self.master_clock_dim) + main_clock_idx = self._ds.indexes.get(self.main_clock_dim) for clock_dim in self.clock_coords: - if clock_dim == self.master_clock_dim: + if clock_dim == self.main_clock_dim: continue clock_idx = self._ds.indexes[clock_dim] - diff_idx = clock_idx.difference(master_clock_idx) + diff_idx = clock_idx.difference(main_clock_idx) if diff_idx.size: raise ValueError( f"Clock coordinate {clock_dim} is not synchronized " - f"with master clock coordinate {self.master_clock_dim}. " + f"with main clock coordinate {self.main_clock_dim}. " "The following coordinate labels are " - f"absent in master clock: {diff_idx.values}" + f"absent in main clock: {diff_idx.values}" ) def _set_input_vars(self, model, input_vars): @@ -460,7 +460,9 @@ def output_vars_by_clock(self): return Frozen(dict(o_vars)) - def update_clocks(self, model=None, clocks=None, master_clock=None): + def update_clocks( + self, model=None, clocks=None, main_clock=None, master_clock=None + ): """Set or update clock coordinates. Also copy from the replaced coordinates any attribute that is @@ -475,16 +477,17 @@ def update_clocks(self, model=None, clocks=None, master_clock=None): values are anything that can be easily converted to :class:`xarray.IndexVariable` objects (e.g., a 1-d :class:`numpy.ndarray` or a :class:`pandas.Index`). - master_clock : str or dict, optional - Name of the clock coordinate (dimension) to use as master clock. + main_clock : str or dict, optional + Name of the clock coordinate (dimension) to use as main clock. If not set, the name is inferred from ``clocks`` (only if - one coordinate is given and if Dataset has no master clock + one coordinate is given and if Dataset has no main clock defined yet). A dictionary can also be given with one of several of these keys: - - ``dim`` : name of the master clock dimension/coordinate + - ``dim`` : name of the main clock dimension/coordinate - ``units`` : units of all clock coordinate labels - ``calendar`` : a unique calendar for all (time) clock coordinates + master_clock : same as `main_clock`, to be deprecated Returns ------- @@ -500,42 +503,44 @@ def update_clocks(self, model=None, clocks=None, master_clock=None): ds = self._ds.copy() - if isinstance(master_clock, str): - master_clock_dict = {"dim": master_clock} + if master_clock is not None: + warnings.warn( + "master_clock is to be deprecated in favour ofmain_clock", + FutureWarning, + ) + main_clock = master_clock - elif master_clock is None: - if ( - clocks is not None - and len(clocks) == 1 - and self.master_clock_dim is None - ): - master_clock_dict = {"dim": list(clocks.keys())[0]} + if isinstance(main_clock, str): + main_clock_dict = {"dim": main_clock} + + elif main_clock is None: + if clocks is not None and len(clocks) == 1 and self.main_clock_dim is None: + main_clock_dict = {"dim": list(clocks.keys())[0]} else: - master_clock_dict = {"dim": self.master_clock_dim} + main_clock_dict = {"dim": self.main_clock_dim} else: - master_clock_dict = master_clock + main_clock_dict = main_clock - master_clock_dim = master_clock_dict.get("dim", self.master_clock_dim) + main_clock_dim = main_clock_dict.get("dim", self.main_clock_dim) if clocks is not None: - if master_clock_dim is None: + if main_clock_dim is None: raise ValueError( - "Cannot determine which clock coordinate is the master clock" + "Cannot determine which clock coordinate is the main clock" ) elif ( - master_clock_dim not in clocks - and master_clock_dim not in self.clock_coords + main_clock_dim not in clocks and main_clock_dim not in self.clock_coords ): raise KeyError( - f"Master clock dimension name {master_clock_dim!r} not found " + f"Main clock dimension name {main_clock_dim!r} not found " "in `clocks` nor in Dataset" ) for dim, data in clocks.items(): ds.xsimlab._set_clock_coord(dim, data) - ds.xsimlab._uniformize_clock_coords(**master_clock_dict) + ds.xsimlab._uniformize_clock_coords(**main_clock_dict) # operations on clock coords may have discarded coord attributes o_vars = {k: v for k, v in self.output_vars.items() if v is None or v in ds} @@ -829,6 +834,7 @@ def create_setup( model=None, clocks=None, master_clock=None, + main_clock=None, input_vars=None, output_vars=None, fill_default=True, @@ -850,14 +856,16 @@ def create_setup( values are anything that can be easily converted to :class:`xarray.IndexVariable` objects (e.g., a 1-d :class:`numpy.ndarray` or a :class:`pandas.Index`). - master_clock : str or dict, optional - Name of the clock coordinate (dimension) to use as master clock. + master_clock: str or dict, optional + Seemain_clock to be deprecated + main_clock : str or dict, optional + Name of the clock coordinate (dimension) to use as main clock. If not set, the name is inferred from ``clocks`` (only if - one coordinate is given and if Dataset has no master clock + one coordinate is given and if Dataset has no main clock defined yet). A dictionary can also be given with one of several of these keys: - - ``dim`` : name of the master clock dimension/coordinate + - ``dim`` : name of the main clock dimension/coordinate - ``units`` : units of all clock coordinate labels - ``calendar`` : a unique calendar for all (time) clock coordinates input_vars : dict, optional @@ -911,9 +919,16 @@ def maybe_fill_default(ds): else: return ds + if master_clock is not None: + warnings.warn( + "master_clock is to be deprecated in favour ofmain_clock", + FutureWarning, + ) + main_clock = master_clock + ds = ( Dataset() - .xsimlab.update_clocks(model=model, clocks=clocks, master_clock=master_clock) + .xsimlab.update_clocks(model=model, clocks=clocks, main_clock=main_clock) .pipe(maybe_fill_default) .xsimlab.update_vars( model=model, input_vars=input_vars, output_vars=output_vars From 7384b4700624635bfb1f83efbf70b9f7ec44a1e6 Mon Sep 17 00:00:00 2001 From: Joeperdefloep Date: Tue, 9 Feb 2021 00:21:00 +0100 Subject: [PATCH 04/33] fixed space and undid changes of access-clock --- xsimlab/drivers.py | 3 --- xsimlab/xr_accessor.py | 6 +++--- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/xsimlab/drivers.py b/xsimlab/drivers.py index 48582bfa..a285dafc 100644 --- a/xsimlab/drivers.py +++ b/xsimlab/drivers.py @@ -162,8 +162,6 @@ def _generate_runtime_datasets(dataset): init_data_vars = { "_sim_start": mclock_coord[0], "_nsteps": dataset.xsimlab.nsteps, - # since we pass a dataset, we need to set the coords - "mclock": dataset.coords[mclock_dim].data, "_sim_end": mclock_coord[-1], } @@ -330,7 +328,6 @@ def _run( sim_start=ds_init["_sim_start"].values, nsteps=ds_init["_nsteps"].values, sim_end=ds_init["_sim_end"].values, - main_clock=ds_init["mclock"], ) in_vars = _get_input_vars(ds_init, model) diff --git a/xsimlab/xr_accessor.py b/xsimlab/xr_accessor.py index a372e2da..640652e2 100644 --- a/xsimlab/xr_accessor.py +++ b/xsimlab/xr_accessor.py @@ -505,7 +505,7 @@ def update_clocks( if master_clock is not None: warnings.warn( - "master_clock is to be deprecated in favour ofmain_clock", + "master_clock is to be deprecated in favour of main_clock", FutureWarning, ) main_clock = master_clock @@ -857,7 +857,7 @@ def create_setup( :class:`xarray.IndexVariable` objects (e.g., a 1-d :class:`numpy.ndarray` or a :class:`pandas.Index`). master_clock: str or dict, optional - Seemain_clock to be deprecated + See main_clock to be deprecated main_clock : str or dict, optional Name of the clock coordinate (dimension) to use as main clock. If not set, the name is inferred from ``clocks`` (only if @@ -921,7 +921,7 @@ def maybe_fill_default(ds): if master_clock is not None: warnings.warn( - "master_clock is to be deprecated in favour ofmain_clock", + "master_clock is to be deprecated in favour of main_clock", FutureWarning, ) main_clock = master_clock From d8165be59e2d0fe6ca1e2295e5def9b7d2343da5 Mon Sep 17 00:00:00 2001 From: Joeperdefloep Date: Tue, 9 Feb 2021 00:47:59 +0100 Subject: [PATCH 05/33] added placeholder --- .vscode/settings.json | 3 +++ xsimlab/__init__.py | 1 + xsimlab/drivers.py | 5 +++-- 3 files changed, 7 insertions(+), 2 deletions(-) create mode 100644 .vscode/settings.json diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 00000000..233aa52f --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "python.pythonPath": "/home/joempie/miniconda3/envs/simlab-dev/bin/python" +} \ No newline at end of file diff --git a/xsimlab/__init__.py b/xsimlab/__init__.py index f0399169..9b31951c 100644 --- a/xsimlab/__init__.py +++ b/xsimlab/__init__.py @@ -25,6 +25,7 @@ group_dict, ) from .xr_accessor import SimlabAccessor, create_setup +from .drivers import MAIN_CLOCK from . import monitoring from ._version import get_versions diff --git a/xsimlab/drivers.py b/xsimlab/drivers.py index 7796ce53..64342c66 100644 --- a/xsimlab/drivers.py +++ b/xsimlab/drivers.py @@ -19,6 +19,7 @@ class CheckDimsOption(Enum): STRICT = "strict" TRANSPOSE = "transpose" +MAIN_CLOCK = "_main_clock" class RuntimeContext(Mapping[str, Any]): """A mapping providing runtime information at the current time step.""" @@ -163,7 +164,7 @@ def _generate_runtime_datasets(dataset): "_sim_start": mclock_coord[0], "_nsteps": dataset.xsimlab.nsteps, # since we pass a dataset, we need to set the coords - "mclock": dataset.coords[mclock_dim].data, + MAIN_CLOCK: dataset.coords[mclock_dim].data, "_sim_end": mclock_coord[-1], } @@ -330,7 +331,7 @@ def _run( sim_start=ds_init["_sim_start"].values, nsteps=ds_init["_nsteps"].values, sim_end=ds_init["_sim_end"].values, - main_clock=ds_init["mclock"], + main_clock=ds_init[MAIN_CLOCK], ) in_vars = _get_input_vars(ds_init, model) From d2a30309c9ba8f0280dec5da83b3bbea98fbb0b4 Mon Sep 17 00:00:00 2001 From: Joeperdefloep Date: Tue, 9 Feb 2021 00:54:57 +0100 Subject: [PATCH 06/33] fixed black (again) --- xsimlab/drivers.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/xsimlab/drivers.py b/xsimlab/drivers.py index 64342c66..c636965a 100644 --- a/xsimlab/drivers.py +++ b/xsimlab/drivers.py @@ -19,8 +19,10 @@ class CheckDimsOption(Enum): STRICT = "strict" TRANSPOSE = "transpose" + MAIN_CLOCK = "_main_clock" + class RuntimeContext(Mapping[str, Any]): """A mapping providing runtime information at the current time step.""" From bc26be901c1effef792653a37b4a8506e1e69fb5 Mon Sep 17 00:00:00 2001 From: Joeperdefloep Date: Tue, 9 Feb 2021 13:34:22 +0100 Subject: [PATCH 07/33] added master_clock_dim + tests, master_clock_coords no tests --- .gitignore | 3 + xsimlab/drivers.py | 1 - xsimlab/tests/test_stores.py | 2 +- xsimlab/tests/test_xr_accessor.py | 146 ++++++++++++++++++++++++++++-- xsimlab/xr_accessor.py | 16 ++++ 5 files changed, 160 insertions(+), 8 deletions(-) diff --git a/.gitignore b/.gitignore index e881711d..0aab20cb 100644 --- a/.gitignore +++ b/.gitignore @@ -50,6 +50,9 @@ bin/ # IPython / Jupyter .ipynb_checkpoints +# VsCode +.vscode/ + # misc .DS_Store diff --git a/xsimlab/drivers.py b/xsimlab/drivers.py index a285dafc..5c8e0c00 100644 --- a/xsimlab/drivers.py +++ b/xsimlab/drivers.py @@ -28,7 +28,6 @@ class RuntimeContext(Mapping[str, Any]): "batch", "sim_start", "sim_end", - "main_clock", "step", "nsteps", "step_start", diff --git a/xsimlab/tests/test_stores.py b/xsimlab/tests/test_stores.py index a48d2ce9..ea7fa415 100644 --- a/xsimlab/tests/test_stores.py +++ b/xsimlab/tests/test_stores.py @@ -122,7 +122,7 @@ def test_write_output_vars(self, in_ds, store): ztest.add__u_diff, np.array([2.0, np.nan, np.nan]) ) - # test save master clock but not out clock + # test save main clock but not out clock store.write_output_vars(-1, 1) np.testing.assert_array_equal(ztest.profile__u[1], np.array([1.0, 2.0, 3.0])) np.testing.assert_array_equal( diff --git a/xsimlab/tests/test_xr_accessor.py b/xsimlab/tests/test_xr_accessor.py index 26683cea..edd18cef 100644 --- a/xsimlab/tests/test_xr_accessor.py +++ b/xsimlab/tests/test_xr_accessor.py @@ -152,6 +152,30 @@ def test_main_clock_dim(self): ds = xr.Dataset() assert ds.xsimlab.main_clock_dim is None + def test_master_clock_dim_warning(self): + attrs = {self._clock_key: 1, self._main_clock_key: 1} + ds = xr.Dataset(coords={"clock": ("clock", [1, 2], attrs)}) + + with pytest.warns( + FutureWarning, + match="master_clock is to be deprecated in favour of main_clock", + ): + assert ds.xsimlab.master_clock_dim == "clock" + # internally, _main_clock_dim is used + assert ds.xsimlab._main_clock_dim == "clock" # cache + with pytest.warns( + FutureWarning, + match="master_clock is to be deprecated in favour of main_clock", + ): + assert ds.xsimlab.master_clock_dim == "clock" # get cached value + + ds = xr.Dataset() + with pytest.warns( + FutureWarning, + match="master_clock is to be deprecated in favour of main_clock", + ): + assert ds.xsimlab.master_clock_dim is None + def test_nsteps(self): attrs = {self._clock_key: 1, self._main_clock_key: 1} ds = xr.Dataset(coords={"clock": ("clock", [1, 2, 3], attrs)}) @@ -232,7 +256,7 @@ def test_update_clocks(self, model): ds.xsimlab.update_clocks( model=model, clocks={"clock": [0, 1, 2]}, - master_clock="non_existing_clock_dim", + main_clock="non_existing_clock_dim", ) ds = xr.Dataset() @@ -247,7 +271,7 @@ def test_update_clocks(self, model): ds.xsimlab.update_clocks( model=model, clocks={"clock": [0, 1, 2], "out": [0, 0.5, 2]}, - master_clock="clock", + main_clock="clock", ) ds = xr.Dataset() @@ -259,7 +283,7 @@ def test_update_clocks(self, model): ds = ds.xsimlab.update_clocks( model=model, clocks={"clock": [0, 1, 2]}, - master_clock={ + main_clock={ "dim": "clock", "units": "days since 1-1-1 0:0:0", "calendar": "365_days", @@ -273,7 +297,7 @@ def test_update_clocks(self, model): new_ds = ds.xsimlab.update_clocks( model=model, clocks={"clock2": [0, 0.5, 1, 1.5, 2]}, - master_clock="clock2", + main_clock="clock2", ) assert new_ds.xsimlab.main_clock_dim == "clock2" @@ -284,6 +308,84 @@ def test_update_clocks(self, model): assert new_ds.xsimlab.main_clock_dim == "clock" np.testing.assert_array_equal(new_ds.clock.values, [0, 2, 4]) + def test_update_clocks_masterclock_warning(self, model): + ds = xr.Dataset() + with pytest.raises(ValueError, match="Cannot determine which clock.*"): + ds.xsimlab.update_clocks(model=model, clocks={}) + + ds = xr.Dataset() + with pytest.raises(ValueError, match="Cannot determine which clock.*"): + ds.xsimlab.update_clocks( + model=model, clocks={"clock": [0, 1, 2], "out": [0, 2]} + ) + + ds = xr.Dataset() + with pytest.raises(KeyError, match="Main clock dimension name.*"): + ds.xsimlab.update_clocks( + model=model, + clocks={"clock": [0, 1, 2]}, + master_clock="non_existing_clock_dim", + ) + + ds = xr.Dataset() + with pytest.raises(ValueError, match="Invalid dimension.*"): + ds.xsimlab.update_clocks( + model=model, + clocks={"clock": ("x", [0, 1, 2])}, + ) + + ds = xr.Dataset() + with pytest.raises(ValueError, match=".*not synchronized.*"): + ds.xsimlab.update_clocks( + model=model, + clocks={"clock": [0, 1, 2], "out": [0, 0.5, 2]}, + master_clock="clock", + ) + + ds = xr.Dataset() + ds = ds.xsimlab.update_clocks(model=model, clocks={"clock": [0, 1, 2]}) + assert ds.xsimlab.main_clock_dim == "clock" + + ds.clock.attrs[self._output_vars_key] = "profile__u" + + # assert that a warning is raised with correct use of update + with pytest.warns( + FutureWarning, + match="master_clock is to be deprecated in favour of main_clock", + ): + ds = ds.xsimlab.update_clocks( + model=model, + clocks={"clock": [0, 1, 2]}, + master_clock={ + "dim": "clock", + "units": "days since 1-1-1 0:0:0", + "calendar": "365_days", + }, + ) + + np.testing.assert_array_equal(ds.clock.values, [0, 1, 2]) + assert "units" in ds.clock.attrs + assert "calendar" in ds.clock.attrs + assert ds.clock.attrs[self._output_vars_key] == "profile__u" + + with pytest.warns( + FutureWarning, + match="master_clock is to be deprecated in favour of main_clock", + ): + new_ds = ds.xsimlab.update_clocks( + model=model, + clocks={"clock2": [0, 0.5, 1, 1.5, 2]}, + master_clock="clock2", + ) + assert new_ds.xsimlab.main_clock_dim == "clock2" + + new_ds = ds.xsimlab.update_clocks(model=model, clocks={"out2": [0, 2]}) + assert new_ds.xsimlab.main_clock_dim == "clock" + + new_ds = ds.xsimlab.update_clocks(model=model, clocks={"clock": [0, 2, 4]}) + assert new_ds.xsimlab.main_clock_dim == "clock" + np.testing.assert_array_equal(new_ds.clock.values, [0, 2, 4]) + def test_update_vars(self, model, in_dataset): ds = in_dataset.xsimlab.update_vars( model=model, @@ -391,7 +493,7 @@ def test_output_vars(self, model): # snapshot clock with no output variable "out2": [0, 8], }, - master_clock="clock", + main_clock="clock", output_vars=o_vars, ) @@ -595,7 +697,7 @@ def test_create_setup(model, in_dataset): "add__offset": ("clock", [1, 2, 3, 4, 5]), }, clocks={"clock": [0, 2, 4, 6, 8], "out": [0, 4, 8]}, - master_clock="clock", + main_clock="clock", output_vars={ "profile__u": "clock", ("roll", "u_diff"): "out", @@ -604,3 +706,35 @@ def test_create_setup(model, in_dataset): }, ) xr.testing.assert_identical(ds, in_dataset) + + +def test_create_setup_masterclock_warning(model, in_dataset): + expected = xr.Dataset() + actual = create_setup(model=model, fill_default=False) + xr.testing.assert_identical(actual, expected) + + expected = xr.Dataset({"roll__shift": 2}) + actual = create_setup(model=model, fill_default=True) + xr.testing.assert_equal(actual, expected) + + with pytest.warns( + FutureWarning, match="master_clock is to be deprecated in favour of main_clock" + ): + ds = create_setup( + model=model, + input_vars={ + "init_profile": {"n_points": 5}, + ("roll", "shift"): 1, + "add__offset": ("clock", [1, 2, 3, 4, 5]), + }, + clocks={"clock": [0, 2, 4, 6, 8], "out": [0, 4, 8]}, + master_clock="clock", + output_vars={ + "profile__u": "clock", + ("roll", "u_diff"): "out", + ("add", "u_diff"): "out", + "profile": {"u_opp": None}, + }, + ) + + xr.testing.assert_identical(ds, in_dataset) diff --git a/xsimlab/xr_accessor.py b/xsimlab/xr_accessor.py index 640652e2..3adb14c8 100644 --- a/xsimlab/xr_accessor.py +++ b/xsimlab/xr_accessor.py @@ -160,6 +160,14 @@ def clock_sizes(self): """ return Frozen({k: coord.size for k, coord in self.clock_coords.items()}) + @property + def master_clock_dim(self): + warnings.warn( + "master_clock is to be deprecated in favour of main_clock", + FutureWarning, + ) + return self.main_clock_dim + @property def main_clock_dim(self): """Dimension used as main clock for model runs. Returns None @@ -184,6 +192,14 @@ def main_clock_dim(self): return dim return None + @property + def master_clock_coord(self): + warnings.warn( + "master_clock is to be deprecated in favour of main_clock", + FutureWarning, + ) + return self.main_clock_coord(self) + @property def main_clock_coord(self): """Main clock coordinate (as a :class:`xarray.DataArray` object). From 95a4b4da5dad04b2075f6cf4e1003e767ea5f55b Mon Sep 17 00:00:00 2001 From: Joeperdefloep <33122845+Joeperdefloep@users.noreply.github.com> Date: Tue, 9 Feb 2021 13:35:42 +0100 Subject: [PATCH 08/33] Update xsimlab/xr_accessor.py Co-authored-by: Benoit Bovy --- xsimlab/xr_accessor.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/xsimlab/xr_accessor.py b/xsimlab/xr_accessor.py index 3adb14c8..2ab10057 100644 --- a/xsimlab/xr_accessor.py +++ b/xsimlab/xr_accessor.py @@ -503,7 +503,8 @@ def update_clocks( - ``dim`` : name of the main clock dimension/coordinate - ``units`` : units of all clock coordinate labels - ``calendar`` : a unique calendar for all (time) clock coordinates - master_clock : same as `main_clock`, to be deprecated + master_clock : str or dict, optional + Same as `main_clock`, to be deprecated Returns ------- From 76033e84789ecb88c231fce05e1f23190b75aa94 Mon Sep 17 00:00:00 2001 From: Joeperdefloep <33122845+Joeperdefloep@users.noreply.github.com> Date: Tue, 9 Feb 2021 13:35:47 +0100 Subject: [PATCH 09/33] Update xsimlab/xr_accessor.py Co-authored-by: Benoit Bovy --- xsimlab/xr_accessor.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xsimlab/xr_accessor.py b/xsimlab/xr_accessor.py index 2ab10057..f3d23dc1 100644 --- a/xsimlab/xr_accessor.py +++ b/xsimlab/xr_accessor.py @@ -936,7 +936,7 @@ def maybe_fill_default(ds): else: return ds - if master_clock is not None: + if master_clock is not None and main_clock is None: warnings.warn( "master_clock is to be deprecated in favour of main_clock", FutureWarning, From 2214139b52a073a503055b558d7cfaabb59dfde2 Mon Sep 17 00:00:00 2001 From: Joeperdefloep <33122845+Joeperdefloep@users.noreply.github.com> Date: Tue, 9 Feb 2021 13:35:52 +0100 Subject: [PATCH 10/33] Update xsimlab/xr_accessor.py Co-authored-by: Benoit Bovy --- xsimlab/xr_accessor.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xsimlab/xr_accessor.py b/xsimlab/xr_accessor.py index f3d23dc1..c73a2b62 100644 --- a/xsimlab/xr_accessor.py +++ b/xsimlab/xr_accessor.py @@ -520,7 +520,7 @@ def update_clocks( ds = self._ds.copy() - if master_clock is not None: + if master_clock is not None and main_clock is None: warnings.warn( "master_clock is to be deprecated in favour of main_clock", FutureWarning, From 570489e0895469ea93187622b73e0aa456cadc86 Mon Sep 17 00:00:00 2001 From: Joeperdefloep Date: Tue, 9 Feb 2021 14:06:10 +0100 Subject: [PATCH 11/33] added master/main_clock_coord access tests, updated whats-new --- doc/whats_new.rst | 4 ++++ xsimlab/tests/test_xr_accessor.py | 34 +++++++++++++++++++++++++++++++ xsimlab/xr_accessor.py | 16 ++++++++++++++- 3 files changed, 53 insertions(+), 1 deletion(-) diff --git a/doc/whats_new.rst b/doc/whats_new.rst index 6aecce94..d2582f90 100644 --- a/doc/whats_new.rst +++ b/doc/whats_new.rst @@ -5,6 +5,10 @@ Release Notes v0.6.0 (Unreleased) ------------------- + - Changed ``master_clock``, ``master_clock_dim`` and ``master_clock_coords`` to + ``main_clock``, ``main_clock_dim`` and ``main_clock_coords`` and all + occurences of ``master`` to ``main`` in the rest of the codebase. all + ``master...`` API hooks are still working, but raise a Futurewarning v0.5.0 (26 January 2021) ------------------------ diff --git a/xsimlab/tests/test_xr_accessor.py b/xsimlab/tests/test_xr_accessor.py index edd18cef..99d2cbcf 100644 --- a/xsimlab/tests/test_xr_accessor.py +++ b/xsimlab/tests/test_xr_accessor.py @@ -130,6 +130,40 @@ def test_clock_coords(self): ) assert set(ds.xsimlab.clock_coords) == {"mclock", "sclock"} + def test_main_clock_coords(self): + ds = xr.Dataset( + coords={ + "mclock": ( + "mclock", + [0, 1, 2], + {self._clock_key: 1, self._main_clock_key: 1}, + ), + "sclock": ("sclock", [0, 2], {self._clock_key: 1}), + "no_clock": ("no_clock", [3, 4]), + } + ) + print(ds.xsimlab.main_clock_coord) + xr.testing.assert_equal(ds.xsimlab.main_clock_coord, ds.mclock) + + def test_master_clock_coords_warning(self): + ds = xr.Dataset( + coords={ + "mclock": ( + "mclock", + [0, 1, 2], + {self._clock_key: 1, self._main_clock_key: 1}, + ), + "sclock": ("sclock", [0, 2], {self._clock_key: 1}), + "no_clock": ("no_clock", [3, 4]), + } + ) + print(ds.xsimlab.main_clock_coord) + with pytest.warns( + FutureWarning, + match="master_clock is to be deprecated in favour of main_clock", + ): + xr.testing.assert_equal(ds.xsimlab.master_clock_coord, ds.mclock) + def test_clock_sizes(self): ds = xr.Dataset( coords={ diff --git a/xsimlab/xr_accessor.py b/xsimlab/xr_accessor.py index 3adb14c8..60103107 100644 --- a/xsimlab/xr_accessor.py +++ b/xsimlab/xr_accessor.py @@ -162,6 +162,15 @@ def clock_sizes(self): @property def master_clock_dim(self): + """Dimension used as main clock for model runs. Returns None + if no dimension is set as main clock. + to be deprecated in favour of `main_clock_dim` + + See Also + -------- + :meth:`Dataset.xsimlab.update_clocks` + + """ warnings.warn( "master_clock is to be deprecated in favour of main_clock", FutureWarning, @@ -194,11 +203,16 @@ def main_clock_dim(self): @property def master_clock_coord(self): + """Main clock coordinate (as a :class:`xarray.DataArray` object). + To be deprecated in a future release in favour of `main_clock_coord` + + Returns None if no main clock is defined in the dataset. + """ warnings.warn( "master_clock is to be deprecated in favour of main_clock", FutureWarning, ) - return self.main_clock_coord(self) + return self.main_clock_coord @property def main_clock_coord(self): From 6f38346bbfa34c455920acd690abacfbf576bdb5 Mon Sep 17 00:00:00 2001 From: Joeperdefloep Date: Tue, 9 Feb 2021 14:16:07 +0100 Subject: [PATCH 12/33] removed vscode settings --- .vscode/settings.json | 3 --- 1 file changed, 3 deletions(-) delete mode 100644 .vscode/settings.json diff --git a/.vscode/settings.json b/.vscode/settings.json deleted file mode 100644 index 233aa52f..00000000 --- a/.vscode/settings.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "python.pythonPath": "/home/joempie/miniconda3/envs/simlab-dev/bin/python" -} \ No newline at end of file From 13f0045eb2282fd142c657109ca5e9ba1e0e13cf Mon Sep 17 00:00:00 2001 From: Joeperdefloep Date: Tue, 9 Feb 2021 19:33:28 +0100 Subject: [PATCH 13/33] created duck-typed singleton class for main clock and managed access --- xsimlab/__init__.py | 3 +-- xsimlab/drivers.py | 16 +++++++++------- xsimlab/utils.py | 34 ++++++++++++++++++++++++++++++++++ xsimlab/xr_accessor.py | 5 ++++- 4 files changed, 48 insertions(+), 10 deletions(-) diff --git a/xsimlab/__init__.py b/xsimlab/__init__.py index 9b31951c..a0593fcc 100644 --- a/xsimlab/__init__.py +++ b/xsimlab/__init__.py @@ -24,8 +24,7 @@ group, group_dict, ) -from .xr_accessor import SimlabAccessor, create_setup -from .drivers import MAIN_CLOCK +from .xr_accessor import MAIN_CLOCK, SimlabAccessor, create_setup from . import monitoring from ._version import get_versions diff --git a/xsimlab/drivers.py b/xsimlab/drivers.py index c636965a..7fba0fd6 100644 --- a/xsimlab/drivers.py +++ b/xsimlab/drivers.py @@ -7,7 +7,7 @@ from .hook import flatten_hooks, group_hooks, RuntimeHook from .process import RuntimeSignal from .stores import ZarrSimulationStore -from .utils import get_batch_size +from .utils import get_batch_size, MAIN_CLOCK class ValidateOption(Enum): @@ -20,9 +20,6 @@ class CheckDimsOption(Enum): TRANSPOSE = "transpose" -MAIN_CLOCK = "_main_clock" - - class RuntimeContext(Mapping[str, Any]): """A mapping providing runtime information at the current time step.""" @@ -31,7 +28,8 @@ class RuntimeContext(Mapping[str, Any]): "batch", "sim_start", "sim_end", - "main_clock", + "main_clock_values", + "main_clock_array", "step", "nsteps", "step_start", @@ -166,7 +164,8 @@ def _generate_runtime_datasets(dataset): "_sim_start": mclock_coord[0], "_nsteps": dataset.xsimlab.nsteps, # since we pass a dataset, we need to set the coords - MAIN_CLOCK: dataset.coords[mclock_dim].data, + "_main_clock_values": dataset.coords[mclock_dim].data, + "_main_clock_array": dataset[mclock_dim].data, "_sim_end": mclock_coord[-1], } @@ -333,7 +332,10 @@ def _run( sim_start=ds_init["_sim_start"].values, nsteps=ds_init["_nsteps"].values, sim_end=ds_init["_sim_end"].values, - main_clock=ds_init[MAIN_CLOCK], + main_clock_values=ds_init["_main_clock_values"].values, + main_clock_array=ds_init["_main_clock_array"].swap_dims( + {"_main_clock_array": MAIN_CLOCK} + ), ) in_vars = _get_input_vars(ds_init, model) diff --git a/xsimlab/utils.py b/xsimlab/utils.py index 64e9416b..50359d39 100644 --- a/xsimlab/utils.py +++ b/xsimlab/utils.py @@ -15,6 +15,40 @@ V = TypeVar("V") +class _MainClockDim(str): + """singleton class to be used as main clock dimension: update on runtime + it has all behaviour that dimensions in a `xr.DataArray` normally have. + """ + + # TODO: it does not show up as a dimension in Jupyter notebook output + _singleton = None + main_clock_dim = "MAIN_CLOCK" + + def __new__(cls): + if _MainClockDim._singleton is None: + # if there is no instance of it yet, create a class instance + _MainClockDim._singleton = super(_MainClockDim, cls).__new__(cls) + return _MainClockDim._singleton + + # xarray dim must be hashable. Normally it returns 0, so define hash function + def __hash__(self): + return hash(self.main_clock_dim) + + def __eq__(self, other): + return self.main_clock_dim == other + + # so that it shows up in xarray dims + def __repr__(self): + return self.main_clock_dim + + # so it shows up in print() + def __str__(self): + return self.main_clock_dim + + +MAIN_CLOCK = _MainClockDim() + + def variables_dict(process_cls): """Get all xsimlab variables declared in a process. diff --git a/xsimlab/xr_accessor.py b/xsimlab/xr_accessor.py index dbbe2af8..cef64462 100644 --- a/xsimlab/xr_accessor.py +++ b/xsimlab/xr_accessor.py @@ -11,7 +11,7 @@ from .drivers import XarraySimulationDriver from .model import get_model_variables, Model -from .utils import Frozen, variables_dict +from .utils import Frozen, variables_dict, MAIN_CLOCK from .variable import VarType @@ -541,6 +541,9 @@ def update_clocks(self, model=None, clocks=None, master_clock=None): o_vars = {k: v for k, v in self.output_vars.items() if v is None or v in ds} ds.xsimlab._set_output_vars(model, o_vars) + # update the MAIN_CLOCK placeholder TODO: change with master-main conversion. + MAIN_CLOCK.main_clock_dim = master_clock + return ds def update_vars(self, model=None, input_vars=None, output_vars=None): From 6aa4f373d503b865546e96a002eb957654e467e2 Mon Sep 17 00:00:00 2001 From: Joeperdefloep Date: Wed, 10 Feb 2021 00:21:43 +0100 Subject: [PATCH 14/33] stuck at 'store_output_vars' has unmatching dimensions --- xsimlab/drivers.py | 4 ++-- xsimlab/utils.py | 1 - xsimlab/xr_accessor.py | 2 +- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/xsimlab/drivers.py b/xsimlab/drivers.py index 7fba0fd6..0e38b1b9 100644 --- a/xsimlab/drivers.py +++ b/xsimlab/drivers.py @@ -7,7 +7,7 @@ from .hook import flatten_hooks, group_hooks, RuntimeHook from .process import RuntimeSignal from .stores import ZarrSimulationStore -from .utils import get_batch_size, MAIN_CLOCK +from .utils import get_batch_size class ValidateOption(Enum): @@ -334,7 +334,7 @@ def _run( sim_end=ds_init["_sim_end"].values, main_clock_values=ds_init["_main_clock_values"].values, main_clock_array=ds_init["_main_clock_array"].swap_dims( - {"_main_clock_array": MAIN_CLOCK} + {"_main_clock_array": dataset.xsimlab.master_clock_dim} ), ) diff --git a/xsimlab/utils.py b/xsimlab/utils.py index 50359d39..c175bb68 100644 --- a/xsimlab/utils.py +++ b/xsimlab/utils.py @@ -30,7 +30,6 @@ def __new__(cls): _MainClockDim._singleton = super(_MainClockDim, cls).__new__(cls) return _MainClockDim._singleton - # xarray dim must be hashable. Normally it returns 0, so define hash function def __hash__(self): return hash(self.main_clock_dim) diff --git a/xsimlab/xr_accessor.py b/xsimlab/xr_accessor.py index cef64462..a00ace03 100644 --- a/xsimlab/xr_accessor.py +++ b/xsimlab/xr_accessor.py @@ -542,7 +542,7 @@ def update_clocks(self, model=None, clocks=None, master_clock=None): ds.xsimlab._set_output_vars(model, o_vars) # update the MAIN_CLOCK placeholder TODO: change with master-main conversion. - MAIN_CLOCK.main_clock_dim = master_clock + MAIN_CLOCK.main_clock_dim = master_clock_dict["dim"] return ds From 5f1f6a8db7bb2de5f00e1795b377ec8285963aac Mon Sep 17 00:00:00 2001 From: Joeperdefloep <33122845+Joeperdefloep@users.noreply.github.com> Date: Wed, 10 Feb 2021 10:31:02 +0100 Subject: [PATCH 15/33] Apply suggestions from code review Co-authored-by: Benoit Bovy --- xsimlab/tests/test_xr_accessor.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/xsimlab/tests/test_xr_accessor.py b/xsimlab/tests/test_xr_accessor.py index 99d2cbcf..7e237b0a 100644 --- a/xsimlab/tests/test_xr_accessor.py +++ b/xsimlab/tests/test_xr_accessor.py @@ -142,7 +142,6 @@ def test_main_clock_coords(self): "no_clock": ("no_clock", [3, 4]), } ) - print(ds.xsimlab.main_clock_coord) xr.testing.assert_equal(ds.xsimlab.main_clock_coord, ds.mclock) def test_master_clock_coords_warning(self): @@ -157,7 +156,6 @@ def test_master_clock_coords_warning(self): "no_clock": ("no_clock", [3, 4]), } ) - print(ds.xsimlab.main_clock_coord) with pytest.warns( FutureWarning, match="master_clock is to be deprecated in favour of main_clock", From 6c5a2237dd4ec6e586c53bb593307f27378ef955 Mon Sep 17 00:00:00 2001 From: Joeperdefloep Date: Wed, 10 Feb 2021 10:47:22 +0100 Subject: [PATCH 16/33] removed raise checks from test_update_clocks_master_clock_warning --- xsimlab/tests/test_xr_accessor.py | 37 +------------------------------ 1 file changed, 1 insertion(+), 36 deletions(-) diff --git a/xsimlab/tests/test_xr_accessor.py b/xsimlab/tests/test_xr_accessor.py index 99d2cbcf..5b1852d6 100644 --- a/xsimlab/tests/test_xr_accessor.py +++ b/xsimlab/tests/test_xr_accessor.py @@ -342,46 +342,11 @@ def test_update_clocks(self, model): assert new_ds.xsimlab.main_clock_dim == "clock" np.testing.assert_array_equal(new_ds.clock.values, [0, 2, 4]) - def test_update_clocks_masterclock_warning(self, model): - ds = xr.Dataset() - with pytest.raises(ValueError, match="Cannot determine which clock.*"): - ds.xsimlab.update_clocks(model=model, clocks={}) - - ds = xr.Dataset() - with pytest.raises(ValueError, match="Cannot determine which clock.*"): - ds.xsimlab.update_clocks( - model=model, clocks={"clock": [0, 1, 2], "out": [0, 2]} - ) - - ds = xr.Dataset() - with pytest.raises(KeyError, match="Main clock dimension name.*"): - ds.xsimlab.update_clocks( - model=model, - clocks={"clock": [0, 1, 2]}, - master_clock="non_existing_clock_dim", - ) - - ds = xr.Dataset() - with pytest.raises(ValueError, match="Invalid dimension.*"): - ds.xsimlab.update_clocks( - model=model, - clocks={"clock": ("x", [0, 1, 2])}, - ) - - ds = xr.Dataset() - with pytest.raises(ValueError, match=".*not synchronized.*"): - ds.xsimlab.update_clocks( - model=model, - clocks={"clock": [0, 1, 2], "out": [0, 0.5, 2]}, - master_clock="clock", - ) - + def test_update_clocks_master_clock_warning(self, model): ds = xr.Dataset() ds = ds.xsimlab.update_clocks(model=model, clocks={"clock": [0, 1, 2]}) assert ds.xsimlab.main_clock_dim == "clock" - ds.clock.attrs[self._output_vars_key] = "profile__u" - # assert that a warning is raised with correct use of update with pytest.warns( FutureWarning, From a9dabac9db7a8a25f2c4dddd85db4ee6d2024911 Mon Sep 17 00:00:00 2001 From: Joeperdefloep Date: Wed, 10 Feb 2021 11:21:44 +0100 Subject: [PATCH 17/33] removed raises in test_update_clocks_master_warning --- xsimlab/tests/test_xr_accessor.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/xsimlab/tests/test_xr_accessor.py b/xsimlab/tests/test_xr_accessor.py index 41c034ac..8a2dafe6 100644 --- a/xsimlab/tests/test_xr_accessor.py +++ b/xsimlab/tests/test_xr_accessor.py @@ -345,7 +345,9 @@ def test_update_clocks_master_clock_warning(self, model): ds = ds.xsimlab.update_clocks(model=model, clocks={"clock": [0, 1, 2]}) assert ds.xsimlab.main_clock_dim == "clock" - # assert that a warning is raised with correct use of update + ds.clock.attrs[self._output_vars_key] = "profile__u" + + # assert that a warning is raised with correct use of update master clock with pytest.warns( FutureWarning, match="master_clock is to be deprecated in favour of main_clock", From 1589466121c83c3e71fa4cea88a281a3f8106cf8 Mon Sep 17 00:00:00 2001 From: Joeperdefloep Date: Wed, 10 Feb 2021 11:27:29 +0100 Subject: [PATCH 18/33] removed redundancy in test_update_master_clock --- xsimlab/tests/test_xr_accessor.py | 7 ------- 1 file changed, 7 deletions(-) diff --git a/xsimlab/tests/test_xr_accessor.py b/xsimlab/tests/test_xr_accessor.py index 8a2dafe6..42924be8 100644 --- a/xsimlab/tests/test_xr_accessor.py +++ b/xsimlab/tests/test_xr_accessor.py @@ -378,13 +378,6 @@ def test_update_clocks_master_clock_warning(self, model): ) assert new_ds.xsimlab.main_clock_dim == "clock2" - new_ds = ds.xsimlab.update_clocks(model=model, clocks={"out2": [0, 2]}) - assert new_ds.xsimlab.main_clock_dim == "clock" - - new_ds = ds.xsimlab.update_clocks(model=model, clocks={"clock": [0, 2, 4]}) - assert new_ds.xsimlab.main_clock_dim == "clock" - np.testing.assert_array_equal(new_ds.clock.values, [0, 2, 4]) - def test_update_vars(self, model, in_dataset): ds = in_dataset.xsimlab.update_vars( model=model, From cceed31cb7b12b2be37e22fa4cf08fbe2ed67d10 Mon Sep 17 00:00:00 2001 From: Joeperdefloep Date: Wed, 10 Feb 2021 19:09:06 +0100 Subject: [PATCH 19/33] properly implemented singleton, should work now --- xsimlab/__init__.py | 3 ++- xsimlab/drivers.py | 12 ++++++------ xsimlab/stores.py | 4 +++- xsimlab/utils.py | 17 ++--------------- xsimlab/variable.py | 7 +++++-- xsimlab/xr_accessor.py | 6 ++---- 6 files changed, 20 insertions(+), 29 deletions(-) diff --git a/xsimlab/__init__.py b/xsimlab/__init__.py index a0593fcc..4a842ff3 100644 --- a/xsimlab/__init__.py +++ b/xsimlab/__init__.py @@ -24,7 +24,8 @@ group, group_dict, ) -from .xr_accessor import MAIN_CLOCK, SimlabAccessor, create_setup +from .utils import MAIN_CLOCK +from .xr_accessor import SimlabAccessor, create_setup from . import monitoring from ._version import get_versions diff --git a/xsimlab/drivers.py b/xsimlab/drivers.py index 0e38b1b9..69ac9727 100644 --- a/xsimlab/drivers.py +++ b/xsimlab/drivers.py @@ -7,7 +7,7 @@ from .hook import flatten_hooks, group_hooks, RuntimeHook from .process import RuntimeSignal from .stores import ZarrSimulationStore -from .utils import get_batch_size +from .utils import get_batch_size, MAIN_CLOCK class ValidateOption(Enum): @@ -29,7 +29,7 @@ class RuntimeContext(Mapping[str, Any]): "sim_start", "sim_end", "main_clock_values", - "main_clock_array", + "main_clock_dataarray", "step", "nsteps", "step_start", @@ -165,7 +165,6 @@ def _generate_runtime_datasets(dataset): "_nsteps": dataset.xsimlab.nsteps, # since we pass a dataset, we need to set the coords "_main_clock_values": dataset.coords[mclock_dim].data, - "_main_clock_array": dataset[mclock_dim].data, "_sim_end": mclock_coord[-1], } @@ -210,6 +209,9 @@ def _maybe_transpose(dataset, model, check_dims, batch_dim): if xr_var is None: continue + if any([MAIN_CLOCK in d for d in model.cache[var_key]["metadata"]["dims"]]): + raise ValueError("Do not pass xs.MAIN_CLOCK into input vars dimensions") + # all valid dimensions in the right order dims = [list(d) for d in model.cache[var_key]["metadata"]["dims"]] dims += [[dataset.xsimlab.master_clock_dim] + d for d in dims] @@ -333,9 +335,7 @@ def _run( nsteps=ds_init["_nsteps"].values, sim_end=ds_init["_sim_end"].values, main_clock_values=ds_init["_main_clock_values"].values, - main_clock_array=ds_init["_main_clock_array"].swap_dims( - {"_main_clock_array": dataset.xsimlab.master_clock_dim} - ), + main_clock_dataarray=dataset.xsimlab.master_clock_coord, ) in_vars = _get_input_vars(ds_init, model) diff --git a/xsimlab/stores.py b/xsimlab/stores.py index 353ade7d..7a4ef644 100644 --- a/xsimlab/stores.py +++ b/xsimlab/stores.py @@ -6,7 +6,7 @@ import zarr from . import Model -from .utils import get_batch_size, normalize_encoding +from .utils import get_batch_size, normalize_encoding, MAIN_CLOCK from .variable import VarType @@ -241,6 +241,8 @@ def _create_zarr_dataset( f"its accepted dimension(s): {var_info['metadata']['dims']}" ) + dim_labels = [self.mclock_dim if d is MAIN_CLOCK else d for d in dim_labels] + if clock is not None: dim_labels.insert(0, clock) if add_batch_dim: diff --git a/xsimlab/utils.py b/xsimlab/utils.py index c175bb68..9983506f 100644 --- a/xsimlab/utils.py +++ b/xsimlab/utils.py @@ -15,14 +15,12 @@ V = TypeVar("V") -class _MainClockDim(str): +class _MainClockDim: """singleton class to be used as main clock dimension: update on runtime it has all behaviour that dimensions in a `xr.DataArray` normally have. """ - # TODO: it does not show up as a dimension in Jupyter notebook output _singleton = None - main_clock_dim = "MAIN_CLOCK" def __new__(cls): if _MainClockDim._singleton is None: @@ -30,19 +28,8 @@ def __new__(cls): _MainClockDim._singleton = super(_MainClockDim, cls).__new__(cls) return _MainClockDim._singleton - def __hash__(self): - return hash(self.main_clock_dim) - - def __eq__(self, other): - return self.main_clock_dim == other - - # so that it shows up in xarray dims def __repr__(self): - return self.main_clock_dim - - # so it shows up in print() - def __str__(self): - return self.main_clock_dim + return "MAIN_CLOCK (uninitialized)" MAIN_CLOCK = _MainClockDim() diff --git a/xsimlab/variable.py b/xsimlab/variable.py index 95823cf6..e187fbc9 100644 --- a/xsimlab/variable.py +++ b/xsimlab/variable.py @@ -5,7 +5,7 @@ import attr from attr._make import _CountingAttr -from .utils import normalize_encoding +from .utils import normalize_encoding, MAIN_CLOCK class VarType(Enum): @@ -57,7 +57,10 @@ def _as_dim_tuple(dims): ambiguous and thus not allowed. """ - if not len(dims): + # MAIN_CLOCK is sentinel and does not have length (or zero), so check explicitly + if dims == MAIN_CLOCK: + dims = [(dims,)] + elif not len(dims): dims = [()] elif isinstance(dims, str): dims = [(dims,)] diff --git a/xsimlab/xr_accessor.py b/xsimlab/xr_accessor.py index a00ace03..3c2acee3 100644 --- a/xsimlab/xr_accessor.py +++ b/xsimlab/xr_accessor.py @@ -11,7 +11,7 @@ from .drivers import XarraySimulationDriver from .model import get_model_variables, Model -from .utils import Frozen, variables_dict, MAIN_CLOCK +from .utils import Frozen, variables_dict from .variable import VarType @@ -289,6 +289,7 @@ def _uniformize_clock_coords(self, dim=None, units=None, calendar=None): ) def _set_input_vars(self, model, input_vars): + invalid_inputs = set(input_vars) - set(model.input_vars) if invalid_inputs: @@ -541,9 +542,6 @@ def update_clocks(self, model=None, clocks=None, master_clock=None): o_vars = {k: v for k, v in self.output_vars.items() if v is None or v in ds} ds.xsimlab._set_output_vars(model, o_vars) - # update the MAIN_CLOCK placeholder TODO: change with master-main conversion. - MAIN_CLOCK.main_clock_dim = master_clock_dict["dim"] - return ds def update_vars(self, model=None, input_vars=None, output_vars=None): From 10673e9924c97c063a2bb5727dda7b39ff5a5bd8 Mon Sep 17 00:00:00 2001 From: Joeperdefloep Date: Wed, 10 Feb 2021 20:11:05 +0100 Subject: [PATCH 20/33] added tests --- xsimlab/tests/test_model.py | 38 +++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/xsimlab/tests/test_model.py b/xsimlab/tests/test_model.py index 90d99bf4..1bcefaab 100644 --- a/xsimlab/tests/test_model.py +++ b/xsimlab/tests/test_model.py @@ -452,3 +452,41 @@ def initialize(self): model.execute("initialize", {}) assert model.state[("baz", "actual")] == Frozen({("foo", "a"): 1, ("bar", "b"): 2}) + + +def test_main_clock_access(): + @xs.process + class Foo: + a = xs.variable(intent="out", dims=xs.MAIN_CLOCK) + b = xs.variable(intent="out", dims=xs.MAIN_CLOCK) + + @xs.runtime(args=["main_clock_values", "main_clock_dataarray"]) + def initialize(self, clock_values, clock_array): + self.a = clock_values + assert all(self.a == [0, 1, 2, 3]) + self.b = clock_array * 2 + assert clock_array.dims[0] == "clock" + assert all(clock_array[clock_array.dims[0]].data == [0, 1, 2, 3]) + + model = xs.Model({"foo": Foo}) + ds_in = xs.create_setup( + model=model, clocks={"clock": [0, 1, 2, 3]}, input_vars={}, output_vars={} + ) + ds_in.xsimlab.run(model=model) + + # test for error when trying to put xs.MAIN_CLOCK as a dim in an input var + @xs.process + class InputMainClockDim: + a = xs.variable(intent="in", dims=xs.MAIN_CLOCK) + + model = xs.Model({"foo": InputMainClockDim}) + ds_in = xs.create_setup( + model=model, + clocks={"clock": [0, 1, 2, 3]}, + input_vars={"foo__a": 5}, + output_vars={}, + ) + with pytest.raises( + ValueError, match="Do not pass xs.MAIN_CLOCK into input vars dimensions" + ): + ds_in.xsimlab.run(model=model) \ No newline at end of file From 1d11793e5c119d9bb02b49c81cc1ffa96f36d0bf Mon Sep 17 00:00:00 2001 From: Joeperdefloep Date: Wed, 10 Feb 2021 23:02:46 +0100 Subject: [PATCH 21/33] added check for double dimensions. --- xsimlab/stores.py | 8 ++++++++ xsimlab/tests/test_model.py | 22 +++++++++++++++++++++- 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/xsimlab/stores.py b/xsimlab/stores.py index 7a4ef644..02044a0f 100644 --- a/xsimlab/stores.py +++ b/xsimlab/stores.py @@ -182,6 +182,7 @@ def write_input_xr_dataset(self): def _create_zarr_dataset( self, model: Model, var_key: VarKey, name: Optional[str] = None ): + print("creating zarr dataset") var_info = self.var_info[var_key] if name is None: @@ -241,6 +242,13 @@ def _create_zarr_dataset( f"its accepted dimension(s): {var_info['metadata']['dims']}" ) + # set MAIN_CLOCK placeholder to main_clock dimension + print("_create_zarr_dataset: ", self.mclock_dim, dim_labels) + if self.mclock_dim in dim_labels and MAIN_CLOCK in dim_labels: + raise ValueError( + f"Main clock: '{self.mclock_dim}' has a duplicate in {dim_labels}." + "Please change the name of 'main_clock' in `create_setup`" + ) dim_labels = [self.mclock_dim if d is MAIN_CLOCK else d for d in dim_labels] if clock is not None: diff --git a/xsimlab/tests/test_model.py b/xsimlab/tests/test_model.py index 1bcefaab..b25e8a60 100644 --- a/xsimlab/tests/test_model.py +++ b/xsimlab/tests/test_model.py @@ -474,6 +474,26 @@ def initialize(self, clock_values, clock_array): ) ds_in.xsimlab.run(model=model) + # test for error when another dim has the same name as xs.MAIN_CLOCK + @xs.process + class DoubleMainClockDim: + a = xs.variable(intent="out", dims=("clock", xs.MAIN_CLOCK)) + + def initialize(self): + self.a = [[1, 2, 3], [3, 4, 5]] + + def run_step(self): + self.a += self.a + + model = xs.Model({"foo": DoubleMainClockDim}) + # with pytest.raises(ValueError,match="") + xs.create_setup( + model=model, + clocks={"clock": [0, 1, 2, 3]}, + input_vars={}, + output_vars={}, + ).xsimlab.run(model) + # test for error when trying to put xs.MAIN_CLOCK as a dim in an input var @xs.process class InputMainClockDim: @@ -489,4 +509,4 @@ class InputMainClockDim: with pytest.raises( ValueError, match="Do not pass xs.MAIN_CLOCK into input vars dimensions" ): - ds_in.xsimlab.run(model=model) \ No newline at end of file + ds_in.xsimlab.run(model=model) From 482c1f94f9b9d0a0613410e82f2a491b81f66c8f Mon Sep 17 00:00:00 2001 From: Joeperdefloep Date: Thu, 11 Feb 2021 00:22:24 +0100 Subject: [PATCH 22/33] stuff, deleted prints --- xsimlab/drivers.py | 2 +- xsimlab/stores.py | 3 --- xsimlab/xr_accessor.py | 4 ++-- 3 files changed, 3 insertions(+), 6 deletions(-) diff --git a/xsimlab/drivers.py b/xsimlab/drivers.py index 907bab96..529e532a 100644 --- a/xsimlab/drivers.py +++ b/xsimlab/drivers.py @@ -335,7 +335,7 @@ def _run( nsteps=ds_init["_nsteps"].values, sim_end=ds_init["_sim_end"].values, main_clock_values=ds_init["_main_clock_values"].values, - main_clock_dataarray=dataset.xsimlab.master_clock_coord, + main_clock_dataarray=dataset.xsimlab.main_clock_coord, ) in_vars = _get_input_vars(ds_init, model) diff --git a/xsimlab/stores.py b/xsimlab/stores.py index 0a526f86..cddd29d8 100644 --- a/xsimlab/stores.py +++ b/xsimlab/stores.py @@ -182,7 +182,6 @@ def write_input_xr_dataset(self): def _create_zarr_dataset( self, model: Model, var_key: VarKey, name: Optional[str] = None ): - print("creating zarr dataset") var_info = self.var_info[var_key] if name is None: @@ -243,7 +242,6 @@ def _create_zarr_dataset( ) # set MAIN_CLOCK placeholder to main_clock dimension - print("_create_zarr_dataset: ", self.mclock_dim, dim_labels) if self.mclock_dim in dim_labels and MAIN_CLOCK in dim_labels: raise ValueError( f"Main clock: '{self.mclock_dim}' has a duplicate in {dim_labels}." @@ -330,7 +328,6 @@ def write_output_vars(self, batch: int, step: int, model: Optional[Model] = None else: idx_dims = [clock_inc] + [slice(0, n) for n in np.shape(value)] - if batch != -1: idx_dims.insert(0, batch) diff --git a/xsimlab/xr_accessor.py b/xsimlab/xr_accessor.py index fd67e269..a12343da 100644 --- a/xsimlab/xr_accessor.py +++ b/xsimlab/xr_accessor.py @@ -209,7 +209,7 @@ def master_clock_coord(self): Returns None if no main clock is defined in the dataset. """ warnings.warn( - "master_clock is to be deprecated in favour of main_clock", + "master_clock_coord is to be deprecated in favour of main_clock", FutureWarning, ) return self.main_clock_coord @@ -224,7 +224,7 @@ def main_clock_coord(self): @property def nsteps(self): - """Number of simulation steps, computed from the master + """Number of simulation steps, computed from the main clock coordinate. Returns 0 if no main clock is defined in the dataset. From 16330bd60d3a28f42d7a9fd5884f47202260bf26 Mon Sep 17 00:00:00 2001 From: Joeperdefloep <33122845+Joeperdefloep@users.noreply.github.com> Date: Thu, 11 Feb 2021 09:57:22 +0100 Subject: [PATCH 23/33] Update xsimlab/utils.py Co-authored-by: Benoit Bovy --- xsimlab/utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xsimlab/utils.py b/xsimlab/utils.py index 9983506f..e99901e6 100644 --- a/xsimlab/utils.py +++ b/xsimlab/utils.py @@ -29,7 +29,7 @@ def __new__(cls): return _MainClockDim._singleton def __repr__(self): - return "MAIN_CLOCK (uninitialized)" + return "MAIN_CLOCK (undefined)" MAIN_CLOCK = _MainClockDim() From 0abba092ad71b805e5abd3ccea16d92195244325 Mon Sep 17 00:00:00 2001 From: Joeperdefloep <33122845+Joeperdefloep@users.noreply.github.com> Date: Thu, 11 Feb 2021 09:58:38 +0100 Subject: [PATCH 24/33] Update xsimlab/variable.py Co-authored-by: Benoit Bovy --- xsimlab/variable.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xsimlab/variable.py b/xsimlab/variable.py index e187fbc9..0a6e7044 100644 --- a/xsimlab/variable.py +++ b/xsimlab/variable.py @@ -58,7 +58,7 @@ def _as_dim_tuple(dims): """ # MAIN_CLOCK is sentinel and does not have length (or zero), so check explicitly - if dims == MAIN_CLOCK: + if dims is MAIN_CLOCK: dims = [(dims,)] elif not len(dims): dims = [()] From 2b05f12de5de0afb30cf7dbb7b44e2eaebaf9522 Mon Sep 17 00:00:00 2001 From: Joeperdefloep Date: Thu, 11 Feb 2021 11:01:43 +0100 Subject: [PATCH 25/33] better tests --- xsimlab/drivers.py | 3 -- xsimlab/tests/test_access_clock.py | 29 ++++++++++++++ xsimlab/tests/test_model.py | 61 ++++++++++++++++++------------ xsimlab/variable.py | 12 ++++-- 4 files changed, 75 insertions(+), 30 deletions(-) create mode 100644 xsimlab/tests/test_access_clock.py diff --git a/xsimlab/drivers.py b/xsimlab/drivers.py index 529e532a..23e12470 100644 --- a/xsimlab/drivers.py +++ b/xsimlab/drivers.py @@ -209,9 +209,6 @@ def _maybe_transpose(dataset, model, check_dims, batch_dim): if xr_var is None: continue - if any([MAIN_CLOCK in d for d in model.cache[var_key]["metadata"]["dims"]]): - raise ValueError("Do not pass xs.MAIN_CLOCK into input vars dimensions") - # all valid dimensions in the right order dims = [list(d) for d in model.cache[var_key]["metadata"]["dims"]] dims += [[dataset.xsimlab.main_clock_dim] + d for d in dims] diff --git a/xsimlab/tests/test_access_clock.py b/xsimlab/tests/test_access_clock.py new file mode 100644 index 00000000..f7724a8d --- /dev/null +++ b/xsimlab/tests/test_access_clock.py @@ -0,0 +1,29 @@ +import xsimlab as xs +import numpy as np + + +@xs.process +class Foo: + a = xs.variable(intent="out", dims=(xs.MAIN_CLOCK)) + b = xs.variable(intent="out", dims=[(), "a"]) + # c = xs.variable(intent="in", dims=["a", ("clock", xs.MAIN_CLOCK)]) + + @xs.runtime(args="main_clock_values") + def initialize(self, clock_values): + self.b = 3 + self.a = clock_values + + @xs.runtime(args="step") + def run_step(self, step): + self.a[step] += 1 * self.b + + +model = xs.Model({"foo": Foo}) +ds_in = xs.create_setup( + model=model, + clocks={"clock": range(5), "iclock": [2, 4]}, + main_clock="clock", + input_vars={}, # "foo__c": 5}, + output_vars={"foo__a": None, "foo__b": "iclock"}, +) +print(ds_in.xsimlab.run(model=model).foo__a.data == [3, 4, 5, 6, 4]) diff --git a/xsimlab/tests/test_model.py b/xsimlab/tests/test_model.py index b25e8a60..99c81dda 100644 --- a/xsimlab/tests/test_model.py +++ b/xsimlab/tests/test_model.py @@ -462,17 +462,30 @@ class Foo: @xs.runtime(args=["main_clock_values", "main_clock_dataarray"]) def initialize(self, clock_values, clock_array): - self.a = clock_values - assert all(self.a == [0, 1, 2, 3]) + self.a = clock_values * 2 + assert all(self.a == [0, 2, 4, 6]) self.b = clock_array * 2 assert clock_array.dims[0] == "clock" assert all(clock_array[clock_array.dims[0]].data == [0, 1, 2, 3]) + @xs.runtime(args=["step_delta", "step"]) + def run_step(self, dt, n): + assert self.a[n] == 2 * n + self.a[n] += 1 + model = xs.Model({"foo": Foo}) ds_in = xs.create_setup( - model=model, clocks={"clock": [0, 1, 2, 3]}, input_vars={}, output_vars={} + model=model, + clocks={"clock": range(4)}, + input_vars={}, + output_vars={"foo__a": None}, ) - ds_in.xsimlab.run(model=model) + ds_out = ds_in.xsimlab.run(model=model) + assert all(ds_out.foo__a.data == [1, 3, 5, 6]) + + # TODO: there is still the problem that the first (0) value of the clock is + # set to np.nan in output (still works fine in input) Also, getting + # time variables as DataArray as output is not working # test for error when another dim has the same name as xs.MAIN_CLOCK @xs.process @@ -486,27 +499,27 @@ def run_step(self): self.a += self.a model = xs.Model({"foo": DoubleMainClockDim}) - # with pytest.raises(ValueError,match="") - xs.create_setup( - model=model, - clocks={"clock": [0, 1, 2, 3]}, - input_vars={}, - output_vars={}, - ).xsimlab.run(model) + with pytest.raises(ValueError, match=r"Main clock:*"): + xs.create_setup( + model=model, + clocks={"clock": [0, 1, 2, 3]}, + input_vars={}, + output_vars={"foo__a": None}, + ).xsimlab.run(model) # test for error when trying to put xs.MAIN_CLOCK as a dim in an input var @xs.process class InputMainClockDim: - a = xs.variable(intent="in", dims=xs.MAIN_CLOCK) - - model = xs.Model({"foo": InputMainClockDim}) - ds_in = xs.create_setup( - model=model, - clocks={"clock": [0, 1, 2, 3]}, - input_vars={"foo__a": 5}, - output_vars={}, - ) - with pytest.raises( - ValueError, match="Do not pass xs.MAIN_CLOCK into input vars dimensions" - ): - ds_in.xsimlab.run(model=model) + with pytest.raises( + ValueError, match="Do not pass xs.MAIN_CLOCK into input vars dimensions" + ): + a = xs.variable(intent="in", dims=xs.MAIN_CLOCK) + + with pytest.raises( + ValueError, match="Do not pass xs.MAIN_CLOCK into input vars dimensions" + ): + b = xs.variable(intent="in", dims=(xs.MAIN_CLOCK,)) + with pytest.raises( + ValueError, match="Do not pass xs.MAIN_CLOCK into input vars dimensions" + ): + c = xs.variable(intent="in", dims=["a", ("a", xs.MAIN_CLOCK)]) \ No newline at end of file diff --git a/xsimlab/variable.py b/xsimlab/variable.py index e187fbc9..6d85295d 100644 --- a/xsimlab/variable.py +++ b/xsimlab/variable.py @@ -58,14 +58,17 @@ def _as_dim_tuple(dims): """ # MAIN_CLOCK is sentinel and does not have length (or zero), so check explicitly - if dims == MAIN_CLOCK: + if dims is MAIN_CLOCK: dims = [(dims,)] elif not len(dims): dims = [()] elif isinstance(dims, str): dims = [(dims,)] elif isinstance(dims, list): - dims = [tuple([d]) if isinstance(d, str) else tuple(d) for d in dims] + dims = [ + tuple([d]) if (isinstance(d, str) or d is MAIN_CLOCK) else tuple(d) + for d in dims + ] else: dims = [dims] @@ -224,6 +227,9 @@ def variable( else: _init = True _repr = True + # also check if MAIN_CLOCK is there + if any([MAIN_CLOCK in d for d in metadata["dims"]]): + raise ValueError("Do not pass xs.MAIN_CLOCK into input vars dimensions") return attr.attrib( metadata=metadata, @@ -342,7 +348,7 @@ def on_demand( Dictionary specifying how to encode this variable's data into a serialized format (i.e., as a zarr dataset). Currently used keys include 'dtype', 'compressor', 'fill_value', 'order', 'filters' - and 'object_codec'. See :func:`zarr.creation.create` for details + and 'object_codec'. See :func:`zarr.creation.df` for details about these options. Other keys are ignored. Notes From 90b0463c941022d20bd4ed961fbae8070a620370 Mon Sep 17 00:00:00 2001 From: Joeperdefloep Date: Thu, 11 Feb 2021 11:05:02 +0100 Subject: [PATCH 26/33] black... --- xsimlab/tests/test_model.py | 2 +- xsimlab/utils.py | 8 ++++++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/xsimlab/tests/test_model.py b/xsimlab/tests/test_model.py index 99c81dda..ccf34f2c 100644 --- a/xsimlab/tests/test_model.py +++ b/xsimlab/tests/test_model.py @@ -522,4 +522,4 @@ class InputMainClockDim: with pytest.raises( ValueError, match="Do not pass xs.MAIN_CLOCK into input vars dimensions" ): - c = xs.variable(intent="in", dims=["a", ("a", xs.MAIN_CLOCK)]) \ No newline at end of file + c = xs.variable(intent="in", dims=["a", ("a", xs.MAIN_CLOCK)]) diff --git a/xsimlab/utils.py b/xsimlab/utils.py index e99901e6..63d6cef6 100644 --- a/xsimlab/utils.py +++ b/xsimlab/utils.py @@ -16,8 +16,12 @@ class _MainClockDim: - """singleton class to be used as main clock dimension: update on runtime - it has all behaviour that dimensions in a `xr.DataArray` normally have. + """Singleton class to be used as a placeholder of the main clock + dimension. + + It will be replaced by the actual dimension label set during simulation setup + (i.e., ``main_clock`` argument). + """ _singleton = None From 097a9aa5054bf8f306ad0b40b5f44cfafc6617f0 Mon Sep 17 00:00:00 2001 From: Joeperdefloep Date: Thu, 11 Feb 2021 12:12:31 +0100 Subject: [PATCH 27/33] stupid test solved --- xsimlab/tests/test_access_clock.py | 29 ----------------------------- xsimlab/tests/test_xr_accessor.py | 4 ++-- xsimlab/xr_accessor.py | 1 + 3 files changed, 3 insertions(+), 31 deletions(-) delete mode 100644 xsimlab/tests/test_access_clock.py diff --git a/xsimlab/tests/test_access_clock.py b/xsimlab/tests/test_access_clock.py deleted file mode 100644 index f7724a8d..00000000 --- a/xsimlab/tests/test_access_clock.py +++ /dev/null @@ -1,29 +0,0 @@ -import xsimlab as xs -import numpy as np - - -@xs.process -class Foo: - a = xs.variable(intent="out", dims=(xs.MAIN_CLOCK)) - b = xs.variable(intent="out", dims=[(), "a"]) - # c = xs.variable(intent="in", dims=["a", ("clock", xs.MAIN_CLOCK)]) - - @xs.runtime(args="main_clock_values") - def initialize(self, clock_values): - self.b = 3 - self.a = clock_values - - @xs.runtime(args="step") - def run_step(self, step): - self.a[step] += 1 * self.b - - -model = xs.Model({"foo": Foo}) -ds_in = xs.create_setup( - model=model, - clocks={"clock": range(5), "iclock": [2, 4]}, - main_clock="clock", - input_vars={}, # "foo__c": 5}, - output_vars={"foo__a": None, "foo__b": "iclock"}, -) -print(ds_in.xsimlab.run(model=model).foo__a.data == [3, 4, 5, 6, 4]) diff --git a/xsimlab/tests/test_xr_accessor.py b/xsimlab/tests/test_xr_accessor.py index 42924be8..17cec751 100644 --- a/xsimlab/tests/test_xr_accessor.py +++ b/xsimlab/tests/test_xr_accessor.py @@ -158,9 +158,9 @@ def test_master_clock_coords_warning(self): ) with pytest.warns( FutureWarning, - match="master_clock is to be deprecated in favour of main_clock", + match="master_clock_coord is to be deprecated in favour of main_clock", ): - xr.testing.assert_equal(ds.xsimlab.master_clock_coord, ds.mclock) + ds.xsimlab.master_clock_coord def test_clock_sizes(self): ds = xr.Dataset( diff --git a/xsimlab/xr_accessor.py b/xsimlab/xr_accessor.py index a12343da..1e334d92 100644 --- a/xsimlab/xr_accessor.py +++ b/xsimlab/xr_accessor.py @@ -212,6 +212,7 @@ def master_clock_coord(self): "master_clock_coord is to be deprecated in favour of main_clock", FutureWarning, ) + warnings.warn("Poep in je hoofd!") return self.main_clock_coord @property From a0d80c0848f9da9dd64b54c801454bab3f17fd6f Mon Sep 17 00:00:00 2001 From: Joeperdefloep <33122845+Joeperdefloep@users.noreply.github.com> Date: Fri, 19 Feb 2021 20:25:23 +0100 Subject: [PATCH 28/33] Update xsimlab/xr_accessor.py Co-authored-by: Benoit Bovy --- xsimlab/xr_accessor.py | 1 - 1 file changed, 1 deletion(-) diff --git a/xsimlab/xr_accessor.py b/xsimlab/xr_accessor.py index 1e334d92..a12343da 100644 --- a/xsimlab/xr_accessor.py +++ b/xsimlab/xr_accessor.py @@ -212,7 +212,6 @@ def master_clock_coord(self): "master_clock_coord is to be deprecated in favour of main_clock", FutureWarning, ) - warnings.warn("Poep in je hoofd!") return self.main_clock_coord @property From 5bc5b6eba0a913d5022f9336378ff2239e07d6b6 Mon Sep 17 00:00:00 2001 From: Joeperdefloep <33122845+Joeperdefloep@users.noreply.github.com> Date: Fri, 19 Feb 2021 20:26:23 +0100 Subject: [PATCH 29/33] Update xsimlab/tests/test_model.py Co-authored-by: Benoit Bovy --- xsimlab/tests/test_model.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xsimlab/tests/test_model.py b/xsimlab/tests/test_model.py index ccf34f2c..4adc7ea1 100644 --- a/xsimlab/tests/test_model.py +++ b/xsimlab/tests/test_model.py @@ -463,7 +463,7 @@ class Foo: @xs.runtime(args=["main_clock_values", "main_clock_dataarray"]) def initialize(self, clock_values, clock_array): self.a = clock_values * 2 - assert all(self.a == [0, 2, 4, 6]) + np.testing.assert_equal(self.a, [0, 2, 4, 6]) self.b = clock_array * 2 assert clock_array.dims[0] == "clock" assert all(clock_array[clock_array.dims[0]].data == [0, 1, 2, 3]) From d8a1fa916e2657d5ab1d3b7d24eb59840250efee Mon Sep 17 00:00:00 2001 From: Joeperdefloep Date: Fri, 19 Feb 2021 21:04:46 +0100 Subject: [PATCH 30/33] did some stuff --- xsimlab/xr_accessor.py | 1 - 1 file changed, 1 deletion(-) diff --git a/xsimlab/xr_accessor.py b/xsimlab/xr_accessor.py index 1e334d92..a12343da 100644 --- a/xsimlab/xr_accessor.py +++ b/xsimlab/xr_accessor.py @@ -212,7 +212,6 @@ def master_clock_coord(self): "master_clock_coord is to be deprecated in favour of main_clock", FutureWarning, ) - warnings.warn("Poep in je hoofd!") return self.main_clock_coord @property From 5f84d679423737406b35f7c45b0b0c9dc7ad3356 Mon Sep 17 00:00:00 2001 From: Joeperdefloep Date: Fri, 19 Feb 2021 21:17:34 +0100 Subject: [PATCH 31/33] should be good --- doc/api.rst | 2 +- xsimlab/tests/test_model.py | 32 +++++++++++++------------------- xsimlab/utils.py | 4 ++++ xsimlab/variable.py | 2 +- 4 files changed, 19 insertions(+), 21 deletions(-) diff --git a/doc/api.rst b/doc/api.rst index 63733318..da949cf3 100644 --- a/doc/api.rst +++ b/doc/api.rst @@ -154,7 +154,7 @@ Variable .. autosummary:: :toctree: _api_generated/ - + MAIN_CLOCK variable index any_object diff --git a/xsimlab/tests/test_model.py b/xsimlab/tests/test_model.py index 4adc7ea1..9228db5d 100644 --- a/xsimlab/tests/test_model.py +++ b/xsimlab/tests/test_model.py @@ -483,10 +483,6 @@ def run_step(self, dt, n): ds_out = ds_in.xsimlab.run(model=model) assert all(ds_out.foo__a.data == [1, 3, 5, 6]) - # TODO: there is still the problem that the first (0) value of the clock is - # set to np.nan in output (still works fine in input) Also, getting - # time variables as DataArray as output is not working - # test for error when another dim has the same name as xs.MAIN_CLOCK @xs.process class DoubleMainClockDim: @@ -508,18 +504,16 @@ def run_step(self): ).xsimlab.run(model) # test for error when trying to put xs.MAIN_CLOCK as a dim in an input var - @xs.process - class InputMainClockDim: - with pytest.raises( - ValueError, match="Do not pass xs.MAIN_CLOCK into input vars dimensions" - ): - a = xs.variable(intent="in", dims=xs.MAIN_CLOCK) - - with pytest.raises( - ValueError, match="Do not pass xs.MAIN_CLOCK into input vars dimensions" - ): - b = xs.variable(intent="in", dims=(xs.MAIN_CLOCK,)) - with pytest.raises( - ValueError, match="Do not pass xs.MAIN_CLOCK into input vars dimensions" - ): - c = xs.variable(intent="in", dims=["a", ("a", xs.MAIN_CLOCK)]) + with pytest.raises( + ValueError, match="Do not pass xs.MAIN_CLOCK into input vars dimensions" + ): + a = xs.variable(intent="in", dims=xs.MAIN_CLOCK) + + with pytest.raises( + ValueError, match="Do not pass xs.MAIN_CLOCK into input vars dimensions" + ): + b = xs.variable(intent="in", dims=(xs.MAIN_CLOCK,)) + with pytest.raises( + ValueError, match="Do not pass xs.MAIN_CLOCK into input vars dimensions" + ): + c = xs.variable(intent="in", dims=["a", ("a", xs.MAIN_CLOCK)]) diff --git a/xsimlab/utils.py b/xsimlab/utils.py index 63d6cef6..bbf2ddd6 100644 --- a/xsimlab/utils.py +++ b/xsimlab/utils.py @@ -37,6 +37,10 @@ def __repr__(self): MAIN_CLOCK = _MainClockDim() +""" +Sentinel to indicate simulation's main clock dimension, to be +replaced by the actual dimension label set in input/output datasets. +""" def variables_dict(process_cls): diff --git a/xsimlab/variable.py b/xsimlab/variable.py index 6d85295d..d6b642a1 100644 --- a/xsimlab/variable.py +++ b/xsimlab/variable.py @@ -348,7 +348,7 @@ def on_demand( Dictionary specifying how to encode this variable's data into a serialized format (i.e., as a zarr dataset). Currently used keys include 'dtype', 'compressor', 'fill_value', 'order', 'filters' - and 'object_codec'. See :func:`zarr.creation.df` for details + and 'object_codec'. See :func:`zarr.creation.create` for details about these options. Other keys are ignored. Notes From 08a17e81c27ac64f60602e313088b7fef7f8f4a3 Mon Sep 17 00:00:00 2001 From: Joeperdefloep Date: Tue, 2 Mar 2021 21:58:00 +0100 Subject: [PATCH 32/33] docs --- doc/api.rst | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/doc/api.rst b/doc/api.rst index da949cf3..091e0c30 100644 --- a/doc/api.rst +++ b/doc/api.rst @@ -141,6 +141,8 @@ Process introspection and variables variable_info filter_variables + + Process runtime methods ----------------------- @@ -154,8 +156,9 @@ Variable .. autosummary:: :toctree: _api_generated/ - MAIN_CLOCK + variable + MAIN_CLOCK index any_object foreign From fc4d3dd2b1375f6be0acc898c0f8442c903a4971 Mon Sep 17 00:00:00 2001 From: Joeperdefloep Date: Thu, 4 Mar 2021 13:09:24 +0100 Subject: [PATCH 33/33] updated what's new --- .vscode/settings.json | 3 --- doc/whats_new.rst | 4 ++++ 2 files changed, 4 insertions(+), 3 deletions(-) delete mode 100644 .vscode/settings.json diff --git a/.vscode/settings.json b/.vscode/settings.json deleted file mode 100644 index 233aa52f..00000000 --- a/.vscode/settings.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "python.pythonPath": "/home/joempie/miniconda3/envs/simlab-dev/bin/python" -} \ No newline at end of file diff --git a/doc/whats_new.rst b/doc/whats_new.rst index d2582f90..45b0be6b 100644 --- a/doc/whats_new.rst +++ b/doc/whats_new.rst @@ -9,6 +9,10 @@ v0.6.0 (Unreleased) ``main_clock``, ``main_clock_dim`` and ``main_clock_coords`` and all occurences of ``master`` to ``main`` in the rest of the codebase. all ``master...`` API hooks are still working, but raise a Futurewarning + - Added access to main clock in initialize step as ``main_clock_values`` + and as a ``xr.DataArray``: ``main_clock_array``. for refering to the main + clock as a dimension label, the placeholder ``xs.MAIN_CLOCK`` can be used. + This will be set to the main clock when storing the dataset. v0.5.0 (26 January 2021) ------------------------