MFEM v4.9.0
Finite element discretization library
Loading...
Searching...
No Matches
fespace.cpp
Go to the documentation of this file.
1// Copyright (c) 2010-2025, Lawrence Livermore National Security, LLC. Produced
2// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
3// LICENSE and NOTICE for details. LLNL-CODE-806117.
4//
5// This file is part of the MFEM library. For more information and source code
6// availability visit https://mfem.org.
7//
8// MFEM is free software; you can redistribute it and/or modify it under the
9// terms of the BSD-3 license. We welcome feedback and contributions, see file
10// CONTRIBUTING.md for details.
11
12// Implementation of FiniteElementSpace
13
14#include "../general/text.hpp"
15#include "../general/forall.hpp"
17#include "fem.hpp"
19
20#include "derefmat_op.hpp"
21
22#include <algorithm>
23#include <cmath>
24#include <cstdarg>
25
26using namespace std;
27
28namespace mfem
29{
30
32 : mesh(NULL), fec(NULL), vdim(0), ordering(Ordering::byNODES),
33 ndofs(0), nvdofs(0), nedofs(0), nfdofs(0), nbdofs(0),
34 bdofs(NULL),
35 elem_dof(NULL), elem_fos(NULL), bdr_elem_dof(NULL), bdr_elem_fos(NULL),
36 face_dof(NULL),
37 NURBSext(NULL), own_ext(false),
38 cP_is_set(false),
39 Th(Operator::ANY_TYPE),
40 sequence(0), mesh_sequence(0), orders_changed(false), relaxed_hp(false)
41{ }
42
44 Mesh *mesh_,
45 const FiniteElementCollection *fec_)
46{
47 mesh_ = mesh_ ? mesh_ : orig.mesh;
48 fec_ = fec_ ? fec_ : orig.fec;
49
50 NURBSExtension *nurbs_ext = NULL;
51 if (orig.NURBSext && orig.NURBSext != orig.mesh->NURBSext)
52 {
53#ifdef MFEM_USE_MPI
54 ParNURBSExtension *pNURBSext =
55 dynamic_cast<ParNURBSExtension *>(orig.NURBSext);
56 if (pNURBSext)
57 {
58 nurbs_ext = new ParNURBSExtension(*pNURBSext);
59 }
60 else
61#endif
62 {
63 nurbs_ext = new NURBSExtension(*orig.NURBSext);
64 }
65 }
66
67 Constructor(mesh_, nurbs_ext, fec_, orig.vdim, orig.ordering);
68}
69
71 const FiniteElementCollection *fec,
72 int vdim, int ordering)
73{ Constructor(mesh, NULL, fec, vdim, ordering); }
74
76 const FiniteElementCollection *fec,
77 int vdim, int ordering)
78{ Constructor(mesh, ext, fec, vdim, ordering); }
79
81 const FiniteElementSpace &fes, const Array<int> *perm)
82{
83 MFEM_VERIFY(cP == NULL, "");
84 MFEM_VERIFY(cR == NULL, "");
85
86 SparseMatrix *perm_mat = NULL, *perm_mat_tr = NULL;
87 if (perm)
88 {
89 // Note: although n and fes.GetVSize() are typically equal, in
90 // variable-order spaces they may differ, since nonconforming edges/faces
91 // my have fictitious DOFs.
92 int n = perm->Size();
93 perm_mat = new SparseMatrix(n, fes.GetVSize());
94 for (int i=0; i<n; ++i)
95 {
96 real_t s;
97 int j = DecodeDof((*perm)[i], s);
98 perm_mat->Set(i, j, s);
99 }
100 perm_mat->Finalize();
101 perm_mat_tr = Transpose(*perm_mat);
102 }
103
104 if (fes.GetConformingProlongation() != NULL)
105 {
106 if (perm) { cP.reset(Mult(*perm_mat, *fes.GetConformingProlongation())); }
107 else { cP.reset(new SparseMatrix(*fes.GetConformingProlongation())); }
108 cP_is_set = true;
109 }
110 else if (perm != NULL)
111 {
112 cP.reset(perm_mat);
113 cP_is_set = true;
114 perm_mat = NULL;
115 }
116 if (fes.GetConformingRestriction() != NULL)
117 {
118 if (perm) { cR.reset(Mult(*fes.GetConformingRestriction(), *perm_mat_tr)); }
119 else { cR.reset(new SparseMatrix(*fes.GetConformingRestriction())); }
120 }
121 else if (perm != NULL)
122 {
123 cR.reset(perm_mat_tr);
124 perm_mat_tr = NULL;
125 }
126
127 delete perm_mat;
128 delete perm_mat_tr;
129}
130
132{
133#ifdef MFEM_USE_MPI
134 MFEM_VERIFY(dynamic_cast<const ParFiniteElementSpace*>(this) == NULL,
135 "Attempting to set serial prolongation operator for "
136 "parallel finite element space.");
137#endif
138
139 if (!cP)
140 {
141 cP = std::unique_ptr<SparseMatrix>(new SparseMatrix(p));
142 }
143 else
144 {
145 *cP = p;
146 }
147 cP_is_set = true;
148}
149
151{
152#ifdef MFEM_USE_MPI
153 MFEM_VERIFY(dynamic_cast<const ParFiniteElementSpace*>(this) == NULL,
154 "Attempting to set serial restriction operator for "
155 "parallel finite element space.");
156#endif
157
158 if (!cR)
159 {
160 cR = std::unique_ptr<SparseMatrix>(new SparseMatrix(r));
161 }
162 else
163 {
164 *cR = r;
165 }
166}
167
169{
170 MFEM_VERIFY(mesh_sequence == mesh->GetSequence(),
171 "Space has not been Updated() after a Mesh change.");
172 MFEM_VERIFY(i >= 0 && i < GetNE(), "Invalid element index");
173 MFEM_VERIFY(p >= 0 && p <= MaxVarOrder, "Order out of range");
174 MFEM_ASSERT(!elem_order.Size() || elem_order.Size() == GetNE(),
175 "Internal error");
176
177 const bool change = elem_order.Size() == 0 || elem_order[i] != p;
178 if (elem_order.Size() == 0) // convert space to variable-order space
179 {
182 }
183
184 if (change)
185 {
186 elem_order[i] = p;
187 orders_changed = true;
188 }
189
190 variableOrder = true;
191}
192
194{
195 MFEM_VERIFY(mesh_sequence == mesh->GetSequence(),
196 "Space has not been Updated() after a Mesh change.");
197 MFEM_VERIFY(i >= 0 && i < GetNE(), "Invalid element index");
198 MFEM_ASSERT(!elem_order.Size() || elem_order.Size() == GetNE(),
199 "Internal error");
200
201 return GetElementOrderImpl(i);
202}
203
205{
206 // (this is an internal version of GetElementOrder without asserts and checks)
207 return elem_order.Size() ? elem_order[i] : fec->GetOrder();
208}
209
210void FiniteElementSpace::GetVDofs(int vd, Array<int>& dofs, int ndofs_) const
211{
212 if (ndofs_ < 0) { ndofs_ = this->ndofs; }
213
215 {
216 for (int i = 0; i < dofs.Size(); i++)
217 {
218 dofs[i] = Ordering::Map<Ordering::byNODES>(ndofs_, vdim, i, vd);
219 }
220 }
221 else
222 {
223 for (int i = 0; i < dofs.Size(); i++)
224 {
225 dofs[i] = Ordering::Map<Ordering::byVDIM>(ndofs_, vdim, i, vd);
226 }
227 }
228}
229
230void FiniteElementSpace::DofsToVDofs(Array<int> &dofs, int ndofs_) const
231{
232 if (vdim == 1) { return; }
233 if (ndofs_ < 0) { ndofs_ = this->ndofs; }
234
236 {
237 Ordering::DofsToVDofs<Ordering::byNODES>(ndofs_, vdim, dofs);
238 }
239 else
240 {
241 Ordering::DofsToVDofs<Ordering::byVDIM>(ndofs_, vdim, dofs);
242 }
243}
244
245void FiniteElementSpace::DofsToVDofs(int vd, Array<int> &dofs, int ndofs_) const
246{
247 if (vdim == 1) { return; }
248 if (ndofs_ < 0) { ndofs_ = this->ndofs; }
249
251 {
252 for (int i = 0; i < dofs.Size(); i++)
253 {
254 dofs[i] = Ordering::Map<Ordering::byNODES>(ndofs_, vdim, dofs[i], vd);
255 }
256 }
257 else
258 {
259 for (int i = 0; i < dofs.Size(); i++)
260 {
261 dofs[i] = Ordering::Map<Ordering::byVDIM>(ndofs_, vdim, dofs[i], vd);
262 }
263 }
264}
265
266int FiniteElementSpace::DofToVDof(int dof, int vd, int ndofs_) const
267{
268 if (vdim == 1) { return dof; }
269 if (ndofs_ < 0) { ndofs_ = this->ndofs; }
270
272 {
273 return Ordering::Map<Ordering::byNODES>(ndofs_, vdim, dof, vd);
274 }
275 else
276 {
277 return Ordering::Map<Ordering::byVDIM>(ndofs_, vdim, dof, vd);
278 }
279}
280
281// static function
283{
284 int n = vdofs.Size(), *vdof = vdofs;
285 for (int i = 0; i < n; i++)
286 {
287 int j;
288 if ((j = vdof[i]) < 0)
289 {
290 vdof[i] = -1-j;
291 }
292 }
293}
294
296 DofTransformation &doftrans) const
297{
298 GetElementDofs(i, vdofs, doftrans);
299 DofsToVDofs(vdofs);
300 doftrans.SetVDim(vdim, ordering);
301}
302
305{
306 GetElementVDofs(i, vdofs, DoFTrans);
307 return DoFTrans.GetDofTransformation() ? &DoFTrans : NULL;
308}
309
311 DofTransformation &doftrans) const
312{
313 GetBdrElementDofs(i, vdofs, doftrans);
314 DofsToVDofs(vdofs);
315 doftrans.SetVDim(vdim, ordering);
316}
317
320{
321 GetBdrElementVDofs(i, vdofs, DoFTrans);
322 return DoFTrans.GetDofTransformation() ? &DoFTrans : NULL;
323}
324
326{
327 GetPatchDofs(i, vdofs);
328 DofsToVDofs(vdofs);
329}
330
332{
333 GetFaceDofs(i, vdofs);
334 DofsToVDofs(vdofs);
335}
336
338{
339 GetEdgeDofs(i, vdofs);
340 DofsToVDofs(vdofs);
341}
342
344{
345 GetVertexDofs(i, vdofs);
346 DofsToVDofs(vdofs);
347}
348
350{
351 GetElementInteriorDofs(i, vdofs);
352 DofsToVDofs(vdofs);
353}
354
356{
357 GetEdgeInteriorDofs(i, vdofs);
358 DofsToVDofs(vdofs);
359}
360
362{
363 if (elem_dof) { return; }
364
365 // TODO: can we call GetElementDofs only once per element?
366 Table *el_dof = new Table;
367 Table *el_fos = (mesh->Dimension() > 2) ? (new Table) : NULL;
368 Array<int> dofs;
369 Array<int> F, Fo;
370 el_dof->MakeI(mesh->GetNE());
371 if (el_fos) { el_fos->MakeI(mesh->GetNE()); }
372 for (int i = 0; i < mesh->GetNE(); i++)
373 {
374 GetElementDofs(i, dofs);
375 el_dof->AddColumnsInRow(i, dofs.Size());
376
377 if (el_fos)
378 {
379 mesh->GetElementFaces(i, F, Fo);
380 el_fos->AddColumnsInRow(i, Fo.Size());
381 }
382 }
383 el_dof->MakeJ();
384 if (el_fos) { el_fos->MakeJ(); }
385 for (int i = 0; i < mesh->GetNE(); i++)
386 {
387 GetElementDofs(i, dofs);
388 el_dof->AddConnections(i, (int *)dofs, dofs.Size());
389
390 if (el_fos)
391 {
392 mesh->GetElementFaces(i, F, Fo);
393 el_fos->AddConnections(i, (int *)Fo, Fo.Size());
394 }
395 }
396 el_dof->ShiftUpI();
397 if (el_fos) { el_fos->ShiftUpI(); }
398 elem_dof = el_dof;
399 elem_fos = el_fos;
400}
401
403{
404 if (bdr_elem_dof) { return; }
405
406 Table *bel_dof = new Table;
407 Table *bel_fos = (mesh->Dimension() == 3) ? (new Table) : NULL;
408 Array<int> dofs;
409 int F, Fo;
410 bel_dof->MakeI(mesh->GetNBE());
411 if (bel_fos) { bel_fos->MakeI(mesh->GetNBE()); }
412 for (int i = 0; i < mesh->GetNBE(); i++)
413 {
414 GetBdrElementDofs(i, dofs);
415 bel_dof->AddColumnsInRow(i, dofs.Size());
416
417 if (bel_fos)
418 {
419 bel_fos->AddAColumnInRow(i);
420 }
421 }
422 bel_dof->MakeJ();
423 if (bel_fos) { bel_fos->MakeJ(); }
424 for (int i = 0; i < mesh->GetNBE(); i++)
425 {
426 GetBdrElementDofs(i, dofs);
427 bel_dof->AddConnections(i, (int *)dofs, dofs.Size());
428
429 if (bel_fos)
430 {
431 mesh->GetBdrElementFace(i, &F, &Fo);
432 bel_fos->AddConnection(i, Fo);
433 }
434 }
435 bel_dof->ShiftUpI();
436 if (bel_fos) { bel_fos->ShiftUpI(); }
437 bdr_elem_dof = bel_dof;
438 bdr_elem_fos = bel_fos;
439}
440
442{
443 // Here, "face" == (dim-1)-dimensional mesh entity.
444
445 if (face_dof) { return; }
446
447 if (NURBSext) { BuildNURBSFaceToDofTable(); return; }
448
449 Table *fc_dof = new Table;
450 Array<int> dofs;
451 fc_dof->MakeI(mesh->GetNumFaces());
452 for (int i = 0; i < fc_dof->Size(); i++)
453 {
454 GetFaceDofs(i, dofs, 0);
455 fc_dof->AddColumnsInRow(i, dofs.Size());
456 }
457 fc_dof->MakeJ();
458 for (int i = 0; i < fc_dof->Size(); i++)
459 {
460 GetFaceDofs(i, dofs, 0);
461 fc_dof->AddConnections(i, (int *)dofs, dofs.Size());
462 }
463 fc_dof->ShiftUpI();
464 face_dof = fc_dof;
465}
466
468{
469 delete elem_dof;
470 delete elem_fos;
471 elem_dof = NULL;
472 elem_fos = NULL;
474}
475
477{
478 Array<int> dof_marker(ndofs);
479
480 dof_marker = -1;
481
482 int *J = elem_dof->GetJ(), nnz = elem_dof->Size_of_connections();
483 for (int k = 0, dof_counter = 0; k < nnz; k++)
484 {
485 const int sdof = J[k]; // signed dof
486 const int dof = (sdof < 0) ? -1-sdof : sdof;
487 int new_dof = dof_marker[dof];
488 if (new_dof < 0)
489 {
490 dof_marker[dof] = new_dof = dof_counter++;
491 }
492 J[k] = (sdof < 0) ? -1-new_dof : new_dof; // preserve the sign of sdof
493 }
494}
495
497{
498 if (dof_elem_array.Size()) { return; }
499
501
504 dof_elem_array = -1;
505 for (int i = 0; i < mesh -> GetNE(); i++)
506 {
507 const int *dofs = elem_dof -> GetRow(i);
508 const int n = elem_dof -> RowSize(i);
509 for (int j = 0; j < n; j++)
510 {
511 int dof = DecodeDof(dofs[j]);
512 if (dof_elem_array[dof] < 0)
513 {
514 dof_elem_array[dof] = i;
515 dof_ldof_array[dof] = j;
516 }
517 }
518 }
519}
520
522{
523 if (dof_bdr_elem_array.Size()) { return; }
524
526
530 for (int i = 0; i < mesh -> GetNBE(); i++)
531 {
532 const int *dofs = bdr_elem_dof -> GetRow(i);
533 const int n = bdr_elem_dof -> RowSize(i);
534 for (int j = 0; j < n; j++)
535 {
536 int dof = DecodeDof(dofs[j]);
537 if (dof_bdr_elem_array[dof] < 0)
538 {
539 dof_bdr_elem_array[dof] = i;
540 dof_bdr_ldof_array[dof] = j;
541 }
542 }
543 }
544}
545
546void MarkDofs(const Array<int> &dofs, Array<int> &mark_array)
547{
548 for (auto d : dofs)
549 {
550 mark_array[d >= 0 ? d : -1 - d] = -1;
551 }
552}
553
555 Array<int> &ess_vdofs,
556 int component) const
557{
558 Array<int> dofs;
559 ess_vdofs.SetSize(GetVSize());
560 ess_vdofs = 0;
561 for (int i = 0; i < GetNBE(); i++)
562 {
563 if (bdr_attr_is_ess[GetBdrAttribute(i)-1])
564 {
565 if (component < 0)
566 {
567 // Mark all components.
568 GetBdrElementVDofs(i, dofs);
569 }
570 else
571 {
572 GetBdrElementDofs(i, dofs);
573 for (auto &d : dofs) { d = DofToVDof(d, component); }
574 }
575 MarkDofs(dofs, ess_vdofs);
576 }
577 }
578
579 // mark possible hidden boundary edges in a non-conforming mesh, also
580 // local DOFs affected by boundary elements on other processors
581 if (Nonconforming())
582 {
583 Array<int> bdr_verts, bdr_edges, bdr_faces;
584 mesh->ncmesh->GetBoundaryClosure(bdr_attr_is_ess, bdr_verts, bdr_edges,
585 bdr_faces);
586 for (auto v : bdr_verts)
587 {
588 if (component < 0)
589 {
590 GetVertexVDofs(v, dofs);
591 }
592 else
593 {
594 GetVertexDofs(v, dofs);
595 for (auto &d : dofs) { d = DofToVDof(d, component); }
596 }
597 MarkDofs(dofs, ess_vdofs);
598 }
599 for (auto e : bdr_edges)
600 {
601 if (component < 0)
602 {
603 GetEdgeVDofs(e, dofs);
604 }
605 else
606 {
607 GetEdgeDofs(e, dofs);
608 for (auto &d : dofs) { d = DofToVDof(d, component); }
609 }
610 MarkDofs(dofs, ess_vdofs);
611 }
612 for (auto f : bdr_faces)
613 {
614 if (component < 0)
615 {
616 GetEntityVDofs(2, f, dofs);
617 }
618 else
619 {
620 GetEntityDofs(2, f, dofs);
621 for (auto &d : dofs) { d = DofToVDof(d, component); }
622 }
623 MarkDofs(dofs, ess_vdofs);
624 }
625 }
626}
627
629 Array<int> &ess_tdof_list,
630 int component) const
631{
632 Array<int> ess_vdofs, ess_tdofs;
633 GetEssentialVDofs(bdr_attr_is_ess, ess_vdofs, component);
635 if (!R)
636 {
637 ess_tdofs.MakeRef(ess_vdofs);
638 }
639 else
640 {
641 R->BooleanMult(ess_vdofs, ess_tdofs);
642#ifdef MFEM_DEBUG
643 // Verify that in boolean arithmetic: P^T ess_dofs = R ess_dofs
644 Array<int> ess_tdofs2(ess_tdofs.Size());
645 GetConformingProlongation()->BooleanMultTranspose(ess_vdofs, ess_tdofs2);
646
647 int counter = 0;
648 std::string error_msg = "failed dof: ";
649 auto ess_tdofs_ = ess_tdofs.HostRead();
650 auto ess_tdofs2_ = ess_tdofs2.HostRead();
651 for (int i = 0; i < ess_tdofs2.Size(); ++i)
652 {
653 if (bool(ess_tdofs_[i]) != bool(ess_tdofs2_[i]))
654 {
655 error_msg += std::to_string(i) += "(R ";
656 error_msg += std::to_string(bool(ess_tdofs_[i])) += " P^T ";
657 error_msg += std::to_string(bool(ess_tdofs2_[i])) += ") ";
658 counter++;
659 }
660 }
661
662 MFEM_ASSERT(R->Height() == GetConformingProlongation()->Width(), "!");
663 MFEM_ASSERT(R->Width() == GetConformingProlongation()->Height(), "!");
664 MFEM_ASSERT(R->Width() == ess_vdofs.Size(), "!");
665 MFEM_VERIFY(counter == 0, "internal MFEM error: counter = " << counter
666 << ' ' << error_msg);
667#endif
668 }
669 MarkerToList(ess_tdofs, ess_tdof_list);
670}
671
673 int component)
674{
675 if (mesh->bdr_attributes.Size())
676 {
677 Array<int> ess_bdr(mesh->bdr_attributes.Max());
678 ess_bdr = 1;
679 GetEssentialTrueDofs(ess_bdr, boundary_dofs, component);
680 }
681 else
682 {
683 boundary_dofs.DeleteAll();
684 }
685}
686
688 int component) const
689{
690 Array<int> dofs;
691 ext_vdofs.SetSize(GetVSize());
692 ext_vdofs = 0;
693
694 Array<int> ext_face_marker;
695 mesh->GetExteriorFaceMarker(ext_face_marker);
696 for (int i = 0; i < ext_face_marker.Size(); i++)
697 {
698 if (ext_face_marker[i])
699 {
700 if (component < 0)
701 {
702 // Mark all components.
703 GetFaceDofs(i, dofs);
704 DofsToVDofs(dofs);
705 }
706 else
707 {
708 GetFaceDofs(i, dofs);
709 for (auto &d : dofs) { d = DofToVDof(d, component); }
710 }
711 MarkDofs(dofs, ext_vdofs);
712 }
713 }
714}
715
717 int component) const
718{
719 Array<int> ext_vdofs, ext_tdofs;
720 GetExteriorVDofs(ext_vdofs, component);
722 if (!R)
723 {
724 ext_tdofs.MakeRef(ext_vdofs);
725 }
726 else
727 {
728 R->BooleanMult(ext_vdofs, ext_tdofs);
729#ifdef MFEM_DEBUG
730 // Verify that in boolean arithmetic: P^T ext_dofs = R ext_dofs
731 Array<int> ext_tdofs2(ext_tdofs.Size());
732 GetConformingProlongation()->BooleanMultTranspose(ext_vdofs, ext_tdofs2);
733
734 int counter = 0;
735 std::string error_msg = "failed dof: ";
736 auto ext_tdofs_ = ext_tdofs.HostRead();
737 auto ext_tdofs2_ = ext_tdofs2.HostRead();
738 for (int i = 0; i < ext_tdofs2.Size(); ++i)
739 {
740 if (bool(ext_tdofs_[i]) != bool(ext_tdofs2_[i]))
741 {
742 error_msg += std::to_string(i) += "(R ";
743 error_msg += std::to_string(bool(ext_tdofs_[i])) += " P^T ";
744 error_msg += std::to_string(bool(ext_tdofs2_[i])) += ") ";
745 counter++;
746 }
747 }
748
749 MFEM_ASSERT(R->Height() == GetConformingProlongation()->Width(), "!");
750 MFEM_ASSERT(R->Width() == GetConformingProlongation()->Height(), "!");
751 MFEM_ASSERT(R->Width() == ext_vdofs.Size(), "!");
752 MFEM_VERIFY(counter == 0, "internal MFEM error: counter = " << counter
753 << ' ' << error_msg);
754#endif
755 }
756 MarkerToList(ext_tdofs, ext_tdof_list);
757}
758
759// static method
761 Array<int> &list)
762{
763 int num_marked = 0;
764 marker.HostRead(); // make sure we can read the array on host
765 for (int i = 0; i < marker.Size(); i++)
766 {
767 if (marker[i]) { num_marked++; }
768 }
769 list.SetSize(0);
770 list.HostWrite();
771 list.Reserve(num_marked);
772 for (int i = 0; i < marker.Size(); i++)
773 {
774 if (marker[i]) { list.Append(i); }
775 }
776}
777
778// static method
779void FiniteElementSpace::ListToMarker(const Array<int> &list, int marker_size,
780 Array<int> &marker, int mark_val)
781{
782 list.HostRead(); // make sure we can read the array on host
783 marker.SetSize(marker_size);
784 marker.HostWrite();
785 marker = 0;
786 for (int i = 0; i < list.Size(); i++)
787 {
788 marker[list[i]] = mark_val;
789 }
790}
791
793 Array<int> &cdofs)
794{
796 if (cP) { cP->BooleanMultTranspose(dofs, cdofs); }
797 else { dofs.Copy(cdofs); }
798}
799
801 Array<int> &dofs)
802{
804 if (cR) { cR->BooleanMultTranspose(cdofs, dofs); }
805 else { cdofs.Copy(dofs); }
806}
807
810{
811 int i, j;
812 Array<int> d_vdofs, c_vdofs;
813 SparseMatrix *R;
814
815 R = new SparseMatrix (cfes -> GetVSize(), GetVSize());
816
817 for (i = 0; i < mesh -> GetNE(); i++)
818 {
819 this -> GetElementVDofs (i, d_vdofs);
820 cfes -> GetElementVDofs (i, c_vdofs);
821
822#ifdef MFEM_DEBUG
823 if (d_vdofs.Size() != c_vdofs.Size())
824 {
825 mfem_error ("FiniteElementSpace::D2C_GlobalRestrictionMatrix (...)");
826 }
827#endif
828
829 for (j = 0; j < d_vdofs.Size(); j++)
830 {
831 R -> Set (c_vdofs[j], d_vdofs[j], 1.0);
832 }
833 }
834
835 R -> Finalize();
836
837 return R;
838}
839
842{
843 int i, j;
844 Array<int> d_dofs, c_dofs;
845 SparseMatrix *R;
846
847 R = new SparseMatrix (cfes -> GetNDofs(), ndofs);
848
849 for (i = 0; i < mesh -> GetNE(); i++)
850 {
851 this -> GetElementDofs (i, d_dofs);
852 cfes -> GetElementDofs (i, c_dofs);
853
854#ifdef MFEM_DEBUG
855 if (c_dofs.Size() != 1)
856 mfem_error ("FiniteElementSpace::"
857 "D2Const_GlobalRestrictionMatrix (...)");
858#endif
859
860 for (j = 0; j < d_dofs.Size(); j++)
861 {
862 R -> Set (c_dofs[0], d_dofs[j], 1.0);
863 }
864 }
865
866 R -> Finalize();
867
868 return R;
869}
870
873{
874 SparseMatrix *R;
875 DenseMatrix loc_restr;
876 Array<int> l_dofs, h_dofs, l_vdofs, h_vdofs;
877
878 int lvdim = lfes->GetVDim();
879 R = new SparseMatrix (lvdim * lfes -> GetNDofs(), lvdim * ndofs);
880
881 Geometry::Type cached_geom = Geometry::INVALID;
882 const FiniteElement *h_fe = NULL;
883 const FiniteElement *l_fe = NULL;
885
886 for (int i = 0; i < mesh -> GetNE(); i++)
887 {
888 this -> GetElementDofs (i, h_dofs);
889 lfes -> GetElementDofs (i, l_dofs);
890
891 // Assuming 'loc_restr' depends only on the Geometry::Type.
893 if (geom != cached_geom)
894 {
895 h_fe = this -> GetFE (i);
896 l_fe = lfes -> GetFE (i);
898 h_fe->Project(*l_fe, T, loc_restr);
899 cached_geom = geom;
900 }
901
902 for (int vd = 0; vd < lvdim; vd++)
903 {
904 l_dofs.Copy(l_vdofs);
905 lfes->DofsToVDofs(vd, l_vdofs);
906
907 h_dofs.Copy(h_vdofs);
908 this->DofsToVDofs(vd, h_vdofs);
909
910 R -> SetSubMatrix (l_vdofs, h_vdofs, loc_restr, 1);
911 }
912 }
913
914 R -> Finalize();
915
916 return R;
917}
918
920 SparseMatrix& deps, Array<int>& master_dofs, Array<int>& slave_dofs,
921 DenseMatrix& I, int skipfirst)
922{
923 for (int i = skipfirst; i < slave_dofs.Size(); i++)
924 {
925 const int sdof = slave_dofs[i];
926 if (!deps.RowSize(sdof)) // not processed yet
927 {
928 for (int j = 0; j < master_dofs.Size(); j++)
929 {
930 const real_t coef = I(i, j);
931 if (std::abs(coef) > 1e-12)
932 {
933 const int mdof = master_dofs[j];
934 if (mdof != sdof && mdof != (-1-sdof))
935 {
936 deps.Add(sdof, mdof, coef);
937 }
938 }
939 }
940 }
941 }
942}
943
945 SparseMatrix &deps, Array<int> &master_dofs, const FiniteElement *master_fe,
946 Array<int> &slave_dofs, int slave_face, const DenseMatrix *pm) const
947{
948 // In variable-order spaces in 3D, we need to only constrain interior face
949 // DOFs (this is done one level up), since edge dependencies can be more
950 // complex and are primarily handled by edge-edge dependencies. The one
951 // exception is edges of slave faces that lie in the interior of the master
952 // face, which are not covered by edge-edge relations. This function finds
953 // such edges and makes them constrained by the master face.
954 // See also https://github.com/mfem/mfem/pull/1423#issuecomment-633916643
955
956 Array<int> V, E, Eo; // TODO: LocalArray
957 mesh->GetFaceVertices(slave_face, V);
958 mesh->GetFaceEdges(slave_face, E, Eo);
959 MFEM_ASSERT(V.Size() == E.Size(), "");
960
961 DenseMatrix I;
963 edge_T.SetFE(&SegmentFE);
964
965 // constrain each edge of the slave face
966 for (int i = 0; i < E.Size(); i++)
967 {
968 int a = i, b = (i+1) % V.Size();
969 if (V[a] > V[b]) { std::swap(a, b); }
970
971 DenseMatrix &edge_pm = edge_T.GetPointMat();
972 edge_pm.SetSize(2, 2);
973
974 // copy two points from the face point matrix
975 real_t mid[2];
976 for (int j = 0; j < 2; j++)
977 {
978 edge_pm(j, 0) = (*pm)(j, a);
979 edge_pm(j, 1) = (*pm)(j, b);
980 mid[j] = 0.5*((*pm)(j, a) + (*pm)(j, b));
981 }
982
983 // check that the edge does not coincide with the master face's edge
984 const real_t eps = 1e-14;
985 if (mid[0] > eps && mid[0] < 1-eps &&
986 mid[1] > eps && mid[1] < 1-eps)
987 {
988 int order = GetEdgeDofs(E[i], slave_dofs, 0);
989
990 const auto *edge_fe = fec->GetFE(Geometry::SEGMENT, order);
991 edge_fe->GetTransferMatrix(*master_fe, edge_T, I);
992
993 AddDependencies(deps, master_dofs, slave_dofs, I, 0);
994 }
995 }
996}
997
998bool FiniteElementSpace::DofFinalizable(int dof, const Array<bool>& finalized,
999 const SparseMatrix& deps)
1000{
1001 const int* dep = deps.GetRowColumns(dof);
1002 int ndep = deps.RowSize(dof);
1003
1004 // are all constraining DOFs finalized?
1005 for (int i = 0; i < ndep; i++)
1006 {
1007 if (!finalized[dep[i]]) { return false; }
1008 }
1009 return true;
1010}
1011
1013 Geometry::Type master_geom,
1014 int variant) const
1015{
1016 // In NC meshes with prisms/tets, a special constraint occurs where a
1017 // prism/tet edge is slave to another element's face (see illustration
1018 // here: https://github.com/mfem/mfem/pull/713#issuecomment-495786362)
1019 // Rather than introduce a new edge-face constraint type, we handle such
1020 // cases as degenerate face-face constraints, where the point-matrix
1021 // rectangle has zero height. This method returns DOFs for the first edge
1022 // of the rectangle, duplicated in the orthogonal direction, to resemble
1023 // DOFs for a quadrilateral face. The extra DOFs are ignored by
1024 // FiniteElementSpace::AddDependencies.
1025
1026 Array<int> edof;
1027 int order = GetEdgeDofs(-1 - index, edof, variant);
1028
1031 int nn = 2*nv + ne;
1032
1033 dofs.SetSize(nn*nn);
1034 if (!dofs.Size()) { return 0; }
1035
1036 dofs = edof[0];
1037
1038 // copy first two vertex DOFs
1039 for (int i = 0; i < nv; i++)
1040 {
1041 dofs[i] = edof[i];
1042 dofs[nv+i] = edof[nv+i];
1043 }
1044 // copy first edge DOFs
1045 int face_vert = Geometry::NumVerts[master_geom];
1046 for (int i = 0; i < ne; i++)
1047 {
1048 dofs[face_vert*nv + i] = edof[2*nv + i];
1049 }
1050
1051 return order;
1052}
1053
1055{
1056 // return the number of vertex and edge DOFs that precede inner DOFs
1057 const int nv = fec->GetNumDof(Geometry::POINT, order);
1058 const int ne = fec->GetNumDof(Geometry::SEGMENT, order);
1059
1060 return Geometry::NumVerts[geom] * (geom == Geometry::SEGMENT ? nv : (nv + ne));
1061}
1062
1064 Geometry::Type master_geom,
1065 int variant) const
1066{
1067 switch (entity)
1068 {
1069 case 0:
1070 GetVertexDofs(index, dofs);
1071 return 0;
1072
1073 case 1:
1074 return GetEdgeDofs(index, dofs, variant);
1075
1076 default:
1077 if (index >= 0)
1078 {
1079 return GetFaceDofs(index, dofs, variant);
1080 }
1081 else
1082 {
1083 return GetDegenerateFaceDofs(index, dofs, master_geom, variant);
1084 }
1085 }
1086}
1087
1089 Geometry::Type master_geom,
1090 int variant) const
1091{
1092 const int n = GetEntityDofs(entity, index, dofs, master_geom, variant);
1093 DofsToVDofs(dofs);
1094 return n;
1095}
1096
1097// Variable-order spaces: enforce minimum rule on conforming edges/faces
1099{
1100 if (!IsVariableOrder()) { return; }
1101
1102 Array<int> master_dofs, slave_dofs;
1103
1105 DenseMatrix I;
1106
1107 for (int entity = 1; entity < mesh->Dimension(); entity++)
1108 {
1109 const Table &ent_dofs = (entity == 1) ? var_edge_dofs : var_face_dofs;
1110 const int num_ent = (entity == 1) ? mesh->GetNEdges() : mesh->GetNFaces();
1111 MFEM_ASSERT(ent_dofs.Size() >= num_ent+1, "");
1112
1113 // add constraints within edges/faces holding multiple DOF sets
1115 for (int i = 0; i < num_ent; i++)
1116 {
1117 if (ent_dofs.RowSize(i) <= 1) { continue; }
1118
1119 Geometry::Type geom =
1120 (entity == 1) ? Geometry::SEGMENT : mesh->GetFaceGeometry(i);
1121
1122 if (geom != last_geom)
1123 {
1125 last_geom = geom;
1126 }
1127
1128 // get lowest order variant DOFs and FE
1129 const int p = GetEntityDofs(entity, i, master_dofs, geom, 0);
1130 const auto *master_fe = fec->GetFE(geom, p);
1131 if (!master_fe) { break; }
1132
1133 // constrain all higher order DOFs: interpolate lowest order function
1134 for (int variant = 1; ; variant++)
1135 {
1136 const int q = GetEntityDofs(entity, i, slave_dofs, geom, variant);
1137 if (q < 0) { break; }
1138
1139 const auto *slave_fe = fec->GetFE(geom, q);
1140 slave_fe->GetTransferMatrix(*master_fe, T, I);
1141
1142 AddDependencies(deps, master_dofs, slave_dofs, I);
1143 }
1144 }
1145 }
1146}
1147
1149{
1150#ifdef MFEM_USE_MPI
1151 MFEM_VERIFY(dynamic_cast<const ParFiniteElementSpace*>(this) == NULL,
1152 "This method should not be used with a ParFiniteElementSpace!");
1153#endif
1154
1155 if (cP_is_set) { return; }
1156 cP_is_set = true;
1157
1158 if (FEColl()->GetContType() == FiniteElementCollection::DISCONTINUOUS)
1159 {
1160 cP.reset();
1161 cR.reset();
1162 cR_hp.reset();
1163 R_transpose.reset();
1164 return;
1165 }
1166
1167 Array<int> master_dofs, slave_dofs, highest_dofs;
1168
1170 DenseMatrix I;
1171
1172 // For each slave DOF, the dependency matrix will contain a row that
1173 // expresses the slave DOF as a linear combination of its immediate master
1174 // DOFs. Rows of independent DOFs will remain empty.
1175 SparseMatrix deps(ndofs);
1176
1177 // Inverse dependencies for the cR_hp matrix in variable-order spaces:
1178 // For each master edge/face with more DOF sets, the inverse dependency
1179 // matrix contains a row that expresses the master true DOF (lowest order)
1180 // as a linear combination of the highest order set of DOFs.
1181 SparseMatrix inv_deps(ndofs);
1182
1184
1185 // Collect local face/edge dependencies, starting with faces
1186 for (int entity = 2; entity >= 1; entity--)
1187 {
1188 const NCMesh::NCList &list = mesh->ncmesh->GetNCList(entity);
1189 if (!list.masters.Size()) { continue; }
1190
1191 // loop through all master edges/faces, constrain their slave edges/faces
1192 for (const NCMesh::Master &master : list.masters)
1193 {
1194 Geometry::Type master_geom = master.Geom();
1195
1196 const int p = GetEntityDofs(entity, master.index, master_dofs,
1197 master_geom);
1198 if (!master_dofs.Size()) { continue; }
1199
1200 const FiniteElement *master_fe = fec->GetFE(master_geom, p);
1201 if (!master_fe) { continue; }
1202
1203 switch (master_geom)
1204 {
1205 case Geometry::SQUARE: T.SetFE(&QuadrilateralFE); break;
1206 case Geometry::TRIANGLE: T.SetFE(&TriangleFE); break;
1207 case Geometry::SEGMENT: T.SetFE(&SegmentFE); break;
1208 default: MFEM_ABORT("unsupported geometry");
1209 }
1210
1211 for (int si = master.slaves_begin; si < master.slaves_end; si++)
1212 {
1213 const NCMesh::Slave &slave = list.slaves[si];
1214
1215 int q = GetEntityDofs(entity, slave.index, slave_dofs, master_geom);
1216 if (!slave_dofs.Size()) { break; }
1217
1218 const FiniteElement *slave_fe = fec->GetFE(slave.Geom(), q);
1219 list.OrientedPointMatrix(slave, T.GetPointMat());
1220 slave_fe->GetTransferMatrix(*master_fe, T, I);
1221
1222 // variable-order spaces: face edges need to be handled separately
1223 int skipfirst = 0;
1224 if (IsVariableOrder() && entity == 2 && slave.index >= 0)
1225 {
1226 skipfirst = GetNumBorderDofs(master_geom, q);
1227 }
1228
1229 // make each slave DOF dependent on all master DOFs
1230 AddDependencies(deps, master_dofs, slave_dofs, I, skipfirst);
1231
1232 if (skipfirst)
1233 {
1234 // constrain internal edge DOFs if they were skipped
1235 const auto *pm = list.point_matrices[master_geom][slave.matrix];
1236 AddEdgeFaceDependencies(deps, master_dofs, master_fe,
1237 slave_dofs, slave.index, pm);
1238 }
1239 }
1240
1241 // Add inverse dependencies for the cR_hp matrix; if a master has
1242 // more DOF sets, the lowest order set interpolates the highest one.
1243 if (IsVariableOrder())
1244 {
1245 int nvar = GetNVariants(entity, master.index);
1246 if (nvar > 1)
1247 {
1248 const int q = GetEntityDofs(entity, master.index, highest_dofs,
1249 master_geom, nvar-1);
1250 const auto *highest_fe = fec->GetFE(master_geom, q);
1251
1252 T.SetIdentityTransformation(master_geom);
1253 master_fe->GetTransferMatrix(*highest_fe, T, I);
1254
1255 // add dependencies only for the inner dofs
1256 const int skip = GetNumBorderDofs(master_geom, p);
1257 AddDependencies(inv_deps, highest_dofs, master_dofs, I, skip);
1258 }
1259 }
1260 }
1261 }
1262
1263 deps.Finalize();
1264 inv_deps.Finalize();
1265
1266 // DOFs that stayed independent are true DOFs
1267 int n_true_dofs = 0;
1268 for (int i = 0; i < ndofs; i++)
1269 {
1270 if (!deps.RowSize(i)) { n_true_dofs++; }
1271 }
1272
1273 // if all dofs are true dofs leave cP and cR NULL
1274 if (n_true_dofs == ndofs)
1275 {
1276 cP.reset();
1277 cR.reset();
1278 cR_hp.reset();
1279 R_transpose.reset();
1280 return;
1281 }
1282
1283 // create the conforming prolongation matrix cP
1284 cP.reset(new SparseMatrix(ndofs, n_true_dofs));
1285
1286 // create the conforming restriction matrix cR
1287 int *cR_J;
1288 {
1289 int *cR_I = Memory<int>(n_true_dofs+1);
1290 real_t *cR_A = Memory<real_t>(n_true_dofs);
1291 cR_J = Memory<int>(n_true_dofs);
1292 for (int i = 0; i < n_true_dofs; i++)
1293 {
1294 cR_I[i] = i;
1295 cR_A[i] = 1.0;
1296 }
1297 cR_I[n_true_dofs] = n_true_dofs;
1298 cR.reset(new SparseMatrix(cR_I, cR_J, cR_A, n_true_dofs, ndofs));
1299 }
1300
1301 // In variable-order spaces, create the restriction matrix cR_hp, which is
1302 // similar to cR but has interpolation of the master edge/face DOFs of
1303 // maximum order per edge/face, since the maximum order is on an adjacent
1304 // element (e.g. where projection would be computed).
1305 if (IsVariableOrder())
1306 {
1307 cR_hp.reset(new SparseMatrix(n_true_dofs, ndofs));
1308 }
1309 else
1310 {
1311 cR_hp.reset();
1312 }
1313
1314 Array<bool> finalized(ndofs);
1315 finalized = false;
1316
1317 Array<int> cols;
1318 Vector srow;
1319
1320 // Put identity in the prolongation matrix for true DOFs, and set cR_hp
1321 for (int i = 0, true_dof = 0; i < ndofs; i++)
1322 {
1323 if (!deps.RowSize(i)) // true dof
1324 {
1325 cP->Add(i, true_dof, 1.0);
1326 cR_J[true_dof] = i;
1327 finalized[i] = true;
1328
1329 if (cR_hp)
1330 {
1331 if (inv_deps.RowSize(i))
1332 {
1333 inv_deps.GetRow(i, cols, srow);
1334 cR_hp->AddRow(true_dof, cols, srow);
1335 }
1336 else
1337 {
1338 cR_hp->Add(true_dof, i, 1.0);
1339 }
1340 }
1341
1342 true_dof++;
1343 }
1344 }
1345
1346 // Now calculate cP rows of slave DOFs as combinations of cP rows of their
1347 // master DOFs. It is possible that some slave DOFs depend on DOFs that are
1348 // themselves slaves. Here we resolve such indirect constraints by first
1349 // calculating rows of the cP matrix for DOFs whose master DOF cP rows are
1350 // already known (in the first iteration these are the true DOFs). In the
1351 // second iteration, slaves of slaves can be 'finalized' (given a row in the
1352 // cP matrix), in the third iteration slaves of slaves of slaves, etc.
1353 bool finished;
1354 int n_finalized = n_true_dofs;
1355 do
1356 {
1357 finished = true;
1358 for (int dof = 0; dof < ndofs; dof++)
1359 {
1360 if (!finalized[dof] && DofFinalizable(dof, finalized, deps))
1361 {
1362 const int* dep_col = deps.GetRowColumns(dof);
1363 const real_t* dep_coef = deps.GetRowEntries(dof);
1364 int n_dep = deps.RowSize(dof);
1365
1366 for (int j = 0; j < n_dep; j++)
1367 {
1368 cP->GetRow(dep_col[j], cols, srow);
1369 srow *= dep_coef[j];
1370 cP->AddRow(dof, cols, srow);
1371 }
1372
1373 finalized[dof] = true;
1374 n_finalized++;
1375 finished = false;
1376 }
1377 }
1378 }
1379 while (!finished);
1380
1381 // If everything is consistent (mesh, face orientations, etc.), we should
1382 // be able to finalize all slave DOFs, otherwise it's a serious error.
1383 MFEM_VERIFY(n_finalized == ndofs,
1384 "Error creating cP matrix: n_finalized = "
1385 << n_finalized << ", ndofs = " << ndofs);
1386
1387 cP->Finalize();
1388 if (cR_hp) { cR_hp->Finalize(); }
1389
1390 if (vdim > 1)
1391 {
1394 if (cR_hp) { MakeVDimMatrix(*cR_hp); }
1395 }
1396}
1397
1399{
1400 if (vdim == 1) { return; }
1401
1402 int height = mat.Height();
1403 int width = mat.Width();
1404
1405 SparseMatrix *vmat = new SparseMatrix(vdim*height, vdim*width);
1406
1407 Array<int> dofs, vdofs;
1408 Vector srow;
1409 for (int i = 0; i < height; i++)
1410 {
1411 mat.GetRow(i, dofs, srow);
1412 for (int vd = 0; vd < vdim; vd++)
1413 {
1414 dofs.Copy(vdofs);
1415 DofsToVDofs(vd, vdofs, width);
1416 vmat->SetRow(DofToVDof(i, vd, height), vdofs, srow);
1417 }
1418 }
1419 vmat->Finalize();
1420
1421 mat.Swap(*vmat);
1422 delete vmat;
1423}
1424
1425
1427{
1428 if (Conforming()) { return NULL; }
1430 return cP.get();
1431}
1432
1434{
1435 if (Conforming()) { return NULL; }
1437 if (cR && !R_transpose) { R_transpose.reset(new TransposeOperator(*cR)); }
1438 return cR.get();
1439}
1440
1442{
1443 if (Conforming()) { return NULL; }
1445 return IsVariableOrder() ? cR_hp.get() : cR.get();
1446}
1447
1449{
1450 GetRestrictionOperator(); // Ensure that R_transpose is built
1451 return R_transpose.get();
1452}
1453
1455{
1457 return P ? (P->Width() / vdim) : ndofs;
1458}
1459
1461{
1462 const FiniteElement *fe = GetTypicalFE();
1464 {
1465 return GetVDim();
1466 }
1467 return GetVDim()*std::max(GetMesh()->SpaceDimension(), fe->GetRangeDim());
1468}
1469
1471{
1472 const FiniteElement *fe = GetTypicalFE();
1474 {
1475 return 2 * GetMesh()->SpaceDimension() - 3;
1476 }
1477 return GetVDim()*fe->GetCurlDim();
1478}
1479
1481 ElementDofOrdering e_ordering) const
1482{
1483 // Check if we have a discontinuous space using the FE collection:
1484 if (IsDGSpace())
1485 {
1486 // TODO: when VDIM is 1, we can return IdentityOperator.
1487 if (L2E_nat.Ptr() == NULL)
1488 {
1489 // The input L-vector layout is:
1490 // * ND x NE x VDIM, for Ordering::byNODES, or
1491 // * VDIM x ND x NE, for Ordering::byVDIM.
1492 // The output E-vector layout is: ND x VDIM x NE.
1494 }
1496 }
1497 if (e_ordering == ElementDofOrdering::LEXICOGRAPHIC)
1498 {
1499 if (L2E_lex.Ptr() == NULL)
1500 {
1501 L2E_lex.Reset(new ElementRestriction(*this, e_ordering));
1502 }
1504 }
1505 // e_ordering == ElementDofOrdering::NATIVE
1506 if (L2E_nat.Ptr() == NULL)
1507 {
1508 L2E_nat.Reset(new ElementRestriction(*this, e_ordering));
1509 }
1511}
1512
1514 ElementDofOrdering f_ordering, FaceType type, L2FaceValues mul) const
1515{
1516 const bool is_dg_space = IsDGSpace();
1517 const L2FaceValues m = (is_dg_space && mul==L2FaceValues::DoubleValued) ?
1519 key_face key = std::make_tuple(is_dg_space, f_ordering, type, m);
1520 auto itr = L2F.find(key);
1521 if (itr != L2F.end())
1522 {
1523 return itr->second;
1524 }
1525 else
1526 {
1527 FaceRestriction *res;
1528 if (is_dg_space)
1529 {
1530 if (Conforming())
1531 {
1532 res = new L2FaceRestriction(*this, f_ordering, type, m);
1533 }
1534 else
1535 {
1536 res = new NCL2FaceRestriction(*this, f_ordering, type, m);
1537 }
1538 }
1539 else if (dynamic_cast<const DG_Interface_FECollection*>(fec))
1540 {
1541 res = new L2InterfaceFaceRestriction(*this, f_ordering, type);
1542 }
1543 else
1544 {
1545 res = new ConformingFaceRestriction(*this, f_ordering, type);
1546 }
1547 L2F[key] = res;
1548 return res;
1549 }
1550}
1551
1553 const IntegrationRule &ir) const
1554{
1556 {
1557 return nullptr;
1558 }
1559
1560 for (int i = 0; i < E2Q_array.Size(); i++)
1561 {
1562 const QuadratureInterpolator *qi = E2Q_array[i];
1563 if (qi->IntRule == &ir) { return qi; }
1564 }
1565
1567 E2Q_array.Append(qi);
1568 return qi;
1569}
1570
1572 const QuadratureSpace &qs) const
1573{
1575 {
1576 return nullptr;
1577 }
1578
1579 for (int i = 0; i < E2Q_array.Size(); i++)
1580 {
1581 const QuadratureInterpolator *qi = E2Q_array[i];
1582 if (qi->qspace == &qs) { return qi; }
1583 }
1584
1586 E2Q_array.Append(qi);
1587 return qi;
1588}
1589
1592 const IntegrationRule &ir, FaceType type) const
1593{
1595 {
1596 return nullptr;
1597 }
1598
1599 if (type==FaceType::Interior)
1600 {
1601 for (int i = 0; i < E2IFQ_array.Size(); i++)
1602 {
1604 if (qi->IntRule == &ir) { return qi; }
1605 }
1606
1608 type);
1609 E2IFQ_array.Append(qi);
1610 return qi;
1611 }
1612 else //Boundary
1613 {
1614 for (int i = 0; i < E2BFQ_array.Size(); i++)
1615 {
1617 if (qi->IntRule == &ir) { return qi; }
1618 }
1619
1621 type);
1622 E2BFQ_array.Append(qi);
1623 return qi;
1624 }
1625}
1626
1628 const int coarse_ndofs, const Table &coarse_elem_dof,
1629 const Table *coarse_elem_fos, const DenseTensor localP[]) const
1630{
1631 /// TODO: Implement DofTransformation support
1632
1633 MFEM_VERIFY(mesh->GetLastOperation() == Mesh::REFINE, "");
1634
1635 Array<int> dofs, coarse_dofs, coarse_vdofs;
1636 Vector row;
1637
1638 Mesh::GeometryList elem_geoms(*mesh);
1639
1640 SparseMatrix *P;
1641 if (elem_geoms.Size() == 1)
1642 {
1643 const int coarse_ldof = localP[elem_geoms[0]].SizeJ();
1644 P = new SparseMatrix(GetVSize(), coarse_ndofs*vdim, coarse_ldof);
1645 }
1646 else
1647 {
1648 P = new SparseMatrix(GetVSize(), coarse_ndofs*vdim);
1649 }
1650
1651 Array<int> mark(P->Height());
1652 mark = 0;
1653
1655
1656 for (int k = 0; k < mesh->GetNE(); k++)
1657 {
1658 const Embedding &emb = rtrans.embeddings[k];
1660 const DenseMatrix &lP = localP[geom](emb.matrix);
1661 const int fine_ldof = localP[geom].SizeI();
1662
1663 elem_dof->GetRow(k, dofs);
1664 coarse_elem_dof.GetRow(emb.parent, coarse_dofs);
1665
1666 for (int vd = 0; vd < vdim; vd++)
1667 {
1668 coarse_dofs.Copy(coarse_vdofs);
1669 DofsToVDofs(vd, coarse_vdofs, coarse_ndofs);
1670
1671 for (int i = 0; i < fine_ldof; i++)
1672 {
1673 int r = DofToVDof(dofs[i], vd);
1674 int m = (r >= 0) ? r : (-1 - r);
1675
1676 if (!mark[m])
1677 {
1678 lP.GetRow(i, row);
1679 P->SetRow(r, coarse_vdofs, row);
1680 mark[m] = 1;
1681 }
1682 }
1683 }
1684 }
1685
1686 MFEM_ASSERT(mark.Sum() == P->Height(), "Not all rows of P set.");
1687 if (elem_geoms.Size() != 1) { P->Finalize(); }
1688 return P;
1689}
1690
1692 const int coarse_ndofs, const Table &coarse_elem_dof) const
1693{
1694 MFEM_VERIFY(mesh->GetLastOperation() == Mesh::REFINE, "");
1695
1696 Array<int> dofs, coarse_dofs, coarse_vdofs;
1697 Vector row;
1698
1699 Mesh::GeometryList elem_geoms(*mesh);
1700
1701 SparseMatrix *P = new SparseMatrix(GetVSize(), coarse_ndofs*vdim);
1702
1703 Array<int> mark(P->Height());
1704 mark = 0;
1705
1707 DenseMatrix lP;
1709 for (int k = 0; k < mesh->GetNE(); k++)
1710 {
1711 const Embedding &emb = rtrans.embeddings[k];
1713
1714 const FiniteElement *fe = GetFE(k);
1715 isotr.SetIdentityTransformation(geom);
1716 const int ldof = fe->GetDof();
1717 lP.SetSize(ldof, ldof);
1718 const DenseTensor &pmats = rtrans.point_matrices[geom];
1719 isotr.SetPointMat(pmats(emb.matrix));
1720 fe->GetLocalInterpolation(isotr, lP);
1721
1722 const int fine_ldof = lP.Height();
1723
1724 elem_dof->GetRow(k, dofs);
1725 coarse_elem_dof.GetRow(emb.parent, coarse_dofs);
1726
1727 for (int vd = 0; vd < vdim; vd++)
1728 {
1729 coarse_dofs.Copy(coarse_vdofs);
1730 DofsToVDofs(vd, coarse_vdofs, coarse_ndofs);
1731
1732 for (int i = 0; i < fine_ldof; i++)
1733 {
1734 const int r = DofToVDof(dofs[i], vd);
1735 int m = (r >= 0) ? r : (-1 - r);
1736
1737 if (!mark[m])
1738 {
1739 lP.GetRow(i, row);
1740 P->SetRow(r, coarse_vdofs, row);
1741 mark[m] = 1;
1742 }
1743 }
1744 }
1745 }
1746
1747 MFEM_VERIFY(mark.Sum() == P->Height(), "Not all rows of P set.");
1748 P->Finalize();
1749 return P;
1750}
1751
1753 Geometry::Type geom, DenseTensor &localP) const
1754{
1755 const FiniteElement *fe = fec->FiniteElementForGeometry(geom);
1756
1758 const DenseTensor &pmats = rtrans.point_matrices[geom];
1759
1760 int nmat = pmats.SizeK();
1761 int ldof = fe->GetDof();
1762
1764 isotr.SetIdentityTransformation(geom);
1765
1766 // calculate local interpolation matrices for all refinement types
1767 localP.SetSize(ldof, ldof, nmat);
1768 for (int i = 0; i < nmat; i++)
1769 {
1770 isotr.SetPointMat(pmats(i));
1771 fe->GetLocalInterpolation(isotr, localP(i));
1772 }
1773}
1774
1776 const Table* old_elem_dof,
1777 const Table* old_elem_fos)
1778{
1779 MFEM_VERIFY(GetNE() >= old_elem_dof->Size(),
1780 "Previous mesh is not coarser.");
1781
1782 Mesh::GeometryList elem_geoms(*mesh);
1783 if (!IsVariableOrder())
1784 {
1786 for (int i = 0; i < elem_geoms.Size(); i++)
1787 {
1788 GetLocalRefinementMatrices(elem_geoms[i], localP[elem_geoms[i]]);
1789 }
1790 return RefinementMatrix_main(old_ndofs, *old_elem_dof, old_elem_fos,
1791 localP);
1792 }
1793 else
1794 {
1795 return VariableOrderRefinementMatrix(old_ndofs, *old_elem_dof);
1796 }
1797}
1798
1800 const FiniteElementSpace* fespace, Table* old_elem_dof, Table* old_elem_fos,
1801 int old_ndofs)
1802 : fespace(fespace),
1803 old_elem_dof(old_elem_dof),
1804 old_elem_fos(old_elem_fos)
1805{
1806 MFEM_VERIFY(fespace->GetNE() >= old_elem_dof->Size(),
1807 "Previous mesh is not coarser.");
1808
1809 width = old_ndofs * fespace->GetVDim();
1810 height = fespace->GetVSize();
1811
1812 Mesh::GeometryList elem_geoms(*fespace->GetMesh());
1813
1814 if (!fespace->IsVariableOrder())
1815 {
1816 for (int i = 0; i < elem_geoms.Size(); i++)
1817 {
1818 fespace->GetLocalRefinementMatrices(elem_geoms[i], localP[elem_geoms[i]]);
1819 }
1820 }
1821
1822 ConstructDoFTransArray();
1823}
1824
1826 const FiniteElementSpace *fespace, const FiniteElementSpace *coarse_fes)
1827 : Operator(fespace->GetVSize(), coarse_fes->GetVSize()),
1828 fespace(fespace), old_elem_dof(NULL), old_elem_fos(NULL)
1829{
1830 Mesh::GeometryList elem_geoms(*fespace->GetMesh());
1831
1832 if (!fespace->IsVariableOrder())
1833 {
1834 for (int i = 0; i < elem_geoms.Size(); i++)
1835 {
1836 fespace->GetLocalRefinementMatrices(*coarse_fes, elem_geoms[i],
1837 localP[elem_geoms[i]]);
1838 }
1839 }
1840
1841 // Make a copy of the coarse elem_dof Table.
1842 old_elem_dof = new Table(coarse_fes->GetElementToDofTable());
1843
1844 // Make a copy of the coarse elem_fos Table if it exists.
1845 if (coarse_fes->GetElementToFaceOrientationTable())
1846 {
1847 old_elem_fos = new Table(*coarse_fes->GetElementToFaceOrientationTable());
1848 }
1849
1850 ConstructDoFTransArray();
1851}
1852
1854{
1855 delete old_elem_dof;
1856 delete old_elem_fos;
1857 for (int i=0; i<old_DoFTransArray.Size(); i++)
1858 {
1859 delete old_DoFTransArray[i];
1860 }
1861}
1862
1863void FiniteElementSpace::RefinementOperator::ConstructDoFTransArray()
1864{
1865 old_DoFTransArray.SetSize(Geometry::NUM_GEOMETRIES);
1866 for (int i=0; i<old_DoFTransArray.Size(); i++)
1867 {
1868 old_DoFTransArray[i] = NULL;
1869 }
1870
1871 const FiniteElementCollection *fec_ref = fespace->FEColl();
1872 if (dynamic_cast<const ND_FECollection*>(fec_ref))
1873 {
1874 const FiniteElement *nd_tri =
1876 if (nd_tri)
1877 {
1878 old_DoFTransArray[Geometry::TRIANGLE] =
1879 new ND_TriDofTransformation(nd_tri->GetOrder());
1880 }
1881
1882 const FiniteElement *nd_tet =
1884 if (nd_tet)
1885 {
1886 old_DoFTransArray[Geometry::TETRAHEDRON] =
1887 new ND_TetDofTransformation(nd_tet->GetOrder());
1888 }
1889
1890 const FiniteElement *nd_pri =
1892 if (nd_pri)
1893 {
1894 old_DoFTransArray[Geometry::PRISM] =
1895 new ND_WedgeDofTransformation(nd_pri->GetOrder());
1896 }
1897
1898 const FiniteElement *nd_pyr =
1900 if (nd_pyr)
1901 {
1902 old_DoFTransArray[Geometry::PYRAMID] =
1903 new ND_PyramidDofTransformation(nd_pyr->GetOrder());
1904 }
1905 }
1906}
1907
1909 Vector &y) const
1910{
1911 Mesh* mesh_ref = fespace->GetMesh();
1912 const CoarseFineTransformations &trans_ref =
1913 mesh_ref->GetRefinementTransforms();
1914
1915 Array<int> dofs, vdofs, old_dofs, old_vdofs, old_Fo;
1916
1917 int rvdim = fespace->GetVDim();
1918 int old_ndofs = width / rvdim;
1919
1920 Vector subY, subX;
1921
1922 DenseMatrix eP;
1924 DofTransformation doftrans;
1925
1926 for (int k = 0; k < mesh_ref->GetNE(); k++)
1927 {
1928 const Embedding &emb = trans_ref.embeddings[k];
1929 const Geometry::Type geom = mesh_ref->GetElementBaseGeometry(k);
1930 if (fespace->IsVariableOrder())
1931 {
1932 const FiniteElement *fe = fespace->GetFE(k);
1933 isotr.SetIdentityTransformation(geom);
1934 const int ldof = fe->GetDof();
1935 eP.SetSize(ldof, ldof);
1936 const DenseTensor &pmats = trans_ref.point_matrices[geom];
1937 isotr.SetPointMat(pmats(emb.matrix));
1938 fe->GetLocalInterpolation(isotr, eP);
1939 }
1940 const DenseMatrix &lP = (fespace->IsVariableOrder()) ? eP : localP[geom](
1941 emb.matrix);
1942
1943 subY.SetSize(lP.Height());
1944
1945 fespace->GetElementDofs(k, dofs, doftrans);
1946 old_elem_dof->GetRow(emb.parent, old_dofs);
1947
1948 if (doftrans.IsIdentity())
1949 {
1950 for (int vd = 0; vd < rvdim; vd++)
1951 {
1952 dofs.Copy(vdofs);
1953 fespace->DofsToVDofs(vd, vdofs);
1954 old_dofs.Copy(old_vdofs);
1955 fespace->DofsToVDofs(vd, old_vdofs, old_ndofs);
1956
1957 x.GetSubVector(old_vdofs, subX);
1958 lP.Mult(subX, subY);
1959 y.SetSubVector(vdofs, subY);
1960 }
1961 }
1962 else
1963 {
1964 old_elem_fos->GetRow(emb.parent, old_Fo);
1965 old_DoFTrans.SetDofTransformation(*old_DoFTransArray[geom]);
1966 old_DoFTrans.SetFaceOrientations(old_Fo);
1967
1968 doftrans.SetVDim();
1969 for (int vd = 0; vd < rvdim; vd++)
1970 {
1971 dofs.Copy(vdofs);
1972 fespace->DofsToVDofs(vd, vdofs);
1973 old_dofs.Copy(old_vdofs);
1974 fespace->DofsToVDofs(vd, old_vdofs, old_ndofs);
1975
1976 x.GetSubVector(old_vdofs, subX);
1977 old_DoFTrans.InvTransformPrimal(subX);
1978 lP.Mult(subX, subY);
1979 doftrans.TransformPrimal(subY);
1980 y.SetSubVector(vdofs, subY);
1981 }
1982 doftrans.SetVDim(rvdim, fespace->GetOrdering());
1983 }
1984 }
1985}
1986
1988 Vector &y) const
1989{
1990 y = 0.0;
1991
1992 Mesh* mesh_ref = fespace->GetMesh();
1993 const CoarseFineTransformations &trans_ref =
1994 mesh_ref->GetRefinementTransforms();
1995
1996 Array<char> processed(fespace->GetVSize());
1997 processed = 0;
1998
1999 Array<int> f_dofs, c_dofs, f_vdofs, c_vdofs, old_Fo;
2000
2001 int rvdim = fespace->GetVDim();
2002 int old_ndofs = width / rvdim;
2003
2004 Vector subY, subX, subYt;
2005
2006 DenseMatrix eP;
2008 const FiniteElement *fe = nullptr;
2009 DofTransformation doftrans;
2010
2011 for (int k = 0; k < mesh_ref->GetNE(); k++)
2012 {
2013 const Embedding &emb = trans_ref.embeddings[k];
2014 const Geometry::Type geom = mesh_ref->GetElementBaseGeometry(k);
2015
2016 if (fespace->IsVariableOrder())
2017 {
2018 fe = fespace->GetFE(k);
2019 isotr.SetIdentityTransformation(geom);
2020 const int ldof = fe->GetDof();
2021 eP.SetSize(ldof);
2022 const DenseTensor &pmats = trans_ref.point_matrices[geom];
2023 isotr.SetPointMat(pmats(emb.matrix));
2024 fe->GetLocalInterpolation(isotr, eP);
2025 }
2026
2027 const DenseMatrix &lP = (fespace->IsVariableOrder()) ? eP : localP[geom](
2028 emb.matrix);
2029
2030 fespace->GetElementDofs(k, f_dofs, doftrans);
2031 old_elem_dof->GetRow(emb.parent, c_dofs);
2032
2033 if (doftrans.IsIdentity())
2034 {
2035 subY.SetSize(lP.Width());
2036
2037 for (int vd = 0; vd < rvdim; vd++)
2038 {
2039 f_dofs.Copy(f_vdofs);
2040 fespace->DofsToVDofs(vd, f_vdofs);
2041 c_dofs.Copy(c_vdofs);
2042 fespace->DofsToVDofs(vd, c_vdofs, old_ndofs);
2043
2044 x.GetSubVector(f_vdofs, subX);
2045 for (int p = 0; p < f_dofs.Size(); ++p)
2046 {
2047 if (processed[DecodeDof(f_dofs[p])])
2048 {
2049 subX[p] = 0.0;
2050 }
2051 }
2052 lP.MultTranspose(subX, subY);
2053 y.AddElementVector(c_vdofs, subY);
2054 }
2055 }
2056 else
2057 {
2058 subYt.SetSize(lP.Width());
2059
2060 old_elem_fos->GetRow(emb.parent, old_Fo);
2061 old_DoFTrans.SetDofTransformation(*old_DoFTransArray[geom]);
2062 old_DoFTrans.SetFaceOrientations(old_Fo);
2063
2064 doftrans.SetVDim();
2065 for (int vd = 0; vd < rvdim; vd++)
2066 {
2067 f_dofs.Copy(f_vdofs);
2068 fespace->DofsToVDofs(vd, f_vdofs);
2069 c_dofs.Copy(c_vdofs);
2070 fespace->DofsToVDofs(vd, c_vdofs, old_ndofs);
2071
2072 x.GetSubVector(f_vdofs, subX);
2073 doftrans.InvTransformDual(subX);
2074 for (int p = 0; p < f_dofs.Size(); ++p)
2075 {
2076 if (processed[DecodeDof(f_dofs[p])])
2077 {
2078 subX[p] = 0.0;
2079 }
2080 }
2081 lP.MultTranspose(subX, subYt);
2082 old_DoFTrans.TransformDual(subYt);
2083 y.AddElementVector(c_vdofs, subYt);
2084 }
2085 doftrans.SetVDim(rvdim, fespace->GetOrdering());
2086 }
2087
2088 for (int p = 0; p < f_dofs.Size(); ++p)
2089 {
2090 processed[DecodeDof(f_dofs[p])] = 1;
2091 }
2092 }
2093}
2094
2095namespace internal
2096{
2097
2098// Used in GetCoarseToFineMap() below.
2099struct RefType
2100{
2101 Geometry::Type geom;
2102 int num_children;
2103 const Pair<int,int> *children;
2104
2105 RefType(Geometry::Type g, int n, const Pair<int,int> *c)
2106 : geom(g), num_children(n), children(c) { }
2107
2108 bool operator<(const RefType &other) const
2109 {
2110 if (geom < other.geom) { return true; }
2111 if (geom > other.geom) { return false; }
2112 if (num_children < other.num_children) { return true; }
2113 if (num_children > other.num_children) { return false; }
2114 for (int i = 0; i < num_children; i++)
2115 {
2116 if (children[i].one < other.children[i].one) { return true; }
2117 if (children[i].one > other.children[i].one) { return false; }
2118 }
2119 return false; // everything is equal
2120 }
2121};
2122
2123void GetCoarseToFineMap(const CoarseFineTransformations &cft,
2124 const mfem::Mesh &fine_mesh,
2125 Table &coarse_to_fine,
2126 Array<int> &coarse_to_ref_type,
2127 Table &ref_type_to_matrix,
2128 Array<Geometry::Type> &ref_type_to_geom)
2129{
2130 const int fine_ne = cft.embeddings.Size();
2131 int coarse_ne = -1;
2132 for (int i = 0; i < fine_ne; i++)
2133 {
2134 coarse_ne = std::max(coarse_ne, cft.embeddings[i].parent);
2135 }
2136 coarse_ne++;
2137
2138 coarse_to_ref_type.SetSize(coarse_ne);
2139 coarse_to_fine.SetDims(coarse_ne, fine_ne);
2140
2141 Array<int> cf_i(coarse_to_fine.GetI(), coarse_ne+1);
2142 Array<Pair<int,int> > cf_j(fine_ne);
2143 cf_i = 0;
2144 for (int i = 0; i < fine_ne; i++)
2145 {
2146 cf_i[cft.embeddings[i].parent+1]++;
2147 }
2148 cf_i.PartialSum();
2149 MFEM_ASSERT(cf_i.Last() == cf_j.Size(), "internal error");
2150 for (int i = 0; i < fine_ne; i++)
2151 {
2152 const Embedding &e = cft.embeddings[i];
2153 cf_j[cf_i[e.parent]].one = e.matrix; // used as sort key below
2154 cf_j[cf_i[e.parent]].two = i;
2155 cf_i[e.parent]++;
2156 }
2157 std::copy_backward(cf_i.begin(), cf_i.end()-1, cf_i.end());
2158 cf_i[0] = 0;
2159 for (int i = 0; i < coarse_ne; i++)
2160 {
2161 std::sort(&cf_j[cf_i[i]], cf_j.GetData() + cf_i[i+1]);
2162 }
2163 for (int i = 0; i < fine_ne; i++)
2164 {
2165 coarse_to_fine.GetJ()[i] = cf_j[i].two;
2166 }
2167
2168 using std::map;
2169 using std::pair;
2170
2171 map<RefType,int> ref_type_map;
2172 for (int i = 0; i < coarse_ne; i++)
2173 {
2174 const int num_children = cf_i[i+1]-cf_i[i];
2175 MFEM_ASSERT(num_children > 0, "");
2176 const int fine_el = cf_j[cf_i[i]].two;
2177 // Assuming the coarse and the fine elements have the same geometry:
2178 const Geometry::Type geom = fine_mesh.GetElementBaseGeometry(fine_el);
2179 const RefType ref_type(geom, num_children, &cf_j[cf_i[i]]);
2180 pair<map<RefType,int>::iterator,bool> res =
2181 ref_type_map.insert(
2182 pair<const RefType,int>(ref_type, (int)ref_type_map.size()));
2183 coarse_to_ref_type[i] = res.first->second;
2184 }
2185
2186 ref_type_to_matrix.MakeI((int)ref_type_map.size());
2187 ref_type_to_geom.SetSize((int)ref_type_map.size());
2188 for (map<RefType,int>::iterator it = ref_type_map.begin();
2189 it != ref_type_map.end(); ++it)
2190 {
2191 ref_type_to_matrix.AddColumnsInRow(it->second, it->first.num_children);
2192 ref_type_to_geom[it->second] = it->first.geom;
2193 }
2194
2195 ref_type_to_matrix.MakeJ();
2196 for (map<RefType,int>::iterator it = ref_type_map.begin();
2197 it != ref_type_map.end(); ++it)
2198 {
2199 const RefType &rt = it->first;
2200 for (int j = 0; j < rt.num_children; j++)
2201 {
2202 ref_type_to_matrix.AddConnection(it->second, rt.children[j].one);
2203 }
2204 }
2205 ref_type_to_matrix.ShiftUpI();
2206}
2207
2208} // namespace internal
2209
2210
2211/// TODO: Implement DofTransformation support
2213 const FiniteElementSpace *f_fes, const FiniteElementSpace *c_fes,
2214 BilinearFormIntegrator *mass_integ)
2215 : Operator(c_fes->GetVSize(), f_fes->GetVSize()),
2216 fine_fes(f_fes)
2217{
2218 MFEM_VERIFY(c_fes->GetOrdering() == f_fes->GetOrdering() &&
2219 c_fes->GetVDim() == f_fes->GetVDim(),
2220 "incompatible coarse and fine FE spaces");
2221
2223 Mesh *f_mesh = f_fes->GetMesh();
2224 const CoarseFineTransformations &rtrans = f_mesh->GetRefinementTransforms();
2225
2226 Mesh::GeometryList elem_geoms(*f_mesh);
2228 for (int gi = 0; gi < elem_geoms.Size(); gi++)
2229 {
2230 const Geometry::Type geom = elem_geoms[gi];
2231 DenseTensor &lP = localP[geom], &lM = localM[geom];
2232 const FiniteElement *fine_fe =
2233 f_fes->fec->FiniteElementForGeometry(geom);
2234 const FiniteElement *coarse_fe =
2235 c_fes->fec->FiniteElementForGeometry(geom);
2236 const DenseTensor &pmats = rtrans.point_matrices[geom];
2237
2238 lP.SetSize(fine_fe->GetDof(), coarse_fe->GetDof(), pmats.SizeK());
2239 lM.SetSize(fine_fe->GetDof(), fine_fe->GetDof(), pmats.SizeK());
2240 emb_tr.SetIdentityTransformation(geom);
2241 for (int i = 0; i < pmats.SizeK(); i++)
2242 {
2243 emb_tr.SetPointMat(pmats(i));
2244 // Get the local interpolation matrix for this refinement type
2245 fine_fe->GetTransferMatrix(*coarse_fe, emb_tr, lP(i));
2246 // Get the local mass matrix for this refinement type
2247 mass_integ->AssembleElementMatrix(*fine_fe, emb_tr, lM(i));
2248 }
2249 }
2250
2251 Table ref_type_to_matrix;
2252 internal::GetCoarseToFineMap(rtrans, *f_mesh, coarse_to_fine,
2253 coarse_to_ref_type, ref_type_to_matrix,
2254 ref_type_to_geom);
2255 MFEM_ASSERT(coarse_to_fine.Size() == c_fes->GetNE(), "");
2256
2257 const int total_ref_types = ref_type_to_geom.Size();
2258 int num_ref_types[Geometry::NumGeom], num_fine_elems[Geometry::NumGeom];
2259 Array<int> ref_type_to_coarse_elem_offset(total_ref_types);
2260 ref_type_to_fine_elem_offset.SetSize(total_ref_types);
2261 std::fill(num_ref_types, num_ref_types+Geometry::NumGeom, 0);
2262 std::fill(num_fine_elems, num_fine_elems+Geometry::NumGeom, 0);
2263 for (int i = 0; i < total_ref_types; i++)
2264 {
2265 Geometry::Type g = ref_type_to_geom[i];
2266 ref_type_to_coarse_elem_offset[i] = num_ref_types[g];
2267 ref_type_to_fine_elem_offset[i] = num_fine_elems[g];
2268 num_ref_types[g]++;
2269 num_fine_elems[g] += ref_type_to_matrix.RowSize(i);
2270 }
2271 DenseTensor localPtMP[Geometry::NumGeom];
2272 for (int g = 0; g < Geometry::NumGeom; g++)
2273 {
2274 if (num_ref_types[g] == 0) { continue; }
2275 const int fine_dofs = localP[g].SizeI();
2276 const int coarse_dofs = localP[g].SizeJ();
2277 localPtMP[g].SetSize(coarse_dofs, coarse_dofs, num_ref_types[g]);
2278 localR[g].SetSize(coarse_dofs, fine_dofs, num_fine_elems[g]);
2279 }
2280 for (int i = 0; i < total_ref_types; i++)
2281 {
2282 Geometry::Type g = ref_type_to_geom[i];
2283 DenseMatrix &lPtMP = localPtMP[g](ref_type_to_coarse_elem_offset[i]);
2284 int lR_offset = ref_type_to_fine_elem_offset[i]; // offset in localR[g]
2285 const int *mi = ref_type_to_matrix.GetRow(i);
2286 const int nm = ref_type_to_matrix.RowSize(i);
2287 lPtMP = 0.0;
2288 for (int s = 0; s < nm; s++)
2289 {
2290 DenseMatrix &lP = localP[g](mi[s]);
2291 DenseMatrix &lM = localM[g](mi[s]);
2292 DenseMatrix &lR = localR[g](lR_offset+s);
2293 MultAtB(lP, lM, lR); // lR = lP^T lM
2294 mfem::AddMult(lR, lP, lPtMP); // lPtMP += lP^T lM lP
2295 }
2296 DenseMatrixInverse lPtMP_inv(lPtMP);
2297 for (int s = 0; s < nm; s++)
2298 {
2299 DenseMatrix &lR = localR[g](lR_offset+s);
2300 lPtMP_inv.Mult(lR); // lR <- (P^T M P)^{-1} P^T M
2301 }
2302 }
2303
2304 // Make a copy of the coarse element-to-dof Table.
2305 coarse_elem_dof = new Table(c_fes->GetElementToDofTable());
2306}
2307
2312
2314 Vector &y) const
2315{
2316 Array<int> c_vdofs, f_vdofs;
2317 Vector loc_x, loc_y;
2318 DenseMatrix loc_x_mat, loc_y_mat;
2319 const int fine_vdim = fine_fes->GetVDim();
2320 const int coarse_ndofs = height/fine_vdim;
2321 for (int coarse_el = 0; coarse_el < coarse_to_fine.Size(); coarse_el++)
2322 {
2323 coarse_elem_dof->GetRow(coarse_el, c_vdofs);
2324 fine_fes->DofsToVDofs(c_vdofs, coarse_ndofs);
2325 loc_y.SetSize(c_vdofs.Size());
2326 loc_y = 0.0;
2327 loc_y_mat.UseExternalData(loc_y.GetData(), c_vdofs.Size()/fine_vdim,
2328 fine_vdim);
2329 const int ref_type = coarse_to_ref_type[coarse_el];
2330 const Geometry::Type geom = ref_type_to_geom[ref_type];
2331 const int *fine_elems = coarse_to_fine.GetRow(coarse_el);
2332 const int num_fine_elems = coarse_to_fine.RowSize(coarse_el);
2333 const int lR_offset = ref_type_to_fine_elem_offset[ref_type];
2334 for (int s = 0; s < num_fine_elems; s++)
2335 {
2336 const DenseMatrix &lR = localR[geom](lR_offset+s);
2337 fine_fes->GetElementVDofs(fine_elems[s], f_vdofs);
2338 x.GetSubVector(f_vdofs, loc_x);
2339 loc_x_mat.UseExternalData(loc_x.GetData(), f_vdofs.Size()/fine_vdim,
2340 fine_vdim);
2341 mfem::AddMult(lR, loc_x_mat, loc_y_mat);
2342 }
2343 y.SetSubVector(c_vdofs, loc_y);
2344 }
2345}
2346
2348 DenseTensor &localR) const
2349{
2350 const FiniteElement *fe = fec->FiniteElementForGeometry(geom);
2351
2352 const CoarseFineTransformations &dtrans =
2354 const DenseTensor &pmats = dtrans.point_matrices[geom];
2355
2356 const int nmat = pmats.SizeK();
2357 const int ldof = fe->GetDof();
2358
2360 isotr.SetIdentityTransformation(geom);
2361
2362 // calculate local restriction matrices for all refinement types
2363 localR.SetSize(ldof, ldof, nmat);
2364 for (int i = 0; i < nmat; i++)
2365 {
2366 isotr.SetPointMat(pmats(i));
2367 fe->GetLocalRestriction(isotr, localR(i));
2368 }
2369}
2370
2372 const Table* old_elem_dof,
2373 const Table* old_elem_fos)
2374{
2375 /// TODO: Implement DofTransformation support
2376
2377 MFEM_VERIFY(Nonconforming(), "Not implemented for conforming meshes.");
2378 MFEM_VERIFY(old_ndofs, "Missing previous (finer) space.");
2379 MFEM_VERIFY(ndofs <= old_ndofs, "Previous space is not finer.");
2380
2381 Array<int> dofs, old_dofs, old_vdofs;
2382 Vector row;
2383
2384 Mesh::GeometryList elem_geoms(*mesh);
2385
2387 if (!IsVariableOrder())
2388 {
2389 for (int i = 0; i < elem_geoms.Size(); i++)
2390 {
2391 GetLocalDerefinementMatrices(elem_geoms[i], localR[elem_geoms[i]]);
2392 }
2393 }
2394
2395 SparseMatrix *R = new SparseMatrix(ndofs*vdim, old_ndofs*vdim);
2396
2397 Array<int> mark(R->Height());
2398 mark = 0;
2399
2400 const CoarseFineTransformations &dtrans =
2402
2403 MFEM_ASSERT(dtrans.embeddings.Size() == old_elem_dof->Size(), "");
2404
2406 int num_marked = 0;
2407 const FiniteElement *fe = nullptr;
2408 DenseMatrix localRVO; //for variable-order only
2409 for (int k = 0; k < dtrans.embeddings.Size(); k++)
2410 {
2411 const Embedding &emb = dtrans.embeddings[k];
2413
2414 if (IsVariableOrder())
2415 {
2416 fe = GetFE(emb.parent);
2417 const DenseTensor &pmats = dtrans.point_matrices[geom];
2418 const int ldof = fe->GetDof();
2419
2421 isotr.SetIdentityTransformation(geom);
2422
2423 localRVO.SetSize(ldof, ldof);
2424 isotr.SetPointMat(pmats(emb.matrix));
2425 // Local restriction is size ldofxldof assuming that the parent and
2426 // child are of same polynomial order.
2427 fe->GetLocalRestriction(isotr, localRVO);
2428 }
2429 DenseMatrix &lR = IsVariableOrder() ? localRVO : localR[geom](emb.matrix);
2430
2431 elem_dof->GetRow(emb.parent, dofs);
2432 old_elem_dof->GetRow(k, old_dofs);
2433 MFEM_VERIFY(old_dofs.Size() == dofs.Size(),
2434 "Parent and child must have same #dofs.");
2435
2436 for (int vd = 0; vd < vdim; vd++)
2437 {
2438 old_dofs.Copy(old_vdofs);
2439 DofsToVDofs(vd, old_vdofs, old_ndofs);
2440
2441 for (int i = 0; i < lR.Height(); i++)
2442 {
2443 if (!std::isfinite(lR(i, 0))) { continue; }
2444
2445 int r = DofToVDof(dofs[i], vd);
2446 int m = (r >= 0) ? r : (-1 - r);
2447
2448 if (is_dg || !mark[m])
2449 {
2450 lR.GetRow(i, row);
2451 R->SetRow(r, old_vdofs, row);
2452
2453 mark[m] = 1;
2454 num_marked++;
2455 }
2456 }
2457 }
2458 }
2459
2460 if (!is_dg && !IsVariableOrder())
2461 {
2462 MFEM_VERIFY(num_marked == R->Height(),
2463 "internal error: not all rows of R were set.");
2464 }
2465
2466 R->Finalize(); // no-op if fixed width
2467 return R;
2468}
2469
2471 const FiniteElementSpace &coarse_fes, Geometry::Type geom,
2472 DenseTensor &localP) const
2473{
2474 // Assumptions: see the declaration of the method.
2475
2476 const FiniteElement *fine_fe = fec->FiniteElementForGeometry(geom);
2477 const FiniteElement *coarse_fe =
2478 coarse_fes.fec->FiniteElementForGeometry(geom);
2479
2481 const DenseTensor &pmats = rtrans.point_matrices[geom];
2482
2483 int nmat = pmats.SizeK();
2484
2486 isotr.SetIdentityTransformation(geom);
2487
2488 // Calculate the local interpolation matrices for all refinement types
2489 localP.SetSize(fine_fe->GetDof(), coarse_fe->GetDof(), nmat);
2490 for (int i = 0; i < nmat; i++)
2491 {
2492 isotr.SetPointMat(pmats(i));
2493 fine_fe->GetTransferMatrix(*coarse_fe, isotr, localP(i));
2494 }
2495}
2496
2498 const FiniteElementCollection *fec_,
2499 int vdim_, int ordering_)
2500{
2501 mesh = mesh_;
2502 fec = fec_;
2503 vdim = vdim_;
2504 ordering = (Ordering::Type) ordering_;
2505
2506 elem_dof = NULL;
2507 elem_fos = NULL;
2508 face_dof = NULL;
2509
2510 sequence = 0;
2511 orders_changed = false;
2512 relaxed_hp = false;
2513
2515
2516 const NURBSFECollection *nurbs_fec =
2517 dynamic_cast<const NURBSFECollection *>(fec_);
2518
2519 if (nurbs_fec)
2520 {
2521 MFEM_VERIFY(mesh_->NURBSext, "NURBS FE space requires a NURBS mesh.");
2522
2523 if (NURBSext_ == NULL)
2524 {
2525 NURBSext = mesh_->NURBSext;
2526 own_ext = 0;
2527 }
2528 else
2529 {
2530 NURBSext = NURBSext_;
2531 own_ext = 1;
2532 }
2533 UpdateNURBS();
2534 cP.reset();
2535 cR.reset();
2536 cR_hp.reset();
2537 R_transpose.reset();
2538 cP_is_set = false;
2539
2541 }
2542 else
2543 {
2544 NURBSext = NULL;
2545 own_ext = 0;
2546 Construct();
2547 }
2548
2550}
2551
2553{
2555
2557 for (int i=0; i<DoFTransArray.Size(); i++)
2558 {
2559 DoFTransArray[i] = NULL;
2560 }
2561 if (mesh->Dimension() < 3) { return; }
2562 if (dynamic_cast<const ND_FECollection*>(fec))
2563 {
2564 const FiniteElement *nd_tri =
2566 if (nd_tri)
2567 {
2569 new ND_TriDofTransformation(nd_tri->GetOrder());
2570 }
2571
2572 const FiniteElement *nd_tet =
2574 if (nd_tet)
2575 {
2577 new ND_TetDofTransformation(nd_tet->GetOrder());
2578 }
2579
2580 const FiniteElement *nd_pri =
2582 if (nd_pri)
2583 {
2585 new ND_WedgeDofTransformation(nd_pri->GetOrder());
2586 }
2587
2588 const FiniteElement *nd_pyr =
2590 if (nd_pyr)
2591 {
2594 }
2595 }
2596}
2597
2599{
2600 if (NURBSext && !own_ext)
2601 {
2602 mfem_error("FiniteElementSpace::StealNURBSext");
2603 }
2604 own_ext = 0;
2605
2606 return NURBSext;
2607}
2608
2610{
2611 MFEM_VERIFY(NURBSext, "NURBSExt not defined.");
2612
2613 nvdofs = 0;
2614 nedofs = 0;
2615 nfdofs = 0;
2616 nbdofs = 0;
2617 bdofs = NULL;
2618
2619 delete face_dof;
2620 face_dof = NULL;
2622
2623 // Depending on the element type create the appropriate extensions
2624 // for the individual components.
2625 dynamic_cast<const NURBSFECollection *>(fec)->Reset();
2626
2627 if (dynamic_cast<const NURBS_HDivFECollection *>(fec))
2628 {
2629 VNURBSext.SetSize(mesh->Dimension());
2630 for (int d = 0; d < mesh->Dimension(); d++)
2631 {
2633 }
2634 }
2635
2636 if (dynamic_cast<const NURBS_HCurlFECollection *>(fec))
2637 {
2638 VNURBSext.SetSize(mesh->Dimension());
2639 for (int d = 0; d < mesh->Dimension(); d++)
2640 {
2642 }
2643 }
2644
2645 // If required: concatenate the dof tables of the individual components into
2646 // one dof table for the vector fespace.
2647 if (VNURBSext.Size() == 2)
2648 {
2649 int offset1 = VNURBSext[0]->GetNDof();
2650 ndofs = VNURBSext[0]->GetNDof() + VNURBSext[1]->GetNDof();
2651
2652 // Merge Tables
2653 elem_dof = new Table(*VNURBSext[0]->GetElementDofTable(),
2654 *VNURBSext[1]->GetElementDofTable(),offset1 );
2655
2656 bdr_elem_dof = new Table(*VNURBSext[0]->GetBdrElementDofTable(),
2657 *VNURBSext[1]->GetBdrElementDofTable(),offset1);
2658 }
2659 else if (VNURBSext.Size() == 3)
2660 {
2661 int offset1 = VNURBSext[0]->GetNDof();
2662 int offset2 = offset1 + VNURBSext[1]->GetNDof();
2663 ndofs = offset2 + VNURBSext[2]->GetNDof();
2664
2665 // Merge Tables
2666 elem_dof = new Table(*VNURBSext[0]->GetElementDofTable(),
2667 *VNURBSext[1]->GetElementDofTable(),offset1,
2668 *VNURBSext[2]->GetElementDofTable(),offset2);
2669
2670 bdr_elem_dof = new Table(*VNURBSext[0]->GetBdrElementDofTable(),
2671 *VNURBSext[1]->GetBdrElementDofTable(),offset1,
2672 *VNURBSext[2]->GetBdrElementDofTable(),offset2);
2673 }
2674 else
2675 {
2676 ndofs = NURBSext->GetNDof();
2679 }
2681 sequence++;
2682}
2683
2685{
2686 if (face_dof) { return; }
2687
2688 const int dim = mesh->Dimension();
2689
2690 // Find bdr to face mapping
2692 face_to_be = -1;
2693 for (int b = 0; b < GetNBE(); b++)
2694 {
2696 face_to_be[f] = b;
2697 }
2698
2699 // Loop over faces in correct order, to prevent a sort
2700 // Sort will destroy orientation info in ordering of dofs
2701 Array<Connection> face_dof_list;
2702 Array<int> row;
2703 for (int f = 0; f < GetNF(); f++)
2704 {
2705 int b = face_to_be[f];
2706 if (b == -1) { continue; }
2707 // FIXME: this assumes that the boundary element and the face element have
2708 // the same orientation.
2709 if (dim > 1)
2710 {
2711 const Element *fe = mesh->GetFace(f);
2712 const Element *be = mesh->GetBdrElement(b);
2713 const int nv = be->GetNVertices();
2714 const int *fv = fe->GetVertices();
2715 const int *bv = be->GetVertices();
2716 for (int i = 0; i < nv; i++)
2717 {
2718 MFEM_VERIFY(fv[i] == bv[i],
2719 "non-matching face and boundary elements detected!");
2720 }
2721 }
2722 GetBdrElementDofs(b, row);
2723 Connection conn(f,0);
2724 for (int i = 0; i < row.Size(); i++)
2725 {
2726 conn.to = row[i];
2727 face_dof_list.Append(conn);
2728 }
2729 }
2730 face_dof = new Table(GetNF(), face_dof_list);
2731}
2732
2734{
2735 // This method should be used only for non-NURBS spaces.
2736 MFEM_VERIFY(!NURBSext, "internal error");
2737
2738 // Variable-order space needs a nontrivial P matrix + also ghost elements
2739 // in parallel, we thus require the mesh to be NC.
2740 MFEM_VERIFY(!IsVariableOrder() || Nonconforming(),
2741 "Variable-order space requires a nonconforming mesh.");
2742
2743 elem_dof = NULL;
2744 elem_fos = NULL;
2745 bdr_elem_dof = NULL;
2746 bdr_elem_fos = NULL;
2747 face_dof = NULL;
2748
2749 ndofs = 0;
2750 nvdofs = nedofs = nfdofs = nbdofs = 0;
2751 bdofs = NULL;
2752
2753 cP.reset();
2754 cR.reset();
2755 cR_hp.reset();
2756 cP_is_set = false;
2757 R_transpose.reset();
2758 // 'Th' is initialized/destroyed before this method is called.
2759
2760 int dim = mesh->Dimension();
2761 int order = fec->GetOrder();
2762
2763 MFEM_VERIFY((mesh->GetNumGeometries(dim) > 0) || (mesh->GetNE() == 0),
2764 "Mesh was not correctly finalized.");
2765
2766 bool mixed_elements = (mesh->GetNumGeometries(dim) > 1);
2767 bool mixed_faces = (dim > 2 && mesh->GetNumGeometries(2) > 1);
2768
2769 Array<VarOrderBits> edge_orders, face_orders, edge_elem_orders,
2770 face_elem_orders;
2771
2772 if (IsVariableOrder())
2773 {
2774 // for variable-order spaces, calculate orders of edges and faces
2775 CalcEdgeFaceVarOrders(edge_orders, face_orders, edge_elem_orders,
2776 face_elem_orders, skip_edge, skip_face);
2777 }
2778 else if (mixed_faces)
2779 {
2780 // for mixed faces we also create the var_face_dofs table, see below
2781 face_orders.SetSize(mesh->GetNFaces());
2782 face_orders = (VarOrderBits(1) << order);
2783 }
2784
2785 // assign vertex DOFs
2786 if (mesh->GetNV())
2787 {
2788 nvdofs = mesh->GetNV() * fec->GetNumDof(Geometry::POINT, order);
2789 }
2790
2791 // assign edge DOFs
2792 if (mesh->GetNEdges())
2793 {
2794 if (IsVariableOrder())
2795 {
2796 nedofs = MakeDofTable(1, edge_orders, var_edge_dofs, &var_edge_orders);
2797 MakeDofTable(1, edge_elem_orders, loc_var_edge_dofs,
2799 // Set lnedofs from the last row of loc_var_edge_dofs
2800 Array<int> lastRow;
2802 MFEM_ASSERT(lastRow.Size() == 1, "");
2803 lnedofs = lastRow[0];
2804 }
2805 else
2806 {
2807 // the simple case: all edges are of the same order
2809 var_edge_dofs.Clear(); // ensure any old var_edge_dof table is dumped.
2810 }
2811 }
2812
2813 // assign face DOFs
2814 if (mesh->GetNFaces())
2815 {
2816 if (IsVariableOrder() || mixed_faces)
2817 {
2818 // NOTE: for simplicity, we also use Table var_face_dofs for mixed faces
2819 nfdofs = MakeDofTable(2, face_orders, var_face_dofs,
2820 IsVariableOrder() ? &var_face_orders : NULL);
2821 uni_fdof = -1;
2822
2823 if (IsVariableOrder())
2824 {
2825 MakeDofTable(2, face_elem_orders, loc_var_face_dofs,
2827 // Set lnfdofs from the last row of loc_var_face_dofs
2828 Array<int> lastRow;
2830 MFEM_ASSERT(lastRow.Size() == 1, "");
2831 lnfdofs = lastRow[0];
2832 }
2833 }
2834 else
2835 {
2836 // the simple case: all faces are of the same geometry and order
2839 var_face_dofs.Clear(); // ensure any old var_face_dof table is dumped.
2840 }
2841 }
2842
2843 // assign internal ("bubble") DOFs
2844 if (mesh->GetNE() && dim > 0)
2845 {
2846 if (IsVariableOrder() || mixed_elements)
2847 {
2848 bdofs = new int[mesh->GetNE()+1];
2849 bdofs[0] = 0;
2850 for (int i = 0; i < mesh->GetNE(); i++)
2851 {
2852 int p = GetElementOrderImpl(i);
2854 bdofs[i+1] = nbdofs;
2855 }
2856 }
2857 else
2858 {
2859 // the simple case: all elements are the same
2860 bdofs = NULL;
2862 nbdofs = mesh->GetNE() * fec->GetNumDof(geom, order);
2863 }
2864 }
2865
2867
2869
2870 // record the current mesh sequence number to detect refinement etc.
2872
2873 // increment our sequence number to let GridFunctions know they need updating
2874 sequence++;
2875
2876 // DOFs are now assigned according to current element orders
2877 orders_changed = false;
2878
2879 // Do not build elem_dof Table here: in parallel it has to be constructed
2880 // later.
2881}
2882
2883void DofMapHelper(int entity, const Table & var_ent_dofs,
2884 const Table & loc_var_ent_dofs,
2885 const Array<char> & var_ent_orders,
2886 const Array<char> & loc_var_ent_orders,
2887 Array<int> & all2local, int & ndof_all, int & ndof_loc)
2888{
2889 const int osall0 = var_ent_dofs.GetI()[entity];
2890 const int osall1 = var_ent_dofs.GetI()[entity + 1];
2891
2892 const int osloc0 = loc_var_ent_dofs.GetI()[entity];
2893 const int osloc1 = loc_var_ent_dofs.GetI()[entity + 1];
2894
2895 // loc_var_ent_orders must be a subset of var_ent_orders
2896 int j = osall0;
2897 for (int i=osloc0; i<osloc1; ++i) // Loop over local variants
2898 {
2899 const int order = loc_var_ent_orders[i];
2900 // Find the variant in var_ent_orders with the same order
2901 int na = var_ent_dofs.GetJ()[j + 1] - var_ent_dofs.GetJ()[j];
2902 while (var_ent_orders[j] != order && j < osall1 - 1)
2903 {
2904 j++;
2905 ndof_all += na;
2906 na = var_ent_dofs.GetJ()[j + 1] - var_ent_dofs.GetJ()[j];
2907 }
2908
2909 MFEM_ASSERT(var_ent_orders[j] == order, "");
2910
2911 const int n = loc_var_ent_dofs.GetJ()[i + 1] - loc_var_ent_dofs.GetJ()[i];
2912
2913 MFEM_ASSERT(n == na &&
2914 n == var_ent_dofs.GetJ()[j + 1] - var_ent_dofs.GetJ()[j], "");
2915
2916 for (int k=0; k<n; ++k) { all2local[ndof_all + k] = ndof_loc + k; }
2917
2918 ndof_loc += n;
2919 ndof_all += na;
2920 j++;
2921 }
2922
2923 // Reach the end of all variants for ndof_all
2924 while (j < osall1)
2925 {
2926 const int na = var_ent_dofs.GetJ()[j + 1] - var_ent_dofs.GetJ()[j];
2927 ndof_all += na;
2928 j++;
2929 }
2930}
2931
2933{
2934 if (!IsVariableOrder()) { return; }
2935
2936 // Set a map from all DOFs to local DOFs
2938 all2local = -1;
2939
2940 // Vertex DOFs simply have the identity mapping
2941 for (int i=0; i<nvdofs; ++i)
2942 {
2943 all2local[i] = i;
2944 }
2945
2946 // Redefine local edge DOFs
2947 int ndof_all = nvdofs;
2948 int ndof_loc = nvdofs;
2949 if (mesh->GetNEdges())
2950 {
2951 for (int edge=0; edge<mesh->GetNEdges(); ++edge)
2952 {
2954 loc_var_edge_orders, all2local, ndof_all, ndof_loc);
2955 }
2956
2957 MFEM_ASSERT(ndof_loc - nvdofs == lnedofs, "");
2958 nedofs = lnedofs;
2959 }
2960
2961 // Redefine local face DOFs
2962 if (mesh->GetNFaces())
2963 {
2964 for (int face=0; face<mesh->GetNFaces(); ++face)
2965 {
2967 loc_var_face_orders, all2local, ndof_all, ndof_loc);
2968 }
2969
2970 MFEM_ASSERT(ndof_loc - nvdofs - lnedofs == lnfdofs, "");
2971 nfdofs = lnfdofs;
2972 }
2973
2974 // The remaining DOFs simply have the identity mapping
2975 for (int i=ndof_all; i<ndofs; ++i)
2976 {
2977 all2local[i] = ndof_loc + i - ndof_all;
2978 }
2979
2981}
2982
2984{
2985 MFEM_ASSERT(bits != 0, "invalid bit mask");
2986 for (int order = 0; bits != 0; order++, bits >>= 1)
2987 {
2988 if (bits & 1) { return order; }
2989 }
2990 return 0;
2991}
2992
2993// For the serial FiniteElementSpace, there are no ghost elements, and this
2994// function just sets the sizes of edge_orders and face_orders, initializing to
2995// 0.
2997 Array<VarOrderBits> &edge_orders,
2998 Array<VarOrderBits> &face_orders) const
2999{
3000 edge_orders.SetSize(mesh->GetNEdges());
3001 face_orders.SetSize(mesh->GetNFaces());
3002
3003 edge_orders = 0;
3004 face_orders = 0;
3005}
3006
3008 Array<VarOrderBits> &edge_orders, Array<VarOrderBits> &face_orders,
3009 Array<VarOrderBits> &edge_elem_orders, Array<VarOrderBits> &face_elem_orders,
3010 Array<bool> &skip_edges, Array<bool> &skip_faces) const
3011{
3012 MFEM_ASSERT(Nonconforming(), "");
3013
3014 const bool localVar = elem_order.Size() == mesh->GetNE();
3015 const int baseOrder = fec->GetOrder();
3016
3017 ApplyGhostElementOrdersToEdgesAndFaces(edge_orders, face_orders);
3018
3019 edge_elem_orders.SetSize(mesh->GetNEdges());
3020 face_elem_orders.SetSize(mesh->GetNFaces());
3021
3022 edge_elem_orders = 0;
3023 face_elem_orders = 0;
3024
3027
3030
3031 // Calculate initial edge/face orders, as required by incident elements.
3032 // For each edge/face we accumulate in a bit-mask the orders of elements
3033 // sharing the edge/face.
3034 Array<int> E, F, ori;
3035 for (int i = 0; i < mesh->GetNE(); i++)
3036 {
3037 const int order = localVar ? elem_order[i] : baseOrder;
3038 MFEM_ASSERT(order <= MaxVarOrder, "");
3039 const VarOrderBits mask = (VarOrderBits(1) << order);
3040
3041 mesh->GetElementEdges(i, E, ori);
3042 for (int j = 0; j < E.Size(); j++)
3043 {
3044 edge_orders[E[j]] |= mask;
3045 edge_elem_orders[E[j]] |= mask;
3046
3047 if (order < edge_min_nghb_order[E[j]])
3048 {
3049 edge_min_nghb_order[E[j]] = order;
3050 }
3051 }
3052
3053 if (mesh->Dimension() > 2)
3054 {
3055 mesh->GetElementFaces(i, F, ori);
3056 for (int j = 0; j < F.Size(); j++)
3057 {
3058 face_orders[F[j]] |= mask;
3059 face_elem_orders[F[j]] |= mask;
3060
3061 if (order < face_min_nghb_order[F[j]])
3062 {
3063 face_min_nghb_order[F[j]] = order;
3064 }
3065 }
3066 }
3067 }
3068
3069 if (relaxed_hp)
3070 {
3071 // for relaxed conformity we don't need the masters to match the minimum
3072 // orders of the slaves, we can stop now
3073 return;
3074 }
3075
3076 // Iterate while minimum orders propagate by master/slave relations
3077 // (and new orders also propagate from faces to incident edges).
3078 // See https://github.com/mfem/mfem/pull/1423#issuecomment-638930559
3079 // for an illustration of why this is necessary in hp meshes.
3080 bool done;
3081 do
3082 {
3083 std::set<int> changedEdges;
3084 std::set<int> changedFaces;
3085
3086 const int numEdges = mesh->GetNEdges();
3087
3088 // Propagate from slave edges to master edges
3089 const NCMesh::NCList &edge_list = mesh->ncmesh->GetEdgeList();
3090 for (const NCMesh::Master &master : edge_list.masters)
3091 {
3092 VarOrderBits slave_orders = 0;
3093 for (int i = master.slaves_begin; i < master.slaves_end; i++)
3094 {
3095 slave_orders |= edge_orders[edge_list.slaves[i].index];
3096 }
3097
3098 if (slave_orders == 0)
3099 {
3100 continue;
3101 }
3102
3103 const int min_order_slaves = MinOrder(slave_orders);
3104 if (edge_orders[master.index] == 0 ||
3105 min_order_slaves < MinOrder(edge_orders[master.index]))
3106 {
3107 edge_orders[master.index] |= VarOrderBits(1) << min_order_slaves;
3108 changedEdges.insert(master.index);
3109 }
3110
3111 // Also apply the minimum order to all the slave edges, since they must
3112 // interpolate the master edge, which has the minimum order.
3113 const VarOrderBits min_mask = VarOrderBits(1) << MinOrder(
3114 edge_orders[master.index]);
3115 for (int i = master.slaves_begin; i < master.slaves_end; i++)
3116 {
3117 if (edge_list.slaves[i].index >= numEdges)
3118 {
3119 continue; // Skip ghost edges
3120 }
3121
3122 const VarOrderBits eo0 = edge_orders[edge_list.slaves[i].index];
3123 edge_orders[edge_list.slaves[i].index] |= min_mask;
3124 if (eo0 != edge_orders[edge_list.slaves[i].index])
3125 {
3126 changedEdges.insert(edge_list.slaves[i].index);
3127 }
3128 }
3129 }
3130
3131 // Propagate from slave faces(+edges) to master faces.
3132 const int numFaces = mesh->GetNumFaces();
3133
3134 const NCMesh::NCList &face_list = mesh->ncmesh->GetFaceList();
3135
3136 for (const NCMesh::Master &master : face_list.masters)
3137 {
3138 VarOrderBits slave_orders = 0;
3139
3140 for (int i = master.slaves_begin; i < master.slaves_end; i++)
3141 {
3142 const NCMesh::Slave &slave = face_list.slaves[i];
3143
3144 if (slave.index >= 0)
3145 {
3146 // Note that master.index >= numFaces occurs for ghost master faces.
3147
3148 slave_orders |= face_orders[slave.index];
3149
3150 if (slave.index >= numFaces)
3151 {
3152 continue; // Skip ghost faces
3153 }
3154
3155 mesh->GetFaceEdges(slave.index, E, ori);
3156 for (int j = 0; j < E.Size(); j++)
3157 {
3158 slave_orders |= edge_orders[E[j]];
3159 }
3160 }
3161 else
3162 {
3163 // degenerate face (i.e., edge-face constraint)
3164 slave_orders |= edge_orders[-1 - slave.index];
3165 }
3166 }
3167
3168 if (slave_orders == 0)
3169 {
3170 continue;
3171 }
3172
3173 const int min_order_slaves = MinOrder(slave_orders);
3174 if (face_orders[master.index] == 0 ||
3175 min_order_slaves < MinOrder(face_orders[master.index]))
3176 {
3177 face_orders[master.index] |= VarOrderBits(1) << min_order_slaves;
3178 changedFaces.insert(master.index);
3179 }
3180
3181 // Also apply the minimum order to all the slave faces, since they must
3182 // interpolate the master face, which has the minimum order.
3183 const VarOrderBits min_mask =
3184 VarOrderBits(1) << MinOrder(face_orders[master.index]);
3185 for (int i = master.slaves_begin; i < master.slaves_end; i++)
3186 {
3187 const NCMesh::Slave &slave = face_list.slaves[i];
3188
3189 if (slave.index >= 0 && slave.index < numFaces) // Skip ghost faces
3190 {
3191 const VarOrderBits fo0 = face_orders[slave.index];
3192 face_orders[slave.index] |= min_mask;
3193 if (fo0 != face_orders[slave.index])
3194 {
3195 changedFaces.insert(slave.index);
3196 }
3197 }
3198 }
3199 }
3200
3201 // Make sure edges support (new) orders required by incident faces.
3202 for (int i = 0; i < mesh->GetNFaces(); i++)
3203 {
3204 mesh->GetFaceEdges(i, E, ori);
3205 for (int j = 0; j < E.Size(); j++)
3206 {
3207 const VarOrderBits eo0 = edge_orders[E[j]];
3208 edge_orders[E[j]] |= face_orders[i];
3209 if (eo0 != edge_orders[E[j]])
3210 {
3211 changedEdges.insert(E[j]);
3212 }
3213 }
3214 }
3215
3216 // In the parallel case, OrderPropagation communicates orders on updated
3217 // edges and faces.
3218 done = OrderPropagation(changedEdges, changedFaces,
3219 edge_orders, face_orders);
3220 }
3221 while (!done);
3222
3223 GhostFaceOrderToEdges(face_orders, edge_orders);
3224
3225 // Some ghost edges and faces (3D) may not have any orders applied, since we
3226 // only communicate orders of neighboring ghost elements. Such ghost entities
3227 // are marked here, to be skipped by BuildParallelConformingInterpolation as
3228 // master entities constraining slave entity DOFs.
3229
3230 skip_edges.SetSize(edge_orders.Size());
3231 skip_edges = false;
3232
3233 skip_faces.SetSize(face_orders.Size());
3234 skip_faces = false;
3235
3236 for (int i=0; i<edge_orders.Size(); ++i)
3237 {
3238 if (edge_orders[i] == 0)
3239 {
3240 skip_edges[i] = true;
3241 }
3242 }
3243
3244 for (int i=0; i<face_orders.Size(); ++i)
3245 {
3246 if (face_orders[i] == 0)
3247 {
3248 skip_faces[i] = true;
3249 }
3250 }
3251}
3252
3254 const Array<VarOrderBits> &entity_orders,
3255 Table &entity_dofs,
3256 Array<char> *var_ent_order)
3257{
3258 // The tables var_edge_dofs and var_face_dofs hold DOF assignments for edges
3259 // and faces of a variable-order space, in which each edge/face may host
3260 // several DOF sets, called DOF set variants. Example: an edge 'i' shared by
3261 // 4 hexes of orders 2, 3, 4, 5 will hold four DOF sets, each starting at
3262 // indices e.g. 100, 101, 103, 106, respectively. These numbers are stored
3263 // in row 'i' of var_edge_dofs. Variant zero is always the lowest order DOF
3264 // set, followed by consecutive ranges of higher order DOFs. Variable-order
3265 // faces are handled similarly by var_face_dofs. The tables are empty for
3266 // constant-order spaces.
3267
3268 int num_ent = entity_orders.Size();
3269 int total_dofs = 0;
3270 int total_dofs_nonghost = 0;
3271
3272 Array<Connection> list;
3273 list.Reserve(2*num_ent);
3274
3275 if (var_ent_order)
3276 {
3277 var_ent_order->SetSize(0);
3278 var_ent_order->Reserve(num_ent);
3279 }
3280
3281 int nonGhost = num_ent;
3282 if (IsVariableOrder())
3283 {
3284 nonGhost -= (ent_dim == 1) ? NumGhostEdges() : NumGhostFaces();
3285 }
3286
3287 // assign DOFs according to order bit masks
3288 for (int i = 0; i < num_ent; i++)
3289 {
3290 auto geom = Geometry::SEGMENT; // ent_dim == 1 case
3291 if (ent_dim != 1)
3292 {
3293 // TODO: put this logic in mesh->GetFaceGeometry?
3294 if (i >= nonGhost) // if ghost
3295 {
3296 geom = mesh->ncmesh->GetFaceGeometry(i);
3297 }
3298 else
3299 {
3300 geom = mesh->GetFaceGeometry(i);
3301 }
3302 }
3303
3304 VarOrderBits bits = entity_orders[i];
3305 for (int order = 0; bits != 0; order++, bits >>= 1)
3306 {
3307 if (bits & 1)
3308 {
3309 const int dofs = fec->GetNumDof(geom, order);
3310 list.Append(Connection(i, total_dofs));
3311 total_dofs += dofs;
3312 if (i < nonGhost) { total_dofs_nonghost += dofs; }
3313 if (var_ent_order) { var_ent_order->Append(order); }
3314 }
3315 }
3316 }
3317
3318 // append a dummy row as terminator
3319 list.Append(Connection(num_ent, total_dofs));
3320
3321 // build the table
3322 entity_dofs.MakeFromList(num_ent+1, list);
3323 return total_dofs_nonghost;
3324}
3325
3326int FiniteElementSpace::FindDofs(const Table &var_dof_table,
3327 int row, int ndof) const
3328{
3329 const int *beg = var_dof_table.GetRow(row);
3330 const int *end = var_dof_table.GetRow(row + 1); // terminator, see above
3331
3332 while (beg < end)
3333 {
3334 // return the appropriate range of DOFs
3335 if ((beg[1] - beg[0]) == ndof) { return beg[0]; }
3336 beg++;
3337 }
3338
3339 MFEM_ABORT("DOFs not found for ndof = " << ndof);
3340 return 0;
3341}
3342
3343int FiniteElementSpace::GetEdgeOrder(int edge, int variant) const
3344{
3345 if (!IsVariableOrder()) { return fec->GetOrder(); }
3346
3347 if (edge >= var_edge_dofs.Size())
3348 {
3349 return ghost_edge_orders[edge - var_edge_dofs.Size()];
3350 }
3351
3352 const int* beg = var_edge_dofs.GetRow(edge);
3353 const int* end = var_edge_dofs.GetRow(edge + 1);
3354 if (variant >= end - beg) { return -1; } // past last variant
3355
3356 return var_edge_orders[var_edge_dofs.GetI()[edge] + variant];
3357}
3358
3359int FiniteElementSpace::GetFaceOrder(int face, int variant) const
3360{
3361 if (!IsVariableOrder())
3362 {
3363 // face order can be different from fec->GetOrder()
3364 Geometry::Type geom = mesh->GetFaceGeometry(face);
3365 return fec->FiniteElementForGeometry(geom)->GetOrder();
3366 }
3367
3368 if (face >= var_face_dofs.Size())
3369 {
3370 return ghost_face_orders[face - var_face_dofs.Size()];
3371 }
3372
3373 const int* beg = var_face_dofs.GetRow(face);
3374 const int* end = var_face_dofs.GetRow(face + 1);
3375 if (variant >= end - beg) { return -1; } // past last variant
3376
3377 return var_face_orders[var_face_dofs.GetI()[face] + variant];
3378}
3379
3380int FiniteElementSpace::GetNVariants(int entity, int index) const
3381{
3382 MFEM_ASSERT(IsVariableOrder(), "");
3383 const Table &dof_table = (entity == 1) ? var_edge_dofs : var_face_dofs;
3384
3385 MFEM_ASSERT(index >= 0 && index < dof_table.Size(), "");
3386 return dof_table.GetRow(index + 1) - dof_table.GetRow(index);
3387}
3388
3389static const char* msg_orders_changed =
3390 "Element orders changed, you need to Update() the space first.";
3391
3393 DofTransformation &doftrans) const
3394{
3395 MFEM_VERIFY(!orders_changed, msg_orders_changed);
3396
3397 doftrans.SetDofTransformation(nullptr);
3398
3399 if (elem_dof)
3400 {
3401 elem_dof->GetRow(elem, dofs);
3402
3404 {
3405 Array<int> Fo;
3406 elem_fos -> GetRow (elem, Fo);
3407 doftrans.SetDofTransformation(
3409 doftrans.SetFaceOrientations(Fo);
3410 doftrans.SetVDim();
3411 }
3412 return;
3413 }
3414
3415 Array<int> V, E, Eo, F, Fo; // TODO: LocalArray
3416
3417 const int dim = mesh->Dimension();
3418 const auto geom = mesh->GetElementGeometry(elem);
3419 const int order = GetElementOrderImpl(elem);
3420
3421 const int nv = fec->GetNumDof(Geometry::POINT, order);
3422 const int ne = (dim > 1) ? fec->GetNumDof(Geometry::SEGMENT, order) : 0;
3423 const int nb = (dim > 0) ? fec->GetNumDof(geom, order) : 0;
3424
3425 if (nv) { mesh->GetElementVertices(elem, V); }
3426 if (ne) { mesh->GetElementEdges(elem, E, Eo); }
3427
3428 int nfd = 0;
3429 if (dim > 2 && fec->HasFaceDofs(geom, order))
3430 {
3431 mesh->GetElementFaces(elem, F, Fo);
3432 for (int i = 0; i < F.Size(); i++)
3433 {
3434 nfd += fec->GetNumDof(mesh->GetFaceGeometry(F[i]), order);
3435 }
3437 {
3438 doftrans.SetDofTransformation(
3440 doftrans.SetFaceOrientations(Fo);
3441 doftrans.SetVDim();
3442 }
3443 }
3444
3445 dofs.SetSize(0);
3446 dofs.Reserve(nv*V.Size() + ne*E.Size() + nfd + nb);
3447
3448 if (nv) // vertex DOFs
3449 {
3450 for (int i = 0; i < V.Size(); i++)
3451 {
3452 for (int j = 0; j < nv; j++)
3453 {
3454 dofs.Append(V[i]*nv + j);
3455 }
3456 }
3457 }
3458
3459 if (ne) // edge DOFs
3460 {
3461 for (int i = 0; i < E.Size(); i++)
3462 {
3463 int ebase = IsVariableOrder() ? FindEdgeDof(E[i], ne) : E[i]*ne;
3464 const int *ind = fec->GetDofOrdering(Geometry::SEGMENT, order, Eo[i]);
3465
3466 for (int j = 0; j < ne; j++)
3467 {
3468 dofs.Append(EncodeDof(nvdofs + ebase, ind[j]));
3469 }
3470 }
3471 }
3472
3473 if (nfd) // face DOFs
3474 {
3475 for (int i = 0; i < F.Size(); i++)
3476 {
3477 auto fgeom = mesh->GetFaceGeometry(F[i]);
3478 int nf = fec->GetNumDof(fgeom, order);
3479
3480 int fbase = (var_face_dofs.Size() > 0) ? FindFaceDof(F[i], nf) : F[i]*nf;
3481 const int *ind = fec->GetDofOrdering(fgeom, order, Fo[i]);
3482
3483 for (int j = 0; j < nf; j++)
3484 {
3485 dofs.Append(EncodeDof(nvdofs + nedofs + fbase, ind[j]));
3486 }
3487 }
3488 }
3489
3490 if (nb) // interior ("bubble") DOFs
3491 {
3492 int bbase = bdofs ? bdofs[elem] : elem*nb;
3493 bbase += nvdofs + nedofs + nfdofs;
3494
3495 for (int j = 0; j < nb; j++)
3496 {
3497 dofs.Append(bbase + j);
3498 }
3499 }
3500}
3501
3503 Array<int> &dofs) const
3504{
3505 GetElementDofs(elem, dofs, DoFTrans);
3506 return DoFTrans.GetDofTransformation() ? &DoFTrans : NULL;
3507}
3508
3510 DofTransformation &doftrans) const
3511{
3512 MFEM_VERIFY(!orders_changed, msg_orders_changed);
3513
3514 doftrans.SetDofTransformation(nullptr);
3515
3516 if (bdr_elem_dof)
3517 {
3518 bdr_elem_dof->GetRow(bel, dofs);
3519
3521 {
3522 Array<int> Fo;
3523 bdr_elem_fos -> GetRow (bel, Fo);
3524 doftrans.SetDofTransformation(
3526 doftrans.SetFaceOrientations(Fo);
3527 doftrans.SetVDim();
3528 }
3529 return;
3530 }
3531
3532 Array<int> V, E, Eo; // TODO: LocalArray
3533 int F, oF;
3534
3535 int dim = mesh->Dimension();
3536 auto geom = mesh->GetBdrElementGeometry(bel);
3537 int order = fec->GetOrder();
3538
3539 if (elem_order.Size()) // determine order from adjacent element
3540 {
3541 int elem, info;
3542 mesh->GetBdrElementAdjacentElement(bel, elem, info);
3543 order = elem_order[elem];
3544 }
3545
3546 int nv = fec->GetNumDof(Geometry::POINT, order);
3547 int ne = (dim > 1) ? fec->GetNumDof(Geometry::SEGMENT, order) : 0;
3548 int nf = (dim > 2) ? fec->GetNumDof(geom, order) : 0;
3549
3550 if (nv) { mesh->GetBdrElementVertices(bel, V); }
3551 if (ne) { mesh->GetBdrElementEdges(bel, E, Eo); }
3552 if (nf)
3553 {
3554 mesh->GetBdrElementFace(bel, &F, &oF);
3555
3557 {
3558 mfem::Array<int> Fo(1);
3559 Fo[0] = oF;
3560 doftrans.SetDofTransformation(
3562 doftrans.SetFaceOrientations(Fo);
3563 doftrans.SetVDim();
3564 }
3565 }
3566
3567 dofs.SetSize(0);
3568 dofs.Reserve(nv*V.Size() + ne*E.Size() + nf);
3569
3570 if (nv) // vertex DOFs
3571 {
3572 for (int i = 0; i < V.Size(); i++)
3573 {
3574 for (int j = 0; j < nv; j++)
3575 {
3576 dofs.Append(V[i]*nv + j);
3577 }
3578 }
3579 }
3580
3581 if (ne) // edge DOFs
3582 {
3583 for (int i = 0; i < E.Size(); i++)
3584 {
3585 int ebase = IsVariableOrder() ? FindEdgeDof(E[i], ne) : E[i]*ne;
3586 const int *ind = fec->GetDofOrdering(Geometry::SEGMENT, order, Eo[i]);
3587
3588 for (int j = 0; j < ne; j++)
3589 {
3590 dofs.Append(EncodeDof(nvdofs + ebase, ind[j]));
3591 }
3592 }
3593 }
3594
3595 if (nf) // face DOFs
3596 {
3597 int fbase = (var_face_dofs.Size() > 0) ? FindFaceDof(F, nf) : F*nf;
3598 const int *ind = fec->GetDofOrdering(geom, order, oF);
3599
3600 for (int j = 0; j < nf; j++)
3601 {
3602 dofs.Append(EncodeDof(nvdofs + nedofs + fbase, ind[j]));
3603 }
3604 }
3605}
3606
3608 Array<int> &dofs) const
3609{
3610 GetBdrElementDofs(bel, dofs, DoFTrans);
3611 return DoFTrans.GetDofTransformation() ? &DoFTrans : NULL;
3612}
3613
3615 int variant) const
3616{
3617 MFEM_VERIFY(!orders_changed, msg_orders_changed);
3618
3619 // If face_dof is already built, use it.
3620 // If it is not and we have a NURBS space, build the face_dof and use it.
3621 if ((face_dof && variant == 0) ||
3622 (NURBSext && (BuildNURBSFaceToDofTable(), true)))
3623 {
3624 face_dof->GetRow(face, dofs);
3625 return fec->GetOrder();
3626 }
3627
3628 int order, nf, fbase;
3629 int dim = mesh->Dimension();
3630 auto fgeom = (dim > 2) ? mesh->GetFaceGeometry(face) : Geometry::INVALID;
3631
3632 if (var_face_dofs.Size() > 0) // variable orders or *mixed* faces
3633 {
3634 const int* beg = var_face_dofs.GetRow(face);
3635 const int* end = var_face_dofs.GetRow(face + 1);
3636 if (variant >= end - beg) { return -1; } // past last face DOFs
3637
3638 fbase = beg[variant];
3639 nf = beg[variant+1] - fbase;
3640
3641 order = !IsVariableOrder() ? fec->GetOrder() :
3642 var_face_orders[var_face_dofs.GetI()[face] + variant];
3643 MFEM_ASSERT(fec->GetNumDof(fgeom, order) == nf, [&]()
3644 {
3645 std::stringstream msg;
3646 msg << "fec->GetNumDof(" << (fgeom == Geometry::SQUARE ? "square" : "triangle")
3647 << ", " << order << ") = " << fec->GetNumDof(fgeom, order) << " nf " << nf;
3648 msg << " face " << face << " variant " << variant << std::endl;
3649 return msg.str();
3650 }());
3651 }
3652 else
3653 {
3654 if (variant > 0) { return -1; }
3655 order = fec->GetOrder();
3656 nf = (dim > 2) ? fec->GetNumDof(fgeom, order) : 0;
3657 fbase = face*nf;
3658 }
3659
3660 // for 1D, 2D and 3D faces
3661 int nv = fec->GetNumDof(Geometry::POINT, order);
3662 int ne = (dim > 1) ? fec->GetNumDof(Geometry::SEGMENT, order) : 0;
3663
3664 Array<int> V, E, Eo;
3665 if (nv) { mesh->GetFaceVertices(face, V); }
3666 if (ne) { mesh->GetFaceEdges(face, E, Eo); }
3667
3668 dofs.SetSize(0);
3669 dofs.Reserve(V.Size() * nv + E.Size() * ne + nf);
3670
3671 if (nv) // vertex DOFs
3672 {
3673 for (int i = 0; i < V.Size(); i++)
3674 {
3675 for (int j = 0; j < nv; j++)
3676 {
3677 dofs.Append(V[i]*nv + j);
3678 }
3679 }
3680 }
3681 if (ne) // edge DOFs
3682 {
3683 for (int i = 0; i < E.Size(); i++)
3684 {
3685 int ebase = IsVariableOrder() ? FindEdgeDof(E[i], ne) : E[i]*ne;
3686 const int *ind = fec->GetDofOrdering(Geometry::SEGMENT, order, Eo[i]);
3687
3688 for (int j = 0; j < ne; j++)
3689 {
3690 dofs.Append(EncodeDof(nvdofs + ebase, ind[j]));
3691 }
3692 }
3693 }
3694 for (int j = 0; j < nf; j++)
3695 {
3696 dofs.Append(nvdofs + nedofs + fbase + j);
3697 }
3698
3699 return order;
3700}
3701
3703 int variant) const
3704{
3705 MFEM_VERIFY(!orders_changed, msg_orders_changed);
3706
3707 int order, ne, base;
3708 if (IsVariableOrder())
3709 {
3710 const int* beg = var_edge_dofs.GetRow(edge);
3711 const int* end = var_edge_dofs.GetRow(edge + 1);
3712 if (variant >= end - beg) { return -1; } // past last edge DOFs
3713
3714 base = beg[variant];
3715 ne = beg[variant+1] - base;
3716
3717 order = var_edge_orders[var_edge_dofs.GetI()[edge] + variant];
3718 MFEM_ASSERT(fec->GetNumDof(Geometry::SEGMENT, order) == ne, "");
3719 }
3720 else
3721 {
3722 if (variant > 0) { return -1; }
3723 order = fec->GetOrder();
3724 ne = fec->GetNumDof(Geometry::SEGMENT, order);
3725 base = edge*ne;
3726 }
3727
3728 Array<int> V; // TODO: LocalArray
3729 int nv = fec->GetNumDof(Geometry::POINT, order);
3730 if (nv) { mesh->GetEdgeVertices(edge, V); }
3731
3732 dofs.SetSize(0);
3733 dofs.Reserve(2*nv + ne);
3734
3735 for (int i = 0; i < 2; i++)
3736 {
3737 for (int j = 0; j < nv; j++)
3738 {
3739 dofs.Append(V[i]*nv + j);
3740 }
3741 }
3742 for (int j = 0; j < ne; j++)
3743 {
3744 dofs.Append(nvdofs + base + j);
3745 }
3746
3747 return order;
3748}
3749
3751{
3753 dofs.SetSize(nv);
3754 for (int j = 0; j < nv; j++)
3755 {
3756 dofs[j] = i*nv+j;
3757 }
3758}
3759
3761{
3762 MFEM_VERIFY(!orders_changed, msg_orders_changed);
3763
3765 int base = bdofs ? bdofs[i] : i*nb;
3766
3767 dofs.SetSize(nb);
3768 base += nvdofs + nedofs + nfdofs;
3769 for (int j = 0; j < nb; j++)
3770 {
3771 dofs[j] = base + j;
3772 }
3773}
3774
3780
3782{
3783 MFEM_VERIFY(!IsVariableOrder(), "not implemented");
3784
3785 int nf, base;
3786 if (var_face_dofs.Size() > 0) // mixed faces
3787 {
3788 base = var_face_dofs.GetRow(i)[0];
3789 nf = var_face_dofs.GetRow(i)[1] - base;
3790 }
3791 else
3792 {
3793 auto geom = mesh->GetTypicalFaceGeometry();
3794 nf = fec->GetNumDof(geom, fec->GetOrder());
3795 base = i*nf;
3796 }
3797
3798 dofs.SetSize(nf);
3799 for (int j = 0; j < nf; j++)
3800 {
3801 dofs[j] = nvdofs + nedofs + base + j;
3802 }
3803}
3804
3806{
3807 MFEM_VERIFY(!IsVariableOrder(), "not implemented");
3808
3810 dofs.SetSize (ne);
3811 for (int j = 0, k = nvdofs+i*ne; j < ne; j++, k++)
3812 {
3813 dofs[j] = k;
3814 }
3815}
3816
3818{
3819 MFEM_ASSERT(NURBSext,
3820 "FiniteElementSpace::GetPatchDofs needs a NURBSExtension");
3821 NURBSext->GetPatchDofs(patch, dofs);
3822}
3823
3825{
3826 if (i < 0 || i >= mesh->GetNE())
3827 {
3828 if (mesh->GetNE() == 0)
3829 {
3830 MFEM_ABORT("Empty MPI partitions are not permitted!");
3831 }
3832 MFEM_ABORT("Invalid element id:" << i << "; minimum allowed:" << 0 <<
3833 ", maximum allowed:" << mesh->GetNE()-1);
3834 }
3835
3836 const FiniteElement *FE =
3838
3839 if (NURBSext)
3840 {
3841 NURBSext->LoadFE(i, FE);
3842 }
3843 else
3844 {
3845#ifdef MFEM_DEBUG
3846 // consistency check: fec->GetOrder() and FE->GetOrder() should return
3847 // the same value (for standard, constant-order spaces)
3848 if (!IsVariableOrder() && FE->GetDim() > 0)
3849 {
3850 MFEM_ASSERT(FE->GetOrder() == fec->GetOrder(),
3851 "internal error: " <<
3852 FE->GetOrder() << " != " << fec->GetOrder());
3853 }
3854#endif
3855 }
3856
3857 return FE;
3858}
3859
3861{
3862 if (mesh->GetNE() > 0) { return GetFE(0); }
3863
3865 const FiniteElement *fe = fec->FiniteElementForGeometry(geom);
3866 MFEM_VERIFY(fe != nullptr, "Could not determine a typical FE!");
3867 return fe;
3868}
3869
3871{
3872 int order = fec->GetOrder();
3873
3874 if (IsVariableOrder()) // determine order from adjacent element
3875 {
3876 int elem, info;
3877 mesh->GetBdrElementAdjacentElement(i, elem, info);
3878 order = GetElementOrderImpl(elem);
3879 }
3880
3881 const FiniteElement *BE;
3882 switch (mesh->Dimension())
3883 {
3884 case 1:
3885 BE = fec->GetFE(Geometry::POINT, order);
3886 break;
3887 case 2:
3888 BE = fec->GetFE(Geometry::SEGMENT, order);
3889 break;
3890 case 3:
3891 default:
3892 BE = fec->GetFE(mesh->GetBdrElementGeometry(i), order);
3893 }
3894
3895 if (NURBSext)
3896 {
3897 NURBSext->LoadBE(i, BE);
3898 }
3899
3900 return BE;
3901}
3902
3904{
3905 MFEM_VERIFY(!IsVariableOrder(), "not implemented");
3906
3907 const FiniteElement *fe;
3908 switch (mesh->Dimension())
3909 {
3910 case 1:
3912 break;
3913 case 2:
3915 break;
3916 case 3:
3917 default:
3919 }
3920
3921 if (NURBSext)
3922 {
3923 // Ensure 'face_to_be' is built:
3925 MFEM_ASSERT(face_to_be[i] >= 0,
3926 "NURBS mesh: only boundary faces are supported!");
3927 NURBSext->LoadBE(face_to_be[i], fe);
3928 }
3929
3930 return fe;
3931}
3932
3934 int variant) const
3935{
3936 MFEM_ASSERT(mesh->Dimension() > 1, "No edges with mesh dimension < 2");
3937
3938 int eo = IsVariableOrder() ? GetEdgeOrder(i, variant) : fec->GetOrder();
3939 return fec->GetFE(Geometry::SEGMENT, eo);
3940}
3941
3943 int i, Geometry::Type geom_type) const
3944{
3945 return fec->GetTraceFE(geom_type, GetElementOrder(i));
3946}
3947
3952
3957
3959{
3960 R_transpose.reset();
3961 cR.reset();
3962 cR_hp.reset();
3963 cP.reset();
3964 Th.Clear();
3965 L2E_nat.Clear();
3966 L2E_lex.Clear();
3967 for (int i = 0; i < E2Q_array.Size(); i++)
3968 {
3969 delete E2Q_array[i];
3970 }
3971 E2Q_array.SetSize(0);
3972 for (auto &x : L2F)
3973 {
3974 delete x.second;
3975 }
3976 L2F.clear();
3977 for (int i = 0; i < E2IFQ_array.Size(); i++)
3978 {
3979 delete E2IFQ_array[i];
3980 }
3981 E2IFQ_array.SetSize(0);
3982 for (int i = 0; i < E2BFQ_array.Size(); i++)
3983 {
3984 delete E2BFQ_array[i];
3985 }
3986 E2BFQ_array.SetSize(0);
3987
3989
3994
3995 for (int i = 0; i < VNURBSext.Size(); i++)
3996 {
3997 delete VNURBSext[i];
3998 }
3999
4000 if (NURBSext)
4001 {
4002 if (own_ext) { delete NURBSext; }
4003 delete face_dof;
4005 if (VNURBSext.Size() > 0 )
4006 {
4007 delete elem_dof;
4008 delete bdr_elem_dof;
4009 }
4010 }
4011 else
4012 {
4013 delete elem_dof;
4014 delete elem_fos;
4015 delete bdr_elem_dof;
4016 delete bdr_elem_fos;
4017 delete face_dof;
4018 delete [] bdofs;
4019 }
4021
4022
4023}
4024
4026{
4027 for (int i = 0; i < DoFTransArray.Size(); i++)
4028 {
4029 delete DoFTransArray[i];
4030 }
4031 DoFTransArray.SetSize(0);
4032}
4033
4035 const FiniteElementSpace &coarse_fes, OperatorHandle &T) const
4036{
4037 // Assumptions: see the declaration of the method.
4038
4039 if (T.Type() == Operator::MFEM_SPARSEMAT)
4040 {
4041 if (!IsVariableOrder())
4042 {
4043 Mesh::GeometryList elem_geoms(*mesh);
4044
4046 for (int i = 0; i < elem_geoms.Size(); i++)
4047 {
4048 GetLocalRefinementMatrices(coarse_fes, elem_geoms[i],
4049 localP[elem_geoms[i]]);
4050 }
4051 T.Reset(RefinementMatrix_main(coarse_fes.GetNDofs(),
4052 coarse_fes.GetElementToDofTable(),
4053 coarse_fes.
4055 localP));
4056 }
4057 else
4058 {
4060 coarse_fes.GetElementToDofTable()));
4061 }
4062 }
4063 else
4064 {
4065 T.Reset(new RefinementOperator(this, &coarse_fes));
4066 }
4067}
4068
4070 const FiniteElementSpace &coarse_fes, OperatorHandle &T) const
4071{
4072 const SparseMatrix *coarse_P = coarse_fes.GetConformingProlongation();
4073
4074 Operator::Type req_type = T.Type();
4075 GetTransferOperator(coarse_fes, T);
4076
4077 if (req_type == Operator::MFEM_SPARSEMAT)
4078 {
4080 {
4081 T.Reset(mfem::Mult(*cR, *T.As<SparseMatrix>()));
4082 }
4083 if (coarse_P)
4084 {
4085 T.Reset(mfem::Mult(*T.As<SparseMatrix>(), *coarse_P));
4086 }
4087 }
4088 else
4089 {
4090 const int RP_case = bool(GetConformingRestriction()) + 2*bool(coarse_P);
4091 if (RP_case == 0) { return; }
4092 const bool owner = T.OwnsOperator();
4093 T.SetOperatorOwner(false);
4094 switch (RP_case)
4095 {
4096 case 1:
4097 T.Reset(new ProductOperator(cR.get(), T.Ptr(), false, owner));
4098 break;
4099 case 2:
4100 T.Reset(new ProductOperator(T.Ptr(), coarse_P, owner, false));
4101 break;
4102 case 3:
4104 cR.get(), T.Ptr(), coarse_P, false, owner, false));
4105 break;
4106 }
4107 }
4108}
4109
4111{
4112 Array<char> new_order(mesh->GetNE());
4113 switch (mesh->GetLastOperation())
4114 {
4115 case Mesh::REFINE:
4116 {
4118 for (int i = 0; i < mesh->GetNE(); i++)
4119 {
4120 new_order[i] = elem_order[cf_tr.embeddings[i].parent];
4121 }
4122 break;
4123 }
4124 case Mesh::DEREFINE:
4125 {
4126 const CoarseFineTransformations &cf_tr =
4128 Table coarse_to_fine;
4129 cf_tr.MakeCoarseToFineTable(coarse_to_fine);
4130 Array<int> tabrow;
4131 for (int i = 0; i < coarse_to_fine.Size(); i++)
4132 {
4133 coarse_to_fine.GetRow(i, tabrow);
4134 // For now we require all children to be of same polynomial order.
4135 new_order[i] = elem_order[tabrow[0]];
4136 }
4137 break;
4138 }
4139 default:
4140 MFEM_ABORT("not implemented yet");
4141 }
4142
4143 mfem::Swap(elem_order, new_order);
4144}
4145
4146void FiniteElementSpace::Update(bool want_transform)
4147{
4148 lastUpdatePRef = false;
4149
4150 if (!orders_changed)
4151 {
4152 if (mesh->GetSequence() == mesh_sequence)
4153 {
4154 return; // mesh and space are in sync, no-op
4155 }
4156 if (want_transform && mesh->GetSequence() != mesh_sequence + 1)
4157 {
4158 MFEM_ABORT("Error in update sequence. Space needs to be updated after "
4159 "each mesh modification.");
4160 }
4161 }
4162 else
4163 {
4164 if (mesh->GetSequence() != mesh_sequence)
4165 {
4166 MFEM_ABORT("Updating space after both mesh change and element order "
4167 "change is not supported. Please update separately after "
4168 "each change.");
4169 }
4170 }
4171
4172 if (NURBSext)
4173 {
4174 UpdateNURBS();
4175 return;
4176 }
4177
4178 Table* old_elem_dof = NULL;
4179 Table* old_elem_fos = NULL;
4180 int old_ndofs;
4181 bool old_orders_changed = orders_changed;
4182
4183 // save old DOF table
4184 if (want_transform)
4185 {
4186 old_elem_dof = elem_dof;
4187 old_elem_fos = elem_fos;
4188 elem_dof = NULL;
4189 elem_fos = NULL;
4190 old_ndofs = ndofs;
4191 }
4192
4193 // update the 'elem_order' array if the mesh has changed
4195 {
4197 }
4198
4199 Destroy(); // calls Th.Clear()
4200 Construct();
4202
4203 if (want_transform)
4204 {
4205 MFEM_VERIFY(!old_orders_changed, "Interpolation for element order change "
4206 "is not implemented yet, sorry.");
4207
4208 // calculate appropriate GridFunction transformation
4209 switch (mesh->GetLastOperation())
4210 {
4211 case Mesh::REFINE:
4212 {
4214 {
4215 Th.Reset(new RefinementOperator(this, old_elem_dof,
4216 old_elem_fos, old_ndofs));
4217 // The RefinementOperator takes ownership of 'old_elem_dof', so
4218 // we no longer own it:
4219 old_elem_dof = NULL;
4220 old_elem_fos = NULL;
4221 }
4222 else
4223 {
4224 // calculate fully assembled matrix
4225 Th.Reset(RefinementMatrix(old_ndofs, old_elem_dof,
4226 old_elem_fos));
4227 }
4228 break;
4229 }
4230
4231 case Mesh::DEREFINE:
4232 {
4234#if 0
4235 Th.Reset(DerefinementMatrix(old_ndofs, old_elem_dof, old_elem_fos));
4236#else
4237 Th.Reset(new DerefineMatrixOp(*this, old_ndofs, old_elem_dof, old_elem_fos));
4238#endif
4239 if (IsVariableOrder())
4240 {
4241 if (cP && cR_hp)
4242 {
4243 Th.SetOperatorOwner(false);
4244 Th.Reset(new TripleProductOperator(cP.get(), cR_hp.get(), Th.Ptr(),
4245 false, false, true));
4246 }
4247 }
4248 else
4249 {
4250 if (cP && cR)
4251 {
4252 Th.SetOperatorOwner(false);
4253 Th.Reset(new TripleProductOperator(cP.get(), cR.get(), Th.Ptr(),
4254 false, false, true));
4255 }
4256 }
4257 break;
4258 }
4259
4260 default:
4261 break;
4262 }
4263
4264 delete old_elem_dof;
4265 delete old_elem_fos;
4266 }
4267}
4268
4270 bool want_transfer)
4271{
4272 if (want_transfer)
4273 {
4275 for (int i = 0; i<mesh->GetNE(); i++)
4276 {
4277 fesPrev->SetElementOrder(i, GetElementOrder(i));
4278 }
4279 fesPrev->Update(false);
4280 }
4281
4282 for (auto ref : refs)
4283 {
4284 SetElementOrder(ref.index, GetElementOrder(ref.index) + ref.delta);
4285 }
4286
4287 Update(false);
4288
4289 if (want_transfer)
4290 {
4291 PTh.reset(new PRefinementTransferOperator(*fesPrev, *this));
4292 }
4293
4294 lastUpdatePRef = true;
4295}
4296
4298{
4299 // Check whether the space type is L2 or H1
4300 if (!dynamic_cast<const L2_FECollection*>(fec) &&
4301 !dynamic_cast<const H1_FECollection*>(fec))
4302 {
4303 return false;
4304 }
4305
4306 // Check whether the mesh is purely quadrilateral or hexahedral.
4307 const int dim = mesh->Dimension();
4309 mesh->GetGeometries(dim, geoms);
4310 if (geoms.Size() != 1) { return false; }
4311 if (dim == 2 && geoms[0] != Geometry::Type::SQUARE) { return false; }
4312 else if (dim == 3 && geoms[0] != Geometry::Type::CUBE) { return false; }
4313
4314 return true;
4315}
4316
4318{
4319 mesh = new_mesh;
4320}
4321
4323 Vector &fes_node_pos,
4324 int fes_nodes_ordering) const
4325{
4326 Mesh *m = GetMesh();
4327 const int NE = m->GetNE();
4328
4329 if (NE == 0) { fes_node_pos.SetSize(0); return; }
4330
4331 const int dim = m->Dimension();
4332 Array<int> dofs;
4333 Vector e_xyz;
4334 fes_node_pos.SetSize(GetNDofs() * dim);
4335 const FiniteElementSpace *mesh_fes = m->GetNodalFESpace();
4336 FiniteElementSpace vector_fes(m, FEColl(), dim, fes_nodes_ordering);
4337
4338 for (int e = 0; e < NE; e++)
4339 {
4340 mesh_fes->GetElementVDofs(e, dofs);
4341 const int mdof_cnt = dofs.Size() / dim;
4342 mesh_nodes.GetSubVector(dofs, e_xyz); //e_xyz is ordered by nodes here
4343
4344 auto ir = GetFE(e)->GetNodes();
4345 const int fdof_cnt = ir.GetNPoints();
4346 Vector mesh_shape(mdof_cnt), gf_xyz(fdof_cnt * dim);
4347 for (int q = 0; q < fdof_cnt; q++)
4348 {
4349 mesh_fes->GetFE(e)->CalcShape(ir.IntPoint(q), mesh_shape);
4350 for (int d = 0; d < dim; d++)
4351 {
4352 Vector x(e_xyz.GetData() + d*mdof_cnt, mdof_cnt);
4353 gf_xyz(d*fdof_cnt + q) = x * mesh_shape; // order by nodes
4354 }
4355 }
4356
4357 // reuse/resize dofs.
4358 vector_fes.GetElementVDofs(e, dofs);
4359 fes_node_pos.SetSubVector(dofs, gf_xyz);
4360 }
4361}
4362
4363void FiniteElementSpace::Save(std::ostream &os) const
4364{
4365 int fes_format = 90; // the original format, v0.9
4366 bool nurbs_unit_weights = false;
4367
4368 // Determine the format that should be used.
4369 if (!NURBSext)
4370 {
4371 // TODO: if this is a variable-order FE space, use fes_format = 100.
4372 }
4373 else
4374 {
4375 const NURBSFECollection *nurbs_fec =
4376 dynamic_cast<const NURBSFECollection *>(fec);
4377 MFEM_VERIFY(nurbs_fec, "invalid FE collection");
4378 nurbs_fec->SetOrder(NURBSext->GetOrder());
4379 const real_t eps = 5e-14;
4380 nurbs_unit_weights = (NURBSext->GetWeights().Min() >= 1.0-eps &&
4381 NURBSext->GetWeights().Max() <= 1.0+eps);
4383 (NURBSext != mesh->NURBSext && !nurbs_unit_weights) ||
4384 (NURBSext->GetMaster().Size() != 0 ))
4385 {
4386 fes_format = 100; // v1.0 format
4387 }
4388 }
4389
4390 os << (fes_format == 90 ?
4391 "FiniteElementSpace\n" : "MFEM FiniteElementSpace v1.0\n")
4392 << "FiniteElementCollection: " << fec->Name() << '\n'
4393 << "VDim: " << vdim << '\n'
4394 << "Ordering: " << ordering << '\n';
4395
4396 if (fes_format == 100) // v1.0
4397 {
4398 if (!NURBSext)
4399 {
4400 // TODO: this is a variable-order FE space --> write 'element_orders'.
4401 }
4402 else if (NURBSext != mesh->NURBSext)
4403 {
4405 {
4406 os << "NURBS_order\n" << NURBSext->GetOrder() << '\n';
4407 }
4408 else
4409 {
4410 os << "NURBS_orders\n";
4411 // 1 = do not write the size, just the entries:
4412 NURBSext->GetOrders().Save(os, 1);
4413 }
4414 // If periodic BCs are given, write connectivity
4415 if (NURBSext->GetMaster().Size() != 0 )
4416 {
4417 os <<"NURBS_periodic\n";
4418 NURBSext->GetMaster().Save(os);
4419 NURBSext->GetSlave().Save(os);
4420 }
4421 // If the weights are not unit, write them to the output:
4422 if (!nurbs_unit_weights)
4423 {
4424 os << "NURBS_weights\n";
4425 NURBSext->GetWeights().Print(os, 1);
4426 }
4427 }
4428 os << "End: MFEM FiniteElementSpace v1.0\n";
4429 }
4430}
4431
4432std::shared_ptr<const PRefinementTransferOperator>
4434
4435void FiniteElementSpace
4436::GetEssentialBdrEdgesFaces(const Array<int> &bdr_attr_is_ess,
4437 std::set<int> & edges, std::set<int> & faces) const
4438{
4439 const int dim = mesh->Dimension();
4440 MFEM_VERIFY(dim == 2 || dim == 3, "");
4441
4442 for (int i = 0; i < GetNBE(); i++)
4443 {
4444 if (bdr_attr_is_ess[GetBdrAttribute(i)-1])
4445 {
4446 int f, o;
4447 mesh->GetBdrElementFace(i, &f, &o);
4448
4449 if (dim == 3)
4450 {
4451 faces.insert(f);
4452 Array<int> edges_i, cor;
4453 mesh->GetBdrElementEdges(i, edges_i, cor);
4454 for (auto edge : edges_i)
4455 {
4456 edges.insert(edge);
4457 }
4458 }
4459 else
4460 {
4461 edges.insert(f);
4462 }
4463 }
4464 }
4465
4466 if (Nonconforming())
4467 {
4468 Array<int> bdr_verts, bdr_edges, bdr_faces;
4469 mesh->ncmesh->GetBoundaryClosure(bdr_attr_is_ess, bdr_verts, bdr_edges,
4470 bdr_faces);
4471
4472 for (auto e : bdr_edges)
4473 {
4474 edges.insert(e);
4475 }
4476
4477 for (auto f : bdr_faces)
4478 {
4479 faces.insert(f);
4480 }
4481 }
4482}
4483
4485{
4486 string buff;
4487 int fes_format = 0, ord;
4489
4490 Destroy();
4491
4492 input >> std::ws;
4493 getline(input, buff); // 'FiniteElementSpace'
4494 filter_dos(buff);
4495 if (buff == "FiniteElementSpace") { fes_format = 90; /* v0.9 */ }
4496 else if (buff == "MFEM FiniteElementSpace v1.0") { fes_format = 100; }
4497 else { MFEM_ABORT("input stream is not a FiniteElementSpace!"); }
4498 getline(input, buff, ' '); // 'FiniteElementCollection:'
4499 input >> std::ws;
4500 getline(input, buff);
4501 filter_dos(buff);
4502 r_fec = FiniteElementCollection::New(buff.c_str());
4503 getline(input, buff, ' '); // 'VDim:'
4504 input >> vdim;
4505 getline(input, buff, ' '); // 'Ordering:'
4506 input >> ord;
4507
4508 NURBSFECollection *nurbs_fec = dynamic_cast<NURBSFECollection*>(r_fec);
4509 if (nurbs_fec) { nurbs_fec->SetDim(m->Dimension()); }
4510 NURBSExtension *nurbs_ext = NULL;
4511 if (fes_format == 90) // original format, v0.9
4512 {
4513 if (nurbs_fec)
4514 {
4515 MFEM_VERIFY(m->NURBSext, "NURBS FE collection requires a NURBS mesh!");
4516 const int order = nurbs_fec->GetOrder();
4517 if (order != m->NURBSext->GetOrder() &&
4519 {
4520 nurbs_ext = new NURBSExtension(m->NURBSext, order);
4521 }
4522 }
4523 }
4524 else if (fes_format == 100) // v1.0
4525 {
4526 while (1)
4527 {
4528 skip_comment_lines(input, '#');
4529 MFEM_VERIFY(input.good(), "error reading FiniteElementSpace v1.0");
4530 getline(input, buff);
4531 filter_dos(buff);
4532 if (buff == "NURBS_order" || buff == "NURBS_orders")
4533 {
4534 MFEM_VERIFY(nurbs_fec,
4535 buff << ": NURBS FE collection is required!");
4536 MFEM_VERIFY(m->NURBSext, buff << ": NURBS mesh is required!");
4537 MFEM_VERIFY(!nurbs_ext, buff << ": order redefinition!");
4538 if (buff == "NURBS_order")
4539 {
4540 int order;
4541 input >> order;
4542 nurbs_ext = new NURBSExtension(m->NURBSext, order);
4543 }
4544 else
4545 {
4546 Array<int> orders;
4547 orders.Load(m->NURBSext->GetNKV(), input);
4548 nurbs_ext = new NURBSExtension(m->NURBSext, orders);
4549 }
4550 }
4551 else if (buff == "NURBS_periodic")
4552 {
4553 Array<int> master, slave;
4554 master.Load(input);
4555 slave.Load(input);
4556 nurbs_ext->ConnectBoundaries(master,slave);
4557 }
4558 else if (buff == "NURBS_weights")
4559 {
4560 MFEM_VERIFY(nurbs_ext, "NURBS_weights: NURBS_orders have to be "
4561 "specified before NURBS_weights!");
4562 nurbs_ext->GetWeights().Load(input, nurbs_ext->GetNDof());
4563 }
4564 else if (buff == "element_orders")
4565 {
4566 MFEM_VERIFY(!nurbs_fec, "section element_orders cannot be used "
4567 "with a NURBS FE collection");
4568 MFEM_ABORT("element_orders: not implemented yet!");
4569 }
4570 else if (buff == "End: MFEM FiniteElementSpace v1.0")
4571 {
4572 break;
4573 }
4574 else
4575 {
4576 MFEM_ABORT("unknown section: " << buff);
4577 }
4578 }
4579 }
4580
4581 Constructor(m, nurbs_ext, r_fec, vdim, ord);
4582
4583 return r_fec;
4584}
4585
4592
4593} // namespace mfem
T Max() const
Find the maximal element in the array, using the comparison operator < for class T.
Definition array.cpp:69
void Load(std::istream &in, int fmt=0)
Read an Array from the stream in using format fmt. The format fmt can be:
Definition array.cpp:54
const T * HostRead() const
Shortcut for mfem::Read(a.GetMemory(), a.Size(), false).
Definition array.hpp:385
void Reserve(int capacity)
Ensures that the allocated size is at least the given size.
Definition array.hpp:184
void SetSize(int nsize)
Change the logical size of the array, keep existing entries.
Definition array.hpp:840
int Size() const
Return the logical size of the array.
Definition array.hpp:166
void MakeRef(T *data_, int size_, bool own_data=false)
Make this Array a reference to a pointer.
Definition array.hpp:1053
void DeleteAll()
Delete the whole array.
Definition array.hpp:1033
int Append(const T &el)
Append element 'el' to array, resize if necessary.
Definition array.hpp:912
void Save(std::ostream &out, int fmt=0) const
Save the Array to the stream out using the format fmt. The format fmt can be:
Definition array.cpp:41
void Copy(Array &copy) const
Create a copy of the internal array to the provided copy.
Definition array.hpp:1042
T Sum() const
Return the sum of all the array entries using the '+'' operator for class 'T'.
Definition array.cpp:129
T * HostWrite()
Shortcut for mfem::Write(a.GetMemory(), a.Size(), false).
Definition array.hpp:393
Abstract base class BilinearFormIntegrator.
virtual void AssembleElementMatrix(const FiniteElement &el, ElementTransformation &Trans, DenseMatrix &elmat)
Given a particular Finite Element computes the element matrix elmat.
Operator that extracts face degrees of freedom for H1, ND, or RT FiniteElementSpaces.
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 SetSize(int s)
Change the size of the DenseMatrix to s x s.
Definition densemat.hpp:116
void UseExternalData(real_t *d, int h, int w)
Change the data array and the size of the DenseMatrix.
Definition densemat.hpp:88
void GetRow(int r, Vector &row) const
Rank 3 tensor (array of matrices)
void SetSize(int i, int j, int k, MemoryType mt_=MemoryType::PRESERVE)
int SizeJ() const
int SizeI() const
int SizeK() const
void SetFaceOrientations(const Array< int > &Fo)
Configure the transformation using face orientations for the current element.
Definition doftrans.hpp:169
void SetDofTransformation(const StatelessDofTransformation &dof_trans)
Set or change the nested StatelessDofTransformation object.
Definition doftrans.hpp:176
void InvTransformDual(real_t *v) const
Definition doftrans.cpp:107
const StatelessDofTransformation * GetDofTransformation() const
Return the nested StatelessDofTransformation object.
Definition doftrans.hpp:186
void SetVDim(int vdim=1, int ordering=0)
Set or change the vdim and ordering parameter.
Definition doftrans.hpp:190
bool IsIdentity() const
Definition doftrans.hpp:204
void TransformPrimal(real_t *v) const
Definition doftrans.cpp:17
Abstract base class that defines an interface for element restrictions.
Operator that converts FiniteElementSpace L-vectors to E-vectors.
Abstract data type element.
Definition element.hpp:29
virtual void GetVertices(Array< int > &v) const =0
Get the indices defining the vertices.
virtual int GetNVertices() const =0
A class that performs interpolation from a face E-vector to quadrature point values and/or derivative...
const IntegrationRule * IntRule
Not owned.
static bool SupportsFESpace(const FiniteElementSpace &fes)
Returns true if the given finite element space is supported by FaceQuadratureInterpolator.
Base class for operators that extracts Face degrees of freedom.
Collection of finite elements from the same family in multiple dimensions. This class is used to matc...
Definition fe_coll.hpp:27
static FiniteElementCollection * New(const char *name)
Factory method: return a newly allocated FiniteElementCollection according to the given name.
Definition fe_coll.cpp:124
const int * GetDofOrdering(Geometry::Type geom, int p, int ori) const
Variable order version of DofOrderForOrientation().
Definition fe_coll.hpp:234
int GetOrder() const
Return the order (polynomial degree) of the FE collection, corresponding to the order/degree returned...
Definition fe_coll.hpp:244
virtual int GetContType() const =0
int HasFaceDofs(Geometry::Type geom, int p) const
Definition fe_coll.cpp:100
virtual int DofForGeometry(Geometry::Type GeomType) const =0
int GetNumDof(Geometry::Type geom, int p) const
Variable order version of DofForGeometry().
Definition fe_coll.hpp:222
virtual const FiniteElement * TraceFiniteElementForGeometry(Geometry::Type GeomType) const
Definition fe_coll.hpp:97
const FiniteElement * GetTraceFE(Geometry::Type geom, int p) const
Variable order version of TraceFiniteElementForGeometry().
Definition fe_coll.hpp:210
virtual const char * Name() const
Definition fe_coll.hpp:79
const FiniteElement * GetFE(Geometry::Type geom, int p) const
Variable order version of FiniteElementForGeometry().
Definition fe_coll.hpp:199
@ DISCONTINUOUS
Field is discontinuous across element interfaces.
Definition fe_coll.hpp:48
virtual const FiniteElement * FiniteElementForGeometry(Geometry::Type GeomType) const =0
void Mult(const Vector &x, Vector &y) const override
Operator application: y=A(x).
Definition fespace.cpp:2313
DerefinementOperator(const FiniteElementSpace *f_fes, const FiniteElementSpace *c_fes, BilinearFormIntegrator *mass_integ)
TODO: Implement DofTransformation support.
Definition fespace.cpp:2212
GridFunction interpolation operator applicable after mesh refinement.
Definition fespace.hpp:497
virtual void MultTranspose(const Vector &x, Vector &y) const
Action of the transpose operator: y=A^t(x). The default behavior in class Operator is to generate an ...
Definition fespace.cpp:1987
RefinementOperator(const FiniteElementSpace *fespace, Table *old_elem_dof, Table *old_elem_fos, int old_ndofs)
Definition fespace.cpp:1799
virtual void Mult(const Vector &x, Vector &y) const
Operator application: y=A(x).
Definition fespace.cpp:1908
Class FiniteElementSpace - responsible for providing FEM view of the mesh, mainly managing the set of...
Definition fespace.hpp:208
std::unique_ptr< FiniteElementSpace > fesPrev
Definition fespace.hpp:309
void Save(std::ostream &out) const
Save finite element space to output stream out.
Definition fespace.cpp:4363
virtual void ApplyGhostElementOrdersToEdgesAndFaces(Array< VarOrderBits > &edge_orders, Array< VarOrderBits > &face_orders) const
Helper function for ParFiniteElementSpace.
Definition fespace.cpp:2996
int GetEntityVDofs(int entity, int index, Array< int > &dofs, Geometry::Type master_geom=Geometry::INVALID, int variant=0) const
Helper to get vertex, edge or face VDOFs (entity=0,1,2 resp.).
Definition fespace.cpp:1088
void GetVDofs(int vd, Array< int > &dofs, int ndofs=-1) const
Returns the indices of all of the VDofs for the specified dimension 'vd'.
Definition fespace.cpp:210
DofTransformation DoFTrans
Definition fespace.hpp:293
static int EncodeDof(int entity_base, int idx)
Helper to encode a sign flip into a DOF index (for Hcurl/Hdiv shapes).
Definition fespace.hpp:1151
const SparseMatrix * GetConformingRestriction() const
The returned SparseMatrix is owned by the FiniteElementSpace.
Definition fespace.cpp:1433
void ReorderElementToDofTable()
Reorder the scalar DOFs based on the element ordering.
Definition fespace.cpp:476
Array< char > var_face_orders
Definition fespace.hpp:261
int GetVectorDim() const
Return the total dimension of a vector in the space.
Definition fespace.cpp:1460
bool IsVariableOrder() const
Returns true if the space contains elements of varying polynomial orders.
Definition fespace.hpp:678
void SetRestriction(const SparseMatrix &r)
Definition fespace.cpp:150
void BuildNURBSFaceToDofTable() const
Generates partial face_dof table for a NURBS space.
Definition fespace.cpp:2684
void BuildDofToBdrArrays() const
Initialize internal data that enables the use of the methods GetBdrElementForDof() and GetBdrLocalDof...
Definition fespace.cpp:521
static void AddDependencies(SparseMatrix &deps, Array< int > &master_dofs, Array< int > &slave_dofs, DenseMatrix &I, int skipfirst=0)
Definition fespace.cpp:919
const Table & GetElementToDofTable() const
Return a reference to the internal Table that stores the lists of scalar dofs, for each mesh element,...
Definition fespace.hpp:1280
Array< int > dof_ldof_array
Definition fespace.hpp:280
Array< StatelessDofTransformation * > DoFTransArray
Definition fespace.hpp:292
void DofsToVDofs(Array< int > &dofs, int ndofs=-1) const
Compute the full set of vdofs corresponding to each entry in dofs.
Definition fespace.cpp:230
void GetEdgeInteriorDofs(int i, Array< int > &dofs) const
Returns the indices of the degrees of freedom for the interior of the specified edge.
Definition fespace.cpp:3805
Array< FaceQuadratureInterpolator * > E2BFQ_array
Definition fespace.hpp:338
const FiniteElement * GetBE(int i) const
Returns pointer to the FiniteElement in the FiniteElementCollection associated with i'th boundary fac...
Definition fespace.cpp:3870
Array< bool > skip_face
Definition fespace.hpp:270
Array< FaceQuadratureInterpolator * > E2IFQ_array
Definition fespace.hpp:337
friend struct DerefineMatrixOp
Definition fespace.hpp:213
Array< int > face_min_nghb_order
Definition fespace.hpp:266
DofTransformation * GetElementDofs(int elem, Array< int > &dofs) const
Returns indices of degrees of freedom of element 'elem'. The returned indices are offsets into an ldo...
Definition fespace.cpp:3502
int GetNumElementInteriorDofs(int i) const
Returns the number of degrees of freedom associated with the interior of the specified element.
Definition fespace.cpp:3775
std::shared_ptr< PRefinementTransferOperator > PTh
Definition fespace.hpp:314
virtual void GetExteriorTrueDofs(Array< int > &exterior_dofs, int component=-1) const
Get a list of all true dofs on the exterior of the mesh, exterior_dofs. For spaces with 'vdim' > 1,...
Definition fespace.cpp:716
void GetEdgeVDofs(int i, Array< int > &vdofs) const
Returns the indices of the degrees of freedom for the specified edge, including the DOFs for the vert...
Definition fespace.cpp:337
NURBSExtension * NURBSext
Definition fespace.hpp:284
virtual int GetFaceDofs(int face, Array< int > &dofs, int variant=0) const
Returns the indices of the degrees of freedom for the specified face, including the DOFs for the edge...
Definition fespace.cpp:3614
virtual void GetTrueTransferOperator(const FiniteElementSpace &coarse_fes, OperatorHandle &T) const
Construct and return an Operator that can be used to transfer true-dof data from coarse_fes,...
Definition fespace.cpp:4069
static void AdjustVDofs(Array< int > &vdofs)
Remove the orientation information encoded into an array of dofs Some basis function types have a rel...
Definition fespace.cpp:282
virtual void GetExteriorVDofs(Array< int > &exterior_vdofs, int component=-1) const
Mark degrees of freedom associated with exterior faces of the mesh. For spaces with 'vdim' > 1,...
Definition fespace.cpp:687
SparseMatrix * VariableOrderRefinementMatrix(const int coarse_ndofs, const Table &coarse_elem_dof) const
Definition fespace.cpp:1691
int GetEdgeOrder(int edge, int variant=0) const
Definition fespace.cpp:3343
Array< char > loc_var_face_orders
Definition fespace.hpp:262
bool Nonconforming() const
Definition fespace.hpp:655
void GetVertexVDofs(int i, Array< int > &vdofs) const
Returns the indices of the degrees of freedom for the specified vertices.
Definition fespace.cpp:343
void GetVertexDofs(int i, Array< int > &dofs) const
Returns the indices of the degrees of freedom for the specified vertices.
Definition fespace.cpp:3750
OperatorHandle L2E_lex
Definition fespace.hpp:320
void BuildFaceToDofTable() const
Definition fespace.cpp:441
int GetFaceOrder(int face, int variant=0) const
Returns the polynomial degree of the i'th face finite element.
Definition fespace.cpp:3359
int GetNumBorderDofs(Geometry::Type geom, int order) const
Definition fespace.cpp:1054
FiniteElementSpace()
Default constructor: the object is invalid until initialized using the method Load().
Definition fespace.cpp:31
Array< int > dof_elem_array
Definition fespace.hpp:279
int FindFaceDof(int face, int ndof) const
Similar to FindEdgeDof, but used for mixed meshes too.
Definition fespace.hpp:448
static int MinOrder(VarOrderBits bits)
Return the minimum order (least significant bit set) in the bit mask.
Definition fespace.cpp:2983
static void ListToMarker(const Array< int > &list, int marker_size, Array< int > &marker, int mark_val=-1)
Convert an array of indices (list) to a Boolean marker array where all indices in the list are marked...
Definition fespace.cpp:779
MFEM_DEPRECATED void RebuildElementToDofTable()
(
Definition fespace.cpp:467
int GetNDofs() const
Returns number of degrees of freedom. This is the number of Local Degrees of Freedom.
Definition fespace.hpp:823
bool orders_changed
True if at least one element order changed (variable-order space only).
Definition fespace.hpp:349
SparseMatrix * DerefinementMatrix(int old_ndofs, const Table *old_elem_dof, const Table *old_elem_fos)
Calculate GridFunction restriction matrix after mesh derefinement.
Definition fespace.cpp:2371
friend class PRefinementTransferOperator
Definition fespace.hpp:210
void GetLocalRefinementMatrices(Geometry::Type geom, DenseTensor &localP) const
Definition fespace.cpp:1752
void GetEdgeInteriorVDofs(int i, Array< int > &vdofs) const
Returns the indices of the degrees of freedom for the interior of the specified edge.
Definition fespace.cpp:355
void GetTransferOperator(const FiniteElementSpace &coarse_fes, OperatorHandle &T) const
Construct and return an Operator that can be used to transfer GridFunction data from coarse_fes,...
Definition fespace.cpp:4034
SparseMatrix * D2C_GlobalRestrictionMatrix(FiniteElementSpace *cfes)
Generate the global restriction matrix from a discontinuous FE space to the continuous FE space of th...
Definition fespace.cpp:809
virtual void GetEssentialTrueDofs(const Array< int > &bdr_attr_is_ess, Array< int > &ess_tdof_list, int component=-1) const
Get a list of essential true dofs, ess_tdof_list, corresponding to the boundary attributes marked in ...
Definition fespace.cpp:628
int GetNBE() const
Returns number of boundary elements in the mesh.
Definition fespace.hpp:878
virtual void UpdateMeshPointer(Mesh *new_mesh)
Definition fespace.cpp:4317
int GetDegenerateFaceDofs(int index, Array< int > &dofs, Geometry::Type master_geom, int variant) const
Definition fespace.cpp:1012
const QuadratureInterpolator * GetQuadratureInterpolator(const IntegrationRule &ir) const
Return a QuadratureInterpolator that interpolates E-vectors to quadrature point values and/or derivat...
Definition fespace.cpp:1552
Array< char > ghost_edge_orders
Definition fespace.hpp:263
int GetBdrAttribute(int i) const
Definition fespace.hpp:919
Array< int > dof_bdr_elem_array
Definition fespace.hpp:281
int GetEntityDofs(int entity, int index, Array< int > &dofs, Geometry::Type master_geom=Geometry::INVALID, int variant=0) const
Helper to get vertex, edge or face DOFs (entity=0,1,2 resp.).
Definition fespace.cpp:1063
virtual const Operator * GetRestrictionOperator() const
An abstract operator that performs the same action as GetRestrictionMatrix.
Definition fespace.hpp:715
static constexpr int MaxVarOrder
Definition fespace.hpp:257
virtual void CopyProlongationAndRestriction(const FiniteElementSpace &fes, const Array< int > *perm)
Copies the prolongation and restriction matrices from fes.
Definition fespace.cpp:80
Array< char > var_edge_orders
Definition fespace.hpp:261
std::unique_ptr< Operator > R_transpose
Operator computing the action of the transpose of the restriction.
Definition fespace.hpp:305
bool Conforming() const
Definition fespace.hpp:650
int MakeDofTable(int ent_dim, const Array< VarOrderBits > &entity_orders, Table &entity_dofs, Array< char > *var_ent_order)
Definition fespace.cpp:3253
void UpdateElementOrders()
Resize the elem_order array on mesh change.
Definition fespace.cpp:4110
void MakeVDimMatrix(SparseMatrix &mat) const
Replicate 'mat' in the vector dimension, according to vdim ordering mode.
Definition fespace.cpp:1398
int GetNF() const
Returns number of faces (i.e. co-dimension 1 entities) in the mesh.
Definition fespace.hpp:875
SparseMatrix * H2L_GlobalRestrictionMatrix(FiniteElementSpace *lfes)
Construct the restriction matrix from the FE space given by (*this) to the lower degree FE space give...
Definition fespace.cpp:872
SparseMatrix * D2Const_GlobalRestrictionMatrix(FiniteElementSpace *cfes)
Generate the global restriction matrix from a discontinuous FE space to the piecewise constant FE spa...
Definition fespace.cpp:841
const FiniteElementCollection * fec
Associated FE collection (not owned).
Definition fespace.hpp:220
void GetNodePositions(const Vector &mesh_nodes, Vector &fes_node_pos, int fes_nodes_ordering=Ordering::byNODES) const
Compute the space's node positions w.r.t. given mesh positions. The function uses FiniteElement::GetN...
Definition fespace.cpp:4322
FiniteElementCollection * Load(Mesh *m, std::istream &input)
Read a FiniteElementSpace from a stream. The returned FiniteElementCollection is owned by the caller.
Definition fespace.cpp:4484
void BuildBdrElementToDofTable() const
Definition fespace.cpp:402
DofTransformation * GetElementVDofs(int i, Array< int > &vdofs) const
Returns indices of degrees of freedom for the i'th element. The returned indices are offsets into an ...
Definition fespace.cpp:304
Array< QuadratureInterpolator * > E2Q_array
Definition fespace.hpp:336
virtual const FiniteElement * GetFE(int i) const
Returns pointer to the FiniteElement in the FiniteElementCollection associated with i'th element in t...
Definition fespace.cpp:3824
Ordering::Type GetOrdering() const
Return the ordering method.
Definition fespace.hpp:854
NURBSExtension * StealNURBSext()
Definition fespace.cpp:2598
void GetPatchDofs(int patch, Array< int > &dofs) const
Returns indices of degrees of freedom for NURBS patch index patch. Cartesian ordering is used,...
Definition fespace.cpp:3817
void BuildDofToArrays_() const
Initialize internal data that enables the use of the methods GetElementForDof() and GetLocalDofForDof...
Definition fespace.cpp:496
const Operator * GetRestrictionTransposeOperator() const
Return an operator that performs the transpose of GetRestrictionOperator.
Definition fespace.cpp:1448
Array< char > elem_order
Definition fespace.hpp:237
static bool DofFinalizable(int dof, const Array< bool > &finalized, const SparseMatrix &deps)
Definition fespace.cpp:998
Array< int > face_to_be
Definition fespace.hpp:290
void GetLocalDerefinementMatrices(Geometry::Type geom, DenseTensor &localR) const
Definition fespace.cpp:2347
void BuildConformingInterpolation() const
Calculate the cP and cR matrices for a nonconforming mesh.
Definition fespace.cpp:1148
int GetNE() const
Returns number of elements in the mesh.
Definition fespace.hpp:869
int vdim
Vector dimension (number of unknowns per degree of freedom).
Definition fespace.hpp:223
Table var_face_dofs
NOTE: also used for spaces with mixed faces.
Definition fespace.hpp:246
OperatorHandle L2E_nat
The element restriction operators, see GetElementRestriction().
Definition fespace.hpp:320
bool lastUpdatePRef
Flag to indicate whether the last update was for p-refinement.
Definition fespace.hpp:317
int * bdofs
internal DOFs of elements if mixed/var-order; NULL otherwise
Definition fespace.hpp:241
const ElementRestrictionOperator * GetElementRestriction(ElementDofOrdering e_ordering) const
Return an Operator that converts L-vectors to E-vectors.
Definition fespace.cpp:1480
const FiniteElement * GetEdgeElement(int i, int variant=0) const
Returns pointer to the FiniteElement in the FiniteElementCollection associated with i'th edge in the ...
Definition fespace.cpp:3933
Array< bool > skip_edge
Definition fespace.hpp:270
Array< char > ghost_face_orders
Definition fespace.hpp:263
int GetEdgeDofs(int edge, Array< int > &dofs, int variant=0) const
Returns the indices of the degrees of freedom for the specified edge, including the DOFs for the vert...
Definition fespace.cpp:3702
std::tuple< bool, ElementDofOrdering, FaceType, L2FaceValues > key_face
The face restriction operators, see GetFaceRestriction().
Definition fespace.hpp:322
std::unique_ptr< SparseMatrix > cR
Conforming restriction matrix such that cR.cP=I.
Definition fespace.hpp:300
void GetElementInteriorVDofs(int i, Array< int > &vdofs) const
Returns the indices of the degrees of freedom for the interior of the specified element.
Definition fespace.cpp:349
void GetFaceVDofs(int i, Array< int > &vdofs) const
Returns the indices of the degrees of freedom for the specified face, including the DOFs for the edge...
Definition fespace.cpp:331
Array< char > loc_var_edge_orders
Definition fespace.hpp:262
virtual void Update(bool want_transform=true)
Reflect changes in the mesh: update number of DOFs, etc. Also, calculate GridFunction transformation ...
Definition fespace.cpp:4146
OperatorHandle Th
Transformation to apply to GridFunctions after space Update().
Definition fespace.hpp:312
SparseMatrix * RefinementMatrix(int old_ndofs, const Table *old_elem_dof, const Table *old_elem_fos)
Definition fespace.cpp:1775
std::uint64_t VarOrderBits
Bit-mask representing a set of orders needed by an edge/face.
Definition fespace.hpp:256
SparseMatrix * RefinementMatrix_main(const int coarse_ndofs, const Table &coarse_elem_dof, const Table *coarse_elem_fos, const DenseTensor localP[]) const
Definition fespace.cpp:1627
int ndofs
Number of degrees of freedom. Number of unknowns is ndofs * vdim.
Definition fespace.hpp:231
std::unique_ptr< SparseMatrix > cP
Definition fespace.hpp:298
void AddEdgeFaceDependencies(SparseMatrix &deps, Array< int > &master_dofs, const FiniteElement *master_fe, Array< int > &slave_dofs, int slave_face, const DenseMatrix *pm) const
Definition fespace.cpp:944
const FiniteElement * GetTraceElement(int i, Geometry::Type geom_type) const
Return the trace element from element 'i' to the given 'geom_type'.
Definition fespace.cpp:3942
const FiniteElement * GetTypicalTraceElement() const
Return a "typical" trace element.
Definition fespace.cpp:3948
static void MarkerToList(const Array< int > &marker, Array< int > &list)
Convert a Boolean marker array to a list containing all marked indices.
Definition fespace.cpp:760
Array< NURBSExtension * > VNURBSext
Definition fespace.hpp:288
int GetElementOrder(int i) const
Returns the order of the i'th finite element.
Definition fespace.cpp:193
void SetVarOrderLocalDofs()
Sets all2local. See documentation of all2local for details.
Definition fespace.cpp:2932
Mesh * mesh
The mesh that FE space lives on (not owned).
Definition fespace.hpp:217
const FiniteElement * GetFaceElement(int i) const
Returns pointer to the FiniteElement in the FiniteElementCollection associated with i'th face in the ...
Definition fespace.cpp:3903
Ordering::Type ordering
Definition fespace.hpp:228
void ConvertToConformingVDofs(const Array< int > &dofs, Array< int > &cdofs)
For a partially conforming FE space, convert a marker array (nonzero entries are true) on the partial...
Definition fespace.cpp:792
void CalcEdgeFaceVarOrders(Array< VarOrderBits > &edge_orders, Array< VarOrderBits > &face_orders, Array< VarOrderBits > &edge_elem_orders, Array< VarOrderBits > &face_elem_orders, Array< bool > &skip_edges, Array< bool > &skip_faces) const
Definition fespace.cpp:3007
virtual bool OrderPropagation(const std::set< int > &edges, const std::set< int > &faces, Array< VarOrderBits > &edge_orders, Array< VarOrderBits > &face_orders) const
Returns true if order propagation is done, for variable-order spaces.
Definition fespace.hpp:422
std::shared_ptr< const PRefinementTransferOperator > GetPrefUpdateOperator()
Definition fespace.cpp:4433
void SetElementOrder(int i, int p)
Sets the order of the i'th finite element.
Definition fespace.cpp:168
const SparseMatrix * GetHpConformingRestriction() const
The returned SparseMatrix is owned by the FiniteElementSpace.
Definition fespace.cpp:1441
const SparseMatrix * GetConformingProlongation() const
Definition fespace.cpp:1426
const FiniteElementCollection * FEColl() const
Definition fespace.hpp:856
Mesh * GetMesh() const
Returns the mesh.
Definition fespace.hpp:644
int GetElementOrderImpl(int i) const
Return element order: internal version of GetElementOrder without checks.
Definition fespace.cpp:204
int GetNVariants(int entity, int index) const
Return number of possible DOF variants for edge/face (var. order spaces).
Definition fespace.cpp:3380
Array< int > dof_bdr_ldof_array
Definition fespace.hpp:282
int GetVSize() const
Return the number of vector dofs, i.e. GetNDofs() x GetVDim().
Definition fespace.hpp:826
const Table * GetElementToFaceOrientationTable() const
Definition fespace.hpp:1276
DofTransformation * GetBdrElementDofs(int bel, Array< int > &dofs) const
Returns indices of degrees of freedom for boundary element 'bel'. The returned indices are offsets in...
Definition fespace.cpp:3607
void GetBoundaryTrueDofs(Array< int > &boundary_dofs, int component=-1)
Get a list of all boundary true dofs, boundary_dofs. For spaces with 'vdim' > 1, the 'component' para...
Definition fespace.cpp:672
int GetVDim() const
Returns the vector dimension of the finite element space.
Definition fespace.hpp:819
const FaceQuadratureInterpolator * GetFaceQuadratureInterpolator(const IntegrationRule &ir, FaceType type) const
Return a FaceQuadratureInterpolator that interpolates E-vectors to quadrature point values and/or der...
Definition fespace.cpp:1591
bool IsDGSpace() const
Return whether or not the space is discontinuous (L2)
Definition fespace.hpp:1503
void GetFaceInteriorDofs(int i, Array< int > &dofs) const
Returns the indices of the degrees of freedom for the interior of the specified face.
Definition fespace.cpp:3781
virtual void PRefineAndUpdate(const Array< pRefinement > &refs, bool want_transfer=true)
Definition fespace.cpp:4269
int GetNConformingDofs() const
Definition fespace.cpp:1454
void SetProlongation(const SparseMatrix &p)
Definition fespace.cpp:131
Array< int > edge_min_nghb_order
Minimum order among neighboring elements.
Definition fespace.hpp:266
const FiniteElement * GetTypicalFE() const
Return GetFE(0) if the local mesh is not empty; otherwise return a typical FE based on the Geometry t...
Definition fespace.cpp:3860
static int DecodeDof(int dof)
Helper to return the DOF associated with a sign encoded DOF.
Definition fespace.hpp:1155
void GetElementInteriorDofs(int i, Array< int > &dofs) const
Returns the indices of the degrees of freedom for the interior of the specified element.
Definition fespace.cpp:3760
virtual int NumGhostEdges() const
Returns the number of ghost edges (nonzero in ParFiniteElementSpace).
Definition fespace.hpp:429
void Constructor(Mesh *mesh, NURBSExtension *ext, const FiniteElementCollection *fec, int vdim=1, int ordering=Ordering::byNODES)
Help function for constructors + Load().
Definition fespace.cpp:2497
DofTransformation * GetBdrElementVDofs(int i, Array< int > &vdofs) const
Returns indices of degrees of freedom for i'th boundary element. The returned indices are offsets int...
Definition fespace.cpp:319
void ConvertFromConformingVDofs(const Array< int > &cdofs, Array< int > &dofs)
For a partially conforming FE space, convert a marker array (nonzero entries are true) on the conform...
Definition fespace.cpp:800
virtual void GetEssentialVDofs(const Array< int > &bdr_attr_is_ess, Array< int > &ess_vdofs, int component=-1) const
Mark degrees of freedom associated with boundary elements with the specified boundary attributes (mar...
Definition fespace.cpp:554
virtual int NumGhostFaces() const
Returns the number of ghost faces (nonzero in ParFiniteElementSpace).
Definition fespace.hpp:432
int DofToVDof(int dof, int vd, int ndofs=-1) const
Compute a single vdof corresponding to the index dof and the vector index vd.
Definition fespace.cpp:266
virtual const FaceRestriction * GetFaceRestriction(ElementDofOrdering f_ordering, FaceType, L2FaceValues mul=L2FaceValues::DoubleValued) const
Return an Operator that converts L-vectors to E-vectors on each face.
Definition fespace.cpp:1513
int GetCurlDim() const
Return the dimension of the curl of a GridFunction defined on this space.
Definition fespace.cpp:1470
virtual void GhostFaceOrderToEdges(const Array< VarOrderBits > &face_orders, Array< VarOrderBits > &edge_orders) const
Helper function for ParFiniteElementSpace.
Definition fespace.hpp:417
int FindEdgeDof(int edge, int ndof) const
Definition fespace.hpp:444
void GetPatchVDofs(int i, Array< int > &vdofs) const
Returns indices of degrees of freedom in vdofs for NURBS patch i.
Definition fespace.cpp:325
void BuildElementToDofTable() const
Definition fespace.cpp:361
std::unique_ptr< SparseMatrix > cR_hp
A version of the conforming restriction matrix for variable-order spaces.
Definition fespace.hpp:302
int FindDofs(const Table &var_dof_table, int row, int ndof) const
Search row of a DOF table for a DOF set of size 'ndof', return first DOF.
Definition fespace.cpp:3326
void VariableOrderMinimumRule(SparseMatrix &deps) const
Definition fespace.cpp:1098
Abstract class for all finite elements.
Definition fe_base.hpp:247
int GetRangeDim() const
Returns the vector dimension for vector-valued finite elements, which is also the dimension of the in...
Definition fe_base.hpp:328
int GetOrder() const
Returns the order of the finite element. In the case of anisotropic orders, returns the maximum order...
Definition fe_base.hpp:341
int GetDim() const
Returns the reference space dimension for the finite element.
Definition fe_base.hpp:324
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 GetRangeType() const
Returns the FiniteElement::RangeType of the element, one of {SCALAR, VECTOR}.
Definition fe_base.hpp:354
virtual void GetLocalRestriction(ElementTransformation &Trans, DenseMatrix &R) const
Return a local restriction matrix R (Dof x Dof) mapping fine dofs to coarse dofs.
Definition fe_base.cpp:123
const IntegrationRule & GetNodes() const
Get a const reference to the nodes of the element.
Definition fe_base.hpp:403
Geometry::Type GetGeomType() const
Returns the Geometry::Type of the reference element.
Definition fe_base.hpp:334
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
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
int GetCurlDim() const
Returns the dimension of the curl for vector-valued finite elements.
Definition fe_base.hpp:331
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...
int GetDof() const
Returns the number of degrees of freedom in the finite element.
Definition fe_base.hpp:337
static const int NumGeom
Definition geom.hpp:46
static const int NumVerts[NumGeom]
Definition geom.hpp:53
Arbitrary order H1-conforming (continuous) finite elements.
Definition fe_coll.hpp:279
Class for an integration rule - an Array of IntegrationPoint.
Definition intrules.hpp:100
int GetNPoints() const
Returns the number of the points in the integration rule.
Definition intrules.hpp:256
A standard isoparametric element transformation.
Definition eltrans.hpp:629
void SetPointMat(const DenseMatrix &pm)
Set the underlying point matrix describing the transformation.
Definition eltrans.hpp:668
void SetFE(const FiniteElement *FE)
Set the element that will be used to compute the transformations.
Definition eltrans.hpp:648
void SetIdentityTransformation(Geometry::Type GeomType)
Set the FiniteElement Geometry for the reference elements being used.
Definition eltrans.cpp:417
const DenseMatrix & GetPointMat() const
Return the stored point matrix.
Definition eltrans.hpp:671
Operator that converts L2 FiniteElementSpace L-vectors to E-vectors.
Operator that extracts Face degrees of freedom for L2 spaces.
Operator that extracts face degrees of freedom for L2 interface spaces.
Arbitrary order "L2-conforming" discontinuous finite elements.
Definition fe_coll.hpp:350
Class used by MFEM to store pointers to host and/or device memory.
List of mesh geometries stored as Array<Geometry::Type>.
Definition mesh.hpp:1590
Mesh data type.
Definition mesh.hpp:65
void GetFaceEdges(int i, Array< int > &edges, Array< int > &o) const
Definition mesh.cpp:7642
void GetGeometries(int dim, Array< Geometry::Type > &el_geoms) const
Return all element geometries of the given dimension present in the mesh.
Definition mesh.cpp:7569
Operation GetLastOperation() const
Return type of last modification of the mesh.
Definition mesh.hpp:2513
int GetNEdges() const
Return the number of edges.
Definition mesh.hpp:1383
void GetBdrElementFace(int i, int *f, int *o) const
Definition mesh.cpp:7886
Array< int > bdr_attributes
A list of all unique boundary attributes used by the Mesh.
Definition mesh.hpp:304
NURBSExtension * NURBSext
Optional NURBS mesh extension.
Definition mesh.hpp:312
virtual void GetExteriorFaceMarker(Array< int > &face_marker) const
Populate a marker array identifying exterior faces.
Definition mesh.cpp:1656
int GetNumFaces() const
Return the number of faces (3D), edges (2D) or vertices (1D).
Definition mesh.cpp:6846
void GetBdrElementVertices(int i, Array< int > &v) const
Returns the indices of the vertices of boundary element i.
Definition mesh.hpp:1613
Geometry::Type GetFaceGeometry(int i) const
Return the Geometry::Type associated with face i.
Definition mesh.cpp:1576
Geometry::Type GetElementGeometry(int i) const
Definition mesh.hpp:1535
Geometry::Type GetBdrElementGeometry(int i) const
Definition mesh.hpp:1547
void GetElementVertices(int i, Array< int > &v) const
Returns the indices of the vertices of element i.
Definition mesh.hpp:1609
const FiniteElementSpace * GetNodalFESpace() const
Definition mesh.cpp:6794
Geometry::Type GetTypicalElementGeometry() const
If the local mesh is not empty, return GetElementGeometry(0); otherwise, return a typical Geometry pr...
Definition mesh.cpp:1628
int GetBdrElementFaceIndex(int be_idx) const
Return the local face (codimension-1) index for the given boundary element index.
Definition mesh.hpp:1689
int GetNFaces() const
Return the number of faces in a 3D mesh.
Definition mesh.hpp:1386
long GetSequence() const
Definition mesh.hpp:2519
const CoarseFineTransformations & GetRefinementTransforms() const
Definition mesh.cpp:11749
int GetNE() const
Returns number of elements.
Definition mesh.hpp:1377
const Element * GetFace(int i) const
Return pointer to the i'th face element object.
Definition mesh.hpp:1461
int Dimension() const
Dimension of the reference space used within the elements.
Definition mesh.hpp:1306
const Element * GetBdrElement(int i) const
Return pointer to the i'th boundary element object.
Definition mesh.hpp:1449
void GetBdrElementEdges(int i, Array< int > &edges, Array< int > &cor) const
Return the indices and the orientations of all edges of bdr element i.
Definition mesh.cpp:7610
void GetElementFaces(int i, Array< int > &faces, Array< int > &ori) const
Return the indices and the orientations of all faces of element i.
Definition mesh.cpp:7835
int SpaceDimension() const
Dimension of the physical space containing the mesh.
Definition mesh.hpp:1309
int GetNV() const
Returns number of vertices. Vertices are only at the corners of elements, where you would expect them...
Definition mesh.hpp:1374
void GetEdgeVertices(int i, Array< int > &vert) const
Returns the indices of the vertices of edge i.
Definition mesh.cpp:7672
void GetBdrElementAdjacentElement(int bdr_el, int &el, int &info) const
For the given boundary element, bdr_el, return its adjacent element and its info, i....
Definition mesh.cpp:7905
void GetFaceVertices(int i, Array< int > &vert) const
Returns the indices of the vertices of face i.
Definition mesh.hpp:1627
int GetNBE() const
Returns number of boundary elements.
Definition mesh.hpp:1380
NCMesh * ncmesh
Optional nonconforming mesh extension.
Definition mesh.hpp:313
void GetElementEdges(int i, Array< int > &edges, Array< int > &cor) const
Return the indices and the orientations of all edges of element i.
Definition mesh.cpp:7588
int GetNumGeometries(int dim) const
Return the number of geometries of the given dimension present in the mesh.
Definition mesh.cpp:7558
Geometry::Type GetTypicalFaceGeometry() const
If the local mesh is not empty, return GetFaceGeometry(0); otherwise return a typical face geometry p...
Definition mesh.cpp:1596
Geometry::Type GetElementBaseGeometry(int i) const
Definition mesh.hpp:1556
Operator that extracts face degrees of freedom for L2 nonconforming spaces.
const NCList & GetNCList(int entity)
Return vertex/edge/face list (entity = 0/1/2, respectively).
Definition ncmesh.hpp:391
const CoarseFineTransformations & GetDerefinementTransforms() const
Definition ncmesh.cpp:5255
const NCList & GetFaceList()
Return the current list of conforming and nonconforming faces.
Definition ncmesh.hpp:369
Geometry::Type GetFaceGeometry(int index) const
Return face geometry type. index is the Mesh face number.
Definition ncmesh.hpp:506
virtual void GetBoundaryClosure(const Array< int > &bdr_attr_is_ess, Array< int > &bdr_vertices, Array< int > &bdr_edges, Array< int > &bdr_faces)
Get a list of vertices (2D/3D), edges (3D) and faces (3D) that coincide with boundary elements with t...
Definition ncmesh.cpp:5827
const NCList & GetEdgeList()
Return the current list of conforming and nonconforming edges.
Definition ncmesh.hpp:376
int GetNFaces() const
Return the number of (2D) faces in the NCMesh.
Definition ncmesh.hpp:223
int GetNEdges() const
Return the number of edges in the NCMesh.
Definition ncmesh.hpp:221
Arbitrary order H(curl)-conforming Nedelec finite elements.
Definition fe_coll.hpp:500
DoF transformation implementation for the Nedelec basis on pyramid elements.
Definition doftrans.hpp:375
DoF transformation implementation for the Nedelec basis on tetrahedra.
Definition doftrans.hpp:352
DoF transformation implementation for the Nedelec basis on wedge elements.
Definition doftrans.hpp:363
NURBSExtension generally contains multiple NURBSPatch objects spanning an entire Mesh....
Definition nurbs.hpp:474
const Vector & GetWeights() const
Access function to the vector of weights weights.
Definition nurbs.hpp:927
const Array< int > & GetSlave() const
Definition nurbs.hpp:789
int GetNKV() const
Return the number of KnotVectors.
Definition nurbs.hpp:837
void LoadBE(int i, const FiniteElement *BE) const
Load boundary element i into BE.
Definition nurbs.cpp:4564
Table * GetElementDofTable()
Definition nurbs.hpp:887
const Array< int > & GetMaster() const
Definition nurbs.hpp:787
void LoadFE(int i, const FiniteElement *FE) const
Load element i into FE.
Definition nurbs.cpp:4543
void GetPatchDofs(const int patch, Array< int > &dofs)
Return the degrees of freedom in dofs on patch patch, in Cartesian order.
Definition nurbs.cpp:4266
Table * GetBdrElementDofTable()
Definition nurbs.hpp:891
int GetNDof() const
Return the number of active DOFs.
Definition nurbs.hpp:855
int GetOrder() const
If all KnotVector orders are identical, return that number. Otherwise, return NURBSFECollection::Vari...
Definition nurbs.hpp:834
NURBSExtension * GetCurlExtension(int component)
Definition nurbs.cpp:4753
const Array< int > & GetOrders() const
Read-only access to the orders of all KnotVectors.
Definition nurbs.hpp:830
NURBSExtension * GetDivExtension(int component)
Definition nurbs.cpp:4738
void ConnectBoundaries()
Set DOF maps for periodic BC.
Definition nurbs.cpp:2907
Arbitrary order non-uniform rational B-splines (NURBS) finite elements.
Definition fe_coll.hpp:717
int GetOrder() const
Get the order of the NURBS collection: either a positive number, when using fixed order,...
Definition fe_coll.hpp:751
virtual void SetOrder(int Order) const
Set the order and the name, based on the given Order: either a positive number for fixed order,...
Definition fe_coll.cpp:3534
virtual void SetDim(const int dim)
Definition fe_coll.hpp:746
Arbitrary order H(curl) NURBS finite elements.
Definition fe_coll.hpp:828
Arbitrary order H(div) NURBS finite elements.
Definition fe_coll.hpp:776
Pointer to an Operator of a specified type.
Definition handle.hpp:34
OpType * As() const
Return the Operator pointer statically cast to a specified OpType. Similar to the method Get().
Definition handle.hpp:104
bool OwnsOperator() const
Return true if the OperatorHandle owns the held Operator.
Definition handle.hpp:117
void SetOperatorOwner(bool own=true)
Set the ownership flag for the held Operator.
Definition handle.hpp:120
void SetType(Operator::Type tid)
Invoke Clear() and set a new type id.
Definition handle.hpp:132
Operator * Ptr() const
Access the underlying Operator pointer.
Definition handle.hpp:87
void Clear()
Clear the OperatorHandle, deleting the held Operator (if owned), while leaving the type id unchanged.
Definition handle.hpp:124
void Reset(OpType *A, bool own_A=true)
Reset the OperatorHandle to the given OpType pointer, A.
Definition handle.hpp:145
OpType * Is() const
Return the Operator pointer dynamically cast to a specified OpType.
Definition handle.hpp:108
Operator::Type Type() const
Get the currently set operator type id.
Definition handle.hpp:99
Abstract operator.
Definition operator.hpp:25
int width
Dimension of the input / number of columns in the matrix.
Definition operator.hpp:28
int Height() const
Get the height (size of output) of the Operator. Synonym with NumRows().
Definition operator.hpp:66
int height
Dimension of the output / number of rows in the matrix.
Definition operator.hpp:27
int Width() const
Get the width (size of input) of the Operator. Synonym with NumCols().
Definition operator.hpp:72
Type
Enumeration defining IDs for some classes derived from Operator.
Definition operator.hpp:296
@ ANY_TYPE
ID for the base class Operator, i.e. any type.
Definition operator.hpp:297
@ MFEM_SPARSEMAT
ID for class SparseMatrix.
Definition operator.hpp:298
The ordering method used when the number of unknowns per mesh node (vector dimension) is bigger than ...
Definition ordering.hpp:13
Type
Ordering methods:
Definition ordering.hpp:17
A pair of objects.
Abstract parallel finite element space.
Definition pfespace.hpp:31
Parallel version of NURBSExtension.
Definition nurbs.hpp:1036
General product operator: x -> (A*B)(x) = A(B(x)).
Definition operator.hpp:906
A class that performs interpolation from an E-vector to quadrature point values and/or derivatives (Q...
static bool SupportsFESpace(const FiniteElementSpace &fespace)
Returns true if the given finite element space is supported by QuadratureInterpolator.
const IntegrationRule * IntRule
Not owned.
const QuadratureSpace * qspace
Not owned.
Class representing the storage layout of a QuadratureFunction.
Definition qspace.hpp:164
Data type sparse matrix.
Definition sparsemat.hpp:51
int GetRow(const int row, Array< int > &cols, Vector &srow) const override
Extract all column indices and values from a given row.
void Add(const int i, const int j, const real_t val)
void Swap(SparseMatrix &other)
void BooleanMultTranspose(const Array< int > &x, Array< int > &y) const
y = At * x, treating all entries as booleans (zero=false, nonzero=true).
void BooleanMult(const Array< int > &x, Array< int > &y) const
y = A * x, treating all entries as booleans (zero=false, nonzero=true).
int * GetRowColumns(const int row)
Return a pointer to the column indices in a row.
int RowSize(const int i) const
Returns the number of elements in row i.
real_t * GetRowEntries(const int row)
Return a pointer to the entries in a row.
void SetRow(const int row, const Array< int > &cols, const Vector &srow)
void Finalize(int skip_zeros=1) override
Finalize the matrix initialization, switching the storage format from LIL to CSR.
void Set(const int i, const int j, const real_t val)
Table stores the connectivity of elements of TYPE I to elements of TYPE II. For example,...
Definition table.hpp:43
int * GetJ()
Definition table.hpp:128
void AddConnections(int r, const int *c, int nc)
Definition table.cpp:152
int RowSize(int i) const
Definition table.hpp:122
void ShiftUpI()
Definition table.cpp:163
void Clear()
Definition table.cpp:420
void GetRow(int i, Array< int > &row) const
Return row i in array row (the Table must be finalized)
Definition table.cpp:233
void AddConnection(int r, int c)
Definition table.hpp:89
void MakeI(int nrows)
Definition table.cpp:130
int Size() const
Returns the number of TYPE I elements.
Definition table.hpp:103
int Size_of_connections() const
Returns the number of connections in the table.
Definition table.hpp:110
void AddColumnsInRow(int r, int ncol)
Definition table.hpp:87
void MakeFromList(int nrows, const Array< Connection > &list)
Create the table from a list of connections {(from, to)}, where 'from' is a TYPE I index and 'to' is ...
Definition table.cpp:322
void MakeJ()
Definition table.cpp:140
int * GetI()
Definition table.hpp:127
void AddAColumnInRow(int r)
Definition table.hpp:86
The transpose of a given operator. Switches the roles of the methods Mult() and MultTranspose().
Definition operator.hpp:859
General triple product operator x -> A*B*C*x, with ownership of the factors.
Definition operator.hpp:982
Vector data type.
Definition vector.hpp:82
void Print(std::ostream &out=mfem::out, int width=8) const
Prints vector to stream out.
Definition vector.cpp:870
void SetSubVector(const Array< int > &dofs, const real_t value)
Set the entries listed in dofs to the given value.
Definition vector.cpp:702
void AddElementVector(const Array< int > &dofs, const Vector &elemvect)
Add elements of the elemvect Vector to the entries listed in dofs. Negative dof values cause the -dof...
Definition vector.cpp:785
void Load(std::istream **in, int np, int *dim)
Reads a vector from multiple files.
Definition vector.cpp:127
real_t Max() const
Returns the maximal element of the vector.
Definition vector.cpp:1200
void SetSize(int s)
Resize the vector to size s.
Definition vector.hpp:584
real_t * GetData() const
Return a pointer to the beginning of the Vector data.
Definition vector.hpp:243
real_t Min() const
Returns the minimal element of the vector.
Definition vector.cpp:1154
void GetSubVector(const Array< int > &dofs, Vector &elemvect) const
Extract entries listed in dofs to the output Vector elemvect.
Definition vector.cpp:676
Vector & Add(const real_t a, const Vector &Va)
(*this) += a * Va
Definition vector.cpp:326
int dim
Definition ex24.cpp:53
int index(int i, int j, int nx, int ny)
Definition life.cpp:236
real_t b
Definition lissajous.cpp:42
real_t a
Definition lissajous.cpp:41
void RemoveBasisAndRestriction(const mfem::FiniteElementSpace *fes)
Remove from ceed_basis_map and ceed_restr_map the entries associated with the given fes.
Definition util.cpp:41
Linear1DFiniteElement SegmentFE
Definition segment.cpp:52
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
void DofMapHelper(int entity, const Table &var_ent_dofs, const Table &loc_var_ent_dofs, const Array< char > &var_ent_orders, const Array< char > &loc_var_ent_orders, Array< int > &all2local, int &ndof_all, int &ndof_loc)
Definition fespace.cpp:2883
void Transpose(const Table &A, Table &At, int ncols_A_)
Transpose a Table.
Definition table.cpp:443
void Swap(T &a, T &b)
Swap objects of type T. The operation is performed using the most specialized swap function from the ...
Definition array.hpp:738
void filter_dos(std::string &line)
Check for, and remove, a trailing '\r' from and std::string.
Definition text.hpp:45
bool UsesTensorBasis(const FiniteElementSpace &fes)
Return true if the mesh contains only one topology and the elements are tensor elements.
Definition fespace.hpp:1548
BiLinear2DFiniteElement QuadrilateralFE
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
void AddMult(const DenseMatrix &b, const DenseMatrix &c, DenseMatrix &a)
Matrix matrix multiplication. A += B * C.
ElementDofOrdering GetEVectorOrdering(const FiniteElementSpace &fes)
Return LEXICOGRAPHIC if mesh contains only one topology and the elements are tensor elements,...
Definition fespace.cpp:4586
void MarkDofs(const Array< int > &dofs, Array< int > &mark_array)
Definition fespace.cpp:546
ElementDofOrdering
Constants describing the possible orderings of the DOFs in one element.
Definition fespace.hpp:47
@ NATIVE
Native ordering as defined by the FiniteElement.
std::function< real_t(const Vector &)> f(real_t mass_coeff)
Definition lor_mms.hpp:30
MFEM_EXPORT Linear2DFiniteElement TriangleFE
Definition fe.cpp:32
void skip_comment_lines(std::istream &is, const char comment_char)
Check if the stream starts with comment_char. If so skip it.
Definition text.hpp:31
FaceType
Definition mesh.hpp:49
real_t p(const Vector &x, real_t t)
bool operator<(const Data &d1, const Data &d2)
Definition nurbs_ex1.cpp:54
Defines the coarse-fine transformations of all fine elements.
Definition ncmesh.hpp:90
Array< Embedding > embeddings
Fine element positions in their parents.
Definition ncmesh.hpp:92
void MakeCoarseToFineTable(Table &coarse_to_fine, bool want_ghosts=false) const
Definition ncmesh.cpp:5313
DenseTensor point_matrices[Geometry::NumGeom]
Definition ncmesh.hpp:96
Helper struct for defining a connectivity table, see Table::MakeFromList.
Definition table.hpp:28
Defines the position of a fine element within a coarse element.
Definition ncmesh.hpp:69
int parent
Coarse Element index in the coarse mesh.
Definition ncmesh.hpp:71
unsigned matrix
Definition ncmesh.hpp:78
int index
Mesh number.
Definition ncmesh.hpp:261
Geometry::Type Geom() const
Definition ncmesh.hpp:266
Lists all edges/faces in the nonconforming mesh.
Definition ncmesh.hpp:301
Array< Slave > slaves
All MeshIds corresponding to slave faces.
Definition ncmesh.hpp:304
Array< Master > masters
All MeshIds corresponding to master faces.
Definition ncmesh.hpp:303
Nonconforming edge/face within a bigger edge/face.
Definition ncmesh.hpp:287
unsigned matrix
index into NCList::point_matrices[geom]
Definition ncmesh.hpp:289