Skip to content
Snippets Groups Projects
SuViscoelasticityTest.cpp 12.7 KiB
Newer Older
Cameron Stewart's avatar
Cameron Stewart committed
//======================================================================================================================
//
//  This file is part of waLBerla. waLBerla 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 3 of 
//  the License, or (at your option) any later version.
//  
//  waLBerla 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 waLBerla (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>.
//
//! \file SuViscoelasticityTest.cpp
//! \ingroup lbm
//! \author Cameron Stewart <cstewart@icp.uni-stuttgart.de>
Cameron Stewart's avatar
Cameron Stewart committed
//! \brief D2Q9 Poiseuille flow simulation with Oldroyd-B viscoelasticity - Checks against analytical formula and
//!        reference data
Cameron Stewart's avatar
Cameron Stewart committed
//
//
//======================================================================================================================

#include "blockforest/Initialization.h"
#include "blockforest/communication/UniformBufferedScheme.h"

#include "boundary/BoundaryHandling.h"

#include "core/Environment.h"
#include "core/SharedFunctor.h"

#include "domain_decomposition/SharedSweep.h"

#include "field/communication/PackInfo.h"

#include "lbm/boundary/all.h"
Cameron Stewart's avatar
Cameron Stewart committed
#include "lbm/field/AddToStorage.h"
#include "lbm/lattice_model/D2Q9.h"
Cameron Stewart's avatar
Cameron Stewart committed
#include "lbm/lattice_model/ForceModel.h"
#include "lbm/SuViscoelasticity.h"
#include "lbm/sweeps/CellwiseSweep.h"

#include "timeloop/SweepTimeloop.h"

using namespace walberla;

//////////////
// TYPEDEFS //
//////////////

typedef GhostLayerField< Vector3<real_t>, 1> ForceField_T;
Cameron Stewart's avatar
Cameron Stewart committed

typedef lbm::collision_model::TRT CollisionModel_T;
typedef lbm::force_model::GuoField< ForceField_T > ForceModel_T;
typedef lbm::D2Q9< CollisionModel_T, false, ForceModel_T >  LatticeModel_T;
typedef LatticeModel_T::Stencil    Stencil_T;

Cameron Stewart's avatar
Cameron Stewart committed
typedef GhostLayerField<Matrix3<real_t>, 1> StressField_T;
typedef GhostLayerField< Vector3<real_t>, 1> VelocityField_T;
typedef lbm::PdfField< LatticeModel_T >  PdfField_T;
typedef walberla::uint8_t flag_t;
typedef FlagField< flag_t > FlagField_T;
Cameron Stewart's avatar
Cameron Stewart committed
const uint_t FieldGhostLayers = 2;
Cameron Stewart's avatar
Cameron Stewart committed

Cameron Stewart's avatar
Cameron Stewart committed
typedef lbm::NoSlip< LatticeModel_T, flag_t> NoSlip_T;
typedef boost::tuples::tuple< NoSlip_T > BoundaryConditions_T;
typedef BoundaryHandling< FlagField_T, Stencil_T, BoundaryConditions_T> BoundaryHandling_T;
Cameron Stewart's avatar
Cameron Stewart committed

Cameron Stewart's avatar
Cameron Stewart committed
///////////
// FLAGS //
///////////
Cameron Stewart's avatar
Cameron Stewart committed

Cameron Stewart's avatar
Cameron Stewart committed
const FlagUID Fluid_Flag( "fluid" );
const FlagUID NoSlip_Flag( "no slip" );
Cameron Stewart's avatar
Cameron Stewart committed

Cameron Stewart's avatar
Cameron Stewart committed
/////////////////////////////////////
// BOUNDARY HANDLING CUSTOMIZATION //
/////////////////////////////////////
Cameron Stewart's avatar
Cameron Stewart committed

