diff --git a/lib/walberla/experimental/sweep/Sweeper.hpp b/lib/walberla/experimental/sweep/Sweeper.hpp index bfc7be2941ed3ef19fc5be047af3f23d612552bc..051c53107e5ad3e308647241929afa4316926cad 100644 --- a/lib/walberla/experimental/sweep/Sweeper.hpp +++ b/lib/walberla/experimental/sweep/Sweeper.hpp @@ -40,6 +40,14 @@ class SerialSweeper for (uint_t x = 0; x < blocks_->getNumberOfXCellsPerBlock(); ++x) func({ x, y, z }); } + + void forAllCells(const CellInterval& ci, std::function< void(Cell) > func) + { + for (uint_t z = ci.zMin(); z <= ci.zMax(); ++z) + for (uint_t y = ci.yMin(); y <= ci.yMax(); ++y) + for (uint_t x = ci.xMin(); x <= ci.xMax(); ++x) + func({ x, y, z }); + } }; } // namespace walberla::experimental::sweep diff --git a/src/walberla/codegen/build_config.py b/src/walberla/codegen/build_config.py index e9048cdfb5a3f38344601126fdb64d61c591a313..434512f8d413ce99c0881ac5e67125b8b3b20b7a 100644 --- a/src/walberla/codegen/build_config.py +++ b/src/walberla/codegen/build_config.py @@ -108,6 +108,20 @@ def get_build_config(sfg: SfgContext | SfgIComposer): class DEBUG_MOCK_CMAKE: BUILD_CONFIG: WalberlaBuildConfig | None = None + @staticmethod + def use_cpu_default(): + DEBUG_MOCK_CMAKE.BUILD_CONFIG = WalberlaBuildConfig( + c_compiler_id="GNU", + cxx_compiler_id="GNU", + use_double_precision=True, + optimize_for_localhost=False, + mpi_enabled=False, + openmp_enabled=False, + hip_enabled=False, + cuda_enabled=False, + likwid_enabled=False, + ) + @staticmethod def use_hip_default(): DEBUG_MOCK_CMAKE.BUILD_CONFIG = WalberlaBuildConfig( diff --git a/src/walberla/codegen/sweep.py b/src/walberla/codegen/sweep.py index 195218f5835525099164125583e59a7e7d00be3e..b445039adf734b265268260b1df4428ccf6d2ddb 100644 --- a/src/walberla/codegen/sweep.py +++ b/src/walberla/codegen/sweep.py @@ -1,6 +1,6 @@ from __future__ import annotations -from typing import Sequence, Iterable, cast +from typing import Sequence, Iterable, cast, Callable from dataclasses import dataclass from itertools import chain from collections import defaultdict @@ -167,12 +167,12 @@ class BlockforestParameters: self, property_cache: SweepClassProperties, block: IBlockPtr, - cell_interval: CellInterval | None = None, ): self._property_cache = property_cache self._block = block - self._ci = cell_interval - self._extractions: dict[SfgVar, AugExpr] = dict() + self._extractions: dict[ + SfgVar, AugExpr | Callable[[CellInterval | None], AugExpr] + ] = dict() self._blockforest: StructuredBlockForest | None = None @@ -214,8 +214,18 @@ class BlockforestParameters: params_filtered = set() - mappings: dict[str, AugExpr] = dict() + mappings: dict[str, AugExpr | Callable[[CellInterval | None], AugExpr]] = dict() for coord in range(3): + + # Need to capture coord explicitly + # See https://stackoverflow.com/questions/2295290/what-do-lambda-function-closures-capture + + def ci_min(ci: CellInterval | None, c=coord) -> AugExpr: + return AugExpr.format("0") if ci is None else ci.min()[c] + + def ci_max(ci: CellInterval | None, c=coord) -> AugExpr: + return AugExpr.format("0") if ci is None else ci.max()[c] + mappings.update( { domain.aabb_min[coord].name: ( @@ -240,16 +250,8 @@ class BlockforestParameters: ), block.aabb_min[coord].name: (self._block.getAABB().min()[coord]), block.aabb_max[coord].name: (self._block.getAABB().max()[coord]), - block.ci_min[coord].name: ( - AugExpr.format("0") - if self._ci is None - else self._ci.min()[coord] - ), - block.ci_max[coord].name: ( - AugExpr.format("0") - if self._ci is None - else self._ci.max()[coord] - ), + block.ci_min[coord].name: ci_min, + block.ci_max[coord].name: ci_max, block_cell_bb.cell_bb_min[coord].name: ( self.blockforest() .getBlockCellBB(self._block.deref()) @@ -276,8 +278,11 @@ class BlockforestParameters: return params_filtered - def render_extractions(self, sfg: SfgComposer): - return (sfg.init(p)(expr) for p, expr in self._extractions.items()) + def render_extractions(self, sfg: SfgComposer, ci: CellInterval | None): + return ( + sfg.init(p)(expr if isinstance(expr, AugExpr) else expr(ci)) + for p, expr in self._extractions.items() + ) @dataclass @@ -650,7 +655,7 @@ class Sweep(CustomGenerator): parameters = khandle.scalar_parameters | ker_call_site_params - blockforest_params = BlockforestParameters(props, block, None) + blockforest_params = BlockforestParameters(props, block) parameters = blockforest_params.filter_params(parameters) vector_groups = combine_vectors(parameters) @@ -692,7 +697,7 @@ class Sweep(CustomGenerator): for vector, components in vector_groups.items() ), # Extract geometry information - *(blockforest_params.render_extractions(sfg)), + *(blockforest_params.render_extractions(sfg, ci)), # Invoke the kernel ker_invocation, # Perform field swaps diff --git a/tests/CodegenFeatures/CMakeLists.txt b/tests/CodegenFeatures/CMakeLists.txt index 6a4f622036ebd9595ba589565a8e1948197ec88f..a559c85b0627e587702914df41406b86528be1b0 100644 --- a/tests/CodegenFeatures/CMakeLists.txt +++ b/tests/CodegenFeatures/CMakeLists.txt @@ -3,4 +3,6 @@ add_executable( TestBlockforestGeometry TestBlockforestGeometry.cpp ) walberla_generate_sources( TestBlockforestGeometry SCRIPTS GeometryKernels.py ) target_link_libraries( TestBlockforestGeometry PRIVATE walberla::core walberla::blockforest walberla::field walberla::experimental ) +add_dependencies( SfgTests TestBlockforestGeometry ) + add_test( NAME TestBlockforestGeometry COMMAND TestBlockforestGeometry ) diff --git a/tests/CodegenFeatures/GeometryKernels.py b/tests/CodegenFeatures/GeometryKernels.py index 98078d81547d952f85df2d91f4cc4b8115a0fe9f..3bd67068fc0039c3b4e465cdb7d2aea60601c271 100644 --- a/tests/CodegenFeatures/GeometryKernels.py +++ b/tests/CodegenFeatures/GeometryKernels.py @@ -1,8 +1,10 @@ import pystencils as ps from pystencilssfg import SourceFileGenerator from walberla.codegen import Sweep, get_build_config +from walberla.codegen.build_config import DEBUG_MOCK_CMAKE from walberla.codegen.symbolic import cell, cell_index +DEBUG_MOCK_CMAKE.use_cpu_default() with SourceFileGenerator() as sfg: get_build_config(sfg).override.target = ps.Target.GenericCPU @@ -53,4 +55,3 @@ with SourceFileGenerator() as sfg: sweep = Sweep("CellIndicesGlobal", asms) sfg.generate(sweep) - diff --git a/tests/CodegenFeatures/TestBlockforestGeometry.cpp b/tests/CodegenFeatures/TestBlockforestGeometry.cpp index 610c588ce09dd196cd46e1888eb67c38e37bc75e..410648b094301cb4fd97ee2c99163f42fbf25347 100644 --- a/tests/CodegenFeatures/TestBlockforestGeometry.cpp +++ b/tests/CodegenFeatures/TestBlockforestGeometry.cpp @@ -88,5 +88,73 @@ int main(int argc, char** argv) }); } + /* The same with cell intervals */ + + CellInterval ci { Cell {1, 2, 1}, Cell (3, 3, 2) }; + + { + CellCentersGlobal cellCenters{ blocks, realFieldId }; + sweeper.sweep([&](IBlock * b){ cellCenters.runOnCellInterval(b, ci); }); + + sweeper.sweep([&](IBlock& block) { + RealField& outp = *block.getData< RealField >(realFieldId); + sweeper.forAllCells(ci, [&](Cell c) { + Vector3< real_t > desired = blocks->getBlockLocalCellCenter(block, c); + + WALBERLA_CHECK_FLOAT_EQUAL(outp.get(c, 0), desired[0]); + WALBERLA_CHECK_FLOAT_EQUAL(outp.get(c, 1), desired[1]); + WALBERLA_CHECK_FLOAT_EQUAL(outp.get(c, 2), desired[2]); + }); + }); + } + + { + CellCentersLocal cellCenters{ blocks, realFieldId }; + sweeper.sweep([&](IBlock * b){ cellCenters.runOnCellInterval(b, ci); }); + + sweeper.sweep([&](IBlock& block) { + RealField& outp = *block.getData< RealField >(realFieldId); + AABB blockAbb = block.getAABB(); + sweeper.forAllCells(ci, [&](Cell c) { + Vector3< real_t > desired = blocks->getBlockLocalCellCenter(block, c) - blockAbb.min(); + + WALBERLA_CHECK_FLOAT_EQUAL(outp.get(c, 0), desired[0]); + WALBERLA_CHECK_FLOAT_EQUAL(outp.get(c, 1), desired[1]); + WALBERLA_CHECK_FLOAT_EQUAL(outp.get(c, 2), desired[2]); + }); + }); + } + + { + CellIndicesLocal localIndices{ blocks, intFieldId }; + sweeper.sweep([&](IBlock * b){ localIndices.runOnCellInterval(b, ci); }); + + sweeper.sweep([&](IBlock& block) { + Int64Field& outp = *block.getData< Int64Field >(intFieldId); + sweeper.forAllCells(ci, [&](Cell c) { + WALBERLA_CHECK_EQUAL(outp.get(c, 0), c[0]); + WALBERLA_CHECK_EQUAL(outp.get(c, 1), c[1]); + WALBERLA_CHECK_EQUAL(outp.get(c, 2), c[2]); + }); + }); + } + + { + CellIndicesGlobal glocalIndices{ blocks, intFieldId }; + sweeper.sweep([&](IBlock * b){ glocalIndices.runOnCellInterval(b, ci); }); + + sweeper.sweep([&](IBlock& block) { + Int64Field& outp = *block.getData< Int64Field >(intFieldId); + sweeper.forAllCells(ci, [&](Cell c) { + Cell globalCell{ c }; + blocks->transformBlockLocalToGlobalCell(globalCell, block); + + WALBERLA_CHECK_EQUAL(outp.get(c, 0), globalCell[0]); + WALBERLA_CHECK_EQUAL(outp.get(c, 1), globalCell[1]); + WALBERLA_CHECK_EQUAL(outp.get(c, 2), globalCell[2]); + }); + }); + } + return EXIT_SUCCESS; } \ No newline at end of file