Beispiel #1
0
def test_free_slip_equivalence():
    # check if Free slip BC does the same if the normal direction is specified or not

    stencil = LBStencil(Stencil.D2Q9)
    dh = create_data_handling(domain_size=(4, 4), periodicity=(False, False))
    src1 = dh.add_array('src1', values_per_cell=stencil.Q, alignment=True)
    src2 = dh.add_array('src2', values_per_cell=stencil.Q, alignment=True)
    dh.fill('src1', 0.0, ghost_layers=True)
    dh.fill('src2', 0.0, ghost_layers=True)

    shape = dh.gather_array('src1', ghost_layers=True).shape

    num = 0
    for x in range(shape[0]):
        for y in range(shape[1]):
            for direction in range(shape[2]):
                dh.cpu_arrays['src1'][x, y, direction] = num
                dh.cpu_arrays['src2'][x, y, direction] = num
                num += 1

    method = create_lb_method(lbm_config=LBMConfig(
        stencil=stencil, method=Method.SRT, relaxation_rate=1.8))

    bh1 = LatticeBoltzmannBoundaryHandling(method, dh, 'src1', name="bh1")
    free_slip1 = FreeSlip(stencil=stencil)
    bh1.set_boundary(free_slip1, slice_from_direction('N', dh.dim))

    bh2 = LatticeBoltzmannBoundaryHandling(method, dh, 'src2', name="bh2")
    free_slip2 = FreeSlip(stencil=stencil, normal_direction=(0, -1))
    bh2.set_boundary(free_slip2, slice_from_direction('N', dh.dim))

    bh1()
    bh2()

    assert np.array_equal(dh.cpu_arrays['src1'], dh.cpu_arrays['src2'])
Beispiel #2
0
def test_boundary_data_setter():
    dh = SerialDataHandling(domain_size=(7, 7))
    src = dh.add_array('src')
    dh.fill("src", 0.0, ghost_layers=True)
    dh.fill("src", 1.0, ghost_layers=False)
    boundary_stencil = [(1, 0), (-1, 0), (0, 1), (0, -1)]

    boundary_handling = BoundaryHandling(dh,
                                         src.name,
                                         boundary_stencil,
                                         name="boundary_handling",
                                         target=Target.CPU)

    neumann = Neumann()
    for d in 'N':
        boundary_handling.set_boundary(neumann, slice_from_direction(d, dim=2))

    boundary_handling.prepare()

    for b in dh.iterate(ghost_layers=True):
        index_array_bd = b[boundary_handling._index_array_name]
        data_setter = index_array_bd.boundary_object_to_data_setter[
            boundary_handling.boundary_objects[0]]

        y_pos = data_setter.boundary_cell_positions(1)

        assert all(y_pos == 5.5)
        assert np.all(data_setter.link_offsets() == [0, -1])
        assert np.all(data_setter.link_positions(1) == 6.)
Beispiel #3
0
def test_dirichlet(with_indices):
    value = (1, 20, 3) if with_indices else 1

    dh = SerialDataHandling(domain_size=(7, 7))
    src = dh.add_array('src', values_per_cell=3 if with_indices else 1)
    dh.cpu_arrays.src[...] = np.random.rand(*src.shape)
    boundary_stencil = [(1, 0), (-1, 0), (0, 1), (0, -1)]
    boundary_handling = BoundaryHandling(dh, src.name, boundary_stencil)
    dirichlet = Dirichlet(value)
    assert dirichlet.name == 'Dirichlet'
    dirichlet.name = "wall"
    assert dirichlet.name == 'wall'

    for d in ('N', 'S', 'W', 'E'):
        boundary_handling.set_boundary(dirichlet, slice_from_direction(d,
                                                                       dim=2))
    boundary_handling()

    assert all(
        [np.allclose(a, np.array(value)) for a in dh.cpu_arrays.src[1:-2, 0]])
    assert all(
        [np.allclose(a, np.array(value)) for a in dh.cpu_arrays.src[1:-2, -1]])
    assert all(
        [np.allclose(a, np.array(value)) for a in dh.cpu_arrays.src[0, 1:-2]])
    assert all(
        [np.allclose(a, np.array(value)) for a in dh.cpu_arrays.src[-1, 1:-2]])
