MessageParticleContainer Class Reference

SPADES API: spades::particles::MessageParticleContainer Class Reference
SPADES API
spades::particles::MessageParticleContainer Class Reference

Main SPADES message container. More...

#include <MessageParticleContainer.H>

Inheritance diagram for spades::particles::MessageParticleContainer:
[legend]
Collaboration diagram for spades::particles::MessageParticleContainer:
[legend]

Public Member Functions

 MessageParticleContainer (amrex::AmrParGDB *par_gdb, int ngrow=0)
 Constructor.
 
 MessageParticleContainer (const amrex::Vector< amrex::Geometry > &geom, const amrex::Vector< amrex::DistributionMapping > &dmap, const amrex::Vector< amrex::BoxArray > &ba, int ngrow=0)
 Constructor.
 
void initialize_messages (const amrex::Real lookahead)
 Initialize the messages.
 
void sort () override
 Sort the messages.
 
void update_undefined ()
 Update the undefined messages.
 
void resolve_pairs ()
 Resolve message pairs (remove message/anti-message pairs)
 
amrex::Real compute_gvt ()
 Compute the minimum time stamp of the messages.
 
void garbage_collect (const amrex::Real gvt)
 Perform garbage collection.
 
void write_plot_file (const std::string &plt_filename) override
 Write the particles to file.
 
void read_parameters () override
 Read user parameters.
 
void initialize_variable_names () override
 Initialize variable names.
 
- Public Member Functions inherited from spades::particles::SpadesParticleContainer< MessageTypes::NTYPES, 0, 0, MessageRealData::ncomps, MessageIntData::ncomps >
 SpadesParticleContainer (amrex::AmrParGDB *par_gdb, int ngrow=0)
 Constructor.
 
 SpadesParticleContainer (const amrex::Vector< amrex::Geometry > &geom, const amrex::Vector< amrex::DistributionMapping > &dmap, const amrex::Vector< amrex::BoxArray > &ba, int ngrow=0)
 Constructor.
 
void initialize_state ()
 Initialize particle states (counts and offsets)
 
void clear_state ()
 Delete particle states (counts and offsets)
 
void update_counts ()
 Update the particle counts and offsets.
 
void count_particles ()
 Update the particle counts.
 
void count_offsets ()
 Update the particle offsets.
 
const amrex::iMultiFab & counts () const
 Get the particle counts.
 
const amrex::iMultiFab & offsets () const
 Get the particle offsets.
 
amrex::Long total_count (const int typ) const
 Get the total number of particles of typ.
 
amrex::Long min_count (const int typ) const
 Get the minimum number of particles of typ.
 
amrex::Long max_count (const int typ) const
 Get the maximum number of particles of typ.
 
void check_sort (const amrex::MFIter &mfi)
 Check the result of the sort operation.
 
void sort_impl (const CompareFunctor &compare)
 Sort the particles implementation.
 
void sort_impl (const CompareFunc &compare)
 
void sort_impl (const CompareFunc &compare)
 
void nonencoded_sort_impl (const CompareFunctor &compare)
 Non-encoded sort the particles implementation.
 
void nonencoded_sort_impl (const CompareFunc &compare)
 
void nonencoded_sort_impl (const CompareFunc &compare)
 
void encoded_sort_impl ()
 Encoded sort the particles implementation.
 
void print_messages (const std::string &header)
 Print all the particles to screen.
 
void reposition_particles ()
 Reposition the particles inside a cell for visualization.
 
int ngrow () const
 Number of grow cells.
 
void write_plot_file_impl (const std::string &plt_filename, const std::string &name)
 Write the particles to file (implementation)
 
void check_sort_type (const std::string &sort_type)
 Check valid sort type.
 
ParticleArrays< NArrayReal, NArrayInt, ParticleType, RealVector, IntVectorparticle_arrays (ParticleTileType &pti) const
 

Static Public Member Functions

static std::string identifier ()
 Class identifier name.
 
