Skip to content

Commit

Permalink
- Python: fix for scalar reading. If a global value has 1 step (i.e. …
Browse files Browse the repository at this point in the history
…always in streaming), read returns a 0-dim numpy array (single value). If the variable has multiple steps (only in ReadRandomAccess mode), read returns a 1-dim numpy array even if the step selection is a single step. This way, read of a certain variable always results in the same type of array no matter the number of steps selected.

- Python: fix for string attributes: return a string, not a list of one element which is a string, to be consistent with string global values and with other APIs.
  • Loading branch information
pnorbert committed Mar 7, 2024
1 parent 0b29dde commit acc1c53
Show file tree
Hide file tree
Showing 6 changed files with 113 additions and 47 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,18 @@
for key, value in info.items():
print("\t" + key + ": " + value, end=" ")
print()
print()

nproc = s.read("nproc")
print(f"nproc is {nproc} of type {type(nproc)}")
print(f"nproc is {nproc} of type {type(nproc)} with ndim {nproc.ndim}")

# read variables return a numpy array with corresponding selection
steps = int(vars["physical_time"]["AvailableStepsCount"])
physical_time = s.read("physical_time", step_selection=[0, steps])
print(f"physical_time is {physical_time} of type {type(physical_time)}")
print(
f"physical_time is {physical_time} of type {type(physical_time)} with "
f"ndim {physical_time.ndim} shape = {physical_time.shape}"
)

steps = int(vars["temperature"]["AvailableStepsCount"])
temperature = s.read("temperature", step_selection=[0, steps])
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@

if s.current_step() == 0:
nproc = s.read("nproc")
print(f"nproc is {nproc} of type {type(nproc)}")
print(f"nproc is {nproc} of type {type(nproc)} with ndim {nproc.ndim}")

# read variables return a numpy array with corresponding selection
physical_time = s.read("physical_time")
Expand All @@ -26,6 +26,6 @@
print(f"temperature array size is {temperature.size} of shape {temperature.shape}")
print(f"temperature unit is {temp_unit} of type {type(temp_unit)}")
pressure = s.read("pressure")
press_unit = s.read_attribute("pressure/unit")
press_unit = s.read_attribute("unit", "pressure")
print(f"pressure unit is {press_unit} of type {type(press_unit)}")
print()
24 changes: 15 additions & 9 deletions docs/user_guide/source/api_python/python_example.rst
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ Python Write example
count = [nx]
temperature = np.zeros(nx, dtype=np.double)
pressure = np.ones(nx, dtype=np.double)
delta_time = 0.01
physical_time = 0.0
nsteps = 5
Expand Down Expand Up @@ -125,17 +126,17 @@ Python Read "step-by-step" example
nproc is 4 of type <class 'numpy.ndarray'>
physical_time is 0.0 of type <class 'numpy.ndarray'>
temperature array size is 40 of shape (40,)
temperature unit is ['K'] of type <class 'list'>
pressure unit is ['Pa'] of type <class 'list'>
temperature unit is K of type <class 'str'>
pressure unit is Pa of type <class 'str'>
Current step is 1
variable_name: physical_time AvailableStepsCount: 1 Max: 0.01 Min: 0.01 Shape: SingleValue: true Type: double
variable_name: pressure AvailableStepsCount: 1 Max: 1 Min: 1 Shape: 40 SingleValue: false Type: double
variable_name: temperature AvailableStepsCount: 1 Max: 0 Min: 0 Shape: 40 SingleValue: false Type: double
physical_time is 0.01 of type <class 'numpy.ndarray'>
temperature array size is 40 of shape (40,)
temperature unit is ['K'] of type <class 'list'>
pressure unit is ['Pa'] of type <class 'list'>
temperature unit is K of type <class 'str'>
pressure unit is Pa of type <class 'str'>
...
Expand All @@ -156,14 +157,18 @@ Python Read Random Access example
for key, value in info.items():
print("\t" + key + ": " + value, end=" ")
print()
print()
nproc = s.read("nproc")
print(f"nproc is {nproc} of type {type(nproc)}")
print(f"nproc is {nproc} of type {type(nproc)} with ndim {nproc.ndim}")
# read variables return a numpy array with corresponding selection
steps = int(vars['physical_time']['AvailableStepsCount'])
physical_time = s.read("physical_time", step_selection=[0, steps])
print(f"physical_time is {physical_time} of type {type(physical_time)}")
print(
f"physical_time is {physical_time} of type {type(physical_time)} with "
f"ndim {physical_time.ndim} shape = {physical_time.shape}"
)
steps = int(vars['temperature']['AvailableStepsCount'])
temperature = s.read("temperature", step_selection=[0, steps])
Expand All @@ -183,8 +188,9 @@ Python Read Random Access example
variable_name: physical_time AvailableStepsCount: 5 Max: 0.04 Min: 0 Shape: SingleValue: true Type: double
variable_name: pressure AvailableStepsCount: 5 Max: 1 Min: 1 Shape: 40 SingleValue: false Type: double
variable_name: temperature AvailableStepsCount: 5 Max: 0 Min: 0 Shape: 40 SingleValue: false Type: double
nproc is 4 of type <class 'numpy.ndarray'>
physical_time is [0. 0.01 0.02 0.03 0.04] of type <class 'numpy.ndarray'>
nproc is 4 of type <class 'numpy.ndarray'> with ndim 0
physical_time is [0. 0.01 0.02 0.03 0.04] of type <class 'numpy.ndarray'> with ndim 1 shape = (5,)
temperature array size is 200 of shape (200,)
temperature unit is ['K'] of type <class 'list'>
temperature unit is K of type <class 'str'>
4 changes: 0 additions & 4 deletions python/adios2/file_reader.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,3 @@ def _(self, io: IO, path, comm=None):
super().__init__(io, path, "rra", comm)

