From ddcbc7089032d18fb0d6d0478dc4efc3a1ecfbe5 Mon Sep 17 00:00:00 2001 From: Hannes Vogt Date: Tue, 30 Jan 2024 17:14:37 +0100 Subject: [PATCH 1/8] feat[next]: add tests with mesh with skip values --- pyproject.toml | 1 + src/gt4py/next/common.py | 7 +- src/gt4py/next/iterator/embedded.py | 12 ++ tests/next_tests/definitions.py | 2 + tests/next_tests/integration_tests/cases.py | 20 +-- .../ffront_tests/ffront_test_utils.py | 162 ++++++++++++++---- .../ffront_tests/test_bound_args.py | 2 +- .../ffront_tests/test_execution.py | 28 ++- .../ffront_tests/test_external_local_field.py | 11 +- .../ffront_tests/test_gt4py_builtins.py | 25 ++- .../test_temporaries_with_sizes.py | 26 +-- 11 files changed, 217 insertions(+), 79 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 51cfc267d5..df4920e0fd 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -354,6 +354,7 @@ markers = [ 'uses_cartesian_shift: tests that use a Cartesian connectivity', 'uses_unstructured_shift: tests that use a unstructured connectivity', 'uses_max_over: tests that use the max_over builtin', + 'uses_mesh_with_skip_values: tests that use a mesh with skip values', 'checks_specific_error: tests that rely on the backend to produce a specific error message' ] norecursedirs = ['dist', 'build', 'cpp_backend_tests/build*', '_local/*', '.*'] diff --git a/src/gt4py/next/common.py b/src/gt4py/next/common.py index 33a0591813..338bc09d34 100644 --- a/src/gt4py/next/common.py +++ b/src/gt4py/next/common.py @@ -32,6 +32,7 @@ Any, Callable, ClassVar, + Final, Generic, Never, Optional, @@ -1102,4 +1103,8 @@ def register_builtin_func( @classmethod def __gt_builtin_func__(cls, /, func: fbuiltins.BuiltInFunction[_R, _P]) -> Callable[_P, _R]: return cls._builtin_func_map.get(func, NotImplemented) - return cls._builtin_func_map.get(func, NotImplemented) + + +#: Numeric value used to represent missing values in connectivities. +#: Adopted from UGRID Conventions (http://ugrid-conventions.github.io/ugrid-conventions/) +FILL_CONNECTIVITY_VALUE: Final[int] = -1 diff --git a/src/gt4py/next/iterator/embedded.py b/src/gt4py/next/iterator/embedded.py index 6d610fd136..237bed5c75 100644 --- a/src/gt4py/next/iterator/embedded.py +++ b/src/gt4py/next/iterator/embedded.py @@ -533,6 +533,18 @@ def execute_shift( for i, p in reversed(list(enumerate(new_entry))): # first shift applies to the last sparse dimensions of that axis type if p is None: + offset_implementation = offset_provider[tag] + assert isinstance(offset_implementation, common.Connectivity) + new_pos = pos.copy() + new_pos.pop(offset_implementation.origin_axis.value) + cur_index = pos[offset_implementation.origin_axis.value] + assert common.is_int_index(cur_index) + if offset_implementation.mapped_index(cur_index, index) in [ + None, + -1, + ]: + return None + new_entry[i] = index break # the assertions above confirm pos is incomplete casting here to avoid duplicating work in a type guard diff --git a/tests/next_tests/definitions.py b/tests/next_tests/definitions.py index dbb2366f47..ff37be2a26 100644 --- a/tests/next_tests/definitions.py +++ b/tests/next_tests/definitions.py @@ -137,6 +137,7 @@ class ProgramFormatterId(_PythonObjectIdMixin, str, enum.Enum): USES_CARTESIAN_SHIFT = "uses_cartesian_shift" USES_UNSTRUCTURED_SHIFT = "uses_unstructured_shift" USES_MAX_OVER = "uses_max_over" +USES_MESH_WITH_SKIP_VALUES = "uses_mesh_with_skip_values" CHECKS_SPECIFIC_ERROR = "checks_specific_error" # Skip messages (available format keys: 'marker', 'backend') @@ -172,6 +173,7 @@ class ProgramFormatterId(_PythonObjectIdMixin, str, enum.Enum): XFAIL, UNSUPPORTED_MESSAGE, ), # we can't extract the field type from scan args + (USES_MESH_WITH_SKIP_VALUES, XFAIL, UNSUPPORTED_MESSAGE), ] GTFN_SKIP_TEST_LIST = COMMON_SKIP_TEST_LIST + [ # floordiv not yet supported, see https://github.com/GridTools/gt4py/issues/1136 diff --git a/tests/next_tests/integration_tests/cases.py b/tests/next_tests/integration_tests/cases.py index 03a0a9f5a7..0c62583ad7 100644 --- a/tests/next_tests/integration_tests/cases.py +++ b/tests/next_tests/integration_tests/cases.py @@ -45,7 +45,7 @@ Koff, Vertex, exec_alloc_descriptor, - reduction_setup, + mesh_descriptor, ) @@ -65,12 +65,12 @@ CField: TypeAlias = gtx.Field[[Cell], np.int32] # type: ignore [valid-type] EmptyField: TypeAlias = gtx.Field[[], np.int32] # type: ignore [valid-type] -# TODO(ricoh): unify the following with the `ffront_test_utils.reduction_setup` -# fixture if `ffront_test_utils.reduction_setup` is not completely superseded +# TODO(ricoh): unify the following with the `ffront_test_utils.mesh_descriptor` +# fixture if `ffront_test_utils.mesh_descriptor` is not completely superseded # by `unstructured_case`. V2EDim = gtx.Dimension("V2E", kind=gtx.DimensionKind.LOCAL) E2VDim = gtx.Dimension("E2V", kind=gtx.DimensionKind.LOCAL) -C2EDim = gtx.Dimension("C2E", kind=common.DimensionKind.LOCAL) +C2EDim = gtx.Dimension("C2E", kind=gtx.DimensionKind.LOCAL) V2E = gtx.FieldOffset("V2E", source=Edge, target=(Vertex, V2EDim)) E2V = gtx.FieldOffset("E2V", source=Vertex, target=(Edge, E2VDim)) C2E = gtx.FieldOffset("C2E", source=Edge, target=(Cell, C2EDim)) @@ -495,17 +495,17 @@ def cartesian_case( @pytest.fixture def unstructured_case( - reduction_setup, # noqa: F811 # fixtures + mesh_descriptor, # noqa: F811 # fixtures exec_alloc_descriptor: test_definitions.ExecutionAndAllocatorDescriptor, # noqa: F811 # fixtures ): yield Case( exec_alloc_descriptor.executor, - offset_provider=reduction_setup.offset_provider, + offset_provider=mesh_descriptor.offset_provider, default_sizes={ - Vertex: reduction_setup.num_vertices, - Edge: reduction_setup.num_edges, - Cell: reduction_setup.num_cells, - KDim: reduction_setup.k_levels, + Vertex: mesh_descriptor.num_vertices, + Edge: mesh_descriptor.num_edges, + Cell: mesh_descriptor.num_cells, + KDim: 10, }, grid_type=common.GridType.UNSTRUCTURED, allocator=exec_alloc_descriptor.allocator, diff --git a/tests/next_tests/integration_tests/feature_tests/ffront_tests/ffront_test_utils.py b/tests/next_tests/integration_tests/feature_tests/ffront_tests/ffront_test_utils.py index e421763699..6adfb5e560 100644 --- a/tests/next_tests/integration_tests/feature_tests/ffront_tests/ffront_test_utils.py +++ b/tests/next_tests/integration_tests/feature_tests/ffront_tests/ffront_test_utils.py @@ -14,12 +14,13 @@ # SPDX-License-Identifier: GPL-3.0-or-later from collections import namedtuple -from typing import Any, Optional, TypeVar +from typing import Any, Protocol, TypeVar import numpy as np import pytest import gt4py.next as gtx +from gt4py.next import common from gt4py.next.ffront import decorator from gt4py.next.iterator import ir as itir from gt4py.next.program_processors import processor_interface as ppi @@ -121,15 +122,32 @@ def debug_itir(tree): size = 10 -@pytest.fixture -def reduction_setup(): +class MeshDescriptor(Protocol): + @property + def num_vertices(self) -> int: + ... + + @property + def num_cells(self) -> int: + ... + + @property + def num_edges(self) -> int: + ... + + @property + def num_levels(self) -> int: + ... + + @property + def offset_provider(self) -> dict[str, common.Connectivity]: + ... + + +def simple_mesh() -> MeshDescriptor: num_vertices = 9 num_cells = 8 - k_levels = 10 - v2edim = gtx.Dimension("V2E", kind=gtx.DimensionKind.LOCAL) - e2vdim = gtx.Dimension("E2V", kind=gtx.DimensionKind.LOCAL) - c2vdim = gtx.Dimension("C2V", kind=gtx.DimensionKind.LOCAL) - c2edim = gtx.Dimension("C2E", kind=gtx.DimensionKind.LOCAL) + num_levels = 10 v2e_arr = np.array( [ @@ -183,57 +201,114 @@ def reduction_setup(): assert all(len(row) == 2 for row in e2v_arr) e2v_arr = np.asarray(e2v_arr, dtype=gtx.IndexType) - yield namedtuple( - "ReductionSetup", + return namedtuple( + "SimpleMesh", [ "num_vertices", "num_edges", "num_cells", - "k_levels", - "V2EDim", - "E2VDim", - "C2VDim", - "C2EDim", - "V2E", - "E2V", - "C2V", - "C2E", - "inp", - "out", "offset_provider", - "v2e_table", - "e2v_table", ], )( num_vertices=num_vertices, num_edges=num_edges, num_cells=num_cells, - k_levels=k_levels, - V2EDim=v2edim, - E2VDim=e2vdim, - C2VDim=c2vdim, - C2EDim=c2edim, - V2E=gtx.FieldOffset("V2E", source=Edge, target=(Vertex, v2edim)), - E2V=gtx.FieldOffset("E2V", source=Vertex, target=(Edge, e2vdim)), - C2V=gtx.FieldOffset("C2V", source=Vertex, target=(Cell, c2vdim)), - C2E=gtx.FieldOffset("C2E", source=Edge, target=(Cell, c2edim)), - # inp=gtx.index_field(edge, dtype=np.int64), # TODO enable once we support gtx.index_fields in bindings - inp=gtx.as_field([Edge], np.arange(num_edges, dtype=np.int32)), - out=gtx.as_field([Vertex], np.zeros([num_vertices], dtype=np.int32)), offset_provider={ "V2E": gtx.NeighborTableOffsetProvider(v2e_arr, Vertex, Edge, 4, has_skip_values=False), "E2V": gtx.NeighborTableOffsetProvider(e2v_arr, Edge, Vertex, 2, has_skip_values=False), "C2V": gtx.NeighborTableOffsetProvider(c2v_arr, Cell, Vertex, 4, has_skip_values=False), "C2E": gtx.NeighborTableOffsetProvider(c2e_arr, Cell, Edge, 4, has_skip_values=False), }, - v2e_table=v2e_arr, - e2v_table=e2v_arr, + ) # type: ignore + + +def skip_value_mesh() -> MeshDescriptor: + """Mesh with skip values from the GT4Py quickstart guide.""" + + num_vertices = 7 + num_cells = 6 + num_edges = 12 + num_levels = 10 + + v2e_arr = np.array( + [ + [1, 8, 7, 0, -1], + [2, 8, 1, -1, -1], + [3, 9, 8, 2, -1], + [4, 10, 3, -1, -1], + [5, 11, 4, -1, -1], + [0, 6, 4, -1, -1], + [6, 7, 9, 10, 11], + ], + dtype=gtx.IndexType, + ) + + e2v_arr = np.array( + [ + [0, 5], + [0, 1], + [1, 2], + [2, 3], + [3, 4], + [4, 5], + [5, 6], + [6, 0], + [0, 2], + [2, 6], + [3, 6], + [4, 6], + ], + dtype=gtx.IndexType, + ) + + c2v_arr = np.array( + [ + [0, 6, 5], + [0, 2, 6], + [0, 1, 2], + [2, 3, 6], + [3, 4, 6], + [4, 5, 6], + ], + dtype=gtx.IndexType, + ) + + c2e_arr = np.array( + [ + [0, 6, 7], # cell 0 (neighbors: edge 0, edge 6, edge 7) + [7, 8, 9], # cell 1 + [1, 2, 8], # cell 2 + [3, 9, 10], # cell 3 + [4, 10, 11], # cell 4 + [5, 6, 11], # cell 5 + ], + dtype=gtx.IndexType, + ) + + return namedtuple( + "SkipValueMesh", + [ + "num_vertices", + "num_edges", + "num_cells", + "offset_provider", + ], + )( + num_vertices=num_vertices, + num_edges=num_edges, + num_cells=num_cells, + offset_provider={ + "V2E": gtx.NeighborTableOffsetProvider(v2e_arr, Vertex, Edge, 5, has_skip_values=True), + "E2V": gtx.NeighborTableOffsetProvider(e2v_arr, Edge, Vertex, 2, has_skip_values=False), + "C2V": gtx.NeighborTableOffsetProvider(c2v_arr, Cell, Vertex, 3, has_skip_values=False), + "C2E": gtx.NeighborTableOffsetProvider(c2e_arr, Cell, Edge, 3, has_skip_values=False), + }, ) # type: ignore __all__ = [ "exec_alloc_descriptor", - "reduction_setup", + "mesh_descriptor", "debug_itir", "DimsType", "DType", @@ -249,3 +324,14 @@ def reduction_setup(): "EdgeOffset", "size", ] + + +@pytest.fixture( + params=[ + simple_mesh(), + pytest.param(skip_value_mesh(), marks=pytest.mark.uses_mesh_with_skip_values), + ], + ids=lambda p: p.__class__.__name__, +) +def mesh_descriptor(request) -> MeshDescriptor: + yield request.param diff --git a/tests/next_tests/integration_tests/feature_tests/ffront_tests/test_bound_args.py b/tests/next_tests/integration_tests/feature_tests/ffront_tests/test_bound_args.py index e4baedc6ee..e4df5b9b78 100644 --- a/tests/next_tests/integration_tests/feature_tests/ffront_tests/test_bound_args.py +++ b/tests/next_tests/integration_tests/feature_tests/ffront_tests/test_bound_args.py @@ -22,7 +22,7 @@ from next_tests.integration_tests.cases import cartesian_case from next_tests.integration_tests.feature_tests.ffront_tests.ffront_test_utils import ( exec_alloc_descriptor, - reduction_setup, + mesh_descriptor, ) diff --git a/tests/next_tests/integration_tests/feature_tests/ffront_tests/test_execution.py b/tests/next_tests/integration_tests/feature_tests/ffront_tests/test_execution.py index 9482860d13..3642dcdd16 100644 --- a/tests/next_tests/integration_tests/feature_tests/ffront_tests/test_execution.py +++ b/tests/next_tests/integration_tests/feature_tests/ffront_tests/test_execution.py @@ -22,6 +22,7 @@ from gt4py.next import ( astype, broadcast, + common, errors, float32, float64, @@ -52,7 +53,7 @@ ) from next_tests.integration_tests.feature_tests.ffront_tests.ffront_test_utils import ( exec_alloc_descriptor, - reduction_setup, + mesh_descriptor, ) @@ -508,9 +509,12 @@ def testee(a: cases.EField) -> cases.EField: unstructured_case, testee, ref=lambda a: np.sum( - np.sum(a[unstructured_case.offset_provider["V2E"].table], axis=1)[ - unstructured_case.offset_provider["E2V"].table - ], + np.sum( + a[unstructured_case.offset_provider["V2E"].table], + axis=1, + initial=0, + where=unstructured_case.offset_provider["V2E"].table > 0, + )[unstructured_case.offset_provider["E2V"].table], axis=1, ), comparison=lambda a, tmp_2: np.all(a == tmp_2), @@ -571,8 +575,13 @@ def reduce_tuple_element(e: cases.EField, v: cases.VField) -> cases.EField: cases.verify_with_default_data( unstructured_case, reduce_tuple_element, + # TODO think about the reference ref=lambda e, v: np.sum( - e[unstructured_case.offset_provider["V2E"].table] + np.tile(v, (4, 1)).T, axis=1 + e[unstructured_case.offset_provider["V2E"].table] + + np.tile(v, (unstructured_case.offset_provider["V2E"].max_neighbors, 1)).T, + axis=1, + initial=0, + where=unstructured_case.offset_provider["V2E"].table > common.FILL_CONNECTIVITY_VALUE, )[unstructured_case.offset_provider["E2V"].table[:, 0]], ) @@ -707,9 +716,12 @@ def testee(a: cases.EField, b: cases.EField) -> cases.VField: unstructured_case, testee, ref=lambda a, b: ( - np.sum(b[unstructured_case.offset_provider["V2E"].table], axis=1) - if 2 < 3 - else np.sum(a[unstructured_case.offset_provider["V2E"].table], axis=1) + np.sum( + b[unstructured_case.offset_provider["V2E"].table], + axis=1, + initial=0, + where=unstructured_case.offset_provider["V2E"].table != -1, + ) ), ) diff --git a/tests/next_tests/integration_tests/feature_tests/ffront_tests/test_external_local_field.py b/tests/next_tests/integration_tests/feature_tests/ffront_tests/test_external_local_field.py index bb1d878a6a..0ca6393b19 100644 --- a/tests/next_tests/integration_tests/feature_tests/ffront_tests/test_external_local_field.py +++ b/tests/next_tests/integration_tests/feature_tests/ffront_tests/test_external_local_field.py @@ -16,13 +16,13 @@ import pytest import gt4py.next as gtx -from gt4py.next import int32, neighbor_sum +from gt4py.next import common, int32, neighbor_sum from next_tests.integration_tests import cases from next_tests.integration_tests.cases import V2E, Edge, V2EDim, Vertex, unstructured_case from next_tests.integration_tests.feature_tests.ffront_tests.ffront_test_utils import ( exec_alloc_descriptor, - reduction_setup, + mesh_descriptor, ) @@ -49,7 +49,12 @@ def testee( inp, ones, out=cases.allocate(unstructured_case, testee, cases.RETURN)(), - ref=np.sum(unstructured_case.offset_provider["V2E"].table, axis=1), + ref=np.sum( + unstructured_case.offset_provider["V2E"].table, + axis=1, + initial=0, + where=unstructured_case.offset_provider["V2E"].table != common.FILL_CONNECTIVITY_VALUE, + ), ) diff --git a/tests/next_tests/integration_tests/feature_tests/ffront_tests/test_gt4py_builtins.py b/tests/next_tests/integration_tests/feature_tests/ffront_tests/test_gt4py_builtins.py index 90d07f360d..5633a0cded 100644 --- a/tests/next_tests/integration_tests/feature_tests/ffront_tests/test_gt4py_builtins.py +++ b/tests/next_tests/integration_tests/feature_tests/ffront_tests/test_gt4py_builtins.py @@ -35,7 +35,7 @@ ) from next_tests.integration_tests.feature_tests.ffront_tests.ffront_test_utils import ( exec_alloc_descriptor, - reduction_setup, + mesh_descriptor, ) @@ -56,7 +56,7 @@ def testee(edge_f: cases.EField) -> cases.VField: out = cases.allocate(unstructured_case, testee, cases.RETURN)() v2e_table = unstructured_case.offset_provider["V2E"].table - ref = np.max(inp.ndarray[v2e_table], axis=1) + ref = np.max(inp.asnumpy()[v2e_table], axis=1, initial=-42000, where=v2e_table != -1) cases.verify(unstructured_case, testee, inp, ref=ref, out=out) @@ -86,7 +86,12 @@ def fencil(edge_f: cases.EField, out: cases.VField): cases.verify_with_default_data( unstructured_case, fencil, - ref=lambda edge_f: np.sum(edge_f[unstructured_case.offset_provider["V2E"].table], axis=1), + ref=lambda edge_f: np.sum( + edge_f[unstructured_case.offset_provider["V2E"].table], + axis=1, + initial=0, + where=unstructured_case.offset_provider["V2E"].table != -1, + ), ) @@ -107,7 +112,12 @@ def fencil(edge_f: cases.EField, out: cases.VField): unstructured_case, fencil, ref=lambda edge_f: 3 - * np.sum(-edge_f[unstructured_case.offset_provider["V2E"].table] ** 2 * 2, axis=1), + * np.sum( + -edge_f[unstructured_case.offset_provider["V2E"].table] ** 2 * 2, + axis=1, + initial=0, + where=unstructured_case.offset_provider["V2E"].table != -1, + ), ) @@ -120,7 +130,12 @@ def testee(flux: cases.EField) -> cases.VField: cases.verify_with_default_data( unstructured_case, testee, - ref=lambda flux: np.sum(flux[unstructured_case.offset_provider["V2E"].table] * 2, axis=1), + ref=lambda flux: np.sum( + flux[unstructured_case.offset_provider["V2E"].table] * 2, + axis=1, + initial=0, + where=unstructured_case.offset_provider["V2E"].table != -1, + ), ) diff --git a/tests/next_tests/integration_tests/feature_tests/ffront_tests/test_temporaries_with_sizes.py b/tests/next_tests/integration_tests/feature_tests/ffront_tests/test_temporaries_with_sizes.py index c4cdd8a4be..4503c6b7a8 100644 --- a/tests/next_tests/integration_tests/feature_tests/ffront_tests/test_temporaries_with_sizes.py +++ b/tests/next_tests/integration_tests/feature_tests/ffront_tests/test_temporaries_with_sizes.py @@ -31,7 +31,7 @@ unstructured_case, ) from next_tests.integration_tests.feature_tests.ffront_tests.ffront_test_utils import ( - reduction_setup, + mesh_descriptor, ) from next_tests.toy_connectivity import Cell, Edge @@ -75,15 +75,15 @@ def prog( return prog -def test_verification(testee, run_gtfn_with_temporaries_and_symbolic_sizes, reduction_setup): +def test_verification(testee, run_gtfn_with_temporaries_and_symbolic_sizes, mesh_descriptor): unstructured_case = Case( run_gtfn_with_temporaries_and_symbolic_sizes.executor, - offset_provider=reduction_setup.offset_provider, + offset_provider=mesh_descriptor.offset_provider, default_sizes={ - Vertex: reduction_setup.num_vertices, - Edge: reduction_setup.num_edges, - Cell: reduction_setup.num_cells, - KDim: reduction_setup.k_levels, + Vertex: mesh_descriptor.num_vertices, + Edge: mesh_descriptor.num_edges, + Cell: mesh_descriptor.num_cells, + KDim: 10, }, grid_type=common.GridType.UNSTRUCTURED, allocator=run_gtfn_with_temporaries_and_symbolic_sizes.allocator, @@ -92,7 +92,7 @@ def test_verification(testee, run_gtfn_with_temporaries_and_symbolic_sizes, redu a = cases.allocate(unstructured_case, testee, "a")() out = cases.allocate(unstructured_case, testee, "out")() - first_nbs, second_nbs = (reduction_setup.offset_provider["E2V"].table[:, i] for i in [0, 1]) + first_nbs, second_nbs = (mesh_descriptor.offset_provider["E2V"].table[:, i] for i in [0, 1]) ref = (a.ndarray * 2)[first_nbs] + (a.ndarray * 2)[second_nbs] cases.verify( @@ -100,19 +100,19 @@ def test_verification(testee, run_gtfn_with_temporaries_and_symbolic_sizes, redu testee, a, out, - reduction_setup.num_vertices, - reduction_setup.num_edges, - reduction_setup.num_cells, + mesh_descriptor.num_vertices, + mesh_descriptor.num_edges, + mesh_descriptor.num_cells, inout=out, ref=ref, ) -def test_temporary_symbols(testee, reduction_setup): +def test_temporary_symbols(testee, mesh_descriptor): itir_with_tmp = apply_common_transforms( testee.itir, lift_mode=LiftMode.FORCE_TEMPORARIES, - offset_provider=reduction_setup.offset_provider, + offset_provider=mesh_descriptor.offset_provider, ) params = ["num_vertices", "num_edges", "num_cells"] From 51152ee6121fb7e0d73a7c6a8f1274cb09ab95a5 Mon Sep 17 00:00:00 2001 From: Hannes Vogt Date: Tue, 30 Jan 2024 19:53:09 +0100 Subject: [PATCH 2/8] fix test case --- .../feature_tests/ffront_tests/ffront_test_utils.py | 4 +--- .../feature_tests/ffront_tests/test_temporaries_with_sizes.py | 2 +- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/tests/next_tests/integration_tests/feature_tests/ffront_tests/ffront_test_utils.py b/tests/next_tests/integration_tests/feature_tests/ffront_tests/ffront_test_utils.py index 6adfb5e560..0e4e079408 100644 --- a/tests/next_tests/integration_tests/feature_tests/ffront_tests/ffront_test_utils.py +++ b/tests/next_tests/integration_tests/feature_tests/ffront_tests/ffront_test_utils.py @@ -147,7 +147,6 @@ def offset_provider(self) -> dict[str, common.Connectivity]: def simple_mesh() -> MeshDescriptor: num_vertices = 9 num_cells = 8 - num_levels = 10 v2e_arr = np.array( [ @@ -211,7 +210,7 @@ def simple_mesh() -> MeshDescriptor: ], )( num_vertices=num_vertices, - num_edges=num_edges, + num_edges=np.int32(num_edges), num_cells=num_cells, offset_provider={ "V2E": gtx.NeighborTableOffsetProvider(v2e_arr, Vertex, Edge, 4, has_skip_values=False), @@ -228,7 +227,6 @@ def skip_value_mesh() -> MeshDescriptor: num_vertices = 7 num_cells = 6 num_edges = 12 - num_levels = 10 v2e_arr = np.array( [ diff --git a/tests/next_tests/integration_tests/feature_tests/ffront_tests/test_temporaries_with_sizes.py b/tests/next_tests/integration_tests/feature_tests/ffront_tests/test_temporaries_with_sizes.py index 4503c6b7a8..13d8f7711e 100644 --- a/tests/next_tests/integration_tests/feature_tests/ffront_tests/test_temporaries_with_sizes.py +++ b/tests/next_tests/integration_tests/feature_tests/ffront_tests/test_temporaries_with_sizes.py @@ -67,7 +67,7 @@ def prog( a: cases.VField, out: cases.EField, num_vertices: int32, - num_edges: int64, + num_edges: int32, num_cells: int32, ): testee_op(a, out=out) From 982a22310befa47d9143af8fa001def32c1037f9 Mon Sep 17 00:00:00 2001 From: Hannes Vogt Date: Tue, 30 Jan 2024 20:06:52 +0100 Subject: [PATCH 3/8] cleanup --- src/gt4py/next/common.py | 2 +- src/gt4py/next/iterator/embedded.py | 4 +-- .../ffront_tests/test_execution.py | 12 +++---- .../ffront_tests/test_external_local_field.py | 5 +-- .../ffront_tests/test_gt4py_builtins.py | 33 ++++++++++++++----- 5 files changed, 36 insertions(+), 20 deletions(-) diff --git a/src/gt4py/next/common.py b/src/gt4py/next/common.py index 338bc09d34..4a128749e0 100644 --- a/src/gt4py/next/common.py +++ b/src/gt4py/next/common.py @@ -1107,4 +1107,4 @@ def __gt_builtin_func__(cls, /, func: fbuiltins.BuiltInFunction[_R, _P]) -> Call #: Numeric value used to represent missing values in connectivities. #: Adopted from UGRID Conventions (http://ugrid-conventions.github.io/ugrid-conventions/) -FILL_CONNECTIVITY_VALUE: Final[int] = -1 +SKIP_VALUE: Final[int] = -1 diff --git a/src/gt4py/next/iterator/embedded.py b/src/gt4py/next/iterator/embedded.py index 237bed5c75..df48979d94 100644 --- a/src/gt4py/next/iterator/embedded.py +++ b/src/gt4py/next/iterator/embedded.py @@ -541,7 +541,7 @@ def execute_shift( assert common.is_int_index(cur_index) if offset_implementation.mapped_index(cur_index, index) in [ None, - -1, + common.SKIP_VALUE, ]: return None @@ -568,7 +568,7 @@ def execute_shift( assert common.is_int_index(cur_index) if offset_implementation.mapped_index(cur_index, index) in [ None, - -1, + common.SKIP_VALUE, ]: return None else: diff --git a/tests/next_tests/integration_tests/feature_tests/ffront_tests/test_execution.py b/tests/next_tests/integration_tests/feature_tests/ffront_tests/test_execution.py index 3642dcdd16..8a045ee827 100644 --- a/tests/next_tests/integration_tests/feature_tests/ffront_tests/test_execution.py +++ b/tests/next_tests/integration_tests/feature_tests/ffront_tests/test_execution.py @@ -572,16 +572,15 @@ def reduce_tuple_element(e: cases.EField, v: cases.VField) -> cases.EField: tmp = red(E2V[0]) return tmp + v2e = unstructured_case.offset_provider["V2E"] cases.verify_with_default_data( unstructured_case, reduce_tuple_element, - # TODO think about the reference ref=lambda e, v: np.sum( - e[unstructured_case.offset_provider["V2E"].table] - + np.tile(v, (unstructured_case.offset_provider["V2E"].max_neighbors, 1)).T, + e[v2e.table] + np.tile(v, (v2e.max_neighbors, 1)).T, axis=1, initial=0, - where=unstructured_case.offset_provider["V2E"].table > common.FILL_CONNECTIVITY_VALUE, + where=v2e.table != common.SKIP_VALUE, )[unstructured_case.offset_provider["E2V"].table[:, 0]], ) @@ -712,15 +711,16 @@ def testee(a: cases.EField, b: cases.EField) -> cases.VField: tmp = neighbor_sum(b(V2E) if 2 < 3 else a(V2E), axis=V2EDim) return tmp + v2e_table = unstructured_case.offset_provider["V2E"].table cases.verify_with_default_data( unstructured_case, testee, ref=lambda a, b: ( np.sum( - b[unstructured_case.offset_provider["V2E"].table], + b[v2e_table], axis=1, initial=0, - where=unstructured_case.offset_provider["V2E"].table != -1, + where=v2e_table != common.SKIP_VALUE, ) ), ) diff --git a/tests/next_tests/integration_tests/feature_tests/ffront_tests/test_external_local_field.py b/tests/next_tests/integration_tests/feature_tests/ffront_tests/test_external_local_field.py index 0ca6393b19..569d7b5631 100644 --- a/tests/next_tests/integration_tests/feature_tests/ffront_tests/test_external_local_field.py +++ b/tests/next_tests/integration_tests/feature_tests/ffront_tests/test_external_local_field.py @@ -43,6 +43,7 @@ def testee( ) ones = cases.allocate(unstructured_case, testee, "ones").strategy(cases.ConstInitializer(1))() + v2e_table = unstructured_case.offset_provider["V2E"].table cases.verify( unstructured_case, testee, @@ -50,10 +51,10 @@ def testee( ones, out=cases.allocate(unstructured_case, testee, cases.RETURN)(), ref=np.sum( - unstructured_case.offset_provider["V2E"].table, + v2e_table, axis=1, initial=0, - where=unstructured_case.offset_provider["V2E"].table != common.FILL_CONNECTIVITY_VALUE, + where=v2e_table != common.SKIP_VALUE, ), ) diff --git a/tests/next_tests/integration_tests/feature_tests/ffront_tests/test_gt4py_builtins.py b/tests/next_tests/integration_tests/feature_tests/ffront_tests/test_gt4py_builtins.py index 5633a0cded..3a03467845 100644 --- a/tests/next_tests/integration_tests/feature_tests/ffront_tests/test_gt4py_builtins.py +++ b/tests/next_tests/integration_tests/feature_tests/ffront_tests/test_gt4py_builtins.py @@ -17,7 +17,7 @@ import pytest import gt4py.next as gtx -from gt4py.next import broadcast, float64, int32, max_over, min_over, neighbor_sum, where +from gt4py.next import broadcast, common, float64, int32, max_over, min_over, neighbor_sum, where from gt4py.next.program_processors.runners import gtfn from next_tests.integration_tests import cases @@ -56,7 +56,12 @@ def testee(edge_f: cases.EField) -> cases.VField: out = cases.allocate(unstructured_case, testee, cases.RETURN)() v2e_table = unstructured_case.offset_provider["V2E"].table - ref = np.max(inp.asnumpy()[v2e_table], axis=1, initial=-42000, where=v2e_table != -1) + ref = np.max( + inp.asnumpy()[v2e_table], + axis=1, + initial=np.iinfo(np.int32).min, + where=v2e_table != common.SKIP_VALUE, + ) cases.verify(unstructured_case, testee, inp, ref=ref, out=out) @@ -69,7 +74,14 @@ def minover(edge_f: cases.EField) -> cases.VField: v2e_table = unstructured_case.offset_provider["V2E"].table cases.verify_with_default_data( - unstructured_case, minover, ref=lambda edge_f: np.min(edge_f[v2e_table], axis=1) + unstructured_case, + minover, + ref=lambda edge_f: np.min( + edge_f[v2e_table], + axis=1, + initial=np.iinfo(np.int32).max, + where=v2e_table != common.SKIP_VALUE, + ), ) @@ -83,14 +95,15 @@ def reduction(edge_f: cases.EField) -> cases.VField: def fencil(edge_f: cases.EField, out: cases.VField): reduction(edge_f, out=out) + v2e_table = unstructured_case.offset_provider["V2E"].table cases.verify_with_default_data( unstructured_case, fencil, ref=lambda edge_f: np.sum( - edge_f[unstructured_case.offset_provider["V2E"].table], + edge_f[v2e_table], axis=1, initial=0, - where=unstructured_case.offset_provider["V2E"].table != -1, + where=v2e_table != common.SKIP_VALUE, ), ) @@ -108,15 +121,16 @@ def reduce_expr(edge_f: cases.EField) -> cases.VField: def fencil(edge_f: cases.EField, out: cases.VField): reduce_expr(edge_f, out=out) + v2e_table = unstructured_case.offset_provider["V2E"].table cases.verify_with_default_data( unstructured_case, fencil, ref=lambda edge_f: 3 * np.sum( - -edge_f[unstructured_case.offset_provider["V2E"].table] ** 2 * 2, + -edge_f[v2e_table] ** 2 * 2, axis=1, initial=0, - where=unstructured_case.offset_provider["V2E"].table != -1, + where=v2e_table != common.SKIP_VALUE, ), ) @@ -127,14 +141,15 @@ def test_reduction_with_common_expression(unstructured_case): def testee(flux: cases.EField) -> cases.VField: return neighbor_sum(flux(V2E) + flux(V2E), axis=V2EDim) + v2e_table = unstructured_case.offset_provider["V2E"].table cases.verify_with_default_data( unstructured_case, testee, ref=lambda flux: np.sum( - flux[unstructured_case.offset_provider["V2E"].table] * 2, + flux[v2e_table] * 2, axis=1, initial=0, - where=unstructured_case.offset_provider["V2E"].table != -1, + where=v2e_table != common.SKIP_VALUE, ), ) From 8415f40ae6ca96c2ec1fe3cbf87c86eeffc1e0cd Mon Sep 17 00:00:00 2001 From: Hannes Vogt Date: Wed, 31 Jan 2024 12:13:32 +0100 Subject: [PATCH 4/8] minor change to embedded --- src/gt4py/next/iterator/embedded.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/gt4py/next/iterator/embedded.py b/src/gt4py/next/iterator/embedded.py index 9cd7486050..7e0e060834 100644 --- a/src/gt4py/next/iterator/embedded.py +++ b/src/gt4py/next/iterator/embedded.py @@ -528,8 +528,6 @@ def execute_shift( if p is None: offset_implementation = offset_provider[tag] assert isinstance(offset_implementation, common.Connectivity) - new_pos = pos.copy() - new_pos.pop(offset_implementation.origin_axis.value) cur_index = pos[offset_implementation.origin_axis.value] assert common.is_int_index(cur_index) if offset_implementation.mapped_index(cur_index, index) in [ From ef4f3a7532147a5a7977249041e7cb6d6c9c590a Mon Sep 17 00:00:00 2001 From: Hannes Vogt Date: Wed, 31 Jan 2024 12:24:12 +0100 Subject: [PATCH 5/8] cleanup --- tests/next_tests/integration_tests/cases.py | 18 +++--- .../ffront_tests/ffront_test_utils.py | 56 +++++++++++++------ 2 files changed, 46 insertions(+), 28 deletions(-) diff --git a/tests/next_tests/integration_tests/cases.py b/tests/next_tests/integration_tests/cases.py index 4f1a354c91..8513c98d89 100644 --- a/tests/next_tests/integration_tests/cases.py +++ b/tests/next_tests/integration_tests/cases.py @@ -35,7 +35,14 @@ from next_tests import definitions as test_definitions from next_tests.integration_tests.feature_tests.ffront_tests.ffront_test_utils import ( # noqa: F401 # fixture and aliases + C2E, + C2V, + E2V, + V2E, + C2EDim, + C2VDim, Cell, + E2VDim, Edge, IDim, Ioff, @@ -43,6 +50,7 @@ Joff, KDim, Koff, + V2EDim, Vertex, exec_alloc_descriptor, mesh_descriptor, @@ -65,16 +73,6 @@ CField: TypeAlias = gtx.Field[[Cell], np.int32] # type: ignore [valid-type] EmptyField: TypeAlias = gtx.Field[[], np.int32] # type: ignore [valid-type] -# TODO(ricoh): unify the following with the `ffront_test_utils.mesh_descriptor` -# fixture if `ffront_test_utils.mesh_descriptor` is not completely superseded -# by `unstructured_case`. -V2EDim = gtx.Dimension("V2E", kind=gtx.DimensionKind.LOCAL) -E2VDim = gtx.Dimension("E2V", kind=gtx.DimensionKind.LOCAL) -C2EDim = gtx.Dimension("C2E", kind=gtx.DimensionKind.LOCAL) -V2E = gtx.FieldOffset("V2E", source=Edge, target=(Vertex, V2EDim)) -E2V = gtx.FieldOffset("E2V", source=Vertex, target=(Edge, E2VDim)) -C2E = gtx.FieldOffset("C2E", source=Edge, target=(Cell, C2EDim)) - ScalarValue: TypeAlias = core_defs.Scalar FieldValue: TypeAlias = gtx.Field FieldViewArg: TypeAlias = FieldValue | ScalarValue | tuple["FieldViewArg", ...] diff --git a/tests/next_tests/integration_tests/feature_tests/ffront_tests/ffront_test_utils.py b/tests/next_tests/integration_tests/feature_tests/ffront_tests/ffront_test_utils.py index 0e4e079408..7c25bf8df1 100644 --- a/tests/next_tests/integration_tests/feature_tests/ffront_tests/ffront_test_utils.py +++ b/tests/next_tests/integration_tests/feature_tests/ffront_tests/ffront_test_utils.py @@ -119,29 +119,33 @@ def debug_itir(tree): Cell = gtx.Dimension("Cell") EdgeOffset = gtx.FieldOffset("EdgeOffset", source=Edge, target=(Edge,)) +V2EDim = gtx.Dimension("V2E", kind=gtx.DimensionKind.LOCAL) +E2VDim = gtx.Dimension("E2V", kind=gtx.DimensionKind.LOCAL) +C2EDim = gtx.Dimension("C2E", kind=gtx.DimensionKind.LOCAL) +C2VDim = gtx.Dimension("C2V", kind=gtx.DimensionKind.LOCAL) +V2E = gtx.FieldOffset("V2E", source=Edge, target=(Vertex, V2EDim)) +E2V = gtx.FieldOffset("E2V", source=Vertex, target=(Edge, E2VDim)) +C2E = gtx.FieldOffset("C2E", source=Edge, target=(Cell, C2EDim)) +C2V = gtx.FieldOffset("C2V", source=Vertex, target=(Cell, C2VDim)) + size = 10 class MeshDescriptor(Protocol): @property - def num_vertices(self) -> int: - ... + def num_vertices(self) -> int: ... @property - def num_cells(self) -> int: - ... + def num_cells(self) -> int: ... @property - def num_edges(self) -> int: - ... + def num_edges(self) -> int: ... @property - def num_levels(self) -> int: - ... + def num_levels(self) -> int: ... @property - def offset_provider(self) -> dict[str, common.Connectivity]: - ... + def offset_provider(self) -> dict[str, common.Connectivity]: ... def simple_mesh() -> MeshDescriptor: @@ -213,10 +217,18 @@ def simple_mesh() -> MeshDescriptor: num_edges=np.int32(num_edges), num_cells=num_cells, offset_provider={ - "V2E": gtx.NeighborTableOffsetProvider(v2e_arr, Vertex, Edge, 4, has_skip_values=False), - "E2V": gtx.NeighborTableOffsetProvider(e2v_arr, Edge, Vertex, 2, has_skip_values=False), - "C2V": gtx.NeighborTableOffsetProvider(c2v_arr, Cell, Vertex, 4, has_skip_values=False), - "C2E": gtx.NeighborTableOffsetProvider(c2e_arr, Cell, Edge, 4, has_skip_values=False), + V2E.value: gtx.NeighborTableOffsetProvider( + v2e_arr, Vertex, Edge, 4, has_skip_values=False + ), + E2V.value: gtx.NeighborTableOffsetProvider( + e2v_arr, Edge, Vertex, 2, has_skip_values=False + ), + C2V.value: gtx.NeighborTableOffsetProvider( + c2v_arr, Cell, Vertex, 4, has_skip_values=False + ), + C2E.value: gtx.NeighborTableOffsetProvider( + c2e_arr, Cell, Edge, 4, has_skip_values=False + ), }, ) # type: ignore @@ -296,10 +308,18 @@ def skip_value_mesh() -> MeshDescriptor: num_edges=num_edges, num_cells=num_cells, offset_provider={ - "V2E": gtx.NeighborTableOffsetProvider(v2e_arr, Vertex, Edge, 5, has_skip_values=True), - "E2V": gtx.NeighborTableOffsetProvider(e2v_arr, Edge, Vertex, 2, has_skip_values=False), - "C2V": gtx.NeighborTableOffsetProvider(c2v_arr, Cell, Vertex, 3, has_skip_values=False), - "C2E": gtx.NeighborTableOffsetProvider(c2e_arr, Cell, Edge, 3, has_skip_values=False), + V2E.value: gtx.NeighborTableOffsetProvider( + v2e_arr, Vertex, Edge, 5, has_skip_values=True + ), + E2V.value: gtx.NeighborTableOffsetProvider( + e2v_arr, Edge, Vertex, 2, has_skip_values=False + ), + C2V.value: gtx.NeighborTableOffsetProvider( + c2v_arr, Cell, Vertex, 3, has_skip_values=False + ), + C2E.value: gtx.NeighborTableOffsetProvider( + c2e_arr, Cell, Edge, 3, has_skip_values=False + ), }, ) # type: ignore From 6711e0609d5776d0de3541f8ce33f7f8593bc535 Mon Sep 17 00:00:00 2001 From: Hannes Vogt Date: Wed, 31 Jan 2024 17:22:19 +0100 Subject: [PATCH 6/8] cleanups --- .../feature_tests/ffront_tests/test_execution.py | 2 +- .../feature_tests/ffront_tests/test_gt4py_builtins.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/next_tests/integration_tests/feature_tests/ffront_tests/test_execution.py b/tests/next_tests/integration_tests/feature_tests/ffront_tests/test_execution.py index 174cb00ad7..4989050006 100644 --- a/tests/next_tests/integration_tests/feature_tests/ffront_tests/test_execution.py +++ b/tests/next_tests/integration_tests/feature_tests/ffront_tests/test_execution.py @@ -513,7 +513,7 @@ def testee(a: cases.EField) -> cases.EField: a[unstructured_case.offset_provider["V2E"].table], axis=1, initial=0, - where=unstructured_case.offset_provider["V2E"].table > 0, + where=unstructured_case.offset_provider["V2E"].table != common.SKIP_VALUE, )[unstructured_case.offset_provider["E2V"].table], axis=1, ), diff --git a/tests/next_tests/integration_tests/feature_tests/ffront_tests/test_gt4py_builtins.py b/tests/next_tests/integration_tests/feature_tests/ffront_tests/test_gt4py_builtins.py index 3a03467845..e27e73c80d 100644 --- a/tests/next_tests/integration_tests/feature_tests/ffront_tests/test_gt4py_builtins.py +++ b/tests/next_tests/integration_tests/feature_tests/ffront_tests/test_gt4py_builtins.py @@ -59,7 +59,7 @@ def testee(edge_f: cases.EField) -> cases.VField: ref = np.max( inp.asnumpy()[v2e_table], axis=1, - initial=np.iinfo(np.int32).min, + initial=np.min(inp.asnumpy()), where=v2e_table != common.SKIP_VALUE, ) cases.verify(unstructured_case, testee, inp, ref=ref, out=out) @@ -79,7 +79,7 @@ def minover(edge_f: cases.EField) -> cases.VField: ref=lambda edge_f: np.min( edge_f[v2e_table], axis=1, - initial=np.iinfo(np.int32).max, + initial=np.max(edge_f), where=v2e_table != common.SKIP_VALUE, ), ) From f8814c88d7d0bd596c05736041150c2ee29911ec Mon Sep 17 00:00:00 2001 From: Hannes Vogt Date: Wed, 31 Jan 2024 17:42:56 +0100 Subject: [PATCH 7/8] named_tuple -> SimpleNamespace --- src/gt4py/next/common.py | 3 +- .../ffront_tests/ffront_test_utils.py | 28 ++++++------------- 2 files changed, 11 insertions(+), 20 deletions(-) diff --git a/src/gt4py/next/common.py b/src/gt4py/next/common.py index 486384c3b4..90e76d671d 100644 --- a/src/gt4py/next/common.py +++ b/src/gt4py/next/common.py @@ -1077,5 +1077,6 @@ def __gt_builtin_func__(cls, /, func: fbuiltins.BuiltInFunction[_R, _P]) -> Call #: Numeric value used to represent missing values in connectivities. -#: Adopted from UGRID Conventions (http://ugrid-conventions.github.io/ugrid-conventions/) +#: Equivalent to the `_FillValue` attribute in the UGRID Conventions +#: (see: http://ugrid-conventions.github.io/ugrid-conventions/). SKIP_VALUE: Final[int] = -1 diff --git a/tests/next_tests/integration_tests/feature_tests/ffront_tests/ffront_test_utils.py b/tests/next_tests/integration_tests/feature_tests/ffront_tests/ffront_test_utils.py index 7c25bf8df1..afca4b564d 100644 --- a/tests/next_tests/integration_tests/feature_tests/ffront_tests/ffront_test_utils.py +++ b/tests/next_tests/integration_tests/feature_tests/ffront_tests/ffront_test_utils.py @@ -13,6 +13,7 @@ # # SPDX-License-Identifier: GPL-3.0-or-later +import types from collections import namedtuple from typing import Any, Protocol, TypeVar @@ -132,6 +133,9 @@ def debug_itir(tree): class MeshDescriptor(Protocol): + @property + def name(self) -> str: ... + @property def num_vertices(self) -> int: ... @@ -204,15 +208,8 @@ def simple_mesh() -> MeshDescriptor: assert all(len(row) == 2 for row in e2v_arr) e2v_arr = np.asarray(e2v_arr, dtype=gtx.IndexType) - return namedtuple( - "SimpleMesh", - [ - "num_vertices", - "num_edges", - "num_cells", - "offset_provider", - ], - )( + return types.SimpleNamespace( + name="simple_mesh", num_vertices=num_vertices, num_edges=np.int32(num_edges), num_cells=num_cells, @@ -295,15 +292,8 @@ def skip_value_mesh() -> MeshDescriptor: dtype=gtx.IndexType, ) - return namedtuple( - "SkipValueMesh", - [ - "num_vertices", - "num_edges", - "num_cells", - "offset_provider", - ], - )( + return types.SimpleNamespace( + name="skip_value_mesh", num_vertices=num_vertices, num_edges=num_edges, num_cells=num_cells, @@ -349,7 +339,7 @@ def skip_value_mesh() -> MeshDescriptor: simple_mesh(), pytest.param(skip_value_mesh(), marks=pytest.mark.uses_mesh_with_skip_values), ], - ids=lambda p: p.__class__.__name__, + ids=lambda p: p.name, ) def mesh_descriptor(request) -> MeshDescriptor: yield request.param From 8d7fd75760f9a87983739a55f686eb5543c5a49d Mon Sep 17 00:00:00 2001 From: Hannes Vogt Date: Wed, 31 Jan 2024 17:53:29 +0100 Subject: [PATCH 8/8] remove type ignore --- .../feature_tests/ffront_tests/ffront_test_utils.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/next_tests/integration_tests/feature_tests/ffront_tests/ffront_test_utils.py b/tests/next_tests/integration_tests/feature_tests/ffront_tests/ffront_test_utils.py index afca4b564d..d8c4696073 100644 --- a/tests/next_tests/integration_tests/feature_tests/ffront_tests/ffront_test_utils.py +++ b/tests/next_tests/integration_tests/feature_tests/ffront_tests/ffront_test_utils.py @@ -227,7 +227,7 @@ def simple_mesh() -> MeshDescriptor: c2e_arr, Cell, Edge, 4, has_skip_values=False ), }, - ) # type: ignore + ) def skip_value_mesh() -> MeshDescriptor: @@ -311,7 +311,7 @@ def skip_value_mesh() -> MeshDescriptor: c2e_arr, Cell, Edge, 3, has_skip_values=False ), }, - ) # type: ignore + ) __all__ = [