Пример #1
0
    def test_implementation(self, test, parameters_dict):
        """Test computed values for implementations generated for all *backends* and *stencil suites*.

        The generated implementations are reused from previous tests by means of a
        :class:`utils.ImplementationsDB` instance shared at module scope.
        """
        # backend = "debug"

        cls = type(self)
        implementation_list = test["implementations"]
        if not implementation_list:
            pytest.skip(
                "Cannot perform validation tests, since there are no valid implementations."
            )
        for implementation in implementation_list:
            if not isinstance(implementation, StencilObject):
                raise RuntimeError(
                    "Wrong function got from implementations_db cache!")

            fields, exec_info = parameters_dict

            # Domain
            from gt4py.definitions import Shape
            from gt4py.ir.nodes import Index

            origin = cls.origin

            shapes = {}
            for name, field in [(k, v) for k, v in fields.items()
                                if isinstance(v, np.ndarray)]:
                shapes[name] = Shape(field.shape)
            max_domain = Shape([sys.maxsize] *
                               implementation.domain_info.ndims)
            for name, shape in shapes.items():
                upper_boundary = Index(
                    [b[1] for b in cls.symbols[name].boundary])
                max_domain &= shape - (Index(origin) + upper_boundary)
            domain = max_domain

            max_boundary = ((0, 0), (0, 0), (0, 0))
            for name, info in implementation.field_info.items():
                if isinstance(info, gt_definitions.FieldInfo):
                    max_boundary = tuple(
                        (max(m[0], abs(b[0])), max(m[1], b[1]))
                        for m, b in zip(max_boundary, info.boundary))

            new_boundary = tuple(
                (max(abs(b[0]), abs(mb[0])), max(abs(b[1]), abs(mb[1])))
                for b, mb in zip(cls.max_boundary, max_boundary))

            shape = None
            for name, field in fields.items():
                if isinstance(field, np.ndarray):
                    assert field.shape == (shape if shape is not None else
                                           field.shape)
                    shape = field.shape

            patched_origin = tuple(nb[0] for nb in new_boundary)
            patching_origin = tuple(po - o
                                    for po, o in zip(patched_origin, origin))
            patched_shape = tuple(nb[0] + nb[1] + d
                                  for nb, d in zip(new_boundary, domain))
            patching_slices = [
                slice(po, po + s) for po, s in zip(patching_origin, shape)
            ]

            for k, v in implementation.constants.items():
                sys.modules[self.__module__].__dict__[k] = v

            inputs = {}
            for k, f in fields.items():
                if isinstance(f, np.ndarray):
                    patched_f = np.empty(shape=patched_shape)
                    patched_f[patching_slices] = f
                    inputs[k] = gt_storage.from_array(
                        patched_f,
                        dtype=test["definition"].__annotations__[k],
                        shape=patched_f.shape,
                        default_origin=patched_origin,
                        backend=test["backend"],
                    )

                else:
                    inputs[k] = f
            validation_fields = {
                name: np.array(field, copy=True)
                for name, field in inputs.items()
            }

            implementation(**inputs,
                           origin=patched_origin,
                           exec_info=exec_info)
            domain = exec_info["domain"]

            validation_origins = {
                name: tuple(
                    nb[0] - g[0]
                    for nb, g in zip(new_boundary, cls.symbols[name].boundary))
                for name in implementation.field_info.keys()
            }

            validation_shapes = {
                name:
                tuple(d + g[0] + g[1]
                      for d, g in zip(domain, cls.symbols[name].boundary))
                for name in implementation.field_info.keys()
            }

            validation_field_views = {
                name: field[tuple(
                    slice(o, o + s) for o, s in zip(validation_origins[name],
                                                    validation_shapes[name]))]
                if name in implementation.field_info else field  # parameters
                for name, field in validation_fields.items()
            }
            cls.validation(
                **validation_field_views,
                domain=domain,
                origin={
                    name: tuple(b[0] for b in cls.symbols[name].boundary)
                    for name in validation_fields
                    if name in implementation.field_info
                },
            )

            # Test values
            for (name,
                 value), (expected_name,
                          expected_value) in zip(inputs.items(),
                                                 validation_fields.items()):
                if isinstance(fields[name], np.ndarray):
                    domain_slice = [
                        slice(new_boundary[d][0],
                              new_boundary[d][0] + domain[d])
                        for d in range(len(domain))
                    ]
                    np.testing.assert_allclose(
                        value.data[domain_slice],
                        expected_value[domain_slice],
                        rtol=RTOL,
                        atol=ATOL,
                        equal_nan=EQUAL_NAN,
                        err_msg="Wrong data in output field '{name}'".format(
                            name=name),
                    )
Пример #2
0
    def _run_test_implementation(self, parameters_dict, implementation):

        cls = type(self)
        fields, exec_info = parameters_dict

        # Domain
        from gt4py.definitions import Shape
        from gt4py.ir.nodes import Index

        origin = cls.origin

        shapes = {}
        for name, field in [(k, v) for k, v in fields.items() if isinstance(v, np.ndarray)]:
            shapes[name] = Shape(field.shape)
        max_domain = Shape([sys.maxsize] * implementation.domain_info.ndims)
        for name, shape in shapes.items():
            upper_boundary = Index([b[1] for b in cls.symbols[name].boundary])
            max_domain &= shape - (Index(origin) + upper_boundary)
        domain = max_domain

        max_boundary = ((0, 0), (0, 0), (0, 0))
        for info in implementation.field_info.values():
            if isinstance(info, gt_definitions.FieldInfo):
                max_boundary = tuple(
                    (max(m[0], abs(b[0])), max(m[1], b[1]))
                    for m, b in zip(max_boundary, info.boundary)
                )

        new_boundary = tuple(
            (max(abs(b[0]), abs(mb[0])), max(abs(b[1]), abs(mb[1])))
            for b, mb in zip(cls.max_boundary, max_boundary)
        )

        shape = None
        for field in fields.values():
            if isinstance(field, np.ndarray):
                assert field.shape == (shape if shape is not None else field.shape)
                shape = field.shape

        patched_origin = tuple(nb[0] for nb in new_boundary)
        patching_origin = tuple(po - o for po, o in zip(patched_origin, origin))
        patched_shape = tuple(nb[0] + nb[1] + d for nb, d in zip(new_boundary, domain))
        patching_slices = [slice(po, po + s) for po, s in zip(patching_origin, shape)]

        for k, v in implementation.constants.items():
            sys.modules[self.__module__].__dict__[k] = v

        inputs = {}
        for k, f in fields.items():
            if isinstance(f, np.ndarray):
                patched_f = np.empty(shape=patched_shape)
                patched_f[patching_slices] = f
                inputs[k] = gt_storage.from_array(
                    patched_f,
                    dtype=f.dtype,
                    shape=patched_f.shape,
                    default_origin=patched_origin,
                    backend=implementation.backend,
                )

            else:
                inputs[k] = f

        # remove unused input parameters
        inputs = {key: value for key, value in inputs.items() if value is not None}

        validation_fields = {name: np.array(field, copy=True) for name, field in inputs.items()}

        implementation(**inputs, origin=patched_origin, exec_info=exec_info)
        domain = exec_info["domain"]

        validation_origins = {
            name: tuple(nb[0] - g[0] for nb, g in zip(new_boundary, cls.symbols[name].boundary))
            for name in inputs
            if name in implementation.field_info
        }

        validation_shapes = {
            name: tuple(d + g[0] + g[1] for d, g in zip(domain, cls.symbols[name].boundary))
            for name in inputs
            if name in implementation.field_info
        }

        validation_field_views = {
            name: field[
                tuple(
                    slice(o, o + s)
                    for o, s in zip(validation_origins[name], validation_shapes[name])
                )
            ]
            if name in implementation.field_info
            else field  # parameters
            for name, field in validation_fields.items()
        }
        cls.validation(
            **validation_field_views,
            domain=domain,
            origin={
                name: tuple(b[0] for b in cls.symbols[name].boundary)
                for name in validation_fields
                if name in implementation.field_info
            },
        )

        # Test values
        for (name, value), expected_value in zip(inputs.items(), validation_fields.values()):
            if isinstance(fields[name], np.ndarray):
                domain_slice = [
                    slice(new_boundary[d][0], new_boundary[d][0] + domain[d])
                    for d in range(len(domain))
                ]

                if gt_backend.from_name(value.backend).storage_info["device"] == "gpu":
                    value.synchronize()
                    value = value.data.get()
                else:
                    value = value.data

                np.testing.assert_allclose(
                    value[domain_slice],
                    expected_value[domain_slice],
                    rtol=RTOL,
                    atol=ATOL,
                    equal_nan=EQUAL_NAN,
                    err_msg="Wrong data in output field '{name}'".format(name=name),
                )
