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