diff options
Diffstat (limited to 'Source')
-rw-r--r-- | Source/Particles/Collision/CollisionType.cpp | 40 | ||||
-rw-r--r-- | Source/Particles/PhysicalParticleContainer.cpp | 3 | ||||
-rw-r--r-- | Source/Particles/Resampling/CMakeLists.txt | 1 | ||||
-rw-r--r-- | Source/Particles/Resampling/LevelingThinning.H | 27 | ||||
-rw-r--r-- | Source/Particles/Resampling/LevelingThinning.cpp | 96 | ||||
-rw-r--r-- | Source/Particles/Resampling/Make.package | 1 | ||||
-rw-r--r-- | Source/Particles/Resampling/Resampling.H | 7 | ||||
-rw-r--r-- | Source/Particles/Resampling/Resampling.cpp | 4 | ||||
-rw-r--r-- | Source/Utils/CMakeLists.txt | 1 | ||||
-rw-r--r-- | Source/Utils/Make.package | 1 | ||||
-rw-r--r-- | Source/Utils/ParticleUtils.H | 31 | ||||
-rw-r--r-- | Source/Utils/ParticleUtils.cpp | 52 |
12 files changed, 217 insertions, 47 deletions
diff --git a/Source/Particles/Collision/CollisionType.cpp b/Source/Particles/Collision/CollisionType.cpp index 8c5fac875..fc30f151a 100644 --- a/Source/Particles/Collision/CollisionType.cpp +++ b/Source/Particles/Collision/CollisionType.cpp @@ -7,7 +7,8 @@ #include "CollisionType.H" #include "ShuffleFisherYates.H" #include "ElasticCollisionPerez.H" -#include <WarpX.H> +#include "Utils/ParticleUtils.H" +#include "WarpX.H" CollisionType::CollisionType( const std::vector<std::string>& species_names, @@ -47,42 +48,7 @@ using ParticleTileType = WarpXParticleContainer::ParticleTileType; using ParticleBins = DenseBins<ParticleType>; using index_type = ParticleBins::index_type; -namespace { - - /* Find the particles and count the particles that are in each cell. - Note that this does *not* rearrange particle arrays */ - ParticleBins - findParticlesInEachCell( int const lev, MFIter const& mfi, - ParticleTileType const& ptile) { - - // Extract particle structures for this tile - int const np = ptile.numParticles(); - ParticleType const* particle_ptr = ptile.GetArrayOfStructs()().data(); - - // Extract box properties - Geometry const& geom = WarpX::GetInstance().Geom(lev); - Box const& cbx = mfi.tilebox(IntVect::TheZeroVector()); //Cell-centered box - const auto lo = lbound(cbx); - const auto dxi = geom.InvCellSizeArray(); - const auto plo = geom.ProbLoArray(); - - // Find particles that are in each cell; - // results are stored in the object `bins`. - ParticleBins bins; - bins.build(np, particle_ptr, cbx, - // Pass lambda function that returns the cell index - [=] AMREX_GPU_HOST_DEVICE (const ParticleType& p) noexcept -> IntVect - { - return IntVect(AMREX_D_DECL( - static_cast<int>((p.pos(0)-plo[0])*dxi[0] - lo.x), - static_cast<int>((p.pos(1)-plo[1])*dxi[1] - lo.y), - static_cast<int>((p.pos(2)-plo[2])*dxi[2] - lo.z))); - }); - - return bins; - } - -} +using namespace ParticleUtils; /** Perform all binary collisions within a tile * diff --git a/Source/Particles/PhysicalParticleContainer.cpp b/Source/Particles/PhysicalParticleContainer.cpp index 68900463b..1ac048cec 100644 --- a/Source/Particles/PhysicalParticleContainer.cpp +++ b/Source/Particles/PhysicalParticleContainer.cpp @@ -2003,11 +2003,12 @@ void PhysicalParticleContainer::resample (const Resampling& resampler, const int if (resampler.triggered(timestep, global_numparts)) { + amrex::Print() << "Resampling " << species_name << ".\n"; for (int lev = 0; lev <= maxLevel(); lev++) { for (WarpXParIter pti(*this, lev); pti.isValid(); ++pti) { - resampler(pti); + resampler(pti, lev, this); } } } diff --git a/Source/Particles/Resampling/CMakeLists.txt b/Source/Particles/Resampling/CMakeLists.txt index 7bba14166..0b44f7a5d 100644 --- a/Source/Particles/Resampling/CMakeLists.txt +++ b/Source/Particles/Resampling/CMakeLists.txt @@ -2,4 +2,5 @@ target_sources(WarpX PRIVATE Resampling.cpp ResamplingTrigger.cpp + LevelingThinning.cpp ) diff --git a/Source/Particles/Resampling/LevelingThinning.H b/Source/Particles/Resampling/LevelingThinning.H index 77d1b967a..920fa07c9 100644 --- a/Source/Particles/Resampling/LevelingThinning.H +++ b/Source/Particles/Resampling/LevelingThinning.H @@ -9,15 +9,32 @@ #include "Resampling.H" -#include <AMReX_Print.H> - /** - * \brief This class will soon implement the leveling thinning algorithm, but for now it is just - * a dummy class that prints "Resampling." used to test the resampling structure. + * \brief This class implements the leveling thinning algorithm as defined in Muraviev, A., et al. + * arXiv:2006.08593 (2020). + * The main steps of the algorithm are the following: for every cell we calculate a level weight, + * defined by the average weight of the species particles in that cell multiplied by the target + * ratio. Then, particles with a weight lower than the level weight are either removed, with a + * probability 1 - particle_weight/level_weight, or have their weight set to the level weight. */ class LevelingThinning: public ResamplingAlgorithm { public: - void operator() (WarpXParIter& /*pti*/) override final {amrex::Print() << "Resampling. \n";} + /** + * \brief Constructor of the LevelingThinning class + */ + LevelingThinning (); + + /** + * \brief A method that performs leveling thinning for the considered species. + * + * @param[in] pti WarpX particle iterator of the particles to resample. + * @param[in] lev the index of the refinement level. + * @param[in] pc a pointer to the particle container. + */ + void operator() (WarpXParIter& pti, const int lev, WarpXParticleContainer * const pc) const override final; + +private: + amrex::Real m_target_ratio = amrex::Real(1.5); }; diff --git a/Source/Particles/Resampling/LevelingThinning.cpp b/Source/Particles/Resampling/LevelingThinning.cpp new file mode 100644 index 000000000..d3ffc9530 --- /dev/null +++ b/Source/Particles/Resampling/LevelingThinning.cpp @@ -0,0 +1,96 @@ +/* Copyright 2019-2020 Neil Zaim + * + * This file is part of WarpX. + * + * License: BSD-3-Clause-LBNL + */ +#include "LevelingThinning.H" +#include "Utils/ParticleUtils.H" + +#include <AMReX_Particles.H> + +LevelingThinning::LevelingThinning () +{ + using namespace amrex::literals; + + amrex::ParmParse pp("resampling_algorithm"); + pp.query("target_ratio", m_target_ratio); + AMREX_ALWAYS_ASSERT_WITH_MESSAGE( m_target_ratio > 0._rt, + "Resampling target ratio should be strictly greater than 0"); + if (m_target_ratio <= 1._rt) + { + amrex::Warning("WARNING: target ratio for leveling thinning is smaller or equal to one." + " It is possible that no particle will be removed during resampling"); + } +} + +void LevelingThinning::operator() (WarpXParIter& pti, const int lev, + WarpXParticleContainer * const pc) const +{ + using namespace amrex::literals; + + auto& ptile = pc->ParticlesAt(lev, pti); + auto& soa = ptile.GetStructOfArrays(); + amrex::ParticleReal * const AMREX_RESTRICT w = soa.GetRealData(PIdx::w).data(); + WarpXParticleContainer::ParticleType * const AMREX_RESTRICT + particle_ptr = ptile.GetArrayOfStructs()().data(); + + // Using this function means that we must loop over the cells in the ParallelFor. In the case + // of the leveling thinning algorithm, it would have possibly been more natural and more + // efficient to directly loop over the particles. Nevertheless, this structure with a loop over + // the cells is more general and can be readily used to implement almost any other resampling + // algorithm. + auto bins = ParticleUtils::findParticlesInEachCell(lev, pti, ptile); + + const int n_cells = bins.numBins(); + const auto indices = bins.permutationPtr(); + const auto cell_offsets = bins.offsetsPtr(); + + const amrex::Real target_ratio = m_target_ratio; + + // Loop over cells + amrex::ParallelFor( n_cells, + [=] AMREX_GPU_DEVICE (int i_cell) noexcept + { + // The particles that are in the cell `i_cell` are + // given by the `indices[cell_start:cell_stop]` + const auto cell_start = cell_offsets[i_cell]; + const auto cell_stop = cell_offsets[i_cell+1]; + const int cell_numparts = cell_stop - cell_start; + + // do nothing for cells without particles + if (cell_numparts == 0) + return; + amrex::Real average_weight = 0._rt; + + // First loop over cell particles to compute average particle weight in the cell + for (int i = cell_start; i < cell_stop; ++i) + { + average_weight += w[indices[i]]; + } + average_weight /= cell_numparts; + + const amrex::Real level_weight = average_weight*target_ratio; + + + // Second loop over cell particles to perform the thinning + for (int i = cell_start; i < cell_stop; ++i) + { + // Particles with weight greater than level_weight are left unchanged + if (w[indices[i]] > level_weight) {continue;} + + amrex::Real const random_number = amrex::Random(); + // Remove particle with probability 1 - particle_weight/level_weight + if (random_number > w[indices[i]]/level_weight) + { + particle_ptr[indices[i]].id() = -1; + } + // Set particle weight to level weight otherwise + else + { + w[indices[i]] = level_weight; + } + } + } + ); +} diff --git a/Source/Particles/Resampling/Make.package b/Source/Particles/Resampling/Make.package index 89470af55..e70e3446c 100644 --- a/Source/Particles/Resampling/Make.package +++ b/Source/Particles/Resampling/Make.package @@ -1,4 +1,5 @@ CEXE_sources += Resampling.cpp CEXE_sources += ResamplingTrigger.cpp +CEXE_sources += LevelingThinning.cpp VPATH_LOCATIONS += $(WARPX_HOME)/Source/Particles/Resampling/ diff --git a/Source/Particles/Resampling/Resampling.H b/Source/Particles/Resampling/Resampling.H index 83b3ccfd5..de919bfcb 100644 --- a/Source/Particles/Resampling/Resampling.H +++ b/Source/Particles/Resampling/Resampling.H @@ -10,6 +10,7 @@ #include "ResamplingTrigger.H" class WarpXParIter; // forward declaration +class WarpXParticleContainer; // forward declaration /** * \brief An empty base class from which specific resampling algorithms are derived. @@ -19,7 +20,7 @@ struct ResamplingAlgorithm /** * \brief Virtual operator() of the abstract ResamplingAlgorithm class */ - virtual void operator() (WarpXParIter& /*pti*/) = 0; + virtual void operator() (WarpXParIter& /*pti*/, const int /*lev*/, WarpXParticleContainer */*pc*/) const = 0; /** * \brief Virtual destructor of the abstract ResamplingAlgorithm class @@ -56,8 +57,10 @@ public: * \brief A method that uses the ResamplingAlgorithm object to perform resampling. * * @param[in] pti WarpX particle iterator of the particles to resample. + * @param[in] lev the index of the refinement level. + * @param[in] pc a pointer to the particle container. */ - void operator() (WarpXParIter& pti) const; + void operator() (WarpXParIter& pti, const int lev, WarpXParticleContainer * const pc) const; private: ResamplingTrigger m_resampling_trigger; diff --git a/Source/Particles/Resampling/Resampling.cpp b/Source/Particles/Resampling/Resampling.cpp index a08145915..65332d191 100644 --- a/Source/Particles/Resampling/Resampling.cpp +++ b/Source/Particles/Resampling/Resampling.cpp @@ -26,7 +26,7 @@ bool Resampling::triggered (const int timestep, const amrex::Real global_numpart return m_resampling_trigger.triggered(timestep, global_numparts); } -void Resampling::operator() (WarpXParIter& pti) const +void Resampling::operator() (WarpXParIter& pti, const int lev, WarpXParticleContainer * const pc) const { - (*m_resampling_algorithm)(pti); + (*m_resampling_algorithm)(pti, lev, pc); } diff --git a/Source/Utils/CMakeLists.txt b/Source/Utils/CMakeLists.txt index ce785cc33..c9da2ae47 100644 --- a/Source/Utils/CMakeLists.txt +++ b/Source/Utils/CMakeLists.txt @@ -4,6 +4,7 @@ target_sources(WarpX CoarsenMR.cpp Interpolate.cpp IntervalsParser.cpp + ParticleUtils.cpp RelativeCellPosition.cpp WarpXAlgorithmSelection.cpp WarpXMovingWindow.cpp diff --git a/Source/Utils/Make.package b/Source/Utils/Make.package index 08b9aa3a9..61ced5d7f 100644 --- a/Source/Utils/Make.package +++ b/Source/Utils/Make.package @@ -7,5 +7,6 @@ CEXE_sources += CoarsenMR.cpp CEXE_sources += Interpolate.cpp CEXE_sources += IntervalsParser.cpp CEXE_sources += RelativeCellPosition.cpp +CEXE_sources += ParticleUtils.cpp VPATH_LOCATIONS += $(WARPX_HOME)/Source/Utils diff --git a/Source/Utils/ParticleUtils.H b/Source/Utils/ParticleUtils.H new file mode 100644 index 000000000..cb25607a3 --- /dev/null +++ b/Source/Utils/ParticleUtils.H @@ -0,0 +1,31 @@ +/* Copyright 2019-2020 Neil Zaim, Yinjian Zhao + * + * This file is part of WarpX. + * + * License: BSD-3-Clause-LBNL + */ +#ifndef WARPX_PARTICLE_UTILS_H_ +#define WARPX_PARTICLE_UTILS_H_ + +#include "Particles/WarpXParticleContainer.H" +#include <AMReX_DenseBins.H> + +namespace ParticleUtils { + + /** + * \brief Find the particles and count the particles that are in each cell. More specifically + * this function returns an amrex::DenseBins object containing an offset array and a permutation + * array which can be used to loop over all the cells in a tile and apply an algorithm to + * particles of a given species present in each cell. + * Note that this does *not* rearrange particle arrays. + * + * @param[in] lev the index of the refinement level. + * @param[in] mfi the MultiFAB iterator. + * @param[in] ptile the particle tile. + */ + amrex::DenseBins<WarpXParticleContainer::ParticleType> + findParticlesInEachCell( int const lev, amrex::MFIter const& mfi, + WarpXParticleContainer::ParticleTileType const& ptile); +} + +#endif // WARPX_PARTICLE_UTILS_H_ diff --git a/Source/Utils/ParticleUtils.cpp b/Source/Utils/ParticleUtils.cpp new file mode 100644 index 000000000..92c03bc30 --- /dev/null +++ b/Source/Utils/ParticleUtils.cpp @@ -0,0 +1,52 @@ +/* Copyright 2019-2020 Neil Zaim, Yinjian Zhao + * + * This file is part of WarpX. + * + * License: BSD-3-Clause-LBNL + */ +#include "ParticleUtils.H" +#include "WarpX.H" + +namespace ParticleUtils { + + using namespace amrex; + // Define shortcuts for frequently-used type names + using ParticleType = WarpXParticleContainer::ParticleType; + using ParticleTileType = WarpXParticleContainer::ParticleTileType; + using ParticleBins = DenseBins<ParticleType>; + using index_type = ParticleBins::index_type; + + /* Find the particles and count the particles that are in each cell. + Note that this does *not* rearrange particle arrays */ + ParticleBins + findParticlesInEachCell( int const lev, MFIter const& mfi, + ParticleTileType const& ptile) { + + // Extract particle structures for this tile + int const np = ptile.numParticles(); + ParticleType const* particle_ptr = ptile.GetArrayOfStructs()().data(); + + // Extract box properties + Geometry const& geom = WarpX::GetInstance().Geom(lev); + Box const& cbx = mfi.tilebox(IntVect::TheZeroVector()); //Cell-centered box + const auto lo = lbound(cbx); + const auto dxi = geom.InvCellSizeArray(); + const auto plo = geom.ProbLoArray(); + + // Find particles that are in each cell; + // results are stored in the object `bins`. + ParticleBins bins; + bins.build(np, particle_ptr, cbx, + // Pass lambda function that returns the cell index + [=] AMREX_GPU_HOST_DEVICE (const ParticleType& p) noexcept -> IntVect + { + return IntVect(AMREX_D_DECL( + static_cast<int>((p.pos(0)-plo[0])*dxi[0] - lo.x), + static_cast<int>((p.pos(1)-plo[1])*dxi[1] - lo.y), + static_cast<int>((p.pos(2)-plo[2])*dxi[2] - lo.z))); + }); + + return bins; + } + +} |