Beispiel #4
0
def test_boundary_utility():
    dh = SerialDataHandling(domain_size=(7, 7))
    src = dh.add_array('src')
    dh.fill("src", 0.0, ghost_layers=True)

    boundary_stencil = [(1, 0), (-1, 0), (0, 1), (0, -1)]

    boundary_handling = BoundaryHandling(dh,
                                         src.name,
                                         boundary_stencil,
                                         name="boundary_handling",
                                         target=Target.CPU)

    neumann = Neumann()
    dirichlet = Dirichlet(2)
    for d in ('N', 'S', 'W', 'E'):
        boundary_handling.set_boundary(neumann, slice_from_direction(d, dim=2))

    boundary_handling.set_boundary(neumann,
                                   (slice(2, 4, None), slice(2, 4, None)))

    boundary_handling.prepare()

    assert boundary_handling.get_flag(
        boundary_handling.boundary_objects[0]) == 2
    assert boundary_handling.shape == dh.shape
    assert boundary_handling.flag_array_name == 'boundary_handlingFlags'
    mask_neumann = boundary_handling.get_mask(
        (slice(0, 7), slice(0, 7)), boundary_handling.boundary_objects[0])
    np.testing.assert_almost_equal(mask_neumann[1:3, 1:3], 2)

    mask_domain = boundary_handling.get_mask((slice(0, 7), slice(0, 7)),
                                             "domain")
    assert np.sum(mask_domain) == 7**2 - 4

    def set_sphere(x, y):
        mid = (4, 4)
        radius = 2
        return (x - mid[0])**2 + (y - mid[1])**2 < radius**2

    boundary_handling.set_boundary(dirichlet,
                                   mask_callback=set_sphere,
                                   force_flag_value=4)
    mask_dirichlet = boundary_handling.get_mask(
        (slice(0, 7), slice(0, 7)), boundary_handling.boundary_objects[1])
    assert np.sum(mask_dirichlet) == 48

    assert boundary_handling.set_boundary("domain") == 1

    assert boundary_handling.set_boundary(dirichlet,
                                          mask_callback=set_sphere,
                                          force_flag_value=8,
                                          replace=False) == 4
    assert boundary_handling.set_boundary(dirichlet,
                                          force_flag_value=16,
                                          replace=False) == 4

    assert boundary_handling.set_boundary_where_flag_is_set(
        boundary_handling.boundary_objects[0], 16) == 16
Beispiel #5
0
def test_parallel_datahandling_boundary_conditions():
    pytest.importorskip('waLBerla.cuda')

    dh = create_data_handling(domain_size=(7, 7), periodicity=True, parallel=True,
                              default_target=pystencils.Target.GPU)

    src = dh.add_array('src', values_per_cell=1)
    dh.fill(src.name, 0.0, ghost_layers=True)
    dh.fill(src.name, 1.0, ghost_layers=False)

    src2 = dh.add_array('src2', values_per_cell=1)

    src_cpu = dh.add_array('src_cpu', values_per_cell=1, gpu=False)
    dh.fill(src_cpu.name, 0.0, ghost_layers=True)
    dh.fill(src_cpu.name, 1.0, ghost_layers=False)

    boundary_stencil = [(1, 0), (-1, 0), (0, 1), (0, -1)]
    boundary_handling_cpu = BoundaryHandling(dh, src_cpu.name, boundary_stencil,
                                             name="boundary_handling_cpu", target=pystencils.Target.CPU)

    boundary_handling = BoundaryHandling(dh, src.name, boundary_stencil,
                                         name="boundary_handling_gpu", target=pystencils.Target.GPU)

    neumann = Neumann()
    for d in ('N', 'S', 'W', 'E'):
        boundary_handling.set_boundary(neumann, slice_from_direction(d, dim=2))
        boundary_handling_cpu.set_boundary(neumann, slice_from_direction(d, dim=2))

    boundary_handling.prepare()
    boundary_handling_cpu.prepare()

    boundary_handling_cpu()

    dh.all_to_gpu()
    boundary_handling()
    dh.all_to_cpu()
    for block in dh.iterate():
        np.testing.assert_almost_equal(block[src_cpu.name], block[src.name])

    assert dh.custom_data_names == ('boundary_handling_cpuIndexArrays', 'boundary_handling_gpuIndexArrays')
    dh.swap(src.name, src2.name, gpu=True)
