This example implements the Couette and Poiseuille laminar flow scenarios between two infinite parallel plates.
The numerical kernels for both scenarios are generated by ParallelPlatesSweeps.py.
from dataclasses import replace
from lbmpy import (
LBStencil,
Stencil,
LBMConfig,
Method,
ForceModel,
)
from lbmpy.boundaries import NoSlip, UBB
from lbmpy import relaxation_rate_from_lattice_viscosity
import sympy as sp
import pystencils as ps
import sweepgen as sg
from pystencilssfg import SourceFileGenerator
from sweepgen import Sweep
from sweepgen.boundaries import SparseBoundary
from sweepgen.symbolic import cell, domain
from sweepgen.prefabs import LbmBulk
from sweepgen.build_config import DEBUG
DEBUG.use_cuda_default()
with SourceFileGenerator(keep_unknown_argv=True) as sfg:
sfg.namespace("ParallelPlates::gen")
Sweep.use_v8core_fields()
stencil = LBStencil(Stencil.D3Q19)
nu, u_max, rho = sp.symbols("nu, u_max, rho")
base_lbm_config = LBMConfig(
stencil=stencil,
method=Method.TRT,
compressible=True,
relaxation_rate=relaxation_rate_from_lattice_viscosity(nu),
)
with sfg.namespace("Poiseuille"):
R = domain.z_max() / 2
a_x = 2 * u_max * nu / R**2
lbm_config = replace(
base_lbm_config,
force_model=ForceModel.GUO,
force=(a_x * rho, 0, 0),
)
lbm_bulk = LbmBulk(sfg, "LBM", lbm_config)
sfg.generate(lbm_bulk)
rho, u = lbm_bulk.rho, lbm_bulk.u
@sg.flow.generate_sweep(sfg)
def SetAnalyticalSolution(_eq):
r = sp.Symbol("r")
_eq.let[r] = sp.Abs(cell.z() - R)
_eq.store[rho()] = 1
_eq.store[u(0)] = a_x / (2 * nu) * (R**2 - r**2)
_eq.store[u(1)] = 0
_eq.store[u(2)] = 0
@sg.flow.generate_sweep(sfg)
def VelocityErrorLmax(_eq):
r, ux = sp.symbols("r, ux")
error_ux = ps.TypedSymbol("error_ux", ps.DynamicType.NUMERIC_TYPE)
_eq.let[r] = sp.Abs(cell.z() - R)
_eq.let[ux] = a_x / (2 * nu) * (R**2 - r**2)
_eq.reduce[error_ux, "max"] = sp.Abs(u(0) - ux)
with sfg.namespace("Couette"):
lbm_bulk = LbmBulk(sfg, "LBM", base_lbm_config)
sfg.generate(lbm_bulk)
rho, u = lbm_bulk.rho, lbm_bulk.u
@sg.flow.generate_sweep(sfg)
def SetAnalyticalSolution(_eq):
_eq.store[rho()] = 1
_eq.store[u(0)] = u_max * cell.z() / domain.z_max()
_eq.store[u(1)] = 0
_eq.store[u(2)] = 0
@sg.flow.generate_sweep(sfg)
def VelocityErrorLmax(_eq):
ux = sp.Symbol("ux")
error_ux = ps.TypedSymbol("error_ux", ps.DynamicType.NUMERIC_TYPE)
_eq.let[ux] = u_max * cell.z() / domain.z_max()
_eq.reduce[error_ux, "max"] = sp.Abs(u(0) - ux)
noSlip = SparseBoundary(NoSlip(name="NoSlip"), lbm_bulk.lb_method, lbm_bulk.pdfs)
sfg.generate(noSlip)
wall_velocity = (u_max, 0, 0)
ubb = SparseBoundary(
UBB(wall_velocity, name="UBB"), lbm_bulk.lb_method, lbm_bulk.pdfs
)
sfg.generate(ubb)
#include "blockforest/all.h"
#include "vtk/all.h"
#include <limits>
#include "gen/ParallelPlatesSweeps.hpp"
{
struct ChannelType
{
{
if (channelType ==
"couette")
return COUETTE;
if (channelType ==
"poiseuille")
return POISEUILLE;
throw std::invalid_argument{ channelType };
}
};
void run(
int argc,
char** argv)
{
std::string channelTypeStr = simParams.
getParameter< std::string >(
"channelType");
std::function< void(
IBlock*) > setAnalytical;
std::function< void(
IBlock*) > initializePdfs;
std::function< void(
IBlock*) > streamCollide;
switch (channelType)
{
setAnalytical = gen::Couette::SetAnalyticalSolution{ blocks, rho, u, channelVelocity };
initializePdfs = gen::Couette::LBM::InitPdfs{ pdfs, rho, u };
streamCollide =
makeSharedSweep(std::make_shared< gen::Couette::LBM::StreamCollide >(pdfs, rho, u, latticeViscosity));
}
break;
setAnalytical = gen::Poiseuille::SetAnalyticalSolution{ blocks, rho, u, channelVelocity };
initializePdfs = gen::Poiseuille::LBM::InitPdfs{ blocks, pdfs, rho, u, latticeViscosity, channelVelocity };
streamCollide =
makeSharedSweep(std::make_shared< gen::Poiseuille::LBM::StreamCollide >(
blocks, pdfs, rho, u, latticeViscosity, channelVelocity));
}
break;
}
for (auto& b : *blocks)
{
setAnalytical(&b);
initializePdfs(&b);
}
.makeShared();
auto intersectsUpperWall = [&](auto link) -> bool {
blocks->transformBlockLocalToGlobalCell(link.wallCell, link.block);
return link.wallCell.z() > blocks->getDomainCellBB().zMax();
};
auto intersectsLowerWall = [&](auto link) -> bool {
blocks->transformBlockLocalToGlobalCell(link.wallCell, link.block);
return link.wallCell.z() < blocks->getDomainCellBB().zMin();
};
auto noSlip = gen::NoSlipFactory{ blocks, pdfs }.fromLinks([&](auto link) {
});
auto ubb = gen::UBBFactory{ blocks, pdfs, channelVelocity }.fromLinks(
loop.addFuncAfterTimeStep(logger);
if (vtkWriteFrequency > 0)
{
auto vtkOutput =
"simulation_step", false, true, true, false, 0);
auto densityWriter = make_shared< memory::FieldVtkWriter< ScalarField_T, float32 > >(rho, "density");
vtkOutput->addCellDataWriter(densityWriter);
auto velWriter = make_shared< memory::FieldVtkWriter< VectorField_T, float32 > >(u, "velocity");
vtkOutput->addCellDataWriter(velWriter);
}
auto velocityErrorLmax =
{}, -std::numeric_limits< real_t >::infinity());
std::function< void(
IBlock*) > computeVelocityError;
switch (channelType)
{
computeVelocityError = gen::Couette::VelocityErrorLmax{ blocks, u, velocityErrorLmax.get(), channelVelocity };
}
break;
computeVelocityError = gen::Poiseuille::VelocityErrorLmax{ blocks, u, velocityErrorLmax.get(), channelVelocity };
}
break;
}
for (auto& b : *blocks)
{
computeVelocityError(&b);
}
}
}
}
int main(
int argc,
char** argv)
{
return EXIT_SUCCESS;
}
int main(int argc, char **argv)
Definition 01_BlocksAndFields.cpp:58
#define WALBERLA_LOG_INFO_ON_ROOT(msg)
Definition Logging.h:669
#define WALBERLA_ROOT_SECTION()
Definition MPIManager.h:287
Parameter< T > getParameter(const std::string &key) const
Returns an extracted parameter.
RAII Object to initialize waLBerla using command line parameters.
Definition Environment.h:39
shared_ptr< Config > config()
Returns configuration object, or null if no configuration object exists.
Definition Environment.h:72
Definition SharedFunctor.h:32
Handle for a Block object.
Definition Config.h:263
Base class for blocks (blocks are used to partition the simulation space: blocks are rectangular part...
Definition IBlock.h:189
Definition RemainingTimeLogger.h:47
static HaloExchangeBuilder< TCommStencil, TMemTag > create(const std::shared_ptr< StructuredBlockForest > &blocks)
Create a new halo-exchange object through its builder.
Definition HaloExchange.hpp:138
Collective header file for module core.
void assert_greater_equal(const T &left, const T &right, const std::source_location loc=std::source_location::current())
Check if one value is greater or equal to another.
Definition Testutils.hpp:367
void assert_less(const T &left, const T &right, const std::source_location loc=std::source_location::current())
Check if one value is less than another.
Definition Testutils.hpp:324
Definition ParallelPlates.cpp:44
memory::Field< real_t, 1, MemoryTag > ScalarField_T
Definition ParallelPlates.cpp:50
void run(int argc, char **argv)
Definition ParallelPlates.cpp:69
stencil::D3Q19 LbStencil
Definition ParallelPlates.cpp:53
v8::memtag::automatic MemoryTag
Definition ParallelPlates.cpp:48
shared_ptr< StructuredBlockForest > createUniformBlockGridFromConfig(const shared_ptr< Config > &config, CellInterval *requestedDomainSize, const bool keepGlobalBlockInformation)
Parses config block called 'DomainSetup' and creates a StructuredBlockForest.
Definition Initialization.cpp:49
shared_ptr< Loop > loop(const IFunctionNodePtr &body, uint_t iterations, bool logTimeStep=true)
Runs the child node for the given amount of iterations.
Definition ExecutionTree.impl.h:82
@ MAX
Definition Operation.h:26
void reduceInplace(T &value, Operation operation, int recvRank=0, MPI_Comm comm=MPI_COMM_WORLD)
Reduces a value over all processes in-place.
Definition Reduce.h:57
FuncCreator< void(IBlock *)> Sweep
Definition SelectableFunctionCreators.h:134
detail::_StreamPullSyncFactory< TStencil > streamPullSync
Definition PackInfoSelection.hpp:80
Definition Allocators.hpp:28
void sync()
Synchronize with concurrent execution on the default stream.
Definition Sweeper.hpp:189
Definition GridGeometry.hpp:32
shared_ptr< VTKOutput > createVTKOutput_BlockData(const StructuredBlockStorage &sbs, const std::string &identifier=std::string("block_data"), const uint_t writeFrequency=1, const uint_t ghostLayers=0, const bool forcePVTU=false, const std::string &baseFolder=std::string("vtk_out"), const std::string &executionFolder=std::string("simulation_step"), const bool continuousNumbering=false, const bool binary=true, const bool littleEndian=true, const bool useMPIIO=true, const uint_t initialExecutionCount=0, const bool amrFileFormat=false, const bool oneFilePerProcess=false)
Definition VTKOutput.h:588
VTKOutput::Write writeFiles(const shared_ptr< VTKOutput > &vtk, const bool immediatelyWriteCollectors=true, const int simultaneousIOOperations=0, const Set< SUID > &requiredStates=Set< SUID >::emptySet(), const Set< SUID > &incompatibleStates=Set< SUID >::emptySet())
Definition VTKOutput.h:710
Storage for detected contacts which can be used to perform actions for all contacts,...
Definition FreeSlip.hpp:42
lbm::PdfField< LatticeModel_T > PdfField_T
[typedefs]
Definition 02_LBMLatticeModelGeneration.cpp:60
typename timeloop::SweepTimeloop< > SweepTimeloop
Definition SweepTimeloop.h:198
internal::SharedSweep< T > makeSharedSweep(const shared_ptr< T > &sweepPtr)
Definition SharedSweep.h:52
field::GhostLayerField< real_t, Stencil_T::D > VectorField_T
Definition 03_AdvancedLBMCodegen.cpp:64
float real_t
Definition DataTypes.h:197
std::size_t uint_t
Definition DataTypes.h:161
Collective header file for module stencil.
static ChannelType::Type fromStr(const std::string &channelType)
Definition ParallelPlates.cpp:61
Type
Definition ParallelPlates.cpp:58
@ COUETTE
Definition ParallelPlates.cpp:58
@ POISEUILLE
Definition ParallelPlates.cpp:58
Definition SelectableFunctionCreators.h:100
Collective header file for module timeloop.