Пример #3
0
    def _run_test_implementation(cls, parameters_dict, implementation):  # noqa: C901  # too complex
        input_data, exec_info = parameters_dict

        origin = cls.origin
        max_boundary = Boundary(cls.max_boundary)
        field_params = cls.field_params
        field_masks = {}
        for name, value in input_data.items():
            if isinstance(value, np.ndarray):
                field_masks[name] = tuple(
                    ax in field_params[name][0] for ax in CartesianSpace.names
                )

        data_shape = Shape((sys.maxsize,) * 3)
        for name, data in input_data.items():
            if isinstance(data, np.ndarray):
                data_shape &= Shape(
                    interpolate_mask(data.shape, field_masks[name], default=sys.maxsize)
                )

        domain = data_shape - (
            Index(max_boundary.lower_indices) + Index(max_boundary.upper_indices)
        )

        referenced_inputs = {
            name: info for name, info in implementation.field_info.items() if info is not None
        }
        referenced_inputs.update(
            {name: info for name, info in implementation.parameter_info.items() if info is not None}
        )

        # set externals for validation method
        for k, v in implementation.constants.items():
            sys.modules[cls.__module__].__dict__[k] = v

        # copy input data
        test_values = {}
        validation_values = {}
        for name, data in input_data.items():
            data = input_data[name]
            if name in referenced_inputs:
                info = referenced_inputs[name]
                if isinstance(info, FieldInfo):
                    data_dims = field_params[name][1]
                    if data_dims:
                        dtype = (data.dtype, data_dims)
                        shape = data.shape[: -len(data_dims)]
                    else:
                        dtype = data.dtype
                        shape = data.shape
                    test_values[name] = gt_storage.from_array(
                        data,
                        dtype=dtype,
                        shape=shape,
                        mask=field_masks[name],
                        default_origin=origin,
                        backend=implementation.backend,
                    )
                    validation_values[name] = np.array(data)
                else:
                    test_values[name] = data
                    validation_values[name] = data
            else:
                test_values[name] = None
                validation_values[name] = None

        # call implementation
        implementation(**test_values, origin=origin, exec_info=exec_info)
        assert domain == exec_info["domain"]

        # for validation data, data is cropped to actually touched domain, so that origin offseting
        # does not have to be implemented for every test suite. This is done based on info
        # specified in test suite
        cropped_validation_values = {}
        for name, data in validation_values.items():
            sym = cls.symbols[name]
            if data is not None and sym.kind == SymbolKind.FIELD:
                field_extent_low = tuple(b[0] for b in sym.boundary)
                offset_low = tuple(b[0] - e for b, e in zip(max_boundary, field_extent_low))
                field_extent_high = tuple(b[1] for b in sym.boundary)
                offset_high = tuple(b[1] - e for b, e in zip(max_boundary, field_extent_high))
                validation_slice = filter_mask(
                    tuple(slice(o, s - h) for o, s, h in zip(offset_low, data_shape, offset_high)),
                    field_masks[name],
                )
                data_dims = field_params[name][1]
                if data_dims:
                    validation_slice = tuple([*validation_slice] + [slice(None)] * len(data_dims))
                cropped_validation_values[name] = data[validation_slice]
            else:
                cropped_validation_values[name] = data

        cls.validation(
            **cropped_validation_values,
            domain=domain,
            origin={
                name: info.boundary.lower_indices
                for name, info in implementation.field_info.items()
                if info is not None
            },
        )

        # Test values
        for name, value in test_values.items():
            if isinstance(value, np.ndarray):
                expected_value = validation_values[name]

                if gt_backend.from_name(value.backend).storage_info["device"] == "gpu":
                    value.synchronize()
                    value = value.data.get()
                else:
                    value = value.data

                np.testing.assert_allclose(
                    value,
                    expected_value,
                    rtol=RTOL,
                    atol=ATOL,
                    equal_nan=EQUAL_NAN,
                    err_msg="Wrong data in output field '{name}'".format(name=name),
                )
