Commit 1a033eb2 authored by Christoph Rettinger's avatar Christoph Rettinger
Browse files

Improved and extended pe time step functionality, removed duplicated time step class

parent 5f158bf0
...@@ -1568,7 +1568,7 @@ int main( int argc, char **argv ) { ...@@ -1568,7 +1568,7 @@ int main( int argc, char **argv ) {
timeloop.add() << Sweep( DummySweep(), "Dummy Sweep ") timeloop.add() << Sweep( DummySweep(), "Dummy Sweep ")
<< AfterFunction( BodiesQuantityEvaluator(&timeloop, blocks, bodyStorageID, vtkBaseFolder+"/quantityLogging.txt", numSpheres, real_t(numSpheres) * particleMass ), "Body Quantity Evaluator") << 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( 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 // 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" ) timeloop.add() << Sweep( pe_coupling::discrete_particle_methods::SolidVolumeFractionFieldEvaluator<FlagField_T, field::KernelDistributor> ( blocks, svfFieldID, bodyStorageID, flagFieldID, Fluid_Flag ), "Solid Volume Fraction Field Evaluation" )
......
//======================================================================================================================
//
// 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
...@@ -28,5 +28,4 @@ ...@@ -28,5 +28,4 @@
#include "CombinedReductionFieldCommunication.h" #include "CombinedReductionFieldCommunication.h"
#include "ExternalForceToForceFieldAdder.h" #include "ExternalForceToForceFieldAdder.h"
#include "ForceFieldResetter.h" #include "ForceFieldResetter.h"
#include "SubgridTimeStep.h"
#include "FieldDataSwapper.h" #include "FieldDataSwapper.h"
...@@ -40,6 +40,18 @@ ...@@ -40,6 +40,18 @@
namespace walberla { namespace walberla {
namespace pe_coupling { 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 class TimeStep
{ {
public: public:
...@@ -48,21 +60,26 @@ public: ...@@ -48,21 +60,26 @@ public:
const BlockDataID & bodyStorageID, const BlockDataID & bodyStorageID,
pe::cr::ICR & collisionResponse, pe::cr::ICR & collisionResponse,
const std::function<void (void)> & synchronizeFunc, const std::function<void (void)> & synchronizeFunc,
const real_t timeStep = real_t(1), const uint_t intermediateSteps = uint_c(1) ) const real_t timeStepSize = real_t(1),
: timeStep_( timeStep ) const uint_t numberOfSubIterations = uint_t(1),
, intermediateSteps_( ( intermediateSteps == 0 ) ? uint_c(1) : intermediateSteps ) const std::function<void (void)> & forceEvaluationFunc = [](){})
: timeStepSize_( timeStepSize )
, numberOfSubIterations_( ( numberOfSubIterations == 0 ) ? uint_t(1) : numberOfSubIterations )
, blockStorage_( blockStorage ) , blockStorage_( blockStorage )
, bodyStorageID_(bodyStorageID) , bodyStorageID_( bodyStorageID )
, collisionResponse_(collisionResponse) , collisionResponse_( collisionResponse )
, synchronizeFunc_(synchronizeFunc) , synchronizeFunc_( synchronizeFunc )
, forceEvaluationFunc_( forceEvaluationFunc )
{} {}
void operator()() void operator()()
{ {
if( intermediateSteps_ == 1 ) if( numberOfSubIterations_ == 1 )
{ {
collisionResponse_.timestep( timeStep_ ); forceEvaluationFunc_();
synchronizeFunc_( );
collisionResponse_.timestep( timeStepSize_ );
synchronizeFunc_();
} }
else else
{ {
...@@ -76,14 +93,14 @@ public: ...@@ -76,14 +93,14 @@ public:
// send total forces/torques to shadow owners // send total forces/torques to shadow owners
pe::distributeForces( blockStorage_->getBlockStorage(), bodyStorageID_ ); 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; std::map< walberla::id_t, std::vector< real_t > > forceMap;
for( auto blockIt = blockStorage_->begin(); blockIt != blockStorage_->end(); ++blockIt ) for( auto blockIt = blockStorage_->begin(); blockIt != blockStorage_->end(); ++blockIt )
{ {
// iterate over local and remote bodies and store force/torque in map // 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, // 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 ). // 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 stores as well. // 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 ) for( auto bodyIt = pe::BodyIterator::begin(*blockIt, bodyStorageID_); bodyIt != pe::BodyIterator::end(); ++bodyIt )
{ {
auto & f = forceMap[ bodyIt->getSystemID() ]; auto & f = forceMap[ bodyIt->getSystemID() ];
...@@ -112,10 +129,11 @@ public: ...@@ -112,10 +129,11 @@ public:
} }
// perform pe time steps // perform pe time steps
const real_t subTimestep = timeStep_ / real_c( intermediateSteps_ ); const real_t subTimeStepSize = timeStepSize_ / real_c( numberOfSubIterations_ );
for( uint_t i = 0; i != intermediateSteps_; ++i ) 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 ) if( i != 0 )
{ {
for( auto blockIt = blockStorage_->begin(); blockIt != blockStorage_->end(); ++blockIt ) for( auto blockIt = blockStorage_->begin(); blockIt != blockStorage_->end(); ++blockIt )
...@@ -131,23 +149,26 @@ public: ...@@ -131,23 +149,26 @@ public:
} }
} }
collisionResponse_.timestep( subTimestep ); // evaluate forces (e.g. lubrication forces)
synchronizeFunc_( ); forceEvaluationFunc_();
collisionResponse_.timestep( subTimeStepSize );
synchronizeFunc_();
} }
} }
} }
protected: protected:
const real_t timeStep_; const real_t timeStepSize_;
const uint_t numberOfSubIterations_;
const uint_t intermediateSteps_;
shared_ptr<StructuredBlockStorage> blockStorage_; shared_ptr<StructuredBlockStorage> blockStorage_;
const BlockDataID & bodyStorageID_; const BlockDataID & bodyStorageID_;
pe::cr::ICR & collisionResponse_; pe::cr::ICR & collisionResponse_;
std::function<void (void)> synchronizeFunc_; std::function<void (void)> synchronizeFunc_;
std::function<void (void)> forceEvaluationFunc_;
}; // class TimeStep }; // class TimeStep
......
...@@ -1643,7 +1643,7 @@ int main( int argc, char **argv ) ...@@ -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 * 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,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::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 ") timeloop.add() << Sweep( DummySweep(), "Dummy Sweep ")
<< AfterFunction( SharedFunctor<CollisionPropertiesEvaluator>( collisionPropertiesEvaluator ), "Collision properties evaluator"); << AfterFunction( SharedFunctor<CollisionPropertiesEvaluator>( collisionPropertiesEvaluator ), "Collision properties evaluator");
......
...@@ -1234,7 +1234,7 @@ int main( int argc, char **argv ) ...@@ -1234,7 +1234,7 @@ int main( int argc, char **argv )
<< AfterFunction( dragAndPressureForceEvaluationFunction, "Fluid-Particle Interaction Force Evaluation" ) << AfterFunction( dragAndPressureForceEvaluationFunction, "Fluid-Particle Interaction Force Evaluation" )
<< AfterFunction( dragForceComm, "Drag Force Field Communication" ) << AfterFunction( dragForceComm, "Drag Force Field Communication" )
<< AfterFunction( pe_coupling::ForceOnBodiesAdder( blocks, bodyStorageID, -gravitationalForce ), "Gravitational and buoyancy force" ) << 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"); << AfterFunction( SharedFunctor<CollisionPropertiesEvaluator>( collisionPropertiesEvaluator ), "Collision properties evaluator");
if( dist == Distribution::DNearestNeighbor ) if( dist == Distribution::DNearestNeighbor )
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment