/* 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.
*/
/* rayleighTaylor2d.cpp:
* Rayleigh-Taylor instability in 2D, 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 "olb2D.h"
#include "olb2D.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 ShanChenDynOmegaForcedD2Q9Descriptor
// Parameters for the simulation setup
const int nx = 400;
const int ny = 200;
const int maxIter = 20000;
// Stores geometry information in form of material numbers
void prepareGeometry( SuperGeometry2D& superGeometry ) {
OstreamManager clout( std::cout,"prepareGeometry" );
clout << "Prepare Geometry ..." << std::endl;
// Sets material number for fluid and boundary
superGeometry.rename( 0,1 );
Vector origin1( -.5, -.5 );
Vector origin2( -.5,ny/2. );
Vector origin3( -.5, ny-1.5 );
Vector extend1( nx+2, 1. );
Vector extend2( nx+2., ny/2.+2. );
IndicatorCuboid2D bottom( extend1, origin1 );
IndicatorCuboid2D upper( extend2, origin2 );
IndicatorCuboid2D 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( SuperLattice2D& sLatticeOne,
SuperLattice2D& sLatticeTwo,
Dynamics& bulkDynamics1,
Dynamics& bulkDynamics2,
Dynamics& bounceBackRho0,
Dynamics& bounceBackRho1,
SuperGeometry2D& 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( SuperLattice2D& sLatticeOne,
SuperLattice2D& sLatticeTwo,
T force, int iT, SuperGeometry2D& superGeometry ) {
if ( iT==0 ) {
AnalyticalConst2D noise( 4.e-2 );
std::vector v( 2,T() );
AnalyticalConst2D zeroV( v );
AnalyticalConst2D zero( 0. );
AnalyticalLinear2D one( 0.,-force*invCs2(),0.98+force*ny*invCs2() );
AnalyticalConst2D onePlus( 0.98+force*ny/2.*invCs2() );
AnalyticalRandom2D random;
AnalyticalIdentity2D randomOne( random*noise+one );
AnalyticalIdentity2D randomPlus( random*noise+onePlus );
std::vector F( 2,T() );
F[1] = -force;
AnalyticalConst2D 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( SuperLattice2D& sLatticeTwo,
SuperLattice2D& sLatticeOne, int iT,
SuperGeometry2D& superGeometry, Timer& timer ) {
OstreamManager clout( std::cout,"getResults" );
SuperVTMwriter2D vtmWriter( "rayleighTaylor2dsLatticeOne" );
const int vtkIter = 100;
const int statIter = 10;
if ( iT==0 ) {
// Writes the geometry, cuboid no. and rank no. as vti file for visualization
SuperLatticeGeometry2D geometry( sLatticeOne, superGeometry );
SuperLatticeCuboid2D cuboid( sLatticeOne );
SuperLatticeRank2D 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;
SuperLatticeVelocity2D velocity( sLatticeOne );
SuperLatticeDensity2D density( sLatticeOne );
vtmWriter.addFunctor( velocity );
vtmWriter.addFunctor( density );
vtmWriter.write( iT );
BlockReduction2D2D planeReduction( density, 600, BlockDataSyncMode::ReduceOnly );
// 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 = 30./( T )ny/( T )ny;
// === 2nd Step: Prepare Geometry ===
// Instantiation of a cuboidGeometry with weights
#ifdef PARALLEL_MODE_MPI
CuboidGeometry2D cGeometry( 0, 0, 1, nx, ny, singleton::mpi().getSize() );
#else
CuboidGeometry2D cGeometry( 0, 0, 1, nx, ny, 1 );
#endif
cGeometry.setPeriodicity( true, false );
HeuristicLoadBalancer loadBalancer( cGeometry );
SuperGeometry2D superGeometry( cGeometry, loadBalancer, 2 );
prepareGeometry( superGeometry );
// === 3rd Step: Prepare Lattice ===
SuperLattice2D sLatticeOne( superGeometry );
SuperLattice2D 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;
ShanChenForcedGenerator2D 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