Cameron Stewart's avatar
Cameron Stewart committed
class MyBoundaryHandling
{
public:
Cameron Stewart's avatar
Cameron Stewart committed

Cameron Stewart's avatar
Cameron Stewart committed
   MyBoundaryHandling( const BlockDataID & flagFieldID, const BlockDataID & pdfFieldID ) : flagFieldID_( flagFieldID ), pdfFieldID_( pdfFieldID ) {}
Cameron Stewart's avatar
Cameron Stewart committed

Cameron Stewart's avatar
Cameron Stewart committed
   BoundaryHandling_T * operator()( IBlock* const block, const StructuredBlockStorage* const storage ) const;
Cameron Stewart's avatar
Cameron Stewart committed

Cameron Stewart's avatar
Cameron Stewart committed
private:
Cameron Stewart's avatar
Cameron Stewart committed

Cameron Stewart's avatar
Cameron Stewart committed
   const BlockDataID flagFieldID_;
   const BlockDataID pdfFieldID_;
Cameron Stewart's avatar
Cameron Stewart committed

Cameron Stewart's avatar
Cameron Stewart committed
}; // class MyBoundaryHandling
Cameron Stewart's avatar
Cameron Stewart committed
BoundaryHandling_T * MyBoundaryHandling::operator()( IBlock * const block, const StructuredBlockStorage * const storage ) const
{
   WALBERLA_ASSERT_NOT_NULLPTR( block );
   WALBERLA_ASSERT_NOT_NULLPTR( storage );
Cameron Stewart's avatar
Cameron Stewart committed

Cameron Stewart's avatar
Cameron Stewart committed
   FlagField_T * flagField       = block->getData< FlagField_T >( flagFieldID_ );
   PdfField_T *  pdfField        = block->getData< PdfField_T > ( pdfFieldID_ );
Cameron Stewart's avatar
Cameron Stewart committed

Cameron Stewart's avatar
Cameron Stewart committed
   const auto fluid = flagField->flagExists( Fluid_Flag ) ? flagField->getFlag( Fluid_Flag ) : flagField->registerFlag( Fluid_Flag );
Cameron Stewart's avatar
Cameron Stewart committed

Cameron Stewart's avatar
Cameron Stewart committed
   BoundaryHandling_T * handling = new BoundaryHandling_T( "moving obstacle boundary handling", flagField, fluid,
                                                           boost::tuples::make_tuple(    NoSlip_T( "NoSlip", NoSlip_Flag, pdfField ) ) );
Cameron Stewart's avatar
Cameron Stewart committed

Cameron Stewart's avatar
Cameron Stewart committed
   const auto noSlip = flagField->getFlag(NoSlip_Flag);
Cameron Stewart's avatar
Cameron Stewart committed

Cameron Stewart's avatar
Cameron Stewart committed
   CellInterval domainBB = storage->getDomainCellBB();
   domainBB.xMin() -= cell_idx_c( 1 );
   domainBB.xMax() += cell_idx_c( 1 );
Cameron Stewart's avatar
Cameron Stewart committed

Cameron Stewart's avatar
Cameron Stewart committed
   domainBB.yMin() -= cell_idx_c( 1 );
   domainBB.yMax() += cell_idx_c( 1 );
Cameron Stewart's avatar
Cameron Stewart committed

Cameron Stewart's avatar
Cameron Stewart committed
   // SOUTH
   CellInterval south( domainBB.xMin(), domainBB.yMin(), domainBB.zMin(), domainBB.xMax(), domainBB.yMin(), domainBB.zMax() );
   storage->transformGlobalToBlockLocalCellInterval( south, *block );
   handling->forceBoundary( noSlip, south );

   // NORTH
   CellInterval north( domainBB.xMin(), domainBB.yMax(), domainBB.zMin(), domainBB.xMax(), domainBB.yMax(), domainBB.zMax() );
   storage->transformGlobalToBlockLocalCellInterval( north, *block );
   handling->forceBoundary( noSlip, north );
Cameron Stewart's avatar
Cameron Stewart committed

Cameron Stewart's avatar
Cameron Stewart committed
   handling->fillWithDomain( FieldGhostLayers );

   return handling;
}
Cameron Stewart's avatar
Cameron Stewart committed

