diff --git a/src/lbmpy/boundaries/boundaryhandling.py b/src/lbmpy/boundaries/boundaryhandling.py index 6a0d01c5e4d067610843a57a4b85172df064cd22..601534ee330d680f67401704d5561816afdb4a31 100644 --- a/src/lbmpy/boundaries/boundaryhandling.py +++ b/src/lbmpy/boundaries/boundaryhandling.py @@ -1,3 +1,4 @@ +from dataclasses import replace import numpy as np from pystencils import Assignment, CreateKernelConfig, create_kernel, Field, Target @@ -167,19 +168,21 @@ def create_lattice_boltzmann_boundary_kernel(pdf_field, index_field, lb_method, dir_symbol = indexing.dir_symbol inv_dir = indexing.inverse_dir_symbol + config = CreateKernelConfig(target=target, default_number_int="int32", + skip_independence_check=True, **kernel_creation_args) + + default_data_type = config.data_type.default_factory() + if force_vector is None: - force_vector_type = np.dtype([(f"F_{i}", np.float64) for i in range(dim)], align=True) + force_vector_type = np.dtype([(f"F_{i}", default_data_type.c_name) for i in range(dim)], align=True) force_vector = Field.create_generic('force_vector', spatial_dimensions=1, - dtype=force_vector_type, - field_type=FieldType.INDEXED) + dtype=force_vector_type, field_type=FieldType.INDEXED) + + config = replace(config, index_fields=[index_field, force_vector]) boundary_assignments = boundary_functor(f_out, f_in, dir_symbol, inv_dir, lb_method, index_field, force_vector) boundary_assignments = indexing.substitute_proxies(boundary_assignments) - config = CreateKernelConfig(index_fields=[index_field, force_vector], target=target, default_number_int="int32", - skip_independence_check=True, **kernel_creation_args) - - default_data_type = config.data_type.default_factory() if pdf_field.dtype != default_data_type: boundary_assignments = add_subexpressions_for_field_reads(boundary_assignments, data_type=default_data_type) diff --git a/tests/test_boundary_handling.py b/tests/test_boundary_handling.py index e02b4a29cebf86ee5e8fa25ff01419397cf2faf4..25e14e545a82fa3581120ea0b07f6fdc64ab50e4 100644 --- a/tests/test_boundary_handling.py +++ b/tests/test_boundary_handling.py @@ -1,14 +1,16 @@ import numpy as np import pytest -from lbmpy.boundaries import NoSlip, UBB, SimpleExtrapolationOutflow, ExtrapolationOutflow, \ - FixedDensity, DiffusionDirichlet, NeumannByCopy, StreamInConstant, FreeSlip -from lbmpy.boundaries.boundaryhandling import LatticeBoltzmannBoundaryHandling +from lbmpy.boundaries import (NoSlip, NoSlipLinearBouzidi, QuadraticBounceBack, + UBB, SimpleExtrapolationOutflow, ExtrapolationOutflow, FixedDensity, DiffusionDirichlet, + NeumannByCopy, StreamInConstant, FreeSlip) +from lbmpy.boundaries.boundaryhandling import LatticeBoltzmannBoundaryHandling, create_lattice_boltzmann_boundary_kernel from lbmpy.creationfunctions import create_lb_function, create_lb_method, LBMConfig from lbmpy.enums import Stencil, Method from lbmpy.geometry import add_box_boundary from lbmpy.lbstep import LatticeBoltzmannStep from lbmpy.stencils import LBStencil +import pystencils as ps from pystencils import create_data_handling, make_slice, Target, CreateKernelConfig from pystencils.slicing import slice_from_direction from pystencils.stencil import inverse_direction @@ -435,3 +437,45 @@ def test_boundary_utility_functions(): assert stream == StreamInConstant(constant=1.0, name="stream") assert not stream == StreamInConstant(constant=1.0, name="test") assert not stream == noslip + + +@pytest.mark.parametrize("given_force_vector", [True, False]) +@pytest.mark.parametrize("dtype", ["float32", "float64"]) +def test_force_on_boundary(given_force_vector, dtype): + stencil = LBStencil(Stencil.D2Q9) + pdfs = ps.fields(f"pdfs_src({stencil.Q}): {dtype}[{stencil.D}D]", layout='fzyx') + + method = create_lb_method(lbm_config=LBMConfig(stencil=stencil, method=Method.SRT, relaxation_rate=1.8)) + + noslip = NoSlip(name="noslip", calculate_force_on_boundary=True) + bouzidi = NoSlipLinearBouzidi(name="bouzidi", calculate_force_on_boundary=True) + qq_bounce_Back = QuadraticBounceBack(name="qqBB", relaxation_rate=1.8, calculate_force_on_boundary=True) + + boundary_objects = [noslip, bouzidi, qq_bounce_Back] + for boundary in boundary_objects: + if given_force_vector: + force_vector_type = np.dtype([(f"F_{i}", dtype) for i in range(stencil.D)], align=True) + force_vector = ps.Field('forceVector', ps.FieldType.INDEXED, force_vector_type, layout=[0], + shape=(ps.TypedSymbol("forceVectorSize", "int32"), 1), strides=(1, 1)) + else: + force_vector = None + + index_struct_dtype = _numpy_data_type_for_boundary_object(boundary, stencil.D) + + index_field = ps.Field('indexVector', ps.FieldType.INDEXED, index_struct_dtype, layout=[0], + shape=(ps.TypedSymbol("indexVectorSize", "int32"), 1), strides=(1, 1)) + + create_lattice_boltzmann_boundary_kernel(pdfs, index_field, method, boundary, force_vector=force_vector) + + +def _numpy_data_type_for_boundary_object(boundary_object, dim): + boundary_index_array_coordinate_names = ["x", "y", "z"] + direction_member_name = "dir" + default_index_array_dtype = np.int32 + + coordinate_names = boundary_index_array_coordinate_names[:dim] + return np.dtype( + [(name, default_index_array_dtype) for name in coordinate_names] + + [(direction_member_name, default_index_array_dtype)] + + [(i[0], i[1].numpy_dtype) for i in boundary_object.additional_data], + align=True,)