MFEM v4.10.0
Finite element discretization library
Loading...
Searching...
No Matches
particles_extras.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 "particles_extras.hpp"
13
14
15namespace mfem
16{
17namespace common
18{
19
20void Add3DPoint(const Vector &center, Mesh &m, real_t scale)
21{
22 real_t s = 0.5*scale;
23 Vector v[8];
24
25 for (int i = 0; i < 8; i++)
26 {
27 v[i].SetSize(3);
28 v[i] = 0.0;
29 }
30
31 for (int i = 0; i < center.Size(); i++)
32 {
33 v[0][i] = center[i];
34 }
35
36 Vector v_s(3); v_s = s;
37 v[0] -= v_s;
38
39 v[1] = v[0];
40 v[1][0] += 2*s;
41
42 v[2] = v[1];
43 v[2][1] += 2*s;
44
45 v[3] = v[2];
46 v[3][0] -= 2*s;
47
48 Vector v_s_z(3);
49 v_s_z = 0.0;
50 v_s_z[2] = s;
51 for (int i = 4; i < 8; i++)
52 {
53 add(1.0, v[i-4], 2.0, v_s_z, v[i]);
54 }
55
56 for (int i = 0; i < 8; i++)
57 {
58 m.AddVertex(v[i]);
59 }
60
61 int vi[8];
62 for (int i = 0; i < 8; i++)
63 {
64 vi[i] = i + (m.GetNE())*8;
65 }
66 m.AddHex(vi);
67}
68
69void Add2DPoint(const Vector &center, Mesh &m, real_t scale)
70{
71 real_t s = 0.5*scale;
72 Vector v[4];
73
74 for (int i = 0; i < 4; i++)
75 {
76 v[i].SetSize(2);
77 v[i] = 0.0;
78 }
79
80 for (int i = 0; i < center.Size(); i++)
81 {
82 v[0][i] = center[i];
83 }
84
85 Vector v_s(2); v_s = s;
86 v[0] -= v_s;
87
88 v[1] = v[0];
89 v[1][0] += 2*s;
90
91 v[2] = v[1];
92 v[2][1] += 2*s;
93
94 v[3] = v[2];
95 v[3][0] -= 2*s;
96
97 for (int i = 0; i < 4; i++)
98 {
99 m.AddVertex(v[i]);
100 }
101
102 int vi[4];
103 for (int i = 0; i < 4; i++)
104 {
105 vi[i] = i + (m.GetNE())*4;
106 }
107 m.AddQuad(vi);
108}
109
110
111void VisualizeParticles(socketstream &sock, const char* vishost, int visport,
112 const ParticleSet &pset, const Vector &scalar_field,
113 real_t psize,
114 const char* title, int x, int y, int w, int h, const char* keys)
115{
116 const int dim = pset.GetDim();
117 MFEM_VERIFY(dim == 2 || dim == 3,
118 "ParticleSet dimension must be 2 or 3 for visualization.");
119 const int nv = dim == 2 ? 4 : 8;
120
121 L2_FECollection l2fec(1,dim);
122 Mesh particles_mesh(dim, pset.GetNParticles()*nv, pset.GetNParticles(),
123 0, dim);
124
125 for (int i = 0; i < pset.GetNParticles(); i++)
126 {
127 Vector pcoords;
128 pset.Coords().GetValues(i, pcoords);
129 pcoords.HostRead();
130 if (dim == 2)
131 {
132 Add2DPoint(pcoords, particles_mesh, psize);
133 }
134 else
135 {
136 Add3DPoint(pcoords, particles_mesh, psize);
137 }
138 }
139 particles_mesh.FinalizeMesh();
140
141 FiniteElementSpace fes(&particles_mesh, &l2fec, 1);
142 GridFunction gf(&fes);
143 gf.HostWrite();
144
145 for (int i = 0; i < pset.GetNParticles(); i++)
146 {
147 for (int j = 0; j < nv; j++)
148 {
149 gf[j+i*nv] = scalar_field[i];
150 }
151 }
152
153#ifdef MFEM_USE_MPI
154 VisualizeField(sock, vishost, visport, gf, pset.GetComm(), title,
155 x, y, w, h, keys, false);
156#else
157 VisualizeField(sock, vishost, visport, gf, title, x, y, w, h, keys, false);
158#endif // MFEM_USE_MPI
159}
160
161
163 int tail_size_, const char *vishost_,
164 int visport_, const char *title_,
165 int x_, int y_, int w_, int h_,
166 const char *keys_)
167 : pset(particles), tail_size(tail_size_),
168 x(x_), y(y_), w(w_), h(h_), title(title_), keys(keys_),
169 vishost(vishost_), visport(visport_)
170#ifdef MFEM_USE_MPI
171 ,comm(particles.GetComm())
172#endif // MFEM_USE_MPI
173{
175}
176
178{
179 // Create a new mesh for all particle segments for this timestep
180 segment_meshes.emplace_front(1, pset.GetNParticles()*2,
182 0, pset.GetDim());
183
184 // Add segment start particle IDs
185 segment_ids.emplace_front(pset.GetIDs());
186
187 if (tail_size > 0 && static_cast<int>(segment_meshes.size()) > tail_size)
188 {
189 segment_meshes.pop_back();
190 segment_ids.pop_back();
191 }
192
193 // Add all particle starting vertices
194 for (int i = 0; i < pset.GetNParticles(); i++)
195 {
196 Vector pcoords;
197 pset.Coords().GetValues(i, pcoords);
198 pcoords.HostRead();
199 segment_meshes.front().AddVertex(pcoords);
200 }
201}
202
204{
205 const Array<ParticleSet::IDType> &end_ids = pset.GetIDs();
206
207 // Add all endpoint vertices + segments for all particles that were in
208 // SetSegmentStart
209 int num_start = segment_ids.front().Size();
210 for (int i = 0; i < num_start; i++)
211 {
212 // If this particle's initial position was set in AddSegmentStart,
213 // set the vertex to its now current location
214 int pidx = end_ids.Find(segment_ids.front()[i]);
215 if (pidx != -1)
216 {
217 Vector pcoords;
218 pset.Coords().GetValues(pidx, pcoords);
219 pcoords.HostRead();
220 segment_meshes.front().AddVertex(pcoords);
221 }
222 else // Otherwise set its end vertex == start vertex
223 {
224 segment_meshes.front().AddVertex(segment_meshes.front().GetVertex(i));
225 }
226 segment_meshes.front().AddSegment(i, i+num_start);
227 }
228 segment_meshes.front().FinalizeMesh();
229}
230
231
233{
235
236 // Create a mesh of all the trajectory segments
237 std::vector<Mesh*> all_meshes;
238 for (Mesh &m : segment_meshes)
239 {
240 all_meshes.push_back(&m);
241 }
242 if (mesh)
243 {
244 all_meshes.push_back(mesh);
245 }
246 if (mesh_bb)
247 {
248 all_meshes.push_back(mesh_bb);
249 }
250
251 Mesh trajectories(all_meshes.data(), all_meshes.size());
252 bool vis = trajectories.GetNE() > 0;
253#ifdef MFEM_USE_MPI
254 MPI_Allreduce(MPI_IN_PLACE, &vis, 1, MFEM_MPI_CXX_BOOL,
255 MPI_LOR, pset.GetComm());
256#endif // MFEM_USE_MPI
257 if (!vis) // if all rank have 0 elements, skip visualization
258 {
260 return;
261 }
262
263
264#ifdef MFEM_USE_MPI
265 VisualizeMesh(sock, vishost, visport, trajectories, comm,
266 title, x, y, w, h, keys);
267#else
268 VisualizeMesh(sock, vishost, visport, trajectories,
269 title, x, y, w, h, keys);
270#endif
271
273}
274
276 const Vector &xmax)
277{
278 MFEM_VERIFY(xmin.Size() == pset.GetDim() &&
279 xmax.Size() == pset.GetDim(),
280 "Bounding box dimension must match ParticleSet dimension.");
281
282 // Create a box mesh for visualization
283 if (mesh_bb)
284 {
285 delete mesh_bb;
286 mesh_bb = nullptr;
287 }
288
289 if (pset.GetDim() == 2)
290 {
291 int dim = 2;
292 int nvert = 4;
293 int nelem = 4;
294 mesh_bb = new Mesh(1, nvert, nelem, 0, dim);
295 Vector v0(dim), v1(dim), v2(dim), v3(dim);
296 v0 = xmin;
297 v1 = xmax;
298 v2[0] = xmax[0]; v2[1] = xmin[1];
299 v3[0] = xmin[0]; v3[1] = xmax[1];
300
301 mesh_bb->AddVertex(v0);
302 mesh_bb->AddVertex(v1);
303 mesh_bb->AddVertex(v2);
304 mesh_bb->AddVertex(v3);
305
306 int vi[2] = {0,1};
307 mesh_bb->AddSegment(vi);
308 vi[0] = 1; vi[1] = 2;
309 mesh_bb->AddSegment(vi);
310 vi[0] = 2; vi[1] = 3;
311 mesh_bb->AddSegment(vi);
312 vi[0] = 3; vi[1] = 0;
313 mesh_bb->AddSegment(vi);
315 }
316 else // dim == 3
317 {
318 int dim = 3;
319 int nvert = 8;
320 int nelem = 12;
321 mesh_bb = new Mesh(1, nvert, nelem, 0, dim);
322 Vector v(dim);
323
324 // Vertices
325 v[0] = xmin[0]; v[1] = xmin[1]; v[2] = xmin[2];
326 mesh_bb->AddVertex(v); // 0: 000
327 v[0] = xmax[0]; v[1] = xmin[1]; v[2] = xmin[2];
328 mesh_bb->AddVertex(v); // 1: 100
329 v[0] = xmax[0]; v[1] = xmax[1]; v[2] = xmin[2];
330 mesh_bb->AddVertex(v); // 2: 110
331 v[0] = xmin[0]; v[1] = xmax[1]; v[2] = xmin[2];
332 mesh_bb->AddVertex(v); // 3: 010
333
334 v[0] = xmin[0]; v[1] = xmin[1]; v[2] = xmax[2];
335 mesh_bb->AddVertex(v); // 4: 001
336 v[0] = xmax[0]; v[1] = xmin[1]; v[2] = xmax[2];
337 mesh_bb->AddVertex(v); // 5: 101
338 v[0] = xmax[0]; v[1] = xmax[1]; v[2] = xmax[2];
339 mesh_bb->AddVertex(v); // 6: 111
340 v[0] = xmin[0]; v[1] = xmax[1]; v[2] = xmax[2];
341 mesh_bb->AddVertex(v); // 7: 011
342
343 // Segments
344 int vi[2];
345 // Bottom face
346 vi[0] = 0; vi[1] = 1; mesh_bb->AddSegment(vi);
347 vi[0] = 1; vi[1] = 2; mesh_bb->AddSegment(vi);
348 vi[0] = 2; vi[1] = 3; mesh_bb->AddSegment(vi);
349 vi[0] = 3; vi[1] = 0; mesh_bb->AddSegment(vi);
350
351 // Top face
352 vi[0] = 4; vi[1] = 5; mesh_bb->AddSegment(vi);
353 vi[0] = 5; vi[1] = 6; mesh_bb->AddSegment(vi);
354 vi[0] = 6; vi[1] = 7; mesh_bb->AddSegment(vi);
355 vi[0] = 7; vi[1] = 4; mesh_bb->AddSegment(vi);
356
357 // Vertical edges
358 vi[0] = 0; vi[1] = 4; mesh_bb->AddSegment(vi);
359 vi[0] = 1; vi[1] = 5; mesh_bb->AddSegment(vi);
360 vi[0] = 2; vi[1] = 6; mesh_bb->AddSegment(vi);
361 vi[0] = 3; vi[1] = 7; mesh_bb->AddSegment(vi);
362
364 }
365}
366
367} // namespace common
368} // namespace mfem
int Size() const
Return the logical size of the array.
Definition array.hpp:192
int Find(const T &el) const
Return the first index where 'el' is found; return -1 if not found.
Definition array.hpp:1000
Class FiniteElementSpace - responsible for providing FEM view of the mesh, mainly managing the set of...
Definition fespace.hpp:210
Class for grid function - Vector with associated FE space.
Definition gridfunc.hpp:53
Arbitrary order "L2-conforming" discontinuous finite elements.
Definition fe_coll.hpp:369
Mesh data type.
Definition mesh.hpp:67
int AddSegment(int v1, int v2, int attr=1)
Adds a segment to the mesh given by 2 vertices v1 and v2.
Definition mesh.cpp:2136
void FinalizeMesh(int refine=0, bool fix_orientation=true)
Finalize the construction of any type of Mesh.
Definition mesh.cpp:3654
int AddQuad(int v1, int v2, int v3, int v4, int attr=1)
Adds a quadrilateral to the mesh given by 4 vertices v1 through v4.
Definition mesh.cpp:2164
int AddVertex(real_t x, real_t y=0.0, real_t z=0.0)
Definition mesh.cpp:2079
int GetNE() const
Returns number of elements.
Definition mesh.hpp:1390
int AddHex(int v1, int v2, int v3, int v4, int v5, int v6, int v7, int v8, int attr=1)
Adds a hexahedron to the mesh given by 8 vertices v1 through v8.
Definition mesh.cpp:2227
ParticleSet initializes and manages data associated with particles.
MPI_Comm GetComm() const
Get the MPI communicator for this ParticleSet.
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 GetDim() const
Get the spatial dimension.
int GetNParticles() const
Get the number of active particles currently held by this ParticleSet.
void GetValues(int i, Vector &nvals) const
Get a copy of particle i 's data.
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
int Size() const
Returns the size of the vector.
Definition vector.hpp:234
void SetSize(int s)
Resize the vector to size s.
Definition vector.hpp:633
virtual real_t * HostWrite()
Shortcut for mfem::Write(vec.GetMemory(), vec.Size(), false).
Definition vector.hpp:532
void Visualize()
Visualize the particle trajectories (and mesh if provided).
void SetVisualizationBoundingBox(const Vector &xmin, const Vector &xmax)
Set the bounding box for visualization.
std::list< Array< ParticleSet::IDType > > segment_ids
Track particle IDs that exist at the segment start.
ParticleTrajectories(const ParticleSet &particles, int tail_size_, const char *vishost_, int visport_, const char *title_, int x_=0, int y_=0, int w_=400, int h_=400, const char *keys_=nullptr)
Setup up the particle trajectory for visualization.
std::list< Mesh > segment_meshes
Each segment is stored as a Mesh snapshot.
int dim
Definition ex24.cpp:53
void Add2DPoint(const Vector &center, Mesh &m, real_t scale)
Add a point to a given Mesh, represented as a quad sized scale.
void VisualizeMesh(socketstream &sock, const char *vishost, int visport, Mesh &mesh, const char *title, int x, int y, int w, int h, const char *keys)
void Add3DPoint(const Vector &center, Mesh &m, real_t scale)
Add a point to a given Mesh, represented as a hex sized scale.
void VisualizeParticles(socketstream &sock, const char *vishost, int visport, const ParticleSet &pset, const Vector &scalar_field, real_t psize, const char *title, int x, int y, int w, int h, const char *keys)
Plot particles in ParticleSet pset, represented as quads/hexes of size psize and colored by scalar_fi...
void VisualizeField(socketstream &sock, const char *vishost, int visport, GridFunction &gf, const char *title, int x, int y, int w, int h, const char *keys, bool vec)
void add(const Vector &v1, const Vector &v2, Vector &v)
Definition vector.cpp:414
float real_t
Definition config.hpp:46
const char vishost[]