/*
* Lattice Boltzmann grid refinement sample, written in C++,
* using the OpenLB library
*
* Copyright (C) 2019 Adrian Kummerländer
* 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.
*/
#include "olb2D.h"
#include "olb2D.hh"
using namespace olb;
typedef double T;
#define DESCRIPTOR descriptors::D2Q9<>
/// Setup geometry relative to cylinder diameter as defined by [SchaeferTurek96]
const T cylinderD = 0.1;
const int N = 5; // resolution of the cylinder
const T Re = 100.; // Reynolds number
const T tau = 0.51; // relaxation time
const T maxPhysT = 16.; // max. simulation time in s, SI unit
const Characteristics PhysCharacteristics(
cylinderD, // char. phys. length
1.0, // char. phys. velocity
0.1/Re, // phsy. kinematic viscosity
1.0); // char. phys. density
#include "../common/model.h"
void setupRefinement(Grid2D& coarseGrid,
Vector domainOrigin, Vector domainExtend,
Vector cylinderCenter)
{
const auto coarseDeltaX = coarseGrid.getConverter().getPhysDeltaX();
const Vector fineOutflowExtend {1*cylinderD, domainExtend[1]};
const Vector fineOutflowOrigin {domainExtend[0]-1*cylinderD, 0};
auto& fineOutflowGrid = coarseGrid.refine(fineOutflowOrigin, fineOutflowExtend, false);
SchaeferTurek::prepareGeometry(fineOutflowGrid, domainOrigin, domainExtend);
{
const Vector origin = fineOutflowGrid.getOrigin();
const Vector extend = fineOutflowGrid.getExtend();
const Vector extendY = {0,extend[1]};
coarseGrid.addFineCoupling(fineOutflowGrid, origin, extendY);
coarseGrid.addCoarseCoupling(fineOutflowGrid, origin + Vector {coarseDeltaX,0}, extendY);
IndicatorCuboid2D refined(extend, origin + Vector {2*coarseDeltaX,0});
coarseGrid.getSuperGeometry().reset(refined);
}
const Vector fineOutflowExtend2 {0.5*cylinderD, domainExtend[1]};
const Vector fineOutflowOrigin2 {domainExtend[0]-0.5*cylinderD, 0};
auto& fineOutflowGrid2 = fineOutflowGrid.refine(fineOutflowOrigin2, fineOutflowExtend2, false);
SchaeferTurek::prepareGeometry(fineOutflowGrid2, domainOrigin, domainExtend);
{
const Vector origin = fineOutflowGrid2.getOrigin();
const Vector extend = fineOutflowGrid2.getExtend();
const Vector extendY = {0,extend[1]};
fineOutflowGrid.addFineCoupling(fineOutflowGrid2, origin, extendY);
fineOutflowGrid.addCoarseCoupling(fineOutflowGrid2, origin + Vector {coarseDeltaX,0}, extendY);
IndicatorCuboid2D refined(extend, origin + Vector {coarseDeltaX,0});
fineOutflowGrid.getSuperGeometry().reset(refined);
}
const Vector fineExtend {10.5*cylinderD, domainExtend[1]-2*coarseDeltaX};
const Vector fineOrigin {0.5*cylinderD, coarseDeltaX};
auto& fineGrid = coarseGrid.refine(fineOrigin, fineExtend);
SchaeferTurek::prepareGeometry(fineGrid, domainOrigin, domainExtend);
const Vector fineExtend2 {5*cylinderD, fineGrid.getExtend()[1]-2*coarseDeltaX};
const Vector fineOrigin2 {1*cylinderD, (domainExtend[1]-fineExtend2[1])/2};
auto& fineGrid2 = fineGrid.refine(fineOrigin2, fineExtend2);
SchaeferTurek::prepareGeometry(fineGrid2, domainOrigin, domainExtend);
const Vector fineExtend3 {1.25*cylinderD, 1.25*cylinderD};
const Vector fineOrigin3 {cylinderCenter[0]-fineExtend3[0]/2, cylinderCenter[1]-fineExtend3[1]/2};
auto& fineGrid3 = fineGrid2.refine(fineOrigin3, fineExtend3);
SchaeferTurek::prepareGeometry(fineGrid3, domainOrigin, domainExtend);
}
int main(int argc, char* argv[])
{
olbInit(&argc, &argv);
singleton::directories().setOutputDir("./tmp/");
OstreamManager clout(std::cout,"main");
IndicatorCuboid2D coarseCuboid(SchaeferTurek::modelExtend, SchaeferTurek::modelOrigin);
Grid2D coarseGrid(
coarseCuboid,
RelaxationTime(tau),
N,
PhysCharacteristics);
const Vector domainOrigin = coarseGrid.getSuperGeometry().getStatistics().getMinPhysR(0);
const Vector domainExtend = coarseGrid.getSuperGeometry().getStatistics().getPhysExtend(0);
SchaeferTurek::prepareGeometry(coarseGrid, domainOrigin, domainExtend);
setupRefinement(coarseGrid, domainOrigin, domainExtend, SchaeferTurek::cylinderCenter);
coarseGrid.forEachGrid(SchaeferTurek::prepareLattice);
clout << "Total number of active cells: " << coarseGrid.getActiveVoxelN() << endl;
clout << "Starting simulation..." << endl;
const int statIter = coarseGrid.getConverter().getLatticeTime(0.5);
Timer timer(
coarseGrid.getConverter().getLatticeTime(maxPhysT),
coarseGrid.getSuperGeometry().getStatistics().getNvoxel());
timer.start();
Grid2D& cylinderGrid = coarseGrid.locate(SchaeferTurek::cylinderCenter);
for (int iT = 0; iT <= coarseGrid.getConverter().getLatticeTime(maxPhysT); ++iT) {
SchaeferTurek::setBoundaryValues(coarseGrid, iT);
coarseGrid.collideAndStream();
if (iT == 0 || iT%statIter == 0) {
timer.update(iT);
timer.printStep();
coarseGrid.forEachGrid("cylinder2d", [&](Grid2D& grid, const std::string& id) {
SchaeferTurek::getResults(grid, id, iT);
});
SchaeferTurek::takeMeasurements(cylinderGrid, iT);
}
}
timer.stop();
timer.printSummary();
}