MFEM v4.10.0
Finite element discretization library
Loading...
Searching...
No Matches
gridfunc.cpp
Go to the documentation of this file.
1// Copyright (c) 2010-2026, 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 "linearform.hpp"
16#include "bilinearform.hpp"
17#include "quadinterpolator.hpp"
18#include "transfer.hpp"
19#include "../mesh/nurbs.hpp"
20#include "../mesh/vtkhdf.hpp"
21#include "../general/text.hpp"
22
23#ifdef MFEM_USE_MPI
24#include "pfespace.hpp"
25#endif
26
27#include <limits>
28#include <cstring>
29#include <string>
30#include <cmath>
31#include <iostream>
32#include <algorithm>
33#include <queue>
34
35namespace mfem
36{
37
38using namespace std;
39
40GridFunction::GridFunction(Mesh *m, std::istream &input)
41 : Vector()
42{
43 // Grid functions are stored on the device
44 UseDevice(true);
45
47 fec_owned = fes->Load(m, input);
48
49 skip_comment_lines(input, '#');
50 istream::int_type next_char = input.peek();
51 if (next_char == 'N') // First letter of "NURBS_patches"
52 {
53 string buff;
54 getline(input, buff);
55 filter_dos(buff);
56 if (buff == "NURBS_patches")
57 {
58 MFEM_VERIFY(fes->GetNURBSext(),
59 "NURBS_patches requires NURBS FE space");
60 fes->GetNURBSext()->LoadSolution(input, *this);
61 }
62 else
63 {
64 MFEM_ABORT("unknown section: " << buff);
65 }
66 }
67 else
68 {
69 Vector::Load(input, fes->GetVSize());
70
71 // if the mesh is a legacy (v1.1) NC mesh, it has old vertex ordering
72 if (fes->Nonconforming() && fes->GetMesh()->ncmesh &&
74 {
76 }
77 }
79}
80
81GridFunction::GridFunction(Mesh *m, GridFunction *gf_array[], int num_pieces)
82{
83 UseDevice(true);
84
85 // all GridFunctions must have the same FE collection, vdim, ordering
86 int vdim, ordering;
87
88 fes = gf_array[0]->FESpace();
90 vdim = fes->GetVDim();
91 ordering = fes->GetOrdering();
92 fes = new FiniteElementSpace(m, fec_owned, vdim, ordering);
94
95 if (m->NURBSext)
96 {
97 m->NURBSext->MergeGridFunctions(gf_array, num_pieces, *this);
98 return;
99 }
100
101 int g_ndofs = fes->GetNDofs();
102 int g_nvdofs = fes->GetNVDofs();
103 int g_nedofs = fes->GetNEDofs();
104 int g_nfdofs = fes->GetNFDofs();
105 int g_nddofs = g_ndofs - (g_nvdofs + g_nedofs + g_nfdofs);
106 int vi, ei, fi, di;
107 vi = ei = fi = di = 0;
108 for (int i = 0; i < num_pieces; i++)
109 {
110 FiniteElementSpace *l_fes = gf_array[i]->FESpace();
111 int l_ndofs = l_fes->GetNDofs();
112 int l_nvdofs = l_fes->GetNVDofs();
113 int l_nedofs = l_fes->GetNEDofs();
114 int l_nfdofs = l_fes->GetNFDofs();
115 int l_nddofs = l_ndofs - (l_nvdofs + l_nedofs + l_nfdofs);
116 const real_t *l_data = gf_array[i]->GetData();
117 real_t *g_data = data;
118 if (ordering == Ordering::byNODES)
119 {
120 for (int d = 0; d < vdim; d++)
121 {
122 memcpy(g_data+vi, l_data, l_nvdofs*sizeof(real_t));
123 l_data += l_nvdofs;
124 g_data += g_nvdofs;
125 memcpy(g_data+ei, l_data, l_nedofs*sizeof(real_t));
126 l_data += l_nedofs;
127 g_data += g_nedofs;
128 memcpy(g_data+fi, l_data, l_nfdofs*sizeof(real_t));
129 l_data += l_nfdofs;
130 g_data += g_nfdofs;
131 memcpy(g_data+di, l_data, l_nddofs*sizeof(real_t));
132 l_data += l_nddofs;
133 g_data += g_nddofs;
134 }
135 }
136 else
137 {
138 memcpy(g_data+vdim*vi, l_data, l_nvdofs*sizeof(real_t)*vdim);
139 l_data += vdim*l_nvdofs;
140 g_data += vdim*g_nvdofs;
141 memcpy(g_data+vdim*ei, l_data, l_nedofs*sizeof(real_t)*vdim);
142 l_data += vdim*l_nedofs;
143 g_data += vdim*g_nedofs;
144 memcpy(g_data+vdim*fi, l_data, l_nfdofs*sizeof(real_t)*vdim);
145 l_data += vdim*l_nfdofs;
146 g_data += vdim*g_nfdofs;
147 memcpy(g_data+vdim*di, l_data, l_nddofs*sizeof(real_t)*vdim);
148 l_data += vdim*l_nddofs;
149 g_data += vdim*g_nddofs;
150 }
151 vi += l_nvdofs;
152 ei += l_nedofs;
153 fi += l_nfdofs;
154 di += l_nddofs;
155 }
157}
158
160{
161 if (fec_owned)
162 {
163 delete fes;
164 delete fec_owned;
165 fec_owned = NULL;
166 }
167}
168
170{
171 if (fes->GetSequence() == fes_sequence)
172 {
173 return; // space and grid function are in sync, no-op
174 }
175 // it seems we cannot use the following, due to FESpace::Update(false)
176 /*if (fes->GetSequence() != fes_sequence + 1)
177 {
178 MFEM_ABORT("Error in update sequence. GridFunction needs to be updated "
179 "right after the space is updated.");
180 }*/
182
183 if (fes->LastUpdatePRef())
185 UpdatePRef();
186 }
187 else
188 {
189 const Operator *T = fes->GetUpdateOperator();
190 if (T)
191 {
192 Vector old_data;
193 old_data.Swap(*this);
194 SetSize(T->Height());
195 UseDevice(true);
196 T->Mult(old_data, *this);
197 }
198 else
199 {
200 SetSize(fes->GetVSize());
201 }
202 }
203
204 if (t_vec.Size() > 0) { SetTrueVector(); }
205}
206
208{
209 const std::shared_ptr<const PRefinementTransferOperator> Tp =
211 if (Tp)
212 {
213 Vector old_data;
214 old_data.Swap(*this);
215 MFEM_VERIFY(Tp->Width() == old_data.Size(),
216 "Wrong size of PRefinementTransferOperator in UpdatePRef");
217 SetSize(Tp->Height());
218 UseDevice(true);
219 Tp->Mult(old_data, *this);
220 }
221 else
222 {
223 MFEM_ABORT("Transfer operator undefined in GridFunction::UpdatePRef");
224 }
225}
226
228{
229 if (f != fes) { Destroy(); }
230 fes = f;
231 SetSize(fes->GetVSize());
233}
234
236{
237 if (f != fes) { Destroy(); }
238 fes = f;
241}
242
244{
245 MFEM_ASSERT(v.Size() >= v_offset + f->GetVSize(), "");
246 if (f != fes) { Destroy(); }
247 fes = f;
248 v.UseDevice(true);
249 this->Vector::MakeRef(v, v_offset, fes->GetVSize());
251}
252
254{
255 if (IsIdentityProlongation(f->GetProlongationMatrix()))
256 {
257 MakeRef(f, tv);
259 }
260 else
261 {
262 SetSpace(f); // works in parallel
263 t_vec.NewDataAndSize(tv, f->GetTrueVSize());
264 }
265}
266
268{
269 tv.UseDevice(true);
270 if (IsIdentityProlongation(f->GetProlongationMatrix()))
271 {
272 MakeRef(f, tv, tv_offset);
274 }
275 else
276 {
277 MFEM_ASSERT(tv.Size() >= tv_offset + f->GetTrueVSize(), "");
278 SetSpace(f); // works in parallel
279 t_vec.MakeRef(tv, tv_offset, f->GetTrueVSize());
280 }
281}
282
284 GridFunction &flux,
285 Array<int>& count,
286 bool wcoef,
287 int subdomain)
288{
289 GridFunction &u = *this;
290
291 ElementTransformation *Transf;
292
293 FiniteElementSpace *ufes = u.FESpace();
294 FiniteElementSpace *ffes = flux.FESpace();
295
296 int nfe = ufes->GetNE();
297 Array<int> udofs;
298 Array<int> fdofs;
299 Vector ul, fl;
300
301 flux = 0.0;
302 count = 0;
303
304 DofTransformation udoftrans, fdoftrans;
305 for (int i = 0; i < nfe; i++)
306 {
307 if (subdomain >= 0 && ufes->GetAttribute(i) != subdomain)
308 {
309 continue;
310 }
311
312 ufes->GetElementVDofs(i, udofs, udoftrans);
313 ffes->GetElementVDofs(i, fdofs, fdoftrans);
314
315 u.GetSubVector(udofs, ul);
316 udoftrans.InvTransformPrimal(ul);
317
318 Transf = ufes->GetElementTransformation(i);
319 blfi.ComputeElementFlux(*ufes->GetFE(i), *Transf, ul,
320 *ffes->GetFE(i), fl, wcoef);
321
322 fdoftrans.TransformPrimal(fl);
323 flux.AddElementVector(fdofs, fl);
324
326 for (int j = 0; j < fdofs.Size(); j++)
327 {
328 count[fdofs[j]]++;
329 }
330 }
331}
332
334 GridFunction &flux, bool wcoef,
335 int subdomain)
336{
337 Array<int> count(flux.Size());
338
339 SumFluxAndCount(blfi, flux, count, wcoef, subdomain);
340
341 // complete averaging
342 for (int i = 0; i < count.Size(); i++)
343 {
344 if (count[i] != 0) { flux(i) /= count[i]; }
345 }
346}
347
349{
352 {
353 // R is identity
354 tv = *this; // no real copy if 'tv' and '*this' use the same data
355 }
356 else
357 {
358 tv.SetSize(R->Height());
359 R->Mult(*this, tv);
360 }
361}
362
364{
365 MFEM_ASSERT(tv.Size() == fes->GetTrueVSize(), "invalid input");
367 if (!cP)
368 {
369 *this = tv; // no real copy if 'tv' and '*this' use the same data
370 }
371 else
372 {
373 cP->Mult(tv, *this);
374 }
375}
376
377void GridFunction::GetNodalValues(int i, Array<real_t> &nval, int vdim) const
378{
379 Array<int> vdofs;
380
381 DofTransformation doftrans;
382 fes->GetElementVDofs(i, vdofs, doftrans);
383 const FiniteElement *FElem = fes->GetFE(i);
384 const IntegrationRule *ElemVert =
386 int dof = FElem->GetDof();
387 int n = ElemVert->GetNPoints();
388 nval.SetSize(n);
389 vdim--;
390 Vector loc_data;
391 GetSubVector(vdofs, loc_data);
392 doftrans.InvTransformPrimal(loc_data);
393
394 if (FElem->GetRangeType() == FiniteElement::SCALAR)
395 {
396 Vector shape(dof);
397 if (FElem->GetMapType() == FiniteElement::VALUE)
398 {
399 for (int k = 0; k < n; k++)
400 {
401 FElem->CalcShape(ElemVert->IntPoint(k), shape);
402 nval[k] = shape * (&loc_data[dof * vdim]);
403 }
404 }
405 else
406 {
408 for (int k = 0; k < n; k++)
409 {
410 Tr->SetIntPoint(&ElemVert->IntPoint(k));
411 FElem->CalcPhysShape(*Tr, shape);
412 nval[k] = shape * (&loc_data[dof * vdim]);
413 }
414 }
415 }
416 else
417 {
419 DenseMatrix vshape(dof, FElem->GetDim());
420 for (int k = 0; k < n; k++)
421 {
422 Tr->SetIntPoint(&ElemVert->IntPoint(k));
423 FElem->CalcVShape(*Tr, vshape);
424 nval[k] = loc_data * (&vshape(0,vdim));
425 }
426 }
427}
428
430const
431{
432 Array<int> dofs;
433 DofTransformation doftrans;
434 fes->GetElementDofs(i, dofs, doftrans);
435 fes->DofsToVDofs(vdim-1, dofs);
436 Vector DofVal(dofs.Size()), LocVec;
437 const FiniteElement *fe = fes->GetFE(i);
438 if (fe->GetMapType() == FiniteElement::VALUE)
439 {
440 fe->CalcShape(ip, DofVal);
441 }
442 else
443 {
445 Tr->SetIntPoint(&ip);
446 fe->CalcPhysShape(*Tr, DofVal);
447 }
448 GetSubVector(dofs, LocVec);
449 doftrans.InvTransformPrimal(LocVec);
450
451 return (DofVal * LocVec);
452}
453
455 Vector &val) const
456{
457 const FiniteElement *FElem = fes->GetFE(i);
458 int dof = FElem->GetDof();
459 Array<int> vdofs;
460 DofTransformation doftrans;
461 fes->GetElementVDofs(i, vdofs, doftrans);
462 Vector loc_data;
463 GetSubVector(vdofs, loc_data);
464 doftrans.InvTransformPrimal(loc_data);
465 if (FElem->GetRangeType() == FiniteElement::SCALAR)
466 {
467 Vector shape(dof);
468 if (FElem->GetMapType() == FiniteElement::VALUE)
469 {
470 FElem->CalcShape(ip, shape);
471 }
472 else
473 {
475 Tr->SetIntPoint(&ip);
476 FElem->CalcPhysShape(*Tr, shape);
477 }
478 int vdim = fes->GetVDim();
479 val.SetSize(vdim);
480 for (int k = 0; k < vdim; k++)
481 {
482 val(k) = shape * (&loc_data[dof * k]);
483 }
484 }
485 else
486 {
487 int vdim = VectorDim();
488 DenseMatrix vshape(dof, vdim);
490 Tr->SetIntPoint(&ip);
491 FElem->CalcVShape(*Tr, vshape);
492 val.SetSize(vdim);
493 vshape.MultTranspose(loc_data, val);
494 }
495}
496
497void GridFunction::GetValues(int i, const IntegrationRule &ir, Vector &vals,
498 int vdim) const
499{
500 Array<int> dofs;
501 int n = ir.GetNPoints();
502 vals.SetSize(n);
503 DofTransformation doftrans;
504 fes->GetElementDofs(i, dofs, doftrans);
505 fes->DofsToVDofs(vdim-1, dofs);
506 const FiniteElement *FElem = fes->GetFE(i);
507 int dof = FElem->GetDof();
508 Vector DofVal(dof), loc_data(dof);
509 GetSubVector(dofs, loc_data);
510 doftrans.InvTransformPrimal(loc_data);
511 if (FElem->GetMapType() == FiniteElement::VALUE)
512 {
513 for (int k = 0; k < n; k++)
514 {
515 FElem->CalcShape(ir.IntPoint(k), DofVal);
516 vals(k) = DofVal * loc_data;
517 }
518 }
519 else
520 {
522 for (int k = 0; k < n; k++)
523 {
524 Tr->SetIntPoint(&ir.IntPoint(k));
525 FElem->CalcPhysShape(*Tr, DofVal);
526 vals(k) = DofVal * loc_data;
527 }
528 }
529}
531void GridFunction::GetValues(int i, const IntegrationRule &ir, Vector &vals,
532 DenseMatrix &tr, int vdim)
533const
534{
537 ET->Transform(ir, tr);
538
539 GetValues(i, ir, vals, vdim);
540}
541
543 int vdim)
544const
545{
546 Array<int> dofs;
547 int n = ir.GetNPoints();
548 laps.SetSize(n);
549 fes->GetElementDofs(i, dofs);
550 fes->DofsToVDofs(vdim-1, dofs);
551 const FiniteElement *FElem = fes->GetFE(i);
554 MFEM_ASSERT(FElem->GetMapType() == FiniteElement::VALUE,
555 "invalid FE map type");
556
557 int dof = FElem->GetDof();
558 Vector DofLap(dof), loc_data(dof);
559 GetSubVector(dofs, loc_data);
560 for (int k = 0; k < n; k++)
561 {
562 const IntegrationPoint &ip = ir.IntPoint(k);
563 ET->SetIntPoint(&ip);
564 FElem->CalcPhysLaplacian(*ET, DofLap);
565 laps(k) = DofLap * loc_data;
566 }
567}
568
570 DenseMatrix &tr, int vdim)
571const
572{
575 ET->Transform(ir, tr);
576
577 GetLaplacians(i, ir, laps, vdim);
578}
579
580
582 DenseMatrix &hess,
583 int vdim)
584const
585{
586
587 Array<int> dofs;
588 int n = ir.GetNPoints();
589 fes->GetElementDofs(i, dofs);
590 fes->DofsToVDofs(vdim-1, dofs);
591 const FiniteElement *FElem = fes->GetFE(i);
594 int dim = FElem->GetDim();
595 int size = (dim*(dim+1))/2;
596
597 MFEM_ASSERT(FElem->GetMapType() == FiniteElement::VALUE,
598 "invalid FE map type");
599
600 int dof = FElem->GetDof();
601 DenseMatrix DofHes(dof, size);
602 hess.SetSize(n, size);
603
604 Vector loc_data(dof);
605 GetSubVector(dofs, loc_data);
606
607 hess = 0.0;
608 for (int k = 0; k < n; k++)
609 {
610 const IntegrationPoint &ip = ir.IntPoint(k);
611 ET->SetIntPoint(&ip);
612 FElem->CalcPhysHessian(*ET, DofHes);
613
614 for (int j = 0; j < size; j++)
615 {
616 for (int d = 0; d < dof; d++)
617 {
618 hess(k,j) += DofHes(d,j) * loc_data[d];
619 }
620 }
621 }
622}
623
625 DenseMatrix &hess,
626 DenseMatrix &tr, int vdim)
627const
628{
631 ET->Transform(ir, tr);
632
633 GetHessians(i, ir, hess, vdim);
634}
635
636
637int GridFunction::GetFaceValues(int i, int side, const IntegrationRule &ir,
638 Vector &vals, DenseMatrix &tr,
639 int vdim) const
640{
641 int n, dir;
643
644 n = ir.GetNPoints();
645 IntegrationRule eir(n); // ---
646 if (side == 2) // automatic choice of side
647 {
648 Transf = fes->GetMesh()->GetFaceElementTransformations(i, 0);
649 if (Transf->Elem2No < 0 ||
650 fes->GetAttribute(Transf->Elem1No) <=
651 fes->GetAttribute(Transf->Elem2No))
652 {
653 dir = 0;
654 }
655 else
656 {
657 dir = 1;
658 }
659 }
660 else
661 {
662 if (side == 1 && !fes->GetMesh()->FaceIsInterior(i))
663 {
664 dir = 0;
665 }
666 else
667 {
668 dir = side;
669 }
670 }
671 if (dir == 0)
672 {
673 Transf = fes->GetMesh()->GetFaceElementTransformations(i, 4);
674 Transf->Loc1.Transform(ir, eir);
675 GetValues(Transf->Elem1No, eir, vals, tr, vdim);
676 }
677 else
678 {
679 Transf = fes->GetMesh()->GetFaceElementTransformations(i, 8);
680 Transf->Loc2.Transform(ir, eir);
681 GetValues(Transf->Elem2No, eir, vals, tr, vdim);
682 }
683
684 return dir;
685}
686
688 DenseMatrix &vals, DenseMatrix &tr) const
689{
691 Tr->Transform(ir, tr);
692
693 GetVectorValues(*Tr, ir, vals);
694}
695
697 const IntegrationPoint &ip,
698 int comp, Vector *tr) const
699{
700 if (tr)
701 {
702 T.SetIntPoint(&ip);
703 T.Transform(ip, *tr);
704 }
705
706 const FiniteElement * fe = NULL;
707 Array<int> dofs;
708
709 switch (T.ElementType)
710 {
712 fe = fes->GetFE(T.ElementNo);
713 fes->GetElementDofs(T.ElementNo, dofs);
714 break;
716 if (fes->FEColl()->GetContType() ==
718 {
720 fes->GetEdgeDofs(T.ElementNo, dofs);
721 }
722 else
723 {
724 MFEM_ABORT("GridFunction::GetValue: Field continuity type \""
725 << fes->FEColl()->GetContType() << "\" not supported "
726 << "on mesh edges.");
727 return NAN;
728 }
729 break;
731 if (fes->FEColl()->GetContType() ==
733 {
735 fes->GetFaceDofs(T.ElementNo, dofs);
736 }
737 else
738 {
739 MFEM_ABORT("GridFunction::GetValue: Field continuity type \""
740 << fes->FEColl()->GetContType() << "\" not supported "
741 << "on mesh faces.");
742 return NAN;
743 }
744 break;
746 {
747 if (fes->FEColl()->GetContType() ==
749 {
750 // This is a continuous field so we can evaluate it on the boundary.
751 fe = fes->GetBE(T.ElementNo);
753 }
754 else
755 {
756 // This is a discontinuous field which cannot be evaluated on the
757 // boundary so we'll evaluate it in the neighboring element.
760 MFEM_ASSERT(FET != nullptr,
761 "FaceElementTransformation must be valid for a boundary element");
762
763 // Boundary elements and boundary faces may have different
764 // orientations so adjust the integration point if necessary.
765 int f, o;
767 IntegrationPoint fip =
769
770 // Compute and set the point in element 1 from fip
771 FET->SetAllIntPoints(&fip);
773 return GetValue(T1, T1.GetIntPoint(), comp);
774 }
775 }
776 break;
778 {
780 dynamic_cast<FaceElementTransformations *>(&T);
781
782 // Evaluate in neighboring element for both continuous and
783 // discontinuous fields (the integration point in T1 should have
784 // already been set).
786 return GetValue(T1, T1.GetIntPoint(), comp);
787 }
788 default:
789 {
790 MFEM_ABORT("GridFunction::GetValue: Unsupported element type \""
791 << T.ElementType << "\"");
792 return NAN;
793 }
794 }
795
796 fes->DofsToVDofs(comp-1, dofs);
797 Vector DofVal(dofs.Size()), LocVec;
798 if (fe->GetMapType() == FiniteElement::VALUE)
799 {
800 fe->CalcShape(ip, DofVal);
801 }
802 else
803 {
804 fe->CalcPhysShape(T, DofVal);
805 }
806 GetSubVector(dofs, LocVec);
807
808 return (DofVal * LocVec);
809}
810
812 const IntegrationRule &ir,
813 Vector &vals, int comp,
814 DenseMatrix *tr) const
815{
816 if (tr)
817 {
818 T.Transform(ir, *tr);
819 }
820
821 int nip = ir.GetNPoints();
822 vals.SetSize(nip);
823 for (int j = 0; j < nip; j++)
824 {
825 const IntegrationPoint &ip = ir.IntPoint(j);
826 T.SetIntPoint(&ip);
827 vals[j] = GetValue(T, ip, comp);
828 }
829}
830
832 const IntegrationPoint &ip,
833 Vector &val, Vector *tr) const
834{
835 if (tr)
836 {
837 T.SetIntPoint(&ip);
838 T.Transform(ip, *tr);
839 }
840
841 Array<int> vdofs;
842 const FiniteElement *fe = NULL;
843 DofTransformation doftrans;
844
845 switch (T.ElementType)
846 {
848 fes->GetElementVDofs(T.ElementNo, vdofs, doftrans);
849 fe = fes->GetFE(T.ElementNo);
850 break;
852 if (fes->FEColl()->GetContType() ==
854 {
856 fes->GetEdgeVDofs(T.ElementNo, vdofs);
857 }
858 else
859 {
860 MFEM_ABORT("GridFunction::GetVectorValue: Field continuity type \""
861 << fes->FEColl()->GetContType() << "\" not supported "
862 << "on mesh edges.");
863 return;
864 }
865 break;
867 if (fes->FEColl()->GetContType() ==
869 {
871 fes->GetFaceVDofs(T.ElementNo, vdofs);
872 }
873 else
874 {
875 MFEM_ABORT("GridFunction::GetVectorValue: Field continuity type \""
876 << fes->FEColl()->GetContType() << "\" not supported "
877 << "on mesh faces.");
878 return;
879 }
880 break;
882 {
883 if (fes->FEColl()->GetContType() ==
885 {
886 // This is a continuous field so we can evaluate it on the boundary.
888 fe = fes->GetBE(T.ElementNo);
889 }
890 else
891 {
892 // This is a discontinuous vector field which cannot be evaluated on
893 // the boundary so we'll evaluate it in the neighboring element.
896 MFEM_ASSERT(FET != nullptr,
897 "FaceElementTransformation must be valid for a boundary element");
898
899 // Boundary elements and boundary faces may have different
900 // orientations so adjust the integration point if necessary.
901 int f, o;
903 IntegrationPoint fip =
905
906 // Compute and set the point in element 1 from fip
907 FET->SetAllIntPoints(&fip);
909 return GetVectorValue(T1, T1.GetIntPoint(), val);
910 }
911 }
912 break;
914 {
916 dynamic_cast<FaceElementTransformations *>(&T);
917 MFEM_ASSERT(FET != nullptr,
918 "FaceElementTransformation must be valid for a boundary element");
919
920 // Evaluate in neighboring element for both continuous and
921 // discontinuous fields (the integration point in T1 should have
922 // already been set).
924 return GetVectorValue(T1, T1.GetIntPoint(), val);
925 }
926 default:
927 {
928 MFEM_ABORT("GridFunction::GetVectorValue: Unsupported element type \""
929 << T.ElementType << "\"");
930 if (val.Size() > 0) { val = NAN; }
931 return;
932 }
933 }
934
935 int dof = fe->GetDof();
936 Vector loc_data;
937 GetSubVector(vdofs, loc_data);
938 doftrans.InvTransformPrimal(loc_data);
940 {
941 Vector shape(dof);
942 if (fe->GetMapType() == FiniteElement::VALUE)
943 {
944 fe->CalcShape(ip, shape);
945 }
946 else
947 {
948 fe->CalcPhysShape(T, shape);
949 }
950 int vdim = fes->GetVDim();
951 val.SetSize(vdim);
952 for (int k = 0; k < vdim; k++)
953 {
954 val(k) = shape * (&loc_data[dof * k]);
955 }
956 }
957 else
958 {
959 int spaceDim = fes->GetMesh()->SpaceDimension();
960 int vdim = std::max(spaceDim, fe->GetRangeDim());
961 DenseMatrix vshape(dof, vdim);
962 fe->CalcVShape(T, vshape);
963 val.SetSize(vdim);
964 vshape.MultTranspose(loc_data, val);
965 }
966}
967
969 const IntegrationRule &ir,
970 DenseMatrix &vals,
971 DenseMatrix *tr) const
972{
973 if (tr)
974 {
975 T.Transform(ir, *tr);
976 }
977
978 const FiniteElement *FElem = fes->GetFE(T.ElementNo);
979 int dof = FElem->GetDof();
980
981 Array<int> vdofs;
982 DofTransformation doftrans;
983 fes->GetElementVDofs(T.ElementNo, vdofs, doftrans);
984 Vector loc_data;
985 GetSubVector(vdofs, loc_data);
986 doftrans.InvTransformPrimal(loc_data);
987
988 int nip = ir.GetNPoints();
989
990 if (FElem->GetRangeType() == FiniteElement::SCALAR)
991 {
992 Vector shape(dof);
993 int vdim = fes->GetVDim();
994 vals.SetSize(vdim, nip);
995 for (int j = 0; j < nip; j++)
996 {
997 const IntegrationPoint &ip = ir.IntPoint(j);
998 T.SetIntPoint(&ip);
999 FElem->CalcPhysShape(T, shape);
1000
1001 for (int k = 0; k < vdim; k++)
1002 {
1003 vals(k,j) = shape * (&loc_data[dof * k]);
1004 }
1005 }
1006 }
1007 else
1008 {
1009 int spaceDim = fes->GetMesh()->SpaceDimension();
1010 int vdim = std::max(spaceDim, FElem->GetRangeDim());
1011 DenseMatrix vshape(dof, vdim);
1012
1013 vals.SetSize(vdim, nip);
1014 Vector val_j;
1015
1016 for (int j = 0; j < nip; j++)
1017 {
1018 const IntegrationPoint &ip = ir.IntPoint(j);
1019 T.SetIntPoint(&ip);
1020 FElem->CalcVShape(T, vshape);
1021
1022 vals.GetColumnReference(j, val_j);
1023 vshape.MultTranspose(loc_data, val_j);
1024 }
1025 }
1026}
1027
1029 int i, int side, const IntegrationRule &ir,
1030 DenseMatrix &vals, DenseMatrix &tr) const
1031{
1032 int di;
1034
1035 IntegrationRule eir(ir.GetNPoints()); // ---
1036 Transf = fes->GetMesh()->GetFaceElementTransformations(i, 0);
1037 if (side == 2)
1038 {
1039 if (Transf->Elem2No < 0 ||
1040 fes->GetAttribute(Transf->Elem1No) <=
1041 fes->GetAttribute(Transf->Elem2No))
1042 {
1043 di = 0;
1044 }
1045 else
1046 {
1047 di = 1;
1048 }
1049 }
1050 else
1051 {
1052 di = side;
1053 }
1054 if (di == 0)
1055 {
1056 Transf = fes->GetMesh()->GetFaceElementTransformations(i, 5);
1057 MFEM_ASSERT(Transf != nullptr, "FaceElementTransformation cannot be null!");
1058 Transf->Loc1.Transform(ir, eir);
1059 GetVectorValues(*Transf->Elem1, eir, vals, &tr);
1060 }
1061 else
1062 {
1063 Transf = fes->GetMesh()->GetFaceElementTransformations(i, 10);
1064 MFEM_ASSERT(Transf != nullptr, "FaceElementTransformation cannot be null!");
1065 Transf->Loc2.Transform(ir, eir);
1066 GetVectorValues(*Transf->Elem2, eir, vals, &tr);
1067 }
1068
1069 return di;
1070}
1071
1073{
1074 // Without averaging ...
1075
1076 const FiniteElementSpace *orig_fes = orig_func.FESpace();
1077 Array<int> vdofs, orig_vdofs;
1078 Vector shape, loc_values, orig_loc_values;
1079 int i, j, d, ne, dof, odof, vdim;
1080
1081 ne = fes->GetNE();
1082 vdim = fes->GetVDim();
1083 DofTransformation doftrans, orig_doftrans;
1084 for (i = 0; i < ne; i++)
1085 {
1086 fes->GetElementVDofs(i, vdofs, doftrans);
1087 orig_fes->GetElementVDofs(i, orig_vdofs, orig_doftrans);
1088 orig_func.GetSubVector(orig_vdofs, orig_loc_values);
1089 orig_doftrans.InvTransformPrimal(orig_loc_values);
1090 const FiniteElement *fe = fes->GetFE(i);
1091 const FiniteElement *orig_fe = orig_fes->GetFE(i);
1092 dof = fe->GetDof();
1093 odof = orig_fe->GetDof();
1094 loc_values.SetSize(dof * vdim);
1095 shape.SetSize(odof);
1096 const IntegrationRule &ir = fe->GetNodes();
1097 for (j = 0; j < dof; j++)
1098 {
1099 const IntegrationPoint &ip = ir.IntPoint(j);
1100 orig_fe->CalcShape(ip, shape);
1101 for (d = 0; d < vdim; d++)
1102 {
1103 loc_values(d*dof+j) = shape * (&orig_loc_values[d * odof]);
1104 }
1105 }
1106 doftrans.TransformPrimal(loc_values);
1107 SetSubVector(vdofs, loc_values);
1108 }
1109}
1110
1112{
1113 // Without averaging ...
1114
1115 const FiniteElementSpace *orig_fes = orig_func.FESpace();
1116 Array<int> vdofs, orig_vdofs;
1117 Vector shape, loc_values, loc_values_t, orig_loc_values, orig_loc_values_t;
1118 int i, j, d, nbe, dof, odof, vdim;
1119
1120 nbe = fes->GetNBE();
1121 vdim = fes->GetVDim();
1122 for (i = 0; i < nbe; i++)
1123 {
1124 fes->GetBdrElementVDofs(i, vdofs);
1125 orig_fes->GetBdrElementVDofs(i, orig_vdofs);
1126 orig_func.GetSubVector(orig_vdofs, orig_loc_values);
1127 const FiniteElement *fe = fes->GetBE(i);
1128 const FiniteElement *orig_fe = orig_fes->GetBE(i);
1129 dof = fe->GetDof();
1130 odof = orig_fe->GetDof();
1131 loc_values.SetSize(dof * vdim);
1132 shape.SetSize(odof);
1133 const IntegrationRule &ir = fe->GetNodes();
1134 for (j = 0; j < dof; j++)
1135 {
1136 const IntegrationPoint &ip = ir.IntPoint(j);
1137 orig_fe->CalcShape(ip, shape);
1138 for (d = 0; d < vdim; d++)
1139 {
1140 loc_values(d*dof+j) = shape * (&orig_loc_values[d * odof]);
1141 }
1142 }
1143 SetSubVector(vdofs, loc_values);
1144 }
1145}
1146
1148 int i, const IntegrationRule &ir, DenseMatrix &vals,
1149 DenseMatrix &tr, int comp) const
1150{
1151 Array<int> vdofs;
1152 ElementTransformation *transf;
1153
1154 const int n = ir.GetNPoints();
1155 DofTransformation doftrans;
1156 fes->GetElementVDofs(i, vdofs, doftrans);
1157 const FiniteElement *fe = fes->GetFE(i);
1158 const int dof = fe->GetDof();
1159 const int sdim = fes->GetMesh()->SpaceDimension();
1160 const int vdim = std::max(sdim, fe->GetRangeDim());
1161 // int *dofs = &vdofs[comp*dof];
1162 transf = fes->GetElementTransformation(i);
1163 transf->Transform(ir, tr);
1164 vals.SetSize(n, vdim);
1165 DenseMatrix vshape(dof, vdim);
1166 Vector loc_data, val(vdim);
1167 GetSubVector(vdofs, loc_data);
1168 doftrans.InvTransformPrimal(loc_data);
1169 for (int k = 0; k < n; k++)
1170 {
1171 const IntegrationPoint &ip = ir.IntPoint(k);
1172 transf->SetIntPoint(&ip);
1173 fe->CalcVShape(*transf, vshape);
1174 vshape.MultTranspose(loc_data, val);
1175 for (int d = 0; d < vdim; d++)
1176 {
1177 vals(k,d) = val(d);
1178 }
1179 }
1180}
1181
1183{
1185 {
1186 return;
1187 }
1188
1189 int i, j, k;
1190 int vdim = fes->GetVDim();
1191 int ndofs = fes->GetNDofs();
1192 real_t *temp = new real_t[size];
1193
1194 k = 0;
1195 for (j = 0; j < ndofs; j++)
1196 for (i = 0; i < vdim; i++)
1197 {
1198 temp[j+i*ndofs] = data[k++];
1199 }
1200
1201 for (i = 0; i < size; i++)
1202 {
1203 data[i] = temp[i];
1204 }
1205
1206 delete [] temp;
1207}
1208
1210{
1211 int i, k;
1212 Array<int> overlap(fes->GetNV());
1213 Array<int> vertices;
1214 DenseMatrix vals, tr;
1215
1216 val.SetSize(overlap.Size());
1217 overlap = 0;
1218 val = 0.0;
1219
1220 comp--;
1221 for (i = 0; i < fes->GetNE(); i++)
1222 {
1223 const IntegrationRule *ir =
1225 fes->GetElementVertices(i, vertices);
1226 GetVectorFieldValues(i, *ir, vals, tr);
1227 for (k = 0; k < ir->GetNPoints(); k++)
1228 {
1229 val(vertices[k]) += vals(k, comp);
1230 overlap[vertices[k]]++;
1231 }
1232 }
1233
1234 for (i = 0; i < overlap.Size(); i++)
1235 {
1236 val(i) /= overlap[i];
1237 }
1238}
1239
1241{
1242 FiniteElementSpace *new_fes = vec_field.FESpace();
1243
1244 Array<int> overlap(new_fes->GetVSize());
1245 Array<int> new_vdofs;
1246 DenseMatrix vals, tr;
1247
1248 overlap = 0;
1249 vec_field = 0.0;
1250
1251 for (int i = 0; i < new_fes->GetNE(); i++)
1252 {
1253 const FiniteElement *fe = new_fes->GetFE(i);
1254 const IntegrationRule &ir = fe->GetNodes();
1255 GetVectorFieldValues(i, ir, vals, tr, comp);
1256 new_fes->GetElementVDofs(i, new_vdofs);
1257 const int dof = fe->GetDof();
1258 for (int d = 0; d < vals.Width(); d++)
1259 {
1260 for (int k = 0; k < dof; k++)
1261 {
1262 real_t s;
1263 int ind = FiniteElementSpace::DecodeDof(new_vdofs[dof*d+k], s);
1264 vec_field(ind) += s * vals(k, d);
1265 overlap[ind]++;
1266 }
1267 }
1268 }
1269
1270 for (int i = 0; i < overlap.Size(); i++)
1271 {
1272 vec_field(i) /= overlap[i];
1273 }
1274}
1275
1277 int comp, int der_comp, GridFunction &der,
1278 Array<int> &zones_per_dof) const
1279{
1280 FiniteElementSpace * der_fes = der.FESpace();
1281 ElementTransformation * transf;
1282 zones_per_dof.SetSize(der_fes->GetVSize());
1283 Array<int> der_dofs, vdofs;
1284 DenseMatrix dshape, inv_jac;
1285 Vector pt_grad, loc_func;
1286 int i, j, k, dim, dof, der_dof, ind;
1287 real_t a;
1288
1289 zones_per_dof = 0;
1290 der = 0.0;
1291
1292 comp--;
1293 for (i = 0; i < der_fes->GetNE(); i++)
1294 {
1295 const FiniteElement *der_fe = der_fes->GetFE(i);
1296 const FiniteElement *fe = fes->GetFE(i);
1297 const IntegrationRule &ir = der_fe->GetNodes();
1298 der_fes->GetElementDofs(i, der_dofs);
1299 fes->GetElementVDofs(i, vdofs);
1300 dim = fe->GetDim();
1301 dof = fe->GetDof();
1302 der_dof = der_fe->GetDof();
1303 dshape.SetSize(dof, dim);
1304 inv_jac.SetSize(dim);
1305 pt_grad.SetSize(dim);
1306 loc_func.SetSize(dof);
1307 transf = fes->GetElementTransformation(i);
1308 for (j = 0; j < dof; j++)
1309 loc_func(j) = ( (ind=vdofs[comp*dof+j]) >= 0 ) ?
1310 (data[ind]) : (-data[-1-ind]);
1311 for (k = 0; k < der_dof; k++)
1312 {
1313 const IntegrationPoint &ip = ir.IntPoint(k);
1314 fe->CalcDShape(ip, dshape);
1315 dshape.MultTranspose(loc_func, pt_grad);
1316 transf->SetIntPoint(&ip);
1317 CalcInverse(transf->Jacobian(), inv_jac);
1318 a = 0.0;
1319 for (j = 0; j < dim; j++)
1320 {
1321 a += inv_jac(j, der_comp) * pt_grad(j);
1322 }
1323 der(der_dofs[k]) += a;
1324 zones_per_dof[der_dofs[k]]++;
1325 }
1326 }
1327}
1328
1329void GridFunction::GetDerivative(int comp, int der_comp,
1330 GridFunction &der) const
1331{
1332 Array<int> overlap;
1333 AccumulateAndCountDerivativeValues(comp, der_comp, der, overlap);
1334
1335 for (int i = 0; i < overlap.Size(); i++)
1336 {
1337 der(i) /= overlap[i];
1338 }
1339}
1340
1342 ElementTransformation &T, DenseMatrix &gh) const
1343{
1344 const FiniteElement *FElem = fes->GetFE(T.ElementNo);
1345 int dim = FElem->GetDim(), dof = FElem->GetDof();
1346 Vector loc_data;
1347 GetElementDofValues(T.ElementNo, loc_data);
1348 // assuming scalar FE
1349 int vdim = fes->GetVDim();
1350 DenseMatrix dshape(dof, dim);
1351 FElem->CalcDShape(T.GetIntPoint(), dshape);
1352 gh.SetSize(vdim, dim);
1353 DenseMatrix loc_data_mat(loc_data.GetData(), dof, vdim);
1354 MultAtB(loc_data_mat, dshape, gh);
1355}
1356
1358 QVectorLayout ql, MemoryType d_mt) const
1359{
1360 const FiniteElement &fe = *fes->GetTypicalFE();
1361 const int dim = fe.GetDim();
1362 const int vdim = fes->GetVDim();
1363 const int NE = fes->GetNE();
1364 const int ND = fe.GetDof();
1365 const int NQ = ir.GetNPoints();
1366
1367 MemoryType my_d_mt = (d_mt != MemoryType::DEFAULT) ? d_mt :
1369
1370 // ql == QVectorLayout::byNODES : NQ x VDIM x DIM x NE
1371 // ql == QVectorLayout::byVDIM : VDIM x DIM x NQPT x NE
1372 grad.SetSize(dim*vdim*NQ*NE, my_d_mt);
1373
1375 qi.SetOutputLayout(ql);
1376
1377 const bool use_tensor_products = UsesTensorBasis(*fes);
1378 qi.DisableTensorProducts(!use_tensor_products);
1379 const ElementDofOrdering e_ordering = use_tensor_products ?
1382 const Operator *elem_restr = fes->GetElementRestriction(e_ordering);
1383
1384 // Pre-compute the geometric factors in order to set the desired MemoryType
1385 // they use:
1387 ir, GeometricFactors::JACOBIANS, my_d_mt);
1388
1389 if (elem_restr) // currently, always true
1390 {
1391 Vector f_e(vdim*ND*NE, my_d_mt);
1392 elem_restr->Mult(*this, f_e);
1393 qi.PhysDerivatives(f_e, grad);
1394 }
1395 else
1396 {
1397 qi.PhysDerivatives(*this, grad);
1398 }
1399}
1400
1402{
1403 DofTransformation doftrans;
1404 switch (T.ElementType)
1405 {
1407 {
1408 int elNo = T.ElementNo;
1409 const FiniteElement *fe = fes->GetFE(elNo);
1411 {
1412 MFEM_ASSERT(fe->GetMapType() == FiniteElement::VALUE,
1413 "invalid FE map type");
1414 DenseMatrix grad_hat;
1415 GetVectorGradientHat(T, grad_hat);
1416 const DenseMatrix &Jinv = T.InverseJacobian();
1417 real_t div_v = 0.0;
1418 for (int i = 0; i < Jinv.Width(); i++)
1419 {
1420 for (int j = 0; j < Jinv.Height(); j++)
1421 {
1422 div_v += grad_hat(i, j) * Jinv(j, i);
1423 }
1424 }
1425 return div_v;
1426 }
1427 else
1428 {
1429 // Assuming RT-type space
1430 Array<int> dofs;
1431 fes->GetElementDofs(elNo, dofs, doftrans);
1432 Vector loc_data, divshape(fe->GetDof());
1433 GetSubVector(dofs, loc_data);
1434 doftrans.InvTransformPrimal(loc_data);
1435 fe->CalcDivShape(T.GetIntPoint(), divshape);
1436 return (loc_data * divshape) / T.Weight();
1437 }
1438 }
1439 break;
1441 {
1442 // In order to properly capture the derivative of the normal component
1443 // of the field (as well as the transverse divergence of the
1444 // tangential components) we must evaluate it in the neighboring
1445 // element.
1448
1449 // Boundary elements and boundary faces may have different
1450 // orientations so adjust the integration point if necessary.
1451 int f, o;
1453 IntegrationPoint fip =
1455 T.GetIntPoint());
1456
1457 // Compute and set the point in element 1 from fip
1458 FET->SetAllIntPoints(&fip);
1460
1461 return GetDivergence(T1);
1462 }
1463 break;
1465 {
1466 // This must be a DG context so this dynamic cast must succeed.
1468 dynamic_cast<FaceElementTransformations *>(&T);
1469
1470 // Evaluate in neighboring element (the integration point in T1 should
1471 // have already been set).
1473 return GetDivergence(T1);
1474 }
1475 break;
1476 default:
1477 {
1478 MFEM_ABORT("GridFunction::GetDivergence: Unsupported element type \""
1479 << T.ElementType << "\"");
1480 }
1481 }
1482 return 0.0; // never reached
1483}
1484
1486{
1487 DofTransformation doftrans;
1488 switch (T.ElementType)
1489 {
1491 {
1492 int elNo = T.ElementNo;
1493 const FiniteElement *fe = fes->GetFE(elNo);
1495 {
1496 MFEM_ASSERT(fe->GetMapType() == FiniteElement::VALUE,
1497 "invalid FE map type");
1498 DenseMatrix grad_hat;
1499 GetVectorGradientHat(T, grad_hat);
1500 const DenseMatrix &Jinv = T.InverseJacobian();
1501 // Dimensions of grad are vdim x FElem->Dim
1502 DenseMatrix grad(grad_hat.Height(), Jinv.Width());
1503 Mult(grad_hat, Jinv, grad);
1504 MFEM_ASSERT(grad.Height() == grad.Width(), "");
1505 if (grad.Height() == 3)
1506 {
1507 curl.SetSize(3);
1508 curl(0) = grad(2,1) - grad(1,2);
1509 curl(1) = grad(0,2) - grad(2,0);
1510 curl(2) = grad(1,0) - grad(0,1);
1511 }
1512 else if (grad.Height() == 2)
1513 {
1514 curl.SetSize(1);
1515 curl(0) = grad(1,0) - grad(0,1);
1516 }
1517 }
1518 else
1519 {
1520 // Assuming ND-type space
1521 Array<int> dofs;
1522 fes->GetElementDofs(elNo, dofs, doftrans);
1523 Vector loc_data;
1524 GetSubVector(dofs, loc_data);
1525 doftrans.InvTransformPrimal(loc_data);
1526 DenseMatrix curl_shape(fe->GetDof(), fe->GetCurlDim());
1527 curl.SetSize(curl_shape.Width());
1528 fe->CalcPhysCurlShape(T, curl_shape);
1529 curl_shape.MultTranspose(loc_data, curl);
1530 }
1531 }
1532 break;
1534 {
1535 // In order to capture the tangential components of the curl we
1536 // must evaluate it in the neighboring element.
1539
1540 // Boundary elements and boundary faces may have different
1541 // orientations so adjust the integration point if necessary.
1542 int f, o;
1544 IntegrationPoint fip =
1546 T.GetIntPoint());
1547
1548 // Compute and set the point in element 1 from fip
1549 FET->SetAllIntPoints(&fip);
1551
1552 GetCurl(T1, curl);
1553 }
1554 break;
1556 {
1557 // This must be a DG context so this dynamic cast must succeed.
1559 dynamic_cast<FaceElementTransformations *>(&T);
1560
1561 // Evaluate in neighboring element (the integration point in T1 should
1562 // have already been set).
1564 GetCurl(T1, curl);
1565 }
1566 break;
1567 default:
1568 {
1569 MFEM_ABORT("GridFunction::GetCurl: Unsupported element type \""
1570 << T.ElementType << "\"");
1571 }
1572 }
1573}
1574
1576{
1577 switch (T.ElementType)
1578 {
1580 {
1581 const FiniteElement *fe = fes->GetFE(T.ElementNo);
1582 MFEM_ASSERT(fe->GetMapType() == FiniteElement::VALUE,
1583 "invalid FE map type");
1584 MFEM_ASSERT(fes->GetVDim() == 1, "Defined for scalar functions.");
1585 int spaceDim = fes->GetMesh()->SpaceDimension();
1586 int dim = fe->GetDim(), dof = fe->GetDof();
1587 DenseMatrix dshape(dof, dim);
1588 Vector lval, gh(dim);
1589
1590 grad.SetSize(spaceDim);
1592 fe->CalcDShape(T.GetIntPoint(), dshape);
1593 dshape.MultTranspose(lval, gh);
1594 T.InverseJacobian().MultTranspose(gh, grad);
1595 }
1596 break;
1598 {
1599 // In order to properly capture the normal component of the gradient
1600 // as well as its tangential components we must evaluate it in the
1601 // neighboring element.
1604
1605 // Boundary elements and boundary faces may have different
1606 // orientations so adjust the integration point if necessary.
1607 int f, o;
1609 IntegrationPoint fip =
1611 T.GetIntPoint());
1612
1613 // Compute and set the point in element 1 from fip
1614 FET->SetAllIntPoints(&fip);
1616
1617 GetGradient(T1, grad);
1618 }
1619 break;
1621 {
1622 // This must be a DG context so this dynamic cast must succeed.
1624 dynamic_cast<FaceElementTransformations *>(&T);
1625
1626 // Evaluate in neighboring element (the integration point in T1 should
1627 // have already been set).
1629 GetGradient(T1, grad);
1630 }
1631 break;
1632 default:
1633 {
1634 MFEM_ABORT("GridFunction::GetGradient: Unsupported element type \""
1635 << T.ElementType << "\"");
1636 }
1637 }
1638}
1639
1641 const IntegrationRule &ir,
1642 DenseMatrix &grad) const
1643{
1644 int elNo = tr.ElementNo;
1645 const FiniteElement *fe = fes->GetFE(elNo);
1646 MFEM_ASSERT(fe->GetMapType() == FiniteElement::VALUE, "invalid FE map type");
1647 DenseMatrix dshape(fe->GetDof(), fe->GetDim());
1648 Vector lval, gh(fe->GetDim()), gcol;
1649
1650 GetElementDofValues(tr.ElementNo, lval);
1651 grad.SetSize(fe->GetDim(), ir.GetNPoints());
1652 for (int i = 0; i < ir.GetNPoints(); i++)
1653 {
1654 const IntegrationPoint &ip = ir.IntPoint(i);
1655 fe->CalcDShape(ip, dshape);
1656 dshape.MultTranspose(lval, gh);
1657 tr.SetIntPoint(&ip);
1658 grad.GetColumnReference(i, gcol);
1659 const DenseMatrix &Jinv = tr.InverseJacobian();
1660 Jinv.MultTranspose(gh, gcol);
1661 }
1662}
1663
1665 ElementTransformation &T, DenseMatrix &grad) const
1666{
1667 switch (T.ElementType)
1668 {
1670 {
1671 MFEM_ASSERT(fes->GetFE(T.ElementNo)->GetMapType() ==
1672 FiniteElement::VALUE, "invalid FE map type");
1673 DenseMatrix grad_hat;
1674 GetVectorGradientHat(T, grad_hat);
1675 const DenseMatrix &Jinv = T.InverseJacobian();
1676 grad.SetSize(grad_hat.Height(), Jinv.Width());
1677 Mult(grad_hat, Jinv, grad);
1678 }
1679 break;
1681 {
1682 // In order to capture the normal component of the gradient we
1683 // must evaluate it in the neighboring element.
1686
1687 // Boundary elements and boundary faces may have different
1688 // orientations so adjust the integration point if necessary.
1689 int f, o;
1691 IntegrationPoint fip =
1693 T.GetIntPoint());
1694
1695 // Compute and set the point in element 1 from fip
1696 FET->SetAllIntPoints(&fip);
1698
1699 GetVectorGradient(T1, grad);
1700 }
1701 break;
1703 {
1704 // This must be a DG context so this dynamic cast must succeed.
1706 dynamic_cast<FaceElementTransformations *>(&T);
1707
1708 // Evaluate in neighboring element (the integration point in T1 should
1709 // have already been set).
1711 GetVectorGradient(T1, grad);
1712 }
1713 break;
1714 default:
1715 {
1716 MFEM_ABORT("GridFunction::GetVectorGradient: "
1717 "Unsupported element type \"" << T.ElementType << "\"");
1718 }
1719 }
1720}
1721
1723{
1724 MassIntegrator Mi;
1725 DenseMatrix loc_mass;
1726 Array<int> te_dofs, tr_dofs;
1727 Vector loc_avgs, loc_this;
1728 Vector int_psi(avgs.Size());
1729 DofTransformation tr_doftrans, te_doftrans;
1730
1731 avgs = 0.0;
1732 int_psi = 0.0;
1733 for (int i = 0; i < fes->GetNE(); i++)
1734 {
1735 Mi.AssembleElementMatrix2(*fes->GetFE(i), *avgs.FESpace()->GetFE(i),
1736 *fes->GetElementTransformation(i), loc_mass);
1737 fes->GetElementDofs(i, tr_dofs, tr_doftrans);
1738 avgs.FESpace()->GetElementDofs(i, te_dofs, te_doftrans);
1739 GetSubVector(tr_dofs, loc_this);
1740 tr_doftrans.InvTransformPrimal(loc_this);
1741 loc_avgs.SetSize(te_dofs.Size());
1742 loc_mass.Mult(loc_this, loc_avgs);
1743 te_doftrans.TransformPrimal(loc_avgs);
1744 avgs.AddElementVector(te_dofs, loc_avgs);
1745 loc_this = 1.0; // assume the local basis for 'this' sums to 1
1746 loc_mass.Mult(loc_this, loc_avgs);
1747 int_psi.AddElementVector(te_dofs, loc_avgs);
1748 }
1749 for (int i = 0; i < avgs.Size(); i++)
1750 {
1751 avgs(i) /= int_psi(i);
1752 }
1753}
1754
1755void GridFunction::GetElementDofValues(int el, Vector &dof_vals) const
1756{
1757 Array<int> dof_idx;
1758 DofTransformation doftrans;
1759 fes->GetElementVDofs(el, dof_idx, doftrans);
1760 GetSubVector(dof_idx, dof_vals);
1761 doftrans.InvTransformPrimal(dof_vals);
1762}
1763
1765{
1766 Mesh *mesh = fes->GetMesh();
1767 bool sameP = false;
1768 DenseMatrix P;
1769
1770 if (!mesh->GetNE()) { return; }
1771
1772 Geometry::Type geom, cached_geom = Geometry::INVALID;
1773 if (mesh->GetNumGeometries(mesh->Dimension()) == 1)
1774 {
1775 // Assuming that the projection matrix is the same for all elements
1776 sameP = true;
1779 }
1780 const int vdim = fes->GetVDim();
1781 MFEM_VERIFY(vdim == src.fes->GetVDim(), "incompatible vector dimensions!");
1782
1783 Array<int> src_vdofs, dest_vdofs;
1784 Vector src_lvec, dest_lvec(vdim*P.Height());
1785
1786 DofTransformation src_doftrans, doftrans;
1787 for (int i = 0; i < mesh->GetNE(); i++)
1788 {
1789 // Assuming the projection matrix P depends only on the element geometry
1790 if ( !sameP && (geom = mesh->GetElementBaseGeometry(i)) != cached_geom )
1791 {
1792 fes->GetFE(i)->Project(*src.fes->GetFE(i),
1793 *mesh->GetElementTransformation(i), P);
1794 dest_lvec.SetSize(vdim*P.Height());
1795 cached_geom = geom;
1796 }
1797
1798 src.fes->GetElementVDofs(i, src_vdofs, src_doftrans);
1799 src.GetSubVector(src_vdofs, src_lvec);
1800 src_doftrans.InvTransformPrimal(src_lvec);
1801 for (int vd = 0; vd < vdim; vd++)
1802 {
1803 P.Mult(&src_lvec[vd*P.Width()], &dest_lvec[vd*P.Height()]);
1804 }
1805 fes->GetElementVDofs(i, dest_vdofs, doftrans);
1806 doftrans.TransformPrimal(dest_lvec);
1807 SetSubVector(dest_vdofs, dest_lvec);
1808 }
1809}
1810
1811void GridFunction::ImposeBounds(int i, const Vector &weights,
1812 const Vector &lo_, const Vector &hi_)
1813{
1814 Array<int> vdofs;
1815 DofTransformation doftrans;
1816 fes->GetElementVDofs(i, vdofs, doftrans);
1817 int size = vdofs.Size();
1818 Vector vals, new_vals(size);
1819
1820 GetSubVector(vdofs, vals);
1821 doftrans.InvTransformPrimal(vals);
1822
1823 MFEM_ASSERT(weights.Size() == size, "Different # of weights and dofs.");
1824 MFEM_ASSERT(lo_.Size() == size, "Different # of lower bounds and dofs.");
1825 MFEM_ASSERT(hi_.Size() == size, "Different # of upper bounds and dofs.");
1826
1827 int max_iter = 30;
1828 real_t tol = 1.e-12;
1829 SLBQPOptimizer slbqp;
1830 slbqp.SetMaxIter(max_iter);
1831 slbqp.SetAbsTol(1.0e-18);
1832 slbqp.SetRelTol(tol);
1833 slbqp.SetBounds(lo_, hi_);
1834 slbqp.SetLinearConstraint(weights, weights * vals);
1835 slbqp.SetPrintLevel(0); // print messages only if not converged
1836 slbqp.Mult(vals, new_vals);
1837
1838 doftrans.TransformPrimal(new_vals);
1839 SetSubVector(vdofs, new_vals);
1840}
1841
1842void GridFunction::ImposeBounds(int i, const Vector &weights,
1843 real_t min_, real_t max_)
1844{
1845 Array<int> vdofs;
1846 DofTransformation doftrans;
1847 fes->GetElementVDofs(i, vdofs, doftrans);
1848 int size = vdofs.Size();
1849 Vector vals, new_vals(size);
1850 GetSubVector(vdofs, vals);
1851 doftrans.InvTransformPrimal(vals);
1852
1853 real_t max_val = vals.Max();
1854 real_t min_val = vals.Min();
1855
1856 if (max_val <= min_)
1857 {
1858 new_vals = min_;
1859 doftrans.TransformPrimal(new_vals);
1860 SetSubVector(vdofs, new_vals);
1861 return;
1862 }
1863
1864 if (min_ <= min_val && max_val <= max_)
1865 {
1866 return;
1867 }
1868
1869 Vector minv(size), maxv(size);
1870 minv = (min_ > min_val) ? min_ : min_val;
1871 maxv = (max_ < max_val) ? max_ : max_val;
1872
1873 ImposeBounds(i, weights, minv, maxv);
1874}
1875
1877{
1879 const Operator *P = fes->GetProlongationMatrix();
1880
1881 if (P && R)
1882 {
1883 Vector tmp(R->Height());
1884 R->Mult(*this, tmp);
1885 P->Mult(tmp, *this);
1886 }
1887}
1888
1889void GridFunction::GetNodalValues(Vector &nval, int vdim) const
1890{
1891 Array<int> vertices;
1892 Array<real_t> values;
1893 Array<int> overlap(fes->GetNV());
1894 nval.SetSize(fes->GetNV());
1895 nval = 0.0;
1896 overlap = 0;
1897 nval.HostReadWrite();
1898 for (int i = 0; i < fes->GetNE(); i++)
1899 {
1900 fes->GetElementVertices(i, vertices);
1901 GetNodalValues(i, values, vdim);
1902 for (int j = 0; j < vertices.Size(); j++)
1903 {
1904 nval(vertices[j]) += values[j];
1905 overlap[vertices[j]]++;
1906 }
1907 }
1908 for (int i = 0; i < overlap.Size(); i++)
1909 {
1910 nval(i) /= overlap[i];
1911 }
1912}
1913
1914
1916{
1917 elem_per_vdof.SetSize(fes->GetVSize());
1918 elem_per_vdof = 0;
1919 Array<int> vdofs;
1920
1921 for (int i = 0; i < fes->GetNE(); i++)
1922 {
1923 fes->GetElementVDofs(i, vdofs);
1924 // Accumulate values in all dofs, count the zones.
1925 for (int j = 0; j < vdofs.Size(); j++)
1926 {
1927 elem_per_vdof[vdofs[j]]++;
1928 }
1929 }
1930}
1931
1933 AvgType type,
1934 Array<int> &zones_per_vdof)
1935{
1936 zones_per_vdof.SetSize(fes->GetVSize());
1937 zones_per_vdof = 0;
1938
1939 // Local interpolation
1940 Array<int> vdofs;
1941 Vector vals;
1942 *this = 0.0;
1943
1944 HostReadWrite();
1945
1946 for (int i = 0; i < fes->GetNE(); i++)
1947 {
1948 fes->GetElementVDofs(i, vdofs);
1949 // Local interpolation of coeff.
1950 vals.SetSize(vdofs.Size());
1951 fes->GetFE(i)->Project(coeff, *fes->GetElementTransformation(i), vals);
1952
1953 // Accumulate values in all dofs, count the zones.
1954 for (int j = 0; j < vdofs.Size(); j++)
1955 {
1956 if (type == HARMONIC)
1957 {
1958 MFEM_VERIFY(vals[j] != 0.0,
1959 "Coefficient has zeros, harmonic avg is undefined!");
1960 (*this)(vdofs[j]) += 1.0 / vals[j];
1961 }
1962 else if (type == ARITHMETIC)
1963 {
1964 (*this)(vdofs[j]) += vals[j];
1965 }
1966 else { MFEM_ABORT("Not implemented"); }
1967
1968 zones_per_vdof[vdofs[j]]++;
1969 }
1970 }
1971}
1972
1974 AvgType type,
1975 Array<int> &zones_per_vdof)
1976{
1977 zones_per_vdof.SetSize(fes->GetVSize());
1978 zones_per_vdof = 0;
1979
1980 // Local interpolation
1981 Array<int> vdofs;
1982 Vector vals;
1983 *this = 0.0;
1984
1985 HostReadWrite();
1986
1987 for (int i = 0; i < fes->GetNE(); i++)
1988 {
1989 fes->GetElementVDofs(i, vdofs);
1990 // Local interpolation of coeff.
1991 vals.SetSize(vdofs.Size());
1992 fes->GetFE(i)->Project(vcoeff, *fes->GetElementTransformation(i), vals);
1993
1994 // Accumulate values in all dofs, count the zones.
1995 for (int j = 0; j < vdofs.Size(); j++)
1996 {
1997 int ldof;
1998 int isign;
1999 if (vdofs[j] < 0 )
2000 {
2001 ldof = -1-vdofs[j];
2002 isign = -1;
2003 }
2004 else
2005 {
2006 ldof = vdofs[j];
2007 isign = 1;
2008 }
2009
2010 if (type == HARMONIC)
2011 {
2012 MFEM_VERIFY(vals[j] != 0.0,
2013 "Coefficient has zeros, harmonic avg is undefined!");
2014 (*this)(ldof) += isign / vals[j];
2015 }
2016 else if (type == ARITHMETIC)
2017 {
2018 (*this)(ldof) += isign*vals[j];
2019
2020 }
2021 else { MFEM_ABORT("Not implemented"); }
2022
2023 zones_per_vdof[ldof]++;
2024 }
2025 }
2026}
2027
2029 Coefficient *coeff[], VectorCoefficient *vcoeff, const Array<int> &attr,
2030 Array<int> &values_counter)
2031{
2032 if (vcoeff)
2033 {
2034 MFEM_VERIFY(fes->GetVDim() == vcoeff->GetVDim(),
2035 "vcoeff vdim != fes VDim");
2036 MFEM_VERIFY(fes->GetTypicalBE()->GetMapType() == FiniteElement::VALUE &&
2039 "Can only call ProjectBdrCoefficient on scalar value-type "
2040 "boundary elements. "
2041 "Did you intended to call ProjectBdrCoefficientNormal or "
2042 "ProjectBdrCoefficientTangent for vector finite elements?");
2043 }
2044 Array<int> vdofs;
2045 Vector vc;
2046
2047 values_counter.SetSize(Size());
2048 values_counter = 0;
2049
2050 const int vdim = fes->GetVDim();
2051 HostReadWrite();
2052
2053 for (int i = 0; i < fes->GetNBE(); i++)
2054 {
2055 if (attr[fes->GetBdrAttribute(i) - 1] == 0) { continue; }
2056
2057 const FiniteElement *fe = fes->GetBE(i);
2058 const int fdof = fe->GetDof();
2060 const IntegrationRule &ir = fe->GetNodes();
2061 fes->GetBdrElementVDofs(i, vdofs);
2062
2063 for (int j = 0; j < fdof; j++)
2064 {
2065 const IntegrationPoint &ip = ir.IntPoint(j);
2066 transf->SetIntPoint(&ip);
2067 if (vcoeff) { vcoeff->Eval(vc, *transf, ip); }
2068 for (int d = 0; d < vdim; d++)
2069 {
2070 if (!vcoeff && !coeff[d]) { continue; }
2071
2072 real_t val = vcoeff ? vc(d) : coeff[d]->Eval(*transf, ip);
2073 int ind = vdofs[fdof*d+j];
2074 if ( ind < 0 )
2075 {
2076 val = -val, ind = -1-ind;
2077 }
2078 if (++values_counter[ind] == 1)
2079 {
2080 (*this)(ind) = val;
2081 }
2082 else
2083 {
2084 (*this)(ind) += val;
2085 }
2086 }
2087 }
2088 }
2089
2090 // In the case of partially conforming space, i.e. (fes->cP != NULL), we need
2091 // to set the values of all dofs on which the dofs set above depend.
2092 // Dependency is defined from the matrix A = cP.cR: dof i depends on dof j
2093 // iff A_ij != 0. It is sufficient to resolve just the first level of
2094 // dependency, since A is a projection matrix: A^n = A due to cR.cP = I.
2095 // Cases like these arise in 3D when boundary edges are constrained by
2096 // (depend on) internal faces/elements, or for internal boundaries in 2 or
2097 // 3D. We use the virtual method GetBoundaryClosure from NCMesh to resolve
2098 // the dependencies.
2099 if (fes->Nonconforming() && (fes->GetMesh()->Dimension() == 2 ||
2100 fes->GetMesh()->Dimension() == 3))
2101 {
2102 Vector vals;
2103 Mesh *mesh = fes->GetMesh();
2104 NCMesh *ncmesh = mesh->ncmesh;
2105 Array<int> bdr_edges, bdr_vertices, bdr_faces;
2106 ncmesh->GetBoundaryClosure(attr, bdr_vertices, bdr_edges, bdr_faces);
2107
2108 auto mark_dofs = [&](ElementTransformation &transf, const FiniteElement &fe)
2109 {
2110 if (!vcoeff)
2111 {
2112 vals.SetSize(fe.GetDof());
2113 for (int d = 0; d < vdim; d++)
2114 {
2115 if (!coeff[d]) { continue; }
2116
2117 fe.Project(*coeff[d], transf, vals);
2118 for (int k = 0; k < vals.Size(); k++)
2119 {
2120 const int ind = vdofs[d*vals.Size()+k];
2121 if (++values_counter[ind] == 1)
2122 {
2123 (*this)(ind) = vals(k);
2124 }
2125 else
2126 {
2127 (*this)(ind) += vals(k);
2128 }
2129 }
2130 }
2131 }
2132 else // vcoeff != NULL
2133 {
2134 vals.SetSize(vdim*fe.GetDof());
2135 fe.Project(*vcoeff, transf, vals);
2136 for (int k = 0; k < vals.Size(); k++)
2137 {
2138 const int ind = vdofs[k];
2139 if (++values_counter[ind] == 1)
2140 {
2141 (*this)(ind) = vals(k);
2142 }
2143 else
2144 {
2145 (*this)(ind) += vals(k);
2146 }
2147 }
2148 }
2149 };
2150
2151 for (auto edge : bdr_edges)
2152 {
2153 fes->GetEdgeVDofs(edge, vdofs);
2154 if (vdofs.Size() == 0) { continue; }
2155
2156 ElementTransformation *transf = mesh->GetEdgeTransformation(edge);
2157 const FiniteElement *fe = fes->GetEdgeElement(edge);
2158 mark_dofs(*transf, *fe);
2159 }
2160
2161 for (auto face : bdr_faces)
2162 {
2163 fes->GetFaceVDofs(face, vdofs);
2164 if (vdofs.Size() == 0) { continue; }
2165
2166 ElementTransformation *transf = mesh->GetFaceTransformation(face);
2167 const FiniteElement *fe = fes->GetFaceElement(face);
2168 mark_dofs(*transf, *fe);
2169 }
2170 }
2171}
2172
2173static void accumulate_dofs(const Array<int> &dofs, const Vector &vals,
2174 Vector &gf, Array<int> &values_counter)
2175{
2176 for (int i = 0; i < dofs.Size(); i++)
2177 {
2178 int k = dofs[i];
2179 real_t val = vals(i);
2180 if (k < 0) { k = -1 - k; val = -val; }
2181 if (++values_counter[k] == 1)
2182 {
2183 gf(k) = val;
2184 }
2185 else
2186 {
2187 gf(k) += val;
2188 }
2189 }
2190}
2191
2193 VectorCoefficient &vcoeff, const Array<int> &bdr_attr,
2194 Array<int> &values_counter)
2195{
2196 MFEM_VERIFY(fes->GetTypicalBE()->GetPhysRangeDim(
2197 fes->GetMesh()->SpaceDimension()) == vcoeff.GetVDim(),
2198 "vcoeff vdim != PhysRangeDim");
2199 const FiniteElement *fe;
2201 Array<int> dofs;
2202 Vector lvec;
2203 DofTransformation dof_tr;
2204
2205 values_counter.SetSize(Size());
2206 values_counter = 0;
2207
2208 HostReadWrite();
2209
2210 for (int i = 0; i < fes->GetNBE(); i++)
2211 {
2212 if (bdr_attr[fes->GetBdrAttribute(i)-1] == 0)
2213 {
2214 continue;
2215 }
2216 fe = fes->GetBE(i);
2218 fes->GetBdrElementDofs(i, dofs, dof_tr);
2219 lvec.SetSize(fe->GetDof());
2220 fe->Project(vcoeff, *T, lvec);
2221 dof_tr.TransformPrimal(lvec);
2222 accumulate_dofs(dofs, lvec, *this, values_counter);
2223 }
2224
2225 if (fes->Nonconforming() && (fes->GetMesh()->Dimension() == 2 ||
2226 fes->GetMesh()->Dimension() == 3))
2227 {
2228 Mesh *mesh = fes->GetMesh();
2229 NCMesh *ncmesh = mesh->ncmesh;
2230 Array<int> bdr_edges, bdr_vertices, bdr_faces;
2231 ncmesh->GetBoundaryClosure(bdr_attr, bdr_vertices, bdr_edges, bdr_faces);
2232
2233 for (auto edge : bdr_edges)
2234 {
2235 fes->GetEdgeDofs(edge, dofs);
2236 if (dofs.Size() == 0) { continue; }
2237
2238 T = mesh->GetEdgeTransformation(edge);
2239 fe = fes->GetEdgeElement(edge);
2240 lvec.SetSize(fe->GetDof());
2241 fe->Project(vcoeff, *T, lvec);
2242 accumulate_dofs(dofs, lvec, *this, values_counter);
2243 }
2244
2245 for (auto face : bdr_faces)
2246 {
2247 fes->GetFaceDofs(face, dofs);
2248 if (dofs.Size() == 0) { continue; }
2249
2250 T = mesh->GetFaceTransformation(face);
2251 fe = fes->GetFaceElement(face);
2252 lvec.SetSize(fe->GetDof());
2253 fe->Project(vcoeff, *T, lvec);
2254 accumulate_dofs(dofs, lvec, *this, values_counter);
2255 }
2256 }
2257}
2258
2260 Coefficient *coeff[], VectorCoefficient *vcoeff,
2261 Array<int> &values_counter)
2262{
2263 if (vcoeff)
2264 {
2265 MFEM_VERIFY(fes->GetVDim() == vcoeff->GetVDim(),
2266 "vcoeff vdim != fes VDim");
2267 MFEM_VERIFY(fes->GetTypicalTraceElement()->GetMapType() ==
2271 "Can only call ProjectTraceCoefficient on scalar value-type "
2272 "trace elements. "
2273 "Use ProjectTraceCoefficientNormal for RT and "
2274 "ProjectTraceCoefficientTangent for ND finite elements.");
2275 }
2276
2277 Array<int> vdofs;
2278 Vector vc;
2279
2280 values_counter.SetSize(Size());
2281 values_counter = 0;
2282
2283 const int vdim = fes->GetVDim();
2284 HostReadWrite();
2285
2286 for (int i = 0; i < fes->GetMesh()->GetNumFaces(); i++)
2287 {
2288
2289 const FiniteElement *fe = fes->GetFaceElement(i);
2290 const int fdof = fe->GetDof();
2292 const IntegrationRule &ir = fe->GetNodes();
2293 fes->GetFaceVDofs(i, vdofs);
2294
2295 for (int j = 0; j < fdof; j++)
2296 {
2297 const IntegrationPoint &ip = ir.IntPoint(j);
2298 transf->SetIntPoint(&ip);
2299 if (vcoeff) { vcoeff->Eval(vc, *transf, ip); }
2300 for (int d = 0; d < vdim; d++)
2301 {
2302 if (!vcoeff && !coeff[d]) { continue; }
2303
2304 real_t val = vcoeff ? vc(d) : coeff[d]->Eval(*transf, ip);
2305 int ind = vdofs[fdof*d+j];
2306 if ( ind < 0 )
2307 {
2308 val = -val, ind = -1-ind;
2309 }
2310 if (++values_counter[ind] == 1)
2311 {
2312 (*this)(ind) = val;
2313 }
2314 else
2315 {
2316 (*this)(ind) += val;
2317 }
2318 }
2319 }
2320 }
2321}
2322
2324 VectorCoefficient &vcoeff, Array<int> &values_counter)
2325{
2326 MFEM_VERIFY(fes->GetVDim() == 1, "fespace VDim != 1");
2327 MFEM_VERIFY(fes->GetTypicalTraceElement()
2331 "Not an ND FE space!");
2333 fes->GetMesh()->SpaceDimension()) == vcoeff.GetVDim(),
2334 "vcoeff vdim != PhysRangeDim");
2335
2336 const FiniteElement *fe;
2338 Array<int> dofs;
2339 Vector lvec;
2340
2341 values_counter.SetSize(Size());
2342 values_counter = 0;
2343
2344 HostReadWrite();
2345
2346 for (int i = 0; i < fes->GetMesh()->GetNumFaces(); i++)
2347 {
2348 fe = fes->GetFaceElement(i);
2350 fes->GetFaceVDofs(i, dofs);
2351 lvec.SetSize(fe->GetDof());
2352 fe->Project(vcoeff, *T, lvec);
2353 accumulate_dofs(dofs, lvec, *this, values_counter);
2354 }
2355}
2356
2357void GridFunction::ComputeMeans(AvgType type, const Array<int> &zones_per_vdof)
2358{
2359 HostReadWrite();
2360 zones_per_vdof.HostRead();
2361 switch (type)
2362 {
2363 case ARITHMETIC:
2364 for (int i = 0; i < size; i++)
2365 {
2366 const int nz = zones_per_vdof[i];
2367 if (nz) { (*this)(i) /= nz; }
2368 }
2369 break;
2370
2371 case HARMONIC:
2372 for (int i = 0; i < size; i++)
2373 {
2374 const int nz = zones_per_vdof[i];
2375 if (nz) { (*this)(i) = nz/(*this)(i); }
2376 }
2377 break;
2378
2379 default:
2380 MFEM_ABORT("invalid AvgType");
2381 }
2382}
2383
2385 real_t &integral)
2386{
2387 if (!fes->GetNE())
2388 {
2389 integral = 0.0;
2390 return;
2391 }
2392
2393 Mesh *mesh = fes->GetMesh();
2394 const int dim = mesh->Dimension();
2395 const real_t *center = delta_coeff.Center();
2396 const real_t *vert = mesh->GetVertex(0);
2397 real_t min_dist, dist;
2398 int v_idx = 0;
2399
2400 // find the vertex closest to the center of the delta function
2401 min_dist = Distance(center, vert, dim);
2402 for (int i = 0; i < mesh->GetNV(); i++)
2403 {
2404 vert = mesh->GetVertex(i);
2405 dist = Distance(center, vert, dim);
2406 if (dist < min_dist)
2407 {
2408 min_dist = dist;
2409 v_idx = i;
2410 }
2411 }
2412
2413 (*this) = 0.0;
2414 integral = 0.0;
2415
2416 if (min_dist >= delta_coeff.Tol())
2417 {
2418 return;
2419 }
2420
2421 // find the elements that have 'v_idx' as a vertex
2422 MassIntegrator Mi(*delta_coeff.Weight());
2423 DenseMatrix loc_mass;
2424 Array<int> vdofs, vertices;
2425 Vector vals, loc_mass_vals;
2426 DofTransformation doftrans;
2427
2428 for (int i = 0; i < mesh->GetNE(); i++)
2429 {
2430 mesh->GetElementVertices(i, vertices);
2431 for (int j = 0; j < vertices.Size(); j++)
2432 if (vertices[j] == v_idx)
2433 {
2434 const FiniteElement *fe = fes->GetFE(i);
2436 loc_mass);
2437 vals.SetSize(fe->GetDof());
2438 fe->ProjectDelta(j, vals);
2439 fes->GetElementVDofs(i, vdofs, doftrans);
2440 doftrans.TransformPrimal(vals);
2441 SetSubVector(vdofs, vals);
2442 loc_mass_vals.SetSize(vals.Size());
2443 loc_mass.Mult(vals, loc_mass_vals);
2444 integral += loc_mass_vals.Sum(); // partition of unity basis
2445 break;
2446 }
2447 }
2448}
2449
2451{
2452 MFEM_VERIFY(
2453 VectorDim() == 1,
2454 "Cannot project scalar Coefficient onto vector GridFunction");
2455 DeltaCoefficient *delta_c = dynamic_cast<DeltaCoefficient *>(&coeff);
2456 DofTransformation doftrans;
2457 Array<int> vdofs;
2458 Vector vals;
2459
2460 if (delta_c == NULL)
2461 {
2462 if (fes->GetNURBSext() == NULL)
2463 {
2464 switch (type)
2465 {
2468 return;
2471 return;
2472 default:
2473 for (int i = 0; i < fes->GetNE(); i++)
2474 {
2475 fes->GetElementVDofs(i, vdofs, doftrans);
2476 vals.SetSize(vdofs.Size());
2477 fes->GetFE(i)->Project(coeff, *fes->GetElementTransformation(i), vals);
2478 doftrans.TransformPrimal(vals);
2479 SetSubVector(vdofs, vals);
2480 }
2481 }
2482 }
2483 else
2484 {
2485 switch (type)
2486 {
2490 return;
2493 return;
2495 constexpr real_t signal = -infinity();
2496
2497 for (int i = 0; i < fes->GetNE(); i++)
2498 {
2499 fes->GetElementVDofs(i, vdofs, doftrans);
2500 vals.SetSize(vdofs.Size());
2501 vals = signal;
2502
2503 fes->GetFE(i)->Project(coeff,
2505 vals);
2506 doftrans.TransformPrimal(vals);
2507
2508 // Remove undefined dofs
2509 // The knot location (either Botella, Demko or Greville point)
2510 // where the NURBS dof are evaluated might fall outside of the
2511 // domain of the element. In that case the value is not set, and
2512 // the value remains the signal value.
2513 int s = 0;
2514 for (int ii = 0; ii < vals.Size(); ii++)
2515 {
2516 if (vals[ii] != signal)
2517 {
2518 vdofs[s] = vdofs[ii];
2519 vals(s) = vals(ii);
2520 s++;
2521 }
2522 }
2523 vdofs.SetSize(s);
2524 vals.SetSize(s);
2525
2526 // Add reduced dofs to global vector
2527 SetSubVector(vdofs, vals);
2528 }
2529 }
2530 }
2531 }
2532 else
2533 {
2534 real_t integral;
2535
2536 ProjectDeltaCoefficient(*delta_c, integral);
2537
2538 (*this) *= (delta_c->Scale() / integral);
2539 }
2540}
2541
2543 int iter)
2544{
2545 // Define and assemble linear form
2546 LinearForm b(fes);
2547 b.AddDomainIntegrator(new DomainLFIntegrator(coeff));
2548 b.Assemble();
2549
2550 // Define and assemble bilinear form
2552 a.AddDomainIntegrator(new MassIntegrator());
2553 a.Assemble();
2554
2555 // Set solver and preconditioner
2556 SparseMatrix A(a.SpMat());
2557 GSSmoother prec(A);
2558 CGSolver cg;
2559 cg.SetOperator(A);
2560 cg.SetPreconditioner(prec);
2561 cg.SetRelTol(rtol);
2562 cg.SetMaxIter(iter);
2563 cg.SetPrintLevel(0);
2564
2565 // Solve and get solution
2566 *this = 0.0;
2567 cg.Mult(b,*this);
2568}
2569
2571{
2572 Vector Va;
2573 ProjectCoefficientElementL2_(coeff, *this, Va);
2574 (*this) /= Va;
2575}
2576
2578 Vector &x, Vector &Va)
2579{
2580 DofTransformation doftrans;
2581 Array<int> vdofs;
2582 Vector shape,shape2, elvect, elwght;
2583 DenseMatrix elmat;
2584 Va.SetSize(fes->GetNDofs() );
2585 x.SetSize(fes->GetNDofs() );
2586 Va = 0.0;
2587 x = 0.0;
2588
2589 if (fes->GetNURBSext() == NULL)
2590 {
2591 for (int e = 0; e < fes->GetNE(); e++)
2592 {
2593 fes->GetElementDofs (e, vdofs, doftrans);
2594 ElementTransformation &tr = *fes -> GetElementTransformation (e);
2595 const FiniteElement &el = *fes->GetFE(e);
2596 int dof = el.GetDof();
2597 shape.SetSize(dof);
2598 elvect.SetSize(dof);
2599 elwght.SetSize(dof);
2600 elmat.SetSize(dof,dof);
2601 elvect = 0.0;
2602 elwght = 0.0;
2603 elmat = 0.0;
2604
2605 const IntegrationRule &ir = IntRules.Get(el.GetGeomType(),
2606 2 * el.GetOrder() + 1);
2607
2608 // Element vector & weight
2609 for (int i = 0; i < ir.GetNPoints(); i++)
2610 {
2611 const IntegrationPoint &ip = ir.IntPoint(i);
2612
2613 tr.SetIntPoint (&ip);
2614 real_t wght = ip.weight*tr.Weight();
2615 real_t val = coeff.Eval(tr, ip);
2616
2617 el.CalcPhysShape(tr, shape);
2618
2619 elvect.Add(wght * val, shape);
2620 elwght.Add(wght, shape);
2621 AddMult_a_VVt(wght, shape, elmat);
2622 }
2623
2624 // Solve
2625 if (!LinearSolve(elmat, elvect.GetData(),1e-12))
2626 {
2627 MFEM_WARNING("Error in inverting element local matrix");
2628 }
2629
2630 // Scale
2631 elvect *= elwght;
2632
2633 // Add reduced dofs to global vector
2634 x.AddElementVector(vdofs, elvect);
2635 Va.AddElementVector(vdofs, elwght);
2636 }
2637 }
2638 else
2639 {
2640 for (int e = 0; e < fes->GetNE(); e++)
2641 {
2642 fes->GetElementDofs (e, vdofs, doftrans);
2643 ElementTransformation &tr = *fes -> GetElementTransformation (e);
2644 const FiniteElement &el = *fes->GetFE(e);
2645 int dof = el.GetDof();
2646 int dim = el.GetDim();
2647 int p = el.GetOrder();
2648 L2_FECollection fe_coll(p, dim);
2649 //H1_FECollection fe_coll(p, dim, BasisType::Positive);
2650 const FiniteElement &el2 = *fe_coll.FiniteElementForGeometry(el.GetGeomType());
2651 MFEM_ASSERT(el2.GetDof() == dof, "Element dofs do not match.");
2652
2653 shape.SetSize(dof);
2654 shape2.SetSize(dof);
2655 elvect.SetSize(dof);
2656 elwght.SetSize(dof);
2657 elmat.SetSize(dof,dof);
2658 elvect = 0.0;
2659 elwght = 0.0;
2660 elmat = 0.0;
2661
2662 const IntegrationRule &ir = IntRules.Get(el.GetGeomType(),
2663 2 * el.GetOrder() + 1);
2664
2665 // Element vector & weight
2666 for (int i = 0; i < ir.GetNPoints(); i++)
2667 {
2668 const IntegrationPoint &ip = ir.IntPoint(i);
2669
2670 tr.SetIntPoint (&ip);
2671 real_t wght = ip.weight*tr.Weight();
2672 real_t val = coeff.Eval(tr, ip);
2673 el.CalcPhysShape(tr, shape);
2674 el2.CalcPhysShape(tr, shape2);
2675
2676 elvect.Add(wght * val, shape2);
2677 elwght.Add(wght, shape);
2678 AddMult_a_VVt(wght, shape2, elmat);
2679 }
2680 // Solve
2681 if (!LinearSolve(elmat, elvect.GetData(),1e-12))
2682 {
2683 MFEM_WARNING("Error in inverting element local matrix 2");
2684 }
2685 // Map to NURBS
2686 DenseMatrix I;
2687 el2.Project(el,tr,I);
2688 if (!LinearSolve(I, elvect.GetData(),1e-32))
2689 {
2690 MFEM_WARNING("Error in inverting element local matrix 3");
2691 }
2692
2693 // Scale
2694 elvect *= elwght;
2695
2696 // Add reduced dofs to global vector
2697 x.AddElementVector(vdofs, elvect);
2698 Va.AddElementVector(vdofs, elwght);
2699 }
2700 }
2701}
2702
2704 Coefficient &coeff, Array<int> &dofs, int vd)
2705{
2706 int el = -1;
2707 ElementTransformation *T = NULL;
2708 const FiniteElement *fe = NULL;
2709
2710 for (int i = 0; i < dofs.Size(); i++)
2711 {
2712 int dof = dofs[i], j = fes->GetElementForDof(dof);
2713 if (el != j)
2714 {
2715 el = j;
2717 fe = fes->GetFE(el);
2718 }
2719 int vdof = fes->DofToVDof(dof, vd);
2720 int ld = fes->GetLocalDofForDof(dof);
2721 const IntegrationPoint &ip = fe->GetNodes().IntPoint(ld);
2722 T->SetIntPoint(&ip);
2723 (*this)(vdof) = coeff.Eval(*T, ip);
2724 }
2725}
2726
2728 ProjectType type)
2729{
2730 MFEM_VERIFY(VectorDim() == vcoeff.GetVDim(), "vcoeff vdim != VectorDim()");
2731 Array<int> vdofs;
2732 Vector vals;
2733 DofTransformation doftrans;
2734
2735 if (fes->GetNURBSext() == NULL)
2736 {
2737 switch (type)
2738 {
2741 return;
2744 return;
2745 default:
2746 for (int i = 0; i < fes->GetNE(); i++)
2747 {
2748 fes->GetElementVDofs(i, vdofs, doftrans);
2749 vals.SetSize(vdofs.Size());
2750 fes->GetFE(i)->Project(vcoeff, *fes->GetElementTransformation(i), vals);
2751 doftrans.TransformPrimal(vals);
2752 SetSubVector(vdofs, vals);
2753 }
2754 }
2755 }
2756 else
2757 {
2758 switch (type)
2759 {
2763 return;
2766 return;
2768 constexpr real_t signal = -infinity();
2769 for (int i = 0; i < fes->GetNE(); i++)
2770 {
2771 fes->GetElementVDofs(i, vdofs, doftrans);
2772 vals.SetSize(vdofs.Size());
2773 vals = signal;
2774 fes->GetFE(i)->Project(vcoeff, *fes->GetElementTransformation(i), vals);
2775 doftrans.TransformPrimal(vals);
2776 // Remove undefined dofs
2777 // The knot location (either Botella, Demko or Greville point)
2778 // where the NURBS dof are evaluated might fall outside of the
2779 // domain of the element. In that case the value is not set, and
2780 // the value remains the signal value.
2781 int s = 0;
2782 for (int ii = 0; ii < vals.Size(); ii++)
2783 {
2784 if (vals[ii] != signal)
2785 {
2786 vdofs[s] = vdofs[ii];
2787 vals(s) = vals(ii);
2788 s++;
2789 }
2790 }
2791 vdofs.SetSize(s);
2792 vals.SetSize(s);
2793
2794 // Add reduced dofs to global vector
2795 SetSubVector(vdofs, vals);
2796 }
2797 }
2798 }
2799}
2800
2802{
2803 Array<int> values_counter;
2804 AccumulateAndCountTraceValues(coeff, NULL, values_counter);
2805 ComputeMeans(ARITHMETIC, values_counter);
2806}
2807
2809{
2810 MFEM_VERIFY(FESpace()->GetVDim() == 1, "ProjectTraceCoefficient(Coefficient&)"
2811 "is only valid for scalar GridFunction");
2812 Coefficient *coeff_p = &coeff;
2813 ProjectTraceCoefficient(&coeff_p);
2814}
2815
2817{
2818 MFEM_VERIFY(FESpace()->GetVDim() == vcoeff.GetVDim(),
2819 "Incompatible vcoeff vdim and fes vdim");
2820 Array<int> values_counter;
2821 AccumulateAndCountTraceValues(NULL, &vcoeff, values_counter);
2822 ComputeMeans(ARITHMETIC, values_counter);
2823}
2824
2826{
2827 MFEM_VERIFY(fes->GetVDim() == 1, "fespace VDim != 1");
2828 MFEM_VERIFY(fes->GetTypicalTraceElement()->GetRangeType() ==
2831 FiniteElement::INTEGRAL, "Not an RT FE space!");
2832 MFEM_VERIFY(vcoeff.GetVDim() == fes->GetMesh()->SpaceDimension(),
2833 "vcoeff vdim (" << vcoeff.GetVDim()
2834 << ") != SpaceDimension ("
2835 << fes->GetMesh()->SpaceDimension() << ")");
2836
2837 const FiniteElement *fe;
2839 Array<int> dofs;
2840 int dim = vcoeff.GetVDim();
2841 Vector vc(dim), nor(dim), lvec;
2842
2843 for (int i = 0; i < fes->GetMesh()->GetNumFaces(); i++)
2844 {
2845 fe = fes->GetFaceElement(i);
2847 const IntegrationRule &ir = fe->GetNodes();
2848 lvec.SetSize(fe->GetDof());
2849 for (int j = 0; j < ir.GetNPoints(); j++)
2850 {
2851 const IntegrationPoint &ip = ir.IntPoint(j);
2852 T->SetIntPoint(&ip);
2853 vcoeff.Eval(vc, *T, ip);
2854 CalcOrtho(T->Jacobian(), nor);
2855 lvec(j) = (vc * nor);
2856 }
2857 fes->GetFaceVDofs(i, dofs);
2858 SetSubVector(dofs, lvec);
2859 }
2860}
2861
2863{
2864 Array<int> values_counter;
2865 AccumulateAndCountTraceTangentValues(vcoeff, values_counter);
2866 ComputeMeans(ARITHMETIC, values_counter);
2867}
2868
2870 real_t rtol, int iter)
2871{
2872 // Define and assemble linear form
2873 LinearForm b(fes);
2875
2877 {
2878 b.AddDomainIntegrator(new VectorFEDomainLFIntegrator(vcoeff));
2879 a.AddDomainIntegrator(new VectorFEMassIntegrator());
2880 }
2881 else
2882 {
2883 b.AddDomainIntegrator(new VectorDomainLFIntegrator(vcoeff));
2884 a.AddDomainIntegrator(new VectorMassIntegrator());
2885 }
2886 a.Assemble();
2887 b.Assemble();
2888
2889 // Set solver and preconditioner
2890 SparseMatrix A(a.SpMat());
2891 GSSmoother prec(A);
2892 CGSolver cg;
2893 cg.SetOperator(A);
2894 cg.SetPreconditioner(prec);
2895 cg.SetRelTol(rtol);
2896 cg.SetMaxIter(iter);
2897 cg.SetPrintLevel(0);
2898
2899 // Solve and get solution
2900 *this = 0.0;
2901 cg.Mult(b,*this);
2902}
2903
2905 Vector &x, Vector &Va)
2906{
2907 DofTransformation doftrans;
2908 Array<int> vdofs;
2909 Vector shapel2, elvect, elwght, val;
2910 DenseMatrix shape, elmat;
2911 Va.SetSize(Size());
2912 x.SetSize(Size());
2913 Va = 0.0;
2914 x = 0.0;
2915
2916 if (fes->GetNURBSext() == NULL)
2917 {
2918 for (int e = 0; e < fes->GetNE(); e++)
2919 {
2920 fes->GetElementVDofs (e, vdofs, doftrans);
2921 ElementTransformation &tr = *fes -> GetElementTransformation (e);
2922 const FiniteElement &el = *fes->GetFE(e);
2923 int dof = el.GetDof();
2924 int dim = el.GetRangeDim();
2925 shape.SetSize(dof,dim);
2926 shapel2.SetSize(dof);
2927 elvect.SetSize(dof);
2928 elwght.SetSize(dof);
2929 elmat.SetSize(dof,dof);
2930 elvect = 0.0;
2931 elwght = 0.0;
2932 elmat = 0.0;
2933
2934 const IntegrationRule &ir = IntRules.Get(el.GetGeomType(),
2935 2 * el.GetOrder() + 1);
2936
2937 // Element vector & weight
2938 for (int i = 0; i < ir.GetNPoints(); i++)
2939 {
2940 const IntegrationPoint &ip = ir.IntPoint(i);
2941
2942 tr.SetIntPoint (&ip);
2943 real_t wght = ip.weight*tr.Weight();
2944 vcoeff.Eval(val, tr, ip);
2945 val *= wght;
2946
2947 el.CalcPhysVShape(tr, shape);
2948
2949 shape.AddMult (val, elvect);
2950 AddMult_a_AAt(wght, shape, elmat);
2951
2952 shape.GetRowl2(shapel2);
2953 elwght.Add(wght, shapel2);
2954 }
2955
2956 // Solve
2957 if (!LinearSolve(elmat, elvect.GetData(),1e-12))
2958 {
2959 MFEM_WARNING("Error in inverting element local matrix");
2960 }
2961
2962 // Scale
2963 elvect *= elwght;
2964
2965 // Add to global vector
2966 x.AddElementVector(vdofs, elvect);
2967
2968 // Add to weight vector -- no need for an orientation
2969 for (int i = 0; i < vdofs.Size(); i++)
2970 {
2971 vdofs[i] = FiniteElementSpace::DecodeDof(vdofs[i]);
2972 }
2973 Va.AddElementVector(vdofs, elwght);
2974 }
2975 }
2976 else
2977 {
2978 DenseMatrix partelmat;
2979 Vector shape2;
2980
2981 if (fes->GetTypicalFE()->GetOrder() >= 6 )
2982 {
2983 MFEM_WARNING("This project is not stable for"
2984 "NURBS VectorFE with order >= 5");
2985 }
2986 for (int e = 0; e < fes->GetNE(); e++)
2987 {
2988 fes->GetElementVDofs (e, vdofs, doftrans);
2989 ElementTransformation &tr = *fes -> GetElementTransformation (e);
2990 const FiniteElement &el = *fes->GetFE(e);
2991 int dof = el.GetDof();
2992 int dim = el.GetRangeDim();
2993 int p = el.GetOrder();
2994 L2_FECollection fe_coll(p, dim);
2995 const FiniteElement &el2 = *fe_coll.FiniteElementForGeometry(el.GetGeomType());
2996 int dof2 = el2.GetDof();
2997 MFEM_ASSERT(dof2*dim >= dof, "Element dofs do not match.");
2998 shape2.SetSize(dof2);
2999 shape.SetSize(dof,dim);
3000 shapel2.SetSize(dof);
3001 elvect.SetSize(dof2*dim);
3002 elwght.SetSize(dof);
3003 elmat.SetSize(dof2*dim,dof2*dim);
3004 partelmat.SetSize(dof2,dof2);
3005 elvect = 0.0;
3006 elwght = 0.0;
3007 elmat = 0.0;
3008
3009 const IntegrationRule &ir = IntRules.Get(el.GetGeomType(),
3010 2 * el.GetOrder() + 1);
3011
3012 // Element vector & weight
3013 for (int i = 0; i < ir.GetNPoints(); i++)
3014 {
3015 const IntegrationPoint &ip = ir.IntPoint(i);
3016
3017 tr.SetIntPoint (&ip);
3018 real_t wght = ip.weight*tr.Weight();
3019 vcoeff.Eval(val, tr, ip);
3020 val *= wght;
3021
3022 el2.CalcPhysShape(tr, shape2);
3023 el.CalcPhysVShape(tr, shape);
3024
3025 for (int k = 0; k < dim; k++)
3026 {
3027 for (int s = 0; s < dof2; s++)
3028 {
3029 elvect(dof2*k+s) += val(k) * shape2(s);
3030 }
3031 }
3032
3033 MultVVt(shape2, partelmat);
3034 partelmat *= wght;
3035 for (int k = 0; k < dim; k++)
3036 {
3037 elmat.AddMatrix(partelmat, dof2*k, dof2*k);
3038 }
3039
3040 shape.GetRowl2(shapel2);
3041 elwght.Add(wght, shapel2);
3042 }
3043
3044 // Solve
3045 if (!LinearSolve(elmat, elvect.GetData()))
3046 {
3047 MFEM_WARNING("Error in inverting element local matrix");
3048 }
3049
3050 // Map to NURBS
3051 DenseMatrix I;
3052 el2.Project(el,tr,I);
3053
3054 // LSQ solve
3055 // For higher order NURBS solving this non-square matrix causes issues.
3056 // For Order <=4 the routine seems to work fine.
3057 Vector vec(dof);
3058 DenseMatrix mat(dof, dof);
3059 I.Transpose();
3060 I.Mult(elvect, vec);
3061 MultAAt(I, mat);
3062 if (!LinearSolve(mat, vec.GetData(), 1e-24))
3063 {
3064 mat.TestInversion();
3065 MFEM_WARNING("Error in inverting element local matrix");
3066 }
3067 elvect = vec;
3068
3069 // Scale
3070 elvect *= elwght;
3071
3072 // Add to global vector
3073 x.AddElementVector(vdofs, elvect);
3074
3075 // Add to weight vector -- no need for an orientation
3076 for (int i = 0; i < vdofs.Size(); i++)
3077 {
3078 vdofs[i] = FiniteElementSpace::DecodeDof(vdofs[i]);
3079 }
3080 Va.AddElementVector(vdofs, elwght);
3081 }
3082 }
3083}
3084
3086{
3088 {
3089 Vector Va;
3090 ProjectCoefficientElementL2_(vcoeff, *this, Va);
3091 (*this) /= Va;
3092 }
3093 else
3094 {
3095 Array<int> vdofs(fes->GetNDofs());
3096 Vector x, Va;
3097 VectorComponentCoefficient coeff(vcoeff,
3098 0); // 0 to ensure we have a valid object
3099
3100 for (int v = 0; v < VectorDim(); v++)
3101 {
3102 coeff.SetComponent(v);
3103 ProjectCoefficientElementL2_(coeff, x, Va);
3104 x /= Va;
3105 fes->GetVDofs(v, vdofs);
3106 SetSubVector(vdofs, x);
3107 }
3108 }
3109}
3110
3112 VectorCoefficient &vcoeff, Array<int> &dofs)
3113{
3114 MFEM_VERIFY(VectorDim() == vcoeff.GetVDim(), "vcoeff vdim != VectorDim()");
3115 int el = -1;
3116 ElementTransformation *T = NULL;
3117 const FiniteElement *fe = NULL;
3118
3119 Vector val;
3120
3121 for (int i = 0; i < dofs.Size(); i++)
3122 {
3123 int dof = dofs[i], j = fes->GetElementForDof(dof);
3124 if (el != j)
3125 {
3126 el = j;
3128 fe = fes->GetFE(el);
3129 }
3130 int ld = fes->GetLocalDofForDof(dof);
3131 const IntegrationPoint &ip = fe->GetNodes().IntPoint(ld);
3132 T->SetIntPoint(&ip);
3133 vcoeff.Eval(val, *T, ip);
3134 for (int vd = 0; vd < fes->GetVDim(); vd ++)
3135 {
3136 int vdof = fes->DofToVDof(dof, vd);
3137 (*this)(vdof) = val(vd);
3138 }
3139 }
3140}
3141
3143{
3144 MFEM_VERIFY(VectorDim() == vcoeff.GetVDim(), "vcoeff vdim != VectorDim()");
3145 int i;
3146 Array<int> vdofs;
3147 Vector vals;
3148 DofTransformation doftrans;
3149
3150 for (i = 0; i < fes->GetNE(); i++)
3151 {
3152 if (fes->GetAttribute(i) != attribute)
3153 {
3154 continue;
3155 }
3156
3157 fes->GetElementVDofs(i, vdofs, doftrans);
3158 vals.SetSize(vdofs.Size());
3159 fes->GetFE(i)->Project(vcoeff, *fes->GetElementTransformation(i), vals);
3160 doftrans.TransformPrimal(vals);
3161 SetSubVector(vdofs, vals);
3162 }
3163}
3164
3166{
3167 int i, j, fdof, d, ind, vdim;
3168 real_t val;
3169 const FiniteElement *fe;
3170 ElementTransformation *transf;
3171 Array<int> vdofs;
3172
3173 vdim = fes->GetVDim();
3174 for (i = 0; i < fes->GetNE(); i++)
3175 {
3176 fe = fes->GetFE(i);
3177 fdof = fe->GetDof();
3178 transf = fes->GetElementTransformation(i);
3179 const IntegrationRule &ir = fe->GetNodes();
3180 // doftrans = fes->GetElementVDofs(i, vdofs);
3181 fes->GetElementVDofs(i, vdofs);
3182 for (j = 0; j < fdof; j++)
3183 {
3184 const IntegrationPoint &ip = ir.IntPoint(j);
3185 transf->SetIntPoint(&ip);
3186 for (d = 0; d < vdim; d++)
3187 {
3188 if (!coeff[d]) { continue; }
3189
3190 val = coeff[d]->Eval(*transf, ip);
3191 if ( (ind = vdofs[fdof*d+j]) < 0 )
3192 {
3193 val = -val, ind = -1-ind;
3194 }
3195 (*this)(ind) = val;
3196 }
3197 }
3198 }
3199}
3200
3202 std::variant<Coefficient*, VectorCoefficient*> coeff, Array<int> &dof_attr)
3203{
3204 std::visit([&](auto* c)
3205 {
3206 MFEM_VERIFY(VectorDim() == c->GetVDim(), "coeff vdim != VectorDim()");
3207 }, coeff);
3208
3209 Array<int> vdofs;
3210 Vector vals;
3211
3212 HostWrite();
3213 // maximal element attribute for each dof
3214 dof_attr.SetSize(fes->GetVSize());
3215 dof_attr = -1;
3216
3217 // local projection
3218 for (int i = 0; i < fes->GetNE(); i++)
3219 {
3220 fes->GetElementVDofs(i, vdofs);
3221 vals.SetSize(vdofs.Size());
3222 std::visit([&](auto* c)
3223 {
3224 fes->GetFE(i)->Project(*c, *fes->GetElementTransformation(i), vals);
3225 }, coeff);
3226
3227 // the values in shared dofs are determined from the element with maximal
3228 // attribute
3229 int attr = fes->GetAttribute(i);
3230 for (int j = 0; j < vdofs.Size(); j++)
3231 {
3232 if (attr > dof_attr[vdofs[j]])
3233 {
3234 (*this)(vdofs[j]) = vals[j];
3235 dof_attr[vdofs[j]] = attr;
3236 }
3237 }
3238 }
3239}
3240
3242{
3243 // Harmonic (x1 ... xn) = [ (1/x1 + ... + 1/xn) / n ]^-1.
3244 // Arithmetic(x1 ... xn) = (x1 + ... + xn) / n.
3245
3246 MFEM_VERIFY(
3247 VectorDim() == 1,
3248 "Cannot project a scalar coefficient onto a vector GridFunction");
3249
3250 Array<int> zones_per_vdof;
3251 AccumulateAndCountZones(coeff, type, zones_per_vdof);
3252
3253 ComputeMeans(type, zones_per_vdof);
3254}
3255
3257 AvgType type)
3258{
3259 MFEM_VERIFY(VectorDim() == coeff.GetVDim(), "coeff vdim != VectorDim()");
3260 Array<int> zones_per_vdof;
3261 AccumulateAndCountZones(coeff, type, zones_per_vdof);
3262
3263 ComputeMeans(type, zones_per_vdof);
3264}
3265
3267 const Array<int> &attr)
3268{
3269 Array<int> values_counter;
3270 AccumulateAndCountBdrValues(NULL, &vcoeff, attr, values_counter);
3271 ComputeMeans(ARITHMETIC, values_counter);
3272
3273#ifdef MFEM_DEBUG
3274 Array<int> ess_vdofs_marker;
3275 fes->GetEssentialVDofs(attr, ess_vdofs_marker);
3276 for (int i = 0; i < values_counter.Size(); i++)
3277 {
3278 MFEM_ASSERT(bool(values_counter[i]) == bool(ess_vdofs_marker[i]),
3279 "internal error");
3280 }
3281#endif
3282}
3283
3285 const Array<int> &attr)
3286{
3287 Array<int> values_counter;
3288 // this->HostReadWrite(); // done inside the next call
3289 AccumulateAndCountBdrValues(coeff, NULL, attr, values_counter);
3290 ComputeMeans(ARITHMETIC, values_counter);
3291
3292#ifdef MFEM_DEBUG
3293 Array<int> ess_vdofs_marker(Size());
3294 ess_vdofs_marker = 0;
3295 Array<int> component_dof_marker;
3296 for (int i = 0; i < fes->GetVDim(); i++)
3297 {
3298 if (!coeff[i]) { continue; }
3299 fes->GetEssentialVDofs(attr, component_dof_marker,i);
3300 for (int j = 0; j<Size(); j++)
3301 {
3302 ess_vdofs_marker[j] = bool(ess_vdofs_marker[j]) ||
3303 bool(component_dof_marker[j]);
3304 }
3305 }
3306 for (int i = 0; i < values_counter.Size(); i++)
3307 {
3308 MFEM_ASSERT(bool(values_counter[i]) == bool(ess_vdofs_marker[i]),
3309 "internal error");
3310 }
3311#endif
3312}
3313
3315 Coefficient *coeff, VectorCoefficient *vcoeff, const Array<int> &bdr_attr)
3316{
3317 MFEM_VERIFY(fes->GetVDim() == 1, "fespace VDim != 1");
3318 MFEM_VERIFY(fes->GetTypicalBE()->GetRangeType() == FiniteElement::SCALAR &&
3320 "Not an RT FE space!");
3321 if (vcoeff)
3322 {
3323 MFEM_VERIFY(vcoeff->GetVDim() == fes->GetMesh()->SpaceDimension(),
3324 "vcoeff vdim (" << vcoeff->GetVDim()
3325 << ") != SpaceDimension ("
3326 << fes->GetMesh()->SpaceDimension() << ")");
3327 }
3328
3329 // implementation for the case when the face dofs are scaled point
3330 // values of the normal component.
3331 const FiniteElement *fe;
3333 Array<int> dofs;
3334 Vector vc, nor, lvec;
3335 DofTransformation doftrans;
3336 if (vcoeff)
3337 {
3338 const int dim = vcoeff->GetVDim();
3339 vc.SetSize(dim);
3340 nor.SetSize(dim);
3341 }
3342
3343 for (int i = 0; i < fes->GetNBE(); i++)
3344 {
3345 if (bdr_attr[fes->GetBdrAttribute(i)-1] == 0)
3346 {
3347 continue;
3348 }
3349 fe = fes->GetBE(i);
3351 const IntegrationRule &ir = fe->GetNodes();
3352 lvec.SetSize(fe->GetDof());
3353 for (int j = 0; j < ir.GetNPoints(); j++)
3354 {
3355 const IntegrationPoint &ip = ir.IntPoint(j);
3356 T->SetIntPoint(&ip);
3357 if (coeff)
3358 {
3359 const real_t c = coeff->Eval(*T, ip);
3360 lvec(j) = c * T->Weight();
3361 }
3362 else if (vcoeff)
3363 {
3364 vcoeff->Eval(vc, *T, ip);
3365 CalcOrtho(T->Jacobian(), nor);
3366 lvec(j) = (vc * nor);
3367 }
3368 }
3369 fes->GetBdrElementDofs(i, dofs, doftrans);
3370 doftrans.TransformPrimal(lvec);
3371 SetSubVector(dofs, lvec);
3372 }
3373}
3374
3376 VectorCoefficient &vcoeff, const Array<int> &bdr_attr)
3377{
3378 Array<int> values_counter;
3379 AccumulateAndCountBdrTangentValues(vcoeff, bdr_attr, values_counter);
3380 ComputeMeans(ARITHMETIC, values_counter);
3381#ifdef MFEM_DEBUG
3382 Array<int> ess_vdofs_marker;
3383 fes->GetEssentialVDofs(bdr_attr, ess_vdofs_marker);
3384 for (int i = 0; i < values_counter.Size(); i++)
3385 {
3386 MFEM_ASSERT(bool(values_counter[i]) == bool(ess_vdofs_marker[i]),
3387 "internal error");
3388 }
3389#endif
3390}
3391
3393 Coefficient *exsol[], const IntegrationRule *irs[],
3394 const Array<int> *elems) const
3395{
3396 real_t error = 0.0, a;
3397 const FiniteElement *fe;
3398 ElementTransformation *transf;
3399 Vector shape;
3400 Array<int> vdofs;
3401 int fdof, d, i, intorder, j, k;
3402
3403 for (i = 0; i < fes->GetNE(); i++)
3404 {
3405 if (elems != NULL && (*elems)[i] == 0) { continue; }
3406 fe = fes->GetFE(i);
3407 fdof = fe->GetDof();
3408 transf = fes->GetElementTransformation(i);
3409 shape.SetSize(fdof);
3410 intorder = 2*fe->GetOrder() + 3; // <----------
3411 const IntegrationRule *ir;
3412 if (irs)
3413 {
3414 ir = irs[fe->GetGeomType()];
3415 }
3416 else
3417 {
3418 ir = &(IntRules.Get(fe->GetGeomType(), intorder));
3419 }
3420 fes->GetElementVDofs(i, vdofs);
3421 real_t elem_error = 0.0;
3422 for (j = 0; j < ir->GetNPoints(); j++)
3423 {
3424 const IntegrationPoint &ip = ir->IntPoint(j);
3425 transf->SetIntPoint(&ip);
3426 fe->CalcPhysShape(*transf, shape);
3427 for (d = 0; d < fes->GetVDim(); d++)
3428 {
3429 a = 0;
3430 for (k = 0; k < fdof; k++)
3431 if (vdofs[fdof*d+k] >= 0)
3432 {
3433 a += (*this)(vdofs[fdof*d+k]) * shape(k);
3434 }
3435 else
3436 {
3437 a -= (*this)(-1-vdofs[fdof*d+k]) * shape(k);
3438 }
3439 a -= exsol[d]->Eval(*transf, ip);
3440 elem_error += ip.weight * transf->Weight() * a * a;
3441 }
3442 }
3443 // negative quadrature weights may cause the error to be negative
3444 error += fabs(elem_error);
3445 }
3446
3447 return sqrt(error);
3448}
3449
3451 VectorCoefficient &exsol, const IntegrationRule *irs[],
3452 const Array<int> *elems) const
3453{
3454 real_t error = 0.0;
3455 const FiniteElement *fe;
3457 DenseMatrix vals, exact_vals;
3458 Vector loc_errs;
3459
3460 for (int i = 0; i < fes->GetNE(); i++)
3461 {
3462 if (elems != NULL && (*elems)[i] == 0) { continue; }
3463 fe = fes->GetFE(i);
3464 int intorder = 2*fe->GetOrder() + 3; // <----------
3465 const IntegrationRule *ir;
3466 if (irs)
3467 {
3468 ir = irs[fe->GetGeomType()];
3469 }
3470 else
3471 {
3472 ir = &(IntRules.Get(fe->GetGeomType(), intorder));
3473 }
3474 real_t elem_error = 0.0;
3476 GetVectorValues(*T, *ir, vals);
3477 exsol.Eval(exact_vals, *T, *ir);
3478 vals -= exact_vals;
3479 loc_errs.SetSize(vals.Width());
3480 vals.Norm2(loc_errs);
3481 for (int j = 0; j < ir->GetNPoints(); j++)
3482 {
3483 const IntegrationPoint &ip = ir->IntPoint(j);
3484 T->SetIntPoint(&ip);
3485 elem_error += ip.weight * T->Weight() * (loc_errs(j) * loc_errs(j));
3486 }
3487 // negative quadrature weights may cause the error to be negative
3488 error += fabs(elem_error);
3489 }
3490 return sqrt(error);
3491}
3492
3494 VectorCoefficient *exgrad,
3495 const IntegrationRule *irs[]) const
3496{
3497 real_t error = 0.0;
3498 const FiniteElement *fe;
3500 Array<int> dofs;
3501 Vector grad;
3502 int intorder;
3503 int dim = fes->GetMesh()->SpaceDimension();
3504 Vector vec(dim);
3505
3506 fe = fes->GetFE(ielem);
3507 Tr = fes->GetElementTransformation(ielem);
3508 intorder = 2*fe->GetOrder() + 3; // <--------
3509 const IntegrationRule *ir;
3510 if (irs)
3511 {
3512 ir = irs[fe->GetGeomType()];
3513 }
3514 else
3515 {
3516 ir = &(IntRules.Get(fe->GetGeomType(), intorder));
3517 }
3518 fes->GetElementDofs(ielem, dofs);
3519 for (int j = 0; j < ir->GetNPoints(); j++)
3520 {
3521 const IntegrationPoint &ip = ir->IntPoint(j);
3522 Tr->SetIntPoint(&ip);
3523 GetGradient(*Tr,grad);
3524 exgrad->Eval(vec,*Tr,ip);
3525 vec-=grad;
3526 error += ip.weight * Tr->Weight() * (vec * vec);
3527 }
3528 return sqrt(fabs(error));
3529}
3530
3532 const IntegrationRule *irs[]) const
3533{
3534 real_t error = 0.0;
3535 const FiniteElement *fe;
3537 Array<int> dofs;
3538 Vector grad;
3539 int intorder;
3540 int dim = fes->GetMesh()->SpaceDimension();
3541 Vector vec(dim);
3542
3543 for (int i = 0; i < fes->GetNE(); i++)
3544 {
3545 fe = fes->GetFE(i);
3547 intorder = 2*fe->GetOrder() + 3; // <--------
3548 const IntegrationRule *ir;
3549 if (irs)
3550 {
3551 ir = irs[fe->GetGeomType()];
3552 }
3553 else
3554 {
3555 ir = &(IntRules.Get(fe->GetGeomType(), intorder));
3556 }
3557 fes->GetElementDofs(i, dofs);
3558 real_t elem_error = 0.0;
3559 for (int j = 0; j < ir->GetNPoints(); j++)
3560 {
3561 const IntegrationPoint &ip = ir->IntPoint(j);
3562 Tr->SetIntPoint(&ip);
3563 GetGradient(*Tr,grad);
3564 exgrad->Eval(vec,*Tr,ip);
3565 vec-=grad;
3566 elem_error += ip.weight * Tr->Weight() * (vec * vec);
3567 }
3568 // negative quadrature weights may cause the error to be negative
3569 error += fabs(elem_error);
3570 }
3571 return sqrt(error);
3572}
3573
3575 const IntegrationRule *irs[]) const
3576{
3577 real_t error = 0.0;
3578 const FiniteElement *fe;
3580 Array<int> dofs;
3581 int intorder;
3582 int n = CurlDim();
3583 Vector curl(n);
3584 Vector vec(n);
3585
3586 for (int i = 0; i < fes->GetNE(); i++)
3587 {
3588 fe = fes->GetFE(i);
3590 intorder = 2*fe->GetOrder() + 3;
3591 const IntegrationRule *ir;
3592 if (irs)
3593 {
3594 ir = irs[fe->GetGeomType()];
3595 }
3596 else
3597 {
3598 ir = &(IntRules.Get(fe->GetGeomType(), intorder));
3599 }
3600 fes->GetElementDofs(i, dofs);
3601 real_t elem_error = 0.0;
3602 for (int j = 0; j < ir->GetNPoints(); j++)
3603 {
3604 const IntegrationPoint &ip = ir->IntPoint(j);
3605 Tr->SetIntPoint(&ip);
3606 GetCurl(*Tr,curl);
3607 excurl->Eval(vec,*Tr,ip);
3608 vec-=curl;
3609 elem_error += ip.weight * Tr->Weight() * ( vec * vec );
3610 }
3611 // negative quadrature weights may cause the error to be negative
3612 error += fabs(elem_error);
3613 }
3614
3615 return sqrt(error);
3616}
3617
3619 Coefficient *exdiv, const IntegrationRule *irs[]) const
3620{
3621 real_t error = 0.0, a;
3622 const FiniteElement *fe;
3624 Array<int> dofs;
3625 int intorder;
3626
3627 for (int i = 0; i < fes->GetNE(); i++)
3628 {
3629 fe = fes->GetFE(i);
3631 intorder = 2*fe->GetOrder() + 3;
3632 const IntegrationRule *ir;
3633 if (irs)
3634 {
3635 ir = irs[fe->GetGeomType()];
3636 }
3637 else
3638 {
3639 ir = &(IntRules.Get(fe->GetGeomType(), intorder));
3640 }
3641 fes->GetElementDofs(i, dofs);
3642 real_t elem_error = 0.0;
3643 for (int j = 0; j < ir->GetNPoints(); j++)
3644 {
3645 const IntegrationPoint &ip = ir->IntPoint(j);
3646 Tr->SetIntPoint (&ip);
3647 a = GetDivergence(*Tr) - exdiv->Eval(*Tr, ip);
3648 elem_error += ip.weight * Tr->Weight() * a * a;
3649 }
3650 // negative quadrature weights may cause the error to be negative
3651 error += fabs(elem_error);
3652 }
3653
3654 return sqrt(error);
3655}
3656
3658 Coefficient *ell_coeff,
3659 class JumpScaling jump_scaling,
3660 const IntegrationRule *irs[]) const
3661{
3662 int fdof, intorder, k;
3663 Mesh *mesh;
3664 const FiniteElement *fe;
3665 ElementTransformation *transf;
3666 FaceElementTransformations *face_elem_transf;
3667 Vector shape, el_dofs, err_val, ell_coeff_val;
3668 Array<int> vdofs;
3669 IntegrationPoint eip;
3670 real_t error = 0.0;
3671
3672 mesh = fes->GetMesh();
3673
3674 for (int i = 0; i < mesh->GetNumFaces(); i++)
3675 {
3676 int i1, i2;
3677 mesh->GetFaceElements(i, &i1, &i2);
3678 real_t h = mesh->GetElementSize(i1);
3679 intorder = fes->GetFE(i1)->GetOrder();
3680 if (i2 >= 0)
3681 {
3682 if ( (k = fes->GetFE(i2)->GetOrder()) > intorder )
3683 {
3684 intorder = k;
3685 }
3686 h = std::min(h, mesh->GetElementSize(i2));
3687 }
3688 int p = intorder;
3689 intorder = 2 * intorder; // <-------------
3690 face_elem_transf = mesh->GetFaceElementTransformations(i, 5);
3691 const IntegrationRule *ir;
3692 if (irs)
3693 {
3694 ir = irs[face_elem_transf->GetGeometryType()];
3695 }
3696 else
3697 {
3698 ir = &(IntRules.Get(face_elem_transf->GetGeometryType(), intorder));
3699 }
3700 err_val.SetSize(ir->GetNPoints());
3701 ell_coeff_val.SetSize(ir->GetNPoints());
3702 // side 1
3703 transf = face_elem_transf->Elem1;
3704 fe = fes->GetFE(i1);
3705 fdof = fe->GetDof();
3706 fes->GetElementVDofs(i1, vdofs);
3707 shape.SetSize(fdof);
3708 el_dofs.SetSize(fdof);
3709 for (k = 0; k < fdof; k++)
3710 if (vdofs[k] >= 0)
3711 {
3712 el_dofs(k) = (*this)(vdofs[k]);
3713 }
3714 else
3715 {
3716 el_dofs(k) = - (*this)(-1-vdofs[k]);
3717 }
3718 for (int j = 0; j < ir->GetNPoints(); j++)
3719 {
3720 face_elem_transf->Loc1.Transform(ir->IntPoint(j), eip);
3721 fe->CalcShape(eip, shape);
3722 transf->SetIntPoint(&eip);
3723 ell_coeff_val(j) = ell_coeff->Eval(*transf, eip);
3724 err_val(j) = exsol->Eval(*transf, eip) - (shape * el_dofs);
3725 }
3726 if (i2 >= 0)
3727 {
3728 // side 2
3729 face_elem_transf = mesh->GetFaceElementTransformations(i, 10);
3730 transf = face_elem_transf->Elem2;
3731 fe = fes->GetFE(i2);
3732 fdof = fe->GetDof();
3733 fes->GetElementVDofs(i2, vdofs);
3734 shape.SetSize(fdof);
3735 el_dofs.SetSize(fdof);
3736 for (k = 0; k < fdof; k++)
3737 if (vdofs[k] >= 0)
3738 {
3739 el_dofs(k) = (*this)(vdofs[k]);
3740 }
3741 else
3742 {
3743 el_dofs(k) = - (*this)(-1-vdofs[k]);
3744 }
3745 for (int j = 0; j < ir->GetNPoints(); j++)
3746 {
3747 face_elem_transf->Loc2.Transform(ir->IntPoint(j), eip);
3748 fe->CalcShape(eip, shape);
3749 transf->SetIntPoint(&eip);
3750 ell_coeff_val(j) += ell_coeff->Eval(*transf, eip);
3751 ell_coeff_val(j) *= 0.5;
3752 err_val(j) -= (exsol->Eval(*transf, eip) - (shape * el_dofs));
3753 }
3754 }
3755 real_t face_error = 0.0;
3756 face_elem_transf = mesh->GetFaceElementTransformations(i, 16);
3757 transf = face_elem_transf;
3758 for (int j = 0; j < ir->GetNPoints(); j++)
3759 {
3760 const IntegrationPoint &ip = ir->IntPoint(j);
3761 transf->SetIntPoint(&ip);
3762 real_t nu = jump_scaling.Eval(h, p);
3763 face_error += (ip.weight * nu * ell_coeff_val(j) *
3764 transf->Weight() *
3765 err_val(j) * err_val(j));
3766 }
3767 // negative quadrature weights may cause the error to be negative
3768 error += fabs(face_error);
3769 }
3770
3771 return sqrt(error);
3772}
3773
3775 Coefficient *ell_coeff,
3776 real_t Nu,
3777 const IntegrationRule *irs[]) const
3778{
3780 exsol, ell_coeff, {Nu, JumpScaling::ONE_OVER_H}, irs);
3781}
3782
3784 VectorCoefficient *exgrad,
3785 Coefficient *ell_coef, real_t Nu,
3786 int norm_type) const
3787{
3788 real_t error1 = 0.0;
3789 real_t error2 = 0.0;
3790 if (norm_type & 1) { error1 = GridFunction::ComputeGradError(exgrad); }
3791 if (norm_type & 2)
3792 {
3794 exsol, ell_coef, {Nu, JumpScaling::ONE_OVER_H});
3795 }
3796
3797 return sqrt(error1 * error1 + error2 * error2);
3798}
3799
3801 VectorCoefficient *exgrad,
3802 const IntegrationRule *irs[]) const
3803{
3804 real_t L2error = GridFunction::ComputeLpError(2.0,*exsol,NULL,irs);
3805 real_t GradError = GridFunction::ComputeGradError(exgrad,irs);
3806 return sqrt(L2error*L2error + GradError*GradError);
3807}
3808
3810 Coefficient *exdiv,
3811 const IntegrationRule *irs[]) const
3812{
3813 real_t L2error = GridFunction::ComputeLpError(2.0,*exsol,NULL,NULL,irs);
3814 real_t DivError = GridFunction::ComputeDivError(exdiv,irs);
3815 return sqrt(L2error*L2error + DivError*DivError);
3816}
3817
3819 VectorCoefficient *excurl,
3820 const IntegrationRule *irs[]) const
3821{
3822 real_t L2error = GridFunction::ComputeLpError(2.0,*exsol,NULL,NULL,irs);
3823 real_t CurlError = GridFunction::ComputeCurlError(excurl,irs);
3824 return sqrt(L2error*L2error + CurlError*CurlError);
3825}
3826
3828 Coefficient *exsol[], const IntegrationRule *irs[]) const
3829{
3830 real_t error = 0.0, a;
3831 const FiniteElement *fe;
3832 ElementTransformation *transf;
3833 Vector shape;
3834 Array<int> vdofs;
3835 int fdof, d, i, intorder, j, k;
3836
3837 for (i = 0; i < fes->GetNE(); i++)
3838 {
3839 fe = fes->GetFE(i);
3840 fdof = fe->GetDof();
3841 transf = fes->GetElementTransformation(i);
3842 shape.SetSize(fdof);
3843 intorder = 2*fe->GetOrder() + 3; // <----------
3844 const IntegrationRule *ir;
3845 if (irs)
3846 {
3847 ir = irs[fe->GetGeomType()];
3848 }
3849 else
3850 {
3851 ir = &(IntRules.Get(fe->GetGeomType(), intorder));
3852 }
3853 fes->GetElementVDofs(i, vdofs);
3854 for (j = 0; j < ir->GetNPoints(); j++)
3855 {
3856 const IntegrationPoint &ip = ir->IntPoint(j);
3857 fe->CalcShape(ip, shape);
3858 transf->SetIntPoint(&ip);
3859 for (d = 0; d < fes->GetVDim(); d++)
3860 {
3861 a = 0;
3862 for (k = 0; k < fdof; k++)
3863 if (vdofs[fdof*d+k] >= 0)
3864 {
3865 a += (*this)(vdofs[fdof*d+k]) * shape(k);
3866 }
3867 else
3868 {
3869 a -= (*this)(-1-vdofs[fdof*d+k]) * shape(k);
3870 }
3871 a -= exsol[d]->Eval(*transf, ip);
3872 a = fabs(a);
3873 if (error < a)
3874 {
3875 error = a;
3876 }
3877 }
3878 }
3879 }
3880 return error;
3881}
3882
3884 Coefficient *exsol, VectorCoefficient *exgrad, int norm_type,
3885 const Array<int> *elems, const IntegrationRule *irs[]) const
3886{
3887 // assuming vdim is 1
3888 int i, fdof, dim, intorder, j, k;
3889 Mesh *mesh;
3890 const FiniteElement *fe;
3891 ElementTransformation *transf;
3892 Vector e_grad, a_grad, shape, el_dofs, err_val, ell_coeff_val;
3893 DenseMatrix dshape, dshapet, Jinv;
3894 Array<int> vdofs;
3895 real_t a, error = 0.0;
3896
3897 mesh = fes->GetMesh();
3898 dim = mesh->Dimension();
3899 e_grad.SetSize(dim);
3900 a_grad.SetSize(dim);
3901 Jinv.SetSize(dim);
3902
3903 if (norm_type & 1) // L_1 norm
3904 for (i = 0; i < mesh->GetNE(); i++)
3905 {
3906 if (elems != NULL && (*elems)[i] == 0) { continue; }
3907 fe = fes->GetFE(i);
3908 fdof = fe->GetDof();
3909 transf = fes->GetElementTransformation(i);
3910 el_dofs.SetSize(fdof);
3911 shape.SetSize(fdof);
3912 intorder = 2*fe->GetOrder() + 1; // <----------
3913 const IntegrationRule *ir;
3914 if (irs)
3915 {
3916 ir = irs[fe->GetGeomType()];
3917 }
3918 else
3919 {
3920 ir = &(IntRules.Get(fe->GetGeomType(), intorder));
3921 }
3922 real_t elem_error = 0.0;
3923 fes->GetElementVDofs(i, vdofs);
3924 for (k = 0; k < fdof; k++)
3925 if (vdofs[k] >= 0)
3926 {
3927 el_dofs(k) = (*this)(vdofs[k]);
3928 }
3929 else
3930 {
3931 el_dofs(k) = -(*this)(-1-vdofs[k]);
3932 }
3933 for (j = 0; j < ir->GetNPoints(); j++)
3934 {
3935 const IntegrationPoint &ip = ir->IntPoint(j);
3936 fe->CalcShape(ip, shape);
3937 transf->SetIntPoint(&ip);
3938 a = (el_dofs * shape) - (exsol->Eval(*transf, ip));
3939 elem_error += ip.weight * transf->Weight() * fabs(a);
3940 }
3941 error += fabs(elem_error);
3942 }
3943
3944 if (norm_type & 2) // W^1_1 seminorm
3945 for (i = 0; i < mesh->GetNE(); i++)
3946 {
3947 if (elems != NULL && (*elems)[i] == 0) { continue; }
3948 fe = fes->GetFE(i);
3949 fdof = fe->GetDof();
3950 transf = mesh->GetElementTransformation(i);
3951 el_dofs.SetSize(fdof);
3952 dshape.SetSize(fdof, dim);
3953 dshapet.SetSize(fdof, dim);
3954 intorder = 2*fe->GetOrder() + 1; // <----------
3955 const IntegrationRule *ir;
3956 if (irs)
3957 {
3958 ir = irs[fe->GetGeomType()];
3959 }
3960 else
3961 {
3962 ir = &(IntRules.Get(fe->GetGeomType(), intorder));
3963 }
3964 real_t elem_error = 0.0;
3965 fes->GetElementVDofs(i, vdofs);
3966 for (k = 0; k < fdof; k++)
3967 if (vdofs[k] >= 0)
3968 {
3969 el_dofs(k) = (*this)(vdofs[k]);
3970 }
3971 else
3972 {
3973 el_dofs(k) = -(*this)(-1-vdofs[k]);
3974 }
3975 for (j = 0; j < ir->GetNPoints(); j++)
3976 {
3977 const IntegrationPoint &ip = ir->IntPoint(j);
3978 fe->CalcDShape(ip, dshape);
3979 transf->SetIntPoint(&ip);
3980 exgrad->Eval(e_grad, *transf, ip);
3981 CalcInverse(transf->Jacobian(), Jinv);
3982 Mult(dshape, Jinv, dshapet);
3983 dshapet.MultTranspose(el_dofs, a_grad);
3984 e_grad -= a_grad;
3985 elem_error += ip.weight * transf->Weight() * e_grad.Norml1();
3986 }
3987 error += fabs(elem_error);
3988 }
3989
3990 return error;
3991}
3992
3995 const IntegrationRule *irs[],
3996 const Array<int> *elems) const
3997{
3998 real_t error = 0.0;
3999 const FiniteElement *fe;
4001 Vector vals;
4002
4003 for (int i = 0; i < fes->GetNE(); i++)
4004 {
4005 if (elems != NULL && (*elems)[i] == 0) { continue; }
4006 fe = fes->GetFE(i);
4007 const IntegrationRule *ir;
4008 if (irs)
4009 {
4010 ir = irs[fe->GetGeomType()];
4011 }
4012 else
4013 {
4014 int intorder = 2*fe->GetOrder() + 3; // <----------
4015 ir = &(IntRules.Get(fe->GetGeomType(), intorder));
4016 }
4017 real_t elem_error = 0.0;
4018 GetValues(i, *ir, vals);
4020 for (int j = 0; j < ir->GetNPoints(); j++)
4021 {
4022 const IntegrationPoint &ip = ir->IntPoint(j);
4023 T->SetIntPoint(&ip);
4024 real_t diff = fabs(vals(j) - exsol.Eval(*T, ip));
4025 if (p < infinity())
4026 {
4027 diff = pow(diff, p);
4028 if (weight)
4029 {
4030 diff *= weight->Eval(*T, ip);
4031 }
4032 elem_error += ip.weight * T->Weight() * diff;
4033 }
4034 else
4035 {
4036 if (weight)
4037 {
4038 diff *= weight->Eval(*T, ip);
4039 }
4040 error = std::max(error, diff);
4041 }
4042 }
4043 if (p < infinity())
4044 {
4045 // negative quadrature weights may cause the error to be negative
4046 error += fabs(elem_error);
4047 }
4048 }
4049
4050 if (p < infinity())
4051 {
4052 error = pow(error, 1./p);
4053 }
4054
4055 return error;
4056}
4057
4059 Vector &error,
4061 const IntegrationRule *irs[]) const
4062{
4063 MFEM_ASSERT(error.Size() == fes->GetNE(),
4064 "Incorrect size for result vector");
4065
4066 error = 0.0;
4067 const FiniteElement *fe;
4069 Vector vals;
4070
4071 for (int i = 0; i < fes->GetNE(); i++)
4072 {
4073 fe = fes->GetFE(i);
4074 const IntegrationRule *ir;
4075 if (irs)
4076 {
4077 ir = irs[fe->GetGeomType()];
4078 }
4079 else
4080 {
4081 int intorder = 2*fe->GetOrder() + 3; // <----------
4082 ir = &(IntRules.Get(fe->GetGeomType(), intorder));
4083 }
4084 GetValues(i, *ir, vals);
4086 for (int j = 0; j < ir->GetNPoints(); j++)
4087 {
4088 const IntegrationPoint &ip = ir->IntPoint(j);
4089 T->SetIntPoint(&ip);
4090 real_t diff = fabs(vals(j) - exsol.Eval(*T, ip));
4091 if (p < infinity())
4092 {
4093 diff = pow(diff, p);
4094 if (weight)
4095 {
4096 diff *= weight->Eval(*T, ip);
4097 }
4098 error[i] += ip.weight * T->Weight() * diff;
4099 }
4100 else
4101 {
4102 if (weight)
4103 {
4104 diff *= weight->Eval(*T, ip);
4105 }
4106 error[i] = std::max(error[i], diff);
4107 }
4108 }
4109 if (p < infinity())
4110 {
4111 // negative quadrature weights may cause the error to be negative
4112 error[i] = pow(fabs(error[i]), 1./p);
4113 }
4114 }
4115}
4116
4119 VectorCoefficient *v_weight,
4120 const IntegrationRule *irs[]) const
4121{
4122 real_t error = 0.0;
4123 const FiniteElement *fe;
4125 DenseMatrix vals, exact_vals;
4126 Vector loc_errs;
4127
4128 for (int i = 0; i < fes->GetNE(); i++)
4129 {
4130 fe = fes->GetFE(i);
4131 const IntegrationRule *ir;
4132 if (irs)
4133 {
4134 ir = irs[fe->GetGeomType()];
4135 }
4136 else
4137 {
4138 int intorder = 2*fe->GetOrder() + 3; // <----------
4139 ir = &(IntRules.Get(fe->GetGeomType(), intorder));
4140 }
4141 real_t elem_error = 0.0;
4143 GetVectorValues(*T, *ir, vals);
4144 exsol.Eval(exact_vals, *T, *ir);
4145 vals -= exact_vals;
4146 loc_errs.SetSize(vals.Width());
4147 if (!v_weight)
4148 {
4149 // compute the lengths of the errors at the integration points
4150 // thus the vector norm is rotationally invariant
4151 vals.Norm2(loc_errs);
4152 }
4153 else
4154 {
4155 v_weight->Eval(exact_vals, *T, *ir);
4156 // column-wise dot product of the vector error (in vals) and the
4157 // vector weight (in exact_vals)
4158 for (int j = 0; j < vals.Width(); j++)
4159 {
4160 real_t errj = 0.0;
4161 for (int d = 0; d < vals.Height(); d++)
4162 {
4163 errj += vals(d,j)*exact_vals(d,j);
4164 }
4165 loc_errs(j) = fabs(errj);
4166 }
4167 }
4168 for (int j = 0; j < ir->GetNPoints(); j++)
4169 {
4170 const IntegrationPoint &ip = ir->IntPoint(j);
4171 T->SetIntPoint(&ip);
4172 real_t errj = loc_errs(j);
4173 if (p < infinity())
4174 {
4175 errj = pow(errj, p);
4176 if (weight)
4177 {
4178 errj *= weight->Eval(*T, ip);
4179 }
4180 elem_error += ip.weight * T->Weight() * errj;
4181 }
4182 else
4183 {
4184 if (weight)
4185 {
4186 errj *= weight->Eval(*T, ip);
4187 }
4188 error = std::max(error, errj);
4189 }
4190 }
4191 if (p < infinity())
4192 {
4193 // negative quadrature weights may cause the error to be negative
4194 error += fabs(elem_error);
4195 }
4196 }
4197
4198 if (p < infinity())
4199 {
4200 error = pow(error, 1./p);
4201 }
4202
4203 return error;
4204}
4205
4207 VectorCoefficient &exsol,
4208 Vector &error,
4210 VectorCoefficient *v_weight,
4211 const IntegrationRule *irs[]) const
4212{
4213 MFEM_ASSERT(error.Size() == fes->GetNE(),
4214 "Incorrect size for result vector");
4215
4216 error = 0.0;
4217 const FiniteElement *fe;
4219 DenseMatrix vals, exact_vals;
4220 Vector loc_errs;
4221
4222 for (int i = 0; i < fes->GetNE(); i++)
4223 {
4224 fe = fes->GetFE(i);
4225 const IntegrationRule *ir;
4226 if (irs)
4227 {
4228 ir = irs[fe->GetGeomType()];
4229 }
4230 else
4231 {
4232 int intorder = 2*fe->GetOrder() + 3; // <----------
4233 ir = &(IntRules.Get(fe->GetGeomType(), intorder));
4234 }
4236 GetVectorValues(*T, *ir, vals);
4237 exsol.Eval(exact_vals, *T, *ir);
4238 vals -= exact_vals;
4239 loc_errs.SetSize(vals.Width());
4240 if (!v_weight)
4241 {
4242 // compute the lengths of the errors at the integration points thus the
4243 // vector norm is rotationally invariant
4244 vals.Norm2(loc_errs);
4245 }
4246 else
4247 {
4248 v_weight->Eval(exact_vals, *T, *ir);
4249 // column-wise dot product of the vector error (in vals) and the vector
4250 // weight (in exact_vals)
4251 for (int j = 0; j < vals.Width(); j++)
4252 {
4253 real_t errj = 0.0;
4254 for (int d = 0; d < vals.Height(); d++)
4255 {
4256 errj += vals(d,j)*exact_vals(d,j);
4257 }
4258 loc_errs(j) = fabs(errj);
4259 }
4260 }
4261 for (int j = 0; j < ir->GetNPoints(); j++)
4262 {
4263 const IntegrationPoint &ip = ir->IntPoint(j);
4264 T->SetIntPoint(&ip);
4265 real_t errj = loc_errs(j);
4266 if (p < infinity())
4267 {
4268 errj = pow(errj, p);
4269 if (weight)
4270 {
4271 errj *= weight->Eval(*T, ip);
4272 }
4273 error[i] += ip.weight * T->Weight() * errj;
4274 }
4275 else
4276 {
4277 if (weight)
4278 {
4279 errj *= weight->Eval(*T, ip);
4280 }
4281 error[i] = std::max(error[i], errj);
4282 }
4283 }
4284 if (p < infinity())
4285 {
4286 // negative quadrature weights may cause the error to be negative
4287 error[i] = pow(fabs(error[i]), 1./p);
4288 }
4289 }
4290}
4291
4293{
4294 Vector::operator=(value);
4295 return *this;
4296}
4297
4299{
4300 MFEM_ASSERT(fes && v.Size() == fes->GetVSize(), "");
4302 return *this;
4303}
4304
4305void GridFunction::Save(std::ostream &os) const
4306{
4307 fes->Save(os);
4308 os << '\n';
4309#if 0
4310 // Testing: write NURBS GridFunctions using "NURBS_patches" format.
4311 if (fes->GetNURBSext())
4312 {
4313 os << "NURBS_patches\n";
4314 fes->GetNURBSext()->PrintSolution(*this, os);
4315 os.flush();
4316 return;
4317 }
4318#endif
4320 {
4321 Vector::Print(os, 1);
4322 }
4323 else
4324 {
4325 Vector::Print(os, fes->GetVDim());
4326 }
4327 os.flush();
4328}
4329
4330void GridFunction::Save(const char *fname, int precision) const
4331{
4332 ofstream ofs(fname);
4333 ofs.precision(precision);
4334 Save(ofs);
4335}
4336
4337#ifdef MFEM_USE_ADIOS2
4339 const std::string& variable_name,
4340 const adios2stream::data_type type) const
4341{
4342 os.Save(*this, variable_name, type);
4343}
4344#endif
4345
4346void GridFunction::SaveVTK(std::ostream &os, const std::string &field_name,
4347 int ref)
4348{
4349 Mesh *mesh = fes->GetMesh();
4350 RefinedGeometry *RefG;
4351 Vector val;
4352 DenseMatrix vval, pmat;
4353 int vec_dim = VectorDim();
4354
4355 if (vec_dim == 1)
4356 {
4357 // scalar data
4358 os << "SCALARS " << field_name << " double 1\n"
4359 << "LOOKUP_TABLE default\n";
4360 for (int i = 0; i < mesh->GetNE(); i++)
4361 {
4363 mesh->GetElementBaseGeometry(i), ref, 1);
4364
4365 GetValues(i, RefG->RefPts, val, pmat);
4366
4367 for (int j = 0; j < val.Size(); j++)
4368 {
4369 os << val(j) << '\n';
4370 }
4371 }
4372 }
4373 else if ( (vec_dim == 2 || vec_dim == 3) && mesh->SpaceDimension() > 1)
4374 {
4375 // vector data
4376 os << "VECTORS " << field_name << " double\n";
4377 for (int i = 0; i < mesh->GetNE(); i++)
4378 {
4380 mesh->GetElementBaseGeometry(i), ref, 1);
4381
4382 // GetVectorValues(i, RefG->RefPts, vval, pmat);
4384 GetVectorValues(*T, RefG->RefPts, vval, &pmat);
4385
4386 for (int j = 0; j < vval.Width(); j++)
4387 {
4388 os << vval(0, j) << ' ' << vval(1, j) << ' ';
4389 if (vval.Height() == 2)
4390 {
4391 os << 0.0;
4392 }
4393 else
4394 {
4395 os << vval(2, j);
4396 }
4397 os << '\n';
4398 }
4399 }
4400 }
4401 else
4402 {
4403 // other data: save the components as separate scalars
4404 for (int vd = 0; vd < vec_dim; vd++)
4405 {
4406 os << "SCALARS " << field_name << vd << " double 1\n"
4407 << "LOOKUP_TABLE default\n";
4408 for (int i = 0; i < mesh->GetNE(); i++)
4409 {
4411 mesh->GetElementBaseGeometry(i), ref, 1);
4412
4413 GetValues(i, RefG->RefPts, val, pmat, vd + 1);
4414
4415 for (int j = 0; j < val.Size(); j++)
4416 {
4417 os << val(j) << '\n';
4418 }
4419 }
4420 }
4421 }
4422 os.flush();
4423}
4424
4425#ifdef MFEM_USE_HDF5
4426
4427void GridFunction::SaveVTKHDF(const std::string &fname, const std::string &name,
4428 bool high_order, int ref)
4429{
4430 if (ref == -1) { ref = high_order ? fes->GetMaxElementOrder() : 1; }
4431#ifdef MFEM_USE_MPI
4432 if (ParFiniteElementSpace* pfes = dynamic_cast<ParFiniteElementSpace*>(fes))
4433 {
4434#ifdef MFEM_PARALLEL_HDF5
4435 VTKHDF vtkhdf(fname, pfes->GetComm());
4436 vtkhdf.SaveMesh(*fes->GetMesh(), high_order, ref);
4437 vtkhdf.SaveGridFunction(*this, name);
4438 return;
4439#else
4440 MFEM_ABORT("Requires HDF5 library with parallel support enabled");
4441#endif
4442 }
4443#endif
4444 VTKHDF vtkhdf(fname);
4445 vtkhdf.SaveMesh(*fes->GetMesh(), high_order, ref);
4446 vtkhdf.SaveGridFunction(*this, name);
4447}
4448
4449#endif
4450
4451void GridFunction::SaveSTLTri(std::ostream &os, real_t p1[], real_t p2[],
4452 real_t p3[])
4453{
4454 real_t v1[3] = { p2[0] - p1[0], p2[1] - p1[1], p2[2] - p1[2] };
4455 real_t v2[3] = { p3[0] - p1[0], p3[1] - p1[1], p3[2] - p1[2] };
4456 real_t n[] = { v1[1] * v2[2] - v1[2] * v2[1],
4457 v1[2] * v2[0] - v1[0] * v2[2],
4458 v1[0] * v2[1] - v1[1] * v2[0]
4459 };
4460 real_t rl = 1.0 / sqrt(n[0] * n[0] + n[1] * n[1] + n[2] * n[2]);
4461 n[0] *= rl; n[1] *= rl; n[2] *= rl;
4462
4463 os << " facet normal " << n[0] << ' ' << n[1] << ' ' << n[2]
4464 << "\n outer loop"
4465 << "\n vertex " << p1[0] << ' ' << p1[1] << ' ' << p1[2]
4466 << "\n vertex " << p2[0] << ' ' << p2[1] << ' ' << p2[2]
4467 << "\n vertex " << p3[0] << ' ' << p3[1] << ' ' << p3[2]
4468 << "\n endloop\n endfacet\n";
4469}
4470
4471void GridFunction::SaveSTL(std::ostream &os, int TimesToRefine)
4472{
4473 Mesh *mesh = fes->GetMesh();
4474
4475 if (mesh->Dimension() != 2)
4476 {
4477 return;
4478 }
4479
4480 int i, j, k, l, n;
4481 DenseMatrix pointmat;
4482 Vector values;
4483 RefinedGeometry * RefG;
4484 real_t pts[4][3], bbox[3][2];
4485
4486 os << "solid GridFunction\n";
4487
4488 bbox[0][0] = bbox[0][1] = bbox[1][0] = bbox[1][1] =
4489 bbox[2][0] = bbox[2][1] = 0.0;
4490 for (i = 0; i < mesh->GetNE(); i++)
4491 {
4492 Geometry::Type geom = mesh->GetElementBaseGeometry(i);
4493 RefG = GlobGeometryRefiner.Refine(geom, TimesToRefine);
4494 GetValues(i, RefG->RefPts, values, pointmat);
4495 Array<int> &RG = RefG->RefGeoms;
4496 n = Geometries.NumBdr(geom);
4497 for (k = 0; k < RG.Size()/n; k++)
4498 {
4499 for (j = 0; j < n; j++)
4500 {
4501 l = RG[n*k+j];
4502 pts[j][0] = pointmat(0,l);
4503 pts[j][1] = pointmat(1,l);
4504 pts[j][2] = values(l);
4505 }
4506
4507 if (n == 3)
4508 {
4509 SaveSTLTri(os, pts[0], pts[1], pts[2]);
4510 }
4511 else
4512 {
4513 SaveSTLTri(os, pts[0], pts[1], pts[2]);
4514 SaveSTLTri(os, pts[0], pts[2], pts[3]);
4515 }
4516 }
4517
4518 if (i == 0)
4519 {
4520 bbox[0][0] = pointmat(0,0);
4521 bbox[0][1] = pointmat(0,0);
4522 bbox[1][0] = pointmat(1,0);
4523 bbox[1][1] = pointmat(1,0);
4524 bbox[2][0] = values(0);
4525 bbox[2][1] = values(0);
4526 }
4527
4528 for (j = 0; j < values.Size(); j++)
4529 {
4530 if (bbox[0][0] > pointmat(0,j))
4531 {
4532 bbox[0][0] = pointmat(0,j);
4533 }
4534 if (bbox[0][1] < pointmat(0,j))
4535 {
4536 bbox[0][1] = pointmat(0,j);
4537 }
4538 if (bbox[1][0] > pointmat(1,j))
4539 {
4540 bbox[1][0] = pointmat(1,j);
4541 }
4542 if (bbox[1][1] < pointmat(1,j))
4543 {
4544 bbox[1][1] = pointmat(1,j);
4545 }
4546 if (bbox[2][0] > values(j))
4547 {
4548 bbox[2][0] = values(j);
4549 }
4550 if (bbox[2][1] < values(j))
4551 {
4552 bbox[2][1] = values(j);
4553 }
4554 }
4555 }
4556
4557 mfem::out << "[xmin,xmax] = [" << bbox[0][0] << ',' << bbox[0][1] << "]\n"
4558 << "[ymin,ymax] = [" << bbox[1][0] << ',' << bbox[1][1] << "]\n"
4559 << "[zmin,zmax] = [" << bbox[2][0] << ',' << bbox[2][1] << ']'
4560 << endl;
4561
4562 os << "endsolid GridFunction" << endl;
4563}
4564
4565std::ostream &operator<<(std::ostream &os, const GridFunction &sol)
4566{
4567 sol.Save(os);
4568 return os;
4569}
4570
4572{
4573 const Mesh* mesh = fes->GetMesh();
4574 MFEM_ASSERT(mesh->Nonconforming(), "");
4575
4576 // get the mapping (old_vertex_index -> new_vertex_index)
4577 Array<int> new_vertex, old_vertex;
4578 mesh->ncmesh->LegacyToNewVertexOrdering(new_vertex);
4579 MFEM_ASSERT(new_vertex.Size() == mesh->GetNV(), "");
4580
4581 // get the mapping (new_vertex_index -> old_vertex_index)
4582 old_vertex.SetSize(new_vertex.Size());
4583 for (int i = 0; i < new_vertex.Size(); i++)
4584 {
4585 old_vertex[new_vertex[i]] = i;
4586 }
4587
4588 Vector tmp = *this;
4589
4590 // reorder vertex DOFs
4591 Array<int> old_vdofs, new_vdofs;
4592 for (int i = 0; i < mesh->GetNV(); i++)
4593 {
4594 fes->GetVertexVDofs(i, old_vdofs);
4595 fes->GetVertexVDofs(new_vertex[i], new_vdofs);
4596
4597 for (int j = 0; j < new_vdofs.Size(); j++)
4598 {
4599 tmp(new_vdofs[j]) = (*this)(old_vdofs[j]);
4600 }
4601 }
4602
4603 // reorder edge DOFs -- edge orientation has changed too
4604 Array<int> dofs, ev;
4605 for (int i = 0; i < mesh->GetNEdges(); i++)
4606 {
4607 mesh->GetEdgeVertices(i, ev);
4608 if (old_vertex[ev[0]] > old_vertex[ev[1]])
4609 {
4610 const int *ind = fes->FEColl()->DofOrderForOrientation(Geometry::SEGMENT, -1);
4611
4612 fes->GetEdgeInteriorDofs(i, dofs);
4613 for (int k = 0; k < dofs.Size(); k++)
4614 {
4615 int new_dof = dofs[k];
4616 int old_dof = dofs[(ind[k] < 0) ? -1-ind[k] : ind[k]];
4617
4618 for (int j = 0; j < fes->GetVDim(); j++)
4619 {
4620 int new_vdof = fes->DofToVDof(new_dof, j);
4621 int old_vdof = fes->DofToVDof(old_dof, j);
4622
4623 real_t sign = (ind[k] < 0) ? -1.0 : 1.0;
4624 tmp(new_vdof) = sign * (*this)(old_vdof);
4625 }
4626 }
4627 }
4628 }
4629
4630 Vector::Swap(tmp);
4631}
4632
4633std::unique_ptr<GridFunction> GridFunction::ProlongateToMaxOrder() const
4634{
4635 Mesh *mesh = fes->GetMesh();
4636 const FiniteElementCollection *fesc = fes->FEColl();
4637 const int vdim = fes->GetVDim();
4638
4639 // Find the max order in the space
4640 int maxOrder = fes->GetMaxElementOrder();
4641
4642 // Create a space of maximum order over all elements for output
4643 FiniteElementCollection *fecMax = fesc->Clone(maxOrder);
4644 FiniteElementSpace *fesMax = new FiniteElementSpace(mesh, fecMax, vdim,
4645 fes->GetOrdering());
4646
4647 GridFunction *xMax = new GridFunction(fesMax);
4648
4649 // Interpolate in the maximum-order space
4650 PRefinementTransferOperator P(*fes, *fesMax);
4651 P.Mult(*this, *xMax);
4652
4653 xMax->MakeOwner(fecMax);
4654 return std::unique_ptr<GridFunction>(xMax);
4655}
4656
4658 GridFunction &u,
4659 GridFunction &flux, Vector &error_estimates,
4660 Array<int>* aniso_flags,
4661 int with_subdomains,
4662 bool with_coeff)
4663{
4664 FiniteElementSpace *ufes = u.FESpace();
4665 FiniteElementSpace *ffes = flux.FESpace();
4666 ElementTransformation *Transf;
4667 DofTransformation utrans, ftrans;
4668
4669 int dim = ufes->GetMesh()->Dimension();
4670 int nfe = ufes->GetNE();
4671
4672 Array<int> udofs;
4673 Array<int> fdofs;
4674 Vector ul, fl, fla, d_xyz;
4675
4676 error_estimates.SetSize(nfe);
4677 if (aniso_flags)
4678 {
4679 aniso_flags->SetSize(nfe);
4680 d_xyz.SetSize(dim);
4681 }
4682
4683 int nsd = 1;
4684 if (with_subdomains)
4685 {
4686 nsd = ufes->GetMesh()->attributes.Max();
4687 }
4688
4689 real_t total_error = 0.0;
4690 for (int s = 1; s <= nsd; s++)
4691 {
4692 // This calls the parallel version when u is a ParGridFunction
4693 u.ComputeFlux(blfi, flux, with_coeff, (with_subdomains ? s : -1));
4694
4695 for (int i = 0; i < nfe; i++)
4696 {
4697 if (with_subdomains && ufes->GetAttribute(i) != s) { continue; }
4698
4699 ufes->GetElementVDofs(i, udofs, utrans);
4700 ffes->GetElementVDofs(i, fdofs, ftrans);
4701
4702 u.GetSubVector(udofs, ul);
4703 flux.GetSubVector(fdofs, fla);
4704 utrans.InvTransformPrimal(ul);
4705 ftrans.InvTransformPrimal(fla);
4706
4707 Transf = ufes->GetElementTransformation(i);
4708 blfi.ComputeElementFlux(*ufes->GetFE(i), *Transf, ul,
4709 *ffes->GetFE(i), fl, with_coeff);
4710
4711 fl -= fla;
4712
4713 real_t eng = blfi.ComputeFluxEnergy(*ffes->GetFE(i), *Transf, fl,
4714 (aniso_flags ? &d_xyz : NULL));
4715
4716 error_estimates(i) = std::sqrt(eng);
4717 total_error += eng;
4718
4719 if (aniso_flags)
4720 {
4721 real_t sum = 0;
4722 for (int k = 0; k < dim; k++)
4723 {
4724 sum += d_xyz[k];
4725 }
4726
4727 real_t thresh = 0.15 * 3.0/dim;
4728 int flag = 0;
4729 for (int k = 0; k < dim; k++)
4730 {
4731 if (d_xyz[k] / sum > thresh) { flag |= (1 << k); }
4732 }
4733
4734 (*aniso_flags)[i] = flag;
4735 }
4736 }
4737 }
4738#ifdef MFEM_USE_MPI
4739 auto pfes = dynamic_cast<ParFiniteElementSpace*>(ufes);
4740 if (pfes)
4741 {
4742 auto process_local_error = total_error;
4743 MPI_Allreduce(&process_local_error, &total_error, 1,
4745 MPI_SUM, pfes->GetComm());
4746 }
4747#endif // MFEM_USE_MPI
4748 return std::sqrt(total_error);
4749}
4750
4751void TensorProductLegendre(int dim, // input
4752 int order, // input
4753 const Vector &x_in, // input
4754 const Vector &xmax, // input
4755 const Vector &xmin, // input
4756 Vector &poly, // output
4757 real_t angle, // input (optional)
4758 const Vector *midpoint) // input (optional)
4759{
4760 MFEM_VERIFY(dim >= 1, "dim must be positive");
4761 MFEM_VERIFY(dim <= 3, "dim cannot be greater than 3");
4762 MFEM_VERIFY(order >= 0, "order cannot be negative");
4763
4764 bool rotate = (angle != 0.0) || (midpoint->Norml2() != 0.0);
4765
4766 Vector x(dim);
4767 if (rotate && dim == 2)
4768 {
4769 // Rotate coordinates to match rotated bounding box
4770 Vector tmp(dim);
4771 tmp = x_in;
4772 tmp -= *midpoint;
4773 x[0] = tmp[0]*cos(-angle) - tmp[1]*sin(-angle);
4774 x[1] = tmp[0]*sin(-angle) + tmp[1]*cos(-angle);
4775 }
4776 else
4777 {
4778 // Bounding box is not reoriented no need to change orientation
4779 x = x_in;
4780 }
4781
4782 // Map x to [0, 1] to use CalcLegendre since it uses shifted Legendre Polynomials.
4783 real_t x1 = (x(0) - xmin(0))/(xmax(0)-xmin(0)), x2, x3;
4784 Vector poly_x(order+1), poly_y(order+1), poly_z(order+1);
4785 poly1d.CalcLegendre(order, x1, poly_x.GetData());
4786 if (dim > 1)
4787 {
4788 x2 = (x(1)-xmin(1))/(xmax(1)-xmin(1));
4789 poly1d.CalcLegendre(order, x2, poly_y.GetData());
4790 }
4791 if (dim == 3)
4792 {
4793 x3 = (x(2)-xmin(2))/(xmax(2)-xmin(2));
4794 poly1d.CalcLegendre(order, x3, poly_z.GetData());
4795 }
4796
4797 int basis_dimension = static_cast<int>(pow(order+1,dim));
4798 poly.SetSize(basis_dimension);
4799 switch (dim)
4800 {
4801 case 1:
4802 {
4803 for (int i = 0; i <= order; i++)
4804 {
4805 poly(i) = poly_x(i);
4806 }
4807 }
4808 break;
4809 case 2:
4810 {
4811 for (int j = 0; j <= order; j++)
4812 {
4813 for (int i = 0; i <= order; i++)
4814 {
4815 int cnt = i + (order+1) * j;
4816 poly(cnt) = poly_x(i) * poly_y(j);
4817 }
4818 }
4819 }
4820 break;
4821 case 3:
4822 {
4823 for (int k = 0; k <= order; k++)
4824 {
4825 for (int j = 0; j <= order; j++)
4826 {
4827 for (int i = 0; i <= order; i++)
4828 {
4829 int cnt = i + (order+1) * j + (order+1) * (order+1) * k;
4830 poly(cnt) = poly_x(i) * poly_y(j) * poly_z(k);
4831 }
4832 }
4833 }
4834 }
4835 break;
4836 default:
4837 {
4838 MFEM_ABORT("TensorProductLegendre: invalid value of dim");
4839 }
4840 }
4841}
4842
4843void BoundingBox(const Array<int> &patch, // input
4844 FiniteElementSpace *ufes, // input
4845 int order, // input
4846 Vector &xmin, // output
4847 Vector &xmax, // output
4848 real_t &angle, // output
4849 Vector &midpoint, // output
4850 int iface) // input (optional)
4851{
4852 Mesh *mesh = ufes->GetMesh();
4853 int dim = mesh->Dimension();
4854 int num_elems = patch.Size();
4856
4857 xmax = -infinity();
4858 xmin = infinity();
4859 angle = 0.0;
4860 midpoint = 0.0;
4861 bool rotate = (dim == 2);
4862
4863 // Rotate bounding box to match the face orientation
4864 if (rotate && iface >= 0)
4865 {
4866 IntegrationPoint reference_pt;
4867 mesh->GetFaceTransformation(iface, &Tr);
4868 Vector physical_pt(2);
4869 Vector physical_diff(2);
4870 physical_diff = 0.0;
4871 // Get the endpoints of the edge in physical space
4872 // then compute midpoint and angle
4873 for (int i = 0; i < 2; i++)
4874 {
4875 reference_pt.Set1w((real_t)i, 0.0);
4876 Tr.Transform(reference_pt, physical_pt);
4877 midpoint += physical_pt;
4878 physical_pt *= pow(-1.0,i);
4879 physical_diff += physical_pt;
4880 }
4881 midpoint /= 2.0;
4882 angle = atan2(physical_diff(1),physical_diff(0));
4883 }
4884
4885 for (int i = 0; i < num_elems; i++)
4886 {
4887 int ielem = patch[i];
4888 const IntegrationRule *ir = &(IntRules.Get(mesh->GetElementGeometry(ielem),
4889 order));
4890 ufes->GetElementTransformation(ielem, &Tr);
4891 for (int k = 0; k < ir->GetNPoints(); k++)
4892 {
4893 const IntegrationPoint ip = ir->IntPoint(k);
4894 Vector transip(dim);
4895 Tr.Transform(ip, transip);
4896 if (rotate)
4897 {
4898 transip -= midpoint;
4899 Vector tmp(dim);
4900 tmp = transip;
4901 transip[0] = tmp[0]*cos(-angle) - tmp[1]*sin(-angle);
4902 transip[1] = tmp[0]*sin(-angle) + tmp[1]*cos(-angle);
4903 }
4904 for (int d = 0; d < dim; d++) { xmax(d) = max(xmax(d), transip(d)); }
4905 for (int d = 0; d < dim; d++) { xmin(d) = min(xmin(d), transip(d)); }
4906 }
4907 }
4908}
4909
4911 GridFunction &u, // input
4912 Vector &error_estimates, // output
4913 bool subdomain_reconstruction, // input (optional)
4914 bool with_coeff, // input (optional)
4915 real_t tichonov_coeff) // input (optional)
4916{
4917 MFEM_VERIFY(tichonov_coeff >= 0.0, "tichonov_coeff cannot be negative");
4918 FiniteElementSpace *ufes = u.FESpace();
4919 ElementTransformation *Transf;
4920 DofTransformation utrans;
4921
4922 Mesh *mesh = ufes->GetMesh();
4923 int dim = mesh->Dimension();
4924 int sdim = mesh->SpaceDimension();
4925 int nfe = ufes->GetNE();
4926 int nfaces = ufes->GetNF();
4927
4928 Array<int> udofs;
4929 Array<int> fdofs;
4930 Vector ul, fl, fla;
4931
4932 error_estimates.SetSize(nfe);
4933 error_estimates = 0.0;
4934 Array<int> counters(nfe);
4935 counters = 0;
4936
4937 Vector xmax(dim);
4938 Vector xmin(dim);
4939 real_t angle = 0.0;
4940 Vector midpoint(dim);
4941
4942 // Compute the number of subdomains
4943 int nsd = 1;
4944 if (subdomain_reconstruction)
4945 {
4946 nsd = ufes->GetMesh()->attributes.Max();
4947 }
4948
4949 real_t total_error = 0.0;
4950 for (int iface = 0; iface < nfaces; iface++)
4951 {
4952 // 1.A. Find all elements in the face patch.
4953 int el1;
4954 int el2;
4955 mesh->GetFaceElements(iface, &el1, &el2);
4956 Array<int> patch(2);
4957 patch[0] = el1; patch[1] = el2;
4958
4959 // 1.B. Check if boundary face or non-conforming coarse face and continue if true.
4960 if (el1 == -1 || el2 == -1)
4961 {
4962 continue;
4963 }
4964
4965 // 1.C Check if face patch crosses an attribute interface and
4966 // continue if true (only active if subdomain_reconstruction == true)
4967 if (nsd > 1)
4968 {
4969 int el1_attr = ufes->GetAttribute(el1);
4970 int el2_attr = ufes->GetAttribute(el2);
4971 if (el1_attr != el2_attr) { continue; }
4972 }
4973
4974 // 2. Compute global flux polynomial.
4975
4976 // 2.A. Compute polynomial order of patch (for hp FEM)
4977 const int patch_order = max(ufes->GetElementOrder(el1),
4978 ufes->GetElementOrder(el2));
4979
4980 int num_basis_functions = static_cast<int>(pow(patch_order+1,dim));
4981 int flux_order = 2*patch_order + 1;
4982 DenseMatrix A(num_basis_functions);
4983 Array<real_t> b(sdim * num_basis_functions);
4984 A = 0.0;
4985 b = 0.0;
4986
4987 // 2.B. Estimate the smallest bounding box around the face patch
4988 // (this is used in 2.C.ii. to define a global polynomial basis)
4989 BoundingBox(patch, ufes, flux_order,
4990 xmin, xmax, angle, midpoint, iface);
4991
4992 // 2.C. Compute the normal equations for the least-squares problem
4993 // 2.C.i. Evaluate the discrete flux at all integration points in all
4994 // elements in the face patch
4995 for (int i = 0; i < patch.Size(); i++)
4996 {
4997 int ielem = patch[i];
4998 const IntegrationRule *ir = &(IntRules.Get(mesh->GetElementGeometry(ielem),
4999 flux_order));
5000 int num_integration_pts = ir->GetNPoints();
5001
5002 ufes->GetElementVDofs(ielem, udofs, utrans);
5003 u.GetSubVector(udofs, ul);
5004 utrans.InvTransformPrimal(ul);
5005 Transf = ufes->GetElementTransformation(ielem);
5006 const auto *dummy = ufes->GetFE(ielem);
5007 blfi.ComputeElementFlux(*ufes->GetFE(ielem), *Transf, ul,
5008 *dummy, fl, with_coeff, ir);
5009
5010 // 2.C.ii. Use global polynomial basis to construct normal
5011 // equations
5012 for (int k = 0; k < num_integration_pts; k++)
5013 {
5014 const IntegrationPoint ip = ir->IntPoint(k);
5015 real_t tmp[3];
5016 Vector transip(tmp, 3);
5017 Transf->Transform(ip, transip);
5018
5019 Vector p;
5020 TensorProductLegendre(dim, patch_order, transip, xmax, xmin, p, angle,
5021 &midpoint);
5022 AddMultVVt(p, A);
5023
5024 for (int l = 0; l < num_basis_functions; l++)
5025 {
5026 // Loop through each component of the discrete flux
5027 for (int n = 0; n < sdim; n++)
5028 {
5029 b[l + n * num_basis_functions] += p(l) * fl(k + n * num_integration_pts);
5030 }
5031 }
5032 }
5033 }
5034
5035 // 2.D. Shift spectrum of A to avoid conditioning issues.
5036 // Regularization is necessary if the tensor product space used for the
5037 // flux reconstruction leads to an underdetermined system of linear equations.
5038 // This should not happen if there are tensor product elements in the patch,
5039 // but it can happen if there are other element shapes (those with few
5040 // integration points) in the patch.
5041 for (int i = 0; i < num_basis_functions; i++)
5042 {
5043 A(i,i) += tichonov_coeff;
5044 }
5045
5046 // 2.E. Solve for polynomial coefficients
5047 Array<int> ipiv(num_basis_functions);
5048 LUFactors lu(A.Data(), ipiv);
5049 real_t TOL = 1e-9;
5050 if (!lu.Factor(num_basis_functions,TOL))
5051 {
5052 // Singular matrix
5053 mfem::out << "LSZZErrorEstimator: Matrix A is singular.\t"
5054 << "Consider increasing tichonov_coeff." << endl;
5055 for (int i = 0; i < num_basis_functions; i++)
5056 {
5057 A(i,i) += 1e-8;
5058 }
5059 lu.Factor(num_basis_functions,TOL);
5060 }
5061 lu.Solve(num_basis_functions, sdim, b);
5062
5063 // 2.F. Construct l2-minimizing global polynomial
5064 auto global_poly_tmp = [=] (const Vector &x, Vector &f)
5065 {
5066 Vector p;
5067 TensorProductLegendre(dim, patch_order, x, xmax, xmin, p, angle, &midpoint);
5068 f = 0.0;
5069 for (int i = 0; i < num_basis_functions; i++)
5070 {
5071 for (int j = 0; j < sdim; j++)
5072 {
5073 f(j) += b[i + j * num_basis_functions] * p(i);
5074 }
5075 }
5076 };
5077 VectorFunctionCoefficient global_poly(sdim, global_poly_tmp);
5078
5079 // 3. Compute error contributions from the face.
5080 real_t element_error = 0.0;
5081 real_t patch_error = 0.0;
5082 for (int i = 0; i < patch.Size(); i++)
5083 {
5084 int ielem = patch[i];
5085 element_error = u.ComputeElementGradError(ielem, &global_poly);
5086 element_error *= element_error;
5087 patch_error += element_error;
5088 error_estimates(ielem) += element_error;
5089 counters[ielem]++;
5090 }
5091
5092 total_error += patch_error;
5093 }
5094
5095 // 4. Calibrate the final error estimates. Note that the l2 norm of
5096 // error_estimates vector converges to total_error.
5097 // The error estimates have been calibrated so that high order
5098 // benchmark problems with tensor product elements are asymptotically
5099 // exact.
5100 for (int ielem = 0; ielem < nfe; ielem++)
5101 {
5102 if (counters[ielem] == 0)
5103 {
5104 error_estimates(ielem) = infinity();
5105 }
5106 else
5107 {
5108 error_estimates(ielem) /= counters[ielem]/2.0;
5109 error_estimates(ielem) = sqrt(error_estimates(ielem));
5110 }
5111 }
5112 return std::sqrt(total_error/dim);
5113}
5114
5116 GridFunction& gf1, GridFunction& gf2)
5117{
5118 real_t norm = 0.0;
5119
5120 FiniteElementSpace *fes1 = gf1.FESpace();
5121 FiniteElementSpace *fes2 = gf2.FESpace();
5122
5123 const FiniteElement* fe1 = fes1->GetFE(i);
5124 const FiniteElement* fe2 = fes2->GetFE(i);
5125
5126 const IntegrationRule *ir;
5127 int intorder = 2*std::max(fe1->GetOrder(),fe2->GetOrder()) + 1; // <-------
5128 ir = &(IntRules.Get(fe1->GetGeomType(), intorder));
5129 int nip = ir->GetNPoints();
5130 Vector val1, val2;
5131
5133 for (int j = 0; j < nip; j++)
5134 {
5135 const IntegrationPoint &ip = ir->IntPoint(j);
5136 T->SetIntPoint(&ip);
5137
5138 gf1.GetVectorValue(i, ip, val1);
5139 gf2.GetVectorValue(i, ip, val2);
5140
5141 val1 -= val2;
5142 real_t errj = val1.Norml2();
5143 if (p < infinity())
5144 {
5145 errj = pow(errj, p);
5146 norm += ip.weight * T->Weight() * errj;
5147 }
5148 else
5149 {
5150 norm = std::max(norm, errj);
5151 }
5152 }
5153
5154 if (p < infinity())
5155 {
5156 // Negative quadrature weights may cause the norm to be negative
5157 norm = pow(fabs(norm), 1./p);
5158 }
5159
5160 return norm;
5161}
5162
5163
5165 const IntegrationPoint &ip)
5166{
5167 ElementTransformation *T_in =
5168 mesh_in->GetElementTransformation(T.ElementNo / n);
5169 T_in->SetIntPoint(&ip);
5170 return sol_in.Eval(*T_in, ip);
5171}
5172
5174 const IntegrationPoint &ip)
5175{
5176 ElementTransformation *T_in =
5177 mesh_in->GetElementTransformation(T.ElementNo / n);
5178 T_in->SetIntPoint(&ip);
5179 sol_in.Eval(v, *T_in, ip);
5180}
5181
5183 GridFunction *sol, const int ny)
5184{
5185 GridFunction *sol2d;
5186
5187 FiniteElementCollection *solfec2d;
5188 const char *name = sol->FESpace()->FEColl()->Name();
5189 string cname = name;
5190 if (cname == "Linear")
5191 {
5192 solfec2d = new LinearFECollection;
5193 }
5194 else if (cname == "Quadratic")
5195 {
5196 solfec2d = new QuadraticFECollection;
5197 }
5198 else if (cname == "Cubic")
5199 {
5200 solfec2d = new CubicFECollection;
5201 }
5202 else if (!strncmp(name, "H1_", 3))
5203 {
5204 solfec2d = new H1_FECollection(atoi(name + 7), 2);
5205 }
5206 else if (!strncmp(name, "H1Pos_", 6))
5207 {
5208 // use regular (nodal) H1_FECollection
5209 solfec2d = new H1_FECollection(atoi(name + 10), 2);
5210 }
5211 else if (!strncmp(name, "L2_T", 4))
5212 {
5213 solfec2d = new L2_FECollection(atoi(name + 10), 2);
5214 }
5215 else if (!strncmp(name, "L2_", 3))
5216 {
5217 solfec2d = new L2_FECollection(atoi(name + 7), 2);
5218 }
5219 else if (!strncmp(name, "L2Int_", 6))
5220 {
5221 solfec2d = new L2_FECollection(atoi(name + 7), 2, BasisType::GaussLegendre,
5223 }
5224 else
5225 {
5226 mfem::err << "Extrude1DGridFunction : unknown FE collection : "
5227 << cname << endl;
5228 return NULL;
5229 }
5230 FiniteElementSpace *solfes2d;
5231 const int vdim = sol->FESpace()->GetVDim();
5232 solfes2d = new FiniteElementSpace(mesh2d, solfec2d, vdim);
5233 sol2d = new GridFunction(solfes2d);
5234 sol2d->MakeOwner(solfec2d);
5235 if (vdim > 1)
5236 {
5238 VectorExtrudeCoefficient vc2d(mesh, vcsol, ny);
5239 sol2d->ProjectCoefficient(vc2d);
5240 }
5241 else
5242 {
5244 ExtrudeCoefficient c2d(mesh, csol, ny);
5245 sol2d->ProjectCoefficient(c2d);
5246 }
5247 return sol2d;
5248}
5249
5251 const PLBound &plb,
5252 Vector &lower, Vector &upper,
5253 const int vdim) const
5254{
5255 const FiniteElement *fe = fes->GetFE(elem);
5256 int fes_dim = fes->GetVDim();
5257 int rdim = fe->GetDim();
5258
5259 const TensorBasisElement *tbe =
5260 dynamic_cast<const TensorBasisElement *>(fe);
5261 MFEM_VERIFY(tbe != NULL, "TensorBasis FiniteElement expected.");
5262 const Array<int> &dof_map = tbe->GetDofMap();
5263
5264 Vector loc_data;
5265 Array<int> dof_idx;
5266 fes->GetElementDofs(elem, dof_idx);
5267 int ndofs = dof_idx.Size();
5268
5269 int n_c_pts = static_cast<int>(std::pow(plb.GetNControlPoints(), rdim));
5270 lower.SetSize(n_c_pts*(vdim > 0 ? 1 : fes_dim));
5271 upper.SetSize(n_c_pts*(vdim > 0 ? 1 : fes_dim));
5272
5273 for (int d = 0; d < fes_dim; d++)
5274 {
5275 if (vdim > 0 && d != vdim-1) { continue; }
5276 const int d_off = vdim > 0 ? 0 : d;
5277 Array<int> dof_idx_c = dof_idx;
5278 Vector lowerT(lower, d_off*n_c_pts, n_c_pts);
5279 Vector upperT(upper, d_off*n_c_pts, n_c_pts);
5280 fes->DofsToVDofs(vdim > 0 ? vdim-1 : d, dof_idx_c);
5281 GetSubVector(dof_idx_c, loc_data);
5282 Vector nodal_data;
5283 if (dof_map.Size() == 0)
5284 {
5285 nodal_data.SetDataAndSize(loc_data.GetData(), ndofs);
5286 }
5287 else
5288 {
5289 nodal_data.SetSize(ndofs);
5290 for (int j = 0; j < ndofs; j++)
5291 {
5292 nodal_data(j) = loc_data(dof_map[j]);
5293 }
5294 }
5295 plb.GetNDBounds(rdim, nodal_data, lowerT, upperT);
5296 }
5297}
5298
5300 const PLBound &plb,
5301 const Vector &ref_range,
5302 const int vdim,
5303 Vector &lower, Vector &upper,
5304 Vector &control_pos) const
5305{
5306 const FiniteElement *fe = fes->GetFE(elem);
5307 const IntegrationRule ir_in = fe->GetNodes();
5308 IntegrationRule ir_new(ir_in.GetNPoints());
5309 const int dim = fes->GetMesh()->Dimension();
5310 const L2_FECollection *l2fec = dynamic_cast<const L2_FECollection *>
5311 (fes->FEColl());
5312
5313 const TensorBasisElement *tbe =
5314 dynamic_cast<const TensorBasisElement *>(fe);
5315 MFEM_VERIFY(tbe != NULL, "TensorBasis FiniteElement expected.");
5316
5317 const Array<int> &dof_map = tbe->GetDofMap();
5318 bool lexico = (dof_map.Size() == 0);
5319 bool bern = (tbe->GetBasisType() == BasisType::Positive);
5320 bool h1 = (l2fec == nullptr);
5321
5322 Vector loc_data; // gridfunction values
5323 // Construct an integration rule to evaluate the gridfunction in
5324 // subinterval.
5325 for (int i = 0; i < ir_in.GetNPoints(); i++)
5326 {
5327 IntegrationPoint &ip_new = ir_new.IntPoint(i);
5328 const IntegrationPoint &ip_old =
5329 ir_in.IntPoint((lexico || bern) ? i : dof_map[i]);
5330 Vector ip_coord(dim);
5331 ip_old.Get(ip_coord.GetData(), dim);
5332 for (int d = 0; d < dim; d++)
5333 {
5334 ip_coord(d) = ref_range(d) +
5335 (ref_range(dim+d) - ref_range(d)) * ip_coord(d);
5336 }
5337 ip_new.Set(ip_coord.GetData(), dim);
5338 }
5339 GetValues(elem, ir_new, loc_data, vdim);
5340 // At this point, the loc_data contains function values ordered
5341 // lexicographically, unless we are using Bernstein bases.
5342 // For Bernstein, we need to project and get coefficients first.
5343
5344 // For bernstein, we get coefficients corresponding to these function values
5345 if (bern)
5346 {
5347 int bt = 4; // BasisType::ClosedUniform
5348 int o = fe->GetOrder();
5349 DenseMatrix projmat;
5350 NodalTensorFiniteElement *ntfe = nullptr;
5351 if (dim == 1)
5352 {
5353 if (h1) { ntfe = new H1_SegmentElement(o, bt); }
5354 else { ntfe = new L2_SegmentElement(o, bt); }
5355 }
5356 else if (dim == 2)
5357 {
5358 if (h1) { ntfe = new H1_QuadrilateralElement(o, bt); }
5359 else { ntfe = new L2_QuadrilateralElement(o, bt); }
5360 }
5361 else if (dim == 3)
5362 {
5363 if (h1) { ntfe = new H1_HexahedronElement(o, bt); }
5364 else { ntfe = new L2_HexahedronElement(o, bt); }
5365 }
5366 // projection matrix from H1 to Positive
5368 fe->Project(*ntfe, *eltran, projmat);
5369 Vector loc_data_temp(loc_data.Size());
5370 projmat.Mult(loc_data, loc_data_temp);
5371 for (int i = 0; i < dof_map.Size(); i++)
5372 {
5373 loc_data(i) = loc_data_temp(dof_map[i]);
5374 }
5375 if (dof_map.Size() == 0) { loc_data = loc_data_temp; }
5376 delete ntfe;
5377 }
5378
5379 // Get bounds at control points
5380 plb.GetNDBounds(dim, loc_data, lower, upper);
5381
5382 // Save control point positions
5383 int ncp = plb.GetNControlPoints();
5384 control_pos.SetSize(dim * ncp);
5385 const Vector control_pos_1D = plb.GetControlPoints();
5386 for (int i = 0; i < ncp; i++)
5387 {
5388 for (int d = 0; d < dim; d++)
5389 {
5390 control_pos(i + d*ncp) =
5391 ref_range(d) + (ref_range(dim+d)-ref_range(d))*control_pos_1D(i);
5392 }
5393 }
5394}
5395
5396void GridFunction::GetElementBounds(const int elem, const PLBound &plb,
5397 Vector &lower, Vector &upper,
5398 const int vdim) const
5399{
5400 Vector lowerC, upperC;
5401 GetElementBoundsAtControlPoints(elem, plb, lowerC, upperC, vdim);
5402 const FiniteElement *fe = fes->GetFE(elem);
5403 int rdim = fe->GetDim();
5404 int n_c_pts = static_cast<int>(std::pow(plb.GetNControlPoints(), rdim));
5405 int fes_dim = fes->GetVDim();
5406 lower.SetSize((vdim > 0 ? 1 :fes_dim));
5407 upper.SetSize((vdim > 0 ? 1 :fes_dim));
5408 for (int d = 0; d < fes_dim; d++)
5409 {
5410 if (vdim > 0 && d != vdim-1) { continue; }
5411 const int d_off = vdim > 0 ? 0 : d;
5412 Vector lowerT(lowerC, d_off*n_c_pts, n_c_pts);
5413 Vector upperT(upperC, d_off*n_c_pts, n_c_pts);
5414 lower(d_off) = lowerT.Min();
5415 upper(d_off) = upperT.Max();
5416 }
5417}
5418
5420 Vector &lower, Vector &upper,
5421 const int vdim) const
5422{
5423 int nel = fes->GetNE();
5424 int fes_dim = fes->GetVDim();
5425 lower.SetSize(nel*(vdim > 0 ? 1 :fes_dim));
5426 upper.SetSize(nel*(vdim > 0 ? 1 :fes_dim));
5427 for (int e = 0; e < nel; e++)
5428 {
5429 Vector lt, ut;
5430 GetElementBounds(e, plb, lt, ut, vdim);
5431 for (int d = 0; d < fes_dim ; d++)
5432 {
5433 if (vdim > 0 && d != vdim-1) { continue; }
5434 const int d_off = vdim > 0 ? 0 : d;
5435 lower(e + d_off*nel) = lt(d_off);
5436 upper(e + d_off*nel) = ut(d_off);
5437 }
5438 }
5439}
5440
5442 Vector &upper,
5443 const int ref_factor,
5444 const int vdim) const
5445{
5446 int max_order = fes->GetMaxElementOrder();
5447 PLBound plb(fes, ref_factor*(max_order+1));
5448 GetElementBounds(plb, lower, upper, vdim);
5449 return plb;
5450}
5451
5453 const int ref_factor, const int vdim) const
5454{
5455 int max_order = fes->GetMaxElementOrder();
5456 PLBound plb(fes, ref_factor*(max_order+1));
5457
5458 Vector lel, uel;
5459 GetElementBounds(plb, lel, uel, vdim);
5460
5461 int nel = fes->GetNE();
5462 int fes_dim = fes->GetVDim();
5463 lower.SetSize(vdim > 0 ? 1 : fes_dim);
5464 upper.SetSize(vdim > 0 ? 1 : fes_dim);
5465 for (int d = 0; d < fes_dim; d++)
5466 {
5467 if (vdim > 0 && d != vdim-1) { continue; }
5468 const int d_off = vdim > 0 ? 0 : d;
5469 Vector lelt(lel, d_off*nel, nel);
5470 Vector uelt(uel, d_off*nel, nel);
5471 lower(d_off) = lelt.Min();
5472 upper(d_off) = uelt.Max();
5473 }
5474 return plb;
5475}
5476
5477struct IntervalNode
5478{
5479 real_t val_min;
5480 real_t val_max;
5482 IntervalNode(real_t vmin, real_t vmax)
5483 : val_min(vmin), val_max(vmax)
5484 {
5485 child.SetSize(0);
5486 }
5487 void AddChild(IntervalNode *ch) { child.Append(ch); }
5488 real_t GetChildMinLower()
5489 {
5490 if (child.Size() == 0)
5491 {
5492 return val_min;
5493 }
5494 real_t valmin = numeric_limits<real_t>::max();
5495 for (int i = 0; i < child.Size(); i++)
5496 {
5497 real_t candidate = child[i]->GetChildMinLower();
5498 valmin = std::min(valmin, candidate);
5499 }
5500 return valmin;
5501 }
5502 real_t GetChildMinUpper()
5503 {
5504 if (child.Size() == 0)
5505 {
5506 return val_max;
5507 }
5508 real_t valmax = numeric_limits<real_t>::max();
5509 for (int i = 0; i < child.Size(); i++)
5510 {
5511 real_t candidate = child[i]->GetChildMinUpper();
5512 valmax = std::min(valmax, candidate);
5513 }
5514 return valmax;
5515 }
5516 real_t GetChildMaxLower()
5517 {
5518 if (child.Size() == 0)
5519 {
5520 return val_min;
5521 }
5522 real_t valmin = numeric_limits<real_t>::lowest();
5523 for (int i = 0; i < child.Size(); i++)
5524 {
5525 real_t candidate = child[i]->GetChildMaxLower();
5526 valmin = std::max(valmin, candidate);
5527 }
5528 return valmin;
5529 }
5530 real_t GetChildMaxUpper()
5531 {
5532 if (child.Size() == 0)
5533 {
5534 return val_max;
5535 }
5536 real_t valmax = numeric_limits<real_t>::lowest();
5537 for (int i = 0; i < child.Size(); i++)
5538 {
5539 real_t candidate = child[i]->GetChildMaxUpper();
5540 valmax = std::max(valmax, candidate);
5541 }
5542 return valmax;
5543 }
5544 void DeleteChildren()
5545 {
5546 for (int i = 0; i < child.Size(); i++)
5547 {
5548 child[i]->DeleteChildren();
5549 delete child[i];
5550 }
5551 child.SetSize(0);
5552 }
5553};
5554
5555struct SearchInterval
5556{
5557 Vector ref_range;
5558 int depth;
5559 IntervalNode *node;
5560 SearchInterval(const Vector &ref_range_in, int d, IntervalNode *n)
5561 : ref_range(ref_range_in), depth(d), node(n)
5562 { }
5563};
5564
5565struct IntervalCompareMin
5566{
5567 bool operator()(const SearchInterval *a, const SearchInterval *b) const
5568 {
5569 return a->node->val_min > b->node->val_min;
5570 }
5571};
5572
5573struct IntervalCompareMax
5574{
5575 bool operator()(const SearchInterval *a, const SearchInterval *b) const
5576 {
5577 return a->node->val_max < b->node->val_max;
5578 }
5579};
5580
5582 const int elem, const PLBound &plb, const int vdim,
5583 const int max_depth, const real_t tol) const
5584{
5585 real_t min_threshold = std::numeric_limits<real_t>::max();
5586 return EstimateFunctionMinimum(elem, plb, vdim, max_depth, tol,
5587 min_threshold);
5588}
5589
5591 const int elem, const PLBound &plb, const int vdim,
5592 const int max_depth, const real_t tol, real_t &min_threshold) const
5593{
5594 const int dim = this->FESpace()->GetMesh()->Dimension();
5595 const int ncp = plb.GetNControlPoints();
5596 Vector pos_range(2*dim); pos_range = 0.0;
5597 for (int d = 0; d < dim; d++) { pos_range(d+dim) = 1.0; }
5598 Vector lower, upper, cp_ref_loc;
5599
5600 GetElementBoundsAtControlPoints(elem, plb, lower, upper, vdim);
5601 real_t val_min = lower.Min();
5602 real_t val_max = upper.Min();
5603
5604 min_threshold = std::min(min_threshold, val_max);
5605
5606 // Pruning: if the element's lower bound is greater than the current global
5607 // upper bound, this element cannot contain the global minimum.
5608 if (val_min >= min_threshold)
5609 {
5610 return std::make_pair(val_min, val_max);
5611 }
5612
5613 if (val_min == val_max || max_depth == 0)
5614 {
5615 min_threshold = std::min(min_threshold, val_min);
5616 return std::make_pair(val_min, val_max);
5617 }
5618 real_t abs_tol = tol*(val_max-val_min);
5619
5620 IntervalNode *initial_node = new IntervalNode(val_min, val_max);
5621 SearchInterval *initial_interval = new SearchInterval(pos_range, 0,
5622 initial_node);
5623
5624 std::priority_queue<SearchInterval*,
5625 std::vector<SearchInterval*>, IntervalCompareMin> pq;
5626 pq.push(initial_interval);
5627
5628 real_t min_upper_bound = upper.Min();
5629 real_t min_lower_bound = lower.Min();
5630
5631 while (!pq.empty())
5632 {
5633 SearchInterval *current = pq.top();
5634 pq.pop();
5635 int curr_depth = current->depth;
5636
5637 // Reached max depth or this interval cannot contain the global minimum
5638 if (current->node->val_min >= min_threshold || curr_depth >= max_depth)
5639 {
5640 delete current;
5641 continue;
5642 }
5643
5644 min_lower_bound = initial_node->GetChildMinLower();
5645 if (min_upper_bound - min_lower_bound < abs_tol)
5646 {
5647 delete current;
5648 break;
5649 }
5650
5651 // Subdivide the interval and get bounds on it
5652 GetElementBoundsAtControlPoints(elem, plb, current->ref_range,
5653 vdim, lower, upper, cp_ref_loc);
5654
5655 // process the bounds and create sub-intervals
5656 for (int k = 0; k < (dim == 3 ? ncp-1 : 1); k++)
5657 {
5658 for (int j = 0; j < (dim >= 2 ? ncp-1 : 1); j++)
5659 {
5660 for (int i = 0; i < ncp-1; i++)
5661 {
5662 real_t lv = 0.0, uv = 0.0;
5663 if (dim == 1)
5664 {
5665 lv = std::min(lower(i), lower(i+1));
5666 uv = std::min(upper(i), upper(i+1));
5667 }
5668 else if (dim == 2)
5669 {
5670 lv = std::min({lower(i + j*ncp), lower((i+1) + j*ncp),
5671 lower(i + (j+1)*ncp),
5672 lower((i+1) + (j+1)*ncp)});
5673 uv = std::min({upper(i + j*ncp), upper((i+1) + j*ncp),
5674 upper(i + (j+1)*ncp),
5675 upper((i+1) + (j+1)*ncp)});
5676 }
5677 else if (dim == 3)
5678 {
5679 lv = std::min({lower(i + j*ncp + k*ncp*ncp),
5680 lower((i+1) + j*ncp + k*ncp*ncp),
5681 lower(i + (j+1)*ncp + k*ncp*ncp),
5682 lower((i+1) + (j+1)*ncp + k*ncp*ncp),
5683 lower(i + j*ncp + (k+1)*ncp*ncp),
5684 lower((i+1) + j*ncp + (k+1)*ncp*ncp),
5685 lower(i + (j+1)*ncp + (k+1)*ncp*ncp),
5686 lower((i+1) + (j+1)*ncp + (k+1)*ncp*ncp)});
5687 uv = std::min({upper(i + j*ncp + k*ncp*ncp),
5688 upper((i+1) + j*ncp + k*ncp*ncp),
5689 upper(i + (j+1)*ncp + k*ncp*ncp),
5690 upper((i+1) + (j+1)*ncp + k*ncp*ncp),
5691 upper(i + j*ncp + (k+1)*ncp*ncp),
5692 upper((i+1) + j*ncp + (k+1)*ncp*ncp),
5693 upper(i + (j+1)*ncp + (k+1)*ncp*ncp),
5694 upper((i+1) + (j+1)*ncp + (k+1)*ncp*ncp)});
5695 }
5696 IntervalNode *child_node = new IntervalNode(lv, uv);
5697 current->node->AddChild(child_node);
5698
5699 if (lv < min_threshold)
5700 {
5701 min_upper_bound = std::min(min_upper_bound, uv);
5702 min_threshold = std::min(min_threshold, uv);
5703 if (curr_depth < max_depth)
5704 {
5705 pos_range(0) = cp_ref_loc(i);
5706 pos_range(0+dim) = cp_ref_loc(i+1);
5707 if (dim >= 2)
5708 {
5709 pos_range(1) = cp_ref_loc(ncp + j);
5710 pos_range(1+dim) = cp_ref_loc(ncp + j+1);
5711 }
5712 if (dim == 3)
5713 {
5714 pos_range(2) = cp_ref_loc(2*ncp + k);
5715 pos_range(2+dim) = cp_ref_loc(2*ncp + k+1);
5716 }
5717 SearchInterval *child_interval =
5718 new SearchInterval(pos_range, curr_depth + 1,
5719 child_node);
5720 pq.push(child_interval);
5721 }
5722 }
5723 }
5724 }
5725 }
5726 delete current;
5727 }
5728
5729 // clean up remaining intervals in queue
5730 while (!pq.empty())
5731 {
5732 delete pq.top();
5733 pq.pop();
5734 }
5735
5736 min_lower_bound = initial_node->GetChildMinLower();
5737 initial_node->DeleteChildren();
5738 delete initial_node;
5739
5740 min_threshold = std::min(min_threshold, min_lower_bound);
5741 return std::make_pair(min_lower_bound, min_upper_bound);
5742}
5743
5745 const int elem, const PLBound &plb, const int vdim,
5746 const int max_depth, const real_t tol) const
5747{
5748 real_t max_threshold = std::numeric_limits<real_t>::lowest();
5749 return EstimateFunctionMaximum(elem, plb, vdim, max_depth, tol,
5750 max_threshold);
5751}
5752
5754 const int elem, const PLBound &plb, const int vdim,
5755 const int max_depth, const real_t tol, real_t &max_threshold) const
5756{
5757 const int dim = this->FESpace()->GetMesh()->Dimension();
5758 const int ncp = plb.GetNControlPoints();
5759 Vector pos_range(2*dim); pos_range = 0.0;
5760 for (int d = 0; d < dim; d++) { pos_range(d+dim) = 1.0; }
5761 Vector lower, upper, cp_ref_loc;
5762
5763 GetElementBoundsAtControlPoints(elem, plb, lower, upper, vdim);
5764 real_t val_min = lower.Max();
5765 real_t val_max = upper.Max();
5766
5767 max_threshold = std::max(max_threshold, val_min);
5768
5769 // Pruning: if the element's upper bound is less than the current global
5770 // lower bound, this element cannot contain the global maximum.
5771 if (val_max <= max_threshold)
5772 {
5773 return std::make_pair(val_min, val_max);
5774 }
5775
5776 if (val_min == val_max || max_depth == 0)
5777 {
5778 max_threshold = std::max(max_threshold, val_max);
5779 return std::make_pair(val_min, val_max);
5780 }
5781 real_t abs_tol = tol*(val_max-val_min);
5782
5783 IntervalNode *initial_node = new IntervalNode(val_min, val_max);
5784 SearchInterval *initial_interval = new SearchInterval(pos_range, 0,
5785 initial_node);
5786
5787 std::priority_queue<SearchInterval*,
5788 std::vector<SearchInterval*>, IntervalCompareMax> pq;
5789 pq.push(initial_interval);
5790
5791 real_t max_lower_bound = val_min;
5792 real_t max_upper_bound = val_max;
5793
5794 while (!pq.empty())
5795 {
5796 SearchInterval *current = pq.top();
5797 pq.pop();
5798 int curr_depth = current->depth;
5799
5800 // Reached max depth or this interval cannot contain the global maximum.
5801 if (current->node->val_max <= max_threshold || curr_depth >= max_depth)
5802 {
5803 delete current;
5804 continue;
5805 }
5806
5807 max_upper_bound = initial_node->GetChildMaxUpper();
5808 if (max_upper_bound - max_lower_bound < abs_tol)
5809 {
5810 delete current;
5811 break;
5812 }
5813
5814 // Subdivide the interval and get bounds on it
5815 GetElementBoundsAtControlPoints(elem, plb, current->ref_range,
5816 vdim, lower, upper, cp_ref_loc);
5817
5818 // process the bounds and create sub-intervals
5819 for (int k = 0; k < (dim == 3 ? ncp-1 : 1); k++)
5820 {
5821 for (int j = 0; j < (dim >= 2 ? ncp-1 : 1); j++)
5822 {
5823 for (int i = 0; i < ncp-1; i++)
5824 {
5825 real_t lv = 0.0, uv = 0.0;
5826 if (dim == 1)
5827 {
5828 lv = std::max(lower(i), lower(i+1));
5829 uv = std::max(upper(i), upper(i+1));
5830 }
5831 else if (dim == 2)
5832 {
5833 lv = std::max({lower(i + j*ncp), lower((i+1) + j*ncp),
5834 lower(i + (j+1)*ncp),
5835 lower((i+1) + (j+1)*ncp)});
5836 uv = std::max({upper(i + j*ncp), upper((i+1) + j*ncp),
5837 upper(i + (j+1)*ncp),
5838 upper((i+1) + (j+1)*ncp)});
5839 }
5840 else if (dim == 3)
5841 {
5842 lv = std::max({lower(i + j*ncp + k*ncp*ncp),
5843 lower((i+1) + j*ncp + k*ncp*ncp),
5844 lower(i + (j+1)*ncp + k*ncp*ncp),
5845 lower((i+1) + (j+1)*ncp + k*ncp*ncp),
5846 lower(i + j*ncp + (k+1)*ncp*ncp),
5847 lower((i+1) + j*ncp + (k+1)*ncp*ncp),
5848 lower(i + (j+1)*ncp + (k+1)*ncp*ncp),
5849 lower((i+1) + (j+1)*ncp + (k+1)*ncp*ncp)});
5850 uv = std::max({upper(i + j*ncp + k*ncp*ncp),
5851 upper((i+1) + j*ncp + k*ncp*ncp),
5852 upper(i + (j+1)*ncp + k*ncp*ncp),
5853 upper((i+1) + (j+1)*ncp + k*ncp*ncp),
5854 upper(i + j*ncp + (k+1)*ncp*ncp),
5855 upper((i+1) + j*ncp + (k+1)*ncp*ncp),
5856 upper(i + (j+1)*ncp + (k+1)*ncp*ncp),
5857 upper((i+1) + (j+1)*ncp + (k+1)*ncp*ncp)});
5858 }
5859 IntervalNode *child_node = new IntervalNode(lv, uv);
5860 current->node->AddChild(child_node);
5861
5862 if (uv > max_threshold)
5863 {
5864 max_lower_bound = std::max(max_lower_bound, lv);
5865 max_threshold = std::max(max_threshold, lv);
5866 if (curr_depth < max_depth)
5867 {
5868 pos_range(0) = cp_ref_loc(i);
5869 pos_range(0+dim) = cp_ref_loc(i+1);
5870 if (dim >= 2)
5871 {
5872 pos_range(1) = cp_ref_loc(ncp + j);
5873 pos_range(1+dim) = cp_ref_loc(ncp + j+1);
5874 }
5875 if (dim == 3)
5876 {
5877 pos_range(2) = cp_ref_loc(2*ncp + k);
5878 pos_range(2+dim) = cp_ref_loc(2*ncp + k+1);
5879 }
5880 SearchInterval *child_interval =
5881 new SearchInterval(pos_range, curr_depth + 1,
5882 child_node);
5883 pq.push(child_interval);
5884 }
5885 }
5886 }
5887 }
5888 }
5889 delete current;
5890 }
5891 // clean up remaining intervals in queue
5892 while (!pq.empty())
5893 {
5894 delete pq.top();
5895 pq.pop();
5896 }
5897
5898 max_upper_bound = initial_node->GetChildMaxUpper();
5899 initial_node->DeleteChildren();
5900 delete initial_node;
5901 max_threshold = std::max(max_threshold, max_upper_bound);
5902
5903 return std::make_pair(max_lower_bound, max_upper_bound);
5904}
5905
5907 const int vdim, const PLBound &plb, const int max_depth,
5908 const real_t tol) const
5909{
5910 real_t global_min_lower = std::numeric_limits<real_t>::max();
5911 real_t global_min_upper = std::numeric_limits<real_t>::max();
5912
5913 for (int i = 0; i < fes->GetNE(); i++)
5914 {
5915 std::pair<real_t, real_t> min_pair =
5916 EstimateFunctionMinimum(i, plb, vdim, max_depth, tol,
5917 global_min_lower);
5918 global_min_upper = std::min(global_min_upper, min_pair.second);
5919 }
5920 return std::make_pair(global_min_lower, global_min_upper);
5921}
5922
5924 const int vdim, const PLBound &plb, const int max_depth,
5925 const real_t tol) const
5926{
5927 real_t global_max_lower = std::numeric_limits<real_t>::lowest();
5928 real_t global_max_upper = std::numeric_limits<real_t>::lowest();
5929
5930 for (int i = 0; i < fes->GetNE(); i++)
5931 {
5932 std::pair<real_t, real_t> max_pair =
5933 EstimateFunctionMaximum(i, plb, vdim, max_depth, tol,
5934 global_max_upper);
5935 global_max_lower = std::max(global_max_lower, max_pair.first);
5936 }
5937 return std::make_pair(global_max_lower, global_max_upper);
5938}
5939
5940}
T Max() const
Find the maximal element in the array, using the comparison operator < for class T.
Definition array.cpp:69
const T * HostRead() const
Shortcut for mfem::Read(a.GetMemory(), a.Size(), false).
Definition array.hpp:414
void SetSize(int nsize)
Change the logical size of the array, keep existing entries.
Definition array.hpp:869
int Size() const
Return the logical size of the array.
Definition array.hpp:192
int Append(const T &el)
Append element 'el' to array, resize if necessary.
Definition array.hpp:941
@ GaussLegendre
Open type.
Definition fe_base.hpp:35
@ Positive
Bernstein polynomials.
Definition fe_base.hpp:37
Abstract base class BilinearFormIntegrator.
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.
virtual real_t ComputeFluxEnergy(const FiniteElement &fluxelem, ElementTransformation &Trans, Vector &flux, Vector *d_energy=NULL)
Virtual method required for Zienkiewicz-Zhu type error estimators.
A "square matrix" operator for the associated FE space and BLFIntegrators The sum of all the BLFInteg...
Conjugate gradient method.
Definition solvers.hpp:627
Base class Coefficients that optionally depend on space and time. These are used by the BilinearFormI...
virtual real_t Eval(ElementTransformation &T, const IntegrationPoint &ip)=0
Evaluate the coefficient in the element described by T at the point ip.
Piecewise-(bi)cubic continuous finite elements.
Definition fe_coll.hpp:991
Delta function coefficient optionally multiplied by a weight coefficient and a scaled time dependent ...
const real_t * Center()
Coefficient * Weight()
See SetWeight() for description of the weight Coefficient.
real_t Scale()
Return the scale factor times the optional time dependent function. Returns with when not set by th...
real_t Tol()
Return the tolerance used to identify the mesh vertices.
Data type dense matrix using column-major storage.
Definition densemat.hpp:24
void Mult(const real_t *x, real_t *y) const
Matrix vector multiplication.
Definition densemat.cpp:108
void TestInversion()
Invert and print the numerical conditioning of the inversion.
void MultTranspose(const real_t *x, real_t *y) const
Multiply a vector with the transpose matrix.
Definition densemat.cpp:158
void Transpose()
(*this) = (*this)^t
void GetColumnReference(int c, Vector &col)
Definition densemat.hpp:340
real_t * Data() const
Returns the matrix data array. Warning: this method casts away constness.
Definition densemat.hpp:131
void AddMult(const Vector &x, Vector &y, const real_t a=1.0) const override
y += a * A.x
Definition densemat.cpp:194
void SetSize(int s)
Change the size of the DenseMatrix to s x s.
Definition densemat.hpp:125
void GetRowl2(Vector &l) const
Returns the l2norm of the rows of the DenseMatrix.
void AddMatrix(DenseMatrix &A, int ro, int co)
Perform (ro+i,co+j)+=A(i,j) for 0<=i.
void Norm2(real_t *v) const
Take the 2-norm of the columns of A and store in v.
Definition densemat.cpp:829
static MemoryType GetDeviceMemoryType()
Get the current Device MemoryType. This is the MemoryType used by most MFEM classes when allocating m...
Definition device.hpp:298
void InvTransformPrimal(real_t *v) const
Definition doftrans.cpp:47
void TransformPrimal(real_t *v) const
Definition doftrans.cpp:17
Class for domain integration .
Definition lininteg.hpp:108
Geometry::Type GetGeometryType() const
Return the Geometry::Type of the reference element.
Definition eltrans.hpp:175
const DenseMatrix & InverseJacobian()
Return the inverse of the Jacobian matrix of the transformation at the currently set IntegrationPoint...
Definition eltrans.hpp:158
const IntegrationPoint & GetIntPoint()
Get a const reference to the currently set integration point. This will return NULL if no integration...
Definition eltrans.hpp:111
real_t Weight()
Return the weight of the Jacobian matrix of the transformation at the currently set IntegrationPoint....
Definition eltrans.hpp:144
const DenseMatrix & Jacobian()
Return the Jacobian matrix of the transformation at the currently set IntegrationPoint,...
Definition eltrans.hpp:132
void SetIntPoint(const IntegrationPoint *ip)
Set the integration point ip that weights and Jacobians will be evaluated at.
Definition eltrans.hpp:106
virtual void Transform(const IntegrationPoint &, Vector &)=0
Transform integration point from reference coordinates to physical coordinates and store them in the ...
Class used for extruding a scalar coefficient.
real_t Eval(ElementTransformation &T, const IntegrationPoint &ip) override
Evaluate the coefficient in the element described by T at the point ip.
A specialized ElementTransformation class representing a face and its two neighboring elements.
Definition eltrans.hpp:750
ElementTransformation * Elem2
Definition eltrans.hpp:791
ElementTransformation * Elem1
Definition eltrans.hpp:791
IntegrationPointTransformation Loc1
Definition eltrans.hpp:793
void SetAllIntPoints(const IntegrationPoint *face_ip)
Set the integration point in the Face and the two neighboring elements, if present.
Definition eltrans.hpp:835
ElementTransformation & GetElement1Transformation()
Definition eltrans.cpp:632
IntegrationPointTransformation Loc2
Definition eltrans.hpp:793
Collection of finite elements from the same family in multiple dimensions. This class is used to matc...
Definition fe_coll.hpp:27
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].
static FiniteElementCollection * New(const char *name)
Factory method: return a newly allocated FiniteElementCollection according to the given name.
Definition fe_coll.cpp:124
virtual int GetContType() const =0
virtual FiniteElementCollection * Clone(int p) const
Instantiate a new collection of the same type with a different order.
Definition fe_coll.cpp:462
virtual const char * Name() const
Definition fe_coll.hpp:79
@ CONTINUOUS
Field is continuous across element interfaces.
Definition fe_coll.hpp:45
Class FiniteElementSpace - responsible for providing FEM view of the mesh, mainly managing the set of...
Definition fespace.hpp:210
void Save(std::ostream &out) const
Save finite element space to output stream out.
Definition fespace.cpp:4409
void GetVDofs(int vd, Array< int > &dofs, int ndofs=-1) const
Returns the indices of all of the VDofs for the specified dimension 'vd'.
Definition fespace.cpp:212
int GetNVDofs() const
Number of all scalar vertex dofs.
Definition fespace.hpp:857
void DofsToVDofs(Array< int > &dofs, int ndofs=-1) const
Compute the full set of vdofs corresponding to each entry in dofs.
Definition fespace.cpp:232
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:3841
const FiniteElement * GetBE(int i) const
Returns pointer to the FiniteElement in the FiniteElementCollection associated with i'th boundary fac...
Definition fespace.cpp:3906
virtual int GetTrueVSize() const
Return the number of vector true (conforming) dofs.
Definition fespace.hpp:827
DofTransformation * GetElementDofs(int elem, Array< int > &dofs) const
Returns indices of degrees of freedom of element 'elem'. The returned indices are offsets into an ldo...
Definition fespace.cpp:3538
ElementTransformation * GetElementTransformation(int i) const
Definition fespace.hpp:903
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:332
virtual const SparseMatrix * GetRestrictionMatrix() const
The returned SparseMatrix is owned by the FiniteElementSpace.
Definition fespace.hpp:714
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:3650
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:284
bool Nonconforming() const
Definition fespace.hpp:650
void GetVertexVDofs(int i, Array< int > &vdofs) const
Returns the indices of the degrees of freedom for the specified vertices.
Definition fespace.cpp:338
int GetNEDofs() const
Number of all scalar edge-interior dofs.
Definition fespace.hpp:859
int GetAttribute(int i) const
Definition fespace.hpp:915
int GetNDofs() const
Returns number of degrees of freedom. This is the number of Local Degrees of Freedom.
Definition fespace.hpp:821
int GetNBE() const
Returns number of boundary elements in the mesh.
Definition fespace.hpp:876
const NURBSExtension * GetNURBSext() const
Definition fespace.hpp:641
virtual const Operator * GetProlongationMatrix() const
Definition fespace.hpp:691
const QuadratureInterpolator * GetQuadratureInterpolator(const IntegrationRule &ir) const
Return a QuadratureInterpolator that interpolates E-vectors to quadrature point values and/or derivat...
Definition fespace.cpp:1588
int GetBdrAttribute(int i) const
Definition fespace.hpp:917
int GetLocalDofForDof(int i) const
Return the dof index within the element from GetElementForDof() for ldof index i.
Definition fespace.hpp:1301
int GetElementForDof(int i) const
Return the index of the first element that contains ldof index i.
Definition fespace.hpp:1298
const FiniteElement * GetTypicalBE() const
Return a "typical" boundary element.
Definition fespace.cpp:3939
int GetNF() const
Returns number of faces (i.e. co-dimension 1 entities) in the mesh.
Definition fespace.hpp:873
FiniteElementCollection * Load(Mesh *m, std::istream &input)
Read a FiniteElementSpace from a stream. The returned FiniteElementCollection is owned by the caller.
Definition fespace.cpp:4734
DofTransformation * GetElementVDofs(int i, Array< int > &vdofs) const
Returns indices of degrees of freedom for the i'th element. The returned indices are offsets into an ...
Definition fespace.cpp:299
virtual const FiniteElement * GetFE(int i) const
Returns pointer to the FiniteElement in the FiniteElementCollection associated with i'th element in t...
Definition fespace.cpp:3860
Ordering::Type GetOrdering() const
Return the ordering method.
Definition fespace.hpp:852
ElementTransformation * GetBdrElementTransformation(int i) const
Returns ElementTransformation for the i-th boundary element.
Definition fespace.hpp:912
bool LastUpdatePRef() const
Return a flag indicating whether the last update was for p-refinement.
Definition fespace.hpp:1584
int GetNE() const
Returns number of elements in the mesh.
Definition fespace.hpp:867
const ElementRestrictionOperator * GetElementRestriction(ElementDofOrdering e_ordering) const
Return an Operator that converts L-vectors to E-vectors.
Definition fespace.cpp:1476
const FiniteElement * GetEdgeElement(int i, int variant=0) const
Returns pointer to the FiniteElement in the FiniteElementCollection associated with i'th edge in the ...
Definition fespace.cpp:3984
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:3738
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:326
void GetElementVertices(int i, Array< int > &vertices) const
Returns the vertices of element i.
Definition fespace.hpp:892
const FiniteElement * GetTypicalTraceElement() const
Return a "typical" trace element.
Definition fespace.cpp:3999
int GetNFDofs() const
Number of all scalar face-interior dofs.
Definition fespace.hpp:861
int GetElementOrder(int i) const
Returns the order of the i'th finite element.
Definition fespace.cpp:195
const FiniteElement * GetFaceElement(int i) const
Returns pointer to the FiniteElement in the FiniteElementCollection associated with i'th face in the ...
Definition fespace.cpp:3949
std::shared_ptr< const PRefinementTransferOperator > GetPrefUpdateOperator()
Definition fespace.cpp:4479
const SparseMatrix * GetConformingProlongation() const
Definition fespace.cpp:1422
const FiniteElementCollection * FEColl() const
Definition fespace.hpp:854
Mesh * GetMesh() const
Returns the mesh.
Definition fespace.hpp:639
int GetNV() const
Returns number of vertices in the mesh.
Definition fespace.hpp:864
int GetVSize() const
Return the number of vector dofs, i.e. GetNDofs() x GetVDim().
Definition fespace.hpp:824
DofTransformation * GetBdrElementDofs(int bel, Array< int > &dofs) const
Returns indices of degrees of freedom for boundary element 'bel'. The returned indices are offsets in...
Definition fespace.cpp:3643
int GetVDim() const
Returns the vector dimension of the finite element space.
Definition fespace.hpp:817
const FiniteElement * GetTypicalFE() const
Return GetFE(0) if the local mesh is not empty; otherwise return a typical FE based on the Geometry t...
Definition fespace.cpp:3896
static int DecodeDof(int dof)
Helper to return the DOF associated with a sign encoded DOF.
Definition fespace.hpp:1153
virtual int GetMaxElementOrder() const
Return the maximum polynomial order over all elements.
Definition fespace.hpp:669
DofTransformation * GetBdrElementVDofs(int i, Array< int > &vdofs) const
Returns indices of degrees of freedom for i'th boundary element. The returned indices are offsets int...
Definition fespace.cpp:314
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:550
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:268
const Operator * GetUpdateOperator()
Get the GridFunction update operator.
Definition fespace.hpp:1552
Abstract class for all finite elements.
Definition fe_base.hpp:294
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:50
int GetRangeDim() const
Returns the vector dimension for vector-valued finite elements, which is also the dimension of the in...
Definition fe_base.hpp:387
int GetOrder() const
Returns the order of the finite element. In the case of anisotropic orders, returns the maximum order...
Definition fe_base.hpp:414
int GetDim() const
Returns the reference space dimension for the finite element.
Definition fe_base.hpp:381
virtual int GetPhysRangeDim(int) const
Returns the vector dimension, in physical space, for vector-valued finite elements,...
Definition fe_base.hpp:393
void CalcPhysHessian(ElementTransformation &Trans, DenseMatrix &Hessian) const
Evaluate the Hessian of all shape functions of a scalar finite element in physical space at the given...
Definition fe_base.cpp:296
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:160
int GetMapType() const
Returns the FiniteElement::MapType of the element describing how reference functions are mapped to ph...
Definition fe_base.hpp:436
int GetRangeType() const
Returns the FiniteElement::RangeType of the element, one of {SCALAR, VECTOR}.
Definition fe_base.hpp:427
const IntegrationRule & GetNodes() const
Get a const reference to the nodes of the element.
Definition fe_base.hpp:476
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...
Geometry::Type GetGeomType() const
Returns the Geometry::Type of the reference element.
Definition fe_base.hpp:407
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:62
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:136
void CalcPhysLaplacian(ElementTransformation &Trans, Vector &Laplacian) const
Evaluate the Laplacian of all shape functions of a scalar finite element in physical space at the giv...
Definition fe_base.cpp:213
void CalcPhysVShape(ElementTransformation &Trans, DenseMatrix &shape) const
Equivalent to the CalcVShape() method with the same arguments.
Definition fe_base.hpp:524
int GetCurlDim() const
Definition fe_base.hpp:398
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...
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:81
int GetDof() const
Returns the number of degrees of freedom in the finite element.
Definition fe_base.hpp:410
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:192
Gauss-Seidel smoother of a sparse matrix.
RefinedGeometry * Refine(Geometry::Type Geom, int Times, int ETimes=1)
Definition geom.cpp:1136
const IntegrationRule * GetVertices(int GeomType) const
Return an IntegrationRule consisting of all vertices of the given Geometry::Type, GeomType.
Definition geom.cpp:293
int NumBdr(int GeomType) const
Return the number of boundary "faces" of a given Geometry::Type.
Definition geom.hpp:133
Coefficient defined by a GridFunction. This coefficient is mesh dependent.
Class for grid function - Vector with associated FE space.
Definition gridfunc.hpp:53
void GetLaplacians(int i, const IntegrationRule &ir, Vector &laps, int vdim=1) const
Definition gridfunc.cpp:542
void AccumulateAndCountBdrTangentValues(VectorCoefficient &vcoeff, const Array< int > &bdr_attr, Array< int > &values_counter)
void ProjectVectorFieldOn(GridFunction &vec_field, int comp=0)
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...
virtual real_t GetValue(int i, const IntegrationPoint &ip, int vdim=1) const
Definition gridfunc.cpp:429
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....
virtual real_t ComputeDGFaceJumpError(Coefficient *exsol, Coefficient *ell_coeff, class JumpScaling jump_scaling, const IntegrationRule *irs[]=NULL) const
Returns the Face Jumps error for L2 elements.
void GetValues(int i, const IntegrationRule &ir, Vector &vals, int vdim=1) const
Definition gridfunc.cpp:497
virtual real_t ComputeHCurlError(VectorCoefficient *exsol, VectorCoefficient *excurl, const IntegrationRule *irs[]=NULL) const
Returns the error measured in H(curl)-norm for ND elements.
void UpdatePRef()
P-refinement version of Update().
Definition gridfunc.cpp:207
virtual real_t ComputeH1Error(Coefficient *exsol, VectorCoefficient *exgrad, Coefficient *ell_coef, real_t Nu, int norm_type) const
void GetGradients(ElementTransformation &tr, const IntegrationRule &ir, DenseMatrix &grad) const
Extension of GetGradient(...) for a collection of IntegrationPoints.
virtual void ProjectCoefficientGlobalL2(Coefficient &coeff, real_t rtol=1e-12, int iter=1000)
Project coeff Coefficient to this GridFunction. The projection is a global L2 projection....
void AccumulateAndCountBdrValues(Coefficient *coeff[], VectorCoefficient *vcoeff, const Array< int > &attr, Array< int > &values_counter)
void GetDerivative(int comp, int der_comp, GridFunction &der) const
Compute a certain derivative of a function's component. Derivatives of the function are computed at t...
void GetVectorGradient(ElementTransformation &tr, DenseMatrix &grad) const
Compute the vector gradient with respect to the physical element variable.
virtual real_t ComputeMaxError(Coefficient &exsol, const IntegrationRule *irs[]=NULL) const
Returns Max|u_ex - u_h| error for H1 or L2 elements.
virtual void Update()
Transform by the Space UpdateMatrix (e.g., on Mesh change).
Definition gridfunc.cpp:169
virtual PLBound GetBounds(Vector &lower, Vector &upper, const int ref_factor=1, const int vdim=-1) const
virtual void MakeRef(FiniteElementSpace *f, real_t *v)
Make the GridFunction reference external data on a new FiniteElementSpace.
Definition gridfunc.cpp:235
void ImposeBounds(int i, const Vector &weights, const Vector &lo_, const Vector &hi_)
void SetTrueVector()
Shortcut for calling GetTrueDofs() with GetTrueVector() as argument.
Definition gridfunc.hpp:187
virtual void Save(std::ostream &out) const
Save the GridFunction to an output stream.
virtual real_t ComputeL2Error(Coefficient *exsol[], const IntegrationRule *irs[]=NULL, const Array< int > *elems=NULL) const
Returns ||exsol - u_h||_L2 for scalar or vector H1 or L2 elements.
void MakeTRef(FiniteElementSpace *f, real_t *tv)
Associate a new FiniteElementSpace and new true-dof data with the GridFunction.
Definition gridfunc.cpp:253
void GetVectorFieldValues(int i, const IntegrationRule &ir, DenseMatrix &vals, DenseMatrix &tr, int comp=0) const
virtual void ProjectBdrCoefficientTangent(VectorCoefficient &vcoeff, const Array< int > &bdr_attr)
Project the tangential components of the given VectorCoefficient on the boundary.
PLBound GetElementBounds(Vector &lower, Vector &upper, const int ref_factor=1, const int vdim=-1) const
void GetElementAverages(GridFunction &avgs) const
virtual real_t 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.
void MakeOwner(FiniteElementCollection *fec_)
Make the GridFunction the owner of fec_owned and fes.
Definition gridfunc.hpp:160
void ProjectTraceCoefficientNormal(VectorCoefficient &vcoeff)
Project a VectorCoefficient on a GridFunction defined on an RT trace space.
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...
virtual void ComputeElementLpErrors(const real_t p, Coefficient &exsol, Vector &error, Coefficient *weight=NULL, const IntegrationRule *irs[]=NULL) const
Returns ||u_ex - u_h||_Lp elementwise for H1 or L2 elements.
virtual void SetFromTrueDofs(const Vector &tv)
Set the GridFunction from the given true-dof vector.
Definition gridfunc.cpp:363
virtual void GetElementDofValues(int el, Vector &dof_vals) const
virtual void ProjectDiscCoefficient(std::variant< Coefficient *, VectorCoefficient * > coeff, Array< int > &dof_attr)
Project a discontinuous (vector) coefficient as a grid function on a continuous finite element space....
virtual real_t ComputeLpError(const real_t p, Coefficient &exsol, Coefficient *weight=NULL, const IntegrationRule *irs[]=NULL, const Array< int > *elems=NULL) const
Returns ||u_ex - u_h||_Lp for H1 or L2 elements.
FiniteElementSpace * FESpace()
void SaveSTLTri(std::ostream &out, real_t p1[], real_t p2[], real_t p3[])
void AccumulateAndCountTraceValues(Coefficient *coeff[], VectorCoefficient *vcoeff, Array< int > &values_counter)
std::pair< real_t, real_t > EstimateFunctionMinimum(const int elem, const PLBound &plb, const int vdim, const int max_depth, const real_t tol, real_t &min_threshold) const
Estimate the minimum value of the GridFunction in element elem if it is below a certain min_threshold...
void ComputeMeans(AvgType type, const Array< int > &zones_per_vdof)
int GetFaceVectorValues(int i, int side, const IntegrationRule &ir, DenseMatrix &vals, DenseMatrix &tr) const
std::pair< real_t, real_t > EstimateFunctionMaximum(const int elem, const PLBound &plb, const int vdim, const int max_depth, const real_t tol, real_t &max_threshold) const
Estimate the maximum value of the GridFunction in element elem if it is above a certain max_threshold...
void ProjectTraceCoefficient(Coefficient *coeff[])
Project a Coefficient on a GridFunction defined on H1 trace space.
void GetValuesFrom(const GridFunction &orig_func)
void SaveVTKHDF(const std::string &fname, const std::string &name="u", bool high_order=true, int ref=-1)
Save the GridFunction in VTKHDF format.
void LegacyNCReorder()
Loading helper.
void ProjectDeltaCoefficient(DeltaCoefficient &delta_coeff, real_t &integral)
virtual void ComputeFlux(BilinearFormIntegrator &blfi, GridFunction &flux, bool wcoef=true, int subdomain=-1)
Definition gridfunc.cpp:333
virtual void ProjectCoefficientElementL2(Coefficient &coeff)
Project coeff Coefficient to this GridFunction. The projection is an element local L2 projection,...
FiniteElementSpace * fes
FE space on which the grid function lives. Owned if fec_owned is not NULL.
Definition gridfunc.hpp:56
virtual real_t ComputeCurlError(VectorCoefficient *excurl, const IntegrationRule *irs[]=NULL) const
Returns ||curl u_ex - curl u_h||_L2 for ND elements.
void GetBdrValuesFrom(const GridFunction &orig_func)
virtual real_t ComputeHDivError(VectorCoefficient *exsol, Coefficient *exdiv, const IntegrationRule *irs[]=NULL) const
Returns the error measured in H(div)-norm for RT elements.
int VectorDim() const
Shortcut for calling FiniteElementSpace::GetVectorDim() on the underlying fes.
Definition gridfunc.hpp:166
virtual real_t ComputeW11Error(Coefficient *exsol, VectorCoefficient *exgrad, int norm_type, const Array< int > *elems=NULL, const IntegrationRule *irs[]=NULL) const
Returns norm (or portions thereof) for H1 or L2 elements.
void AccumulateAndCountTraceTangentValues(VectorCoefficient &vcoeff, Array< int > &values_counter)
std::unique_ptr< GridFunction > ProlongateToMaxOrder() const
Return a GridFunction with the values of this, prolongated to the maximum order of all elements in th...
int GetFaceValues(int i, int side, const IntegrationRule &ir, Vector &vals, DenseMatrix &tr, int vdim=1) const
Definition gridfunc.cpp:637
FiniteElementCollection * fec_owned
Used when the grid function is read from a file. It can also be set explicitly, see MakeOwner().
Definition gridfunc.hpp:62
int CurlDim() const
Shortcut for calling FiniteElementSpace::GetCurlDim() on the underlying fes.
Definition gridfunc.hpp:170
void ProjectTraceCoefficientTangent(VectorCoefficient &vcoeff)
Project a VectorCoefficient on a GridFunction defined on an ND trace space.
void SumFluxAndCount(BilinearFormIntegrator &blfi, GridFunction &flux, Array< int > &counts, bool wcoef, int subdomain)
Definition gridfunc.cpp:283
GridFunction & operator=(const GridFunction &rhs)
Copy assignment. Only the data of the base class Vector is copied.
Definition gridfunc.hpp:154
virtual real_t ComputeDivError(Coefficient *exdiv, const IntegrationRule *irs[]=NULL) const
Returns ||div u_ex - div u_h||_L2 for RT elements.
void ProjectBdrCoefficientNormal(Coefficient *coeff, VectorCoefficient *vcoeff, const Array< int > &attr)
virtual void ProjectCoefficient(Coefficient &coeff, ProjectType type=ProjectType::DEFAULT)
Project coeff Coefficient to this GridFunction. The projection computation depends on the choice of t...
void GetElementBoundsAtControlPoints(const int elem, const PLBound &plb, Vector &lower, Vector &upper, const int vdim=-1) const
void GetTrueDofs(Vector &tv) const
Extract the true-dofs from the GridFunction.
Definition gridfunc.cpp:348
void AccumulateAndCountDerivativeValues(int comp, int der_comp, GridFunction &der, Array< int > &zones_per_dof) const
Used for the serial and parallel implementations of the GetDerivative() method; see its documentation...
void ProjectCoefficientElementL2_(Coefficient &coeff, Vector &sol, Vector &Va)
virtual real_t ComputeGradError(VectorCoefficient *exgrad, const IntegrationRule *irs[]=NULL) const
Returns ||grad u_ex - grad u_h||_L2 for H1 or L2 elements.
void GetNodalValues(int i, Array< real_t > &nval, int vdim=1) const
Returns the values at the vertices of element i for the 1-based dimension vdim.
Definition gridfunc.cpp:377
virtual void GetVectorValue(int i, const IntegrationPoint &ip, Vector &val) const
Definition gridfunc.cpp:454
real_t GetDivergence(ElementTransformation &tr) const
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 ...
void GetCurl(ElementTransformation &tr, Vector &curl) const
void GetGradient(ElementTransformation &tr, Vector &grad) const
Gradient of a scalar function at a quadrature point.
void GetVectorGradientHat(ElementTransformation &T, DenseMatrix &gh) const
Compute the vector gradient with respect to the reference element variable.
virtual void SetSpace(FiniteElementSpace *f)
Associate a new FiniteElementSpace with the GridFunction.
Definition gridfunc.cpp:227
void GetHessians(int i, const IntegrationRule &ir, DenseMatrix &hess, int vdim=1) const
Definition gridfunc.cpp:581
void GetVectorValues(int i, const IntegrationRule &ir, DenseMatrix &vals, DenseMatrix &tr) const
Definition gridfunc.cpp:687
void ProjectGridFunction(const GridFunction &src)
Project the src GridFunction to this GridFunction, both of which must be on the same mesh.
void GetVectorFieldNodalValues(Vector &val, int comp) const
void ProjectBdrCoefficient(Coefficient &coeff, const Array< int > &attr)
Project a Coefficient on the GridFunction, modifying only DOFs on the boundary associated with the bo...
Definition gridfunc.hpp:672
void ReorderByNodes()
For a vector grid function, makes sure that the ordering is byNODES.
Arbitrary order H1-conforming (continuous) finite elements.
Definition fe_coll.hpp:291
Arbitrary order H1 elements in 3D on a cube.
Definition fe_h1.hpp:64
Arbitrary order H1 elements in 2D on a square.
Definition fe_h1.hpp:43
Arbitrary order H1 elements in 1D.
Definition fe_h1.hpp:23
void Transform(const IntegrationPoint &, IntegrationPoint &)
Definition eltrans.cpp:587
Class for integration point with weight.
Definition intrules.hpp:35
void Get(real_t *p, const int dim) const
Definition intrules.hpp:82
void Set1w(const real_t x1, const real_t w)
Definition intrules.hpp:50
void Set(const real_t x1, const real_t x2, const real_t x3, const real_t w)
Definition intrules.hpp:68
Class for an integration rule - an Array of IntegrationPoint.
Definition intrules.hpp:96
int GetNPoints() const
Returns the number of the points in the integration rule.
Definition intrules.hpp:255
IntegrationPoint & IntPoint(int i)
Returns a reference to the i-th integration point.
Definition intrules.hpp:258
const IntegrationRule & Get(int GeomType, int Order)
Returns an integration rule for given GeomType and Order.
A standard isoparametric element transformation.
Definition eltrans.hpp:629
void Transform(const IntegrationPoint &, Vector &) override
Transform integration point from reference coordinates to physical coordinates and store them in the ...
Definition eltrans.cpp:532
void SetRelTol(real_t rtol)
Definition solvers.hpp:238
virtual void SetPrintLevel(int print_lvl)
Legacy method to set the level of verbosity of the solver output.
Definition solvers.cpp:76
void SetMaxIter(int max_it)
Definition solvers.hpp:240
void SetAbsTol(real_t atol)
Definition solvers.hpp:239
real_t Eval(real_t h, int p) const
Arbitrary order "L2-conforming" discontinuous finite elements.
Definition fe_coll.hpp:369
const FiniteElement * FiniteElementForGeometry(Geometry::Type GeomType) const override
Definition fe_coll.cpp:2485
Arbitrary order L2 elements in 3D on a cube.
Definition fe_l2.hpp:80
Arbitrary order L2 elements in 2D on a square.
Definition fe_l2.hpp:46
Arbitrary order L2 elements in 1D on a segment.
Definition fe_l2.hpp:23
bool Factor(int m, real_t TOL=0.0) override
Compute the LU factorization of the current matrix.
void Solve(int m, int n, real_t *X) const override
Piecewise-(bi/tri)linear continuous finite elements.
Definition fe_coll.hpp:911
Vector with associated FE space and LinearFormIntegrators.
void AssembleElementMatrix(const FiniteElement &el, ElementTransformation &Trans, DenseMatrix &elmat) override
void AssembleElementMatrix2(const FiniteElement &trial_fe, const FiniteElement &test_fe, ElementTransformation &Trans, DenseMatrix &elmat) override
Mesh data type.
Definition mesh.hpp:67
int GetNEdges() const
Return the number of edges.
Definition mesh.hpp:1396
void GetBdrElementFace(int i, int *f, int *o) const
Definition mesh.cpp:8369
virtual FaceElementTransformations * GetFaceElementTransformations(int FaceNo, int mask=31)
Definition mesh.cpp:1179
NURBSExtension * NURBSext
Optional NURBS mesh extension.
Definition mesh.hpp:317
int GetNumFaces() const
Return the number of faces (3D), edges (2D) or vertices (1D).
Definition mesh.cpp:7302
Geometry::Type GetElementGeometry(int i) const
Definition mesh.hpp:1548
void GetElementVertices(int i, Array< int > &v) const
Returns the indices of the vertices of element i.
Definition mesh.hpp:1622
bool Nonconforming() const
Definition mesh.hpp:2539
ElementTransformation * GetFaceTransformation(int FaceNo)
Returns a pointer to the transformation defining the given face element.
Definition mesh.cpp:610
int GetNE() const
Returns number of elements.
Definition mesh.hpp:1390
int Dimension() const
Dimension of the reference space used within the elements.
Definition mesh.hpp:1314
ElementTransformation * GetTypicalElementTransformation()
If the local mesh is not empty return GetElementTransformation(0); otherwise, return the identity tra...
Definition mesh.cpp:394
real_t GetElementSize(int i, int type=0)
Get the size of the i-th element relative to the perfect reference element.
Definition mesh.cpp:111
void GetElementTransformation(int i, IsoparametricTransformation *ElTr) const
Builds the transformation defining the i-th element in ElTr. ElTr must be allocated in advance and wi...
Definition mesh.cpp:361
void GetFaceElements(int Face, int *Elem1, int *Elem2) const
Return the indices of the elements sharing face Face.
Definition mesh.cpp:1632
bool FaceIsInterior(int FaceNo) const
Return true if the given face is interior.
Definition mesh.hpp:1576
int SpaceDimension() const
Dimension of the physical space containing the mesh.
Definition mesh.hpp:1317
const GeometricFactors * GetGeometricFactors(const IntegrationRule &ir, const int flags, MemoryType d_mt=MemoryType::DEFAULT)
Return the mesh geometric factors corresponding to the given integration rule.
Definition mesh.cpp:958
FaceElementTransformations * GetBdrFaceTransformations(int BdrElemNo)
Builds the transformation defining the given boundary face.
Definition mesh.cpp:1298
int GetNV() const
Returns number of vertices. Vertices are only at the corners of elements, where you would expect them...
Definition mesh.hpp:1387
void GetEdgeVertices(int i, Array< int > &vert) const
Returns the indices of the vertices of edge i.
Definition mesh.cpp:8139
static IntegrationPoint TransformBdrElementToFace(Geometry::Type geom, int o, const IntegrationPoint &ip)
For the vertex (1D), edge (2D), or face (3D) of a boundary element with the orientation o,...
Definition mesh.cpp:7909
void GetEdgeTransformation(int i, IsoparametricTransformation *EdTr) const
Builds the transformation defining the i-th edge element in EdTr. EdTr must be allocated in advance a...
Definition mesh.cpp:616
NCMesh * ncmesh
Optional nonconforming mesh extension.
Definition mesh.hpp:318
int GetNumGeometries(int dim) const
Return the number of geometries of the given dimension present in the mesh.
Definition mesh.cpp:8014
Geometry::Type GetElementBaseGeometry(int i) const
Definition mesh.hpp:1569
Array< int > attributes
A list of all unique element attributes used by the Mesh.
Definition mesh.hpp:307
const real_t * GetVertex(int i) const
Return pointer to vertex i's coordinates.
Definition mesh.hpp:1429
A class for non-conforming AMR. The class is not used directly by the user, rather it is an extension...
Definition ncmesh.hpp:190
bool IsLegacyLoaded() const
I/O: Return true if the mesh was loaded from the legacy v1.1 format.
Definition ncmesh.hpp:534
virtual void GetBoundaryClosure(const Array< int > &bdr_attr_is_ess, Array< int > &bdr_vertices, Array< int > &bdr_edges, Array< int > &bdr_faces)
Get a list of vertices (2D/3D), edges (3D) and faces (3D) that coincide with boundary elements with t...
Definition ncmesh.cpp:5827
void LegacyToNewVertexOrdering(Array< int > &order) const
I/O: Return a map from old (v1.1) vertex indices to new vertex indices.
Definition ncmesh.cpp:6939
void PrintSolution(const GridFunction &sol, std::ostream &os) const
Write a GridFunction sol patch-by-patch to stream os.
Definition nurbs.cpp:5130
void MergeGridFunctions(GridFunction *gf_array[], int num_pieces, GridFunction &merged)
Set the DOFs of merged to values from active elements in num_pieces of Gridfunctions gf_array.
Definition nurbs.cpp:3677
void LoadSolution(std::istream &input, GridFunction &sol) const
Read a GridFunction sol from stream input, written patch-by-patch, e.g. with PrintSolution().
Definition nurbs.cpp:5093
Abstract operator.
Definition operator.hpp:27
int Height() const
Get the height (size of output) of the Operator. Synonym with NumRows().
Definition operator.hpp:68
virtual void Mult(const Vector &x, Vector &y) const =0
Operator application: y=A(x).
int Width() const
Get the width (size of input) of the Operator. Synonym with NumCols().
Definition operator.hpp:74
const Vector & GetControlPoints() const
Get 1D control point locations (lexicographic order) in [0,1].
Definition bounds.hpp:141
void GetNDBounds(const int rdim, const Vector &coeff, Vector &intmin, Vector &intmax) const
Compute piecewise linear bounds for the lexicographically-ordered nodal coefficients in coeff in 1D/2...
Definition bounds.cpp:636
int GetNControlPoints() const
Get number of control points used to compute the bounds.
Definition bounds.hpp:138
Matrix-free transfer operator between finite element spaces on the same mesh.
Definition transfer.hpp:636
void Mult(const Vector &x, Vector &y) const override
Interpolation or prolongation of a vector x corresponding to the coarse space to the vector y corresp...
Abstract parallel finite element space.
Definition pfespace.hpp:31
static void CalcLegendre(const int p, const real_t x, real_t *u)
Definition fe_base.cpp:2343
Piecewise-(bi)quadratic continuous finite elements.
Definition fe_coll.hpp:939
A class that performs interpolation from an E-vector to quadrature point values and/or derivatives (Q...
void SetOutputLayout(QVectorLayout layout) const
Set the desired output Q-vector layout. The default value is QVectorLayout::byNODES.
void DisableTensorProducts(bool disable=true) const
Disable the use of tensor product evaluations, for tensor-product elements, e.g. quads and hexes....
void PhysDerivatives(const Vector &e_vec, Vector &q_der) const
Interpolate the derivatives in physical space of the E-vector e_vec at quadrature points.
IntegrationRule RefPts
Definition geom.hpp:321
Array< int > RefGeoms
Definition geom.hpp:322
void Mult(const Vector &xt, Vector &x) const override
Definition solvers.cpp:2649
void SetBounds(const Vector &lo_, const Vector &hi_)
Definition solvers.cpp:2628
void SetLinearConstraint(const Vector &w_, real_t a_)
Definition solvers.cpp:2634
Data type sparse matrix.
Definition sparsemat.hpp:51
void Mult(const Vector &x, Vector &y) const override
Matrix vector multiplication.
const Array< int > & GetDofMap() const
Get an Array<int> that maps lexicographically ordered indices to the indices of the respective nodes/...
Definition fe_base.hpp:1353
Low-level class for writing VTKHDF data (for use in ParaView).
Definition vtkhdf.hpp:37
void SaveGridFunction(const GridFunction &gf, const std::string &name)
Save the grid function with the given name, appending as a new time step.
Definition vtkhdf.cpp:753
void SaveMesh(const Mesh &mesh, bool high_order=true, int ref=-1)
Save the mesh, appending as a new time step.
Definition vtkhdf.cpp:534
Base class for vector Coefficients that optionally depend on time and space.
int GetVDim()
Returns dimension of the vector.
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 ...
Scalar coefficient defined as component of a vector coefficient.
void SetComponent(int c)
Set the component.
Class used for extruding a vector coefficient.
void Eval(Vector &v, ElementTransformation &T, const IntegrationPoint &ip) override
Evaluate the vector coefficient in the element described by T at the point ip, storing the result in ...
for VectorFiniteElements (Nedelec, Raviart-Thomas)
Definition lininteg.hpp:365
A general vector function coefficient.
Vector coefficient defined by a vector GridFunction.
Vector data type.
Definition vector.hpp:82
void Print(std::ostream &out=mfem::out, int width=8) const
Prints vector to stream out.
Definition vector.cpp:870
void SetDataAndSize(real_t *d, int s)
Set the Vector data and size.
Definition vector.hpp:191
real_t Norml1() const
Returns the l_1 norm of the vector.
Definition vector.cpp:1018
void SetSubVector(const Array< int > &dofs, const real_t value)
Set the entries listed in dofs to the given value.
Definition vector.cpp:702
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:785
Memory< real_t > data
Definition vector.hpp:85
void Swap(Vector &other)
Swap the contents of two Vectors.
Definition vector.hpp:746
real_t Norml2() const
Returns the l2 norm of the vector.
Definition vector.cpp:968
void Load(std::istream **in, int np, int *dim)
Reads a vector from multiple files.
Definition vector.cpp:127
void NewMemoryAndSize(const Memory< real_t > &mem, int s, bool own_mem)
Reset the Vector to use the given external Memory mem and size s.
Definition vector.hpp:694
real_t Max() const
Returns the maximal element of the vector.
Definition vector.cpp:1200
virtual bool UseDevice() const
Return the device flag of the Memory object used by the Vector.
Definition vector.hpp:148
int Size() const
Returns the size of the vector.
Definition vector.hpp:234
virtual void UseDevice(bool use_dev) const
Enable execution of Vector operations using the mfem::Device.
Definition vector.hpp:145
real_t Sum() const
Return the sum of the vector entries.
Definition vector.cpp:1246
void SetSize(int s)
Resize the vector to size s.
Definition vector.hpp:633
virtual real_t * HostWrite()
Shortcut for mfem::Write(vec.GetMemory(), vec.Size(), false).
Definition vector.hpp:532
void NewDataAndSize(real_t *d, int s)
Set the Vector data and size, deleting the old data, if owned.
Definition vector.hpp:197
real_t * GetData() const
Return a pointer to the beginning of the Vector data.
Definition vector.hpp:243
Vector & operator=(const real_t *v)
Copy Size() entries from v.
Definition vector.cpp:197
virtual real_t * HostReadWrite()
Shortcut for mfem::ReadWrite(vec.GetMemory(), vec.Size(), false).
Definition vector.hpp:540
real_t Min() const
Returns the minimal element of the vector.
Definition vector.cpp:1154
void GetSubVector(const Array< int > &dofs, Vector &elemvect) const
Extract entries listed in dofs to the output Vector elemvect.
Definition vector.cpp:676
Vector & Add(const real_t a, const Vector &Va)
(*this) += a * Va
Definition vector.cpp:326
void MakeRef(Vector &base, int offset, int size)
Reset the Vector to be a reference to a sub-vector of base.
Definition vector.hpp:709
void Save(const GridFunction &grid_function, const std::string &variable_name, const data_type type)
int dim
Definition ex24.cpp:53
real_t b
Definition lissajous.cpp:42
real_t a
Definition lissajous.cpp:41
real_t weight(const Vector &x)
mfem::real_t real_t
std::ostream & operator<<(std::ostream &os, SparseMatrix const &mat)
ProjectType
This enumerated type describes the main projection types used by GridFunction::ProjectCoefficient():
Definition gridfunc.hpp:49
void CalcOrtho(const DenseMatrix &J, Vector &n)
void TensorProductLegendre(int dim, int order, const Vector &x_in, const Vector &xmax, const Vector &xmin, Vector &poly, real_t angle, const Vector *midpoint)
Defines the global tensor product polynomial space used by NewZZErorrEstimator.
GridFunction * Extrude1DGridFunction(Mesh *mesh, Mesh *mesh2d, GridFunction *sol, const int ny)
Extrude a 1D GridFunction, after extruding the mesh with Extrude1D()
real_t u(const Vector &xvec)
Definition lor_mms.hpp:22
void Mult(const Table &A, const Table &B, Table &C)
C = A * B (as boolean matrices)
Definition table.cpp:505
GeometryRefiner GlobGeometryRefiner
Definition geom.cpp:2014
void AddMultVVt(const Vector &v, DenseMatrix &VVt)
VVt += v v^t.
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
Geometry Geometries
Definition fe.cpp:49
real_t Distance(const real_t *x, const real_t *y, const int n)
Definition vector.hpp:776
void CalcInverse(const DenseMatrix &a, DenseMatrix &inva)
void AddMult_a_VVt(const real_t a, const Vector &v, DenseMatrix &VVt)
VVt += a * v v^t.
real_t ZZErrorEstimator(BilinearFormIntegrator &blfi, GridFunction &u, GridFunction &flux, Vector &error_estimates, Array< int > *aniso_flags, int with_subdomains, bool with_coeff)
bool IsIdentityProlongation(const Operator *P)
Definition operator.hpp:892
real_t LSZZErrorEstimator(BilinearFormIntegrator &blfi, GridFunction &u, Vector &error_estimates, bool subdomain_reconstruction, bool with_coeff, real_t tichonov_coeff)
A `‘true’' ZZ error estimator that uses face-based patches for flux reconstruction.
void BoundingBox(const Array< int > &patch, FiniteElementSpace *ufes, int order, Vector &xmin, Vector &xmax, real_t &angle, Vector &midpoint, int iface)
Defines the bounding box for the face patches used by NewZZErorrEstimator.
void MultVVt(const Vector &v, DenseMatrix &vvt)
Make a matrix from a vector V.Vt.
bool LinearSolve(DenseMatrix &A, real_t *X, real_t TOL)
Solves the dense linear system, A * X = B for X
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
void AddMult_a_AAt(real_t a, const DenseMatrix &A, DenseMatrix &AAt)
AAt += a * A * A^t.
void filter_dos(std::string &line)
Check for, and remove, a trailing '\r' from and std::string.
Definition text.hpp:45
bool UsesTensorBasis(const FiniteElementSpace &fes)
Return true if the mesh contains only one topology and the elements are tensor elements.
Definition fespace.hpp:1644
void MultAAt(const DenseMatrix &a, DenseMatrix &aat)
Calculate the matrix A.At.
real_t ComputeElementLpDistance(real_t p, int i, GridFunction &gf1, GridFunction &gf2)
Compute the Lp distance between two grid functions on the given element.
QVectorLayout
Type describing possible layouts for Q-vectors.
Definition fespace.hpp:33
ComplexDenseMatrix * MultAtB(const ComplexDenseMatrix &A, const ComplexDenseMatrix &B)
Multiply the complex conjugate transpose of a matrix A with a matrix B. A^H*B.
float real_t
Definition config.hpp:46
MemoryType
Memory types supported by MFEM.
Poly_1D poly1d
Definition fe.cpp:28
ElementDofOrdering
Constants describing the possible orderings of the DOFs in one element.
Definition fespace.hpp:49
@ NATIVE
Native ordering as defined by the FiniteElement.
std::function< real_t(const Vector &)> f(real_t mass_coeff)
Definition lor_mms.hpp:30
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
constexpr real_t infinity()
Define a shortcut for std::numeric_limits<double>::infinity()
Definition vector.hpp:47
IntegrationRules IntRules(0, Quadrature1D::GaussLegendre)
A global object with all integration rules (defined in intrules.cpp)
Definition intrules.hpp:549
STL namespace.
real_t p(const Vector &x, real_t t)
real_t sol(const Vector &x)
void Project(GridFunction &gf, CoefficientType &coef, int proj_type)
MFEM_HOST_DEVICE real_t norm(const Complex &z)
void rotate(real_t *x)
Definition snake.cpp:316
Helper struct to convert a C++ type to an MPI type.
void pts(int iphi, int t, real_t x[])