14#if defined(MFEM_USE_MPI) && defined(MFEM_USE_GSLIB)
17#ifdef MFEM_HAVE_GCC_PRAGMA_DIAGNOSTIC
18#pragma GCC diagnostic push
19#pragma GCC diagnostic ignored "-Wunused-function"
30#ifdef MFEM_HAVE_GCC_PRAGMA_DIAGNOSTIC
31#pragma GCC diagnostic pop
41 : coords(
dim), fields(), tags()
46 for (
int f = 0;
f < field_vdims.
Size();
f++)
48 fields.emplace_back(field_vdims[
f]);
52 tags.reserve(num_tags);
53 for (
int t = 0; t < num_tags; t++)
63 static_cast<size_t>(t) <
tags.size(),
"Invalid tag index");
64 tags[t].MakeRef(tag_data, 1);
70 static_cast<size_t>(
f) <
fields.size(),
"Invalid field "
95 for (
size_t f = 0;
f <
fields.size();
f++)
101 for (
int c = 0; c <
fields[
f].Size(); c++)
114 for (
size_t t = 0; t <
tags.size(); t++)
132 for (
size_t f = 0;
f <
fields.size();
f++)
134 os <<
"Field " <<
f <<
": (";
135 for (
int c = 0; c <
fields[
f].Size(); c++)
140 for (
size_t t = 0; t <
tags.size(); t++)
142 os <<
"Tag " << t <<
": " <<
tags[t][0] <<
"\n";
152std::string ParticleSet::GetDefaultFieldName(
int i)
154 return "Field_" + std::to_string(i);
157std::string ParticleSet::GetDefaultTagName(
int i)
159 return "Tag_" + std::to_string(i);
162Array<const char*> ParticleSet::GetEmptyNameArray(
int N)
164 Array<const char*> names(N);
170int ParticleSet::GetRank(MPI_Comm comm_)
172 int r; MPI_Comm_rank(comm_, &r);
175int ParticleSet::GetSize(MPI_Comm comm_)
177 int s; MPI_Comm_size(comm_, &s);
194 for (
int t = 0; t <
GetNTags(); t++)
196 tags[t]->Reserve(res);
214 int num_add = new_ids.
Size();
216 int new_np = old_np + num_add;
222 for (
int i = 0; i < num_add; i++)
224 (*new_indices)[i] =
ids.
Size() + i;
238 for (
int t = 0; t <
GetNTags(); t++)
240 tags[t]->SetSize(new_np);
244#if defined(MFEM_USE_MPI) && defined(MFEM_USE_GSLIB)
247template<
size_t NBytes>
248void ParticleSet::TransferParticlesImpl(
ParticleSet &pset,
254 alignas(
real_t) std::array<std::byte, NBytes> data;
260 size_t nbytes = nreals*
sizeof(
real_t) + ntags*
sizeof(
int);
261 MFEM_VERIFY(nbytes <= NBytes,
"More data than can be packed.");
263 using parr_t = pdata_t;
264 gslib::array gsl_arr;
266 array_init(parr_t, &gsl_arr, send_idxs.
Size());
267 pdata_arr = (parr_t*) gsl_arr.ptr;
269 gsl_arr.n = send_idxs.
Size();
270 for (
int i = 0; i < send_idxs.
Size(); i++)
272 parr_t &pdata = pdata_arr[i];
273 pdata.id = pset.
GetIDs()[send_idxs[i]];
279 ParticleVector &pv = (
f == -1 ? pset.
Coords() : pset.
Field(
f));
280 for (
int c = 0; c < pv.GetVDim(); c++)
282 std::memcpy(pdata.data.data() + counter, &pv(send_idxs[i], c),
284 counter +=
sizeof(
real_t);
289 for (
int t = 0; t < pset.
GetNTags(); t++)
291 Array<int> &tag_arr = pset.
Tag(t);
292 std::memcpy(pdata.data.data() + counter, &tag_arr[send_idxs[i]],
294 counter +=
sizeof(int);
299 int nsend = send_idxs.
Size();
302 sarray_transfer_ext(parr_t, &gsl_arr, send_ranks.
GetData(),
303 sizeof(
unsigned int), pset.
cr);
306 int nrecv = (int) gsl_arr.n;
307 int ndelete = nsend - nrecv;
311 auto datap =
const_cast<int*
>(send_idxs.
GetData());
312 Array<int> delete_idxs(datap + nrecv, ndelete);
317 pset.
Reserve(nparticles-ndelete);
320 pdata_arr = (parr_t*) gsl_arr.ptr;
323 for (
int i = 0; i < nrecv; i++)
325 parr_t &pdata = pdata_arr[i];
331 new_loc_idx = send_idxs[i];
339 new_loc_idx = idx_temp[0];
345 ParticleVector &pv = (
f == -1 ? pset.
Coords() : pset.
Field(
f));
346 for (
int c = 0; c < pv.GetVDim(); c++)
348 real_t& val = pv(new_loc_idx, c);
349 std::memcpy(&val, pdata.data.data() + counter,
sizeof(
real_t));
350 counter +=
sizeof(
real_t);
354 for (
int t = 0; t < pset.
GetNTags(); t++)
356 Array<int> &tag_arr = pset.
Tag(t);
357 std::memcpy(&tag_arr[new_loc_idx],
358 pdata.data.data() + counter,
sizeof(
int));
359 counter +=
sizeof(int);
362 array_free(&gsl_arr);
365template<
size_t NBytes>
366ParticleSet::TransferParticlesType ParticleSet::TransferParticles::Kernel()
368 return &ParticleSet::TransferParticlesImpl<NBytes>;
371ParticleSet::Kernels::Kernels()
373 constexpr size_t sizd =
sizeof(
real_t);
374 TransferParticles::Specialization<2*sizd>::Add();
375 TransferParticles::Specialization<3*sizd>::Add();
376 TransferParticles::Specialization<4*sizd>::Add();
377 TransferParticles::Specialization<8*sizd>::Add();
378 TransferParticles::Specialization<12*sizd>::Add();
379 TransferParticles::Specialization<16*sizd>::Add();
380 TransferParticles::Specialization<20*sizd>::Add();
381 TransferParticles::Specialization<24*sizd>::Add();
382 TransferParticles::Specialization<28*sizd>::Add();
383 TransferParticles::Specialization<32*sizd>::Add();
384 TransferParticles::Specialization<36*sizd>::Add();
385 TransferParticles::Specialization<40*sizd>::Add();
388auto ParticleSet::TransferParticles::Fallback(
size_t bufsize)
389-> ParticleSet::TransferParticlesType
391 constexpr size_t sizd =
sizeof(
real_t);
392 if (bufsize < 4*sizd)
394 return &ParticleSet::TransferParticlesImpl<4*sizd>;
396 else if (bufsize < 8*sizd)
398 return &ParticleSet::TransferParticlesImpl<8*sizd>;
400 else if (bufsize < 12*sizd)
402 return &ParticleSet::TransferParticlesImpl<12*sizd>;
404 else if (bufsize < 16*sizd)
406 return &ParticleSet::TransferParticlesImpl<16*sizd>;
408 else if (bufsize < 20*sizd)
410 return &ParticleSet::TransferParticlesImpl<20*sizd>;
412 else if (bufsize < 24*sizd)
414 return &ParticleSet::TransferParticlesImpl<24*sizd>;
416 else if (bufsize < 28*sizd)
418 return &ParticleSet::TransferParticlesImpl<28*sizd>;
420 else if (bufsize < 32*sizd)
422 return &ParticleSet::TransferParticlesImpl<32*sizd>;
424 else if (bufsize < 36*sizd)
426 return &ParticleSet::TransferParticlesImpl<36*sizd>;
428 else if (bufsize < 40*sizd)
430 return &ParticleSet::TransferParticlesImpl<40*sizd>;
432 return &ParticleSet::TransferParticlesImpl<60*sizd>;
439 "rank_list must be of size GetNParticles().");
441 int rank = GetRank(
comm);
449 for (
int i = 0; i < rank_list.
Size(); i++)
451 if (rank !=
static_cast<int>(rank_list[i]))
454 send_ranks.
Append(rank_list[i]);
461 size_t nbytes = nreals*
sizeof(
real_t) + ntags*
sizeof(
int);
464 TransferParticles::Run(nbytes, *
this, send_idxs, send_ranks);
475 const std::stringstream &ss_header,
const std::stringstream &ss_data)
480 int rank = GetRank(
comm);
482 MPI_File_delete(fname, MPI_INFO_NULL);
484 int mpi_err = MPI_File_open(
comm, fname, MPI_MODE_CREATE | MPI_MODE_WRONLY,
485 MPI_INFO_NULL, &file);
486 MFEM_VERIFY(mpi_err == MPI_SUCCESS,
"MPI_File_open failed.");
491 MPI_File_write_at(file, 0, ss_header.str().data(), ss_header.str().size(),
492 MPI_CHAR, MPI_STATUS_IGNORE);
496 MPI_Offset data_size = ss_data.str().size();
500 MPI_Exscan(&data_size, &offset, 1, MPI_OFFSET, MPI_SUM,
comm);
507 offset += ss_header.str().size();
510 MPI_File_write_at_all(file, offset, ss_data.str().data(),
511 data_size, MPI_BYTE, MPI_STATUS_IGNORE);
514 MPI_File_close(&file);
517 std::ofstream ofs(fname);
518 MFEM_VERIFY(ofs.is_open() && !ofs.fail(),
519 "Error: Could not open file " << fname <<
" for writing.");
520 ofs << ss_header.str() << ss_data.str();
530 : id_stride(id_stride_),
531 id_counter(id_counter_),
532 coords(
dim, coords_ordering)
535 for (
int f = 0;
f < field_vdims.
Size();
f++)
537 AddField(field_vdims[
f], field_orderings[
f], field_names_[
f]);
541 for (
int t = 0; t < num_tags; t++)
548 for (
int i = 0; i < num_particles; i++)
586 Array<const char*>())
594 :
ParticleSet(1, 0, num_particles,
dim, all_ordering, field_vdims,
595 GetOrderingArray(all_ordering, field_vdims.Size()),
596 GetEmptyNameArray(field_vdims.Size()), num_tags,
597 GetEmptyNameArray(num_tags))
603 char*> &field_names_,
int num_tags,
606 :
ParticleSet(1, 0, num_particles,
dim, all_ordering, field_vdims,
607 GetOrderingArray(all_ordering, field_vdims.Size()),
608 field_names_, num_tags,
620 :
ParticleSet(1, 0, num_particles,
dim, coords_ordering, field_vdims,
621 field_orderings, field_names_, num_tags, tag_names_)
633 Array<const char*>())
641 :
ParticleSet(comm_, rank_num_particles,
dim, all_ordering, field_vdims,
642 GetOrderingArray(all_ordering, field_vdims.Size()),
643 GetEmptyNameArray(field_vdims.Size()), num_tags,
644 GetEmptyNameArray(num_tags))
651 char*> &field_names_,
654 :
ParticleSet(comm_, rank_num_particles,
dim, all_ordering, field_vdims,
655 GetOrderingArray(all_ordering, field_vdims.Size()),
656 field_names_, num_tags,
681 cr =
new gslib::crystal;
692 MPI_Allreduce(MPI_IN_PLACE, &total, 1, MPI_UNSIGNED_LONG_LONG,
699 const char* field_name)
701 std::string field_name_str(field_name ? field_name :
"");
704 field_name_str = GetDefaultFieldName(
field_names.size());
706 fields.emplace_back(std::make_unique<ParticleVector>(vdim, field_ordering,
715 std::string tag_name_str(tag_name ? tag_name :
"");
718 tag_name_str = GetDefaultTagName(
tag_names.size());
729 "Particle is incompatible with ParticleSet.");
744 for (
int i = 0; i < num_particles; i++)
766 for (
int t = 0; t <
GetNTags(); t++)
768 tags[t]->DeleteAt(list);
783 for (
int t = 0; t <
GetNTags(); t++)
785 p.Tag(t) =
Tag(t)[i];
816 "GetParticleRef only valid when all fields ordered byVDIM.");
820 for (
int t = 0; t <
GetNTags(); t++)
822 p.SetTagRef(t, &(*
tags[t])[i]);
831 "Particle is incompatible with ParticleSet.");
840 for (
int t = 0; t <
GetNTags(); t++)
842 Tag(t)[i] =
p.Tag(t);
852 all_field_idxs[
f] =
f;
855 for (
int t = 0; t <
GetNTags(); t++)
860 PrintCSV(fname, all_field_idxs, all_tag_idxs, precision);
866 std::stringstream ss_header;
872 ss_header <<
",rank";
875 std::array<char, 3> ax = {
'X',
'Y',
'Z'};
878 ss_header <<
"," << ax[c];
881 for (
int f = 0;
f < field_idxs.
Size();
f++)
884 for (
int c = 0; c < pv.
GetVDim(); c++)
887 (pv.
GetVDim() > 1 ?
"_" + std::to_string(c) :
"");
891 for (
int t = 0; t < tag_idxs.
Size(); t++)
893 ss_header <<
"," <<
tag_names[tag_idxs[t]];
898 std::stringstream ss_data;
899 ss_data.precision(precision);
901 int rank = GetRank(
comm);
907 ss_data <<
"," << rank;
912 ss_data <<
"," <<
coords(i, c);
914 for (
int f = 0;
f < field_idxs.
Size();
f++)
917 for (
int c = 0; c < pv.
GetVDim(); c++)
919 ss_data <<
"," << pv(i, c);
922 for (
int t = 0; t < tag_idxs.
Size(); t++)
924 ss_data <<
"," << (*
tags[tag_idxs[t]])[i];
935#if defined(MFEM_USE_MPI) && defined(MFEM_USE_GSLIB)
void Reserve(int capacity)
Ensures that the allocated size is at least the given size.
void SetSize(int nsize)
Change the logical size of the array, keep existing entries.
int Size() const
Return the logical size of the array.
int Append(const T &el)
Append element 'el' to array, resize if necessary.
T * GetData()
Returns the data.
void DeleteAt(const Array< int > &indices)
Delete entries at indices, and resize.
T Sum() const
Return the sum of all the array entries using the '+'' operator for class 'T'.
static bool IsFinalized()
Return true if MPI has been finalized.
The ordering method used when the number of unknowns per mesh node (vector dimension) is bigger than ...
ParticleSet initializes and manages data associated with particles.
Array< IDType > ids
Global unique IDs of particles owned by this rank.
ParticleVector coords
Spatial coordinates of particles owned by this rank.
~ParticleSet()
Destructor.
unsigned long long IDType
void Redistribute(const Array< unsigned int > &rank_list)
Redistribute particle data to rank_list.
int GetNTags() const
Get the number of tags registered to particles.
void AddParticle(const Particle &p)
Add a particle using Particle .
bool IsValidParticle(const Particle &p) const
Check if a particle could belong in this ParticleSet by comparing field and tag dimension.
Particle GetParticleRef(int i)
Get Particle object whose members reference the actual data associated with particle i in this Partic...
std::vector< std::string > tag_names
Tag names, to be written when PrintCSV() is called.
std::vector< std::unique_ptr< ParticleVector > > fields
All particle fields for particles owned by this rank.
Particle GetParticle(int i) const
Get new Particle object with copy of data associated with particle i .
const Array< int > GetFieldVDims() const
Get an Array<int> of the field vector-dimensions registered to particles.
ParticleVector & Coords()
Get a reference to the coordinates ParticleVector.
const Array< IDType > & GetIDs() const
Get the global IDs of the active particles owned by this ParticleSet.
int GetNFields() const
Get the number of fields registered to particles.
int AddTag(const char *tag_name=nullptr)
Add a tag to the ParticleSet.
const int id_stride
Stride for IDs (used internally when new particles are added).
void UpdateID(int local_idx, IDType new_global_id)
Update global ID of a particle.
bool IsParticleRefValid() const
Determine if GetParticleRef is valid.
ParticleVector & Field(int f)
Get a reference to field f 's ParticleVector.
int GetDim() const
Get the spatial dimension.
int GetNParticles() const
Get the number of active particles currently held by this ParticleSet.
void WriteToFile(const char *fname, const std::stringstream &ss_header, const std::stringstream &ss_data)
Write string in ss_header , followed by ss_data , to a single file; compatible in parallel.
ParticleSet(int id_stride_, IDType id_counter_, int num_particles, int dim, Ordering::Type coords_ordering, const Array< int > &field_vdims, const Array< Ordering::Type > &field_orderings, const Array< const char * > &field_names_, int num_tags, const Array< const char * > &tag_names_)
Hidden main constructor of ParticleSet.
Array< int > & Tag(int t)
Get a reference to tag t 's Array<int>.
int AddField(int vdim, Ordering::Type field_ordering=Ordering::byVDIM, const char *field_name=nullptr)
Add a field to the ParticleSet.
struct gslib::crystal * cr
IDType GetGlobalNParticles() const
Get the global number of active particles across all ranks.
void PrintCSV(const char *fname, int precision=16)
Print all particle data to a comma-delimited CSV file.
void Reserve(int res)
Reserve memory for res particles.
std::vector< std::unique_ptr< Array< int > > > tags
All particle tags for particles owned by this rank.
IDType id_counter
Current globally unique ID to be assigned to the next particle added.
void RemoveParticles(const Array< int > &list)
Remove particle data specified by list of particle indices.
struct gslib::comm * gsl_comm
void AddParticles(const Array< IDType > &new_ids, Array< int > *new_indices=nullptr)
Add particles with global identifiers new_ids and optionally get the local indices of new particles i...
std::vector< std::string > field_names
Field names, to be written when PrintCSV() is called.
Particle CreateParticle() const
Create a Particle object with the same spatial dimension, number of fields and field vdims,...
void SetParticle(int i, const Particle &p)
Set data for particle at index i with data from provided particle p.
ParticleVector carries vector data (of a given vector dimension) for an arbitrary number of particles...
void SetValues(int i, const Vector &nvals)
Set particle i 's data to nvals .
void GetValues(int i, Vector &nvals) const
Get a copy of particle i 's data.
void DeleteParticles(const Array< int > &indices)
Remove particle data at indices.
void SetNumParticles(int num_vectors, bool keep_data=true)
Set the number of particle Vector data to be held by the ParticleVector, keeping existing data.
int GetVDim() const
Get the Vector dimension of the ParticleVector.
void GetValuesRef(int i, Vector &nref)
For GetOrdering == Ordering::byVDIM, set nref to refer to particle i 's data.
Ordering::Type GetOrdering() const
Get the ordering of data in the ParticleVector.
Container for data associated with a single particle.
std::vector< Array< int > > tags
A std::vector of Array<int> where each Array<int> holds data for a given tag.
bool operator==(const Particle &rhs) const
Particle equality operator.
std::vector< Vector > fields
A std::vector of Vector where each Vector holds data for a given field (e.g., mass,...
Vector coords
Spatial coordinates.
Particle(int dim, const Array< int > &field_vdims, int num_tags)
Construct a Particle instance.
void Print(std::ostream &os=mfem::out) const
Print all particle data to os.
void SetTagRef(int t, int *tag_data)
Set tag t to reference external data.
void SetFieldRef(int f, real_t *field_data)
Set field f to reference external data.
int Size() const
Returns the size of the vector.
void Reserve(int res)
Update Capacity() to res (if less than current), keeping existing entries.
std::function< real_t(const Vector &)> f(real_t mass_coeff)
real_t p(const Vector &x, real_t t)