Skip to content
GitLab
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
Jonas Plewinski
waLBerla
Commits
b2d65c45
Commit
b2d65c45
authored
May 25, 2022
by
Christoph Schwarzmeier
Browse files
Add free surface implementation
parent
f664fd07
Pipeline
#40341
failed with stages
in 19 minutes and 49 seconds
Changes
155
Pipelines
1
Expand all
Show whitespace changes
Inline
Side-by-side
apps/benchmarks/ComplexGeometry/ComplexGeometry.cpp
View file @
b2d65c45
...
...
@@ -239,7 +239,7 @@ int main( int argc, char * argv[] )
flagFieldId
,
fluidFlagUID
)
),
"LBM stability check"
);
timeloop
.
addFuncAfterTimeStep
(
perfLogger
,
"
P
erformance
L
ogg
er
"
);
timeloop
.
addFuncAfterTimeStep
(
perfLogger
,
"
Evaluator: p
erformance
l
ogg
ing
"
);
// add VTK output to time loop
...
...
apps/showcases/CMakeLists.txt
View file @
b2d65c45
add_subdirectory
(
BidisperseFluidizedBed
)
add_subdirectory
(
CombinedResolvedUnresolved
)
add_subdirectory
(
FluidizedBed
)
add_subdirectory
(
FreeSurface
)
add_subdirectory
(
HeatConduction
)
add_subdirectory
(
LightRisingParticleInFluidAMR
)
add_subdirectory
(
Mixer
)
...
...
@@ -12,3 +13,4 @@ endif()
if
(
WALBERLA_BUILD_WITH_CODEGEN AND NOT WALBERLA_BUILD_WITH_OPENMP
)
add_subdirectory
(
PorousMedia
)
endif
()
apps/showcases/FreeSurface/BreakingDam.cpp
0 → 100644
View file @
b2d65c45
This diff is collapsed.
Click to expand it.
apps/showcases/FreeSurface/BreakingDam.prm
0 → 100644
View file @
b2d65c45
BlockForestParameters
{
cellsPerBlock < 50, 50, 1 >;
periodicity < 0, 0, 1 >;
loadBalancingFrequency 5000;
printLoadBalancingStatistics true;
}
DomainParameters
{
columnWidth 50; // initial width of the liquid column, "a" in Martin & Moyce's paper
columnRatio 2; // ratio between columnHeight and columnWidth, "n^2" in Martin & Moyce's paper
}
PhysicsParameters
{
galileiNumber 1831123818;
bondNumber 445;
relaxationRate 1.99990085841269;
enableWetting false;
contactAngle 0; // only used if enableWetting=true
timesteps 50000;
}
ModelParameters
{
pdfReconstructionModel OnlyMissing;
pdfRefillingModel EquilibriumRefilling;
excessMassDistributionModel EvenlyAllInterface;
curvatureModel FiniteDifferenceMethod;
enableForceWeighting false;
useSimpleMassExchange false;
cellConversionThreshold 1e-2;
cellConversionForceThreshold 1e-1;
enableBubbleModel false;
enableBubbleSplits false; // only used if enableBubbleModel=true
smagorinskyConstant 0.1;
}
EvaluationParameters
{
performanceLogFrequency 25000;
evaluationFrequency 500;
filename breaking-dam.txt;
}
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 500;
ghostLayers 0;
baseFolder vtk-out;
samplingResolution 1;
writers
{
velocity;
density;
//pdf;
flag;
fill_level;
force;
curvature;
normal;
obstacle_normal;
mapped_flag;
}
inclusion_filters
{
// only include liquid and interface cells in VTK output
//liquidInterfaceFilter;
}
before_functions
{
//ghost_layer_synchronization; // only needed if writing the ghost layer
}
}
domain_decomposition
{
writeFrequency 5000;
baseFolder vtk-out;
outputDomainDecomposition true;
}
}
\ No newline at end of file
apps/showcases/FreeSurface/CMakeLists.txt
0 → 100644
View file @
b2d65c45
waLBerla_link_files_to_builddir
(
*.prm
)
waLBerla_add_executable
(
NAME BreakingDam
FILES BreakingDam.cpp
DEPENDS blockforest boundary core domain_decomposition field lbm postprocessing timeloop vtk
)
waLBerla_add_executable
(
NAME CapillaryWave
FILES CapillaryWave.cpp
DEPENDS blockforest boundary core domain_decomposition field lbm postprocessing timeloop vtk
)
waLBerla_add_executable
(
NAME DropInPool
FILES DropInPool.cpp
DEPENDS blockforest boundary core domain_decomposition field lbm postprocessing timeloop vtk
)
waLBerla_add_executable
(
NAME DropOnPlane
FILES DropOnPlane.cpp
DEPENDS blockforest boundary core domain_decomposition field lbm postprocessing timeloop vtk
)
waLBerla_add_executable
(
NAME FallingDrop
FILES FallingDrop.cpp
DEPENDS blockforest boundary core domain_decomposition field lbm postprocessing timeloop vtk
)
waLBerla_add_executable
(
NAME GravityWave
FILES GravityWave.cpp
DEPENDS blockforest boundary core domain_decomposition field lbm postprocessing timeloop vtk
)
if
(
WALBERLA_BUILD_WITH_CODEGEN
)
walberla_generate_target_from_python
(
NAME GravityWaveLatticeModelGeneration
FILE GravityWaveLatticeModelGeneration.py
OUT_FILES GravityWaveLatticeModel.cpp GravityWaveLatticeModel.h
)
waLBerla_add_executable
(
NAME GravityWaveCodegen
FILES GravityWaveCodegen.cpp
DEPENDS blockforest boundary core domain_decomposition field lbm postprocessing timeloop vtk
GravityWaveLatticeModelGeneration
)
endif
()
waLBerla_add_executable
(
NAME InflowShowcase
FILES InflowShowcase.cpp
DEPENDS blockforest boundary core domain_decomposition field lbm postprocessing timeloop vtk
)
waLBerla_add_executable
(
NAME RayleighTaylorInstability
FILES RayleighTaylorInstability.cpp
DEPENDS blockforest boundary core domain_decomposition field lbm postprocessing timeloop vtk
)
waLBerla_add_executable
(
NAME RestingBubble
FILES RestingBubble.cpp
DEPENDS blockforest boundary core domain_decomposition field lbm postprocessing timeloop vtk
)
waLBerla_add_executable
(
NAME RisingBubble
FILES RisingBubble.cpp
DEPENDS blockforest boundary core domain_decomposition field lbm postprocessing timeloop vtk
)
waLBerla_add_executable
(
NAME RotBreakingDam
FILES RotBreakingDam.cpp
DEPENDS blockforest boundary core domain_decomposition field lbm postprocessing timeloop vtk
)
waLBerla_add_executable
(
NAME TaylorBubble
FILES TaylorBubble.cpp
DEPENDS blockforest boundary core domain_decomposition field lbm postprocessing timeloop vtk
)
apps/showcases/FreeSurface/CapillaryWave.cpp
0 → 100644
View file @
b2d65c45
This diff is collapsed.
Click to expand it.
apps/showcases/FreeSurface/CapillaryWave.prm
0 → 100644
View file @
b2d65c45
BlockForestParameters
{
cellsPerBlock < 25, 25, 1 >;
periodicity < 1, 0, 1 >;
loadBalancingFrequency 50;
printLoadBalancingStatistics true;
}
DomainParameters
{
domainWidth 100; // equivalent to wavelength
liquidDepth 50;
initialAmplitude 1;
}
PhysicsParameters
{
reynoldsNumber 10;
relaxationRate 1.8;
enableWetting false;
contactAngle 0; // only used if enableWetting=true
timesteps 20000;
}
ModelParameters
{
pdfReconstructionModel OnlyMissing;
pdfRefillingModel EquilibriumRefilling;
excessMassDistributionModel EvenlyAllInterface;
curvatureModel FiniteDifferenceMethod;
enableForceWeighting false;
useSimpleMassExchange false;
cellConversionThreshold 1e-2;
cellConversionForceThreshold 1e-1;
enableBubbleModel false;
enableBubbleSplits false; // only used if enableBubbleModel=true
}
EvaluationParameters
{
performanceLogFrequency 5000;
evaluationFrequency 20;
filename capillary-wave.txt;
}
BoundaryParameters
{
// X
//Border { direction W; walldistance -1; NoSlip{} }
//Border { direction E; walldistance -1; NoSlip{} }
// Y
Border { direction N; walldistance -1; NoSlip{} }
Border { direction S; walldistance -1; NoSlip{} }
// Z
//Border { direction T; walldistance -1; NoSlip{} }
//Border { direction B; walldistance -1; NoSlip{} }
}
MeshOutputParameters
{
writeFrequency 100;
baseFolder mesh-out;
}
VTK
{
fluid_field
{
writeFrequency 100;
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
}
}
domain_decomposition
{
writeFrequency 100;
baseFolder vtk-out;
outputDomainDecomposition true;
}
}
\ No newline at end of file
apps/showcases/FreeSurface/DropInPool.cpp
0 → 100644
View file @
b2d65c45
//======================================================================================================================
//
// 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 DropInPool.cpp
//! \author Christoph Schwarzmeier <christoph.schwarzmeier@fau.de>
//! \brief This showcase simulates the impact of a droplet into a pool of liquid.
//
//======================================================================================================================
#include
"blockforest/Initialization.h"
#include
"core/Environment.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/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/D3Q19.h"
namespace
walberla
{
namespace
free_surface
{
namespace
DropInPool
{
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
::
D3Q19
<
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
>
;
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"
);
// read domain parameters from parameter file
const
auto
domainParameters
=
walberlaEnv
.
config
()
->
getOneBlock
(
"DomainParameters"
);
const
real_t
dropDiameter
=
domainParameters
.
getParameter
<
real_t
>
(
"dropDiameter"
);
const
Vector3
<
real_t
>
dropCenterFactor
=
domainParameters
.
getParameter
<
Vector3
<
real_t
>
>
(
"dropCenterFactor"
);
const
real_t
poolHeightFactor
=
domainParameters
.
getParameter
<
real_t
>
(
"poolHeightFactor"
);
const
Vector3
<
real_t
>
domainSizeFactor
=
domainParameters
.
getParameter
<
Vector3
<
real_t
>
>
(
"domainSizeFactor"
);
// define domain size
Vector3
<
uint_t
>
domainSize
=
domainSizeFactor
*
dropDiameter
;
domainSize
[
0
]
=
uint_c
(
domainSizeFactor
[
0
]
*
dropDiameter
);
domainSize
[
1
]
=
uint_c
(
domainSizeFactor
[
1
]
*
dropDiameter
);
domainSize
[
2
]
=
uint_c
(
domainSizeFactor
[
2
]
*
dropDiameter
);
// 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
(
numBlocks
);
WALBERLA_LOG_DEVEL_VAR_ON_ROOT
(
dropDiameter
);
WALBERLA_LOG_DEVEL_VAR_ON_ROOT
(
dropCenterFactor
);
WALBERLA_LOG_DEVEL_VAR_ON_ROOT
(
poolHeightFactor
);
WALBERLA_LOG_DEVEL_VAR_ON_ROOT
(
domainSizeFactor
);
WALBERLA_LOG_DEVEL_VAR_ON_ROOT
(
periodicity
);
WALBERLA_LOG_DEVEL_VAR_ON_ROOT
(
domainSize
);
Vector3
<
uint_t
>
realDomainSize
;
realDomainSize
[
0
]
=
cellsPerBlock
[
0
]
*
numBlocks
[
0
];
realDomainSize
[
1
]
=
cellsPerBlock
[
1
]
*
numBlocks
[
1
];
realDomainSize
[
2
]
=
cellsPerBlock
[
2
]
*
numBlocks
[
2
];
WALBERLA_LOG_DEVEL_VAR_ON_ROOT
(
realDomainSize
);
if
(
domainSize
[
0
]
!=
realDomainSize
[
0
]
&&
periodicity
[
0
])
{
WALBERLA_ABORT
(
"The specified domain size in x-direction can not be obtained with the number of blocks you specified."
)
}
if
(
domainSize
[
1
]
!=
realDomainSize
[
1
]
&&
periodicity
[
1
])
{
WALBERLA_ABORT
(
"The specified domain size in y-direction can not be obtained with the number of blocks you specified."
)
}
// the z-direction must be no slip in this setup and is simply extended (see below) to obtain the specified size
int
boundaryThicknessZ
=
int_c
(
realDomainSize
[
2
])
-
int_c
(
domainSize
[
2
]);
if
(
boundaryThicknessZ
<
0
)
{
WALBERLA_ABORT
(
"Something went wrong: the resulting domain size in z-direction is less than specified."
)
}
// read physics parameters from parameter file
const
auto
physicsParameters
=
walberlaEnv
.
config
()
->
getOneBlock
(
"PhysicsParameters"
);
const
real_t
bondNumber
=
physicsParameters
.
getParameter
<
real_t
>
(
"bondNumber"
);
const
real_t
weberNumber
=
physicsParameters
.
getParameter
<
real_t
>
(
"weberNumber"
);
const
real_t
ohnesorgeNumber
=
physicsParameters
.
getParameter
<
real_t
>
(
"ohnesorgeNumber"
);
const
real_t
relaxationRate
=
physicsParameters
.
getParameter
<
real_t
>
(
"relaxationRate"
);
const
real_t
impactAngleDegree
=
physicsParameters
.
getParameter
<
real_t
>
(
"impactAngleDegree"
);
const
CollisionModel_T
collisionModel
=
CollisionModel_T
(
relaxationRate
);
const
real_t
viscosity
=
collisionModel
.
viscosity
();
const
real_t
surfaceTension
=
real_c
(
std
::
pow
(
viscosity
/
ohnesorgeNumber
,
2
))
/
dropDiameter
;
const
real_t
gravitationalAccelerationZ
=
bondNumber
*
surfaceTension
/
(
dropDiameter
*
dropDiameter
);
const
real_t
impactVelocityMagnitude
=
real_c
(
std
::
pow
(
weberNumber
*
surfaceTension
/
dropDiameter
,
0.5
));
const
Vector3
<
real_t
>
force
(
real_c
(
0
),
real_c
(
0
),
-
gravitationalAccelerationZ
);
const
real_t
impactVelocityY
=
impactVelocityMagnitude
*
real_c
(
std
::
sin
(
impactAngleDegree
*
math
::
pi
/
real_c
(
180
)));
const
real_t
impactVelocityZ
=
impactVelocityMagnitude
*
real_c
(
std
::
cos
(
impactAngleDegree
*
math
::
pi
/
real_c
(
180
)));
const
Vector3
<
real_t
>
impactVelocity
(
real_c
(
0
),
impactVelocityY
,
-
impactVelocityZ
);
const
bool
enableWetting
=
physicsParameters
.
getParameter
<
bool
>
(
"enableWetting"
);
const
real_t
contactAngle
=
physicsParameters
.
getParameter
<
real_t
>
(
"contactAngle"
);
const
uint_t
timesteps
=
physicsParameters
.
getParameter
<
uint_t
>
(
"timesteps"
);
WALBERLA_LOG_DEVEL_VAR_ON_ROOT
(
relaxationRate
);
WALBERLA_LOG_DEVEL_VAR_ON_ROOT
(
surfaceTension
);
WALBERLA_LOG_DEVEL_VAR_ON_ROOT
(
force
);
WALBERLA_LOG_DEVEL_VAR_ON_ROOT
(
impactVelocity
);
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
);
// 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
bool
enableBubbleModel
=
modelParameters
.
getParameter
<
bool
>
(
"enableBubbleModel"
);
const
bool
enableBubbleSplits
=
modelParameters
.
getParameter
<
bool
>
(
"enableBubbleSplits"
);
const
real_t
cellConversionThreshold
=
modelParameters
.
getParameter
<
real_t
>
(
"cellConversionThreshold"
);
const
real_t
cellConversionForceThreshold
=
modelParameters
.
getParameter
<
real_t
>
(
"cellConversionForceThreshold"
);
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
(
enableBubbleModel
);
WALBERLA_LOG_DEVEL_VAR_ON_ROOT
(
enableBubbleSplits
);
WALBERLA_LOG_DEVEL_VAR_ON_ROOT
(
cellConversionThreshold
);
WALBERLA_LOG_DEVEL_VAR_ON_ROOT
(
cellConversionForceThreshold
);
// 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
,
impactVelocity
,
real_c
(
1
),
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
(
0.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
();
const
real_t
poolHeight
=
poolHeightFactor
*
dropDiameter
;
// initialize a pool of liquid at the bottom of the domain in z-direction
const
AABB
poolAABB
(
real_c
(
0
),
real_c
(
0
),
real_c
(
0
),
real_c
(
domainSize
[
0
]),
real_c
(
domainSize
[
1
]),
poolHeight
);
for
(
auto
blockIt
=
blockForest
->
begin
();
blockIt
!=
blockForest
->
end
();
++
blockIt
)
{
ScalarField_T
*
const
fillField
=
blockIt
->
getData
<
ScalarField_T
>
(
fillFieldID
);
PdfField_T
*
const
pdfField
=
blockIt
->
getData
<
PdfField_T
>
(
pdfFieldID
);
// determine the cells that are relevant for a block (still in global coordinates)
const
CellInterval
relevantCellBB
=
blockForest
->
getCellBBFromAABB
(
poolAABB
.
getIntersection
(
blockIt
->
getAABB
()));
// transform the global coordinates of relevant cells to block local coordinates
CellInterval
blockLocalCellBB
;
blockForest
->
transformGlobalToBlockLocalCellInterval
(
blockLocalCellBB
,
*
blockIt
,
relevantCellBB
);
WALBERLA_FOR_ALL_CELLS_IN_INTERVAL_XYZ
(
blockLocalCellBB
,
{
fillField
->
get
(
x
,
y
,
z
)
=
real_c
(
1
);
pdfField
->
setDensityAndVelocity
(
x
,
y
,
z
,
Vector3
<
real_t
>
(
real_c
(
0
)),
real_c
(
1
));
})
// WALBERLA_FOR_ALL_CELLS_IN_INTERVAL_XYZ
}
const
Vector3
<
real_t
>
dropCenter
=
dropCenterFactor
*
dropDiameter
;
const
geometry
::
Sphere
sphereDrop
(
dropCenter
,
dropDiameter
*
real_c
(
0.5
));
bubble_model
::
addBodyToFillLevelField
<
geometry
::
Sphere
>
(
*
blockForest
,
fillFieldID
,
sphereDrop
,
false
);
// initialize boundary conditions from config file
const
auto
boundaryParameters
=
walberlaEnv
.
config
()
->
getOneBlock
(
"BoundaryParameters"
);
freeSurfaceBoundaryHandling
->
initFromConfig
(
boundaryParameters
);
for
(
int
i
=
-
1
;
i
!=
boundaryThicknessZ
;
++
i
)
{
freeSurfaceBoundaryHandling
->
setNoSlipAtBorder
(
stencil
::
T
,
cell_idx_c
(
i
));
}
// IMPORTANT REMARK: this must be only called 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
<
CommunicationStencil_T
>
>
bubbleModelDerived
=
std
::
make_shared
<
bubble_model
::
BubbleModel
<
CommunicationStencil_T
>
>
(
blockForest
,
enableBubbleSplits
);
bubbleModelDerived
->
initFromFillLevelField
(
fillFieldID
);
bubbleModelDerived
->
setAtmosphere
(
Cell
(
domainSize
[
0
]
-
uint_c
(
1
),
domainSize
[
1
]
-
uint_c
(
1
),
domainSize
[
2
]
-
uint_c
(
1
)),
real_c
(
1
));
bubbleModel
=
std
::
static_pointer_cast
<
bubble_model
::
BubbleModelBase
>
(
bubbleModelDerived
);
}