diff --git a/examples/ForceDrivenChannel/LbmAlgorithms.py b/examples/ForceDrivenChannel/LbmAlgorithms.py index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..c27d3ee7d8e490de863ba5fff77d581b6b8f33e2 100644 --- a/examples/ForceDrivenChannel/LbmAlgorithms.py +++ b/examples/ForceDrivenChannel/LbmAlgorithms.py @@ -0,0 +1,61 @@ +import sympy as sp + +from pystencilssfg import SourceFileGenerator +from sfg_walberla import Sweep +from pystencils import Target, fields +import pystencils.config as cfg +from lbmpy import ( + LBStencil, + Stencil, + Method, + LBMConfig, + LBMOptimisation, + create_lb_method, + create_lb_update_rule, +) + +from lbmpy.macroscopic_value_kernels import macroscopic_values_setter + +stencil = LBStencil(Stencil.D3Q19) +dim = stencil.D +f, f_tmp, rho, u = fields( + f"f({stencil.Q}), f_tmp({stencil.Q}), rho(1), u({dim}): [{dim}D]", layout="fzyx" +) +omega = sp.Symbol("omega") +force = sp.symbols(f"F_:{dim}") + +lbm_config = LBMConfig( + stencil=stencil, + method=Method.CENTRAL_MOMENT, + relaxation_rate=omega, + force=force, + compressible=True, + zero_centered=False, + output={"density": rho, "velocity": u}, +) + +lb_method = create_lb_method(lbm_config) + +with SourceFileGenerator() as sfg: + sfg.namespace("ForceDrivenChannel::gen") + + sfg.include(f"stencil/{stencil.name}.h") + sfg.code(f"using LbStencil = walberla::stencil::{stencil.name};") + + lbm_opt = LBMOptimisation(symbolic_field=f, symbolic_temporary_field=f_tmp) + + gen_config = cfg.CreateKernelConfig( + target=Target.CPU, cpu_optim=cfg.CpuOptimConfig(openmp=True) + ) + + lb_update = create_lb_update_rule(lbm_config=lbm_config, lbm_optimisation=lbm_opt) + lb_update_sweep = Sweep("LbStreamCollide", lb_update, gen_config) + lb_update_sweep.swap_fields(f, f_tmp) + sfg.generate(lb_update_sweep) + + lb_init = macroscopic_values_setter( + lb_update.method, density=rho, velocity=u, pdfs=f, set_pre_collision_pdfs=True + ) + lb_init_sweep = Sweep("LbInit", lb_init, gen_config) + sfg.generate(lb_init_sweep) + diff --git a/examples/SimpleK b/examples/SimpleK deleted file mode 100644 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000 diff --git a/src/sfg_walberla/api.py b/src/sfg_walberla/api.py index ad2819acb6f725ea2a240f221671bc4deb7d69ef..2818b43f0ebe7bec7ef17859bc6857e7c40d8430 100644 --- a/src/sfg_walberla/api.py +++ b/src/sfg_walberla/api.py @@ -1,5 +1,7 @@ from __future__ import annotations +from typing import Callable + from pystencils import Field from pystencils.types import ( UserTypeSpec, @@ -15,8 +17,9 @@ from pystencilssfg.lang import ( SrcVector, Ref, ExprLike, + cpptype, ) -from pystencilssfg.ir import SfgHeaderInclude +from pystencilssfg.lang.types import CppType real_t = PsCustomType("walberla::real_t") @@ -24,39 +27,53 @@ cell_idx_t = PsCustomType("walberla::cell_idx_t") uint_t = PsCustomType("walberla::uint_t") +class _CppClass(AugExpr): + _type: Callable[..., CppType] + + def __init__(self, const: bool = False, ref: bool = False): + dtype = self._type(const=const, ref=ref) + super().__init__(dtype) + + class Vector2(SrcVector): - def __init__(self, val_type: UserTypeSpec): - self._value_type = create_type(val_type) - val_type_str = self._value_type.c_string() - super().__init__(PsCustomType(f"walberla::Vector2< {val_type_str} >")) + _template = cpptype("walberla::Vector2< {element_type} >", "core/math/Vector2.h") + + def __init__( + self, element_type: UserTypeSpec, const: bool = False, ref: bool = False + ): + self._element_type = create_type(element_type) + dtype = self._template(element_type=element_type, const=const, ref=ref) + super().__init__(dtype) def extract_component(self, coordinate: int) -> AugExpr: if coordinate > 1: raise ValueError(f"Cannot extract component {coordinate} from Vector2") - return AugExpr(self._value_type).bind("{}[{}]", self, coordinate) + return AugExpr(self._element_type).bind("{}[{}]", self, coordinate) class Vector3(SrcVector): - def __init__(self, val_type: UserTypeSpec): - self._value_type = create_type(val_type) - val_type_str = self._value_type.c_string() - super().__init__(PsCustomType(f"walberla::Vector3< {val_type_str} >")) + _template = cpptype("walberla::Vector3< {element_type} >", "core/math/Vector3.h") + + def __init__( + self, element_type: UserTypeSpec, const: bool = False, ref: bool = False + ): + self._element_type = create_type(element_type) + dtype = self._template(element_type=element_type, const=const, ref=ref) + super().__init__(dtype) def extract_component(self, coordinate: int) -> AugExpr: if coordinate > 2: raise ValueError(f"Cannot extract component {coordinate} from Vector3") - return AugExpr(self._value_type).bind("{}[{}]", self, coordinate) + return AugExpr(self._element_type).bind("{}[{}]", self, coordinate) def __getitem__(self, idx: int | ExprLike): - return AugExpr(self._value_type).bind("{}[{}]", self, idx) + return AugExpr(self._element_type).bind("{}[{}]", self, idx) -class AABB(AugExpr): - def __init__(self): - dtype = PsCustomType("walberla::AABB") - super().__init__(dtype) +class AABB(_CppClass): + _type = cpptype("walberla::AABB", "core/math/AABB.h") def min(self) -> Vector3: return Vector3(real_t).bind("{}.min()", self) @@ -65,26 +82,16 @@ class AABB(AugExpr): return Vector3(real_t).bind("{}.max()", self) -class CellInterval(AugExpr): - def __init__(self, const: bool = False, ref: bool = False): - dtype = PsCustomType("walberla::CellInterval", const=const) - if ref: - dtype = Ref(dtype) - super().__init__(dtype) +class CellInterval(_CppClass): + _type = cpptype("walberla::CellInterval", "core/cell/CellInterval.h") -class BlockDataID(AugExpr): - def __init__(self): - super().__init__(PsCustomType("walberla::BlockDataID")) +class BlockDataID(_CppClass): + _type = cpptype("walberla::BlockDataID", "domain_decomposition/BlockDataID.h") - @property - def required_includes(self) -> set[SfgHeaderInclude]: - return {SfgHeaderInclude.parse("domain_decomposition/BlockDataID.h")} - -class IBlockPtr(AugExpr): - def __init__(self): - super().__init__(PsCustomType("walberla::IBlock *")) +class IBlockPtr(_CppClass): + _type = cpptype("walberla::IBlock *", "domain_decomposition/IBlock.h") def getData(self, dtype: str | PsType, id: BlockDataID) -> AugExpr: return AugExpr.format("{}->template getData< {} >({})", self, dtype, id) @@ -92,10 +99,6 @@ class IBlockPtr(AugExpr): def getAABB(self) -> AABB: return AABB().bind("{}->getAABB()", self) - @property - def required_includes(self) -> set[SfgHeaderInclude]: - return {SfgHeaderInclude.parse("domain_decomposition/IBlock.h")} - def deref(self) -> AugExpr: return AugExpr.format("*{}", self) @@ -208,6 +211,11 @@ class GenericWalberlaField(SrcField): class GhostLayerFieldPtr(GenericWalberlaField): + _template = cpptype( + "walberla::field::GhostLayerField< {element_type}, {fsize} >", + "field/GhostLayerField.h", + ) + @staticmethod def create(field: Field): if field.index_dimensions > 1: @@ -226,19 +234,17 @@ class GhostLayerFieldPtr(GenericWalberlaField): fsize: int, ): element_type = create_type(element_type) - elmt_type_str = element_type.c_string() - field_type = PsCustomType( - f"walberla::field::GhostLayerField< {elmt_type_str}, {fsize} >" - ) + field_type = self._template(element_type=element_type, fsize=fsize) super().__init__(element_type, field_type, ptr=True) - @property - def required_includes(self) -> set[SfgHeaderInclude]: - return {SfgHeaderInclude("field/GhostLayerField.h")} - class GpuFieldPtr(GenericWalberlaField): + _template = cpptype( + "walberla::gpu::GpuField< {element_type} >", + "gpu/GpuField.h", + ) + @staticmethod def create(field: Field): if field.index_dimensions > 1: @@ -257,15 +263,10 @@ class GpuFieldPtr(GenericWalberlaField): fsize: int, ): element_type = create_type(element_type) - elmt_type_str = element_type.c_string() - field_type = PsCustomType(f"walberla::gpu::GpuField< {elmt_type_str} >") + field_type = self._template(element_type=element_type) super().__init__(element_type, field_type, ptr=True) - @property - def required_includes(self) -> set[SfgHeaderInclude]: - return {SfgHeaderInclude("gpu/GpuField.h")} - class GhostLayerFieldExtraction(IFieldExtraction): def __init__(