-
Notifications
You must be signed in to change notification settings - Fork 508
/
Copy pathfield-interp.cpp
419 lines (388 loc) · 14.1 KB
/
field-interp.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
// Copyright (c) 2010-2024, Lawrence Livermore National Security, LLC. Produced
// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
// LICENSE and NOTICE for details. LLNL-CODE-806117.
//
// This file is part of the MFEM library. For more information and source code
// availability visit https://mfem.org.
//
// MFEM is free software; you can redistribute it and/or modify it under the
// terms of the BSD-3 license. We welcome feedback and contributions, see file
// CONTRIBUTING.md for details.
//
// -------------------------------------------------------------
// Field Interp Miniapp: Transfer a grid function between meshes
// -------------------------------------------------------------
//
// This miniapp provides the capability to transfer a grid function (H1, L2,
// H(div), and H(curl)) from one mesh onto another using GSLIB-FindPoints. Using
// FindPoints, we identify the nodal positions of the target mesh with respect
// to the source mesh and then interpolate the source grid function. The
// interpolated values are then projected onto the desired finite element space
// on the target mesh. Finally, the transferred solution is visualized using
// GLVis. Note that the source grid function can be a user-defined vector
// function or a grid function file that is compatible with the source mesh.
//
// Compile with: make field-interp
//
// Sample runs:
// field-interp
// field-interp -o 1
// field-interp -fts 3 -ft 0
// field-interp -m1 triple-pt-1.mesh -s1 triple-pt-1.gf -m2 triple-pt-2.mesh -ft 1
// field-interp -m1 triple-pt-1.mesh -m2 triple-pt-2.mesh -ft 1
// field-interp -m2 ../meshing/amr-quad-q2.mesh -ft 0 -r 1 -fts 0
#include "mfem.hpp"
#include <fstream>
using namespace mfem;
using namespace std;
// Scalar function to project
double scalar_func(const Vector &x)
{
const int dim = x.Size();
double res = 0.0;
for (int d = 0; d < dim; d++) { res += x(d) * x(d); }
return res;
}
void vector_func(const Vector &p, Vector &F)
{
F(0) = scalar_func(p);
for (int i = 1; i < F.Size(); i++) { F(i) = (i+1)*pow(-1, i)*F(0); }
}
int main (int argc, char *argv[])
{
// Set the method's default parameters.
const char *src_mesh_file = "../meshing/square01.mesh";
const char *tar_mesh_file = "../../data/inline-tri.mesh";
const char *src_sltn_file = "must_be_provided_by_the_user.gf";
int src_fieldtype = 0;
int src_ncomp = 1;
int src_gf_ordering = 0;
int ref_levels = 0;
int fieldtype = -1;
int order = 3;
bool visualization = true;
int visport = 19916;
// Parse command-line options.
OptionsParser args(argc, argv);
args.AddOption(&src_mesh_file, "-m1", "--mesh1",
"Mesh file for the starting solution.");
args.AddOption(&tar_mesh_file, "-m2", "--mesh2",
"Mesh file for interpolation.");
args.AddOption(&src_sltn_file, "-s1", "--solution1",
"(optional) GridFunction file compatible with src_mesh_file."
"Set src_fieldtype to -1 if this option is used.");
args.AddOption(&src_fieldtype, "-fts", "--field-type-src",
"Source GridFunction type:"
"0 - H1 (default), 1 - L2, 2 - H(div), 3 - H(curl).");
args.AddOption(&src_ncomp, "-nc", "--ncomp",
"Number of components for H1 or L2 GridFunctions.");
args.AddOption(&src_gf_ordering, "-gfo", "--gfo",
"Node ordering: 0 (byNodes) or 1 (byVDim)");
args.AddOption(&ref_levels, "-r", "--refine",
"Number of refinements of the interpolation mesh.");
args.AddOption(&fieldtype, "-ft", "--field-type",
"Target GridFunction type: -1 - source GridFunction type (default),"
"0 - H1, 1 - L2, 2 - H(div), 3 - H(curl).");
args.AddOption(&order, "-o", "--order",
"Order of the interpolated solution.");
args.AddOption(&visualization, "-vis", "--visualization", "-no-vis",
"--no-visualization",
"Enable or disable GLVis visualization.");
args.AddOption(&visport, "-p", "--send-port", "Socket for GLVis.");
args.Parse();
if (!args.Good())
{
args.PrintUsage(cout);
return 1;
}
args.PrintOptions(cout);
// If a gridfunction is specified, set src_fieldtype to -1
if (strcmp(src_sltn_file, "must_be_provided_by_the_user.gf") != 0)
{
src_fieldtype = -1;
}
// Input meshes.
Mesh mesh_1(src_mesh_file, 1, 1, false);
Mesh mesh_2(tar_mesh_file, 1, 1, false);
const int dim = mesh_1.Dimension();
MFEM_ASSERT(dim == mesh_2.Dimension(), "Source and target meshes "
"must be in the same dimension.");
MFEM_VERIFY(dim > 1, "GSLIB requires a 2D or a 3D mesh" );
for (int lev = 0; lev < ref_levels; lev++)
{
mesh_2.UniformRefinement();
}
if (mesh_1.GetNodes() == NULL) { mesh_1.SetCurvature(1); }
if (mesh_2.GetNodes() == NULL) { mesh_2.SetCurvature(1); }
const int mesh_poly_deg =
mesh_2.GetNodes()->FESpace()->GetElementOrder(0);
cout << "Source mesh curvature: "
<< mesh_1.GetNodes()->OwnFEC()->Name() << endl
<< "Target mesh curvature: "
<< mesh_2.GetNodes()->OwnFEC()->Name() << endl;
int src_vdim = src_ncomp;
FiniteElementCollection *src_fec = NULL;
FiniteElementSpace *src_fes = NULL;
GridFunction *func_source = NULL;
if (src_fieldtype < 0) // use src_sltn_file
{
ifstream mat_stream_1(src_sltn_file);
func_source = new GridFunction(&mesh_1, mat_stream_1);
src_vdim = func_source->FESpace()->GetVDim();
src_fes = func_source->FESpace();
}
else if (src_fieldtype == 0)
{
src_fec = new H1_FECollection(order, dim);
}
else if (src_fieldtype == 1)
{
src_fec = new L2_FECollection(order, dim);
}
else if (src_fieldtype == 2)
{
src_fec = new RT_FECollection(order, dim);
src_ncomp = 1;
src_vdim = dim;
}
else if (src_fieldtype == 3)
{
src_fec = new ND_FECollection(order, dim);
src_ncomp = 1;
src_vdim = dim;
}
else
{
MFEM_ABORT("Invalid FECollection type.");
}
if (src_fieldtype > -1)
{
MFEM_VERIFY(src_gf_ordering >= 0 && src_gf_ordering <= 1,
" Source grid function ordering must be 0 (byNodes)"
" or 1 (byVDIM.");
src_fes = new FiniteElementSpace(&mesh_1, src_fec, src_ncomp, src_gf_ordering);
func_source = new GridFunction(src_fes);
// Project the grid function using VectorFunctionCoefficient.
VectorFunctionCoefficient F(src_vdim, vector_func);
func_source->ProjectCoefficient(F);
}
// Display the starting mesh and the field.
if (visualization)
{
char vishost[] = "localhost";
socketstream sout1;
sout1.open(vishost, visport);
if (!sout1)
{
cout << "Unable to connect to GLVis server at "
<< vishost << ':' << visport << endl;
}
else
{
sout1.precision(8);
sout1 << "solution\n" << mesh_1 << *func_source
<< "window_title 'Source mesh and solution'"
<< "window_geometry 0 0 600 600";
if (dim == 2) { sout1 << "keys RmjAc"; }
if (dim == 3) { sout1 << "keys mA\n"; }
sout1 << flush;
}
}
const Geometry::Type gt = mesh_2.GetTypicalElementGeometry();
MFEM_VERIFY(gt != Geometry::PRISM, "Wedge elements are not currently "
"supported.");
MFEM_VERIFY(mesh_2.GetNumGeometries(mesh_2.Dimension()) == 1, "Mixed meshes"
"are not currently supported.");
// Ensure the source grid function can be transferred using GSLIB-FindPoints.
const FiniteElementCollection *fec_in = func_source->FESpace()->FEColl();
std::cout << "Source FE collection: " << fec_in->Name() << std::endl;
if (src_fieldtype < 0)
{
const H1_FECollection *fec_h1 = dynamic_cast<const H1_FECollection *>(fec_in);
const L2_FECollection *fec_l2 = dynamic_cast<const L2_FECollection *>(fec_in);
const RT_FECollection *fec_rt = dynamic_cast<const RT_FECollection *>(fec_in);
const ND_FECollection *fec_nd = dynamic_cast<const ND_FECollection *>(fec_in);
if (fec_h1) { src_fieldtype = 0; }
else if (fec_l2) { src_fieldtype = 1; }
else if (fec_rt) { src_fieldtype = 2; }
else if (fec_nd) { src_fieldtype = 3; }
else { MFEM_ABORT("GridFunction type not supported yet."); }
}
if (fieldtype < 0) { fieldtype = src_fieldtype; }
// Setup the FiniteElementSpace and GridFunction on the target mesh.
FiniteElementCollection *tar_fec = NULL;
FiniteElementSpace *tar_fes = NULL;
int tar_vdim = src_vdim;
if (fieldtype == 0)
{
tar_fec = new H1_FECollection(order, dim);
tar_vdim = (src_fieldtype > 1) ? dim : src_vdim;
}
else if (fieldtype == 1)
{
tar_fec = new L2_FECollection(order, dim);
tar_vdim = (src_fieldtype > 1) ? dim : src_vdim;
}
else if (fieldtype == 2)
{
tar_fec = new RT_FECollection(order, dim);
tar_vdim = 1;
MFEM_VERIFY(src_fieldtype > 1, "Cannot interpolate a scalar "
"grid function to a vector");
}
else if (fieldtype == 3)
{
tar_fec = new ND_FECollection(order, dim);
tar_vdim = 1;
MFEM_VERIFY(src_fieldtype > 1, "Cannot interpolate a scalar "
"grid function to a vector");
}
else
{
MFEM_ABORT("GridFunction type not supported.");
}
std::cout << "Target FE collection: " << tar_fec->Name() << std::endl;
tar_fes = new FiniteElementSpace(&mesh_2, tar_fec, tar_vdim,
src_fes->GetOrdering());
GridFunction func_target(tar_fes);
const int NE = mesh_2.GetNE(),
nsp = tar_fes->GetTypicalFE()->GetNodes().GetNPoints(),
tar_ncomp = func_target.VectorDim();
// Generate list of points where the grid function will be evaluated.
Vector vxyz;
int point_ordering;
if (fieldtype == 0 && order == mesh_poly_deg)
{
vxyz = *mesh_2.GetNodes();
point_ordering = mesh_2.GetNodes()->FESpace()->GetOrdering();
}
else
{
vxyz.SetSize(nsp*NE*dim);
for (int i = 0; i < NE; i++)
{
const FiniteElement *fe = tar_fes->GetFE(i);
const IntegrationRule ir = fe->GetNodes();
ElementTransformation *et = tar_fes->GetElementTransformation(i);
DenseMatrix pos;
et->Transform(ir, pos);
Vector rowx(vxyz.GetData() + i*nsp, nsp),
rowy(vxyz.GetData() + i*nsp + NE*nsp, nsp),
rowz;
if (dim == 3)
{
rowz.SetDataAndSize(vxyz.GetData() + i*nsp + 2*NE*nsp, nsp);
}
pos.GetRow(0, rowx);
pos.GetRow(1, rowy);
if (dim == 3) { pos.GetRow(2, rowz); }
}
point_ordering = Ordering::byNODES;
}
const int nodes_cnt = vxyz.Size() / dim;
// Evaluate source grid function.
Vector interp_vals(nodes_cnt*tar_ncomp);
FindPointsGSLIB finder;
finder.Setup(mesh_1);
finder.Interpolate(vxyz, *func_source, interp_vals, point_ordering);
// Project the interpolated values to the target FiniteElementSpace.
if (fieldtype <= 1) // H1 or L2
{
if ((fieldtype == 0 && order == mesh_poly_deg) || fieldtype == 1)
{
func_target = interp_vals;
}
else // H1 - but mesh order != GridFunction order
{
Array<int> vdofs;
Vector vals;
Vector elem_dof_vals(nsp*tar_ncomp);
for (int i = 0; i < mesh_2.GetNE(); i++)
{
tar_fes->GetElementVDofs(i, vdofs);
vals.SetSize(vdofs.Size());
for (int j = 0; j < nsp; j++)
{
for (int d = 0; d < tar_ncomp; d++)
{
// Arrange values byNodes
int idx = src_fes->GetOrdering() == Ordering::byNODES ?
d*nsp*NE + i*nsp + j : i*nsp*dim + d + j*dim;
elem_dof_vals(j + d*nsp) = interp_vals(idx);
}
}
func_target.SetSubVector(vdofs, elem_dof_vals);
}
}
}
else // H(div) or H(curl)
{
Array<int> vdofs;
Vector vals;
Vector elem_dof_vals(nsp*tar_ncomp);
for (int i = 0; i < mesh_2.GetNE(); i++)
{
tar_fes->GetElementVDofs(i, vdofs);
vals.SetSize(vdofs.Size());
for (int j = 0; j < nsp; j++)
{
for (int d = 0; d < tar_ncomp; d++)
{
// Arrange values byVDim
int idx = src_fes->GetOrdering() == Ordering::byNODES ?
d*nsp*NE + i*nsp + j : i*nsp*dim + d + j*dim;
elem_dof_vals(j*tar_ncomp+d) = interp_vals(idx);
}
}
tar_fes->GetFE(i)->ProjectFromNodes(elem_dof_vals,
*tar_fes->GetElementTransformation(i),
vals);
func_target.SetSubVector(vdofs, vals);
}
}
// Visualize the transferred solution.
if (visualization)
{
char vishost[] = "localhost";
socketstream sout1;
sout1.open(vishost, visport);
if (!sout1)
{
cout << "Unable to connect to GLVis server at "
<< vishost << ':' << visport << endl;
}
else
{
sout1.precision(8);
sout1 << "solution\n" << mesh_2 << func_target
<< "window_title 'Target mesh and solution'"
<< "window_geometry 600 0 600 600";
if (dim == 2) { sout1 << "keys RmjAc"; }
if (dim == 3) { sout1 << "keys mA\n"; }
sout1 << flush;
}
}
// Output the target mesh with the interpolated solution.
ostringstream rho_name;
rho_name << "interpolated.gf";
ofstream rho_ofs(rho_name.str().c_str());
rho_ofs.precision(8);
func_target.Save(rho_ofs);
rho_ofs.close();
// Free the internal gslib data.
finder.FreeData();
// Delete remaining memory.
if (func_source->OwnFEC())
{
delete func_source;
}
else
{
delete func_source;
delete src_fes;
delete src_fec;
}
delete tar_fes;
delete tar_fec;
return 0;
}