Skip to content
Snippets Groups Projects
Commit 62c94737 authored by Martin Bauer's avatar Martin Bauer
Browse files

New CMake integration for lbmpy code generation

- one python file can now generate multiple source files
parent ebf029b5
No related branches found
No related tags found
No related merge requests found
Showing
with 111 additions and 94 deletions
......@@ -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)
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment