19#include <dune/common/fvector.hh>
20#include <dune/common/exceptions.hh>
79template<
class Scalar,
class Gr
idGeometry>
82 static constexpr int dim = GridGeometry::GridView::dimension;
83 static constexpr int dimWorld = GridGeometry::GridView::dimensionworld;
88 using Velocity = Dune::FieldVector<Scalar, dim>;
92 FokkerPlanck(std::shared_ptr<const GridGeometry> gg, std::shared_ptr<Cloud> cloud)
93 : gridGeometry_(std::move(gg))
94 , cloud_(std::move(cloud))
95 , rndGen_(std::random_device{}())
97 if (cloud_->size(
false) == 0)
98 cloud_->resize(getParam<int>(
"FokkerPlanck.NumParticles"));
100 const auto numParticles = cloud_->size(
false);
101 diffusionCoefficient_ = getParam<Scalar>(
"FokkerPlanck.DiffusionCoefficient");
102 data_.resize(numParticles);
103 particleMass_ = getParam<Scalar>(
"FokkerPlanck.ParticleMass", 1.0/numParticles);
104 volumes_.resize(gridGeometry_->gridView().size(0), 0.0);
105 for (
const auto& element : elements(gridGeometry_->gridView()))
107 const auto eIdx = gridGeometry_->elementMapper().index(element);
108 const auto geometry = element.geometry();
109 volumes_[eIdx] = geometry.volume();
131 cloud_->forEachParticle([&](
auto& p){
132 func(p, data_[p.id()]);
153 if (velocities_.empty())
154 DUNE_THROW(Dune::InvalidStateException,
"A velocity field must be set before calling run");
157 cloud_->forEachActiveParticle([&](
auto& p){
158 moveParticle_(p, dt);
178 density.assign(gridGeometry_->gridView().size(0), 0.0);
179 for (
const auto& p : particles(*cloud_))
181 const auto eIdx = data_[p.id()].eIdx;
182 density[eIdx] += particleMass_/volumes_[eIdx];
193 if (velocities.size() != gridGeometry_->gridView().size(0) && velocities.size() != 1)
194 DUNE_THROW(Dune::InvalidStateException,
"Velocity data size does not match number of elements or 1");
195 velocities_ = velocities;
203 void moveParticle_(
Particle& p,
const Scalar dt)
205 auto& particleData = data_[p.
id()];
208 particleData.time = dt;
210 while (particleData.time > 0.0 && velocity_(particleData.eIdx).two_norm2() > 0.0)
212 const auto tStartIteration = particleData.time;
214 const auto velocityInGrid = velocity_(particleData.eIdx);
215 moveParticleInGridElement_(p, velocityInGrid);
217 count = particleData.time < tStartIteration ? 0 : count + 1;
220 std::cout <<
"Particle [" << p.
id() <<
"] at " << p.
position() <<
" in element " << particleData.eIdx <<
", t=" << particleData.time <<
", velocity: " << velocityInGrid <<
"\n";
221 std::cout <<
"-- during advection step: particle got stuck and is deactivated\n";
223 cloud_->deactivateParticle(p);
224 particleData.time = -1.0;
228 static_assert(dim == dimWorld,
"Not implemented yet for dim != dimWorld");
231 particleData.time = 1.0;
232 const auto velocityInGrid = [&]{
233 const auto scale = std::sqrt(2.0*diffusionCoefficient_);
234 Dune::FieldVector<Scalar, dimWorld> newPos(p.
position());
235 for (
int i = 0; i < dim; ++i)
236 newPos[i] += scale * std::normal_distribution<Scalar>(0.0, std::sqrt(dt))(rndGen_);
240 const auto velocityNorm = velocityInGrid.two_norm2();
242 while (particleData.time > 0.0 && velocityNorm > 0.0)
244 const auto tStartIteration = particleData.time;
246 moveParticleInGridElement_(p, velocityInGrid);
248 count = particleData.time < tStartIteration ? 0 : count + 1;
251 std::cout <<
"Particle [" << p.
id() <<
"] at " << p.
position() <<
" in element " << particleData.eIdx <<
", t=" << particleData.time <<
", velocity: " << velocityInGrid <<
"\n";
252 std::cout <<
"-- during diffusion step: particle got stuck and is deactivated\n";
254 cloud_->deactivateParticle(p);
255 particleData.time = -1.0;
260 void moveParticleInGridElement_(Particle& p,
const Velocity& velocity)
262 auto& particleData = data_[p.id()];
263 assert(particleData.time > 0.0);
265 const auto eIdx = particleData.eIdx;
266 if (eIdx >= gridGeometry_->gridView().size(0))
267 DUNE_THROW(Dune::InvalidStateException,
"Element index is invalid");
269 const auto&
element = gridGeometry_->element(eIdx);
270 const auto geometry =
element.geometry();
272 const auto startPos = p.position();
273 auto endPos = startPos;
274 endPos.axpy(particleData.time, velocity);
279 p.setPosition(endPos);
280 particleData.time = -1.0;
286 auto beforeStart = startPos;
287 beforeStart.axpy(-1e-4*particleData.time, velocity);
289 const auto fvGeometry =
localView(*gridGeometry_).bind(element);
290 Dune::AffineGeometry<double, 1, dimWorld> segGeo(
Dune::GeometryTypes::line, std::array<GlobalPosition, 2>{{beforeStart, endPos}});
292 using IntersectionAlgorithm = GeometryIntersection<Dune::AffineGeometry<double, 1, dimWorld>,
decltype(fvGeometry.geometry(fvGeometry.scvf(0))), IP>;
293 using Intersection =
typename IntersectionAlgorithm::Intersection;
294 Intersection intersection;
296 static_assert(dim >= 1,
"Particle transport only makes sense for 1D and higher");
297 const auto intersectionFound = [&](
const auto& scvf, Intersection& intersection)
299 if constexpr (dim == 1)
302 if (found) intersection = scvf.ipGlobal();
306 return IntersectionAlgorithm::intersection(
307 segGeo, fvGeometry.geometry(scvf), intersection
311 for (
const auto& scvf : scvfs(fvGeometry))
313 if (intersectionFound(scvf, intersection))
318 cloud_->deactivateParticle(p);
319 particleData.time = -1.0;
324 if (scvf.unitOuterNormal()*velocity < 1e-4*velocity.two_norm())
328 const auto velocityNorm = velocity.two_norm2();
329 const auto distance = (intersection-startPos).two_norm2();
330 intersection.axpy(1e-3, endPos-startPos);
331 p.setPosition(intersection);
332 particleData.eIdx = scvf.outsideScvIdx();
333 particleData.time -= std::sqrt(
distance/velocityNorm);
339 static constexpr bool isCartesianGrid = Dune::Capabilities::isCartesian<typename GridGeometry::GridView::Grid>::v;
340 const auto entities =
intersectingEntities(p.position(), gridGeometry_->boundingBoxTree(), isCartesianGrid);
341 if (entities.empty())
343 cloud_->deactivateParticle(p);
344 particleData.time = -1.0;
349 particleData.eIdx = entities[0];
352 const Velocity& velocity_(std::size_t eIdx)
const
354 if (velocities_.size() == 1)
355 return velocities_[0];
356 return velocities_[eIdx];
359 std::shared_ptr<const GridGeometry> gridGeometry_;
360 std::vector<ParticleData> data_;
361 std::shared_ptr<Cloud> cloud_;
362 std::mt19937 rndGen_;
364 std::vector<Velocity> velocities_;
365 Scalar diffusionCoefficient_;
367 std::vector<Scalar> volumes_;
368 Scalar particleMass_;
A particle solver for the Fokker-Planck equation.
Definition: fokkerplanck.hh:81
void run(const Scalar dt)
Evolve particle state with Euler scheme.
Definition: fokkerplanck.hh:151
void setVelocityData(const std::vector< Velocity > &velocities)
set the velocity data for each grid element
Definition: fokkerplanck.hh:191
std::shared_ptr< const Cloud > particleCloud() const
access the underlying particle cloud
Definition: fokkerplanck.hh:199
FokkerPlanck(std::shared_ptr< const GridGeometry > gg, std::shared_ptr< Cloud > cloud)
Definition: fokkerplanck.hh:92
void init(const Func &func)
For each particle apply a function to initialize it's state.
Definition: fokkerplanck.hh:129
void computeDensity(std::vector< Scalar > &density) const
computes the particle density in the grid
Definition: fokkerplanck.hh:176
a basic particle
Definition: particle.hh:25
Dune::FieldVector< CoordScalar, dimWorld > GlobalPosition
Definition: particle.hh:29
const GlobalPosition & position() const
Definition: particle.hh:37
std::size_t id() const
Definition: particle.hh:40
A simple implementation of a cloud of particles.
Definition: simpleparticlecloud.hh:36
A class for collision detection of two geometries and computation of intersection corners.
GridCache::LocalView localView(const GridCache &gridCache)
Free function to get the local view of a grid cache object.
Definition: localview.hh:26
bool intersectsPointGeometry(const Dune::FieldVector< ctype, dimworld > &point, const Geometry &g)
Find out whether a point is inside a three-dimensional geometry.
Definition: intersectspointgeometry.hh:28
static ctype distance(const Dune::FieldVector< ctype, dimWorld > &a, const Dune::FieldVector< ctype, dimWorld > &b)
Compute the shortest distance between two points.
Definition: distance.hh:282
std::vector< std::size_t > intersectingEntities(const Dune::FieldVector< ctype, dimworld > &point, const BoundingBoxTree< EntitySet > &tree, bool isCartesianGrid=false)
Compute all intersections between entities and a point.
Definition: intersectingentities.hh:102
Algorithms that finds which geometric entities intersect.
constexpr CCTpfa cctpfa
Definition: method.hh:145
constexpr Line line
Definition: couplingmanager1d3d_line.hh:31
std::string density(int phaseIdx) noexcept
I/O name of density for multiphase systems.
Definition: name.hh:53
Definition: fokkerplanck.hh:31
Parallel for loop (multithreading)
A simple implementation of a cloud of particles.
Policy structure for point-like intersections.
Definition: geometryintersection.hh:34
data associated with each particle id
Definition: fokkerplanck.hh:119
Scalar time
Definition: fokkerplanck.hh:121
std::size_t eIdx
Definition: fokkerplanck.hh:120