MFEM v4.8.0
Finite element discretization library
Loading...
Searching...
No Matches
field-diff.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// Field Diff Miniapp: Compare grid functions on different meshes
14// --------------------------------------------------------------
15//
16// This miniapp compares two different high-order grid functions, defined on two
17// different high-order meshes, based on the GSLIB-FindPoints general off-grid
18// interpolation utility. Using a set of points defined within the bounding box
19// of the domain, FindPoints is used to interpolate the grid functions from the
20// two different meshes and output the difference between the interpolated
21// values. The miniapp also uses FindPoints to interpolate the solution from one
22// mesh onto another, and visualize the difference using GLVis.
23//
24// Compile with: make field-diff
25//
26// Sample runs:
27// field-diff
28// field-diff -m1 triple-pt-1.mesh -s1 triple-pt-1.gf -m2 triple-pt-2.mesh -s2 triple-pt-2.gf -p 200
29
30#include "mfem.hpp"
31#include <fstream>
32
33using namespace mfem;
34using namespace std;
35
36int main (int argc, char *argv[])
37{
38 // Set the method's default parameters.
39 const char *mesh_file_1 = "triple-pt-1.mesh";
40 const char *mesh_file_2 = "triple-pt-2.mesh";
41 const char *sltn_file_1 = "triple-pt-1.gf";
42 const char *sltn_file_2 = "triple-pt-2.gf";
43 bool visualization = true;
44 int pts_cnt_1D = 100;
45 int visport = 19916;
46
47 // Parse command-line options.
48 OptionsParser args(argc, argv);
49 args.AddOption(&mesh_file_1, "-m1", "--mesh1",
50 "Mesh file for solution 1.");
51 args.AddOption(&mesh_file_2, "-m2", "--mesh2",
52 "Mesh file for solution 2.");
53 args.AddOption(&sltn_file_1, "-s1", "--solution1",
54 "Grid function for solution 1.");
55 args.AddOption(&sltn_file_2, "-s2", "--solution2",
56 "Grid function for solution 2.");
57 args.AddOption(&pts_cnt_1D, "-p", "--points1D",
58 "Number of comparison points in one direction");
59 args.AddOption(&visualization, "-vis", "--visualization", "-no-vis",
60 "--no-visualization",
61 "Enable or disable GLVis visualization.");
62 args.AddOption(&visport, "-p", "--send-port", "Socket for GLVis.");
63 args.Parse();
64 if (!args.Good())
65 {
66 args.PrintUsage(cout);
67 return 1;
68 }
69 args.PrintOptions(cout);
70
71 // Input meshes.
72 Mesh mesh_1(mesh_file_1, 1, 1, false);
73 Mesh mesh_2(mesh_file_2, 1, 1, false);
74 const int dim = mesh_1.Dimension();
75 MFEM_VERIFY(dim > 1, "GSLIB requires a 2D or a 3D mesh" );
76
77 // The Nodes GridFunctions for each mesh are required.
78 if (mesh_1.GetNodes() == NULL) { mesh_1.SetCurvature(1, false, dim, 0); }
79 if (mesh_2.GetNodes() == NULL) { mesh_2.SetCurvature(1, false, dim, 0); }
80 const int mesh_poly_deg = mesh_1.GetNodes()->FESpace()->GetElementOrder(0);
81 cout << "Mesh curvature: "
82 << mesh_1.GetNodes()->OwnFEC()->Name() << " " << mesh_poly_deg << endl;
83
84 // The visualization of the difference assumes byNODES ordering.
85 if (mesh_1.GetNodes()->FESpace()->GetOrdering() == Ordering::byVDIM)
86 { mesh_1.SetCurvature(mesh_poly_deg, false, dim, Ordering::byNODES); }
87 if (mesh_2.GetNodes()->FESpace()->GetOrdering() == Ordering::byVDIM)
88 { mesh_2.SetCurvature(mesh_poly_deg, false, dim, Ordering::byNODES); }
89
90 // Mesh bounding box.
91 Vector pos_min, pos_max;
92 MFEM_VERIFY(mesh_poly_deg > 0, "The order of the mesh must be positive.");
93 mesh_1.GetBoundingBox(pos_min, pos_max, mesh_poly_deg);
94 cout << "Generating equidistant points for:\n"
95 << " x in [" << pos_min(0) << ", " << pos_max(0) << "]\n"
96 << " y in [" << pos_min(1) << ", " << pos_max(1) << "]\n";
97 if (dim == 3)
98 {
99 cout << "z in [" << pos_min(2) << ", " << pos_max(2) << "]\n";
100 }
101
102 ifstream mat_stream_1(sltn_file_1), mat_stream_2(sltn_file_2);
103 GridFunction func_1(&mesh_1, mat_stream_1);
104 GridFunction func_2(&mesh_2, mat_stream_2);
105
106 // Display the meshes and the fields through glvis.
107 if (visualization)
108 {
109 char vishost[] = "localhost";
110 socketstream sout1, sout2;
111 sout1.open(vishost, visport);
112 sout2.open(vishost, visport);
113 if (!sout1)
114 {
115 cout << "Unable to connect to GLVis server at "
116 << vishost << ':' << visport << endl;
117 }
118 else
119 {
120 sout1.precision(8);
121 sout1 << "solution\n" << mesh_1 << func_1
122 << "window_title 'Solution 1'"
123 << "window_geometry 0 0 600 600";
124 if (dim == 2) { sout1 << "keys RmjAc"; }
125 if (dim == 3) { sout1 << "keys mA\n"; }
126 sout1 << flush;
127
128 sout2.precision(8);
129 sout2 << "solution\n" << mesh_2 << func_2
130 << "window_title 'Solution 2'"
131 << "window_geometry 600 0 600 600";
132 if (dim == 2) { sout2 << "keys RmjAc"; }
133 if (dim == 3) { sout2 << "keys mA\n"; }
134 sout2 << flush;
135 }
136 }
137
138 // Generate equidistant points in physical coordinates over the whole mesh.
139 // Note that some points might be outside, if the mesh is not a box. Note
140 // also that all tasks search the same points (not mandatory).
141 const int pts_cnt = pow(pts_cnt_1D, dim);
142 Vector vxyz(pts_cnt * dim);
143 if (dim == 2)
144 {
146 const IntegrationRule &ir = el.GetNodes();
147 for (int i = 0; i < ir.GetNPoints(); i++)
148 {
149 const IntegrationPoint &ip = ir.IntPoint(i);
150 vxyz(i) = pos_min(0) + ip.x * (pos_max(0)-pos_min(0));
151 vxyz(pts_cnt + i) = pos_min(1) + ip.y * (pos_max(1)-pos_min(1));
152 }
153 }
154 else
155 {
157 const IntegrationRule &ir = el.GetNodes();
158 for (int i = 0; i < ir.GetNPoints(); i++)
159 {
160 const IntegrationPoint &ip = ir.IntPoint(i);
161 vxyz(i) = pos_min(0) + ip.x * (pos_max(0)-pos_min(0));
162 vxyz(pts_cnt + i) = pos_min(1) + ip.y * (pos_max(1)-pos_min(1));
163 vxyz(2*pts_cnt + i) = pos_min(2) + ip.z * (pos_max(2)-pos_min(2));
164 }
165 }
166
167 FindPointsGSLIB finder1, finder2;
168 Vector interp_vals_1(pts_cnt), interp_vals_2(pts_cnt);
169
170 // First solution.
171 finder1.Interpolate(mesh_1, vxyz, func_1, interp_vals_1);
172
173 // Second solution.
174 finder2.Interpolate(mesh_2, vxyz, func_2, interp_vals_2);
175
176 // Compute differences between the two sets of values.
177 double avg_diff = 0.0, max_diff = 0.0, diff_p;
178 for (int p = 0; p < pts_cnt; p++)
179 {
180 diff_p = fabs(interp_vals_1(p) - interp_vals_2(p));
181 avg_diff += diff_p;
182 if (diff_p > max_diff) { max_diff = diff_p; }
183 }
184 avg_diff /= pts_cnt;
185
186 GridFunction *n1 = mesh_1.GetNodes(), *n2 = mesh_2.GetNodes();
187 double *nd1 = n1->GetData(), *nd2 = n2->GetData();
188 double avg_dist = 0.0;
189 const int node_cnt = n1->Size() / dim;
190 if (n1->Size() == n2->Size())
191 {
192 for (int i = 0; i < node_cnt; i++)
193 {
194 double diff_i = 0.0;
195 for (int d = 0; d < dim; d++)
196 {
197 const int j = i + d * node_cnt;
198 diff_i += (nd1[j] - nd2[j]) * (nd1[j] - nd2[j]);
199 }
200 avg_dist += sqrt(diff_i);
201 }
202 avg_dist /= node_cnt;
203 }
204 else { avg_dist = -1.0; }
205
206 std::cout << "Avg position difference: " << avg_dist << std::endl
207 << "Searched " << pts_cnt << " points.\n"
208 << "Max diff: " << max_diff << std::endl
209 << "Avg diff: " << avg_diff << std::endl;
210
211 // Visualize the difference at the nodes of mesh 1.
212 FiniteElementSpace m1_fes(&mesh_1, mesh_1.GetNodes()->FESpace()->FEColl());
213 GridFunction diff(&m1_fes);
214 GridFunctionCoefficient f1c(&func_1);
216 vxyz = *mesh_1.GetNodes();
217 const int nodes_cnt = vxyz.Size() / dim;
218 interp_vals_2.SetSize(nodes_cnt);
219 finder2.Interpolate(vxyz, func_2, interp_vals_2);
220
221 for (int n = 0; n < nodes_cnt; n++)
222 {
223 diff(n) = fabs(diff(n) - interp_vals_2(n));
224 }
225
226 if (visualization)
227 {
228 char vishost[] = "localhost";
229 socketstream sout3;
230 sout3.open(vishost, visport);
231 sout3.precision(8);
232 sout3 << "solution\n" << mesh_1 << diff
233 << "window_title 'Difference'"
234 << "window_geometry 1200 0 600 600";
235 if (dim == 2) { sout3 << "keys RmjAcpppppppppppppppppppppp"; }
236 if (dim == 3) { sout3 << "keys mA\n"; }
237 sout3 << flush;
238 }
239
240 ConstantCoefficient coeff1(1.0);
241 DomainLFIntegrator *lf_integ = new DomainLFIntegrator(coeff1);
242 LinearForm lf(func_1.FESpace());
243 lf.AddDomainIntegrator(lf_integ);
244 lf.Assemble();
245 const double vol_diff = diff * lf;
246 std::cout << "Vol diff: " << vol_diff << std::endl;
247
248 // Free the internal gslib data.
249 finder1.FreeData();
250 finder2.FreeData();
251
252 return 0;
253}
@ ClosedUniform
Nodes: x_i = i/(n-1), i=0,...,n-1.
Definition fe_base.hpp:39
A coefficient that is constant across space and time.
Class for domain integration .
Definition lininteg.hpp:106
FindPointsGSLIB can robustly evaluate a GridFunction on an arbitrary collection of points.
Definition gslib.hpp:67
virtual void Interpolate(const GridFunction &field_in, Vector &field_out)
Definition gslib.cpp:1721
virtual void FreeData()
Definition gslib.cpp:1128
Class FiniteElementSpace - responsible for providing FEM view of the mesh, mainly managing the set of...
Definition fespace.hpp:244
const IntegrationRule & GetNodes() const
Get a const reference to the nodes of the element.
Definition fe_base.hpp:400
Coefficient defined by a GridFunction. This coefficient is mesh dependent.
Class for grid function - Vector with associated FE space.
Definition gridfunc.hpp:31
FiniteElementSpace * FESpace()
void ProjectDiscCoefficient(VectorCoefficient &coeff, Array< int > &dof_attr)
Class for integration point with weight.
Definition intrules.hpp:35
Class for an integration rule - an Array of IntegrationPoint.
Definition intrules.hpp:100
int GetNPoints() const
Returns the number of the points in the integration rule.
Definition intrules.hpp:256
IntegrationPoint & IntPoint(int i)
Returns a reference to the i-th integration point.
Definition intrules.hpp:259
Arbitrary order L2 elements in 3D on a cube.
Definition fe_l2.hpp:80
Arbitrary order L2 elements in 2D on a square.
Definition fe_l2.hpp:46
Vector with associated FE space and LinearFormIntegrators.
void AddDomainIntegrator(LinearFormIntegrator *lfi)
Adds new Domain Integrator. Assumes ownership of lfi.
void Assemble()
Assembles the linear form i.e. sums over all domain/bdr integrators.
Mesh data type.
Definition mesh.hpp:64
void GetBoundingBox(Vector &min, Vector &max, int ref=2)
Returns the minimum and maximum corners of the mesh bounding box.
Definition mesh.cpp:138
int Dimension() const
Dimension of the reference space used within the elements.
Definition mesh.hpp:1216
void GetNodes(Vector &node_coord) const
Definition mesh.cpp:9294
virtual void SetCurvature(int order, bool discont=false, int space_dim=-1, int ordering=1)
Set the curvature of the mesh nodes using the given polynomial degree.
Definition mesh.cpp:6484
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.
Vector data type.
Definition vector.hpp:82
int Size() const
Returns the size of the vector.
Definition vector.hpp:226
void SetSize(int s)
Resize the vector to size s.
Definition vector.hpp:558
real_t * GetData() const
Return a pointer to the beginning of the Vector data.
Definition vector.hpp:235
int open(const char hostname[], int port)
Open the socket stream on 'port' at 'hostname'.
int dim
Definition ex24.cpp:53
int main()
const char vishost[]
real_t p(const Vector &x, real_t t)