Skip to content
Snippets Groups Projects
Commit 5557c6cc authored by Christoph Alt's avatar Christoph Alt
Browse files

Merge branch 'fhennig/fix-field-memory-descriptors' into 'v2.0-dev'

fix memory layout descriptor parsing (v2.0-dev edition)

See merge request pycodegen/pystencils!432
parents 6ded5017 bd27e85d
Branches
No related tags found
No related merge requests found
...@@ -988,24 +988,35 @@ def create_numpy_array_with_layout(shape, layout, alignment=False, byte_offset=0 ...@@ -988,24 +988,35 @@ def create_numpy_array_with_layout(shape, layout, alignment=False, byte_offset=0
def spatial_layout_string_to_tuple(layout_str: str, dim: int) -> Tuple[int, ...]: def spatial_layout_string_to_tuple(layout_str: str, dim: int) -> Tuple[int, ...]:
if layout_str in ('fzyx', 'zyxf'): if dim <= 0:
assert dim <= 3 raise ValueError("Dimensionality must be positive")
return tuple(reversed(range(dim)))
layout_str = layout_str.lower()
if layout_str in ('fzyx', 'f', 'reverse_numpy', 'SoA'): if layout_str in ('fzyx', 'zyxf', 'soa', 'aos'):
if dim > 3:
raise ValueError(f"Invalid spatial dimensionality for layout descriptor {layout_str}: May be at most 3.")
return tuple(reversed(range(dim)))
if layout_str in ('f', 'reverse_numpy'):
return tuple(reversed(range(dim))) return tuple(reversed(range(dim)))
elif layout_str in ('c', 'numpy', 'AoS'): elif layout_str in ('c', 'numpy'):
return tuple(range(dim)) return tuple(range(dim))
raise ValueError("Unknown layout descriptor " + layout_str) raise ValueError("Unknown layout descriptor " + layout_str)
def layout_string_to_tuple(layout_str, dim): def layout_string_to_tuple(layout_str, dim):
if dim <= 0:
raise ValueError("Dimensionality must be positive")
layout_str = layout_str.lower() layout_str = layout_str.lower()
if layout_str == 'fzyx' or layout_str == 'soa': if layout_str == 'fzyx' or layout_str == 'soa':
assert dim <= 4 if dim > 4:
raise ValueError(f"Invalid total dimensionality for layout descriptor {layout_str}: May be at most 4.")
return tuple(reversed(range(dim))) return tuple(reversed(range(dim)))
elif layout_str == 'zyxf' or layout_str == 'aos': elif layout_str == 'zyxf' or layout_str == 'aos':
assert dim <= 4 if dim > 4:
raise ValueError(f"Invalid total dimensionality for layout descriptor {layout_str}: May be at most 4.")
return tuple(reversed(range(dim - 1))) + (dim - 1,) return tuple(reversed(range(dim - 1))) + (dim - 1,)
elif layout_str == 'f' or layout_str == 'reverse_numpy': elif layout_str == 'f' or layout_str == 'reverse_numpy':
return tuple(reversed(range(dim))) return tuple(reversed(range(dim)))
......
...@@ -3,23 +3,39 @@ import pytest ...@@ -3,23 +3,39 @@ import pytest
import sympy as sp import sympy as sp
import pystencils as ps import pystencils as ps
from pystencils import TypedSymbol, DEFAULTS from pystencils import DEFAULTS
from pystencils.types import create_type from pystencils.field import (
from pystencils.field import Field, FieldType, layout_string_to_tuple Field,
FieldType,
layout_string_to_tuple,
spatial_layout_string_to_tuple,
)
def test_field_basic(): def test_field_basic():
f = Field.create_generic('f', spatial_dimensions=2) f = Field.create_generic("f", spatial_dimensions=2)
assert FieldType.is_generic(f) assert FieldType.is_generic(f)
assert f['E'] == f[1, 0] assert f["E"] == f[1, 0]
assert f['N'] == f[0, 1] assert f["N"] == f[0, 1]
assert '_' in f.center._latex('dummy') assert "_" in f.center._latex("dummy")
assert f.index_to_physical(index_coordinates=sp.Matrix([0, 0]), staggered=False)[0] == 0 assert (
assert f.index_to_physical(index_coordinates=sp.Matrix([0, 0]), staggered=False)[1] == 0 f.index_to_physical(index_coordinates=sp.Matrix([0, 0]), staggered=False)[0]
== 0
assert f.physical_to_index(physical_coordinates=sp.Matrix([0, 0]), staggered=False)[0] == 0 )
assert f.physical_to_index(physical_coordinates=sp.Matrix([0, 0]), staggered=False)[1] == 0 assert (
f.index_to_physical(index_coordinates=sp.Matrix([0, 0]), staggered=False)[1]
== 0
)
assert (
f.physical_to_index(physical_coordinates=sp.Matrix([0, 0]), staggered=False)[0]
== 0
)
assert (
f.physical_to_index(physical_coordinates=sp.Matrix([0, 0]), staggered=False)[1]
== 0
)
f1 = f.new_field_with_different_name("f1") f1 = f.new_field_with_different_name("f1")
assert f1.ndim == f.ndim assert f1.ndim == f.ndim
...@@ -28,7 +44,7 @@ def test_field_basic(): ...@@ -28,7 +44,7 @@ def test_field_basic():
fixed = ps.fields("f(5, 5) : double[20, 20]") fixed = ps.fields("f(5, 5) : double[20, 20]")
assert fixed.neighbor_vector((1, 1)).shape == (5, 5) assert fixed.neighbor_vector((1, 1)).shape == (5, 5)
f = Field.create_fixed_size('f', (10, 10), strides=(80, 8), dtype=np.float64) f = Field.create_fixed_size("f", (10, 10), strides=(80, 8), dtype=np.float64)
assert f.spatial_strides == (10, 1) assert f.spatial_strides == (10, 1)
assert f.index_strides == () assert f.index_strides == ()
assert f.center_vector == sp.Matrix([f.center]) assert f.center_vector == sp.Matrix([f.center])
...@@ -37,84 +53,99 @@ def test_field_basic(): ...@@ -37,84 +53,99 @@ def test_field_basic():
assert f1.ndim == f.ndim assert f1.ndim == f.ndim
assert f1.values_per_cell() == f.values_per_cell() assert f1.values_per_cell() == f.values_per_cell()
f = Field.create_fixed_size('f', (8, 8, 2, 2), index_dimensions=2) f = Field.create_fixed_size("f", (8, 8, 2, 2), index_dimensions=2)
assert f.center_vector == sp.Matrix([[f(0, 0), f(0, 1)], assert f.center_vector == sp.Matrix([[f(0, 0), f(0, 1)], [f(1, 0), f(1, 1)]])
[f(1, 0), f(1, 1)]])
field_access = f[1, 1] field_access = f[1, 1]
assert field_access.nr_of_coordinates == 2 assert field_access.nr_of_coordinates == 2
assert field_access.offset_name == 'NE' assert field_access.offset_name == "NE"
neighbor = field_access.neighbor(coord_id=0, offset=-2) neighbor = field_access.neighbor(coord_id=0, offset=-2)
assert neighbor.offsets == (-1, 1) assert neighbor.offsets == (-1, 1)
assert '_' in neighbor._latex('dummy') assert "_" in neighbor._latex("dummy")
f = Field.create_fixed_size('f', (8, 8, 2, 2, 2), index_dimensions=3) f = Field.create_fixed_size("f", (8, 8, 2, 2, 2), index_dimensions=3)
assert f.center_vector == sp.Array([[[f(i, j, k) for k in range(2)] for j in range(2)] for i in range(2)]) assert f.center_vector == sp.Array(
[[[f(i, j, k) for k in range(2)] for j in range(2)] for i in range(2)]
)
f = Field.create_generic('f', spatial_dimensions=5, index_dimensions=2) f = Field.create_generic("f", spatial_dimensions=5, index_dimensions=2)
field_access = f[1, -1, 2, -3, 0](1, 0) field_access = f[1, -1, 2, -3, 0](1, 0)
assert field_access.offsets == (1, -1, 2, -3, 0) assert field_access.offsets == (1, -1, 2, -3, 0)
assert field_access.index == (1, 0) assert field_access.index == (1, 0)
def test_error_handling(): def test_error_handling():
struct_dtype = np.dtype([('a', np.int32), ('b', np.float64), ('c', np.uint32)], align=True) struct_dtype = np.dtype(
Field.create_generic('f', spatial_dimensions=2, index_dimensions=0, dtype=struct_dtype) [("a", np.int32), ("b", np.float64), ("c", np.uint32)], align=True
)
Field.create_generic(
"f", spatial_dimensions=2, index_dimensions=0, dtype=struct_dtype
)
with pytest.raises(ValueError) as e: with pytest.raises(ValueError) as e:
Field.create_generic('f', spatial_dimensions=2, index_dimensions=1, dtype=struct_dtype) Field.create_generic(
assert 'index dimension' in str(e.value) "f", spatial_dimensions=2, index_dimensions=1, dtype=struct_dtype
)
assert "index dimension" in str(e.value)
arr = np.array([[[(1,)*3, (2,)*3, (3,)*3]]*2], dtype=struct_dtype) arr = np.array([[[(1,) * 3, (2,) * 3, (3,) * 3]] * 2], dtype=struct_dtype)
Field.create_from_numpy_array('f', arr, index_dimensions=0) Field.create_from_numpy_array("f", arr, index_dimensions=0)
with pytest.raises(ValueError) as e: with pytest.raises(ValueError) as e:
Field.create_from_numpy_array('f', arr, index_dimensions=1) Field.create_from_numpy_array("f", arr, index_dimensions=1)
assert 'Structured arrays' in str(e.value) assert "Structured arrays" in str(e.value)
arr = np.zeros([3, 3, 3]) arr = np.zeros([3, 3, 3])
Field.create_from_numpy_array('f', arr, index_dimensions=2) Field.create_from_numpy_array("f", arr, index_dimensions=2)
with pytest.raises(ValueError) as e: with pytest.raises(ValueError) as e:
Field.create_from_numpy_array('f', arr, index_dimensions=3) Field.create_from_numpy_array("f", arr, index_dimensions=3)
assert 'Too many' in str(e.value) assert "Too many" in str(e.value)
Field.create_fixed_size('f', (3, 2, 4), index_dimensions=0, dtype=struct_dtype, layout='reverse_numpy') Field.create_fixed_size(
"f", (3, 2, 4), index_dimensions=0, dtype=struct_dtype, layout="reverse_numpy"
)
with pytest.raises(ValueError) as e: with pytest.raises(ValueError) as e:
Field.create_fixed_size('f', (3, 2, 4), index_dimensions=1, dtype=struct_dtype, layout='reverse_numpy') Field.create_fixed_size(
assert 'Structured arrays' in str(e.value) "f",
(3, 2, 4),
f = Field.create_fixed_size('f', (10, 10)) index_dimensions=1,
dtype=struct_dtype,
layout="reverse_numpy",
)
assert "Structured arrays" in str(e.value)
f = Field.create_fixed_size("f", (10, 10))
with pytest.raises(ValueError) as e: with pytest.raises(ValueError) as e:
f[1] f[1]
assert 'Wrong number of spatial indices' in str(e.value) assert "Wrong number of spatial indices" in str(e.value)
f = Field.create_generic('f', spatial_dimensions=2, index_shape=(3,)) f = Field.create_generic("f", spatial_dimensions=2, index_shape=(3,))
with pytest.raises(ValueError) as e: with pytest.raises(ValueError) as e:
f(3) f(3)
assert 'out of bounds' in str(e.value) assert "out of bounds" in str(e.value)
f = Field.create_fixed_size('f', (10, 10, 3, 4), index_dimensions=2) f = Field.create_fixed_size("f", (10, 10, 3, 4), index_dimensions=2)
with pytest.raises(ValueError) as e: with pytest.raises(ValueError) as e:
f(3, 0) f(3, 0)
assert 'out of bounds' in str(e.value) assert "out of bounds" in str(e.value)
with pytest.raises(ValueError) as e: with pytest.raises(ValueError) as e:
f(1, 0)(1, 0) f(1, 0)(1, 0)
assert 'Indexing an already indexed' in str(e.value) assert "Indexing an already indexed" in str(e.value)
with pytest.raises(ValueError) as e: with pytest.raises(ValueError) as e:
f(1) f(1)
assert 'Wrong number of indices' in str(e.value) assert "Wrong number of indices" in str(e.value)
with pytest.raises(ValueError) as e: with pytest.raises(ValueError) as e:
Field.create_generic('f', spatial_dimensions=2, layout='wrong') Field.create_generic("f", spatial_dimensions=2, layout="wrong")
assert 'Unknown layout descriptor' in str(e.value) assert "Unknown layout descriptor" in str(e.value)
assert layout_string_to_tuple('fzyx', dim=4) == (3, 2, 1, 0) assert layout_string_to_tuple("fzyx", dim=4) == (3, 2, 1, 0)
with pytest.raises(ValueError) as e: with pytest.raises(ValueError) as e:
layout_string_to_tuple('wrong', dim=4) layout_string_to_tuple("wrong", dim=4)
assert 'Unknown layout descriptor' in str(e.value) assert "Unknown layout descriptor" in str(e.value)
def test_decorator_scoping(): def test_decorator_scoping():
dst = ps.fields('dst : double[2D]') dst = ps.fields("dst : double[2D]")
def f1(): def f1():
a = sp.Symbol("a") a = sp.Symbol("a")
...@@ -134,7 +165,7 @@ def test_decorator_scoping(): ...@@ -134,7 +165,7 @@ def test_decorator_scoping():
def test_string_creation(): def test_string_creation():
x, y, z = ps.fields(' x(4), y(3,5) z : double[ 3, 47]') x, y, z = ps.fields(" x(4), y(3,5) z : double[ 3, 47]")
assert x.index_shape == (4,) assert x.index_shape == (4,)
assert y.index_shape == (3, 5) assert y.index_shape == (3, 5)
assert z.spatial_shape == (3, 47) assert z.spatial_shape == (3, 47)
...@@ -142,19 +173,85 @@ def test_string_creation(): ...@@ -142,19 +173,85 @@ def test_string_creation():
def test_itemsize(): def test_itemsize():
x = ps.fields('x: float32[1d]') x = ps.fields("x: float32[1d]")
y = ps.fields('y: float64[2d]') y = ps.fields("y: float64[2d]")
i = ps.fields('i: int16[1d]') i = ps.fields("i: int16[1d]")
assert x.itemsize == 4 assert x.itemsize == 4
assert y.itemsize == 8 assert y.itemsize == 8
assert i.itemsize == 2 assert i.itemsize == 2
def test_spatial_memory_layout_descriptors():
assert (
spatial_layout_string_to_tuple("AoS", 3)
== spatial_layout_string_to_tuple("aos", 3)
== spatial_layout_string_to_tuple("ZYXF", 3)
== spatial_layout_string_to_tuple("zyxf", 3)
== (2, 1, 0)
)
assert (
spatial_layout_string_to_tuple("SoA", 3)
== spatial_layout_string_to_tuple("soa", 3)
== spatial_layout_string_to_tuple("FZYX", 3)
== spatial_layout_string_to_tuple("fzyx", 3)
== spatial_layout_string_to_tuple("f", 3)
== spatial_layout_string_to_tuple("F", 3)
== (2, 1, 0)
)
assert (
spatial_layout_string_to_tuple("c", 3)
== spatial_layout_string_to_tuple("C", 3)
== (0, 1, 2)
)
assert spatial_layout_string_to_tuple("C", 5) == (0, 1, 2, 3, 4)
with pytest.raises(ValueError):
spatial_layout_string_to_tuple("aos", -1)
with pytest.raises(ValueError):
spatial_layout_string_to_tuple("aos", 4)
def test_memory_layout_descriptors():
assert (
layout_string_to_tuple("AoS", 4)
== layout_string_to_tuple("aos", 4)
== layout_string_to_tuple("ZYXF", 4)
== layout_string_to_tuple("zyxf", 4)
== (2, 1, 0, 3)
)
assert (
layout_string_to_tuple("SoA", 4)
== layout_string_to_tuple("soa", 4)
== layout_string_to_tuple("FZYX", 4)
== layout_string_to_tuple("fzyx", 4)
== layout_string_to_tuple("f", 4)
== layout_string_to_tuple("F", 4)
== (3, 2, 1, 0)
)
assert (
layout_string_to_tuple("c", 4)
== layout_string_to_tuple("C", 4)
== (0, 1, 2, 3)
)
assert layout_string_to_tuple("C", 5) == (0, 1, 2, 3, 4)
with pytest.raises(ValueError):
layout_string_to_tuple("aos", -1)
with pytest.raises(ValueError):
layout_string_to_tuple("aos", 5)
def test_staggered(): def test_staggered():
# D2Q5 # D2Q5
j1, j2, j3 = ps.fields('j1(2), j2(2,2), j3(2,2,2) : double[2D]', field_type=FieldType.STAGGERED) j1, j2, j3 = ps.fields(
"j1(2), j2(2,2), j3(2,2,2) : double[2D]", field_type=FieldType.STAGGERED
)
assert j1[0, 1](1) == j1.staggered_access((0, sp.Rational(1, 2))) assert j1[0, 1](1) == j1.staggered_access((0, sp.Rational(1, 2)))
assert j1[0, 1](1) == j1.staggered_access(np.array((0, sp.Rational(1, 2)))) assert j1[0, 1](1) == j1.staggered_access(np.array((0, sp.Rational(1, 2))))
...@@ -163,44 +260,68 @@ def test_staggered(): ...@@ -163,44 +260,68 @@ def test_staggered():
assert j1[0, 1](1) == j1.staggered_access("N") assert j1[0, 1](1) == j1.staggered_access("N")
assert j1[0, 0](1) == j1.staggered_access("S") assert j1[0, 0](1) == j1.staggered_access("S")
assert j1.staggered_vector_access("N") == sp.Matrix([j1.staggered_access("N")]) assert j1.staggered_vector_access("N") == sp.Matrix([j1.staggered_access("N")])
assert j1.staggered_stencil_name == 'D2Q5' assert j1.staggered_stencil_name == "D2Q5"
assert j1.physical_coordinates[0] == DEFAULTS.spatial_counters[0] assert j1.physical_coordinates[0] == DEFAULTS.spatial_counters[0]
assert j1.physical_coordinates[1] == DEFAULTS.spatial_counters[1] assert j1.physical_coordinates[1] == DEFAULTS.spatial_counters[1]
assert j1.physical_coordinates_staggered[0] == DEFAULTS.spatial_counters[0] + 0.5 assert j1.physical_coordinates_staggered[0] == DEFAULTS.spatial_counters[0] + 0.5
assert j1.physical_coordinates_staggered[1] == DEFAULTS.spatial_counters[1] + 0.5 assert j1.physical_coordinates_staggered[1] == DEFAULTS.spatial_counters[1] + 0.5
assert j1.index_to_physical(index_coordinates=sp.Matrix([0, 0]), staggered=True)[0] == 0.5 assert (
assert j1.index_to_physical(index_coordinates=sp.Matrix([0, 0]), staggered=True)[1] == 0.5 j1.index_to_physical(index_coordinates=sp.Matrix([0, 0]), staggered=True)[0]
assert j1.physical_to_index(physical_coordinates=sp.Matrix([0, 0]), staggered=True)[0] == -0.5 == 0.5
assert j1.physical_to_index(physical_coordinates=sp.Matrix([0, 0]), staggered=True)[1] == -0.5 )
assert (
j1.index_to_physical(index_coordinates=sp.Matrix([0, 0]), staggered=True)[1]
== 0.5
)
assert (
j1.physical_to_index(physical_coordinates=sp.Matrix([0, 0]), staggered=True)[0]
== -0.5
)
assert (
j1.physical_to_index(physical_coordinates=sp.Matrix([0, 0]), staggered=True)[1]
== -0.5
)
assert j2[0, 1](1, 1) == j2.staggered_access((0, sp.Rational(1, 2)), 1) assert j2[0, 1](1, 1) == j2.staggered_access((0, sp.Rational(1, 2)), 1)
assert j2[0, 1](1, 1) == j2.staggered_access("N", 1) assert j2[0, 1](1, 1) == j2.staggered_access("N", 1)
assert j2.staggered_vector_access("N") == sp.Matrix([j2.staggered_access("N", 0), j2.staggered_access("N", 1)]) assert j2.staggered_vector_access("N") == sp.Matrix(
[j2.staggered_access("N", 0), j2.staggered_access("N", 1)]
)
assert j3[0, 1](1, 1, 1) == j3.staggered_access((0, sp.Rational(1, 2)), (1, 1)) assert j3[0, 1](1, 1, 1) == j3.staggered_access((0, sp.Rational(1, 2)), (1, 1))
assert j3[0, 1](1, 1, 1) == j3.staggered_access("N", (1, 1)) assert j3[0, 1](1, 1, 1) == j3.staggered_access("N", (1, 1))
assert j3.staggered_vector_access("N") == sp.Matrix([[j3.staggered_access("N", (i, j)) assert j3.staggered_vector_access("N") == sp.Matrix(
for j in range(2)] for i in range(2)]) [[j3.staggered_access("N", (i, j)) for j in range(2)] for i in range(2)]
)
# D2Q9 # D2Q9
k1, k2 = ps.fields('k1(4), k2(2) : double[2D]', field_type=FieldType.STAGGERED) k1, k2 = ps.fields("k1(4), k2(2) : double[2D]", field_type=FieldType.STAGGERED)
assert k1[1, 1](2) == k1.staggered_access("NE") assert k1[1, 1](2) == k1.staggered_access("NE")
assert k1[0, 0](2) == k1.staggered_access("SW") assert k1[0, 0](2) == k1.staggered_access("SW")
assert k1[0, 0](3) == k1.staggered_access("NW") assert k1[0, 0](3) == k1.staggered_access("NW")
a = k1.staggered_access("NE") a = k1.staggered_access("NE")
assert a._staggered_offset(a.offsets, a.index[0]) == [sp.Rational(1, 2), sp.Rational(1, 2)] assert a._staggered_offset(a.offsets, a.index[0]) == [
sp.Rational(1, 2),
sp.Rational(1, 2),
]
a = k1.staggered_access("SW") a = k1.staggered_access("SW")
assert a._staggered_offset(a.offsets, a.index[0]) == [sp.Rational(-1, 2), sp.Rational(-1, 2)] assert a._staggered_offset(a.offsets, a.index[0]) == [
sp.Rational(-1, 2),
sp.Rational(-1, 2),
]
a = k1.staggered_access("NW") a = k1.staggered_access("NW")
assert a._staggered_offset(a.offsets, a.index[0]) == [sp.Rational(-1, 2), sp.Rational(1, 2)] assert a._staggered_offset(a.offsets, a.index[0]) == [
sp.Rational(-1, 2),
sp.Rational(1, 2),
]
# sign reversed when using as flux field # sign reversed when using as flux field
r = ps.fields('r(2) : double[2D]', field_type=FieldType.STAGGERED_FLUX) r = ps.fields("r(2) : double[2D]", field_type=FieldType.STAGGERED_FLUX)
assert r[0, 0](0) == r.staggered_access("W") assert r[0, 0](0) == r.staggered_access("W")
assert -r[1, 0](0) == r.staggered_access("E") assert -r[1, 0](0) == r.staggered_access("E")
# test_staggered() # test_staggered()
\ No newline at end of file
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment