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