/* Lattice Boltzmann sample, written in C++, using the OpenLB
* library
*
* Copyright (C) 2016 Vojtech Cvrcek, Mathias J. Krause
* 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.
*/
/* powerLaw2d.cpp:
* This example examines a steady flow of a non-newtonian fluid in a channel.
* At the inlet, a profile for non-newtonian fluid is imposed on the velocity,
* where as the outlet implements an outflow condition grad_x p = 0.
* The power law model is for n=1 and m=charNu in fact the classical poiseuille flow.
* One can validate the error with using functors in void error.
*
*
*/
#include "olb2D.h"
#include "olb2D.hh" // include full template code
#include
#include
#include
#include
using namespace olb;
using namespace olb::descriptors;
using namespace olb::graphics;
using namespace olb::util;
using namespace std;
typedef double T;
#define DESCRIPTOR DynOmegaD2Q9Descriptor
// Parameters for the simulation setup
int N = 40; // resolution of the model
T Re = 10.; // Reynolds number
T tau = 0.8;
T lx = 2.; // channel lenght
T ly = 1.; // channel width
T maxU = 1; // Max velocity
T Tmax = 20; // max. phys. time in s
T Tprint = 1; // Phys time at which the status of the system is print
// set the changes for n and m in powerLawBGKdynamics.h
T n = .2; // parameter in power law model (n=1 Newtonian fluid)
bool bcTypePeriodic = false; //true works only with one core
const T residuum = 1e-5; // residuum for the convergence check
void prepareGeometry( PowerLawUnitConverter const& converter,
SuperGeometry2D& superGeometry ) {
OstreamManager clout( std::cout,"prepareGeometry" );
clout << "Prepare Geometry ..." << std::endl;
Vector extend( lx, ly );
Vector origin;
superGeometry.rename( 0,2 );
superGeometry.rename( 2,1,1,1 );
// Set material number for inflow
extend[0] = 1.2*converter.getConversionFactorLength();
origin[0] = -converter.getConversionFactorLength();
IndicatorCuboid2D inflow( extend, origin );
if (bcTypePeriodic)
superGeometry.rename( 1,3,inflow );
else
superGeometry.rename( 2,3,1,inflow );
// Set material number for outflow
origin[0] = lx-.5*converter.getConversionFactorLength();
IndicatorCuboid2D outflow( extend, origin );
if (bcTypePeriodic)
superGeometry.rename( 1,4,outflow );
else
superGeometry.rename( 2,4,1,outflow );
// 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.getStatistics().print();
clout << "Prepare Geometry ... OK" << std::endl;
return;
}
// Set up the geometry of the simulation
void prepareLattice( SuperLattice2D& sLattice,
PowerLawUnitConverter const& converter,
Dynamics& bulkDynamics,
Dynamics& inDynamics,
Dynamics& outDynamics,
sOnLatticeBoundaryCondition2D& sBoundaryCondition,
SuperGeometry2D& superGeometry ) {
OstreamManager clout( std::cout,"prepareLattice" );
clout << "Prepare Lattice ..." << std::endl;
const T omega = converter.getLatticeRelaxationFrequency();
// Material=0 -->do nothing
sLattice.defineDynamics( superGeometry.getMaterialIndicator(0), &instances::getNoDynamics() );
// Material=1 -->bulk dynamics
sLattice.defineDynamics( superGeometry.getMaterialIndicator(1), &bulkDynamics );
// Material=2 -->bounce back
sLattice.defineDynamics( superGeometry.getMaterialIndicator(2), &instances::getBounceBack() );
// Material=3 -->bulk dynamics (inflow)
if (bcTypePeriodic)
sLattice.defineDynamics( superGeometry.getMaterialIndicator(3), &inDynamics );
else {
sLattice.defineDynamics( superGeometry.getMaterialIndicator(3), &bulkDynamics );
// Setting of the boundary conditions
sBoundaryCondition.addVelocityBoundary( superGeometry, 3, omega );
}
// Material=4 -->bulk dynamics (outflow)
if (bcTypePeriodic)
sLattice.defineDynamics( superGeometry.getMaterialIndicator(4), &outDynamics );
else {
sLattice.defineDynamics( superGeometry.getMaterialIndicator(4), &bulkDynamics );
// Setting of the boundary conditions
sBoundaryCondition.addPressureBoundary( superGeometry, 4, omega );
}
clout << "Prepare Lattice ... OK" << std::endl;
}
void setBoundaryValues( SuperLattice2D& sLattice,
PowerLawUnitConverter const& converter,
int iT, SuperGeometry2D& superGeometry ) {
OstreamManager clout( std::cout,"setBoundaryValues" );
// Set initial and steady boundary conditions
if ( iT==0 ) {
// Define the analytical solutions for pressure and velocity
T maxVelocity = converter.getCharLatticeVelocity();
T distance2Wall = converter.getConversionFactorLength()/2.;
T p0 = converter.getPhysConsistencyCoeff()*pow( converter.getCharPhysVelocity(),n )*pow( ( n + 1. )/n,n )*pow( 2./( ly-distance2Wall*2 ),n + 1. );
AnalyticalLinear2D rho( converter.getLatticeDensityFromPhysPressure( -p0 ) - 1., 0, converter.getLatticeDensityFromPhysPressure( p0*(lx + distance2Wall*2.)/2. ) );
PowerLaw2D u( superGeometry, 3, maxVelocity, distance2Wall, ( n + 1. )/n );
// Set the analytical solutions for pressure and velocity
AnalyticalConst2D omega0( converter.getLatticeRelaxationFrequency() );
sLattice.defineField( superGeometry, 1, omega0 );
sLattice.defineField( superGeometry, 3, omega0 );
sLattice.defineField( superGeometry, 4, omega0 );
// Set the analytical solutions for pressure and velocity
// Initialize all values of distribution functions to their local equilibrium
sLattice.defineRhoU( superGeometry, 1, rho, u );
sLattice.iniEquilibrium( superGeometry, 1, rho, u );
sLattice.iniEquilibrium( superGeometry, 3, rho, u );
sLattice.defineRhoU( superGeometry, 3, rho, u );
sLattice.iniEquilibrium( superGeometry, 4, rho, u );
sLattice.defineRhoU( superGeometry, 4, rho, u );
// Make the lattice ready for simulation
sLattice.initialize();
}
}
// Compute error norms
void error( SuperGeometry2D& superGeometry,
SuperLattice2D& sLattice,
PowerLawUnitConverter const& converter,
Dynamics& bulkDynamics ) {
OstreamManager clout( std::cout,"error" );
int input[1] = { };
T result[1] = { };
T distance2Wall = converter.getConversionFactorLength()/2.;
PowerLaw2D uSol( superGeometry,3,converter.getCharPhysVelocity(),distance2Wall,( n + 1. )/n );
SuperLatticePhysVelocity2D u( sLattice,converter );
T p0 = converter.getPhysConsistencyCoeff()*pow( converter.getCharPhysVelocity(),n )*pow( ( n + 1. )/n,n )*pow( 2./( ly-distance2Wall*2 ),n + 1. );
AnalyticalLinear2D pressureSol( -p0, 0, p0*(lx + distance2Wall*2.)/2. );
SuperLatticePhysPressure2D pressure( sLattice,converter );
auto indicatorF = superGeometry.getMaterialIndicator(1);
// velocity error
SuperAbsoluteErrorL1Norm2D absVelocityErrorNormL1(u, uSol, indicatorF);
absVelocityErrorNormL1(result, input);
clout << "velocity-L1-error(abs)=" << result[0];
SuperRelativeErrorL1Norm2D relVelocityErrorNormL1(u, uSol, indicatorF);
relVelocityErrorNormL1(result, input);
clout << "; velocity-L1-error(rel)=" << result[0] << std::endl;
SuperAbsoluteErrorL2Norm2D absVelocityErrorNormL2(u, uSol, indicatorF);
absVelocityErrorNormL2(result, input);
clout << "velocity-L2-error(abs)=" << result[0];
SuperRelativeErrorL2Norm2D relVelocityErrorNormL2(u, uSol, indicatorF);
relVelocityErrorNormL2(result, input);
clout << "; velocity-L2-error(rel)=" << result[0] << std::endl;
SuperAbsoluteErrorLinfNorm2D absVelocityErrorNormLinf(u, uSol, indicatorF);
absVelocityErrorNormLinf(result, input);
clout << "velocity-Linf-error(abs)=" << result[0];
SuperRelativeErrorLinfNorm2D relVelocityErrorNormLinf(u, uSol, indicatorF);
relVelocityErrorNormLinf(result, input);
clout << "; velocity-Linf-error(rel)=" << result[0] << std::endl;
// pressure error
SuperAbsoluteErrorL1Norm2D absPressureErrorNormL1(pressure, pressureSol, indicatorF);
absPressureErrorNormL1(result, input);
clout << "pressure-L1-error(abs)=" << result[0];
SuperRelativeErrorL1Norm2D relPressureErrorNormL1(pressure, pressureSol, indicatorF);
relPressureErrorNormL1(result, input);
clout << "; pressure-L1-error(rel)=" << result[0] << std::endl;
SuperAbsoluteErrorL2Norm2D absPressureErrorNormL2(pressure, pressureSol, indicatorF);
absPressureErrorNormL2(result, input);
clout << "pressure-L2-error(abs)=" << result[0];
SuperRelativeErrorL2Norm2D relPressureErrorNormL2(pressure, pressureSol, indicatorF);
relPressureErrorNormL2(result, input);
clout << "; pressure-L2-error(rel)=" << result[0] << std::endl;
SuperAbsoluteErrorLinfNorm2D absPressureErrorNormLinf(pressure, pressureSol, indicatorF);
absPressureErrorNormLinf(result, input);
clout << "pressure-Linf-error(abs)=" << result[0];
SuperRelativeErrorLinfNorm2D relPressureErrorNormLinf(pressure, pressureSol, indicatorF);
relPressureErrorNormLinf(result, input);
clout << "; pressure-Linf-error(rel)=" << result[0] << std::endl;
}
// Output to console and files
void getResults( SuperLattice2D& sLattice,
Dynamics& bulkDynamics,
PowerLawUnitConverter const& converter, int iT,
SuperGeometry2D& superGeometry, Timer& timer ) {
OstreamManager clout( std::cout,"getResults" );
SuperVTMwriter2D vtmWriter( "powerLaw2d" );
SuperLatticePhysVelocity2D velocity( sLattice, converter );
SuperLatticePhysPressure2D pressure( sLattice, converter );
vtmWriter.addFunctor( velocity );
vtmWriter.addFunctor( pressure );
if ( iT==0 ) {
SuperLatticeCuboid2D cuboid( sLattice );
SuperLatticeGeometry2D geometry( sLattice,superGeometry );
SuperLatticeRank2D rank( sLattice );
vtmWriter.write( geometry );
vtmWriter.write( cuboid );
vtmWriter.write( rank );
vtmWriter.createMasterFile();
}
if ( iT%converter.getLatticeTime( Tprint )==0 ) {
vtmWriter.write( iT );
SuperEuklidNorm2D normVel( velocity );
BlockReduction2D2D planeReduction( normVel, 600, BlockDataSyncMode::ReduceOnly );
// write output of velocity as JPEG
heatmap::write(planeReduction, iT);
}
// Writes output on the console
if ( iT%converter.getLatticeTime( Tprint )==0 ) {
timer.update( iT );
timer.printStep();
sLattice.getStatistics().print( iT,converter.getPhysTime( iT ) );
error( superGeometry, sLattice, converter, bulkDynamics );
}
return;
}
int main( int argc, char* argv[] ) {
// === 1st Step: Initialization ===
olbInit( &argc, &argv );
singleton::directories().setOutputDir( "./tmp/" );
OstreamManager clout( std::cout,"main" );
/*
if ( argc > 1 ) {
N = atoi( argv[1] );
}
if ( argc > 2 ) {
n = atof( argv[2] );
}
*/
singleton::directories().setOutputDir( "./tmp/" );
XMLreader config("input.xml");
config["geometry"]["N"].read(N);
config["geometry"]["lx"].read(lx);
config["geometry"]["ly"].read(ly);
config["dynamics"]["maxU"].read(maxU);
config["dynamics"]["Re"].read(Re);
config["dynamics"]["tau"].read(tau);
config["dynamics"]["n"].read(n);
config["time"]["Tmax"].read(Tmax);
config["time"]["Tprint"].read(Tprint);
/*
T physDeltaX = (ly/N);
T m = ly*maxU*pow( maxU/(2*ly),1-n )/Re;
T physViscosity = m*pow( maxU/(2*ly),n-1 );
T physDeltaT = (tau - 0.5) / DESCRIPTOR::invCs2 * pow(physDeltaX,2) / physViscosity;
PowerLawUnitConverter const converter(
(T) physDeltaX,
(T) physDeltaT,
(T) ly,
(T) maxU,
(T) m,
(T) n, // power-law index
(T) 1.0 // physDensity: physical density in __kg / m^3__
);
*/
PowerLawUnitConverterFrom_Resolution_RelaxationTime_Reynolds_PLindex const converter(
int {N}, // resolution: number of voxels per charPhysL
(T) tau, // latticeRelaxationTime: relaxation time, have to be greater than 0.5!
(T) ly, // charPhysLength: reference length of simulation geometry
(T) maxU, // charPhysVelocity: maximal/highest expected velocity during simulation in __m / s__
(T) Re, // Reynolds number
(T) n, // power-law index
(T) 1.0 // physDensity: physical density in __kg / m^3__
);
// Prints the converter log as console output
converter.print();
// Writes the converter log in a file
converter.write("powerLaw2d");
// === 2rd Step: Prepare Geometry ===
// Instantiation of a cuboidGeometry with weights
Vector extend( lx, ly );
Vector origin;
IndicatorCuboid2D cuboid( extend, origin );
#ifdef PARALLEL_MODE_MPI
CuboidGeometry2D cuboidGeometry( cuboid, converter.getConversionFactorLength(), singleton::mpi().getSize() );
#else
CuboidGeometry2D cuboidGeometry( cuboid, converter.getConversionFactorLength(), 7 );
#endif
// Periodic boundaries in x-direction
if (bcTypePeriodic)
cuboidGeometry.setPeriodicity( true, false );
//cuboidGeometry.printExtended();
HeuristicLoadBalancer loadBalancer( cuboidGeometry );
SuperGeometry2D superGeometry( cuboidGeometry, loadBalancer, 2 );
prepareGeometry( converter, superGeometry );
// === 3rd Step: Prepare Lattice ===
SuperLattice2D sLattice( superGeometry );
T distance2Wall = converter.getConversionFactorLength()/2.;
T p0 = converter.getPhysConsistencyCoeff()*pow( converter.getCharPhysVelocity(),n )*pow( ( n + 1. )/n,n )*pow( 2./( ly-distance2Wall*2 ),n + 1. );
clout << "Dimensionalized version-1." << std::endl;
PowerLawBGKdynamics bulkDynamics( converter.getLatticeRelaxationFrequency(), instances::getBulkMomenta(), converter.getLatticeConsistencyCoeff(), n );
PeriodicPressureDynamics> outDynamics( bulkDynamics,converter.getLatticeDensityFromPhysPressure( p0*(lx + distance2Wall*2.))-1,1,0);
PeriodicPressureDynamics> inDynamics( bulkDynamics,-converter.getLatticeDensityFromPhysPressure( p0*(lx + distance2Wall*2. ))+1,-1,0);
std::cout << -converter.getLatticeDensityFromPhysPressure( p0 )+1 << std::endl;
sOnLatticeBoundaryCondition2D sBoundaryCondition( sLattice );
createLocalBoundaryCondition2D > ( sBoundaryCondition );
prepareLattice( sLattice, converter, bulkDynamics, inDynamics, outDynamics, sBoundaryCondition, superGeometry );
// === 4th Step: Main Loop with Timer ===
Timer timer( converter.getLatticeTime( Tmax ), superGeometry.getStatistics().getNvoxel() );
util::ValueTracer converge( converter.getLatticeTime( 0.1*Tprint ), residuum );
timer.start();
for ( int iT=0; iT gplot( "centerVelocity" );
T Ly = converter.getLatticeLength( ly );
for ( int iY=0; iY<=Ly; ++iY ) {
T dx = 1. / T(converter.getResolution());
// const T maxVelocity = converter.getPhysVelocity( converter.getCharLatticeVelocity() );
T point[2]= {T(),T()};
point[0] = .9*lx;
point[1] = ( T )iY/Ly;
// const T radius = ly/2.;
std::vector axisPoint( 2,T() );
axisPoint[0] = lx/2.;
axisPoint[1] = ly/2.;
std::vector axisDirection( 2,T() );
axisDirection[0] = 1;
axisDirection[1] = 0;
T distance2Wall = converter.getConversionFactorLength()/2.;
PowerLaw2D uSol( superGeometry,3,converter.getCharPhysVelocity(),distance2Wall,( n + 1. )/n );
//Poiseuille2D uSol( axisPoint, axisDirection, maxVelocity, radius ); // <---
T analytical[2] = {T(),T()};
uSol( analytical,point );
SuperLatticePhysVelocity2D velocity( sLattice, converter );
AnalyticalFfromSuperF2D intpolateVelocity( velocity, true );
T numerical[2] = {T(),T()};
intpolateVelocity( numerical,point );
gplot.setData( iY*dx, {analytical[0],numerical[0]}, {"analytical","numerical"} );
}
// Create PNG file
gplot.writePNG();
}