Beispiel #6
0
def create_lid_driven_cavity(domain_size=None,
                             lid_velocity=0.005,
                             lbm_kernel=None,
                             parallel=False,
                             data_handling=None,
                             **kwargs):
    """Creates a lid driven cavity scenario.

    Args:
        domain_size: tuple specifying the number of cells in each dimension
        lid_velocity: x velocity of lid in lattice coordinates.
        lbm_kernel: a LBM function, which would otherwise automatically created
        kwargs: other parameters are passed on to the method, see :mod:`lbmpy.creationfunctions`
        parallel: True for distributed memory parallelization with walberla
        data_handling: see documentation of :func:`create_fully_periodic_flow`
    Returns:
        instance of :class:`Scenario`
    """
    assert domain_size is not None or data_handling is not None
    if data_handling is None:
        optimization = kwargs.get('optimization', None)
        target = optimization.get('target', None) if optimization else None
        data_handling = create_data_handling(domain_size,
                                             periodicity=False,
                                             default_ghost_layers=1,
                                             parallel=parallel,
                                             default_target=target)
    step = LatticeBoltzmannStep(data_handling=data_handling,
                                lbm_kernel=lbm_kernel,
                                name="ldc",
                                **kwargs)

    my_ubb = UBB(velocity=[lid_velocity, 0, 0][:step.method.dim])
    step.boundary_handling.set_boundary(my_ubb,
                                        slice_from_direction('N', step.dim))
    for direction in ('W', 'E', 'S') if step.dim == 2 else ('W', 'E', 'S', 'T',
                                                            'B'):
        step.boundary_handling.set_boundary(
            NoSlip(), slice_from_direction(direction, step.dim))

    return step
Beispiel #7
0
def test_boundary_gpu():
    pytest.importorskip('pycuda')
    dh = SerialDataHandling(domain_size=(7, 7), default_target=Target.GPU)
    src = dh.add_array('src')
    dh.fill("src", 0.0, ghost_layers=True)
    dh.fill("src", 1.0, ghost_layers=False)
    src_cpu = dh.add_array('src_cpu', gpu=False)
    dh.fill("src_cpu", 0.0, ghost_layers=True)
    dh.fill("src_cpu", 1.0, ghost_layers=False)

    boundary_stencil = [(1, 0), (-1, 0), (0, 1), (0, -1)]
    boundary_handling_cpu = BoundaryHandling(dh,
                                             src_cpu.name,
                                             boundary_stencil,
                                             name="boundary_handling_cpu",
                                             target=Target.CPU)

    boundary_handling = BoundaryHandling(dh,
                                         src.name,
                                         boundary_stencil,
                                         name="boundary_handling_gpu",
                                         target=Target.GPU)

    neumann = Neumann()
    for d in ('N', 'S', 'W', 'E'):
        boundary_handling.set_boundary(neumann, slice_from_direction(d, dim=2))
        boundary_handling_cpu.set_boundary(neumann,
                                           slice_from_direction(d, dim=2))

    boundary_handling.prepare()
    boundary_handling_cpu.prepare()

    boundary_handling_cpu()

    dh.all_to_gpu()
    boundary_handling()
    dh.all_to_cpu()
    np.testing.assert_almost_equal(dh.cpu_arrays["src_cpu"],
                                   dh.cpu_arrays["src"])
Beispiel #8
0
def test_add_fix_steps():
    dh = SerialDataHandling(domain_size=(7, 7))
    src = dh.add_array('src')
    dh.fill("src", 0.0, ghost_layers=True)
    dh.fill("src", 1.0, ghost_layers=False)
    boundary_stencil = [(1, 0), (-1, 0), (0, 1), (0, -1)]

    boundary_handling = BoundaryHandling(dh,
                                         src.name,
                                         boundary_stencil,
                                         name="boundary_handling",
                                         target=pystencils.Target.CPU)

    neumann = Neumann()
    for d in ('N', 'S', 'W', 'E'):
        boundary_handling.set_boundary(neumann, slice_from_direction(d, dim=2))

    timeloop = TimeLoop(steps=1)
    boundary_handling.add_fixed_steps(timeloop)

    timeloop.run()
    assert np.sum(dh.cpu_arrays['src']) == 7 * 7 + 7 * 4
