From 1a033eb2626aef3629ae7d1351ef0c49e07de34e Mon Sep 17 00:00:00 2001 From: Christoph Rettinger <christoph.rettinger@fau.de> Date: Wed, 21 Feb 2018 14:17:19 +0100 Subject: [PATCH] Improved and extended pe time step functionality, removed duplicated time step class --- .../BidisperseFluidizedBedDPM.cpp | 2 +- .../utility/SubgridTimeStep.h | 164 ------------------ .../discrete_particle_methods/utility/all.h | 1 - src/pe_coupling/utility/TimeStep.h | 61 ++++--- .../HinderedSettlingDynamicsDPM.cpp | 2 +- .../SphereWallCollisionBehaviorDPM.cpp | 2 +- 6 files changed, 44 insertions(+), 188 deletions(-) delete mode 100644 src/pe_coupling/discrete_particle_methods/utility/SubgridTimeStep.h diff --git a/apps/showcases/BidisperseFluidizedBed/BidisperseFluidizedBedDPM.cpp b/apps/showcases/BidisperseFluidizedBed/BidisperseFluidizedBedDPM.cpp index 7e5cab129..03a294859 100644 --- a/apps/showcases/BidisperseFluidizedBed/BidisperseFluidizedBedDPM.cpp +++ b/apps/showcases/BidisperseFluidizedBed/BidisperseFluidizedBedDPM.cpp @@ -1568,7 +1568,7 @@ int main( int argc, char **argv ) { timeloop.add() << Sweep( DummySweep(), "Dummy Sweep ") << AfterFunction( BodiesQuantityEvaluator(&timeloop, blocks, bodyStorageID, vtkBaseFolder+"/quantityLogging.txt", numSpheres, real_t(numSpheres) * particleMass ), "Body Quantity Evaluator") << AfterFunction( ForceOnBodiesAdder( blocks, bodyStorageID, Vector3<real_t>(0,0,- gravitationalAcc * ( densityRatio - real_t(1) ) ) ), "Gravitational and Buoyancy Force Add" ) - << AfterFunction( pe_coupling::discrete_particle_methods::SubgridTimeStep( blocks, bodyStorageID, *cr, syncCall, lubricationEvaluationFunction, dtInteractionSubCycle, peSubSteps ), "Pe Time Step" ); + << AfterFunction( pe_coupling::TimeStep( blocks, bodyStorageID, *cr, syncCall, dtInteractionSubCycle, peSubSteps, lubricationEvaluationFunction ), "Pe Time Step" ); // update solid volume fraction field timeloop.add() << Sweep( pe_coupling::discrete_particle_methods::SolidVolumeFractionFieldEvaluator<FlagField_T, field::KernelDistributor> ( blocks, svfFieldID, bodyStorageID, flagFieldID, Fluid_Flag ), "Solid Volume Fraction Field Evaluation" ) diff --git a/src/pe_coupling/discrete_particle_methods/utility/SubgridTimeStep.h b/src/pe_coupling/discrete_particle_methods/utility/SubgridTimeStep.h deleted file mode 100644 index b337175e0..000000000 --- a/src/pe_coupling/discrete_particle_methods/utility/SubgridTimeStep.h +++ /dev/null @@ -1,164 +0,0 @@ -//====================================================================================================================== -// -// 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 SubgridTimeStep.h -//! \ingroup pe_coupling -//! \author Christoph Rettinger <christoph.rettinger@fau.de> -// -//====================================================================================================================== - -#pragma once - -#include "core/debug/Debug.h" -#include "core/timing/TimingTree.h" - -#include "domain_decomposition/BlockStorage.h" - -#include "field/GhostLayerField.h" - -#include "pe/cr/ICR.h" -#include "pe/rigidbody/BodyIterators.h" -#include "pe/synchronization/SyncForces.h" - -#include <functional> - -#include <map> - -/*!\brief Carries out the the PE time steps, including sub iteration functionality. - * - * This class is similar to src/pe_coupling/utility/TimeStep. - * - * It executes 'intermediateSteps' PE steps within one timestep of size 'timeStepSize'. - * - * These PE sub iterations require, that the current external (e.g. hydrodynamic, gravitational,..) forces and torques - * acting on each particle remains unchanged. Thus, a map is set up internally that stores and re-sets these forces - * and torques in each PE sub iteration - * . - * Additionally, a function 'forceEvaluationFunc' can be given that allows to evaluate different forces before the PE - * step is carried out. An example are particle-particle lubrication forces that have to be updated in each sub iteration. - * - */ -namespace walberla { -namespace pe_coupling { -namespace discrete_particle_methods { - -class SubgridTimeStep -{ -public: - - typedef field::GhostLayerField< Vector3<real_t>, 1 > ForceField_T; - - explicit SubgridTimeStep( const shared_ptr<StructuredBlockStorage> & blockStorage, - const BlockDataID & bodyStorageID, - pe::cr::ICR & collisionResponse, - const std::function<void (void)> & synchronizeFunc, - const std::function<void ()> & forceEvaluationFunc, - const real_t timeStepSize = real_t(1), const uint_t intermediateSteps = uint_t(1) ) - : timeStepSize_( timeStepSize ) - , intermediateSteps_( ( intermediateSteps == 0 ) ? uint_t(1) : intermediateSteps ) - , blockStorage_( blockStorage ) - , bodyStorageID_(bodyStorageID) - , collisionResponse_(collisionResponse) - , synchronizeFunc_(synchronizeFunc) - , forceEvaluationFunc_(forceEvaluationFunc) - {} - - void operator()() - { - if( intermediateSteps_ == 1 ) - { - forceEvaluationFunc_(); - - collisionResponse_.timestep( timeStepSize_ ); - synchronizeFunc_(); - } - else - { - // sum up all forces from shadow copies on local body (owner) - pe::reduceForces(blockStorage_->getBlockStorage(), bodyStorageID_); - // send total forces to shadow owners - pe::distributeForces(blockStorage_->getBlockStorage(), bodyStorageID_); - - // store force/torques. Those should only contain external forces (gravity, buoyancy,..) - // generate map from all known bodies (process local) to total forces - std::map< walberla::id_t, std::vector< real_t > > forceMap; - for (auto blockIt = blockStorage_->begin(); blockIt != blockStorage_->end(); ++blockIt) - { - for( auto bodyIt = pe::BodyIterator::begin(*blockIt, bodyStorageID_); bodyIt != pe::BodyIterator::end(); ++bodyIt ) - { - auto & f = forceMap[ bodyIt->getSystemID() ]; - - const auto & force = bodyIt->getForce(); - f.push_back( force[0] ); - f.push_back( force[1] ); - f.push_back( force[2] ); - - const auto & torque = bodyIt->getTorque(); - f.push_back( torque[0] ); - f.push_back( torque[1] ); - f.push_back( torque[2] ); - - if ( bodyIt->isRemote() ) - { - bodyIt->resetForceAndTorque(); - } - } - } - - // perform pe sub time steps - const real_t subTimeStepSize = timeStepSize_ / real_c( intermediateSteps_ ); - for( uint_t i = 0; i != intermediateSteps_; ++i ) - { - // evaluate forces (e.g. lubrication forces) - forceEvaluationFunc_(); - - // in the first set forces on local bodies are already set by force synchronization - if( i != 0 ) { - for (auto blockIt = blockStorage_->begin(); blockIt != blockStorage_->end(); ++blockIt) - { - for( auto body = pe::LocalBodyIterator::begin(*blockIt, bodyStorageID_); body != pe::LocalBodyIterator::end(); ++body ) - { - const auto & f = forceMap[ body->getSystemID() ]; - body->addForce ( f[0], f[1], f[2] ); - body->addTorque( f[3], f[4], f[5] ); - } - } - } - - collisionResponse_.timestep( subTimeStepSize ); - synchronizeFunc_(); - } - } - } - -protected: - - const real_t timeStepSize_; - - const uint_t intermediateSteps_; - - shared_ptr<StructuredBlockStorage> blockStorage_; - const BlockDataID & bodyStorageID_; - - pe::cr::ICR & collisionResponse_; - std::function<void (void)> synchronizeFunc_; - std::function<void ()> forceEvaluationFunc_; - -}; - - -} // namespace discrete_particle_methods -} // namespace pe_coupling -} // namespace walberla diff --git a/src/pe_coupling/discrete_particle_methods/utility/all.h b/src/pe_coupling/discrete_particle_methods/utility/all.h index 6c4711714..31cb9cf9f 100644 --- a/src/pe_coupling/discrete_particle_methods/utility/all.h +++ b/src/pe_coupling/discrete_particle_methods/utility/all.h @@ -28,5 +28,4 @@ #include "CombinedReductionFieldCommunication.h" #include "ExternalForceToForceFieldAdder.h" #include "ForceFieldResetter.h" -#include "SubgridTimeStep.h" #include "FieldDataSwapper.h" diff --git a/src/pe_coupling/utility/TimeStep.h b/src/pe_coupling/utility/TimeStep.h index 684fb6bf6..d89e0a6e7 100644 --- a/src/pe_coupling/utility/TimeStep.h +++ b/src/pe_coupling/utility/TimeStep.h @@ -40,6 +40,18 @@ namespace walberla { namespace pe_coupling { +/*!\brief Carries out the the PE time steps, including sub iteration functionality. + * + * It executes 'numberOfSubIterations' PE steps within one timestep of size 'timeStepSize'. + * + * These PE sub iterations require, that the current external (e.g. hydrodynamic, gravitational,..) forces and torques + * acting on each particle remains unchanged. Thus, a map is set up internally that stores and re-sets these forces + * and torques in each PE sub iteration + * . + * Additionally, a function 'forceEvaluationFunc' can be given that allows to evaluate different forces before the PE + * step is carried out. An example are particle-particle lubrication forces that have to be updated in each sub iteration. + * + */ class TimeStep { public: @@ -48,21 +60,26 @@ public: const BlockDataID & bodyStorageID, pe::cr::ICR & collisionResponse, const std::function<void (void)> & synchronizeFunc, - const real_t timeStep = real_t(1), const uint_t intermediateSteps = uint_c(1) ) - : timeStep_( timeStep ) - , intermediateSteps_( ( intermediateSteps == 0 ) ? uint_c(1) : intermediateSteps ) + const real_t timeStepSize = real_t(1), + const uint_t numberOfSubIterations = uint_t(1), + const std::function<void (void)> & forceEvaluationFunc = [](){}) + : timeStepSize_( timeStepSize ) + , numberOfSubIterations_( ( numberOfSubIterations == 0 ) ? uint_t(1) : numberOfSubIterations ) , blockStorage_( blockStorage ) - , bodyStorageID_(bodyStorageID) - , collisionResponse_(collisionResponse) - , synchronizeFunc_(synchronizeFunc) + , bodyStorageID_( bodyStorageID ) + , collisionResponse_( collisionResponse ) + , synchronizeFunc_( synchronizeFunc ) + , forceEvaluationFunc_( forceEvaluationFunc ) {} void operator()() { - if( intermediateSteps_ == 1 ) + if( numberOfSubIterations_ == 1 ) { - collisionResponse_.timestep( timeStep_ ); - synchronizeFunc_( ); + forceEvaluationFunc_(); + + collisionResponse_.timestep( timeStepSize_ ); + synchronizeFunc_(); } else { @@ -76,14 +93,14 @@ public: // send total forces/torques to shadow owners pe::distributeForces( blockStorage_->getBlockStorage(), bodyStorageID_ ); - // generate map from all known bodies (process local) to total forces + // generate map from all known bodies (process local) to total forces/torques std::map< walberla::id_t, std::vector< real_t > > forceMap; for( auto blockIt = blockStorage_->begin(); blockIt != blockStorage_->end(); ++blockIt ) { // iterate over local and remote bodies and store force/torque in map // Remote bodies are required since during the then following collision response time steps, - // bodies can change owner ship (i.e. a now remote body could become a local body ). - // Since only the owning process re-sets the force/torque later, remote body values have to be stores as well. + // bodies can change ownership (i.e. a now remote body could become a local body ). + // Since only the owning process re-sets the force/torque later, remote body values have to be stored as well. for( auto bodyIt = pe::BodyIterator::begin(*blockIt, bodyStorageID_); bodyIt != pe::BodyIterator::end(); ++bodyIt ) { auto & f = forceMap[ bodyIt->getSystemID() ]; @@ -112,10 +129,11 @@ public: } // perform pe time steps - const real_t subTimestep = timeStep_ / real_c( intermediateSteps_ ); - for( uint_t i = 0; i != intermediateSteps_; ++i ) + const real_t subTimeStepSize = timeStepSize_ / real_c( numberOfSubIterations_ ); + for( uint_t i = 0; i != numberOfSubIterations_; ++i ) { - // in the first set forces on local bodies are already set by force synchronization + + // in the first iteration, forces on local bodies are already set by force synchronization if( i != 0 ) { for( auto blockIt = blockStorage_->begin(); blockIt != blockStorage_->end(); ++blockIt ) @@ -131,23 +149,26 @@ public: } } - collisionResponse_.timestep( subTimestep ); - synchronizeFunc_( ); + // evaluate forces (e.g. lubrication forces) + forceEvaluationFunc_(); + + collisionResponse_.timestep( subTimeStepSize ); + synchronizeFunc_(); } } } protected: - const real_t timeStep_; - - const uint_t intermediateSteps_; + const real_t timeStepSize_; + const uint_t numberOfSubIterations_; shared_ptr<StructuredBlockStorage> blockStorage_; const BlockDataID & bodyStorageID_; pe::cr::ICR & collisionResponse_; std::function<void (void)> synchronizeFunc_; + std::function<void (void)> forceEvaluationFunc_; }; // class TimeStep diff --git a/tests/pe_coupling/discrete_particle_methods/HinderedSettlingDynamicsDPM.cpp b/tests/pe_coupling/discrete_particle_methods/HinderedSettlingDynamicsDPM.cpp index cc700fde4..c3cdade9e 100644 --- a/tests/pe_coupling/discrete_particle_methods/HinderedSettlingDynamicsDPM.cpp +++ b/tests/pe_coupling/discrete_particle_methods/HinderedSettlingDynamicsDPM.cpp @@ -1643,7 +1643,7 @@ int main( int argc, char **argv ) << AfterFunction( pe_coupling::ForceOnBodiesAdder( blocks, bodyStorageID, Vector3<real_t>(0,0,- gravity * densityRatio * diameter * diameter * diameter * math::PI / real_t(6) ) ), "Gravitational Force Add" ) << AfterFunction( pe_coupling::ForceOnBodiesAdder( blocks, bodyStorageID, Vector3<real_t>(0,0,gravity * real_t(1) * diameter * diameter * diameter * math::PI / real_t(6) ) ), "Buoyancy Force (due to gravity) Add" ) << AfterFunction( pe_coupling::ForceOnBodiesAdder( blocks, bodyStorageID, Vector3<real_t>(0,0,extForce[2] * real_t(1) * diameter * diameter * diameter * math::PI / real_t(6) ) ), "Buoyancy Force (due to external fluid force) Add" ) - << AfterFunction( pe_coupling::discrete_particle_methods::SubgridTimeStep( blocks, bodyStorageID, *cr, syncCall, lubricationEvaluationFunction, dtInteractionSubCycle, peSubSteps ), "Pe Time Step" ); + << AfterFunction( pe_coupling::TimeStep( blocks, bodyStorageID, *cr, syncCall, dtInteractionSubCycle, peSubSteps, lubricationEvaluationFunction ), "Pe Time Step" ); timeloop.add() << Sweep( DummySweep(), "Dummy Sweep ") << AfterFunction( SharedFunctor<CollisionPropertiesEvaluator>( collisionPropertiesEvaluator ), "Collision properties evaluator"); diff --git a/tests/pe_coupling/discrete_particle_methods/SphereWallCollisionBehaviorDPM.cpp b/tests/pe_coupling/discrete_particle_methods/SphereWallCollisionBehaviorDPM.cpp index 3ac3679f5..b6c7eaab5 100644 --- a/tests/pe_coupling/discrete_particle_methods/SphereWallCollisionBehaviorDPM.cpp +++ b/tests/pe_coupling/discrete_particle_methods/SphereWallCollisionBehaviorDPM.cpp @@ -1234,7 +1234,7 @@ int main( int argc, char **argv ) << AfterFunction( dragAndPressureForceEvaluationFunction, "Fluid-Particle Interaction Force Evaluation" ) << AfterFunction( dragForceComm, "Drag Force Field Communication" ) << AfterFunction( pe_coupling::ForceOnBodiesAdder( blocks, bodyStorageID, -gravitationalForce ), "Gravitational and buoyancy force" ) - << AfterFunction( pe_coupling::discrete_particle_methods::SubgridTimeStep( blocks, bodyStorageID, *cr, syncCall, lubricationEvaluationFunction, dtInteractionSubCycle, peSubSteps ), "Pe Time Step" ) + << AfterFunction( pe_coupling::TimeStep( blocks, bodyStorageID, *cr, syncCall, dtInteractionSubCycle, peSubSteps, lubricationEvaluationFunction ), "Pe Time Step" ) << AfterFunction( SharedFunctor<CollisionPropertiesEvaluator>( collisionPropertiesEvaluator ), "Collision properties evaluator"); if( dist == Distribution::DNearestNeighbor ) -- GitLab