diff --git a/apps/showcases/RayleighBenardConvection/CMakeLists.txt b/apps/showcases/RayleighBenardConvection/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..cccb8326e04677ce82a2d3f1b60c8b2c908b2146 --- /dev/null +++ b/apps/showcases/RayleighBenardConvection/CMakeLists.txt @@ -0,0 +1,4 @@ +if ( WALBERLA_BUILD_WITH_CODEGEN ) + add_subdirectory( Codegen ) + add_subdirectory( Native ) +endif () diff --git a/apps/showcases/RayleighBenardConvection/Codegen/RayleighBenardConvection_codegen.py b/apps/showcases/RayleighBenardConvection/Codegen/RayleighBenardConvection_codegen.py index da8bd3e236b894cd4bf6b8afebd3e4cff947c9ff..b187973f5c6e314211c44d699b7265487c9d7227 100644 --- a/apps/showcases/RayleighBenardConvection/Codegen/RayleighBenardConvection_codegen.py +++ b/apps/showcases/RayleighBenardConvection/Codegen/RayleighBenardConvection_codegen.py @@ -95,6 +95,7 @@ lbm_config_thermal = LBMConfig( method=Method.SRT, relaxation_rate=omega_thermal, compressible=True, + zero_centered=False, velocity_input=velocity_field, equilibrium_order=1, entropic=False, diff --git a/apps/showcases/RayleighBenardConvection/Native/CMakeLists.txt b/apps/showcases/RayleighBenardConvection/Native/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..eabc2d9c1a8ee84b5ec11245a48e3b90362f8ea1 --- /dev/null +++ b/apps/showcases/RayleighBenardConvection/Native/CMakeLists.txt @@ -0,0 +1,15 @@ +waLBerla_link_files_to_builddir(*.prm) +waLBerla_link_files_to_builddir(*.py) +waLBerla_link_files_to_builddir(*.obj) + +if( WALBERLA_BUILD_WITH_CODEGEN ) + walberla_generate_target_from_python( NAME RayleighBenardConvectionLatticeModelGeneration + FILE RayleighBenardConvectionLatticeModelGeneration.py + OUT_FILES RayleighBenardConvectionLatticeModel_fluid.cpp RayleighBenardConvectionLatticeModel_fluid.h + RayleighBenardConvectionLatticeModel_thermal.cpp RayleighBenardConvectionLatticeModel_thermal.h ) + + waLBerla_add_executable(NAME RayleighBenardConvectionNative + FILES RayleighBenardConvectionNative.cpp #InitializerFunctions.cpp #SQLProperties.cpp + DEPENDS blockforest boundary core domain_decomposition field lbm postprocessing python_coupling#sqlite + timeloop vtk RayleighBenardConvectionLatticeModelGeneration) +endif() diff --git a/apps/showcases/RayleighBenardConvection/Native/RayleighBenardConvectionLatticeModelGeneration.py b/apps/showcases/RayleighBenardConvection/Native/RayleighBenardConvectionLatticeModelGeneration.py new file mode 100644 index 0000000000000000000000000000000000000000..047d05affc4ed6a046fbbee9e83da9ef625a901f --- /dev/null +++ b/apps/showcases/RayleighBenardConvection/Native/RayleighBenardConvectionLatticeModelGeneration.py @@ -0,0 +1,73 @@ +import sympy as sp +import pystencils as ps +from lbmpy.creationfunctions import LBMConfig, LBMOptimisation, create_lb_collision_rule +from lbmpy.enums import ForceModel, Method, Stencil +from lbmpy.stencils import LBStencil + +from pystencils_walberla import CodeGeneration +from lbmpy_walberla import generate_lattice_model + + +with CodeGeneration() as ctx: + stencil_thermal = LBStencil(Stencil.D3Q7) + stencil_fluid = LBStencil(Stencil.D3Q19) + + target = ps.Target.CPU + layout = "fzyx" + zero_centered = False + force_model = ForceModel.SIMPLE + + omega_fluid = sp.Symbol("omega_fluid") + omega_thermal = sp.Symbol("omega_thermal") + gravity_LBM = sp.Symbol("gravity") #! gravity? gravitational acceleration? ...? what exactly do I use / need here? + rho = sp.Symbol("rho") + + # optimizations to be used by the code generator + lbm_opt = LBMOptimisation(cse_global=True, field_layout=layout) + + velocity_field = ps.fields( + f"vel_field({stencil_fluid.D}): [{stencil_fluid.D}D]", layout=layout + ) + temperature_field = ps.fields(f"temperature_field: [{stencil_thermal.D}D]", layout=layout) + + force = sp.Matrix([0, gravity_LBM * temperature_field(0) * rho, 0]) + + #------------------------------ Fluid LBM ------------------------------ + # Fluid LBM + lbm_config_fluid = LBMConfig( + stencil=stencil_fluid, + method=Method.SRT, + relaxation_rate=omega_fluid, + compressible=False, + zero_centered=zero_centered, + output={"velocity": velocity_field}, + force=force, + force_model=ForceModel.SIMPLE, + ) # Simple force model (automatisch w_i, c_i, 3) + + #> currently optimizations turned off! + collision_rule_fluid = create_lb_collision_rule(lbm_config=lbm_config_fluid)#, + #lbm_optimisation=lbm_opt) + + generate_lattice_model(ctx, "RayleighBenardConvectionLatticeModel_fluid", collision_rule_fluid, field_layout=layout) + + #------------------------------ Thermal LBM ------------------------------ + # Thermal LBM + lbm_config_thermal = LBMConfig( + stencil=stencil_thermal, + method=Method.SRT, + relaxation_rate=omega_thermal, + compressible=True, + zero_centered=False, #? think about that -> if "defualt" delta_rho not known + velocity_input=velocity_field, + equilibrium_order=1, + entropic=False, + output={"density": temperature_field}, + ) + #> currently optimizations turned off! + collision_rule_thermal = create_lb_collision_rule(lbm_config=lbm_config_thermal)#, + #lbm_optimisation=lbm_opt) + + generate_lattice_model(ctx, "RayleighBenardConvectionLatticeModel_thermal", collision_rule_thermal, field_layout=layout) + +print("\t >>> finished code generation successfully <<<") diff --git a/apps/showcases/RayleighBenardConvection/Native/RayleighBenardConvectionNative.cpp b/apps/showcases/RayleighBenardConvection/Native/RayleighBenardConvectionNative.cpp new file mode 100644 index 0000000000000000000000000000000000000000..a8eca2f17b1f2f72ff3011baafa18e28ba8e4218 --- /dev/null +++ b/apps/showcases/RayleighBenardConvection/Native/RayleighBenardConvectionNative.cpp @@ -0,0 +1,378 @@ +//====================================================================================================================== +// +// 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 RayleighBenardConvection.cpp +//! \author Jonas Plewinski <jonas.plewinski@fau.de> +// +//====================================================================================================================== + +#include "blockforest/Initialization.h" +// #include "blockforest/communication/UniformBufferedScheme.h" +#include "core/Environment.h" +#include "core/logging/Initialization.h" +#include "core/math/Constants.h" +#include "core/timing/RemainingTimeLogger.h" + +#include "field/AddToStorage.h" + +#include "lbm/blockforest/communication/SimpleCommunication.h" +// #include "field/Gather.h" +#include "field/FlagField.h" +#include "field/vtk/VTKWriter.h" + +#include "geometry/InitBoundaryHandling.h" +#include "geometry/mesh/TriangleMeshIO.h" + +#include "lbm/PerformanceEvaluation.h" +#include "lbm/boundary/all.h" +#include "lbm/field/AddToStorage.h" +#include "lbm/vtk/Density.h" + +#include "python_coupling/CreateConfig.h" +// #include "python_coupling/PythonCallback.h" + +#include "timeloop/SweepTimeloop.h" + +//#include "InitializerFunctions.h" +#include "RayleighBenardConvectionLatticeModel_fluid.h" +#include "RayleighBenardConvectionLatticeModel_thermal.h" + +using namespace walberla; + +/////////////////////// +/// Typedef Aliases /// +/////////////////////// +using ScalarField_T = GhostLayerField< real_t, 1 >; +using VectorField_T = GhostLayerField< Vector3< real_t >, 1 >; +using VectorFieldFlattened_T = GhostLayerField< real_t, 3 >; + +//using CollisionModel_T = lbm::collision_model::SRT; + +//--------------------------- fluid ----------------------------- +using LatticeModelFluid_T = lbm::RayleighBenardConvectionLatticeModel_fluid; +using FluidStencil_T = LatticeModelFluid_T::Stencil; +using PdfFieldFluid_T = lbm::PdfField< LatticeModelFluid_T >; +using PdfFluidCommunication_T = blockforest::SimpleCommunication< FluidStencil_T >; + +//--------------------------- thermal --------------------------- +using LatticeModelThermal_T = lbm::RayleighBenardConvectionLatticeModel_thermal; +using ThermalStencil_T = LatticeModelThermal_T::Stencil; +using PdfFieldThermal_T = lbm::PdfField< LatticeModelThermal_T >; +using PdfThermalCommunication_T = blockforest::SimpleCommunication< ThermalStencil_T >; + +using flag_t = walberla::uint8_t; +using FlagField_T = FlagField< flag_t >; + +// function describing the initialization profile (in global coordinates) +real_t initializationProfile(real_t x, real_t amplitude, real_t offset, real_t wavelength) +{ + return amplitude * std::cos(x / wavelength * real_c(2) * math::pi + math::pi) + offset; +} + +template< typename LatticeModel_T > +void initTemperatureFieldTest(const shared_ptr< StructuredBlockStorage >& blocks, + BlockDataID temperature_field_ID, + BlockDataID pdf_field_ID, + real_t amplitude, Vector3< uint_t > domainSize, real_t temperatureRange) +{ + for (auto& block : *blocks) + { + auto temperatureField = block.getData< ScalarField_T >(temperature_field_ID); + auto pdfField = block.getData< lbm::PdfField< LatticeModel_T > >(pdf_field_ID); + + WALBERLA_FOR_ALL_CELLS_INCLUDING_GHOST_LAYER_XYZ(temperatureField, { + //WALBERLA_FOR_ALL_CELLS_INCLUDING_GHOST_LAYER_XYZ(pdfField, { + // cell in block-local coordinates + Cell globalCell; + blocks->transformBlockLocalToGlobalCell(globalCell, block, Cell(x, y, z)); + + uint_t sampleSize = 100; + real_t stepSize = real_c(1.) / real_c(sampleSize); + real_t offset = real_c(domainSize[1] / 2); + real_t wavelength = real_c(domainSize[0]); + + //-- + Vector3 vel(real_c(0)); + //-- + for (uint_t xSample = uint_c(0); xSample <= sampleSize; ++xSample) + { + // value of the sine-function + const real_t functionValue = initializationProfile(real_c(globalCell[0]) + real_c(xSample) * stepSize, amplitude, offset, wavelength); + for (uint_t ySample = uint_c(0); ySample <= sampleSize; ++ySample) + { + const real_t yPoint = real_c(globalCell[1]) + real_c(ySample) * stepSize; + //temperatureField->get(x, y, z) = (yPoint < functionValue) ? temperatureRange/50 : -temperatureRange/50; + auto temp = (yPoint < functionValue) ? temperatureRange/50 : -temperatureRange/50; + pdfField->setDensityAndVelocity(x, y, z, vel, temp); + } + } + }) // WALBERLA_FOR_ALL_CELLS + } +} + +///////////////////// +/// Main Function /// +///////////////////// +int main(int argc, char** argv) +{ + mpi::Environment Env(argc, argv); + // exportDataStructuresToPython(); //> what does that do? + + for (auto cfg = python_coupling::configBegin(argc, argv); cfg != python_coupling::configEnd(); ++cfg) + { + WALBERLA_MPI_WORLD_BARRIER() + + auto config = *cfg; + logging::configureLogging(config); + // WALBERLA_LOG_DEVEL_VAR_ON_ROOT(*config) + + /////////////////////////// + // ADD DOMAIN PARAMETERS // + /////////////////////////// + + uint_t nrOfProcesses = uint_c(MPIManager::instance()->numProcesses()); + WALBERLA_LOG_DEVEL_VAR_ON_ROOT(nrOfProcesses) + + auto domainSetup = config->getOneBlock("DomainSetup"); + Vector3< uint_t > cellsPerBlock = domainSetup.getParameter< Vector3< uint_t > >("cellsPerBlock"); + std::vector< config::Config::Block* > configDomainSetupBlock; + config->getWritableGlobalBlock().getWritableBlocks("DomainSetup", configDomainSetupBlock, 1, 1); + Vector3< uint_t > blocksPerDimension; + Vector3< uint_t > cellsPerBlockDummy; + blockforest::calculateCellDistribution(cellsPerBlock, nrOfProcesses, blocksPerDimension, cellsPerBlockDummy); + + Vector3< uint_t > domainSize; + domainSize[0] = blocksPerDimension[0] * cellsPerBlock[0]; + domainSize[1] = blocksPerDimension[1] * cellsPerBlock[1]; + domainSize[2] = blocksPerDimension[2] * cellsPerBlock[2]; + // WALBERLA_LOG_INFO_ON_ROOT("cellsPerBlock = (" << cellsPerBlock[0] << ", " << cellsPerBlock[1] << ", " << + // cellsPerBlock[2] << ")") WALBERLA_LOG_INFO_ON_ROOT("blocksPerDimension = (" << blocksPerDimension[0] << ", " << + // blocksPerDimension[1] << ", " << blocksPerDimension[2] << ")") WALBERLA_LOG_INFO_ON_ROOT("domain size = (" << + // domainSize[0] << ", " << domainSize[1] << ", " << domainSize[2] << ")") + + std::string tmp = "< " + std::to_string(blocksPerDimension[0]) + ", " + std::to_string(blocksPerDimension[1]) + + ", " + std::to_string(blocksPerDimension[2]) + " >"; + WALBERLA_LOG_DEVEL_VAR_ON_ROOT(tmp) + configDomainSetupBlock[0]->setOrAddParameter("blocks", tmp); + + WALBERLA_LOG_DEVEL_VAR_ON_ROOT(*config) + + const shared_ptr< StructuredBlockForest > blockForest = blockforest::createUniformBlockGridFromConfig(config); + /*WALBERLA_LOG_DEVEL_VAR_ON_ROOT(blocks->getXSize()) + WALBERLA_LOG_DEVEL_VAR_ON_ROOT(blocks->getYSize()) + WALBERLA_LOG_DEVEL_VAR_ON_ROOT(blocks->getZSize()) + WALBERLA_LOG_DEVEL_VAR_ON_ROOT(blocks->getRootBlockXSize()) + WALBERLA_LOG_DEVEL_VAR_ON_ROOT(blocks->getRootBlockYSize()) + WALBERLA_LOG_DEVEL_VAR_ON_ROOT(blocks->getRootBlockZSize())*/ + + /////////////////////////////////////// + // ADD GENERAL SIMULATION PARAMETERS // + /////////////////////////////////////// + auto parameters = config->getOneBlock("Parameters"); + //const std::string timeStepStrategy = parameters.getParameter< std::string >("timeStepStrategy", "normal"); + const uint_t timesteps = parameters.getParameter< uint_t >("timesteps", uint_c(50)); + const real_t remainingTimeLoggerFrequency = + parameters.getParameter< real_t >("remainingTimeLoggerFrequency", real_c(3.0)); + // const uint_t scenario = parameters.getParameter< uint_t >("scenario", uint_c(1)); + // WALBERLA_LOG_DEVEL_VAR_ON_ROOT(timesteps) + // WALBERLA_LOG_DEVEL_VAR_ON_ROOT(remainingTimeLoggerFrequency) + + ///////////////////////////// + // ADD PHYSICAL PARAMETERS // + ///////////////////////////// + auto physical_parameters = config->getOneBlock("PhysicalParameters"); + const real_t omegaFluid = physical_parameters.getParameter< real_t >("omegaFluid", real_c(1.95)); + const real_t omegaThermal = physical_parameters.getParameter< real_t >("omegaThermal"); + const real_t temperatureHot = physical_parameters.getParameter< real_t >("temperatureHot", real_c(0.5)); + const real_t temperatureCold = physical_parameters.getParameter< real_t >("temperatureCold", real_c(-0.5)); + const real_t gravity = physical_parameters.getParameter< real_t >("gravitationalAcceleration"); + // WALBERLA_LOG_DEVEL_VAR_ON_ROOT(omegaFluid) + // WALBERLA_LOG_DEVEL_VAR_ON_ROOT(omegaThermal) + // WALBERLA_LOG_DEVEL_VAR_ON_ROOT(temperatureHot) + // WALBERLA_LOG_DEVEL_VAR_ON_ROOT(temperatureCold) + + /////////////////////////////////// + // ADD INITIALIZATION PARAMETERS // + /////////////////////////////////// + auto initialization_parameters = config->getOneBlock("InitializationParameters"); + const real_t initAmplitude = initialization_parameters.getParameter< real_t >("initAmplitude"); + const real_t initTemperatureRange = initialization_parameters.getParameter< real_t >("initTemperatureRange"); + // WALBERLA_LOG_DEVEL_VAR_ON_ROOT(initAmplitude) + // WALBERLA_LOG_DEVEL_VAR_ON_ROOT(initTemperatureRange) + + //////////////////////// + // ADD DATA TO BLOCKS // + //////////////////////// + const BlockDataID temperatureFieldId = + field::addToStorage< ScalarField_T >(blockForest, "Temperature field", real_c(0), field::fzyx); + const BlockDataID velocityFieldId = field::addToStorage< VectorFieldFlattened_T >( + blockForest, "Velocity field", real_c(0), field::fzyx, uint_c(1)); + //const BlockDataID densityFieldID = field::addToStorage< ScalarField_T >(blockForest, "density", real_c(0), field::fzyx); + + // create lattice model + LatticeModelFluid_T latticeModelFluid = //? currently force + LatticeModelFluid_T(temperatureFieldId, velocityFieldId, gravity, omegaFluid); //? gravity needs a sign???? + LatticeModelThermal_T latticeModelThermal = + LatticeModelThermal_T(temperatureFieldId, velocityFieldId, omegaThermal); + + // add pdf fields for fluid and thermal parts + const BlockDataID pdfFieldFluidId = lbm::addPdfFieldToStorage(blockForest, "PDF field fluid", latticeModelFluid, + Vector3(real_c(0), real_c(0), real_c(0)), + real_t(1), uint_t(1), field::fzyx); + const BlockDataID pdfFieldThermalId = + lbm::addPdfFieldToStorage(blockForest, "PDF field thermal", latticeModelThermal, Vector3(real_c(0), real_c(0), real_c(0)), + real_t(0), uint_t(1),field::fzyx); + //? what initial density makes sense here? + //initTemperatureField(blockForest, temperatureFieldId, initAmplitude, domainSize, initTemperatureRange); + initTemperatureFieldTest<LatticeModelThermal_T>(blockForest, temperatureFieldId, pdfFieldThermalId, initAmplitude, domainSize, initTemperatureRange); + + PdfThermalCommunication_T pdfThermalCommunication(blockForest, pdfFieldThermalId); + + //////////////// + // ADD SWEEPS // + //////////////// + auto lbmSweepFluid = LatticeModelFluid_T::Sweep(pdfFieldFluidId); + auto lbmSweepThermal = LatticeModelThermal_T::Sweep(pdfFieldThermalId); + + /////////////////////// + // BOUNDARY HANDLING // + /////////////////////// + const FlagUID fluidFlagUID("Fluid"); + const FlagUID thermalFlagUID("Thermal"); + + // Boundaries Fluid + typedef lbm::DefaultBoundaryHandlingFactory< LatticeModelFluid_T, FlagField_T > BHFactoryFluid; + + BlockDataID flagFieldFluidId = field::addFlagFieldToStorage< FlagField_T >(blockForest, "fluid flag field"); + + BlockDataID fluidBoundaryHandlingId = BHFactoryFluid::addBoundaryHandlingToStorage( + blockForest, "Fluid Boundary Handling", flagFieldFluidId, pdfFieldFluidId, fluidFlagUID, + Vector3< real_t >(real_c(0), real_c(0), real_c(0)), Vector3< real_t >(real_c(0), real_c(0), real_c(0)), + real_c(1), real_c(1)); + + auto fluidBoundariesConfig = config->getBlock("Boundaries_Fluid"); + geometry::initBoundaryHandling< BHFactoryFluid::BoundaryHandling >(*blockForest, fluidBoundaryHandlingId, + fluidBoundariesConfig); + geometry::setNonBoundaryCellsToDomain< BHFactoryFluid::BoundaryHandling >(*blockForest, fluidBoundaryHandlingId); + + // Boundaries Thermal + typedef lbm::DefaultBoundaryHandlingFactory< LatticeModelThermal_T, FlagField_T > BHFactoryThermal; + + BlockDataID flagFieldThermalId = field::addFlagFieldToStorage< FlagField_T >(blockForest, "Thermal flag field"); + + BlockDataID thermalBoundaryHandlingId = BHFactoryThermal::addBoundaryHandlingToStorage( + blockForest, "Thermal Boundary Handling", flagFieldThermalId, pdfFieldThermalId, + thermalFlagUID, //? fluidFlagUID, does that work like that? + Vector3< real_t >(real_c(0), real_c(0), real_c(0)), Vector3< real_t >(real_c(0), real_c(0), real_c(0)), + temperatureCold, temperatureHot); + + auto thermalBoundariesConfig = config->getBlock("Boundaries_Thermal"); + geometry::initBoundaryHandling< BHFactoryThermal::BoundaryHandling >(*blockForest, thermalBoundaryHandlingId, + thermalBoundariesConfig); + geometry::setNonBoundaryCellsToDomain< BHFactoryThermal::BoundaryHandling >(*blockForest, + thermalBoundaryHandlingId); + + /////////////// + // TIME LOOP // + /////////////// + auto benchmark_parameters = config->getOneBlock("BenchmarkParameters"); + std::string scaling_type = benchmark_parameters.getParameter< std::string >("scalingType"); + WALBERLA_LOG_DEVEL_VAR_ON_ROOT(scaling_type) + WALBERLA_LOG_DEVEL_VAR_ON_ROOT(nrOfProcesses) + WALBERLA_LOG_INFO_ON_ROOT("#blocks = (" + << blockForest->getXSize() << ", " << blockForest->getYSize() << ", " + << blockForest->getZSize() << ") | total #blocks = " + << blockForest->getXSize() * blockForest->getYSize() * blockForest->getZSize()) + WALBERLA_LOG_INFO_ON_ROOT("block size = (" << blockForest->getRootBlockXSize() << ", " + << blockForest->getRootBlockYSize() << ", " + << blockForest->getRootBlockZSize() << ")") + WALBERLA_LOG_INFO_ON_ROOT("domain size = (" << domainSize[0] << ", " << domainSize[1] << ", " << domainSize[2] + << ")") + + bool weak_scaling = benchmark_parameters.getParameter< bool >("weakScaling"); + + SweepTimeloop timeloop(blockForest->getBlockStorage(), timesteps); + if (!weak_scaling) + { + timeloop.add() << Sweep(BHFactoryThermal::BoundaryHandling::getBlockSweep(thermalBoundaryHandlingId), + "Thermal boundary conditions") + << AfterFunction(PdfThermalCommunication_T(blockForest, pdfFieldThermalId), + "Communication of thermal PDFs"); + timeloop.add() << Sweep(lbmSweepThermal, "Thermal LB Step"); + + timeloop.add() << BeforeFunction(PdfFluidCommunication_T(blockForest, pdfFieldFluidId), + "Communication of fluid PDFs") + << Sweep(BHFactoryFluid::BoundaryHandling::getBlockSweep(fluidBoundaryHandlingId), + "Fluid NoSlip boundary conditions"); + timeloop.add() << Sweep(lbmSweepFluid, "Fluid LB Step"); + + // remaining time logger + timeloop.addFuncAfterTimeStep( + RemainingTimeLogger(timeloop.getNrOfTimeSteps(), remainingTimeLoggerFrequency), + "remaining time logger"); + + // write VTK files + uint_t vtkWriteFrequency = parameters.getParameter< uint_t >("vtkWriteFrequency", 0); + if (vtkWriteFrequency > 0) + { + auto vtkOutput = vtk::createVTKOutput_BlockData(*blockForest, "vtk", vtkWriteFrequency, 1, false, "vtk_out", + "simulation_step", false, true, true, false, 0); + + vtkOutput->addCellDataWriter( make_shared< lbm::DensityVTKWriter < LatticeModelFluid_T, float > >( pdfFieldFluidId, "DensityFromPDF" ) ); + vtkOutput->addCellDataWriter( make_shared< lbm::DensityVTKWriter < LatticeModelThermal_T, float > >( pdfFieldThermalId, "TemperatureFromPDF" ) ); + + // add velocity field as VTK output + auto velWriter = make_shared< field::VTKWriter< VectorFieldFlattened_T > >(velocityFieldId, "Velocity"); + vtkOutput->addCellDataWriter(velWriter); + + // add temperature field as VTK output + auto tempWriter = make_shared< field::VTKWriter< ScalarField_T > >(temperatureFieldId, "Temperature"); + vtkOutput->addCellDataWriter(tempWriter); + + // add thermal flag field as VTK output + auto thermalFlagWriter = + make_shared< field::VTKWriter< FlagField_T > >(flagFieldThermalId, "FlagFieldThermal"); + vtkOutput->addCellDataWriter(thermalFlagWriter); + + // add fluid flag field as VTK output + auto fluidFlagWriter = make_shared< field::VTKWriter< FlagField_T > >(flagFieldFluidId, "FlagFieldFluid"); + vtkOutput->addCellDataWriter(fluidFlagWriter); + + timeloop.addFuncBeforeTimeStep(writeFiles(vtkOutput), "VTK Output"); + } + + // Performance evaluation + lbm::PerformanceEvaluation< FlagField_T > performance(blockForest, flagFieldFluidId, fluidFlagUID); + WcTimingPool timeloopTiming; + WcTimer simTimer; + + WALBERLA_LOG_INFO_ON_ROOT("Starting simulation with " << timesteps << " time steps") + WALBERLA_MPI_WORLD_BARRIER() + simTimer.start(); + timeloop.run(timeloopTiming); + WALBERLA_MPI_WORLD_BARRIER() + simTimer.end(); + + auto time = real_c(simTimer.max()); + WALBERLA_MPI_SECTION() { reduceInplace(time, walberla::mpi::MAX); } + performance.logResultOnRoot(timesteps, time); + + const auto reducedTimeloopTiming = timeloopTiming.getReduced(); + WALBERLA_LOG_RESULT_ON_ROOT("Time loop timing:\n" << *reducedTimeloopTiming) + WALBERLA_LOG_INFO_ON_ROOT("Simulation done!") + } + } + return EXIT_SUCCESS; +} \ No newline at end of file diff --git a/apps/showcases/RayleighBenardConvection/Native/RayleighBenardConvection_config.py b/apps/showcases/RayleighBenardConvection/Native/RayleighBenardConvection_config.py new file mode 100755 index 0000000000000000000000000000000000000000..30cb3c5040919867802229cd41c5d5f2d72a0504 --- /dev/null +++ b/apps/showcases/RayleighBenardConvection/Native/RayleighBenardConvection_config.py @@ -0,0 +1,134 @@ +import numpy as np +import waLBerla as wlb +import math + + +class Scenario: + def __init__(self, weak_scaling=False, scaling_type=None, cells=(32, 32, 1), timesteps=100): + #> Domain Parameters + self.domain_size = (32, 32, 1) + self.blocks = (4, 1, 1) + self.periodic = (1, 0, 1) + self.cells = (self.domain_size[0] // self.blocks[0], self.domain_size[1] // self.blocks[1], self.domain_size[2] // self.blocks[2]) + self.cells = cells + #print(f"self.cells = {self.cells}") + #> Standard Parameters + self.timesteps = timesteps + self.vtk_write_frequency = 200 + self.scenario = 1 + #> Physical Parameters + #! Prandtl + self.Prandtl = 1 + #! Rayleigh + self.Rayleigh = 50000 + #! omega_fluid + self.omega_fluid = 1.95 + #! omega_thermal + self.length_x_SI = 2 + self.length_conversion = self.length_x_SI / self.domain_size[0] + self.viscosity_LBM = 1./3 * (1. / self.omega_fluid - 1./2) + self.time_conversion = self.viscosity_LBM * self.length_conversion * self.length_conversion / \ + np.sqrt(self.Prandtl / self.Rayleigh) + self.thermal_diffusivity_LBM = np.sqrt(1. / (self.Prandtl * self.Rayleigh)) * self.time_conversion / \ + (self.length_conversion * self.length_conversion) + self.omega_thermal = 1. / (3 * self.thermal_diffusivity_LBM + 1./2) + #print(f"omega_fluid = {self.omega_fluid} | omega_thermal = {self.omega_thermal}") + #! temperature_hot + self.temperature_hot = 0.5 + #! temperature_cold + self.temperature_cold = - self.temperature_hot + #print(f"temperature_hot = {self.temperature_hot} | temperature_cold = {self.temperature_cold}") + #! gravity_LBM + self.gravity_SI = 9.81 + self.gravity_conversion = self.length_conversion / (self.time_conversion * self.time_conversion) #! look + self.gravity_LBM = self.gravity_SI / self.gravity_conversion + #> Initialization Parameters + self.delta_temperature = abs(self.temperature_hot) + abs(self.temperature_cold) + self.init_amplitude = self.delta_temperature / 20 * self.domain_size[0] + self.init_temperature_range = 2 * self.delta_temperature / self.domain_size[0] + #print(f"init_amplitude = {self.init_amplitude}") + #print(f"init_temperature_range = {self.init_temperature_range}") + + #> Benchmark Parameters + self.weakScaling = weak_scaling # True + self.scalingType = scaling_type #"fluid", "thermal", "rbc" + self.benchmarkingIterations = 5 + self.warmupSteps = 10 + + #?self.viscosity_SI = 1.516e-5 #? look + #?self.thermal_diffusivity_SI = 2.074e-5 #? look + + #?self.alpha = 3.43e-3 #? look + + @wlb.member_callback + def config(self): + return { + 'DomainSetup': { + #'blocks': self.blocks, + #'domainSize': self.domain_size, + #'cellsPerBlock': self.cells, + 'cellsPerBlock': self.cells, + 'blocks': self.blocks, + 'periodic': self.periodic, + 'dx': 1.0, + }, + 'Parameters': { + 'timesteps': self.timesteps, + 'vtkWriteFrequency': self.vtk_write_frequency, + 'remainingTimeLoggerFrequency': 10.0, + 'scenario': self.scenario, + }, + 'PhysicalParameters': { #todo check gravity! + 'omegaFluid': self.omega_fluid, + 'omegaThermal': self.omega_thermal, + 'temperatureHot': self.temperature_hot, + 'temperatureCold': self.temperature_cold, + 'gravitationalAcceleration': self.gravity_LBM, #? is this the right gravity I use here? + #? What do I have to use here? + #? - gravitaional acceleration + #? - gravitaional density + #? - ... + }, + 'InitializationParameters': { + 'initAmplitude': self.init_amplitude, + 'initTemperatureRange': self.init_temperature_range, + }, + 'BenchmarkParameters': { + 'weakScaling': self.weakScaling, + 'scalingType': self.scalingType, #"fluid", "thermal", "rbc" + 'benchmarkingIterations': self.benchmarkingIterations, + 'warmupSteps': self.warmupSteps, + }, + 'Boundaries_Fluid': { + 'Border': [ + {'direction': 'N', 'walldistance': -1, 'flag': 'NoSlip'}, + {'direction': 'S', 'walldistance': -1, 'flag': 'NoSlip'}, + ] + }, + 'Boundaries_Thermal': { + 'Border': [ + {'direction': 'N', 'walldistance': -1, 'flag': 'Pressure0'}, + {'direction': 'S', 'walldistance': -1, 'flag': 'Pressure1'}, + ] + }, + } + + +def runSimulation(): + scenarios = wlb.ScenarioManager() + scenarios.add(Scenario(timesteps=10000)) + + +def weakScalingBenchmark(): + scenarios = wlb.ScenarioManager() + block_sizes = [(i, i, i) for i in (8, 16, 32, 64, 128)] + timestepsPerBlockSize = [1024, 512, 256, 128, 64] + + for scaling_type in ['rbc', 'fluid', 'thermal']: + for block_size, timesteps in [(block_sizes[i], timestepsPerBlockSize[i]) for i in range(len(timestepsPerBlockSize))]: + scenario = Scenario(weak_scaling=True, scaling_type=scaling_type, cells=block_size, timesteps=timesteps) + scenarios.add(scenario) + + +runSimulation() +#weakScalingBenchmark()