Skip to content

Commit 9703458

Browse files
committed
MR: Implement Chunked Slicing
1 parent b8b5a48 commit 9703458

File tree

2 files changed

+55
-40
lines changed

2 files changed

+55
-40
lines changed

openpmd_viewer/openpmd_timeseries/data_reader/io_reader/utilities.py

Lines changed: 53 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,14 @@
1313

1414
def chunk_to_slice(chunk):
1515
"""
16-
Convert an openPMD_api.ChunkInfo to np.s_
16+
Convert an openPMD_api.ChunkInfo to slice
1717
"""
1818
stops = [a + b for a, b in zip(chunk.offset, chunk.extent)]
1919
indices_per_dim = zip(chunk.offset, stops)
2020
index_tuple = map(lambda s: slice(s[0], s[1], None), indices_per_dim)
2121
return tuple(index_tuple)
2222

23+
2324
def get_data(series, record_component, i_slice=None, pos_slice=None,
2425
output_type=np.float64):
2526
"""
@@ -67,46 +68,60 @@ def get_data(series, record_component, i_slice=None, pos_slice=None,
6768
series.flush()
6869
data[chunk_slice] = x
6970
else:
70-
# Get largest element of pos_slice
71-
max_pos = max(pos_slice)
72-
# Create list of indices list_index of type
73-
# [:, :, :, ...] where Ellipsis starts at max_pos + 1
74-
list_index = [np.s_[:]] * (max_pos + 2)
75-
list_index[max_pos + 1] = np.s_[...]
76-
# Fill list_index with elements of i_slice
77-
for count, dir_index in enumerate(pos_slice):
78-
list_index[dir_index] = i_slice[count]
79-
# Convert list_index into a tuple
80-
tuple_index = tuple(list_index)
81-
print("tuple_index={}".format(tuple_index))
82-
83-
# potentially a better approach as below, since we only slice
84-
# out hyperplanes, planes & lines:
85-
# - allocate zero array for result, which is a hyperplane/plane/line
86-
# - iterate over slices in tuple_index
87-
# - reduce selected read range to "valid" range
88-
89-
# initial experiment:
90-
# full_indices can be HUGE, avoid!!
91-
full_indices = np.indices(record_component.shape)[0]
92-
#full_shape = full_indices.shape
93-
#print("full_shape.shape={}".format(full_shape))
94-
#print("full_shape={}".format(full_shape))
95-
96-
# prepare sliced data according to tuple_index
97-
slice_indices = full_indices[tuple_index]
98-
slice_shape = slice_indices.shape
71+
full_shape = record_component.shape
72+
73+
slice_shape = list(full_shape) # copy
74+
pos_slice_sorted = pos_slice.copy() # copy for in-place sort
75+
pos_slice_sorted.sort(reverse=True)
76+
for dir_index in pos_slice_sorted: # remove indices in list
77+
# future note: slice_shape needs to be converted to list and back
78+
# to tuple once we fix
79+
# https://github.com/openPMD/openPMD-api/issues/808
80+
del slice_shape[dir_index]
81+
82+
# mask invalid regions with zero
9983
data = np.zeros(slice_shape, dtype=output_type)
100-
# write now in index space between intersection of slice_indices and chunk indices
84+
85+
# build requested ND slice with respect to full data
86+
s = []
87+
for d in range(len(full_shape)):
88+
if d in pos_slice:
89+
s.append(i_slice[pos_slice.index(d)]) # one index in such directions
90+
else: # all indices in other direction
91+
s.append(slice(None, None, None))
92+
s = tuple(s)
93+
94+
# now we check which chunks contribute to the slice
10195
for chunk in chunks:
96+
skip_this_chunk = False
97+
s_valid = list(s) # same as s but reduced to valid regions in chunk
98+
s_target = [] # starts and stops in sliced array
10299
chunk_slice = chunk_to_slice(chunk)
103-
chunk_indices = full_indices[chunk_slice]
104-
intersect_indices = np.intersect1d(chunk_indices, slice_indices)
105-
print(intersect_indices)
106-
data[slice_indices] = record_component[intersect_indices]
107-
#data = np.zeros_like(record_component)[tuple_index] # just avoid invalid reads for now
108-
109-
series.flush()
100+
# read only valid region
101+
for d, slice_d in enumerate(s):
102+
start = chunk_slice[d].start
103+
stop = chunk_slice[d].stop
104+
if isinstance(slice_d, int):
105+
# Nothing to do for s_target (dimension sliced out)
106+
# Nothing to do for s_valid (dimension index is set)
107+
if slice_d < start or slice_d >= stop:
108+
# chunk not in slice line/plane
109+
skip_this_chunk = True
110+
else:
111+
if slice_d.start is None or slice_d.start < start:
112+
s_valid[d] = slice(start, s_valid[d].stop)
113+
if slice_d.stop is None or slice_d.stop > stop:
114+
s_valid[d] = slice(s_valid[d].start, stop)
115+
s_target.append(slice(start, stop))
116+
117+
s_valid = tuple(s_valid)
118+
s_target = tuple(s_target)
119+
120+
# read
121+
if not skip_this_chunk:
122+
x = record_component[s_valid]
123+
series.flush()
124+
data[s_target] = x
110125

111126
# Convert to the right type
112127
if data.dtype != output_type:

setup.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,12 +38,12 @@ def run_tests(self):
3838
tests_require=['pytest', 'jupyter'],
3939
install_requires=install_requires,
4040
extras_require = {
41-
'all': ["ipympl", "ipywidgets", "matplotlib", "numba", "openpmd-api~=0.13.3,~=0.14.0", "wget"],
41+
'all': ["ipympl", "ipywidgets", "matplotlib", "numba", "openpmd-api~=0.14.0", "wget"],
4242
'GUI': ["ipywidgets", "ipympl", "matplotlib"],
4343
'plot': ["matplotlib"],
4444
'tutorials': ["ipywidgets", "ipympl", "matplotlib", "wget"],
4545
'numba': ["numba"],
46-
'openpmd-api': ["openpmd-api~=0.13.3,~=0.14.0"]
46+
'openpmd-api': ["openpmd-api~=0.14.0"]
4747
},
4848
cmdclass={'test': PyTest},
4949
platforms='any',

0 commit comments

Comments
 (0)