From d514fba41ed0ec8de86f64cd8668bdf9e9670889 Mon Sep 17 00:00:00 2001 From: Markus Holzer <markus.holzer@fau.de> Date: Tue, 13 Feb 2024 14:39:43 +0100 Subject: [PATCH] Integration for Interpolation BCs --- .../lbmpy_walberla/additional_data_handler.py | 135 +++++++++++-- python/lbmpy_walberla/boundary_collection.py | 3 +- tests/lbm_generated/CMakeLists.txt | 21 ++ tests/lbm_generated/InterpolationNoSlip.cpp | 191 ++++++++++++++++++ tests/lbm_generated/InterpolationNoSlip.prm | 30 +++ tests/lbm_generated/InterpolationNoSlip.py | 53 +++++ 6 files changed, 420 insertions(+), 13 deletions(-) create mode 100644 tests/lbm_generated/InterpolationNoSlip.cpp create mode 100644 tests/lbm_generated/InterpolationNoSlip.prm create mode 100644 tests/lbm_generated/InterpolationNoSlip.py diff --git a/python/lbmpy_walberla/additional_data_handler.py b/python/lbmpy_walberla/additional_data_handler.py index 6df75061a..daaab32fd 100644 --- a/python/lbmpy_walberla/additional_data_handler.py +++ b/python/lbmpy_walberla/additional_data_handler.py @@ -9,21 +9,38 @@ try: except ImportError: from lbmpy.custom_code_nodes import MirroredStencilDirections from lbmpy.boundaries.boundaryconditions import LbBoundary -from lbmpy.boundaries import ExtrapolationOutflow, FreeSlip, UBB, DiffusionDirichlet +from lbmpy.boundaries import (ExtrapolationOutflow, FreeSlip, UBB, DiffusionDirichlet, + NoSlipLinearBouzidi, QuadraticBounceBack) from pystencils_walberla.additional_data_handler import AdditionalDataHandler -def default_additional_data_handler(boundary_obj: LbBoundary, lb_method, field_name, target=Target.CPU): +interpolation_bc_check_template = """ +if(!isFlagSet(it.neighbor({cx}, {cy}, {cz}, 0), domainFlag)){{ + //Linear-Bouzidi requires 2 fluid nodes: if the 2nd node is not available abort, + //apply Bounce Back at that point. This clearly lowers the accuracy and makes inconsistent the + //calculation of the total force + element.q = -1.0; + WALBERLA_LOG_INFO_ON_ROOT("Warning: Bouzidi cannot be applied at least on one boundary link.") +}} //end if to check Bouzidi applicability +""" + + +def default_additional_data_handler(boundary_obj: LbBoundary, lb_method, field_name, target=Target.CPU, + pdfs_data_type=None, zeroth_timestep=None): if not boundary_obj.additional_data: return None - if isinstance(boundary_obj, FreeSlip): return FreeSlipAdditionalDataHandler(lb_method.stencil, boundary_obj) elif isinstance(boundary_obj, UBB): return UBBAdditionalDataHandler(lb_method.stencil, boundary_obj) elif isinstance(boundary_obj, ExtrapolationOutflow): - return OutflowAdditionalDataHandler(lb_method.stencil, boundary_obj, target=target, field_name=field_name) + return OutflowAdditionalDataHandler(lb_method.stencil, boundary_obj, target=target, field_name=field_name, + pdfs_data_type=pdfs_data_type, zeroth_timestep=zeroth_timestep) + elif isinstance(boundary_obj, NoSlipLinearBouzidi): + return NoSlipLinearBouzidiAdditionalDataHandler(lb_method.stencil, boundary_obj) + elif isinstance(boundary_obj, QuadraticBounceBack): + return QuadraticBounceBackAdditionalDataHandler(lb_method.stencil, boundary_obj) else: raise ValueError(f"No default AdditionalDataHandler available for boundary of type {boundary_obj.__class__}") @@ -107,7 +124,7 @@ class UBBAdditionalDataHandler(AdditionalDataHandler): @property def initialiser_list(self): - return "elementInitaliser(velocityCallback)," + return "elementInitialiser(velocityCallback)," @property def additional_arguments_for_fill_function(self): @@ -117,23 +134,117 @@ class UBBAdditionalDataHandler(AdditionalDataHandler): def additional_parameters_for_fill_function(self): return " const shared_ptr<StructuredBlockForest> &blocks, " - def data_initialisation(self, direction): - init_list = ["Vector3<real_t> InitialisatonAdditionalData = elementInitaliser(Cell(it.x(), it.y(), it.z()), " - "blocks, *block);", "element.vel_0 = InitialisatonAdditionalData[0];", - "element.vel_1 = InitialisatonAdditionalData[1];"] + def data_initialisation(self, *_): + init_list = ["Vector3<real_t> InitialisationAdditionalData = elementInitialiser(Cell(it.x(), it.y(), it.z()), " + "blocks, *block);", "element.vel_0 = InitialisationAdditionalData[0];", + "element.vel_1 = InitialisationAdditionalData[1];"] if self._dim == 3: - init_list.append("element.vel_2 = InitialisatonAdditionalData[2];") + init_list.append("element.vel_2 = InitialisationAdditionalData[2];") return "\n".join(init_list) @property def additional_member_variable(self): return "std::function<Vector3<real_t>(const Cell &, const shared_ptr<StructuredBlockForest>&, IBlock&)> " \ - "elementInitaliser; " + "elementInitialiser; " + + +class NoSlipLinearBouzidiAdditionalDataHandler(AdditionalDataHandler): + def __init__(self, stencil, boundary_object): + assert isinstance(boundary_object, NoSlipLinearBouzidi) + + self._dtype = BasicType(boundary_object.data_type).c_name + self._blocks = "const shared_ptr<StructuredBlockForest>&, IBlock&)>" + super(NoSlipLinearBouzidiAdditionalDataHandler, self).__init__(stencil=stencil) + + @property + def constructor_argument_name(self): + return "wallDistanceBouzidi" + + @property + def constructor_arguments(self): + return f", std::function<{self._dtype}(const Cell &, const Cell &, {self._blocks}&" \ + f"{self.constructor_argument_name} " + + @property + def initialiser_list(self): + return f"elementInitialiser({self.constructor_argument_name})," + + @property + def additional_arguments_for_fill_function(self): + return "blocks, " + + @property + def additional_parameters_for_fill_function(self): + return " const shared_ptr<StructuredBlockForest> &blocks, " + + def data_initialisation(self, direction): + cx = self._walberla_stencil[direction][0] + cy = self._walberla_stencil[direction][1] + cz = self._walberla_stencil[direction][2] + fluid_cell = "Cell(it.x(), it.y(), it.z())" + boundary_cell = f"Cell(it.x() + {cx}, it.y() + {cy}, it.z() + {cz})" + check_str = interpolation_bc_check_template.format(cx=-cx, cy=-cy, cz=-cz) + init_element = f"elementInitialiser({fluid_cell}, {boundary_cell}, blocks, *block)" + init_list = [f"const {self._dtype} q = (({self._dtype}) {init_element});", + "element.q = q;", + check_str] + + return "\n".join(init_list) + + @property + def additional_member_variable(self): + return f"std::function<{self._dtype}(const Cell &, const Cell &, {self._blocks} elementInitialiser; " + + +class QuadraticBounceBackAdditionalDataHandler(AdditionalDataHandler): + def __init__(self, stencil, boundary_object): + assert isinstance(boundary_object, QuadraticBounceBack) + + self._dtype = BasicType(boundary_object.data_type).c_name + self._blocks = "const shared_ptr<StructuredBlockForest>&, IBlock&)>" + super(QuadraticBounceBackAdditionalDataHandler, self).__init__(stencil=stencil) + + @property + def constructor_argument_name(self): + return "wallDistanceQuadraticBB" + + @property + def constructor_arguments(self): + return f", std::function<{self._dtype}(const Cell &, const Cell &, {self._blocks}&" \ + f"{self.constructor_argument_name} " + + @property + def initialiser_list(self): + return f"elementInitialiser({self.constructor_argument_name})," + + @property + def additional_arguments_for_fill_function(self): + return "blocks, " + + @property + def additional_parameters_for_fill_function(self): + return " const shared_ptr<StructuredBlockForest> &blocks, " + + def data_initialisation(self, direction): + cx = self._walberla_stencil[direction][0] + cy = self._walberla_stencil[direction][1] + cz = self._walberla_stencil[direction][2] + fluid_cell = "Cell(it.x(), it.y(), it.z())" + boundary_cell = f"Cell(it.x() + {cx}, it.y() + {cy}, it.z() + {cz})" + init_element = f"elementInitialiser({fluid_cell}, {boundary_cell}, blocks, *block)" + init_list = [f"const {self._dtype} q = (({self._dtype}) {init_element});", "element.q = q;"] + + return "\n".join(init_list) + + @property + def additional_member_variable(self): + return f"std::function<{self._dtype}(const Cell &, const Cell &, {self._blocks} elementInitialiser; " class OutflowAdditionalDataHandler(AdditionalDataHandler): - def __init__(self, stencil, boundary_object, target=Target.CPU, field_name='pdfs', pdfs_data_type=None, zeroth_timestep=None): + def __init__(self, stencil, boundary_object, target=Target.CPU, field_name='pdfs', + pdfs_data_type=None, zeroth_timestep=None): assert isinstance(boundary_object, ExtrapolationOutflow) self._stencil = boundary_object.stencil self._lb_method = boundary_object.lb_method diff --git a/python/lbmpy_walberla/boundary_collection.py b/python/lbmpy_walberla/boundary_collection.py index 082567204..3830d8bb4 100644 --- a/python/lbmpy_walberla/boundary_collection.py +++ b/python/lbmpy_walberla/boundary_collection.py @@ -113,7 +113,8 @@ def __generate_alternating_lbm_boundary(generation_context, **create_kernel_params): if boundary_object.additional_data and additional_data_handler is None: target = create_kernel_params.get('target', Target.CPU) - additional_data_handler = default_additional_data_handler(boundary_object, lb_method, field_name, target=target) + additional_data_handler = default_additional_data_handler(boundary_object, lb_method, field_name, + target=target, pdfs_data_type=field_data_type) timestep_param_name = 'timestep' timestep_param_dtype = np.uint8 diff --git a/tests/lbm_generated/CMakeLists.txt b/tests/lbm_generated/CMakeLists.txt index c221e14ce..8ba33e735 100644 --- a/tests/lbm_generated/CMakeLists.txt +++ b/tests/lbm_generated/CMakeLists.txt @@ -6,8 +6,11 @@ waLBerla_link_files_to_builddir( "*.prm" ) waLBerla_link_files_to_builddir( "*.py" ) +if( WALBERLA_BUILD_WITH_CODEGEN ) + waLBerla_generate_target_from_python(NAME ExampleGenerated FILE Example.py + CODEGEN_CFG example_codegen OUT_FILES LBMStorageSpecification.h LBMStorageSpecification.cpp LBMSweepCollection.h LBMSweepCollection.cpp NoSlip.h NoSlip.cpp @@ -16,6 +19,24 @@ waLBerla_generate_target_from_python(NAME ExampleGenerated Example_InfoHeader.h) waLBerla_compile_test( FILES Example.cpp DEPENDS ExampleGenerated blockforest field lbm_generated timeloop ) +waLBerla_generate_target_from_python(NAME InterpolationNoSlipGenerated + FILE InterpolationNoSlip.py + CODEGEN_CFG interpolation_no_slip_codegen + OUT_FILES InterpolationNoSlipStorageSpecification.h InterpolationNoSlipStorageSpecification.cpp + InterpolationNoSlipSweepCollection.h InterpolationNoSlipSweepCollection.cpp + NoSlip.h NoSlip.cpp + NoSlipBouzidi.h NoSlipBouzidi.cpp + NoSlipQuadraticBB.h NoSlipQuadraticBB.cpp + UBB.h UBB.cpp + InterpolationNoSlipBoundaryCollection.h + InterpolationNoSlipHeader.h) + +waLBerla_compile_test( FILES InterpolationNoSlip.cpp DEPENDS InterpolationNoSlipGenerated blockforest core field geometry lbm_generated timeloop ) +# waLBerla_execute_test( NAME InterpolationNoSlip1 COMMAND $<TARGET_FILE:InterpolationNoSlip> ${CMAKE_CURRENT_SOURCE_DIR}/InterpolationNoSlip.prm -Parameters.distanceWall=0.1 ) +# waLBerla_execute_test( NAME InterpolationNoSlip2 COMMAND $<TARGET_FILE:InterpolationNoSlip> ${CMAKE_CURRENT_SOURCE_DIR}/InterpolationNoSlip.prm -Parameters.distanceWall=0.5 ) +waLBerla_execute_test( NAME InterpolationNoSlip3 COMMAND $<TARGET_FILE:InterpolationNoSlip> ${CMAKE_CURRENT_SOURCE_DIR}/InterpolationNoSlip.prm ) +endif() + waLBerla_generate_target_from_python(NAME FreeSlipRefinementGenerated FILE FreeSlipRefinement.py CODEGEN_CFG free_slip_refinement_codegen diff --git a/tests/lbm_generated/InterpolationNoSlip.cpp b/tests/lbm_generated/InterpolationNoSlip.cpp new file mode 100644 index 000000000..cfbe99fcc --- /dev/null +++ b/tests/lbm_generated/InterpolationNoSlip.cpp @@ -0,0 +1,191 @@ +//====================================================================================================================== +// +// This file is part of waLBerla. waLBerla is free software: you can +// redistribute it and/or modify it under the terms of the GNU General Public +// License as published by the Free Software Foundation, either version 3 of +// the License, or (at your option) any later version. +// +// waLBerla is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with waLBerla (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>. +// +//! \file InterpolatedNoSlip.cpp +//! \author Markus Holzer <markus.holzer@fau.de> +//! \brief Couette flow driven by a UBB BC in Nord and wall boundary in the South. Remaining directions are periodic +//! If Interpolation BC are used the distance of the southern wall can be controlled. The velocity in the +//! first fluid cell is checked and compared with the velocity obtained from a default NoSlip BC. +//! Depending on the set distance for the interpolation BCs the velocity is expected to be higher or lower +// +//====================================================================================================================== +#include "blockforest/Initialization.h" +#include "blockforest/communication/UniformBufferedScheme.h" + +#include "core/DataTypes.h" +#include "core/Environment.h" +#include "core/debug/TestSubsystem.h" +#include "core/logging/Initialization.h" +#include "core/math/Vector3.h" +#include "core/timing/RemainingTimeLogger.h" + +#include "field/AddToStorage.h" +#include "field/FlagField.h" +#include "field/GhostLayerField.h" +#include "field/vtk/VTKWriter.h" + +#include "geometry/InitBoundaryHandling.h" + +#include "timeloop/SweepTimeloop.h" + +#include "lbm_generated/communication/UniformGeneratedPdfPackInfo.h" +#include "lbm_generated/field/AddToStorage.h" +#include "lbm_generated/field/PdfField.h" + +// include the generated header file. It includes all generated classes +#include "InterpolationNoSlipHeader.h" + +using namespace walberla; +using namespace std::placeholders; + +using StorageSpecification_T = lbm::InterpolationNoSlipStorageSpecification; +using Stencil_T = StorageSpecification_T::Stencil; +using CommunicationStencil_T = StorageSpecification_T::CommunicationStencil; +using PdfField_T = lbm_generated::PdfField< StorageSpecification_T >; +using PackInfo_T = lbm_generated::UniformGeneratedPdfPackInfo< PdfField_T >; + +using SweepCollection_T = lbm::InterpolationNoSlipSweepCollection; + +using VectorField_T = GhostLayerField< real_t, StorageSpecification_T::Stencil::D >; +using ScalarField_T = GhostLayerField< real_t, 1 >; + +using flag_t = walberla::uint8_t; +using FlagField_T = FlagField< flag_t >; +using BoundaryCollection_T = lbm::InterpolationNoSlipBoundaryCollection< FlagField_T >; + +using blockforest::communication::UniformBufferedScheme; + +class wallDistance +{ + public: + wallDistance(const real_t q) : q_(q) {} + + real_t operator()(const Cell& fluidCell, const Cell& boundaryCell, const shared_ptr< StructuredBlockForest >& SbF, + IBlock& block) const; + + private: + const real_t q_; +}; // class wallDistance + +real_t wallDistance::operator()(const Cell& /*fluidCell*/, const Cell& /*boundaryCell*/, + const shared_ptr< StructuredBlockForest >& /*SbF*/, IBlock& /*block*/) const +{ + return q_; +} + +int main(int argc, char** argv) +{ + debug::enterTestMode(); + walberla::Environment walberlaEnv(argc, argv); + logging::configureLogging(walberlaEnv.config()); + + auto blocks = blockforest::createUniformBlockGridFromConfig(walberlaEnv.config()); + + auto domainSetup = walberlaEnv.config()->getOneBlock("DomainSetup"); + Vector3< uint_t > cellsPerBlock = domainSetup.getParameter< Vector3< uint_t > >("cellsPerBlock"); + + // read parameters + auto parameters = walberlaEnv.config()->getOneBlock("Parameters"); + const real_t omega = parameters.getParameter< real_t >("omega", real_c(1.4)); + const real_t distanceWall = parameters.getParameter< real_t >("distanceWall", real_c(0.5)); + const uint_t timesteps = parameters.getParameter< uint_t >("timesteps", uint_c(10)) + uint_c(1); + + WALBERLA_LOG_DEVEL_VAR(distanceWall) + + auto remainingTimeLoggerFrequency = + parameters.getParameter< real_t >("remainingTimeLoggerFrequency", real_c(3.0)); // in seconds + + const StorageSpecification_T StorageSpec = StorageSpecification_T(); + BlockDataID pdfFieldId = lbm_generated::addPdfFieldToStorage(blocks, "pdf field", StorageSpec, uint_c(1)); + BlockDataID velFieldId = field::addToStorage< VectorField_T >(blocks, "Velocity", real_c(0.0), field::fzyx); + + BlockDataID flagFieldId = field::addFlagFieldToStorage< FlagField_T >(blocks, "flag field", uint_c(1)); + + SweepCollection_T sweepCollection(blocks, pdfFieldId, velFieldId, omega); + for (auto& block : *blocks) + { + sweepCollection.initialise(&block); + } + + const FlagUID fluidFlagUID("Fluid"); + auto boundariesConfig = walberlaEnv.config()->getBlock("Boundaries"); + geometry::initBoundaryHandling< FlagField_T >(*blocks, flagFieldId, boundariesConfig); + geometry::setNonBoundaryCellsToDomain< FlagField_T >(*blocks, flagFieldId, fluidFlagUID); + + const wallDistance wallDistanceCallback{ distanceWall }; + std::function< real_t(const Cell&, const Cell&, const shared_ptr< StructuredBlockForest >&, IBlock&) > + wallDistanceFunctor = wallDistanceCallback; + // For the BoundaryCollection a funcotr to calculate the wall distance for the Bouzidi NoSlip and for the QuadraticBB + // have to be provided. In this test case we use the same function to calculate the wall distance + BoundaryCollection_T boundaryCollection(blocks, flagFieldId, pdfFieldId, fluidFlagUID, omega, wallDistanceFunctor, + wallDistanceFunctor); + + auto packInfo = std::make_shared< lbm_generated::UniformGeneratedPdfPackInfo< PdfField_T > >(pdfFieldId); + UniformBufferedScheme< Stencil_T > communication(blocks); + communication.addPackInfo(packInfo); + + SweepTimeloop timeloop(blocks->getBlockStorage(), timesteps); + timeloop.add() << BeforeFunction(communication, "communication") + << Sweep(boundaryCollection.getSweep(BoundaryCollection_T::ALL), "Boundary Conditions"); + timeloop.add() << Sweep(sweepCollection.streamCollide(SweepCollection_T::ALL), "LBM StreamCollide"); + + uint_t vtkWriteFrequency = parameters.getParameter< uint_t >("vtkWriteFrequency", 0); + if (vtkWriteFrequency > 0) + { + auto vtkOutput = vtk::createVTKOutput_BlockData(*blocks, "InterpolationNoSlipVTK", vtkWriteFrequency, 0, false, + "vtk_out", "simulation_step", false, true, true, false, 0); + + auto velWriter = make_shared< field::VTKWriter< VectorField_T > >(velFieldId, "velocity"); + vtkOutput->addBeforeFunction([&]() { + for (auto& block : *blocks) + { + sweepCollection.calculateMacroscopicParameters(&block); + } + }); + + vtkOutput->addCellDataWriter(velWriter); + timeloop.addFuncBeforeTimeStep(vtk::writeFiles(vtkOutput), "VTK Output"); + } + + if (remainingTimeLoggerFrequency > 0) + { + // log remaining time + timeloop.addFuncAfterTimeStep( + timing::RemainingTimeLogger(timeloop.getNrOfTimeSteps(), remainingTimeLoggerFrequency), + "remaining time logger"); + } + + timeloop.run(); + + // This is the velocity at the wall, when a NoSlip BC is used. This is similar to using an interpolation BC with a + // wall distance of 0.5. This value can be obtained by either setting distanceWall to 0.5 in the Parameter file or + // specifying the NoSlip BC at the southern boundary + const real_t defaultNoSlipVelocity = real_c(0.0002); + + for (auto& block : *blocks) + { + sweepCollection.calculateMacroscopicParameters(&block); + + auto velField = block.getData< VectorField_T >(velFieldId); + auto velAtWall = velField->get(cell_idx_c(cellsPerBlock[0] / 2), 0, cell_idx_c(cellsPerBlock[2] / 2), 0); + // WALBERLA_LOG_DEVEL_VAR(velAtWall) + + if (distanceWall > 0.49 && distanceWall < 0.51) { WALBERLA_CHECK_FLOAT_EQUAL(velAtWall, defaultNoSlipVelocity) } + else if (distanceWall < 0.49) { WALBERLA_CHECK_GREATER(defaultNoSlipVelocity, velAtWall) } + else if (distanceWall > 0.51) { WALBERLA_CHECK_LESS(defaultNoSlipVelocity, velAtWall) } + } + + return EXIT_SUCCESS; +} diff --git a/tests/lbm_generated/InterpolationNoSlip.prm b/tests/lbm_generated/InterpolationNoSlip.prm new file mode 100644 index 000000000..4b15df27e --- /dev/null +++ b/tests/lbm_generated/InterpolationNoSlip.prm @@ -0,0 +1,30 @@ +Parameters +{ + omega 1.1; + timesteps 5000; + distanceWall 0.9; + + remainingTimeLoggerFrequency 0; // in seconds + vtkWriteFrequency 0; +} + +DomainSetup +{ + blocks < 1, 1, 1 >; + cellsPerBlock < 50, 25, 25 >; + periodic < 1, 0, 1 >; +} + +Boundaries +{ + // Border { direction S; walldistance -1; flag NoSlip; } + // Border { direction S; walldistance -1; flag NoSlipBouzidi; } + Border { direction S; walldistance -1; flag NoSlipQuadraticBB; } + Border { direction N; walldistance -1; flag UBB; } +} + + +Logging +{ + logLevel info; // info progress detail tracing +} diff --git a/tests/lbm_generated/InterpolationNoSlip.py b/tests/lbm_generated/InterpolationNoSlip.py new file mode 100644 index 000000000..62463033e --- /dev/null +++ b/tests/lbm_generated/InterpolationNoSlip.py @@ -0,0 +1,53 @@ +import sympy as sp + +from pystencils import Target +from pystencils import fields + +from lbmpy.advanced_streaming.utility import get_timesteps +from lbmpy.boundaries import NoSlip, NoSlipLinearBouzidi, QuadraticBounceBack, UBB +from lbmpy.creationfunctions import create_lb_method, create_lb_collision_rule +from lbmpy import LBMConfig, LBMOptimisation, Stencil, Method, LBStencil +from pystencils_walberla import CodeGeneration, generate_info_header +from lbmpy_walberla import generate_lbm_package, lbm_boundary_generator + +import warnings + +warnings.filterwarnings("ignore") +with CodeGeneration() as ctx: + target = Target.CPU # Target.GPU if ctx.cuda else Target.CPU + data_type = "float64" if ctx.double_accuracy else "float32" + + streaming_pattern = 'pull' + timesteps = get_timesteps(streaming_pattern) + + omega = sp.symbols("omega") + + stencil = LBStencil(Stencil.D3Q27) + pdfs, vel_field = fields(f"pdfs({stencil.Q}), velocity({stencil.D}): {data_type}[{stencil.D}D]", + layout='fzyx') + + macroscopic_fields = {'velocity': vel_field} + + lbm_config = LBMConfig(stencil=stencil, method=Method.SRT, relaxation_rate=omega, + streaming_pattern=streaming_pattern) + lbm_opt = LBMOptimisation(cse_global=False, field_layout='fzyx') + + method = create_lb_method(lbm_config=lbm_config) + collision_rule = create_lb_collision_rule(lbm_config=lbm_config, lbm_optimisation=lbm_opt) + + no_slip = lbm_boundary_generator(class_name='NoSlip', flag_uid='NoSlip', + boundary_object=NoSlip()) + no_slip_bouzidi = lbm_boundary_generator(class_name='NoSlipBouzidi', flag_uid='NoSlipBouzidi', + boundary_object=NoSlipLinearBouzidi(data_type=data_type)) + no_slip_quadraticbb = lbm_boundary_generator(class_name='NoSlipQuadraticBB', flag_uid='NoSlipQuadraticBB', + boundary_object=QuadraticBounceBack(omega, data_type=data_type)) + ubb = lbm_boundary_generator(class_name='UBB', flag_uid='UBB', + boundary_object=UBB([0.01, 0, 0], data_type=data_type)) + + generate_lbm_package(ctx, name="InterpolationNoSlip", + collision_rule=collision_rule, + lbm_config=lbm_config, lbm_optimisation=lbm_opt, + nonuniform=True, boundaries=[no_slip, no_slip_bouzidi, no_slip_quadraticbb, ubb], + macroscopic_fields=macroscopic_fields, data_type=data_type) + + generate_info_header(ctx, 'InterpolationNoSlipHeader') -- GitLab