MFEM v4.10.0
Finite element discretization library
Loading...
Searching...
No Matches
particleset.hpp
Go to the documentation of this file.
1// Copyright (c) 2010-2026, Lawrence Livermore National Security, LLC. Produced
2// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
3// LICENSE and NOTICE for details. LLNL-CODE-806117.
4//
5// This file is part of the MFEM library. For more information and source code
6// availability visit https://mfem.org.
7//
8// MFEM is free software; you can redistribute it and/or modify it under the
9// terms of the BSD-3 license. We welcome feedback and contributions, see file
10// CONTRIBUTING.md for details.
11
12#ifndef MFEM_PARTICLESET
13#define MFEM_PARTICLESET
14
15#include "../config/config.hpp"
16#include "../linalg/linalg.hpp"
17#include "gslib.hpp"
18#include "kernel_dispatch.hpp"
19
20namespace mfem
21{
22
23/** @brief Container for data associated with a single particle.
24 *
25 * @note This class mainly serves as a convenience interface to individual
26 * particle data from ParticleSet. We recommend seeing ParticleSet first.
27 *
28 * @details As described in ParticleSet documentation, each particle has a
29 * position (\ref coords), arbitrary number of scalar or vector \ref real_t
30 * data (\ref fields), and arbitrary number of integers (\ref tags)
31 * associated with it.
32 *
33 * \ref fields can thus hold data such as mass, momentum, and velocity, while
34 * \ref tags can hold integer data such as particle type, color, etc.
35 *
36 * Each particle also has a unique global ID, but that is managed by the
37 * ParticleSet class and not stored in this Particle class. Similarly, the names
38 * of the fields and tags, typically useful for output purposes, are managed by
39 * the ParticleSet class.
40 *
41 *
42 * For clarity, we will use the particles below to illustrate the data layout
43 * for \ref coords, \ref fields, and \ref tags
44 *
45 * @anchor sample_particle_data
46 * @code
47 * Particle_0: coords = (x0, y0),
48 * fields = {'mass'=m0, 'vel' = (vx0, vy0)},
49 * tags = {'type'=t0, 'color'=color0}
50 * Particle_1: coords = (x1, y1),
51 * fields = {'mass'=m1, 'vel' = (vx1, vy1)},
52 * tags = {'type'=t1, 'color'=color1}
53 * Particle_2: coords = (x2, y2),
54 * fields = {'mass'=m2, 'vel' = (vx2, vy2)},
55 * tags = {'type'=t2, 'color'=color2}
56 * @endcode
57 *
58 */
60{
61protected:
62 /** @brief Spatial coordinates
63 *
64 * @details For the \ref sample_particle_data, \ref coords would hold
65 * (x_i, y_i) for each particle i.
66 */
68
69 /** @brief A std::vector of Vector where each Vector holds data for a given
70 * field (e.g., mass, momentum or velocity) associated with the particle.
71 *
72 * @details For the \ref sample_particle_data, \ref fields would be
73 * fields[0]=(m_i), fields[1]=(vx_i,vy_i) for each particle i.
74 */
75 std::vector<Vector> fields;
76
77 /** @brief A std::vector of Array<int> where each Array<int> holds data
78 * for a given tag.
79 *
80 * @details For the \ref sample_particle_data, \ref tags would be
81 * tags[0]=(type_i), tags[1]=(color_i) for each particle i. \n
82 *
83 * @note An Array of length 1 is used for EACH tag, strictly for
84 * its owning/non-owning semantics (see Array<T>::MakeRef).
85 */
86 std::vector<Array<int>> tags;
87public:
88 /** @brief Construct a Particle instance.
89 * @param[in] dim Spatial dimension (size of #coords).
90 * @param[in] field_vdims Vector dimensions of particle fields.
91 * @param[in] num_tags Number of integer tags.
92 */
93 Particle(int dim, const Array<int> &field_vdims, int num_tags);
94
95 // Force default constructors and destructor
96 Particle(const Particle &) = default;
97 Particle &operator=(const Particle &) = default;
98 Particle(Particle &&) = default;
99 Particle &operator=(Particle &&) = default;
100 ~Particle() = default;
101
102 /// Get the spatial dimension of this particle.
103 int GetDim() const { return coords.Size(); }
104
105 /// Get the number of fields associated with this particle.
106 int GetNFields() const { return fields.size(); }
107
108 /// Get the vector dimension of field \p f .
109 int GetFieldVDim(int f) const { return fields[f].Size(); }
110
111 /// Get the number of tags associated with this particle.
112 int GetNTags() const { return tags.size(); }
113
114 /// Get reference to particle coordinates Vector.
115 Vector &Coords() { return coords; }
116
117 /// Get const reference to particle coordinates Vector.
118 const Vector &Coords() const { return coords; }
119
120 /// Get reference to field \p f , component \p c value.
121 real_t &FieldValue(int f, int c = 0)
122 {
123 MFEM_ASSERT(f >= 0 && static_cast<std::size_t>(f) < fields.size(),
124 "invalid field index");
125 MFEM_ASSERT(c >= 0 && c < fields[f].Size(),
126 "invalid component index");
127 return fields[f][c];
128 }
129
130 /// Get const reference to field \p f , component \p c value.
131 const real_t &FieldValue(int f, int c = 0) const
132 {
133 MFEM_ASSERT(f >= 0 && static_cast<std::size_t>(f) < fields.size(),
134 "invalid field index");
135 MFEM_ASSERT(c >= 0 && c < fields[f].Size(),
136 "invalid component index");
137 return fields[f][c];
138 }
139
140 /// Get reference to field \p f Vector.
142 {
143 MFEM_ASSERT(f >= 0 && static_cast<std::size_t>(f) < fields.size(),
144 "invalid field index");
145 return fields[f];
146 }
147
148 /// Get const reference to field \p f Vector.
149 const Vector &Field(int f) const
150 {
151 MFEM_ASSERT(f >= 0 && static_cast<std::size_t>(f) < fields.size(),
152 "invalid field index");
153 return fields[f];
154 }
155
156 /// Get reference to tag \p t .
157 int &Tag(int t)
158 {
159 MFEM_ASSERT(t >= 0 && static_cast<std::size_t>(t) < tags.size(),
160 "invalid tag index");
161 return tags[t][0];
162 }
163
164 /// Get const reference to tag \p t .
165 const int &Tag(int t) const
166 {
167 MFEM_ASSERT(t >= 0 && static_cast<std::size_t>(t) < tags.size(),
168 "invalid tag index");
169 return tags[t][0];
170 }
171
172 /// Set tag \p t to reference external data.
173 void SetTagRef(int t, int *tag_data);
174
175 /// Set field \p f to reference external data.
176 void SetFieldRef(int f, real_t *field_data);
177
178 /// Particle equality operator.
179 bool operator==(const Particle &rhs) const;
180
181 /// Particle inequality operator.
182 bool operator!=(const Particle &rhs) const { return !operator==(rhs); }
183
184 /// Print all particle data to \p os.
185 void Print(std::ostream &os = mfem::out) const;
186};
187
188/** @brief ParticleSet initializes and manages data associated with particles.
189 *
190 * @details Particles are inherently initialized to have a position and an ID,
191 * and optionally can have any number of Vector (of arbitrary vdim) and scalar
192 * integer data in the form of @b fields and @b tags respectively. All particle
193 * data are internally stored in a Struct-of-Arrays fashion, as elaborated on
194 * below.
195 *
196 * @par Coordinates:
197 * All particle coordinates are stored in a ParticleVector with vector
198 * dimension equal to the spatial dimension, ordered either byNODES or byVDIM.
199 * The ParticleVector \ref coords contains the coordinates of all particles.
200 *
201 * @par IDs:
202 * Each particle is assigned a unique global ID of type IDType. In parallel,
203 * IDs are initialized starting with @b rank and striding by @b size. The IDs
204 * of all particles owned by this rank are stored in \ref ids.
205 *
206 * @par Fields:
207 * Fields represent scalar or vector \ref real_t data to be associated with
208 * each particle, such as mass, momentum, or moment. For a given field, all
209 * particle data is stored in a single ParticleVector with a given
210 * vector dimension (1 for scalar data) and Ordering::Type (byNODES or
211 * byVDIM). The unique_ptrs to all the ParticleVectors are stored in the
212 * std::vector \ref fields.
213 *
214 * @par Device Behavior:
215 * When a ParticleSet is constructed with \p use_device=true, \ref coords and
216 * all ParticleVector fields are marked to use device memory. Fields added
217 * later through \ref AddField inherit the current device mode (through
218 * \ref coords).
219 *
220 * @par Tags:
221 * Tags represent integers associated with each particle. For a given tag,
222 * all particle data are stored in a single Array<int>. The unique_ptrs to all
223 * the Array<int> are stored in the std::vector \ref tags.
224 *
225 * @par Names:
226 * Each field and tag can optionally be given a name (string) to be used when
227 * printing particle data in CSV format using PrintCSV(). The names of all
228 * fields and tags are stored in the std::vectors \ref field_names and
229 * \ref tag_names, respectively.
230 *
231 * @note We assume that all particles in a ParticleSet have the same number
232 * of fields and tags.
233 *
234 * Following the example in the Particle class, we will use the
235 * particles below to illustrate the data layout for \ref coords, \ref ids,
236 * \ref fields, \ref tags, \ref field_names, and \ref tag_names.
237 * In each case, the name of the field and tag is enclosed in '...' for
238 * clarity. Additionally, we assume for this example that the particle
239 * coordinates and the 'vel' field are ordered byVDIM in their respective
240 * ParticleVector.
241 * @anchor sample_particleset_data
242 * @code
243 * Particle_0: id = id0, coords = (x0, y0),
244 * fields = {'mass'=m0, 'vel' = (vx0, vy0)},
245 * tags = {'type'=t0, 'color'=c0}
246 * Particle_1: id = id1, coords = (x1, y1),
247 * fields = {'mass'=m1, 'vel' = (vx1, vy1)},
248 * tags = {'type'=t1, 'color'=c1}
249 * Particle_2: id = id2, coords = (x2, y2),
250 * fields = {'mass'=m2, 'vel' = (vx2, vy2)},
251 * tags = {'type'=t2, 'color'=c2}
252 * @endcode
253 */
255{
256public:
257 using IDType = unsigned long long;
258private:
259 /// Constructs an Array of size N filled with Ordering::Type o.
260 static Array<Ordering::Type> GetOrderingArray(Ordering::Type o, int N);
261
262 /// Returns default field name for field index i. "Field_{i}"
263 static std::string GetDefaultFieldName(int i);
264
265 /// Returns default tag name for tag index i. "Tag_{i}"
266 static std::string GetDefaultTagName(int i);
267
268 /// Constructs an Array of size N filled with nullptr.
269 static Array<const char*> GetEmptyNameArray(int N);
270
271#ifdef MFEM_USE_MPI
272 static int GetRank(MPI_Comm comm_);
273 static int GetSize(MPI_Comm comm_);
274#endif // MFEM_USE_MPI
275
276protected:
277 /// Stride for IDs (used internally when new particles are added).
278 /** In parallel, this defaults to the number of MPI ranks. */
279 const int id_stride;
280
281 /// Current globally unique ID to be assigned to the next particle added.
282 /** In parallel, this starts locally as the rank and increments with
283 * id_stride, ensuring a global unique identifier whenever a particle is
284 * added.
285 */
287
288 /** @brief Global unique IDs of particles owned by this rank.
289 *
290 * @details For the \ref sample_particleset_data, \ref ids would be
291 * ids[0]=id0, ids[1]=id1, ids[2]=id2.
292 */
294
295 /** @brief Spatial coordinates of particles owned by this rank.
296 *
297 * @details For the \ref sample_particleset_data, \ref coords would be
298 * coords=(x0,y0,x1,y1,x2,y2) assuming coords ordering is byVDIM.
299 */
301
302 /** @brief All particle fields for particles owned by this rank.
303 *
304 * @details For the \ref sample_particleset_data, \ref fields would be
305 * *fields[0]=(m0,m1,m2), *fields[1]=(vx0,vy0,vx1,vy1,vx2,vy2)
306 * assuming fields[1] ordering is byVDIM.
307 */
308 std::vector<std::unique_ptr<ParticleVector>> fields;
309
310 /** @brief All particle tags for particles owned by this rank.
311 *
312 * @details For the \ref sample_particleset_data, \ref tags would be
313 * *tags[0]=(t0,t1,t2), *tags[1]=(c0,c1,c2).
314 */
315 std::vector<std::unique_ptr<Array<int>>> tags;
316
317 /** @brief Field names, to be written when PrintCSV() is called.
318 *
319 * @details For the \ref sample_particleset_data, \ref field_names would be
320 * field_names[0]='mass', field_names[1]='vel'.
321 */
322 std::vector<std::string> field_names;
323
324 /** @brief Tag names, to be written when PrintCSV() is called.
325 *
326 * @details For the \ref sample_particleset_data, \ref tag_names would be
327 * tag_names[0]='type', tag_names[1]='color'.
328 */
329 std::vector<std::string> tag_names;
330
331 /** @brief Add particles with global identifiers \p new_ids and
332 * optionally get the local indices of new particles in \p new_indices .
333 *
334 * @details Note the data of new particles is uninitialized and must be
335 * set.
336 */
337 void AddParticles(const Array<IDType> &new_ids,
338 Array<int> *new_indices = nullptr);
339
340#ifdef MFEM_USE_MPI
341 MPI_Comm comm;
342#endif // MFEM_USE_MPI
343
344#if defined(MFEM_USE_MPI) && defined(MFEM_USE_GSLIB)
345 struct gslib::crystal *cr = nullptr; // gslib's internal data
346 struct gslib::comm *gsl_comm = nullptr; // gslib's internal data
347
348 /// \cond DO_NOT_DOCUMENT
349 template<std::size_t NBytes>
350 static void TransferParticlesImpl(ParticleSet &pset,
351 const Array<int> &send_idxs,
352 const Array<unsigned int> &send_ranks);
353
354 using TransferParticlesType = void (*)(ParticleSet &pset,
355 const Array<int> &send_idxs,
356 const Array<unsigned int> &send_ranks);
357
358 // Specialization parameter: NBytes
359 MFEM_REGISTER_KERNELS(TransferParticles, TransferParticlesType, (size_t));
360 friend TransferParticles;
361 struct Kernels
362 {
363 Kernels();
364 };
365 /// \endcond
366
367#endif // MFEM_USE_MPI && MFEM_USE_GSLIB
368
369 /** @brief Update global ID of a particle.
370 *
371 * @details This method updates the global ID of the particle at given
372 * local index after Redistribute().
373 *
374 * @note This method must be used very carefully as it updates global
375 * ID of a particle.
376 */
377 void UpdateID(int local_idx, IDType new_global_id)
378 {
380 ids[local_idx] = new_global_id;
381 }
382
383 /** @brief Create a Particle object with the same spatial dimension,
384 * number of fields and field vdims, and number of tags as this ParticleSet.
385 */
386 Particle CreateParticle() const;
387
388 /** @brief Write string in \p ss_header , followed by \p ss_data , to a
389 * single file; compatible in parallel.
390 */
391 void WriteToFile(const char *fname, const std::stringstream &ss_header,
392 const std::stringstream &ss_data);
393
394 /** @brief Check if a particle could belong in this ParticleSet by
395 * comparing field and tag dimension.
396 */
397 bool IsValidParticle(const Particle &p) const;
398
399 /** @brief Hidden main constructor of ParticleSet
400 *
401 * @param[in] id_stride_ ID stride.
402 * @param[in] id_counter_ Starting ID counter.
403 * @param[in] num_particles Number of particles to initialize.
404 * @param[in] dim Particle spatial dimension.
405 * @param[in] coords_ordering Ordering of coordinates
406 * @param[in] field_vdims Array of field vector dimensions
407 * @param[in] field_orderings Array of field ordering types.
408 * @param[in] field_names_ Array of field names.
409 * @param[in] num_tags Number of tags to register.
410 * @param[in] tag_names_ Array of tag names.
411 * @param[in] use_device Use device memory for particle fields.
412 */
413 ParticleSet(int id_stride_, IDType id_counter_, int num_particles, int dim,
414 Ordering::Type coords_ordering, const Array<int> &field_vdims,
415 const Array<Ordering::Type> &field_orderings,
416 const Array<const char*> &field_names_, int num_tags,
417 const Array<const char*> &tag_names_,
418 bool use_device);
419
420public:
421
422 /** @brief Construct a serial ParticleSet.
423 *
424 * @param[in] num_particles Number of particles to initialize.
425 * @param[in] dim Particle spatial dimension.
426 * @param[in] coords_ordering Ordering of coordinates.
427 * @param[in] use_device (Optional) Use device memory for particle
428 * fields.
429 */
430 ParticleSet(int num_particles, int dim,
431 Ordering::Type coords_ordering = Ordering::byVDIM,
432 bool use_device = false);
433
434 /** @brief Construct a serial ParticleSet with specified fields and tags at
435 * construction.
436 *
437 * @param[in] num_particles Number of particles to initialize.
438 * @param[in] dim Particle spatial dimension.
439 * @param[in] field_vdims Array of field vector dimensions.
440 * @param[in] num_tags Number of tags to register.
441 * @param[in] all_ordering (Optional) Ordering of coordinates and
442 * field ParticleVector.
443 * @param[in] use_device (Optional) Use device memory for particle
444 * fields.
445 */
446 ParticleSet(int num_particles, int dim, const Array<int> &field_vdims,
447 int num_tags, Ordering::Type all_ordering = Ordering::byVDIM,
448 bool use_device = false);
449
450 /** @brief Construct a serial ParticleSet with specified fields and tags at
451 * construction, with names.
452 *
453 * @param[in] num_particles Number of particles to initialize.
454 * @param[in] dim Particle spatial dimension.
455 * @param[in] field_vdims Array of field vector dimensions.
456 * @param[in] field_names_ Array of field names.
457 * @param[in] num_tags Number of tags to register.
458 * @param[in] tag_names_ Array of tag names.
459 * @param[in] all_ordering (Optional) Ordering of coordinates and
460 * field ParticleVector.
461 * @param[in] use_device (Optional) Use device memory for particle
462 * fields.
463 */
464 ParticleSet(int num_particles, int dim, const Array<int> &field_vdims,
465 const Array<const char*> &field_names_, int num_tags,
466 const Array<const char*> &tag_names_,
467 Ordering::Type all_ordering = Ordering::byVDIM,
468 bool use_device = false);
469
470 /** @brief Comprehensive serial constructor of ParticleSet.
471 *
472 * @param[in] num_particles Number of particles to initialize.
473 * @param[in] dim Particle spatial dimension.
474 * @param[in] coords_ordering Ordering of coordinates.
475 * @param[in] field_vdims Array of field vector dimensions.
476 * @param[in] field_orderings Array of field ordering types.
477 * @param[in] field_names_ Array of field names.
478 * @param[in] num_tags Number of tags to register.
479 * @param[in] tag_names_ Array of tag names.
480 * @param[in] use_device (Optional) Use device memory for particle
481 * fields.
482 */
483 ParticleSet(int num_particles, int dim, Ordering::Type coords_ordering,
484 const Array<int> &field_vdims,
485 const Array<Ordering::Type> &field_orderings,
486 const Array<const char*> &field_names_, int num_tags,
487 const Array<const char*> &tag_names_,
488 bool use_device = false);
489
490#ifdef MFEM_USE_MPI
491 /** @brief Construct a parallel ParticleSet.
492 *
493 * @param[in] comm_ MPI communicator.
494 * @param[in] rank_num_particles Number of particles to initialize.
495 * @param[in] dim Particle spatial dimension.
496 * @param[in] coords_ordering (Optional) Ordering of coordinates.
497 * @param[in] use_device (Optional) Use device memory for particle
498 * fields.
499 */
500 ParticleSet(MPI_Comm comm_, int rank_num_particles, int dim,
501 Ordering::Type coords_ordering = Ordering::byVDIM,
502 bool use_device = false);
503
504 /** @brief Construct a parallel ParticleSet with specified fields and tags
505 * at construction.
506 *
507 * @param[in] comm_ MPI communicator.
508 * @param[in] rank_num_particles # of particles to initialize on this rank.
509 * @param[in] dim Particle spatial dimension.
510 * @param[in] field_vdims Array of field vector dimensions.
511 * @param[in] num_tags Number of tags to register.
512 * @param[in] all_ordering (Optional) Ordering of coordinates and
513 * field ParticleVector.
514 * @param[in] use_device (Optional) Use device memory for particle
515 * fields.
516 */
517 ParticleSet(MPI_Comm comm_, int rank_num_particles, int dim,
518 const Array<int> &field_vdims, int num_tags,
519 Ordering::Type all_ordering = Ordering::byVDIM,
520 bool use_device = false);
521
522 /** @brief Construct a parallel ParticleSet with specified fields and tags
523 * at construction, with names (for PrintCSV()).
524 *
525 * @param[in] comm_ MPI communicator.
526 * @param[in] rank_num_particles # of particles to initialize on this rank.
527 * @param[in] dim Particle spatial dimension.
528 * @param[in] field_vdims Array of field vector dimension.
529 * @param[in] field_names_ Array of field names.
530 * @param[in] num_tags Number of tags to register.
531 * @param[in] tag_names_ Array of tag names.
532 * @param[in] all_ordering (Optional) Ordering of coordinates and
533 * field ParticleVector.
534 * @param[in] use_device (Optional) Use device memory for particle
535 * fields.
536 */
537 ParticleSet(MPI_Comm comm_, int rank_num_particles, int dim,
538 const Array<int> &field_vdims,
539 const Array<const char*> &field_names_,
540 int num_tags, const Array<const char*> &tag_names_,
541 Ordering::Type all_ordering = Ordering::byVDIM,
542 bool use_device = false);
543
544 /** @brief Comprehensive parallel constructor of ParticleSet.
545 *
546 * @param[in] comm_ MPI communicator.
547 * @param[in] rank_num_particles # of particles to initialize on this rank.
548 * @param[in] dim Particle spatial dimension.
549 * @param[in] coords_ordering Ordering of coordinates.
550 * @param[in] field_vdims Array of field vector dimensions.
551 * @param[in] field_orderings Array of field ordering types.
552 * @param[in] field_names_ Array of field names.
553 * @param[in] num_tags Number of tags to register.
554 * @param[in] tag_names_ Array of tag names.
555 * @param[in] use_device (Optional) Use device memory for particle
556 * fields.
557 */
558 ParticleSet(MPI_Comm comm_, int rank_num_particles, int dim,
559 Ordering::Type coords_ordering, const Array<int> &field_vdims,
560 const Array<Ordering::Type> &field_orderings,
561 const Array<const char*> &field_names_, int num_tags,
562 const Array<const char*> &tag_names_,
563 bool use_device = false);
564
565 /// Get the MPI communicator for this ParticleSet.
566 MPI_Comm GetComm() const { return comm; }
567#endif // MFEM_USE_MPI
568 /// Get the global number of active particles across all ranks.
569 IDType GetGlobalNParticles() const;
570
571 /// Get the spatial dimension.
572 int GetDim() const { return coords.GetVDim(); }
573
574 /// Get the global IDs of the active particles owned by this ParticleSet.
575 const Array<IDType> &GetIDs() const { return ids; }
576
577 /** @brief Add a field to the ParticleSet.
578 *
579 * @param[in] vdim Vector dimension of the field.
580 * @param[in] field_ordering (Optional) Ordering::Type of the field.
581 * @param[in] field_name (Optional) Name of the field.
582 *
583 * @note New fields inherit the current device mode of \ref coords.
584 *
585 * @return Index of the newly-added field.
586 */
587 int AddField(int vdim, Ordering::Type field_ordering = Ordering::byVDIM,
588 const char *field_name = nullptr);
589
590 /** @brief Add a field to the ParticleSet.
591 *
592 * @details Same as AddField() but with different parameter order
593 * for convenience.
594 * @param[in] vdim Vector dimension of the field data.
595 * @param[in] field_name Name of the field, used e.g. by PrintCSV().
596 * @param[in] field_ordering Ordering of the field data.
597 * @return Index of the newly-added field.
598 */
599 int AddNamedField(int vdim, const char *field_name,
600 Ordering::Type field_ordering = Ordering::byVDIM)
601 {
602 return AddField(vdim, field_ordering, field_name);
603 }
604
605 /** @brief Add a tag to the ParticleSet.
606 *
607 * @param[in] tag_name (Optional) Name of the tag.
608 *
609 * @return Index of the newly-added tag.
610 */
611 int AddTag(const char *tag_name = nullptr);
612
613 /// Reserve memory for \p res particles.
614 /** Can help to avoid reallocation when adding or removing particles. */
615 void Reserve(int res);
616
617 /// Get the number of active particles currently held by this ParticleSet.
618 int GetNParticles() const { return ids.Size(); }
619
620 /// Get the number of fields registered to particles.
621 int GetNFields() const { return fields.size(); }
622
623 /// Get an Array<int> of the field vector-dimensions registered to particles.
625
626 /// Get the vector dimension of field \p f .
627 int FieldVDim(int f) const { return fields[f]->GetVDim(); }
628
629 /// Get the number of tags registered to particles.
630 int GetNTags() const { return tags.size(); }
631
632 /// Add a particle using Particle .
633 void AddParticle(const Particle &p);
634
635 /** @brief Add \p num_particles particles, and optionally get the local
636 * indices of new particles in \p new_indices .
637 *
638 * @details The data of new particles is uninitialized and must be
639 * set.
640 */
641 void AddParticles(int num_particles, Array<int> *new_indices = nullptr);
642
643 /// Remove particle data specified by \p list of particle indices.
644 void RemoveParticles(const Array<int> &list);
645
646 /// Get a reference to the coordinates ParticleVector.
648
649 /// Get a const reference to the coordinates ParticleVector.
650 const ParticleVector &Coords() const { return coords; }
651
652 /// Get a reference to field \p f 's ParticleVector.
653 ParticleVector &Field(int f) { return *fields[f]; }
654
655 /// Get a const reference to field \p f 's ParticleVector.
656 const ParticleVector &Field(int f) const { return *fields[f]; }
657
658 /// Get a reference to tag \p t 's Array<int>.
659 Array<int> &Tag(int t) { return *tags[t]; }
660
661 /// Get a const reference to tag \p t 's Array<int>.
662 const Array<int> &Tag(int t) const { return *tags[t]; }
663
664 /** @brief Get new Particle object with copy of data associated with
665 particle \p i . */
666 Particle GetParticle(int i) const;
667
668 /** @brief Get Particle object whose members reference the actual data
669 * associated with particle \p i in this ParticleSet.
670 *
671 * @see IsParticleRefValid for when this method can be used.
672 *
673 * @warning If particles are added, removed, or redistributed after
674 * invoking this, the returned Particle member references may be
675 * invalidated.
676 */
678
679 /** @brief Determine if GetParticleRef is valid.
680 *
681 * Returns true when coordinates and all fields are ordered byVDIM and
682 * particle data is host-resident. Otherwise, false.
683 */
684 bool IsParticleRefValid() const;
685
686 /// Set data for particle at index \p i with data from provided particle \p p
687 void SetParticle(int i, const Particle &p);
688
689 /** @brief Print all particle data to a comma-delimited CSV file.
690 *
691 * The first row contains the header. We include the particle ID,
692 * owning rank (in parallel), coordinates, followed by all fields and
693 * tags.
694 *
695 * The output can be visualized in ParaView by loading the CSV files, and
696 * applying the "Table To Points" filter.
697 */
698 void PrintCSV(const char *fname, int precision = 16);
699
700 /** @brief Print only particle field and tags given by \p field_idxs and
701 \p tag_idxs respectively to a CSV file. */
702 void PrintCSV(const char *fname, const Array<int> &field_idxs,
703 const Array<int> &tag_idxs, int precision = 16);
704
705#if defined(MFEM_USE_MPI) && defined(MFEM_USE_GSLIB)
706
707 /** @brief Redistribute particle data to \p rank_list
708
709 @param[in] rank_list Array of size GetNParticles() denoting ultimate
710 destination of particle data. Index = this rank
711 means no data is moved.
712 */
713 void Redistribute(const Array<unsigned int> &rank_list);
714
715#endif // MFEM_USE_MPI && MFEM_USE_GSLIB
716
717 /// Destructor
718 ~ParticleSet();
719 ParticleSet(const ParticleSet &) = delete;
721};
722
723} // namespace mfem
724
725
726#endif // MFEM_PARTICLESET
int Size() const
Return the logical size of the array.
Definition array.hpp:192
T * HostReadWrite()
Shortcut for mfem::ReadWrite(a.GetMemory(), a.Size(), false).
Definition array.hpp:430
Type
Ordering methods:
Definition ordering.hpp:17
ParticleSet initializes and manages data associated with particles.
MPI_Comm GetComm() const
Get the MPI communicator for this ParticleSet.
const ParticleVector & Coords() const
Get a const reference to the coordinates ParticleVector.
Array< IDType > ids
Global unique IDs of particles owned by this rank.
ParticleVector coords
Spatial coordinates of particles owned by this rank.
~ParticleSet()
Destructor.
ParticleSet & operator=(const ParticleSet &)=delete
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.
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_, bool use_device)
Hidden main constructor of ParticleSet.
Particle GetParticle(int i) const
Get new Particle object with copy of data associated with particle i .
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.
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
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.
Array< int > GetFieldVDims() const
Get an Array<int> of the field vector-dimensions registered to 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.
const ParticleVector & Field(int f) const
Get a const reference to field f 's ParticleVector.
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.
int AddNamedField(int vdim, const char *field_name, Ordering::Type field_ordering=Ordering::byVDIM)
Add a field to the ParticleSet.
int FieldVDim(int f) const
Get the vector dimension of field f .
const Array< int > & Tag(int t) const
Get a const reference to tag t 's Array<int>.
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.
ParticleSet(const ParticleSet &)=delete
ParticleVector carries vector data (of a given vector dimension) for an arbitrary number of particles...
int GetVDim() const
Get the Vector dimension of 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.
int GetFieldVDim(int f) const
Get the vector dimension of field f .
int GetDim() const
Get the spatial dimension of this particle.
~Particle()=default
Particle(const Particle &)=default
Particle & operator=(Particle &&)=default
bool operator==(const Particle &rhs) const
Particle equality operator.
int & Tag(int t)
Get reference to tag t .
int GetNTags() const
Get the number of tags associated with this particle.
Particle(Particle &&)=default
Vector & Field(int f)
Get reference to field f Vector.
std::vector< Vector > fields
A std::vector of Vector where each Vector holds data for a given field (e.g., mass,...
const real_t & FieldValue(int f, int c=0) const
Get const reference to field f , component c value.
const Vector & Coords() const
Get const reference to particle coordinates Vector.
const Vector & Field(int f) const
Get const reference to field f Vector.
Vector coords
Spatial coordinates.
real_t & FieldValue(int f, int c=0)
Get reference to field f , component c value.
Particle(int dim, const Array< int > &field_vdims, int num_tags)
Construct a Particle instance.
Particle & operator=(const Particle &)=default
bool operator!=(const Particle &rhs) const
Particle inequality operator.
Vector & Coords()
Get reference to particle coordinates Vector.
void Print(std::ostream &os=mfem::out) const
Print all particle data to os.
const int & Tag(int t) const
Get const reference to tag t .
int GetNFields() const
Get the number of fields associated with this particle.
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.
Vector data type.
Definition vector.hpp:82
int Size() const
Returns the size of the vector.
Definition vector.hpp:234
int dim
Definition ex24.cpp:53
OutStream out(std::cout)
Global stream used by the library for standard output. Initially it uses the same std::streambuf as s...
Definition globals.hpp:66
float real_t
Definition config.hpp:46
std::function< real_t(const Vector &)> f(real_t mass_coeff)
Definition lor_mms.hpp:30
real_t p(const Vector &x, real_t t)
Base class for Schrodinger solver kernels.