1 // Copyright (c) 2010-2021, 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 #ifndef MFEM_GRIDFUNC
13 #define MFEM_GRIDFUNC
14
15 #include "../config/config.hpp"
16 #include "fespace.hpp"
17 #include "coefficient.hpp"
18 #include "bilininteg.hpp"
19 #ifdef MFEM_USE_ADIOS2
20 #include "../general/adios2stream.hpp"
21 #endif
22 #include <limits>
23 #include <ostream>
24 #include <string>
25
26 namespace mfem
27 {
28
29 /// Class for grid function - Vector with associated FE space.
30 class GridFunction : public Vector
31 {
32 protected:
33 /// FE space on which the grid function lives. Owned if #fec is not NULL.
34 FiniteElementSpace *fes;
35
36 /** @brief Used when the grid function is read from a file. It can also be
37 set explicitly, see MakeOwner().
38
39 If not NULL, this pointer is owned by the GridFunction. */
40 FiniteElementCollection *fec;
41
42 long fes_sequence; // see FiniteElementSpace::sequence, Mesh::sequence
43
44 /** Optional, internal true-dof vector: if the FiniteElementSpace #fes has a
45 non-trivial (i.e. not NULL) prolongation operator, this Vector may hold
46 associated true-dof values - either owned or external. */
47 Vector t_vec;
48
49 void SaveSTLTri(std::ostream &out, double p1[], double p2[], double p3[]);
50
51 void GetVectorGradientHat(ElementTransformation &T, DenseMatrix &gh) const;
52
53 // Project the delta coefficient without scaling and return the (local)
54 // integral of the projection.
55 void ProjectDeltaCoefficient(DeltaCoefficient &delta_coeff,
56 double &integral);
57
58 // Sum fluxes to vertices and count element contributions
59 void SumFluxAndCount(BilinearFormIntegrator &blfi,
60 GridFunction &flux,
61 Array<int>& counts,
62 bool wcoef,
63 int subdomain);
64
65 /** Project a discontinuous vector coefficient in a continuous space and
66 return in dof_attr the maximal attribute of the elements containing each
67 degree of freedom. */
68 void ProjectDiscCoefficient(VectorCoefficient &coeff, Array<int> &dof_attr);
69
70 /// Loading helper.
71 void LegacyNCReorder();
72
73 void Destroy();
74
75 public:
76
GridFunction()77 GridFunction() { fes = NULL; fec = NULL; fes_sequence = 0; UseDevice(true); }
78
79 /// Copy constructor. The internal true-dof vector #t_vec is not copied.
GridFunction(const GridFunction & orig)80 GridFunction(const GridFunction &orig)
81 : Vector(orig), fes(orig.fes), fec(NULL), fes_sequence(orig.fes_sequence)
82 { UseDevice(true); }
83
84 /// Construct a GridFunction associated with the FiniteElementSpace @a *f.
GridFunction(FiniteElementSpace * f)85 GridFunction(FiniteElementSpace *f) : Vector(f->GetVSize())
86 { fes = f; fec = NULL; fes_sequence = f->GetSequence(); UseDevice(true); }
87
88 /// Construct a GridFunction using previously allocated array @a data.
89 /** The GridFunction does not assume ownership of @a data which is assumed to
90 be of size at least `f->GetVSize()`. Similar to the Vector constructor
91 for externally allocated array, the pointer @a data can be NULL. The data
92 array can be replaced later using the method SetData().
93 */
GridFunction(FiniteElementSpace * f,double * data)94 GridFunction(FiniteElementSpace *f, double *data)
95 : Vector(data, f->GetVSize())
96 { fes = f; fec = NULL; fes_sequence = f->GetSequence(); UseDevice(true); }
97
98 /// Construct a GridFunction on the given Mesh, using the data from @a input.
99 /** The content of @a input should be in the format created by the method
100 Save(). The reconstructed FiniteElementSpace and FiniteElementCollection
101 are owned by the GridFunction. */
102 GridFunction(Mesh *m, std::istream &input);
103
104 GridFunction(Mesh *m, GridFunction *gf_array[], int num_pieces);
105
106 /// Copy assignment. Only the data of the base class Vector is copied.
107 /** It is assumed that this object and @a rhs use FiniteElementSpace%s that
108 have the same size.
109
110 @note Defining this method overwrites the implicitly defined copy
111 assignment operator. */
operator =(const GridFunction & rhs)112 GridFunction &operator=(const GridFunction &rhs)
113 { return operator=((const Vector &)rhs); }
114
115 /// Make the GridFunction the owner of #fec and #fes.
116 /** If the new FiniteElementCollection, @a fec_, is NULL, ownership of #fec
117 and #fes is taken away. */
MakeOwner(FiniteElementCollection * fec_)118 void MakeOwner(FiniteElementCollection *fec_) { fec = fec_; }
119
OwnFEC()120 FiniteElementCollection *OwnFEC() { return fec; }
121
122 int VectorDim() const;
123
124 /// Read only access to the (optional) internal true-dof Vector.
125 /** Note that the returned Vector may be empty, if not previously allocated
126 or set. */
GetTrueVector() const127 const Vector &GetTrueVector() const { return t_vec; }
128 /// Read and write access to the (optional) internal true-dof Vector.
129 /** Note that the returned Vector may be empty, if not previously allocated
130 or set. */
GetTrueVector()131 Vector &GetTrueVector() { return t_vec; }
132
133 /// Extract the true-dofs from the GridFunction.
134 void GetTrueDofs(Vector &tv) const;
135
136 /// Shortcut for calling GetTrueDofs() with GetTrueVector() as argument.
SetTrueVector()137 void SetTrueVector() { GetTrueDofs(GetTrueVector()); }
138
139 /// Set the GridFunction from the given true-dof vector.
140 virtual void SetFromTrueDofs(const Vector &tv);
141
142 /// Shortcut for calling SetFromTrueDofs() with GetTrueVector() as argument.
SetFromTrueVector()143 void SetFromTrueVector() { SetFromTrueDofs(GetTrueVector()); }
144
145 /// Returns the values in the vertices of i'th element for dimension vdim.
146 void GetNodalValues(int i, Array<double> &nval, int vdim = 1) const;
147
148 /** @name Element index Get Value Methods
149
150 These methods take an element index and return the interpolated value of
151 the field at a given reference point within the element.
152
153 @warning These methods retrieve and use the ElementTransformation object
154 from the mfem::Mesh. This can alter the state of the element
155 transformation object and can also lead to unexpected results when the
156 ElementTransformation object is already in use such as when these methods
157 are called from within an integration loop. Consider using
158 GetValue(ElementTransformation &T, ...) instead.
159 */
160 ///@{
161 /** Return a scalar value from within the given element. */
162 virtual double GetValue(int i, const IntegrationPoint &ip,
163 int vdim = 1) const;
164
165 /** Return a vector value from within the given element. */
166 virtual void GetVectorValue(int i, const IntegrationPoint &ip,
167 Vector &val) const;
168 ///@}
169
170 /** @name Element Index Get Values Methods
171
172 These are convenience methods for repeatedly calling GetValue for
173 multiple points within a given element. The GetValues methods are
174 optimized and should perform better than repeatedly calling GetValue. The
175 GetVectorValues method simply calls GetVectorValue repeatedly.
176
177 @warning These methods retrieve and use the ElementTransformation object
178 from the mfem::Mesh. This can alter the state of the element
179 transformation object and can also lead to unexpected results when the
180 ElementTransformation object is already in use such as when these methods
181 are called from within an integration loop. Consider using
182 GetValues(ElementTransformation &T, ...) instead.
183 */
184 ///@{
185 /** Compute a collection of scalar values from within the element indicated
186 by the index i. */
187 void GetValues(int i, const IntegrationRule &ir, Vector &vals,
188 int vdim = 1) const;
189
190 /** Compute a collection of vector values from within the element indicated
191 by the index i. */
192 void GetValues(int i, const IntegrationRule &ir, Vector &vals,
193 DenseMatrix &tr, int vdim = 1) const;
194
195 void GetVectorValues(int i, const IntegrationRule &ir,
196 DenseMatrix &vals, DenseMatrix &tr) const;
197 ///@}
198
199 /** @name ElementTransformation Get Value Methods
200
201 These member functions are designed for use within
202 GridFunctionCoefficient objects. These can be used with
203 ElementTransformation objects coming from either
204 Mesh::GetElementTransformation() or Mesh::GetBdrElementTransformation().
205
206 @note These methods do not reset the ElementTransformation object so they
207 should be safe to use within integration loops or other contexts where
208 the ElementTransformation is already in use.
209 */
210 ///@{
211 /** Return a scalar value from within the element indicated by the
212 ElementTransformation Object. */
213 virtual double GetValue(ElementTransformation &T, const IntegrationPoint &ip,
214 int comp = 0, Vector *tr = NULL) const;
215
216 /** Return a vector value from within the element indicated by the
217 ElementTransformation Object. */
218 virtual void GetVectorValue(ElementTransformation &T,
219 const IntegrationPoint &ip,
220 Vector &val, Vector *tr = NULL) const;
221 ///@}
222
223 /** @name ElementTransformation Get Values Methods
224
225 These are convenience methods for repeatedly calling GetValue for
226 multiple points within a given element. They work by calling either the
227 ElementTransformation or FaceElementTransformations versions described
228 above. Consequently, these methods should not be expected to run faster
229 than calling the above methods in an external loop.
230
231 @note These methods do not reset the ElementTransformation object so they
232 should be safe to use within integration loops or other contexts where
233 the ElementTransformation is already in use.
234
235 @note These methods can also be used with FaceElementTransformations
236 objects.
237 */
238 ///@{
239 /** Compute a collection of scalar values from within the element indicated
240 by the ElementTransformation object. */
241 void GetValues(ElementTransformation &T, const IntegrationRule &ir,
242 Vector &vals, int comp = 0, DenseMatrix *tr = NULL) const;
243
244 /** Compute a collection of vector values from within the element indicated
245 by the ElementTransformation object. */
246 void GetVectorValues(ElementTransformation &T, const IntegrationRule &ir,
247 DenseMatrix &vals, DenseMatrix *tr = NULL) const;
248 ///@}
249
250 /** @name Face Index Get Values Methods
251
252 These methods are designed to work with Discontinuous Galerkin basis
253 functions. They compute field values on the interface between elements,
254 or on boundary elements, by interpolating the field in a neighboring
255 element. The \a side argument indices which neighboring element should be
256 used: 0, 1, or 2 (automatically chosen).
257
258 @warning These methods retrieve and use the FaceElementTransformations
259 object from the mfem::Mesh. This can alter the state of the face element
260 transformations object and can also lead to unexpected results when the
261 FaceElementTransformations object is already in use such as when these
262 methods are called from within an integration loop. Consider using
263 GetValues(ElementTransformation &T, ...) instead.
264 */
265 ///@{
266 /** Compute a collection of scalar values from within the face
267 indicated by the index i. */
268 int GetFaceValues(int i, int side, const IntegrationRule &ir, Vector &vals,
269 DenseMatrix &tr, int vdim = 1) const;
270
271 /** Compute a collection of vector values from within the face
272 indicated by the index i. */
273 int GetFaceVectorValues(int i, int side, const IntegrationRule &ir,
274 DenseMatrix &vals, DenseMatrix &tr) const;
275 ///@}
276
277 void GetLaplacians(int i, const IntegrationRule &ir, Vector &laps,
278 int vdim = 1) const;
279
280 void GetLaplacians(int i, const IntegrationRule &ir, Vector &laps,
281 DenseMatrix &tr, int vdim = 1) const;
282
283 void GetHessians(int i, const IntegrationRule &ir, DenseMatrix &hess,
284 int vdim = 1) const;
285
286 void GetHessians(int i, const IntegrationRule &ir, DenseMatrix &hess,
287 DenseMatrix &tr, int vdim = 1) const;
288
289 void GetValuesFrom(const GridFunction &orig_func);
290
291 void GetBdrValuesFrom(const GridFunction &orig_func);
292
293 void GetVectorFieldValues(int i, const IntegrationRule &ir,
294 DenseMatrix &vals,
295 DenseMatrix &tr, int comp = 0) const;
296
297 /// For a vector grid function, makes sure that the ordering is byNODES.
298 void ReorderByNodes();
299
300 /// Return the values as a vector on mesh vertices for dimension vdim.
301 void GetNodalValues(Vector &nval, int vdim = 1) const;
302
303 void GetVectorFieldNodalValues(Vector &val, int comp) const;
304
305 void ProjectVectorFieldOn(GridFunction &vec_field, int comp = 0);
306
307 void GetDerivative(int comp, int der_comp, GridFunction &der);
308
309 double GetDivergence(ElementTransformation &tr) const;
310
311 void GetCurl(ElementTransformation &tr, Vector &curl) const;
312
313 void GetGradient(ElementTransformation &tr, Vector &grad) const;
314
315 void GetGradients(ElementTransformation &tr, const IntegrationRule &ir,
316 DenseMatrix &grad) const;
317
GetGradients(const int elem,const IntegrationRule & ir,DenseMatrix & grad) const318 void GetGradients(const int elem, const IntegrationRule &ir,
319 DenseMatrix &grad) const
320 { GetGradients(*fes->GetElementTransformation(elem), ir, grad); }
321
322 void GetVectorGradient(ElementTransformation &tr, DenseMatrix &grad) const;
323
324 /** Compute \f$ (\int_{\Omega} (*this) \psi_i)/(\int_{\Omega} \psi_i) \f$,
325 where \f$ \psi_i \f$ are the basis functions for the FE space of avgs.
326 Both FE spaces should be scalar and on the same mesh. */
327 void GetElementAverages(GridFunction &avgs) const;
328
329 /** Sets the output vector @a dof_vals to the values of the degrees of
330 freedom of element @a el. */
331 virtual void GetElementDofValues(int el, Vector &dof_vals) const;
332
333 /** Impose the given bounds on the function's DOFs while preserving its local
334 * integral (described in terms of the given weights) on the i'th element
335 * through SLBPQ optimization.
336 * Intended to be used for discontinuous FE functions. */
337 void ImposeBounds(int i, const Vector &weights,
338 const Vector &lo_, const Vector &hi_);
339 void ImposeBounds(int i, const Vector &weights,
340 double min_ = 0.0, double max_ = infinity());
341
342 /** On a non-conforming mesh, make sure the function lies in the conforming
343 space by multiplying with R and then with P, the conforming restriction
344 and prolongation matrices of the space, respectively. */
345 void RestrictConforming();
346
347 /** @brief Project the @a src GridFunction to @a this GridFunction, both of
348 which must be on the same mesh. */
349 /** The current implementation assumes that all elements use the same
350 projection matrix. */
351 void ProjectGridFunction(const GridFunction &src);
352
353 /** @brief Project @a coeff Coefficient to @a this GridFunction. The
354 projection computation depends on the choice of the FiniteElementSpace
355 #fes. Note that this is usually interpolation at the degrees of freedom
356 in each element (not L2 projection). */
357 virtual void ProjectCoefficient(Coefficient &coeff);
358
359 /** @brief Project @a coeff Coefficient to @a this GridFunction, using one
360 element for each degree of freedom in @a dofs and nodal interpolation on
361 that element. */
362 void ProjectCoefficient(Coefficient &coeff, Array<int> &dofs, int vd = 0);
363
364 /** @brief Project @a vcoeff VectorCoefficient to @a this GridFunction. The
365 projection computation depends on the choice of the FiniteElementSpace
366 #fes. Note that this is usually interpolation at the degrees of freedom
367 in each element (not L2 projection).*/
368 void ProjectCoefficient(VectorCoefficient &vcoeff);
369
370 /** @brief Project @a vcoeff VectorCoefficient to @a this GridFunction, using
371 one element for each degree of freedom in @a dofs and nodal interpolation
372 on that element. */
373 void ProjectCoefficient(VectorCoefficient &vcoeff, Array<int> &dofs);
374
375 /** @brief Project @a vcoeff VectorCoefficient to @a this GridFunction, only
376 projecting onto elements with the given @a attribute */
377 void ProjectCoefficient(VectorCoefficient &vcoeff, int attribute);
378
379 /** @brief Analogous to the version with argument @a vcoeff VectorCoefficient
380 but using an array of scalar coefficients for each component. */
381 void ProjectCoefficient(Coefficient *coeff[]);
382
383 /** @brief Project a discontinuous vector coefficient as a grid function on
384 a continuous finite element space. The values in shared dofs are
385 determined from the element with maximal attribute. */
386 virtual void ProjectDiscCoefficient(VectorCoefficient &coeff);
387
388 enum AvgType {ARITHMETIC, HARMONIC};
389 /** @brief Projects a discontinuous coefficient so that the values in shared
390 vdofs are computed by taking an average of the possible values. */
391 virtual void ProjectDiscCoefficient(Coefficient &coeff, AvgType type);
392 /** @brief Projects a discontinuous _vector_ coefficient so that the values
393 in shared vdofs are computed by taking an average of the possible values.
394 */
395 virtual void ProjectDiscCoefficient(VectorCoefficient &coeff, AvgType type);
396
397 protected:
398 /** @brief Accumulates (depending on @a type) the values of @a coeff at all
399 shared vdofs and counts in how many zones each vdof appears. */
400 void AccumulateAndCountZones(Coefficient &coeff, AvgType type,
401 Array<int> &zones_per_vdof);
402
403 /** @brief Accumulates (depending on @a type) the values of @a vcoeff at all
404 shared vdofs and counts in how many zones each vdof appears. */
405 void AccumulateAndCountZones(VectorCoefficient &vcoeff, AvgType type,
406 Array<int> &zones_per_vdof);
407
408 void AccumulateAndCountBdrValues(Coefficient *coeff[],
409 VectorCoefficient *vcoeff, Array<int> &attr,
410 Array<int> &values_counter);
411
412 void AccumulateAndCountBdrTangentValues(VectorCoefficient &vcoeff,
413 Array<int> &bdr_attr,
414 Array<int> &values_counter);
415
416 // Complete the computation of averages; called e.g. after
417 // AccumulateAndCountZones().
418 void ComputeMeans(AvgType type, Array<int> &zones_per_vdof);
419
420 public:
421 /** @brief Project a Coefficient on the GridFunction, modifying only DOFs on
422 the boundary associated with the boundary attributes marked in the
423 @a attr array. */
ProjectBdrCoefficient(Coefficient & coeff,Array<int> & attr)424 void ProjectBdrCoefficient(Coefficient &coeff, Array<int> &attr)
425 {
426 Coefficient *coeff_p = &coeff;
427 ProjectBdrCoefficient(&coeff_p, attr);
428 }
429
430 /** @brief Project a VectorCoefficient on the GridFunction, modifying only
431 DOFs on the boundary associated with the boundary attributes marked in
432 the @a attr array. */
433 virtual void ProjectBdrCoefficient(VectorCoefficient &vcoeff,
434 Array<int> &attr);
435
436 /** @brief Project a set of Coefficient%s on the components of the
437 GridFunction, modifying only DOFs on the boundary associated with the
438 boundary attributed marked in the @a attr array. */
439 /** If a Coefficient pointer in the array @a coeff is NULL, that component
440 will not be touched. */
441 virtual void ProjectBdrCoefficient(Coefficient *coeff[], Array<int> &attr);
442
443 /** Project the normal component of the given VectorCoefficient on
444 the boundary. Only boundary attributes that are marked in
445 'bdr_attr' are projected. Assumes RT-type VectorFE GridFunction. */
446 void ProjectBdrCoefficientNormal(VectorCoefficient &vcoeff,
447 Array<int> &bdr_attr);
448
449 /** @brief Project the tangential components of the given VectorCoefficient
450 on the boundary. Only boundary attributes that are marked in @a bdr_attr
451 are projected. Assumes ND-type VectorFE GridFunction. */
452 virtual void ProjectBdrCoefficientTangent(VectorCoefficient &vcoeff,
453 Array<int> &bdr_attr);
454
455
ComputeL2Error(Coefficient & exsol,const IntegrationRule * irs[]=NULL) const456 virtual double ComputeL2Error(Coefficient &exsol,
457 const IntegrationRule *irs[] = NULL) const
458 { return ComputeLpError(2.0, exsol, NULL, irs); }
459
460 virtual double ComputeL2Error(Coefficient *exsol[],
461 const IntegrationRule *irs[] = NULL) const;
462
463 virtual double ComputeL2Error(VectorCoefficient &exsol,
464 const IntegrationRule *irs[] = NULL,
465 Array<int> *elems = NULL) const;
466
467 /// Returns ||grad u_ex - grad u_h||_L2 for H1 or L2 elements
468 virtual double ComputeGradError(VectorCoefficient *exgrad,
469 const IntegrationRule *irs[] = NULL) const;
470
471 /// Returns ||curl u_ex - curl u_h||_L2 for ND elements
472 virtual double ComputeCurlError(VectorCoefficient *excurl,
473 const IntegrationRule *irs[] = NULL) const;
474
475 /// Returns ||div u_ex - div u_h||_L2 for RT elements
476 virtual double ComputeDivError(Coefficient *exdiv,
477 const IntegrationRule *irs[] = NULL) const;
478
479 /// Returns the Face Jumps error for L2 elements. The error can be weighted
480 /// by a constant nu, by nu/h, or nu*p^2/h, depending on the value of
481 /// @a jump_scaling.
482 virtual double ComputeDGFaceJumpError(Coefficient *exsol,
483 Coefficient *ell_coeff,
484 class JumpScaling jump_scaling,
485 const IntegrationRule *irs[] = NULL)
486 const;
487
488 /// Returns the Face Jumps error for L2 elements, with 1/h scaling.
489 MFEM_DEPRECATED
490 double ComputeDGFaceJumpError(Coefficient *exsol,
491 Coefficient *ell_coeff,
492 double Nu,
493 const IntegrationRule *irs[] = NULL) const;
494
495 /** This method is kept for backward compatibility.
496
497 Returns either the H1-seminorm, or the DG face jumps error, or both
498 depending on norm_type = 1, 2, 3. Additional arguments for the DG face
499 jumps norm: ell_coeff: mesh-depended coefficient (weight) Nu: scalar
500 constant weight */
501 virtual double ComputeH1Error(Coefficient *exsol, VectorCoefficient *exgrad,
502 Coefficient *ell_coef, double Nu,
503 int norm_type) const;
504
505 /// Returns the error measured in H1-norm for H1 elements or in "broken"
506 /// H1-norm for L2 elements
507 virtual double ComputeH1Error(Coefficient *exsol, VectorCoefficient *exgrad,
508 const IntegrationRule *irs[] = NULL) const;
509
510 /// Returns the error measured in H(div)-norm for RT elements
511 virtual double ComputeHDivError(VectorCoefficient *exsol,
512 Coefficient *exdiv,
513 const IntegrationRule *irs[] = NULL) const;
514
515 /// Returns the error measured in H(curl)-norm for ND elements
516 virtual double ComputeHCurlError(VectorCoefficient *exsol,
517 VectorCoefficient *excurl,
518 const IntegrationRule *irs[] = NULL) const;
519
ComputeMaxError(Coefficient & exsol,const IntegrationRule * irs[]=NULL) const520 virtual double ComputeMaxError(Coefficient &exsol,
521 const IntegrationRule *irs[] = NULL) const
522 {
523 return ComputeLpError(infinity(), exsol, NULL, irs);
524 }
525
526 virtual double ComputeMaxError(Coefficient *exsol[],
527 const IntegrationRule *irs[] = NULL) const;
528
ComputeMaxError(VectorCoefficient & exsol,const IntegrationRule * irs[]=NULL) const529 virtual double ComputeMaxError(VectorCoefficient &exsol,
530 const IntegrationRule *irs[] = NULL) const
531 {
532 return ComputeLpError(infinity(), exsol, NULL, NULL, irs);
533 }
534
ComputeL1Error(Coefficient & exsol,const IntegrationRule * irs[]=NULL) const535 virtual double ComputeL1Error(Coefficient &exsol,
536 const IntegrationRule *irs[] = NULL) const
537 { return ComputeLpError(1.0, exsol, NULL, irs); }
538
539 virtual double ComputeW11Error(Coefficient *exsol, VectorCoefficient *exgrad,
540 int norm_type, Array<int> *elems = NULL,
541 const IntegrationRule *irs[] = NULL) const;
542
ComputeL1Error(VectorCoefficient & exsol,const IntegrationRule * irs[]=NULL) const543 virtual double ComputeL1Error(VectorCoefficient &exsol,
544 const IntegrationRule *irs[] = NULL) const
545 { return ComputeLpError(1.0, exsol, NULL, NULL, irs); }
546
547 virtual double ComputeLpError(const double p, Coefficient &exsol,
548 Coefficient *weight = NULL,
549 const IntegrationRule *irs[] = NULL) const;
550
551 /** Compute the Lp error in each element of the mesh and store the results in
552 the Vector @a error. The result should be of length number of elements,
553 for example an L2 GridFunction of order zero using map type VALUE. */
554 virtual void ComputeElementLpErrors(const double p, Coefficient &exsol,
555 Vector &error,
556 Coefficient *weight = NULL,
557 const IntegrationRule *irs[] = NULL
558 ) const;
559
ComputeElementL1Errors(Coefficient & exsol,Vector & error,const IntegrationRule * irs[]=NULL) const560 virtual void ComputeElementL1Errors(Coefficient &exsol,
561 Vector &error,
562 const IntegrationRule *irs[] = NULL
563 ) const
564 { ComputeElementLpErrors(1.0, exsol, error, NULL, irs); }
565
ComputeElementL2Errors(Coefficient & exsol,Vector & error,const IntegrationRule * irs[]=NULL) const566 virtual void ComputeElementL2Errors(Coefficient &exsol,
567 Vector &error,
568 const IntegrationRule *irs[] = NULL
569 ) const
570 { ComputeElementLpErrors(2.0, exsol, error, NULL, irs); }
571
ComputeElementMaxErrors(Coefficient & exsol,Vector & error,const IntegrationRule * irs[]=NULL) const572 virtual void ComputeElementMaxErrors(Coefficient &exsol,
573 Vector &error,
574 const IntegrationRule *irs[] = NULL
575 ) const
576 { ComputeElementLpErrors(infinity(), exsol, error, NULL, irs); }
577
578 /** When given a vector weight, compute the pointwise (scalar) error as the
579 dot product of the vector error with the vector weight. Otherwise, the
580 scalar error is the l_2 norm of the vector error. */
581 virtual double ComputeLpError(const double p, VectorCoefficient &exsol,
582 Coefficient *weight = NULL,
583 VectorCoefficient *v_weight = NULL,
584 const IntegrationRule *irs[] = NULL) const;
585
586 /** Compute the Lp error in each element of the mesh and store the results in
587 the Vector @ error. The result should be of length number of elements,
588 for example an L2 GridFunction of order zero using map type VALUE. */
589 virtual void ComputeElementLpErrors(const double p, VectorCoefficient &exsol,
590 Vector &error,
591 Coefficient *weight = NULL,
592 VectorCoefficient *v_weight = NULL,
593 const IntegrationRule *irs[] = NULL
594 ) const;
595
ComputeElementL1Errors(VectorCoefficient & exsol,Vector & error,const IntegrationRule * irs[]=NULL) const596 virtual void ComputeElementL1Errors(VectorCoefficient &exsol,
597 Vector &error,
598 const IntegrationRule *irs[] = NULL
599 ) const
600 { ComputeElementLpErrors(1.0, exsol, error, NULL, NULL, irs); }
601
ComputeElementL2Errors(VectorCoefficient & exsol,Vector & error,const IntegrationRule * irs[]=NULL) const602 virtual void ComputeElementL2Errors(VectorCoefficient &exsol,
603 Vector &error,
604 const IntegrationRule *irs[] = NULL
605 ) const
606 { ComputeElementLpErrors(2.0, exsol, error, NULL, NULL, irs); }
607
ComputeElementMaxErrors(VectorCoefficient & exsol,Vector & error,const IntegrationRule * irs[]=NULL) const608 virtual void ComputeElementMaxErrors(VectorCoefficient &exsol,
609 Vector &error,
610 const IntegrationRule *irs[] = NULL
611 ) const
612 { ComputeElementLpErrors(infinity(), exsol, error, NULL, NULL, irs); }
613
614 virtual void ComputeFlux(BilinearFormIntegrator &blfi,
615 GridFunction &flux,
616 bool wcoef = true, int subdomain = -1);
617
618 /// Redefine '=' for GridFunction = constant.
619 GridFunction &operator=(double value);
620
621 /// Copy the data from @a v.
622 /** The size of @a v must be equal to the size of the associated
623 FiniteElementSpace #fes. */
624 GridFunction &operator=(const Vector &v);
625
626 /// Transform by the Space UpdateMatrix (e.g., on Mesh change).
627 virtual void Update();
628
FESpace()629 FiniteElementSpace *FESpace() { return fes; }
FESpace() const630 const FiniteElementSpace *FESpace() const { return fes; }
631
632 /// Associate a new FiniteElementSpace with the GridFunction.
633 /** The GridFunction is resized using the SetSize() method. */
634 virtual void SetSpace(FiniteElementSpace *f);
635
636 using Vector::MakeRef;
637
638 /** @brief Make the GridFunction reference external data on a new
639 FiniteElementSpace. */
640 /** This method changes the FiniteElementSpace associated with the
641 GridFunction and sets the pointer @a v as external data in the
642 GridFunction. */
643 virtual void MakeRef(FiniteElementSpace *f, double *v);
644
645 /** @brief Make the GridFunction reference external data on a new
646 FiniteElementSpace. */
647 /** This method changes the FiniteElementSpace associated with the
648 GridFunction and sets the data of the Vector @a v (plus the @a v_offset)
649 as external data in the GridFunction.
650 @note This version of the method will also perform bounds checks when
651 the build option MFEM_DEBUG is enabled. */
652 virtual void MakeRef(FiniteElementSpace *f, Vector &v, int v_offset);
653
654 /** @brief Associate a new FiniteElementSpace and new true-dof data with the
655 GridFunction. */
656 /** - If the prolongation matrix of @a f is trivial (i.e. its method
657 FiniteElementSpace::GetProlongationMatrix() returns NULL), then the
658 method MakeRef() is called with the same arguments.
659 - Otherwise, the method SetSpace() is called with argument @a f.
660 - The internal true-dof vector is set to reference @a tv. */
661 void MakeTRef(FiniteElementSpace *f, double *tv);
662
663 /** @brief Associate a new FiniteElementSpace and new true-dof data with the
664 GridFunction. */
665 /** - If the prolongation matrix of @a f is trivial (i.e. its method
666 FiniteElementSpace::GetProlongationMatrix() returns NULL), this method
667 calls MakeRef() with the same arguments.
668 - Otherwise, this method calls SetSpace() with argument @a f.
669 - The internal true-dof vector is set to reference the sub-vector of
670 @a tv starting at the offset @a tv_offset. */
671 void MakeTRef(FiniteElementSpace *f, Vector &tv, int tv_offset);
672
673 /// Save the GridFunction to an output stream.
674 virtual void Save(std::ostream &out) const;
675
676 /// Save the GridFunction to a file. The given @a precision will be used for
677 /// ASCII output.
678 virtual void Save(const char *fname, int precision=16) const;
679
680 #ifdef MFEM_USE_ADIOS2
681 /// Save the GridFunction to a binary output stream using adios2 bp format.
682 virtual void Save(adios2stream &out, const std::string& variable_name,
683 const adios2stream::data_type
684 type = adios2stream::data_type::point_data) const;
685 #endif
686
687 /** @brief Write the GridFunction in VTK format. Note that Mesh::PrintVTK
688 must be called first. The parameter ref > 0 must match the one used in
689 Mesh::PrintVTK. */
690 void SaveVTK(std::ostream &out, const std::string &field_name, int ref);
691
692 /** @brief Write the GridFunction in STL format. Note that the mesh dimension
693 must be 2 and that quad elements will be broken into two triangles.*/
694 void SaveSTL(std::ostream &out, int TimesToRefine = 1);
695
696 /// Destroys grid function.
~GridFunction()697 virtual ~GridFunction() { Destroy(); }
698 };
699
700
701 /** Overload operator<< for std::ostream and GridFunction; valid also for the
702 derived class ParGridFunction */
703 std::ostream &operator<<(std::ostream &out, const GridFunction &sol);
704
705 /// Class used to specify how the jump terms in
706 /// GridFunction::ComputeDGFaceJumpError are scaled.
707 class JumpScaling
708 {
709 public:
710 enum JumpScalingType
711 {
712 CONSTANT,
713 ONE_OVER_H,
714 P_SQUARED_OVER_H
715 };
716 private:
717 double nu;
718 JumpScalingType type;
719 public:
JumpScaling(double nu_=1.0,JumpScalingType type_=CONSTANT)720 JumpScaling(double nu_=1.0, JumpScalingType type_=CONSTANT)
721 : nu(nu_), type(type_) { }
Eval(double h,int p) const722 double Eval(double h, int p) const
723 {
724 double val = nu;
725 if (type != CONSTANT) { val /= h; }
726 if (type == P_SQUARED_OVER_H) { val *= p*p; }
727 return val;
728 }
729 };
730
731
732 /** @brief Class representing a function through its values (scalar or vector)
733 at quadrature points. */
734 class QuadratureFunction : public Vector
735 {
736 protected:
737 QuadratureSpace *qspace; ///< Associated QuadratureSpace
738 int vdim; ///< Vector dimension
739 bool own_qspace; ///< QuadratureSpace ownership flag
740
741 public:
742 /// Create an empty QuadratureFunction.
743 /** The object can be initialized later using the SetSpace() methods. */
QuadratureFunction()744 QuadratureFunction()
745 : qspace(NULL), vdim(0), own_qspace(false) { }
746
747 /** @brief Copy constructor. The QuadratureSpace ownership flag, #own_qspace,
748 in the new object is set to false. */
QuadratureFunction(const QuadratureFunction & orig)749 QuadratureFunction(const QuadratureFunction &orig)
750 : Vector(orig),
751 qspace(orig.qspace), vdim(orig.vdim), own_qspace(false) { }
752
753 /// Create a QuadratureFunction based on the given QuadratureSpace.
754 /** The QuadratureFunction does not assume ownership of the QuadratureSpace.
755 @note The Vector data is not initialized. */
QuadratureFunction(QuadratureSpace * qspace_,int vdim_=1)756 QuadratureFunction(QuadratureSpace *qspace_, int vdim_ = 1)
757 : Vector(vdim_*qspace_->GetSize()),
758 qspace(qspace_), vdim(vdim_), own_qspace(false) { }
759
760 /** @brief Create a QuadratureFunction based on the given QuadratureSpace,
761 using the external data, @a qf_data. */
762 /** The QuadratureFunction does not assume ownership of neither the
763 QuadratureSpace nor the external data. */
QuadratureFunction(QuadratureSpace * qspace_,double * qf_data,int vdim_=1)764 QuadratureFunction(QuadratureSpace *qspace_, double *qf_data, int vdim_ = 1)
765 : Vector(qf_data, vdim_*qspace_->GetSize()),
766 qspace(qspace_), vdim(vdim_), own_qspace(false) { }
767
768 /// Read a QuadratureFunction from the stream @a in.
769 /** The QuadratureFunction assumes ownership of the read QuadratureSpace. */
770 QuadratureFunction(Mesh *mesh, std::istream &in);
771
~QuadratureFunction()772 virtual ~QuadratureFunction() { if (own_qspace) { delete qspace; } }
773
774 /// Get the associated QuadratureSpace.
GetSpace() const775 QuadratureSpace *GetSpace() const { return qspace; }
776
777 /// Change the QuadratureSpace and optionally the vector dimension.
778 /** If the new QuadratureSpace is different from the current one, the
779 QuadratureFunction will not assume ownership of the new space; otherwise,
780 the ownership flag remains the same.
781
782 If the new vector dimension @a vdim_ < 0, the vector dimension remains
783 the same.
784
785 The data size is updated by calling Vector::SetSize(). */
786 inline void SetSpace(QuadratureSpace *qspace_, int vdim_ = -1);
787
788 /** @brief Change the QuadratureSpace, the data array, and optionally the
789 vector dimension. */
790 /** If the new QuadratureSpace is different from the current one, the
791 QuadratureFunction will not assume ownership of the new space; otherwise,
792 the ownership flag remains the same.
793
794 If the new vector dimension @a vdim_ < 0, the vector dimension remains
795 the same.
796
797 The data array is replaced by calling Vector::NewDataAndSize(). */
798 inline void SetSpace(QuadratureSpace *qspace_, double *qf_data,
799 int vdim_ = -1);
800
801 /// Get the vector dimension.
GetVDim() const802 int GetVDim() const { return vdim; }
803
804 /// Set the vector dimension, updating the size by calling Vector::SetSize().
SetVDim(int vdim_)805 void SetVDim(int vdim_)
806 { vdim = vdim_; SetSize(vdim*qspace->GetSize()); }
807
808 /// Get the QuadratureSpace ownership flag.
OwnsSpace()809 bool OwnsSpace() { return own_qspace; }
810
811 /// Set the QuadratureSpace ownership flag.
SetOwnsSpace(bool own)812 void SetOwnsSpace(bool own) { own_qspace = own; }
813
814 /// Redefine '=' for QuadratureFunction = constant.
815 QuadratureFunction &operator=(double value);
816
817 /// Copy the data from @a v.
818 /** The size of @a v must be equal to the size of the associated
819 QuadratureSpace #qspace times the QuadratureFunction dimension
820 i.e. QuadratureFunction::Size(). */
821 QuadratureFunction &operator=(const Vector &v);
822
823 /// Copy assignment. Only the data of the base class Vector is copied.
824 /** The QuadratureFunctions @a v and @a *this must have QuadratureSpaces with
825 the same size.
826
827 @note Defining this method overwrites the implicitly defined copy
828 assignment operator. */
829 QuadratureFunction &operator=(const QuadratureFunction &v);
830
831 /// Get the IntegrationRule associated with mesh element @a idx.
GetElementIntRule(int idx) const832 const IntegrationRule &GetElementIntRule(int idx) const
833 { return qspace->GetElementIntRule(idx); }
834
835 /// Return all values associated with mesh element @a idx in a Vector.
836 /** The result is stored in the Vector @a values as a reference to the
837 global values.
838
839 Inside the Vector @a values, the index `i+vdim*j` corresponds to the
840 `i`-th vector component at the `j`-th quadrature point.
841 */
842 inline void GetElementValues(int idx, Vector &values);
843
844 /// Return all values associated with mesh element @a idx in a Vector.
845 /** The result is stored in the Vector @a values as a copy of the
846 global values.
847
848 Inside the Vector @a values, the index `i+vdim*j` corresponds to the
849 `i`-th vector component at the `j`-th quadrature point.
850 */
851 inline void GetElementValues(int idx, Vector &values) const;
852
853 /// Return the quadrature function values at an integration point.
854 /** The result is stored in the Vector @a values as a reference to the
855 global values. */
856 inline void GetElementValues(int idx, const int ip_num, Vector &values);
857
858 /// Return the quadrature function values at an integration point.
859 /** The result is stored in the Vector @a values as a copy to the
860 global values. */
861 inline void GetElementValues(int idx, const int ip_num, Vector &values) const;
862
863 /// Return all values associated with mesh element @a idx in a DenseMatrix.
864 /** The result is stored in the DenseMatrix @a values as a reference to the
865 global values.
866
867 Inside the DenseMatrix @a values, the `(i,j)` entry corresponds to the
868 `i`-th vector component at the `j`-th quadrature point.
869 */
870 inline void GetElementValues(int idx, DenseMatrix &values);
871
872 /// Return all values associated with mesh element @a idx in a const DenseMatrix.
873 /** The result is stored in the DenseMatrix @a values as a copy of the
874 global values.
875
876 Inside the DenseMatrix @a values, the `(i,j)` entry corresponds to the
877 `i`-th vector component at the `j`-th quadrature point.
878 */
879 inline void GetElementValues(int idx, DenseMatrix &values) const;
880
881 /// Write the QuadratureFunction to the stream @a out.
882 void Save(std::ostream &out) const;
883 };
884
885 /// Overload operator<< for std::ostream and QuadratureFunction.
886 std::ostream &operator<<(std::ostream &out, const QuadratureFunction &qf);
887
888
889 double ZZErrorEstimator(BilinearFormIntegrator &blfi,
890 GridFunction &u,
891 GridFunction &flux,
892 Vector &error_estimates,
893 Array<int> *aniso_flags = NULL,
894 int with_subdomains = 1,
895 bool with_coeff = false);
896
897 /// Compute the Lp distance between two grid functions on the given element.
898 double ComputeElementLpDistance(double p, int i,
899 GridFunction& gf1, GridFunction& gf2);
900
901
902 /// Class used for extruding scalar GridFunctions
903 class ExtrudeCoefficient : public Coefficient
904 {
905 private:
906 int n;
907 Mesh *mesh_in;
908 Coefficient &sol_in;
909 public:
ExtrudeCoefficient(Mesh * m,Coefficient & s,int n_)910 ExtrudeCoefficient(Mesh *m, Coefficient &s, int n_)
911 : n(n_), mesh_in(m), sol_in(s) { }
912 virtual double Eval(ElementTransformation &T, const IntegrationPoint &ip);
~ExtrudeCoefficient()913 virtual ~ExtrudeCoefficient() { }
914 };
915
916 /// Extrude a scalar 1D GridFunction, after extruding the mesh with Extrude1D.
917 GridFunction *Extrude1DGridFunction(Mesh *mesh, Mesh *mesh2d,
918 GridFunction *sol, const int ny);
919
920
921 // Inline methods
922
SetSpace(QuadratureSpace * qspace_,int vdim_)923 inline void QuadratureFunction::SetSpace(QuadratureSpace *qspace_, int vdim_)
924 {
925 if (qspace_ != qspace)
926 {
927 if (own_qspace) { delete qspace; }
928 qspace = qspace_;
929 own_qspace = false;
930 }
931 vdim = (vdim_ < 0) ? vdim : vdim_;
932 SetSize(vdim*qspace->GetSize());
933 }
934
SetSpace(QuadratureSpace * qspace_,double * qf_data,int vdim_)935 inline void QuadratureFunction::SetSpace(QuadratureSpace *qspace_,
936 double *qf_data, int vdim_)
937 {
938 if (qspace_ != qspace)
939 {
940 if (own_qspace) { delete qspace; }
941 qspace = qspace_;
942 own_qspace = false;
943 }
944 vdim = (vdim_ < 0) ? vdim : vdim_;
945 NewDataAndSize(qf_data, vdim*qspace->GetSize());
946 }
947
GetElementValues(int idx,Vector & values)948 inline void QuadratureFunction::GetElementValues(int idx, Vector &values)
949 {
950 const int s_offset = qspace->element_offsets[idx];
951 const int sl_size = qspace->element_offsets[idx+1] - s_offset;
952 values.NewDataAndSize(data + vdim*s_offset, vdim*sl_size);
953 }
954
GetElementValues(int idx,Vector & values) const955 inline void QuadratureFunction::GetElementValues(int idx, Vector &values) const
956 {
957 const int s_offset = qspace->element_offsets[idx];
958 const int sl_size = qspace->element_offsets[idx+1] - s_offset;
959 values.SetSize(vdim*sl_size);
960 const double *q = data + vdim*s_offset;
961 for (int i = 0; i<values.Size(); i++)
962 {
963 values(i) = *(q++);
964 }
965 }
966
GetElementValues(int idx,const int ip_num,Vector & values)967 inline void QuadratureFunction::GetElementValues(int idx, const int ip_num,
968 Vector &values)
969 {
970 const int s_offset = qspace->element_offsets[idx] * vdim + ip_num * vdim;
971 values.NewDataAndSize(data + s_offset, vdim);
972 }
973
GetElementValues(int idx,const int ip_num,Vector & values) const974 inline void QuadratureFunction::GetElementValues(int idx, const int ip_num,
975 Vector &values) const
976 {
977 const int s_offset = qspace->element_offsets[idx] * vdim + ip_num * vdim;
978 values.SetSize(vdim);
979 const double *q = data + s_offset;
980 for (int i = 0; i < values.Size(); i++)
981 {
982 values(i) = *(q++);
983 }
984 }
985
GetElementValues(int idx,DenseMatrix & values)986 inline void QuadratureFunction::GetElementValues(int idx, DenseMatrix &values)
987 {
988 const int s_offset = qspace->element_offsets[idx];
989 const int sl_size = qspace->element_offsets[idx+1] - s_offset;
990 values.Reset(data + vdim*s_offset, vdim, sl_size);
991 }
992
GetElementValues(int idx,DenseMatrix & values) const993 inline void QuadratureFunction::GetElementValues(int idx,
994 DenseMatrix &values) const
995 {
996 const int s_offset = qspace->element_offsets[idx];
997 const int sl_size = qspace->element_offsets[idx+1] - s_offset;
998 values.SetSize(vdim, sl_size);
999 const double *q = data + vdim*s_offset;
1000 for (int j = 0; j<sl_size; j++)
1001 {
1002 for (int i = 0; i<vdim; i++)
1003 {
1004 values(i,j) = *(q++);
1005 }
1006 }
1007 }
1008
1009 } // namespace mfem
1010
1011 #endif
1012