# pylint: enable=E1121

def variables(self):
"""Returns the list of variables contained in the opened file"""
return [self._io.inquire_variable(var) for var in self.available_variables()]
62 changes: 46 additions & 16 deletions python/adios2/stream.py
Original file line number Diff line number Diff line change
Expand Up @@ -325,11 +325,9 @@ def _(self, name, content, shape=[], start=[], count=[], operations=None):

self.write(variable, content)

@singledispatchmethod
def read(self, variable: Variable):
def _read_var(self, variable: Variable):
"""
Random access read allowed to select steps,
only valid with Stream Engines
Internal common function to read. Settings must be done to Variable before the call.
Parameters
variable
Expand All @@ -342,6 +340,7 @@ def read(self, variable: Variable):
"""
dtype = type_adios_to_numpy(variable.type())
count = variable.count()

if count != []:
# array
# steps = variable.get_steps_from_step_selection()
Expand All @@ -365,7 +364,8 @@ def read(self, variable: Variable):
else:
# scalar
size_all_steps = variable.selection_size()
if size_all_steps > 1:
# if size_all_steps > 1:
if self._mode == bindings.Mode.ReadRandomAccess and variable.steps() > 1:
output_shape = [size_all_steps]
else:
output_shape = []
Expand All @@ -374,15 +374,17 @@ def read(self, variable: Variable):
self._engine.get(variable, output)
return output

@read.register(str)
def _(self, name: str, start=[], count=[], block_id=None, step_selection=None):
@singledispatchmethod
def read(self, variable: Variable, start=[], count=[], block_id=None, step_selection=None):
"""
Random access read allowed to select steps,
only valid with Stream Engines
Read a variable.
Random access read allowed to select steps.
Parameters
name
variable to be read
variable
adios2.Variable object to be read
Use variable.set_selection(), set_block_selection(), set_step_selection()
to prepare a read
start
variable offset dimensions
Expand All @@ -400,10 +402,6 @@ def _(self, name: str, start=[], count=[], block_id=None, step_selection=None):
array
resulting array from selection
"""
variable = self._io.inquire_variable(name)
if not variable:
raise ValueError()

if step_selection is not None and not self._mode == bindings.Mode.ReadRandomAccess:
raise RuntimeError("step_selection parameter requires 'rra' mode")

