/* Lattice Boltzmann sample, written in C++, using the OpenLB * library * * Copyright (C) 2014 Mathias J. Krause, Thomas Henn, * Cyril Masquelier * 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. */ /* venturi3d.cpp: * This example examines a steady flow in a venturi tube. At the * main inlet, a Poiseuille profile is imposed as Dirichlet velocity * boundary condition, whereas at the outlet and the minor inlet * a Dirichlet pressure condition is set by p=0 (i.e. rho=1). * * The example shows the usage of the Indicator functors to * build up a geometry and explains how to set boundary conditions * automatically. */ #include "olb3D.h" #ifndef OLB_PRECOMPILED // Unless precompiled version is used #include "olb3D.hh" // Include full template code #endif #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 D3Q19<> T maxPhysT = 200.0; // max. simulation time in s, SI unit SuperGeometry3D prepareGeometry( ) { OstreamManager clout( std::cout,"prepareGeometry" ); clout << "Prepare Geometry ..." << std::endl; std::string fName("venturi3d.xml"); XMLreader config(fName); std::shared_ptr > inflow = createIndicatorCylinder3D(config["Geometry"]["Inflow"]["IndicatorCylinder3D"], false); std::shared_ptr > outflow0 = createIndicatorCylinder3D(config["Geometry"]["Outflow0"]["IndicatorCylinder3D"], false); std::shared_ptr > outflow1 = createIndicatorCylinder3D(config["Geometry"]["Outflow1"]["IndicatorCylinder3D"], false); std::shared_ptr > venturi = createIndicatorF3D(config["Geometry"]["Venturi"], false); // Build CoboidGeometry from IndicatorF (weights are set, remove and shrink is done) int N = config["Application"]["Discretization"]["Resolution"].get(); CuboidGeometry3D* cuboidGeometry = new CuboidGeometry3D( *venturi, 1./N, 20*singleton::mpi().getSize() ); // Build LoadBalancer from CuboidGeometry (weights are respected) HeuristicLoadBalancer* loadBalancer = new HeuristicLoadBalancer( *cuboidGeometry ); // Default instantiation of superGeometry SuperGeometry3D superGeometry( *cuboidGeometry, *loadBalancer, 2 ); // Set boundary voxels by rename material numbers superGeometry.rename( 0,2, venturi ); superGeometry.rename( 2,1,1,1,1 ); superGeometry.rename( 2,3,1, inflow ); superGeometry.rename( 2,4,1, outflow0 ); superGeometry.rename( 2,5,1, outflow1 ); // 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(); superGeometry.communicate(); clout << "Prepare Geometry ... OK" << std::endl; return superGeometry; } void prepareLattice( SuperLattice3D& sLattice, UnitConverter const& converter, Dynamics& bulkDynamics, sOnLatticeBoundaryCondition3D& bc, sOffLatticeBoundaryCondition3D& offBc, SuperGeometry3D& superGeometry ) { OstreamManager clout( std::cout,"prepareLattice" ); clout << "Prepare Lattice ..." << std::endl; const T omega = converter.getLatticeRelaxationFrequency(); // Material=0 -->do nothing sLattice.defineDynamics( superGeometry, 0, &instances::getNoDynamics() ); // Material=1 -->bulk dynamics sLattice.defineDynamics( superGeometry, 1, &bulkDynamics ); // Material=2 -->bounce back sLattice.defineDynamics( superGeometry, 2, &instances::getBounceBack() ); // Material=3 -->bulk dynamics (inflow) sLattice.defineDynamics( superGeometry, 3, &bulkDynamics ); // Material=4 -->bulk dynamics (outflow) sLattice.defineDynamics( superGeometry, 4, &bulkDynamics ); // Material=5 -->bulk dynamics (2nd outflow) sLattice.defineDynamics( superGeometry, 5, &bulkDynamics ); // Setting of the boundary conditions bc.addVelocityBoundary( superGeometry, 3, omega ); bc.addPressureBoundary( superGeometry, 4, omega ); bc.addPressureBoundary( superGeometry, 5, omega ); clout << "Prepare Lattice ... OK" << std::endl; } // Generates a slowly increasing sinuidal inflow for the first iTMax timesteps void setBoundaryValues( SuperLattice3D& sLattice, UnitConverter const& converter, int iT, SuperGeometry3D& superGeometry ) { OstreamManager clout( std::cout,"setBoundaryValues" ); // No of time steps for smooth start-up int iTmaxStart = converter.getLatticeTime( maxPhysT*0.8 ); int iTperiod = 50; if ( iT==0 ) { // Make the lattice ready for simulation sLattice.initialize(); } else if ( iT%iTperiod==0 && iT<= iTmaxStart ) { //clout << "Set Boundary Values ..." << std::endl; //SinusStartScale startScale(iTmaxStart, (T) 1); PolynomialStartScale startScale( iTmaxStart, T( 1 ) ); int iTvec[1]= {iT}; T frac = T(); startScale( &frac,iTvec ); // Creates and sets the Poiseuille inflow profile using functors CirclePoiseuille3D poiseuilleU( superGeometry, 3, frac*converter.getCharLatticeVelocity(), converter.getConversionFactorLength() ); sLattice.defineU( superGeometry, 3, poiseuilleU ); //clout << "step=" << iT << "; scalingFactor=" << frac << std::endl; } //clout << "Set Boundary Values ... ok" << std::endl; } void getResults( SuperLattice3D& sLattice, UnitConverter& converter, int iT, SuperGeometry3D& superGeometry, Timer& timer ) { OstreamManager clout( std::cout,"getResults" ); SuperVTMwriter3D vtmWriter( "venturi3d" ); if ( iT==0 ) { // Writes the geometry, cuboid no. and rank no. as vti file for visualization SuperLatticeGeometry3D geometry( sLattice, superGeometry ); SuperLatticeCuboid3D cuboid( sLattice ); SuperLatticeRank3D rank( sLattice ); vtmWriter.write( geometry ); vtmWriter.write( cuboid ); vtmWriter.write( rank ); vtmWriter.createMasterFile(); } // Writes the vtm files if ( iT%converter.getLatticeTime( 1. )==0 ) { // Create the data-reading functors... SuperLatticePhysVelocity3D velocity( sLattice, converter ); SuperLatticePhysPressure3D pressure( sLattice, converter ); vtmWriter.addFunctor( velocity ); vtmWriter.addFunctor( pressure ); vtmWriter.write( iT ); SuperEuklidNorm3D normVel( velocity ); BlockReduction3D2D planeReduction( normVel, {0, 0, 1} ); // write output as JPEG heatmap::write(planeReduction, iT); // write output as JPEG and changing properties heatmap::plotParam jpeg_Param; jpeg_Param.name = "outflow"; jpeg_Param.contourlevel = 5; jpeg_Param.colour = "blackbody"; jpeg_Param.zoomOrigin = {0.6, 0.3}; jpeg_Param.zoomExtend = {0.4, 0.7}; heatmap::write(planeReduction, iT, jpeg_Param); } // Writes output on the console if ( iT%converter.getLatticeTime( 1. )==0 ) { timer.update( iT ); timer.printStep(); sLattice.getStatistics().print( iT, converter.getPhysTime( iT ) ); } } int main( int argc, char* argv[] ) { // === 1st Step: Initialization === olbInit( &argc, &argv ); singleton::directories().setOutputDir( "./tmp/" ); OstreamManager clout( std::cout,"main" ); // display messages from every single mpi process // clout.setMultiOutput(true); std::string fName("venturi3d.xml"); XMLreader config(fName); UnitConverter* converter = createUnitConverter(config); // Prints the converter log as console output converter->print(); // Writes the converter log in a file converter->write("venturi3d"); // === 2nd Step: Prepare Geometry === SuperGeometry3D superGeometry( prepareGeometry() ); // === 3rd Step: Prepare Lattice === SuperLattice3D sLattice( superGeometry ); RLBdynamics bulkDynamics( converter->getLatticeRelaxationFrequency(), instances::getBulkMomenta() ); sOnLatticeBoundaryCondition3D sBoundaryCondition( sLattice ); createInterpBoundaryCondition3D ( sBoundaryCondition ); sOffLatticeBoundaryCondition3D sOffBoundaryCondition( sLattice ); createBouzidiBoundaryCondition3D ( sOffBoundaryCondition ); prepareLattice( sLattice, *converter, bulkDynamics, sBoundaryCondition, sOffBoundaryCondition, superGeometry ); Timer timer( converter->getLatticeTime( maxPhysT ), superGeometry.getStatistics().getNvoxel() ); timer.start(); getResults( sLattice, *converter, 0, superGeometry, timer ); // === 4th Step: Main Loop with Timer === for ( int iT = 0; iT <= converter->getLatticeTime( maxPhysT ); ++iT ) { // === 5th Step: Definition of Initial and Boundary Conditions === setBoundaryValues( sLattice, *converter, iT, superGeometry ); // === 6th Step: Collide and Stream Execution === sLattice.collideAndStream(); // === 7th Step: Computation and Output of the Results === getResults( sLattice, *converter, iT, superGeometry, timer ); } timer.stop(); timer.printSummary(); }