Skip to content

Commit 6e69d82

Browse files
authored
Simplify clocks API (#41)
* refactor update_clocks API - High-level API for generating clock coordinate data is not supported anymore - auto_adjust clock coordinate labels has been removed (an error is raised instead) - It is possible to use update_clocks to update only some clock coordinates (all clock coordinates are not dropped first anymore) * update docstrings * update doc (examples, user guide and release notes)
1 parent 4829b3f commit 6e69d82

File tree

5 files changed

+271
-329
lines changed

5 files changed

+271
-329
lines changed

doc/examples/landscape-evolution-model.ipynb

+101-101
Large diffs are not rendered by default.

doc/run_model.rst

+6-6
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ The following imports are necessary for the examples below.
2020

2121
.. ipython:: python
2222
23+
import numpy as np
2324
import xsimlab as xs
2425
import matplotlib.pyplot as plt
2526
@@ -47,12 +48,12 @@ create a new setup in a very declarative way:
4748
4849
in_ds = xs.create_setup(
4950
model=model2,
50-
clocks={'time': {'start': 0, 'end': 1, 'step': 0.01},
51-
'otime': {'data': [0, 0.5, 1]}},
51+
clocks={'time': np.linspace(0., 1., 101),
52+
'otime': [0, 0.5, 1]},
5253
master_clock='time',
5354
input_vars={'grid': {'length': 1.5, 'spacing': 0.01},
54-
'advect': {'v': 1.},
55-
'init': {'loc': 0.3, 'scale': 0.1}},
55+
'init': {'loc': 0.3, 'scale': 0.1},
56+
'advect': {'v': 1.}},
5657
output_vars={None: {'grid': 'x'},
5758
'otime': {'profile': 'u'}}
5859
)
@@ -187,8 +188,7 @@ for the ``otime`` coordinate (which serves to take snapshots of
187188

188189
.. ipython:: python
189190
190-
clocks = {'time': {'data': in_ds.time},
191-
'otime': {'data': [0, 0.25, 0.5]}}
191+
clocks = {'otime': [0, 0.25, 0.5]}
192192
with model2:
193193
out_ds3 = (in_ds.xsimlab.update_clocks(clocks=clocks,
194194
master_clock='time')

doc/whats_new.rst

+12
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,11 @@ changes are effective now!
8787
updating a setup using ``create_setup`` or
8888
``Dataset.xsimlab.update_vars``. this is a regression that will be
8989
fixed in the next releases.
90+
- Argument values for generating clock data in ``create_setup`` and
91+
``Dataset.xsimlab.update_clocks`` have changed and are now more
92+
consistent with how coordinates are set in xarray. Additionally,
93+
``auto_adjust`` has been removed (an error is raised instead when
94+
clock coordinate labels are not synchronized).
9095

9196
- Scalar values from a input ``xarray.Dataset`` are now converted into
9297
scalars (instead of a 0-d numpy array) when setting input model
@@ -117,6 +122,9 @@ Enhancements
117122
but return all variable names in the model.
118123
- ``input_vars`` and ``output_vars`` arguments of ``create_setup`` and
119124
``Dataset.xsimlab.update_vars`` now accepts different formats.
125+
- It is now possible to update only some clocks with
126+
``Dataset.xsimlab.update_clocks`` (previously all existing clock
127+
coordinates were dropped first).
120128

121129
Regressions (will be fixed in future releases)
122130
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -128,6 +136,10 @@ Regressions (will be fixed in future releases)
128136
own name. This may be useful, e.g., for sensitivity analysis, but as
129137
the latter is not implemented yet this feature has been removed and
130138
will be added back in a next release.
139+
- High-level API for generating clock coordinate data (i.e.,
140+
``start``, ``end``, ``step`` and ``auto_adjust`` arguments) is not
141+
supported anymore. This could be added back in a future release in a
142+
cleaner form.
131143

132144
v0.1.1 (20 November 2017)
133145
-------------------------

xsimlab/tests/test_xr_accessor.py

+51-89
Original file line numberDiff line numberDiff line change
@@ -99,88 +99,18 @@ def test_master_clock_dim(self):
9999
ds = xr.Dataset()
100100
assert ds.xsimlab.master_clock_dim is None
101101

102-
def test_set_master_clock_dim(self):
103-
ds = xr.Dataset(coords={'clock': [1, 2], 'clock2': [3, 4]})
104-
105-
ds.xsimlab._set_master_clock_dim('clock')
106-
assert self._master_clock_key in ds.clock.attrs
107-
108-
ds.xsimlab._set_master_clock_dim('clock2')
109-
assert self._master_clock_key not in ds.clock.attrs
110-
assert self._master_clock_key in ds.clock2.attrs
111-
112-
with pytest.raises(KeyError):
113-
ds.xsimlab._set_master_clock_dim('invalid_clock')
114-
115-
def test_set_master_clock(self):
116-
data = [0, 2, 4, 6, 8]
117-
118-
valid_kwargs = [
119-
{'data': data},
120-
# data provided -> ignore other arguments even if invalid
121-
{'data': data, 'end': 0, 'nsteps': -1, 'step': 3},
122-
{'nsteps': 4, 'end': 8, 'step': 2},
123-
{'nsteps': 4, 'end': 8},
124-
{'nsteps': 4, 'step': 2},
125-
{'step': 2, 'end': 8}
126-
]
127-
for kwargs in valid_kwargs:
128-
ds = xr.Dataset()
129-
ds.xsimlab._set_master_clock('clock', **kwargs)
130-
np.testing.assert_array_equal(ds.clock.values, data)
131-
132-
invalid_kwargs = [
133-
{'nsteps': 4, 'end': 8, 'step': 3},
134-
{'start': 1, 'nsteps': 4, 'end': 8, 'step': 2},
135-
{'nsteps': 4}
136-
]
137-
for kwargs in invalid_kwargs:
138-
with pytest.raises(ValueError) as excinfo:
139-
ds = xr.Dataset()
140-
ds.xsimlab._set_master_clock('clock', **kwargs)
141-
assert "Invalid combination" in str(excinfo.value)
102+
# def test_set_master_clock_dim(self):
103+
# ds = xr.Dataset(coords={'clock': [1, 2], 'clock2': [3, 4]})
142104

143-
ds = xr.Dataset()
144-
ds.xsimlab._set_master_clock('clock', data=data,
145-
units='years since 1-1-1 0:0:0',
146-
calendar='365_day')
147-
assert self._master_clock_key in ds.clock.attrs
148-
assert ds.clock.attrs['units'] == 'years since 1-1-1 0:0:0'
149-
assert ds.clock.attrs['calendar'] == '365_day'
150-
151-
with pytest.raises(ValueError) as excinfo:
152-
ds.xsimlab._set_master_clock('clock', data=data)
153-
assert "already exists" in str(excinfo.value)
154-
155-
ds = xr.Dataset()
156-
da = xr.DataArray(data, dims='other_dim')
157-
with pytest.raises(ValueError) as excinfo:
158-
ds.xsimlab._set_master_clock('clock', data=da)
159-
assert "expected dimension" in str(excinfo.value)
105+
# ds.xsimlab._set_master_clock_dim('clock')
106+
# assert self._master_clock_key in ds.clock.attrs
160107

161-
def test_set_snapshot_clock(self):
162-
with pytest.raises(ValueError) as excinfo:
163-
ds = xr.Dataset()
164-
ds.xsimlab._set_snapshot_clock('snap_clock', data=[1, 2])
165-
assert "no master clock" in str(excinfo.value)
108+
# ds.xsimlab._set_master_clock_dim('clock2')
109+
# assert self._master_clock_key not in ds.clock.attrs
110+
# assert self._master_clock_key in ds.clock2.attrs
166111

167-
ds = xr.Dataset()
168-
ds.xsimlab._set_master_clock('clock', data=[0, 2, 4, 6, 8],
169-
units='years since 1-1-1 0:0:0',
170-
calendar='365_day')
171-
172-
ds.xsimlab._set_snapshot_clock('snap_clock', end=8, step=4)
173-
np.testing.assert_array_equal(ds['snap_clock'], [0, 4, 8])
174-
assert self._clock_key in ds['snap_clock'].attrs
175-
assert 'units' in ds['snap_clock'].attrs
176-
assert 'calendar' in ds['snap_clock'].attrs
177-
178-
ds.xsimlab._set_snapshot_clock('snap_clock', data=[0, 3, 8])
179-
np.testing.assert_array_equal(ds['snap_clock'], [0, 4, 8])
180-
181-
with pytest.raises(KeyError):
182-
ds.xsimlab._set_snapshot_clock('snap_clock', data=[0, 3, 8],
183-
auto_adjust=False)
112+
# with pytest.raises(KeyError):
113+
# ds.xsimlab._set_master_clock_dim('invalid_clock')
184114

185115
def test_set_input_vars(self, model, in_dataset):
186116
in_vars = {('init_profile', 'n_points'): 5,
@@ -206,46 +136,78 @@ def test_update_clocks(self, model):
206136
ds = xr.Dataset()
207137
with pytest.raises(ValueError) as excinfo:
208138
ds.xsimlab.update_clocks(model=model, clocks={})
209-
assert "cannot determine which clock" in str(excinfo.value)
139+
assert "Cannot determine which clock" in str(excinfo.value)
210140

211141
ds = xr.Dataset()
212142
with pytest.raises(ValueError) as excinfo:
213143
ds.xsimlab.update_clocks(
214144
model=model,
215-
clocks={'clock': {'data': [0, 1, 2]},
216-
'out': {'data': [0, 2]}}
145+
clocks={'clock': [0, 1, 2],
146+
'out': [0, 2]}
217147
)
218-
assert "cannot determine which clock" in str(excinfo.value)
148+
assert "Cannot determine which clock" in str(excinfo.value)
219149

220150
ds = xr.Dataset()
221151
with pytest.raises(KeyError) as excinfo:
222152
ds.xsimlab.update_clocks(
223153
model=model,
224-
clocks={'clock': {'data': [0, 1, 2]}},
154+
clocks={'clock': [0, 1, 2]},
225155
master_clock='non_existing_clock_dim'
226156
)
227-
assert "master clock dimension name" in str(excinfo.value)
157+
assert "Master clock dimension name" in str(excinfo.value)
158+
159+
ds = xr.Dataset()
160+
with pytest.raises(ValueError) as excinfo:
161+
ds.xsimlab.update_clocks(
162+
model=model,
163+
clocks={'clock': ('x', [0, 1, 2])},
164+
)
165+
assert "Invalid dimension" in str(excinfo.value)
166+
167+
ds = xr.Dataset()
168+
with pytest.raises(ValueError) as excinfo:
169+
ds.xsimlab.update_clocks(
170+
model=model,
171+
clocks={'clock': [0, 1, 2],
172+
'out': [0, 0.5, 2]},
173+
master_clock='clock'
174+
)
175+
assert "not synchronized" in str(excinfo.value)
228176

229177
ds = xr.Dataset()
230178
ds = ds.xsimlab.update_clocks(
231179
model=model,
232-
clocks={'clock': {'data': [0, 1, 2]}}
180+
clocks={'clock': [0, 1, 2]}
233181
)
234182
assert ds.xsimlab.master_clock_dim == 'clock'
235183

236184
ds.clock.attrs[self._output_vars_key] = 'profile__u'
237185

238186
ds = ds.xsimlab.update_clocks(
239187
model=model,
240-
clocks={'clock': {'data': [0, 1, 2]}},
188+
clocks={'clock': [0, 1, 2]},
241189
master_clock={'dim': 'clock',
242190
'units': 'days since 1-1-1 0:0:0',
243191
'calendar': '365_days'}
244192
)
193+
np.testing.assert_array_equal(ds.clock.values, [0, 1, 2])
245194
assert 'units' in ds.clock.attrs
246195
assert 'calendar' in ds.clock.attrs
247196
assert ds.clock.attrs[self._output_vars_key] == 'profile__u'
248197

198+
new_ds = ds.xsimlab.update_clocks(
199+
model=model,
200+
clocks={'clock2': [0, 0.5, 1, 1.5, 2]},
201+
master_clock='clock2'
202+
)
203+
assert new_ds.xsimlab.master_clock_dim == 'clock2'
204+
205+
new_ds = ds.xsimlab.update_clocks(
206+
model=model,
207+
clocks={'out2': [0, 2]}
208+
)
209+
assert new_ds.xsimlab.master_clock_dim == 'clock'
210+
249211
def test_update_vars(self, model, in_dataset):
250212
ds = in_dataset.xsimlab.update_vars(
251213
model=model,
@@ -337,8 +299,8 @@ def test_create_setup(model, in_dataset):
337299
'add__offset': ('clock', [1, 2, 3, 4, 5])
338300
},
339301
clocks={
340-
'clock': {'data': [0, 2, 4, 6, 8]},
341-
'out': {'data': [0, 4, 8]},
302+
'clock': [0, 2, 4, 6, 8],
303+
'out': [0, 4, 8],
342304
},
343305
master_clock='clock',
344306
output_vars={

0 commit comments

Comments
 (0)