示例#1
0
def main():
    """main routine testing the performance"""
    print("Reports calls-per-second (larger is better)\n")

    # Cartesian grid with different shapes and boundary conditions
    for size in [32, 512]:
        grid = UnitGrid([size, size], periodic=False)
        print(grid)

        field = ScalarField.random_normal(grid)
        bc_value = np.ones(size)
        result = field.laplace(bc={"value": 1}).data

        for bc in ["scalar", "array", "function", "time-dependent", "linked"]:
            if bc == "scalar":
                bcs = {"value": 1}
            elif bc == "array":
                bcs = {"value": bc_value}
            elif bc == "function":
                bcs = grid.get_boundary_conditions(
                    {"virtual_point": "2 - value"})
            elif bc == "time-dependent":
                bcs = grid.get_boundary_conditions({"value_expression": "t"})
            elif bc == "linked":
                bcs = grid.get_boundary_conditions({"value": bc_value})
                for ax, upper in grid._iter_boundaries():
                    bcs[ax][upper].link_value(bc_value)
            else:
                raise RuntimeError

            # create the operator with these conditions
            laplace = grid.make_operator("laplace", bc=bcs)
            if bc == "time-dependent":
                args = numba_dict({"t": 1})
                # call once to pre-compile and test result
                np.testing.assert_allclose(laplace(field.data, args=args),
                                           result)
                # estimate the speed
                speed = estimate_computation_speed(laplace,
                                                   field.data,
                                                   args=args)

            else:
                # call once to pre-compile and test result
                np.testing.assert_allclose(laplace(field.data), result)
                # estimate the speed
                speed = estimate_computation_speed(laplace, field.data)

            print(f"{bc:>14s}:{int(speed):>9d}")

        print()
def test_gradient_1d():
    """ test specific boundary conditions for the 1d gradient """
    grid = UnitGrid(5)

    b_l = {"type": "derivative", "value": -1}
    b_r = {"type": "derivative", "value": 1}
    bcs = grid.get_boundary_conditions([b_l, b_r])
    grad = ops._make_gradient_numba_1d(bcs)
    np.testing.assert_allclose(grad(np.arange(5)), np.ones((1, 5)))

    b_l = {"type": "value", "value": 3}
    b_r = {"type": "value", "value": 3}
    bcs = grid.get_boundary_conditions([b_l, b_r])
    grad = ops._make_gradient_numba_1d(bcs)
    np.testing.assert_allclose(grad(np.full(5, 3)), np.zeros((1, 5)))
def test_setting_specific_bcs():
    """test the interface of setting specific conditions"""
    grid = UnitGrid([4, 4], periodic=[False, True])
    bcs = grid.get_boundary_conditions("auto_periodic_neumann")

    # test non-periodic axis
    assert str(bcs[0]) == '"derivative"'
    assert str(bcs["x"]) == '"derivative"'
    bcs["x"] = "value"
    assert str(bcs["x"]) == '"value"'
    bcs["left"] = "derivative"
    assert str(bcs["left"]) == '"derivative"'
    assert str(bcs["right"]) == '"value"'
    bcs["right"] = "derivative"
    assert str(bcs["x"]) == '"derivative"'
    with pytest.raises(PeriodicityError):
        bcs["x"] = "periodic"

    # test periodic axis
    assert str(bcs[1]) == '"periodic"'
    assert str(bcs["y"]) == '"periodic"'
    assert str(bcs["top"]) == '"periodic"'
    bcs["y"] = "periodic"
    with pytest.raises(PeriodicityError):
        bcs["y"] = "value"
    with pytest.raises(PeriodicityError):
        bcs["top"] = "value"

    # test wrong input
    with pytest.raises(KeyError):
        bcs["nonsense"]
    with pytest.raises(TypeError):
        bcs[None]
    with pytest.raises(KeyError):
        bcs["nonsense"] = None
def test_user_bcs_numba(dim, target):
    """test setting user BCs"""
    if dim == 1:
        value = 1
    elif dim == 2:
        value = np.arange(3)
    elif dim == 3:
        value = np.arange(9).reshape(3, 3)
    grid = UnitGrid([3] * dim)
    bcs = grid.get_boundary_conditions({"type": "user"})

    # use normal method to set BCs
    f1 = ScalarField(grid)
    f1.set_ghost_cells(bc={target: value})

    # use user method to set BCs
    f2 = ScalarField(grid)
    setter = bcs.make_ghost_cell_setter()

    # test whether normal call is a no-op
    f2._data_full = 3
    setter(f2._data_full)
    np.testing.assert_allclose(f2._data_full, 3)
    setter(f2._data_full, args={"t": 1})
    np.testing.assert_allclose(f2._data_full, 3)
    f2._data_full = 0

    # test whether calling setter with user data works properly
    setter(f2._data_full, args={target: value})
    np.testing.assert_allclose(f1._data_full, f2._data_full)
