Skip to content

Commit a6993a9

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

File tree

1 file changed

+50
-38
lines changed
  • openpmd_viewer/openpmd_timeseries/data_reader/io_reader

1 file changed

+50
-38
lines changed

openpmd_viewer/openpmd_timeseries/data_reader/io_reader/utilities.py

Lines changed: 50 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,57 @@ 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+
for dir_index, index in zip(pos_slice, i_slice):
73+
slice_shape = list(full_shape) # copy
74+
# future note: this needs to be converted to list and back to
75+
# tuple once we fix
76+
# https://github.com/openPMD/openPMD-api/issues/808
77+
del slice_shape[dir_index]
78+
79+
# mask invalid regions with zero
9980
data = np.zeros(slice_shape, dtype=output_type)
100-
# write now in index space between intersection of slice_indices and chunk indices
81+
82+
# build requested ND slice with respect to full data
83+
s = []
84+
for d in range(len(full_shape)):
85+
if d in pos_slice:
86+
s.append(index) # one index in such directions
87+
else: # all indices in other direction
88+
s.append(slice(None, None, None))
89+
s = tuple(s)
90+
91+
# now we check which chunks contribute to the slice
10192
for chunk in chunks:
93+
skip_this_chunk = False
94+
s_valid = list(s) # same as s but reduced to valid regions in chunk
95+
s_target = [] # starts and stops in sliced array
10296
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()
97+
# read only valid region
98+
for d, slice_d in enumerate(s):
99+
start = chunk_slice[d].start
100+
stop = chunk_slice[d].stop
101+
if isinstance(slice_d, int):
102+
# Nothing to do for s_target (dimension sliced out)
103+
# Nothing to do for s_valid (dimension index is set)
104+
if slice_d < start or slice_d > stop:
105+
# chunk not in slice line/plane
106+
skip_this_chunk = True
107+
else:
108+
if slice_d.start is None or slide_dir.start < start:
109+
s_valid[d] = slice(start, s_valid[d].stop)
110+
if slice_d.start is None or slide_dir.start > stop:
111+
s_valid[d] = slice(s_valid[d].start, stop)
112+
s_target.append(slice(start, stop))
113+
114+
s_valid = tuple(s_valid)
115+
s_target = tuple(s_target)
116+
117+
# read
118+
if not skip_this_chunk:
119+
x = record_component[s_valid]
120+
series.flush()
121+
data[s_target] = x
110122

111123
# Convert to the right type
112124
if data.dtype != output_type:

0 commit comments

Comments
 (0)