Expand All @@ -419,7 +417,39 @@ def _(self, name: str, start=[], count=[], block_id=None, step_selection=None):
if start != [] and count != []:
variable.set_selection([start, count])

return self.read(variable)
return self._read_var(variable)

@read.register(str)
def _(self, name: str, start=[], count=[], block_id=None, step_selection=None):
"""
Read a variable.
Random access read allowed to select steps.
Parameters
name
variable to be read
start
variable offset dimensions
count
variable local dimensions from offset
block_id
(int) Required for reading local variables, local array, and local
value.
step_selection
(list): On the form of [start, count].
Returns
array
resulting array from selection
"""
variable = self._io.inquire_variable(name)
if not variable:
raise ValueError()

return self.read(variable, start, count, block_id, step_selection)

def write_attribute(self, name, content, variable_name="", separator="/"):
"""
Expand Down
58 changes: 44 additions & 14 deletions testing/adios2/python/TestFileReader.py
Original file line number Diff line number Diff line change
@@ -1,45 +1,75 @@
from adios2 import FileReader, Stream
from adios2 import FileReader, Stream, LocalValueDim
from random import randint

import unittest


class TestStream(unittest.TestCase):
class TestFileReader(unittest.TestCase):
def test_basic(self):
with Stream("pythonfiletest.bp", "w") as s:
for _ in s.steps(10):
if s.current_step() == 0:
# String
s.write("Outlook", "Good")
# Global Value single step
s.write("LocationID", 42)
# Global Array
s.write(
"temp",
"Temp",
content=[randint(15, 35), randint(15, 35), randint(15, 35)],
shape=[3],
start=[0],
count=[3],
)
# Local Value
s.write("Wind", [5], shape=[LocalValueDim])
# Local Array
s.write("Coords", [38, -46], [], [], [2])
# Global Value every step
s.write("Hour", 8 + s.current_step())

with FileReader("pythonfiletest.bp") as f:
self.assertEqual(len(f.all_blocks_info("temp")), 10)
for var in f.variables():
outlook_var = f.inquire_variable("Outlook")
outlook = f.read(outlook_var)
self.assertEqual(outlook, "Good")

for name in f.available_variables():
var = f.inquire_variable(name)
if not var.type() == "string":
self.assertEqual(var.steps(), 10)
if var.steps() > 1:
self.assertEqual(var.steps(), 10)
var.set_step_selection([0, var.steps()])

output = f.read(var.name())
print(f"var:{var.name()} output:{output}")
output = f.read(var)
print(f"var:{var.name()} output:{output}")

with FileReader("pythonfiletest.bp") as f:
output = f.read("temp", step_selection=[0, 10])
output = f.read("LocationID")
self.assertEqual(output.ndim, 0)
self.assertEqual(output.size, 1)
self.assertEqual(output, 42)

output = f.read("Hour", step_selection=[0, 10])
self.assertEqual(output.ndim, 1)
self.assertEqual(output.size, 10)
self.assertTrue((output == [8, 9, 10, 11, 12, 13, 14, 15, 16, 17]).all())

output = f.read("Hour", step_selection=[5, 1])
self.assertEqual(output.ndim, 1)
self.assertEqual(output.size, 1)
self.assertEqual(output, [13])

output = f.read("Temp", step_selection=[0, 10])
self.assertEqual(len(output), 30)
print(f"var:temp output:{output}")
print(f"var:Temp output:{output}")

output = f.read("temp", step_selection=[0, 5])
output = f.read("Temp", step_selection=[0, 5])
self.assertEqual(len(output), 15)
print(f"var:temp output:{output}")
print(f"var:Temp output:{output}")

output = f.read("temp", start=[0], count=[2], step_selection=[0, 10])
output = f.read("Temp", start=[0], count=[2], step_selection=[0, 10])
self.assertEqual(len(output), 20)
print(f"var:temp output:{output}")
print(f"var:Temp output:{output}")


if __name__ == "__main__":
Expand Down

0 comments on commit acc1c53

Please sign in to comment.