def test_user_bcs_numpy(dim, target):
    """test setting user BCs"""
    value = np.arange(3) if dim == 2 else 1
    grid = UnitGrid([3] * dim)
    bcs = grid.get_boundary_conditions({"type": "user"})

    # use normal method to set BCs
    f1 = ScalarField(grid)
    f1.set_ghost_cells(bc={target: value})

    # use user method to set BCs
    f2 = ScalarField(grid)

    # test whether normal call is a no-op
    f2._data_full = 3
    f2.set_ghost_cells(bc=bcs)
    np.testing.assert_allclose(f2._data_full, 3)
    f2.set_ghost_cells(bc=bcs, args={"t": 1})
    np.testing.assert_allclose(f2._data_full, 3)
    f2._data_full = 0

    # test whether calling setter with user data works properly
    bcs.set_ghost_cells(f2._data_full, args={target: value})

    np.testing.assert_allclose(f1._data_full, f2._data_full)
示例#6
0
def test_gradient_1d():
    """test specific boundary conditions for the 1d gradient"""
    grid = UnitGrid(5)

    b_l = {"type": "derivative", "value": -1}
    b_r = {"type": "derivative", "value": 1}
    bcs = grid.get_boundary_conditions([b_l, b_r])
    field = ScalarField(grid, np.arange(5))
    res = field.gradient(bcs)
    np.testing.assert_allclose(res.data, np.ones((1, 5)))

    b_l = {"type": "value", "value": 3}
    b_r = {"type": "value", "value": 3}
    bcs = grid.get_boundary_conditions([b_l, b_r])
    field = ScalarField(grid, np.full(5, 3))
    res = field.gradient(bcs)
    np.testing.assert_allclose(res.data, np.zeros((1, 5)))
def test_bc_values():
    """ test setting the values of boundary conditions """
    g = UnitGrid([5])
    bc = g.get_boundary_conditions([{"value": 2}, {"derivative": 3}])
    assert bc[0].low.value == 2 and bc[0].high.value == 3
    bc.scale_value(5)
    assert bc[0].low.value == 10 and bc[0].high.value == 15
    bc.set_value(7)
    assert bc[0].low.value == bc[0].high.value == 7
示例#8
0
def test_set_ghost_cells(dim, periodic):
    """test setting values for ghost cells"""
    grid = UnitGrid([1] * dim, periodic=periodic)
    field = ScalarField.random_uniform(grid)
    bcs = grid.get_boundary_conditions("natural")

    arr1 = field._data_all.copy()
    bcs.set_ghost_cells(arr1)

    arr2 = field._data_all.copy()
    setter = bcs.make_ghost_cell_setter()
    setter(arr2)

    # test valid BCs:
    for n in range(dim):
        idx = [slice(1, -1)] * dim
        idx[n] = slice(None)
        np.testing.assert_allclose(arr1[tuple(idx)], arr2[tuple(idx)])
示例#9
0
def test_setting_boundary_conditions():
    """ test setting some boundary conditions """
    grid = UnitGrid([3, 3], periodic=[True, False])
    for bc in [
            grid.get_boundary_conditions("natural"),
            grid.get_boundary_conditions(["natural", "no-flux"]),
    ]:
        assert isinstance(bc, Boundaries)

    for bc in ["periodic", "value"]:
        with pytest.raises(PeriodicityError):
            grid.get_boundary_conditions(bc)

    grid = UnitGrid([2], periodic=True)
    with pytest.raises(PeriodicityError):
        grid.get_boundary_conditions("derivative")

    grid = UnitGrid([2], periodic=False)
    with pytest.raises(PeriodicityError):
        grid.get_boundary_conditions("periodic")
def test_boundaries_edge_cases():
    """test treatment of invalid data"""
    grid = UnitGrid([3, 3])
    bcs = grid.get_boundary_conditions("auto_periodic_neumann")
    with pytest.raises(BCDataError):
        Boundaries([])
    with pytest.raises(BCDataError):
        Boundaries([bcs[0]])
    with pytest.raises(BCDataError):
        Boundaries([bcs[0], bcs[0]])

    assert bcs == Boundaries([bcs[0], bcs[1]])
    bc0 = get_boundary_axis(grid.copy(), 0, "auto_periodic_neumann")
    assert bcs == Boundaries([bc0, bcs[1]])
    bc0 = get_boundary_axis(UnitGrid([4, 3]), 0, "auto_periodic_neumann")
    with pytest.raises(BCDataError):
        Boundaries([bc0, bcs[1]])
    bc0 = get_boundary_axis(UnitGrid([3, 3], periodic=True), 0, "auto_periodic_neumann")
    with pytest.raises(BCDataError):
        Boundaries([bc0, bcs[1]])
