//======================================================================================================================
//
// 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 .
//
//! \file ParticlePresenceLevelDetermination.h
//! \author Christoph Rettinger
//
//======================================================================================================================
#pragma once
#include "blockforest/BlockForest.h"
#include "lbm_mesapd_coupling/amr/InfoCollection.h"
namespace walberla {
namespace lbm_mesapd_coupling {
namespace amr
{
/*
* Class to determine the minimum level a block can be.
* For coupled LBM-PE simulations the following rules apply:
* - a moving particle will always remain on the finest block
* - a moving particle is not allowed to extend into an area with a coarser block
* - if no moving particle is present, the level can be as coarse as possible (restricted by the 2:1 rule)
* Therefore, if a particle, local or remote (due to particles that are larger than a block), is present on any of the
* neighboring blocks of a certain block, this block's target level is the finest level.
* This, together with a refinement checking frequency that depends on the maximum translational particle velocity,
* ensures the above given requirements.
*/
class ParticlePresenceLevelDetermination
{
public:
ParticlePresenceLevelDetermination(const shared_ptr< InfoCollection > infoCollection,
uint_t finestLevel)
: infoCollection_(infoCollection), finestLevel_(finestLevel)
{}
void operator()(std::vector< std::pair< const Block*, uint_t > >& minTargetLevels, std::vector< const Block* >&,
const BlockForest& /*forest*/)
{
for (auto& minTargetLevel : minTargetLevels)
{
uint_t currentLevelOfBlock = minTargetLevel.first->getLevel();
const uint_t numberOfParticlesInDirectNeighborhood =
getNumberOfLocalAndShadowParticlesInNeighborhood(minTargetLevel.first);
uint_t targetLevelOfBlock = currentLevelOfBlock; // keep everything as it is
if (numberOfParticlesInDirectNeighborhood > uint_t(0))
{
// set block to finest level if there are particles nearby
targetLevelOfBlock = finestLevel_;
}
else
{
// block could coarsen since there are no particles nearby
if (currentLevelOfBlock > uint_t(0)) targetLevelOfBlock = currentLevelOfBlock - uint_t(1);
}
WALBERLA_CHECK_LESS_EQUAL(std::abs(int_c(targetLevelOfBlock) - int_c(currentLevelOfBlock)), uint_t(1),
"Only level difference of maximum 1 allowed!");
minTargetLevel.second = targetLevelOfBlock;
}
}
private:
uint_t getNumberOfLocalAndShadowParticlesInNeighborhood(const Block* block)
{
auto numParticles = uint_t(0);
// add particles of current block
const auto infoIt = infoCollection_->find(block->getId());
WALBERLA_CHECK_UNEQUAL(infoIt, infoCollection_->end(),
"Block with ID " << block->getId() << " not found in info collection!");
numParticles += infoIt->second.numberOfLocalParticles + infoIt->second.numberOfGhostParticles;
// add particles of all neighboring blocks
for (uint_t i = 0; i < block->getNeighborhoodSize(); ++i)
{
const BlockID& neighborBlockID = block->getNeighborId(i);
const auto infoItNeighbor = infoCollection_->find(neighborBlockID);
WALBERLA_CHECK_UNEQUAL(infoItNeighbor, infoCollection_->end(),
"Neighbor block with ID " << neighborBlockID << " not found in info collection!");
numParticles += infoItNeighbor->second.numberOfLocalParticles + infoItNeighbor->second.numberOfGhostParticles;
}
return numParticles;
}
shared_ptr< InfoCollection > infoCollection_;
uint_t finestLevel_;
};
} // namespace amr
} // namespace lbm_mesapd_coupling
} // namespace walberla