From e6aac23aa5146f296c11e4b4bec23dd2a0773c42 Mon Sep 17 00:00:00 2001 From: Christoph Schwarzmeier <christoph.schwarzmeier@fau.de> Date: Mon, 14 Nov 2022 13:25:10 +0100 Subject: [PATCH] Add free-surface LBM showcase: Zalesak's rotating disk --- apps/showcases/FreeSurface/CMakeLists.txt | 4 + apps/showcases/FreeSurface/ZalesakDisk.cpp | 370 +++++++++++++++++++++ apps/showcases/FreeSurface/ZalesakDisk.prm | 105 ++++++ 3 files changed, 479 insertions(+) create mode 100644 apps/showcases/FreeSurface/ZalesakDisk.cpp create mode 100644 apps/showcases/FreeSurface/ZalesakDisk.prm diff --git a/apps/showcases/FreeSurface/CMakeLists.txt b/apps/showcases/FreeSurface/CMakeLists.txt index 0e6edd5b2..b0dd58608 100644 --- a/apps/showcases/FreeSurface/CMakeLists.txt +++ b/apps/showcases/FreeSurface/CMakeLists.txt @@ -46,3 +46,7 @@ waLBerla_add_executable(NAME RisingBubble waLBerla_add_executable(NAME TaylorBubble FILES TaylorBubble.cpp DEPENDS blockforest boundary core domain_decomposition field lbm postprocessing timeloop vtk) + +waLBerla_add_executable(NAME ZalesakDisk + FILES ZalesakDisk.cpp + DEPENDS blockforest boundary core domain_decomposition field lbm postprocessing timeloop vtk) \ No newline at end of file diff --git a/apps/showcases/FreeSurface/ZalesakDisk.cpp b/apps/showcases/FreeSurface/ZalesakDisk.cpp new file mode 100644 index 000000000..02beb5706 --- /dev/null +++ b/apps/showcases/FreeSurface/ZalesakDisk.cpp @@ -0,0 +1,370 @@ +//====================================================================================================================== +// +// 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 ZalesakDisk.cpp +//! \author Christoph Schwarzmeier <christoph.schwarzmeier@fau.de> +// +// This showcase simulates a slotted disk of gas in a constant rotating velocity field. This benchmark is commonly +// referred to as Zalesak's rotating disk (see doi: 10.1016/0021-9991(79)90051-2). +//====================================================================================================================== + +#include "blockforest/Initialization.h" + +#include "core/Environment.h" + +#include "field/Gather.h" + +#include "lbm/PerformanceLogger.h" +#include "lbm/field/AddToStorage.h" +#include "lbm/free_surface/LoadBalancing.h" +#include "lbm/free_surface/SurfaceMeshWriter.h" +#include "lbm/free_surface/TotalMassComputer.h" +#include "lbm/free_surface/VtkWriter.h" +#include "lbm/free_surface/bubble_model/Geometry.h" +#include "lbm/free_surface/dynamics/SurfaceDynamicsHandler.h" +#include "lbm/free_surface/surface_geometry/SurfaceGeometryHandler.h" +#include "lbm/free_surface/surface_geometry/Utility.h" +#include "lbm/lattice_model/D2Q9.h" + +namespace walberla +{ +namespace free_surface +{ +namespace ZalesakDisk +{ +using ScalarField_T = GhostLayerField< real_t, 1 >; +using VectorField_T = GhostLayerField< Vector3< real_t >, 1 >; + +using CollisionModel_T = lbm::collision_model::SRT; +using ForceModel_T = lbm::force_model::GuoField< VectorField_T >; +using LatticeModel_T = lbm::D2Q9< CollisionModel_T, true, ForceModel_T, 2 >; +using LatticeModelStencil_T = LatticeModel_T::Stencil; +using PdfField_T = lbm::PdfField< LatticeModel_T >; +using PdfCommunication_T = blockforest::SimpleCommunication< LatticeModelStencil_T >; + +// the geometry computations in SurfaceGeometryHandler require meaningful values in the ghost layers in corner +// directions (flag field and fill level field); this holds, even if the lattice model uses a D3Q19 stencil +using CommunicationStencil_T = + typename std::conditional< LatticeModel_T::Stencil::D == uint_t(2), stencil::D2Q9, stencil::D3Q27 >::type; +using Communication_T = blockforest::SimpleCommunication< CommunicationStencil_T >; + +using flag_t = uint32_t; +using FlagField_T = FlagField< flag_t >; +using FreeSurfaceBoundaryHandling_T = FreeSurfaceBoundaryHandling< LatticeModel_T, FlagField_T, ScalarField_T >; + +// function describing the initialization velocity profile (in global cell coordinates) +inline Vector3< real_t > velocityProfile(real_t angularVelocity, Cell globalCell, Vector3< real_t > domainCenter) +{ + // add 0.5 to get Cell's center + const real_t velocityX = -angularVelocity * ((real_c(globalCell.y()) + real_c(0.5)) - domainCenter[0]); + const real_t velocityY = angularVelocity * ((real_c(globalCell.x()) + real_c(0.5)) - domainCenter[1]); + + return Vector3< real_t >(velocityX, velocityY, real_c(0)); +} + +int main(int argc, char** argv) +{ + Environment walberlaEnv(argc, argv); + + if (argc < 2) { WALBERLA_ABORT("Please specify a parameter file as input argument.") } + + // print content of parameter file + WALBERLA_LOG_INFO_ON_ROOT(*walberlaEnv.config()); + + // get block forest parameters from parameter file + auto blockForestParameters = walberlaEnv.config()->getOneBlock("BlockForestParameters"); + const Vector3< uint_t > cellsPerBlock = blockForestParameters.getParameter< Vector3< uint_t > >("cellsPerBlock"); + const Vector3< bool > periodicity = blockForestParameters.getParameter< Vector3< bool > >("periodicity"); + const uint_t loadBalancingFrequency = blockForestParameters.getParameter< uint_t >("loadBalancingFrequency"); + const bool printLoadBalancingStatistics = blockForestParameters.getParameter< bool >("printLoadBalancingStatistics"); + + // get domain parameters from parameter file + auto domainParameters = walberlaEnv.config()->getOneBlock("DomainParameters"); + const uint_t domainWidth = domainParameters.getParameter< uint_t >("domainWidth"); + + const real_t diskRadius = real_c(domainWidth) * real_c(0.15); + const Vector3< real_t > diskCenter = + Vector3< real_t >(real_c(domainWidth) * real_c(0.5), real_c(domainWidth) * real_c(0.75), real_c(0.5)); + const real_t diskSlotLength = real_c(0.25) * real_c(domainWidth); + const real_t diskSlotWidth = real_c(0.05) * real_c(domainWidth); + + // define domain size + Vector3< uint_t > domainSize; + domainSize[0] = domainWidth; + domainSize[1] = domainWidth; + domainSize[2] = uint_c(1); + const Vector3< real_t > domainCenter = + real_c(0.5) * Vector3< real_t >(real_c(domainSize[0]), real_c(domainSize[1]), real_c(domainSize[2])); + + // compute number of blocks as defined by domainSize and cellsPerBlock + Vector3< uint_t > numBlocks; + numBlocks[0] = uint_c(std::ceil(real_c(domainSize[0]) / real_c(cellsPerBlock[0]))); + numBlocks[1] = uint_c(std::ceil(real_c(domainSize[1]) / real_c(cellsPerBlock[1]))); + numBlocks[2] = uint_c(std::ceil(real_c(domainSize[2]) / real_c(cellsPerBlock[2]))); + + // get number of (MPI) processes + uint_t numProcesses = uint_c(MPIManager::instance()->numProcesses()); + WALBERLA_CHECK_LESS_EQUAL(numProcesses, numBlocks[0] * numBlocks[1] * numBlocks[2], + "The number of MPI processes is greater than the number of blocks as defined by " + "\"domainSize/cellsPerBlock\". This would result in unused MPI processes. Either decrease " + "the number of MPI processes or increase \"cellsPerBlock\".") + + WALBERLA_LOG_DEVEL_VAR_ON_ROOT(numProcesses); + WALBERLA_LOG_DEVEL_VAR_ON_ROOT(cellsPerBlock); + WALBERLA_LOG_DEVEL_VAR_ON_ROOT(domainSize); + WALBERLA_LOG_DEVEL_VAR_ON_ROOT(numBlocks); + WALBERLA_LOG_DEVEL_VAR_ON_ROOT(domainWidth); + WALBERLA_LOG_DEVEL_VAR_ON_ROOT(periodicity); + WALBERLA_LOG_DEVEL_VAR_ON_ROOT(loadBalancingFrequency); + WALBERLA_LOG_DEVEL_VAR_ON_ROOT(printLoadBalancingStatistics); + + // get physics parameters from parameter file + auto physicsParameters = walberlaEnv.config()->getOneBlock("PhysicsParameters"); + const uint_t timesteps = physicsParameters.getParameter< uint_t >("timesteps"); + + const real_t relaxationRate = physicsParameters.getParameter< real_t >("relaxationRate"); + const CollisionModel_T collisionModel = CollisionModel_T(relaxationRate); + const real_t viscosity = collisionModel.viscosity(); + + const real_t reynoldsNumber = physicsParameters.getParameter< real_t >("reynoldsNumber"); + const real_t angularVelocity = + reynoldsNumber * viscosity / (real_c(0.5) * real_c(domainWidth) * real_c(domainWidth)); + const Vector3< real_t > force(real_c(0), real_c(0), real_c(0)); + + const bool enableWetting = physicsParameters.getParameter< bool >("enableWetting"); + const real_t contactAngle = physicsParameters.getParameter< real_t >("contactAngle"); + + WALBERLA_LOG_DEVEL_VAR_ON_ROOT(reynoldsNumber); + WALBERLA_LOG_DEVEL_VAR_ON_ROOT(relaxationRate); + WALBERLA_LOG_DEVEL_VAR_ON_ROOT(enableWetting); + WALBERLA_LOG_DEVEL_VAR_ON_ROOT(contactAngle); + WALBERLA_LOG_DEVEL_VAR_ON_ROOT(timesteps); + WALBERLA_LOG_DEVEL_VAR_ON_ROOT(viscosity); + WALBERLA_LOG_DEVEL_VAR_ON_ROOT(force); + WALBERLA_LOG_DEVEL_VAR_ON_ROOT(angularVelocity); + WALBERLA_LOG_DEVEL_ON_ROOT("Timesteps for full rotation " << real_c(2) * math::pi / angularVelocity); + + // read model parameters from parameter file + const auto modelParameters = walberlaEnv.config()->getOneBlock("ModelParameters"); + const std::string pdfReconstructionModel = modelParameters.getParameter< std::string >("pdfReconstructionModel"); + const std::string pdfRefillingModel = modelParameters.getParameter< std::string >("pdfRefillingModel"); + const std::string excessMassDistributionModel = + modelParameters.getParameter< std::string >("excessMassDistributionModel"); + const std::string curvatureModel = modelParameters.getParameter< std::string >("curvatureModel"); + const bool enableForceWeighting = modelParameters.getParameter< bool >("enableForceWeighting"); + const bool useSimpleMassExchange = modelParameters.getParameter< bool >("useSimpleMassExchange"); + const real_t cellConversionThreshold = modelParameters.getParameter< real_t >("cellConversionThreshold"); + const real_t cellConversionForceThreshold = modelParameters.getParameter< real_t >("cellConversionForceThreshold"); + const bool enableBubbleModel = modelParameters.getParameter< bool >("enableBubbleModel"); + const bool enableBubbleSplits = modelParameters.getParameter< bool >("enableBubbleSplits"); + + WALBERLA_LOG_DEVEL_VAR_ON_ROOT(pdfReconstructionModel); + WALBERLA_LOG_DEVEL_VAR_ON_ROOT(pdfRefillingModel); + WALBERLA_LOG_DEVEL_VAR_ON_ROOT(excessMassDistributionModel); + WALBERLA_LOG_DEVEL_VAR_ON_ROOT(curvatureModel); + WALBERLA_LOG_DEVEL_VAR_ON_ROOT(enableForceWeighting); + WALBERLA_LOG_DEVEL_VAR_ON_ROOT(useSimpleMassExchange); + WALBERLA_LOG_DEVEL_VAR_ON_ROOT(cellConversionThreshold); + WALBERLA_LOG_DEVEL_VAR_ON_ROOT(cellConversionForceThreshold); + WALBERLA_LOG_DEVEL_VAR_ON_ROOT(enableBubbleModel); + WALBERLA_LOG_DEVEL_VAR_ON_ROOT(enableBubbleSplits); + + // read evaluation parameters from parameter file + const auto evaluationParameters = walberlaEnv.config()->getOneBlock("EvaluationParameters"); + const uint_t performanceLogFrequency = evaluationParameters.getParameter< uint_t >("performanceLogFrequency"); + + WALBERLA_LOG_DEVEL_VAR_ON_ROOT(performanceLogFrequency); + + // create non-uniform block forest (non-uniformity required for load balancing) + const std::shared_ptr< StructuredBlockForest > blockForest = + createNonUniformBlockForest(domainSize, cellsPerBlock, numBlocks, periodicity); + + // add force field + const BlockDataID forceFieldID = + field::addToStorage< VectorField_T >(blockForest, "Force field", force, field::fzyx, uint_c(1)); + + // create lattice model + const LatticeModel_T latticeModel = LatticeModel_T(collisionModel, ForceModel_T(forceFieldID)); + + // add pdf field + const BlockDataID pdfFieldID = lbm::addPdfFieldToStorage(blockForest, "PDF field", latticeModel, field::fzyx); + + // add fill level field (initialized with 0, i.e., gas everywhere) + const BlockDataID fillFieldID = + field::addToStorage< ScalarField_T >(blockForest, "Fill level field", real_c(1.0), field::fzyx, uint_c(2)); + + // add boundary handling + const std::shared_ptr< FreeSurfaceBoundaryHandling_T > freeSurfaceBoundaryHandling = + std::make_shared< FreeSurfaceBoundaryHandling_T >(blockForest, pdfFieldID, fillFieldID); + const BlockDataID flagFieldID = freeSurfaceBoundaryHandling->getFlagFieldID(); + const typename FreeSurfaceBoundaryHandling_T::FlagInfo_T& flagInfo = freeSurfaceBoundaryHandling->getFlagInfo(); + + // initialize the velocity profile + for (auto blockIt = blockForest->begin(); blockIt != blockForest->end(); ++blockIt) + { + PdfField_T* const pdfField = blockIt->getData< PdfField_T >(pdfFieldID); + FlagField_T* const flagField = blockIt->getData< FlagField_T >(flagFieldID); + + WALBERLA_FOR_ALL_CELLS(pdfFieldIt, pdfField, flagFieldIt, flagField, { + // cell in block-local coordinates + const Cell localCell = pdfFieldIt.cell(); + + // get cell in global coordinates + Cell globalCell = pdfFieldIt.cell(); + blockForest->transformBlockLocalToGlobalCell(globalCell, *blockIt, localCell); + + // set velocity profile + const Vector3< real_t > initialVelocity = velocityProfile(angularVelocity, globalCell, domainCenter); + pdfField->setDensityAndVelocity(localCell, initialVelocity, real_c(1)); + }) // WALBERLA_FOR_ALL_CELLS + } + + // create the disk + const Vector3< real_t > diskBottomEnd = diskCenter - Vector3< real_t >(real_c(0), real_c(0), -real_c(domainSize[2])); + const Vector3< real_t > diskTopEnd = diskCenter - Vector3< real_t >(real_c(0), real_c(0), real_c(domainSize[2])); + const geometry::Cylinder disk(diskBottomEnd, diskTopEnd, diskRadius); + bubble_model::addBodyToFillLevelField< geometry::Cylinder >(*blockForest, fillFieldID, disk, true); + + // create the disk's slot + const Vector3< real_t > slotMinCorner = Vector3< real_t >(diskCenter[0] - diskSlotWidth * real_c(0.5), + diskCenter[1] - diskRadius, -real_c(domainSize[2])); + const Vector3< real_t > slotMaxCorner = Vector3< real_t >( + diskCenter[0] + diskSlotWidth * real_c(0.5), diskCenter[1] - diskRadius + diskSlotLength, real_c(domainSize[2])); + AABB slotAABB(slotMinCorner, slotMaxCorner); + bubble_model::addBodyToFillLevelField< AABB >(*blockForest, fillFieldID, slotAABB, false); + + // initialize domain boundary conditions from config file + const auto boundaryParameters = walberlaEnv.config()->getOneBlock("BoundaryParameters"); + freeSurfaceBoundaryHandling->initFromConfig(boundaryParameters); + + // IMPORTANT REMARK: this must be called only after every solid flag has been set; otherwise, the boundary handling + // might not detect solid flags correctly + freeSurfaceBoundaryHandling->initFlagsFromFillLevel(); + + // communication after initialization + Communication_T communication(blockForest, flagFieldID, fillFieldID, forceFieldID); + communication(); + + PdfCommunication_T pdfCommunication(blockForest, pdfFieldID); + pdfCommunication(); + + // add bubble model + std::shared_ptr< bubble_model::BubbleModelBase > bubbleModel = nullptr; + if (enableBubbleModel) + { + const std::shared_ptr< bubble_model::BubbleModel< LatticeModelStencil_T > > bubbleModelDerived = + std::make_shared< bubble_model::BubbleModel< LatticeModelStencil_T > >(blockForest, enableBubbleSplits); + bubbleModelDerived->initFromFillLevelField(fillFieldID); + + bubbleModel = std::static_pointer_cast< bubble_model::BubbleModelBase >(bubbleModelDerived); + } + else { bubbleModel = std::make_shared< bubble_model::BubbleModelConstantPressure >(real_c(1)); } + + // set density in non-liquid or non-interface cells to one (after initializing with hydrostatic pressure) + setDensityInNonFluidCellsToOne< FlagField_T, PdfField_T >(blockForest, flagInfo, flagFieldID, pdfFieldID); + + // create timeloop + SweepTimeloop timeloop(blockForest, timesteps); + + const real_t surfaceTension = real_c(0); + + // Laplace pressure = 2 * surface tension * curvature; curvature computation is not necessary with zero surface + // tension + bool computeCurvature = false; + if (!realIsEqual(surfaceTension, real_c(0), real_c(1e-14))) { computeCurvature = true; } + + // add surface geometry handler + const SurfaceGeometryHandler< LatticeModel_T, FlagField_T, ScalarField_T, VectorField_T > geometryHandler( + blockForest, freeSurfaceBoundaryHandling, fillFieldID, curvatureModel, computeCurvature, enableWetting, + contactAngle); + + geometryHandler.addSweeps(timeloop); + + // get fields created by surface geometry handler + const ConstBlockDataID curvatureFieldID = geometryHandler.getConstCurvatureFieldID(); + const ConstBlockDataID normalFieldID = geometryHandler.getConstNormalFieldID(); + + // add boundary handling for standard boundaries and free surface boundaries + const SurfaceDynamicsHandler< LatticeModel_T, FlagField_T, ScalarField_T, VectorField_T > dynamicsHandler( + blockForest, pdfFieldID, flagFieldID, fillFieldID, forceFieldID, normalFieldID, curvatureFieldID, + freeSurfaceBoundaryHandling, bubbleModel, pdfReconstructionModel, pdfRefillingModel, excessMassDistributionModel, + relaxationRate, force, surfaceTension, enableForceWeighting, useSimpleMassExchange, cellConversionThreshold, + cellConversionForceThreshold); + + dynamicsHandler.addSweeps(timeloop); + + // add load balancing + const LoadBalancer< FlagField_T, CommunicationStencil_T, LatticeModelStencil_T > loadBalancer( + blockForest, communication, pdfCommunication, bubbleModel, uint_c(50), uint_c(10), uint_c(5), + loadBalancingFrequency, printLoadBalancingStatistics); + timeloop.addFuncAfterTimeStep(loadBalancer, "Sweep: load balancing"); + + // add VTK output + addVTKOutput< LatticeModel_T, FreeSurfaceBoundaryHandling_T, PdfField_T, FlagField_T, ScalarField_T, VectorField_T >( + blockForest, timeloop, walberlaEnv.config(), flagInfo, pdfFieldID, flagFieldID, fillFieldID, forceFieldID, + geometryHandler.getCurvatureFieldID(), geometryHandler.getNormalFieldID(), + geometryHandler.getObstNormalFieldID()); + + // add triangle mesh output of free surface + SurfaceMeshWriter< ScalarField_T, FlagField_T > surfaceMeshWriter( + blockForest, fillFieldID, flagFieldID, flagIDs::liquidInterfaceGasFlagIDs, real_c(0), walberlaEnv.config()); + surfaceMeshWriter(); // write initial mesh + timeloop.addFuncAfterTimeStep(surfaceMeshWriter, "Writer: surface mesh"); + + // add logging for computational performance + const lbm::PerformanceLogger< FlagField_T > performanceLogger( + blockForest, flagFieldID, flagIDs::liquidInterfaceFlagIDs, performanceLogFrequency); + timeloop.addFuncAfterTimeStep(performanceLogger, "Evaluator: performance logging"); + + WcTimingPool timingPool; + + for (uint_t t = uint_c(0); t != timesteps; ++t) + { + timeloop.singleStep(timingPool, true); + + // set the constant velocity profile + for (auto blockIt = blockForest->begin(); blockIt != blockForest->end(); ++blockIt) + { + PdfField_T* const pdfField = blockIt->getData< PdfField_T >(pdfFieldID); + FlagField_T* const flagField = blockIt->getData< FlagField_T >(flagFieldID); + + WALBERLA_FOR_ALL_CELLS(pdfFieldIt, pdfField, flagFieldIt, flagField, { + if (flagInfo.isInterface(flagFieldIt) || flagInfo.isLiquid(flagFieldIt)) + { + // cell in block-local coordinates + const Cell localCell = pdfFieldIt.cell(); + + // get cell in global coordinates + Cell globalCell = pdfFieldIt.cell(); + blockForest->transformBlockLocalToGlobalCell(globalCell, *blockIt, localCell); + + // set velocity profile + const Vector3< real_t > initialVelocity = velocityProfile(angularVelocity, globalCell, domainCenter); + pdfField->setDensityAndVelocity(localCell, initialVelocity, real_c(1)); + } + }) // WALBERLA_FOR_ALL_CELLS + } + + if (t % performanceLogFrequency == uint_c(0) && t > uint_c(0)) { timingPool.logResultOnRoot(); } + } + + return EXIT_SUCCESS; +} + +} // namespace ZalesakDisk +} // namespace free_surface +} // namespace walberla + +int main(int argc, char** argv) { return walberla::free_surface::ZalesakDisk::main(argc, argv); } \ No newline at end of file diff --git a/apps/showcases/FreeSurface/ZalesakDisk.prm b/apps/showcases/FreeSurface/ZalesakDisk.prm new file mode 100644 index 000000000..259774efd --- /dev/null +++ b/apps/showcases/FreeSurface/ZalesakDisk.prm @@ -0,0 +1,105 @@ +BlockForestParameters +{ + cellsPerBlock < 50, 50, 1 >; + periodicity < 0, 0, 1 >; + loadBalancingFrequency 0; + printLoadBalancingStatistics false; +} + +DomainParameters +{ + domainWidth 100; +} + +PhysicsParameters +{ + reynoldsNumber 100; // Re = angularVelocity * domainWidth * 0.5 * domainWidth / kin. viscosity + relaxationRate 1.8; + enableWetting false; + contactAngle 0; // only used if enableWetting=true + timesteps 1000000; +} + +ModelParameters +{ + pdfReconstructionModel OnlyMissing; + pdfRefillingModel EquilibriumRefilling; + excessMassDistributionModel EvenlyAllInterface; + curvatureModel FiniteDifferenceMethod; + enableForceWeighting false; + useSimpleMassExchange false; + cellConversionThreshold 1e-2; + cellConversionForceThreshold 1e-1; + + enableBubbleModel True; + enableBubbleSplits false; // only used if enableBubbleModel=true +} + +EvaluationParameters +{ + performanceLogFrequency 10000; +} + +BoundaryParameters +{ + // X + Border { direction W; walldistance -1; FreeSlip{} } + Border { direction E; walldistance -1; FreeSlip{} } + + // Y + Border { direction N; walldistance -1; FreeSlip{} } + Border { direction S; walldistance -1; FreeSlip{} } + + // Z + //Border { direction T; walldistance -1; FreeSlip{} } + //Border { direction B; walldistance -1; FreeSlip{} } +} + +MeshOutputParameters +{ + writeFrequency 0; + baseFolder mesh-out; +} + +VTK +{ + fluid_field + { + writeFrequency 4241; + ghostLayers 0; + baseFolder vtk-out; + samplingResolution 1; + + writers + { + fill_level; + mapped_flag; + velocity; + density; + //curvature; + //normal; + //obstacle_normal; + //pdf; + //flag; + //force; + } + + inclusion_filters + { + //liquidInterfaceFilter; // only include liquid and interface cells in VTK output + } + + before_functions + { + //ghost_layer_synchronization; // only needed if writing the ghost layer + gas_cell_zero_setter; // sets velocity=0 and density=1 all gas cells before writing VTK output + } + } + + domain_decomposition + { + writeFrequency 0; + baseFolder vtk-out; + outputDomainDecomposition true; + } +} \ No newline at end of file -- GitLab