Skip to content

Commit

Permalink
Merge pull request #49 from JoyMonteiro/master
Browse files Browse the repository at this point in the history
Fix issue with numpy indexing
  • Loading branch information
JoyMonteiro authored Feb 8, 2023
2 parents f97e211 + e9a7ff6 commit 6cafb58
Show file tree
Hide file tree
Showing 7 changed files with 65 additions and 39 deletions.
5 changes: 5 additions & 0 deletions HISTORY.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,11 @@
What's New
==========

v0.4.1
------

* use tuple instead of list to index numpy arrays

v0.4.0
------

Expand Down
2 changes: 1 addition & 1 deletion sympl/_components/netcdf.py
Original file line number Diff line number Diff line change
Expand Up @@ -250,7 +250,7 @@ def load(self):
state = {}
for name, value in dataset.data_vars.items():
state[name] = DataArray(value[0, :]) # remove time axis
state['time'] = datetime64_to_datetime(dataset['time'][0])
state['time'] = datetime64_to_datetime(dataset['time'][0].values)
return state


Expand Down
2 changes: 2 additions & 0 deletions sympl/_core/dataarray.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@


class DataArray(xr.DataArray):

__slots__ = ()

def __add__(self, other):
"""If this DataArray is on the left side of the addition, keep its
Expand Down
6 changes: 3 additions & 3 deletions sympl/_core/tracers.py
Original file line number Diff line number Diff line change
Expand Up @@ -199,7 +199,7 @@ def pack(self, state):
for i, name in enumerate(self.tracer_names):
tracer_slice = [slice(0, d) for d in shape]
tracer_slice[self._tracer_index] = i
array[tracer_slice] = raw_state[name]
array[tuple(tracer_slice)] = raw_state[name]
return array

def unpack(self, tracer_array, input_state, multiply_unit=''):
Expand All @@ -226,11 +226,11 @@ def unpack(self, tracer_array, input_state, multiply_unit=''):
for i, name in enumerate(self.tracer_names):
tracer_slice = [slice(0, d) for d in tracer_array.shape]
tracer_slice[self._tracer_index] = i
raw_state[name] = tracer_array[tracer_slice]
raw_state[name] = tracer_array[tuple(tracer_slice)]
out_properties = {}
for name, properties in tracer_properties.items():
out_properties[name] = properties.copy()
if multiply_unit is not '':
if multiply_unit != '':
out_properties[name]['units'] = '{} {}'.format(
out_properties[name]['units'], multiply_unit)
return_state = restore_data_arrays_with_properties(
Expand Down
10 changes: 5 additions & 5 deletions sympl/_core/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ def get_numpy_array(
data_array, out_dims, direction_to_names)
final_shape = get_final_shape(data_array, out_dims, direction_to_names)
return_array = np.reshape(data_array.transpose(
*target_dimension_order).values[slices_or_none], final_shape)
*target_dimension_order).values[tuple(slices_or_none)], final_shape)
if return_wildcard_matches:
wildcard_matches = {
key: value for key, value in direction_to_names.items()
Expand Down Expand Up @@ -181,7 +181,7 @@ def restore_dimensions(array, from_dims, result_like, result_attrs=None):


def datetime64_to_datetime(dt64):
ts = (dt64 - np.datetime64('1970-01-01T00:00:00Z')) / np.timedelta64(1, 's')
ts = (dt64 - np.datetime64('1970-01-01T00:00:00')) / np.timedelta64(1, 's')
return datetime.utcfromtimestamp(ts)


Expand Down Expand Up @@ -301,13 +301,13 @@ def get_slices_and_placeholder_nones(data_array, out_dims, direction_to_names):
for direction in out_dims:
if len(direction_to_names[direction]) == 0:
slices_or_none.append(None)
elif (direction is not '*') and (len(direction_to_names[direction]) > 1):
elif (direction != '*') and (len(direction_to_names[direction]) > 1):
raise ValueError(
'DataArray has multiple dimensions for a single direction')
else:
for name in direction_to_names[direction]:
slices_or_none.append(slice(0, len(data_array.coords[name])))
return slices_or_none
return tuple(slices_or_none)


def get_final_shape(data_array, out_dims, direction_to_names):
Expand All @@ -325,7 +325,7 @@ def get_final_shape(data_array, out_dims, direction_to_names):
final_shape.append(
np.product([len(data_array.coords[name])
for name in direction_to_names[direction]]))
return final_shape
return tuple(final_shape)


def get_component_aliases(*args):
Expand Down
76 changes: 47 additions & 29 deletions tests/test_get_restore_numpy_array.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,13 @@
import numpy as np
import unittest

def arrays_share_same_memory_space(source, target):

if target.base is None:
return target is source
else:
return target.base is source


def test_get_numpy_array_3d_no_change():
array = DataArray(
Expand All @@ -17,7 +24,7 @@ def test_get_numpy_array_3d_no_change():
numpy_array = get_numpy_array(array, ['x', 'y', 'z'])
assert np.byte_bounds(numpy_array) == np.byte_bounds(array.values)
assert np.all(numpy_array == array.values)
assert numpy_array.base is array.values
assert arrays_share_same_memory_space(array.values, numpy_array)


def test_get_numpy_array_3d_reverse():
Expand All @@ -30,7 +37,7 @@ def test_get_numpy_array_3d_reverse():
assert numpy_array.shape == (4, 3, 2)
assert np.all(np.transpose(numpy_array, (2, 1, 0)) == array.values)
assert np.byte_bounds(numpy_array) == np.byte_bounds(array.values)
assert numpy_array.base is array.values
assert arrays_share_same_memory_space(array.values, numpy_array)


def test_get_numpy_array_2d_reverse():
Expand All @@ -43,7 +50,7 @@ def test_get_numpy_array_2d_reverse():
assert numpy_array.shape == (3, 2)
assert np.all(np.transpose(numpy_array, (1, 0)) == array.values)
assert np.byte_bounds(numpy_array) == np.byte_bounds(array.values)
assert numpy_array.base is array.values
assert arrays_share_same_memory_space(array.values, numpy_array)


def test_get_numpy_array_1d():
Expand All @@ -56,7 +63,7 @@ def test_get_numpy_array_1d():
assert numpy_array.shape == (2,)
assert np.all(numpy_array == array.values)
assert np.byte_bounds(numpy_array) == np.byte_bounds(array.values)
assert numpy_array.base is array.values
assert arrays_share_same_memory_space(array.values, numpy_array)


def test_get_numpy_array_creates_new_dim():
Expand All @@ -69,7 +76,7 @@ def test_get_numpy_array_creates_new_dim():
assert numpy_array.shape == (2, 1)
assert np.all(numpy_array[:, 0] == array.values)
assert np.byte_bounds(numpy_array) == np.byte_bounds(array.values)
assert numpy_array.base is array.values
assert arrays_share_same_memory_space(array.values, numpy_array)


def test_get_numpy_array_creates_new_dim_in_front():
Expand All @@ -82,7 +89,7 @@ def test_get_numpy_array_creates_new_dim_in_front():
assert numpy_array.shape == (1, 2)
assert np.all(numpy_array[0, :] == array.values)
assert np.byte_bounds(numpy_array) == np.byte_bounds(array.values)
assert numpy_array.base is array.values
assert arrays_share_same_memory_space(array.values, numpy_array)


def test_get_numpy_array_retrieves_explicit_dimensions():
Expand All @@ -95,7 +102,7 @@ def test_get_numpy_array_retrieves_explicit_dimensions():
assert numpy_array.shape == (3, 2)
assert np.all(np.transpose(numpy_array, (1, 0)) == array.values)
assert np.byte_bounds(numpy_array) == np.byte_bounds(array.values)
assert numpy_array.base is array.values
assert arrays_share_same_memory_space(array.values, numpy_array)


def test_get_numpy_array_invalid_dimension_raises_value_error():
Expand Down Expand Up @@ -124,7 +131,7 @@ def test_get_numpy_array_invalid_dimension_collected_by_asterisk():
assert numpy_array.shape == (2,)
assert np.all(numpy_array == array.values)
assert np.byte_bounds(numpy_array) == np.byte_bounds(array.values)
assert numpy_array.base is array.values
assert arrays_share_same_memory_space(array.values, numpy_array)


def test_get_numpy_array_dimension_not_listed_raises_value_error():
Expand Down Expand Up @@ -185,7 +192,7 @@ def test_get_numpy_array_asterisk_creates_new_dim():
assert numpy_array.shape == (2, 1)
assert np.all(numpy_array[:, 0] == array.values)
assert np.byte_bounds(numpy_array) == np.byte_bounds(array.values)
assert numpy_array.base is array.values
assert arrays_share_same_memory_space(array.values, numpy_array)


def test_get_numpy_array_asterisk_creates_new_dim_reversed():
Expand All @@ -198,7 +205,7 @@ def test_get_numpy_array_asterisk_creates_new_dim_reversed():
assert numpy_array.shape == (1, 2)
assert np.all(numpy_array[0, :] == array.values)
assert np.byte_bounds(numpy_array) == np.byte_bounds(array.values)
assert numpy_array.base is array.values
assert arrays_share_same_memory_space(array.values, numpy_array)


def test_get_numpy_array_asterisk_flattens():
Expand All @@ -211,7 +218,7 @@ def test_get_numpy_array_asterisk_flattens():
assert numpy_array.shape == (6,)
assert np.all(numpy_array.reshape((2, 3)) == array.values)
assert np.byte_bounds(numpy_array) == np.byte_bounds(array.values)
assert numpy_array.base is array.values
assert arrays_share_same_memory_space(array.values, numpy_array)


def test_get_numpy_array_complicated_asterisk():
Expand Down Expand Up @@ -239,7 +246,7 @@ def test_get_numpy_array_zyx_to_starz_doesnt_copy():
assert np.all(numpy_array[:, i] == array.values[i, :, :].flatten())
assert original_array is array.values
assert np.byte_bounds(numpy_array) == np.byte_bounds(array.values)
assert numpy_array.base is array.values
assert arrays_share_same_memory_space(array.values, numpy_array)


def test_restore_dimensions_complicated_asterisk():
Expand Down Expand Up @@ -330,7 +337,8 @@ def test_restore_dimensions_starz_to_zyx_doesnt_copy():
numpy_array, from_dims=['*', 'z'], result_like=array)
assert np.byte_bounds(restored_array.values) == np.byte_bounds(
array.values)
assert restored_array.values.base is array.values
assert arrays_share_same_memory_space(
array.values, restored_array.values)


def test_restore_dimensions_starz_to_zyx_with_attrs():
Expand Down Expand Up @@ -361,7 +369,8 @@ def test_restore_dimensions_3d_reverse():
assert len(restored_array.attrs) == 0
assert np.byte_bounds(restored_array.values) == np.byte_bounds(
array.values)
assert restored_array.values.base is array.values
assert arrays_share_same_memory_space(
array.values, restored_array.values)


def test_restore_dimensions_1d_flatten():
Expand All @@ -377,7 +386,8 @@ def test_restore_dimensions_1d_flatten():
assert len(restored_array.attrs) == 0
assert np.byte_bounds(restored_array.values) == np.byte_bounds(
array.values)
assert restored_array.values.base is array.values
assert arrays_share_same_memory_space(
array.values, restored_array.values)


def test_restore_dimensions_2d_flatten():
Expand All @@ -393,7 +403,8 @@ def test_restore_dimensions_2d_flatten():
assert len(restored_array.attrs) == 0
assert np.byte_bounds(restored_array.values) == np.byte_bounds(
array.values)
assert restored_array.values.base is array.values
assert arrays_share_same_memory_space(
array.values, restored_array.values)


def test_restore_dimensions_removes_dummy_axes():
Expand All @@ -409,9 +420,9 @@ def test_restore_dimensions_removes_dummy_axes():
assert len(restored_array.attrs) == 0
assert np.byte_bounds(restored_array.values) == np.byte_bounds(
array.values)
assert restored_array.values.base is array.values


assert arrays_share_same_memory_space(
array.values, restored_array.values)
class GetNumpyArraysWithPropertiesTests(unittest.TestCase):

def test_returns_numpy_array(self):
Expand All @@ -435,7 +446,8 @@ def test_returns_numpy_array(self):
assert isinstance(return_value['air_temperature'], np.ndarray)
assert np.byte_bounds(return_value['air_temperature']) == np.byte_bounds(
T_array)
assert return_value['air_temperature'].base is T_array
assert arrays_share_same_memory_space(
return_value['air_temperature'], T_array)

def test_returns_numpy_array_using_alias(self):
T_array = np.zeros([2, 3, 4], dtype=np.float64) + 280.
Expand All @@ -459,7 +471,8 @@ def test_returns_numpy_array_using_alias(self):
assert isinstance(return_value['T'], np.ndarray)
assert np.byte_bounds(return_value['T']) == np.byte_bounds(
T_array)
assert return_value['T'].base is T_array
assert arrays_share_same_memory_space(
return_value['T'], T_array)

def test_returns_numpy_array_alias_doesnt_apply_to_state(self):
T_array = np.zeros([2, 3, 4], dtype=np.float64) + 280.
Expand Down Expand Up @@ -529,7 +542,8 @@ def test_scalar_becomes_multidimensional_array(self):
assert len(return_value['air_temperature'].shape) == 1
assert np.byte_bounds(return_value['air_temperature']) == np.byte_bounds(
T_array)
assert return_value['air_temperature'].base is T_array
assert arrays_share_same_memory_space(
T_array, return_value['air_temperature'])

def test_creates_length_1_dimensions(self):
T_array = np.zeros([4], dtype=np.float64) + 280.
Expand All @@ -553,7 +567,8 @@ def test_creates_length_1_dimensions(self):
assert np.byte_bounds(
return_value['air_temperature']) == np.byte_bounds(
T_array)
assert return_value['air_temperature'].base is T_array
assert arrays_share_same_memory_space(
T_array, return_value['air_temperature'])
assert return_value['air_temperature'].shape == (1, 4)

def test_only_requested_properties_are_returned(self):
Expand Down Expand Up @@ -932,8 +947,9 @@ def test_returns_simple_value(self):
assert np.byte_bounds(
return_value['air_temperature_tendency'].values) == np.byte_bounds(
input_state['air_temperature'].values)
assert (return_value['air_temperature_tendency'].values.base is
input_state['air_temperature'].values)
assert (arrays_share_same_memory_space(
return_value['air_temperature_tendency'].values,
input_state['air_temperature'].values))
assert return_value['air_temperature_tendency'].shape == (2, 2, 4)


Expand Down Expand Up @@ -967,8 +983,9 @@ def test_assumes_dims_like_own_name(self):
assert np.byte_bounds(
return_value['air_temperature'].values) == np.byte_bounds(
input_state['air_temperature'].values)
assert (return_value['air_temperature'].values.base is
input_state['air_temperature'].values)
assert (arrays_share_same_memory_space(
return_value['air_temperature'].values,
input_state['air_temperature'].values))
assert return_value['air_temperature'].shape == (2, 2, 4)

def test_restores_collected_horizontal_dimensions(self):
Expand Down Expand Up @@ -1005,8 +1022,9 @@ def test_restores_collected_horizontal_dimensions(self):
assert np.byte_bounds(
return_value['air_temperature_tendency'].values) == np.byte_bounds(
input_state['air_temperature'].values)
assert (return_value['air_temperature_tendency'].values.base is
input_state['air_temperature'].values)
assert (arrays_share_same_memory_space(
input_state['air_temperature'].values,
return_value['air_temperature_tendency'].values))
assert return_value['air_temperature_tendency'].dims == ('z', 'x', 'y')
assert return_value['air_temperature_tendency'].shape == (4, 3, 2)
for i in range(4):
Expand Down
3 changes: 2 additions & 1 deletion tox.ini
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ commands=flake8 sympl

[flake8]
; Ignoring line lengths and requirement of space around arithmetic operators
ignore = E501,E226
; also ignoring "line break after binary operator"
ignore = E501,E226,W504

[testenv]
setenv =
Expand Down

0 comments on commit 6cafb58

Please sign in to comment.