MFEM v4.8.0
Finite element discretization library
Loading...
Searching...
No Matches
nodal-transfer.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// Nodal Transfer Miniapp: Map ParGridFunction to Different MPI Partitioning
14// -------------------------------------------------------------------------
15//
16// The Nodal Transfer Miniapp maps partitioned parallel grid function to a
17// parallel grid function partitioned on a different number of processes. The
18// miniapp has two regimes: 1) Generates partitioned parallel grid function
19// and saves it to a set of files; 2) Reads the partitioned grid function and
20// maps it to the current partition. The map assumes that the position of the
21// nodal DOFs does not change between the original grid function and the target
22// grid function. The transfer does not perform any interpolation. It just
23// copies the nodal values between the two grid functions.
24//
25// Generate second order mesh on 4 processes
26// mpirun -np 4 ./nodal-transfer -rs 2 -rp 1 -gd 1 -o 2
27// Read the generated data and map it to a grid function defined on two processes
28// mpirun -np 2 ./nodal-transfer -rs 2 -rp 0 -gd 0 -snp 4 -o 2
29//
30// Generate first order grid function on 8 processes
31// mpirun -np 8 ./nodal-transfer -rs 2 -rp 2 -gd 1 -o 1 -m ../../data/star.mesh
32// Read the generated data on 4 processes and coarser mesh
33// mpirun -np 4 ./nodal-transfer -rs 2 -rp 0 -gd 0 -snp 8 -o 1 -m ../../data/star.mesh
34
35#include <mfem.hpp>
36#include <fstream>
37#include <iostream>
38#include <cmath>
40
41using namespace mfem;
42
43class TestCoeff : public Coefficient
44{
45public:
46 TestCoeff() {}
47
49 const IntegrationPoint &ip) override
50 {
51 if (T.GetSpaceDim()==3)
52 {
53 real_t x[3];
54 Vector transip(x, 3);
55 T.Transform(ip, transip);
56 return std::sin(x[0])*std::cos(x[1]) +
57 std::sin(x[1])*std::cos(x[2]) +
58 std::sin(x[2])*std::cos(x[0]);
59 }
60 else if (T.GetSpaceDim()==2)
61 {
62 real_t x[2];
63 Vector transip(x, 2);
64 T.Transform(ip, transip);
65 return std::sin(x[0])*std::cos(x[1]) +
66 std::sin(x[1])*std::cos(x[0]);
67 }
68 else
69 {
70 real_t x;
71 Vector transip(&x,1);
72 T.Transform(ip, transip);
73 return std::sin(x)+std::cos(x);
74 }
75 }
76};
77
78int main(int argc, char* argv[])
79{
80 // Initialize MPI.
81 Mpi::Init(argc, argv);
82 int myrank = Mpi::WorldRank();
83
84 // Parse command-line options
85 const char *mesh_file = "../../data/beam-tet.mesh";
86 int ser_ref_levels = 3;
87 int par_ref_levels = 1;
88 int order = 1;
89 int gen_data = 1;
90 int src_num_procs = 4;
91 bool visualization = true;
92
93 OptionsParser args(argc, argv);
94 args.AddOption(&mesh_file, "-m", "--mesh", "Mesh file to use.");
95 args.AddOption(&ser_ref_levels,
96 "-rs",
97 "--refine-serial",
98 "Number of times to refine the mesh uniformly in serial.");
99 args.AddOption(&par_ref_levels,
100 "-rp",
101 "--refine-parallel",
102 "Number of times to refine the mesh uniformly in parallel.");
103 args.AddOption(&gen_data,
104 "-gd",
105 "--generate-data",
106 "Generate input data for the transfer.");
107 args.AddOption(&order,
108 "-o",
109 "--order",
110 "Order (degree) of the finite elements.");
111 args.AddOption(&src_num_procs,
112 "-snp",
113 "--src_num_procs",
114 "Number of processes for the src grid function.");
115 args.AddOption(&visualization, "-vis", "--visualization", "-no-vis",
116 "--no-visualization",
117 "Enable or disable ParaView visualization.");
118 args.Parse();
119 if (!args.Good())
120 {
121 if (myrank == 0)
122 {
123 args.PrintUsage(std::cout);
124 }
125 return 1;
126 }
127
128 if (myrank == 0)
129 {
130 args.PrintOptions(std::cout);
131 }
132
133 // Read the (serial) mesh from the given mesh file on all processors. We
134 // can handle triangular, quadrilateral, tetrahedral and hexahedral meshes
135 // with the same code.
136 Mesh mesh(mesh_file, 1, 1);
137 int dim = mesh.SpaceDimension();
138
139 // Refine the mesh in serial to increase the resolution. In this example
140 // we do 'ser_ref_levels' of uniform refinement, where 'ser_ref_levels' is
141 // a command-line parameter.
142 for (int lev = 0; lev < ser_ref_levels; lev++)
143 {
144 mesh.UniformRefinement();
145 }
146
147 // Define a parallel mesh by a partitioning of the serial mesh. Refine
148 // this mesh further in parallel to increase the resolution. Once the
149 // parallel mesh is defined, the serial mesh can be deleted.
150 ParMesh pmesh(MPI_COMM_WORLD, mesh);
151 for (int lev = 0; lev < par_ref_levels; lev++)
152 {
153 pmesh.UniformRefinement();
154 }
155
156 // Define the finite element spaces for the solution
157 H1_FECollection fec(order, dim);
158 ParFiniteElementSpace fespace(&pmesh, &fec, 1, Ordering::byVDIM);
159 HYPRE_Int glob_size = fespace.GlobalTrueVSize();
160 if (myrank == 0)
161 {
162 std::cout << "Number of finite element unknowns: " << glob_size
163 << std::endl;
164 }
165
166 ParGridFunction x(&fespace); x=0.0;
167 TestCoeff prco;
168 if (gen_data)
169 {
170 Coefficient* coef[2]; coef[0]=&prco; coef[1]=&prco;
171 x.ProjectCoefficient(coef);
172
173 // Save the grid function
174 {
175 // Save the mesh and the data
176 std::ostringstream oss;
177 oss << std::setw(10) << std::setfill('0') << myrank;
178 std::string mname="mesh_"+oss.str()+".msh";
179 std::string gname="gridfunc_"+oss.str()+".gf";
180 std::ofstream sout;
181
182 // Save the mesh
183 sout.open(mname.c_str(),std::ios::out);
184 sout.precision(20);
185 pmesh.ParPrint(sout);
186 sout.close();
187
188 // Save the grid function data
189 sout.open(gname.c_str(),std::ios::out);
190 sout.precision(20);
191 x.Save(sout);
192 sout.close();
193 }
194 }
195 else
196 {
197 // Read the grid function written to files and map it to the current
198 // partition scheme.
199 // x grid function will be the target of the transfer
200 // y will be utilized later for comparison
201 ParGridFunction y(&fespace);
202 Coefficient* coef[2]; coef[0]=&prco; coef[1]=&prco;
203 y.ProjectCoefficient(coef);
204
205 // Map the src grid function
206 {
207 std::ifstream in;
209 if (dim==2)
210 {
211 map = new KDTreeNodalProjection<2>(x);
212 }
213 else
214 {
215 map = new KDTreeNodalProjection<3>(x);
216 }
217 for (int p=0; p<src_num_procs; p++)
218 {
219 std::ostringstream oss;
220 oss << std::setw(10) << std::setfill('0') << p;
221 std::string mname="mesh_"+oss.str()+".msh";
222 std::string gname="gridfunc_"+oss.str()+".gf";
223
224 // Read the mesh
225 Mesh lmesh;
226 in.open(mname.c_str(),std::ios::in);
227 lmesh.Load(in);
228 in.close();
229
230 in.open(gname.c_str(),std::ios::in);
231 GridFunction gf(&lmesh,in);
232 in.close();
233
234 // Project the grid function
235 map->Project(gf,1e-8);
236 }
237 delete map;
238 }
239
240 // Write the result into a ParaView file
241 if (visualization)
242 {
243 ParaViewDataCollection paraview_dc("GridFunc", &pmesh);
244 paraview_dc.SetPrefixPath("ParaView");
245 paraview_dc.SetLevelsOfDetail(order);
247 paraview_dc.SetCycle(0);
248 paraview_dc.SetTime(0.0);
249 paraview_dc.RegisterField("x",&x);
250 paraview_dc.RegisterField("y",&y);
251 paraview_dc.Save();
252 }
253
254 // Compare the results
255 Vector tmpv = x;
256 tmpv -= y;
257 real_t l2err = mfem::InnerProduct(MPI_COMM_WORLD,tmpv,tmpv);
258 if (myrank==0)
259 {
260 std::cout<<"|l2 error|="<<sqrt(l2err)<<std::endl;
261 }
262 }
263
264 return 0;
265}
Base class for KDTreeNodalProjection.
Definition kdtree.hpp:23
Base class Coefficients that optionally depend on space and time. These are used by the BilinearFormI...
virtual void RegisterField(const std::string &field_name, GridFunction *gf)
Add a grid function to the collection.
void SetCycle(int c)
Set time cycle (for time-dependent simulations)
void SetTime(real_t t)
Set physical time (for time-dependent simulations)
void SetPrefixPath(const std::string &prefix)
Set the path where the DataCollection will be saved.
virtual int GetSpaceDim() const =0
Get the dimension of the target (physical) space.
virtual void Transform(const IntegrationPoint &, Vector &)=0
Transform integration point from reference coordinates to physical coordinates and store them in the ...
Class for grid function - Vector with associated FE space.
Definition gridfunc.hpp:31
Arbitrary order H1-conforming (continuous) finite elements.
Definition fe_coll.hpp:275
Class for integration point with weight.
Definition intrules.hpp:35
Mesh data type.
Definition mesh.hpp:64
virtual void Load(std::istream &input, int generate_edges=0, int refine=1, bool fix_orientation=true)
Definition mesh.hpp:749
int SpaceDimension() const
Dimension of the physical space containing the mesh.
Definition mesh.hpp:1219
void UniformRefinement(int i, const DSTable &, int *, int *, int *)
Definition mesh.cpp:11295
static int WorldRank()
Return the MPI rank in 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.
Abstract parallel finite element space.
Definition pfespace.hpp:29
HYPRE_BigInt GlobalTrueVSize() const
Definition pfespace.hpp:346
Class for parallel grid function.
Definition pgridfunc.hpp:50
void Save(std::ostream &out) const override
void ProjectCoefficient(Coefficient &coeff) override
Project coeff Coefficient to this GridFunction. The projection computation depends on the choice of t...
Class for parallel meshes.
Definition pmesh.hpp:34
void ParPrint(std::ostream &out, const std::string &comments="") const
Definition pmesh.cpp:6313
Helper class for ParaView visualization data.
void SetLevelsOfDetail(int levels_of_detail_)
void SetDataFormat(VTKFormat fmt)
Vector data type.
Definition vector.hpp:82
int dim
Definition ex24.cpp:53
int main()
real_t InnerProduct(HypreParVector *x, HypreParVector *y)
Definition hypre.cpp:468
float real_t
Definition config.hpp:43
real_t p(const Vector &x, real_t t)