Beispiel #9
0
def test_kernel_vs_copy_boundary():
    dh = SerialDataHandling(domain_size=(7, 7))
    src = dh.add_array('src')
    dst_builtin = dh.add_array_like('dst_builtin', 'src')
    dst_python_copy = dh.add_array_like('dst_python_copy', 'src')
    dst_handling = dh.add_array_like('dst_handling', 'src')

    src_arr = np.arange(dh.shape[0] * dh.shape[1]).reshape(dh.shape)

    def reset_src():
        for block in dh.iterate(ghost_layers=True, inner_ghost_layers=True):
            np.copyto(block['src'], np.random.rand(*block.shape))

        for block in dh.iterate(ghost_layers=False, inner_ghost_layers=True):
            np.copyto(block['src'], src_arr)

    for b in dh.iterate(ghost_layers=False, inner_ghost_layers=True):
        np.copyto(b['dst_builtin'], 42)
        np.copyto(b['dst_python_copy'], 43)
        np.copyto(b['dst_handling'], 44)

    flags = dh.add_array('flags', dtype=np.uint8)
    dh.fill(flags.name, 0)
    borders = ['N', 'S', 'E', 'W']
    for d in borders:
        dh.fill(flags.name,
                1,
                slice_obj=slice_from_direction(d, dim=2),
                ghost_layers=True,
                inner_ghost_layers=True)

    rhs = sum(src.neighbors([(1, 0), (-1, 0), (0, 1), (0, -1)]))

    simple_kernel = create_kernel([Assignment(dst_python_copy.center,
                                              rhs)]).compile()
    kernel_handling = create_kernel([Assignment(dst_handling.center,
                                                rhs)]).compile()

    assignments_with_boundary = add_neumann_boundary(
        [Assignment(dst_builtin.center, rhs)],
        fields=[src],
        flag_field=flags,
        boundary_flag=1)
    kernel_with_boundary = create_kernel(assignments_with_boundary).compile()

    # ------ Method 1: Built-in boundary
    reset_src()
    dh.run_kernel(kernel_with_boundary)

    # ------ Method 2: Using python to copy out the values (reference)
    reset_src()
    for b in dh.iterate():
        arr = b['src']
        arr[:, 0] = arr[:, 1]
        arr[:, -1] = arr[:, -2]
        arr[0, :] = arr[1, :]
        arr[-1, :] = arr[-2, :]
    dh.run_kernel(simple_kernel)

    # ------ Method 3: Using boundary handling to copy out the values
    reset_src()
    boundary_stencil = [(1, 0), (-1, 0), (0, 1), (0, -1)]
    boundary_handling = BoundaryHandling(dh, src.name, boundary_stencil)
    neumann = Neumann()
    assert neumann.name == 'Neumann'
    neumann.name = "wall"
    assert neumann.name == 'wall'
    assert neumann.additional_data_init_callback is None
    assert len(neumann.additional_data) == 0

    for d in ('N', 'S', 'W', 'E'):
        boundary_handling.set_boundary(neumann, slice_from_direction(d, dim=2))
    boundary_handling()
    dh.run_kernel(kernel_handling)

    python_copy_result = dh.gather_array('dst_python_copy')
    builtin_result = dh.gather_array('dst_builtin')
    handling_result = dh.gather_array('dst_handling')

    np.testing.assert_almost_equal(python_copy_result, builtin_result)
    np.testing.assert_almost_equal(python_copy_result, handling_result)

    with TemporaryDirectory() as tmp_dir:
        pytest.importorskip('pyevtk')
        boundary_handling.geometry_to_vtk(file_name=os.path.join(
            tmp_dir, 'test_output1'),
                                          ghost_layers=False)
        boundary_handling.geometry_to_vtk(file_name=os.path.join(
            tmp_dir, 'test_output2'),
                                          ghost_layers=True)

        boundaries = list(boundary_handling._boundary_object_to_boundary_info.
                          keys()) + ['domain']
        boundary_handling.geometry_to_vtk(file_name=os.path.join(
            tmp_dir, 'test_output3'),
                                          boundaries=boundaries[0],
                                          ghost_layers=False)