- Static Public Member Functions inherited from spades::particles::SpadesParticleContainer< MessageTypes::NTYPES, 0, 0, MessageRealData::ncomps, MessageIntData::ncomps >
static std::string identifier ()
 Class identifier name.
 

Private Attributes

int m_messages_per_lp {1}
 Initial messages per LP.
 
amrex::Real m_lambda {1.0}
 

Additional Inherited Members

- Public Types inherited from spades::particles::SpadesParticleContainer< MessageTypes::NTYPES, 0, 0, MessageRealData::ncomps, MessageIntData::ncomps >
using ParticleType
 
using ParticleTileType
 
using IntVector
 
using RealVector
 
- Static Public Attributes inherited from spades::particles::SpadesParticleContainer< MessageTypes::NTYPES, 0, 0, MessageRealData::ncomps, MessageIntData::ncomps >
static constexpr int LEV
 Level index.
 
- Protected Attributes inherited from spades::particles::SpadesParticleContainer< MessageTypes::NTYPES, 0, 0, MessageRealData::ncomps, MessageIntData::ncomps >
int m_ngrow
 Number of grow cells.
 
amrex::Vector< int > m_writeflags_real
 Flags for real data to write to file.
 
amrex::Vector< int > m_writeflags_int
 Flags for int data to write to file.
 
amrex::Vector< std::string > m_real_data_names
 Names for real data to write to file.
 
amrex::Vector< std::string > m_int_data_names
 Names for int data to write to file.
 
std::string m_sort_type
 Sort type.
 
amrex::iMultiFab m_counts
 Count of particles in each cell.
 
amrex::iMultiFab m_offsets
 Offsets of particles in each cell.
 
amrex::MultiFab m_min_timestamp
 Minimum timestamp in each cell for each type.
 
amrex::MultiFab m_max_timestamp
 Maximum timestamp in each cell for each type.
 

Detailed Description

Main SPADES message container.

Constructor & Destructor Documentation

◆ MessageParticleContainer() [1/2]

spades::particles::MessageParticleContainer::MessageParticleContainer ( amrex::AmrParGDB * par_gdb,
int ngrow = 0 )
explicit

Constructor.

Parameters
par_gdb[in] particle database
ngrow[in] number of grow cells
10 0,
11 0,
14{}
SpadesParticleContainer(amrex::AmrParGDB *par_gdb, int ngrow=0)
Definition SpadesParticleContainer.H:9
@ ncomps
Definition MessageData.H:28
@ ncomps
Definition MessageData.H:14
static constexpr int NTYPES
Number of different message types.
Definition MessageData.H:46

◆ MessageParticleContainer() [2/2]

spades::particles::MessageParticleContainer::MessageParticleContainer ( const amrex::Vector< amrex::Geometry > & geom,
const amrex::Vector< amrex::DistributionMapping > & dmap,
const amrex::Vector< amrex::BoxArray > & ba,
int ngrow = 0 )
explicit

Constructor.

Parameters
geom[in] geometry
dmap[in] distribution map
ba[in] box array
ngrow[in] number of grow cells

Member Function Documentation

◆ compute_gvt()

amrex::Real spades::particles::MessageParticleContainer::compute_gvt ( )

Compute the minimum time stamp of the messages.