Cameron Stewart's avatar
Cameron Stewart committed
//////////////////////
// Poiseuille Force //
//////////////////////
Cameron Stewart's avatar
Cameron Stewart committed

template < typename BoundaryHandling_T >
class ConstantForce
{
public:

   ConstantForce( BlockDataID forceFieldId, BlockDataID boundaryHandlingId, real_t force)
         : forceFieldId_( forceFieldId ), boundaryHandlingId_(boundaryHandlingId), force_(force)
   {}

   void operator()( IBlock * block )
   {
      ForceField_T *forceField = block->getData< ForceField_T >(forceFieldId_);
      BoundaryHandling_T *boundaryHandling = block->getData< BoundaryHandling_T >( boundaryHandlingId_ );

      WALBERLA_FOR_ALL_CELLS_XYZ(forceField,
                                 {
                                    Cell cell(x,y,z);
                                    if (boundaryHandling->isDomain(cell)) {
                                       forceField->get(cell)[0] += force_;
                                    }
                                 })
   }

private:

   BlockDataID forceFieldId_, boundaryHandlingId_;
   real_t force_;
};

Cameron Stewart's avatar
Cameron Stewart committed
////////////////////
// Take Test Data //
////////////////////

class TestData
{
public:
   TestData(Timeloop & timeloop, shared_ptr< StructuredBlockForest > blocks, BlockDataID pdfFieldId, BlockDataID stressFieldId, uint_t timesteps, uint_t blockSize, real_t L, real_t H, real_t uExpected)
            : timeloop_(timeloop), blocks_(blocks), pdfFieldId_(pdfFieldId), stressFieldId_(stressFieldId), timesteps_(timesteps), blockSize_(blockSize), t0_(0), t1_(0), L_(L), H_(H), uMax_(0.0), uPrev_(0.0),
            uExpected_(uExpected), uSteady_(0.0) {}

   void operator()() {
      for (auto blockIt = blocks_->begin(); blockIt != blocks_->end(); ++blockIt) {
         PdfField_T *pdf = blockIt.get()->getData<PdfField_T>(pdfFieldId_);

         if (blockIt.get()->getAABB().contains(float_c(L_/2.0), float_c(H_/2.0), 0)) {
Cameron Stewart's avatar
Cameron Stewart committed
            uCurr_ = pdf->getVelocity(int32_c(blockSize_/2), int32_c(blockSize_/2), 0)[0]/uExpected_;
            tCurr_ = timeloop_.getCurrentTimeStep();
            if (tCurr_ == timesteps_ - 1){
               uSteady_ = uCurr_;
            }
            if (maxFlag_ == 0) {
               if (uCurr_ >= uPrev_) {
                  uMax_ = uCurr_;
               } else {
                  t0_ = tCurr_;
                  maxFlag_ = 1;
               }
               uPrev_ = uCurr_;
            }
            else if (maxFlag_ == 1) {
               if ((uCurr_ - 1.0) <= (uMax_ - 1.0) / std::exp(1)) {
                  t1_ = tCurr_ - t0_;
                  maxFlag_ = 2;
               }
            }
         }
      }
   }

   real_t getUSteady(){
      return uSteady_;
   }

   real_t getUMax(){
      return uMax_;
   }

   real_t getT0(){
      return real_c(t0_);
   }

   real_t getT1(){
      return real_c(t1_);
   }

private:
   Timeloop & timeloop_;
   shared_ptr< StructuredBlockForest > blocks_;
   BlockDataID pdfFieldId_, stressFieldId_;
   uint_t timesteps_, blockSize_, t0_, t1_, tCurr_;
   uint_t maxFlag_ = 0;
   real_t L_, H_, uMax_, uPrev_, uCurr_, uExpected_, uSteady_;
};


//////////
// Main //
//////////

Cameron Stewart's avatar
Cameron Stewart committed
int main(int argc, char ** argv ){

   walberla::Environment env( argc, argv );

Cameron Stewart's avatar
Cameron Stewart committed
   // read parameter
Cameron Stewart's avatar
Cameron Stewart committed
   shared_ptr<StructuredBlockForest> blocks = blockforest::createUniformBlockGridFromConfig( env.config() );
   auto parameters = env.config()->getOneBlock( "Parameters" );

   // extract some constants from the parameters
Cameron Stewart's avatar
Cameron Stewart committed
   const real_t          eta_s           = parameters.getParameter< real_t > ("eta_s");
   const real_t          force           = parameters.getParameter< real_t > ("force");
   const real_t          eta_p           = parameters.getParameter< real_t > ("eta_p");
   const real_t          lambda_p        = parameters.getParameter< real_t > ("lambda_p");
   const uint_t          period          = parameters.getParameter< uint_t > ("period");
   const real_t          L               = parameters.getParameter< real_t > ("L");
   const real_t          H               = parameters.getParameter< real_t > ("H");
   const uint_t          blockSize       = parameters.getParameter< uint_t > ("blockSize");
   const uint_t          timesteps       = parameters.getParameter< uint_t > ("timesteps");
Cameron Stewart's avatar
Cameron Stewart committed

Cameron Stewart's avatar
Cameron Stewart committed
   // reference data
   const real_t          uExpected       = force*H*H/(real_c(8.0)*(eta_s + eta_p));
Cameron Stewart's avatar
Cameron Stewart committed
   const real_t          uMax            = parameters.getParameter< real_t > ("uMax");
   const real_t          t0              = parameters.getParameter< real_t > ("t0");
   const real_t          t1              = parameters.getParameter< real_t > ("t1");
Cameron Stewart's avatar
Cameron Stewart committed

   // create fields
Cameron Stewart's avatar
Cameron Stewart committed
   BlockDataID flagFieldId = field::addFlagFieldToStorage< FlagField_T >(blocks, "flag field", FieldGhostLayers);
   BlockDataID forceFieldId = field::addToStorage<ForceField_T>( blocks, "Force Field", Vector3<real_t>(0.0), field::zyxf, FieldGhostLayers);
Cameron Stewart's avatar
Cameron Stewart committed
   LatticeModel_T latticeModel = LatticeModel_T(lbm::collision_model::TRT::constructWithMagicNumber( walberla::lbm::collision_model::omegaFromViscosity(eta_s)), lbm::force_model::GuoField<ForceField_T>( forceFieldId ) );
Cameron Stewart's avatar
Cameron Stewart committed
   BlockDataID pdfFieldId = lbm::addPdfFieldToStorage( blocks, "pdf field", latticeModel, Vector3<real_t>(), real_c(1.0), FieldGhostLayers );
Cameron Stewart's avatar
Cameron Stewart committed
   BlockDataID stressId = walberla::field::addToStorage<StressField_T>( blocks, "Stress Field", Matrix3<real_t>(0.0), field::zyxf, FieldGhostLayers);
   BlockDataID stressOldId = walberla::field::addToStorage<StressField_T>( blocks, "Old Stress Field", Matrix3<real_t>(0.0), field::zyxf, FieldGhostLayers);
   BlockDataID velocityId = walberla::field::addToStorage<VelocityField_T> (blocks, "Velocity Field", Vector3<real_t>(0.0), field::zyxf, FieldGhostLayers);
Cameron Stewart's avatar
Cameron Stewart committed

Cameron Stewart's avatar
Cameron Stewart committed
   // add boundary handling
   BlockDataID boundaryHandlingId = blocks->addStructuredBlockData< BoundaryHandling_T >( MyBoundaryHandling( flagFieldId, pdfFieldId ), "boundary handling" );
Cameron Stewart's avatar
Cameron Stewart committed

   // create time loop
   SweepTimeloop timeloop( blocks->getBlockStorage(), timesteps );

   // create communication for PdfField
Cameron Stewart's avatar
Cameron Stewart committed
   blockforest::communication::UniformBufferedScheme< Stencil_T > communication( blocks );
Cameron Stewart's avatar
Cameron Stewart committed
   communication.addPackInfo( make_shared< field::communication::PackInfo< PdfField_T > >( pdfFieldId ) );
Cameron Stewart's avatar
Cameron Stewart committed
   auto testData = make_shared< TestData >(TestData(timeloop, blocks, pdfFieldId, stressId, timesteps, blockSize, L, H, uExpected));
Cameron Stewart's avatar
Cameron Stewart committed

Cameron Stewart's avatar
Cameron Stewart committed
   // structure timeloop
Cameron Stewart's avatar
Cameron Stewart committed
   timeloop.add() << BeforeFunction( communication, "communication" )
Cameron Stewart's avatar
Cameron Stewart committed
                  << Sweep( BoundaryHandling_T::getBlockSweep( boundaryHandlingId ), "boundary handling" );
   timeloop.add() << BeforeFunction( lbm::viscoelastic::Su<LatticeModel_T, BoundaryHandling_T>(blocks, forceFieldId, pdfFieldId, boundaryHandlingId, stressId, stressOldId, velocityId,
Cameron Stewart's avatar
Cameron Stewart committed
                                                                                               lambda_p, eta_p, period, true), "viscoelasticity")
Cameron Stewart's avatar
Cameron Stewart committed
                  << Sweep( ConstantForce<BoundaryHandling_T>(forceFieldId, boundaryHandlingId, force),"Poiseuille Force");
   timeloop.add() << Sweep( makeSharedSweep( lbm::makeCellwiseSweep< LatticeModel_T, FlagField_T >( pdfFieldId, flagFieldId, Fluid_Flag ) ),
                            "LB stream & collide" )
                  << AfterFunction(makeSharedFunctor(testData), "test data");
Cameron Stewart's avatar
Cameron Stewart committed

Cameron Stewart's avatar
Cameron Stewart committed
   timeloop.run();
Cameron Stewart's avatar
Cameron Stewart committed
   // compare to reference data
   real_t errSteady = real_c(fabs(testData->getUSteady() - real_c(1.0))/real_c(1.0));
   real_t errMax = real_c(fabs(testData->getUMax() - uMax)/uMax);
   real_t errt0 = real_c(fabs(testData->getT0() - t0)/t0);
   real_t errt1 = real_c(fabs(testData->getT1() - t1)/t1);
Cameron Stewart's avatar
Cameron Stewart committed

Cameron Stewart's avatar
Cameron Stewart committed
   WALBERLA_LOG_RESULT("Steady State Velocity Error: " << errSteady );
   WALBERLA_LOG_RESULT("Maximum Velocity Error: " << errMax );
   WALBERLA_LOG_RESULT("Time of Maximum Error: " << errt0 );
   WALBERLA_LOG_RESULT("Decay Time Error: " << errt1 );
Cameron Stewart's avatar
Cameron Stewart committed

Cameron Stewart's avatar
Cameron Stewart committed
   // check that errors < 1%
Cameron Stewart's avatar
Cameron Stewart committed
   if (errSteady < 0.01 && errMax < 0.01 && errt0 < 0.01 && errt1 < 0.01){
Cameron Stewart's avatar
Cameron Stewart committed
      WALBERLA_LOG_RESULT("Success" );
Cameron Stewart's avatar
Cameron Stewart committed
      return EXIT_SUCCESS;
   }
   else {
Cameron Stewart's avatar
Cameron Stewart committed
      WALBERLA_LOG_RESULT("Failure" );
Cameron Stewart's avatar
Cameron Stewart committed
      return EXIT_FAILURE;
   }