Beispiel #10
0
def create_channel(domain_size=None,
                   force=None,
                   pressure_difference=None,
                   u_max=None,
                   diameter_callback=None,
                   duct=False,
                   wall_boundary=NoSlip(),
                   parallel=False,
                   data_handling=None,
                   **kwargs):
    """Create a channel scenario (2D or 3D).

    The channel can be driven either by force, velocity inflow or pressure difference. Choose one and pass
    exactly one of the parameters 'force', 'pressure_difference' or 'u_max'.

    Args:
        domain_size: size of the simulation domain. First coordinate is the flow direction.
        force: Periodic channel, driven by a body force. Pass force in flow direction in lattice units here.
        pressure_difference: Inflow and outflow are fixed pressure conditions, with the given pressure difference.
        u_max: Parabolic velocity profile prescribed at inflow, pressure boundary =1.0 at outflow.
        diameter_callback: optional callback for channel with varying diameters. Only valid if duct=False.
                          The callback receives x coordinate array and domain_size and returns a
                          an array of diameters of the same shape
        duct: if true the channel has rectangular instead of circular cross section
        wall_boundary: instance of boundary class that should be set at the channel walls
        parallel: True for distributed memory parallelization with walberla
        data_handling: see documentation of :func:`create_fully_periodic_flow`
        kwargs: all other keyword parameters are passed directly to scenario class.
    """
    assert domain_size is not None or data_handling is not None

    if [bool(p) for p in (force, pressure_difference, u_max)].count(True) != 1:
        raise ValueError(
            "Please specify exactly one of the parameters 'force', 'pressure_difference' or 'u_max'"
        )

    periodicity = (True, False, False) if force else (False, False, False)
    if data_handling is None:
        dim = len(domain_size)
        assert dim in (2, 3)
        data_handling = create_data_handling(domain_size,
                                             periodicity=periodicity[:dim],
                                             default_ghost_layers=1,
                                             parallel=parallel)

    dim = data_handling.dim
    if force:
        kwargs['force'] = tuple([force, 0, 0][:dim])
        assert data_handling.periodicity[0]
        step = LatticeBoltzmannStep(data_handling=data_handling,
                                    name="force_driven_channel",
                                    **kwargs)
    elif pressure_difference:
        inflow = FixedDensity(1.0 + pressure_difference)
        outflow = FixedDensity(1.0)
        step = LatticeBoltzmannStep(data_handling=data_handling,
                                    name="pressure_driven_channel",
                                    **kwargs)
        step.boundary_handling.set_boundary(inflow,
                                            slice_from_direction('W', dim))
        step.boundary_handling.set_boundary(outflow,
                                            slice_from_direction('E', dim))
    elif u_max:
        if duct:
            raise NotImplementedError(
                "Velocity inflow for duct flows not yet implemented")
        step = LatticeBoltzmannStep(data_handling=data_handling,
                                    name="velocity_driven_channel",
                                    **kwargs)
        diameter = diameter_callback(np.array([
            0
        ]), domain_size)[0] if diameter_callback else min(domain_size[1:])
        add_pipe_inflow_boundary(step.boundary_handling,
                                 u_max,
                                 slice_from_direction('W', dim),
                                 flow_direction=0,
                                 diameter=diameter)
        outflow = FixedDensity(1.0)
        step.boundary_handling.set_boundary(outflow,
                                            slice_from_direction('E', dim))
    else:
        assert False

    directions = ('N', 'S', 'T', 'B') if dim == 3 else ('N', 'S')
    for direction in directions:
        step.boundary_handling.set_boundary(
            wall_boundary, slice_from_direction(direction, dim))

    if duct and diameter_callback is not None:
        raise ValueError(
            "For duct flows, passing a diameter callback does not make sense.")

    if not duct:
        diameter = min(step.boundary_handling.shape[1:])
        add_pipe_walls(step.boundary_handling,
                       diameter_callback if diameter_callback else diameter,
                       wall_boundary)

    return step
Beispiel #11
0
def rod_simulation(stencil_name,
                   diameter,
                   parallel=False,
                   entropic=False,
                   re=150,
                   time_to_simulate=17.0,
                   eval_interval=0.5,
                   write_vtk=True,
                   write_numpy=True):

    if stencil_name == 'D3Q19_new':
        stencil = Stencil.D3Q19
        maxwellian_moments = True
    elif stencil_name == 'D3Q19_old':
        stencil = Stencil.D3Q19
        maxwellian_moments = False
    elif stencil_name == 'D3Q27':
        stencil = Stencil.D3Q27
        maxwellian_moments = False
    else:
        raise ValueError("Unknown stencil name " + stencil_name)
    d = diameter
    length = 16 * d

    u_max_at_throat = 0.07
    u_max_at_inflow = 0.07 / (3**2)

    # Geometry parameters
    inflow_area = int(1.5 * d)
    constriction_length = int(1.8904 * d)
    throat_length = int(10 / 3 * d)
    constriction_diameter = int(d / 3)

    u_mean_at_throat = u_max_at_throat / 2
    lattice_viscosity = u_mean_at_throat * constriction_diameter / re
    omega = relaxation_rate_from_lattice_viscosity(lattice_viscosity)

    lbm_config = LBMConfig(stencil=LBStencil(stencil),
                           compressible=True,
                           method=Method.SRT,
                           relaxation_rate=omega,
                           entropic=entropic,
                           maxwellian_moments=maxwellian_moments)
    kernel_params = {}

    print("ω=", omega)

    dh = create_data_handling(domain_size=(length, d, d), parallel=parallel)
    sc = LatticeBoltzmannStep(data_handling=dh,
                              kernel_params=kernel_params,
                              name=stencil_name,
                              lbm_config=lbm_config)

    # -----------------   Boundary Setup   --------------------------------

    def pipe_geometry(x, *_):
        # initialize with full diameter everywhere
        result = np.ones_like(x) * d

        # constriction
        constriction_begin = inflow_area
        constriction_end = constriction_begin + constriction_length
        c_x = np.linspace(0, 1, constriction_length)
        result[constriction_begin:constriction_end] = d * (
            1 - c_x) + constriction_diameter * c_x

        # throat
        throat_start = constriction_end
        throat_end = throat_start + throat_length
        result[throat_start:throat_end] = constriction_diameter

        return result

    bh = sc.boundary_handling
    add_pipe_inflow_boundary(bh, u_max_at_inflow, make_slice[0, :, :])
    outflow = FixedDensity(1.0)
    bh.set_boundary(outflow, slice_from_direction('E', 3))
    wall = NoSlip()
    add_pipe_walls(bh, pipe_geometry, wall)

    # -----------------   Run  --------------------------------------------

    scenario_name = stencil_name

    if not os.path.exists(scenario_name):
        os.mkdir(scenario_name)

    def to_time_steps(non_dimensional_time):
        return int(diameter / (u_max_at_inflow / 2) * non_dimensional_time)

    time_steps = to_time_steps(time_to_simulate)
    eval_interval = to_time_steps(eval_interval)

    print("Total number of time steps", time_steps)

    for i in range(time_steps // eval_interval):
        sc.run(eval_interval)
        if write_vtk:
            sc.write_vtk()
        vel = sc.velocity[:, :, :, :]
        max_vel = np.max(vel)
        print("Time steps:", sc.time_steps_run, "/", time_steps,
              "Max velocity: ", max_vel)
        if np.isnan(max_vel):
            raise ValueError("Simulation went unstable")
        if write_numpy:
            np.save(scenario_name + f'/velocity_{sc.time_steps_run}',
                    sc.velocity_slice().filled(0.0))
Beispiel #12
0
def test_diffusion():
    """
      Runs the "Diffusion from Plate in Uniform Flow" benchmark as it is described
      in [ch. 8.6.3, The Lattice Boltzmann Method, Krüger et al.].

                dC/dy = 0
            ┌───────────────┐
            │     → → →     │
      C = 0 │     → u →     │ dC/dx = 0
            │     → → →     │
            └───────────────┘
                  C = 1

      The analytical solution is given by:
        C(x,y) = 1 * erfc(y / sqrt(4Dx/u))

      The hydrodynamic field is not simulated, instead a constant velocity is assumed.
    """
    pytest.importorskip("pycuda")
    # Parameters
    domain_size = (1600, 160)
    omega = 1.38
    diffusion = (1 / omega - 0.5) / 3
    velocity = 0.05
    time_steps = 50000
    stencil = LBStencil(Stencil.D2Q9)
    target = ps.Target.GPU

    # Data Handling
    dh = ps.create_data_handling(domain_size=domain_size,
                                 default_target=target)

    vel_field = dh.add_array('vel_field', values_per_cell=stencil.D)
    dh.fill('vel_field', velocity, 0, ghost_layers=True)
    dh.fill('vel_field', 0.0, 1, ghost_layers=True)

    con_field = dh.add_array('con_field', values_per_cell=1)
    dh.fill('con_field', 0.0, ghost_layers=True)

    pdfs = dh.add_array('pdfs', values_per_cell=stencil.Q)
    dh.fill('pdfs', 0.0, ghost_layers=True)
    pdfs_tmp = dh.add_array('pdfs_tmp', values_per_cell=stencil.Q)
    dh.fill('pdfs_tmp', 0.0, ghost_layers=True)

    # Lattice Boltzmann method
    lbm_config = LBMConfig(stencil=stencil,
                           method=Method.MRT,
                           relaxation_rates=[1, 1.5, 1, 1.5, 1],
                           velocity_input=vel_field,
                           output={'density': con_field},
                           compressible=True,
                           weighted=True,
                           kernel_type='stream_pull_collide')

    lbm_opt = LBMOptimisation(symbolic_field=pdfs,
                              symbolic_temporary_field=pdfs_tmp)
    config = ps.CreateKernelConfig(target=dh.default_target, cpu_openmp=True)

    method = create_lb_method(lbm_config=lbm_config)
    method.set_conserved_moments_relaxation_rate(omega)

    lbm_config = replace(lbm_config, lb_method=method)
    update_rule = create_lb_update_rule(lbm_config=lbm_config,
                                        lbm_optimisation=lbm_opt)
    kernel = ps.create_kernel(update_rule, config=config).compile()

    # PDF initalization
    init = pdf_initialization_assignments(method, con_field.center,
                                          vel_field.center_vector,
                                          pdfs.center_vector)
    dh.run_kernel(ps.create_kernel(init).compile())

    dh.all_to_gpu()

    # Boundary Handling
    bh = LatticeBoltzmannBoundaryHandling(update_rule.method,
                                          dh,
                                          'pdfs',
                                          name="bh",
                                          target=dh.default_target)
    add_box_boundary(bh, boundary=NeumannByCopy())
    bh.set_boundary(DiffusionDirichlet(0), slice_from_direction('W', dh.dim))
    bh.set_boundary(DiffusionDirichlet(1), slice_from_direction('S', dh.dim))

    # Timeloop
    for i in range(time_steps):
        bh()
        dh.run_kernel(kernel)
        dh.swap("pdfs", "pdfs_tmp")

    dh.all_to_cpu()
    # Verification
    x = np.arange(1, domain_size[0], 1)
    y = np.arange(0, domain_size[1], 1)
    X, Y = np.meshgrid(x, y)
    analytical = np.zeros(domain_size)
    analytical[1:, :] = np.vectorize(math.erfc)(
        Y / np.vectorize(math.sqrt)(4 * diffusion * X / velocity)).transpose()
    simulated = dh.gather_array('con_field', ghost_layers=False)

    residual = 0
    for i in x:
        for j in y:
            residual += (simulated[i, j] - analytical[i, j])**2
    residual = math.sqrt(residual / (domain_size[0] * domain_size[1]))

    assert residual < 1e-2
Beispiel #13
0
def flow_around_sphere(stencil, galilean_correction, L_LU, total_steps):
    if galilean_correction and stencil.Q != 27:
        return True

    target = Target.GPU
    streaming_pattern = 'aa'
    timesteps = get_timesteps(streaming_pattern)

    u_max = 0.05
    Re = 500000

    kinematic_viscosity = (L_LU * u_max) / Re
    initial_velocity = (u_max, ) + (0, ) * (stencil.D - 1)

    omega_v = relaxation_rate_from_lattice_viscosity(kinematic_viscosity)

    channel_size = (10 * L_LU, ) + (5 * L_LU, ) * (stencil.D - 1)
    sphere_position = (channel_size[0] //
                       3, ) + (channel_size[1] // 2, ) * (stencil.D - 1)
    sphere_radius = L_LU // 2

    lbm_config = LBMConfig(stencil=stencil,
                           method=Method.CUMULANT,
                           relaxation_rate=omega_v,
                           galilean_correction=galilean_correction)

    lbm_opt = LBMOptimisation(pre_simplification=True)
    config = CreateKernelConfig(target=target)

    lb_method = create_lb_method(lbm_config=lbm_config)

    def get_extrapolation_kernel(timestep):
        boundary_assignments = []
        indexing = BetweenTimestepsIndexing(
            pdf_field,
            stencil,
            streaming_pattern=streaming_pattern,
            prev_timestep=timestep)
        f_out, _ = indexing.proxy_fields
        for i, d in enumerate(stencil):
            if d[0] == -1:
                asm = Assignment(f_out.neighbor(0, 1)(i), f_out.center(i))
                boundary_assignments.append(asm)
        boundary_assignments = indexing.substitute_proxies(
            boundary_assignments)
        iter_slice = get_slice_before_ghost_layer((1, ) + (0, ) *
                                                  (stencil.D - 1))
        extrapolation_ast = create_kernel(boundary_assignments,
                                          config=CreateKernelConfig(
                                              iteration_slice=iter_slice,
                                              ghost_layers=1,
                                              target=target))
        return extrapolation_ast.compile()

    dh = create_data_handling(channel_size,
                              periodicity=False,
                              default_layout='fzyx',
                              default_target=target)

    u_field = dh.add_array('u', stencil.D)
    rho_field = dh.add_array('rho', 1)
    pdf_field = dh.add_array('pdfs', stencil.Q)

    dh.fill(u_field.name, 0.0, ghost_layers=True)
    dh.fill(rho_field.name, 0.0, ghost_layers=True)

    dh.to_gpu(u_field.name)
    dh.to_gpu(rho_field.name)

    lbm_opt = replace(lbm_opt, symbolic_field=pdf_field)

    bh = LatticeBoltzmannBoundaryHandling(lb_method,
                                          dh,
                                          pdf_field.name,
                                          streaming_pattern=streaming_pattern,
                                          target=target)
    wall = NoSlip()
    inflow = UBB(initial_velocity)

    bh.set_boundary(inflow, slice_from_direction('W', stencil.D))

    directions = ('N', 'S', 'T', 'B') if stencil.D == 3 else ('N', 'S')
    for direction in directions:
        bh.set_boundary(wall, slice_from_direction(direction, stencil.D))

    outflow_kernels = [
        get_extrapolation_kernel(Timestep.EVEN),
        get_extrapolation_kernel(Timestep.ODD)
    ]

    def sphere_boundary_callback(x, y, z=None):
        x = x - sphere_position[0]
        y = y - sphere_position[1]
        z = z - sphere_position[2] if z is not None else 0
        return np.sqrt(x**2 + y**2 + z**2) <= sphere_radius

    bh.set_boundary(wall, mask_callback=sphere_boundary_callback)

    init_eqs = pdf_initialization_assignments(
        lb_method,
        1.0,
        initial_velocity,
        pdf_field,
        streaming_pattern=streaming_pattern,
        previous_timestep=timesteps[0])
    init_kernel = create_kernel(init_eqs, config=config).compile()

    output = {'density': rho_field, 'velocity': u_field}
    lbm_config = replace(lbm_config, output=output)

    lb_collision_rule = create_lb_collision_rule(lb_method=lb_method,
                                                 lbm_config=lbm_config,
                                                 lbm_optimisation=lbm_opt)

    lb_kernels = []
    for t in timesteps:
        lbm_config = replace(lbm_config, timestep=t)
        lbm_config = replace(lbm_config, streaming_pattern=streaming_pattern)
        lb_kernels.append(
            create_lb_function(collision_rule=lb_collision_rule,
                               lbm_config=lbm_config,
                               lbm_optimisation=lbm_opt,
                               config=config))

    timestep = timesteps[0]

    dh.run_kernel(init_kernel)

    stability_check_frequency = 1000

    for i in range(total_steps):
        bh(prev_timestep=timestep)
        dh.run_kernel(outflow_kernels[timestep.idx])
        timestep = timestep.next()
        dh.run_kernel(lb_kernels[timestep.idx])

        if i % stability_check_frequency == 0:
            dh.to_cpu(u_field.name)
            assert np.isfinite(dh.cpu_arrays[u_field.name]).all()