MFEM v4.9.0
Finite element discretization library
Loading...
Searching...
No Matches
fe_base.cpp
Go to the documentation of this file.
1// Copyright (c) 2010-2025, 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// Finite Element Base classes
13
14#include "fe_base.hpp"
15#include "face_map_utils.hpp"
16#include "../coefficient.hpp"
17
18namespace mfem
19{
20
21using namespace std;
22
24{
25 DofToQuad d2q(*this);
26 d2q.B.Abs();
27 d2q.Bt.Abs();
28 d2q.G.Abs();
29 d2q.Gt.Abs();
30 return d2q;
31}
32
34 int Do, int O, int F)
35 : Nodes(Do)
36{
37 dim = D ; geom_type = G ; dof = Do ; order = O ; func_space = F;
38 vdim = 0 ; cdim = 0;
44 for (int i = 0; i < Geometry::MaxDim; i++) { orders[i] = -1; }
45#ifndef MFEM_THREAD_SAFE
47#endif
48}
49
51 const IntegrationPoint &ip, DenseMatrix &shape) const
52{
53 MFEM_ABORT("method is not implemented for this class");
54}
55
57 ElementTransformation &Trans, DenseMatrix &shape) const
58{
59 MFEM_ABORT("method is not implemented for this class");
60}
61
63 const IntegrationPoint &ip, Vector &divshape) const
64{
65 MFEM_ABORT("method is not implemented for this class");
66}
67
69 ElementTransformation &Trans, Vector &div_shape) const
70{
71 CalcDivShape(Trans.GetIntPoint(), div_shape);
72 div_shape *= (1.0 / Trans.Weight());
73}
74
76 DenseMatrix &curl_shape) const
77{
78 MFEM_ABORT("method is not implemented for this class");
79}
80
82 DenseMatrix &curl_shape) const
83{
84 switch (dim)
85 {
86 case 3:
87 {
88#ifdef MFEM_THREAD_SAFE
90#endif
92 MultABt(vshape, Trans.Jacobian(), curl_shape);
93 curl_shape *= (1.0 / Trans.Weight());
94 break;
95 }
96 case 2:
97 // This is valid for both 2x2 and 3x2 Jacobians
98 CalcCurlShape(Trans.GetIntPoint(), curl_shape);
99 curl_shape *= (1.0 / Trans.Weight());
100 break;
101 default:
102 MFEM_ABORT("Invalid dimension, Dim = " << dim);
103 }
104}
105
106void FiniteElement::GetFaceDofs(int face, int **dofs, int *ndofs) const
107{
108 MFEM_ABORT("method is not overloaded");
109}
110
112 DenseMatrix &h) const
113{
114 MFEM_ABORT("method is not overloaded");
115}
116
118 DenseMatrix &I) const
119{
120 MFEM_ABORT("method is not overloaded");
121}
122
124 DenseMatrix &) const
125{
126 MFEM_ABORT("method is not overloaded");
127}
128
131 DenseMatrix &I) const
132{
133 MFEM_ABORT("method is not overloaded");
134}
135
137 Coefficient &coeff, ElementTransformation &Trans, Vector &dofs) const
138{
139 MFEM_ABORT("method is not overloaded");
140}
141
143 VectorCoefficient &vc, ElementTransformation &Trans, Vector &dofs) const
144{
145 MFEM_ABORT("method is not overloaded");
146}
147
149 Vector &dofs) const
150{
151 mfem_error("FiniteElement::ProjectFromNodes() (vector) is not overloaded!");
152}
153
156{
157 MFEM_ABORT("method is not overloaded");
158}
159
160void FiniteElement::ProjectDelta(int vertex, Vector &dofs) const
161{
162 MFEM_ABORT("method is not implemented for this element");
163}
164
166 const FiniteElement &fe, ElementTransformation &Trans, DenseMatrix &I) const
167{
168 MFEM_ABORT("method is not implemented for this element");
169}
170
172 const FiniteElement &fe, ElementTransformation &Trans,
173 DenseMatrix &grad) const
174{
175 MFEM_ABORT("method is not implemented for this element");
176}
177
179 const FiniteElement &fe, ElementTransformation &Trans,
180 DenseMatrix &curl) const
181{
182 MFEM_ABORT("method is not implemented for this element");
183}
184
186 const FiniteElement &fe, ElementTransformation &Trans,
187 DenseMatrix &div) const
188{
189 MFEM_ABORT("method is not implemented for this element");
190}
191
193 Vector &shape) const
194{
195 CalcShape(Trans.GetIntPoint(), shape);
196 if (map_type == INTEGRAL)
197 {
198 shape /= Trans.Weight();
199 }
200}
201
203 DenseMatrix &dshape) const
204{
205 MFEM_ASSERT(map_type == VALUE, "");
206#ifdef MFEM_THREAD_SAFE
208#endif
209 CalcDShape(Trans.GetIntPoint(), vshape);
210 Mult(vshape, Trans.InverseJacobian(), dshape);
211}
212
214 Vector &Laplacian) const
215{
216 MFEM_ASSERT(map_type == VALUE, "");
217
218 // Simpler routine if mapping is affine
219 if (Trans.Hessian().FNorm2() < 1e-20)
220 {
221 CalcPhysLinLaplacian(Trans, Laplacian);
222 return;
223 }
224
225 // Compute full Hessian first if non-affine
226 int size = (dim*(dim+1))/2;
227 DenseMatrix hess(dof, size);
228 CalcPhysHessian(Trans,hess);
229
230 if (dim == 3)
231 {
232 for (int nd = 0; nd < dof; nd++)
233 {
234 Laplacian[nd] = hess(nd,0) + hess(nd,4) + hess(nd,5);
235 }
236 }
237 else if (dim == 2)
238 {
239 for (int nd = 0; nd < dof; nd++)
240 {
241 Laplacian[nd] = hess(nd,0) + hess(nd,2);
242 }
243 }
244 else
245 {
246 for (int nd = 0; nd < dof; nd++)
247 {
248 Laplacian[nd] = hess(nd,0);
249 }
250 }
251}
252
253// Assume a linear mapping
255 Vector &Laplacian) const
256{
257 MFEM_ASSERT(map_type == VALUE, "");
258 int size = (dim*(dim+1))/2;
259 DenseMatrix hess(dof, size);
260 DenseMatrix Gij(dim,dim);
261 Vector scale(size);
262
263 CalcHessian(Trans.GetIntPoint(), hess);
264 MultAAt(Trans.InverseJacobian(), Gij);
265
266 if (dim == 3)
267 {
268 scale[0] = Gij(0,0);
269 scale[1] = 2*Gij(0,1);
270 scale[2] = 2*Gij(0,2);
271
272 scale[3] = 2*Gij(1,2);
273 scale[4] = Gij(2,2);
274
275 scale[5] = Gij(1,1);
276 }
277 else if (dim == 2)
278 {
279 scale[0] = Gij(0,0);
280 scale[1] = 2*Gij(0,1);
281 scale[2] = Gij(1,1);
282 }
283 else
284 {
285 scale[0] = Gij(0,0);
286 }
287
288 for (int nd = 0; nd < dof; nd++)
289 {
290 Laplacian[nd] = 0.0;
291 for (int ii = 0; ii < size; ii++)
292 {
293 Laplacian[nd] += hess(nd,ii)*scale[ii];
294 }
295 }
296}
297
299 DenseMatrix& Hessian) const
300{
301 MFEM_ASSERT(map_type == VALUE, "");
302
303 // Roll 2-Tensors in vectors and 4-Tensor in Matrix, exploiting symmetry
304 Array<int> map(dim*dim);
305 if (dim == 3)
306 {
307 map[0] = 0;
308 map[1] = 1;
309 map[2] = 2;
310
311 map[3] = 1;
312 map[4] = 5;
313 map[5] = 3;
314
315 map[6] = 2;
316 map[7] = 3;
317 map[8] = 4;
318 }
319 else if (dim == 2)
320 {
321 map[0] = 0;
322 map[1] = 1;
323
324 map[2] = 1;
325 map[3] = 2;
326 }
327 else
328 {
329 map[0] = 0;
330 }
331
332 // Hessian in ref coords
333 int size = (dim*(dim+1))/2;
334 DenseMatrix hess(dof, size);
335 CalcHessian(Trans.GetIntPoint(), hess);
336
337 // Gradient in physical coords
338 if (Trans.Hessian().FNorm2() > 1e-10)
339 {
340 DenseMatrix grad(dof, dim);
341 CalcPhysDShape(Trans, grad);
342 DenseMatrix gmap(dof, size);
343 Mult(grad,Trans.Hessian(),gmap);
344 hess -= gmap;
345 }
346
347 // LHM
348 DenseMatrix lhm(size,size);
349 DenseMatrix invJ = Trans.Jacobian();
350 lhm = 0.0;
351 for (int i = 0; i < dim; i++)
352 {
353 for (int j = 0; j < dim; j++)
354 {
355 for (int k = 0; k < dim; k++)
356 {
357 for (int l = 0; l < dim; l++)
358 {
359 lhm(map[i*dim+j],map[k*dim+l]) += invJ(i,k)*invJ(j,l);
360 }
361 }
362 }
363 }
364 // Correct multiplicity
365 Vector mult(size);
366 mult = 0.0;
367 for (int i = 0; i < dim*dim; i++) { mult[map[i]]++; }
368 lhm.InvRightScaling(mult);
369
370 // Hessian in physical coords
371 lhm.Invert();
372 Mult(hess, lhm, Hessian);
373}
374
376 DofToQuad::Mode mode) const
377{
378 DofToQuad *d2q = nullptr;
379 MFEM_VERIFY(mode == DofToQuad::FULL, "invalid mode requested");
380
381#if defined(MFEM_THREAD_SAFE) && defined(MFEM_USE_OPENMP)
382 #pragma omp critical (DofToQuad)
383#endif
384 {
385 for (int i = 0; i < dof2quad_array.Size(); i++)
386 {
387 d2q = dof2quad_array[i];
388 if (d2q->IntRule != &ir || d2q->mode != mode) { d2q = nullptr; }
389 }
390 if (!d2q)
391 {
392#ifdef MFEM_THREAD_SAFE
394#endif
395 d2q = new DofToQuad;
396 const int nqpt = ir.GetNPoints();
397 d2q->FE = this;
398 d2q->IntRule = &ir;
399 d2q->mode = mode;
400 d2q->ndof = dof;
401 d2q->nqpt = nqpt;
402 switch (range_type)
403 {
404 case SCALAR:
405 {
406 d2q->B.SetSize(nqpt*dof);
407 d2q->Bt.SetSize(dof*nqpt);
408
409 Vector shape;
410 vshape.GetColumnReference(0, shape);
411 for (int i = 0; i < nqpt; i++)
412 {
413 const IntegrationPoint &ip = ir.IntPoint(i);
414 CalcShape(ip, shape);
415 for (int j = 0; j < dof; j++)
416 {
417 d2q->B[i+nqpt*j] = d2q->Bt[j+dof*i] = shape(j);
418 }
419 }
420 break;
421 }
422 case VECTOR:
423 {
424 d2q->B.SetSize(nqpt*dim*dof);
425 d2q->Bt.SetSize(dof*nqpt*dim);
426
427 for (int i = 0; i < nqpt; i++)
428 {
429 const IntegrationPoint &ip = ir.IntPoint(i);
430 CalcVShape(ip, vshape);
431 for (int d = 0; d < dim; d++)
432 {
433 for (int j = 0; j < dof; j++)
434 {
435 d2q->B[i+nqpt*(d+dim*j)] =
436 d2q->Bt[j+dof*(i+nqpt*d)] = vshape(j, d);
438 }
439 }
440 break;
441 }
443 // Skip B and Bt for unknown range type
444 break;
445 }
446 switch (deriv_type)
447 {
448 case GRAD:
449 {
450 d2q->G.SetSize(nqpt*dim*dof);
451 d2q->Gt.SetSize(dof*nqpt*dim);
452
453 for (int i = 0; i < nqpt; i++)
454 {
455 const IntegrationPoint &ip = ir.IntPoint(i);
456 CalcDShape(ip, vshape);
457 for (int d = 0; d < dim; d++)
458 {
459 for (int j = 0; j < dof; j++)
460 {
461 d2q->G[i+nqpt*(d+dim*j)] =
462 d2q->Gt[j+dof*(i+nqpt*d)] = vshape(j, d);
463 }
464 }
465 }
466 break;
467 }
468 case DIV:
469 {
470 d2q->G.SetSize(nqpt*dof);
471 d2q->Gt.SetSize(dof*nqpt);
472
473 Vector divshape;
474 vshape.GetColumnReference(0, divshape);
475 for (int i = 0; i < nqpt; i++)
476 {
477 const IntegrationPoint &ip = ir.IntPoint(i);
478 CalcDivShape(ip, divshape);
479 for (int j = 0; j < dof; j++)
480 {
481 d2q->G[i+nqpt*j] = d2q->Gt[j+dof*i] = divshape(j);
482 }
483 }
484 break;
485 }
486 case CURL:
487 {
488 d2q->G.SetSize(nqpt*cdim*dof);
489 d2q->Gt.SetSize(dof*nqpt*cdim);
490
491 DenseMatrix curlshape(vshape.GetData(), dof, cdim); // cdim <= dim
492 for (int i = 0; i < nqpt; i++)
493 {
494 const IntegrationPoint &ip = ir.IntPoint(i);
495 CalcCurlShape(ip, curlshape);
496 for (int d = 0; d < cdim; d++)
497 {
498 for (int j = 0; j < dof; j++)
499 {
500 d2q->G[i+nqpt*(d+cdim*j)] =
501 d2q->Gt[j+dof*(i+nqpt*d)] = curlshape(j, d);
502 }
503 }
504 }
505 break;
506 }
507 case NONE:
508 // Skip G and Gt for unknown derivative type
509 break;
510 }
511 dof2quad_array.Append(d2q);
512 }
513 }
514 return *d2q;
515}
516
517void FiniteElement::GetFaceMap(const int face_id,
518 Array<int> &face_map) const
519{
520 MFEM_ABORT("method is not implemented for this element");
521}
522
524{
525 for (int i = 0; i < dof2quad_array.Size(); i++)
526 {
527 delete dof2quad_array[i];
528 }
529}
530
531
534 const ScalarFiniteElement &fine_fe) const
535{
537 Vector vv(v, dim);
538 IntegrationPoint f_ip;
539
540#ifdef MFEM_THREAD_SAFE
541 Vector shape(dof);
542#else
543 Vector shape;
544 vshape.GetColumnReference(0, shape);
545#endif
546
547 MFEM_ASSERT(map_type == fine_fe.GetMapType(), "");
548
549 I.SetSize(fine_fe.dof, dof);
550 for (int i = 0; i < fine_fe.dof; i++)
551 {
552 Trans.Transform(fine_fe.Nodes.IntPoint(i), vv);
553 f_ip.Set(v, dim);
554 CalcShape(f_ip, shape);
555 for (int j = 0; j < dof; j++)
556 {
557 if (fabs(I(i,j) = shape(j)) < 1.0e-12)
558 {
559 I(i,j) = 0.0;
560 }
561 }
562 }
563 if (map_type == INTEGRAL)
564 {
565 // assuming Trans is linear; this should be ok for all refinement types
567 I *= Trans.Weight();
568 }
569}
570
573 const ScalarFiniteElement &fine_fe) const
574{
575 // General "interpolation", defined by L2 projection
576
578 Vector vv(v, dim);
579 IntegrationPoint f_ip;
580
581 const int fs = fine_fe.GetDof(), cs = this->GetDof();
582 I.SetSize(fs, cs);
583 Vector fine_shape(fs), coarse_shape(cs);
584 DenseMatrix fine_mass(fs), fine_coarse_mass(fs, cs); // initialized with 0
585 const int ir_order =
586 std::max(GetOrder(), fine_fe.GetOrder()) + fine_fe.GetOrder();
587 const IntegrationRule &ir = IntRules.Get(fine_fe.GetGeomType(), ir_order);
588
589 for (int i = 0; i < ir.GetNPoints(); i++)
590 {
591 const IntegrationPoint &ip = ir.IntPoint(i);
592 fine_fe.CalcShape(ip, fine_shape);
593 Trans.Transform(ip, vv);
594 f_ip.Set(v, dim);
595 this->CalcShape(f_ip, coarse_shape);
596
597 AddMult_a_VVt(ip.weight, fine_shape, fine_mass);
598 AddMult_a_VWt(ip.weight, fine_shape, coarse_shape, fine_coarse_mass);
599 }
600
601 DenseMatrixInverse fine_mass_inv(fine_mass);
602 fine_mass_inv.Mult(fine_coarse_mass, I);
603
604 if (map_type == INTEGRAL)
605 {
606 // assuming Trans is linear; this should be ok for all refinement types
608 I *= Trans.Weight();
609 }
610}
611
614 const ScalarFiniteElement &coarse_fe) const
615{
616 // General "restriction", defined by L2 projection
618 Vector vv(v, dim);
619
620 const int cs = coarse_fe.GetDof(), fs = this->GetDof();
621 R.SetSize(cs, fs);
622 Vector fine_shape(fs), coarse_shape(cs);
623 DenseMatrix coarse_mass(cs), coarse_fine_mass(cs, fs); // initialized with 0
624 const int ir_order = GetOrder() + coarse_fe.GetOrder();
625 const IntegrationRule &ir = IntRules.Get(coarse_fe.GetGeomType(), ir_order);
626
627 // integrate coarse_mass in the coarse space
628 for (int i = 0; i < ir.GetNPoints(); i++)
629 {
630 const IntegrationPoint &c_ip = ir.IntPoint(i);
631 coarse_fe.CalcShape(c_ip, coarse_shape);
632 AddMult_a_VVt(c_ip.weight, coarse_shape, coarse_mass);
633 }
634
635 // integrate coarse_fine_mass in the fine space
637 for (int i = 0; i < ir.GetNPoints(); i++)
638 {
639 const IntegrationPoint &f_ip = ir.IntPoint(i);
640 this->CalcShape(f_ip, fine_shape);
641 Trans.Transform(f_ip, vv);
642
643 IntegrationPoint c_ip;
644 c_ip.Set(v, dim);
645 coarse_fe.CalcShape(c_ip, coarse_shape);
646 AddMult_a_VWt(f_ip.weight*Trans.Weight(), coarse_shape, fine_shape,
647 coarse_fine_mass);
648 }
649
650 DenseMatrixInverse coarse_mass_inv(coarse_mass);
651 coarse_mass_inv.Mult(coarse_fine_mass, R);
652
653 if (map_type == INTEGRAL)
654 {
655 // assuming Trans is linear; this should be ok for all refinement types
657 R *= 1.0 / Trans.Weight();
658 }
659}
660
661void NodalFiniteElement::CreateLexicographicFullMap(const IntegrationRule &ir)
662const
663{
664
665#if defined(MFEM_THREAD_SAFE) && defined(MFEM_USE_OPENMP)
666 #pragma omp critical (DofToQuad)
667#endif
668 {
669 // Get the FULL version of the map.
670 auto &d2q = GetDofToQuad(ir, DofToQuad::FULL);
671 //Undo the native ordering which is what FiniteElement::GetDofToQuad returns.
672 auto *d2q_new = new DofToQuad(d2q);
673 d2q_new->mode = DofToQuad::LEXICOGRAPHIC_FULL;
674 const int nqpt = ir.GetNPoints();
675
676 const int b_dim = (range_type == VECTOR) ? dim : 1;
677
678 for (int i = 0; i < nqpt; i++)
679 {
680 for (int d = 0; d < b_dim; d++)
681 {
682 for (int j = 0; j < dof; j++)
683 {
684 const double val = d2q.B[i + nqpt*(d+b_dim*lex_ordering[j])];
685 d2q_new->B[i+nqpt*(d+b_dim*j)] = val;
686 d2q_new->Bt[j+dof*(i+nqpt*d)] = val;
687 }
688 }
689 }
690
691 const int g_dim = [this]()
692 {
693 switch (deriv_type)
694 {
695 case GRAD: return dim;
696 case DIV: return 1;
697 case CURL: return cdim;
698 default: return 0;
699 }
700 }();
701
702 for (int i = 0; i < nqpt; i++)
703 {
704 for (int d = 0; d < g_dim; d++)
705 {
706 for (int j = 0; j < dof; j++)
707 {
708 const double val = d2q.G[i + nqpt*(d+g_dim*lex_ordering[j])];
709 d2q_new->G[i+nqpt*(d+g_dim*j)] = val;
710 d2q_new->Gt[j+dof*(i+nqpt*d)] = val;
711 }
712 }
713 }
714
715 dof2quad_array.Append(d2q_new);
716 }
717}
718
720 DofToQuad::Mode mode) const
721{
722 DofToQuad *d2q = nullptr;
723#if defined(MFEM_THREAD_SAFE) && defined(MFEM_USE_OPENMP)
724 #pragma omp critical (DofToQuad)
725#endif
726 {
727 //Should make this loop a function of FiniteElement
728 for (int i = 0; i < dof2quad_array.Size(); i++)
729 {
730 d2q = dof2quad_array[i];
731 if (d2q->IntRule == &ir && d2q->mode == mode) { break; }
732 d2q = nullptr;
733 }
734 }
735 if (d2q) { return *d2q; }
737 {
738 return FiniteElement::GetDofToQuad(ir, mode);
739 }
740 else
741 {
742 CreateLexicographicFullMap(ir);
743 return NodalFiniteElement::GetDofToQuad(ir, mode);
744 }
745}
746
748 const FiniteElement &fe, ElementTransformation &Trans,
749 DenseMatrix &curl) const
750{
751 DenseMatrix curl_shape(fe.GetDof(), 1);
752
753 curl.SetSize(dof, fe.GetDof());
754 for (int i = 0; i < dof; i++)
755 {
756 fe.CalcCurlShape(Nodes.IntPoint(i), curl_shape);
757
758 real_t w = 1.0;
760 {
761 Trans.SetIntPoint(&Nodes.IntPoint(i));
762 w /= Trans.Weight();
763 }
764 for (int j = 0; j < fe.GetDof(); j++)
765 {
766 curl(i,j) = w * curl_shape(j,0);
767 }
768 }
769}
770
772 const IntegrationPoint &pt, Vector &x)
773{
774 // invert a linear transform with one Newton step
776 p0.Set3(0, 0, 0);
777 trans.Transform(p0, x);
778
779 real_t store[3];
780 Vector v(store, x.Size());
781 pt.Get(store, x.Size());
782 v -= x;
783
784 trans.InverseJacobian().Mult(v, x);
785}
786
788 DenseMatrix &R) const
789{
791 Vector pt(&ipt.x, dim);
792
793#ifdef MFEM_THREAD_SAFE
794 Vector shape(dof);
795#else
796 Vector shape;
797 vshape.GetColumnReference(0, shape);
798#endif
799
800 Trans.SetIntPoint(&Nodes[0]);
801
802 for (int j = 0; j < dof; j++)
803 {
804 InvertLinearTrans(Trans, Nodes[j], pt);
805 if (Geometries.CheckPoint(geom_type, ipt)) // do we need an epsilon here?
806 {
807 CalcShape(ipt, shape);
808 R.SetRow(j, shape);
809 }
810 else
811 {
812 // Set the whole row to avoid valgrind warnings in R.Threshold().
813 R.SetRow(j, infinity());
814 }
815 }
816 R.Threshold(1e-12);
817}
818
820 Coefficient &coeff, ElementTransformation &Trans, Vector &dofs) const
821{
822 for (int i = 0; i < dof; i++)
823 {
824 const IntegrationPoint &ip = Nodes.IntPoint(i);
825 // some coefficients expect that Trans.IntPoint is the same
826 // as the second argument of Eval
827 Trans.SetIntPoint(&ip);
828 dofs(i) = coeff.Eval(Trans, ip);
829 if (map_type == INTEGRAL)
830 {
831 dofs(i) *= Trans.Weight();
832 }
833 }
834}
835
837 VectorCoefficient &vc, ElementTransformation &Trans, Vector &dofs) const
838{
839 MFEM_ASSERT(dofs.Size() == vc.GetVDim()*dof, "");
840 Vector x(vc.GetVDim());
841
842 for (int i = 0; i < dof; i++)
843 {
844 const IntegrationPoint &ip = Nodes.IntPoint(i);
845 Trans.SetIntPoint(&ip);
846 vc.Eval (x, Trans, ip);
847 if (map_type == INTEGRAL)
848 {
849 x *= Trans.Weight();
850 }
851 for (int j = 0; j < x.Size(); j++)
852 {
853 dofs(dof*j+i) = x(j);
854 }
855 }
856}
857
860{
861 // (mc.height x mc.width) @ DOFs -> (dof x mc.width x mc.height) in dofs
862 MFEM_ASSERT(dofs.Size() == mc.GetHeight()*mc.GetWidth()*dof, "");
863 DenseMatrix MQ(mc.GetHeight(), mc.GetWidth());
864
865 for (int k = 0; k < dof; k++)
866 {
868 mc.Eval(MQ, T, Nodes.IntPoint(k));
869 if (map_type == INTEGRAL) { MQ *= T.Weight(); }
870 for (int r = 0; r < MQ.Height(); r++)
871 {
872 for (int d = 0; d < MQ.Width(); d++)
873 {
874 dofs(k+dof*(d+MQ.Width()*r)) = MQ(r,d);
875 }
876 }
877 }
878}
879
881 const FiniteElement &fe, ElementTransformation &Trans, DenseMatrix &I) const
882{
883 if (fe.GetRangeType() == SCALAR)
884 {
885 Vector shape(fe.GetDof());
886
887 I.SetSize(dof, fe.GetDof());
888 if (map_type == fe.GetMapType())
889 {
890 for (int k = 0; k < dof; k++)
891 {
892 fe.CalcShape(Nodes.IntPoint(k), shape);
893 for (int j = 0; j < shape.Size(); j++)
894 {
895 I(k,j) = (fabs(shape(j)) < 1e-12) ? 0.0 : shape(j);
896 }
897 }
898 }
899 else
900 {
901 for (int k = 0; k < dof; k++)
902 {
903 Trans.SetIntPoint(&Nodes.IntPoint(k));
904 fe.CalcPhysShape(Trans, shape);
905 if (map_type == INTEGRAL)
906 {
907 shape *= Trans.Weight();
908 }
909 for (int j = 0; j < shape.Size(); j++)
910 {
911 I(k,j) = (fabs(shape(j)) < 1e-12) ? 0.0 : shape(j);
912 }
913 }
914 }
915 }
916 else
917 {
918 DenseMatrix vshape(fe.GetDof(), std::max(Trans.GetSpaceDim(),
919 fe.GetRangeDim()));
920
921 I.SetSize(vshape.Width()*dof, fe.GetDof());
922 for (int k = 0; k < dof; k++)
923 {
924 Trans.SetIntPoint(&Nodes.IntPoint(k));
925 fe.CalcVShape(Trans, vshape);
926 if (map_type == INTEGRAL)
927 {
928 vshape *= Trans.Weight();
929 }
930 for (int j = 0; j < vshape.Height(); j++)
931 for (int d = 0; d < vshape.Width(); d++)
932 {
933 I(k+d*dof,j) = vshape(j,d);
934 }
935 }
936 }
937}
938
940 const FiniteElement &fe, ElementTransformation &Trans,
941 DenseMatrix &grad) const
942{
943 MFEM_ASSERT(fe.GetMapType() == VALUE, "");
944 MFEM_ASSERT(Trans.GetSpaceDim() == dim, "")
945
946 DenseMatrix dshape(fe.GetDof(), dim), grad_k(fe.GetDof(), dim), Jinv(dim);
947
948 grad.SetSize(dim*dof, fe.GetDof());
949 for (int k = 0; k < dof; k++)
950 {
951 const IntegrationPoint &ip = Nodes.IntPoint(k);
952 fe.CalcDShape(ip, dshape);
953 Trans.SetIntPoint(&ip);
954 CalcInverse(Trans.Jacobian(), Jinv);
955 Mult(dshape, Jinv, grad_k);
956 if (map_type == INTEGRAL)
957 {
958 grad_k *= Trans.Weight();
959 }
960 for (int j = 0; j < grad_k.Height(); j++)
961 for (int d = 0; d < dim; d++)
962 {
963 grad(k+d*dof,j) = grad_k(j,d);
964 }
965 }
966}
967
969 const FiniteElement &fe, ElementTransformation &Trans,
970 DenseMatrix &div) const
971{
972 real_t detJ;
973 Vector div_shape(fe.GetDof());
974
975 div.SetSize(dof, fe.GetDof());
976 for (int k = 0; k < dof; k++)
977 {
978 const IntegrationPoint &ip = Nodes.IntPoint(k);
979 fe.CalcDivShape(ip, div_shape);
980 if (map_type == VALUE)
981 {
982 Trans.SetIntPoint(&ip);
983 detJ = Trans.Weight();
984 for (int j = 0; j < div_shape.Size(); j++)
985 {
986 div(k,j) = (fabs(div_shape(j)) < 1e-12) ? 0.0 : div_shape(j)/detJ;
987 }
988 }
989 else
990 {
991 for (int j = 0; j < div_shape.Size(); j++)
992 {
993 div(k,j) = (fabs(div_shape(j)) < 1e-12) ? 0.0 : div_shape(j);
994 }
995 }
996 }
997}
998
1000 Vector &dofs) const
1001{
1002 MFEM_ASSERT(lex_ordering.Size() == dof, "Permutation is not defined by FE.");
1003 MFEM_ASSERT(dofs.Size() == ncomp * dof, "Wrong input size.");
1004
1005 Vector dofs_native(ncomp * dof);
1006 for (int i = 0; i < dof; i++)
1007 {
1008 for (int c = 0; c < ncomp; c++)
1009 {
1010 dofs_native(c*dof + lex_ordering[i]) = dofs(c*dof + i);
1011 }
1012 }
1013 dofs = dofs_native;
1014}
1015
1017 int Do, int O, int M, int F)
1018 : FiniteElement(D, G, Do, O, F)
1019{
1021 map_type = M;
1023 is_nodal = true;
1024 vdim = dim;
1025 if (map_type == H_CURL)
1026 {
1027 cdim = (dim == 3) ? 3 : 1;
1028 }
1029}
1030
1031void VectorFiniteElement::CalcShape(
1032 const IntegrationPoint &ip, Vector &shape) const
1033{
1034 mfem_error("Error: Cannot use scalar CalcShape(...) function with\n"
1035 " VectorFiniteElements!");
1036}
1037
1038void VectorFiniteElement::CalcDShape(
1039 const IntegrationPoint &ip, DenseMatrix &dshape) const
1040{
1041 mfem_error("Error: Cannot use scalar CalcDShape(...) function with\n"
1042 " VectorFiniteElements!");
1043}
1044
1046{
1047 switch (map_type)
1048 {
1049 case H_DIV:
1050 deriv_type = DIV;
1053 break;
1054 case H_CURL:
1055 switch (dim)
1056 {
1057 case 3: // curl: 3D H_CURL -> 3D H_DIV
1058 deriv_type = CURL;
1061 break;
1062 case 2:
1063 // curl: 2D H_CURL -> INTEGRAL
1064 deriv_type = CURL;
1067 break;
1068 case 1:
1069 deriv_type = NONE;
1072 break;
1073 default:
1074 MFEM_ABORT("Invalid dimension, Dim = " << dim);
1075 }
1076 break;
1077 default:
1078 MFEM_ABORT("Invalid MapType = " << map_type);
1079 }
1080}
1081
1083 ElementTransformation &Trans, DenseMatrix &shape) const
1084{
1085 MFEM_ASSERT(map_type == H_DIV, "");
1086#ifdef MFEM_THREAD_SAFE
1088#endif
1089 CalcVShape(Trans.GetIntPoint(), vshape);
1090 MultABt(vshape, Trans.Jacobian(), shape);
1091 shape *= (1.0 / Trans.Weight());
1092}
1093
1095 ElementTransformation &Trans, DenseMatrix &shape) const
1096{
1097 MFEM_ASSERT(map_type == H_CURL, "");
1098#ifdef MFEM_THREAD_SAFE
1100#endif
1101 CalcVShape(Trans.GetIntPoint(), vshape);
1102 Mult(vshape, Trans.InverseJacobian(), shape);
1103}
1104
1106 const real_t *nk, const Array<int> &d2n,
1107 VectorCoefficient &vc, ElementTransformation &Trans, Vector &dofs) const
1108{
1110 const int sdim = Trans.GetSpaceDim();
1111 MFEM_ASSERT(vc.GetVDim() == sdim, "");
1112 Vector xk(vk, sdim);
1113 const bool square_J = (dim == sdim);
1114
1115 for (int k = 0; k < dof; k++)
1116 {
1117 Trans.SetIntPoint(&Nodes.IntPoint(k));
1118 vc.Eval(xk, Trans, Nodes.IntPoint(k));
1119 // dof_k = nk^t adj(J) xk
1120 dofs(k) = Trans.AdjugateJacobian().InnerProduct(vk, nk + d2n[k]*dim);
1121 if (!square_J) { dofs(k) /= Trans.Weight(); }
1122 }
1123}
1124
1126 const real_t *nk, const Array<int> &d2n,
1127 Vector &vc, ElementTransformation &Trans, Vector &dofs) const
1128{
1129 const int sdim = Trans.GetSpaceDim();
1130 const bool square_J = (dim == sdim);
1131
1132 for (int k = 0; k < dof; k++)
1133 {
1134 Trans.SetIntPoint(&Nodes.IntPoint(k));
1135 // dof_k = nk^t adj(J) xk
1136 dofs(k) = Trans.AdjugateJacobian().InnerProduct(
1137 &vc[k*sdim], nk + d2n[k]*dim);
1138 if (!square_J) { dofs(k) /= Trans.Weight(); }
1139 }
1140}
1141
1143 const real_t *nk, const Array<int> &d2n,
1144 MatrixCoefficient &mc, ElementTransformation &T, Vector &dofs) const
1145{
1146 // project the rows of the matrix coefficient in an RT space
1147
1148 const int sdim = T.GetSpaceDim();
1149 MFEM_ASSERT(mc.GetWidth() == sdim, "");
1150 const bool square_J = (dim == sdim);
1151 DenseMatrix MQ(mc.GetHeight(), mc.GetWidth());
1152 Vector nk_phys(sdim), dofs_k(MQ.Height());
1153 MFEM_ASSERT(dofs.Size() == dof*MQ.Height(), "");
1154
1155 for (int k = 0; k < dof; k++)
1156 {
1157 T.SetIntPoint(&Nodes.IntPoint(k));
1158 mc.Eval(MQ, T, Nodes.IntPoint(k));
1159 // nk_phys = adj(J)^t nk
1160 T.AdjugateJacobian().MultTranspose(nk + d2n[k]*dim, nk_phys);
1161 if (!square_J) { nk_phys /= T.Weight(); }
1162 MQ.Mult(nk_phys, dofs_k);
1163 for (int r = 0; r < MQ.Height(); r++)
1164 {
1165 dofs(k+dof*r) = dofs_k(r);
1166 }
1167 }
1168}
1169
1171 const real_t *nk, const Array<int> &d2n, const FiniteElement &fe,
1172 ElementTransformation &Trans, DenseMatrix &I) const
1173{
1174 if (fe.GetRangeType() == SCALAR)
1175 {
1177 Vector shape(fe.GetDof());
1178 int sdim = Trans.GetSpaceDim();
1179
1180 I.SetSize(dof, sdim*fe.GetDof());
1181 for (int k = 0; k < dof; k++)
1182 {
1183 const IntegrationPoint &ip = Nodes.IntPoint(k);
1184
1185 fe.CalcShape(ip, shape);
1186 Trans.SetIntPoint(&ip);
1187 // Transform RT face normals from reference to physical space
1188 // vk = adj(J)^T nk
1189 Trans.AdjugateJacobian().MultTranspose(nk + d2n[k]*dim, vk);
1190 if (fe.GetMapType() == INTEGRAL)
1191 {
1192 real_t w = 1.0/Trans.Weight();
1193 for (int d = 0; d < dim; d++)
1194 {
1195 vk[d] *= w;
1196 }
1197 }
1198
1199 for (int j = 0; j < shape.Size(); j++)
1200 {
1201 real_t s = shape(j);
1202 if (fabs(s) < 1e-12)
1203 {
1204 s = 0.0;
1205 }
1206 // Project scalar basis function multiplied by each coordinate
1207 // direction onto the transformed face normals
1208 for (int d = 0; d < sdim; d++)
1209 {
1210 I(k,j+d*shape.Size()) = s*vk[d];
1211 }
1212 }
1213 }
1214 }
1215 else
1216 {
1217 int sdim = Trans.GetSpaceDim();
1219 DenseMatrix vshape(fe.GetDof(), sdim);
1220 Vector vshapenk(fe.GetDof());
1221 const bool square_J = (dim == sdim);
1222
1223 I.SetSize(dof, fe.GetDof());
1224 for (int k = 0; k < dof; k++)
1225 {
1226 const IntegrationPoint &ip = Nodes.IntPoint(k);
1227
1228 Trans.SetIntPoint(&ip);
1229 // Transform RT face normals from reference to physical space
1230 // vk = adj(J)^T nk
1231 Trans.AdjugateJacobian().MultTranspose(nk + d2n[k]*dim, vk);
1232 // Compute fe basis functions in physical space
1233 fe.CalcVShape(Trans, vshape);
1234 // Project fe basis functions onto transformed face normals
1235 vshape.Mult(vk, vshapenk);
1236 if (!square_J) { vshapenk /= Trans.Weight(); }
1237 for (int j=0; j<vshapenk.Size(); j++)
1238 {
1239 I(k,j) = vshapenk(j);
1240 }
1241 }
1242 }
1243}
1244
1246 const real_t *nk, const Array<int> &d2n, const FiniteElement &fe,
1247 ElementTransformation &Trans, DenseMatrix &grad) const
1248{
1249 if (dim != 2)
1250 {
1251 mfem_error("VectorFiniteElement::ProjectGrad_RT works only in 2D!");
1252 }
1253
1254 DenseMatrix dshape(fe.GetDof(), fe.GetDim());
1255 Vector grad_k(fe.GetDof());
1256 real_t tk[2];
1257
1258 grad.SetSize(dof, fe.GetDof());
1259 for (int k = 0; k < dof; k++)
1260 {
1261 fe.CalcDShape(Nodes.IntPoint(k), dshape);
1262 tk[0] = nk[d2n[k]*dim+1];
1263 tk[1] = -nk[d2n[k]*dim];
1264 dshape.Mult(tk, grad_k);
1265 for (int j = 0; j < grad_k.Size(); j++)
1266 {
1267 grad(k,j) = (fabs(grad_k(j)) < 1e-12) ? 0.0 : grad_k(j);
1268 }
1269 }
1270}
1271
1273 const real_t *tk, const Array<int> &d2t, const FiniteElement &fe,
1274 ElementTransformation &Trans, DenseMatrix &curl) const
1275{
1276#ifdef MFEM_THREAD_SAFE
1280#else
1281 curlshape.SetSize(fe.GetDof(), dim);
1283 JtJ.SetSize(dim, dim);
1284#endif
1285
1286 Vector curl_k(fe.GetDof());
1287
1288 curl.SetSize(dof, fe.GetDof());
1289 for (int k = 0; k < dof; k++)
1290 {
1291 const IntegrationPoint &ip = Nodes.IntPoint(k);
1292
1293 // calculate J^t * J / |J|
1294 Trans.SetIntPoint(&ip);
1295 MultAtB(Trans.Jacobian(), Trans.Jacobian(), JtJ);
1296 JtJ *= 1.0 / Trans.Weight();
1297
1298 // transform curl of shapes (rows) by J^t * J / |J|
1299 fe.CalcCurlShape(ip, curlshape);
1301
1302 curlshape_J.Mult(tk + d2t[k]*dim, curl_k);
1303 for (int j = 0; j < curl_k.Size(); j++)
1304 {
1305 curl(k,j) = (fabs(curl_k(j)) < 1e-12) ? 0.0 : curl_k(j);
1306 }
1307 }
1308}
1309
1311 const real_t *nk, const Array<int> &d2n, const FiniteElement &fe,
1312 ElementTransformation &Trans, DenseMatrix &curl) const
1313{
1314 DenseMatrix curl_shape(fe.GetDof(), dim);
1315 Vector curl_k(fe.GetDof());
1316
1317 curl.SetSize(dof, fe.GetDof());
1318 for (int k = 0; k < dof; k++)
1319 {
1320 fe.CalcCurlShape(Nodes.IntPoint(k), curl_shape);
1321 curl_shape.Mult(nk + d2n[k]*dim, curl_k);
1322 for (int j = 0; j < curl_k.Size(); j++)
1323 {
1324 curl(k,j) = (fabs(curl_k(j)) < 1e-12) ? 0.0 : curl_k(j);
1325 }
1326 }
1327}
1328
1330 const real_t *tk, const Array<int> &d2t,
1331 VectorCoefficient &vc, ElementTransformation &Trans, Vector &dofs) const
1332{
1334 Vector xk(vk, vc.GetVDim());
1335
1336 for (int k = 0; k < dof; k++)
1337 {
1338 Trans.SetIntPoint(&Nodes.IntPoint(k));
1339
1340 vc.Eval(xk, Trans, Nodes.IntPoint(k));
1341 // dof_k = xk^t J tk
1342 dofs(k) = Trans.Jacobian().InnerProduct(tk + d2t[k]*dim, vk);
1343 }
1344}
1345
1347 const real_t *tk, const Array<int> &d2t,
1348 Vector &vc, ElementTransformation &Trans, Vector &dofs) const
1349{
1350 for (int k = 0; k < dof; k++)
1351 {
1352 Trans.SetIntPoint(&Nodes.IntPoint(k));
1353 // dof_k = xk^t J tk
1354 dofs(k) = Trans.Jacobian().InnerProduct(tk + d2t[k]*dim, &vc[k*dim]);
1355 }
1356}
1357
1359 const real_t *tk, const Array<int> &d2t,
1360 MatrixCoefficient &mc, ElementTransformation &T, Vector &dofs) const
1361{
1362 // project the rows of the matrix coefficient in an ND space
1363
1364 const int sdim = T.GetSpaceDim();
1365 MFEM_ASSERT(mc.GetWidth() == sdim, "");
1366 DenseMatrix MQ(mc.GetHeight(), mc.GetWidth());
1367 Vector tk_phys(sdim), dofs_k(MQ.Height());
1368 MFEM_ASSERT(dofs.Size() == dof*MQ.Height(), "");
1369
1370 for (int k = 0; k < dof; k++)
1371 {
1372 T.SetIntPoint(&Nodes.IntPoint(k));
1373 mc.Eval(MQ, T, Nodes.IntPoint(k));
1374 // tk_phys = J tk
1375 T.Jacobian().Mult(tk + d2t[k]*dim, tk_phys);
1376 MQ.Mult(tk_phys, dofs_k);
1377 for (int r = 0; r < MQ.Height(); r++)
1378 {
1379 dofs(k+dof*r) = dofs_k(r);
1380 }
1381 }
1382}
1383
1385 const real_t *tk, const Array<int> &d2t, const FiniteElement &fe,
1386 ElementTransformation &Trans, DenseMatrix &I) const
1387{
1388 if (fe.GetRangeType() == SCALAR)
1389 {
1390 int sdim = Trans.GetSpaceDim();
1392 Vector shape(fe.GetDof());
1393
1394 I.SetSize(dof, sdim*fe.GetDof());
1395 for (int k = 0; k < dof; k++)
1396 {
1397 const IntegrationPoint &ip = Nodes.IntPoint(k);
1398
1399 fe.CalcShape(ip, shape);
1400 Trans.SetIntPoint(&ip);
1401 // Transform ND edge tengents from reference to physical space
1402 // vk = J tk
1403 Trans.Jacobian().Mult(tk + d2t[k]*dim, vk);
1404 if (fe.GetMapType() == INTEGRAL)
1405 {
1406 real_t w = 1.0/Trans.Weight();
1407 for (int d = 0; d < sdim; d++)
1408 {
1409 vk[d] *= w;
1410 }
1411 }
1412
1413 for (int j = 0; j < shape.Size(); j++)
1414 {
1415 real_t s = shape(j);
1416 if (fabs(s) < 1e-12)
1417 {
1418 s = 0.0;
1419 }
1420 // Project scalar basis function multiplied by each coordinate
1421 // direction onto the transformed edge tangents
1422 for (int d = 0; d < sdim; d++)
1423 {
1424 I(k, j + d*shape.Size()) = s*vk[d];
1425 }
1426 }
1427 }
1428 }
1429 else
1430 {
1431 int sdim = Trans.GetSpaceDim();
1433 DenseMatrix vshape(fe.GetDof(), sdim);
1434 Vector vshapetk(fe.GetDof());
1435
1436 I.SetSize(dof, fe.GetDof());
1437 for (int k = 0; k < dof; k++)
1438 {
1439 const IntegrationPoint &ip = Nodes.IntPoint(k);
1440
1441 Trans.SetIntPoint(&ip);
1442 // Transform ND edge tangents from reference to physical space
1443 // vk = J tk
1444 Trans.Jacobian().Mult(tk + d2t[k]*dim, vk);
1445 // Compute fe basis functions in physical space
1446 fe.CalcVShape(Trans, vshape);
1447 // Project fe basis functions onto transformed edge tangents
1448 vshape.Mult(vk, vshapetk);
1449 for (int j=0; j<vshapetk.Size(); j++)
1450 {
1451 I(k, j) = vshapetk(j);
1452 }
1453 }
1454 }
1455}
1456
1458 const real_t *tk, const Array<int> &d2t, const FiniteElement &fe,
1459 ElementTransformation &Trans, DenseMatrix &grad) const
1460{
1461 MFEM_ASSERT(fe.GetMapType() == VALUE, "");
1462
1463 DenseMatrix dshape(fe.GetDof(), fe.GetDim());
1464 Vector grad_k(fe.GetDof());
1465
1466 grad.SetSize(dof, fe.GetDof());
1467 for (int k = 0; k < dof; k++)
1468 {
1469 fe.CalcDShape(Nodes.IntPoint(k), dshape);
1470 dshape.Mult(tk + d2t[k]*dim, grad_k);
1471 for (int j = 0; j < grad_k.Size(); j++)
1472 {
1473 grad(k,j) = (fabs(grad_k(j)) < 1e-12) ? 0.0 : grad_k(j);
1474 }
1475 }
1476}
1477
1479 const VectorFiniteElement &cfe, ElementTransformation &Trans,
1480 DenseMatrix &I) const
1481{
1482 Vector v(dim);
1483 IntegrationPoint tr_ip;
1484
1485 const int fs = dof, cs = cfe.GetDof();
1486 I.SetSize(fs, cs);
1487 DenseMatrix fine_shape(fs, dim), coarse_shape(cs, cfe.GetDim());
1488 DenseMatrix fine_mass(fs), fine_coarse_mass(fs, cs); // initialized with 0
1489 const int ir_order =
1490 std::max(GetOrder(), this->GetOrder()) + this->GetOrder();
1491 const IntegrationRule &ir = IntRules.Get(this->GetGeomType(), ir_order);
1492
1494 const DenseMatrix &adjJ = Trans.AdjugateJacobian();
1495 for (int i = 0; i < ir.GetNPoints(); i++)
1496 {
1497 const IntegrationPoint &ip = ir.IntPoint(i);
1498 real_t w = ip.weight;
1499 this->CalcVShape(ip, fine_shape);
1500 Trans.Transform(ip, v);
1501 tr_ip.Set(v.GetData(), dim);
1502 cfe.CalcVShape(tr_ip, coarse_shape);
1503
1504 AddMult_a_AAt(w, fine_shape, fine_mass);
1505 for (int k=0; k<fs; ++k)
1506 {
1507 for (int j=0; j<cs; ++j)
1508 {
1509 real_t Mkj = 0.0;
1510 for (int d1=0; d1<dim; ++d1)
1511 {
1512 for (int d2=0; d2<dim; ++d2)
1513 {
1514 Mkj += w*fine_shape(k,d1)*adjJ(d2,d1)*coarse_shape(j,d2);
1515 }
1516 }
1517 fine_coarse_mass(k,j) += (fabs(Mkj) < 1e-12) ? 0.0 : Mkj;
1518 }
1519 }
1520 }
1521 DenseMatrixInverse fine_mass_inv(fine_mass);
1522 fine_mass_inv.Mult(fine_coarse_mass, I);
1523}
1524
1526 const VectorFiniteElement &cfe, const real_t *nk, const Array<int> &d2n,
1527 ElementTransformation &Trans, DenseMatrix &I) const
1528{
1529 MFEM_ASSERT(map_type == cfe.GetMapType(), "");
1530
1531 if (!is_nodal) { return LocalL2Projection_RT(cfe, Trans, I); }
1532
1534 Vector xk(vk, dim);
1536#ifdef MFEM_THREAD_SAFE
1537 DenseMatrix vshape(cfe.GetDof(), cfe.GetDim());
1538#else
1539 DenseMatrix vshape(cfe.vshape.Data(), cfe.GetDof(), cfe.GetDim());
1540#endif
1541 I.SetSize(dof, vshape.Height());
1542
1543 // assuming Trans is linear; this should be ok for all refinement types
1545 const DenseMatrix &adjJ = Trans.AdjugateJacobian();
1546 for (int k = 0; k < dof; k++)
1547 {
1548 Trans.Transform(Nodes.IntPoint(k), xk);
1549 ip.Set3(vk);
1550 cfe.CalcVShape(ip, vshape);
1551 // xk = |J| J^{-t} n_k
1552 adjJ.MultTranspose(nk + d2n[k]*dim, vk);
1553 // I_k = vshape_k.adj(J)^t.n_k, k=1,...,dof
1554 for (int j = 0; j < vshape.Height(); j++)
1555 {
1556 real_t Ikj = 0.;
1557 for (int i = 0; i < dim; i++)
1558 {
1559 Ikj += vshape(j, i) * vk[i];
1560 }
1561 I(k, j) = (fabs(Ikj) < 1e-12) ? 0.0 : Ikj;
1562 }
1563 }
1564}
1565
1567 const VectorFiniteElement &cfe,
1568 ElementTransformation &Trans, DenseMatrix &I) const
1569{
1570 Vector v(dim);
1571 IntegrationPoint tr_ip;
1572
1573 const int fs = dof, cs = cfe.GetDof();
1574 I.SetSize(fs, cs);
1575 DenseMatrix fine_shape(fs, dim), coarse_shape(cs, cfe.GetDim());
1576 DenseMatrix fine_mass(fs), fine_coarse_mass(fs, cs); // initialized with 0
1577 const int ir_order =
1578 std::max(GetOrder(), this->GetOrder()) + this->GetOrder();
1579 const IntegrationRule &ir = IntRules.Get(this->GetGeomType(), ir_order);
1580
1582 const DenseMatrix &J = Trans.Jacobian();
1583 for (int i = 0; i < ir.GetNPoints(); i++)
1584 {
1585 const IntegrationPoint &ip = ir.IntPoint(i);
1586 this->CalcVShape(ip, fine_shape);
1587 Trans.Transform(ip, v);
1588 tr_ip.Set(v.GetData(), dim);
1589 cfe.CalcVShape(tr_ip, coarse_shape);
1590
1591 AddMult_a_AAt(ip.weight, fine_shape, fine_mass);
1592 for (int k=0; k<fs; ++k)
1593 {
1594 for (int j=0; j<cs; ++j)
1595 {
1596 real_t Mkj = 0.0;
1597 for (int d1=0; d1<dim; ++d1)
1598 {
1599 for (int d2=0; d2<dim; ++d2)
1600 {
1601 Mkj += ip.weight*fine_shape(k,d1)*J(d1,d2)*coarse_shape(j,d2);
1602 }
1603 }
1604 fine_coarse_mass(k,j) += (fabs(Mkj) < 1e-12) ? 0.0 : Mkj;
1605 }
1606 }
1607 }
1608 DenseMatrixInverse fine_mass_inv(fine_mass);
1609 fine_mass_inv.Mult(fine_coarse_mass, I);
1610}
1611
1613 const VectorFiniteElement &cfe, const real_t *tk, const Array<int> &d2t,
1614 ElementTransformation &Trans, DenseMatrix &I) const
1615{
1616 if (!is_nodal) { return LocalL2Projection_ND(cfe, Trans, I); }
1617
1619 Vector xk(vk, dim);
1621#ifdef MFEM_THREAD_SAFE
1622 DenseMatrix vshape(cfe.GetDof(), cfe.GetDim());
1623#else
1624 DenseMatrix vshape(cfe.vshape.Data(), cfe.GetDof(), cfe.GetDim());
1625#endif
1626 I.SetSize(dof, vshape.Height());
1627
1628 // assuming Trans is linear; this should be ok for all refinement types
1630 const DenseMatrix &J = Trans.Jacobian();
1631 for (int k = 0; k < dof; k++)
1632 {
1633 Trans.Transform(Nodes.IntPoint(k), xk);
1634 ip.Set3(vk);
1635 cfe.CalcVShape(ip, vshape);
1636 // xk = J t_k
1637 J.Mult(tk + d2t[k]*dim, vk);
1638 // I_k = vshape_k.J.t_k, k=1,...,Dof
1639 for (int j = 0; j < vshape.Height(); j++)
1640 {
1641 real_t Ikj = 0.;
1642 for (int i = 0; i < dim; i++)
1643 {
1644 Ikj += vshape(j, i) * vk[i];
1645 }
1646 I(k, j) = (fabs(Ikj) < 1e-12) ? 0.0 : Ikj;
1647 }
1648 }
1649}
1650
1652 const real_t *nk, const Array<int> &d2n, ElementTransformation &Trans,
1653 DenseMatrix &R) const
1654{
1655 real_t pt_data[Geometry::MaxDim];
1657 Vector pt(pt_data, dim);
1658
1659#ifdef MFEM_THREAD_SAFE
1661#endif
1662
1664 const DenseMatrix &J = Trans.Jacobian();
1665 const real_t weight = Trans.Weight();
1666 for (int j = 0; j < dof; j++)
1667 {
1668 InvertLinearTrans(Trans, Nodes.IntPoint(j), pt);
1669 ip.Set(pt_data, dim);
1670 if (Geometries.CheckPoint(geom_type, ip)) // do we need an epsilon here?
1671 {
1672 CalcVShape(ip, vshape);
1673 J.MultTranspose(nk+dim*d2n[j], pt_data);
1674 pt /= weight;
1675 for (int k = 0; k < dof; k++)
1676 {
1677 real_t R_jk = 0.0;
1678 for (int d = 0; d < dim; d++)
1679 {
1680 R_jk += vshape(k,d)*pt_data[d];
1681 }
1682 R(j,k) = R_jk;
1683 }
1684 }
1685 else
1686 {
1687 // Set the whole row to avoid valgrind warnings in R.Threshold().
1688 R.SetRow(j, infinity());
1689 }
1690 }
1691 R.Threshold(1e-12);
1692}
1693
1695 const real_t *tk, const Array<int> &d2t, ElementTransformation &Trans,
1696 DenseMatrix &R) const
1697{
1698 real_t pt_data[Geometry::MaxDim];
1700 Vector pt(pt_data, dim);
1701
1702#ifdef MFEM_THREAD_SAFE
1704#endif
1705
1707 const DenseMatrix &Jinv = Trans.InverseJacobian();
1708 for (int j = 0; j < dof; j++)
1709 {
1710 InvertLinearTrans(Trans, Nodes.IntPoint(j), pt);
1711 ip.Set(pt_data, dim);
1712 if (Geometries.CheckPoint(geom_type, ip)) // do we need an epsilon here?
1713 {
1714 CalcVShape(ip, vshape);
1715 Jinv.Mult(tk+dim*d2t[j], pt_data);
1716 for (int k = 0; k < dof; k++)
1717 {
1718 real_t R_jk = 0.0;
1719 for (int d = 0; d < dim; d++)
1720 {
1721 R_jk += vshape(k,d)*pt_data[d];
1722 }
1723 R(j,k) = R_jk;
1724 }
1725 }
1726 else
1727 {
1728 // Set the whole row to avoid valgrind warnings in R.Threshold().
1729 R.SetRow(j, infinity());
1730 }
1731 }
1732 R.Threshold(1e-12);
1733}
1734
1735
1737 : etype(etype), auxiliary_basis(NULL), scale_integrated(false)
1738{
1739 switch (etype)
1740 {
1741 case ChangeOfBasis:
1742 {
1743 x.SetSize(p + 1);
1744 w.SetSize(p + 1);
1745 DenseMatrix A(p + 1);
1746 for (int i = 0; i <= p; i++)
1747 {
1748 CalcBasis(p, nodes[i], A.GetColumn(i));
1749 }
1750 Ai.Factor(A);
1751 // mfem::out << "Poly_1D::Basis(" << p << ",...) : "; Ai.TestInversion();
1752 break;
1753 }
1754 case Barycentric:
1755 {
1756 x.SetSize(p + 1);
1757 w.SetSize(p + 1);
1758 x = nodes;
1759 w = 1.0;
1760 for (int i = 0; i <= p; i++)
1761 {
1762 for (int j = 0; j < i; j++)
1763 {
1764 real_t xij = x(i) - x(j);
1765 w(i) *= xij;
1766 w(j) *= -xij;
1767 }
1768 }
1769 for (int i = 0; i <= p; i++)
1770 {
1771 w(i) = 1.0/w(i);
1772 }
1773
1774#ifdef MFEM_DEBUG
1775 // Make sure the nodes are increasing
1776 for (int i = 0; i < p; i++)
1777 {
1778 if (x(i) >= x(i+1))
1779 {
1780 mfem_error("Poly_1D::Basis::Basis : nodes are not increasing!");
1781 }
1782 }
1783#endif
1784 break;
1785 }
1786 case Positive:
1787 x.SetDataAndSize(NULL, p + 1); // use x to store (p + 1)
1788 break;
1789 case Integrated:
1790 auxiliary_basis = new Basis(
1792 u_aux.SetSize(p+2);
1793 d_aux.SetSize(p+2);
1794 d2_aux.SetSize(p+2);
1795 break;
1796 default: break;
1797 }
1798}
1799
1801{
1802 switch (etype)
1803 {
1804 case ChangeOfBasis:
1805 {
1806 CalcBasis(Ai.Width() - 1, y, x);
1807 Ai.Mult(x, u);
1808 break;
1809 }
1810 case Barycentric:
1811 {
1812 int i, k, p = x.Size() - 1;
1813 real_t l, lk;
1814
1815 if (p == 0)
1816 {
1817 u(0) = 1.0;
1818 return;
1819 }
1820
1821 lk = 1.0;
1822 for (k = 0; k < p; k++)
1823 {
1824 if (y >= (x(k) + x(k+1))/2)
1825 {
1826 lk *= y - x(k);
1827 }
1828 else
1829 {
1830 for (i = k+1; i <= p; i++)
1831 {
1832 lk *= y - x(i);
1833 }
1834 break;
1835 }
1836 }
1837 l = lk * (y - x(k));
1838
1839 for (i = 0; i < k; i++)
1840 {
1841 u(i) = l * w(i) / (y - x(i));
1842 }
1843 u(k) = lk * w(k);
1844 for (i++; i <= p; i++)
1845 {
1846 u(i) = l * w(i) / (y - x(i));
1847 }
1848 break;
1849 }
1850 case Positive:
1851 CalcBernstein(x.Size() - 1, y, u);
1852 break;
1853 case Integrated:
1854 auxiliary_basis->Eval(y, u_aux, d_aux);
1855 EvalIntegrated(d_aux, u);
1856 break;
1857 default: break;
1858 }
1859}
1860
1861void Poly_1D::Basis::Eval(const real_t y, Vector &u, Vector &d) const
1862{
1863 switch (etype)
1864 {
1865 case ChangeOfBasis:
1866 {
1867 CalcBasis(Ai.Width() - 1, y, x, w);
1868 Ai.Mult(x, u);
1869 Ai.Mult(w, d);
1870 break;
1871 }
1872 case Barycentric:
1873 {
1874 int i, k, p = x.Size() - 1;
1875 real_t l, lp, lk, sk, si;
1876
1877 if (p == 0)
1878 {
1879 u(0) = 1.0;
1880 d(0) = 0.0;
1881 return;
1882 }
1883
1884 lk = 1.0;
1885 for (k = 0; k < p; k++)
1886 {
1887 if (y >= (x(k) + x(k+1))/2)
1888 {
1889 lk *= y - x(k);
1890 }
1891 else
1892 {
1893 for (i = k+1; i <= p; i++)
1894 {
1895 lk *= y - x(i);
1896 }
1897 break;
1898 }
1899 }
1900 l = lk * (y - x(k));
1901
1902 sk = 0.0;
1903 for (i = 0; i < k; i++)
1904 {
1905 si = 1.0/(y - x(i));
1906 sk += si;
1907 u(i) = l * si * w(i);
1908 }
1909 u(k) = lk * w(k);
1910 for (i++; i <= p; i++)
1911 {
1912 si = 1.0/(y - x(i));
1913 sk += si;
1914 u(i) = l * si * w(i);
1915 }
1916 lp = l * sk + lk;
1917
1918 for (i = 0; i < k; i++)
1919 {
1920 d(i) = (lp * w(i) - u(i))/(y - x(i));
1921 }
1922 d(k) = sk * u(k);
1923 for (i++; i <= p; i++)
1924 {
1925 d(i) = (lp * w(i) - u(i))/(y - x(i));
1926 }
1927 break;
1928 }
1929 case Positive:
1930 CalcBernstein(x.Size() - 1, y, u, d);
1931 break;
1932 case Integrated:
1933 auxiliary_basis->Eval(y, u_aux, d_aux, d2_aux);
1934 EvalIntegrated(d_aux,u);
1935 EvalIntegrated(d2_aux,d);
1936 break;
1937 default: break;
1938 }
1939}
1940
1942 Vector &d2) const
1943{
1944 MFEM_VERIFY(etype == Barycentric,
1945 "Basis::Eval with second order derivatives not implemented for"
1946 " etype = " << etype);
1947 switch (etype)
1948 {
1949 case ChangeOfBasis:
1950 {
1951 CalcBasis(Ai.Width() - 1, y, x, w);
1952 Ai.Mult(x, u);
1953 Ai.Mult(w, d);
1954 // set d2 (not implemented yet)
1955 break;
1956 }
1957 case Barycentric:
1958 {
1959 int i, k, p = x.Size() - 1;
1960 real_t l, lp, lp2, lk, sk, si, sk2;
1961
1962 if (p == 0)
1963 {
1964 u(0) = 1.0;
1965 d(0) = 0.0;
1966 d2(0) = 0.0;
1967 return;
1968 }
1969
1970 lk = 1.0;
1971 for (k = 0; k < p; k++)
1972 {
1973 if (y >= (x(k) + x(k+1))/2)
1974 {
1975 lk *= y - x(k);
1976 }
1977 else
1978 {
1979 for (i = k+1; i <= p; i++)
1980 {
1981 lk *= y - x(i);
1982 }
1983 break;
1984 }
1985 }
1986 l = lk * (y - x(k));
1987
1988 sk = 0.0;
1989 sk2 = 0.0;
1990 for (i = 0; i < k; i++)
1991 {
1992 si = 1.0/(y - x(i));
1993 sk += si;
1994 sk2 -= si * si;
1995 u(i) = l * si * w(i);
1996 }
1997 u(k) = lk * w(k);
1998 for (i++; i <= p; i++)
1999 {
2000 si = 1.0/(y - x(i));
2001 sk += si;
2002 sk2 -= si * si;
2003 u(i) = l * si * w(i);
2004 }
2005 lp = l * sk + lk;
2006 lp2 = lp * sk + l * sk2 + sk * lk;
2007
2008 for (i = 0; i < k; i++)
2009 {
2010 d(i) = (lp * w(i) - u(i))/(y - x(i));
2011 d2(i) = (lp2 * w(i) - 2 * d(i))/(y - x(i));
2012 }
2013 d(k) = sk * u(k);
2014 d2(k) = sk2 * u(k) + sk * d(k);
2015 for (i++; i <= p; i++)
2016 {
2017 d(i) = (lp * w(i) - u(i))/(y - x(i));
2018 d2(i) = (lp2 * w(i) - 2 * d(i))/(y - x(i));
2019 }
2020 break;
2021 }
2022 case Positive:
2023 CalcBernstein(x.Size() - 1, y, u, d);
2024 break;
2025 case Integrated:
2026 MFEM_ABORT("Integrated basis must be evaluated with EvalIntegrated");
2027 break;
2028 default: break;
2029 }
2030}
2031
2033{
2034 MFEM_VERIFY(etype == Integrated,
2035 "EvalIntegrated is only valid for Integrated basis type");
2036 int p = d_aux_.Size() - 1;
2037 // See Gerritsma, M. (2010). "Edge functions for spectral element methods",
2038 // in Lecture Notes in Computational Science and Engineering, 199--207.
2039 u[0] = -d_aux_[0];
2040 for (int j=1; j<p; ++j)
2041 {
2042 u[j] = u[j-1] - d_aux_[j];
2043 }
2044 // If scale_integrated is true, the degrees of freedom represent mean values,
2045 // otherwise they represent subcell integrals. Generally, scale_integrated
2046 // should be true for MapType::VALUE, and false for other map types.
2047 if (scale_integrated)
2048 {
2049 Vector &aux_nodes = auxiliary_basis->x;
2050 for (int j=0; j<aux_nodes.Size()-1; ++j)
2051 {
2052 u[j] *= aux_nodes[j+1] - aux_nodes[j];
2053 }
2054 }
2055}
2056
2057void Poly_1D::Basis::ScaleIntegrated(bool scale_integrated_)
2058{
2059 scale_integrated = scale_integrated_;
2060}
2061
2063{
2064 delete auxiliary_basis;
2065}
2066
2067const int *Poly_1D::Binom(const int p)
2068{
2069 if (binom.NumCols() <= p)
2070 {
2071 binom.SetSize(p + 1, p + 1);
2072 for (int i = 0; i <= p; i++)
2073 {
2074 binom(i,0) = binom(i,i) = 1;
2075 for (int j = 1; j < i; j++)
2076 {
2077 binom(i,j) = binom(i-1,j) + binom(i-1,j-1);
2078 }
2079 }
2080 }
2081 return binom[p];
2082}
2083
2085{
2086 for (int i = 0; i <= p; i++)
2087 {
2088 // x[i] = 0.5*(1. + cos(M_PI*(p - i + 0.5)/(p + 1)));
2089 real_t s = sin(M_PI_2*(i + 0.5)/(p + 1));
2090 x[i] = s*s;
2091 }
2092}
2093
2094void Poly_1D::CalcMono(const int p, const real_t x, real_t *u)
2095{
2096 real_t xn;
2097 u[0] = xn = 1.;
2098 for (int n = 1; n <= p; n++)
2099 {
2100 u[n] = (xn *= x);
2101 }
2102}
2103
2104void Poly_1D::CalcMono(const int p, const real_t x, real_t *u, real_t *d)
2105{
2106 real_t xn;
2107 u[0] = xn = 1.;
2108 d[0] = 0.;
2109 for (int n = 1; n <= p; n++)
2110 {
2111 d[n] = n * xn;
2112 u[n] = (xn *= x);
2113 }
2114}
2115
2116void Poly_1D::CalcBinomTerms(const int p, const real_t x, const real_t y,
2117 real_t *u)
2118{
2119 if (p == 0)
2120 {
2121 u[0] = 1.;
2122 }
2123 else
2124 {
2125 int i;
2126 const int *b = Binom(p);
2127 real_t z = x;
2128
2129 for (i = 1; i < p; i++)
2130 {
2131 u[i] = b[i]*z;
2132 z *= x;
2133 }
2134 u[p] = z;
2135 z = y;
2136 for (i--; i > 0; i--)
2137 {
2138 u[i] *= z;
2139 z *= y;
2140 }
2141 u[0] = z;
2142 }
2143}
2144
2145void Poly_1D::CalcBinomTerms(const int p, const real_t x, const real_t y,
2146 real_t *u, real_t *d)
2147{
2148 if (p == 0)
2149 {
2150 u[0] = 1.;
2151 d[0] = 0.;
2152 }
2153 else
2154 {
2155 int i;
2156 const int *b = Binom(p);
2157 const real_t xpy = x + y, ptx = p*x;
2158 real_t z = 1.;
2159
2160 for (i = 1; i < p; i++)
2161 {
2162 d[i] = b[i]*z*(i*xpy - ptx);
2163 z *= x;
2164 u[i] = b[i]*z;
2165 }
2166 d[p] = p*z;
2167 u[p] = z*x;
2168 z = 1.;
2169 for (i--; i > 0; i--)
2170 {
2171 d[i] *= z;
2172 z *= y;
2173 u[i] *= z;
2174 }
2175 d[0] = -p*z;
2176 u[0] = z*y;
2177 }
2178}
2179
2180void Poly_1D::CalcDBinomTerms(const int p, const real_t x, const real_t y,
2181 real_t *d)
2182{
2183 if (p == 0)
2184 {
2185 d[0] = 0.;
2186 }
2187 else
2188 {
2189 int i;
2190 const int *b = Binom(p);
2191 const real_t xpy = x + y, ptx = p*x;
2192 real_t z = 1.;
2193
2194 for (i = 1; i < p; i++)
2195 {
2196 d[i] = b[i]*z*(i*xpy - ptx);
2197 z *= x;
2198 }
2199 d[p] = p*z;
2200 z = 1.;
2201 for (i--; i > 0; i--)
2202 {
2203 d[i] *= z;
2204 z *= y;
2205 }
2206 d[0] = -p*z;
2207 }
2208}
2209
2210void Poly_1D::CalcDxBinomTerms(const int p, const real_t x, const real_t y,
2211 real_t *u)
2212{
2213 if (p == 0)
2214 {
2215 u[0] = 0.;
2216 }
2217 else
2218 {
2219 int i;
2220 const int *b = Binom(p);
2221 real_t z = 1.;
2222
2223 for (i = 1; i < p; i++)
2224 {
2225 u[i] = i * b[i]*z;
2226 z *= x;
2227 }
2228 u[p] = i * z;
2229 z = y;
2230 for (i--; i > 0; i--)
2231 {
2232 u[i] *= z;
2233 z *= y;
2234 }
2235 u[0] = 0;
2236 }
2237}
2238
2239void Poly_1D::CalcDyBinomTerms(const int p, const real_t x, const real_t y,
2240 real_t *u)
2241{
2242 if (p == 0)
2243 {
2244 u[0] = 0.;
2245 }
2246 else
2247 {
2248 int i;
2249 const int *b = Binom(p);
2250 real_t z = x;
2251
2252 for (i = 1; i < p; i++)
2253 {
2254 u[i] = b[i]*z;
2255 z *= x;
2256 }
2257 u[p] = 0.;
2258 z = 1.;
2259 for (i--; i > 0; i--)
2260 {
2261 u[i] *= (p - i) * z;
2262 z *= y;
2263 }
2264 u[0] = p * z;
2265 }
2266}
2267
2268void Poly_1D::CalcLegendre(const int p, const real_t x, real_t *u)
2269{
2270 // use the recursive definition for [-1,1]:
2271 // (n+1)*P_{n+1}(z) = (2*n+1)*z*P_n(z)-n*P_{n-1}(z)
2272 real_t z;
2273 u[0] = 1.;
2274 if (p == 0) { return; }
2275 u[1] = z = 2.*x - 1.;
2276 for (int n = 1; n < p; n++)
2277 {
2278 u[n+1] = ((2*n + 1)*z*u[n] - n*u[n-1])/(n + 1);
2279 }
2280}
2281
2282void Poly_1D::CalcLegendre(const int p, const real_t x, real_t *u, real_t *d)
2283{
2284 // use the recursive definition for [-1,1]:
2285 // (n+1)*P_{n+1}(z) = (2*n+1)*z*P_n(z)-n*P_{n-1}(z)
2286 // for the derivative use, z in [-1,1]:
2287 // P'_{n+1}(z) = (2*n+1)*P_n(z)+P'_{n-1}(z)
2288 real_t z;
2289 u[0] = 1.;
2290 d[0] = 0.;
2291 if (p == 0) { return; }
2292 u[1] = z = 2.*x - 1.;
2293 d[1] = 2.;
2294 for (int n = 1; n < p; n++)
2295 {
2296 u[n+1] = ((2*n + 1)*z*u[n] - n*u[n-1])/(n + 1);
2297 d[n+1] = (4*n + 2)*u[n] + d[n-1];
2298 }
2299}
2300
2301void Poly_1D::CalcChebyshev(const int p, const real_t x, real_t *u)
2302{
2303 // recursive definition, z in [-1,1]
2304 // T_0(z) = 1, T_1(z) = z
2305 // T_{n+1}(z) = 2*z*T_n(z) - T_{n-1}(z)
2306 real_t z;
2307 u[0] = 1.;
2308 if (p == 0) { return; }
2309 u[1] = z = 2.*x - 1.;
2310 for (int n = 1; n < p; n++)
2311 {
2312 u[n+1] = 2*z*u[n] - u[n-1];
2313 }
2314}
2315
2316void Poly_1D::CalcChebyshev(const int p, const real_t x, real_t *u, real_t *d)
2317{
2318 // recursive definition, z in [-1,1]
2319 // T_0(z) = 1, T_1(z) = z
2320 // T_{n+1}(z) = 2*z*T_n(z) - T_{n-1}(z)
2321 // T'_n(z) = n*U_{n-1}(z)
2322 // U_0(z) = 1 U_1(z) = 2*z
2323 // U_{n+1}(z) = 2*z*U_n(z) - U_{n-1}(z)
2324 // U_n(z) = z*U_{n-1}(z) + T_n(z) = z*T'_n(z)/n + T_n(z)
2325 // T'_{n+1}(z) = (n + 1)*(z*T'_n(z)/n + T_n(z))
2326 real_t z;
2327 u[0] = 1.;
2328 d[0] = 0.;
2329 if (p == 0) { return; }
2330 u[1] = z = 2.*x - 1.;
2331 d[1] = 2.;
2332 for (int n = 1; n < p; n++)
2333 {
2334 u[n+1] = 2*z*u[n] - u[n-1];
2335 d[n+1] = (n + 1)*(z*d[n]/n + 2*u[n]);
2336 }
2337}
2338
2339void Poly_1D::CalcChebyshev(const int p, const real_t x, real_t *u, real_t *d,
2340 real_t *dd)
2341{
2342 // recursive definition, z in [-1,1]
2343 // T_0(z) = 1, T_1(z) = z
2344 // T_{n+1}(z) = 2*z*T_n(z) - T_{n-1}(z)
2345 // T'_n(z) = n*U_{n-1}(z)
2346 // U_0(z) = 1 U_1(z) = 2*z
2347 // U_{n+1}(z) = 2*z*U_n(z) - U_{n-1}(z)
2348 // U_n(z) = z*U_{n-1}(z) + T_n(z) = z*T'_n(z)/n + T_n(z)
2349 // T'_{n+1}(z) = (n + 1)*(z*T'_n(z)/n + T_n(z))
2350 // T''_{n+1}(z) = (n + 1)*(2*(n + 1)*T'_n(z) + z*T''_n(z)) / n
2351 real_t z;
2352 u[0] = 1.;
2353 d[0] = 0.;
2354 dd[0]= 0.;
2355 if (p == 0) { return; }
2356 u[1] = z = 2.*x - 1.;
2357 d[1] = 2.;
2358 dd[1] = 0;
2359 for (int n = 1; n < p; n++)
2360 {
2361 u[n+1] = 2*z*u[n] - u[n-1];
2362 d[n+1] = (n + 1)*(z*d[n]/n + 2*u[n]);
2363 dd[n+1] = (n + 1)*(2.*(n + 1)*d[n] + z*dd[n])/n;
2364 }
2365}
2366
2367const Array<real_t>* Poly_1D::GetPointsArray(const int p, const int btype)
2368{
2369 Array<real_t> *val;
2370 BasisType::Check(btype);
2371 const int qtype = BasisType::GetQuadrature1D(btype);
2372 if (qtype == Quadrature1D::Invalid) { return nullptr; }
2373
2374#if defined(MFEM_THREAD_SAFE) && defined(MFEM_USE_OPENMP)
2375 #pragma omp critical (Poly1DGetPoints)
2376#endif
2377 {
2378 std::pair<int, int> key(btype, p);
2379 auto it = points_container.find(key);
2380 if (it == points_container.end())
2381 {
2382 it = points_container.emplace(key, new Array<real_t>(p + 1, h_mt)).first;
2383 val = it->second.get();
2384 real_t* hptr = val->HostWrite();
2385 quad_func.GivePolyPoints(p + 1, hptr, qtype);
2386 }
2387 else
2388 {
2389 val = it->second.get();
2390 }
2391 }
2392 return val;
2393}
2394
2395Poly_1D::Basis &Poly_1D::GetBasis(const int p, const int btype)
2396{
2397 BasisType::Check(btype);
2398 Basis* val;
2399
2400#if defined(MFEM_THREAD_SAFE) && defined(MFEM_USE_OPENMP)
2401 #pragma omp critical (Poly1DGetBasis)
2402#endif
2403 {
2404 std::pair<int, int> key(btype, p);
2405 auto it = bases_container.find(key);
2406 if (it == bases_container.end())
2407 {
2408 EvalType etype;
2409 if (btype == BasisType::Positive) { etype = Positive; }
2410 else if (btype == BasisType::IntegratedGLL) { etype = Integrated; }
2411 else { etype = Barycentric; }
2412 it = bases_container
2413 .emplace(key, new Basis(p, GetPoints(p, btype), etype))
2414 .first;
2415 }
2416 val = it->second.get();
2417 }
2418 return *val;
2419}
2420
2421
2423 const int btype, const DofMapType dmtype)
2424 : b_type(btype),
2425 basis1d(poly1d.GetBasis(p, b_type))
2426{
2427 if (dmtype == H1_DOF_MAP || dmtype == Sr_DOF_MAP)
2428 {
2429 switch (dims)
2430 {
2431 case 1:
2432 {
2433 dof_map.SetSize(p + 1);
2434 dof_map[0] = 0;
2435 dof_map[p] = 1;
2436 for (int i = 1; i < p; i++)
2437 {
2438 dof_map[i] = i+1;
2439 }
2440 break;
2441 }
2442 case 2:
2443 {
2444 const int p1 = p + 1;
2445 dof_map.SetSize(p1*p1);
2446
2447 // vertices
2448 dof_map[0 + 0*p1] = 0;
2449 dof_map[p + 0*p1] = 1;
2450 dof_map[p + p*p1] = 2;
2451 dof_map[0 + p*p1] = 3;
2452
2453 // edges
2454 int o = 4;
2455 for (int i = 1; i < p; i++)
2456 {
2457 dof_map[i + 0*p1] = o++;
2458 }
2459 for (int i = 1; i < p; i++)
2460 {
2461 dof_map[p + i*p1] = o++;
2462 }
2463 for (int i = 1; i < p; i++)
2464 {
2465 dof_map[(p-i) + p*p1] = o++;
2466 }
2467 for (int i = 1; i < p; i++)
2468 {
2469 dof_map[0 + (p-i)*p1] = o++;
2470 }
2471
2472 // interior
2473 for (int j = 1; j < p; j++)
2474 {
2475 for (int i = 1; i < p; i++)
2476 {
2477 dof_map[i + j*p1] = o++;
2478 }
2479 }
2480 break;
2481 }
2482 case 3:
2483 {
2484 const int p1 = p + 1;
2485 dof_map.SetSize(p1*p1*p1);
2486
2487 // vertices
2488 dof_map[0 + (0 + 0*p1)*p1] = 0;
2489 dof_map[p + (0 + 0*p1)*p1] = 1;
2490 dof_map[p + (p + 0*p1)*p1] = 2;
2491 dof_map[0 + (p + 0*p1)*p1] = 3;
2492 dof_map[0 + (0 + p*p1)*p1] = 4;
2493 dof_map[p + (0 + p*p1)*p1] = 5;
2494 dof_map[p + (p + p*p1)*p1] = 6;
2495 dof_map[0 + (p + p*p1)*p1] = 7;
2496
2497 // edges (see Hexahedron::edges in mesh/hexahedron.cpp).
2498 // edges (see Constants<Geometry::CUBE>::Edges in fem/geom.cpp).
2499 int o = 8;
2500 for (int i = 1; i < p; i++)
2501 {
2502 dof_map[i + (0 + 0*p1)*p1] = o++; // (0,1)
2503 }
2504 for (int i = 1; i < p; i++)
2505 {
2506 dof_map[p + (i + 0*p1)*p1] = o++; // (1,2)
2507 }
2508 for (int i = 1; i < p; i++)
2509 {
2510 dof_map[i + (p + 0*p1)*p1] = o++; // (3,2)
2511 }
2512 for (int i = 1; i < p; i++)
2513 {
2514 dof_map[0 + (i + 0*p1)*p1] = o++; // (0,3)
2515 }
2516 for (int i = 1; i < p; i++)
2517 {
2518 dof_map[i + (0 + p*p1)*p1] = o++; // (4,5)
2519 }
2520 for (int i = 1; i < p; i++)
2521 {
2522 dof_map[p + (i + p*p1)*p1] = o++; // (5,6)
2523 }
2524 for (int i = 1; i < p; i++)
2525 {
2526 dof_map[i + (p + p*p1)*p1] = o++; // (7,6)
2527 }
2528 for (int i = 1; i < p; i++)
2529 {
2530 dof_map[0 + (i + p*p1)*p1] = o++; // (4,7)
2531 }
2532 for (int i = 1; i < p; i++)
2533 {
2534 dof_map[0 + (0 + i*p1)*p1] = o++; // (0,4)
2535 }
2536 for (int i = 1; i < p; i++)
2537 {
2538 dof_map[p + (0 + i*p1)*p1] = o++; // (1,5)
2539 }
2540 for (int i = 1; i < p; i++)
2541 {
2542 dof_map[p + (p + i*p1)*p1] = o++; // (2,6)
2543 }
2544 for (int i = 1; i < p; i++)
2545 {
2546 dof_map[0 + (p + i*p1)*p1] = o++; // (3,7)
2547 }
2548
2549 // faces (see Mesh::GenerateFaces in mesh/mesh.cpp)
2550 for (int j = 1; j < p; j++)
2551 {
2552 for (int i = 1; i < p; i++)
2553 {
2554 dof_map[i + ((p-j) + 0*p1)*p1] = o++; // (3,2,1,0)
2555 }
2556 }
2557 for (int j = 1; j < p; j++)
2558 {
2559 for (int i = 1; i < p; i++)
2560 {
2561 dof_map[i + (0 + j*p1)*p1] = o++; // (0,1,5,4)
2562 }
2563 }
2564 for (int j = 1; j < p; j++)
2565 {
2566 for (int i = 1; i < p; i++)
2567 {
2568 dof_map[p + (i + j*p1)*p1] = o++; // (1,2,6,5)
2569 }
2570 }
2571 for (int j = 1; j < p; j++)
2572 {
2573 for (int i = 1; i < p; i++)
2574 {
2575 dof_map[(p-i) + (p + j*p1)*p1] = o++; // (2,3,7,6)
2576 }
2577 }
2578 for (int j = 1; j < p; j++)
2579 {
2580 for (int i = 1; i < p; i++)
2581 {
2582 dof_map[0 + ((p-i) + j*p1)*p1] = o++; // (3,0,4,7)
2583 }
2584 }
2585 for (int j = 1; j < p; j++)
2586 {
2587 for (int i = 1; i < p; i++)
2588 {
2589 dof_map[i + (j + p*p1)*p1] = o++; // (4,5,6,7)
2590 }
2591 }
2592
2593 // interior
2594 for (int k = 1; k < p; k++)
2595 {
2596 for (int j = 1; j < p; j++)
2597 {
2598 for (int i = 1; i < p; i++)
2599 {
2600 dof_map[i + (j + k*p1)*p1] = o++;
2601 }
2602 }
2603 }
2604 break;
2605 }
2606 default:
2607 MFEM_ABORT("invalid dimension: " << dims);
2608 break;
2609 }
2610 }
2611 else if (dmtype == L2_DOF_MAP)
2612 {
2613 // leave dof_map empty, indicating that the dofs are ordered
2614 // lexicographically, i.e. the dof_map is identity
2615 }
2616 else
2617 {
2618 MFEM_ABORT("invalid DofMapType: " << dmtype);
2619 }
2620}
2621
2623 const FiniteElement &fe, const IntegrationRule &ir,
2624 DofToQuad::Mode mode, const Poly_1D::Basis &basis, bool closed,
2625 Array<DofToQuad*> &dof2quad_array)
2626{
2627 DofToQuad *d2q = nullptr;
2628 MFEM_VERIFY(mode == DofToQuad::TENSOR, "invalid mode requested");
2629
2630#if defined(MFEM_THREAD_SAFE) && defined(MFEM_USE_OPENMP)
2631 #pragma omp critical (DofToQuad)
2632#endif
2633 {
2634 for (int i = 0; i < dof2quad_array.Size(); i++)
2635 {
2636 auto* d2q_ = dof2quad_array[i];
2637 if (d2q_->IntRule == &ir && d2q_->mode == mode)
2638 {
2639 d2q = d2q_;
2640 break;
2641 }
2642 }
2643 if (!d2q)
2644 {
2645 d2q = new DofToQuad;
2646 const int ndof = closed ? fe.GetOrder() + 1 : fe.GetOrder();
2647 const int nqpt = (int)floor(pow(ir.GetNPoints(), 1.0/fe.GetDim()) + 0.5);
2648 d2q->FE = &fe;
2649 d2q->IntRule = &ir;
2650 d2q->mode = mode;
2651 d2q->ndof = ndof;
2652 d2q->nqpt = nqpt;
2653 d2q->B.SetSize(nqpt*ndof);
2654 d2q->Bt.SetSize(ndof*nqpt);
2655 d2q->G.SetSize(nqpt*ndof);
2656 d2q->Gt.SetSize(ndof*nqpt);
2657 Vector val(ndof), grad(ndof);
2658 for (int i = 0; i < nqpt; i++)
2659 {
2660 // The first 'nqpt' points in 'ir' have the same x-coordinates as those
2661 // of the 1D rule.
2662 basis.Eval(ir.IntPoint(i).x, val, grad);
2663 for (int j = 0; j < ndof; j++)
2664 {
2665 d2q->B[i+nqpt*j] = d2q->Bt[j+ndof*i] = val(j);
2666 d2q->G[i+nqpt*j] = d2q->Gt[j+ndof*i] = grad(j);
2667 }
2668 }
2669 dof2quad_array.Append(d2q);
2670 }
2671 }
2672 return *d2q;
2673}
2674
2676 const int p,
2677 const int btype,
2678 const DofMapType dmtype)
2679 : NodalFiniteElement(dims, GetTensorProductGeometry(dims), Pow(p + 1, dims),
2680 p, dims > 1 ? FunctionSpace::Qk : FunctionSpace::Pk),
2681 TensorBasisElement(dims, p, btype, dmtype)
2682{
2684}
2685
2687{
2689 // If we are using the "integrated" basis, the basis functions should be
2690 // scaled for MapType::VALUE, and not scaled for MapType::INTEGRAL. This
2691 // ensures spectral equivalence of the mass matrix with its low-order-refined
2692 // counterpart (cf. LORDiscretization)
2694 {
2696 }
2697}
2698
2700 const IntegrationRule &ir,
2701 DofToQuad::Mode mode) const
2702{
2703 if (mode != DofToQuad::TENSOR)
2704 {
2705 return NodalFiniteElement::GetDofToQuad(ir, mode);
2706 }
2707 else
2708 {
2709 return GetTensorDofToQuad(*this, ir, mode, basis1d, true, dof2quad_array);
2710 }
2711}
2712
2714 Array<int> &face_map) const
2715{
2716 internal::GetTensorFaceMap(dim, order, face_id, face_map);
2717}
2718
2720 const int d,
2721 const int p,
2722 const int cbtype,
2723 const int obtype,
2724 const int M,
2725 const DofMapType dmtype)
2726 : VectorFiniteElement(dims, GetTensorProductGeometry(dims), d,
2727 p, M, FunctionSpace::Qk),
2728 TensorBasisElement(dims, p, VerifyNodal(VerifyClosed(cbtype)), dmtype),
2729 obasis1d(poly1d.GetBasis(p - 1, VerifyOpen(obtype)))
2730{
2731 MFEM_VERIFY(dims > 1, "Constructor for VectorTensorFiniteElement with both "
2732 "open and closed bases is not valid for 1D elements.");
2733}
2734
2736 const int d,
2737 const int p,
2738 const int obtype,
2739 const int M,
2740 const DofMapType dmtype)
2741 : VectorFiniteElement(dims, GetTensorProductGeometry(dims), d,
2742 p, M, FunctionSpace::Pk),
2743 TensorBasisElement(dims, p, VerifyOpen(obtype), dmtype),
2744 obasis1d(poly1d.GetBasis(p, VerifyOpen(obtype)))
2745{
2746 MFEM_VERIFY(dims == 1, "Constructor for VectorTensorFiniteElement without "
2747 "closed basis is only valid for 1D elements.");
2748}
2749
2751{
2752 for (int i = 0; i < dof2quad_array_open.Size(); i++)
2753 {
2754 delete dof2quad_array_open[i];
2755 }
2756}
2757
2758}
int NumCols() const
Definition array.hpp:448
void SetSize(int m, int n)
Set the 2D array size to m x n.
Definition array.hpp:445
void SetSize(int nsize)
Change the logical size of the array, keep existing entries.
Definition array.hpp:840
int Size() const
Return the logical size of the array.
Definition array.hpp:166
int Append(const T &el)
Append element 'el' to array, resize if necessary.
Definition array.hpp:912
void Abs()
Replace each entry of the array with its absolute value.
Definition array.cpp:115
T * HostWrite()
Shortcut for mfem::Write(a.GetMemory(), a.Size(), false).
Definition array.hpp:393
static int GetQuadrature1D(int b_type)
Get the corresponding Quadrature1D constant, when that makes sense; otherwise return Quadrature1D::In...
Definition fe_base.hpp:65
static int Check(int b_type)
If the input does not represents a valid BasisType, abort with an error; otherwise return the input.
Definition fe_base.hpp:49
@ GaussLobatto
Closed type.
Definition fe_base.hpp:36
@ Positive
Bernstein polynomials.
Definition fe_base.hpp:37
@ IntegratedGLL
Integrated GLL indicator functions.
Definition fe_base.hpp:43
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.
void Factor()
Factor the current DenseMatrix, *a.
void Mult(const real_t *x, real_t *y) const
Matrix vector multiplication with the inverse of dense matrix.
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 MultTranspose(const real_t *x, real_t *y) const
Multiply a vector with the transpose matrix.
Definition densemat.cpp:158
void Threshold(real_t eps)
Replace small entries, abs(a_ij) <= eps, with zero.
void SetRow(int r, const real_t *row)
void GetColumnReference(int c, Vector &col)
Definition densemat.hpp:331
real_t InnerProduct(const real_t *x, const real_t *y) const
Compute y^t A x.
Definition densemat.cpp:281
real_t * Data() const
Returns the matrix data array. Warning: this method casts away constness.
Definition densemat.hpp:122
real_t * GetData() const
Returns the matrix data array. Warning: this method casts away constness.
Definition densemat.hpp:126
void SetSize(int s)
Change the size of the DenseMatrix to s x s.
Definition densemat.hpp:116
void Invert()
Replaces the current matrix with its inverse.
Definition densemat.cpp:674
void InvRightScaling(const Vector &s)
InvRightScaling: this = this * diag(1./s);.
Definition densemat.cpp:340
void GetColumn(int c, Vector &col) const
real_t FNorm2() const
Compute the square of the Frobenius norm of the matrix.
Definition densemat.hpp:288
Structure representing the matrices/tensors needed to evaluate (in reference space) the values,...
Definition fe_base.hpp:141
Mode mode
Describes the contents of the B, Bt, G, and Gt arrays, see Mode.
Definition fe_base.hpp:174
const IntegrationRule * IntRule
IntegrationRule that defines the quadrature points at which the basis functions of the FE are evaluat...
Definition fe_base.hpp:150
Array< real_t > G
Gradients/divergences/curls of basis functions evaluated at quadrature points.
Definition fe_base.hpp:214
Mode
Type of data stored in the arrays B, Bt, G, and Gt.
Definition fe_base.hpp:154
@ FULL
Full multidimensional representation which does not use tensor product structure. The ordering of the...
Definition fe_base.hpp:158
@ LEXICOGRAPHIC_FULL
Full multidimensional representation which does not use tensor product structure. The ordering of the...
Definition fe_base.hpp:170
@ TENSOR
Tensor product representation using 1D matrices/tensors with dimensions using 1D number of quadrature...
Definition fe_base.hpp:165
Array< real_t > B
Basis functions evaluated at quadrature points.
Definition fe_base.hpp:193
int ndof
Number of degrees of freedom = number of basis functions. When mode is TENSOR, this is the 1D number.
Definition fe_base.hpp:178
Array< real_t > Gt
Transpose of G.
Definition fe_base.hpp:221
const class FiniteElement * FE
The FiniteElement that created and owns this object.
Definition fe_base.hpp:145
int nqpt
Number of quadrature points. When mode is TENSOR, this is the 1D number.
Definition fe_base.hpp:182
Array< real_t > Bt
Transpose of B.
Definition fe_base.hpp:199
DofToQuad Abs() const
Returns absolute value of the maps.
Definition fe_base.cpp:23
const DenseMatrix & Hessian()
Return the Hessian matrix of the transformation at the currently set IntegrationPoint,...
Definition eltrans.hpp:138
const DenseMatrix & InverseJacobian()
Return the inverse of the Jacobian matrix of the transformation at the currently set IntegrationPoint...
Definition eltrans.hpp:158
const DenseMatrix & AdjugateJacobian()
Return the adjugate of the Jacobian matrix of the transformation at the currently set IntegrationPoin...
Definition eltrans.hpp:148
const IntegrationPoint & GetIntPoint()
Get a const reference to the currently set integration point. This will return NULL if no integration...
Definition eltrans.hpp:111
virtual int GetSpaceDim() const =0
Get the dimension of the target (physical) space.
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 ...
Abstract class for all finite elements.
Definition fe_base.hpp:247
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 dof
Number of degrees of freedom.
Definition fe_base.hpp:256
virtual void CalcHessian(const IntegrationPoint &ip, DenseMatrix &Hessian) const
Evaluate the Hessians of all shape functions of a scalar finite element in reference space at the giv...
Definition fe_base.cpp:111
virtual void ProjectMatrixCoefficient(MatrixCoefficient &mc, ElementTransformation &T, Vector &dofs) const
Given a matrix coefficient and a transformation, compute an approximation ("projection") in the local...
Definition fe_base.cpp:154
virtual ~FiniteElement()
Deconstruct the FiniteElement.
Definition fe_base.cpp:523
virtual void ProjectDiv(const FiniteElement &fe, ElementTransformation &Trans, DenseMatrix &div) const
Compute the discrete divergence matrix from the given FiniteElement onto 'this' FiniteElement....
Definition fe_base.cpp:185
virtual void ProjectFromNodes(Vector &vc, ElementTransformation &Trans, Vector &dofs) const
Given a vector of values at the finite element nodes and a transformation, compute its projection (ap...
Definition fe_base.cpp:148
virtual void GetFaceDofs(int face, int **dofs, int *ndofs) const
Get the dofs associated with the given face. *dofs is set to an internal array of the local dofc on t...
Definition fe_base.cpp:106
virtual const DofToQuad & GetDofToQuad(const IntegrationRule &ir, DofToQuad::Mode mode) const
Return a DofToQuad structure corresponding to the given IntegrationRule using the given DofToQuad::Mo...
Definition fe_base.cpp:375
int GetRangeDim() const
Returns the vector dimension for vector-valued finite elements, which is also the dimension of the in...
Definition fe_base.hpp:328
int GetOrder() const
Returns the order of the finite element. In the case of anisotropic orders, returns the maximum order...
Definition fe_base.hpp:341
void CalcPhysDShape(ElementTransformation &Trans, DenseMatrix &dshape) const
Evaluate the gradients of all shape functions of a scalar finite element in physical space at the poi...
Definition fe_base.cpp:202
virtual void CalcCurlShape(const IntegrationPoint &ip, DenseMatrix &curl_shape) const
Evaluate the curl of all shape functions of a vector finite element in reference space at the given p...
Definition fe_base.cpp:75
virtual void ProjectGrad(const FiniteElement &fe, ElementTransformation &Trans, DenseMatrix &grad) const
Compute the discrete gradient matrix from the given FiniteElement onto 'this' FiniteElement....
Definition fe_base.cpp:171
IntegrationRule Nodes
Definition fe_base.hpp:259
virtual void GetFaceMap(const int face_id, Array< int > &face_map) const
Return the mapping from lexicographic face DOFs to lexicographic element DOFs for the given local fac...
Definition fe_base.cpp:517
int GetDim() const
Returns the reference space dimension for the finite element.
Definition fe_base.hpp:324
int vdim
Vector dimension of vector-valued basis functions.
Definition fe_base.hpp:250
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:298
FiniteElement(int D, Geometry::Type G, int Do, int O, int F=FunctionSpace::Pk)
Construct FiniteElement with given.
Definition fe_base.cpp:33
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 orders[Geometry::MaxDim]
Anisotropic orders.
Definition fe_base.hpp:258
virtual void GetTransferMatrix(const FiniteElement &fe, ElementTransformation &Trans, DenseMatrix &I) const
Return interpolation matrix, I, which maps dofs from a coarse element, fe, to the fine dofs on this f...
Definition fe_base.cpp:129
int GetMapType() const
Returns the FiniteElement::MapType of the element describing how reference functions are mapped to ph...
Definition fe_base.hpp:363
int GetRangeType() const
Returns the FiniteElement::RangeType of the element, one of {SCALAR, VECTOR}.
Definition fe_base.hpp:354
virtual void GetLocalRestriction(ElementTransformation &Trans, DenseMatrix &R) const
Return a local restriction matrix R (Dof x Dof) mapping fine dofs to coarse dofs.
Definition fe_base.cpp:123
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:334
int cdim
Dimension of curl for vector-valued basis functions.
Definition fe_base.hpp:251
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 GetLocalInterpolation(ElementTransformation &Trans, DenseMatrix &I) const
Return the local interpolation matrix I (Dof x Dof) where the fine element is the image of the base g...
Definition fe_base.cpp:117
@ DIV
Implements CalcDivShape methods.
Definition fe_base.hpp:309
@ NONE
No derivatives implemented.
Definition fe_base.hpp:307
@ CURL
Implements CalcCurlShape methods.
Definition fe_base.hpp:310
@ GRAD
Implements CalcDShape methods.
Definition fe_base.hpp:308
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
Geometry::Type geom_type
Geometry::Type of the reference element.
Definition fe_base.hpp:252
void CalcPhysDivShape(ElementTransformation &Trans, Vector &divshape) const
Evaluate the divergence of all shape functions of a vector finite element in physical space at the po...
Definition fe_base.cpp:68
Array< DofToQuad * > dof2quad_array
Container for all DofToQuad objects created by the FiniteElement.
Definition fe_base.hpp:266
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
DenseMatrix vshape
Definition fe_base.hpp:261
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 ProjectCurl(const FiniteElement &fe, ElementTransformation &Trans, DenseMatrix &curl) const
Compute the discrete curl matrix from the given FiniteElement onto 'this' FiniteElement....
Definition fe_base.cpp:178
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:337
int order
Order/degree of the shape functions.
Definition fe_base.hpp:257
void CalcPhysLinLaplacian(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:254
int dim
Dimension of reference space.
Definition fe_base.hpp:249
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
Describes the function space on each element.
Definition fe_base.hpp:229
static const int MaxDim
Definition geom.hpp:47
const IntegrationPoint & GetCenter(int GeomType) const
Return the center of the given Geometry::Type, GeomType.
Definition geom.hpp:75
static bool CheckPoint(int GeomType, const IntegrationPoint &ip)
Check if the given point is inside the given reference element.
Definition geom.cpp:435
Class for integration point with weight.
Definition intrules.hpp:35
void Get(real_t *p, const int dim) const
Definition intrules.hpp:60
void Set(const real_t *p, const int dim)
Definition intrules.hpp:46
void Set3(const real_t x1, const real_t x2, const real_t x3)
Definition intrules.hpp:79
Class for an integration rule - an Array of IntegrationPoint.
Definition intrules.hpp:100
int GetNPoints() const
Returns the number of the points in the integration rule.
Definition intrules.hpp:256
IntegrationPoint & IntPoint(int i)
Returns a reference to the i-th integration point.
Definition intrules.hpp:259
const IntegrationRule & Get(int GeomType, int Order)
Returns an integration rule for given GeomType and Order.
Base class for Matrix Coefficients that optionally depend on time and space.
virtual void Eval(DenseMatrix &K, ElementTransformation &T, const IntegrationPoint &ip)=0
Evaluate the matrix coefficient in the element described by T at the point ip, storing the result in ...
int GetWidth() const
Get the width of the matrix.
int GetHeight() const
Get the height of the matrix.
Class for standard nodal finite elements.
Definition fe_base.hpp:724
void Project(Coefficient &coeff, ElementTransformation &Trans, Vector &dofs) const override
Given a coefficient and a transformation, compute its projection (approximation) in the local finite ...
Definition fe_base.cpp:819
void ProjectCurl_2D(const FiniteElement &fe, ElementTransformation &Trans, DenseMatrix &curl) const
Definition fe_base.cpp:747
void ReorderLexToNative(int ncomp, Vector &dofs) const
Definition fe_base.cpp:999
void ProjectDiv(const FiniteElement &fe, ElementTransformation &Trans, DenseMatrix &div) const override
Compute the discrete divergence matrix from the given FiniteElement onto 'this' FiniteElement....
Definition fe_base.cpp:968
void GetLocalRestriction(ElementTransformation &Trans, DenseMatrix &R) const override
Return a local restriction matrix R (Dof x Dof) mapping fine dofs to coarse dofs.
Definition fe_base.cpp:787
void ProjectGrad(const FiniteElement &fe, ElementTransformation &Trans, DenseMatrix &grad) const override
Compute the discrete gradient matrix from the given FiniteElement onto 'this' FiniteElement....
Definition fe_base.cpp:939
void ProjectMatrixCoefficient(MatrixCoefficient &mc, ElementTransformation &T, Vector &dofs) const override
Given a matrix coefficient and a transformation, compute an approximation ("projection") in the local...
Definition fe_base.cpp:858
Array< int > lex_ordering
Definition fe_base.hpp:729
const DofToQuad & GetDofToQuad(const IntegrationRule &ir, DofToQuad::Mode mode) const override
Return a DofToQuad structure corresponding to the given IntegrationRule using the given DofToQuad::Mo...
Definition fe_base.cpp:719
void GetFaceMap(const int face_id, Array< int > &face_map) const override
Return the mapping from lexicographic face DOFs to lexicographic element DOFs for the given local fac...
Definition fe_base.cpp:2713
NodalTensorFiniteElement(const int dims, const int p, const int btype, const DofMapType dmtype)
Definition fe_base.cpp:2675
const DofToQuad & GetDofToQuad(const IntegrationRule &ir, DofToQuad::Mode mode) const override
Return a DofToQuad structure corresponding to the given IntegrationRule using the given DofToQuad::Mo...
Definition fe_base.cpp:2699
void SetMapType(const int map_type_) override
Set the FiniteElement::MapType of the element to either VALUE or INTEGRAL. Also sets the FiniteElemen...
Definition fe_base.cpp:2686
int Height() const
Get the height (size of output) of the Operator. Synonym with NumRows().
Definition operator.hpp:66
int Width() const
Get the width (size of input) of the Operator. Synonym with NumCols().
Definition operator.hpp:72
Class for evaluating 1D nodal, positive (Bernstein), or integrated (Gerritsma) bases.
Definition fe_base.hpp:1006
void Eval(const real_t x, Vector &u) const
Evaluate the basis functions at point x in [0,1].
Definition fe_base.cpp:1800
bool IsIntegratedType() const
Returns true if the basis is "integrated", false otherwise.
Definition fe_base.hpp:1050
void ScaleIntegrated(bool scale_integrated_)
Set whether the "integrated" basis should be scaled by the subcell sizes. Has no effect for non-integ...
Definition fe_base.cpp:2057
void EvalIntegrated(const Vector &d, Vector &i) const
Evaluate the "integrated" basis type using pre-computed closed basis derivatives.
Definition fe_base.cpp:2032
Basis(const int p, const real_t *nodes, EvalType etype=Barycentric)
Create a nodal or positive (Bernstein) basis of degree p.
Definition fe_base.cpp:1736
static void CalcDBinomTerms(const int p, const real_t x, const real_t y, real_t *d)
Compute the derivatives (w.r.t. x) of the terms in the expansion of the binomial (x + y)^p assuming t...
Definition fe_base.cpp:2180
const real_t * GetPoints(const int p, const int btype, bool on_device=false)
Get the coordinates of the points of the given BasisType, btype.
Definition fe_base.hpp:1109
static const int * Binom(const int p)
Get a pointer to an array containing the binomial coefficients "pchoose k" for k=0,...
Definition fe_base.cpp:2067
Basis & GetBasis(const int p, const int btype)
Get a Poly_1D::Basis object of the given degree and BasisType, btype.
Definition fe_base.cpp:2395
const Array< real_t > * GetPointsArray(const int p, const int btype)
Get the coordinates of the points of the given BasisType, btype.
Definition fe_base.cpp:2367
static void CalcDyBinomTerms(const int p, const real_t x, const real_t y, real_t *d)
Compute the derivatives (w.r.t. y) of the terms in the expansion of the binomial (x + y)^p....
Definition fe_base.cpp:2239
static void CalcLegendre(const int p, const real_t x, real_t *u)
Definition fe_base.cpp:2268
static void CalcBernstein(const int p, const real_t x, real_t *u)
Compute the values of the Bernstein basis functions of order p at coordinate x and store the results ...
Definition fe_base.hpp:1218
EvalType
One-dimensional basis evaluation type.
Definition fe_base.hpp:995
@ ChangeOfBasis
Use change of basis, O(p^2) Evals.
Definition fe_base.hpp:996
@ Integrated
Integrated indicator functions (cf. Gerritsma)
Definition fe_base.hpp:999
@ Positive
Fast evaluation of Bernstein polynomials.
Definition fe_base.hpp:998
@ Barycentric
Use barycentric Lagrangian interpolation, O(p) Evals.
Definition fe_base.hpp:997
static void ChebyshevPoints(const int p, real_t *x)
Compute the points for the Chebyshev polynomials of order p and place them in the already allocated x...
Definition fe_base.cpp:2084
static void CalcBasis(const int p, const real_t x, real_t *u)
Evaluate the values of a hierarchical 1D basis at point x hierarchical = k-th basis function is degre...
Definition fe_base.hpp:1143
static void CalcBinomTerms(const int p, const real_t x, const real_t y, real_t *u)
Compute the p terms in the expansion of the binomial (x + y)^p and store them in the already allocate...
Definition fe_base.cpp:2116
static void CalcDxBinomTerms(const int p, const real_t x, const real_t y, real_t *d)
Compute the derivatives (w.r.t. x) of the terms in the expansion of the binomial (x + y)^p....
Definition fe_base.cpp:2210
static void GivePolyPoints(const int np, real_t *pts, const int type)
Definition intrules.cpp:717
Class for finite elements with basis functions that return scalar values.
Definition fe_base.hpp:665
void NodalLocalInterpolation(ElementTransformation &Trans, DenseMatrix &I, const ScalarFiniteElement &fine_fe) const
Get the matrix I that defines nodal interpolation between this element and the refined element fine_f...
Definition fe_base.cpp:532
virtual void SetMapType(int M)
Set the FiniteElement::MapType of the element to either VALUE or INTEGRAL. Also sets the FiniteElemen...
Definition fe_base.hpp:690
void ScalarLocalInterpolation(ElementTransformation &Trans, DenseMatrix &I, const ScalarFiniteElement &fine_fe) const
Get matrix I "Interpolation" defined through local L2-projection in the space defined by the fine_fe.
Definition fe_base.cpp:571
void ScalarLocalL2Restriction(ElementTransformation &Trans, DenseMatrix &R, const ScalarFiniteElement &coarse_fe) const
Get restriction matrix R defined through local L2-projection in the space defined by the coarse_fe.
Definition fe_base.cpp:612
Poly_1D::Basis & basis1d
Definition fe_base.hpp:1254
static const DofToQuad & GetTensorDofToQuad(const FiniteElement &fe, const IntegrationRule &ir, DofToQuad::Mode mode, const Poly_1D::Basis &basis, bool closed, Array< DofToQuad * > &dof2quad_array)
Definition fe_base.cpp:2622
TensorBasisElement(const int dims, const int p, const int btype, const DofMapType dmtype)
Definition fe_base.cpp:2422
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 ...
Intermediate class for finite elements whose basis functions return vector values.
Definition fe_base.hpp:816
void ProjectGrad_RT(const real_t *nk, const Array< int > &d2n, const FiniteElement &fe, ElementTransformation &Trans, DenseMatrix &grad) const
Definition fe_base.cpp:1245
void LocalRestriction_RT(const real_t *nk, const Array< int > &d2n, ElementTransformation &Trans, DenseMatrix &R) const
Definition fe_base.cpp:1651
void Project_ND(const real_t *tk, const Array< int > &d2t, VectorCoefficient &vc, ElementTransformation &Trans, Vector &dofs) const
Project a vector coefficient onto the ND basis functions.
Definition fe_base.cpp:1329
void Project_RT(const real_t *nk, const Array< int > &d2n, VectorCoefficient &vc, ElementTransformation &Trans, Vector &dofs) const
Project a vector coefficient onto the RT basis functions.
Definition fe_base.cpp:1105
void LocalInterpolation_RT(const VectorFiniteElement &cfe, const real_t *nk, const Array< int > &d2n, ElementTransformation &Trans, DenseMatrix &I) const
Definition fe_base.cpp:1525
void ProjectMatrixCoefficient_ND(const real_t *tk, const Array< int > &d2t, MatrixCoefficient &mc, ElementTransformation &T, Vector &dofs) const
Project the rows of the matrix coefficient in an ND space.
Definition fe_base.cpp:1358
void LocalRestriction_ND(const real_t *tk, const Array< int > &d2t, ElementTransformation &Trans, DenseMatrix &R) const
Definition fe_base.cpp:1694
void LocalL2Projection_RT(const VectorFiniteElement &cfe, ElementTransformation &Trans, DenseMatrix &I) const
Definition fe_base.cpp:1478
void ProjectGrad_ND(const real_t *tk, const Array< int > &d2t, const FiniteElement &fe, ElementTransformation &Trans, DenseMatrix &grad) const
Definition fe_base.cpp:1457
void CalcVShape_ND(ElementTransformation &Trans, DenseMatrix &shape) const
Definition fe_base.cpp:1094
void CalcVShape_RT(ElementTransformation &Trans, DenseMatrix &shape) const
Definition fe_base.cpp:1082
VectorFiniteElement(int D, Geometry::Type G, int Do, int O, int M, int F=FunctionSpace::Pk)
Definition fe_base.cpp:1016
void LocalInterpolation_ND(const VectorFiniteElement &cfe, const real_t *tk, const Array< int > &d2t, ElementTransformation &Trans, DenseMatrix &I) const
Definition fe_base.cpp:1612
void ProjectCurl_RT(const real_t *nk, const Array< int > &d2n, const FiniteElement &fe, ElementTransformation &Trans, DenseMatrix &curl) const
Definition fe_base.cpp:1310
void LocalL2Projection_ND(const VectorFiniteElement &cfe, ElementTransformation &Trans, DenseMatrix &I) const
Definition fe_base.cpp:1566
void ProjectCurl_ND(const real_t *tk, const Array< int > &d2t, const FiniteElement &fe, ElementTransformation &Trans, DenseMatrix &curl) const
Definition fe_base.cpp:1272
void ProjectMatrixCoefficient_RT(const real_t *nk, const Array< int > &d2n, MatrixCoefficient &mc, ElementTransformation &T, Vector &dofs) const
Project the rows of the matrix coefficient in an RT space.
Definition fe_base.cpp:1142
VectorTensorFiniteElement(const int dims, const int d, const int p, const int cbtype, const int obtype, const int M, const DofMapType dmtype)
Definition fe_base.cpp:2719
Vector data type.
Definition vector.hpp:82
void SetDataAndSize(real_t *d, int s)
Set the Vector data and size.
Definition vector.hpp:191
int Size() const
Returns the size of the vector.
Definition vector.hpp:234
void SetSize(int s)
Resize the vector to size s.
Definition vector.hpp:584
real_t * GetData() const
Return a pointer to the beginning of the Vector data.
Definition vector.hpp:243
void trans(const Vector &u, Vector &x)
Definition ex27.cpp:412
real_t b
Definition lissajous.cpp:42
mfem::real_t real_t
real_t infinity()
Define a shortcut for std::numeric_limits<double>::infinity()
Definition vector.hpp:47
real_t u(const Vector &xvec)
Definition lor_mms.hpp:22
void mfem_error(const char *msg)
Definition error.cpp:154
void Mult(const Table &A, const Table &B, Table &C)
C = A * B (as boolean matrices)
Definition table.cpp:505
Geometry Geometries
Definition fe.cpp:49
void MultABt(const DenseMatrix &A, const DenseMatrix &B, DenseMatrix &ABt)
Multiply a matrix A with the transpose of a matrix B: A*Bt.
void CalcInverse(const DenseMatrix &a, DenseMatrix &inva)
void AddMult_a_VWt(const real_t a, const Vector &v, const Vector &w, DenseMatrix &VWt)
VWt += a * v w^t.
void AddMult_a_VVt(const real_t a, const Vector &v, DenseMatrix &VVt)
VVt += a * v v^t.
void AddMult_a_AAt(real_t a, const DenseMatrix &A, DenseMatrix &AAt)
AAt += a * A * A^t.
void MultAAt(const DenseMatrix &a, DenseMatrix &aat)
Calculate the matrix A.At.
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
Poly_1D poly1d
Definition fe.cpp:28
void InvertLinearTrans(ElementTransformation &trans, const IntegrationPoint &pt, Vector &x)
Definition fe_base.cpp:771
IntegrationRules IntRules(0, Quadrature1D::GaussLegendre)
A global object with all integration rules (defined in intrules.cpp)
Definition intrules.hpp:492
real_t p(const Vector &x, real_t t)
std::array< int, NCMesh::MaxFaceNodes > nodes