MFEM  v4.5.1
Finite element discretization library
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Pages
gridfunc.cpp
Go to the documentation of this file.
1 // Copyright (c) 2010-2022, 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 // Implementation of GridFunction
13 
14 #include "gridfunc.hpp"
15 #include "quadinterpolator.hpp"
16 #include "../mesh/nurbs.hpp"
17 #include "../general/text.hpp"
18 
19 #ifdef MFEM_USE_MPI
20 #include "pfespace.hpp"
21 #endif
22 
23 #include <limits>
24 #include <cstring>
25 #include <string>
26 #include <cmath>
27 #include <iostream>
28 #include <algorithm>
29 
30 
31 namespace mfem
32 {
33 
34 using namespace std;
35 
36 GridFunction::GridFunction(Mesh *m, std::istream &input)
37  : Vector()
38 {
39  // Grid functions are stored on the device
40  UseDevice(true);
41 
42  fes = new FiniteElementSpace;
43  fec = fes->Load(m, input);
44 
45  skip_comment_lines(input, '#');
46  istream::int_type next_char = input.peek();
47  if (next_char == 'N') // First letter of "NURBS_patches"
48  {
49  string buff;
50  getline(input, buff);
51  filter_dos(buff);
52  if (buff == "NURBS_patches")
53  {
54  MFEM_VERIFY(fes->GetNURBSext(),
55  "NURBS_patches requires NURBS FE space");
56  fes->GetNURBSext()->LoadSolution(input, *this);
57  }
58  else
59  {
60  MFEM_ABORT("unknown section: " << buff);
61  }
62  }
63  else
64  {
65  Vector::Load(input, fes->GetVSize());
66 
67  // if the mesh is a legacy (v1.1) NC mesh, it has old vertex ordering
68  if (fes->Nonconforming() &&
70  {
72  }
73  }
75 }
76 
77 GridFunction::GridFunction(Mesh *m, GridFunction *gf_array[], int num_pieces)
78 {
79  UseDevice(true);
80 
81  // all GridFunctions must have the same FE collection, vdim, ordering
82  int vdim, ordering;
83 
84  fes = gf_array[0]->FESpace();
86  vdim = fes->GetVDim();
87  ordering = fes->GetOrdering();
88  fes = new FiniteElementSpace(m, fec, vdim, ordering);
89  SetSize(fes->GetVSize());
90 
91  if (m->NURBSext)
92  {
93  m->NURBSext->MergeGridFunctions(gf_array, num_pieces, *this);
94  return;
95  }
96 
97  int g_ndofs = fes->GetNDofs();
98  int g_nvdofs = fes->GetNVDofs();
99  int g_nedofs = fes->GetNEDofs();
100  int g_nfdofs = fes->GetNFDofs();
101  int g_nddofs = g_ndofs - (g_nvdofs + g_nedofs + g_nfdofs);
102  int vi, ei, fi, di;
103  vi = ei = fi = di = 0;
104  for (int i = 0; i < num_pieces; i++)
105  {
106  FiniteElementSpace *l_fes = gf_array[i]->FESpace();
107  int l_ndofs = l_fes->GetNDofs();
108  int l_nvdofs = l_fes->GetNVDofs();
109  int l_nedofs = l_fes->GetNEDofs();
110  int l_nfdofs = l_fes->GetNFDofs();
111  int l_nddofs = l_ndofs - (l_nvdofs + l_nedofs + l_nfdofs);
112  const double *l_data = gf_array[i]->GetData();
113  double *g_data = data;
114  if (ordering == Ordering::byNODES)
115  {
116  for (int d = 0; d < vdim; d++)
117  {
118  memcpy(g_data+vi, l_data, l_nvdofs*sizeof(double));
119  l_data += l_nvdofs;
120  g_data += g_nvdofs;
121  memcpy(g_data+ei, l_data, l_nedofs*sizeof(double));
122  l_data += l_nedofs;
123  g_data += g_nedofs;
124  memcpy(g_data+fi, l_data, l_nfdofs*sizeof(double));
125  l_data += l_nfdofs;
126  g_data += g_nfdofs;
127  memcpy(g_data+di, l_data, l_nddofs*sizeof(double));
128  l_data += l_nddofs;
129  g_data += g_nddofs;
130  }
131  }
132  else
133  {
134  memcpy(g_data+vdim*vi, l_data, l_nvdofs*sizeof(double)*vdim);
135  l_data += vdim*l_nvdofs;
136  g_data += vdim*g_nvdofs;
137  memcpy(g_data+vdim*ei, l_data, l_nedofs*sizeof(double)*vdim);
138  l_data += vdim*l_nedofs;
139  g_data += vdim*g_nedofs;
140  memcpy(g_data+vdim*fi, l_data, l_nfdofs*sizeof(double)*vdim);
141  l_data += vdim*l_nfdofs;
142  g_data += vdim*g_nfdofs;
143  memcpy(g_data+vdim*di, l_data, l_nddofs*sizeof(double)*vdim);
144  l_data += vdim*l_nddofs;
145  g_data += vdim*g_nddofs;
146  }
147  vi += l_nvdofs;
148  ei += l_nedofs;
149  fi += l_nfdofs;
150  di += l_nddofs;
151  }
153 }
154 
156 {
157  if (fec)
158  {
159  delete fes;
160  delete fec;
161  fec = NULL;
162  }
163 }
164 
166 {
167  if (fes->GetSequence() == fes_sequence)
168  {
169  return; // space and grid function are in sync, no-op
170  }
171  // it seems we cannot use the following, due to FESpace::Update(false)
172  /*if (fes->GetSequence() != fes_sequence + 1)
173  {
174  MFEM_ABORT("Error in update sequence. GridFunction needs to be updated "
175  "right after the space is updated.");
176  }*/
178 
179  const Operator *T = fes->GetUpdateOperator();
180  if (T)
181  {
182  Vector old_data;
183  old_data.Swap(*this);
184  SetSize(T->Height());
185  UseDevice(true);
186  T->Mult(old_data, *this);
187  }
188  else
189  {
190  SetSize(fes->GetVSize());
191  }
192 
193  if (t_vec.Size() > 0) { SetTrueVector(); }
194 }
195 
197 {
198  if (f != fes) { Destroy(); }
199  fes = f;
200  SetSize(fes->GetVSize());
202 }
203 
205 {
206  if (f != fes) { Destroy(); }
207  fes = f;
208  NewDataAndSize(v, fes->GetVSize());
210 }
211 
213 {
214  MFEM_ASSERT(v.Size() >= v_offset + f->GetVSize(), "");
215  if (f != fes) { Destroy(); }
216  fes = f;
217  v.UseDevice(true);
218  this->Vector::MakeRef(v, v_offset, fes->GetVSize());
220 }
221 
223 {
225  {
226  MakeRef(f, tv);
228  }
229  else
230  {
231  SetSpace(f); // works in parallel
233  }
234 }
235 
237 {
238  tv.UseDevice(true);
240  {
241  MakeRef(f, tv, tv_offset);
242  t_vec.NewMemoryAndSize(data, size, false);
243  }
244  else
245  {
246  MFEM_ASSERT(tv.Size() >= tv_offset + f->GetTrueVSize(), "");
247  SetSpace(f); // works in parallel
248  t_vec.MakeRef(tv, tv_offset, f->GetTrueVSize());
249  }
250 }
251 
253  GridFunction &flux,
254  Array<int>& count,
255  bool wcoef,
256  int subdomain)
257 {
258  GridFunction &u = *this;
259 
260  ElementTransformation *Transf;
261  DofTransformation *udoftrans;
262  DofTransformation *fdoftrans;
263 
264  FiniteElementSpace *ufes = u.FESpace();
265  FiniteElementSpace *ffes = flux.FESpace();
266 
267  int nfe = ufes->GetNE();
268  Array<int> udofs;
269  Array<int> fdofs;
270  Vector ul, fl;
271 
272  flux = 0.0;
273  count = 0;
274 
275  for (int i = 0; i < nfe; i++)
276  {
277  if (subdomain >= 0 && ufes->GetAttribute(i) != subdomain)
278  {
279  continue;
280  }
281 
282  udoftrans = ufes->GetElementVDofs(i, udofs);
283  fdoftrans = ffes->GetElementVDofs(i, fdofs);
284 
285  u.GetSubVector(udofs, ul);
286  if (udoftrans)
287  {
288  udoftrans->InvTransformPrimal(ul);
289  }
290 
291  Transf = ufes->GetElementTransformation(i);
292  blfi.ComputeElementFlux(*ufes->GetFE(i), *Transf, ul,
293  *ffes->GetFE(i), fl, wcoef);
294 
295  if (fdoftrans)
296  {
297  fdoftrans->TransformPrimal(fl);
298  }
299  flux.AddElementVector(fdofs, fl);
300 
302  for (int j = 0; j < fdofs.Size(); j++)
303  {
304  count[fdofs[j]]++;
305  }
306  }
307 }
308 
310  GridFunction &flux, bool wcoef,
311  int subdomain)
312 {
313  Array<int> count(flux.Size());
314 
315  SumFluxAndCount(blfi, flux, count, wcoef, subdomain);
316 
317  // complete averaging
318  for (int i = 0; i < count.Size(); i++)
319  {
320  if (count[i] != 0) { flux(i) /= count[i]; }
321  }
322 }
323 
325 {
326  const FiniteElement *fe;
327  if (!fes->GetNE())
328  {
329  const FiniteElementCollection *fe_coll = fes->FEColl();
330  static const Geometry::Type geoms[3] =
332  fe = fe_coll->
333  FiniteElementForGeometry(geoms[fes->GetMesh()->Dimension()-1]);
334  }
335  else
336  {
337  fe = fes->GetFE(0);
338  }
339  if (!fe || fe->GetRangeType() == FiniteElement::SCALAR)
340  {
341  return fes->GetVDim();
342  }
343  return fes->GetVDim()*std::max(fes->GetMesh()->SpaceDimension(),
344  fe->GetVDim());
345 }
346 
348 {
349  const FiniteElement *fe;
350  if (!fes->GetNE())
351  {
352  static const Geometry::Type geoms[3] =
354  fe = fec->FiniteElementForGeometry(geoms[fes->GetMesh()->Dimension()-1]);
355  }
356  else
357  {
358  fe = fes->GetFE(0);
359  }
360  if (!fe || fe->GetRangeType() == FiniteElement::SCALAR)
361  {
362  return 2 * fes->GetMesh()->SpaceDimension() - 3;
363  }
364  return fes->GetVDim()*fe->GetCurlDim();
365 }
366 
368 {
369  const SparseMatrix *R = fes->GetRestrictionMatrix();
371  {
372  // R is identity
373  tv = *this; // no real copy if 'tv' and '*this' use the same data
374  }
375  else
376  {
377  tv.SetSize(R->Height());
378  R->Mult(*this, tv);
379  }
380 }
381 
383 {
384  MFEM_ASSERT(tv.Size() == fes->GetTrueVSize(), "invalid input");
386  if (!cP)
387  {
388  *this = tv; // no real copy if 'tv' and '*this' use the same data
389  }
390  else
391  {
392  cP->Mult(tv, *this);
393  }
394 }
395 
396 void GridFunction::GetNodalValues(int i, Array<double> &nval, int vdim) const
397 {
398  Array<int> vdofs;
399 
400  int k;
401 
402  DofTransformation * doftrans = fes->GetElementVDofs(i, vdofs);
403  const FiniteElement *FElem = fes->GetFE(i);
404  const IntegrationRule *ElemVert =
406  int dof = FElem->GetDof();
407  int n = ElemVert->GetNPoints();
408  nval.SetSize(n);
409  vdim--;
410  Vector loc_data;
411  GetSubVector(vdofs, loc_data);
412  if (doftrans)
413  {
414  doftrans->InvTransformPrimal(loc_data);
415  }
416 
417  if (FElem->GetRangeType() == FiniteElement::SCALAR)
418  {
419  MFEM_ASSERT(FElem->GetMapType() == FiniteElement::VALUE,
420  "invalid FE map type");
421  Vector shape(dof);
422  for (k = 0; k < n; k++)
423  {
424  FElem->CalcShape(ElemVert->IntPoint(k), shape);
425  nval[k] = shape * ((const double *)loc_data + dof * vdim);
426  }
427  }
428  else
429  {
431  DenseMatrix vshape(dof, FElem->GetDim());
432  for (k = 0; k < n; k++)
433  {
434  Tr->SetIntPoint(&ElemVert->IntPoint(k));
435  FElem->CalcVShape(*Tr, vshape);
436  nval[k] = loc_data * (&vshape(0,vdim));
437  }
438  }
439 }
440 
441 double GridFunction::GetValue(int i, const IntegrationPoint &ip, int vdim)
442 const
443 {
444  Array<int> dofs;
445  DofTransformation * doftrans = fes->GetElementDofs(i, dofs);
446  fes->DofsToVDofs(vdim-1, dofs);
447  Vector DofVal(dofs.Size()), LocVec;
448  const FiniteElement *fe = fes->GetFE(i);
449  if (fe->GetMapType() == FiniteElement::VALUE)
450  {
451  fe->CalcShape(ip, DofVal);
452  }
453  else
454  {
456  Tr->SetIntPoint(&ip);
457  fe->CalcPhysShape(*Tr, DofVal);
458  }
459  GetSubVector(dofs, LocVec);
460  if (doftrans)
461  {
462  doftrans->InvTransformPrimal(LocVec);
463  }
464 
465  return (DofVal * LocVec);
466 }
467 
469  Vector &val) const
470 {
471  const FiniteElement *FElem = fes->GetFE(i);
472  int dof = FElem->GetDof();
473  Array<int> vdofs;
474  DofTransformation * doftrans = fes->GetElementVDofs(i, vdofs);
475  Vector loc_data;
476  GetSubVector(vdofs, loc_data);
477  if (doftrans)
478  {
479  doftrans->InvTransformPrimal(loc_data);
480  }
481  if (FElem->GetRangeType() == FiniteElement::SCALAR)
482  {
483  Vector shape(dof);
484  if (FElem->GetMapType() == FiniteElement::VALUE)
485  {
486  FElem->CalcShape(ip, shape);
487  }
488  else
489  {
491  Tr->SetIntPoint(&ip);
492  FElem->CalcPhysShape(*Tr, shape);
493  }
494  int vdim = fes->GetVDim();
495  val.SetSize(vdim);
496  for (int k = 0; k < vdim; k++)
497  {
498  val(k) = shape * ((const double *)loc_data + dof * k);
499  }
500  }
501  else
502  {
503  int vdim = VectorDim();
504  DenseMatrix vshape(dof, vdim);
506  Tr->SetIntPoint(&ip);
507  FElem->CalcVShape(*Tr, vshape);
508  val.SetSize(vdim);
509  vshape.MultTranspose(loc_data, val);
510  }
511 }
512 
513 void GridFunction::GetValues(int i, const IntegrationRule &ir, Vector &vals,
514  int vdim)
515 const
516 {
517  Array<int> dofs;
518  int n = ir.GetNPoints();
519  vals.SetSize(n);
520  DofTransformation * doftrans = fes->GetElementDofs(i, dofs);
521  fes->DofsToVDofs(vdim-1, dofs);
522  const FiniteElement *FElem = fes->GetFE(i);
523  int dof = FElem->GetDof();
524  Vector DofVal(dof), loc_data(dof);
525  GetSubVector(dofs, loc_data);
526  if (doftrans)
527  {
528  doftrans->InvTransformPrimal(loc_data);
529  }
530  if (FElem->GetMapType() == FiniteElement::VALUE)
531  {
532  for (int k = 0; k < n; k++)
533  {
534  FElem->CalcShape(ir.IntPoint(k), DofVal);
535  vals(k) = DofVal * loc_data;
536  }
537  }
538  else
539  {
541  for (int k = 0; k < n; k++)
542  {
543  Tr->SetIntPoint(&ir.IntPoint(k));
544  FElem->CalcPhysShape(*Tr, DofVal);
545  vals(k) = DofVal * loc_data;
546  }
547  }
548 }
549 
550 void GridFunction::GetValues(int i, const IntegrationRule &ir, Vector &vals,
551  DenseMatrix &tr, int vdim)
552 const
553 {
555  ET = fes->GetElementTransformation(i);
556  ET->Transform(ir, tr);
557 
558  GetValues(i, ir, vals, vdim);
559 }
560 
562  int vdim)
563 const
564 {
565  Array<int> dofs;
566  int n = ir.GetNPoints();
567  laps.SetSize(n);
568  fes->GetElementDofs(i, dofs);
569  fes->DofsToVDofs(vdim-1, dofs);
570  const FiniteElement *FElem = fes->GetFE(i);
572  ET = fes->GetElementTransformation(i);
573  MFEM_ASSERT(FElem->GetMapType() == FiniteElement::VALUE,
574  "invalid FE map type");
575 
576  int dof = FElem->GetDof();
577  Vector DofLap(dof), loc_data(dof);
578  GetSubVector(dofs, loc_data);
579  for (int k = 0; k < n; k++)
580  {
581  const IntegrationPoint &ip = ir.IntPoint(k);
582  ET->SetIntPoint(&ip);
583  FElem->CalcPhysLaplacian(*ET, DofLap);
584  laps(k) = DofLap * loc_data;
585  }
586 }
587 
589  DenseMatrix &tr, int vdim)
590 const
591 {
593  ET = fes->GetElementTransformation(i);
594  ET->Transform(ir, tr);
595 
596  GetLaplacians(i, ir, laps, vdim);
597 }
598 
599 
601  DenseMatrix &hess,
602  int vdim)
603 const
604 {
605 
606  Array<int> dofs;
607  int n = ir.GetNPoints();
608  fes->GetElementDofs(i, dofs);
609  fes->DofsToVDofs(vdim-1, dofs);
610  const FiniteElement *FElem = fes->GetFE(i);
612  ET = fes->GetElementTransformation(i);
613  int dim = FElem->GetDim();
614  int size = (dim*(dim+1))/2;
615 
616  MFEM_ASSERT(FElem->GetMapType() == FiniteElement::VALUE,
617  "invalid FE map type");
618 
619  int dof = FElem->GetDof();
620  DenseMatrix DofHes(dof, size);
621  hess.SetSize(n, size);
622 
623  Vector loc_data(dof);
624  GetSubVector(dofs, loc_data);
625 
626  hess = 0.0;
627  for (int k = 0; k < n; k++)
628  {
629  const IntegrationPoint &ip = ir.IntPoint(k);
630  ET->SetIntPoint(&ip);
631  FElem->CalcPhysHessian(*ET, DofHes);
632 
633  for (int j = 0; j < size; j++)
634  {
635  for (int d = 0; d < dof; d++)
636  {
637  hess(k,j) += DofHes(d,j) * loc_data[d];
638  }
639  }
640  }
641 }
642 
644  DenseMatrix &hess,
645  DenseMatrix &tr, int vdim)
646 const
647 {
649  ET = fes->GetElementTransformation(i);
650  ET->Transform(ir, tr);
651 
652  GetHessians(i, ir, hess, vdim);
653 }
654 
655 
656 int GridFunction::GetFaceValues(int i, int side, const IntegrationRule &ir,
657  Vector &vals, DenseMatrix &tr,
658  int vdim) const
659 {
660  int n, dir;
662 
663  n = ir.GetNPoints();
664  IntegrationRule eir(n); // ---
665  if (side == 2) // automatic choice of side
666  {
667  Transf = fes->GetMesh()->GetFaceElementTransformations(i, 0);
668  if (Transf->Elem2No < 0 ||
669  fes->GetAttribute(Transf->Elem1No) <=
670  fes->GetAttribute(Transf->Elem2No))
671  {
672  dir = 0;
673  }
674  else
675  {
676  dir = 1;
677  }
678  }
679  else
680  {
681  if (side == 1 && !fes->GetMesh()->FaceIsInterior(i))
682  {
683  dir = 0;
684  }
685  else
686  {
687  dir = side;
688  }
689  }
690  if (dir == 0)
691  {
692  Transf = fes->GetMesh()->GetFaceElementTransformations(i, 4);
693  Transf->Loc1.Transform(ir, eir);
694  GetValues(Transf->Elem1No, eir, vals, tr, vdim);
695  }
696  else
697  {
698  Transf = fes->GetMesh()->GetFaceElementTransformations(i, 8);
699  Transf->Loc2.Transform(ir, eir);
700  GetValues(Transf->Elem2No, eir, vals, tr, vdim);
701  }
702 
703  return dir;
704 }
705 
707  DenseMatrix &vals, DenseMatrix &tr) const
708 {
710  Tr->Transform(ir, tr);
711 
712  GetVectorValues(*Tr, ir, vals);
713 }
714 
715 void be_to_bfe(Geometry::Type geom, int o, const IntegrationPoint &ip,
716  IntegrationPoint &fip)
717 {
718  if (geom == Geometry::TRIANGLE)
719  {
720  if (o == 2)
721  {
722  fip.x = 1.0 - ip.x - ip.y;
723  fip.y = ip.x;
724  }
725  else if (o == 4)
726  {
727  fip.x = ip.y;
728  fip.y = 1.0 - ip.x - ip.y;
729  }
730  else
731  {
732  fip.x = ip.x;
733  fip.y = ip.y;
734  }
735  fip.z = ip.z;
736  }
737  else
738  {
739  if (o == 2)
740  {
741  fip.x = ip.y;
742  fip.y = 1.0 - ip.x;
743  }
744  else if (o == 4)
745  {
746  fip.x = 1.0 - ip.x;
747  fip.y = 1.0 - ip.y;
748  }
749  else if (o == 6)
750  {
751  fip.x = 1.0 - ip.y;
752  fip.y = ip.x;
753  }
754  else
755  {
756  fip.x = ip.x;
757  fip.y = ip.y;
758  }
759  fip.z = ip.z;
760  }
761  fip.weight = ip.weight;
762  fip.index = ip.index;
763 }
764 
766  const IntegrationPoint &ip,
767  int comp, Vector *tr) const
768 {
769  if (tr)
770  {
771  T.SetIntPoint(&ip);
772  T.Transform(ip, *tr);
773  }
774 
775  const FiniteElement * fe = NULL;
776  Array<int> dofs;
777 
778  switch (T.ElementType)
779  {
781  fe = fes->GetFE(T.ElementNo);
782  fes->GetElementDofs(T.ElementNo, dofs);
783  break;
785  if (fes->FEColl()->GetContType() ==
787  {
788  fe = fes->GetEdgeElement(T.ElementNo);
789  fes->GetEdgeDofs(T.ElementNo, dofs);
790  }
791  else
792  {
793  MFEM_ABORT("GridFunction::GetValue: Field continuity type \""
794  << fes->FEColl()->GetContType() << "\" not supported "
795  << "on mesh edges.");
796  return NAN;
797  }
798  break;
800  if (fes->FEColl()->GetContType() ==
802  {
803  fe = fes->GetFaceElement(T.ElementNo);
804  fes->GetFaceDofs(T.ElementNo, dofs);
805  }
806  else
807  {
808  MFEM_ABORT("GridFunction::GetValue: Field continuity type \""
809  << fes->FEColl()->GetContType() << "\" not supported "
810  << "on mesh faces.");
811  return NAN;
812  }
813  break;
815  {
816  if (fes->FEColl()->GetContType() ==
818  {
819  // This is a continuous field so we can evaluate it on the boundary.
820  fe = fes->GetBE(T.ElementNo);
821  fes->GetBdrElementDofs(T.ElementNo, dofs);
822  }
823  else
824  {
825  // This is a discontinuous field which cannot be evaluated on the
826  // boundary so we'll evaluate it in the neighboring element.
829 
830  // Boundary elements and Boundary Faces may have different
831  // orientations so adjust the integration point if necessary.
832  int o = 0;
833  if (fes->GetMesh()->Dimension() == 3)
834  {
835  int f;
836  fes->GetMesh()->GetBdrElementFace(T.ElementNo, &f, &o);
837  }
838 
839  IntegrationPoint fip;
840  be_to_bfe(FET->GetGeometryType(), o, ip, fip);
841 
842  // Compute and set the point in element 1 from fip
843  FET->SetAllIntPoints(&fip);
845  return GetValue(T1, T1.GetIntPoint(), comp);
846  }
847  }
848  break;
850  {
852  dynamic_cast<FaceElementTransformations *>(&T);
853 
854  // Evaluate in neighboring element for both continuous and
855  // discontinuous fields (the integration point in T1 should have
856  // already been set).
858  return GetValue(T1, T1.GetIntPoint(), comp);
859  }
860  default:
861  {
862  MFEM_ABORT("GridFunction::GetValue: Unsupported element type \""
863  << T.ElementType << "\"");
864  return NAN;
865  }
866  }
867 
868  fes->DofsToVDofs(comp-1, dofs);
869  Vector DofVal(dofs.Size()), LocVec;
870  if (fe->GetMapType() == FiniteElement::VALUE)
871  {
872  fe->CalcShape(ip, DofVal);
873  }
874  else
875  {
876  fe->CalcPhysShape(T, DofVal);
877  }
878  GetSubVector(dofs, LocVec);
879 
880  return (DofVal * LocVec);
881 }
882 
884  const IntegrationRule &ir,
885  Vector &vals, int comp,
886  DenseMatrix *tr) const
887 {
888  if (tr)
889  {
890  T.Transform(ir, *tr);
891  }
892 
893  int nip = ir.GetNPoints();
894  vals.SetSize(nip);
895  for (int j = 0; j < nip; j++)
896  {
897  const IntegrationPoint &ip = ir.IntPoint(j);
898  T.SetIntPoint(&ip);
899  vals[j] = GetValue(T, ip, comp);
900  }
901 }
902 
904  const IntegrationPoint &ip,
905  Vector &val, Vector *tr) const
906 {
907  if (tr)
908  {
909  T.SetIntPoint(&ip);
910  T.Transform(ip, *tr);
911  }
912 
913  Array<int> vdofs;
914  const FiniteElement *fe = NULL;
915  DofTransformation * doftrans = NULL;
916 
917  switch (T.ElementType)
918  {
920  doftrans = fes->GetElementVDofs(T.ElementNo, vdofs);
921  fe = fes->GetFE(T.ElementNo);
922  break;
924  if (fes->FEColl()->GetContType() ==
926  {
927  fe = fes->GetEdgeElement(T.ElementNo);
928  fes->GetEdgeVDofs(T.ElementNo, vdofs);
929  }
930  else
931  {
932  MFEM_ABORT("GridFunction::GetVectorValue: Field continuity type \""
933  << fes->FEColl()->GetContType() << "\" not supported "
934  << "on mesh edges.");
935  return;
936  }
937  break;
939  if (fes->FEColl()->GetContType() ==
941  {
942  fe = fes->GetFaceElement(T.ElementNo);
943  fes->GetFaceVDofs(T.ElementNo, vdofs);
944  }
945  else
946  {
947  MFEM_ABORT("GridFunction::GetVectorValue: Field continuity type \""
948  << fes->FEColl()->GetContType() << "\" not supported "
949  << "on mesh faces.");
950  return;
951  }
952  break;
954  {
955  if (fes->FEColl()->GetContType() ==
957  {
958  // This is a continuous field so we can evaluate it on the boundary.
959  fes->GetBdrElementVDofs(T.ElementNo, vdofs);
960  fe = fes->GetBE(T.ElementNo);
961  }
962  else
963  {
964  // This is a discontinuous vector field which cannot be evaluated on
965  // the boundary so we'll evaluate it in the neighboring element.
968 
969  // Boundary elements and Boundary Faces may have different
970  // orientations so adjust the integration point if necessary.
971  int o = 0;
972  if (fes->GetMesh()->Dimension() == 3)
973  {
974  int f;
975  fes->GetMesh()->GetBdrElementFace(T.ElementNo, &f, &o);
976  }
977 
978  IntegrationPoint fip;
979  be_to_bfe(FET->GetGeometryType(), o, ip, fip);
980 
981  // Compute and set the point in element 1 from fip
982  FET->SetAllIntPoints(&fip);
984  return GetVectorValue(T1, T1.GetIntPoint(), val);
985  }
986  }
987  break;
989  {
991  dynamic_cast<FaceElementTransformations *>(&T);
992 
993  // Evaluate in neighboring element for both continuous and
994  // discontinuous fields (the integration point in T1 should have
995  // already been set).
997  return GetVectorValue(T1, T1.GetIntPoint(), val);
998  }
999  default:
1000  {
1001  MFEM_ABORT("GridFunction::GetVectorValue: Unsupported element type \""
1002  << T.ElementType << "\"");
1003  if (val.Size() > 0) { val = NAN; }
1004  return;
1005  }
1006  }
1007 
1008  int dof = fe->GetDof();
1009  Vector loc_data;
1010  GetSubVector(vdofs, loc_data);
1011  if (doftrans)
1012  {
1013  doftrans->InvTransformPrimal(loc_data);
1014  }
1015  if (fe->GetRangeType() == FiniteElement::SCALAR)
1016  {
1017  Vector shape(dof);
1018  if (fe->GetMapType() == FiniteElement::VALUE)
1019  {
1020  fe->CalcShape(ip, shape);
1021  }
1022  else
1023  {
1024  fe->CalcPhysShape(T, shape);
1025  }
1026  int vdim = fes->GetVDim();
1027  val.SetSize(vdim);
1028  for (int k = 0; k < vdim; k++)
1029  {
1030  val(k) = shape * ((const double *)loc_data + dof * k);
1031  }
1032  }
1033  else
1034  {
1035  int spaceDim = fes->GetMesh()->SpaceDimension();
1036  int vdim = std::max(spaceDim, fe->GetVDim());
1037  DenseMatrix vshape(dof, vdim);
1038  fe->CalcVShape(T, vshape);
1039  val.SetSize(vdim);
1040  vshape.MultTranspose(loc_data, val);
1041  }
1042 }
1043 
1045  const IntegrationRule &ir,
1046  DenseMatrix &vals,
1047  DenseMatrix *tr) const
1048 {
1049  if (tr)
1050  {
1051  T.Transform(ir, *tr);
1052  }
1053 
1054  const FiniteElement *FElem = fes->GetFE(T.ElementNo);
1055  int dof = FElem->GetDof();
1056 
1057  Array<int> vdofs;
1058  DofTransformation * doftrans = fes->GetElementVDofs(T.ElementNo, vdofs);
1059  Vector loc_data;
1060  GetSubVector(vdofs, loc_data);
1061  if (doftrans)
1062  {
1063  doftrans->InvTransformPrimal(loc_data);
1064  }
1065 
1066  int nip = ir.GetNPoints();
1067 
1068  if (FElem->GetRangeType() == FiniteElement::SCALAR)
1069  {
1070  Vector shape(dof);
1071  int vdim = fes->GetVDim();
1072  vals.SetSize(vdim, nip);
1073  for (int j = 0; j < nip; j++)
1074  {
1075  const IntegrationPoint &ip = ir.IntPoint(j);
1076  T.SetIntPoint(&ip);
1077  FElem->CalcPhysShape(T, shape);
1078 
1079  for (int k = 0; k < vdim; k++)
1080  {
1081  vals(k,j) = shape * ((const double *)loc_data + dof * k);
1082  }
1083  }
1084  }
1085  else
1086  {
1087  int spaceDim = fes->GetMesh()->SpaceDimension();
1088  int vdim = std::max(spaceDim, FElem->GetVDim());
1089  DenseMatrix vshape(dof, vdim);
1090 
1091  vals.SetSize(vdim, nip);
1092  Vector val_j;
1093 
1094  for (int j = 0; j < nip; j++)
1095  {
1096  const IntegrationPoint &ip = ir.IntPoint(j);
1097  T.SetIntPoint(&ip);
1098  FElem->CalcVShape(T, vshape);
1099 
1100  vals.GetColumnReference(j, val_j);
1101  vshape.MultTranspose(loc_data, val_j);
1102  }
1103  }
1104 }
1105 
1107  int i, int side, const IntegrationRule &ir,
1108  DenseMatrix &vals, DenseMatrix &tr) const
1109 {
1110  int n, di;
1112 
1113  n = ir.GetNPoints();
1114  IntegrationRule eir(n); // ---
1115  Transf = fes->GetMesh()->GetFaceElementTransformations(i, 0);
1116  if (side == 2)
1117  {
1118  if (Transf->Elem2No < 0 ||
1119  fes->GetAttribute(Transf->Elem1No) <=
1120  fes->GetAttribute(Transf->Elem2No))
1121  {
1122  di = 0;
1123  }
1124  else
1125  {
1126  di = 1;
1127  }
1128  }
1129  else
1130  {
1131  di = side;
1132  }
1133  if (di == 0)
1134  {
1135  Transf = fes->GetMesh()->GetFaceElementTransformations(i, 5);
1136  Transf->Loc1.Transform(ir, eir);
1137  GetVectorValues(*Transf->Elem1, eir, vals, &tr);
1138  }
1139  else
1140  {
1141  Transf = fes->GetMesh()->GetFaceElementTransformations(i, 10);
1142  Transf->Loc2.Transform(ir, eir);
1143  GetVectorValues(*Transf->Elem2, eir, vals, &tr);
1144  }
1145 
1146  return di;
1147 }
1148 
1150 {
1151  // Without averaging ...
1152 
1153  const FiniteElementSpace *orig_fes = orig_func.FESpace();
1154  DofTransformation * doftrans;
1155  DofTransformation * orig_doftrans;
1156  Array<int> vdofs, orig_vdofs;
1157  Vector shape, loc_values, orig_loc_values;
1158  int i, j, d, ne, dof, odof, vdim;
1159 
1160  ne = fes->GetNE();
1161  vdim = fes->GetVDim();
1162  for (i = 0; i < ne; i++)
1163  {
1164  doftrans = fes->GetElementVDofs(i, vdofs);
1165  orig_doftrans = orig_fes->GetElementVDofs(i, orig_vdofs);
1166  orig_func.GetSubVector(orig_vdofs, orig_loc_values);
1167  if (orig_doftrans)
1168  {
1169  orig_doftrans->InvTransformPrimal(orig_loc_values);
1170  }
1171  const FiniteElement *fe = fes->GetFE(i);
1172  const FiniteElement *orig_fe = orig_fes->GetFE(i);
1173  dof = fe->GetDof();
1174  odof = orig_fe->GetDof();
1175  loc_values.SetSize(dof * vdim);
1176  shape.SetSize(odof);
1177  const IntegrationRule &ir = fe->GetNodes();
1178  for (j = 0; j < dof; j++)
1179  {
1180  const IntegrationPoint &ip = ir.IntPoint(j);
1181  orig_fe->CalcShape(ip, shape);
1182  for (d = 0; d < vdim; d++)
1183  {
1184  loc_values(d*dof+j) =
1185  shape * ((const double *)orig_loc_values + d * odof) ;
1186  }
1187  }
1188  if (doftrans)
1189  {
1190  doftrans->TransformPrimal(loc_values);
1191  }
1192  SetSubVector(vdofs, loc_values);
1193  }
1194 }
1195 
1197 {
1198  // Without averaging ...
1199 
1200  const FiniteElementSpace *orig_fes = orig_func.FESpace();
1201  // DofTransformation * doftrans;
1202  // DofTransformation * orig_doftrans;
1203  Array<int> vdofs, orig_vdofs;
1204  Vector shape, loc_values, loc_values_t, orig_loc_values, orig_loc_values_t;
1205  int i, j, d, nbe, dof, odof, vdim;
1206 
1207  nbe = fes->GetNBE();
1208  vdim = fes->GetVDim();
1209  for (i = 0; i < nbe; i++)
1210  {
1211  fes->GetBdrElementVDofs(i, vdofs);
1212  orig_fes->GetBdrElementVDofs(i, orig_vdofs);
1213  orig_func.GetSubVector(orig_vdofs, orig_loc_values);
1214  const FiniteElement *fe = fes->GetBE(i);
1215  const FiniteElement *orig_fe = orig_fes->GetBE(i);
1216  dof = fe->GetDof();
1217  odof = orig_fe->GetDof();
1218  loc_values.SetSize(dof * vdim);
1219  shape.SetSize(odof);
1220  const IntegrationRule &ir = fe->GetNodes();
1221  for (j = 0; j < dof; j++)
1222  {
1223  const IntegrationPoint &ip = ir.IntPoint(j);
1224  orig_fe->CalcShape(ip, shape);
1225  for (d = 0; d < vdim; d++)
1226  {
1227  loc_values(d*dof+j) =
1228  shape * ((const double *)orig_loc_values + d * odof);
1229  }
1230  }
1231  SetSubVector(vdofs, loc_values);
1232  }
1233 }
1234 
1236  int i, const IntegrationRule &ir, DenseMatrix &vals,
1237  DenseMatrix &tr, int comp) const
1238 {
1239  Array<int> vdofs;
1240  ElementTransformation *transf;
1241 
1242  int d, k, n, sdim, dof;
1243 
1244  n = ir.GetNPoints();
1245  DofTransformation * doftrans = fes->GetElementVDofs(i, vdofs);
1246  const FiniteElement *fe = fes->GetFE(i);
1247  dof = fe->GetDof();
1248  sdim = fes->GetMesh()->SpaceDimension();
1249  // int *dofs = &vdofs[comp*dof];
1250  transf = fes->GetElementTransformation(i);
1251  transf->Transform(ir, tr);
1252  vals.SetSize(n, sdim);
1253  DenseMatrix vshape(dof, sdim);
1254  Vector loc_data, val(sdim);
1255  GetSubVector(vdofs, loc_data);
1256  if (doftrans)
1257  {
1258  doftrans->InvTransformPrimal(loc_data);
1259  }
1260  for (k = 0; k < n; k++)
1261  {
1262  const IntegrationPoint &ip = ir.IntPoint(k);
1263  transf->SetIntPoint(&ip);
1264  fe->CalcVShape(*transf, vshape);
1265  vshape.MultTranspose(loc_data, val);
1266  for (d = 0; d < sdim; d++)
1267  {
1268  vals(k,d) = val(d);
1269  }
1270  }
1271 }
1272 
1274 {
1275  if (fes->GetOrdering() == Ordering::byNODES)
1276  {
1277  return;
1278  }
1279 
1280  int i, j, k;
1281  int vdim = fes->GetVDim();
1282  int ndofs = fes->GetNDofs();
1283  double *temp = new double[size];
1284 
1285  k = 0;
1286  for (j = 0; j < ndofs; j++)
1287  for (i = 0; i < vdim; i++)
1288  {
1289  temp[j+i*ndofs] = data[k++];
1290  }
1291 
1292  for (i = 0; i < size; i++)
1293  {
1294  data[i] = temp[i];
1295  }
1296 
1297  delete [] temp;
1298 }
1299 
1301 {
1302  int i, k;
1303  Array<int> overlap(fes->GetNV());
1304  Array<int> vertices;
1305  DenseMatrix vals, tr;
1306 
1307  val.SetSize(overlap.Size());
1308  overlap = 0;
1309  val = 0.0;
1310 
1311  comp--;
1312  for (i = 0; i < fes->GetNE(); i++)
1313  {
1314  const IntegrationRule *ir =
1316  fes->GetElementVertices(i, vertices);
1317  GetVectorFieldValues(i, *ir, vals, tr);
1318  for (k = 0; k < ir->GetNPoints(); k++)
1319  {
1320  val(vertices[k]) += vals(k, comp);
1321  overlap[vertices[k]]++;
1322  }
1323  }
1324 
1325  for (i = 0; i < overlap.Size(); i++)
1326  {
1327  val(i) /= overlap[i];
1328  }
1329 }
1330 
1332 {
1333  FiniteElementSpace *new_fes = vec_field.FESpace();
1334 
1335  int d, i, k, ind, dof, sdim;
1336  Array<int> overlap(new_fes->GetVSize());
1337  Array<int> new_vdofs;
1338  DenseMatrix vals, tr;
1339 
1340  sdim = fes->GetMesh()->SpaceDimension();
1341  overlap = 0;
1342  vec_field = 0.0;
1343 
1344  for (i = 0; i < new_fes->GetNE(); i++)
1345  {
1346  const FiniteElement *fe = new_fes->GetFE(i);
1347  const IntegrationRule &ir = fe->GetNodes();
1348  GetVectorFieldValues(i, ir, vals, tr, comp);
1349  new_fes->GetElementVDofs(i, new_vdofs);
1350  dof = fe->GetDof();
1351  for (d = 0; d < sdim; d++)
1352  {
1353  for (k = 0; k < dof; k++)
1354  {
1355  if ( (ind=new_vdofs[dof*d+k]) < 0 )
1356  {
1357  ind = -1-ind, vals(k, d) = - vals(k, d);
1358  }
1359  vec_field(ind) += vals(k, d);
1360  overlap[ind]++;
1361  }
1362  }
1363  }
1364 
1365  for (i = 0; i < overlap.Size(); i++)
1366  {
1367  vec_field(i) /= overlap[i];
1368  }
1369 }
1370 
1372  GridFunction &der,
1373  Array<int> &zones_per_dof)
1374 {
1375  FiniteElementSpace * der_fes = der.FESpace();
1376  ElementTransformation * transf;
1377  zones_per_dof.SetSize(der_fes->GetVSize());
1378  Array<int> der_dofs, vdofs;
1379  DenseMatrix dshape, inv_jac;
1380  Vector pt_grad, loc_func;
1381  int i, j, k, dim, dof, der_dof, ind;
1382  double a;
1383 
1384  zones_per_dof = 0;
1385  der = 0.0;
1386 
1387  comp--;
1388  for (i = 0; i < der_fes->GetNE(); i++)
1389  {
1390  const FiniteElement *der_fe = der_fes->GetFE(i);
1391  const FiniteElement *fe = fes->GetFE(i);
1392  const IntegrationRule &ir = der_fe->GetNodes();
1393  der_fes->GetElementDofs(i, der_dofs);
1394  fes->GetElementVDofs(i, vdofs);
1395  dim = fe->GetDim();
1396  dof = fe->GetDof();
1397  der_dof = der_fe->GetDof();
1398  dshape.SetSize(dof, dim);
1399  inv_jac.SetSize(dim);
1400  pt_grad.SetSize(dim);
1401  loc_func.SetSize(dof);
1402  transf = fes->GetElementTransformation(i);
1403  for (j = 0; j < dof; j++)
1404  loc_func(j) = ( (ind=vdofs[comp*dof+j]) >= 0 ) ?
1405  (data[ind]) : (-data[-1-ind]);
1406  for (k = 0; k < der_dof; k++)
1407  {
1408  const IntegrationPoint &ip = ir.IntPoint(k);
1409  fe->CalcDShape(ip, dshape);
1410  dshape.MultTranspose(loc_func, pt_grad);
1411  transf->SetIntPoint(&ip);
1412  CalcInverse(transf->Jacobian(), inv_jac);
1413  a = 0.0;
1414  for (j = 0; j < dim; j++)
1415  {
1416  a += inv_jac(j, der_comp) * pt_grad(j);
1417  }
1418  der(der_dofs[k]) += a;
1419  zones_per_dof[der_dofs[k]]++;
1420  }
1421  }
1422 }
1423 
1424 void GridFunction::GetDerivative(int comp, int der_comp, GridFunction &der)
1425 {
1426  Array<int> overlap;
1427  AccumulateAndCountDerivativeValues(comp, der_comp, der, overlap);
1428 
1429  for (int i = 0; i < overlap.Size(); i++)
1430  {
1431  der(i) /= overlap[i];
1432  }
1433 }
1434 
1435 
1437  ElementTransformation &T, DenseMatrix &gh) const
1438 {
1439  int elNo = T.ElementNo;
1440  const FiniteElement *FElem = fes->GetFE(elNo);
1441  int dim = FElem->GetDim(), dof = FElem->GetDof();
1442  Array<int> vdofs;
1443  DofTransformation * doftrans = fes->GetElementVDofs(elNo, vdofs);
1444  Vector loc_data;
1445  GetSubVector(vdofs, loc_data);
1446  if (doftrans)
1447  {
1448  doftrans->InvTransformPrimal(loc_data);
1449  }
1450  // assuming scalar FE
1451  int vdim = fes->GetVDim();
1452  DenseMatrix dshape(dof, dim);
1453  FElem->CalcDShape(T.GetIntPoint(), dshape);
1454  gh.SetSize(vdim, dim);
1455  DenseMatrix loc_data_mat(loc_data.GetData(), dof, vdim);
1456  MultAtB(loc_data_mat, dshape, gh);
1457 }
1458 
1460 {
1461  switch (T.ElementType)
1462  {
1464  {
1465  int elNo = T.ElementNo;
1466  const FiniteElement *fe = fes->GetFE(elNo);
1467  if (fe->GetRangeType() == FiniteElement::SCALAR)
1468  {
1469  MFEM_ASSERT(fe->GetMapType() == FiniteElement::VALUE,
1470  "invalid FE map type");
1471  DenseMatrix grad_hat;
1472  GetVectorGradientHat(T, grad_hat);
1473  const DenseMatrix &Jinv = T.InverseJacobian();
1474  double div_v = 0.0;
1475  for (int i = 0; i < Jinv.Width(); i++)
1476  {
1477  for (int j = 0; j < Jinv.Height(); j++)
1478  {
1479  div_v += grad_hat(i, j) * Jinv(j, i);
1480  }
1481  }
1482  return div_v;
1483  }
1484  else
1485  {
1486  // Assuming RT-type space
1487  Array<int> dofs;
1488  DofTransformation * doftrans = fes->GetElementDofs(elNo, dofs);
1489  Vector loc_data, divshape(fe->GetDof());
1490  GetSubVector(dofs, loc_data);
1491  if (doftrans)
1492  {
1493  doftrans->InvTransformPrimal(loc_data);
1494  }
1495  fe->CalcDivShape(T.GetIntPoint(), divshape);
1496  return (loc_data * divshape) / T.Weight();
1497  }
1498  }
1499  break;
1501  {
1502  // In order to properly capture the derivative of the normal component
1503  // of the field (as well as the transverse divergence of the
1504  // tangential components) we must evaluate it in the neighboring
1505  // element.
1508 
1509  // Boundary elements and Boundary Faces may have different
1510  // orientations so adjust the integration point if necessary.
1511  int o = 0;
1512  if (fes->GetMesh()->Dimension() == 3)
1513  {
1514  int f;
1515  fes->GetMesh()->GetBdrElementFace(T.ElementNo, &f, &o);
1516  }
1517 
1518  IntegrationPoint fip;
1519  be_to_bfe(FET->GetGeometryType(), o, T.GetIntPoint(), fip);
1520 
1521  // Compute and set the point in element 1 from fip
1522  FET->SetAllIntPoints(&fip);
1524 
1525  return GetDivergence(T1);
1526  }
1527  break;
1529  {
1530  // This must be a DG context so this dynamic cast must succeed.
1532  dynamic_cast<FaceElementTransformations *>(&T);
1533 
1534  // Evaluate in neighboring element (the integration point in T1 should
1535  // have already been set).
1537  return GetDivergence(T1);
1538  }
1539  break;
1540  default:
1541  {
1542  MFEM_ABORT("GridFunction::GetDivergence: Unsupported element type \""
1543  << T.ElementType << "\"");
1544  }
1545  }
1546  return 0.0; // never reached
1547 }
1548 
1550 {
1551  switch (T.ElementType)
1552  {
1554  {
1555  int elNo = T.ElementNo;
1556  const FiniteElement *fe = fes->GetFE(elNo);
1557  if (fe->GetRangeType() == FiniteElement::SCALAR)
1558  {
1559  MFEM_ASSERT(fe->GetMapType() == FiniteElement::VALUE,
1560  "invalid FE map type");
1561  DenseMatrix grad_hat;
1562  GetVectorGradientHat(T, grad_hat);
1563  const DenseMatrix &Jinv = T.InverseJacobian();
1564  // Dimensions of grad are vdim x FElem->Dim
1565  DenseMatrix grad(grad_hat.Height(), Jinv.Width());
1566  Mult(grad_hat, Jinv, grad);
1567  MFEM_ASSERT(grad.Height() == grad.Width(), "");
1568  if (grad.Height() == 3)
1569  {
1570  curl.SetSize(3);
1571  curl(0) = grad(2,1) - grad(1,2);
1572  curl(1) = grad(0,2) - grad(2,0);
1573  curl(2) = grad(1,0) - grad(0,1);
1574  }
1575  else if (grad.Height() == 2)
1576  {
1577  curl.SetSize(1);
1578  curl(0) = grad(1,0) - grad(0,1);
1579  }
1580  }
1581  else
1582  {
1583  // Assuming ND-type space
1584  Array<int> dofs;
1585  DofTransformation * doftrans = fes->GetElementDofs(elNo, dofs);
1586  Vector loc_data;
1587  GetSubVector(dofs, loc_data);
1588  if (doftrans)
1589  {
1590  doftrans->InvTransformPrimal(loc_data);
1591  }
1592  DenseMatrix curl_shape(fe->GetDof(), fe->GetCurlDim());
1593  curl.SetSize(curl_shape.Width());
1594  fe->CalcPhysCurlShape(T, curl_shape);
1595  curl_shape.MultTranspose(loc_data, curl);
1596  }
1597  }
1598  break;
1600  {
1601  // In order to capture the tangential components of the curl we
1602  // must evaluate it in the neighboring element.
1605 
1606  // Boundary elements and Boundary Faces may have different
1607  // orientations so adjust the integration point if necessary.
1608  int o = 0;
1609  if (fes->GetMesh()->Dimension() == 3)
1610  {
1611  int f;
1612  fes->GetMesh()->GetBdrElementFace(T.ElementNo, &f, &o);
1613  }
1614 
1615  IntegrationPoint fip;
1616  be_to_bfe(FET->GetGeometryType(), o, T.GetIntPoint(), fip);
1617 
1618  // Compute and set the point in element 1 from fip
1619  FET->SetAllIntPoints(&fip);
1621 
1622  GetCurl(T1, curl);
1623  }
1624  break;
1626  {
1627  // This must be a DG context so this dynamic cast must succeed.
1629  dynamic_cast<FaceElementTransformations *>(&T);
1630 
1631  // Evaluate in neighboring element (the integration point in T1 should
1632  // have already been set).
1634  GetCurl(T1, curl);
1635  }
1636  break;
1637  default:
1638  {
1639  MFEM_ABORT("GridFunction::GetCurl: Unsupported element type \""
1640  << T.ElementType << "\"");
1641  }
1642  }
1643 }
1644 
1646 {
1647  switch (T.ElementType)
1648  {
1650  {
1651  const FiniteElement *fe = fes->GetFE(T.ElementNo);
1652  MFEM_ASSERT(fe->GetMapType() == FiniteElement::VALUE,
1653  "invalid FE map type");
1654  int spaceDim = fes->GetMesh()->SpaceDimension();
1655  int dim = fe->GetDim(), dof = fe->GetDof();
1656  DenseMatrix dshape(dof, dim);
1657  Vector lval, gh(dim);
1658 
1659  grad.SetSize(spaceDim);
1660  GetElementDofValues(T.ElementNo, lval);
1661  fe->CalcDShape(T.GetIntPoint(), dshape);
1662  dshape.MultTranspose(lval, gh);
1663  T.InverseJacobian().MultTranspose(gh, grad);
1664  }
1665  break;
1667  {
1668  // In order to properly capture the normal component of the gradient
1669  // as well as its tangential components we must evaluate it in the
1670  // neighboring element.
1673 
1674  // Boundary elements and Boundary Faces may have different
1675  // orientations so adjust the integration point if necessary.
1676  int o = 0;
1677  if (fes->GetMesh()->Dimension() == 3)
1678  {
1679  int f;
1680  fes->GetMesh()->GetBdrElementFace(T.ElementNo, &f, &o);
1681  }
1682 
1683  IntegrationPoint fip;
1684  be_to_bfe(FET->GetGeometryType(), o, T.GetIntPoint(), fip);
1685 
1686  // Compute and set the point in element 1 from fip
1687  FET->SetAllIntPoints(&fip);
1689 
1690  GetGradient(T1, grad);
1691  }
1692  break;
1694  {
1695  // This must be a DG context so this dynamic cast must succeed.
1697  dynamic_cast<FaceElementTransformations *>(&T);
1698 
1699  // Evaluate in neighboring element (the integration point in T1 should
1700  // have already been set).
1702  GetGradient(T1, grad);
1703  }
1704  break;
1705  default:
1706  {
1707  MFEM_ABORT("GridFunction::GetGradient: Unsupported element type \""
1708  << T.ElementType << "\"");
1709  }
1710  }
1711 }
1712 
1714  const IntegrationRule &ir,
1715  DenseMatrix &grad) const
1716 {
1717  int elNo = tr.ElementNo;
1718  const FiniteElement *fe = fes->GetFE(elNo);
1719  MFEM_ASSERT(fe->GetMapType() == FiniteElement::VALUE, "invalid FE map type");
1720  DenseMatrix dshape(fe->GetDof(), fe->GetDim());
1721  Vector lval, gh(fe->GetDim()), gcol;
1722  Array<int> dofs;
1723  DofTransformation * doftrans = fes->GetElementDofs(elNo, dofs);
1724  GetSubVector(dofs, lval);
1725  if (doftrans)
1726  {
1727  doftrans->InvTransformPrimal(lval);
1728  }
1729  grad.SetSize(fe->GetDim(), ir.GetNPoints());
1730  for (int i = 0; i < ir.GetNPoints(); i++)
1731  {
1732  const IntegrationPoint &ip = ir.IntPoint(i);
1733  fe->CalcDShape(ip, dshape);
1734  dshape.MultTranspose(lval, gh);
1735  tr.SetIntPoint(&ip);
1736  grad.GetColumnReference(i, gcol);
1737  const DenseMatrix &Jinv = tr.InverseJacobian();
1738  Jinv.MultTranspose(gh, gcol);
1739  }
1740 }
1741 
1743  ElementTransformation &T, DenseMatrix &grad) const
1744 {
1745  switch (T.ElementType)
1746  {
1748  {
1749  MFEM_ASSERT(fes->GetFE(T.ElementNo)->GetMapType() ==
1750  FiniteElement::VALUE, "invalid FE map type");
1751  DenseMatrix grad_hat;
1752  GetVectorGradientHat(T, grad_hat);
1753  const DenseMatrix &Jinv = T.InverseJacobian();
1754  grad.SetSize(grad_hat.Height(), Jinv.Width());
1755  Mult(grad_hat, Jinv, grad);
1756  }
1757  break;
1759  {
1760  // In order to capture the normal component of the gradient we
1761  // must evaluate it in the neighboring element.
1764 
1765  // Boundary elements and Boundary Faces may have different
1766  // orientations so adjust the integration point if necessary.
1767  int o = 0;
1768  if (fes->GetMesh()->Dimension() == 3)
1769  {
1770  int f;
1771  fes->GetMesh()->GetBdrElementFace(T.ElementNo, &f, &o);
1772  }
1773 
1774  IntegrationPoint fip;
1775  be_to_bfe(FET->GetGeometryType(), o, T.GetIntPoint(), fip);
1776 
1777  // Compute and set the point in element 1 from fip
1778  FET->SetAllIntPoints(&fip);
1780 
1781  GetVectorGradient(T1, grad);
1782  }
1783  break;
1785  {
1786  // This must be a DG context so this dynamic cast must succeed.
1788  dynamic_cast<FaceElementTransformations *>(&T);
1789 
1790  // Evaluate in neighboring element (the integration point in T1 should
1791  // have already been set).
1793  GetVectorGradient(T1, grad);
1794  }
1795  break;
1796  default:
1797  {
1798  MFEM_ABORT("GridFunction::GetVectorGradient: "
1799  "Unsupported element type \"" << T.ElementType << "\"");
1800  }
1801  }
1802 }
1803 
1805 {
1806  MassIntegrator Mi;
1807  DenseMatrix loc_mass;
1808  DofTransformation * te_doftrans;
1809  DofTransformation * tr_doftrans;
1810  Array<int> te_dofs, tr_dofs;
1811  Vector loc_avgs, loc_this;
1812  Vector int_psi(avgs.Size());
1813 
1814  avgs = 0.0;
1815  int_psi = 0.0;
1816  for (int i = 0; i < fes->GetNE(); i++)
1817  {
1818  Mi.AssembleElementMatrix2(*fes->GetFE(i), *avgs.FESpace()->GetFE(i),
1819  *fes->GetElementTransformation(i), loc_mass);
1820  tr_doftrans = fes->GetElementDofs(i, tr_dofs);
1821  te_doftrans = avgs.FESpace()->GetElementDofs(i, te_dofs);
1822  GetSubVector(tr_dofs, loc_this);
1823  if (tr_doftrans)
1824  {
1825  tr_doftrans->InvTransformPrimal(loc_this);
1826  }
1827  loc_avgs.SetSize(te_dofs.Size());
1828  loc_mass.Mult(loc_this, loc_avgs);
1829  if (te_doftrans)
1830  {
1831  te_doftrans->TransformPrimal(loc_avgs);
1832  }
1833  avgs.AddElementVector(te_dofs, loc_avgs);
1834  loc_this = 1.0; // assume the local basis for 'this' sums to 1
1835  loc_mass.Mult(loc_this, loc_avgs);
1836  int_psi.AddElementVector(te_dofs, loc_avgs);
1837  }
1838  for (int i = 0; i < avgs.Size(); i++)
1839  {
1840  avgs(i) /= int_psi(i);
1841  }
1842 }
1843 
1844 void GridFunction::GetElementDofValues(int el, Vector &dof_vals) const
1845 {
1846  Array<int> dof_idx;
1847  DofTransformation * doftrans = fes->GetElementVDofs(el, dof_idx);
1848  GetSubVector(dof_idx, dof_vals);
1849  if (doftrans)
1850  {
1851  doftrans->InvTransformPrimal(dof_vals);
1852  }
1853 }
1854 
1856 {
1857  Mesh *mesh = fes->GetMesh();
1858  bool sameP = false;
1859  DenseMatrix P;
1860 
1861  if (!mesh->GetNE()) { return; }
1862 
1863  Geometry::Type geom, cached_geom = Geometry::INVALID;
1864  if (mesh->GetNumGeometries(mesh->Dimension()) == 1)
1865  {
1866  // Assuming that the projection matrix is the same for all elements
1867  sameP = true;
1868  fes->GetFE(0)->Project(*src.fes->GetFE(0),
1869  *mesh->GetElementTransformation(0), P);
1870  }
1871  const int vdim = fes->GetVDim();
1872  MFEM_VERIFY(vdim == src.fes->GetVDim(), "incompatible vector dimensions!");
1873 
1874  Array<int> src_vdofs, dest_vdofs;
1875  Vector src_lvec, dest_lvec(vdim*P.Height());
1876 
1877  for (int i = 0; i < mesh->GetNE(); i++)
1878  {
1879  // Assuming the projection matrix P depends only on the element geometry
1880  if ( !sameP && (geom = mesh->GetElementBaseGeometry(i)) != cached_geom )
1881  {
1882  fes->GetFE(i)->Project(*src.fes->GetFE(i),
1883  *mesh->GetElementTransformation(i), P);
1884  dest_lvec.SetSize(vdim*P.Height());
1885  cached_geom = geom;
1886  }
1887 
1888  DofTransformation * src_doftrans = src.fes->GetElementVDofs(i, src_vdofs);
1889  src.GetSubVector(src_vdofs, src_lvec);
1890  if (src_doftrans)
1891  {
1892  src_doftrans->InvTransformPrimal(src_lvec);
1893  }
1894  for (int vd = 0; vd < vdim; vd++)
1895  {
1896  P.Mult(&src_lvec[vd*P.Width()], &dest_lvec[vd*P.Height()]);
1897  }
1898  DofTransformation * doftrans = fes->GetElementVDofs(i, dest_vdofs);
1899  if (doftrans)
1900  {
1901  doftrans->TransformPrimal(dest_lvec);
1902  }
1903  SetSubVector(dest_vdofs, dest_lvec);
1904  }
1905 }
1906 
1907 void GridFunction::ImposeBounds(int i, const Vector &weights,
1908  const Vector &lo_, const Vector &hi_)
1909 {
1910  Array<int> vdofs;
1911  DofTransformation * doftrans = fes->GetElementVDofs(i, vdofs);
1912  int size = vdofs.Size();
1913  Vector vals, new_vals(size);
1914 
1915  GetSubVector(vdofs, vals);
1916  if (doftrans)
1917  {
1918  doftrans->InvTransformPrimal(vals);
1919  }
1920 
1921  MFEM_ASSERT(weights.Size() == size, "Different # of weights and dofs.");
1922  MFEM_ASSERT(lo_.Size() == size, "Different # of lower bounds and dofs.");
1923  MFEM_ASSERT(hi_.Size() == size, "Different # of upper bounds and dofs.");
1924 
1925  int max_iter = 30;
1926  double tol = 1.e-12;
1927  SLBQPOptimizer slbqp;
1928  slbqp.SetMaxIter(max_iter);
1929  slbqp.SetAbsTol(1.0e-18);
1930  slbqp.SetRelTol(tol);
1931  slbqp.SetBounds(lo_, hi_);
1932  slbqp.SetLinearConstraint(weights, weights * vals);
1933  slbqp.SetPrintLevel(0); // print messages only if not converged
1934  slbqp.Mult(vals, new_vals);
1935 
1936  if (doftrans)
1937  {
1938  doftrans->TransformPrimal(new_vals);
1939  }
1940  SetSubVector(vdofs, new_vals);
1941 }
1942 
1943 void GridFunction::ImposeBounds(int i, const Vector &weights,
1944  double min_, double max_)
1945 {
1946  Array<int> vdofs;
1947  DofTransformation * doftrans = fes->GetElementVDofs(i, vdofs);
1948  int size = vdofs.Size();
1949  Vector vals, new_vals(size);
1950  GetSubVector(vdofs, vals);
1951  if (doftrans)
1952  {
1953  doftrans->InvTransformPrimal(vals);
1954  }
1955 
1956  double max_val = vals.Max();
1957  double min_val = vals.Min();
1958 
1959  if (max_val <= min_)
1960  {
1961  new_vals = min_;
1962  if (doftrans)
1963  {
1964  doftrans->TransformPrimal(new_vals);
1965  }
1966  SetSubVector(vdofs, new_vals);
1967  return;
1968  }
1969 
1970  if (min_ <= min_val && max_val <= max_)
1971  {
1972  return;
1973  }
1974 
1975  Vector minv(size), maxv(size);
1976  minv = (min_ > min_val) ? min_ : min_val;
1977  maxv = (max_ < max_val) ? max_ : max_val;
1978 
1979  ImposeBounds(i, weights, minv, maxv);
1980 }
1981 
1983 {
1984  const SparseMatrix *R = fes->GetRestrictionMatrix();
1985  const Operator *P = fes->GetProlongationMatrix();
1986 
1987  if (P && R)
1988  {
1989  Vector tmp(R->Height());
1990  R->Mult(*this, tmp);
1991  P->Mult(tmp, *this);
1992  }
1993 }
1994 
1995 void GridFunction::GetNodalValues(Vector &nval, int vdim) const
1996 {
1997  int i, j;
1998  Array<int> vertices;
1999  Array<double> values;
2000  Array<int> overlap(fes->GetNV());
2001  nval.SetSize(fes->GetNV());
2002 
2003  nval = 0.0;
2004  overlap = 0;
2005  for (i = 0; i < fes->GetNE(); i++)
2006  {
2007  fes->GetElementVertices(i, vertices);
2008  GetNodalValues(i, values, vdim);
2009  for (j = 0; j < vertices.Size(); j++)
2010  {
2011  nval(vertices[j]) += values[j];
2012  overlap[vertices[j]]++;
2013  }
2014  }
2015  for (i = 0; i < overlap.Size(); i++)
2016  {
2017  nval(i) /= overlap[i];
2018  }
2019 }
2020 
2022  AvgType type,
2023  Array<int> &zones_per_vdof)
2024 {
2025  zones_per_vdof.SetSize(fes->GetVSize());
2026  zones_per_vdof = 0;
2027 
2028  // Local interpolation
2029  Array<int> vdofs;
2030  Vector vals;
2031  *this = 0.0;
2032 
2033  HostReadWrite();
2034 
2035  for (int i = 0; i < fes->GetNE(); i++)
2036  {
2037  fes->GetElementVDofs(i, vdofs);
2038  // Local interpolation of coeff.
2039  vals.SetSize(vdofs.Size());
2040  fes->GetFE(i)->Project(coeff, *fes->GetElementTransformation(i), vals);
2041 
2042  // Accumulate values in all dofs, count the zones.
2043  for (int j = 0; j < vdofs.Size(); j++)
2044  {
2045  if (type == HARMONIC)
2046  {
2047  MFEM_VERIFY(vals[j] != 0.0,
2048  "Coefficient has zeros, harmonic avg is undefined!");
2049  (*this)(vdofs[j]) += 1.0 / vals[j];
2050  }
2051  else if (type == ARITHMETIC)
2052  {
2053  (*this)(vdofs[j]) += vals[j];
2054  }
2055  else { MFEM_ABORT("Not implemented"); }
2056 
2057  zones_per_vdof[vdofs[j]]++;
2058  }
2059  }
2060 }
2061 
2063  AvgType type,
2064  Array<int> &zones_per_vdof)
2065 {
2066  zones_per_vdof.SetSize(fes->GetVSize());
2067  zones_per_vdof = 0;
2068 
2069  // Local interpolation
2070  Array<int> vdofs;
2071  Vector vals;
2072  *this = 0.0;
2073 
2074  HostReadWrite();
2075 
2076  for (int i = 0; i < fes->GetNE(); i++)
2077  {
2078  fes->GetElementVDofs(i, vdofs);
2079  // Local interpolation of coeff.
2080  vals.SetSize(vdofs.Size());
2081  fes->GetFE(i)->Project(vcoeff, *fes->GetElementTransformation(i), vals);
2082 
2083  // Accumulate values in all dofs, count the zones.
2084  for (int j = 0; j < vdofs.Size(); j++)
2085  {
2086  int ldof;
2087  int isign;
2088  if (vdofs[j] < 0 )
2089  {
2090  ldof = -1-vdofs[j];
2091  isign = -1;
2092  }
2093  else
2094  {
2095  ldof = vdofs[j];
2096  isign = 1;
2097  }
2098 
2099  if (type == HARMONIC)
2100  {
2101  MFEM_VERIFY(vals[j] != 0.0,
2102  "Coefficient has zeros, harmonic avg is undefined!");
2103  (*this)(ldof) += isign / vals[j];
2104  }
2105  else if (type == ARITHMETIC)
2106  {
2107  (*this)(ldof) += isign*vals[j];
2108 
2109  }
2110  else { MFEM_ABORT("Not implemented"); }
2111 
2112  zones_per_vdof[ldof]++;
2113  }
2114  }
2115 }
2116 
2118  Coefficient *coeff[], VectorCoefficient *vcoeff, Array<int> &attr,
2119  Array<int> &values_counter)
2120 {
2121  int i, j, fdof, d, ind, vdim;
2122  double val;
2123  const FiniteElement *fe;
2124  ElementTransformation *transf;
2125  Array<int> vdofs;
2126  Vector vc;
2127 
2128  values_counter.SetSize(Size());
2129  values_counter = 0;
2130 
2131  vdim = fes->GetVDim();
2132 
2133  HostReadWrite();
2134 
2135  for (i = 0; i < fes->GetNBE(); i++)
2136  {
2137  if (attr[fes->GetBdrAttribute(i) - 1] == 0) { continue; }
2138 
2139  fe = fes->GetBE(i);
2140  fdof = fe->GetDof();
2141  transf = fes->GetBdrElementTransformation(i);
2142  const IntegrationRule &ir = fe->GetNodes();
2143  fes->GetBdrElementVDofs(i, vdofs);
2144 
2145  for (j = 0; j < fdof; j++)
2146  {
2147  const IntegrationPoint &ip = ir.IntPoint(j);
2148  transf->SetIntPoint(&ip);
2149  if (vcoeff) { vcoeff->Eval(vc, *transf, ip); }
2150  for (d = 0; d < vdim; d++)
2151  {
2152  if (!vcoeff && !coeff[d]) { continue; }
2153 
2154  val = vcoeff ? vc(d) : coeff[d]->Eval(*transf, ip);
2155  if ( (ind = vdofs[fdof*d+j]) < 0 )
2156  {
2157  val = -val, ind = -1-ind;
2158  }
2159  if (++values_counter[ind] == 1)
2160  {
2161  (*this)(ind) = val;
2162  }
2163  else
2164  {
2165  (*this)(ind) += val;
2166  }
2167  }
2168  }
2169  }
2170 
2171  // In the case of partially conforming space, i.e. (fes->cP != NULL), we need
2172  // to set the values of all dofs on which the dofs set above depend.
2173  // Dependency is defined from the matrix A = cP.cR: dof i depends on dof j
2174  // iff A_ij != 0. It is sufficient to resolve just the first level of
2175  // dependency, since A is a projection matrix: A^n = A due to cR.cP = I.
2176  // Cases like these arise in 3D when boundary edges are constrained by
2177  // (depend on) internal faces/elements. We use the virtual method
2178  // GetBoundaryClosure from NCMesh to resolve the dependencies.
2179 
2180  if (fes->Nonconforming() && fes->GetMesh()->Dimension() == 3)
2181  {
2182  Vector vals;
2183  Mesh *mesh = fes->GetMesh();
2184  NCMesh *ncmesh = mesh->ncmesh;
2185  Array<int> bdr_edges, bdr_vertices;
2186  ncmesh->GetBoundaryClosure(attr, bdr_vertices, bdr_edges);
2187 
2188  for (i = 0; i < bdr_edges.Size(); i++)
2189  {
2190  int edge = bdr_edges[i];
2191  fes->GetEdgeVDofs(edge, vdofs);
2192  if (vdofs.Size() == 0) { continue; }
2193 
2194  transf = mesh->GetEdgeTransformation(edge);
2195  transf->Attribute = -1; // TODO: set the boundary attribute
2196  fe = fes->GetEdgeElement(edge);
2197  if (!vcoeff)
2198  {
2199  vals.SetSize(fe->GetDof());
2200  for (d = 0; d < vdim; d++)
2201  {
2202  if (!coeff[d]) { continue; }
2203 
2204  fe->Project(*coeff[d], *transf, vals);
2205  for (int k = 0; k < vals.Size(); k++)
2206  {
2207  ind = vdofs[d*vals.Size()+k];
2208  if (++values_counter[ind] == 1)
2209  {
2210  (*this)(ind) = vals(k);
2211  }
2212  else
2213  {
2214  (*this)(ind) += vals(k);
2215  }
2216  }
2217  }
2218  }
2219  else // vcoeff != NULL
2220  {
2221  vals.SetSize(vdim*fe->GetDof());
2222  fe->Project(*vcoeff, *transf, vals);
2223  for (int k = 0; k < vals.Size(); k++)
2224  {
2225  ind = vdofs[k];
2226  if (++values_counter[ind] == 1)
2227  {
2228  (*this)(ind) = vals(k);
2229  }
2230  else
2231  {
2232  (*this)(ind) += vals(k);
2233  }
2234  }
2235  }
2236  }
2237  }
2238 }
2239 
2240 static void accumulate_dofs(const Array<int> &dofs, const Vector &vals,
2241  Vector &gf, Array<int> &values_counter)
2242 {
2243  for (int i = 0; i < dofs.Size(); i++)
2244  {
2245  int k = dofs[i];
2246  double val = vals(i);
2247  if (k < 0) { k = -1 - k; val = -val; }
2248  if (++values_counter[k] == 1)
2249  {
2250  gf(k) = val;
2251  }
2252  else
2253  {
2254  gf(k) += val;
2255  }
2256  }
2257 }
2258 
2260  VectorCoefficient &vcoeff, Array<int> &bdr_attr,
2261  Array<int> &values_counter)
2262 {
2263  const FiniteElement *fe;
2265  Array<int> dofs;
2266  Vector lvec;
2267 
2268  values_counter.SetSize(Size());
2269  values_counter = 0;
2270 
2271  HostReadWrite();
2272 
2273  for (int i = 0; i < fes->GetNBE(); i++)
2274  {
2275  if (bdr_attr[fes->GetBdrAttribute(i)-1] == 0)
2276  {
2277  continue;
2278  }
2279  fe = fes->GetBE(i);
2281  DofTransformation *dof_tr = fes->GetBdrElementDofs(i, dofs);
2282  lvec.SetSize(fe->GetDof());
2283  fe->Project(vcoeff, *T, lvec);
2284  if (dof_tr) { dof_tr->TransformPrimal(lvec); }
2285  accumulate_dofs(dofs, lvec, *this, values_counter);
2286  }
2287 
2288  if (fes->Nonconforming() && fes->GetMesh()->Dimension() == 3)
2289  {
2290  Mesh *mesh = fes->GetMesh();
2291  NCMesh *ncmesh = mesh->ncmesh;
2292  Array<int> bdr_edges, bdr_vertices;
2293  ncmesh->GetBoundaryClosure(bdr_attr, bdr_vertices, bdr_edges);
2294 
2295  for (int i = 0; i < bdr_edges.Size(); i++)
2296  {
2297  int edge = bdr_edges[i];
2298  fes->GetEdgeDofs(edge, dofs);
2299  if (dofs.Size() == 0) { continue; }
2300 
2301  T = mesh->GetEdgeTransformation(edge);
2302  T->Attribute = -1; // TODO: set the boundary attribute
2303  fe = fes->GetEdgeElement(edge);
2304  lvec.SetSize(fe->GetDof());
2305  fe->Project(vcoeff, *T, lvec);
2306  accumulate_dofs(dofs, lvec, *this, values_counter);
2307  }
2308  }
2309 }
2310 
2311 void GridFunction::ComputeMeans(AvgType type, Array<int> &zones_per_vdof)
2312 {
2313  switch (type)
2314  {
2315  case ARITHMETIC:
2316  for (int i = 0; i < size; i++)
2317  {
2318  const int nz = zones_per_vdof[i];
2319  if (nz) { (*this)(i) /= nz; }
2320  }
2321  break;
2322 
2323  case HARMONIC:
2324  for (int i = 0; i < size; i++)
2325  {
2326  const int nz = zones_per_vdof[i];
2327  if (nz) { (*this)(i) = nz/(*this)(i); }
2328  }
2329  break;
2330 
2331  default:
2332  MFEM_ABORT("invalid AvgType");
2333  }
2334 }
2335 
2337  double &integral)
2338 {
2339  if (!fes->GetNE())
2340  {
2341  integral = 0.0;
2342  return;
2343  }
2344 
2345  Mesh *mesh = fes->GetMesh();
2346  const int dim = mesh->Dimension();
2347  const double *center = delta_coeff.Center();
2348  const double *vert = mesh->GetVertex(0);
2349  double min_dist, dist;
2350  int v_idx = 0;
2351 
2352  // find the vertex closest to the center of the delta function
2353  min_dist = Distance(center, vert, dim);
2354  for (int i = 0; i < mesh->GetNV(); i++)
2355  {
2356  vert = mesh->GetVertex(i);
2357  dist = Distance(center, vert, dim);
2358  if (dist < min_dist)
2359  {
2360  min_dist = dist;
2361  v_idx = i;
2362  }
2363  }
2364 
2365  (*this) = 0.0;
2366  integral = 0.0;
2367 
2368  if (min_dist >= delta_coeff.Tol())
2369  {
2370  return;
2371  }
2372 
2373  // find the elements that have 'v_idx' as a vertex
2374  MassIntegrator Mi(*delta_coeff.Weight());
2375  DenseMatrix loc_mass;
2376  Array<int> vdofs, vertices;
2377  Vector vals, loc_mass_vals;
2378  for (int i = 0; i < mesh->GetNE(); i++)
2379  {
2380  mesh->GetElementVertices(i, vertices);
2381  for (int j = 0; j < vertices.Size(); j++)
2382  if (vertices[j] == v_idx)
2383  {
2384  const FiniteElement *fe = fes->GetFE(i);
2385  Mi.AssembleElementMatrix(*fe, *fes->GetElementTransformation(i),
2386  loc_mass);
2387  vals.SetSize(fe->GetDof());
2388  fe->ProjectDelta(j, vals);
2389  fes->GetElementVDofs(i, vdofs);
2390  SetSubVector(vdofs, vals);
2391  loc_mass_vals.SetSize(vals.Size());
2392  loc_mass.Mult(vals, loc_mass_vals);
2393  integral += loc_mass_vals.Sum(); // partition of unity basis
2394  break;
2395  }
2396  }
2397 }
2398 
2400 {
2401  DeltaCoefficient *delta_c = dynamic_cast<DeltaCoefficient *>(&coeff);
2402  DofTransformation * doftrans = NULL;
2403 
2404  if (delta_c == NULL)
2405  {
2406  Array<int> vdofs;
2407  Vector vals;
2408 
2409  for (int i = 0; i < fes->GetNE(); i++)
2410  {
2411  doftrans = fes->GetElementVDofs(i, vdofs);
2412  vals.SetSize(vdofs.Size());
2413  fes->GetFE(i)->Project(coeff, *fes->GetElementTransformation(i), vals);
2414  if (doftrans)
2415  {
2416  doftrans->TransformPrimal(vals);
2417  }
2418  SetSubVector(vdofs, vals);
2419  }
2420  }
2421  else
2422  {
2423  double integral;
2424 
2425  ProjectDeltaCoefficient(*delta_c, integral);
2426 
2427  (*this) *= (delta_c->Scale() / integral);
2428  }
2429 }
2430 
2432  Coefficient &coeff, Array<int> &dofs, int vd)
2433 {
2434  int el = -1;
2435  ElementTransformation *T = NULL;
2436  const FiniteElement *fe = NULL;
2437 
2438  fes->BuildDofToArrays(); // ensures GetElementForDof(), GetLocalDofForDof() initialized.
2439 
2440  for (int i = 0; i < dofs.Size(); i++)
2441  {
2442  int dof = dofs[i], j = fes->GetElementForDof(dof);
2443  if (el != j)
2444  {
2445  el = j;
2446  T = fes->GetElementTransformation(el);
2447  fe = fes->GetFE(el);
2448  }
2449  int vdof = fes->DofToVDof(dof, vd);
2450  int ld = fes->GetLocalDofForDof(dof);
2451  const IntegrationPoint &ip = fe->GetNodes().IntPoint(ld);
2452  T->SetIntPoint(&ip);
2453  (*this)(vdof) = coeff.Eval(*T, ip);
2454  }
2455 }
2456 
2458 {
2459  int i;
2460  Array<int> vdofs;
2461  Vector vals;
2462 
2463  DofTransformation * doftrans = NULL;
2464 
2465  for (i = 0; i < fes->GetNE(); i++)
2466  {
2467  doftrans = fes->GetElementVDofs(i, vdofs);
2468  vals.SetSize(vdofs.Size());
2469  fes->GetFE(i)->Project(vcoeff, *fes->GetElementTransformation(i), vals);
2470  if (doftrans)
2471  {
2472  doftrans->TransformPrimal(vals);
2473  }
2474  SetSubVector(vdofs, vals);
2475  }
2476 }
2477 
2479  VectorCoefficient &vcoeff, Array<int> &dofs)
2480 {
2481  int el = -1;
2482  ElementTransformation *T = NULL;
2483  const FiniteElement *fe = NULL;
2484 
2485  Vector val;
2486 
2487  fes->BuildDofToArrays(); // ensures GetElementForDof(), GetLocalDofForDof() initialized.
2488 
2489  for (int i = 0; i < dofs.Size(); i++)
2490  {
2491  int dof = dofs[i], j = fes->GetElementForDof(dof);
2492  if (el != j)
2493  {
2494  el = j;
2495  T = fes->GetElementTransformation(el);
2496  fe = fes->GetFE(el);
2497  }
2498  int ld = fes->GetLocalDofForDof(dof);
2499  const IntegrationPoint &ip = fe->GetNodes().IntPoint(ld);
2500  T->SetIntPoint(&ip);
2501  vcoeff.Eval(val, *T, ip);
2502  for (int vd = 0; vd < fes->GetVDim(); vd ++)
2503  {
2504  int vdof = fes->DofToVDof(dof, vd);
2505  (*this)(vdof) = val(vd);
2506  }
2507  }
2508 }
2509 
2511 {
2512  int i;
2513  Array<int> vdofs;
2514  Vector vals;
2515 
2516  DofTransformation * doftrans = NULL;
2517 
2518  for (i = 0; i < fes->GetNE(); i++)
2519  {
2520  if (fes->GetAttribute(i) != attribute)
2521  {
2522  continue;
2523  }
2524 
2525  doftrans = fes->GetElementVDofs(i, vdofs);
2526  vals.SetSize(vdofs.Size());
2527  fes->GetFE(i)->Project(vcoeff, *fes->GetElementTransformation(i), vals);
2528  if (doftrans)
2529  {
2530  doftrans->TransformPrimal(vals);
2531  }
2532  SetSubVector(vdofs, vals);
2533  }
2534 }
2535 
2537 {
2538  int i, j, fdof, d, ind, vdim;
2539  double val;
2540  const FiniteElement *fe;
2541  ElementTransformation *transf;
2542  // DofTransformation * doftrans;
2543  Array<int> vdofs;
2544 
2545  vdim = fes->GetVDim();
2546  for (i = 0; i < fes->GetNE(); i++)
2547  {
2548  fe = fes->GetFE(i);
2549  fdof = fe->GetDof();
2550  transf = fes->GetElementTransformation(i);
2551  const IntegrationRule &ir = fe->GetNodes();
2552  // doftrans = fes->GetElementVDofs(i, vdofs);
2553  fes->GetElementVDofs(i, vdofs);
2554  for (j = 0; j < fdof; j++)
2555  {
2556  const IntegrationPoint &ip = ir.IntPoint(j);
2557  transf->SetIntPoint(&ip);
2558  for (d = 0; d < vdim; d++)
2559  {
2560  if (!coeff[d]) { continue; }
2561 
2562  val = coeff[d]->Eval(*transf, ip);
2563  if ( (ind = vdofs[fdof*d+j]) < 0 )
2564  {
2565  val = -val, ind = -1-ind;
2566  }
2567  (*this)(ind) = val;
2568  }
2569  }
2570  }
2571 }
2572 
2574  Array<int> &dof_attr)
2575 {
2576  Array<int> vdofs;
2577  Vector vals;
2578 
2579  HostWrite();
2580  // maximal element attribute for each dof
2581  dof_attr.SetSize(fes->GetVSize());
2582  dof_attr = -1;
2583 
2584  // local projection
2585  for (int i = 0; i < fes->GetNE(); i++)
2586  {
2587  fes->GetElementVDofs(i, vdofs);
2588  vals.SetSize(vdofs.Size());
2589  fes->GetFE(i)->Project(coeff, *fes->GetElementTransformation(i), vals);
2590 
2591  // the values in shared dofs are determined from the element with maximal
2592  // attribute
2593  int attr = fes->GetAttribute(i);
2594  for (int j = 0; j < vdofs.Size(); j++)
2595  {
2596  if (attr > dof_attr[vdofs[j]])
2597  {
2598  (*this)(vdofs[j]) = vals[j];
2599  dof_attr[vdofs[j]] = attr;
2600  }
2601  }
2602  }
2603 }
2604 
2606 {
2607  Array<int> dof_attr;
2608  ProjectDiscCoefficient(coeff, dof_attr);
2609 }
2610 
2612 {
2613  // Harmonic (x1 ... xn) = [ (1/x1 + ... + 1/xn) / n ]^-1.
2614  // Arithmetic(x1 ... xn) = (x1 + ... + xn) / n.
2615 
2616  Array<int> zones_per_vdof;
2617  AccumulateAndCountZones(coeff, type, zones_per_vdof);
2618 
2619  ComputeMeans(type, zones_per_vdof);
2620 }
2621 
2623  AvgType type)
2624 {
2625  Array<int> zones_per_vdof;
2626  AccumulateAndCountZones(coeff, type, zones_per_vdof);
2627 
2628  ComputeMeans(type, zones_per_vdof);
2629 }
2630 
2632  Array<int> &attr)
2633 {
2634  Array<int> values_counter;
2635  AccumulateAndCountBdrValues(NULL, &vcoeff, attr, values_counter);
2636  ComputeMeans(ARITHMETIC, values_counter);
2637 
2638 #ifdef MFEM_DEBUG
2639  Array<int> ess_vdofs_marker;
2640  fes->GetEssentialVDofs(attr, ess_vdofs_marker);
2641  for (int i = 0; i < values_counter.Size(); i++)
2642  {
2643  MFEM_ASSERT(bool(values_counter[i]) == bool(ess_vdofs_marker[i]),
2644  "internal error");
2645  }
2646 #endif
2647 }
2648 
2650 {
2651  Array<int> values_counter;
2652  // this->HostReadWrite(); // done inside the next call
2653  AccumulateAndCountBdrValues(coeff, NULL, attr, values_counter);
2654  ComputeMeans(ARITHMETIC, values_counter);
2655 
2656 #ifdef MFEM_DEBUG
2657  Array<int> ess_vdofs_marker(Size());
2658  ess_vdofs_marker = 0;
2659  Array<int> component_dof_marker;
2660  for (int i = 0; i < fes->GetVDim(); i++)
2661  {
2662  if (!coeff[i]) { continue; }
2663  fes->GetEssentialVDofs(attr, component_dof_marker,i);
2664  for (int j = 0; j<Size(); j++)
2665  {
2666  ess_vdofs_marker[j] = bool(ess_vdofs_marker[j]) ||
2667  bool(component_dof_marker[j]);
2668  }
2669  }
2670  for (int i = 0; i < values_counter.Size(); i++)
2671  {
2672  MFEM_ASSERT(bool(values_counter[i]) == ess_vdofs_marker[i],
2673  "internal error");
2674  }
2675 #endif
2676 }
2677 
2679  VectorCoefficient &vcoeff, Array<int> &bdr_attr)
2680 {
2681 #if 0
2682  // implementation for the case when the face dofs are integrals of the
2683  // normal component.
2684  const FiniteElement *fe;
2686  Array<int> dofs;
2687  int dim = vcoeff.GetVDim();
2688  Vector vc(dim), nor(dim), lvec, shape;
2689 
2690  for (int i = 0; i < fes->GetNBE(); i++)
2691  {
2692  if (bdr_attr[fes->GetBdrAttribute(i)-1] == 0)
2693  {
2694  continue;
2695  }
2696  fe = fes->GetBE(i);
2698  int intorder = 2*fe->GetOrder(); // !!!
2699  const IntegrationRule &ir = IntRules.Get(fe->GetGeomType(), intorder);
2700  int nd = fe->GetDof();
2701  lvec.SetSize(nd);
2702  shape.SetSize(nd);
2703  lvec = 0.0;
2704  for (int j = 0; j < ir.GetNPoints(); j++)
2705  {
2706  const IntegrationPoint &ip = ir.IntPoint(j);
2707  T->SetIntPoint(&ip);
2708  vcoeff.Eval(vc, *T, ip);
2709  CalcOrtho(T->Jacobian(), nor);
2710  fe->CalcShape(ip, shape);
2711  lvec.Add(ip.weight * (vc * nor), shape);
2712  }
2713  fes->GetBdrElementDofs(i, dofs);
2714  SetSubVector(dofs, lvec);
2715  }
2716 #else
2717  // implementation for the case when the face dofs are scaled point
2718  // values of the normal component.
2719  const FiniteElement *fe;
2721  Array<int> dofs;
2722  int dim = vcoeff.GetVDim();
2723  Vector vc(dim), nor(dim), lvec;
2724 
2725  for (int i = 0; i < fes->GetNBE(); i++)
2726  {
2727  if (bdr_attr[fes->GetBdrAttribute(i)-1] == 0)
2728  {
2729  continue;
2730  }
2731  fe = fes->GetBE(i);
2733  const IntegrationRule &ir = fe->GetNodes();
2734  lvec.SetSize(fe->GetDof());
2735  for (int j = 0; j < ir.GetNPoints(); j++)
2736  {
2737  const IntegrationPoint &ip = ir.IntPoint(j);
2738  T->SetIntPoint(&ip);
2739  vcoeff.Eval(vc, *T, ip);
2740  CalcOrtho(T->Jacobian(), nor);
2741  lvec(j) = (vc * nor);
2742  }
2743  fes->GetBdrElementDofs(i, dofs);
2744  SetSubVector(dofs, lvec);
2745  }
2746 #endif
2747 }
2748 
2750  VectorCoefficient &vcoeff, Array<int> &bdr_attr)
2751 {
2752  Array<int> values_counter;
2753  AccumulateAndCountBdrTangentValues(vcoeff, bdr_attr, values_counter);
2754  ComputeMeans(ARITHMETIC, values_counter);
2755 #ifdef MFEM_DEBUG
2756  Array<int> ess_vdofs_marker;
2757  fes->GetEssentialVDofs(bdr_attr, ess_vdofs_marker);
2758  for (int i = 0; i < values_counter.Size(); i++)
2759  {
2760  MFEM_ASSERT(bool(values_counter[i]) == bool(ess_vdofs_marker[i]),
2761  "internal error");
2762  }
2763 #endif
2764 }
2765 
2767  Coefficient *exsol[], const IntegrationRule *irs[],
2768  const Array<int> *elems) const
2769 {
2770  double error = 0.0, a;
2771  const FiniteElement *fe;
2772  ElementTransformation *transf;
2773  Vector shape;
2774  Array<int> vdofs;
2775  int fdof, d, i, intorder, j, k;
2776 
2777  for (i = 0; i < fes->GetNE(); i++)
2778  {
2779  if (elems != NULL && (*elems)[i] == 0) { continue; }
2780  fe = fes->GetFE(i);
2781  fdof = fe->GetDof();
2782  transf = fes->GetElementTransformation(i);
2783  shape.SetSize(fdof);
2784  intorder = 2*fe->GetOrder() + 3; // <----------
2785  const IntegrationRule *ir;
2786  if (irs)
2787  {
2788  ir = irs[fe->GetGeomType()];
2789  }
2790  else
2791  {
2792  ir = &(IntRules.Get(fe->GetGeomType(), intorder));
2793  }
2794  fes->GetElementVDofs(i, vdofs);
2795  for (j = 0; j < ir->GetNPoints(); j++)
2796  {
2797  const IntegrationPoint &ip = ir->IntPoint(j);
2798  fe->CalcShape(ip, shape);
2799  for (d = 0; d < fes->GetVDim(); d++)
2800  {
2801  a = 0;
2802  for (k = 0; k < fdof; k++)
2803  if (vdofs[fdof*d+k] >= 0)
2804  {
2805  a += (*this)(vdofs[fdof*d+k]) * shape(k);
2806  }
2807  else
2808  {
2809  a -= (*this)(-1-vdofs[fdof*d+k]) * shape(k);
2810  }
2811  transf->SetIntPoint(&ip);
2812  a -= exsol[d]->Eval(*transf, ip);
2813  error += ip.weight * transf->Weight() * a * a;
2814  }
2815  }
2816  }
2817 
2818  return (error < 0.0) ? -sqrt(-error) : sqrt(error);
2819 }
2820 
2822  VectorCoefficient &exsol, const IntegrationRule *irs[],
2823  const Array<int> *elems) const
2824 {
2825  double error = 0.0;
2826  const FiniteElement *fe;
2828  DenseMatrix vals, exact_vals;
2829  Vector loc_errs;
2830 
2831  for (int i = 0; i < fes->GetNE(); i++)
2832  {
2833  if (elems != NULL && (*elems)[i] == 0) { continue; }
2834  fe = fes->GetFE(i);
2835  int intorder = 2*fe->GetOrder() + 3; // <----------
2836  const IntegrationRule *ir;
2837  if (irs)
2838  {
2839  ir = irs[fe->GetGeomType()];
2840  }
2841  else
2842  {
2843  ir = &(IntRules.Get(fe->GetGeomType(), intorder));
2844  }
2845  T = fes->GetElementTransformation(i);
2846  GetVectorValues(*T, *ir, vals);
2847  exsol.Eval(exact_vals, *T, *ir);
2848  vals -= exact_vals;
2849  loc_errs.SetSize(vals.Width());
2850  vals.Norm2(loc_errs);
2851  for (int j = 0; j < ir->GetNPoints(); j++)
2852  {
2853  const IntegrationPoint &ip = ir->IntPoint(j);
2854  T->SetIntPoint(&ip);
2855  error += ip.weight * T->Weight() * (loc_errs(j) * loc_errs(j));
2856  }
2857  }
2858 
2859  return (error < 0.0) ? -sqrt(-error) : sqrt(error);
2860 }
2861 
2863  VectorCoefficient *exgrad,
2864  const IntegrationRule *irs[]) const
2865 {
2866  double error = 0.0;
2867  const FiniteElement *fe;
2869  Array<int> dofs;
2870  Vector grad;
2871  int intorder;
2872  int dim = fes->GetMesh()->SpaceDimension();
2873  Vector vec(dim);
2874 
2875  fe = fes->GetFE(ielem);
2876  Tr = fes->GetElementTransformation(ielem);
2877  intorder = 2*fe->GetOrder() + 3; // <--------
2878  const IntegrationRule *ir;
2879  if (irs)
2880  {
2881  ir = irs[fe->GetGeomType()];
2882  }
2883  else
2884  {
2885  ir = &(IntRules.Get(fe->GetGeomType(), intorder));
2886  }
2887  fes->GetElementDofs(ielem, dofs);
2888  for (int j = 0; j < ir->GetNPoints(); j++)
2889  {
2890  const IntegrationPoint &ip = ir->IntPoint(j);
2891  Tr->SetIntPoint(&ip);
2892  GetGradient(*Tr,grad);
2893  exgrad->Eval(vec,*Tr,ip);
2894  vec-=grad;
2895  error += ip.weight * Tr->Weight() * (vec * vec);
2896  }
2897  return (error < 0.0) ? -sqrt(-error) : sqrt(error);
2898 }
2899 
2901  const IntegrationRule *irs[]) const
2902 {
2903  double error = 0.0;
2904  const FiniteElement *fe;
2906  Array<int> dofs;
2907  Vector grad;
2908  int intorder;
2909  int dim = fes->GetMesh()->SpaceDimension();
2910  Vector vec(dim);
2911 
2912  for (int i = 0; i < fes->GetNE(); i++)
2913  {
2914  fe = fes->GetFE(i);
2915  Tr = fes->GetElementTransformation(i);
2916  intorder = 2*fe->GetOrder() + 3; // <--------
2917  const IntegrationRule *ir;
2918  if (irs)
2919  {
2920  ir = irs[fe->GetGeomType()];
2921  }
2922  else
2923  {
2924  ir = &(IntRules.Get(fe->GetGeomType(), intorder));
2925  }
2926  fes->GetElementDofs(i, dofs);
2927  for (int j = 0; j < ir->GetNPoints(); j++)
2928  {
2929  const IntegrationPoint &ip = ir->IntPoint(j);
2930  Tr->SetIntPoint(&ip);
2931  GetGradient(*Tr,grad);
2932  exgrad->Eval(vec,*Tr,ip);
2933  vec-=grad;
2934  error += ip.weight * Tr->Weight() * (vec * vec);
2935  }
2936  }
2937  return (error < 0.0) ? -sqrt(-error) : sqrt(error);
2938 }
2939 
2941  const IntegrationRule *irs[]) const
2942 {
2943  double error = 0.0;
2944  const FiniteElement *fe;
2946  Array<int> dofs;
2947  int intorder;
2948  int n = CurlDim();
2949  Vector curl(n);
2950  Vector vec(n);
2951 
2952  for (int i = 0; i < fes->GetNE(); i++)
2953  {
2954  fe = fes->GetFE(i);
2955  Tr = fes->GetElementTransformation(i);
2956  intorder = 2*fe->GetOrder() + 3;
2957  const IntegrationRule *ir;
2958  if (irs)
2959  {
2960  ir = irs[fe->GetGeomType()];
2961  }
2962  else
2963  {
2964  ir = &(IntRules.Get(fe->GetGeomType(), intorder));
2965  }
2966  fes->GetElementDofs(i, dofs);
2967  for (int j = 0; j < ir->GetNPoints(); j++)
2968  {
2969  const IntegrationPoint &ip = ir->IntPoint(j);
2970  Tr->SetIntPoint(&ip);
2971  GetCurl(*Tr,curl);
2972  excurl->Eval(vec,*Tr,ip);
2973  vec-=curl;
2974  error += ip.weight * Tr->Weight() * ( vec * vec );
2975  }
2976  }
2977 
2978  return (error < 0.0) ? -sqrt(-error) : sqrt(error);
2979 }
2980 
2982  Coefficient *exdiv, const IntegrationRule *irs[]) const
2983 {
2984  double error = 0.0, a;
2985  const FiniteElement *fe;
2987  Array<int> dofs;
2988  int intorder;
2989 
2990  for (int i = 0; i < fes->GetNE(); i++)
2991  {
2992  fe = fes->GetFE(i);
2993  Tr = fes->GetElementTransformation(i);
2994  intorder = 2*fe->GetOrder() + 3;
2995  const IntegrationRule *ir;
2996  if (irs)
2997  {
2998  ir = irs[fe->GetGeomType()];
2999  }
3000  else
3001  {
3002  ir = &(IntRules.Get(fe->GetGeomType(), intorder));
3003  }
3004  fes->GetElementDofs(i, dofs);
3005  for (int j = 0; j < ir->GetNPoints(); j++)
3006  {
3007  const IntegrationPoint &ip = ir->IntPoint(j);
3008  Tr->SetIntPoint (&ip);
3009  a = GetDivergence(*Tr) - exdiv->Eval(*Tr, ip);
3010  error += ip.weight * Tr->Weight() * a * a;
3011  }
3012  }
3013 
3014  return (error < 0.0) ? -sqrt(-error) : sqrt(error);
3015 }
3016 
3018  Coefficient *ell_coeff,
3019  class JumpScaling jump_scaling,
3020  const IntegrationRule *irs[]) const
3021 {
3022  int fdof, intorder, k;
3023  Mesh *mesh;
3024  const FiniteElement *fe;
3025  ElementTransformation *transf;
3026  FaceElementTransformations *face_elem_transf;
3027  Vector shape, el_dofs, err_val, ell_coeff_val;
3028  Array<int> vdofs;
3029  IntegrationPoint eip;
3030  double error = 0.0;
3031 
3032  mesh = fes->GetMesh();
3033 
3034  for (int i = 0; i < mesh->GetNumFaces(); i++)
3035  {
3036  int i1, i2;
3037  mesh->GetFaceElements(i, &i1, &i2);
3038  double h = mesh->GetElementSize(i1);
3039  intorder = fes->GetFE(i1)->GetOrder();
3040  if (i2 >= 0)
3041  {
3042  if ( (k = fes->GetFE(i2)->GetOrder()) > intorder )
3043  {
3044  intorder = k;
3045  }
3046  h = std::min(h, mesh->GetElementSize(i2));
3047  }
3048  int p = intorder;
3049  intorder = 2 * intorder; // <-------------
3050  face_elem_transf = mesh->GetFaceElementTransformations(i, 5);
3051  const IntegrationRule *ir;
3052  if (irs)
3053  {
3054  ir = irs[face_elem_transf->GetGeometryType()];
3055  }
3056  else
3057  {
3058  ir = &(IntRules.Get(face_elem_transf->GetGeometryType(), intorder));
3059  }
3060  err_val.SetSize(ir->GetNPoints());
3061  ell_coeff_val.SetSize(ir->GetNPoints());
3062  // side 1
3063  transf = face_elem_transf->Elem1;
3064  fe = fes->GetFE(i1);
3065  fdof = fe->GetDof();
3066  fes->GetElementVDofs(i1, vdofs);
3067  shape.SetSize(fdof);
3068  el_dofs.SetSize(fdof);
3069  for (k = 0; k < fdof; k++)
3070  if (vdofs[k] >= 0)
3071  {
3072  el_dofs(k) = (*this)(vdofs[k]);
3073  }
3074  else
3075  {
3076  el_dofs(k) = - (*this)(-1-vdofs[k]);
3077  }
3078  for (int j = 0; j < ir->GetNPoints(); j++)
3079  {
3080  face_elem_transf->Loc1.Transform(ir->IntPoint(j), eip);
3081  fe->CalcShape(eip, shape);
3082  transf->SetIntPoint(&eip);
3083  ell_coeff_val(j) = ell_coeff->Eval(*transf, eip);
3084  err_val(j) = exsol->Eval(*transf, eip) - (shape * el_dofs);
3085  }
3086  if (i2 >= 0)
3087  {
3088  // side 2
3089  face_elem_transf = mesh->GetFaceElementTransformations(i, 10);
3090  transf = face_elem_transf->Elem2;
3091  fe = fes->GetFE(i2);
3092  fdof = fe->GetDof();
3093  fes->GetElementVDofs(i2, vdofs);
3094  shape.SetSize(fdof);
3095  el_dofs.SetSize(fdof);
3096  for (k = 0; k < fdof; k++)
3097  if (vdofs[k] >= 0)
3098  {
3099  el_dofs(k) = (*this)(vdofs[k]);
3100  }
3101  else
3102  {
3103  el_dofs(k) = - (*this)(-1-vdofs[k]);
3104  }
3105  for (int j = 0; j < ir->GetNPoints(); j++)
3106  {
3107  face_elem_transf->Loc2.Transform(ir->IntPoint(j), eip);
3108  fe->CalcShape(eip, shape);
3109  transf->SetIntPoint(&eip);
3110  ell_coeff_val(j) += ell_coeff->Eval(*transf, eip);
3111  ell_coeff_val(j) *= 0.5;
3112  err_val(j) -= (exsol->Eval(*transf, eip) - (shape * el_dofs));
3113  }
3114  }
3115  face_elem_transf = mesh->GetFaceElementTransformations(i, 16);
3116  transf = face_elem_transf;
3117  for (int j = 0; j < ir->GetNPoints(); j++)
3118  {
3119  const IntegrationPoint &ip = ir->IntPoint(j);
3120  transf->SetIntPoint(&ip);
3121  double nu = jump_scaling.Eval(h, p);
3122  error += (ip.weight * nu * ell_coeff_val(j) *
3123  transf->Weight() *
3124  err_val(j) * err_val(j));
3125  }
3126  }
3127 
3128  return (error < 0.0) ? -sqrt(-error) : sqrt(error);
3129 }
3130 
3132  Coefficient *ell_coeff,
3133  double Nu,
3134  const IntegrationRule *irs[]) const
3135 {
3136  return ComputeDGFaceJumpError(
3137  exsol, ell_coeff, {Nu, JumpScaling::ONE_OVER_H}, irs);
3138 }
3139 
3141  VectorCoefficient *exgrad,
3142  Coefficient *ell_coef, double Nu,
3143  int norm_type) const
3144 {
3145  double error1 = 0.0;
3146  double error2 = 0.0;
3147  if (norm_type & 1) { error1 = GridFunction::ComputeGradError(exgrad); }
3148  if (norm_type & 2)
3149  {
3151  exsol, ell_coef, {Nu, JumpScaling::ONE_OVER_H});
3152  }
3153 
3154  return sqrt(error1 * error1 + error2 * error2);
3155 }
3156 
3158  VectorCoefficient *exgrad,
3159  const IntegrationRule *irs[]) const
3160 {
3161  double L2error = GridFunction::ComputeLpError(2.0,*exsol,NULL,irs);
3162  double GradError = GridFunction::ComputeGradError(exgrad,irs);
3163  return sqrt(L2error*L2error + GradError*GradError);
3164 }
3165 
3167  Coefficient *exdiv,
3168  const IntegrationRule *irs[]) const
3169 {
3170  double L2error = GridFunction::ComputeLpError(2.0,*exsol,NULL,NULL,irs);
3171  double DivError = GridFunction::ComputeDivError(exdiv,irs);
3172  return sqrt(L2error*L2error + DivError*DivError);
3173 }
3174 
3176  VectorCoefficient *excurl,
3177  const IntegrationRule *irs[]) const
3178 {
3179  double L2error = GridFunction::ComputeLpError(2.0,*exsol,NULL,NULL,irs);
3180  double CurlError = GridFunction::ComputeCurlError(excurl,irs);
3181  return sqrt(L2error*L2error + CurlError*CurlError);
3182 }
3183 
3185  Coefficient *exsol[], const IntegrationRule *irs[]) const
3186 {
3187  double error = 0.0, a;
3188  const FiniteElement *fe;
3189  ElementTransformation *transf;
3190  Vector shape;
3191  Array<int> vdofs;
3192  int fdof, d, i, intorder, j, k;
3193 
3194  for (i = 0; i < fes->GetNE(); i++)
3195  {
3196  fe = fes->GetFE(i);
3197  fdof = fe->GetDof();
3198  transf = fes->GetElementTransformation(i);
3199  shape.SetSize(fdof);
3200  intorder = 2*fe->GetOrder() + 3; // <----------
3201  const IntegrationRule *ir;
3202  if (irs)
3203  {
3204  ir = irs[fe->GetGeomType()];
3205  }
3206  else
3207  {
3208  ir = &(IntRules.Get(fe->GetGeomType(), intorder));
3209  }
3210  fes->GetElementVDofs(i, vdofs);
3211  for (j = 0; j < ir->GetNPoints(); j++)
3212  {
3213  const IntegrationPoint &ip = ir->IntPoint(j);
3214  fe->CalcShape(ip, shape);
3215  transf->SetIntPoint(&ip);
3216  for (d = 0; d < fes->GetVDim(); d++)
3217  {
3218  a = 0;
3219  for (k = 0; k < fdof; k++)
3220  if (vdofs[fdof*d+k] >= 0)
3221  {
3222  a += (*this)(vdofs[fdof*d+k]) * shape(k);
3223  }
3224  else
3225  {
3226  a -= (*this)(-1-vdofs[fdof*d+k]) * shape(k);
3227  }
3228  a -= exsol[d]->Eval(*transf, ip);
3229  a = fabs(a);
3230  if (error < a)
3231  {
3232  error = a;
3233  }
3234  }
3235  }
3236  }
3237  return error;
3238 }
3239 
3241  Coefficient *exsol, VectorCoefficient *exgrad, int norm_type,
3242  const Array<int> *elems, const IntegrationRule *irs[]) const
3243 {
3244  // assuming vdim is 1
3245  int i, fdof, dim, intorder, j, k;
3246  Mesh *mesh;
3247  const FiniteElement *fe;
3248  ElementTransformation *transf;
3249  Vector e_grad, a_grad, shape, el_dofs, err_val, ell_coeff_val;
3250  DenseMatrix dshape, dshapet, Jinv;
3251  Array<int> vdofs;
3252  double a, error = 0.0;
3253 
3254  mesh = fes->GetMesh();
3255  dim = mesh->Dimension();
3256  e_grad.SetSize(dim);
3257  a_grad.SetSize(dim);
3258  Jinv.SetSize(dim);
3259 
3260  if (norm_type & 1) // L_1 norm
3261  for (i = 0; i < mesh->GetNE(); i++)
3262  {
3263  if (elems != NULL && (*elems)[i] == 0) { continue; }
3264  fe = fes->GetFE(i);
3265  fdof = fe->GetDof();
3266  transf = fes->GetElementTransformation(i);
3267  el_dofs.SetSize(fdof);
3268  shape.SetSize(fdof);
3269  intorder = 2*fe->GetOrder() + 1; // <----------
3270  const IntegrationRule *ir;
3271  if (irs)
3272  {
3273  ir = irs[fe->GetGeomType()];
3274  }
3275  else
3276  {
3277  ir = &(IntRules.Get(fe->GetGeomType(), intorder));
3278  }
3279  fes->GetElementVDofs(i, vdofs);
3280  for (k = 0; k < fdof; k++)
3281  if (vdofs[k] >= 0)
3282  {
3283  el_dofs(k) = (*this)(vdofs[k]);
3284  }
3285  else
3286  {
3287  el_dofs(k) = -(*this)(-1-vdofs[k]);
3288  }
3289  for (j = 0; j < ir->GetNPoints(); j++)
3290  {
3291  const IntegrationPoint &ip = ir->IntPoint(j);
3292  fe->CalcShape(ip, shape);
3293  transf->SetIntPoint(&ip);
3294  a = (el_dofs * shape) - (exsol->Eval(*transf, ip));
3295  error += ip.weight * transf->Weight() * fabs(a);
3296  }
3297  }
3298 
3299  if (norm_type & 2) // W^1_1 seminorm
3300  for (i = 0; i < mesh->GetNE(); i++)
3301  {
3302  if (elems != NULL && (*elems)[i] == 0) { continue; }
3303  fe = fes->GetFE(i);
3304  fdof = fe->GetDof();
3305  transf = mesh->GetElementTransformation(i);
3306  el_dofs.SetSize(fdof);
3307  dshape.SetSize(fdof, dim);
3308  dshapet.SetSize(fdof, dim);
3309  intorder = 2*fe->GetOrder() + 1; // <----------
3310  const IntegrationRule *ir;
3311  if (irs)
3312  {
3313  ir = irs[fe->GetGeomType()];
3314  }
3315  else
3316  {
3317  ir = &(IntRules.Get(fe->GetGeomType(), intorder));
3318  }
3319  fes->GetElementVDofs(i, vdofs);
3320  for (k = 0; k < fdof; k++)
3321  if (vdofs[k] >= 0)
3322  {
3323  el_dofs(k) = (*this)(vdofs[k]);
3324  }
3325  else
3326  {
3327  el_dofs(k) = -(*this)(-1-vdofs[k]);
3328  }
3329  for (j = 0; j < ir->GetNPoints(); j++)
3330  {
3331  const IntegrationPoint &ip = ir->IntPoint(j);
3332  fe->CalcDShape(ip, dshape);
3333  transf->SetIntPoint(&ip);
3334  exgrad->Eval(e_grad, *transf, ip);
3335  CalcInverse(transf->Jacobian(), Jinv);
3336  Mult(dshape, Jinv, dshapet);
3337  dshapet.MultTranspose(el_dofs, a_grad);
3338  e_grad -= a_grad;
3339  error += ip.weight * transf->Weight() * e_grad.Norml1();
3340  }
3341  }
3342 
3343  return error;
3344 }
3345 
3346 double GridFunction::ComputeLpError(const double p, Coefficient &exsol,
3347  Coefficient *weight,
3348  const IntegrationRule *irs[],
3349  const Array<int> *elems) const
3350 {
3351  double error = 0.0;
3352  const FiniteElement *fe;
3354  Vector vals;
3355 
3356  for (int i = 0; i < fes->GetNE(); i++)
3357  {
3358  if (elems != NULL && (*elems)[i] == 0) { continue; }
3359  fe = fes->GetFE(i);
3360  const IntegrationRule *ir;
3361  if (irs)
3362  {
3363  ir = irs[fe->GetGeomType()];
3364  }
3365  else
3366  {
3367  int intorder = 2*fe->GetOrder() + 3; // <----------
3368  ir = &(IntRules.Get(fe->GetGeomType(), intorder));
3369  }
3370  GetValues(i, *ir, vals);
3371  T = fes->GetElementTransformation(i);
3372  for (int j = 0; j < ir->GetNPoints(); j++)
3373  {
3374  const IntegrationPoint &ip = ir->IntPoint(j);
3375  T->SetIntPoint(&ip);
3376  double diff = fabs(vals(j) - exsol.Eval(*T, ip));
3377  if (p < infinity())
3378  {
3379  diff = pow(diff, p);
3380  if (weight)
3381  {
3382  diff *= weight->Eval(*T, ip);
3383  }
3384  error += ip.weight * T->Weight() * diff;
3385  }
3386  else
3387  {
3388  if (weight)
3389  {
3390  diff *= weight->Eval(*T, ip);
3391  }
3392  error = std::max(error, diff);
3393  }
3394  }
3395  }
3396 
3397  if (p < infinity())
3398  {
3399  // negative quadrature weights may cause the error to be negative
3400  if (error < 0.)
3401  {
3402  error = -pow(-error, 1./p);
3403  }
3404  else
3405  {
3406  error = pow(error, 1./p);
3407  }
3408  }
3409 
3410  return error;
3411 }
3412 
3414  Vector &error,
3415  Coefficient *weight,
3416  const IntegrationRule *irs[]) const
3417 {
3418  MFEM_ASSERT(error.Size() == fes->GetNE(),
3419  "Incorrect size for result vector");
3420 
3421  error = 0.0;
3422  const FiniteElement *fe;
3424  Vector vals;
3425 
3426  for (int i = 0; i < fes->GetNE(); i++)
3427  {
3428  fe = fes->GetFE(i);
3429  const IntegrationRule *ir;
3430  if (irs)
3431  {
3432  ir = irs[fe->GetGeomType()];
3433  }
3434  else
3435  {
3436  int intorder = 2*fe->GetOrder() + 3; // <----------
3437  ir = &(IntRules.Get(fe->GetGeomType(), intorder));
3438  }
3439  GetValues(i, *ir, vals);
3440  T = fes->GetElementTransformation(i);
3441  for (int j = 0; j < ir->GetNPoints(); j++)
3442  {
3443  const IntegrationPoint &ip = ir->IntPoint(j);
3444  T->SetIntPoint(&ip);
3445  double diff = fabs(vals(j) - exsol.Eval(*T, ip));
3446  if (p < infinity())
3447  {
3448  diff = pow(diff, p);
3449  if (weight)
3450  {
3451  diff *= weight->Eval(*T, ip);
3452  }
3453  error[i] += ip.weight * T->Weight() * diff;
3454  }
3455  else
3456  {
3457  if (weight)
3458  {
3459  diff *= weight->Eval(*T, ip);
3460  }
3461  error[i] = std::max(error[i], diff);
3462  }
3463  }
3464  if (p < infinity())
3465  {
3466  // negative quadrature weights may cause the error to be negative
3467  if (error[i] < 0.)
3468  {
3469  error[i] = -pow(-error[i], 1./p);
3470  }
3471  else
3472  {
3473  error[i] = pow(error[i], 1./p);
3474  }
3475  }
3476  }
3477 }
3478 
3480  Coefficient *weight,
3481  VectorCoefficient *v_weight,
3482  const IntegrationRule *irs[]) const
3483 {
3484  double error = 0.0;
3485  const FiniteElement *fe;
3487  DenseMatrix vals, exact_vals;
3488  Vector loc_errs;
3489 
3490  for (int i = 0; i < fes->GetNE(); i++)
3491  {
3492  fe = fes->GetFE(i);
3493  const IntegrationRule *ir;
3494  if (irs)
3495  {
3496  ir = irs[fe->GetGeomType()];
3497  }
3498  else
3499  {
3500  int intorder = 2*fe->GetOrder() + 3; // <----------
3501  ir = &(IntRules.Get(fe->GetGeomType(), intorder));
3502  }
3503  T = fes->GetElementTransformation(i);
3504  GetVectorValues(*T, *ir, vals);
3505  exsol.Eval(exact_vals, *T, *ir);
3506  vals -= exact_vals;
3507  loc_errs.SetSize(vals.Width());
3508  if (!v_weight)
3509  {
3510  // compute the lengths of the errors at the integration points
3511  // thus the vector norm is rotationally invariant
3512  vals.Norm2(loc_errs);
3513  }
3514  else
3515  {
3516  v_weight->Eval(exact_vals, *T, *ir);
3517  // column-wise dot product of the vector error (in vals) and the
3518  // vector weight (in exact_vals)
3519  for (int j = 0; j < vals.Width(); j++)
3520  {
3521  double errj = 0.0;
3522  for (int d = 0; d < vals.Height(); d++)
3523  {
3524  errj += vals(d,j)*exact_vals(d,j);
3525  }
3526  loc_errs(j) = fabs(errj);
3527  }
3528  }
3529  for (int j = 0; j < ir->GetNPoints(); j++)
3530  {
3531  const IntegrationPoint &ip = ir->IntPoint(j);
3532  T->SetIntPoint(&ip);
3533  double errj = loc_errs(j);
3534  if (p < infinity())
3535  {
3536  errj = pow(errj, p);
3537  if (weight)
3538  {
3539  errj *= weight->Eval(*T, ip);
3540  }
3541  error += ip.weight * T->Weight() * errj;
3542  }
3543  else
3544  {
3545  if (weight)
3546  {
3547  errj *= weight->Eval(*T, ip);
3548  }
3549  error = std::max(error, errj);
3550  }
3551  }
3552  }
3553 
3554  if (p < infinity())
3555  {
3556  // negative quadrature weights may cause the error to be negative
3557  if (error < 0.)
3558  {
3559  error = -pow(-error, 1./p);
3560  }
3561  else
3562  {
3563  error = pow(error, 1./p);
3564  }
3565  }
3566 
3567  return error;
3568 }
3569 
3571  VectorCoefficient &exsol,
3572  Vector &error,
3573  Coefficient *weight,
3574  VectorCoefficient *v_weight,
3575  const IntegrationRule *irs[]) const
3576 {
3577  MFEM_ASSERT(error.Size() == fes->GetNE(),
3578  "Incorrect size for result vector");
3579 
3580  error = 0.0;
3581  const FiniteElement *fe;
3583  DenseMatrix vals, exact_vals;
3584  Vector loc_errs;
3585 
3586  for (int i = 0; i < fes->GetNE(); i++)
3587  {
3588  fe = fes->GetFE(i);
3589  const IntegrationRule *ir;
3590  if (irs)
3591  {
3592  ir = irs[fe->GetGeomType()];
3593  }
3594  else
3595  {
3596  int intorder = 2*fe->GetOrder() + 3; // <----------
3597  ir = &(IntRules.Get(fe->GetGeomType(), intorder));
3598  }
3599  T = fes->GetElementTransformation(i);
3600  GetVectorValues(*T, *ir, vals);
3601  exsol.Eval(exact_vals, *T, *ir);
3602  vals -= exact_vals;
3603  loc_errs.SetSize(vals.Width());
3604  if (!v_weight)
3605  {
3606  // compute the lengths of the errors at the integration points thus the
3607  // vector norm is rotationally invariant
3608  vals.Norm2(loc_errs);
3609  }
3610  else
3611  {
3612  v_weight->Eval(exact_vals, *T, *ir);
3613  // column-wise dot product of the vector error (in vals) and the vector
3614  // weight (in exact_vals)
3615  for (int j = 0; j < vals.Width(); j++)
3616  {
3617  double errj = 0.0;
3618  for (int d = 0; d < vals.Height(); d++)
3619  {
3620  errj += vals(d,j)*exact_vals(d,j);
3621  }
3622  loc_errs(j) = fabs(errj);
3623  }
3624  }
3625  for (int j = 0; j < ir->GetNPoints(); j++)
3626  {
3627  const IntegrationPoint &ip = ir->IntPoint(j);
3628  T->SetIntPoint(&ip);
3629  double errj = loc_errs(j);
3630  if (p < infinity())
3631  {
3632  errj = pow(errj, p);
3633  if (weight)
3634  {
3635  errj *= weight->Eval(*T, ip);
3636  }
3637  error[i] += ip.weight * T->Weight() * errj;
3638  }
3639  else
3640  {
3641  if (weight)
3642  {
3643  errj *= weight->Eval(*T, ip);
3644  }
3645  error[i] = std::max(error[i], errj);
3646  }
3647  }
3648  if (p < infinity())
3649  {
3650  // negative quadrature weights may cause the error to be negative
3651  if (error[i] < 0.)
3652  {
3653  error[i] = -pow(-error[i], 1./p);
3654  }
3655  else
3656  {
3657  error[i] = pow(error[i], 1./p);
3658  }
3659  }
3660  }
3661 }
3662 
3664 {
3665  Vector::operator=(value);
3666  return *this;
3667 }
3668 
3670 {
3671  MFEM_ASSERT(fes && v.Size() == fes->GetVSize(), "");
3672  Vector::operator=(v);
3673  return *this;
3674 }
3675 
3676 void GridFunction::Save(std::ostream &os) const
3677 {
3678  fes->Save(os);
3679  os << '\n';
3680 #if 0
3681  // Testing: write NURBS GridFunctions using "NURBS_patches" format.
3682  if (fes->GetNURBSext())
3683  {
3684  os << "NURBS_patches\n";
3685  fes->GetNURBSext()->PrintSolution(*this, os);
3686  os.flush();
3687  return;
3688  }
3689 #endif
3690  if (fes->GetOrdering() == Ordering::byNODES)
3691  {
3692  Vector::Print(os, 1);
3693  }
3694  else
3695  {
3696  Vector::Print(os, fes->GetVDim());
3697  }
3698  os.flush();
3699 }
3700 
3701 void GridFunction::Save(const char *fname, int precision) const
3702 {
3703  ofstream ofs(fname);
3704  ofs.precision(precision);
3705  Save(ofs);
3706 }
3707 
3708 #ifdef MFEM_USE_ADIOS2
3710  const std::string& variable_name,
3711  const adios2stream::data_type type) const
3712 {
3713  os.Save(*this, variable_name, type);
3714 }
3715 #endif
3716 
3717 void GridFunction::SaveVTK(std::ostream &os, const std::string &field_name,
3718  int ref)
3719 {
3720  Mesh *mesh = fes->GetMesh();
3721  RefinedGeometry *RefG;
3722  Vector val;
3723  DenseMatrix vval, pmat;
3724  int vec_dim = VectorDim();
3725 
3726  if (vec_dim == 1)
3727  {
3728  // scalar data
3729  os << "SCALARS " << field_name << " double 1\n"
3730  << "LOOKUP_TABLE default\n";
3731  for (int i = 0; i < mesh->GetNE(); i++)
3732  {
3733  RefG = GlobGeometryRefiner.Refine(
3734  mesh->GetElementBaseGeometry(i), ref, 1);
3735 
3736  GetValues(i, RefG->RefPts, val, pmat);
3737 
3738  for (int j = 0; j < val.Size(); j++)
3739  {
3740  os << val(j) << '\n';
3741  }
3742  }
3743  }
3744  else if ( (vec_dim == 2 || vec_dim == 3) && mesh->SpaceDimension() > 1)
3745  {
3746  // vector data
3747  os << "VECTORS " << field_name << " double\n";
3748  for (int i = 0; i < mesh->GetNE(); i++)
3749  {
3750  RefG = GlobGeometryRefiner.Refine(
3751  mesh->GetElementBaseGeometry(i), ref, 1);
3752 
3753  // GetVectorValues(i, RefG->RefPts, vval, pmat);
3755  GetVectorValues(*T, RefG->RefPts, vval, &pmat);
3756 
3757  for (int j = 0; j < vval.Width(); j++)
3758  {
3759  os << vval(0, j) << ' ' << vval(1, j) << ' ';
3760  if (vval.Height() == 2)
3761  {
3762  os << 0.0;
3763  }
3764  else
3765  {
3766  os << vval(2, j);
3767  }
3768  os << '\n';
3769  }
3770  }
3771  }
3772  else
3773  {
3774  // other data: save the components as separate scalars
3775  for (int vd = 0; vd < vec_dim; vd++)
3776  {
3777  os << "SCALARS " << field_name << vd << " double 1\n"
3778  << "LOOKUP_TABLE default\n";
3779  for (int i = 0; i < mesh->GetNE(); i++)
3780  {
3781  RefG = GlobGeometryRefiner.Refine(
3782  mesh->GetElementBaseGeometry(i), ref, 1);
3783 
3784  GetValues(i, RefG->RefPts, val, pmat, vd + 1);
3785 
3786  for (int j = 0; j < val.Size(); j++)
3787  {
3788  os << val(j) << '\n';
3789  }
3790  }
3791  }
3792  }
3793  os.flush();
3794 }
3795 
3796 void GridFunction::SaveSTLTri(std::ostream &os, double p1[], double p2[],
3797  double p3[])
3798 {
3799  double v1[3] = { p2[0] - p1[0], p2[1] - p1[1], p2[2] - p1[2] };
3800  double v2[3] = { p3[0] - p1[0], p3[1] - p1[1], p3[2] - p1[2] };
3801  double n[] = { v1[1] * v2[2] - v1[2] * v2[1],
3802  v1[2] * v2[0] - v1[0] * v2[2],
3803  v1[0] * v2[1] - v1[1] * v2[0]
3804  };
3805  double rl = 1.0 / sqrt(n[0] * n[0] + n[1] * n[1] + n[2] * n[2]);
3806  n[0] *= rl; n[1] *= rl; n[2] *= rl;
3807 
3808  os << " facet normal " << n[0] << ' ' << n[1] << ' ' << n[2]
3809  << "\n outer loop"
3810  << "\n vertex " << p1[0] << ' ' << p1[1] << ' ' << p1[2]
3811  << "\n vertex " << p2[0] << ' ' << p2[1] << ' ' << p2[2]
3812  << "\n vertex " << p3[0] << ' ' << p3[1] << ' ' << p3[2]
3813  << "\n endloop\n endfacet\n";
3814 }
3815 
3816 void GridFunction::SaveSTL(std::ostream &os, int TimesToRefine)
3817 {
3818  Mesh *mesh = fes->GetMesh();
3819 
3820  if (mesh->Dimension() != 2)
3821  {
3822  return;
3823  }
3824 
3825  int i, j, k, l, n;
3826  DenseMatrix pointmat;
3827  Vector values;
3828  RefinedGeometry * RefG;
3829  double pts[4][3], bbox[3][2];
3830 
3831  os << "solid GridFunction\n";
3832 
3833  bbox[0][0] = bbox[0][1] = bbox[1][0] = bbox[1][1] =
3834  bbox[2][0] = bbox[2][1] = 0.0;
3835  for (i = 0; i < mesh->GetNE(); i++)
3836  {
3837  Geometry::Type geom = mesh->GetElementBaseGeometry(i);
3838  RefG = GlobGeometryRefiner.Refine(geom, TimesToRefine);
3839  GetValues(i, RefG->RefPts, values, pointmat);
3840  Array<int> &RG = RefG->RefGeoms;
3841  n = Geometries.NumBdr(geom);
3842  for (k = 0; k < RG.Size()/n; k++)
3843  {
3844  for (j = 0; j < n; j++)
3845  {
3846  l = RG[n*k+j];
3847  pts[j][0] = pointmat(0,l);
3848  pts[j][1] = pointmat(1,l);
3849  pts[j][2] = values(l);
3850  }
3851 
3852  if (n == 3)
3853  {
3854  SaveSTLTri(os, pts[0], pts[1], pts[2]);
3855  }
3856  else
3857  {
3858  SaveSTLTri(os, pts[0], pts[1], pts[2]);
3859  SaveSTLTri(os, pts[0], pts[2], pts[3]);
3860  }
3861  }
3862 
3863  if (i == 0)
3864  {
3865  bbox[0][0] = pointmat(0,0);
3866  bbox[0][1] = pointmat(0,0);
3867  bbox[1][0] = pointmat(1,0);
3868  bbox[1][1] = pointmat(1,0);
3869  bbox[2][0] = values(0);
3870  bbox[2][1] = values(0);
3871  }
3872 
3873  for (j = 0; j < values.Size(); j++)
3874  {
3875  if (bbox[0][0] > pointmat(0,j))
3876  {
3877  bbox[0][0] = pointmat(0,j);
3878  }
3879  if (bbox[0][1] < pointmat(0,j))
3880  {
3881  bbox[0][1] = pointmat(0,j);
3882  }
3883  if (bbox[1][0] > pointmat(1,j))
3884  {
3885  bbox[1][0] = pointmat(1,j);
3886  }
3887  if (bbox[1][1] < pointmat(1,j))
3888  {
3889  bbox[1][1] = pointmat(1,j);
3890  }
3891  if (bbox[2][0] > values(j))
3892  {
3893  bbox[2][0] = values(j);
3894  }
3895  if (bbox[2][1] < values(j))
3896  {
3897  bbox[2][1] = values(j);
3898  }
3899  }
3900  }
3901 
3902  mfem::out << "[xmin,xmax] = [" << bbox[0][0] << ',' << bbox[0][1] << "]\n"
3903  << "[ymin,ymax] = [" << bbox[1][0] << ',' << bbox[1][1] << "]\n"
3904  << "[zmin,zmax] = [" << bbox[2][0] << ',' << bbox[2][1] << ']'
3905  << endl;
3906 
3907  os << "endsolid GridFunction" << endl;
3908 }
3909 
3910 std::ostream &operator<<(std::ostream &os, const GridFunction &sol)
3911 {
3912  sol.Save(os);
3913  return os;
3914 }
3915 
3917 {
3918  const Mesh* mesh = fes->GetMesh();
3919  MFEM_ASSERT(mesh->Nonconforming(), "");
3920 
3921  // get the mapping (old_vertex_index -> new_vertex_index)
3922  Array<int> new_vertex, old_vertex;
3923  mesh->ncmesh->LegacyToNewVertexOrdering(new_vertex);
3924  MFEM_ASSERT(new_vertex.Size() == mesh->GetNV(), "");
3925 
3926  // get the mapping (new_vertex_index -> old_vertex_index)
3927  old_vertex.SetSize(new_vertex.Size());
3928  for (int i = 0; i < new_vertex.Size(); i++)
3929  {
3930  old_vertex[new_vertex[i]] = i;
3931  }
3932 
3933  Vector tmp = *this;
3934 
3935  // reorder vertex DOFs
3936  Array<int> old_vdofs, new_vdofs;
3937  for (int i = 0; i < mesh->GetNV(); i++)
3938  {
3939  fes->GetVertexVDofs(i, old_vdofs);
3940  fes->GetVertexVDofs(new_vertex[i], new_vdofs);
3941 
3942  for (int j = 0; j < new_vdofs.Size(); j++)
3943  {
3944  tmp(new_vdofs[j]) = (*this)(old_vdofs[j]);
3945  }
3946  }
3947 
3948  // reorder edge DOFs -- edge orientation has changed too
3949  Array<int> dofs, ev;
3950  for (int i = 0; i < mesh->GetNEdges(); i++)
3951  {
3952  mesh->GetEdgeVertices(i, ev);
3953  if (old_vertex[ev[0]] > old_vertex[ev[1]])
3954  {
3955  const int *ind = fec->DofOrderForOrientation(Geometry::SEGMENT, -1);
3956 
3957  fes->GetEdgeInteriorDofs(i, dofs);
3958  for (int k = 0; k < dofs.Size(); k++)
3959  {
3960  int new_dof = dofs[k];
3961  int old_dof = dofs[(ind[k] < 0) ? -1-ind[k] : ind[k]];
3962 
3963  for (int j = 0; j < fes->GetVDim(); j++)
3964  {
3965  int new_vdof = fes->DofToVDof(new_dof, j);
3966  int old_vdof = fes->DofToVDof(old_dof, j);
3967 
3968  double sign = (ind[k] < 0) ? -1.0 : 1.0;
3969  tmp(new_vdof) = sign * (*this)(old_vdof);
3970  }
3971  }
3972  }
3973  }
3974 
3975  Vector::Swap(tmp);
3976 }
3977 
3979  GridFunction &u,
3980  GridFunction &flux, Vector &error_estimates,
3981  Array<int>* aniso_flags,
3982  int with_subdomains,
3983  bool with_coeff)
3984 {
3985  FiniteElementSpace *ufes = u.FESpace();
3986  FiniteElementSpace *ffes = flux.FESpace();
3987  ElementTransformation *Transf;
3988 
3989  int dim = ufes->GetMesh()->Dimension();
3990  int nfe = ufes->GetNE();
3991 
3992  Array<int> udofs;
3993  Array<int> fdofs;
3994  Vector ul, fl, fla, d_xyz;
3995 
3996  error_estimates.SetSize(nfe);
3997  if (aniso_flags)
3998  {
3999  aniso_flags->SetSize(nfe);
4000  d_xyz.SetSize(dim);
4001  }
4002 
4003  int nsd = 1;
4004  if (with_subdomains)
4005  {
4006  nsd = ufes->GetMesh()->attributes.Max();
4007  }
4008 
4009  double total_error = 0.0;
4010  for (int s = 1; s <= nsd; s++)
4011  {
4012  // This calls the parallel version when u is a ParGridFunction
4013  u.ComputeFlux(blfi, flux, with_coeff, (with_subdomains ? s : -1));
4014 
4015  for (int i = 0; i < nfe; i++)
4016  {
4017  if (with_subdomains && ufes->GetAttribute(i) != s) { continue; }
4018 
4019  ufes->GetElementVDofs(i, udofs);
4020  ffes->GetElementVDofs(i, fdofs);
4021 
4022  u.GetSubVector(udofs, ul);
4023  flux.GetSubVector(fdofs, fla);
4024 
4025  Transf = ufes->GetElementTransformation(i);
4026  blfi.ComputeElementFlux(*ufes->GetFE(i), *Transf, ul,
4027  *ffes->GetFE(i), fl, with_coeff);
4028 
4029  fl -= fla;
4030 
4031  double eng = blfi.ComputeFluxEnergy(*ffes->GetFE(i), *Transf, fl,
4032  (aniso_flags ? &d_xyz : NULL));
4033 
4034  error_estimates(i) = std::sqrt(eng);
4035  total_error += eng;
4036 
4037  if (aniso_flags)
4038  {
4039  double sum = 0;
4040  for (int k = 0; k < dim; k++)
4041  {
4042  sum += d_xyz[k];
4043  }
4044 
4045  double thresh = 0.15 * 3.0/dim;
4046  int flag = 0;
4047  for (int k = 0; k < dim; k++)
4048  {
4049  if (d_xyz[k] / sum > thresh) { flag |= (1 << k); }
4050  }
4051 
4052  (*aniso_flags)[i] = flag;
4053  }
4054  }
4055  }
4056 #ifdef MFEM_USE_MPI
4057  auto pfes = dynamic_cast<ParFiniteElementSpace*>(ufes);
4058  if (pfes)
4059  {
4060  auto process_local_error = total_error;
4061  MPI_Allreduce(&process_local_error, &total_error, 1, MPI_DOUBLE,
4062  MPI_SUM, pfes->GetComm());
4063  }
4064 #endif // MFEM_USE_MPI
4065  return std::sqrt(total_error);
4066 }
4067 
4068 void TensorProductLegendre(int dim, // input
4069  int order, // input
4070  const Vector &x_in, // input
4071  const Vector &xmax, // input
4072  const Vector &xmin, // input
4073  Vector &poly, // output
4074  double angle, // input (optional)
4075  const Vector *midpoint) // input (optional)
4076 {
4077  MFEM_VERIFY(dim >= 1, "dim must be positive");
4078  MFEM_VERIFY(dim <= 3, "dim cannot be greater than 3");
4079  MFEM_VERIFY(order >= 0, "order cannot be negative");
4080 
4081  bool rotate = (angle != 0.0) || (midpoint->Norml2() != 0.0);
4082 
4083  Vector x(dim);
4084  if (rotate && dim == 2)
4085  {
4086  // Rotate coordinates to match rotated bounding box
4087  Vector tmp(dim);
4088  tmp = x_in;
4089  tmp -= *midpoint;
4090  x[0] = tmp[0]*cos(-angle) - tmp[1]*sin(-angle);
4091  x[1] = tmp[0]*sin(-angle) + tmp[1]*cos(-angle);
4092  }
4093  else
4094  {
4095  // Bounding box is not reoriented no need to change orientation
4096  x = x_in;
4097  }
4098 
4099  // Map x to [0, 1] to use CalcLegendre since it uses shifted Legendre Polynomials.
4100  double x1 = (x(0) - xmin(0))/(xmax(0)-xmin(0)), x2, x3;
4101  Vector poly_x(order+1), poly_y(order+1), poly_z(order+1);
4102  poly1d.CalcLegendre(order, x1, poly_x);
4103  if (dim > 1)
4104  {
4105  x2 = (x(1)-xmin(1))/(xmax(1)-xmin(1));
4106  poly1d.CalcLegendre(order, x2, poly_y);
4107  }
4108  if (dim == 3)
4109  {
4110  x3 = (x(2)-xmin(2))/(xmax(2)-xmin(2));
4111  poly1d.CalcLegendre(order, x3, poly_z);
4112  }
4113 
4114  int basis_dimension = static_cast<int>(pow(order+1,dim));
4115  poly.SetSize(basis_dimension);
4116  switch (dim)
4117  {
4118  case 1:
4119  {
4120  for (int i = 0; i <= order; i++)
4121  {
4122  poly(i) = poly_x(i);
4123  }
4124  }
4125  break;
4126  case 2:
4127  {
4128  for (int j = 0; j <= order; j++)
4129  {
4130  for (int i = 0; i <= order; i++)
4131  {
4132  int cnt = i + (order+1) * j;
4133  poly(cnt) = poly_x(i) * poly_y(j);
4134  }
4135  }
4136  }
4137  break;
4138  case 3:
4139  {
4140  for (int k = 0; k <= order; k++)
4141  {
4142  for (int j = 0; j <= order; j++)
4143  {
4144  for (int i = 0; i <= order; i++)
4145  {
4146  int cnt = i + (order+1) * j + (order+1) * (order+1) * k;
4147  poly(cnt) = poly_x(i) * poly_y(j) * poly_z(k);
4148  }
4149  }
4150  }
4151  }
4152  break;
4153  default:
4154  {
4155  MFEM_ABORT("TensorProductLegendre: invalid value of dim");
4156  }
4157  }
4158 }
4159 
4160 void BoundingBox(const Array<int> &patch, // input
4161  FiniteElementSpace *ufes, // input
4162  int order, // input
4163  Vector &xmin, // output
4164  Vector &xmax, // output
4165  double &angle, // output
4166  Vector &midpoint, // output
4167  int iface) // input (optional)
4168 {
4169  Mesh *mesh = ufes->GetMesh();
4170  int dim = mesh->Dimension();
4171  int num_elems = patch.Size();
4173 
4174  xmax = -infinity();
4175  xmin = infinity();
4176  angle = 0.0;
4177  midpoint = 0.0;
4178  bool rotate = (dim == 2);
4179 
4180  // Rotate bounding box to match the face orientation
4181  if (rotate && iface >= 0)
4182  {
4183  IntegrationPoint reference_pt;
4184  mesh->GetFaceTransformation(iface, &Tr);
4185  Vector physical_pt(2);
4186  Vector physical_diff(2);
4187  physical_diff = 0.0;
4188  // Get the endpoints of the edge in physical space
4189  // then compute midpoint and angle
4190  for (int i = 0; i < 2; i++)
4191  {
4192  reference_pt.Set1w((double)i, 0.0);
4193  Tr.Transform(reference_pt, physical_pt);
4194  midpoint += physical_pt;
4195  physical_pt *= pow(-1.0,i);
4196  physical_diff += physical_pt;
4197  }
4198  midpoint /= 2.0;
4199  angle = atan2(physical_diff(1),physical_diff(0));
4200  }
4201 
4202  for (int i = 0; i < num_elems; i++)
4203  {
4204  int ielem = patch[i];
4205  const IntegrationRule *ir = &(IntRules.Get(mesh->GetElementGeometry(ielem),
4206  order));
4207  ufes->GetElementTransformation(ielem, &Tr);
4208  for (int k = 0; k < ir->GetNPoints(); k++)
4209  {
4210  const IntegrationPoint ip = ir->IntPoint(k);
4211  Vector transip(dim);
4212  Tr.Transform(ip, transip);
4213  if (rotate)
4214  {
4215  transip -= midpoint;
4216  Vector tmp(dim);
4217  tmp = transip;
4218  transip[0] = tmp[0]*cos(-angle) - tmp[1]*sin(-angle);
4219  transip[1] = tmp[0]*sin(-angle) + tmp[1]*cos(-angle);
4220  }
4221  for (int d = 0; d < dim; d++) { xmax(d) = max(xmax(d), transip(d)); }
4222  for (int d = 0; d < dim; d++) { xmin(d) = min(xmin(d), transip(d)); }
4223  }
4224  }
4225 }
4226 
4228  GridFunction &u, // input
4229  Vector &error_estimates, // output
4230  bool subdomain_reconstruction, // input (optional)
4231  bool with_coeff, // input (optional)
4232  double tichonov_coeff) // input (optional)
4233 {
4234  MFEM_VERIFY(tichonov_coeff >= 0.0, "tichonov_coeff cannot be negative");
4235  FiniteElementSpace *ufes = u.FESpace();
4236  ElementTransformation *Transf;
4237 
4238  Mesh *mesh = ufes->GetMesh();
4239  int dim = mesh->Dimension();
4240  int sdim = mesh->SpaceDimension();
4241  int nfe = ufes->GetNE();
4242  int nfaces = ufes->GetNF();
4243 
4244  Array<int> udofs;
4245  Array<int> fdofs;
4246  Vector ul, fl, fla;
4247 
4248  error_estimates.SetSize(nfe);
4249  error_estimates = 0.0;
4250  Array<int> counters(nfe);
4251  counters = 0;
4252 
4253  Vector xmax(dim);
4254  Vector xmin(dim);
4255  double angle = 0.0;
4256  Vector midpoint(dim);
4257 
4258  // Compute the number of subdomains
4259  int nsd = 1;
4260  if (subdomain_reconstruction)
4261  {
4262  nsd = ufes->GetMesh()->attributes.Max();
4263  }
4264 
4265  double total_error = 0.0;
4266  for (int iface = 0; iface < nfaces; iface++)
4267  {
4268  // 1.A. Find all elements in the face patch.
4269  int el1;
4270  int el2;
4271  mesh->GetFaceElements(iface, &el1, &el2);
4272  Array<int> patch(2);
4273  patch[0] = el1; patch[1] = el2;
4274 
4275  // 1.B. Check if boundary face or non-conforming coarse face and continue if true.
4276  if (el1 == -1 || el2 == -1)
4277  {
4278  continue;
4279  }
4280 
4281  // 1.C Check if face patch crosses an attribute interface and
4282  // continue if true (only active if subdomain_reconstruction == true)
4283  if (nsd > 1)
4284  {
4285  int el1_attr = ufes->GetAttribute(el1);
4286  int el2_attr = ufes->GetAttribute(el2);
4287  if (el1_attr != el2_attr) { continue; }
4288  }
4289 
4290  // 2. Compute global flux polynomial.
4291 
4292  // 2.A. Compute polynomial order of patch (for hp FEM)
4293  const int patch_order = max(ufes->GetElementOrder(el1),
4294  ufes->GetElementOrder(el2));
4295 
4296  int num_basis_functions = static_cast<int>(pow(patch_order+1,dim));
4297  int flux_order = 2*patch_order + 1;
4298  DenseMatrix A(num_basis_functions);
4299  Array<double> b(sdim * num_basis_functions);
4300  A = 0.0;
4301  b = 0.0;
4302 
4303  // 2.B. Estimate the smallest bounding box around the face patch
4304  // (this is used in 2.C.ii. to define a global polynomial basis)
4305  BoundingBox(patch, ufes, flux_order,
4306  xmin, xmax, angle, midpoint, iface);
4307 
4308  // 2.C. Compute the normal equations for the least-squares problem
4309  // 2.C.i. Evaluate the discrete flux at all integration points in all
4310  // elements in the face patch
4311  for (int i = 0; i < patch.Size(); i++)
4312  {
4313  int ielem = patch[i];
4314  const IntegrationRule *ir = &(IntRules.Get(mesh->GetElementGeometry(ielem),
4315  flux_order));
4316  int num_integration_pts = ir->GetNPoints();
4317 
4318  ufes->GetElementVDofs(ielem, udofs);
4319  u.GetSubVector(udofs, ul);
4320  Transf = ufes->GetElementTransformation(ielem);
4321  FiniteElement *dummy = nullptr;
4322  blfi.ComputeElementFlux(*ufes->GetFE(ielem), *Transf, ul,
4323  *dummy, fl, with_coeff, ir);
4324 
4325  // 2.C.ii. Use global polynomial basis to construct normal
4326  // equations
4327  for (int k = 0; k < num_integration_pts; k++)
4328  {
4329  const IntegrationPoint ip = ir->IntPoint(k);
4330  double tmp[3];
4331  Vector transip(tmp, 3);
4332  Transf->Transform(ip, transip);
4333 
4334  Vector p;
4335  TensorProductLegendre(dim, patch_order, transip, xmax, xmin, p, angle,
4336  &midpoint);
4337  AddMultVVt(p, A);
4338 
4339  for (int l = 0; l < num_basis_functions; l++)
4340  {
4341  // Loop through each component of the discrete flux
4342  for (int n = 0; n < sdim; n++)
4343  {
4344  b[l + n * num_basis_functions] += p(l) * fl(k + n * num_integration_pts);
4345  }
4346  }
4347  }
4348  }
4349 
4350  // 2.D. Shift spectrum of A to avoid conditioning issues.
4351  // Regularization is necessary if the tensor product space used for the
4352  // flux reconstruction leads to an underdetermined system of linear equations.
4353  // This should not happen if there are tensor product elements in the patch,
4354  // but it can happen if there are other element shapes (those with few
4355  // integration points) in the patch.
4356  for (int i = 0; i < num_basis_functions; i++)
4357  {
4358  A(i,i) += tichonov_coeff;
4359  }
4360 
4361  // 2.E. Solve for polynomial coefficients
4362  Array<int> ipiv(num_basis_functions);
4363  LUFactors lu(A.Data(), ipiv);
4364  double TOL = 1e-9;
4365  if (!lu.Factor(num_basis_functions,TOL))
4366  {
4367  // Singular matrix
4368  mfem::out << "LSZZErrorEstimator: Matrix A is singular.\t"
4369  << "Consider increasing tichonov_coeff." << endl;
4370  for (int i = 0; i < num_basis_functions; i++)
4371  {
4372  A(i,i) += 1e-8;
4373  }
4374  lu.Factor(num_basis_functions,TOL);
4375  }
4376  lu.Solve(num_basis_functions, sdim, b);
4377 
4378  // 2.F. Construct l2-minimizing global polynomial
4379  auto global_poly_tmp = [=] (const Vector &x, Vector &f)
4380  {
4381  Vector p;
4382  TensorProductLegendre(dim, patch_order, x, xmax, xmin, p, angle, &midpoint);
4383  f = 0.0;
4384  for (int i = 0; i < num_basis_functions; i++)
4385  {
4386  for (int j = 0; j < sdim; j++)
4387  {
4388  f(j) += b[i + j * num_basis_functions] * p(i);
4389  }
4390  }
4391  };
4392  VectorFunctionCoefficient global_poly(sdim, global_poly_tmp);
4393 
4394  // 3. Compute error contributions from the face.
4395  double element_error = 0.0;
4396  double patch_error = 0.0;
4397  for (int i = 0; i < patch.Size(); i++)
4398  {
4399  int ielem = patch[i];
4400  element_error = u.ComputeElementGradError(ielem, &global_poly);
4401  element_error *= element_error;
4402  patch_error += element_error;
4403  error_estimates(ielem) += element_error;
4404  counters[ielem]++;
4405  }
4406 
4407  total_error += patch_error;
4408  }
4409 
4410  // 4. Calibrate the final error estimates. Note that the l2 norm of
4411  // error_estimates vector converges to total_error.
4412  // The error estimates have been calibrated so that high order
4413  // benchmark problems with tensor product elements are asymptotically
4414  // exact.
4415  for (int ielem = 0; ielem < nfe; ielem++)
4416  {
4417  if (counters[ielem] == 0)
4418  {
4419  error_estimates(ielem) = infinity();
4420  }
4421  else
4422  {
4423  error_estimates(ielem) /= counters[ielem]/2.0;
4424  error_estimates(ielem) = sqrt(error_estimates(ielem));
4425  }
4426  }
4427  return std::sqrt(total_error/dim);
4428 }
4429 
4430 double ComputeElementLpDistance(double p, int i,
4431  GridFunction& gf1, GridFunction& gf2)
4432 {
4433  double norm = 0.0;
4434 
4435  FiniteElementSpace *fes1 = gf1.FESpace();
4436  FiniteElementSpace *fes2 = gf2.FESpace();
4437 
4438  const FiniteElement* fe1 = fes1->GetFE(i);
4439  const FiniteElement* fe2 = fes2->GetFE(i);
4440 
4441  const IntegrationRule *ir;
4442  int intorder = 2*std::max(fe1->GetOrder(),fe2->GetOrder()) + 1; // <-------
4443  ir = &(IntRules.Get(fe1->GetGeomType(), intorder));
4444  int nip = ir->GetNPoints();
4445  Vector val1, val2;
4446 
4447 
4449  for (int j = 0; j < nip; j++)
4450  {
4451  const IntegrationPoint &ip = ir->IntPoint(j);
4452  T->SetIntPoint(&ip);
4453 
4454  gf1.GetVectorValue(i, ip, val1);
4455  gf2.GetVectorValue(i, ip, val2);
4456 
4457  val1 -= val2;
4458  double errj = val1.Norml2();
4459  if (p < infinity())
4460  {
4461  errj = pow(errj, p);
4462  norm += ip.weight * T->Weight() * errj;
4463  }
4464  else
4465  {
4466  norm = std::max(norm, errj);
4467  }
4468  }
4469 
4470  if (p < infinity())
4471  {
4472  // Negative quadrature weights may cause the norm to be negative
4473  if (norm < 0.)
4474  {
4475  norm = -pow(-norm, 1./p);
4476  }
4477  else
4478  {
4479  norm = pow(norm, 1./p);
4480  }
4481  }
4482 
4483  return norm;
4484 }
4485 
4486 
4488  const IntegrationPoint &ip)
4489 {
4490  ElementTransformation *T_in =
4491  mesh_in->GetElementTransformation(T.ElementNo / n);
4492  T_in->SetIntPoint(&ip);
4493  return sol_in.Eval(*T_in, ip);
4494 }
4495 
4496 
4498  GridFunction *sol, const int ny)
4499 {
4500  GridFunction *sol2d;
4501 
4502  FiniteElementCollection *solfec2d;
4503  const char *name = sol->FESpace()->FEColl()->Name();
4504  string cname = name;
4505  if (cname == "Linear")
4506  {
4507  solfec2d = new LinearFECollection;
4508  }
4509  else if (cname == "Quadratic")
4510  {
4511  solfec2d = new QuadraticFECollection;
4512  }
4513  else if (cname == "Cubic")
4514  {
4515  solfec2d = new CubicFECollection;
4516  }
4517  else if (!strncmp(name, "H1_", 3))
4518  {
4519  solfec2d = new H1_FECollection(atoi(name + 7), 2);
4520  }
4521  else if (!strncmp(name, "H1Pos_", 6))
4522  {
4523  // use regular (nodal) H1_FECollection
4524  solfec2d = new H1_FECollection(atoi(name + 10), 2);
4525  }
4526  else if (!strncmp(name, "L2_T", 4))
4527  {
4528  solfec2d = new L2_FECollection(atoi(name + 10), 2);
4529  }
4530  else if (!strncmp(name, "L2_", 3))
4531  {
4532  solfec2d = new L2_FECollection(atoi(name + 7), 2);
4533  }
4534  else
4535  {
4536  mfem::err << "Extrude1DGridFunction : unknown FE collection : "
4537  << cname << endl;
4538  return NULL;
4539  }
4540  FiniteElementSpace *solfes2d;
4541  // assuming sol is scalar
4542  solfes2d = new FiniteElementSpace(mesh2d, solfec2d);
4543  sol2d = new GridFunction(solfes2d);
4544  sol2d->MakeOwner(solfec2d);
4545  {
4546  GridFunctionCoefficient csol(sol);
4547  ExtrudeCoefficient c2d(mesh, csol, ny);
4548  sol2d->ProjectCoefficient(c2d);
4549  }
4550  return sol2d;
4551 }
4552 
4553 }
int GetNPoints() const
Returns the number of the points in the integration rule.
Definition: intrules.hpp:247
void SaveSTLTri(std::ostream &out, double p1[], double p2[], double p3[])
Definition: gridfunc.cpp:3796
Abstract class for all finite elements.
Definition: fe_base.hpp:235
void LegacyToNewVertexOrdering(Array< int > &order) const
I/O: Return a map from old (v1.1) vertex indices to new vertex indices.
Definition: ncmesh.cpp:5950
Ordering::Type GetOrdering() const
Return the ordering method.
Definition: fespace.hpp:599
int Size() const
Return the logical size of the array.
Definition: array.hpp:138
void SetSubVector(const Array< int > &dofs, const double value)
Set the entries listed in dofs to the given value.
Definition: vector.cpp:573
int GetVSize() const
Return the number of vector dofs, i.e. GetNDofs() x GetVDim().
Definition: fespace.hpp:587
void GetVertexVDofs(int i, Array< int > &vdofs) const
Definition: fespace.cpp:324
int GetDim() const
Returns the reference space dimension for the finite element.
Definition: fe_base.hpp:311
int GetAttribute(int i) const
Definition: fespace.hpp:659
int GetNDofs() const
Returns number of degrees of freedom.
Definition: fespace.hpp:584
void Save(const GridFunction &grid_function, const std::string &variable_name, const data_type type)
Class for an integration rule - an Array of IntegrationPoint.
Definition: intrules.hpp:90
void GetElementAverages(GridFunction &avgs) const
Definition: gridfunc.cpp:1804
void GetVectorValues(int i, const IntegrationRule &ir, DenseMatrix &vals, DenseMatrix &tr) const
Definition: gridfunc.cpp:706
const double * GetVertex(int i) const
Return pointer to vertex i&#39;s coordinates.
Definition: mesh.hpp:1012
void NewDataAndSize(double *d, int s)
Set the Vector data and size, deleting the old data, if owned.
Definition: vector.hpp:163
Class for grid function - Vector with associated FE space.
Definition: gridfunc.hpp:30
int DofToVDof(int dof, int vd, int ndofs=-1) const
Definition: fespace.cpp:251
const SparseMatrix * GetConformingProlongation() const
The returned SparseMatrix is owned by the FiniteElementSpace.
Definition: fespace.cpp:1232
Memory< double > data
Definition: vector.hpp:64
virtual void CalcVShape(const IntegrationPoint &ip, DenseMatrix &shape) const
Evaluate the values of all shape functions of a vector finite element in reference space at the given...
Definition: fe_base.cpp:39
Class used for extruding scalar GridFunctions.
Definition: gridfunc.hpp:840
void SumFluxAndCount(BilinearFormIntegrator &blfi, GridFunction &flux, Array< int > &counts, bool wcoef, int subdomain)
Definition: gridfunc.cpp:252
void GetElementVertices(int i, Array< int > &vertices) const
Returns the vertices of element i.
Definition: fespace.hpp:639
const IntegrationRule & Get(int GeomType, int Order)
Returns an integration rule for given GeomType and Order.
Definition: intrules.cpp:923
virtual void ComputeElementFlux(const FiniteElement &el, ElementTransformation &Trans, Vector &u, const FiniteElement &fluxelem, Vector &flux, bool with_coef=true, const IntegrationRule *ir=NULL)
Virtual method required for Zienkiewicz-Zhu type error estimators.
Definition: bilininteg.hpp:223
void GetEdgeVertices(int i, Array< int > &vert) const
Returns the indices of the vertices of edge i.
Definition: mesh.cpp:6016
void MergeGridFunctions(GridFunction *gf_array[], int num_pieces, GridFunction &merged)
Definition: nurbs.cpp:2115
Geometry::Type GetGeometryType() const
Return the Geometry::Type of the reference element.
Definition: eltrans.hpp:162
Base class for vector Coefficients that optionally depend on time and space.
void ProjectDeltaCoefficient(DeltaCoefficient &delta_coeff, double &integral)
Definition: gridfunc.cpp:2336
const FiniteElement * GetEdgeElement(int i, int variant=0) const
Returns pointer to the FiniteElement in the FiniteElementCollection associated with i&#39;th edge in the ...
Definition: fespace.cpp:3163
int CurlDim() const
Definition: gridfunc.cpp:347
virtual void CalcPhysHessian(ElementTransformation &Trans, DenseMatrix &Hessian) const
Evaluate the Hessian of all shape functions of a scalar finite element in reference space at the give...
Definition: fe_base.cpp:289
virtual void Project(Coefficient &coeff, ElementTransformation &Trans, Vector &dofs) const
Given a coefficient and a transformation, compute its projection (approximation) in the local finite ...
Definition: fe_base.cpp:125
virtual void ComputeElementLpErrors(const double p, Coefficient &exsol, Vector &error, Coefficient *weight=NULL, const IntegrationRule *irs[]=NULL) const
Definition: gridfunc.cpp:3413
virtual void Eval(Vector &V, ElementTransformation &T, const IntegrationPoint &ip)=0
Evaluate the vector coefficient in the element described by T at the point ip, storing the result in ...
virtual double ComputeCurlError(VectorCoefficient *excurl, const IntegrationRule *irs[]=NULL) const
Returns ||curl u_ex - curl u_h||_L2 for ND elements.
Definition: gridfunc.cpp:2940
virtual int GetContType() const =0
virtual void GetVectorValue(int i, const IntegrationPoint &ip, Vector &val) const
Definition: gridfunc.cpp:468
void GetBdrElementFace(int i, int *f, int *o) const
Return the index and the orientation of the face of bdr element i. (3D)
Definition: mesh.cpp:6171
int GetNumGeometries(int dim) const
Return the number of geometries of the given dimension present in the mesh.
Definition: mesh.cpp:5908
void SetSize(int s)
Resize the vector to size s.
Definition: vector.hpp:513
void RestrictConforming()
Definition: gridfunc.cpp:1982
virtual void CalcPhysLaplacian(ElementTransformation &Trans, Vector &Laplacian) const
Evaluate the Laplacian of all shape functions of a scalar finite element in reference space at the gi...
Definition: fe_base.cpp:202
GridFunction * Extrude1DGridFunction(Mesh *mesh, Mesh *mesh2d, GridFunction *sol, const int ny)
Extrude a scalar 1D GridFunction, after extruding the mesh with Extrude1D.
Definition: gridfunc.cpp:4497
double Scale()
Return the scale factor times the optional time dependent function. Returns with when not set by th...
virtual DofTransformation * GetBdrElementDofs(int bel, Array< int > &dofs) const
Returns indices of degrees of freedom for boundary element &#39;bel&#39;.
Definition: fespace.cpp:2812
void BoundingBox(const Array< int > &patch, FiniteElementSpace *ufes, int order, Vector &xmin, Vector &xmax, double &angle, Vector &midpoint, int iface)
Defines the bounding box for the face patches used by NewZZErorrEstimator.
Definition: gridfunc.cpp:4160
void ProjectDiscCoefficient(VectorCoefficient &coeff, Array< int > &dof_attr)
Definition: gridfunc.cpp:2573
void Mult(const Table &A, const Table &B, Table &C)
C = A * B (as boolean matrices)
Definition: table.cpp:475
int Width() const
Get the width (size of input) of the Operator. Synonym with NumCols().
Definition: operator.hpp:73
double Norml2() const
Returns the l2 norm of the vector.
Definition: vector.cpp:812
virtual const FiniteElement * FiniteElementForGeometry(Geometry::Type GeomType) const =0
void SetIntPoint(const IntegrationPoint *ip)
Set the integration point ip that weights and Jacobians will be evaluated at.
Definition: eltrans.hpp:93
A specialized ElementTransformation class representing a face and its two neighboring elements...
Definition: eltrans.hpp:480
void GetSubVector(const Array< int > &dofs, Vector &elemvect) const
Extract entries listed in dofs to the output Vector elemvect.
Definition: vector.cpp:547
int GetOrder() const
Returns the order of the finite element. In the case of anisotropic orders, returns the maximum order...
Definition: fe_base.hpp:327
int VectorDim() const
Definition: gridfunc.cpp:324
Coefficient defined by a GridFunction. This coefficient is mesh dependent.
virtual void GetEssentialVDofs(const Array< int > &bdr_attr_is_ess, Array< int > &ess_vdofs, int component=-1) const
Mark degrees of freedom associated with boundary elements with the specified boundary attributes (mar...
Definition: fespace.cpp:495
Piecewise-(bi/tri)linear continuous finite elements.
Definition: fe_coll.hpp:663
Data type dense matrix using column-major storage.
Definition: densemat.hpp:23
virtual double * HostWrite()
Shortcut for mfem::Write(vec.GetMemory(), vec.Size(), false).
Definition: vector.hpp:461
Delta function coefficient optionally multiplied by a weight coefficient and a scaled time dependent ...
int Size() const
Returns the size of the vector.
Definition: vector.hpp:200
int GetElementOrder(int i) const
Returns the order of the i&#39;th finite element.
Definition: fespace.cpp:178
int GetBdrAttribute(int i) const
Definition: fespace.hpp:661
IntegrationPointTransformation Loc2
Definition: eltrans.hpp:524
int GetNE() const
Returns number of elements.
Definition: mesh.hpp:923
int GetEdgeDofs(int edge, Array< int > &dofs, int variant=0) const
Returns the indices of the degrees of freedom for the specified edge, including the DOFs for the vert...
Definition: fespace.cpp:2985
double Tol()
Return the tolerance used to identify the mesh vertices.
const DenseMatrix & InverseJacobian()
Return the inverse of the Jacobian matrix of the transformation at the currently set IntegrationPoint...
Definition: eltrans.hpp:145
virtual void Mult(const Vector &x, Vector &y) const =0
Operator application: y=A(x).
void AccumulateAndCountBdrTangentValues(VectorCoefficient &vcoeff, Array< int > &bdr_attr, Array< int > &values_counter)
Definition: gridfunc.cpp:2259
Abstract parallel finite element space.
Definition: pfespace.hpp:28
virtual double ComputeHDivError(VectorCoefficient *exsol, Coefficient *exdiv, const IntegrationRule *irs[]=NULL) const
Returns the error measured in H(div)-norm for RT elements.
Definition: gridfunc.cpp:3166
void GetVectorGradientHat(ElementTransformation &T, DenseMatrix &gh) const
Definition: gridfunc.cpp:1436
int GetNV() const
Returns number of vertices in the mesh.
Definition: fespace.hpp:611
const FiniteElement * GetFaceElement(int i) const
Returns pointer to the FiniteElement in the FiniteElementCollection associated with i&#39;th face in the ...
Definition: fespace.cpp:3133
int GetMapType() const
Returns the FiniteElement::MapType of the element describing how reference functions are mapped to ph...
Definition: fe_base.hpp:349
void MakeOwner(FiniteElementCollection *fec_)
Make the GridFunction the owner of fec and fes.
Definition: gridfunc.hpp:124
FiniteElementCollection * Load(Mesh *m, std::istream &input)
Read a FiniteElementSpace from a stream. The returned FiniteElementCollection is owned by the caller...
Definition: fespace.cpp:3513
virtual void Transform(const IntegrationPoint &, Vector &)
Transform integration point from reference coordinates to physical coordinates and store them in the ...
Definition: eltrans.cpp:492
const IntegrationPoint & GetIntPoint()
Get a const reference to the currently set integration point. This will return NULL if no integration...
Definition: eltrans.hpp:98
static void CalcLegendre(const int p, const double x, double *u)
Definition: fe_base.cpp:2032
void ComputeMeans(AvgType type, Array< int > &zones_per_vdof)
Definition: gridfunc.cpp:2311
virtual double ComputeFluxEnergy(const FiniteElement &fluxelem, ElementTransformation &Trans, Vector &flux, Vector *d_energy=NULL)
Virtual method required for Zienkiewicz-Zhu type error estimators.
Definition: bilininteg.hpp:249
ElementTransformation * Elem2
Definition: eltrans.hpp:522
double * GetData() const
Return a pointer to the beginning of the Vector data.
Definition: vector.hpp:209
void CalcOrtho(const DenseMatrix &J, Vector &n)
Definition: densemat.cpp:2654
void GetNodalValues(int i, Array< double > &nval, int vdim=1) const
Returns the values in the vertices of i&#39;th element for dimension vdim.
Definition: gridfunc.cpp:396
virtual int GetFaceDofs(int face, Array< int > &dofs, int variant=0) const
Returns the indices of the degrees of freedom for the specified face, including the DOFs for the edge...
Definition: fespace.cpp:2904
virtual FaceElementTransformations * GetFaceElementTransformations(int FaceNo, int mask=31)
Definition: mesh.cpp:961
Geometry::Type GetElementBaseGeometry(int i) const
Definition: mesh.hpp:1069
virtual void UseDevice(bool use_dev) const
Enable execution of Vector operations using the mfem::Device.
Definition: vector.hpp:118
const IntegrationRule * GetVertices(int GeomType)
Return an IntegrationRule consisting of all vertices of the given Geometry::Type, GeomType...
Definition: geom.cpp:265
int GetCurlDim() const
Returns the dimension of the curl for vector-valued finite elements.
Definition: fe_base.hpp:317
void skip_comment_lines(std::istream &is, const char comment_char)
Check if the stream starts with comment_char. If so skip it.
Definition: text.hpp:31
virtual void CalcPhysCurlShape(ElementTransformation &Trans, DenseMatrix &curl_shape) const
Evaluate the curl of all shape functions of a vector finite element in physical space at the point de...
Definition: fe_base.cpp:70
DofTransformation * GetBdrElementVDofs(int i, Array< int > &vdofs) const
Returns indexes of degrees of freedom for i&#39;th boundary element.
Definition: fespace.cpp:297
void GetEdgeTransformation(int i, IsoparametricTransformation *EdTr)
Definition: mesh.cpp:574
void GetVectorFieldNodalValues(Vector &val, int comp) const
Definition: gridfunc.cpp:1300
void ImposeBounds(int i, const Vector &weights, const Vector &lo_, const Vector &hi_)
Definition: gridfunc.cpp:1907
Vector & operator=(const double *v)
Copy Size() entries from v.
Definition: vector.cpp:124
int GetNumFaces() const
Return the number of faces (3D), edges (2D) or vertices (1D).
Definition: mesh.cpp:5376
virtual void Save(std::ostream &out) const
Save the GridFunction to an output stream.
Definition: gridfunc.cpp:3676
Geometry::Type GetGeomType() const
Returns the Geometry::Type of the reference element.
Definition: fe_base.hpp:320
virtual void GetElementDofValues(int el, Vector &dof_vals) const
Definition: gridfunc.cpp:1844
void Load(std::istream **in, int np, int *dim)
Reads a vector from multiple files.
Definition: vector.cpp:57
Piecewise-(bi)cubic continuous finite elements.
Definition: fe_coll.hpp:743
int GetNE() const
Returns number of elements in the mesh.
Definition: fespace.hpp:614
virtual double Eval(ElementTransformation &T, const IntegrationPoint &ip)
Evaluate the coefficient in the element described by T at the point ip.
Definition: gridfunc.cpp:4487
Geometry Geometries
Definition: fe.cpp:49
IntegrationPoint & IntPoint(int i)
Returns a reference to the i-th integration point.
Definition: intrules.hpp:250
void GetDerivative(int comp, int der_comp, GridFunction &der)
Compute a certain derivative of a function&#39;s component. Derivatives of the function are computed at t...
Definition: gridfunc.cpp:1424
bool Nonconforming() const
Definition: mesh.hpp:1651
void MultTranspose(const double *x, double *y) const
Multiply a vector with the transpose matrix.
Definition: densemat.cpp:201
void ProjectBdrCoefficientNormal(VectorCoefficient &vcoeff, Array< int > &bdr_attr)
Definition: gridfunc.cpp:2678
void SetTrueVector()
Shortcut for calling GetTrueDofs() with GetTrueVector() as argument.
Definition: gridfunc.hpp:146
DofTransformation * GetElementVDofs(int i, Array< int > &vdofs) const
Returns indexes of degrees of freedom in array dofs for i&#39;th element.
Definition: fespace.cpp:281
virtual void SetPrintLevel(int print_lvl)
Legacy method to set the level of verbosity of the solver output.
Definition: solvers.cpp:71
double f(const Vector &xvec)
Definition: lor_mms.hpp:32
void GetHessians(int i, const IntegrationRule &ir, DenseMatrix &hess, int vdim=1) const
Definition: gridfunc.cpp:600
double GetElementSize(ElementTransformation *T, int type=0)
Definition: mesh.cpp:76
int GetNBE() const
Returns number of boundary elements in the mesh.
Definition: fespace.hpp:623
Data type sparse matrix.
Definition: sparsemat.hpp:50
const double * Center()
int Height() const
Get the height (size of output) of the Operator. Synonym with NumRows().
Definition: operator.hpp:67
void Swap(Vector &other)
Swap the contents of two Vectors.
Definition: vector.hpp:615
Mesh * GetMesh() const
Returns the mesh.
Definition: fespace.hpp:441
void GetVectorFieldValues(int i, const IntegrationRule &ir, DenseMatrix &vals, DenseMatrix &tr, int comp=0) const
Definition: gridfunc.cpp:1235
IntegrationPointTransformation Loc1
Definition: eltrans.hpp:524
void PrintSolution(const GridFunction &sol, std::ostream &out) const
Definition: nurbs.cpp:3051
Coefficient * Weight()
See SetWeight() for description of the weight Coefficient.
double b
Definition: lissajous.cpp:42
void GetFaceTransformation(int i, IsoparametricTransformation *FTr)
Returns the transformation defining the given face element in a user-defined variable.
Definition: mesh.cpp:497
void SetAllIntPoints(const IntegrationPoint *face_ip)
Set the integration point in the Face and the two neighboring elements, if present.
Definition: eltrans.hpp:566
const DenseMatrix & Jacobian()
Return the Jacobian matrix of the transformation at the currently set IntegrationPoint, using the method SetIntPoint().
Definition: eltrans.hpp:119
virtual double ComputeH1Error(Coefficient *exsol, VectorCoefficient *exgrad, Coefficient *ell_coef, double Nu, int norm_type) const
Definition: gridfunc.cpp:3140
virtual double ComputeElementGradError(int ielem, VectorCoefficient *exgrad, const IntegrationRule *irs[]=NULL) const
Returns ||grad u_ex - grad u_h||_L2 in element ielem for H1 or L2 elements.
Definition: gridfunc.cpp:2862
void MakeTRef(FiniteElementSpace *f, double *tv)
Associate a new FiniteElementSpace and new true-dof data with the GridFunction.
Definition: gridfunc.cpp:222
void SetMaxIter(int max_it)
Definition: solvers.hpp:200
virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const =0
Evaluate the values of all shape functions of a scalar finite element in reference space at the given...
void Norm2(double *v) const
Take the 2-norm of the columns of A and store in v.
Definition: densemat.cpp:795
T Max() const
Find the maximal element in the array, using the comparison operator &lt; for class T.
Definition: array.cpp:68
void SetLinearConstraint(const Vector &w_, double a_)
Definition: solvers.cpp:2362
virtual const Operator * GetProlongationMatrix() const
The returned Operator is owned by the FiniteElementSpace.
Definition: fespace.hpp:479
int GetElementForDof(int i) const
Return the index of the first element that contains dof i.
Definition: fespace.hpp:773
const IntegrationRule & GetNodes() const
Get a const reference to the nodes of the element.
Definition: fe_base.hpp:390
void rotate(double *x)
Definition: snake.cpp:316
void AccumulateAndCountDerivativeValues(int comp, int der_comp, GridFunction &der, Array< int > &zones_per_dof)
Used for the serial and parallel implementations of the GetDerivative() method; see its documentation...
Definition: gridfunc.cpp:1371
void AddMultVVt(const Vector &v, DenseMatrix &VVt)
VVt += v v^t.
Definition: densemat.cpp:3148
GeometryRefiner GlobGeometryRefiner
Definition: geom.cpp:1773
ElementTransformation * GetBdrElementTransformation(int i) const
Returns ElementTransformation for the i-th boundary element.
Definition: fespace.hpp:656
double Weight()
Return the weight of the Jacobian matrix of the transformation at the currently set IntegrationPoint...
Definition: eltrans.hpp:131
void AccumulateAndCountZones(Coefficient &coeff, AvgType type, Array< int > &zones_per_vdof)
Accumulates (depending on type) the values of coeff at all shared vdofs and counts in how many zones ...
Definition: gridfunc.cpp:2021
virtual void MakeRef(FiniteElementSpace *f, double *v)
Make the GridFunction reference external data on a new FiniteElementSpace.
Definition: gridfunc.cpp:204
IntegrationRule RefPts
Definition: geom.hpp:282
void GetLaplacians(int i, const IntegrationRule &ir, Vector &laps, int vdim=1) const
Definition: gridfunc.cpp:561
void GetTrueDofs(Vector &tv) const
Extract the true-dofs from the GridFunction.
Definition: gridfunc.cpp:367
virtual int GetTrueVSize() const
Return the number of vector true (conforming) dofs.
Definition: fespace.hpp:590
RefinedGeometry * Refine(Geometry::Type Geom, int Times, int ETimes=1)
Definition: geom.cpp:1099
void GetValues(int i, const IntegrationRule &ir, Vector &vals, int vdim=1) const
Definition: gridfunc.cpp:513
int GetVDim()
Returns dimension of the vector.
int GetVDim() const
Returns vector dimension.
Definition: fespace.hpp:581
A class for non-conforming AMR. The class is not used directly by the user, rather it is an extension...
Definition: ncmesh.hpp:121
void LoadSolution(std::istream &input, GridFunction &sol) const
Definition: nurbs.cpp:3014
FaceElementTransformations * GetBdrFaceTransformations(int BdrElemNo)
Definition: mesh.cpp:1095
int GetNF() const
Returns number of faces (i.e. co-dimension 1 entities) in the mesh.
Definition: fespace.hpp:620
FiniteElementSpace * FESpace()
Definition: gridfunc.hpp:668
int Dimension() const
Definition: mesh.hpp:1006
GridFunction & operator=(const GridFunction &rhs)
Copy assignment. Only the data of the base class Vector is copied.
Definition: gridfunc.hpp:118
virtual void GetBoundaryClosure(const Array< int > &bdr_attr_is_ess, Array< int > &bdr_vertices, Array< int > &bdr_edges)
Definition: ncmesh.cpp:4966
void AddElementVector(const Array< int > &dofs, const Vector &elemvect)
Add elements of the elemvect Vector to the entries listed in dofs. Negative dof values cause the -dof...
Definition: vector.cpp:639
virtual DofTransformation * GetElementDofs(int elem, Array< int > &dofs) const
Returns indices of degrees of freedom of element &#39;elem&#39;.
Definition: fespace.cpp:2678
void CalcInverse(const DenseMatrix &a, DenseMatrix &inva)
Definition: densemat.cpp:2548
int GetVDim() const
Returns the vector dimension for vector-valued finite elements.
Definition: fe_base.hpp:314
A general vector function coefficient.
int SpaceDimension() const
Definition: mesh.hpp:1007
double Min() const
Returns the minimal element of the vector.
Definition: vector.cpp:1202
ElementTransformation * GetElementTransformation(int i) const
Returns ElementTransformation for the i-th element.
Definition: fespace.hpp:647
double Norml1() const
Returns the l_1 norm of the vector.
Definition: vector.cpp:841
virtual double ComputeGradError(VectorCoefficient *exgrad, const IntegrationRule *irs[]=NULL) const
Returns ||grad u_ex - grad u_h||_L2 for H1 or L2 elements.
Definition: gridfunc.cpp:2900
bool FaceIsInterior(int FaceNo) const
Return true if the given face is interior.
Definition: mesh.hpp:1280
bool IsIdentityProlongation(const Operator *P)
Definition: operator.hpp:693
bool IsLegacyLoaded() const
I/O: Return true if the mesh was loaded from the legacy v1.1 format.
Definition: ncmesh.hpp:384
void GetFaceElements(int Face, int *Elem1, int *Elem2) const
Definition: mesh.cpp:1394
double * Data() const
Returns the matrix data array.
Definition: densemat.hpp:111
virtual const int * DofOrderForOrientation(Geometry::Type GeomType, int Or) const =0
Returns an array, say p, that maps a local permuted index i to a local base index: base_i = p[i]...
virtual void InvTransformPrimal(double *v) const =0
Abstract base class BilinearFormIntegrator.
Definition: bilininteg.hpp:35
void SetAbsTol(double atol)
Definition: solvers.hpp:199
void SetRelTol(double rtol)
Definition: solvers.hpp:198
const NURBSExtension * GetNURBSext() const
Definition: fespace.hpp:443
ComplexDenseMatrix * MultAtB(const ComplexDenseMatrix &A, const ComplexDenseMatrix &B)
Multiply the complex conjugate transpose of a matrix A with a matrix B. A^H*B.
double Distance(const double *x, const double *y, const int n)
Definition: vector.hpp:644
void Print(std::ostream &out=mfem::out, int width=8) const
Prints vector to stream out.
Definition: vector.cpp:724
Class FiniteElementSpace - responsible for providing FEM view of the mesh, mainly managing the set of...
Definition: fespace.hpp:96
int GetDof() const
Returns the number of degrees of freedom in the finite element.
Definition: fe_base.hpp:323
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
int GetLocalDofForDof(int i) const
Return the local dof index in the first element that contains dof i.
Definition: fespace.hpp:777
virtual void Mult(const Vector &x, Vector &y) const
Matrix vector multiplication.
Definition: sparsemat.cpp:729
Base class Coefficients that optionally depend on space and time. These are used by the BilinearFormI...
Definition: coefficient.hpp:41
FiniteElementSpace * fes
FE space on which the grid function lives. Owned if fec is not NULL.
Definition: gridfunc.hpp:34
Collection of finite elements from the same family in multiple dimensions. This class is used to matc...
Definition: fe_coll.hpp:26
void ProjectGridFunction(const GridFunction &src)
Project the src GridFunction to this GridFunction, both of which must be on the same mesh...
Definition: gridfunc.cpp:1855
void CalcPhysShape(ElementTransformation &Trans, Vector &shape) const
Evaluate the values of all shape functions of a scalar finite element in physical space at the point ...
Definition: fe_base.cpp:181
virtual void TransformPrimal(double *v) const =0
void SetSize(int nsize)
Change the logical size of the array, keep existing entries.
Definition: array.hpp:679
virtual double ComputeMaxError(Coefficient &exsol, const IntegrationRule *irs[]=NULL) const
Definition: gridfunc.hpp:555
void Transform(const IntegrationPoint &, IntegrationPoint &)
Definition: eltrans.cpp:546
int NumBdr(int GeomType)
Return the number of boundary &quot;faces&quot; of a given Geometry::Type.
Definition: geom.hpp:126
void GetColumnReference(int c, Vector &col)
Definition: densemat.hpp:289
virtual void CalcDivShape(const IntegrationPoint &ip, Vector &divshape) const
Evaluate the divergence of all shape functions of a vector finite element in reference space at the g...
Definition: fe_base.cpp:51
FiniteElementCollection * fec
Used when the grid function is read from a file. It can also be set explicitly, see MakeOwner()...
Definition: gridfunc.hpp:40
void GetVectorGradient(ElementTransformation &tr, DenseMatrix &grad) const
Definition: gridfunc.cpp:1742
virtual double ComputeL2Error(Coefficient *exsol[], const IntegrationRule *irs[]=NULL, const Array< int > *elems=NULL) const
Definition: gridfunc.cpp:2766
Geometry::Type GetElementGeometry(int i) const
Definition: mesh.hpp:1055
double GetDivergence(ElementTransformation &tr) const
Definition: gridfunc.cpp:1459
virtual void Update()
Transform by the Space UpdateMatrix (e.g., on Mesh change).
Definition: gridfunc.cpp:165
double ComputeElementLpDistance(double p, int i, GridFunction &gf1, GridFunction &gf2)
Compute the Lp distance between two grid functions on the given element.
Definition: gridfunc.cpp:4430
virtual double ComputeDivError(Coefficient *exdiv, const IntegrationRule *irs[]=NULL) const
Returns ||div u_ex - div u_h||_L2 for RT elements.
Definition: gridfunc.cpp:2981
int GetFaceVectorValues(int i, int side, const IntegrationRule &ir, DenseMatrix &vals, DenseMatrix &tr) const
Definition: gridfunc.cpp:1106
static FiniteElementCollection * New(const char *name)
Factory method: return a newly allocated FiniteElementCollection according to the given name...
Definition: fe_coll.cpp:51
virtual double ComputeHCurlError(VectorCoefficient *exsol, VectorCoefficient *excurl, const IntegrationRule *irs[]=NULL) const
Returns the error measured in H(curl)-norm for ND elements.
Definition: gridfunc.cpp:3175
bool Nonconforming() const
Definition: fespace.hpp:448
double ZZErrorEstimator(BilinearFormIntegrator &blfi, GridFunction &u, GridFunction &flux, Vector &error_estimates, Array< int > *aniso_flags, int with_subdomains, bool with_coeff)
Definition: gridfunc.cpp:3978
double a
Definition: lissajous.cpp:41
NURBSExtension * NURBSext
Optional NURBS mesh extension.
Definition: mesh.hpp:272
int GetNV() const
Returns number of vertices. Vertices are only at the corners of elements, where you would expect them...
Definition: mesh.hpp:920
int GetNVDofs() const
Number of all scalar vertex dofs.
Definition: fespace.hpp:604
virtual const char * Name() const
Definition: fe_coll.hpp:65
Vector & Add(const double a, const Vector &Va)
(*this) += a * Va
Definition: vector.cpp:252
Class for integration point with weight.
Definition: intrules.hpp:25
A standard isoparametric element transformation.
Definition: eltrans.hpp:361
void SaveSTL(std::ostream &out, int TimesToRefine=1)
Write the GridFunction in STL format. Note that the mesh dimension must be 2 and that quad elements w...
Definition: gridfunc.cpp:3816
void GetElementTransformation(int i, IsoparametricTransformation *ElTr)
Definition: mesh.cpp:348
double Max() const
Returns the maximal element of the vector.
Definition: vector.cpp:902
virtual double ComputeLpError(const double p, Coefficient &exsol, Coefficient *weight=NULL, const IntegrationRule *irs[]=NULL, const Array< int > *elems=NULL) const
Definition: gridfunc.cpp:3346
double LSZZErrorEstimator(BilinearFormIntegrator &blfi, GridFunction &u, Vector &error_estimates, bool subdomain_reconstruction, bool with_coeff, double tichonov_coeff)
A ``true&#39;&#39; ZZ error estimator that uses face-based patches for flux reconstruction.
Definition: gridfunc.cpp:4227
void GetEdgeInteriorDofs(int i, Array< int > &dofs) const
Definition: fespace.cpp:3064
virtual void AssembleElementMatrix2(const FiniteElement &trial_fe, const FiniteElement &test_fe, ElementTransformation &Trans, DenseMatrix &elmat)
int dim
Definition: ex24.cpp:53
void NewMemoryAndSize(const Memory< double > &mem, int s, bool own_mem)
Reset the Vector to use the given external Memory mem and size s.
Definition: vector.hpp:562
int GetFaceValues(int i, int side, const IntegrationRule &ir, Vector &vals, DenseMatrix &tr, int vdim=1) const
Definition: gridfunc.cpp:656
ElementTransformation & GetElement1Transformation()
Definition: eltrans.cpp:591
virtual const FiniteElement * GetFE(int i) const
Returns pointer to the FiniteElement in the FiniteElementCollection associated with i&#39;th element in t...
Definition: fespace.cpp:2781
const Operator * GetUpdateOperator()
Get the GridFunction update operator.
Definition: fespace.hpp:897
void GetGradients(ElementTransformation &tr, const IntegrationRule &ir, DenseMatrix &grad) const
Definition: gridfunc.cpp:1713
virtual void ProjectBdrCoefficientTangent(VectorCoefficient &vcoeff, Array< int > &bdr_attr)
Project the tangential components of the given VectorCoefficient on the boundary. Only boundary attri...
Definition: gridfunc.cpp:2749
void LegacyNCReorder()
Loading helper.
Definition: gridfunc.cpp:3916
ElementTransformation * Elem1
Definition: eltrans.hpp:522
void TensorProductLegendre(int dim, int order, const Vector &x_in, const Vector &xmax, const Vector &xmin, Vector &poly, double angle, const Vector *midpoint)
Defines the global tensor product polynomial space used by NewZZErorrEstimator.
Definition: gridfunc.cpp:4068
double infinity()
Define a shortcut for std::numeric_limits&lt;double&gt;::infinity()
Definition: vector.hpp:46
virtual void Mult(const Vector &xt, Vector &x) const
Definition: solvers.cpp:2377
virtual void ProjectCoefficient(Coefficient &coeff)
Project coeff Coefficient to this GridFunction. The projection computation depends on the choice of t...
Definition: gridfunc.cpp:2399
Piecewise-(bi)quadratic continuous finite elements.
Definition: fe_coll.hpp:691
virtual void SetSpace(FiniteElementSpace *f)
Associate a new FiniteElementSpace with the GridFunction.
Definition: gridfunc.cpp:196
void ReorderByNodes()
For a vector grid function, makes sure that the ordering is byNODES.
Definition: gridfunc.cpp:1273
std::ostream & operator<<(std::ostream &os, SparseMatrix const &mat)
Definition: sparsemat.hpp:710
NCMesh * ncmesh
Optional nonconforming mesh extension.
Definition: mesh.hpp:273
void GetFaceVDofs(int i, Array< int > &vdofs) const
Returns indexes of degrees of freedom for i&#39;th face element (2D and 3D).
Definition: fespace.cpp:312
virtual double Eval(ElementTransformation &T, const IntegrationPoint &ip)=0
Evaluate the coefficient in the element described by T at the point ip.
void GetEdgeVDofs(int i, Array< int > &vdofs) const
Returns indexes of degrees of freedom for i&#39;th edge.
Definition: fespace.cpp:318
int GetNEdges() const
Return the number of edges.
Definition: mesh.hpp:929
void filter_dos(std::string &line)
Check for, and remove, a trailing &#39;\r&#39; from and std::string.
Definition: text.hpp:45
void GetCurl(ElementTransformation &tr, Vector &curl) const
Definition: gridfunc.cpp:1549
Vector data type.
Definition: vector.hpp:60
const FiniteElementCollection * FEColl() const
Definition: fespace.hpp:601
void Mult(const double *x, double *y) const
Matrix vector multiplication.
Definition: densemat.cpp:173
virtual void Transform(const IntegrationPoint &, Vector &)=0
Transform integration point from reference coordinates to physical coordinates and store them in the ...
void be_to_bfe(Geometry::Type geom, int o, const IntegrationPoint &ip, IntegrationPoint &fip)
Definition: gridfunc.cpp:715
void MakeRef(Vector &base, int offset, int size)
Reset the Vector to be a reference to a sub-vector of base.
Definition: vector.hpp:577
virtual bool UseDevice() const
Return the device flag of the Memory object used by the Vector.
Definition: vector.hpp:121
virtual void ComputeFlux(BilinearFormIntegrator &blfi, GridFunction &flux, bool wcoef=true, int subdomain=-1)
Definition: gridfunc.cpp:309
Arbitrary order H1-conforming (continuous) finite elements.
Definition: fe_coll.hpp:220
virtual double ComputeW11Error(Coefficient *exsol, VectorCoefficient *exgrad, int norm_type, const Array< int > *elems=NULL, const IntegrationRule *irs[]=NULL) const
Definition: gridfunc.cpp:3240
void pts(int iphi, int t, double x[])
RefCoord s[3]
virtual double ComputeDGFaceJumpError(Coefficient *exsol, Coefficient *ell_coeff, class JumpScaling jump_scaling, const IntegrationRule *irs[]=NULL) const
Definition: gridfunc.cpp:3017
Field is continuous across element interfaces.
Definition: fe_coll.hpp:45
double u(const Vector &xvec)
Definition: lor_mms.hpp:24
const FiniteElement * GetBE(int i) const
Returns pointer to the FiniteElement in the FiniteElementCollection associated with i&#39;th boundary fac...
Definition: fespace.cpp:3100
void SetSize(int s)
Change the size of the DenseMatrix to s x s.
Definition: densemat.hpp:105
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
Abstract operator.
Definition: operator.hpp:24
virtual const SparseMatrix * GetRestrictionMatrix() const
The returned SparseMatrix is owned by the FiniteElementSpace.
Definition: fespace.hpp:495
long GetSequence() const
Definition: fespace.hpp:922
void SetBounds(const Vector &lo_, const Vector &hi_)
Definition: solvers.cpp:2356
double Eval(double h, int p) const
Definition: gridfunc.hpp:761
virtual void SetFromTrueDofs(const Vector &tv)
Set the GridFunction from the given true-dof vector.
Definition: gridfunc.cpp:382
virtual void CalcDShape(const IntegrationPoint &ip, DenseMatrix &dshape) const =0
Evaluate the gradients of all shape functions of a scalar finite element in reference space at the gi...
int GetRangeType() const
Returns the FiniteElement::RangeType of the element, one of {SCALAR, VECTOR}.
Definition: fe_base.hpp:340
IntegrationRules IntRules(0, Quadrature1D::GaussLegendre)
A global object with all integration rules (defined in intrules.cpp)
Definition: intrules.hpp:379
void Save(std::ostream &out) const
Save finite element space to output stream out.
Definition: fespace.cpp:3444
void BuildDofToArrays()
Initialize internal data that enables the use of the methods GetElementForDof() and GetLocalDofForDof...
Definition: fespace.cpp:460
double Sum() const
Return the sum of the vector entries.
Definition: vector.cpp:920
void Set1w(const double x1, const double w)
Definition: intrules.hpp:84
void GetValuesFrom(const GridFunction &orig_func)
Definition: gridfunc.cpp:1149
int GetNFDofs() const
Number of all scalar face-interior dofs.
Definition: fespace.hpp:608
int GetNEDofs() const
Number of all scalar edge-interior dofs.
Definition: fespace.hpp:606
Array< int > RefGeoms
Definition: geom.hpp:283
void GetElementVertices(int i, Array< int > &v) const
Returns the indices of the vertices of element i.
Definition: mesh.hpp:1109
virtual double * HostReadWrite()
Shortcut for mfem::ReadWrite(vec.GetMemory(), vec.Size(), false).
Definition: vector.hpp:469
void GetBdrValuesFrom(const GridFunction &orig_func)
Definition: gridfunc.cpp:1196
static void AdjustVDofs(Array< int > &vdofs)
Definition: fespace.cpp:267
Array< int > attributes
A list of all unique element attributes used by the Mesh.
Definition: mesh.hpp:268
virtual void ProjectDelta(int vertex, Vector &dofs) const
Project a delta function centered on the given vertex in the local finite dimensional space represent...
Definition: fe_base.cpp:149
void AccumulateAndCountBdrValues(Coefficient *coeff[], VectorCoefficient *vcoeff, Array< int > &attr, Array< int > &values_counter)
Definition: gridfunc.cpp:2117
Poly_1D poly1d
Definition: fe.cpp:28
void SaveVTK(std::ostream &out, const std::string &field_name, int ref)
Write the GridFunction in VTK format. Note that Mesh::PrintVTK must be called first. The parameter ref &gt; 0 must match the one used in Mesh::PrintVTK.
Definition: gridfunc.cpp:3717
void ProjectBdrCoefficient(Coefficient &coeff, Array< int > &attr)
Project a Coefficient on the GridFunction, modifying only DOFs on the boundary associated with the bo...
Definition: gridfunc.hpp:449
virtual double GetValue(int i, const IntegrationPoint &ip, int vdim=1) const
Definition: gridfunc.cpp:441
void GetGradient(ElementTransformation &tr, Vector &grad) const
Definition: gridfunc.cpp:1645
Arbitrary order &quot;L2-conforming&quot; discontinuous finite elements.
Definition: fe_coll.hpp:288
void ProjectVectorFieldOn(GridFunction &vec_field, int comp=0)
Definition: gridfunc.cpp:1331
void DofsToVDofs(Array< int > &dofs, int ndofs=-1) const
Definition: fespace.cpp:215