Commit 62c94737 authored by Martin Bauer's avatar Martin Bauer

New CMake integration for lbmpy code generation

- one python file can now generate multiple source files
parent ebf029b5
Pipeline #6202 passed with stages
in 58 minutes and 5 seconds
......@@ -211,6 +211,7 @@ function ( waLBerla_add_executable )
set( generatedSourceFiles )
set( generatorSourceFiles )
handle_python_codegen(sourceFiles generatedSourceFiles generatorSourceFiles codeGenRequired ${sourceFiles})
if( NOT WALBERLA_BUILD_WITH_CODEGEN AND codeGenRequired)
message(STATUS "Skipping ${ARG_NAME} since pystencils code generation is not enabled")
return()
......
......@@ -19,14 +19,17 @@ endfunction ( add_flag )
#######################################################################################################################
#
# Function to handle source files of type .gen.py and .gen.cuda.py
# Function to handle python code generation files
#
# files .gen.py generate a .h and a .cpp file
# files .gen.cuda.py generate a .h and a .cu file
# Takes a list of source files that contain .py files, and returns a list of source files
# where the generated version are added and the .py files are removed.
# Additionally creates a custom build rule for the code generation
# parameters:
# sourceFilesOut: variable where source files without python files are written to
# generatedSourceFilesOut: variable where generated source files (with custom command) are written to
# generatorsOut: only the python files that have been passed
# codeGenRequired: true if at least one python file was part of the sources
#
# The list of generated files is determined via the pystencils_walberla package mechanism.
# The python script, when called with -l, should return a semicolon-separated list of generated files
# if this list changes, CMake has to be run manually again.
#######################################################################################################################
function( handle_python_codegen sourceFilesOut generatedSourceFilesOut generatorsOut codeGenRequiredOut )
set(result )
......@@ -34,25 +37,27 @@ function( handle_python_codegen sourceFilesOut generatedSourceFilesOut generator
set(generatorsResult )
set(codeGenRequired NO)
foreach( sourceFile ${ARGN} )
if( ${sourceFile} MATCHES ".*\\.gen\\.py$" )
get_filename_component(sourceFileName ${sourceFile} NAME)
if( ${sourceFileName} MATCHES ".*\\.cuda\\.gen\\.py$" )
string(REPLACE ".cuda.gen.py" ".h" genHeaderFile ${sourceFileName})
string(REPLACE ".cuda.gen.py" ".cu" genSourceFile ${sourceFileName})
else()
string(REPLACE ".gen.py" ".h" genHeaderFile ${sourceFileName})
string(REPLACE ".gen.py" ".cpp" genSourceFile ${sourceFileName})
endif()
list(APPEND generatedResult ${CMAKE_CURRENT_BINARY_DIR}/${genSourceFile}
${CMAKE_CURRENT_BINARY_DIR}/${genHeaderFile})
add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${genSourceFile}
${CMAKE_CURRENT_BINARY_DIR}/${genHeaderFile}
DEPENDS ${sourceFile}
COMMAND ${PYTHON_EXECUTABLE} ${sourceFile}
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
include_directories(${CMAKE_CURRENT_BINARY_DIR})
list(APPEND generatorsResult ${sourceFile} )
if( ${sourceFile} MATCHES ".*\\.py$" )
set(codeGenRequired YES)
if( WALBERLA_BUILD_WITH_CODEGEN)
execute_process(COMMAND ${PYTHON_EXECUTABLE} ${sourceFile} -l
OUTPUT_VARIABLE generatedSourceFiles)
string(REGEX REPLACE "\n$" "" generatedSourceFiles "${generatedSourceFiles}")
set(generatedWithAbsolutePath )
foreach( filename ${generatedSourceFiles} )
list(APPEND generatedWithAbsolutePath ${CMAKE_CURRENT_BINARY_DIR}/${filename})
endforeach()
list(APPEND generatedResult ${generatedWithAbsolutePath} )
list(APPEND generatorsResult ${sourceFile} )
add_custom_command(OUTPUT ${generatedWithAbsolutePath}
DEPENDS ${sourceFile}
COMMAND ${PYTHON_EXECUTABLE} ${sourceFile} -g
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
include_directories(${CMAKE_CURRENT_BINARY_DIR})
endif()
else()
list(APPEND result ${sourceFile})
endif()
......
......@@ -8,6 +8,8 @@ from waLBerla.tools.jobscripts.hornet import createJobscript as _cr_hor
from waLBerla.tools.jobscripts.supermuc import createJobscript as _cr_supermuc
from waLBerla.tools.jobscripts.supermuc_phase2 import createJobscript as _cr_supermuc2
from waLBerla.tools.jobscripts.juqueen import createJobscript as _cr_juqueen
from waLBerla.tools.jobscripts.pizdaint_hybrid import createJobscript as _cr_pizdainth
def createJobscript(*args, **kwargs):
"""
......@@ -43,6 +45,6 @@ def createJobscript(*args, **kwargs):
if kwargs['machine'].lower() == 'supermuc_phase2': return _cr_supermuc2 ( *args, **kwargs )
if kwargs['machine'].lower() == 'juqueen' : return _cr_juqueen ( *args, **kwargs )
if kwargs['machine'].lower() == 'hornet' : return _cr_hornet ( *args, **kwargs )
raise ValueError( "Unknown Machine: supported machines <supermuc,supermuc_phase2,juqueen,hornet>" )
if kwargs['machine'].lower() == 'pizdaint_hybrid': return _cr_pizdainth ( *args, **kwargs )
raise ValueError( "Unknown Machine: supported machines <supermuc,supermuc_phase2,juqueen,hornet,pizdaint_hybrid>" )
\ No newline at end of file
......@@ -17,8 +17,7 @@ waLBerla_compile_test( FILES FieldIndexing3DTest.cpp FieldIndexing3DTest.cu )
waLBerla_execute_test( NAME FieldIndexing3DTest )
waLBerla_compile_test( FILES codegen/CodegenJacobiGPU.cpp
codegen/JacobiKernel2D.cuda.gen.py
codegen/JacobiKernel3D.cuda.gen.py
codegen/CudaJacobiKernel.py
DEPENDS blockforest timeloop gui )
waLBerla_execute_test( NAME CodegenJacobiGPU )
......
......@@ -18,8 +18,8 @@
//
//======================================================================================================================
#include "JacobiKernel2D.h"
#include "JacobiKernel3D.h"
#include "CudaJacobiKernel2D.h"
#include "CudaJacobiKernel3D.h"
#include "cuda/HostFieldAllocator.h"
#include "blockforest/Initialization.h"
......@@ -110,7 +110,7 @@ void testJacobi2D()
// Registering the sweep
timeloop.add() << BeforeFunction( commScheme, "Communication" )
<< Sweep( pystencils::JacobiKernel2D(gpuField, 1.0), "Jacobi Kernel" );
<< Sweep( pystencils::CudaJacobiKernel2D(gpuField, 1.0), "Jacobi Kernel" );
cuda::fieldCpy<GPUField, ScalarField>( blocks, gpuField, cpuFieldID );
......@@ -165,7 +165,7 @@ void testJacobi3D()
// Registering the sweep
timeloop.add() << BeforeFunction( commScheme, "Communication" )
<< Sweep( pystencils::JacobiKernel3D(gpuField, 1.0), "Jacobi Kernel" );
<< Sweep( pystencils::CudaJacobiKernel3D(gpuField, 1.0), "Jacobi Kernel" );
cuda::fieldCpy<GPUField, ScalarField>( blocks, gpuField, cpuFieldID );
......
from pystencils_walberla.sweep import Sweep
from pystencils_walberla.cmake_integration import codegen
def jacobi2D(sweep):
src = sweep.field("f1")
dst = sweep.temporaryField(src)
dst[0, 0] @= (src[1, 0] + src[-1, 0] + src[0, 1] + src[0, -1]) / (4 * S.h ** 2)
def jacobi3D(sweep):
src = sweep.field("f1")
dst = sweep.temporaryField(src)
dst[0,0,0] @= (src[1,0,0] + src[-1,0,0] + src[0,1,0] + src[0, -1, 0] + src[0, 0, 1] + src[0, 0 , -1] ) / (6 * S.h**2)
Sweep.generate('CudaJacobiKernel2D', jacobi2D, dim=2, target='gpu')
Sweep.generate('CudaJacobiKernel3D', jacobi3D, dim=3, target='gpu')
\ No newline at end of file
from pystencils_walberla import Sweep
k = Sweep(dim=2)
src = k.field("f1")
dst = k.temporaryField(src)
h = k.constant("h")
rhs = (src[1,0] + src[-1,0] + src[0,1] + src[0, -1] ) / (4 * h**2)
k.addEq(dst[0,0], rhs)
k.generate()
from pystencils_walberla import Sweep
k = Sweep(dim=3)
src = k.field("f1")
dst = k.temporaryField(src)
h = k.constant("h")
rhs = (src[1,0,0] + src[-1,0,0] + src[0,1,0] + src[0, -1, 0] + src[0, 0, 1] + src[0, 0 , -1] ) / (6 * h**2)
k.addEq(dst[0,0,0], rhs)
k.generate()
......@@ -59,7 +59,7 @@ endif( WALBERLA_BUILD_WITH_MPI )
# CodeGen Tests
waLBerla_compile_test( FILES codegen/CodegenJacobiCPU.cpp codegen/JacobiKernel2D.gen.py codegen/JacobiKernel3D.gen.py
waLBerla_compile_test( FILES codegen/CodegenJacobiCPU.cpp codegen/JacobiKernel.py
DEPENDS gui timeloop )
waLBerla_execute_test( NAME CodegenJacobiCPU )
......
from pystencils_walberla.sweep import Sweep
def jacobi2D(sweep):
src = sweep.field("f1")
dst = sweep.temporaryField(src)
dst[0, 0] @= (src[1, 0] + src[-1, 0] + src[0, 1] + src[0, -1]) / (4 * S.h ** 2)
def jacobi3D(sweep):
src = sweep.field("f1")
dst = sweep.temporaryField(src)
dst[0,0,0] @= (src[1,0,0] + src[-1,0,0] + src[0,1,0] + src[0, -1, 0] + src[0, 0, 1] + src[0, 0 , -1] ) / (6 * S.h**2)
Sweep.generate('JacobiKernel2D', jacobi2D, dim=2)
Sweep.generate('JacobiKernel3D', jacobi3D, dim=3)
\ No newline at end of file
from pystencils_walberla import Sweep
k = Sweep(dim=2)
src = k.field("f1")
dst = k.temporaryField(src)
h = k.constant("h")
rhs = (src[1,0] + src[-1,0] + src[0,1] + src[0, -1] ) / (4 * h**2)
k.addEq(dst[0,0], rhs)
k.generate()
from pystencils_walberla import Sweep
k = Sweep(dim=3)
src = k.field("f1")
dst = k.temporaryField(src)
h = k.constant("h")
rhs = (src[1,0,0] + src[-1,0,0] + src[0,1,0] + src[0, -1, 0] + src[0, 0, 1] + src[0, 0 , -1] ) / (6 * h**2)
k.addEq(dst[0,0,0], rhs)
k.generate()
......@@ -26,9 +26,16 @@
#include "field/all.h"
#include "geometry/all.h"
#include "gui/all.h"
#include "lbm/all.h"
#include "timeloop/all.h"
#include "lbm/field/PdfField.h"
#include "lbm/field/AddToStorage.h"
#include "lbm/communication/PdfFieldPackInfo.h"
#include "lbm/gui/Connection.h"
#include "lbm/vtk/VTKOutput.h"
#include "MyUBB.h"
#include "MyNoSlip.h"
using namespace walberla;
......@@ -60,8 +67,6 @@ int main( int argc, char ** argv )
const double remainingTimeLoggerFrequency = parameters.getParameter< double >( "remainingTimeLoggerFrequency", 3.0 ); // in seconds
// create force field
// create fields
BlockDataID forceFieldId = field::addToStorage<ForceField_T>(blocks, "Force", real_t(0.0) );
......@@ -72,18 +77,17 @@ int main( int argc, char ** argv )
// create and initialize boundary handling
const FlagUID fluidFlagUID( "Fluid" );
auto boundariesConfig = walberlaEnv.config()->getOneBlock( "Boundaries" );
typedef lbm::DefaultBoundaryHandlingFactory< LatticeModel_T, FlagField_T > BHFactory;
lbm::MyUBB ubb(blocks, pdfFieldId);
lbm::MyNoSlip noSlip(blocks, pdfFieldId);
BlockDataID boundaryHandlingId = BHFactory::addBoundaryHandlingToStorage( blocks, "boundary handling", flagFieldId, pdfFieldId, fluidFlagUID,
boundariesConfig.getParameter< Vector3<real_t> >( "velocity0", Vector3<real_t>() ),
boundariesConfig.getParameter< Vector3<real_t> >( "velocity1", Vector3<real_t>() ),
boundariesConfig.getParameter< real_t > ( "pressure0", real_c( 1.0 ) ),
boundariesConfig.getParameter< real_t > ( "pressure1", real_c( 1.0 ) ) );
geometry::initBoundaryHandling<FlagField_T>(*blocks, flagFieldId, boundariesConfig);
geometry::setNonBoundaryCellsToDomain<FlagField_T>(*blocks, flagFieldId, fluidFlagUID);
geometry::initBoundaryHandling<BHFactory::BoundaryHandling>( *blocks, boundaryHandlingId, boundariesConfig );
geometry::setNonBoundaryCellsToDomain<BHFactory::BoundaryHandling> ( *blocks, boundaryHandlingId );
ubb.fillFromFlagField<FlagField_T>( blocks, flagFieldId, FlagUID("UBB"), fluidFlagUID );
noSlip.fillFromFlagField<FlagField_T>( blocks, flagFieldId, FlagUID("NoSlip"), fluidFlagUID );
// create time loop
SweepTimeloop timeloop( blocks->getBlockStorage(), timesteps );
......@@ -94,7 +98,8 @@ int main( int argc, char ** argv )
// add LBM sweep and communication to time loop
timeloop.add() << BeforeFunction( communication, "communication" )
<< Sweep( BHFactory::BoundaryHandling::getBlockSweep( boundaryHandlingId ), "boundary handling" );
<< Sweep( noSlip, "noSlip boundary" );
timeloop.add() << Sweep( ubb, "ubb boundary" );
timeloop.add() << Sweep( LatticeModel_T::Sweep( pdfFieldId ), "LB stream & collide" );
// LBM stability check
......
import sympy as sp
from lbmpy.boundaries import NoSlip, UBB
from lbmpy_walberla import Field, generateLatticeModelFiles, RefinementScaling
from lbmpy.creationfunctions import createLatticeBoltzmannMethod
from lbmpy_walberla.boundary import createBoundaryClass
from pystencils_walberla.cmake_integration import codegen
# ------------- Lattice Model ------------------------------
forceField = Field.createGeneric('force', spatialDimensions=3, indexDimensions=1, layout='fzyx')
force = [forceField(0), forceField(1), forceField(2)]
......@@ -10,6 +15,21 @@ scaling = RefinementScaling()
scaling.addStandardRelaxationRateScaling(omega)
scaling.addForceScaling(forceField)
generateLatticeModelFiles(method='srt', stencil='D3Q19', forceModel='guo', force=force,
generateLatticeModelFiles(className='SrtWithForceFieldModel',
method='srt', stencil='D3Q19', forceModel='guo', force=force,
relaxationRates=[omega], refinementScaling=scaling)
def genBoundary():
boundary = UBB([0.05, 0, 0], dim=3, name="MyUBB")
method = createLatticeBoltzmannMethod(stencil='D3Q19', method='srt')
return createBoundaryClass(boundary, method)
def genNoSlip():
boundary = NoSlip(name='MyNoSlip')
method = createLatticeBoltzmannMethod(stencil='D3Q19', method='srt')
return createBoundaryClass(boundary, method)
codegen.register(['MyUBB.h', 'MyUBB.cpp'], genBoundary)
codegen.register(['MyNoSlip.h', 'MyNoSlip.cpp',], genNoSlip)
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment