MFEM  v4.3.0
Finite element discretization library
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Pages
convergence.cpp
Go to the documentation of this file.
1 #include "convergence.hpp"
2 
3 using namespace std;
4 
5 
6 namespace mfem
7 {
8 
9 void ConvergenceStudy::Reset()
10 {
11  counter=0;
12  dcounter=0;
13  fcounter=0;
14  cont_type=-1;
15  print_flag=1;
16  L2Errors.SetSize(0);
17  L2Rates.SetSize(0);
18  DErrors.SetSize(0);
19  DRates.SetSize(0);
20  EnErrors.SetSize(0);
21  EnRates.SetSize(0);
22  DGFaceErrors.SetSize(0);
23  DGFaceRates.SetSize(0);
24  ndofs.SetSize(0);
25 }
26 
27 double ConvergenceStudy::GetNorm(GridFunction *gf, Coefficient *scalar_u,
28  VectorCoefficient *vector_u)
29 {
30  bool norm_set = false;
31  double norm=0.0;
32  int order = gf->FESpace()->GetMaxElementOrder();
33  int order_quad = std::max(2, 2*order+1);
34  const IntegrationRule *irs[Geometry::NumGeom];
35  for (int i=0; i < Geometry::NumGeom; ++i)
36  {
37  irs[i] = &(IntRules.Get(i, order_quad));
38  }
39 #ifdef MFEM_USE_MPI
40  ParGridFunction *pgf = dynamic_cast<ParGridFunction *>(gf);
41  if (pgf)
42  {
43  ParMesh *pmesh = pgf->ParFESpace()->GetParMesh();
44  if (scalar_u)
45  {
46  norm = ComputeGlobalLpNorm(2.0,*scalar_u,*pmesh,irs);
47  }
48  else if (vector_u)
49  {
50  norm = ComputeGlobalLpNorm(2.0,*vector_u,*pmesh,irs);
51  }
52  norm_set = true;
53  }
54 #endif
55  if (!norm_set)
56  {
57  Mesh *mesh = gf->FESpace()->GetMesh();
58  if (scalar_u)
59  {
60  norm = ComputeLpNorm(2.0,*scalar_u,*mesh,irs);
61  }
62  else if (vector_u)
63  {
64  norm = ComputeLpNorm(2.0,*vector_u,*mesh,irs);
65  }
66  }
67  return norm;
68 }
69 
70 void ConvergenceStudy::AddL2Error(GridFunction *gf,
71  Coefficient *scalar_u, VectorCoefficient *vector_u)
72 {
73  int tdofs=0;
74 #ifdef MFEM_USE_MPI
75  ParGridFunction *pgf = dynamic_cast<ParGridFunction *>(gf);
76  if (pgf)
77  {
78  MPI_Comm comm = pgf->ParFESpace()->GetComm();
79  int rank;
80  MPI_Comm_rank(comm, &rank);
81  print_flag = 0;
82  if (rank==0) { print_flag = 1; }
83  tdofs = pgf->ParFESpace()->GlobalTrueVSize();
84  }
85 #endif
86  if (!tdofs) { tdofs = gf->FESpace()->GetTrueVSize(); }
87  ndofs.Append(tdofs);
88  double L2Err = 1.;
89  if (scalar_u)
90  {
91  L2Err = gf->ComputeL2Error(*scalar_u);
92  CoeffNorm = GetNorm(gf,scalar_u,nullptr);
93  }
94  else if (vector_u)
95  {
96  L2Err = gf->ComputeL2Error(*vector_u);
97  CoeffNorm = GetNorm(gf,nullptr,vector_u);
98  }
99  else
100  {
101  MFEM_ABORT("Exact Solution Coefficient pointer is NULL");
102  }
103  L2Errors.Append(L2Err);
104  // Compute the rate of convergence by:
105  // rate = log (||u - u_h|| / ||u - u_{h/2}||)/log(2)
106  double val = (counter) ? log(L2Errors[counter-1]/L2Err)/log(2.0) : 0.0;
107  L2Rates.Append(val);
108  counter++;
109 }
110 
111 void ConvergenceStudy::AddGf(GridFunction *gf, Coefficient *scalar_u,
112  VectorCoefficient *grad,
113  Coefficient *ell_coeff,
114  JumpScaling jump_scaling)
115 {
116  cont_type = gf->FESpace()->FEColl()->GetContType();
117 
118  MFEM_VERIFY((cont_type == mfem::FiniteElementCollection::CONTINUOUS) ||
120  "This constructor is intended for H1 or L2 Elements")
121 
122  AddL2Error(gf,scalar_u, nullptr);
123 
124  if (grad)
125  {
126  double GradErr = gf->ComputeGradError(grad);
127  DErrors.Append(GradErr);
128  double err = sqrt(L2Errors[counter-1]*L2Errors[counter-1]+GradErr*GradErr);
129  EnErrors.Append(err);
130  // Compute the rate of convergence by:
131  // rate = log (||u - u_h|| / ||u - u_{h/2}||)/log(2)
132  double val = (dcounter) ? log(DErrors[dcounter-1]/GradErr)/log(2.0) : 0.0;
133  double eval = (dcounter) ? log(EnErrors[dcounter-1]/err)/log(2.0) : 0.0;
134  DRates.Append(val);
135  EnRates.Append(eval);
136  CoeffDNorm = GetNorm(gf,nullptr,grad);
137  dcounter++;
138  MFEM_VERIFY(counter == dcounter,
139  "Number of added solutions and derivatives do not match")
140  }
141 
142  if (cont_type == mfem::FiniteElementCollection::DISCONTINUOUS && ell_coeff)
143  {
144  double DGErr = gf->ComputeDGFaceJumpError(scalar_u,ell_coeff,jump_scaling);
145  DGFaceErrors.Append(DGErr);
146  // Compute the rate of convergence by:
147  // rate = log (||u - u_h|| / ||u - u_{h/2}||)/log(2)
148  double val=(fcounter) ? log(DGFaceErrors[fcounter-1]/DGErr)/log(2.0):0.;
149  DGFaceRates.Append(val);
150  fcounter++;
151  MFEM_VERIFY(fcounter == counter, "Number of added solutions mismatch");
152  }
153 }
154 
155 void ConvergenceStudy::AddGf(GridFunction *gf, VectorCoefficient *vector_u,
156  VectorCoefficient *curl, Coefficient *div)
157 {
158  cont_type = gf->FESpace()->FEColl()->GetContType();
159 
160  AddL2Error(gf,nullptr,vector_u);
161  double DErr = 0.0;
162  bool derivative = false;
163  if (curl)
164  {
165  DErr = gf->ComputeCurlError(curl);
166  CoeffDNorm = GetNorm(gf,nullptr,curl);
167  derivative = true;
168  }
169  else if (div)
170  {
171  DErr = gf->ComputeDivError(div);
172  // update coefficient norm
173  CoeffDNorm = GetNorm(gf,div,nullptr);
174  derivative = true;
175  }
176  if (derivative)
177  {
178  double err = sqrt(L2Errors[counter-1]*L2Errors[counter-1] + DErr*DErr);
179  DErrors.Append(DErr);
180  EnErrors.Append(err);
181  // Compute the rate of convergence by:
182  // rate = log (||u - u_h|| / ||u - u_{h/2}||)/log(2)
183  double val = (dcounter) ? log(DErrors[dcounter-1]/DErr)/log(2.0) : 0.0;
184  double eval = (dcounter) ? log(EnErrors[dcounter-1]/err)/log(2.0) : 0.0;
185  DRates.Append(val);
186  EnRates.Append(eval);
187  dcounter++;
188  MFEM_VERIFY(counter == dcounter,
189  "Number of added solutions and derivatives do not match")
190  }
191 }
192 
193 void ConvergenceStudy::Print(bool relative, std::ostream &out)
194 {
195  if (print_flag)
196  {
197  std::string title = (relative) ? "Relative " : "Absolute ";
198  out << "\n";
199  out << " -------------------------------------------" << "\n";
200  out << std::setw(21) << title << "L2 Error " << "\n";
201  out << " -------------------------------------------"
202  << "\n";
203  out << std::right<< std::setw(11)<< "DOFs "<< std::setw(13) << "Error ";
204  out << std::setw(15) << "Rate " << "\n";
205  out << " -------------------------------------------"
206  << "\n";
207  out << std::setprecision(4);
208  double d = (relative) ? CoeffNorm : 1.0;
209  for (int i =0; i<counter; i++)
210  {
211  out << std::right << std::setw(10)<< ndofs[i] << std::setw(16)
212  << std::scientific << L2Errors[i]/d << std::setw(13)
213  << std::fixed << L2Rates[i] << "\n";
214  }
215  out << "\n";
216  if (dcounter == counter)
217  {
218  std::string dname;
219  switch (cont_type)
220  {
221  case 0: dname = "Grad"; break;
222  case 1: dname = "Curl"; break;
223  case 2: dname = "Div"; break;
224  case 3: dname = "DG Grad"; break;
225  default: break;
226  }
227  out << " -------------------------------------------" << "\n";
228  out << std::setw(21) << title << dname << " Error " << "\n";
229  out << " -------------------------------------------" << "\n";
230  out << std::right<<std::setw(11)<< "DOFs "<< std::setw(13) << "Error";
231  out << std::setw(15) << "Rate " << "\n";
232  out << " -------------------------------------------"
233  << "\n";
234  out << std::setprecision(4);
235  d = (relative) ? CoeffDNorm : 1.0;
236  for (int i =0; i<dcounter; i++)
237  {
238  out << std::right << std::setw(10)<< ndofs[i] << std::setw(16)
239  << std::scientific << DErrors[i]/d << std::setw(13)
240  << std::fixed << DRates[i] << "\n";
241  }
242  out << "\n";
243  switch (cont_type)
244  {
245  case 0: dname = "H1"; break;
246  case 1: dname = "H(Curl)"; break;
247  case 2: dname = "H(Div)"; break;
248  case 3: dname = "DG H1"; break;
249  default: break;
250  }
251 
252  if (dcounter)
253  {
254  d = (relative) ?
255  sqrt(CoeffNorm*CoeffNorm + CoeffDNorm*CoeffDNorm):1.0;
256 
257  out << " -------------------------------------------" << "\n";
258  out << std::setw(21) << title << dname << " Error " << "\n";
259  out << " -------------------------------------------" << "\n";
260  out << std::right<< std::setw(11)<< "DOFs "<< std::setw(13);
261  out << "Error ";
262  out << std::setw(15) << "Rate " << "\n";
263  out << " -------------------------------------------"
264  << "\n";
265  out << std::setprecision(4);
266  for (int i =0; i<dcounter; i++)
267  {
268  out << std::right << std::setw(10)<< ndofs[i] << std::setw(16)
269  << std::scientific << EnErrors[i]/d << std::setw(13)
270  << std::fixed << EnRates[i] << "\n";
271  }
272  out << "\n";
273  }
274  }
275  if (cont_type == 3 && fcounter)
276  {
277  out << " -------------------------------------------" << "\n";
278  out << " DG Face Jump Error " << "\n";
279  out << " -------------------------------------------"
280  << "\n";
281  out << std::right<< std::setw(11)<< "DOFs "<< std::setw(13);
282  out << "Error ";
283  out << std::setw(15) << "Rate " << "\n";
284  out << " -------------------------------------------"
285  << "\n";
286  out << std::setprecision(4);
287  for (int i =0; i<fcounter; i++)
288  {
289  out << std::right << std::setw(10)<< ndofs[i] << std::setw(16)
290  << std::scientific << DGFaceErrors[i] << std::setw(13)
291  << std::fixed << DGFaceRates[i] << "\n";
292  }
293  out << "\n";
294  }
295  }
296 }
297 
298 } // namespace mfem
Field is discontinuous across element interfaces.
Definition: fe_coll.hpp:48
Class for an integration rule - an Array of IntegrationPoint.
Definition: intrules.hpp:90
Class for grid function - Vector with associated FE space.
Definition: gridfunc.hpp:30
const IntegrationRule & Get(int GeomType, int Order)
Returns an integration rule for given GeomType and Order.
Definition: intrules.cpp:920
Base class for vector Coefficients that optionally depend on time and space.
double ComputeLpNorm(double p, Coefficient &coeff, Mesh &mesh, const IntegrationRule *irs[])
Compute the Lp norm of a function f. .
Mesh * GetMesh() const
Returns the mesh.
Definition: fespace.hpp:410
int GetMaxElementOrder() const
Return the maximum polynomial order.
Definition: fespace.hpp:428
FiniteElementSpace * FESpace()
Definition: gridfunc.hpp:629
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
Base class Coefficients that optionally depend on space and time. These are used by the BilinearFormI...
Definition: coefficient.hpp:39
Field is continuous across element interfaces.
Definition: fe_coll.hpp:45
double ComputeGlobalLpNorm(double p, Coefficient &coeff, ParMesh &pmesh, const IntegrationRule *irs[])
Compute the global Lp norm of a function f. .
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
IntegrationRules IntRules(0, Quadrature1D::GaussLegendre)
A global object with all integration rules (defined in intrules.cpp)
Definition: intrules.hpp:377