From 3b27c0f40b7ea2536ca7d887a418c59c1e627513 Mon Sep 17 00:00:00 2001 From: Cameron Stewart <cstewart@icp.uni-stuttgart.de> Date: Fri, 23 Nov 2018 15:15:47 +0100 Subject: [PATCH] add test file --- tests/lbm/SuViscoelasticityTest.cpp | 323 ++++++++++++++++++++++++++++ 1 file changed, 323 insertions(+) create mode 100644 tests/lbm/SuViscoelasticityTest.cpp diff --git a/tests/lbm/SuViscoelasticityTest.cpp b/tests/lbm/SuViscoelasticityTest.cpp new file mode 100644 index 000000000..cd63004be --- /dev/null +++ b/tests/lbm/SuViscoelasticityTest.cpp @@ -0,0 +1,323 @@ +//====================================================================================================================== +// +// 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> +//! \brief D2Q9 Poisuielle flow simulation with viscoelasticity +// +// +//====================================================================================================================== + + +#include "blockforest/Initialization.h" +#include "blockforest/communication/UniformBufferedScheme.h" + +#include "boundary/BoundaryHandling.h" + +#include "core/Abort.h" +#include "core/Environment.h" +#include "core/debug/TestSubsystem.h" +#include "core/logging/Logging.h" +#include "core/timing/RemainingTimeLogger.h" +#include "core/SharedFunctor.h" +#include "core/Filesystem.h" + +#include "domain_decomposition/SharedSweep.h" + +#include "field/communication/PackInfo.h" +#include "field/StabilityChecker.h" + +#include "geometry/initializer/BoundaryFromDomainBorder.h" +#include "geometry/InitBoundaryHandling.h" + +#include "lbm/lattice_model/D2Q9.h" +#include "lbm/field/AddToStorage.h" +#include "lbm/boundary/all.h" +#include "lbm/communication/PdfFieldPackInfo.h" +#include "lbm/lattice_model/ForceModel.h" +#include "lbm/SuViscoelasticity.h" +#include "lbm/sweeps/CellwiseSweep.h" +#include "lbm/vtk/all.h" + +#include "timeloop/SweepTimeloop.h" + +#include <math.h> +#include <iostream> +#include <iomanip> +#include <vector> +#include <lbm/boundary/factories/ExtendedBoundaryHandlingFactory.h> + +using namespace walberla; + +////////////// +// TYPEDEFS // +////////////// + +typedef GhostLayerField< Vector3<real_t>, 1> ForceField_T; +typedef lbm::D2Q9< lbm::collision_model::TRT, false, lbm::force_model::GuoField< ForceField_T > > LatticeModel_T; +typedef LatticeModel_T::CommunicationStencil CommunicationStencil_T; +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; +typedef lbm::ExtendedBoundaryHandlingFactory< LatticeModel_T, FlagField_T > BHFactory; + +class WriteCheckpoint { +public: + WriteCheckpoint(Timeloop &timeloop, BlockStorage & blockStorage, uint_t checkpointFrequency, uint_t timesteps, + BlockDataID pdfFieldId, BlockDataID stressId, std::string dir, std::string paramFile) : timeloop_(timeloop), blockStorage_(blockStorage), + checkpointFrequency_(checkpointFrequency), timesteps_(timesteps), + pdfFieldId_(pdfFieldId), stressId_(stressId), dir_(dir + "_chk"), paramFile_(paramFile) {} + void operator()(){ + if(checkpointFrequency_ > 0 && timeloop_.getCurrentTimeStep() % checkpointFrequency_== 0 && timeloop_.getCurrentTimeStep() > 0){ + Save(); + } + if(timeloop_.getCurrentTimeStep() == timesteps_-1 && filesystem::is_directory(dir_)){ + filesystem::remove_all(dir_); + } + } + + bool canLoad() + { + if(!filesystem::is_directory(dir_)){ + std::cout << "No Checkpoint Found" << std::endl; + return false; + } + + std::ifstream f1; + std::ifstream f2; + f1.open(paramFile_, std::ifstream::binary|std::ifstream::ate); + f2.open(dir_ + "/" + paramFile_, std::ifstream::binary|std::ifstream::ate); + + if (f1.fail() || f2.fail()) { + std::cout << "Failed to check parameter file" << std::endl; + return false; //file problem + } + + if (f1.tellg() != f2.tellg()) { + std::cout << "Ignoring checkpoint for different size config file" << std::endl; + return false; //size mismatch + } + + f1.seekg(0, std::ifstream::beg); + f2.seekg(0, std::ifstream::beg); + if(!std::equal(std::istreambuf_iterator<char>(f1.rdbuf()), std::istreambuf_iterator<char>(), std::istreambuf_iterator<char>(f2.rdbuf()))){ + std::cout << "Ignoring checkpoint for different config file" << std::endl; + return false; + } + return true; + } + + void Load() + { + std::cout << "Loading Checkpoint" << std::endl; + field::readFromFile<PdfField_T>(dir_ + "/pdfField.chk", blockStorage_, pdfFieldId_); + field::readFromFile<StressField_T>(dir_ + "/stressField.chk", blockStorage_, stressId_); + std::ifstream f; + f.open(dir_ + "/chkpoint"); + uint_t currentTime; + f >> currentTime; + timeloop_.setCurrentTimeStep(currentTime + 1); + } + + void Save(){ + + auto tmpdir = dir_ + "~"; + if(filesystem::is_directory(tmpdir)){ + filesystem::remove_all(tmpdir); + } + + filesystem::create_directory(tmpdir); + + filesystem::copy(paramFile_, tmpdir + "/" + paramFile_); + field::writeToFile<PdfField_T>(tmpdir + "/pdfField.chk", blockStorage_, pdfFieldId_); + field::writeToFile<StressField_T>(tmpdir + "/stressField.chk", blockStorage_, stressId_); + std::ofstream f; + f.open(tmpdir + "/chkpoint"); + f << timeloop_.getCurrentTimeStep(); + f.close(); + + if(filesystem::is_directory(dir_)) { + filesystem::remove_all(dir_); + } + filesystem::rename(tmpdir, dir_); + } + +private: + Timeloop & timeloop_; + BlockStorage & blockStorage_; + uint_t checkpointFrequency_, timesteps_; + BlockDataID pdfFieldId_, stressId_; + std::string dir_, paramFile_; +}; + +class WriteVelocity +{ +public: + WriteVelocity(Timeloop & timeloop, uint_t writeFrequency, shared_ptr< StructuredBlockForest > blocks, BlockDataID pdfFieldId) : timeloop_(timeloop), writeFrequency_(writeFrequency), blocks_(blocks), + pdfFieldId_(pdfFieldId){} + + void operator()(){ + if(writeFrequency_ > 0 && timeloop_.getCurrentTimeStep() % writeFrequency_==0 ){ + + std::ofstream f; + f.open("vel.dat", std::ios_base::app); + for( auto blockIt = blocks_->begin(); blockIt != blocks_->end(); ++blockIt ) + { + PdfField_T * pdf = blockIt.get()->getData< PdfField_T >(pdfFieldId_); + + if(blockIt.get()->getAABB().contains(15,15,0)){ + std::cout<< pdf->getVelocity(5,5,0).length() << std::endl; + f << std::setprecision(10) << pdf->getVelocity(5,5,0).length() << ","; + } + + } + f.close(); + } + } + +private: + Timeloop & timeloop_; + uint_t writeFrequency_; + shared_ptr< StructuredBlockForest > blocks_; + BlockDataID pdfFieldId_; +}; + + + +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_; +}; + +int main(int argc, char ** argv ){ + + walberla::Environment env( argc, argv ); + + // create block storage from the config file + shared_ptr<StructuredBlockForest> blocks = blockforest::createUniformBlockGridFromConfig( env.config() ); + + // read parameters + auto parameters = env.config()->getOneBlock( "Parameters" ); + + // extract some constants from the parameters + const std::string paramFile(argv[1]); + const real_t eta_s = parameters.getParameter< real_t > ( "eta_s", real_c( 1.4 ) ); + const real_t force = parameters.getParameter< real_t > ( "force", real_t( 1 ) ); + const real_t eta_p = parameters.getParameter< real_t > ( "eta_p", real_c( 1.0 ) ); + const uint_t period = parameters.getParameter< uint_t > ( "period", uint_c( 1 ) ); + const uint_t writePeriod = parameters.getParameter< uint_t > ( "writePeriod", uint_c( 10 ) ); + + const uint_t checkpointFrequency = parameters.getParameter< uint_t > ("checkpointFrequency", uint_c(5000)); + const real_t remainingTimeLoggerFrequency = parameters.getParameter< real_t >( "remainingTimeLoggerFrequency", real_c(3.0) ); // in seconds + + // take parameters from command line args preferably + char* end; + const real_t lambda_p = ((argc > 2)? atof(argv[2]) : parameters.getParameter<real_t>( "lambda_p", real_c(10))); + const std::string baseFolder = ((argc > 2)? std::string(argv[2]) : parameters.getParameter<std::string>( "baseFolder", std::string("vtk_out"))); + const uint_t timesteps = ((argc > 3)? strtoul(argv[3],&end,10) : parameters.getParameter<uint_t>( "timesteps", uint_c(10) )); + + // create fields + BlockDataID flagFieldId = field::addFlagFieldToStorage< FlagField_T >(blocks, "flag field", uint_c(2)); + BlockDataID forceFieldId = field::addToStorage<ForceField_T>( blocks, "Force Field", Vector3<real_t>(0.0), field::zyxf, uint_c(2)); + LatticeModel_T latticeModel = LatticeModel_T(lbm::collision_model::TRT::constructWithMagicNumber( walberla::lbm::collision_model::omegaFromViscosity(eta_s)), lbm::force_model::GuoField<ForceField_T>( forceFieldId ) ); + BlockDataID pdfFieldId = lbm::addPdfFieldToStorage( blocks, "pdf field", latticeModel, Vector3<real_t>(), real_c(1), uint_c(2) ); + BlockDataID stressId = walberla::field::addToStorage<StressField_T>( blocks, "Stress Field", Matrix3<real_t>(0.0), field::zyxf, uint_c(2)); + BlockDataID stressOldId = walberla::field::addToStorage<StressField_T>( blocks, "Old Stress Field", Matrix3<real_t>(0.0), field::zyxf, uint_c(2)); + BlockDataID velocityId = walberla::field::addToStorage<VelocityField_T> (blocks, "Velocity Field", Vector3<real_t>(0.0), field::zyxf, uint_c(1)); + + // create and initialize boundary handling + const FlagUID fluidFlagUID( "Fluid" ); + + auto boundariesConfig = env.config()->getOneBlock( "Boundaries" ); + + BlockDataID boundaryHandlingId = BHFactory::addBoundaryHandlingToStorage( blocks, "boundary handling", flagFieldId, pdfFieldId, fluidFlagUID ); + geometry::initBoundaryHandling<BHFactory::BoundaryHandling>( *blocks, boundaryHandlingId, boundariesConfig ); + geometry::setNonBoundaryCellsToDomain<BHFactory::BoundaryHandling> ( *blocks, boundaryHandlingId ); + + + // create time loop + SweepTimeloop timeloop( blocks->getBlockStorage(), timesteps ); + + // create communication for PdfField + blockforest::communication::UniformBufferedScheme< CommunicationStencil_T > communication( blocks ); + communication.addPackInfo( make_shared< field::communication::PackInfo< PdfField_T > >( pdfFieldId ) ); + + timeloop.add() << BeforeFunction( communication, "communication" ) + << Sweep( BHFactory::BoundaryHandling::getBlockSweep( boundaryHandlingId ), "boundary handling" ); + timeloop.add() << BeforeFunction( lbm::viscoelastic::Su<LatticeModel_T, BHFactory::BoundaryHandling>(blocks, forceFieldId, pdfFieldId, boundaryHandlingId, stressId, stressOldId, velocityId, + lambda_p, eta_p, period, true), "viscoelasticity") + << Sweep( ConstantForce<BHFactory::BoundaryHandling>(forceFieldId, boundaryHandlingId, force),"Poiseuille Force"); + timeloop.add() << Sweep( makeSharedSweep( lbm::makeCellwiseSweep< LatticeModel_T, FlagField_T >( pdfFieldId, flagFieldId, fluidFlagUID ) ), + "LB stream & collide" ); + + // LBM stability check + timeloop.addFuncAfterTimeStep( makeSharedFunctor( field::makeStabilityChecker< ForceField_T, FlagField_T >( env.config(), blocks, forceFieldId, + flagFieldId, fluidFlagUID ) ), + "LBM stability check" ); + + // log remaining time + timeloop.addFuncAfterTimeStep( timing::RemainingTimeLogger( timeloop.getNrOfTimeSteps(), remainingTimeLoggerFrequency ), "remaining time logger" ); + + // Add checkpointing + //auto checkpointing = WriteCheckpoint(timeloop, blocks->getBlockStorage(), checkpointFrequency, timesteps, pdfFieldId, stressId, baseFolder, paramFile); + //timeloop.addFuncAfterTimeStep(checkpointing); + //if(checkpointing.canLoad()){checkpointing.Load();} + + // write midvelocity + //auto writeVelocity = WriteVelocity(timeloop, writePeriod, blocks, pdfFieldId); + //timeloop.addFuncAfterTimeStep(writeVelocity); + + // add VTK outputs + timeloop.addFuncAfterTimeStep(field::createVTKOutput<StressField_T>(stressId, *blocks, "stress", writePeriod, uint_c(0), false, baseFolder, std::string("step"), + false, true, true, 0, Set<SUID>::emptySet(), Set<SUID>::emptySet(), true, timeloop.getCurrentTimeStep())); + timeloop.addFuncAfterTimeStep(field::createVTKOutput<VelocityField_T>(velocityId, *blocks, "velocity", writePeriod, uint_c(0), false, baseFolder, std::string("step"), + false, true, true, 0, Set<SUID>::emptySet(), Set<SUID>::emptySet(), true, timeloop.getCurrentTimeStep())); + + auto flagFieldVTK = vtk::createVTKOutput_BlockData( blocks, "flag_field", writePeriod, 0, false, baseFolder ); + flagFieldVTK->addCellDataWriter( make_shared< field::VTKWriter< FlagField_T > >( flagFieldId, "FlagField" ) ); + timeloop.addFuncAfterTimeStep(vtk::writeFiles( flagFieldVTK ), "Flag field VTK"); + + timeloop.run(); + + + return EXIT_SUCCESS; +} -- GitLab