Пример #4
0
    def _run_test_implementation(self, parameters_dict, implementation):

        cls = type(self)
        input_data, exec_info = parameters_dict

        origin = cls.origin
        max_boundary = Boundary(cls.max_boundary)

        shape_iter = (Shape(v.shape) for v in input_data.values()
                      if isinstance(v, np.ndarray))
        shape = next(shape_iter)
        assert all(shape == sh for sh in shape_iter)

        domain = shape - (Index(max_boundary.lower_indices) +
                          Index(max_boundary.upper_indices))

        referenced_inputs = {
            name: info
            for name, info in implementation.field_info.items()
            if info is not None
        }
        referenced_inputs.update({
            name: info
            for name, info in implementation.parameter_info.items()
            if info is not None
        })

        # set externals for validation method
        for k, v in implementation.constants.items():
            sys.modules[self.__module__].__dict__[k] = v

        # copy input data
        inputs = {}
        validation_inputs = {}
        for name, data in input_data.items():
            data = input_data[name]
            if name in referenced_inputs:
                info = referenced_inputs[name]
                if isinstance(info, FieldInfo):
                    inputs[name] = gt_storage.from_array(
                        data,
                        dtype=data.dtype,
                        shape=shape,
                        default_origin=origin,
                        backend=implementation.backend,
                    )
                    validation_inputs[name] = np.array(data)
                else:
                    inputs[name] = data
                    validation_inputs[name] = data
            else:
                inputs[name] = None
                validation_inputs[name] = None

        # call implementation
        implementation(**inputs, origin=origin, exec_info=exec_info)
        assert domain == exec_info["domain"]

        # for validation data, data is cropped to actually touched domain, so that origin offseting
        # does not have to be implemented for every test suite. This is done based on info
        # specified in test suite
        cropped_validation_inputs = {}
        for name, data in validation_inputs.items():
            sym = cls.symbols[name]
            if data is not None and sym.kind == SymbolKind.FIELD:
                field_extent_low = tuple(b[0] for b in sym.boundary)
                offset_low = tuple(
                    b[0] - e for b, e in zip(max_boundary, field_extent_low))
                field_extent_high = tuple(b[1] for b in sym.boundary)
                offset_high = tuple(
                    b[1] - e for b, e in zip(max_boundary, field_extent_high))
                validation_slice = tuple(
                    slice(o, s - h)
                    for o, s, h in zip(offset_low, shape, offset_high))
                cropped_validation_inputs[name] = data[validation_slice]
            else:
                cropped_validation_inputs[name] = data

        cls.validation(
            **cropped_validation_inputs,
            domain=domain,
            origin={
                name: info.boundary.lower_indices
                for name, info in implementation.field_info.items()
                if info is not None
            },
        )

        # Test values
        for name, value in inputs.items():
            if isinstance(value, np.ndarray):
                expected_value = validation_inputs[name]

                if gt_backend.from_name(
                        value.backend).storage_info["device"] == "gpu":
                    value.synchronize()
                    value = value.data.get()
                else:
                    value = value.data

                np.testing.assert_allclose(
                    value,
                    expected_value,
                    rtol=RTOL,
                    atol=ATOL,
                    equal_nan=EQUAL_NAN,
                    err_msg="Wrong data in output field '{name}'".format(
                        name=name),
                )