474{
475 BL_PROFILE("spades::MessageParticleContainer::compute_gvt()");
476 // If this becomes a performance bottleneck it could be sped up by
477 // making a vector of just the message time stamps before the min op
478
479 amrex::Real gvt = constants::LARGE_NUM;
480
481#ifdef AMREX_USE_OMP
482#pragma omp parallel if (amrex::Gpu::notInLaunchRegion()) reduction(min : gvt)
483#endif
484 for (MyParIter pti(*this, LEV); pti.isValid(); ++pti) {
485 const size_t np = pti.numParticles();
486 const auto parrs = particle_arrays(pti.GetParticleTile());
487
488 amrex::Gpu::DeviceVector<amrex::Real> ts(np, constants::LARGE_NUM);
489 auto* p_ts = ts.data();
490 amrex::ParallelFor(np, [=] AMREX_GPU_DEVICE(long pidx) noexcept {
491 if (parrs.m_idata[CommonIntData::type_id][pidx] ==
493 p_ts[pidx] = parrs.m_rdata[CommonRealData::timestamp][pidx];
494 }
495 });
496 gvt = std::min(amrex::Reduce::Min(np, ts.data()), gvt);
497 }
498 amrex::ParallelDescriptor::ReduceRealMin(gvt);
499
500 return gvt;
501}
ParticleArrays< NArrayReal, NArrayInt, ParticleType, RealVector, IntVector > particle_arrays(ParticleTileType &pti) const
Definition SpadesParticleContainer.H:218
static constexpr amrex::Real LARGE_NUM
A large number.
Definition Constants.H:34
@ type_id
Definition ParticleData.H:18
@ timestamp
Definition ParticleData.H:12
static constexpr int MESSAGE
Message.
Definition MessageData.H:36
Here is the call graph for this function:

◆ garbage_collect()

void spades::particles::MessageParticleContainer::garbage_collect ( const amrex::Real gvt)

Perform garbage collection.

Parameters
gvt[in] global virtual time
447{
448 BL_PROFILE("spades::MessageParticleContainer::garbage_collect()");
449
450#ifdef AMREX_USE_OMP
451#pragma omp parallel if (amrex::Gpu::notInLaunchRegion())
452#endif
453 for (MyParIter pti(*this, LEV); pti.isValid(); ++pti) {
454 const size_t np = pti.numParticles();
455 const auto parrs = particle_arrays(pti.GetParticleTile());
456
457 amrex::ParallelFor(np, [=] AMREX_GPU_DEVICE(long pidx) noexcept {
458 if (((parrs.m_rdata[CommonRealData::timestamp][pidx] < gvt) &&
459 (parrs.m_idata[CommonIntData::type_id][pidx] !=
461 ((parrs.m_idata[CommonIntData::type_id][pidx] ==
463 (parrs.m_rdata[MessageRealData::creation_time][pidx] < gvt))) {
464 AMREX_ASSERT(
465 parrs.m_idata[CommonIntData::type_id][pidx] !=
467 MarkMessageUndefined()(pidx, parrs);
468 }
469 });
470 }
471}
@ creation_time
Definition MessageData.H:13
static constexpr int UNDEFINED
Undefined message.
Definition MessageData.H:44
static constexpr int CONJUGATE
Conjugate message (unsent anti-message)
Definition MessageData.H:42
Here is the call graph for this function:

◆ identifier()

static std::string spades::particles::MessageParticleContainer::identifier ( )
inlinestatic

Class identifier name.

Returns
class identifier
31{ return "messages"; }
Here is the caller graph for this function:

◆ initialize_messages()

void spades::particles::MessageParticleContainer::initialize_messages ( const amrex::Real lookahead)

Initialize the messages.

Parameters
lookahead[in] lookahead
79{
80 BL_PROFILE("spades::MessageParticleContainer::initialize_messages()");
81
82 const auto& plo = Geom(LEV).ProbLoArray();
83 const auto& dx = Geom(LEV).CellSizeArray();
84 const auto& dom = Geom(LEV).Domain();
85 const auto messages_per_lp = m_messages_per_lp;
86 const auto lambda = m_lambda;
87 const int total_messages_per_lp = 3 * messages_per_lp;
88 AMREX_ALWAYS_ASSERT(total_messages_per_lp > messages_per_lp);
89
90 for (amrex::MFIter mfi = MakeMFIter(LEV); mfi.isValid(); ++mfi) {
91 DefineAndReturnParticleTile(LEV, mfi);
92 }
93
94 amrex::iMultiFab num_particles(
95 ParticleBoxArray(LEV), ParticleDistributionMap(LEV), 1, 0,
96 amrex::MFInfo());
97 amrex::iMultiFab init_offsets(
98 ParticleBoxArray(LEV), ParticleDistributionMap(LEV), 1, 0,
99 amrex::MFInfo());
100 num_particles.setVal(total_messages_per_lp);
101 init_offsets.setVal(0);
102
103 for (amrex::MFIter mfi = MakeMFIter(LEV); mfi.isValid(); ++mfi) {
104 const amrex::Box& box = mfi.tilebox();
105
106 const auto ncells = static_cast<int>(box.numPts());
107 const int* in = num_particles[mfi].dataPtr();
108 int* out = init_offsets[mfi].dataPtr();
109 const auto np = amrex::Scan::PrefixSum<int>(
110 ncells, [=] AMREX_GPU_DEVICE(int i) -> int { return in[i]; },
111 [=] AMREX_GPU_DEVICE(int i, int const& xi) { out[i] = xi; },
112 amrex::Scan::Type::exclusive, amrex::Scan::retSum);
113
114 const amrex::Long pid = ParticleType::NextID();
115 ParticleType::NextID(pid + np);
116 AMREX_ALWAYS_ASSERT_WITH_MESSAGE(
117 static_cast<amrex::Long>(pid + np) < amrex::LastParticleID,
118 "Error: overflow on particle id numbers!");
119
120 const auto my_proc = amrex::ParallelDescriptor::MyProc();
121 const auto& offset_arr = init_offsets[mfi].const_array();
122 const auto& num_particles_arr = num_particles[mfi].const_array();
123 const auto index = std::make_pair(mfi.index(), mfi.LocalTileIndex());
124 auto& pti = GetParticles(LEV)[index];
125 pti.resize(np);
126 const auto parrs = particle_arrays(pti);
127 amrex::ParallelForRNG(
128 box, [=] AMREX_GPU_DEVICE(
129 int i, int j, int AMREX_D_PICK(, , k),
130 amrex::RandomEngine const& engine) noexcept {
131 const amrex::IntVect iv(AMREX_D_DECL(i, j, k));
132 const int start = offset_arr(iv);
133 for (int n = start; n < start + num_particles_arr(iv); n++) {
134 auto& p = parrs.m_aos[n];
135 p.id() = pid + n;
136 p.cpu() = my_proc;
137
138 MarkMessageUndefined()(n, parrs);
139 parrs.m_idata[MessageIntData::sender_lp][n] =
140 static_cast<int>(dom.index(iv));
141 parrs.m_idata[MessageIntData::sender_entity][n] = 0;
142 parrs.m_idata[MessageIntData::receiver_lp][n] =
143 static_cast<int>(dom.index(iv));
144 parrs.m_idata[MessageIntData::receiver_entity][n] = 0;
145
146 AMREX_D_TERM(
147 p.pos(0) = plo[0] + (iv[0] + constants::HALF) * dx[0];
148 , p.pos(1) = plo[1] + (iv[1] + constants::HALF) * dx[1];
149 ,
150 p.pos(2) = plo[2] + (iv[2] + constants::HALF) * dx[2];)
151
152 AMREX_D_TERM(parrs.m_idata[CommonIntData::i][n] = iv[0];
153 , parrs.m_idata[CommonIntData::j][n] = iv[1];
154 , parrs.m_idata[CommonIntData::k][n] = iv[2];)
155 }
156
157 for (int n = start; n < start + messages_per_lp; n++) {
158 const amrex::Real ts =
159 random_exponential(lambda, engine) + lookahead;
160
161 parrs.m_rdata[CommonRealData::timestamp][n] = ts;
162 parrs.m_rdata[MessageRealData::creation_time][n] = 0.0;
163 parrs.m_idata[CommonIntData::type_id][n] =
165 parrs.m_idata[MessageIntData::pair_id][n] = -1;
166 parrs.m_idata[MessageIntData::pair_cpu][n] = -1;
167 }
168 });
169
170 // This is necessary
171 amrex::Gpu::streamSynchronize();
172 }
173 Redistribute();
174
175 // Sanity check all initial particles
176#ifdef AMREX_USE_OMP
177#pragma omp parallel if (amrex::Gpu::notInLaunchRegion())
178#endif
179 for (MyParIter pti(*this, LEV); pti.isValid(); ++pti) {
180 const size_t np = pti.numParticles();
181 const auto parrs = particle_arrays(pti.GetParticleTile());
182
183 amrex::ParallelFor(np, [=] AMREX_GPU_DEVICE(long pidx) noexcept {
184 bool valid_type = false;
185 for (int typ = 0; typ < MessageTypes::NTYPES; typ++) {
186 valid_type = parrs.m_idata[CommonIntData::type_id][pidx] == typ;
187 if (valid_type) {
188 break;
189 }
190 }
191 AMREX_ASSERT(valid_type);
192 AMREX_ASSERT(parrs.m_aos[pidx].id() >= 0);
193 });
194 }
195}
int m_messages_per_lp
Initial messages per LP.
Definition MessageParticleContainer.H:90
amrex::Real m_lambda
Definition MessageParticleContainer.H:95
static constexpr amrex::Real HALF
Definition Constants.H:37
amrex::Real random_exponential(const amrex::Real lambda)
Exponential distribution.
Definition Utilities.cpp:4
@ receiver_lp
Definition MessageData.H:23
@ pair_id
Definition MessageData.H:27
@ sender_entity
Definition MessageData.H:24
@ pair_cpu
Definition MessageData.H:26
@ sender_lp
Definition MessageData.H:22
@ receiver_entity
Definition MessageData.H:25
Here is the call graph for this function:

◆ initialize_variable_names()

void spades::particles::MessageParticleContainer::initialize_variable_names ( )
overridevirtual

Initialize variable names.

Implements spades::particles::SpadesParticleContainer< MessageTypes::NTYPES, 0, 0, MessageRealData::ncomps, MessageIntData::ncomps >.

40{
41 BL_PROFILE("spades::MessageParticleContainer::initialize_variable_names()");
42
47
54
55 AMREX_D_TERM(
56 m_int_data_names[CommonIntData::i] = "i";
57 m_writeflags_int[CommonIntData::i] = 1;
58 , m_int_data_names[CommonIntData::j] = "j";
59 m_writeflags_int[CommonIntData::j] = 1;
60 , m_int_data_names[CommonIntData::k] = "k";
61 m_writeflags_int[CommonIntData::k] = 1;)
76}
@ old_timestamp
Definition MessageData.H:12

◆ read_parameters()

void spades::particles::MessageParticleContainer::read_parameters ( )
overridevirtual

Read user parameters.

Reimplemented from spades::particles::SpadesParticleContainer< MessageTypes::NTYPES, 0, 0, MessageRealData::ncomps, MessageIntData::ncomps >.

30{
32 {
33 amrex::ParmParse pp("spades");
34 pp.query("messages_per_lp", m_messages_per_lp);
35 pp.query("lambda", m_lambda);
36 }
37}
virtual void read_parameters()
Read user parameters.
Definition SpadesParticleContainer.H:197
Here is the call graph for this function:

◆ resolve_pairs()

void spades::particles::MessageParticleContainer::resolve_pairs ( )

Resolve message pairs (remove message/anti-message pairs)

341{
342 BL_PROFILE("spades::MessageParticleContainer::resolve_pairs()");
343
344#ifdef AMREX_DEBUG
345 const auto& dom = Geom(LEV).Domain();
346#endif
347
348#ifdef AMREX_USE_OMP
349#pragma omp parallel if (amrex::Gpu::notInLaunchRegion())
350#endif
351 for (amrex::MFIter mfi = MakeMFIter(LEV); mfi.isValid(); ++mfi) {
352 const amrex::Box& box = mfi.tilebox();
353 const auto& cnt_arr = m_counts.const_array(mfi);
354 const auto& offsets_arr = m_offsets.const_array(mfi);
355 const auto index = std::make_pair(mfi.index(), mfi.LocalTileIndex());
356 auto& pti = GetParticles(LEV)[index];
357 const auto parrs = particle_arrays(pti);
358
359 amrex::ParallelFor(
360 box, [=] AMREX_GPU_DEVICE(
361 int i, int j, int AMREX_D_PICK(, , k)) noexcept {
362 const amrex::IntVect iv(AMREX_D_DECL(i, j, k));
363 const auto getter = Get(iv, cnt_arr, offsets_arr, parrs);
364
365 for (int n = 0; n < cnt_arr(iv, MessageTypes::ANTI); n++) {
366 const auto pant_soa = getter(n, MessageTypes::ANTI);
367 AMREX_ASSERT(
368 parrs.m_idata[MessageIntData::pair_id][pant_soa] != -1);
369 AMREX_ASSERT(
370 parrs.m_idata[MessageIntData::pair_cpu][pant_soa] !=
371 -1);
372 AMREX_ASSERT(
373 parrs.m_idata[MessageIntData::receiver_lp][pant_soa] ==
374 dom.index(iv));
375
376#ifdef AMREX_DEBUG
377 bool found_pair = false;
378#endif
379 for (int m = 0; m < cnt_arr(iv, MessageTypes::MESSAGE);
380 m++) {
381 // This is a message that was already treated,
382 // expect it to be undefined
383 if (!getter.check(m, MessageTypes::MESSAGE)) {
384 getter.assert_different(
387 continue;
388 }
389 const auto pmsg_soa = getter(m, MessageTypes::MESSAGE);
390 if ((parrs.m_idata[MessageIntData::pair_id][pmsg_soa] ==
391 parrs
392 .m_idata[MessageIntData::pair_id][pant_soa]) &&
393 (parrs
394 .m_idata[MessageIntData::pair_cpu][pmsg_soa] ==
395 parrs.m_idata[MessageIntData::pair_cpu]
396 [pant_soa]) &&
397 (std::abs(
398 parrs.m_rdata[CommonRealData::timestamp]
399 [pmsg_soa] -
400 parrs.m_rdata[CommonRealData::timestamp]
401 [pant_soa]) < constants::EPS)) {
402 AMREX_ASSERT(
403 parrs.m_idata[MessageIntData::sender_lp]
404 [pmsg_soa] ==
405 parrs.m_idata[MessageIntData::sender_lp]
406 [pant_soa]);
407 AMREX_ASSERT(
408 parrs.m_idata[MessageIntData::sender_entity]
409 [pmsg_soa] ==
410 parrs.m_idata[MessageIntData::sender_entity]
411 [pant_soa]);
412 AMREX_ASSERT(
413 parrs.m_idata[MessageIntData::receiver_lp]
414 [pmsg_soa] ==
415 parrs.m_idata[MessageIntData::receiver_lp]
416 [pant_soa]);
417 AMREX_ASSERT(
419 [pmsg_soa] ==
421 [pant_soa]);
422 AMREX_ASSERT(
423 std::abs(
424 parrs
426 [pmsg_soa] -
427 parrs
429 [pant_soa]) < constants::EPS);
430 MarkMessageUndefined()(pant_soa, parrs);
431 MarkMessageUndefined()(pmsg_soa, parrs);
432#ifdef AMREX_DEBUG
433 found_pair = true;
434#endif
435 break;
436 }
437 }
438 AMREX_ASSERT(found_pair);
439 }
440 });
441 }
442
443 sort();
444}
void sort() override
Sort the messages.
Definition MessageParticleContainer.cpp:196
static constexpr amrex::Real EPS
A number very close to zero.
Definition Constants.H:27
static constexpr int ANTI
Anti-message.
Definition MessageData.H:40
Here is the call graph for this function:

◆ sort()

void spades::particles::MessageParticleContainer::sort ( )
overridevirtual

Sort the messages.

Implements spades::particles::SpadesParticleContainer< MessageTypes::NTYPES, 0, 0, MessageRealData::ncomps, MessageIntData::ncomps >.

197{
198 BL_PROFILE("spades::MessageParticleContainer::sort()");
199
200 sort_impl(CompareParticle());
201}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ update_undefined()

void spades::particles::MessageParticleContainer::update_undefined ( )

Update the undefined messages.

204{
205 BL_PROFILE("spades::MessageParticleContainer::update_undefined()");
206
207 const auto& plo = Geom(LEV).ProbLoArray();
208 const auto& dx = Geom(LEV).CellSizeArray();
209 const auto& dom = Geom(LEV).Domain();
210 int n_removals = 0;
211
213 m_gdb->Geom(), m_gdb->DistributionMap(), m_gdb->boxArray(), ngrow());
214 for (amrex::MFIter mfi = MakeMFIter(LEV); mfi.isValid(); ++mfi) {
215 pc_adds.DefineAndReturnParticleTile(LEV, mfi);
216 }
217
218 for (amrex::MFIter mfi = MakeMFIter(LEV); mfi.isValid(); ++mfi) {
219 const amrex::Box& box = mfi.tilebox();
220 const auto index = std::make_pair(mfi.index(), mfi.LocalTileIndex());
221 const auto& cnt_arr = m_counts.const_array(mfi);
222 const auto& offsets_arr = m_offsets.const_array(mfi);
223 auto& pti = GetParticles(LEV)[index];
224 const auto parrs = particle_arrays(pti);
225
226 // remove particles
227 const auto ncells = static_cast<int>(box.numPts());
228 amrex::Gpu::DeviceVector<int> removals(ncells, 0);
229 auto* p_removals = removals.data();
230 amrex::ParallelFor(ncells, [=] AMREX_GPU_DEVICE(long icell) noexcept {
231 const auto iv = box.atOffset(icell);
232 const int msg_count = cnt_arr(iv, MessageTypes::MESSAGE);
233 const int target_count = std::max(2 * msg_count, 2);
234 const int current_count = cnt_arr(iv, MessageTypes::UNDEFINED);
235 if (current_count > target_count) {
236 p_removals[icell] = current_count - target_count;
237 }
238 });
239
240 n_removals += amrex::Reduce::Sum(removals.size(), p_removals);
241
242 amrex::ParallelFor(
243 box, [=] AMREX_GPU_DEVICE(
244 int i, int j, int AMREX_D_PICK(, , k)) noexcept {
245 const amrex::IntVect iv(AMREX_D_DECL(i, j, k));
246 const auto idx = box.index(iv);
247 const auto np = p_removals[idx];
248 const auto getter = Get(iv, cnt_arr, offsets_arr, parrs);
249 for (int m = 0; m < np; m++) {
250 const auto pidx = getter(m, MessageTypes::UNDEFINED);
251 parrs.m_aos[pidx].id() = -1;
252 }
253 });
254
255 amrex::Gpu::DeviceVector<int> additions(ncells, 0);
256 auto* p_additions = additions.data();
257 amrex::ParallelFor(ncells, [=] AMREX_GPU_DEVICE(long icell) noexcept {
258 const auto iv = box.atOffset(icell);
259 const int msg_count = cnt_arr(iv, MessageTypes::MESSAGE);
260 const int target_count = std::max(2 * msg_count, 2);
261 const int current_count = cnt_arr(iv, MessageTypes::UNDEFINED);
262 if (target_count > current_count) {
263 p_additions[icell] = target_count - current_count;
264 }
265#ifdef AMREX_DEBUG
266 if (p_removals[icell] > 0) {
267 AMREX_ASSERT(p_additions[icell] == 0);
268 }
269 if (p_additions[icell] > 0) {
270 AMREX_ASSERT(p_removals[icell] == 0);
271 }
272#endif
273 });
274
275 amrex::Gpu::DeviceVector<int> update_offsets(ncells, 0);
276 auto* p_update_offsets = update_offsets.data();
277 const auto np = amrex::Scan::PrefixSum<int>(
278 ncells,
279 [=] AMREX_GPU_DEVICE(int i) -> int { return p_additions[i]; },
280 [=] AMREX_GPU_DEVICE(int i, int const& xi) {
281 p_update_offsets[i] = xi;
282 },
283 amrex::Scan::Type::exclusive, amrex::Scan::retSum);
284
285 const amrex::Long pid = ParticleType::NextID();
286 ParticleType::NextID(pid + np);
287 AMREX_ALWAYS_ASSERT_WITH_MESSAGE(
288 static_cast<amrex::Long>(pid + np) < amrex::LastParticleID,
289 "Error: overflow on particle id numbers!");
290
291 auto& pti_adds = pc_adds.GetParticles(LEV)[index];
292 pti_adds.resize(np);
293 const auto my_proc = amrex::ParallelDescriptor::MyProc();
294 const auto parrs_adds = pc_adds.particle_arrays(pti_adds);
295 amrex::ParallelFor(ncells, [=] AMREX_GPU_DEVICE(long icell) noexcept {
296 const int start = p_update_offsets[icell];
297 const auto iv = box.atOffset(icell);
298 for (int n = start; n < start + p_additions[icell]; n++) {
299 auto& p = parrs_adds.m_aos[n];
300 p.id() = pid + n;
301 p.cpu() = my_proc;
302
303 AMREX_D_TERM(
304 p.pos(0) = plo[0] + (iv[0] + constants::HALF) * dx[0];
305 , p.pos(1) = plo[1] + (iv[1] + constants::HALF) * dx[1];
306 , p.pos(2) = plo[2] + (iv[2] + constants::HALF) * dx[2];)
307
308 MarkMessageUndefined()(n, parrs_adds);
309 parrs_adds.m_idata[MessageIntData::sender_lp][n] =
310 static_cast<int>(dom.index(iv));
311 parrs_adds.m_idata[MessageIntData::sender_entity][n] = 0;
312 parrs_adds.m_idata[MessageIntData::receiver_lp][n] =
313 static_cast<int>(dom.index(iv));
314 parrs_adds.m_idata[MessageIntData::receiver_entity][n] = 0;
315
316 AMREX_D_TERM(
317 p.pos(0) = plo[0] + (iv[0] + constants::HALF) * dx[0];
318 , p.pos(1) = plo[1] + (iv[1] + constants::HALF) * dx[1];
319 , p.pos(2) = plo[2] + (iv[2] + constants::HALF) * dx[2];)
320
321 AMREX_D_TERM(parrs_adds.m_idata[CommonIntData::i][n] = iv[0];
322 , parrs_adds.m_idata[CommonIntData::j][n] = iv[1];
323 , parrs_adds.m_idata[CommonIntData::k][n] = iv[2];)
324 }
325 });
326
327 // This is necessary
328 amrex::Gpu::streamSynchronize();
329 }
330
331 addParticles(pc_adds, true);
332
333 amrex::ParallelAllReduce::Sum<int>(
334 n_removals, amrex::ParallelContext::CommunicatorSub());
335 if (n_removals > 0) {
336 Redistribute(); // kind of a bummer
337 }
338}
MessageParticleContainer(amrex::AmrParGDB *par_gdb, int ngrow=0)
Constructor.
Definition MessageParticleContainer.cpp:6
Here is the call graph for this function:

◆ write_plot_file()

void spades::particles::MessageParticleContainer::write_plot_file ( const std::string & plt_filename)
inlineoverridevirtual

Write the particles to file.

Parameters
plt_filename[in] file name for the plot file

Implements spades::particles::SpadesParticleContainer< MessageTypes::NTYPES, 0, 0, MessageRealData::ncomps, MessageIntData::ncomps >.

78 {
79 write_plot_file_impl(plt_filename, identifier());
80 };
static std::string identifier()
Class identifier name.
Definition MessageParticleContainer.H:31
void write_plot_file_impl(const std::string &plt_filename, const std::string &name)
Definition SpadesParticleContainer.H:760
Here is the call graph for this function:

Member Data Documentation

◆ m_lambda

amrex::Real spades::particles::MessageParticleContainer::m_lambda {1.0}
private

Width of exponential distribution (optional user input) smaller values of lambda = larger variance in random values larger values of lambda = smaller variance in random values

95{1.0};

◆ m_messages_per_lp

int spades::particles::MessageParticleContainer::m_messages_per_lp {1}
private

Initial messages per LP.

90{1};

The documentation for this class was generated from the following files: