diff --git a/src/pe_coupling/momentum_exchange_method/restoration/ExtrapolationDirectionFinder.cpp b/src/pe_coupling/momentum_exchange_method/restoration/ExtrapolationDirectionFinder.cpp new file mode 100644 index 0000000000000000000000000000000000000000..9821dbb80e8e9565c889ee61be52b83a1a733e14 --- /dev/null +++ b/src/pe_coupling/momentum_exchange_method/restoration/ExtrapolationDirectionFinder.cpp @@ -0,0 +1,49 @@ +//====================================================================================================================== +// +// 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 ExtrapolationDirectionFinder.cpp +//! \ingroup pe_coupling +//! \author Christoph Rettinger <christoph.rettinger@fau.de> +// +//====================================================================================================================== + + +#include "ExtrapolationDirectionFinder.h" + +namespace walberla { +namespace pe_coupling { + + +void SphereNormalExtrapolationDirectionFinder +::getDirection( const cell_idx_t & x, const cell_idx_t & y, const cell_idx_t & z, IBlock * const block, Vector3<cell_idx_t> & extrapolationDirection ) const +{ + BodyField_T * bodyField = block->getData< BodyField_T >( bodyFieldID_ ); + + WALBERLA_ASSERT_NOT_NULLPTR( bodyField ); + WALBERLA_ASSERT_NOT_NULLPTR( (*bodyField)(x,y,z) ); + + real_t cx, cy, cz; + blockStorage_->getBlockLocalCellCenter( *block, Cell(x,y,z), cx, cy, cz ); + + Vector3<real_t> bodyCenterPosition = (*bodyField)(x,y,z)->getPosition(); + WALBERLA_ASSERT( !math::isnan(bodyCenterPosition) ); + + Vector3<real_t> bodyNormal( cx - bodyCenterPosition[0], cy - bodyCenterPosition[1], cz - bodyCenterPosition[2] ); + + findCorrespondingLatticeDirection< stencil::D3Q27 >( bodyNormal, extrapolationDirection ); +} + +} // namespace pe_coupling +} // namespace walberla diff --git a/src/pe_coupling/momentum_exchange_method/restoration/ExtrapolationDirectionFinder.h b/src/pe_coupling/momentum_exchange_method/restoration/ExtrapolationDirectionFinder.h index e23d38be85023d5d2976b62d0a995cb09a517de5..7e9968d83b16e7070931e6be79f7e79a92efba53 100644 --- a/src/pe_coupling/momentum_exchange_method/restoration/ExtrapolationDirectionFinder.h +++ b/src/pe_coupling/momentum_exchange_method/restoration/ExtrapolationDirectionFinder.h @@ -134,24 +134,5 @@ private: }; -void SphereNormalExtrapolationDirectionFinder -::getDirection( const cell_idx_t & x, const cell_idx_t & y, const cell_idx_t & z, IBlock * const block, Vector3<cell_idx_t> & extrapolationDirection ) const -{ - BodyField_T * bodyField = block->getData< BodyField_T >( bodyFieldID_ ); - - WALBERLA_ASSERT_NOT_NULLPTR( bodyField ); - WALBERLA_ASSERT_NOT_NULLPTR( (*bodyField)(x,y,z) ); - - real_t cx, cy, cz; - blockStorage_->getBlockLocalCellCenter( *block, Cell(x,y,z), cx, cy, cz ); - - Vector3<real_t> bodyCenterPosition = (*bodyField)(x,y,z)->getPosition(); - WALBERLA_ASSERT( !math::isnan(bodyCenterPosition) ); - - Vector3<real_t> bodyNormal( cx - bodyCenterPosition[0], cy - bodyCenterPosition[1], cz - bodyCenterPosition[2] ); - - findCorrespondingLatticeDirection< stencil::D3Q27 >( bodyNormal, extrapolationDirection ); -} - } // namespace pe_coupling } // namespace walberla diff --git a/src/pe_coupling/partially_saturated_cells_method/BodyAndVolumeFractionMapping.cpp b/src/pe_coupling/partially_saturated_cells_method/BodyAndVolumeFractionMapping.cpp new file mode 100644 index 0000000000000000000000000000000000000000..75ea1ed2f3f6870152d54fc0b921e1219fcc8a4a --- /dev/null +++ b/src/pe_coupling/partially_saturated_cells_method/BodyAndVolumeFractionMapping.cpp @@ -0,0 +1,235 @@ +//====================================================================================================================== +// +// 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 BodyAndVolumeFractionMapping.cpp +//! \ingroup pe_coupling +//! \author Christoph Rettinger <christoph.rettinger@fau.de> +// +//====================================================================================================================== + +#include "BodyAndVolumeFractionMapping.h" + +#include "geometry/bodies/BodyOverlapFunctions.h" + +#include "pe/rigidbody/BodyIterators.h" + +#include "pe_coupling/geometry/PeOverlapFraction.h" +#include "pe_coupling/mapping/BodyBBMapping.h" + +namespace walberla { +namespace pe_coupling { + + +void mapPSMBodyAndVolumeFraction( const pe::BodyID body, IBlock & block, StructuredBlockStorage & blockStorage, + const BlockDataID bodyAndVolumeFractionFieldID ) +{ + typedef std::pair< pe::BodyID, real_t > BodyAndVolumeFraction_T; + typedef GhostLayerField< std::vector< BodyAndVolumeFraction_T >, 1 > BodyAndVolumeFractionField_T; + + BodyAndVolumeFractionField_T * bodyAndVolumeFractionField = block.getData< BodyAndVolumeFractionField_T >( bodyAndVolumeFractionFieldID ); + WALBERLA_ASSERT_NOT_NULLPTR( bodyAndVolumeFractionField ); + + // get bounding box of body + CellInterval cellBB = getCellBB( body, block, blockStorage, bodyAndVolumeFractionField->nrOfGhostLayers() ); + + uint_t level = blockStorage.getLevel( block ); + Vector3<real_t> dxVec(blockStorage.dx(level), blockStorage.dy(level), blockStorage.dz(level)); + + for( auto cellIt = cellBB.begin(); cellIt != cellBB.end(); ++cellIt ) + { + Cell cell( *cellIt ); + + // get the cell's center + Vector3<real_t> cellCenter; + cellCenter = blockStorage.getBlockLocalCellCenter( block, cell ); + + const real_t fraction = overlapFractionPe( *body, cellCenter, dxVec ); + + // if the cell intersected with the body, store a pointer to that body and the corresponding volume fraction in the field + if( fraction > real_t(0) ) + { + bodyAndVolumeFractionField->get(cell).push_back( BodyAndVolumeFraction_T( body, fraction ) ); + } + } +} + + +void BodyAndVolumeFractionMapping::initialize() +{ + for( auto blockIt = blockStorage_->begin(); blockIt != blockStorage_->end(); ++blockIt ) + { + BodyAndVolumeFractionField_T * bodyAndVolumeFractionField = blockIt->getData< BodyAndVolumeFractionField_T >( bodyAndVolumeFractionFieldID_ ); + + if( updatedBodyAndVolumeFractionField_ == NULL ) + { + // hold internally an identical field for swapping + updatedBodyAndVolumeFractionField_ = shared_ptr<BodyAndVolumeFractionField_T>( bodyAndVolumeFractionField->cloneUninitialized() ); + + auto xyzFieldSize = updatedBodyAndVolumeFractionField_->xyzSize(); + for( auto fieldIt = xyzFieldSize.begin(); fieldIt != xyzFieldSize.end(); ++fieldIt ) + { + (updatedBodyAndVolumeFractionField_->get(*fieldIt)).clear(); + } + } + + // clear the field + auto xyzFieldSize = bodyAndVolumeFractionField->xyzSize(); + for( auto fieldIt = xyzFieldSize.begin(); fieldIt != xyzFieldSize.end(); ++fieldIt ) + { + (bodyAndVolumeFractionField->get(*fieldIt)).clear(); + } + + for( auto bodyIt = pe::BodyIterator::begin( *blockIt, bodyStorageID_); bodyIt != pe::BodyIterator::end(); ++bodyIt ) + { + if( mappingBodySelectorFct_(bodyIt.getBodyID()) ) + { + mapPSMBodyAndVolumeFraction(bodyIt.getBodyID(), *blockIt, *blockStorage_, bodyAndVolumeFractionFieldID_ ); + lastUpdatedPositionMap_.insert( std::pair< walberla::id_t, Vector3< real_t > >( bodyIt->getSystemID(), bodyIt->getPosition() ) ); + } + } + + for( auto bodyIt = globalBodyStorage_->begin(); bodyIt != globalBodyStorage_->end(); ++bodyIt ) + { + if( mappingBodySelectorFct_(bodyIt.getBodyID()) ) + { + mapPSMBodyAndVolumeFraction(bodyIt.getBodyID(), *blockIt, *blockStorage_, bodyAndVolumeFractionFieldID_); + lastUpdatedPositionMap_.insert( std::pair< walberla::id_t, Vector3< real_t > >( bodyIt->getSystemID(), bodyIt->getPosition() ) ); + } + } + + } +} + +void BodyAndVolumeFractionMapping::update() +{ + std::map< walberla::id_t, Vector3< real_t > > tempLastUpdatedPositionMap; + + for( auto blockIt = blockStorage_->begin(); blockIt != blockStorage_->end(); ++blockIt ) + { + BodyAndVolumeFractionField_T * bodyAndVolumeFractionField = blockIt->getData< BodyAndVolumeFractionField_T >( bodyAndVolumeFractionFieldID_ ); + + for( auto bodyIt = pe::BodyIterator::begin( *blockIt, bodyStorageID_); bodyIt != pe::BodyIterator::end(); ++bodyIt ) + { + if( mappingBodySelectorFct_(bodyIt.getBodyID()) ) + { + updatePSMBodyAndVolumeFraction(bodyIt.getBodyID(), *blockIt, bodyAndVolumeFractionField, tempLastUpdatedPositionMap); + } + } + + for( auto bodyIt = globalBodyStorage_->begin(); bodyIt != globalBodyStorage_->end(); ++bodyIt ) + { + if( mappingBodySelectorFct_(bodyIt.getBodyID()) ) + { + updatePSMBodyAndVolumeFraction(bodyIt.getBodyID(), *blockIt, bodyAndVolumeFractionField, tempLastUpdatedPositionMap); + } + } + + bodyAndVolumeFractionField->swapDataPointers( *updatedBodyAndVolumeFractionField_ ); + + auto xyzFieldSize = updatedBodyAndVolumeFractionField_->xyzSize(); + for( auto fieldIt = xyzFieldSize.begin(); fieldIt != xyzFieldSize.end(); ++fieldIt ) + { + (updatedBodyAndVolumeFractionField_->get(*fieldIt)).clear(); + } + } + + lastUpdatedPositionMap_ = tempLastUpdatedPositionMap; +} + +void BodyAndVolumeFractionMapping::updatePSMBodyAndVolumeFraction( pe::BodyID body, IBlock & block, + BodyAndVolumeFractionField_T * oldBodyAndVolumeFractionField, + std::map< walberla::id_t, Vector3< real_t > > & tempLastUpdatedPositionMap ) +{ + + WALBERLA_ASSERT_NOT_NULLPTR( oldBodyAndVolumeFractionField ); + + // estimate traveled distance since last volume fraction update + real_t traveledSquaredDistance( real_t(0) ); + auto mapBodyIt = lastUpdatedPositionMap_.find( body->getSystemID() ); + if( mapBodyIt != lastUpdatedPositionMap_.end() ) + { + // body found and traveled distance can be estimated + Vector3<real_t> distanceVec = body->getPosition() - mapBodyIt->second; + traveledSquaredDistance = distanceVec.sqrLength(); + } else + { + // body was not found in map -> is a new body, so no information is known + traveledSquaredDistance = std::numeric_limits<real_t>::max(); + } + + // get bounding box of body + CellInterval cellBB = getCellBB( body, block, *blockStorage_, oldBodyAndVolumeFractionField->nrOfGhostLayers() ); + + uint_t level = blockStorage_->getLevel( block ); + Vector3<real_t> dxVec(blockStorage_->dx(level), blockStorage_->dy(level), blockStorage_->dz(level)); + + // if body has not moved (specified by some epsilon), just reuse old fraction values + if( body->getLinearVel().sqrLength() < velocityUpdatingEpsilonSquared_ && + body->getAngularVel().sqrLength() < velocityUpdatingEpsilonSquared_ && + traveledSquaredDistance < positionUpdatingEpsilonSquared_ ) + { + for( cell_idx_t z = cellBB.zMin(); z <= cellBB.zMax(); ++z ) + { + for( cell_idx_t y = cellBB.yMin(); y <= cellBB.yMax(); ++y ) + { + for( cell_idx_t x = cellBB.xMin(); x <= cellBB.xMax(); ++x ) + { + + auto oldVec = oldBodyAndVolumeFractionField->get(x,y,z); + for( auto pairIt = oldVec.begin(); pairIt != oldVec.end(); ++pairIt ) + { + if( pairIt->first == body ) + { + updatedBodyAndVolumeFractionField_->get(x,y,z).push_back(*pairIt); + break; + } + } + } + } + } + tempLastUpdatedPositionMap.insert( std::pair< walberla::id_t, Vector3< real_t > >( body->getSystemID(), mapBodyIt->second ) ); + + } else + { + // else body has moved significantly or is new to this block, thus the volume fraction has to be calculated + for( cell_idx_t z = cellBB.zMin(); z <= cellBB.zMax(); ++z ) + { + for( cell_idx_t y = cellBB.yMin(); y <= cellBB.yMax(); ++y ) + { + for( cell_idx_t x = cellBB.xMin(); x <= cellBB.xMax(); ++x ) + { + // get the cell's center + Vector3<real_t> cellCenter; + cellCenter = blockStorage_->getBlockLocalCellCenter( block, Cell(x,y,z) ); + + const real_t fraction = overlapFractionPe( *body, cellCenter, dxVec, superSamplingDepth_ ); + + // if the cell intersected with the body, store a pointer to that body and the corresponding volume fraction in the field + if( fraction > real_t(0) ) + { + updatedBodyAndVolumeFractionField_->get(x,y,z).push_back( BodyAndVolumeFraction_T( body, fraction ) ); + } + } + } + } + + tempLastUpdatedPositionMap.insert( std::pair< walberla::id_t, Vector3< real_t > >( body->getSystemID(), body->getPosition() ) ); + } +} + + +} // namespace pe_coupling +} // namespace walberla + diff --git a/src/pe_coupling/partially_saturated_cells_method/BodyAndVolumeFractionMapping.h b/src/pe_coupling/partially_saturated_cells_method/BodyAndVolumeFractionMapping.h index 5f59d9754cb9e3edd911d1127d912244f5bdfae2..59fb85590fd9db424523e3f2c6cf6db0d9d84bef 100644 --- a/src/pe_coupling/partially_saturated_cells_method/BodyAndVolumeFractionMapping.h +++ b/src/pe_coupling/partially_saturated_cells_method/BodyAndVolumeFractionMapping.h @@ -22,16 +22,8 @@ #pragma once #include "domain_decomposition/StructuredBlockStorage.h" - #include "field/GhostLayerField.h" - -#include "geometry/bodies/BodyOverlapFunctions.h" - -#include "pe/rigidbody/BodyIterators.h" #include "pe/Types.h" - -#include "pe_coupling/geometry/PeOverlapFraction.h" -#include "pe_coupling/mapping/BodyBBMapping.h" #include "pe_coupling/utility/BodySelectorFunctions.h" #include <functional> @@ -49,37 +41,7 @@ namespace pe_coupling { * */ void mapPSMBodyAndVolumeFraction( const pe::BodyID body, IBlock & block, StructuredBlockStorage & blockStorage, - const BlockDataID bodyAndVolumeFractionFieldID ) -{ - typedef std::pair< pe::BodyID, real_t > BodyAndVolumeFraction_T; - typedef GhostLayerField< std::vector< BodyAndVolumeFraction_T >, 1 > BodyAndVolumeFractionField_T; - - BodyAndVolumeFractionField_T * bodyAndVolumeFractionField = block.getData< BodyAndVolumeFractionField_T >( bodyAndVolumeFractionFieldID ); - WALBERLA_ASSERT_NOT_NULLPTR( bodyAndVolumeFractionField ); - - // get bounding box of body - CellInterval cellBB = getCellBB( body, block, blockStorage, bodyAndVolumeFractionField->nrOfGhostLayers() ); - - uint_t level = blockStorage.getLevel( block ); - Vector3<real_t> dxVec(blockStorage.dx(level), blockStorage.dy(level), blockStorage.dz(level)); - - for( auto cellIt = cellBB.begin(); cellIt != cellBB.end(); ++cellIt ) - { - Cell cell( *cellIt ); - - // get the cell's center - Vector3<real_t> cellCenter; - cellCenter = blockStorage.getBlockLocalCellCenter( block, cell ); - - const real_t fraction = overlapFractionPe( *body, cellCenter, dxVec ); - - // if the cell intersected with the body, store a pointer to that body and the corresponding volume fraction in the field - if( fraction > real_t(0) ) - { - bodyAndVolumeFractionField->get(cell).push_back( BodyAndVolumeFraction_T( body, fraction ) ); - } - } -} + const BlockDataID bodyAndVolumeFractionFieldID ); /*!\brief Mapping class that can be used inside the timeloop to update the volume fractions and body mappings * @@ -154,168 +116,6 @@ private: const uint_t superSamplingDepth_; }; -void BodyAndVolumeFractionMapping::initialize() -{ - for( auto blockIt = blockStorage_->begin(); blockIt != blockStorage_->end(); ++blockIt ) - { - BodyAndVolumeFractionField_T * bodyAndVolumeFractionField = blockIt->getData< BodyAndVolumeFractionField_T >( bodyAndVolumeFractionFieldID_ ); - - if( updatedBodyAndVolumeFractionField_ == NULL ) - { - // hold internally an identical field for swapping - updatedBodyAndVolumeFractionField_ = shared_ptr<BodyAndVolumeFractionField_T>( bodyAndVolumeFractionField->cloneUninitialized() ); - - auto xyzFieldSize = updatedBodyAndVolumeFractionField_->xyzSize(); - for( auto fieldIt = xyzFieldSize.begin(); fieldIt != xyzFieldSize.end(); ++fieldIt ) - { - (updatedBodyAndVolumeFractionField_->get(*fieldIt)).clear(); - } - } - - // clear the field - auto xyzFieldSize = bodyAndVolumeFractionField->xyzSize(); - for( auto fieldIt = xyzFieldSize.begin(); fieldIt != xyzFieldSize.end(); ++fieldIt ) - { - (bodyAndVolumeFractionField->get(*fieldIt)).clear(); - } - - for( auto bodyIt = pe::BodyIterator::begin( *blockIt, bodyStorageID_); bodyIt != pe::BodyIterator::end(); ++bodyIt ) - { - if( mappingBodySelectorFct_(bodyIt.getBodyID()) ) - { - mapPSMBodyAndVolumeFraction(bodyIt.getBodyID(), *blockIt, *blockStorage_, bodyAndVolumeFractionFieldID_ ); - lastUpdatedPositionMap_.insert( std::pair< walberla::id_t, Vector3< real_t > >( bodyIt->getSystemID(), bodyIt->getPosition() ) ); - } - } - - for( auto bodyIt = globalBodyStorage_->begin(); bodyIt != globalBodyStorage_->end(); ++bodyIt ) - { - if( mappingBodySelectorFct_(bodyIt.getBodyID()) ) - { - mapPSMBodyAndVolumeFraction(bodyIt.getBodyID(), *blockIt, *blockStorage_, bodyAndVolumeFractionFieldID_); - lastUpdatedPositionMap_.insert( std::pair< walberla::id_t, Vector3< real_t > >( bodyIt->getSystemID(), bodyIt->getPosition() ) ); - } - } - - } -} - -void BodyAndVolumeFractionMapping::update() -{ - std::map< walberla::id_t, Vector3< real_t > > tempLastUpdatedPositionMap; - - for( auto blockIt = blockStorage_->begin(); blockIt != blockStorage_->end(); ++blockIt ) - { - BodyAndVolumeFractionField_T * bodyAndVolumeFractionField = blockIt->getData< BodyAndVolumeFractionField_T >( bodyAndVolumeFractionFieldID_ ); - - for( auto bodyIt = pe::BodyIterator::begin( *blockIt, bodyStorageID_); bodyIt != pe::BodyIterator::end(); ++bodyIt ) - { - if( mappingBodySelectorFct_(bodyIt.getBodyID()) ) - { - updatePSMBodyAndVolumeFraction(bodyIt.getBodyID(), *blockIt, bodyAndVolumeFractionField, tempLastUpdatedPositionMap); - } - } - - for( auto bodyIt = globalBodyStorage_->begin(); bodyIt != globalBodyStorage_->end(); ++bodyIt ) - { - if( mappingBodySelectorFct_(bodyIt.getBodyID()) ) - { - updatePSMBodyAndVolumeFraction(bodyIt.getBodyID(), *blockIt, bodyAndVolumeFractionField, tempLastUpdatedPositionMap); - } - } - - bodyAndVolumeFractionField->swapDataPointers( *updatedBodyAndVolumeFractionField_ ); - - auto xyzFieldSize = updatedBodyAndVolumeFractionField_->xyzSize(); - for( auto fieldIt = xyzFieldSize.begin(); fieldIt != xyzFieldSize.end(); ++fieldIt ) - { - (updatedBodyAndVolumeFractionField_->get(*fieldIt)).clear(); - } - } - - lastUpdatedPositionMap_ = tempLastUpdatedPositionMap; -} - -void BodyAndVolumeFractionMapping::updatePSMBodyAndVolumeFraction( pe::BodyID body, IBlock & block, - BodyAndVolumeFractionField_T * oldBodyAndVolumeFractionField, - std::map< walberla::id_t, Vector3< real_t > > & tempLastUpdatedPositionMap ) -{ - - WALBERLA_ASSERT_NOT_NULLPTR( oldBodyAndVolumeFractionField ); - - // estimate traveled distance since last volume fraction update - real_t traveledSquaredDistance( real_t(0) ); - auto mapBodyIt = lastUpdatedPositionMap_.find( body->getSystemID() ); - if( mapBodyIt != lastUpdatedPositionMap_.end() ) - { - // body found and traveled distance can be estimated - Vector3<real_t> distanceVec = body->getPosition() - mapBodyIt->second; - traveledSquaredDistance = distanceVec.sqrLength(); - } else - { - // body was not found in map -> is a new body, so no information is known - traveledSquaredDistance = std::numeric_limits<real_t>::max(); - } - - // get bounding box of body - CellInterval cellBB = getCellBB( body, block, *blockStorage_, oldBodyAndVolumeFractionField->nrOfGhostLayers() ); - - uint_t level = blockStorage_->getLevel( block ); - Vector3<real_t> dxVec(blockStorage_->dx(level), blockStorage_->dy(level), blockStorage_->dz(level)); - - // if body has not moved (specified by some epsilon), just reuse old fraction values - if( body->getLinearVel().sqrLength() < velocityUpdatingEpsilonSquared_ && - body->getAngularVel().sqrLength() < velocityUpdatingEpsilonSquared_ && - traveledSquaredDistance < positionUpdatingEpsilonSquared_ ) - { - for( cell_idx_t z = cellBB.zMin(); z <= cellBB.zMax(); ++z ) - { - for( cell_idx_t y = cellBB.yMin(); y <= cellBB.yMax(); ++y ) - { - for( cell_idx_t x = cellBB.xMin(); x <= cellBB.xMax(); ++x ) - { - - auto oldVec = oldBodyAndVolumeFractionField->get(x,y,z); - for( auto pairIt = oldVec.begin(); pairIt != oldVec.end(); ++pairIt ) - { - if( pairIt->first == body ) - { - updatedBodyAndVolumeFractionField_->get(x,y,z).push_back(*pairIt); - break; - } - } - } - } - } - tempLastUpdatedPositionMap.insert( std::pair< walberla::id_t, Vector3< real_t > >( body->getSystemID(), mapBodyIt->second ) ); - - } else - { - // else body has moved significantly or is new to this block, thus the volume fraction has to be calculated - for( cell_idx_t z = cellBB.zMin(); z <= cellBB.zMax(); ++z ) - { - for( cell_idx_t y = cellBB.yMin(); y <= cellBB.yMax(); ++y ) - { - for( cell_idx_t x = cellBB.xMin(); x <= cellBB.xMax(); ++x ) - { - // get the cell's center - Vector3<real_t> cellCenter; - cellCenter = blockStorage_->getBlockLocalCellCenter( block, Cell(x,y,z) ); - - const real_t fraction = overlapFractionPe( *body, cellCenter, dxVec, superSamplingDepth_ ); - - // if the cell intersected with the body, store a pointer to that body and the corresponding volume fraction in the field - if( fraction > real_t(0) ) - { - updatedBodyAndVolumeFractionField_->get(x,y,z).push_back( BodyAndVolumeFraction_T( body, fraction ) ); - } - } - } - } - - tempLastUpdatedPositionMap.insert( std::pair< walberla::id_t, Vector3< real_t > >( body->getSystemID(), body->getPosition() ) ); - } -} } // namespace pe_coupling diff --git a/src/pe_coupling/utility/BodiesForceTorqueContainer.cpp b/src/pe_coupling/utility/BodiesForceTorqueContainer.cpp new file mode 100644 index 0000000000000000000000000000000000000000..bed1c267c35770e232638d6b423e283cf3bc9172 --- /dev/null +++ b/src/pe_coupling/utility/BodiesForceTorqueContainer.cpp @@ -0,0 +1,97 @@ +//====================================================================================================================== +// +// 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 BodiesForceTorqueContainer.cpp +//! \ingroup pe_coupling +//! \author Christoph Rettinger <christoph.rettinger@fau.de> +// +//====================================================================================================================== + +#include "BodiesForceTorqueContainer.h" + +#include "blockforest/StructuredBlockForest.h" +#include "core/math/Vector3.h" +#include "pe/rigidbody/BodyIterators.h" + +namespace walberla { +namespace pe_coupling { + + + +void BodiesForceTorqueContainer::store() +{ + // clear map + clear(); + + // (re-)build map + for( auto blockIt = blockForest_->begin(); blockIt != blockForest_->end(); ++blockIt ) + { + auto bodyForceTorqueStorage = blockIt->getData<ForceTorqueStorage_T>(bodyForceTorqueStorageID_); + + for( auto bodyIt = pe::BodyIterator::begin(*blockIt, bodyStorageID_); bodyIt != pe::BodyIterator::end(); ++bodyIt ) + { + auto & f = (*bodyForceTorqueStorage)[ bodyIt->getSystemID() ]; + + const auto & force = bodyIt->getForce(); + const auto & torque = bodyIt->getTorque(); + f = {{force[0], force[1], force[2], torque[0], torque[1], torque[2] }}; + } + } +} + +void BodiesForceTorqueContainer::setOnBodies() +{ + // set the force/torque stored in the block-local map onto all bodies + for( auto blockIt = blockForest_->begin(); blockIt != blockForest_->end(); ++blockIt ) + { + auto bodyForceTorqueStorage = blockIt->getData<ForceTorqueStorage_T>(bodyForceTorqueStorageID_); + + for( auto bodyIt = pe::BodyIterator::begin(*blockIt, bodyStorageID_); bodyIt != pe::BodyIterator::end(); ++bodyIt ) + { + const auto f = bodyForceTorqueStorage->find( bodyIt->getSystemID() ); + + if( f != bodyForceTorqueStorage->end() ) + { + const auto & ftValues = f->second; + bodyIt->addForce ( ftValues[0], ftValues[1], ftValues[2] ); + bodyIt->addTorque( ftValues[3], ftValues[4], ftValues[5] ); + } + // else: new body has arrived that was not known before + } + } +} + +void BodiesForceTorqueContainer::clear() +{ + for( auto blockIt = blockForest_->begin(); blockIt != blockForest_->end(); ++blockIt ) + { + auto bodyForceTorqueStorage = blockIt->getData<ForceTorqueStorage_T>(bodyForceTorqueStorageID_); + bodyForceTorqueStorage->clear(); + } +} + +void BodiesForceTorqueContainer::swap( BodiesForceTorqueContainer & other ) +{ + std::swap( bodyForceTorqueStorageID_, other.bodyForceTorqueStorageID_); +} + + + + + + + +} // namespace pe_coupling +} // namespace walberla diff --git a/src/pe_coupling/utility/BodiesForceTorqueContainer.h b/src/pe_coupling/utility/BodiesForceTorqueContainer.h index d69b6791b23734526521e10a3b42a6acb8b5f6bf..fe367b5e095075f7882c19f9cf213d793be40351 100644 --- a/src/pe_coupling/utility/BodiesForceTorqueContainer.h +++ b/src/pe_coupling/utility/BodiesForceTorqueContainer.h @@ -22,9 +22,6 @@ #pragma once #include "blockforest/StructuredBlockForest.h" -#include "core/math/Vector3.h" -#include "pe/rigidbody/BodyIterators.h" -#include "pe/synchronization/SyncForces.h" #include <map> #include <array> @@ -50,63 +47,13 @@ public: store(); } - void store() - { - // clear map - clear(); - - // (re-)build map - for( auto blockIt = blockForest_->begin(); blockIt != blockForest_->end(); ++blockIt ) - { - auto bodyForceTorqueStorage = blockIt->getData<ForceTorqueStorage_T>(bodyForceTorqueStorageID_); - - for( auto bodyIt = pe::BodyIterator::begin(*blockIt, bodyStorageID_); bodyIt != pe::BodyIterator::end(); ++bodyIt ) - { - auto & f = (*bodyForceTorqueStorage)[ bodyIt->getSystemID() ]; - - const auto & force = bodyIt->getForce(); - const auto & torque = bodyIt->getTorque(); - f = {{force[0], force[1], force[2], torque[0], torque[1], torque[2] }}; - } - } - - } + void store(); - void setOnBodies() - { - // set the force/torque stored in the block-local map onto all bodies - for( auto blockIt = blockForest_->begin(); blockIt != blockForest_->end(); ++blockIt ) - { - auto bodyForceTorqueStorage = blockIt->getData<ForceTorqueStorage_T>(bodyForceTorqueStorageID_); - - for( auto bodyIt = pe::BodyIterator::begin(*blockIt, bodyStorageID_); bodyIt != pe::BodyIterator::end(); ++bodyIt ) - { - const auto f = bodyForceTorqueStorage->find( bodyIt->getSystemID() ); - - if( f != bodyForceTorqueStorage->end() ) - { - const auto & ftValues = f->second; - bodyIt->addForce ( ftValues[0], ftValues[1], ftValues[2] ); - bodyIt->addTorque( ftValues[3], ftValues[4], ftValues[5] ); - } - // else: new body has arrived that was not known before - } - } - } + void setOnBodies(); - void clear() - { - for( auto blockIt = blockForest_->begin(); blockIt != blockForest_->end(); ++blockIt ) - { - auto bodyForceTorqueStorage = blockIt->getData<ForceTorqueStorage_T>(bodyForceTorqueStorageID_); - bodyForceTorqueStorage->clear(); - } - } + void clear(); - void swap( BodiesForceTorqueContainer & other ) - { - std::swap( bodyForceTorqueStorageID_, other.bodyForceTorqueStorageID_); - } + void swap( BodiesForceTorqueContainer & other ); private: diff --git a/src/pe_coupling/utility/ForceOnBodiesAdder.cpp b/src/pe_coupling/utility/ForceOnBodiesAdder.cpp new file mode 100644 index 0000000000000000000000000000000000000000..4c7c17f8376763af77004bedb8cd83186515460e --- /dev/null +++ b/src/pe_coupling/utility/ForceOnBodiesAdder.cpp @@ -0,0 +1,49 @@ +//====================================================================================================================== +// +// 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 ForceOnBodiesAdder.cpp +//! \ingroup pe_coupling +//! \author Christoph Rettinger <christoph.rettinger@fau.de> +// +//====================================================================================================================== + +#include "ForceOnBodiesAdder.h" + +#include "core/math/Vector3.h" +#include "domain_decomposition/StructuredBlockStorage.h" +#include "pe/rigidbody/BodyIterators.h" + + +namespace walberla { +namespace pe_coupling { + +void ForceOnBodiesAdder::operator()() +{ + for( auto blockIt = blockStorage_->begin(); blockIt != blockStorage_->end(); ++blockIt ) + { + for( auto bodyIt = pe::LocalBodyIterator::begin( *blockIt, bodyStorageID_); bodyIt != pe::LocalBodyIterator::end(); ++bodyIt ) + { + bodyIt->addForce ( force_ ); + } + } +} + +void ForceOnBodiesAdder::updateForce( const Vector3<real_t> & newForce ) +{ + force_ = newForce; +} + +} // namespace pe_coupling +} // namespace walberla diff --git a/src/pe_coupling/utility/ForceOnBodiesAdder.h b/src/pe_coupling/utility/ForceOnBodiesAdder.h index 2d6e3f4ead588cc83b1fbc147e76fed8d4a1d38c..b0b7056d52aa54498197317eb48f4fdf294c4b0b 100644 --- a/src/pe_coupling/utility/ForceOnBodiesAdder.h +++ b/src/pe_coupling/utility/ForceOnBodiesAdder.h @@ -23,8 +23,6 @@ #include "core/math/Vector3.h" #include "domain_decomposition/StructuredBlockStorage.h" -#include "pe/rigidbody/BodyIterators.h" - namespace walberla { namespace pe_coupling { @@ -39,21 +37,9 @@ public: { } // set a constant force on all (only local, to avoid force duplication) bodies - void operator()() - { - for( auto blockIt = blockStorage_->begin(); blockIt != blockStorage_->end(); ++blockIt ) - { - for( auto bodyIt = pe::LocalBodyIterator::begin( *blockIt, bodyStorageID_); bodyIt != pe::LocalBodyIterator::end(); ++bodyIt ) - { - bodyIt->addForce ( force_ ); - } - } - } + void operator()(); - void updateForce( const Vector3<real_t> & newForce ) - { - force_ = newForce; - } + void updateForce( const Vector3<real_t> & newForce ); private: diff --git a/src/pe_coupling/utility/ForceTorqueOnBodiesResetter.cpp b/src/pe_coupling/utility/ForceTorqueOnBodiesResetter.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e3301650a01ce5b2a5a6cfc7f517576891ddfaf4 --- /dev/null +++ b/src/pe_coupling/utility/ForceTorqueOnBodiesResetter.cpp @@ -0,0 +1,41 @@ +//====================================================================================================================== +// +// 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 ForceTorqueOnBodiesResetter.cpp +//! \ingroup pe_coupling +//! \author Christoph Rettinger <christoph.rettinger@fau.de> +// +//====================================================================================================================== + +#include "ForceTorqueOnBodiesResetter.h" + +#include "pe/rigidbody/BodyIterators.h" + +namespace walberla { +namespace pe_coupling { + +void ForceTorqueOnBodiesResetter::operator()() +{ + for( auto blockIt = blockStorage_->begin(); blockIt != blockStorage_->end(); ++blockIt ) + { + for( auto bodyIt = pe::BodyIterator::begin( *blockIt, bodyStorageID_); bodyIt != pe::BodyIterator::end(); ++bodyIt ) + { + bodyIt->resetForceAndTorque(); + } + } +} + +} // namespace pe_coupling +} // namespace walberla diff --git a/src/pe_coupling/utility/ForceTorqueOnBodiesResetter.h b/src/pe_coupling/utility/ForceTorqueOnBodiesResetter.h index c42e96b0c9cd6bdbac95688654aa9d4b1b979e17..a86368f83fdaf26b4f2c586ac90f178042d567f6 100644 --- a/src/pe_coupling/utility/ForceTorqueOnBodiesResetter.h +++ b/src/pe_coupling/utility/ForceTorqueOnBodiesResetter.h @@ -21,10 +21,7 @@ #pragma once -#include "core/math/Vector3.h" #include "domain_decomposition/StructuredBlockStorage.h" -#include "pe/rigidbody/BodyIterators.h" - namespace walberla { namespace pe_coupling { @@ -38,17 +35,7 @@ public: { } // resets forces and torques on all (local and remote) bodies - void operator()() - { - for( auto blockIt = blockStorage_->begin(); blockIt != blockStorage_->end(); ++blockIt ) - { - for( auto bodyIt = pe::BodyIterator::begin( *blockIt, bodyStorageID_); bodyIt != pe::BodyIterator::end(); ++bodyIt ) - { - bodyIt->resetForceAndTorque(); - } - } - } - + void operator()(); private: diff --git a/src/pe_coupling/utility/ForceTorqueOnBodiesScaler.cpp b/src/pe_coupling/utility/ForceTorqueOnBodiesScaler.cpp new file mode 100644 index 0000000000000000000000000000000000000000..677c5788d7dea105e6952d911d9d8942deb0cbce --- /dev/null +++ b/src/pe_coupling/utility/ForceTorqueOnBodiesScaler.cpp @@ -0,0 +1,55 @@ +//====================================================================================================================== +// +// 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 ForceTorqueOnBodiesScaler.cpp +//! \ingroup pe_coupling +//! \author Christoph Rettinger <christoph.rettinger@fau.de> +// +//====================================================================================================================== + +#include "ForceTorqueOnBodiesScaler.h" + +#include "core/math/Vector3.h" +#include "pe/rigidbody/BodyIterators.h" + +namespace walberla { +namespace pe_coupling { + +void ForceTorqueOnBodiesScaler::operator()() +{ + Vector3<real_t> force(real_t(0)); + Vector3<real_t> torque(real_t(0)); + for( auto blockIt = blockStorage_->begin(); blockIt != blockStorage_->end(); ++blockIt ) + { + for( auto bodyIt = pe::BodyIterator::begin( *blockIt, bodyStorageID_); bodyIt != pe::BodyIterator::end(); ++bodyIt ) + { + force = scalingFactor_ * bodyIt->getForce(); + torque = scalingFactor_ * bodyIt->getTorque(); + + bodyIt->resetForceAndTorque(); + + bodyIt->setForce ( force ); + bodyIt->setTorque( torque ); + } + } +} + +void ForceTorqueOnBodiesScaler::resetScalingFactor( const real_t newScalingFactor ) +{ + scalingFactor_ = newScalingFactor; +} + +} // namespace pe_coupling +} // namespace walberla diff --git a/src/pe_coupling/utility/ForceTorqueOnBodiesScaler.h b/src/pe_coupling/utility/ForceTorqueOnBodiesScaler.h index ead115a69ea789ec629c600d396b7c2028d6fa7e..f903e8ddc1606112f60dbf19a872379077a4c325 100644 --- a/src/pe_coupling/utility/ForceTorqueOnBodiesScaler.h +++ b/src/pe_coupling/utility/ForceTorqueOnBodiesScaler.h @@ -21,15 +21,12 @@ #pragma once -#include "core/math/Vector3.h" #include "domain_decomposition/StructuredBlockStorage.h" -#include "pe/rigidbody/BodyIterators.h" - namespace walberla { namespace pe_coupling { -// scales force/torquew on all bodies (local and remote) by a constant scalar value +// scales force/torque on all bodies (local and remote) by a constant scalar value // can e.g. be used to average the force/torque over two time steps class ForceTorqueOnBodiesScaler { @@ -41,29 +38,9 @@ public: { } // resets forces and torques on all (local and remote) bodies - void operator()() - { - Vector3<real_t> force(real_t(0)); - Vector3<real_t> torque(real_t(0)); - for( auto blockIt = blockStorage_->begin(); blockIt != blockStorage_->end(); ++blockIt ) - { - for( auto bodyIt = pe::BodyIterator::begin( *blockIt, bodyStorageID_); bodyIt != pe::BodyIterator::end(); ++bodyIt ) - { - force = scalingFactor_ * bodyIt->getForce(); - torque = scalingFactor_ * bodyIt->getTorque(); - - bodyIt->resetForceAndTorque(); - - bodyIt->setForce ( force ); - bodyIt->setTorque( torque ); - } - } - } + void operator()(); - void resetScalingFactor( const real_t newScalingFactor ) - { - scalingFactor_ = newScalingFactor; - } + void resetScalingFactor( const real_t newScalingFactor ); private: diff --git a/src/pe_coupling/utility/LubricationCorrection.cpp b/src/pe_coupling/utility/LubricationCorrection.cpp new file mode 100644 index 0000000000000000000000000000000000000000..eaf1952149fc4c35d7b6b45b23549c3516557f76 --- /dev/null +++ b/src/pe_coupling/utility/LubricationCorrection.cpp @@ -0,0 +1,278 @@ +//====================================================================================================================== +// +// 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 LubricationCorrection.cpp +//! \ingroup pe_coupling +//! \author Kristina Pickl <kristina.pickl@fau.de> +//! \author Dominik Bartuschat +//! \author Christoph Rettinger <christoph.rettinger@fau.de> +//! \author Sebastian Eibl <sebastian.eibl@fau.de> +// +//====================================================================================================================== + +#include "LubricationCorrection.h" + +#include "core/logging/all.h" +#include "core/debug/Debug.h" + +#include "pe/rigidbody/BodyIterators.h" +#include "pe/utility/Distance.h" + +namespace walberla { +namespace pe_coupling { + +void LubricationCorrection::operator ()() +{ + WALBERLA_LOG_PROGRESS( "Calculating Lubrication Force" ); + + for (auto blockIt = blockStorage_->begin(); blockIt != blockStorage_->end(); ++blockIt) + { + // loop over all rigid bodies + for( auto body1It = pe::BodyIterator::begin( *blockIt, bodyStorageID_ ); body1It != pe::BodyIterator::end(); ++body1It ) + { + // lubrication forces for spheres + if ( body1It->getTypeID() == pe::Sphere::getStaticTypeID() ) + { + pe::SphereID sphereI = static_cast<pe::SphereID> ( body1It.getBodyID() ); + + auto copyBody1It = body1It; + // loop over all rigid bodies after current body1 to avoid double forces + for( auto body2It = (++copyBody1It); body2It != pe::BodyIterator::end(); ++body2It ) + { + // sphere-sphere lubrication + if ( body2It->getTypeID() == pe::Sphere::getStaticTypeID() ) + { + pe::SphereID sphereJ = static_cast<pe::SphereID>( body2It.getBodyID() ); + treatLubricationSphrSphr( sphereI, sphereJ, blockIt->getAABB() ); + } + } + } + } + + // lubrication correction for local bodies with global bodies (for example sphere-plane) + for( auto body1It = pe::LocalBodyIterator::begin( *blockIt, bodyStorageID_ ); body1It != pe::LocalBodyIterator::end(); ++body1It ) + { + if ( body1It->getTypeID() == pe::Sphere::getStaticTypeID() ) + { + pe::SphereID sphereI = static_cast<pe::SphereID> ( body1It.getBodyID() ); + + for (auto body2It = globalBodyStorage_->begin(); body2It != globalBodyStorage_->end(); ++body2It) + { + if ( body2It->getTypeID() == pe::Plane::getStaticTypeID() ) + { + // sphere-plane lubrication + pe::PlaneID planeJ = static_cast<pe::PlaneID>( body2It.getBodyID() ); + treatLubricationSphrPlane( sphereI, planeJ ); + } else if ( body2It->getTypeID() == pe::Sphere::getStaticTypeID() ) + { + // sphere-sphere lubrication + pe::SphereID sphereJ = static_cast<pe::SphereID>( body2It.getBodyID() ); + treatLubricationSphrSphr( sphereI, sphereJ, blockIt->getAABB() ); + } + } + } + } + } +} +//***************************************************************************************************************************************** + + + +////////////////////// +// Helper Functions // +////////////////////// + +void LubricationCorrection::treatLubricationSphrSphr( const pe::SphereID sphereI, const pe::SphereID sphereJ, const math::AABB & blockAABB ) +{ + + WALBERLA_ASSERT_UNEQUAL( sphereI->getSystemID(), sphereJ->getSystemID() ); + + real_t gap = pe::getSurfaceDistance( sphereI, sphereJ ); + + if ( gap > cutOffDistance_ || gap < real_t(0) ) + { + WALBERLA_LOG_DETAIL("gap " << gap << " larger than cutOff " << cutOffDistance_ << " - ignoring pair"); + return; + } + + if ( gap < minimalGapSize_ ) + { + WALBERLA_LOG_DETAIL("gap " << gap << " smaller than minimal gap " << minimalGapSize_ << " - using minimal gap"); + gap = minimalGapSize_; + } + + const pe::Vec3 &posSphereI = sphereI->getPosition(); + const pe::Vec3 &posSphereJ = sphereJ->getPosition(); + pe::Vec3 fLub(0); + + // compute (global) coordinate between spheres' centers of gravity + pe::Vec3 midPoint( (posSphereI + posSphereJ ) * real_c(0.5) ); + + // Let process on which midPoint lies do the lubrication correction + // or the local process of sphereI if sphereJ is global + if ( blockAABB.contains(midPoint) || sphereJ->isGlobal() ) + { + fLub = compLubricationSphrSphr(gap, sphereI, sphereJ); + sphereI->addForce( fLub); + sphereJ->addForce(-fLub); + + WALBERLA_LOG_DETAIL( "Lubrication force on sphere " << sphereI->getID() << " from sphere " << sphereJ->getID() << " is:" << fLub); + WALBERLA_LOG_DETAIL( "Lubrication force on sphere " << sphereJ->getID() << " from sphere " << sphereI->getID() << " is:" << -fLub << "\n"); + } + +} + +void LubricationCorrection::treatLubricationSphrPlane( const pe::SphereID sphereI, const pe::ConstPlaneID planeJ ) +{ + + real_t gap = pe::getSurfaceDistance( sphereI, planeJ ); + + if ( gap > cutOffDistance_ || gap < real_t(0) ) + { + WALBERLA_LOG_DETAIL("gap " << gap << " larger than cutOff " << cutOffDistance_ << " - ignoring pair"); + return; + } + + if ( gap < minimalGapSize_ ) + { + WALBERLA_LOG_DETAIL("gap " << gap << " smaller than minimal gap " << minimalGapSize_ << " - using minimal gap"); + gap = minimalGapSize_; + } + + pe::Vec3 fLub = compLubricationSphrPlane( gap, sphereI, planeJ); + + WALBERLA_LOG_DETAIL( "Lubrication force on sphere " << sphereI->getID() << " to plane with id " << planeJ->getID() << " is:" << fLub << std::endl ); + sphereI->addForce( fLub ); + +} + + + +//***************************************************************************************************************************************** +/*! \brief Computes lubrication correction force between spheres. + * \ingroup pe_coupling + * + * Lubrication correction according to Ladd and Verberg, 2001 + * ("Lattice-Boltzmann Simulations of Particle-Fluid Suspensions") + * + * Note: Verified quantitatively by computation in spreadsheet + * and qualitatively by considering direction of force for example setup. + */ +//***************************************************************************************************************************************** +pe::Vec3 LubricationCorrection::compLubricationSphrSphr( real_t gap, const pe::SphereID sphereI, const pe::SphereID sphereJ) const +{ + const pe::Vec3 &posSphereI = sphereI->getPosition(); + const pe::Vec3 &posSphereJ = sphereJ->getPosition(); + + const pe::Vec3 &tmpVec = posSphereJ - posSphereI; + const pe::Vec3 &rIJ = tmpVec.getNormalized(); + + real_t radiusSphereI = sphereI->getRadius(); + real_t radiusSphereJ = sphereJ->getRadius(); + + pe::Vec3 velDiff(sphereI->getLinearVel() - sphereJ->getLinearVel()); + + real_t length = velDiff * rIJ; + + real_t radiiSQR = ( radiusSphereI * radiusSphereJ ) * ( radiusSphereI * radiusSphereJ ); + real_t radiiSumSQR = ( radiusSphereI + radiusSphereJ ) * ( radiusSphereI + radiusSphereJ ); + + pe::Vec3 fLub = ( -real_t(6) * dynamicViscosity_ * walberla::math::PI * radiiSQR / radiiSumSQR * ( real_t(1) / gap - real_t(1) / cutOffDistance_) * length * rIJ); + + WALBERLA_LOG_DETAIL_SECTION() + { + std::stringstream ss; + ss << "Sphere I: \n uid:" << sphereI->getID() << "\n"; + ss << "vel: " << sphereI->getLinearVel() << "\n"; + ss << "rad: " << radiusSphereI << "\n"; + ss << "pos: " << posSphereI << "\n\n"; + + ss << "Sphere J: \n uid:" << sphereJ->getID() << "\n"; + ss << "vel: " << sphereJ->getLinearVel() << "\n"; + ss << "rad: " << radiusSphereJ << "\n"; + ss << "pos: " << posSphereJ << "\n\n"; + + real_t distance = gap + radiusSphereI + radiusSphereJ; + ss << "distance: " << distance << "\n"; + ss << "viscosity: " << dynamicViscosity_ << "\n"; + + ss << "gap: " << gap << "\n"; + ss << "cutOff: " << cutOffDistance_ << "\n"; + ss << "velDiff " << velDiff << "\n"; + ss << "rIJ " << rIJ << "\n\n"; + + ss << "Resulting lubrication force: " << fLub << "\n"; + + WALBERLA_LOG_DETAIL( ss.str() ); + } + + return fLub; +} +//***************************************************************************************************************************************** + + + +//***************************************************************************************************************************************** +/*! \brief Computes lubrication correction force between sphere and wall. + * \ingroup pe_coupling + * + * Lubrication correction according to Ladd and Verberg, 2001 + * ("Lattice-Boltzmann Simulations of Particle-Fluid Suspensions" ) + * + * Note: Verified quantitatively by computation in spreadsheet + * and qualitatively by considering direction of force for example setup. + */ +//***************************************************************************************************************************************** +pe::Vec3 LubricationCorrection::compLubricationSphrPlane( real_t gap, const pe::SphereID sphereI, const pe::ConstPlaneID planeJ) const +{ + const pe::Vec3 &posSphereI( sphereI->getPosition() ); + real_t radiusSphereI = sphereI->getRadius(); + + const pe::Vec3 &planeNormal( planeJ->getNormal() ); // took negative of normal from sphere to plane (plane's normal) - sign cancels out anyway + pe::Vec3 rIJ( planeNormal.getNormalized() ); // for safety reasons, normalize normal + + real_t length = sphereI->getLinearVel() * rIJ; + + real_t radiiSQR = radiusSphereI * radiusSphereI; + + pe::Vec3 fLub( -real_t(6) * dynamicViscosity_ * walberla::math::PI * radiiSQR * (real_t(1) / gap - real_t(1) / cutOffDistance_) * length * rIJ); + + WALBERLA_LOG_DETAIL_SECTION() { + std::stringstream ss; + ss << "Sphere I: \n uid:" << sphereI->getID() << "\n"; + ss << "vel: " << sphereI->getLinearVel() << "\n"; + ss << "rad: " << radiusSphereI << "\n"; + ss << "pos: " << posSphereI << "\n\n"; + + real_t distance = gap + radiusSphereI; + ss << "distance: " << distance << "\n"; + ss << "viscosity: " << dynamicViscosity_ << "\n"; + + ss << "gap: " << gap << "\n"; + ss << "cutOff: " << cutOffDistance_ << "\n"; + ss << "velDiff " << sphereI->getLinearVel() << "\n"; + ss << "rIJ " << -rIJ << "\n\n"; + + ss << "Resulting lubrication force: " << fLub << "\n"; + + WALBERLA_LOG_DETAIL( ss.str() ); + } + + return fLub; +} + + +} // pe_coupling +} // walberla diff --git a/src/pe_coupling/utility/LubricationCorrection.h b/src/pe_coupling/utility/LubricationCorrection.h index 4a5afa830d09352ff53ae87c69e88c96c7533eae..b4f34181505f1a42472222875c72f74596f62162 100644 --- a/src/pe_coupling/utility/LubricationCorrection.h +++ b/src/pe_coupling/utility/LubricationCorrection.h @@ -24,15 +24,11 @@ #pragma once -#include "core/logging/all.h" -#include "core/debug/Debug.h" -#include "domain_decomposition/BlockStorage.h" -#include "lbm/field/PdfField.h" -#include "pe/rigidbody/BodyIterators.h" +#include "domain_decomposition/StructuredBlockStorage.h" + #include "pe/rigidbody/Plane.h" #include "pe/rigidbody/Sphere.h" -#include "pe/utility/Distance.h" namespace walberla { namespace pe_coupling { @@ -67,7 +63,6 @@ private: // member variables shared_ptr<StructuredBlockStorage> blockStorage_; shared_ptr<pe::BodyStorage> globalBodyStorage_; - const BlockDataID pdfFieldID_; const BlockDataID bodyStorageID_; real_t dynamicViscosity_; @@ -76,247 +71,5 @@ private: }; // class LubricationCorrection - -void LubricationCorrection::operator ()() -{ - WALBERLA_LOG_PROGRESS( "Calculating Lubrication Force" ); - - for (auto blockIt = blockStorage_->begin(); blockIt != blockStorage_->end(); ++blockIt) - { - // loop over all rigid bodies - for( auto body1It = pe::BodyIterator::begin( *blockIt, bodyStorageID_ ); body1It != pe::BodyIterator::end(); ++body1It ) - { - // lubrication forces for spheres - if ( body1It->getTypeID() == pe::Sphere::getStaticTypeID() ) - { - pe::SphereID sphereI = static_cast<pe::SphereID> ( body1It.getBodyID() ); - - auto copyBody1It = body1It; - // loop over all rigid bodies after current body1 to avoid double forces - for( auto body2It = (++copyBody1It); body2It != pe::BodyIterator::end(); ++body2It ) - { - // sphere-sphere lubrication - if ( body2It->getTypeID() == pe::Sphere::getStaticTypeID() ) - { - pe::SphereID sphereJ = static_cast<pe::SphereID>( body2It.getBodyID() ); - treatLubricationSphrSphr( sphereI, sphereJ, blockIt->getAABB() ); - } - } - } - } - - // lubrication correction for local bodies with global bodies (for example sphere-plane) - for( auto body1It = pe::LocalBodyIterator::begin( *blockIt, bodyStorageID_ ); body1It != pe::LocalBodyIterator::end(); ++body1It ) - { - if ( body1It->getTypeID() == pe::Sphere::getStaticTypeID() ) - { - pe::SphereID sphereI = static_cast<pe::SphereID> ( body1It.getBodyID() ); - - for (auto body2It = globalBodyStorage_->begin(); body2It != globalBodyStorage_->end(); ++body2It) - { - if ( body2It->getTypeID() == pe::Plane::getStaticTypeID() ) - { - // sphere-plane lubrication - pe::PlaneID planeJ = static_cast<pe::PlaneID>( body2It.getBodyID() ); - treatLubricationSphrPlane( sphereI, planeJ ); - } else if ( body2It->getTypeID() == pe::Sphere::getStaticTypeID() ) - { - // sphere-sphere lubrication - pe::SphereID sphereJ = static_cast<pe::SphereID>( body2It.getBodyID() ); - treatLubricationSphrSphr( sphereI, sphereJ, blockIt->getAABB() ); - } - } - } - } - } -} -//***************************************************************************************************************************************** - - - -////////////////////// -// Helper Functions // -////////////////////// - -void LubricationCorrection::treatLubricationSphrSphr( const pe::SphereID sphereI, const pe::SphereID sphereJ, const math::AABB & blockAABB ) -{ - - WALBERLA_ASSERT_UNEQUAL( sphereI->getSystemID(), sphereJ->getSystemID() ); - - real_t gap = pe::getSurfaceDistance( sphereI, sphereJ ); - - if ( gap > cutOffDistance_ || gap < real_t(0) ) - { - WALBERLA_LOG_DETAIL("gap " << gap << " larger than cutOff " << cutOffDistance_ << " - ignoring pair"); - return; - } - - if ( gap < minimalGapSize_ ) - { - WALBERLA_LOG_DETAIL("gap " << gap << " smaller than minimal gap " << minimalGapSize_ << " - using minimal gap"); - gap = minimalGapSize_; - } - - const pe::Vec3 &posSphereI = sphereI->getPosition(); - const pe::Vec3 &posSphereJ = sphereJ->getPosition(); - pe::Vec3 fLub(0); - - // compute (global) coordinate between spheres' centers of gravity - pe::Vec3 midPoint( (posSphereI + posSphereJ ) * real_c(0.5) ); - - // Let process on which midPoint lies do the lubrication correction - // or the local process of sphereI if sphereJ is global - if ( blockAABB.contains(midPoint) || sphereJ->isGlobal() ) - { - fLub = compLubricationSphrSphr(gap, sphereI, sphereJ); - sphereI->addForce( fLub); - sphereJ->addForce(-fLub); - - WALBERLA_LOG_DETAIL( "Lubrication force on sphere " << sphereI->getID() << " from sphere " << sphereJ->getID() << " is:" << fLub); - WALBERLA_LOG_DETAIL( "Lubrication force on sphere " << sphereJ->getID() << " from sphere " << sphereI->getID() << " is:" << -fLub << "\n"); - } - -} - -void LubricationCorrection::treatLubricationSphrPlane( const pe::SphereID sphereI, const pe::ConstPlaneID planeJ ) -{ - - real_t gap = pe::getSurfaceDistance( sphereI, planeJ ); - - if ( gap > cutOffDistance_ || gap < real_t(0) ) - { - WALBERLA_LOG_DETAIL("gap " << gap << " larger than cutOff " << cutOffDistance_ << " - ignoring pair"); - return; - } - - if ( gap < minimalGapSize_ ) - { - WALBERLA_LOG_DETAIL("gap " << gap << " smaller than minimal gap " << minimalGapSize_ << " - using minimal gap"); - gap = minimalGapSize_; - } - - pe::Vec3 fLub = compLubricationSphrPlane( gap, sphereI, planeJ); - - WALBERLA_LOG_DETAIL( "Lubrication force on sphere " << sphereI->getID() << " to plane with id " << planeJ->getID() << " is:" << fLub << std::endl ); - sphereI->addForce( fLub ); - -} - - - -//***************************************************************************************************************************************** -/*! \brief Computes lubrication correction force between spheres. - * \ingroup pe_coupling - * - * Lubrication correction according to Ladd and Verberg, 2001 - * ("Lattice-Boltzmann Simulations of Particle-Fluid Suspensions") - * - * Note: Verified quantitatively by computation in spreadsheet - * and qualitatively by considering direction of force for example setup. - */ -//***************************************************************************************************************************************** -pe::Vec3 LubricationCorrection::compLubricationSphrSphr( real_t gap, const pe::SphereID sphereI, const pe::SphereID sphereJ) const -{ - const pe::Vec3 &posSphereI = sphereI->getPosition(); - const pe::Vec3 &posSphereJ = sphereJ->getPosition(); - - const pe::Vec3 &tmpVec = posSphereJ - posSphereI; - const pe::Vec3 &rIJ = tmpVec.getNormalized(); - - real_t radiusSphereI = sphereI->getRadius(); - real_t radiusSphereJ = sphereJ->getRadius(); - - pe::Vec3 velDiff(sphereI->getLinearVel() - sphereJ->getLinearVel()); - - real_t length = velDiff * rIJ; - - real_t radiiSQR = ( radiusSphereI * radiusSphereJ ) * ( radiusSphereI * radiusSphereJ ); - real_t radiiSumSQR = ( radiusSphereI + radiusSphereJ ) * ( radiusSphereI + radiusSphereJ ); - - pe::Vec3 fLub = ( -real_t(6) * dynamicViscosity_ * walberla::math::PI * radiiSQR / radiiSumSQR * ( real_t(1) / gap - real_t(1) / cutOffDistance_) * length * rIJ); - - WALBERLA_LOG_DETAIL_SECTION() - { - std::stringstream ss; - ss << "Sphere I: \n uid:" << sphereI->getID() << "\n"; - ss << "vel: " << sphereI->getLinearVel() << "\n"; - ss << "rad: " << radiusSphereI << "\n"; - ss << "pos: " << posSphereI << "\n\n"; - - ss << "Sphere J: \n uid:" << sphereJ->getID() << "\n"; - ss << "vel: " << sphereJ->getLinearVel() << "\n"; - ss << "rad: " << radiusSphereJ << "\n"; - ss << "pos: " << posSphereJ << "\n\n"; - - real_t distance = gap + radiusSphereI + radiusSphereJ; - ss << "distance: " << distance << "\n"; - ss << "viscosity: " << dynamicViscosity_ << "\n"; - - ss << "gap: " << gap << "\n"; - ss << "cutOff: " << cutOffDistance_ << "\n"; - ss << "velDiff " << velDiff << "\n"; - ss << "rIJ " << rIJ << "\n\n"; - - ss << "Resulting lubrication force: " << fLub << "\n"; - - WALBERLA_LOG_DETAIL( ss.str() ); - } - - return fLub; -} -//***************************************************************************************************************************************** - - - -//***************************************************************************************************************************************** -/*! \brief Computes lubrication correction force between sphere and wall. - * \ingroup pe_coupling - * - * Lubrication correction according to Ladd and Verberg, 2001 - * ("Lattice-Boltzmann Simulations of Particle-Fluid Suspensions" ) - * - * Note: Verified quantitatively by computation in spreadsheet - * and qualitatively by considering direction of force for example setup. - */ -//***************************************************************************************************************************************** -pe::Vec3 LubricationCorrection::compLubricationSphrPlane( real_t gap, const pe::SphereID sphereI, const pe::ConstPlaneID planeJ) const -{ - const pe::Vec3 &posSphereI( sphereI->getPosition() ); - real_t radiusSphereI = sphereI->getRadius(); - - const pe::Vec3 &planeNormal( planeJ->getNormal() ); // took negative of normal from sphere to plane (plane's normal) - sign cancels out anyway - pe::Vec3 rIJ( planeNormal.getNormalized() ); // for safety reasons, normalize normal - - real_t length = sphereI->getLinearVel() * rIJ; - - real_t radiiSQR = radiusSphereI * radiusSphereI; - - pe::Vec3 fLub( -real_t(6) * dynamicViscosity_ * walberla::math::PI * radiiSQR * (real_t(1) / gap - real_t(1) / cutOffDistance_) * length * rIJ); - - WALBERLA_LOG_DETAIL_SECTION() { - std::stringstream ss; - ss << "Sphere I: \n uid:" << sphereI->getID() << "\n"; - ss << "vel: " << sphereI->getLinearVel() << "\n"; - ss << "rad: " << radiusSphereI << "\n"; - ss << "pos: " << posSphereI << "\n\n"; - - real_t distance = gap + radiusSphereI; - ss << "distance: " << distance << "\n"; - ss << "viscosity: " << dynamicViscosity_ << "\n"; - - ss << "gap: " << gap << "\n"; - ss << "cutOff: " << cutOffDistance_ << "\n"; - ss << "velDiff " << sphereI->getLinearVel() << "\n"; - ss << "rIJ " << -rIJ << "\n\n"; - - ss << "Resulting lubrication force: " << fLub << "\n"; - - WALBERLA_LOG_DETAIL( ss.str() ); - } - - return fLub; -} - - } // pe_coupling } // walberla diff --git a/src/pe_coupling/utility/TimeStep.cpp b/src/pe_coupling/utility/TimeStep.cpp new file mode 100644 index 0000000000000000000000000000000000000000..79a9d85d03946047bb91c2bcfda7d40c7a44aaea --- /dev/null +++ b/src/pe_coupling/utility/TimeStep.cpp @@ -0,0 +1,112 @@ +//====================================================================================================================== +// +// 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 TimeStep.cpp +//! \ingroup pe_coupling +//! \author Florian Schornbaum <florian.schornbaum@fau.de> +//! \author Christoph Rettinger <christoph.rettinger@fau.de> +//! \author Sebastian Eibl <sebastian.eibl@fau.de> +// +//====================================================================================================================== + +#include "TimeStep.h" + +#include "pe/rigidbody/BodyIterators.h" + +#include <map> +#include <array> + +namespace walberla { +namespace pe_coupling { + +void TimeStep::operator()() +{ + if( numberOfSubIterations_ == 1 ) + { + forceEvaluationFunc_(); + + collisionResponse_.timestep( timeStepSize_ ); + synchronizeFunc_(); + } + else + { + // during the intermediate time steps of the collision response, the currently acting forces + // (interaction forces, gravitational force, ...) have to remain constant. + // Since they are reset after the call to collision response, they have to be stored explicitly before. + // Then they are set again after each intermediate step. + + // generate map from all known bodies (process local) to total forces/torques + // this has to be done on a block-local basis, since the same body could reside on several blocks from this process + typedef domain_decomposition::IBlockID::IDType BlockID_T; + std::map< BlockID_T, std::map< walberla::id_t, std::array< real_t, 6 > > > forceTorqueMap; + + for( auto blockIt = blockStorage_->begin(); blockIt != blockStorage_->end(); ++blockIt ) + { + BlockID_T blockID = blockIt->getId().getID(); + auto& blockLocalForceTorqueMap = forceTorqueMap[blockID]; + + // iterate over local and remote bodies and store force/torque in map + for( auto bodyIt = pe::BodyIterator::begin(*blockIt, bodyStorageID_); bodyIt != pe::BodyIterator::end(); ++bodyIt ) + { + auto & f = blockLocalForceTorqueMap[ bodyIt->getSystemID() ]; + + const auto & force = bodyIt->getForce(); + const auto & torque = bodyIt->getTorque(); + + f = {{force[0], force[1], force[2], torque[0], torque[1], torque[2] }}; + } + } + + // perform pe time steps + const real_t subTimeStepSize = timeStepSize_ / real_c( numberOfSubIterations_ ); + for( uint_t i = 0; i != numberOfSubIterations_; ++i ) + { + + // in the first iteration, forces are already set + if( i != 0 ) + { + for( auto blockIt = blockStorage_->begin(); blockIt != blockStorage_->end(); ++blockIt ) + { + BlockID_T blockID = blockIt->getId().getID(); + auto& blockLocalForceTorqueMap = forceTorqueMap[blockID]; + + // re-set stored force/torque on bodies + for( auto bodyIt = pe::BodyIterator::begin(*blockIt, bodyStorageID_); bodyIt != pe::BodyIterator::end(); ++bodyIt ) + { + + const auto f = blockLocalForceTorqueMap.find( bodyIt->getSystemID() ); + + if( f != blockLocalForceTorqueMap.end() ) + { + const auto & ftValues = f->second; + bodyIt->addForce ( ftValues[0], ftValues[1], ftValues[2] ); + bodyIt->addTorque( ftValues[3], ftValues[4], ftValues[5] ); + } + } + } + } + + // evaluate forces (e.g. lubrication forces) + forceEvaluationFunc_(); + + collisionResponse_.timestep( subTimeStepSize ); + synchronizeFunc_(); + } + } +} + + +} // namespace pe_coupling +} // namespace walberla diff --git a/src/pe_coupling/utility/TimeStep.h b/src/pe_coupling/utility/TimeStep.h index f32c306142dbe01c904f7e081e8aa49dd2cd3455..283282b6893e9b6307b7dcb77b2ddc734dee9523 100644 --- a/src/pe_coupling/utility/TimeStep.h +++ b/src/pe_coupling/utility/TimeStep.h @@ -23,20 +23,12 @@ #pragma once -#include "core/debug/Debug.h" #include "core/timing/TimingTree.h" - -#include "domain_decomposition/BlockStorage.h" - +#include "domain_decomposition/StructuredBlockStorage.h" #include "pe/cr/ICR.h" -#include "pe/rigidbody/BodyIterators.h" -#include "pe/synchronization/SyncForces.h" #include <functional> -#include <map> -#include <array> - namespace walberla { namespace pe_coupling { @@ -72,83 +64,9 @@ public: , forceEvaluationFunc_( forceEvaluationFunc ) {} - void operator()() - { - if( numberOfSubIterations_ == 1 ) - { - forceEvaluationFunc_(); - - collisionResponse_.timestep( timeStepSize_ ); - synchronizeFunc_(); - } - else - { - // during the intermediate time steps of the collision response, the currently acting forces - // (interaction forces, gravitational force, ...) have to remain constant. - // Since they are reset after the call to collision response, they have to be stored explicitly before. - // Then they are set again after each intermediate step. - - // generate map from all known bodies (process local) to total forces/torques - // this has to be done on a block-local basis, since the same body could reside on several blocks from this process - typedef domain_decomposition::IBlockID::IDType BlockID_T; - std::map< BlockID_T, std::map< walberla::id_t, std::array< real_t, 6 > > > forceTorqueMap; - - for( auto blockIt = blockStorage_->begin(); blockIt != blockStorage_->end(); ++blockIt ) - { - BlockID_T blockID = blockIt->getId().getID(); - auto& blockLocalForceTorqueMap = forceTorqueMap[blockID]; - - // iterate over local and remote bodies and store force/torque in map - for( auto bodyIt = pe::BodyIterator::begin(*blockIt, bodyStorageID_); bodyIt != pe::BodyIterator::end(); ++bodyIt ) - { - auto & f = blockLocalForceTorqueMap[ bodyIt->getSystemID() ]; - - const auto & force = bodyIt->getForce(); - const auto & torque = bodyIt->getTorque(); - - f = {{force[0], force[1], force[2], torque[0], torque[1], torque[2] }}; - } - } - - // perform pe time steps - const real_t subTimeStepSize = timeStepSize_ / real_c( numberOfSubIterations_ ); - for( uint_t i = 0; i != numberOfSubIterations_; ++i ) - { - - // in the first iteration, forces are already set - if( i != 0 ) - { - for( auto blockIt = blockStorage_->begin(); blockIt != blockStorage_->end(); ++blockIt ) - { - BlockID_T blockID = blockIt->getId().getID(); - auto& blockLocalForceTorqueMap = forceTorqueMap[blockID]; - - // re-set stored force/torque on bodies - for( auto bodyIt = pe::BodyIterator::begin(*blockIt, bodyStorageID_); bodyIt != pe::BodyIterator::end(); ++bodyIt ) - { - - const auto f = blockLocalForceTorqueMap.find( bodyIt->getSystemID() ); - - if( f != blockLocalForceTorqueMap.end() ) - { - const auto & ftValues = f->second; - bodyIt->addForce ( ftValues[0], ftValues[1], ftValues[2] ); - bodyIt->addTorque( ftValues[3], ftValues[4], ftValues[5] ); - } - } - } - } - - // evaluate forces (e.g. lubrication forces) - forceEvaluationFunc_(); - - collisionResponse_.timestep( subTimeStepSize ); - synchronizeFunc_(); - } - } - } + void operator()(); -protected: +private: const real_t timeStepSize_; const uint_t numberOfSubIterations_;