MFEM v4.10.0
Finite element discretization library
Loading...
Searching...
No Matches
particlevector.cpp
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#include "particlevector.hpp"
13#include "../general/forall.hpp"
14
15namespace mfem
16{
17
18void ParticleVector::GrowSize(int min_num_vectors, bool keep_data)
19{
20 const int nsize = std::max(min_num_vectors*vdim, 2 * data.Capacity());
22 if (keep_data) { p.CopyFrom(data, size); }
23 p.UseDevice(data.UseDevice());
24 data.Delete();
25 data = p;
26}
27
29 : ParticleVector(vdim_, ordering_, 0) { }
30
32 int num_nodes)
33 : Vector(num_nodes*vdim_), vdim(vdim_), ordering(ordering_)
34{
36}
37
39 const Vector &vec)
40 : Vector(vec), vdim(vdim_), ordering(ordering_)
41{
42 MFEM_ASSERT(vec.Size() % vdim == 0,
43 "Incompatible Vector size of " << vec.Size() << " given vdim " << vdim);
44}
45
46void ParticleVector::GetValues(int i, Vector &nvals) const
47{
48 nvals.SetSize(vdim);
49
50 const bool nvals_use_dev = nvals.UseDevice();
51 // Use ParticleVector's device flag to minimize movement from large source
52 const bool use_dev = UseDevice();
53 const auto d_src = Read(use_dev);
54 auto d_dest = nvals.Write(use_dev);
55
56 const int vdim_ = vdim;
57 const int ordering_ = (int)ordering;
58 const int nv = (ordering == Ordering::byNODES) ? size / vdim : 0;
59
60 mfem::forall_switch(use_dev, vdim_, [=] MFEM_HOST_DEVICE (int c)
61 {
62 if (ordering_ == Ordering::byNODES)
63 {
64 d_dest[c] = d_src[i + nv*c];
65 }
66 else
67 {
68 d_dest[c] = d_src[c + vdim_*i];
69 }
70 });
71
72 // If nvals was not using device but ParticleVector is, copy back to host
73 if (!nvals_use_dev && use_dev)
74 {
75 nvals.HostRead();
76 nvals.UseDevice(false);
77 }
78 // If nvals was using device but ParticleVector is not, copy back to device
79 if (!use_dev && nvals_use_dev)
80 {
81 nvals.Read();
82 }
83}
84
86{
87 MFEM_ASSERT(ordering == Ordering::byVDIM,
88 "GetValuesRef only valid when ordering byVDIM.");
89
90 nref.MakeRef(*this, i*vdim, vdim);
91}
92
94{
95 int vdim_temp = vdim;
96
97 // For byNODES: Treat each component as a vector temporarily
98 // For byVDIM: Treat each vector as a component temporarily
102
103 GetValues(vd, comp);
104
105 // Reset ordering back to original
108
109 vdim = vdim_temp;
110}
111
113{
114 MFEM_ASSERT(ordering == Ordering::byNODES,
115 "GetComponentsRef only valid when ordering byNODES.");
116 nref.MakeRef(*this, vd*GetNumParticles(), GetNumParticles());
117}
118
119void ParticleVector::SetValues(int i, const Vector &nvals)
120{
121 const bool use_dev = UseDevice(); // use ParticleVector's device flag
122 const auto mc = use_dev ? Device::GetDeviceMemoryClass()
124 auto d_dest = ReadWrite(use_dev);
125 const auto d_src = nvals.GetMemory().Read(mc, nvals.Size());
126
127 const int vdim_ = vdim;
128 const int ordering_ = (int)ordering;
129 const int nv = (ordering == Ordering::byNODES) ? size / vdim : 0;
130
131 mfem::forall_switch(use_dev, vdim_, [=] MFEM_HOST_DEVICE (int c)
132 {
133 if (ordering_ == Ordering::byNODES)
134 {
135 d_dest[i + c*nv] = d_src[c];
136 }
137 else
138 {
139 d_dest[c + i*vdim_] = d_src[c];
140 }
141 });
142}
143
144void ParticleVector::SetComponents(int vd, const Vector &comp)
145{
146 int vdim_temp = vdim;
147
148 // For byNODES: Treat each component as a vector temporarily
149 // For byVDIM: Treat each vector as a component temporarily
153
154 SetValues(vd, comp);
155
156 // Reset ordering back to original
159
160 vdim = vdim_temp;
161}
162
164{
165 MFEM_ASSERT(i < GetNumParticles(),
166 "Particle index " << i <<
167 " is invalid for number of particles " << GetNumParticles());
168 MFEM_ASSERT(comp < vdim,
169 "Component index " << comp <<
170 " is invalid for vector dimension " << vdim);
171
172 // non-const so we make host flag valid in case user modifies data
174
176 {
177 return Vector::operator[](i + comp*GetNumParticles());
178 }
179 else
180 {
181 return Vector::operator[](comp + i*vdim);
182 }
183}
184
185const real_t& ParticleVector::operator()(int i, int comp) const
186{
187 MFEM_ASSERT(i < GetNumParticles(),
188 "Particle index " << i <<
189 " is invalid for number of particles " << GetNumParticles());
190 MFEM_ASSERT(comp < vdim,
191 "Component index " << comp <<
192 " is invalid for vector dimension " << vdim);
193
194 HostRead();
195
197 {
198 return Vector::operator[](i + comp*GetNumParticles());
199 }
200 else
201 {
202 return Vector::operator[](comp + i*vdim);
203 }
204}
205
207{
208 if (indices.Size() == 0) { return; }
209 // Convert list index array of "ldofs" to "vdofs"
210 Array<int> v_list;
211 v_list.Reserve(indices.Size()*vdim);
212 MFEM_VERIFY(indices.Max() < GetNumParticles(),
213 "Particle index " << indices.Max() <<
214 " is out-of-range for number of particles " <<
217 {
218 for (int l = 0; l < indices.Size(); l++)
219 {
220 for (int vd = 0; vd < vdim; vd++)
221 {
222 v_list.Append(Ordering::Map<Ordering::byNODES>(GetNumParticles(),
223 vdim,
224 indices[l], vd));
225 }
226 }
227 }
228 else
229 {
230 for (int l = 0; l < indices.Size(); l++)
231 {
232 for (int vd = 0; vd < vdim; vd++)
233 {
234 v_list.Append(Ordering::Map<Ordering::byVDIM>(GetNumParticles(),
235 vdim,
236 indices[l],
237 vd));
238 }
239 }
240 }
241
242 Vector::DeleteAt(v_list);
243}
244
245void ParticleVector::SetVDim(int vdim_, bool keep_data)
246{
247 if (!keep_data)
248 {
249 int num_particles = GetNumParticles();
250 vdim = vdim_;
251 Vector::SetSize(num_particles*vdim_);
252 return;
253 }
254
255 // Reorder/shift existing entries
256 // For byNODES: Treat each component as a vector temporarily
257 // For byVDIM: Treat each vector as a component temporarily
261
262 SetNumParticles(vdim_, keep_data);
263
264 // Reset ordering back to original
267
268 vdim = vdim_;
269}
270
271void ParticleVector::SetOrdering(Ordering::Type ordering_, bool keep_data)
272{
273 if (keep_data && ordering != ordering_)
274 {
275 int num_particles = GetNumParticles();
276 // create deep copy of old data that will be copied
277 Vector old_data(*this);
278
279 const bool use_dev = UseDevice();
280 const auto d_src = old_data.Read(use_dev);
281 auto d_dest = Write(use_dev);
282
283 const int vdim_ = vdim;
284 const int size_ = size;
285
286 if (ordering_ == Ordering::byNODES) // byVDIM -> byNODES
287 {
288 mfem::forall_switch(use_dev, size_, [=] MFEM_HOST_DEVICE (int k)
289 {
290 int i = k / vdim_; // src particle index
291 int d = k % vdim_; // src component index
292 d_dest[i + d * num_particles] = d_src[k];
293 });
294 }
295 else // byNODES -> byVDIM
296 {
297 mfem::forall_switch(use_dev, size_, [=] MFEM_HOST_DEVICE (int k)
298 {
299 int d = k / num_particles; // src component index
300 int i = k % num_particles; // src particle index
301 d_dest[d + i * vdim_] = d_src[k];
302 });
303 }
304 }
305 ordering = ordering_;
306}
307
308void ParticleVector::SetNumParticles(int num_vectors, bool keep_data)
309{
310 int old_nv = GetNumParticles();
311
312 if (num_vectors == old_nv)
313 {
314 return;
315 }
316
317 // If resizing larger...
318 if (num_vectors > old_nv)
319 {
320 // Increase capacity if needed
321 if (num_vectors*vdim > Vector::Capacity())
322 {
323 GrowSize(num_vectors, keep_data);
324 }
325
326 // Set larger new size
327 Vector::SetSize(num_vectors*vdim);
328
329 if (!keep_data) { return; }
330
331 const bool use_dev = UseDevice();
332 auto d_dest = this->ReadWrite(use_dev);
333
335 {
336 // create deep copy of old data that will be copied
337 Vector old_slice;
338 old_slice.MakeRef(*this, 0, old_nv * vdim);
339 Vector old_copy(old_slice);
340
341 const auto d_src = old_copy.Read(use_dev);
342 const int vdim_ = vdim;
343
344 // Shift entries for byNODES
345 mfem::forall_switch(use_dev, old_nv * vdim_,
346 [=] MFEM_HOST_DEVICE (int k)
347 {
348 const int d = k / old_nv;
349 const int i = k % old_nv;
350 d_dest[i + d*num_vectors] = d_src[k];
351 });
352
353 // Zero-out new data slots
354 const int diff = num_vectors - old_nv;
355 mfem::forall_switch(use_dev, diff * vdim,
356 [=] MFEM_HOST_DEVICE (int k)
357 {
358 const int d = k / diff;
359 const int i = k % diff;
360 d_dest[d * num_vectors + old_nv + i] = 0.0;
361 });
362 }
363 else // byVDIM
364 {
365 const int start_idx = old_nv * vdim;
366 const int end_idx = num_vectors * vdim;
367 const int diff = end_idx - start_idx;
368 mfem::forall_switch(use_dev, diff, [=] MFEM_HOST_DEVICE (int i)
369 {
370 d_dest[start_idx + i] = 0.0;
371 });
372 }
373 }
374 else // Else just remove the trailing vector data
375 {
376 if (!keep_data) { Vector::SetSize(num_vectors*vdim); return; }
377 Array<int> rm_indices(old_nv-num_vectors);
378 for (int i = 0; i < rm_indices.Size(); i++)
379 {
380 rm_indices[i] = old_nv - rm_indices.Size() + i;
381 }
382 DeleteParticles(rm_indices);
383 }
384}
385
386} // namespace mfem
T Max() const
Find the maximal element in the array, using the comparison operator < for class T.
Definition array.cpp:69
void Reserve(int capacity)
Ensures that the allocated size is at least the given size.
Definition array.hpp:210
int Size() const
Return the logical size of the array.
Definition array.hpp:192
int Append(const T &el)
Append element 'el' to array, resize if necessary.
Definition array.hpp:941
static MemoryClass GetHostMemoryClass()
Get the current Host MemoryClass. This is the MemoryClass used by most MFEM host Memory objects.
Definition device.hpp:293
static MemoryClass GetDeviceMemoryClass()
Get the current Device MemoryClass. This is the MemoryClass used by most MFEM device kernels to acces...
Definition device.hpp:306
Class used by MFEM to store pointers to host and/or device memory.
int Capacity() const
Return the size of the allocated memory.
bool UseDevice() const
Read the internal device flag.
MemoryType GetMemoryType() const
Return a MemoryType that is currently valid. If both the host and the device pointers are currently v...
const T * Read(MemoryClass mc, int size) const
Get read-only access to the memory with the given MemoryClass.
void Delete()
Delete the owned pointers and reset the Memory object.
Type
Ordering methods:
Definition ordering.hpp:17
ParticleVector carries vector data (of a given vector dimension) for an arbitrary number of particles...
Ordering::Type ordering
Ordering of Vector data in ParticleVector.
void SetValues(int i, const Vector &nvals)
Set particle i 's data to nvals .
real_t & operator()(int i, int comp)
Reference to particle i component comp value.
void GetValues(int i, Vector &nvals) const
Get a copy of particle i 's data.
int vdim
Vector dimension.
int GetNumParticles() const
Get the number of particle data in the ParticleVector.
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.
void SetOrdering(Ordering::Type ordering_, bool keep_data=true)
Set the ordering of the particle Vector data in ParticleVector.
void GetComponents(int vd, Vector &comp)
Get a copy of component vd for all particle vector data.
void SetVDim(int vdim_, bool keep_data=true)
Set 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.
void SetComponents(int vd, const Vector &comp)
Set component vd values for all particle data to comp .
void GetComponentsRef(int vd, Vector &nref)
For GetOrdering == Ordering::byNODES, set nref to refer to component vd 's data.
void GrowSize(int min_num_vectors, bool keep_data)
Re-allocate + copy memory. See Array::GrowSize.
Vector data type.
Definition vector.hpp:82
virtual const real_t * HostRead() const
Shortcut for mfem::Read(vec.GetMemory(), vec.Size(), false).
Definition vector.hpp:524
virtual const real_t * Read(bool on_dev=true) const
Shortcut for mfem::Read(vec.GetMemory(), vec.Size(), on_dev).
Definition vector.hpp:520
virtual real_t * ReadWrite(bool on_dev=true)
Shortcut for mfem::ReadWrite(vec.GetMemory(), vec.Size(), on_dev).
Definition vector.hpp:536
Memory< real_t > & GetMemory()
Return a reference to the Memory object used by the Vector.
Definition vector.hpp:265
Memory< real_t > data
Definition vector.hpp:85
real_t & operator[](int i)
Access Vector entries using [] for 0-based indexing.
Definition vector.hpp:304
void DeleteAt(const Array< int > &indices)
Definition vector.cpp:1260
virtual bool UseDevice() const
Return the device flag of the Memory object used by the Vector.
Definition vector.hpp:148
int Size() const
Returns the size of the vector.
Definition vector.hpp:234
virtual void UseDevice(bool use_dev) const
Enable execution of Vector operations using the mfem::Device.
Definition vector.hpp:145
void SetSize(int s)
Resize the vector to size s.
Definition vector.hpp:633
int Capacity() const
Return the size of the currently allocated data array.
Definition vector.hpp:238
Vector & operator=(const real_t *v)
Copy Size() entries from v.
Definition vector.cpp:197
virtual real_t * HostReadWrite()
Shortcut for mfem::ReadWrite(vec.GetMemory(), vec.Size(), false).
Definition vector.hpp:540
virtual real_t * Write(bool on_dev=true)
Shortcut for mfem::Write(vec.GetMemory(), vec.Size(), on_dev).
Definition vector.hpp:528
void MakeRef(Vector &base, int offset, int size)
Reset the Vector to be a reference to a sub-vector of base.
Definition vector.hpp:709
float real_t
Definition config.hpp:46
void forall_switch(bool use_dev, int N, lambda &&body)
Definition forall.hpp:1214
real_t p(const Vector &x, real_t t)