/* Lattice Boltzmann sample, written in C++, using the OpenLB
* library
*
* Copyright (C) 2008 Orestis Malaspinas, Andrea Parmigiani
* E-mail contact: info@openlb.net
* The most recent release of OpenLB can be downloaded at
*
*
* This program 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 2
* of the License, or (at your option) any later version.
*
* This program 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 this program; if not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
/* rayleighTaylor3d.cpp:
* Rayleigh-Taylor instability in 3D, generated by a heavy
* fluid penetrating a light one. The multi-component fluid model
* by X. Shan and H. Chen is used. This example shows the usage
* of multicomponent flow and periodic boundaries.
*/
#include "olb3D.h"
#include "olb3D.hh" // use only generic version!
#include
#include
using namespace olb;
using namespace olb::descriptors;
using namespace olb::graphics;
using namespace std;
typedef double T;
#define DESCRIPTOR ShanChenDynOmegaForcedD3Q19Descriptor
// Parameters for the simulation setup
const int nx = 70;
const int ny = 35;
const int nz = 70;
const int maxIter = 4000;
// Stores geometry information in form of material numbers
void prepareGeometry( SuperGeometry3D& superGeometry ) {
OstreamManager clout( std::cout,"prepareGeometry" );
clout << "Prepare Geometry ..." << std::endl;
// Sets material number for fluid and boundary
superGeometry.rename( 0,1 );
Vector origin1( -2. );
Vector origin2( -2., ny/2., -2. );
Vector origin3( -2., ny-1., -2. );
Vector extend1( nx+3., 2., nz+3. );
Vector extend2( nx+3., ny/2+2., nz+3. );
IndicatorCuboid3D bottom( extend1, origin1 );
IndicatorCuboid3D upper( extend2, origin2 );
IndicatorCuboid3D top( extend1, origin3 );
superGeometry.rename( 1,2,upper );
superGeometry.rename( 1,3,bottom );
superGeometry.rename( 2,4,top );
// Removes all not needed boundary voxels outside the surface
//superGeometry.clean();
// Removes all not needed boundary voxels inside the surface
superGeometry.innerClean();
superGeometry.checkForErrors();
superGeometry.print();
clout << "Prepare Geometry ... OK" << std::endl;
}
void prepareLattice( SuperLattice3D& sLatticeOne,
SuperLattice3D& sLatticeTwo,
Dynamics& bulkDynamics1,
Dynamics& bulkDynamics2,
Dynamics& bounceBackRho0,
Dynamics& bounceBackRho1,
SuperGeometry3D& superGeometry ) {
OstreamManager clout( std::cout,"prepareLattice" );
clout << "Prepare Lattice ..." << std::endl;
// The setup is: periodicity along horizontal direction, bounce-back on top
// and bottom. The upper half is initially filled with fluid 1 + random noise,
// and the lower half with fluid 2. Only fluid 1 experiences a forces,
// directed downwards.
// define lattice Dynamics
sLatticeOne.defineDynamics( superGeometry, 0, &instances::getNoDynamics() );
sLatticeTwo.defineDynamics( superGeometry, 0, &instances::getNoDynamics() );
sLatticeOne.defineDynamics( superGeometry, 1, &bulkDynamics1 );
sLatticeOne.defineDynamics( superGeometry, 2, &bulkDynamics1 );
sLatticeOne.defineDynamics( superGeometry, 3, &bulkDynamics1 );
sLatticeOne.defineDynamics( superGeometry, 4, &bulkDynamics1 );
sLatticeTwo.defineDynamics( superGeometry, 1, &bulkDynamics2 );
sLatticeTwo.defineDynamics( superGeometry, 2, &bulkDynamics2 );
sLatticeTwo.defineDynamics( superGeometry, 3, &bulkDynamics2 );
sLatticeTwo.defineDynamics( superGeometry, 4, &bulkDynamics2 );
sLatticeOne.defineDynamics( superGeometry, 3, &bounceBackRho0 );
sLatticeTwo.defineDynamics( superGeometry, 3, &bounceBackRho1 );
sLatticeOne.defineDynamics( superGeometry, 4, &bounceBackRho1 );
sLatticeTwo.defineDynamics( superGeometry, 4, &bounceBackRho0 );
clout << "Prepare Lattice ... OK" << std::endl;
}
void setBoundaryValues( SuperLattice3D& sLatticeOne,
SuperLattice3D& sLatticeTwo,
T force, int iT, SuperGeometry3D& superGeometry ) {
if ( iT==0 ) {
AnalyticalConst3D noise( 4.e-2 );
std::vector v( 3,T() );
AnalyticalConst3D zeroV( v );
AnalyticalConst3D zero( 0. );
AnalyticalLinear3D one( 0.,-force*descriptors::invCs2(),0.,0.98+force*ny*descriptors::invCs2() );
AnalyticalConst3D onePlus( 0.98+force*ny/2.*descriptors::invCs2() );
AnalyticalRandom3D random;
AnalyticalIdentity3D randomOne( random*noise+one );
AnalyticalIdentity3D randomPlus( random*noise+onePlus );
std::vector F( 3,T() );
F[1] = -force;
AnalyticalConst3D f( F );
// for each material set the defineRhou and the Equilibrium
sLatticeOne.defineRhoU( superGeometry, 1, zero, zeroV );
sLatticeOne.iniEquilibrium( superGeometry, 1, zero, zeroV );
sLatticeOne.defineField( superGeometry, 1, f );
sLatticeTwo.defineRhoU( superGeometry, 1, randomPlus, zeroV );
sLatticeTwo.iniEquilibrium( superGeometry, 1, randomPlus, zeroV );
sLatticeOne.defineRhoU( superGeometry, 2, randomOne, zeroV );
sLatticeOne.iniEquilibrium( superGeometry, 2, randomOne, zeroV );
sLatticeOne.defineField( superGeometry, 2, f );
sLatticeTwo.defineRhoU( superGeometry, 2, zero, zeroV );
sLatticeTwo.iniEquilibrium( superGeometry, 2, zero, zeroV );
/*sLatticeOne.defineRhoU(superGeometry, 3, zero, zeroV);
sLatticeOne.iniEquilibrium(superGeometry, 3, zero, zeroV);
sLatticeOne.defineField(superGeometry, 3, f);
sLatticeTwo.defineRhoU(superGeometry, 3, one, zeroV);
sLatticeTwo.iniEquilibrium(superGeometry, 3, one, zeroV);
sLatticeOne.defineRhoU(superGeometry, 4, one, zeroV);
sLatticeOne.iniEquilibrium(superGeometry, 4, one, zeroV);
sLatticeOne.defineField(superGeometry, 4, f);
sLatticeTwo.defineRhoU(superGeometry, 4, zero, zeroV);
sLatticeTwo.iniEquilibrium(superGeometry, 4, zero, zeroV);*/
// Make the lattice ready for simulation
sLatticeOne.initialize();
sLatticeTwo.initialize();
}
}
void getResults( SuperLattice3D& sLatticeTwo,
SuperLattice3D& sLatticeOne, int iT,
SuperGeometry3D& superGeometry, Timer& timer ) {
OstreamManager clout( std::cout,"getResults" );
SuperVTMwriter3D vtmWriter( "rayleighTaylor3dsLatticeOne" );
const int vtkIter = 50;
const int statIter = 10;
if ( iT==0 ) {
// Writes the geometry, cuboid no. and rank no. as vti file for visualization
SuperLatticeGeometry3D geometry( sLatticeOne, superGeometry );
SuperLatticeCuboid3D cuboid( sLatticeOne );
SuperLatticeRank3D rank( sLatticeOne );
vtmWriter.write( geometry );
vtmWriter.write( cuboid );
vtmWriter.write( rank );
vtmWriter.createMasterFile();
}
// Get statistics
if ( iT%statIter==0 && iT > 0 ) {
// Timer console output
timer.update( iT );
timer.printStep();
clout << "averageRhoFluidOne=" << sLatticeOne.getStatistics().getAverageRho();
clout << "; averageRhoFluidTwo=" << sLatticeTwo.getStatistics().getAverageRho() << std::endl;
}
// Writes the VTK files
if ( iT%vtkIter==0 ) {
clout << "Writing VTK ..." << std::endl;
SuperLatticeVelocity3D velocity( sLatticeOne );
SuperLatticeDensity3D density( sLatticeOne );
vtmWriter.addFunctor( velocity );
vtmWriter.addFunctor( density );
vtmWriter.write( iT );
BlockReduction3D2D planeReduction( density, {0, 0, 1} );
// write output as JPEG
heatmap::write(planeReduction, iT);
clout << "Writing VTK ... OK" << std::endl;
}
}
int main( int argc, char *argv[] ) {
// === 1st Step: Initialization ===
olbInit( &argc, &argv );
singleton::directories().setOutputDir( "./tmp/" );
OstreamManager clout( std::cout,"main" );
const T omega1 = 1.0;
const T omega2 = 1.0;
const T G = 3.;
T force = 7./( T )ny/( T )ny;
// === 2nd Step: Prepare Geometry ===
// Instantiation of a cuboidGeometry with weights
#ifdef PARALLEL_MODE_MPI
CuboidGeometry3D cGeometry( 0, 0, 0, 1, nx, ny, nz, singleton::mpi().getSize() );
#else
CuboidGeometry3D cGeometry( 0, 0, 0, 1, nx, ny, nz, 1 );
#endif
cGeometry.setPeriodicity( true, false, true );
HeuristicLoadBalancer loadBalancer( cGeometry );
SuperGeometry3D superGeometry( cGeometry,loadBalancer,2 );
prepareGeometry( superGeometry );
// === 3rd Step: Prepare Lattice ===
SuperLattice3D sLatticeOne( superGeometry );
SuperLattice3D sLatticeTwo( superGeometry );
ForcedBGKdynamics bulkDynamics1 (
omega1, instances::getExternalVelocityMomenta() );
ForcedBGKdynamics bulkDynamics2 (
omega2, instances::getExternalVelocityMomenta() );
// A bounce-back node with fictitious density 1,
// which is experienced by the partner fluid
BounceBack bounceBackRho1( 1. );
// A bounce-back node with fictitious density 0,
// which is experienced by the partner fluid
BounceBack bounceBackRho0( 0. );
std::vector rho0;
rho0.push_back( 1 );
rho0.push_back( 1 );
PsiEqualsRho interactionPotential;
ShanChenForcedGenerator3D coupling( G,rho0,interactionPotential );
sLatticeOne.addLatticeCoupling(coupling, sLatticeTwo );
prepareLattice( sLatticeOne, sLatticeTwo, bulkDynamics1, bulkDynamics2,
bounceBackRho0, bounceBackRho1, superGeometry );
// === 4th Step: Main Loop with Timer ===
int iT = 0;
clout << "starting simulation..." << endl;
Timer timer( maxIter, superGeometry.getStatistics().getNvoxel() );
timer.start();
for ( iT=0; iT