MFEM v4.9.0
Finite element discretization library
Loading...
Searching...
No Matches
particles_redist.cpp
Go to the documentation of this file.
1// Copyright (c) 2010-2025, 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// -----------------------------------------------------------------------
13// Particles Redistribute: Transfer particles to ranks they are located on
14// -----------------------------------------------------------------------
15//
16// This miniapp highlights the ParticleSet::Redistribute feature. Particles
17// are initialized onto an input mesh by all ranks, and then re-distributed
18// so that particles are held by the ranks of which they are actually physically
19// located in on the ParMesh.
20//
21// Compile with: make particles_redist
22//
23// Sample runs:
24// mpirun -np 4 particles_redist
25// mpirun -np 4 particles_redist -npt 5000 -m ../../data/star.mesh
26// mpirun -np 4 particles_redist -npt 7500 -m ../../data/toroid-hex.mesh
27// mpirun -np 4 particles_redist -npt 7500 -m ../../data/fichera-q3.mesh
28
29#include "mfem.hpp"
31
32#include <random>
33
34using namespace std;
35using namespace mfem;
36using namespace mfem::common;
37
39
40template<typename T>
41Vector ArrayToVector(const Array<T> &fields);
42
43int main (int argc, char *argv[])
44{
45 // Initialize MPI and HYPRE.
46 Mpi::Init(argc, argv);
47 int rank = Mpi::WorldRank();
49
50 const char *mesh_file = "../../data/rt-2d-q3.mesh";
51 int npt = 1000;
52 bool visualization = true;
53 int visport = 19916;
54 char vishost[] = "localhost";
55
56 OptionsParser args(argc, argv);
57 args.AddOption(&mesh_file, "-m", "--mesh", "Mesh file to use");
58 args.AddOption(&npt, "-npt", "--num-particles",
59 "Number of particles to initialize on global mesh "
60 "bounding box.");
61 args.AddOption(&visualization, "-vis", "--visualization", "-no-vis",
62 "--no-visualization",
63 "Enable or disable GLVis visualization.");
64 args.AddOption(&visport, "-p", "--send-port", "Socket for GLVis.");
65
66 args.Parse();
67 if (!args.Good())
68 {
69 args.PrintUsage(cout);
70 return 1;
71 }
72 if (rank == 0) { args.PrintOptions(cout); }
73
74 // Create mesh
75 Mesh mesh(mesh_file);
76 int space_dim = mesh.Dimension();
77
78 // Create parallel particle set
79 ParticleSet pset(MPI_COMM_WORLD, npt, space_dim);
80
81 Vector pos_min, pos_max;
82 mesh.GetBoundingBox(pos_min, pos_max);
83
84 ParMesh pmesh(MPI_COMM_WORLD, mesh);
85
86 // Set particles randomly on entire mesh domain, for each rank
87 std::mt19937 gen(rank);
88 std::uniform_real_distribution<real_t> real_dist;
89 for (int i = 0; i < pset.GetNParticles(); i++)
90 {
91 Particle p = pset.GetParticleRef(i);
92 for (int d = 0; d < pset.GetDim(); d++)
93 {
94 p.Coords()[d] = pos_min[d] + real_dist(gen)*(pos_max[d] - pos_min[d]);
95 }
96 }
97
98 // Find points
99 FindPointsGSLIB finder(MPI_COMM_WORLD);
100 pmesh.EnsureNodes();
101 finder.Setup(pmesh);
102 finder.FindPoints(pset.Coords(), pset.Coords().GetOrdering());
103
104 // Remove points not in domain
105 const Array<int> rm_idxs = finder.GetPointsNotFoundIndices();
106 pset.RemoveParticles(rm_idxs);
107
108 int num_removed = rm_idxs.Size();
109 MPI_Allreduce(MPI_IN_PLACE, &num_removed, 1, MPI_INT, MPI_SUM, MPI_COMM_WORLD);
110 if (rank == 0)
111 {
112 mfem::out << endl << "Removed " << num_removed <<
113 " particles that were not within the mesh" << endl << endl;
114 }
115
116 // Remove ranks from finder proc list corresponding to removed particles
117 Array<unsigned int> ranks = finder.GetProc();
118 ranks.DeleteAt(rm_idxs);
119 if (rank == 0)
120 {
121 mfem::out << "Pre-Redistribute:" << endl;
122 }
123
125
126 // Particle size for visualization
127 real_t psize = Distance(pos_min, pos_max)*2e-3;
128 if (visualization)
129 {
130 socketstream sock;
131 Vector rank_vector(pset.GetNParticles());
132 rank_vector = rank;
133 VisualizeParticles(sock, vishost, visport,
134 pset, rank_vector, psize,
135 "Particle Owning Rank (Pre-Redistribute)",
136 0, 0, 400, 400, pset.GetDim() == 2 ? "Rjbcb" : "cb");
137 }
138
139
140 // Redistribute
141 pset.Redistribute(ranks);
142
143 // Find again
144 finder.FindPoints(pset.Coords(), pset.Coords().GetOrdering());
145
146 if (rank == 0)
147 {
148 mfem::out << "\nPost-Redistribute:\n";
149 }
151
152 if (visualization)
153 {
154 socketstream sock;
155 Vector rank_vector(pset.GetNParticles());
156 rank_vector = rank;
157 VisualizeParticles(sock, "localhost", visport, pset, rank_vector, psize,
158 "Particle Owning Rank (Post-Redistribute)",
159 410, 0, 400, 400, pset.GetDim() == 2 ? "Rjbcb" : "cb");
160 }
161
162 return 0;
163}
164
166{
167 int rank = Mpi::WorldRank(),
168 size = Mpi::WorldSize();
169
170 int on_rank = 0, off_rank = 0;
171 for (int i = 0; i < procs.Size(); i++)
172 {
173 if (static_cast<int>(procs[i]) == rank)
174 {
175 on_rank++;
176 }
177 else
178 {
179 off_rank++;
180 }
181 }
182
183 std::vector<int> all_on_rank(size), all_off_rank(size);
184 MPI_Gather(&on_rank, 1, MPI_INT, all_on_rank.data(), 1, MPI_INT, 0,
185 MPI_COMM_WORLD);
186 MPI_Gather(&off_rank, 1, MPI_INT, all_off_rank.data(), 1, MPI_INT, 0,
187 MPI_COMM_WORLD);
188 if (rank == 0)
189 {
190 for (int r = 0; r < size; r++)
191 {
192 mfem::out << "Rank " << r << " owns "
193 << all_on_rank[r] << " within it, "
194 << all_off_rank[r] << " particles outside it\n";
195 }
196 }
197}
198
199template<typename T>
201{
202 Vector v(fields.Size());
203 for (int i = 0; i < fields.Size(); i++)
204 {
205 v[i] = static_cast<real_t>(fields[i]);
206 }
207 return v;
208}
int Size() const
Return the logical size of the array.
Definition array.hpp:166
void DeleteAt(const Array< int > &indices)
Delete entries at indices, and resize.
Definition array.hpp:1007
FindPointsGSLIB can robustly evaluate a GridFunction on an arbitrary collection of points....
Definition gslib.hpp:73
void FindPoints(const Vector &point_pos, int point_pos_ordering=Ordering::byNODES)
Definition gslib.cpp:236
void Setup(Mesh &m, const double bb_t=0.1, const double newt_tol=1.0e-12, const int npt_max=256)
Definition gslib.cpp:183
Array< unsigned int > GetPointsNotFoundIndices() const
Get array of indices of not-found points.
Definition gslib.cpp:2122
virtual const Array< unsigned int > & GetProc() const
Return MPI rank on which each point was found by FindPoints.
Definition gslib.hpp:323
static void Init()
Initialize hypre by calling HYPRE_Init() and set default options. After calling Hypre::Init(),...
Definition hypre.cpp:33
Mesh data type.
Definition mesh.hpp:65
void EnsureNodes()
Make sure that the mesh has valid nodes, i.e. its geometry is described by a vector finite element gr...
Definition mesh.cpp:6747
void GetBoundingBox(Vector &min, Vector &max, int ref=2)
Returns the minimum and maximum corners of the mesh bounding box.
Definition mesh.cpp:141
int Dimension() const
Dimension of the reference space used within the elements.
Definition mesh.hpp:1306
static int WorldRank()
Return the MPI rank in MPI_COMM_WORLD.
static int WorldSize()
Return the size of MPI_COMM_WORLD.
static void Init(int &argc, char **&argv, int required=default_thread_required, int *provided=nullptr)
Singleton creation with Mpi::Init(argc, argv).
void Parse()
Parse the command-line options. Note that this function expects all the options provided through the ...
void PrintUsage(std::ostream &out) const
Print the usage message.
void PrintOptions(std::ostream &out) const
Print the options.
void AddOption(bool *var, const char *enable_short_name, const char *enable_long_name, const char *disable_short_name, const char *disable_long_name, const char *description, bool required=false)
Add a boolean option and set 'var' to receive the value. Enable/disable tags are used to set the bool...
Definition optparser.hpp:82
bool Good() const
Return true if the command line options were parsed successfully.
Class for parallel meshes.
Definition pmesh.hpp:34
ParticleSet initializes and manages data associated with particles.
void Redistribute(const Array< unsigned int > &rank_list)
Redistribute particle data to rank_list.
Particle GetParticleRef(int i)
Get Particle object whose members reference the actual data associated with particle i in this Partic...
ParticleVector & Coords()
Get a reference to the coordinates ParticleVector.
int GetDim() const
Get the spatial dimension.
int GetNParticles() const
Get the number of active particles currently held by this ParticleSet.
void RemoveParticles(const Array< int > &list)
Remove particle data specified by list of particle indices.
Ordering::Type GetOrdering() const
Get the ordering of data in the ParticleVector.
Container for data associated with a single particle.
Vector & Coords()
Get reference to particle coordinates Vector.
Vector data type.
Definition vector.hpp:82
int main()
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...
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
real_t Distance(const real_t *x, const real_t *y, const int n)
Definition vector.hpp:727
float real_t
Definition config.hpp:46
const char vishost[]
real_t p(const Vector &x, real_t t)
void PrintOnOffRankCounts(const Array< unsigned int > &procs)
Vector ArrayToVector(const Array< T > &fields)