From 0c6803a1cec2ce4345601e8276852d3afbe3dee9 Mon Sep 17 00:00:00 2001 From: Michael Kuron <mkuron@icp.uni-stuttgart.de> Date: Fri, 4 Feb 2022 23:45:46 +0100 Subject: [PATCH] Fix and test codegen on staggered fields --- python/pystencils_walberla/codegen.py | 3 + tests/field/CMakeLists.txt | 5 + tests/field/codegen/EK.cpp | 148 ++++++++++++++++++++++++++ tests/field/codegen/EK.py | 19 ++++ 4 files changed, 175 insertions(+) create mode 100644 tests/field/codegen/EK.cpp create mode 100644 tests/field/codegen/EK.py diff --git a/python/pystencils_walberla/codegen.py b/python/pystencils_walberla/codegen.py index c0f3c3ed3..7e27e19cc 100644 --- a/python/pystencils_walberla/codegen.py +++ b/python/pystencils_walberla/codegen.py @@ -61,6 +61,9 @@ def generate_sweep(generation_context, class_name, assignments, cpu_vectorize_info: dictionary containing necessary information for the usage of a SIMD instruction set. **create_kernel_params: remaining keyword arguments are passed to `pystencils.create_kernel` """ + if staggered: + assert 'omp_single_loop' not in create_kernel_params + create_kernel_params['omp_single_loop'] = False config = config_from_context(generation_context, target=target, data_type=data_type, cpu_openmp=cpu_openmp, cpu_vectorize_info=cpu_vectorize_info, **create_kernel_params) diff --git a/tests/field/CMakeLists.txt b/tests/field/CMakeLists.txt index aa0ee9bb1..cf1e69f77 100644 --- a/tests/field/CMakeLists.txt +++ b/tests/field/CMakeLists.txt @@ -84,4 +84,9 @@ waLBerla_generate_target_from_python(NAME CodegenGeneratedCPUFieldPackInfo FILE waLBerla_compile_test( FILES codegen/GeneratedFieldPackInfoTest.cpp DEPENDS blockforest core field CodegenGeneratedCPUFieldPackInfo ) waLBerla_execute_test( NAME GeneratedFieldPackInfoTest ) + +waLBerla_generate_target_from_python(NAME CodeGenEK FILE codegen/EK.py + OUT_FILES EKFlux.cpp EKFlux.h EKContinuity.cpp EKContinuity.h ) +waLBerla_compile_test( FILES codegen/EK.cpp DEPENDS blockforest core field timeloop CodeGenEK) +waLBerla_execute_test( NAME EK ) endif() diff --git a/tests/field/codegen/EK.cpp b/tests/field/codegen/EK.cpp new file mode 100644 index 000000000..dbfdcb32d --- /dev/null +++ b/tests/field/codegen/EK.cpp @@ -0,0 +1,148 @@ +//====================================================================================================================== +// +// 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 EK.cpp +//! \author Michael Kuron <mkuron@icp.uni-stuttgart.de> +// +//====================================================================================================================== + +#include "EKContinuity.h" +#include "EKFlux.h" + +#include "blockforest/Initialization.h" +#include "blockforest/communication/UniformBufferedScheme.h" + +#include "core/Environment.h" +#include "core/debug/TestSubsystem.h" +#include "core/math/Constants.h" + +#include "field/AddToStorage.h" +#include "field/communication/PackInfo.h" + +#include "stencil/D2Q9.h" + +#include "timeloop/SweepTimeloop.h" + + +using namespace walberla; + +typedef GhostLayerField<real_t, 1> DensityField_T; +typedef GhostLayerField<real_t, 2> FluxField_T; + +void initC(const shared_ptr< StructuredBlockStorage > & blocks, BlockDataID cID) +{ + for(auto blockIt = blocks->begin(); blockIt != blocks->end(); ++blockIt) + { + auto c = blockIt->getData<DensityField_T>( cID ); + uint_t size = c->ySize() * c->xSize(); + c->get( cell_idx_c(c->ySize()/2), cell_idx_c(c->ySize()/2), 0 ) = real_c(size)/real_c(4); + c->get( cell_idx_c(c->ySize()/2), cell_idx_c(c->ySize()/2)-1, 0 ) = real_c(size)/real_c(4); + c->get( cell_idx_c(c->ySize()/2)-1, cell_idx_c(c->ySize()/2), 0 ) = real_c(size)/real_c(4); + c->get( cell_idx_c(c->ySize()/2)-1, cell_idx_c(c->ySize()/2)-1, 0 ) = real_c(size)/real_c(4); + } +} + +void checkC(const shared_ptr< StructuredBlockStorage > & blocks, BlockDataID cID, real_t D, uint_t t) +{ + real_t sum(0); + uint_t size(0); + for(auto blockIt = blocks->begin(); blockIt != blocks->end(); ++blockIt) + { + auto c = blockIt->getData<DensityField_T>( cID ); + size += c->ySize() * c->xSize(); + } + + std::cout << "#cell pos actual expected deviation" << std::endl; + for(auto blockIt = blocks->begin(); blockIt != blocks->end(); ++blockIt) + { + auto c = blockIt->getData<DensityField_T>( cID ); + + for( cell_idx_t y = 0; y < cell_idx_c( c->ySize() ); ++y ) + { + for( cell_idx_t x = 0; x < cell_idx_c( c->xSize() ); ++x ) + { + const real_t val = c->get(x, y, 0); + sum += val; + + const real_t x0 = real_c(x) - real_c(c->xSize()/2) + real_t(0.5); + const real_t y0 = real_c(y) - real_c(c->ySize()/2) + real_t(0.5); + const real_t r2 = x0*x0 + y0*y0; + + // solution to the diffusion equation in 2D + const real_t ref = real_t(size)/(real_t(4)*math::pi*D*real_c(t)) * std::exp(-r2/real_c(4*D*real_c(t))); + + real_t rel = std::abs(real_c(1) - val/ref); + if(ref >= 1) // we only expect good agreement where the values are larger than sum/size + { + if(x == cell_idx_c(c->ySize()/2)) // print out the values in the middle + { + std::cout << y << " " << y0 << " " << val << " " << ref << " " << (rel*100) << "%" << std::endl; + } + + WALBERLA_CHECK_LESS(rel, 0.03); // 3% deviation is okay + } + } + } + } + WALBERLA_CHECK_FLOAT_EQUAL(sum, real_c(size)); +} + +void testEK() +{ + uint_t xSize = 100; + uint_t ySize = 100; + real_t D = real_c(0.1); + + // Create blocks + shared_ptr< StructuredBlockForest > blocks = blockforest::createUniformBlockGrid ( + uint_t(1) , uint_t(1), uint_t(1), // number of blocks in x,y,z direction + xSize, ySize, uint_t(1), // how many cells per block (x,y,z) + real_t(1), // dx: length of one cell in physical coordinates + false, // one block per process - "false" means all blocks to one process + true, true, true ); // full periodicity + + BlockDataID c = field::addToStorage<DensityField_T>(blocks, "c", real_t(0.0), field::fzyx); + initC(blocks, c); + BlockDataID j = field::addToStorage<FluxField_T>(blocks, "j", real_t(0.0), field::fzyx); + + typedef blockforest::communication::UniformBufferedScheme<stencil::D2Q9> CommScheme; + typedef field::communication::PackInfo<DensityField_T> Packing; + CommScheme commScheme(blocks); + commScheme.addDataToCommunicate( make_shared<Packing>(c) ); + + const uint_t numberOfTimesteps = uint_t(200); + SweepTimeloop timeloop(blocks, numberOfTimesteps); + + // Registering the sweep + timeloop.add() << BeforeFunction( commScheme, "Communication" ) + << Sweep( pystencils::EKFlux(D, c, j), "EK flux Kernel" ); + timeloop.add() << Sweep( pystencils::EKContinuity(c, j), "EK continuity Kernel" ); + + timeloop.run(); + + checkC(blocks, c, D, numberOfTimesteps); +} + + + +int main( int argc, char ** argv ) +{ + mpi::Environment env( argc, argv ); + debug::enterTestMode(); + + testEK(); + + return EXIT_SUCCESS; +} diff --git a/tests/field/codegen/EK.py b/tests/field/codegen/EK.py new file mode 100644 index 000000000..7cf53c035 --- /dev/null +++ b/tests/field/codegen/EK.py @@ -0,0 +1,19 @@ +import sympy as sp +import pystencils as ps +from pystencils_walberla import CodeGeneration, generate_sweep + +def grad(f): + return sp.Matrix([ps.fd.diff(f, i) for i in range(f.spatial_dimensions)]) + +D = sp.Symbol("D") + +with CodeGeneration() as ctx: + data_type = "float64" if ctx.double_accuracy else "float32" + + c = ps.fields(f"c: {data_type}[2D]", layout='fzyx') + j = ps.fields(f"j(2): {data_type}[2D]", layout='fzyx', field_type=ps.FieldType.STAGGERED_FLUX) + + ek = ps.fd.FVM1stOrder(c, flux=-D * grad(c)) + + generate_sweep(ctx, 'EKFlux', ek.discrete_flux(j), staggered=True) + generate_sweep(ctx, 'EKContinuity', ek.discrete_continuity(j)) -- GitLab