示例#11
0
def test_setting_domain_rect():
    """test various versions of settings bcs for Cartesian grids"""
    grid = UnitGrid([2, 2])
    grid.get_boundary_conditions(["derivative", "derivative"])

    # wrong number of conditions
    with pytest.raises(ValueError):
        grid.get_boundary_conditions(["derivative"])
    with pytest.raises(ValueError):
        grid.get_boundary_conditions(["derivative"] * 3)

    grid = UnitGrid([2, 2], periodic=[True, False])
    grid.get_boundary_conditions("auto_periodic_neumann")
    grid.get_boundary_conditions(["periodic", "derivative"])

    # incompatible conditions
    with pytest.raises(RuntimeError):
        grid.get_boundary_conditions("periodic")
    with pytest.raises(RuntimeError):
        grid.get_boundary_conditions("derivative")
    with pytest.raises(RuntimeError):
        grid.get_boundary_conditions(["derivative", "periodic"])
示例#12
0
def main():
    """main routine testing the performance"""
    print("Reports calls-per-second (larger is better)")
    print("  The `CUSTOM` method implemented by hand is the baseline case.")
    print("  The `FLEXIBLE` method is a serial implementation using the "
          "boundary conditions from the package.")
    print("  The other methods use the functions supplied by the package.\n")

    # Cartesian grid with different shapes and boundary conditions
    for shape in [(32, 32), (512, 512)]:
        for periodic in [True, False]:
            grid = UnitGrid(shape, periodic=periodic)
            print(grid)
            field = ScalarField.random_normal(grid)
            bcs = grid.get_boundary_conditions("natural", rank=0)
            expected = field.laplace("natural")

            for method in [
                    "CUSTOM", "FLEXIBLE", "OPTIMIZED", "numba", "scipy"
            ]:
                if method == "CUSTOM":
                    laplace = custom_laplace_2d(shape, periodic=periodic)
                elif method == "FLEXIBLE":
                    laplace = flexible_laplace_2d(bcs)
                elif method == "OPTIMIZED":
                    laplace = optimized_laplace_2d(bcs)
                elif method in {"numba", "scipy"}:
                    laplace = grid.make_operator("laplace",
                                                 bc=bcs,
                                                 backend=method)
                else:
                    raise ValueError(f"Unknown method `{method}`")

                # call once to pre-compile and test result
                if method == "OPTIMIZED":
                    result = laplace(field._data_all)
                    np.testing.assert_allclose(result, expected.data)
                    speed = estimate_computation_speed(laplace,
                                                       field._data_all)
                else:
                    np.testing.assert_allclose(laplace(field.data),
                                               expected.data)
                    speed = estimate_computation_speed(laplace, field.data)
                print(f"{method:>9s}: {int(speed):>9d}")
            print()

    # Cylindrical grid with different shapes
    for shape in [(32, 64), (512, 512)]:
        grid = CylindricalSymGrid(shape[0], [0, shape[1]], shape)
        print(f"Cylindrical grid, shape={shape}")
        field = ScalarField.random_normal(grid)
        bcs = Boundaries.from_data(grid, "derivative")
        expected = field.laplace(bcs)

        for method in ["CUSTOM", "numba"]:
            if method == "CUSTOM":
                laplace = custom_laplace_cyl_neumann(shape)
            elif method == "numba":
                laplace = grid.make_operator("laplace", bc=bcs)
            else:
                raise ValueError(f"Unknown method `{method}`")
            # call once to pre-compile and test result
            np.testing.assert_allclose(laplace(field.data), expected.data)
            speed = estimate_computation_speed(laplace, field.data)
            print(f"{method:>8s}: {int(speed):>9d}")
        print()

    # Spherical grid with different shapes
    for shape in [32, 512]:
        grid = SphericalSymGrid(shape, shape)
        print(grid)
        field = ScalarField.random_normal(grid)
        bcs = Boundaries.from_data(grid, "derivative")

        for conservative in [True, False]:
            laplace = grid.make_operator("laplace",
                                         bcs,
                                         conservative=conservative)
            laplace(field.data)  # call once to pre-compile
            speed = estimate_computation_speed(laplace, field.data)
            print(
                f" numba (conservative={str(conservative):<5}): {int(speed):>9d}"
            )
        print()
示例#13
0
def test_setting_domain_rect():
    """ test various versions of settings bcs for cartesian grids """
    grid = UnitGrid([2, 2])
    grid.get_boundary_conditions(["no-flux", "no-flux"])

    # wrong number of conditions
    with pytest.raises(ValueError):
        grid.get_boundary_conditions(["no-flux"])
    with pytest.raises(ValueError):
        grid.get_boundary_conditions(["no-flux"] * 3)

    grid = UnitGrid([2, 2], periodic=[True, False])
    grid.get_boundary_conditions("natural")
    grid.get_boundary_conditions(["periodic", "no-flux"])

    # incompatible conditions
    with pytest.raises(RuntimeError):
        grid.get_boundary_conditions("periodic")
    with pytest.raises(RuntimeError):
        grid.get_boundary_conditions("no-flux")
    with pytest.raises(RuntimeError):
        grid.get_boundary_conditions(["no-flux", "periodic"])