MFEM v4.9.0
Finite element discretization library
Loading...
Searching...
No Matches
ex1p.cpp
Go to the documentation of this file.
1// MFEM + Moonolith Example 1 (parallel version)
2//
3// Compile with: make ex1p
4//
5// Moonolith sample runs:
6// mpirun -np 4 ex1p
7// mpirun -np 4 ex1p --source_refinements 1 --dest_refinements 2
8// mpirun -np 4 ex1p -s ../../data/inline-hex.mesh -d ../../data/inline-tet.mesh
9//
10// Description: This example code demonstrates the use of MFEM for transferring
11// discrete fields from one conforming finite element mesh to another. The
12// meshes can be of arbitrary shape and completely unrelated with
13// each other. This feature can be used for implementing immersed
14// domain methods for fluid-structure interaction or general
15// multi-physics applications.
16//
17// This particular example is for parallel runtimes. Vector FE is
18// an experimental feature in parallel. For non-conforming meshes
19// please have a look at example "ex2p.cpp".
20
21#include "example_utils.hpp"
22#include "mfem.hpp"
23
24#ifndef MFEM_USE_MOONOLITH
25#error This example requires that MFEM is built with MFEM_USE_MOONOLITH=YES
26#endif
27
28using namespace mfem;
29using namespace std;
30
31void destination_transform(const Vector &x, Vector &x_new)
32{
33 x_new = x;
34 // x_new *= 0.5;
35}
36
37int main(int argc, char *argv[])
38{
39 MPI_Init(&argc, &argv);
40
41 int num_procs, rank;
42
43 MPI_Comm_size(MPI_COMM_WORLD, &num_procs);
44 MPI_Comm_rank(MPI_COMM_WORLD, &rank);
45
46 // Init transfer library context, with MPI handled outside the library
47 InitTransfer(argc, argv, MPI_COMM_WORLD);
48
49 const char *source_mesh_file = "../../data/inline-tri.mesh";
50 const char *destination_mesh_file = "../../data/inline-quad.mesh";
51
52 int src_n_refinements = 0;
53 int dest_n_refinements = 0;
54 int source_fe_order = 1;
55 int dest_fe_order = 1;
56 bool visualization = true;
57 bool use_vector_fe = false;
58 bool use_h1 = true;
59 bool use_vector_space = false;
60 bool verbose = false;
61 bool assemble_mass_and_coupling_together = true;
62
63 OptionsParser args(argc, argv);
64 args.AddOption(&source_mesh_file, "-s", "--source_mesh",
65 "Mesh file to use for src.");
66 args.AddOption(&destination_mesh_file, "-d", "--destination_mesh",
67 "Mesh file to use for dest.");
68 args.AddOption(&src_n_refinements, "-sr", "--source_refinements",
69 "Number of src refinements");
70 args.AddOption(&dest_n_refinements, "-dr", "--dest_refinements",
71 "Number of dest refinements");
72 args.AddOption(&visualization, "-vis", "--visualization", "-no-vis",
73 "--no-visualization",
74 "Enable or disable GLVis visualization.");
75 args.AddOption(&source_fe_order, "-so", "--source_fe_order",
76 "Order of the src finite elements");
77 args.AddOption(&dest_fe_order, "-do", "--dest_fe_order",
78 "Order of the dest finite elements");
79 args.AddOption(&verbose, "-verb", "--verbose", "--no-verb", "--no-verbose",
80 "Enable/Disable verbose output");
81 args.AddOption(&use_vector_fe, "-vfe", "--use_vector_fe", "-no-vfe",
82 "--no-vector_fe",
83 "Use RT|ND vector finite elements (Experimental)");
84 args.AddOption(&use_vector_space, "-vfs", "--use_vector_space", "-no-vfs",
85 "--no-vector_space",
86 "Use Lagrange vector finite elements (Experimental)");
87 args.AddOption(&use_h1, "-h1", "--use-h1", "-nh1", "--no-h1",
88 "Use H1 collection");
89 args.AddOption(&assemble_mass_and_coupling_together, "-act",
90 "--assemble_mass_and_coupling_together", "-no-act",
91 "--no-assemble_mass_and_coupling_together",
92 "Assemble mass and coupling operators together (better for "
93 "non-affine elements)");
94 args.Parse();
95 check_options(args);
96
97 if (use_vector_fe && use_vector_space)
98 {
99 mfem::err <<
100 "WARNING: use_vector_fe and use_vector_space options"
101 "are both true, ignoring use_vector_fe\n";
102 }
103
104 shared_ptr<Mesh> src_mesh, dest_mesh;
105
106 ifstream imesh;
107
108 imesh.open(destination_mesh_file);
109 if (imesh)
110 {
111 dest_mesh = make_shared<Mesh>(imesh, 1, 1);
112 imesh.close();
113 }
114 else
115 {
116 if (rank == 0)
117 mfem::err << "WARNING: Destination mesh file not found: "
118 << destination_mesh_file << "\n"
119 << "Using default 2D quad mesh.";
120
121 dest_mesh = make_shared<Mesh>(4, 4, Element::QUADRILATERAL);
122 }
123
124 const int dim = dest_mesh->Dimension();
125
126 dest_mesh->Transform(&destination_transform);
127
128 Vector box_min(dim), box_max(dim), range(dim);
129 dest_mesh->GetBoundingBox(box_min, box_max);
130 range = box_max;
131 range -= box_min;
132
133 imesh.open(source_mesh_file);
134
135 if (imesh)
136 {
137 src_mesh = make_shared<Mesh>(imesh, 1, 1);
138 imesh.close();
139 }
140 else
141 {
142 if (rank == 0)
143 mfem::err << "WARNING: Source mesh file not found: " << source_mesh_file
144 << "\n"
145 << "Using default box mesh.\n";
146
147 if (dim == 2)
148 {
149 src_mesh =
150 make_shared<Mesh>(4, 4, Element::TRIANGLE, 1, range[0], range[1]);
151 }
152 else if (dim == 3)
153 {
154 src_mesh = make_shared<Mesh>(4, 4, 4, Element::TETRAHEDRON, 1, range[0],
155 range[1], range[2]);
156 }
157
158 for (int i = 0; i < src_mesh->GetNV(); ++i)
159 {
160 double *v = src_mesh->GetVertex(i);
161
162 for (int d = 0; d < dim; ++d)
163 {
164 v[d] += box_min[d];
165 }
166 }
167 }
168
169 for (int i = 0; i < src_n_refinements; ++i)
170 {
171 src_mesh->UniformRefinement();
172 }
173
174 for (int i = 0; i < dest_n_refinements; ++i)
175 {
176 dest_mesh->UniformRefinement();
177 }
178
179 auto p_src_mesh = make_shared<ParMesh>(MPI_COMM_WORLD, *src_mesh);
180 auto p_dest_mesh = make_shared<ParMesh>(MPI_COMM_WORLD, *dest_mesh);
181
182 shared_ptr<FiniteElementCollection> src_fe_coll, dest_fe_coll;
183
184 if (use_vector_fe)
185 {
186 src_fe_coll =
187 make_shared<RT_FECollection>(source_fe_order, src_mesh->Dimension());
188 dest_fe_coll =
189 make_shared<RT_FECollection>(dest_fe_order, dest_mesh->Dimension());
190 }
191 else
192 {
193
194 if (use_h1)
195 {
196 src_fe_coll =
197 make_shared<H1_FECollection>(source_fe_order, src_mesh->Dimension());
198 dest_fe_coll =
199 make_shared<H1_FECollection>(dest_fe_order, dest_mesh->Dimension());
200 }
201 else
202 {
203 src_fe_coll =
204 make_shared<L2_FECollection>(source_fe_order, src_mesh->Dimension());
205 dest_fe_coll =
206 make_shared<L2_FECollection>(dest_fe_order, dest_mesh->Dimension());
207 }
208 }
209
210 auto src_fe = make_shared<ParFiniteElementSpace>(
211 p_src_mesh.get(), src_fe_coll.get(),
212 use_vector_space ? src_mesh->Dimension() : 1);
213
214 auto dest_fe = make_shared<ParFiniteElementSpace>(
215 p_dest_mesh.get(), dest_fe_coll.get(),
216 use_vector_space ? dest_mesh->Dimension() : 1);
217
218 ParGridFunction src_fun(src_fe.get());
219
220 // To be used with standard fe
222
223 // To be used with vector fe
225
226 if (use_vector_fe || use_vector_space)
227 {
228 src_fun.ProjectCoefficient(vector_coeff);
229 src_fun.Update();
230 }
231 else
232 {
233 src_fun.ProjectCoefficient(coeff);
234 src_fun.Update();
235 }
236
237 ParGridFunction dest_fun(dest_fe.get());
238 dest_fun = 0.0;
239 dest_fun.Update();
240
241 ParMortarAssembler assembler(src_fe, dest_fe);
243 assemble_mass_and_coupling_together);
244 assembler.SetVerbose(verbose);
245
246 if (use_vector_space)
247 {
248 assembler.AddMortarIntegrator(make_shared<LagrangeVectorL2MortarIntegrator>());
249 }
250 else if (use_vector_fe)
251 {
252 assembler.AddMortarIntegrator(make_shared<VectorL2MortarIntegrator>());
253 }
254 else
255 {
256 assembler.AddMortarIntegrator(make_shared<L2MortarIntegrator>());
257 }
258
259 if (assembler.Transfer(src_fun, dest_fun))
260 {
261
262 if (visualization)
263 {
264 double src_err = 0;
265 double dest_err = 0;
266
267 if (use_vector_fe)
268 {
269 src_err = src_fun.ComputeL2Error(vector_coeff);
270 dest_err = dest_fun.ComputeL2Error(vector_coeff);
271 }
272 else
273 {
274 src_err = src_fun.ComputeL2Error(coeff);
275 dest_err = dest_fun.ComputeL2Error(coeff);
276 }
277
278 if (rank == 0)
279 {
280 mfem::out << "l2 error: src: " << src_err << ", dest: " << dest_err
281 << std::endl;
282 }
283
284 plot(*p_src_mesh, src_fun, "source", 0);
285 plot(*p_dest_mesh, dest_fun, "destination", 1);
286 }
287 }
288 else
289 {
290 mfem::out << "No intersection no transfer!" << std::endl;
291 }
292
293 // Finalize transfer library context
295 return MPI_Finalize();
296}
A general function coefficient.
void Parse()
Parse the command-line options. Note that this function expects all the options provided through the ...
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
Class for parallel grid function.
Definition pgridfunc.hpp:50
real_t ComputeL2Error(Coefficient *exsol[], const IntegrationRule *irs[]=NULL, const Array< int > *elems=NULL) const override
Returns ||u_ex - u_h||_L2 in parallel for H1 or L2 elements.
void Update() override
Transform by the Space UpdateMatrix (e.g., on Mesh change).
Definition pgridfunc.cpp:85
This class implements the parallel variational transfer between finite element spaces....
void SetAssembleMassAndCouplingTogether(const bool value)
Control if the Mass matrix is computed together with the coupling operator every time.
bool Transfer(const ParGridFunction &src_fun, ParGridFunction &dest_fun)
transfer a function from source to destination. if the transfer is to be performed multiple times use...
void SetVerbose(const bool verbose)
Expose process details with verbose output.
void AddMortarIntegrator(const std::shared_ptr< MortarIntegrator > &integrator)
This method must be called before Assemble or Transfer. It will assemble the operator in all intersec...
A general vector function coefficient.
Vector data type.
Definition vector.hpp:82
int dim
Definition ex24.cpp:53
void vector_fun(const mfem::Vector &x, mfem::Vector &f)
void plot(mfem::Mesh &mesh, mfem::GridFunction &x, std::string title, const int plot_number=0)
double example_fun(const mfem::Vector &x)
void check_options(mfem::OptionsParser &args)
void destination_transform(const Vector &x, Vector &x_new)
Definition ex1p.cpp:31
int main()
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
OutStream err(std::cerr)
Global stream used by the library for standard error output. Initially it uses the same std::streambu...
Definition globals.hpp:71
void InitTransfer(int argc, char *argv[])
Initializes the par_moonolith library. It also calls MPI_Init.
Definition transfer.cpp:23
int FinalizeTransfer()
Finalize the par_moonolith library.
Definition transfer.cpp:27