MFEM  v4.5.1
Finite element discretization library
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Pages
fespace.cpp
Go to the documentation of this file.
1 // Copyright (c) 2010-2022, 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"
16 #include "../mesh/mesh_headers.hpp"
17 #include "fem.hpp"
18 #include "ceed/interface/util.hpp"
19 
20 #include <cmath>
21 #include <cstdarg>
22 
23 using namespace std;
24 
25 namespace mfem
26 {
27 
28 template <> void Ordering::
29 DofsToVDofs<Ordering::byNODES>(int ndofs, int vdim, Array<int> &dofs)
30 {
31  // static method
32  int size = dofs.Size();
33  dofs.SetSize(size*vdim);
34  for (int vd = 1; vd < vdim; vd++)
35  {
36  for (int i = 0; i < size; i++)
37  {
38  dofs[i+size*vd] = Map<byNODES>(ndofs, vdim, dofs[i], vd);
39  }
40  }
41 }
42 
43 template <> void Ordering::
44 DofsToVDofs<Ordering::byVDIM>(int ndofs, int vdim, Array<int> &dofs)
45 {
46  // static method
47  int size = dofs.Size();
48  dofs.SetSize(size*vdim);
49  for (int vd = vdim-1; vd >= 0; vd--)
50  {
51  for (int i = 0; i < size; i++)
52  {
53  dofs[i+size*vd] = Map<byVDIM>(ndofs, vdim, dofs[i], vd);
54  }
55  }
56 }
57 
58 
59 FiniteElementSpace::FiniteElementSpace()
60  : mesh(NULL), fec(NULL), vdim(0), ordering(Ordering::byNODES),
61  ndofs(0), nvdofs(0), nedofs(0), nfdofs(0), nbdofs(0),
62  bdofs(NULL),
63  elem_dof(NULL), elem_fos(NULL), bdr_elem_dof(NULL), bdr_elem_fos(NULL),
64  face_dof(NULL),
65  NURBSext(NULL), own_ext(false),
66  DoFTrans(0), VDoFTrans(vdim, ordering),
67  cP(NULL), cR(NULL), cR_hp(NULL), cP_is_set(false),
68  Th(Operator::ANY_TYPE),
69  sequence(0), mesh_sequence(0), orders_changed(false), relaxed_hp(false)
70 { }
71 
73  Mesh *mesh_,
74  const FiniteElementCollection *fec_)
75  : VDoFTrans(orig.vdim, orig.ordering)
76 {
77  mesh_ = mesh_ ? mesh_ : orig.mesh;
78  fec_ = fec_ ? fec_ : orig.fec;
79 
80  NURBSExtension *nurbs_ext = NULL;
81  if (orig.NURBSext && orig.NURBSext != orig.mesh->NURBSext)
82  {
83 #ifdef MFEM_USE_MPI
84  ParNURBSExtension *pNURBSext =
85  dynamic_cast<ParNURBSExtension *>(orig.NURBSext);
86  if (pNURBSext)
87  {
88  nurbs_ext = new ParNURBSExtension(*pNURBSext);
89  }
90  else
91 #endif
92  {
93  nurbs_ext = new NURBSExtension(*orig.NURBSext);
94  }
95  }
96 
97  Constructor(mesh_, nurbs_ext, fec_, orig.vdim, orig.ordering);
98 }
99 
101  const FiniteElementSpace &fes, const Array<int> *perm)
102 {
103  MFEM_VERIFY(cP == NULL, "");
104  MFEM_VERIFY(cR == NULL, "");
105 
106  SparseMatrix *perm_mat = NULL, *perm_mat_tr = NULL;
107  if (perm)
108  {
109  // Note: although n and fes.GetVSize() are typically equal, in
110  // variable-order spaces they may differ, since nonconforming edges/faces
111  // my have fictitious DOFs.
112  int n = perm->Size();
113  perm_mat = new SparseMatrix(n, fes.GetVSize());
114  for (int i=0; i<n; ++i)
115  {
116  double s;
117  int j = DecodeDof((*perm)[i], s);
118  perm_mat->Set(i, j, s);
119  }
120  perm_mat->Finalize();
121  perm_mat_tr = Transpose(*perm_mat);
122  }
123 
124  if (fes.GetConformingProlongation() != NULL)
125  {
126  if (perm) { cP = Mult(*perm_mat, *fes.GetConformingProlongation()); }
127  else { cP = new SparseMatrix(*fes.GetConformingProlongation()); }
128  cP_is_set = true;
129  }
130  else if (perm != NULL)
131  {
132  cP = perm_mat;
133  cP_is_set = true;
134  perm_mat = NULL;
135  }
136  if (fes.GetConformingRestriction() != NULL)
137  {
138  if (perm) { cR = Mult(*fes.GetConformingRestriction(), *perm_mat_tr); }
139  else { cR = new SparseMatrix(*fes.GetConformingRestriction()); }
140  }
141  else if (perm != NULL)
142  {
143  cR = perm_mat_tr;
144  perm_mat_tr = NULL;
145  }
146 
147  delete perm_mat;
148  delete perm_mat_tr;
149 }
150 
152 {
153  MFEM_VERIFY(mesh_sequence == mesh->GetSequence(),
154  "Space has not been Updated() after a Mesh change.");
155  MFEM_VERIFY(i >= 0 && i < GetNE(), "Invalid element index");
156  MFEM_VERIFY(p >= 0 && p <= MaxVarOrder, "Order out of range");
157  MFEM_ASSERT(!elem_order.Size() || elem_order.Size() == GetNE(),
158  "Internal error");
159 
160  if (elem_order.Size()) // already a variable-order space
161  {
162  if (elem_order[i] != p)
163  {
164  elem_order[i] = p;
165  orders_changed = true;
166  }
167  }
168  else // convert space to variable-order space
169  {
171  elem_order = fec->GetOrder();
172 
173  elem_order[i] = p;
174  orders_changed = true;
175  }
176 }
177 
179 {
180  MFEM_VERIFY(mesh_sequence == mesh->GetSequence(),
181  "Space has not been Updated() after a Mesh change.");
182  MFEM_VERIFY(i >= 0 && i < GetNE(), "Invalid element index");
183  MFEM_ASSERT(!elem_order.Size() || elem_order.Size() == GetNE(),
184  "Internal error");
185 
186  return GetElementOrderImpl(i);
187 }
188 
190 {
191  // (this is an internal version of GetElementOrder without asserts and checks)
192  return elem_order.Size() ? elem_order[i] : fec->GetOrder();
193 }
194 
195 void FiniteElementSpace::GetVDofs(int vd, Array<int>& dofs, int ndofs_) const
196 {
197  if (ndofs_ < 0) { ndofs_ = this->ndofs; }
198 
200  {
201  for (int i = 0; i < dofs.Size(); i++)
202  {
203  dofs[i] = Ordering::Map<Ordering::byNODES>(ndofs_, vdim, i, vd);
204  }
205  }
206  else
207  {
208  for (int i = 0; i < dofs.Size(); i++)
209  {
210  dofs[i] = Ordering::Map<Ordering::byVDIM>(ndofs_, vdim, i, vd);
211  }
212  }
213 }
214 
215 void FiniteElementSpace::DofsToVDofs (Array<int> &dofs, int ndofs_) const
216 {
217  if (vdim == 1) { return; }
218  if (ndofs_ < 0) { ndofs_ = this->ndofs; }
219 
221  {
222  Ordering::DofsToVDofs<Ordering::byNODES>(ndofs_, vdim, dofs);
223  }
224  else
225  {
226  Ordering::DofsToVDofs<Ordering::byVDIM>(ndofs_, vdim, dofs);
227  }
228 }
229 
230 void FiniteElementSpace::DofsToVDofs(int vd, Array<int> &dofs, int ndofs_) const
231 {
232  if (vdim == 1) { return; }
233  if (ndofs_ < 0) { ndofs_ = this->ndofs; }
234 
236  {
237  for (int i = 0; i < dofs.Size(); i++)
238  {
239  dofs[i] = Ordering::Map<Ordering::byNODES>(ndofs_, vdim, dofs[i], vd);
240  }
241  }
242  else
243  {
244  for (int i = 0; i < dofs.Size(); i++)
245  {
246  dofs[i] = Ordering::Map<Ordering::byVDIM>(ndofs_, vdim, dofs[i], vd);
247  }
248  }
249 }
250 
251 int FiniteElementSpace::DofToVDof(int dof, int vd, int ndofs_) const
252 {
253  if (vdim == 1) { return dof; }
254  if (ndofs_ < 0) { ndofs_ = this->ndofs; }
255 
257  {
258  return Ordering::Map<Ordering::byNODES>(ndofs_, vdim, dof, vd);
259  }
260  else
261  {
262  return Ordering::Map<Ordering::byVDIM>(ndofs_, vdim, dof, vd);
263  }
264 }
265 
266 // static function
268 {
269  int n = vdofs.Size(), *vdof = vdofs;
270  for (int i = 0; i < n; i++)
271  {
272  int j;
273  if ((j = vdof[i]) < 0)
274  {
275  vdof[i] = -1-j;
276  }
277  }
278 }
279 
282 {
283  DofTransformation * doftrans = GetElementDofs(i, vdofs);
284  DofsToVDofs(vdofs);
285  if (vdim == 1 || doftrans == NULL)
286  {
287  return doftrans;
288  }
289  else
290  {
291  VDoFTrans.SetDofTransformation(*doftrans);
292  return &VDoFTrans;
293  }
294 }
295 
298 {
299  DofTransformation * doftrans = GetBdrElementDofs(i, vdofs);
300  DofsToVDofs(vdofs);
301  if (vdim == 1 || doftrans == NULL)
302  {
303  return doftrans;
304  }
305  else
306  {
307  VDoFTrans.SetDofTransformation(*doftrans);
308  return &VDoFTrans;
309  }
310 }
311 
313 {
314  GetFaceDofs(i, vdofs);
315  DofsToVDofs(vdofs);
316 }
317 
319 {
320  GetEdgeDofs(i, vdofs);
321  DofsToVDofs(vdofs);
322 }
323 
325 {
326  GetVertexDofs(i, vdofs);
327  DofsToVDofs(vdofs);
328 }
329 
331 {
332  GetElementInteriorDofs(i, vdofs);
333  DofsToVDofs(vdofs);
334 }
335 
337 {
338  GetEdgeInteriorDofs(i, vdofs);
339  DofsToVDofs(vdofs);
340 }
341 
343 {
344  if (elem_dof) { return; }
345 
346  // TODO: can we call GetElementDofs only once per element?
347  Table *el_dof = new Table;
348  Table *el_fos = (mesh->Dimension() > 2) ? (new Table) : NULL;
349  Array<int> dofs;
350  Array<int> F, Fo;
351  el_dof -> MakeI (mesh -> GetNE());
352  if (el_fos) { el_fos -> MakeI (mesh -> GetNE()); }
353  for (int i = 0; i < mesh -> GetNE(); i++)
354  {
355  GetElementDofs (i, dofs);
356  el_dof -> AddColumnsInRow (i, dofs.Size());
357 
358  if (el_fos)
359  {
360  mesh->GetElementFaces(i, F, Fo);
361  el_fos -> AddColumnsInRow (i, Fo.Size());
362  }
363  }
364  el_dof -> MakeJ();
365  if (el_fos) { el_fos -> MakeJ(); }
366  for (int i = 0; i < mesh -> GetNE(); i++)
367  {
368  GetElementDofs (i, dofs);
369  el_dof -> AddConnections (i, (int *)dofs, dofs.Size());
370 
371  if (el_fos)
372  {
373  mesh->GetElementFaces(i, F, Fo);
374  el_fos -> AddConnections (i, (int *)Fo, Fo.Size());
375  }
376  }
377  el_dof -> ShiftUpI();
378  if (el_fos) { el_fos -> ShiftUpI(); }
379  elem_dof = el_dof;
380  elem_fos = el_fos;
381 }
382 
384 {
385  if (bdr_elem_dof) { return; }
386 
387  Table *bel_dof = new Table;
388  Array<int> dofs;
389  bel_dof->MakeI(mesh->GetNBE());
390  for (int i = 0; i < mesh->GetNBE(); i++)
391  {
392  GetBdrElementDofs(i, dofs);
393  bel_dof->AddColumnsInRow(i, dofs.Size());
394  }
395  bel_dof->MakeJ();
396  for (int i = 0; i < mesh->GetNBE(); i++)
397  {
398  GetBdrElementDofs(i, dofs);
399  bel_dof->AddConnections(i, (int *)dofs, dofs.Size());
400  }
401  bel_dof->ShiftUpI();
402  bdr_elem_dof = bel_dof;
403 }
404 
406 {
407  // Here, "face" == (dim-1)-dimensional mesh entity.
408 
409  if (face_dof) { return; }
410 
411  if (NURBSext) { BuildNURBSFaceToDofTable(); return; }
412 
413  Table *fc_dof = new Table;
414  Array<int> dofs;
415  fc_dof->MakeI(mesh->GetNumFaces());
416  for (int i = 0; i < fc_dof->Size(); i++)
417  {
418  GetFaceDofs(i, dofs, 0);
419  fc_dof->AddColumnsInRow(i, dofs.Size());
420  }
421  fc_dof->MakeJ();
422  for (int i = 0; i < fc_dof->Size(); i++)
423  {
424  GetFaceDofs(i, dofs, 0);
425  fc_dof->AddConnections(i, (int *)dofs, dofs.Size());
426  }
427  fc_dof->ShiftUpI();
428  face_dof = fc_dof;
429 }
430 
432 {
433  delete elem_dof;
434  delete elem_fos;
435  elem_dof = NULL;
436  elem_fos = NULL;
438 }
439 
441 {
442  Array<int> dof_marker(ndofs);
443 
444  dof_marker = -1;
445 
446  int *J = elem_dof->GetJ(), nnz = elem_dof->Size_of_connections();
447  for (int k = 0, dof_counter = 0; k < nnz; k++)
448  {
449  const int sdof = J[k]; // signed dof
450  const int dof = (sdof < 0) ? -1-sdof : sdof;
451  int new_dof = dof_marker[dof];
452  if (new_dof < 0)
453  {
454  dof_marker[dof] = new_dof = dof_counter++;
455  }
456  J[k] = (sdof < 0) ? -1-new_dof : new_dof; // preserve the sign of sdof
457  }
458 }
459 
461 {
462  if (dof_elem_array.Size()) { return; }
463 
465 
468  dof_elem_array = -1;
469  for (int i = 0; i < mesh -> GetNE(); i++)
470  {
471  const int *dofs = elem_dof -> GetRow(i);
472  const int n = elem_dof -> RowSize(i);
473  for (int j = 0; j < n; j++)
474  {
475  int dof = DecodeDof(dofs[j]);
476  if (dof_elem_array[dof] < 0)
477  {
478  dof_elem_array[dof] = i;
479  dof_ldof_array[dof] = j;
480  }
481  }
482  }
483 }
484 
485 static void mark_dofs(const Array<int> &dofs, Array<int> &mark_array)
486 {
487  for (int i = 0; i < dofs.Size(); i++)
488  {
489  int k = dofs[i];
490  if (k < 0) { k = -1 - k; }
491  mark_array[k] = -1;
492  }
493 }
494 
496  Array<int> &ess_vdofs,
497  int component) const
498 {
499  Array<int> vdofs, dofs;
500 
501  ess_vdofs.SetSize(GetVSize());
502  ess_vdofs = 0;
503 
504  for (int i = 0; i < GetNBE(); i++)
505  {
506  if (bdr_attr_is_ess[GetBdrAttribute(i)-1])
507  {
508  if (component < 0)
509  {
510  // Mark all components.
511  GetBdrElementVDofs(i, vdofs);
512  mark_dofs(vdofs, ess_vdofs);
513  }
514  else
515  {
516  GetBdrElementDofs(i, dofs);
517  for (int d = 0; d < dofs.Size(); d++)
518  { dofs[d] = DofToVDof(dofs[d], component); }
519  mark_dofs(dofs, ess_vdofs);
520  }
521  }
522  }
523 
524  // mark possible hidden boundary edges in a non-conforming mesh, also
525  // local DOFs affected by boundary elements on other processors
526  if (Nonconforming())
527  {
528  Array<int> bdr_verts, bdr_edges;
529  mesh->ncmesh->GetBoundaryClosure(bdr_attr_is_ess, bdr_verts, bdr_edges);
530 
531  for (int i = 0; i < bdr_verts.Size(); i++)
532  {
533  if (component < 0)
534  {
535  GetVertexVDofs(bdr_verts[i], vdofs);
536  mark_dofs(vdofs, ess_vdofs);
537  }
538  else
539  {
540  GetVertexDofs(bdr_verts[i], dofs);
541  for (int d = 0; d < dofs.Size(); d++)
542  { dofs[d] = DofToVDof(dofs[d], component); }
543  mark_dofs(dofs, ess_vdofs);
544  }
545  }
546  for (int i = 0; i < bdr_edges.Size(); i++)
547  {
548  if (component < 0)
549  {
550  GetEdgeVDofs(bdr_edges[i], vdofs);
551  mark_dofs(vdofs, ess_vdofs);
552  }
553  else
554  {
555  GetEdgeDofs(bdr_edges[i], dofs);
556  for (int d = 0; d < dofs.Size(); d++)
557  { dofs[d] = DofToVDof(dofs[d], component); }
558  mark_dofs(dofs, ess_vdofs);
559  }
560  }
561  }
562 }
563 
565  Array<int> &ess_tdof_list,
566  int component)
567 {
568  Array<int> ess_vdofs, ess_tdofs;
569  GetEssentialVDofs(bdr_attr_is_ess, ess_vdofs, component);
571  if (!R)
572  {
573  ess_tdofs.MakeRef(ess_vdofs);
574  }
575  else
576  {
577  R->BooleanMult(ess_vdofs, ess_tdofs);
578  }
579  MarkerToList(ess_tdofs, ess_tdof_list);
580 }
581 
583  int component)
584 {
585  if (mesh->bdr_attributes.Size())
586  {
587  Array<int> ess_bdr(mesh->bdr_attributes.Max());
588  ess_bdr = 1;
589  GetEssentialTrueDofs(ess_bdr, boundary_dofs, component);
590  }
591  else
592  {
593  boundary_dofs.DeleteAll();
594  }
595 }
596 
597 // static method
599  Array<int> &list)
600 {
601  int num_marked = 0;
602  marker.HostRead(); // make sure we can read the array on host
603  for (int i = 0; i < marker.Size(); i++)
604  {
605  if (marker[i]) { num_marked++; }
606  }
607  list.SetSize(0);
608  list.HostWrite();
609  list.Reserve(num_marked);
610  for (int i = 0; i < marker.Size(); i++)
611  {
612  if (marker[i]) { list.Append(i); }
613  }
614 }
615 
616 // static method
617 void FiniteElementSpace::ListToMarker(const Array<int> &list, int marker_size,
618  Array<int> &marker, int mark_val)
619 {
620  list.HostRead(); // make sure we can read the array on host
621  marker.SetSize(marker_size);
622  marker.HostWrite();
623  marker = 0;
624  for (int i = 0; i < list.Size(); i++)
625  {
626  marker[list[i]] = mark_val;
627  }
628 }
629 
631  Array<int> &cdofs)
632 {
634  if (cP) { cP->BooleanMultTranspose(dofs, cdofs); }
635  else { dofs.Copy(cdofs); }
636 }
637 
639  Array<int> &dofs)
640 {
642  if (cR) { cR->BooleanMultTranspose(cdofs, dofs); }
643  else { cdofs.Copy(dofs); }
644 }
645 
646 SparseMatrix *
648 {
649  int i, j;
650  Array<int> d_vdofs, c_vdofs;
651  SparseMatrix *R;
652 
653  R = new SparseMatrix (cfes -> GetVSize(), GetVSize());
654 
655  for (i = 0; i < mesh -> GetNE(); i++)
656  {
657  this -> GetElementVDofs (i, d_vdofs);
658  cfes -> GetElementVDofs (i, c_vdofs);
659 
660 #ifdef MFEM_DEBUG
661  if (d_vdofs.Size() != c_vdofs.Size())
662  {
663  mfem_error ("FiniteElementSpace::D2C_GlobalRestrictionMatrix (...)");
664  }
665 #endif
666 
667  for (j = 0; j < d_vdofs.Size(); j++)
668  {
669  R -> Set (c_vdofs[j], d_vdofs[j], 1.0);
670  }
671  }
672 
673  R -> Finalize();
674 
675  return R;
676 }
677 
678 SparseMatrix *
680 {
681  int i, j;
682  Array<int> d_dofs, c_dofs;
683  SparseMatrix *R;
684 
685  R = new SparseMatrix (cfes -> GetNDofs(), ndofs);
686 
687  for (i = 0; i < mesh -> GetNE(); i++)
688  {
689  this -> GetElementDofs (i, d_dofs);
690  cfes -> GetElementDofs (i, c_dofs);
691 
692 #ifdef MFEM_DEBUG
693  if (c_dofs.Size() != 1)
694  mfem_error ("FiniteElementSpace::"
695  "D2Const_GlobalRestrictionMatrix (...)");
696 #endif
697 
698  for (j = 0; j < d_dofs.Size(); j++)
699  {
700  R -> Set (c_dofs[0], d_dofs[j], 1.0);
701  }
702  }
703 
704  R -> Finalize();
705 
706  return R;
707 }
708 
709 SparseMatrix *
711 {
712  SparseMatrix *R;
713  DenseMatrix loc_restr;
714  Array<int> l_dofs, h_dofs, l_vdofs, h_vdofs;
715 
716  int lvdim = lfes->GetVDim();
717  R = new SparseMatrix (lvdim * lfes -> GetNDofs(), lvdim * ndofs);
718 
719  Geometry::Type cached_geom = Geometry::INVALID;
720  const FiniteElement *h_fe = NULL;
721  const FiniteElement *l_fe = NULL;
723 
724  for (int i = 0; i < mesh -> GetNE(); i++)
725  {
726  this -> GetElementDofs (i, h_dofs);
727  lfes -> GetElementDofs (i, l_dofs);
728 
729  // Assuming 'loc_restr' depends only on the Geometry::Type.
730  const Geometry::Type geom = mesh->GetElementBaseGeometry(i);
731  if (geom != cached_geom)
732  {
733  h_fe = this -> GetFE (i);
734  l_fe = lfes -> GetFE (i);
736  h_fe->Project(*l_fe, T, loc_restr);
737  cached_geom = geom;
738  }
739 
740  for (int vd = 0; vd < lvdim; vd++)
741  {
742  l_dofs.Copy(l_vdofs);
743  lfes->DofsToVDofs(vd, l_vdofs);
744 
745  h_dofs.Copy(h_vdofs);
746  this->DofsToVDofs(vd, h_vdofs);
747 
748  R -> SetSubMatrix (l_vdofs, h_vdofs, loc_restr, 1);
749  }
750  }
751 
752  R -> Finalize();
753 
754  return R;
755 }
756 
759  Array<int>& slave_dofs, DenseMatrix& I, int skipfirst)
760 {
761  for (int i = skipfirst; i < slave_dofs.Size(); i++)
762  {
763  int sdof = slave_dofs[i];
764  if (!deps.RowSize(sdof)) // not processed yet
765  {
766  for (int j = 0; j < master_dofs.Size(); j++)
767  {
768  double coef = I(i, j);
769  if (std::abs(coef) > 1e-12)
770  {
771  int mdof = master_dofs[j];
772  if (mdof != sdof && mdof != (-1-sdof))
773  {
774  deps.Add(sdof, mdof, coef);
775  }
776  }
777  }
778  }
779  }
780 }
781 
784  const FiniteElement *master_fe,
785  Array<int> &slave_dofs, int slave_face,
786  const DenseMatrix *pm) const
787 {
788  // In variable-order spaces in 3D, we need to only constrain interior face
789  // DOFs (this is done one level up), since edge dependencies can be more
790  // complex and are primarily handled by edge-edge dependencies. The one
791  // exception is edges of slave faces that lie in the interior of the master
792  // face, which are not covered by edge-edge relations. This function finds
793  // such edges and makes them constrained by the master face.
794  // See also https://github.com/mfem/mfem/pull/1423#issuecomment-633916643
795 
796  Array<int> V, E, Eo; // TODO: LocalArray
797  mesh->GetFaceVertices(slave_face, V);
798  mesh->GetFaceEdges(slave_face, E, Eo);
799  MFEM_ASSERT(V.Size() == E.Size(), "");
800 
801  DenseMatrix I;
803  edge_T.SetFE(&SegmentFE);
804 
805  // constrain each edge of the slave face
806  for (int i = 0; i < E.Size(); i++)
807  {
808  int a = i, b = (i+1) % V.Size();
809  if (V[a] > V[b]) { std::swap(a, b); }
810 
811  DenseMatrix &edge_pm = edge_T.GetPointMat();
812  edge_pm.SetSize(2, 2);
813 
814  // copy two points from the face point matrix
815  double mid[2];
816  for (int j = 0; j < 2; j++)
817  {
818  edge_pm(j, 0) = (*pm)(j, a);
819  edge_pm(j, 1) = (*pm)(j, b);
820  mid[j] = 0.5*((*pm)(j, a) + (*pm)(j, b));
821  }
822 
823  // check that the edge does not coincide with the master face's edge
824  const double eps = 1e-14;
825  if (mid[0] > eps && mid[0] < 1-eps &&
826  mid[1] > eps && mid[1] < 1-eps)
827  {
828  int order = GetEdgeDofs(E[i], slave_dofs, 0);
829 
830  const auto *edge_fe = fec->GetFE(Geometry::SEGMENT, order);
831  edge_fe->GetTransferMatrix(*master_fe, edge_T, I);
832 
833  AddDependencies(deps, master_dofs, slave_dofs, I, 0);
834  }
835  }
836 }
837 
838 bool FiniteElementSpace::DofFinalizable(int dof, const Array<bool>& finalized,
839  const SparseMatrix& deps)
840 {
841  const int* dep = deps.GetRowColumns(dof);
842  int ndep = deps.RowSize(dof);
843 
844  // are all constraining DOFs finalized?
845  for (int i = 0; i < ndep; i++)
846  {
847  if (!finalized[dep[i]]) { return false; }
848  }
849  return true;
850 }
851 
853  Geometry::Type master_geom,
854  int variant) const
855 {
856  // In NC meshes with prisms/tets, a special constraint occurs where a
857  // prism/tet edge is slave to another element's face (see illustration
858  // here: https://github.com/mfem/mfem/pull/713#issuecomment-495786362)
859  // Rather than introduce a new edge-face constraint type, we handle such
860  // cases as degenerate face-face constraints, where the point-matrix
861  // rectangle has zero height. This method returns DOFs for the first edge
862  // of the rectangle, duplicated in the orthogonal direction, to resemble
863  // DOFs for a quadrilateral face. The extra DOFs are ignored by
864  // FiniteElementSpace::AddDependencies.
865 
866  Array<int> edof;
867  int order = GetEdgeDofs(-1 - index, edof, variant);
868 
871  int nn = 2*nv + ne;
872 
873  dofs.SetSize(nn*nn);
874  if (!dofs.Size()) { return 0; }
875 
876  dofs = edof[0];
877 
878  // copy first two vertex DOFs
879  for (int i = 0; i < nv; i++)
880  {
881  dofs[i] = edof[i];
882  dofs[nv+i] = edof[nv+i];
883  }
884  // copy first edge DOFs
885  int face_vert = Geometry::NumVerts[master_geom];
886  for (int i = 0; i < ne; i++)
887  {
888  dofs[face_vert*nv + i] = edof[2*nv + i];
889  }
890 
891  return order;
892 }
893 
895 {
896  // return the number of vertex and edge DOFs that precede inner DOFs
897  const int nv = fec->GetNumDof(Geometry::POINT, order);
898  const int ne = fec->GetNumDof(Geometry::SEGMENT, order);
899 
900  return Geometry::NumVerts[geom] * (geom == Geometry::SEGMENT ? nv : (nv + ne));
901 }
902 
904  Geometry::Type master_geom,
905  int variant) const
906 {
907  switch (entity)
908  {
909  case 0:
910  GetVertexDofs(index, dofs);
911  return 0;
912 
913  case 1:
914  return GetEdgeDofs(index, dofs, variant);
915 
916  default:
917  if (index >= 0)
918  {
919  return GetFaceDofs(index, dofs, variant);
920  }
921  else
922  {
923  return GetDegenerateFaceDofs(index, dofs, master_geom, variant);
924  }
925  }
926 }
927 
929 {
930 #ifdef MFEM_USE_MPI
931  MFEM_VERIFY(dynamic_cast<const ParFiniteElementSpace*>(this) == NULL,
932  "This method should not be used with a ParFiniteElementSpace!");
933 #endif
934 
935  if (cP_is_set) { return; }
936  cP_is_set = true;
937 
938  if (FEColl()->GetContType() == FiniteElementCollection::DISCONTINUOUS)
939  {
940  cP = cR = cR_hp = NULL; // will be treated as identities
941  return;
942  }
943 
944  Array<int> master_dofs, slave_dofs, highest_dofs;
945 
947  DenseMatrix I;
948 
949  // For each slave DOF, the dependency matrix will contain a row that
950  // expresses the slave DOF as a linear combination of its immediate master
951  // DOFs. Rows of independent DOFs will remain empty.
952  SparseMatrix deps(ndofs);
953 
954  // Inverse dependencies for the cR_hp matrix in variable order spaces:
955  // For each master edge/face with more DOF sets, the inverse dependency
956  // matrix contains a row that expresses the master true DOF (lowest order)
957  // as a linear combination of the highest order set of DOFs.
958  SparseMatrix inv_deps(ndofs);
959 
960  // collect local face/edge dependencies
961  for (int entity = 2; entity >= 1; entity--)
962  {
963  const NCMesh::NCList &list = mesh->ncmesh->GetNCList(entity);
964  if (!list.masters.Size()) { continue; }
965 
966  // loop through all master edges/faces, constrain their slave edges/faces
967  for (const NCMesh::Master &master : list.masters)
968  {
969  Geometry::Type master_geom = master.Geom();
970 
971  int p = GetEntityDofs(entity, master.index, master_dofs, master_geom);
972  if (!master_dofs.Size()) { continue; }
973 
974  const FiniteElement *master_fe = fec->GetFE(master_geom, p);
975  if (!master_fe) { continue; }
976 
977  switch (master_geom)
978  {
979  case Geometry::SQUARE: T.SetFE(&QuadrilateralFE); break;
980  case Geometry::TRIANGLE: T.SetFE(&TriangleFE); break;
981  case Geometry::SEGMENT: T.SetFE(&SegmentFE); break;
982  default: MFEM_ABORT("unsupported geometry");
983  }
984 
985  for (int si = master.slaves_begin; si < master.slaves_end; si++)
986  {
987  const NCMesh::Slave &slave = list.slaves[si];
988 
989  int q = GetEntityDofs(entity, slave.index, slave_dofs, master_geom);
990  if (!slave_dofs.Size()) { break; }
991 
992  const FiniteElement *slave_fe = fec->GetFE(slave.Geom(), q);
993  list.OrientedPointMatrix(slave, T.GetPointMat());
994  slave_fe->GetTransferMatrix(*master_fe, T, I);
995 
996  // variable order spaces: face edges need to be handled separately
997  int skipfirst = 0;
998  if (IsVariableOrder() && entity == 2 && slave.index >= 0)
999  {
1000  skipfirst = GetNumBorderDofs(master_geom, q);
1001  }
1002 
1003  // make each slave DOF dependent on all master DOFs
1004  AddDependencies(deps, master_dofs, slave_dofs, I, skipfirst);
1005 
1006  if (skipfirst)
1007  {
1008  // constrain internal edge DOFs if they were skipped
1009  const auto *pm = list.point_matrices[master_geom][slave.matrix];
1010  AddEdgeFaceDependencies(deps, master_dofs, master_fe,
1011  slave_dofs, slave.index, pm);
1012  }
1013  }
1014 
1015  // Add inverse dependencies for the cR_hp matrix; if a master has
1016  // more DOF sets, the lowest order set interpolates the highest one.
1017  if (IsVariableOrder())
1018  {
1019  int nvar = GetNVariants(entity, master.index);
1020  if (nvar > 1)
1021  {
1022  int q = GetEntityDofs(entity, master.index, highest_dofs,
1023  master_geom, nvar-1);
1024  const auto *highest_fe = fec->GetFE(master_geom, q);
1025 
1026  T.SetIdentityTransformation(master_geom);
1027  master_fe->GetTransferMatrix(*highest_fe, T, I);
1028 
1029  // add dependencies only for the inner dofs
1030  int skip = GetNumBorderDofs(master_geom, p);
1031  AddDependencies(inv_deps, highest_dofs, master_dofs, I, skip);
1032  }
1033  }
1034  }
1035  }
1036 
1037  // variable order spaces: enforce minimum rule on conforming edges/faces
1038  if (IsVariableOrder())
1039  {
1040  for (int entity = 1; entity < mesh->Dimension(); entity++)
1041  {
1042  const Table &ent_dofs = (entity == 1) ? var_edge_dofs : var_face_dofs;
1043  int num_ent = (entity == 1) ? mesh->GetNEdges() : mesh->GetNFaces();
1044  MFEM_ASSERT(ent_dofs.Size() == num_ent+1, "");
1045 
1046  // add constraints within edges/faces holding multiple DOF sets
1047  Geometry::Type last_geom = Geometry::INVALID;
1048  for (int i = 0; i < num_ent; i++)
1049  {
1050  if (ent_dofs.RowSize(i) <= 1) { continue; }
1051 
1052  Geometry::Type geom =
1053  (entity == 1) ? Geometry::SEGMENT : mesh->GetFaceGeometry(i);
1054 
1055  if (geom != last_geom)
1056  {
1057  T.SetIdentityTransformation(geom);
1058  last_geom = geom;
1059  }
1060 
1061  // get lowest order variant DOFs and FE
1062  int p = GetEntityDofs(entity, i, master_dofs, geom, 0);
1063  const auto *master_fe = fec->GetFE(geom, p);
1064  if (!master_fe) { break; }
1065 
1066  // constrain all higher order DOFs: interpolate lowest order function
1067  for (int variant = 1; ; variant++)
1068  {
1069  int q = GetEntityDofs(entity, i, slave_dofs, geom, variant);
1070  if (q < 0) { break; }
1071 
1072  const auto *slave_fe = fec->GetFE(geom, q);
1073  slave_fe->GetTransferMatrix(*master_fe, T, I);
1074 
1075  AddDependencies(deps, master_dofs, slave_dofs, I);
1076  }
1077  }
1078  }
1079  }
1080 
1081  deps.Finalize();
1082  inv_deps.Finalize();
1083 
1084  // DOFs that stayed independent are true DOFs
1085  int n_true_dofs = 0;
1086  for (int i = 0; i < ndofs; i++)
1087  {
1088  if (!deps.RowSize(i)) { n_true_dofs++; }
1089  }
1090 
1091  // if all dofs are true dofs leave cP and cR NULL
1092  if (n_true_dofs == ndofs)
1093  {
1094  cP = cR = cR_hp = NULL; // will be treated as identities
1095  return;
1096  }
1097 
1098  // create the conforming prolongation matrix cP
1099  cP = new SparseMatrix(ndofs, n_true_dofs);
1100 
1101  // create the conforming restriction matrix cR
1102  int *cR_J;
1103  {
1104  int *cR_I = Memory<int>(n_true_dofs+1);
1105  double *cR_A = Memory<double>(n_true_dofs);
1106  cR_J = Memory<int>(n_true_dofs);
1107  for (int i = 0; i < n_true_dofs; i++)
1108  {
1109  cR_I[i] = i;
1110  cR_A[i] = 1.0;
1111  }
1112  cR_I[n_true_dofs] = n_true_dofs;
1113  cR = new SparseMatrix(cR_I, cR_J, cR_A, n_true_dofs, ndofs);
1114  }
1115 
1116  // In var. order spaces, create the restriction matrix cR_hp which is similar
1117  // to cR, but has interpolation in the extra master edge/face DOFs.
1118  cR_hp = IsVariableOrder() ? new SparseMatrix(n_true_dofs, ndofs) : NULL;
1119 
1120  Array<bool> finalized(ndofs);
1121  finalized = false;
1122 
1123  Array<int> cols;
1124  Vector srow;
1125 
1126  // put identity in the prolongation matrix for true DOFs, initialize cR_hp
1127  for (int i = 0, true_dof = 0; i < ndofs; i++)
1128  {
1129  if (!deps.RowSize(i)) // true dof
1130  {
1131  cP->Add(i, true_dof, 1.0);
1132  cR_J[true_dof] = i;
1133  finalized[i] = true;
1134 
1135  if (cR_hp)
1136  {
1137  if (inv_deps.RowSize(i))
1138  {
1139  inv_deps.GetRow(i, cols, srow);
1140  cR_hp->AddRow(true_dof, cols, srow);
1141  }
1142  else
1143  {
1144  cR_hp->Add(true_dof, i, 1.0);
1145  }
1146  }
1147 
1148  true_dof++;
1149  }
1150  }
1151 
1152  // Now calculate cP rows of slave DOFs as combinations of cP rows of their
1153  // master DOFs. It is possible that some slave DOFs depend on DOFs that are
1154  // themselves slaves. Here we resolve such indirect constraints by first
1155  // calculating rows of the cP matrix for DOFs whose master DOF cP rows are
1156  // already known (in the first iteration these are the true DOFs). In the
1157  // second iteration, slaves of slaves can be 'finalized' (given a row in the
1158  // cP matrix), in the third iteration slaves of slaves of slaves, etc.
1159  bool finished;
1160  int n_finalized = n_true_dofs;
1161  do
1162  {
1163  finished = true;
1164  for (int dof = 0; dof < ndofs; dof++)
1165  {
1166  if (!finalized[dof] && DofFinalizable(dof, finalized, deps))
1167  {
1168  const int* dep_col = deps.GetRowColumns(dof);
1169  const double* dep_coef = deps.GetRowEntries(dof);
1170  int n_dep = deps.RowSize(dof);
1171 
1172  for (int j = 0; j < n_dep; j++)
1173  {
1174  cP->GetRow(dep_col[j], cols, srow);
1175  srow *= dep_coef[j];
1176  cP->AddRow(dof, cols, srow);
1177  }
1178 
1179  finalized[dof] = true;
1180  n_finalized++;
1181  finished = false;
1182  }
1183  }
1184  }
1185  while (!finished);
1186 
1187  // If everything is consistent (mesh, face orientations, etc.), we should
1188  // be able to finalize all slave DOFs, otherwise it's a serious error.
1189  MFEM_VERIFY(n_finalized == ndofs,
1190  "Error creating cP matrix: n_finalized = "
1191  << n_finalized << ", ndofs = " << ndofs);
1192 
1193  cP->Finalize();
1194  if (cR_hp) { cR_hp->Finalize(); }
1195 
1196  if (vdim > 1)
1197  {
1198  MakeVDimMatrix(*cP);
1199  MakeVDimMatrix(*cR);
1200  if (cR_hp) { MakeVDimMatrix(*cR_hp); }
1201  }
1202 }
1203 
1205 {
1206  if (vdim == 1) { return; }
1207 
1208  int height = mat.Height();
1209  int width = mat.Width();
1210 
1211  SparseMatrix *vmat = new SparseMatrix(vdim*height, vdim*width);
1212 
1213  Array<int> dofs, vdofs;
1214  Vector srow;
1215  for (int i = 0; i < height; i++)
1216  {
1217  mat.GetRow(i, dofs, srow);
1218  for (int vd = 0; vd < vdim; vd++)
1219  {
1220  dofs.Copy(vdofs);
1221  DofsToVDofs(vd, vdofs, width);
1222  vmat->SetRow(DofToVDof(i, vd, height), vdofs, srow);
1223  }
1224  }
1225  vmat->Finalize();
1226 
1227  mat.Swap(*vmat);
1228  delete vmat;
1229 }
1230 
1231 
1233 {
1234  if (Conforming()) { return NULL; }
1236  return cP;
1237 }
1238 
1240 {
1241  if (Conforming()) { return NULL; }
1243  return cR;
1244 }
1245 
1247 {
1248  if (Conforming()) { return NULL; }
1250  return IsVariableOrder() ? cR_hp : cR;
1251 }
1252 
1254 {
1256  return P ? (P->Width() / vdim) : ndofs;
1257 }
1258 
1260  ElementDofOrdering e_ordering) const
1261 {
1262  // Check if we have a discontinuous space using the FE collection:
1263  if (IsDGSpace())
1264  {
1265  // TODO: when VDIM is 1, we can return IdentityOperator.
1266  if (L2E_nat.Ptr() == NULL)
1267  {
1268  // The input L-vector layout is:
1269  // * ND x NE x VDIM, for Ordering::byNODES, or
1270  // * VDIM x ND x NE, for Ordering::byVDIM.
1271  // The output E-vector layout is: ND x VDIM x NE.
1272  L2E_nat.Reset(new L2ElementRestriction(*this));
1273  }
1275  }
1276  if (e_ordering == ElementDofOrdering::LEXICOGRAPHIC)
1277  {
1278  if (L2E_lex.Ptr() == NULL)
1279  {
1280  L2E_lex.Reset(new ElementRestriction(*this, e_ordering));
1281  }
1283  }
1284  // e_ordering == ElementDofOrdering::NATIVE
1285  if (L2E_nat.Ptr() == NULL)
1286  {
1287  L2E_nat.Reset(new ElementRestriction(*this, e_ordering));
1288  }
1290 }
1291 
1293  ElementDofOrdering e_ordering, FaceType type, L2FaceValues mul) const
1294 {
1295  const bool is_dg_space = IsDGSpace();
1296  const L2FaceValues m = (is_dg_space && mul==L2FaceValues::DoubleValued) ?
1298  key_face key = std::make_tuple(is_dg_space, e_ordering, type, m);
1299  auto itr = L2F.find(key);
1300  if (itr != L2F.end())
1301  {
1302  return itr->second;
1303  }
1304  else
1305  {
1306  FaceRestriction *res;
1307  if (is_dg_space)
1308  {
1309  if (Conforming())
1310  {
1311  res = new L2FaceRestriction(*this, e_ordering, type, m);
1312  }
1313  else
1314  {
1315  res = new NCL2FaceRestriction(*this, e_ordering, type, m);
1316  }
1317  }
1318  else
1319  {
1320  res = new H1FaceRestriction(*this, e_ordering, type);
1321  }
1322  L2F[key] = res;
1323  return res;
1324  }
1325 }
1326 
1328  const IntegrationRule &ir) const
1329 {
1330  for (int i = 0; i < E2Q_array.Size(); i++)
1331  {
1332  const QuadratureInterpolator *qi = E2Q_array[i];
1333  if (qi->IntRule == &ir) { return qi; }
1334  }
1335 
1336  QuadratureInterpolator *qi = new QuadratureInterpolator(*this, ir);
1337  E2Q_array.Append(qi);
1338  return qi;
1339 }
1340 
1342  const QuadratureSpace &qs) const
1343 {
1344  for (int i = 0; i < E2Q_array.Size(); i++)
1345  {
1346  const QuadratureInterpolator *qi = E2Q_array[i];
1347  if (qi->qspace == &qs) { return qi; }
1348  }
1349 
1350  QuadratureInterpolator *qi = new QuadratureInterpolator(*this, qs);
1351  E2Q_array.Append(qi);
1352  return qi;
1353 }
1354 
1357  const IntegrationRule &ir, FaceType type) const
1358 {
1359  if (type==FaceType::Interior)
1360  {
1361  for (int i = 0; i < E2IFQ_array.Size(); i++)
1362  {
1363  const FaceQuadratureInterpolator *qi = E2IFQ_array[i];
1364  if (qi->IntRule == &ir) { return qi; }
1365  }
1366 
1368  type);
1369  E2IFQ_array.Append(qi);
1370  return qi;
1371  }
1372  else //Boundary
1373  {
1374  for (int i = 0; i < E2BFQ_array.Size(); i++)
1375  {
1376  const FaceQuadratureInterpolator *qi = E2BFQ_array[i];
1377  if (qi->IntRule == &ir) { return qi; }
1378  }
1379 
1381  type);
1382  E2BFQ_array.Append(qi);
1383  return qi;
1384  }
1385 }
1386 
1388  const int coarse_ndofs, const Table &coarse_elem_dof,
1389  const Table *coarse_elem_fos, const DenseTensor localP[]) const
1390 {
1391  /// TODO: Implement DofTransformation support
1392 
1393  MFEM_VERIFY(mesh->GetLastOperation() == Mesh::REFINE, "");
1394 
1395  Array<int> dofs, coarse_dofs, coarse_vdofs;
1396  Vector row;
1397 
1398  Mesh::GeometryList elem_geoms(*mesh);
1399 
1400  SparseMatrix *P;
1401  if (elem_geoms.Size() == 1)
1402  {
1403  const int coarse_ldof = localP[elem_geoms[0]].SizeJ();
1404  P = new SparseMatrix(GetVSize(), coarse_ndofs*vdim, coarse_ldof);
1405  }
1406  else
1407  {
1408  P = new SparseMatrix(GetVSize(), coarse_ndofs*vdim);
1409  }
1410 
1411  Array<int> mark(P->Height());
1412  mark = 0;
1413 
1415 
1416  for (int k = 0; k < mesh->GetNE(); k++)
1417  {
1418  const Embedding &emb = rtrans.embeddings[k];
1419  const Geometry::Type geom = mesh->GetElementBaseGeometry(k);
1420  const DenseMatrix &lP = localP[geom](emb.matrix);
1421  const int fine_ldof = localP[geom].SizeI();
1422 
1423  elem_dof->GetRow(k, dofs);
1424  coarse_elem_dof.GetRow(emb.parent, coarse_dofs);
1425 
1426  for (int vd = 0; vd < vdim; vd++)
1427  {
1428  coarse_dofs.Copy(coarse_vdofs);
1429  DofsToVDofs(vd, coarse_vdofs, coarse_ndofs);
1430 
1431  for (int i = 0; i < fine_ldof; i++)
1432  {
1433  int r = DofToVDof(dofs[i], vd);
1434  int m = (r >= 0) ? r : (-1 - r);
1435 
1436  if (!mark[m])
1437  {
1438  lP.GetRow(i, row);
1439  P->SetRow(r, coarse_vdofs, row);
1440  mark[m] = 1;
1441  }
1442  }
1443  }
1444  }
1445 
1446  MFEM_ASSERT(mark.Sum() == P->Height(), "Not all rows of P set.");
1447  if (elem_geoms.Size() != 1) { P->Finalize(); }
1448  return P;
1449 }
1450 
1452  Geometry::Type geom, DenseTensor &localP) const
1453 {
1454  const FiniteElement *fe = fec->FiniteElementForGeometry(geom);
1455 
1457  const DenseTensor &pmats = rtrans.point_matrices[geom];
1458 
1459  int nmat = pmats.SizeK();
1460  int ldof = fe->GetDof();
1461 
1463  isotr.SetIdentityTransformation(geom);
1464 
1465  // calculate local interpolation matrices for all refinement types
1466  localP.SetSize(ldof, ldof, nmat);
1467  for (int i = 0; i < nmat; i++)
1468  {
1469  isotr.SetPointMat(pmats(i));
1470  fe->GetLocalInterpolation(isotr, localP(i));
1471  }
1472 }
1473 
1475  const Table* old_elem_dof,
1476  const Table* old_elem_fos)
1477 {
1478  MFEM_VERIFY(GetNE() >= old_elem_dof->Size(),
1479  "Previous mesh is not coarser.");
1480 
1481  Mesh::GeometryList elem_geoms(*mesh);
1482 
1484  for (int i = 0; i < elem_geoms.Size(); i++)
1485  {
1486  GetLocalRefinementMatrices(elem_geoms[i], localP[elem_geoms[i]]);
1487  }
1488 
1489  return RefinementMatrix_main(old_ndofs, *old_elem_dof, old_elem_fos,
1490  localP);
1491 }
1492 
1494 (const FiniteElementSpace* fespace, Table* old_elem_dof, Table* old_elem_fos,
1495  int old_ndofs)
1496  : fespace(fespace)
1497  , old_elem_dof(old_elem_dof)
1498  , old_elem_fos(old_elem_fos)
1499 {
1500  MFEM_VERIFY(fespace->GetNE() >= old_elem_dof->Size(),
1501  "Previous mesh is not coarser.");
1502 
1503  width = old_ndofs * fespace->GetVDim();
1504  height = fespace->GetVSize();
1505 
1506  Mesh::GeometryList elem_geoms(*fespace->GetMesh());
1507 
1508  for (int i = 0; i < elem_geoms.Size(); i++)
1509  {
1510  fespace->GetLocalRefinementMatrices(elem_geoms[i], localP[elem_geoms[i]]);
1511  }
1512 
1513  ConstructDoFTrans();
1514 }
1515 
1517  const FiniteElementSpace *fespace, const FiniteElementSpace *coarse_fes)
1518  : Operator(fespace->GetVSize(), coarse_fes->GetVSize()),
1519  fespace(fespace), old_elem_dof(NULL), old_elem_fos(NULL)
1520 {
1521  Mesh::GeometryList elem_geoms(*fespace->GetMesh());
1522 
1523  for (int i = 0; i < elem_geoms.Size(); i++)
1524  {
1525  fespace->GetLocalRefinementMatrices(*coarse_fes, elem_geoms[i],
1526  localP[elem_geoms[i]]);
1527  }
1528 
1529  // Make a copy of the coarse elem_dof Table.
1530  old_elem_dof = new Table(coarse_fes->GetElementToDofTable());
1531 
1532  // Make a copy of the coarse elem_fos Table if it exists.
1533  if (coarse_fes->GetElementToFaceOrientationTable())
1534  {
1535  old_elem_fos = new Table(*coarse_fes->GetElementToFaceOrientationTable());
1536  }
1537 
1538  ConstructDoFTrans();
1539 }
1540 
1542 {
1543  delete old_elem_dof;
1544  delete old_elem_fos;
1545 }
1546 
1547 void FiniteElementSpace::RefinementOperator
1548 ::ConstructDoFTrans()
1549 {
1550  old_DoFTrans.SetSize(Geometry::NUM_GEOMETRIES);
1551  for (int i=0; i<old_DoFTrans.Size(); i++)
1552  {
1553  old_DoFTrans[i] = NULL;
1554  }
1555 
1556  const FiniteElementCollection *fec_ref = fespace->FEColl();
1557  if (dynamic_cast<const ND_FECollection*>(fec_ref))
1558  {
1559  const FiniteElement * nd_tri =
1561  if (nd_tri)
1562  {
1563  old_DoFTrans[Geometry::TRIANGLE] =
1564  new ND_TriDofTransformation(nd_tri->GetOrder());
1565  }
1566 
1567  const FiniteElement * nd_tet =
1569  if (nd_tet)
1570  {
1571  old_DoFTrans[Geometry::TETRAHEDRON] =
1572  new ND_TetDofTransformation(nd_tet->GetOrder());
1573  }
1574 
1575  const FiniteElement * nd_pri =
1577  if (nd_pri)
1578  {
1579  old_DoFTrans[Geometry::PRISM] =
1580  new ND_WedgeDofTransformation(nd_pri->GetOrder());
1581  }
1582  }
1583 }
1584 
1586 ::Mult(const Vector &x, Vector &y) const
1587 {
1588  Mesh* mesh_ref = fespace->GetMesh();
1589  const CoarseFineTransformations &trans_ref =
1590  mesh_ref->GetRefinementTransforms();
1591 
1592  Array<int> dofs, vdofs, old_dofs, old_vdofs, old_Fo;
1593 
1594  int rvdim = fespace->GetVDim();
1595  int old_ndofs = width / rvdim;
1596 
1597  Vector subY, subX;
1598 
1599  for (int k = 0; k < mesh_ref->GetNE(); k++)
1600  {
1601  const Embedding &emb = trans_ref.embeddings[k];
1602  const Geometry::Type geom = mesh_ref->GetElementBaseGeometry(k);
1603  const DenseMatrix &lP = localP[geom](emb.matrix);
1604 
1605  subY.SetSize(lP.Height());
1606 
1607  DofTransformation *doftrans = fespace->GetElementDofs(k, dofs);
1608  old_elem_dof->GetRow(emb.parent, old_dofs);
1609 
1610  if (!doftrans)
1611  {
1612  for (int vd = 0; vd < rvdim; vd++)
1613  {
1614  dofs.Copy(vdofs);
1615  fespace->DofsToVDofs(vd, vdofs);
1616  old_dofs.Copy(old_vdofs);
1617  fespace->DofsToVDofs(vd, old_vdofs, old_ndofs);
1618  x.GetSubVector(old_vdofs, subX);
1619  lP.Mult(subX, subY);
1620  y.SetSubVector(vdofs, subY);
1621  }
1622  }
1623  else
1624  {
1625  old_elem_fos->GetRow(emb.parent, old_Fo);
1626  old_DoFTrans[geom]->SetFaceOrientations(old_Fo);
1627 
1628  DofTransformation *new_doftrans = NULL;
1629  VDofTransformation *vdoftrans =
1630  dynamic_cast<VDofTransformation*>(doftrans);
1631  if (vdoftrans)
1632  {
1633  new_doftrans = doftrans;
1634  doftrans = vdoftrans->GetDofTransformation();
1635  }
1636 
1637  for (int vd = 0; vd < rvdim; vd++)
1638  {
1639  dofs.Copy(vdofs);
1640  fespace->DofsToVDofs(vd, vdofs);
1641  old_dofs.Copy(old_vdofs);
1642  fespace->DofsToVDofs(vd, old_vdofs, old_ndofs);
1643  x.GetSubVector(old_vdofs, subX);
1644  old_DoFTrans[geom]->InvTransformPrimal(subX);
1645  lP.Mult(subX, subY);
1646  doftrans->TransformPrimal(subY);
1647  y.SetSubVector(vdofs, subY);
1648  }
1649 
1650  if (vdoftrans)
1651  {
1652  doftrans = new_doftrans;
1653  }
1654  }
1655  }
1656 }
1657 
1659 ::MultTranspose(const Vector &x, Vector &y) const
1660 {
1661  y = 0.0;
1662 
1663  Mesh* mesh_ref = fespace->GetMesh();
1664  const CoarseFineTransformations &trans_ref =
1665  mesh_ref->GetRefinementTransforms();
1666 
1667  Array<char> processed(fespace->GetVSize());
1668  processed = 0;
1669 
1670  Array<int> f_dofs, c_dofs, f_vdofs, c_vdofs, old_Fo;
1671 
1672  int rvdim = fespace->GetVDim();
1673  int old_ndofs = width / rvdim;
1674 
1675  Vector subY, subX, subYt;
1676 
1677  for (int k = 0; k < mesh_ref->GetNE(); k++)
1678  {
1679  const Embedding &emb = trans_ref.embeddings[k];
1680  const Geometry::Type geom = mesh_ref->GetElementBaseGeometry(k);
1681  const DenseMatrix &lP = localP[geom](emb.matrix);
1682 
1683  DofTransformation * doftrans = fespace->GetElementDofs(k, f_dofs);
1684  old_elem_dof->GetRow(emb.parent, c_dofs);
1685 
1686  if (!doftrans)
1687  {
1688  subY.SetSize(lP.Width());
1689 
1690  for (int vd = 0; vd < rvdim; vd++)
1691  {
1692  f_dofs.Copy(f_vdofs);
1693  fespace->DofsToVDofs(vd, f_vdofs);
1694  c_dofs.Copy(c_vdofs);
1695  fespace->DofsToVDofs(vd, c_vdofs, old_ndofs);
1696 
1697  x.GetSubVector(f_vdofs, subX);
1698 
1699  for (int p = 0; p < f_dofs.Size(); ++p)
1700  {
1701  if (processed[DecodeDof(f_dofs[p])])
1702  {
1703  subX[p] = 0.0;
1704  }
1705  }
1706 
1707  lP.MultTranspose(subX, subY);
1708  y.AddElementVector(c_vdofs, subY);
1709  }
1710  }
1711  else
1712  {
1713  subYt.SetSize(lP.Width());
1714 
1715  old_elem_fos->GetRow(emb.parent, old_Fo);
1716  old_DoFTrans[geom]->SetFaceOrientations(old_Fo);
1717 
1718  DofTransformation *new_doftrans = NULL;
1719  VDofTransformation *vdoftrans =
1720  dynamic_cast<VDofTransformation*>(doftrans);
1721  if (vdoftrans)
1722  {
1723  new_doftrans = doftrans;
1724  doftrans = vdoftrans->GetDofTransformation();
1725  }
1726 
1727  for (int vd = 0; vd < rvdim; vd++)
1728  {
1729  f_dofs.Copy(f_vdofs);
1730  fespace->DofsToVDofs(vd, f_vdofs);
1731  c_dofs.Copy(c_vdofs);
1732  fespace->DofsToVDofs(vd, c_vdofs, old_ndofs);
1733 
1734  x.GetSubVector(f_vdofs, subX);
1735  doftrans->InvTransformDual(subX);
1736  for (int p = 0; p < f_dofs.Size(); ++p)
1737  {
1738  if (processed[DecodeDof(f_dofs[p])])
1739  {
1740  subX[p] = 0.0;
1741  }
1742  }
1743 
1744  lP.MultTranspose(subX, subYt);
1745  old_DoFTrans[geom]->TransformDual(subYt);
1746  y.AddElementVector(c_vdofs, subYt);
1747  }
1748 
1749  if (vdoftrans)
1750  {
1751  doftrans = new_doftrans;
1752  }
1753  }
1754 
1755  for (int p = 0; p < f_dofs.Size(); ++p)
1756  {
1757  processed[DecodeDof(f_dofs[p])] = 1;
1758  }
1759  }
1760 }
1761 
1762 namespace internal
1763 {
1764 
1765 // Used in GetCoarseToFineMap() below.
1766 struct RefType
1767 {
1768  Geometry::Type geom;
1769  int num_children;
1770  const Pair<int,int> *children;
1771 
1772  RefType(Geometry::Type g, int n, const Pair<int,int> *c)
1773  : geom(g), num_children(n), children(c) { }
1774 
1775  bool operator<(const RefType &other) const
1776  {
1777  if (geom < other.geom) { return true; }
1778  if (geom > other.geom) { return false; }
1779  if (num_children < other.num_children) { return true; }
1780  if (num_children > other.num_children) { return false; }
1781  for (int i = 0; i < num_children; i++)
1782  {
1783  if (children[i].one < other.children[i].one) { return true; }
1784  if (children[i].one > other.children[i].one) { return false; }
1785  }
1786  return false; // everything is equal
1787  }
1788 };
1789 
1790 void GetCoarseToFineMap(const CoarseFineTransformations &cft,
1791  const mfem::Mesh &fine_mesh,
1792  Table &coarse_to_fine,
1793  Array<int> &coarse_to_ref_type,
1794  Table &ref_type_to_matrix,
1795  Array<Geometry::Type> &ref_type_to_geom)
1796 {
1797  const int fine_ne = cft.embeddings.Size();
1798  int coarse_ne = -1;
1799  for (int i = 0; i < fine_ne; i++)
1800  {
1801  coarse_ne = std::max(coarse_ne, cft.embeddings[i].parent);
1802  }
1803  coarse_ne++;
1804 
1805  coarse_to_ref_type.SetSize(coarse_ne);
1806  coarse_to_fine.SetDims(coarse_ne, fine_ne);
1807 
1808  Array<int> cf_i(coarse_to_fine.GetI(), coarse_ne+1);
1809  Array<Pair<int,int> > cf_j(fine_ne);
1810  cf_i = 0;
1811  for (int i = 0; i < fine_ne; i++)
1812  {
1813  cf_i[cft.embeddings[i].parent+1]++;
1814  }
1815  cf_i.PartialSum();
1816  MFEM_ASSERT(cf_i.Last() == cf_j.Size(), "internal error");
1817  for (int i = 0; i < fine_ne; i++)
1818  {
1819  const Embedding &e = cft.embeddings[i];
1820  cf_j[cf_i[e.parent]].one = e.matrix; // used as sort key below
1821  cf_j[cf_i[e.parent]].two = i;
1822  cf_i[e.parent]++;
1823  }
1824  std::copy_backward(cf_i.begin(), cf_i.end()-1, cf_i.end());
1825  cf_i[0] = 0;
1826  for (int i = 0; i < coarse_ne; i++)
1827  {
1828  std::sort(&cf_j[cf_i[i]], cf_j.GetData() + cf_i[i+1]);
1829  }
1830  for (int i = 0; i < fine_ne; i++)
1831  {
1832  coarse_to_fine.GetJ()[i] = cf_j[i].two;
1833  }
1834 
1835  using std::map;
1836  using std::pair;
1837 
1838  map<RefType,int> ref_type_map;
1839  for (int i = 0; i < coarse_ne; i++)
1840  {
1841  const int num_children = cf_i[i+1]-cf_i[i];
1842  MFEM_ASSERT(num_children > 0, "");
1843  const int fine_el = cf_j[cf_i[i]].two;
1844  // Assuming the coarse and the fine elements have the same geometry:
1845  const Geometry::Type geom = fine_mesh.GetElementBaseGeometry(fine_el);
1846  const RefType ref_type(geom, num_children, &cf_j[cf_i[i]]);
1847  pair<map<RefType,int>::iterator,bool> res =
1848  ref_type_map.insert(
1849  pair<const RefType,int>(ref_type, (int)ref_type_map.size()));
1850  coarse_to_ref_type[i] = res.first->second;
1851  }
1852 
1853  ref_type_to_matrix.MakeI((int)ref_type_map.size());
1854  ref_type_to_geom.SetSize((int)ref_type_map.size());
1855  for (map<RefType,int>::iterator it = ref_type_map.begin();
1856  it != ref_type_map.end(); ++it)
1857  {
1858  ref_type_to_matrix.AddColumnsInRow(it->second, it->first.num_children);
1859  ref_type_to_geom[it->second] = it->first.geom;
1860  }
1861 
1862  ref_type_to_matrix.MakeJ();
1863  for (map<RefType,int>::iterator it = ref_type_map.begin();
1864  it != ref_type_map.end(); ++it)
1865  {
1866  const RefType &rt = it->first;
1867  for (int j = 0; j < rt.num_children; j++)
1868  {
1869  ref_type_to_matrix.AddConnection(it->second, rt.children[j].one);
1870  }
1871  }
1872  ref_type_to_matrix.ShiftUpI();
1873 }
1874 
1875 } // namespace internal
1876 
1877 
1878 /// TODO: Implement DofTransformation support
1880  const FiniteElementSpace *f_fes, const FiniteElementSpace *c_fes,
1881  BilinearFormIntegrator *mass_integ)
1882  : Operator(c_fes->GetVSize(), f_fes->GetVSize()),
1883  fine_fes(f_fes)
1884 {
1885  MFEM_VERIFY(c_fes->GetOrdering() == f_fes->GetOrdering() &&
1886  c_fes->GetVDim() == f_fes->GetVDim(),
1887  "incompatible coarse and fine FE spaces");
1888 
1890  Mesh *f_mesh = f_fes->GetMesh();
1891  const CoarseFineTransformations &rtrans = f_mesh->GetRefinementTransforms();
1892 
1893  Mesh::GeometryList elem_geoms(*f_mesh);
1895  for (int gi = 0; gi < elem_geoms.Size(); gi++)
1896  {
1897  const Geometry::Type geom = elem_geoms[gi];
1898  DenseTensor &lP = localP[geom], &lM = localM[geom];
1899  const FiniteElement *fine_fe =
1900  f_fes->fec->FiniteElementForGeometry(geom);
1901  const FiniteElement *coarse_fe =
1902  c_fes->fec->FiniteElementForGeometry(geom);
1903  const DenseTensor &pmats = rtrans.point_matrices[geom];
1904 
1905  lP.SetSize(fine_fe->GetDof(), coarse_fe->GetDof(), pmats.SizeK());
1906  lM.SetSize(fine_fe->GetDof(), fine_fe->GetDof(), pmats.SizeK());
1907  emb_tr.SetIdentityTransformation(geom);
1908  for (int i = 0; i < pmats.SizeK(); i++)
1909  {
1910  emb_tr.SetPointMat(pmats(i));
1911  // Get the local interpolation matrix for this refinement type
1912  fine_fe->GetTransferMatrix(*coarse_fe, emb_tr, lP(i));
1913  // Get the local mass matrix for this refinement type
1914  mass_integ->AssembleElementMatrix(*fine_fe, emb_tr, lM(i));
1915  }
1916  }
1917 
1918  Table ref_type_to_matrix;
1919  internal::GetCoarseToFineMap(rtrans, *f_mesh, coarse_to_fine,
1920  coarse_to_ref_type, ref_type_to_matrix,
1921  ref_type_to_geom);
1922  MFEM_ASSERT(coarse_to_fine.Size() == c_fes->GetNE(), "");
1923 
1924  const int total_ref_types = ref_type_to_geom.Size();
1925  int num_ref_types[Geometry::NumGeom], num_fine_elems[Geometry::NumGeom];
1926  Array<int> ref_type_to_coarse_elem_offset(total_ref_types);
1927  ref_type_to_fine_elem_offset.SetSize(total_ref_types);
1928  std::fill(num_ref_types, num_ref_types+Geometry::NumGeom, 0);
1929  std::fill(num_fine_elems, num_fine_elems+Geometry::NumGeom, 0);
1930  for (int i = 0; i < total_ref_types; i++)
1931  {
1932  Geometry::Type g = ref_type_to_geom[i];
1933  ref_type_to_coarse_elem_offset[i] = num_ref_types[g];
1934  ref_type_to_fine_elem_offset[i] = num_fine_elems[g];
1935  num_ref_types[g]++;
1936  num_fine_elems[g] += ref_type_to_matrix.RowSize(i);
1937  }
1938  DenseTensor localPtMP[Geometry::NumGeom];
1939  for (int g = 0; g < Geometry::NumGeom; g++)
1940  {
1941  if (num_ref_types[g] == 0) { continue; }
1942  const int fine_dofs = localP[g].SizeI();
1943  const int coarse_dofs = localP[g].SizeJ();
1944  localPtMP[g].SetSize(coarse_dofs, coarse_dofs, num_ref_types[g]);
1945  localR[g].SetSize(coarse_dofs, fine_dofs, num_fine_elems[g]);
1946  }
1947  for (int i = 0; i < total_ref_types; i++)
1948  {
1949  Geometry::Type g = ref_type_to_geom[i];
1950  DenseMatrix &lPtMP = localPtMP[g](ref_type_to_coarse_elem_offset[i]);
1951  int lR_offset = ref_type_to_fine_elem_offset[i]; // offset in localR[g]
1952  const int *mi = ref_type_to_matrix.GetRow(i);
1953  const int nm = ref_type_to_matrix.RowSize(i);
1954  lPtMP = 0.0;
1955  for (int s = 0; s < nm; s++)
1956  {
1957  DenseMatrix &lP = localP[g](mi[s]);
1958  DenseMatrix &lM = localM[g](mi[s]);
1959  DenseMatrix &lR = localR[g](lR_offset+s);
1960  MultAtB(lP, lM, lR); // lR = lP^T lM
1961  AddMult(lR, lP, lPtMP); // lPtMP += lP^T lM lP
1962  }
1963  DenseMatrixInverse lPtMP_inv(lPtMP);
1964  for (int s = 0; s < nm; s++)
1965  {
1966  DenseMatrix &lR = localR[g](lR_offset+s);
1967  lPtMP_inv.Mult(lR); // lR <- (P^T M P)^{-1} P^T M
1968  }
1969  }
1970 
1971  // Make a copy of the coarse element-to-dof Table.
1972  coarse_elem_dof = new Table(c_fes->GetElementToDofTable());
1973 }
1974 
1976 {
1977  delete coarse_elem_dof;
1978 }
1979 
1981 ::Mult(const Vector &x, Vector &y) const
1982 {
1983  Array<int> c_vdofs, f_vdofs;
1984  Vector loc_x, loc_y;
1985  DenseMatrix loc_x_mat, loc_y_mat;
1986  const int fine_vdim = fine_fes->GetVDim();
1987  const int coarse_ndofs = height/fine_vdim;
1988  for (int coarse_el = 0; coarse_el < coarse_to_fine.Size(); coarse_el++)
1989  {
1990  coarse_elem_dof->GetRow(coarse_el, c_vdofs);
1991  fine_fes->DofsToVDofs(c_vdofs, coarse_ndofs);
1992  loc_y.SetSize(c_vdofs.Size());
1993  loc_y = 0.0;
1994  loc_y_mat.UseExternalData(loc_y.GetData(), c_vdofs.Size()/fine_vdim,
1995  fine_vdim);
1996  const int ref_type = coarse_to_ref_type[coarse_el];
1997  const Geometry::Type geom = ref_type_to_geom[ref_type];
1998  const int *fine_elems = coarse_to_fine.GetRow(coarse_el);
1999  const int num_fine_elems = coarse_to_fine.RowSize(coarse_el);
2000  const int lR_offset = ref_type_to_fine_elem_offset[ref_type];
2001  for (int s = 0; s < num_fine_elems; s++)
2002  {
2003  const DenseMatrix &lR = localR[geom](lR_offset+s);
2004  fine_fes->GetElementVDofs(fine_elems[s], f_vdofs);
2005  x.GetSubVector(f_vdofs, loc_x);
2006  loc_x_mat.UseExternalData(loc_x.GetData(), f_vdofs.Size()/fine_vdim,
2007  fine_vdim);
2008  AddMult(lR, loc_x_mat, loc_y_mat);
2009  }
2010  y.SetSubVector(c_vdofs, loc_y);
2011  }
2012 }
2013 
2015  DenseTensor &localR) const
2016 {
2017  const FiniteElement *fe = fec->FiniteElementForGeometry(geom);
2018 
2019  const CoarseFineTransformations &dtrans =
2021  const DenseTensor &pmats = dtrans.point_matrices[geom];
2022 
2023  const int nmat = pmats.SizeK();
2024  const int ldof = fe->GetDof();
2025 
2027  isotr.SetIdentityTransformation(geom);
2028 
2029  // calculate local restriction matrices for all refinement types
2030  localR.SetSize(ldof, ldof, nmat);
2031  for (int i = 0; i < nmat; i++)
2032  {
2033  isotr.SetPointMat(pmats(i));
2034  fe->GetLocalRestriction(isotr, localR(i));
2035  }
2036 }
2037 
2039  const Table* old_elem_dof,
2040  const Table* old_elem_fos)
2041 {
2042  /// TODO: Implement DofTransformation support
2043 
2044  MFEM_VERIFY(Nonconforming(), "Not implemented for conforming meshes.");
2045  MFEM_VERIFY(old_ndofs, "Missing previous (finer) space.");
2046  MFEM_VERIFY(ndofs <= old_ndofs, "Previous space is not finer.");
2047 
2048  Array<int> dofs, old_dofs, old_vdofs;
2049  Vector row;
2050 
2051  Mesh::GeometryList elem_geoms(*mesh);
2052 
2054  for (int i = 0; i < elem_geoms.Size(); i++)
2055  {
2056  GetLocalDerefinementMatrices(elem_geoms[i], localR[elem_geoms[i]]);
2057  }
2058 
2059  SparseMatrix *R = (elem_geoms.Size() != 1)
2060  ? new SparseMatrix(ndofs*vdim, old_ndofs*vdim) // variable row size
2061  : new SparseMatrix(ndofs*vdim, old_ndofs*vdim,
2062  localR[elem_geoms[0]].SizeI());
2063 
2064  Array<int> mark(R->Height());
2065  mark = 0;
2066 
2067  const CoarseFineTransformations &dtrans =
2069 
2070  MFEM_ASSERT(dtrans.embeddings.Size() == old_elem_dof->Size(), "");
2071 
2072  int num_marked = 0;
2073  for (int k = 0; k < dtrans.embeddings.Size(); k++)
2074  {
2075  const Embedding &emb = dtrans.embeddings[k];
2077  DenseMatrix &lR = localR[geom](emb.matrix);
2078 
2079  elem_dof->GetRow(emb.parent, dofs);
2080  old_elem_dof->GetRow(k, old_dofs);
2081 
2082  for (int vd = 0; vd < vdim; vd++)
2083  {
2084  old_dofs.Copy(old_vdofs);
2085  DofsToVDofs(vd, old_vdofs, old_ndofs);
2086 
2087  for (int i = 0; i < lR.Height(); i++)
2088  {
2089  if (!std::isfinite(lR(i, 0))) { continue; }
2090 
2091  int r = DofToVDof(dofs[i], vd);
2092  int m = (r >= 0) ? r : (-1 - r);
2093 
2094  if (!mark[m])
2095  {
2096  lR.GetRow(i, row);
2097  R->SetRow(r, old_vdofs, row);
2098  mark[m] = 1;
2099  num_marked++;
2100  }
2101  }
2102  }
2103  }
2104 
2105  MFEM_VERIFY(num_marked == R->Height(),
2106  "internal error: not all rows of R were set.");
2107 
2108  R->Finalize(); // no-op if fixed width
2109  return R;
2110 }
2111 
2113  const FiniteElementSpace &coarse_fes, Geometry::Type geom,
2114  DenseTensor &localP) const
2115 {
2116  // Assumptions: see the declaration of the method.
2117 
2118  const FiniteElement *fine_fe = fec->FiniteElementForGeometry(geom);
2119  const FiniteElement *coarse_fe =
2120  coarse_fes.fec->FiniteElementForGeometry(geom);
2121 
2123  const DenseTensor &pmats = rtrans.point_matrices[geom];
2124 
2125  int nmat = pmats.SizeK();
2126 
2128  isotr.SetIdentityTransformation(geom);
2129 
2130  // Calculate the local interpolation matrices for all refinement types
2131  localP.SetSize(fine_fe->GetDof(), coarse_fe->GetDof(), nmat);
2132  for (int i = 0; i < nmat; i++)
2133  {
2134  isotr.SetPointMat(pmats(i));
2135  fine_fe->GetTransferMatrix(*coarse_fe, isotr, localP(i));
2136  }
2137 }
2138 
2140  const FiniteElementCollection *fec_,
2141  int vdim_, int ordering_)
2142 {
2143  mesh = mesh_;
2144  fec = fec_;
2145  vdim = vdim_;
2146  ordering = (Ordering::Type) ordering_;
2147 
2148  elem_dof = NULL;
2149  elem_fos = NULL;
2150  face_dof = NULL;
2151 
2152  sequence = 0;
2153  orders_changed = false;
2154  relaxed_hp = false;
2155 
2157 
2158  const NURBSFECollection *nurbs_fec =
2159  dynamic_cast<const NURBSFECollection *>(fec_);
2160  if (nurbs_fec)
2161  {
2162  MFEM_VERIFY(mesh_->NURBSext, "NURBS FE space requires a NURBS mesh.");
2163 
2164  if (NURBSext_ == NULL)
2165  {
2166  NURBSext = mesh_->NURBSext;
2167  own_ext = 0;
2168  }
2169  else
2170  {
2171  NURBSext = NURBSext_;
2172  own_ext = 1;
2173  }
2174  UpdateNURBS();
2175  cP = cR = cR_hp = NULL;
2176  cP_is_set = false;
2177 
2179  }
2180  else
2181  {
2182  NURBSext = NULL;
2183  own_ext = 0;
2184  Construct();
2185  }
2186 
2188 }
2189 
2191 {
2192  DestroyDoFTrans();
2193 
2196  for (int i=0; i<DoFTrans.Size(); i++)
2197  {
2198  DoFTrans[i] = NULL;
2199  }
2200  if (mesh->Dimension() < 3) { return; }
2201  if (dynamic_cast<const ND_FECollection*>(fec))
2202  {
2203  const FiniteElement * nd_tri =
2205  if (nd_tri)
2206  {
2208  new ND_TriDofTransformation(nd_tri->GetOrder());
2209  }
2210 
2211  const FiniteElement * nd_tet =
2213  if (nd_tet)
2214  {
2216  new ND_TetDofTransformation(nd_tet->GetOrder());
2217  }
2218 
2219  const FiniteElement * nd_pri =
2221  if (nd_pri)
2222  {
2224  new ND_WedgeDofTransformation(nd_pri->GetOrder());
2225  }
2226  }
2227 }
2228 
2230 {
2231  if (NURBSext && !own_ext)
2232  {
2233  mfem_error("FiniteElementSpace::StealNURBSext");
2234  }
2235  own_ext = 0;
2236 
2237  return NURBSext;
2238 }
2239 
2241 {
2242  MFEM_VERIFY(NURBSext, "NURBSExt not defined.");
2243 
2244  nvdofs = 0;
2245  nedofs = 0;
2246  nfdofs = 0;
2247  nbdofs = 0;
2248  bdofs = NULL;
2249 
2250  delete face_dof;
2251  face_dof = NULL;
2253 
2254  dynamic_cast<const NURBSFECollection *>(fec)->Reset();
2255 
2256  ndofs = NURBSext->GetNDof();
2259 
2261  sequence++;
2262 }
2263 
2265 {
2266  if (face_dof) { return; }
2267 
2268  const int dim = mesh->Dimension();
2269 
2270  // Find bdr to face mapping
2272  face_to_be = -1;
2273  for (int b = 0; b < GetNBE(); b++)
2274  {
2275  int f = mesh->GetBdrElementEdgeIndex(b);
2276  face_to_be[f] = b;
2277  }
2278 
2279  // Loop over faces in correct order, to prevent a sort
2280  // Sort will destroy orientation info in ordering of dofs
2281  Array<Connection> face_dof_list;
2282  Array<int> row;
2283  for (int f = 0; f < GetNF(); f++)
2284  {
2285  int b = face_to_be[f];
2286  if (b == -1) { continue; }
2287  // FIXME: this assumes that the boundary element and the face element have
2288  // the same orientation.
2289  if (dim > 1)
2290  {
2291  const Element *fe = mesh->GetFace(f);
2292  const Element *be = mesh->GetBdrElement(b);
2293  const int nv = be->GetNVertices();
2294  const int *fv = fe->GetVertices();
2295  const int *bv = be->GetVertices();
2296  for (int i = 0; i < nv; i++)
2297  {
2298  MFEM_VERIFY(fv[i] == bv[i],
2299  "non-matching face and boundary elements detected!");
2300  }
2301  }
2302  GetBdrElementDofs(b, row);
2303  Connection conn(f,0);
2304  for (int i = 0; i < row.Size(); i++)
2305  {
2306  conn.to = row[i];
2307  face_dof_list.Append(conn);
2308  }
2309  }
2310  face_dof = new Table(GetNF(), face_dof_list);
2311 }
2312 
2314 {
2315  // This method should be used only for non-NURBS spaces.
2316  MFEM_VERIFY(!NURBSext, "internal error");
2317 
2318  // Variable order space needs a nontrivial P matrix + also ghost elements
2319  // in parallel, we thus require the mesh to be NC.
2320  MFEM_VERIFY(!IsVariableOrder() || Nonconforming(),
2321  "Variable order space requires a nonconforming mesh.");
2322 
2323  elem_dof = NULL;
2324  elem_fos = NULL;
2325  bdr_elem_dof = NULL;
2326  bdr_elem_fos = NULL;
2327  face_dof = NULL;
2328 
2329  ndofs = 0;
2330  nvdofs = nedofs = nfdofs = nbdofs = 0;
2331  bdofs = NULL;
2332 
2333  cP = NULL;
2334  cR = NULL;
2335  cR_hp = NULL;
2336  cP_is_set = false;
2337  // 'Th' is initialized/destroyed before this method is called.
2338 
2339  int dim = mesh->Dimension();
2340  int order = fec->GetOrder();
2341 
2342  MFEM_VERIFY((mesh->GetNumGeometries(dim) > 0) || (mesh->GetNE() == 0),
2343  "Mesh was not correctly finalized.");
2344 
2345  bool mixed_elements = (mesh->GetNumGeometries(dim) > 1);
2346  bool mixed_faces = (dim > 2 && mesh->GetNumGeometries(2) > 1);
2347 
2348  Array<VarOrderBits> edge_orders, face_orders;
2349  if (IsVariableOrder())
2350  {
2351  // for variable order spaces, calculate orders of edges and faces
2352  CalcEdgeFaceVarOrders(edge_orders, face_orders);
2353  }
2354  else if (mixed_faces)
2355  {
2356  // for mixed faces we also create the var_face_dofs table, see below
2357  face_orders.SetSize(mesh->GetNFaces());
2358  face_orders = (VarOrderBits(1) << order);
2359  }
2360 
2361  // assign vertex DOFs
2362  if (mesh->GetNV())
2363  {
2364  nvdofs = mesh->GetNV() * fec->GetNumDof(Geometry::POINT, order);
2365  }
2366 
2367  // assign edge DOFs
2368  if (mesh->GetNEdges())
2369  {
2370  if (IsVariableOrder())
2371  {
2372  nedofs = MakeDofTable(1, edge_orders, var_edge_dofs, &var_edge_orders);
2373  }
2374  else
2375  {
2376  // the simple case: all edges are of the same order
2378  }
2379  }
2380 
2381  // assign face DOFs
2382  if (mesh->GetNFaces())
2383  {
2384  if (IsVariableOrder() || mixed_faces)
2385  {
2386  // NOTE: for simplicity, we also use Table var_face_dofs for mixed faces
2387  nfdofs = MakeDofTable(2, face_orders, var_face_dofs,
2388  IsVariableOrder() ? &var_face_orders : NULL);
2389  uni_fdof = -1;
2390  }
2391  else
2392  {
2393  // the simple case: all faces are of the same geometry and order
2394  uni_fdof = fec->GetNumDof(mesh->GetFaceGeometry(0), order);
2395  nfdofs = mesh->GetNFaces() * uni_fdof;
2396  }
2397  }
2398 
2399  // assign internal ("bubble") DOFs
2400  if (mesh->GetNE() && dim > 0)
2401  {
2402  if (IsVariableOrder() || mixed_elements)
2403  {
2404  bdofs = new int[mesh->GetNE()+1];
2405  bdofs[0] = 0;
2406  for (int i = 0; i < mesh->GetNE(); i++)
2407  {
2408  int p = GetElementOrderImpl(i);
2410  bdofs[i+1] = nbdofs;
2411  }
2412  }
2413  else
2414  {
2415  // the simple case: all elements are the same
2416  bdofs = NULL;
2418  nbdofs = mesh->GetNE() * fec->GetNumDof(geom, order);
2419  }
2420  }
2421 
2422  ndofs = nvdofs + nedofs + nfdofs + nbdofs;
2423 
2425 
2426  // record the current mesh sequence number to detect refinement etc.
2428 
2429  // increment our sequence number to let GridFunctions know they need updating
2430  sequence++;
2431 
2432  // DOFs are now assigned according to current element orders
2433  orders_changed = false;
2434 
2435  // Do not build elem_dof Table here: in parallel it has to be constructed
2436  // later.
2437 }
2438 
2440 {
2441  MFEM_ASSERT(bits != 0, "invalid bit mask");
2442  for (int order = 0; bits != 0; order++, bits >>= 1)
2443  {
2444  if (bits & 1) { return order; }
2445  }
2446  return 0;
2447 }
2448 
2449 void FiniteElementSpace
2451  Array<VarOrderBits> &face_orders) const
2452 {
2453  MFEM_ASSERT(IsVariableOrder(), "");
2454  MFEM_ASSERT(Nonconforming(), "");
2455  MFEM_ASSERT(elem_order.Size() == mesh->GetNE(), "");
2456 
2457  edge_orders.SetSize(mesh->GetNEdges()); edge_orders = 0;
2458  face_orders.SetSize(mesh->GetNFaces()); face_orders = 0;
2459 
2460  // Calculate initial edge/face orders, as required by incident elements.
2461  // For each edge/face we accumulate in a bit-mask the orders of elements
2462  // sharing the edge/face.
2463  Array<int> E, F, ori;
2464  for (int i = 0; i < mesh->GetNE(); i++)
2465  {
2466  int order = elem_order[i];
2467  MFEM_ASSERT(order <= MaxVarOrder, "");
2468  VarOrderBits mask = (VarOrderBits(1) << order);
2469 
2470  mesh->GetElementEdges(i, E, ori);
2471  for (int j = 0; j < E.Size(); j++)
2472  {
2473  edge_orders[E[j]] |= mask;
2474  }
2475 
2476  if (mesh->Dimension() > 2)
2477  {
2478  mesh->GetElementFaces(i, F, ori);
2479  for (int j = 0; j < F.Size(); j++)
2480  {
2481  face_orders[F[j]] |= mask;
2482  }
2483  }
2484  }
2485 
2486  if (relaxed_hp)
2487  {
2488  // for relaxed conformity we don't need the masters to match the minimum
2489  // orders of the slaves, we can stop now
2490  return;
2491  }
2492 
2493  // Iterate while minimum orders propagate by master/slave relations
2494  // (and new orders also propagate from faces to incident edges).
2495  // See https://github.com/mfem/mfem/pull/1423#issuecomment-638930559
2496  // for an illustration of why this is necessary in hp meshes.
2497  bool done;
2498  do
2499  {
2500  done = true;
2501 
2502  // propagate from slave edges to master edges
2503  const NCMesh::NCList &edge_list = mesh->ncmesh->GetEdgeList();
2504  for (const NCMesh::Master &master : edge_list.masters)
2505  {
2506  VarOrderBits slave_orders = 0;
2507  for (int i = master.slaves_begin; i < master.slaves_end; i++)
2508  {
2509  slave_orders |= edge_orders[edge_list.slaves[i].index];
2510  }
2511 
2512  int min_order = MinOrder(slave_orders);
2513  if (min_order < MinOrder(edge_orders[master.index]))
2514  {
2515  edge_orders[master.index] |= (VarOrderBits(1) << min_order);
2516  done = false;
2517  }
2518  }
2519 
2520  // propagate from slave faces(+edges) to master faces(+edges)
2521  const NCMesh::NCList &face_list = mesh->ncmesh->GetFaceList();
2522  for (const NCMesh::Master &master : face_list.masters)
2523  {
2524  VarOrderBits slave_orders = 0;
2525  for (int i = master.slaves_begin; i < master.slaves_end; i++)
2526  {
2527  const NCMesh::Slave &slave = face_list.slaves[i];
2528  if (slave.index >= 0)
2529  {
2530  slave_orders |= face_orders[slave.index];
2531 
2532  mesh->GetFaceEdges(slave.index, E, ori);
2533  for (int j = 0; j < E.Size(); j++)
2534  {
2535  slave_orders |= edge_orders[E[j]];
2536  }
2537  }
2538  else
2539  {
2540  // degenerate face (i.e., edge-face constraint)
2541  slave_orders |= edge_orders[-1 - slave.index];
2542  }
2543  }
2544 
2545  int min_order = MinOrder(slave_orders);
2546  if (min_order < MinOrder(face_orders[master.index]))
2547  {
2548  face_orders[master.index] |= (VarOrderBits(1) << min_order);
2549  done = false;
2550  }
2551  }
2552 
2553  // make sure edges support (new) orders required by incident faces
2554  for (int i = 0; i < mesh->GetNFaces(); i++)
2555  {
2556  mesh->GetFaceEdges(i, E, ori);
2557  for (int j = 0; j < E.Size(); j++)
2558  {
2559  edge_orders[E[j]] |= face_orders[i];
2560  }
2561  }
2562  }
2563  while (!done);
2564 }
2565 
2567  const Array<int> &entity_orders,
2568  Table &entity_dofs,
2569  Array<char> *var_ent_order)
2570 {
2571  // The tables var_edge_dofs and var_face_dofs hold DOF assignments for edges
2572  // and faces of a variable order space, in which each edge/face may host
2573  // several DOF sets, called DOF set variants. Example: an edge 'i' shared by
2574  // 4 hexes of orders 2, 3, 4, 5 will hold four DOF sets, each starting at
2575  // indices e.g. 100, 101, 103, 106, respectively. These numbers are stored
2576  // in row 'i' of var_edge_dofs. Variant zero is always the lowest order DOF
2577  // set, followed by consecutive ranges of higher order DOFs. Variable order
2578  // faces are handled similarly by var_face_dofs, which holds at most two DOF
2579  // set variants per face. The tables are empty for constant-order spaces.
2580 
2581  int num_ent = entity_orders.Size();
2582  int total_dofs = 0;
2583 
2584  Array<Connection> list;
2585  list.Reserve(2*num_ent);
2586 
2587  if (var_ent_order)
2588  {
2589  var_ent_order->SetSize(0);
2590  var_ent_order->Reserve(num_ent);
2591  }
2592 
2593  // assign DOFs according to order bit masks
2594  for (int i = 0; i < num_ent; i++)
2595  {
2596  auto geom = (ent_dim == 1) ? Geometry::SEGMENT : mesh->GetFaceGeometry(i);
2597 
2598  VarOrderBits bits = entity_orders[i];
2599  for (int order = 0; bits != 0; order++, bits >>= 1)
2600  {
2601  if (bits & 1)
2602  {
2603  int dofs = fec->GetNumDof(geom, order);
2604  list.Append(Connection(i, total_dofs));
2605  total_dofs += dofs;
2606 
2607  if (var_ent_order) { var_ent_order->Append(order); }
2608  }
2609  }
2610  }
2611 
2612  // append a dummy row as terminator
2613  list.Append(Connection(num_ent, total_dofs));
2614 
2615  // build the table
2616  entity_dofs.MakeFromList(num_ent+1, list);
2617 
2618  return total_dofs;
2619 }
2620 
2621 int FiniteElementSpace::FindDofs(const Table &var_dof_table,
2622  int row, int ndof) const
2623 {
2624  const int *beg = var_dof_table.GetRow(row);
2625  const int *end = var_dof_table.GetRow(row + 1); // terminator, see above
2626 
2627  while (beg < end)
2628  {
2629  // return the appropriate range of DOFs
2630  if ((beg[1] - beg[0]) == ndof) { return beg[0]; }
2631  beg++;
2632  }
2633 
2634  MFEM_ABORT("DOFs not found for ndof = " << ndof);
2635  return 0;
2636 }
2637 
2638 int FiniteElementSpace::GetEdgeOrder(int edge, int variant) const
2639 {
2640  if (!IsVariableOrder()) { return fec->GetOrder(); }
2641 
2642  const int* beg = var_edge_dofs.GetRow(edge);
2643  const int* end = var_edge_dofs.GetRow(edge + 1);
2644  if (variant >= end - beg) { return -1; } // past last variant
2645 
2646  return var_edge_orders[var_edge_dofs.GetI()[edge] + variant];
2647 }
2648 
2649 int FiniteElementSpace::GetFaceOrder(int face, int variant) const
2650 {
2651  if (!IsVariableOrder())
2652  {
2653  // face order can be different from fec->GetOrder()
2654  Geometry::Type geom = mesh->GetFaceGeometry(face);
2655  return fec->FiniteElementForGeometry(geom)->GetOrder();
2656  }
2657 
2658  const int* beg = var_face_dofs.GetRow(face);
2659  const int* end = var_face_dofs.GetRow(face + 1);
2660  if (variant >= end - beg) { return -1; } // past last variant
2661 
2662  return var_face_orders[var_face_dofs.GetI()[face] + variant];
2663 }
2664 
2665 int FiniteElementSpace::GetNVariants(int entity, int index) const
2666 {
2667  MFEM_ASSERT(IsVariableOrder(), "");
2668  const Table &dof_table = (entity == 1) ? var_edge_dofs : var_face_dofs;
2669 
2670  MFEM_ASSERT(index >= 0 && index < dof_table.Size(), "");
2671  return dof_table.GetRow(index + 1) - dof_table.GetRow(index);
2672 }
2673 
2674 static const char* msg_orders_changed =
2675  "Element orders changed, you need to Update() the space first.";
2676 
2679 {
2680  MFEM_VERIFY(!orders_changed, msg_orders_changed);
2681 
2682  if (elem_dof)
2683  {
2684  elem_dof->GetRow(elem, dofs);
2685 
2686  if (DoFTrans[mesh->GetElementBaseGeometry(elem)])
2687  {
2688  Array<int> Fo;
2689  elem_fos -> GetRow (elem, Fo);
2690  DoFTrans[mesh->GetElementBaseGeometry(elem)]->SetFaceOrientations(Fo);
2691  }
2692  return DoFTrans[mesh->GetElementBaseGeometry(elem)];
2693  }
2694 
2695  Array<int> V, E, Eo, F, Fo; // TODO: LocalArray
2696 
2697  int dim = mesh->Dimension();
2698  auto geom = mesh->GetElementGeometry(elem);
2699  int order = GetElementOrderImpl(elem);
2700 
2701  int nv = fec->GetNumDof(Geometry::POINT, order);
2702  int ne = (dim > 1) ? fec->GetNumDof(Geometry::SEGMENT, order) : 0;
2703  int nb = (dim > 0) ? fec->GetNumDof(geom, order) : 0;
2704 
2705  if (nv) { mesh->GetElementVertices(elem, V); }
2706  if (ne) { mesh->GetElementEdges(elem, E, Eo); }
2707 
2708  int nfd = 0;
2709  if (dim > 2 && fec->HasFaceDofs(geom, order))
2710  {
2711  mesh->GetElementFaces(elem, F, Fo);
2712  for (int i = 0; i < F.Size(); i++)
2713  {
2714  nfd += fec->GetNumDof(mesh->GetFaceGeometry(F[i]), order);
2715  }
2716  if (DoFTrans[mesh->GetElementBaseGeometry(elem)])
2717  {
2719  -> SetFaceOrientations(Fo);
2720  }
2721  }
2722 
2723  dofs.SetSize(0);
2724  dofs.Reserve(nv*V.Size() + ne*E.Size() + nfd + nb);
2725 
2726  if (nv) // vertex DOFs
2727  {
2728  for (int i = 0; i < V.Size(); i++)
2729  {
2730  for (int j = 0; j < nv; j++)
2731  {
2732  dofs.Append(V[i]*nv + j);
2733  }
2734  }
2735  }
2736 
2737  if (ne) // edge DOFs
2738  {
2739  for (int i = 0; i < E.Size(); i++)
2740  {
2741  int ebase = IsVariableOrder() ? FindEdgeDof(E[i], ne) : E[i]*ne;
2742  const int *ind = fec->GetDofOrdering(Geometry::SEGMENT, order, Eo[i]);
2743 
2744  for (int j = 0; j < ne; j++)
2745  {
2746  dofs.Append(EncodeDof(nvdofs + ebase, ind[j]));
2747  }
2748  }
2749  }
2750 
2751  if (nfd) // face DOFs
2752  {
2753  for (int i = 0; i < F.Size(); i++)
2754  {
2755  auto fgeom = mesh->GetFaceGeometry(F[i]);
2756  int nf = fec->GetNumDof(fgeom, order);
2757 
2758  int fbase = (var_face_dofs.Size() > 0) ? FindFaceDof(F[i], nf) : F[i]*nf;
2759  const int *ind = fec->GetDofOrdering(fgeom, order, Fo[i]);
2760 
2761  for (int j = 0; j < nf; j++)
2762  {
2763  dofs.Append(EncodeDof(nvdofs + nedofs + fbase, ind[j]));
2764  }
2765  }
2766  }
2767 
2768  if (nb) // interior ("bubble") DOFs
2769  {
2770  int bbase = bdofs ? bdofs[elem] : elem*nb;
2771  bbase += nvdofs + nedofs + nfdofs;
2772 
2773  for (int j = 0; j < nb; j++)
2774  {
2775  dofs.Append(bbase + j);
2776  }
2777  }
2778  return DoFTrans[mesh->GetElementBaseGeometry(elem)];
2779 }
2780 
2782 {
2783  if (i < 0 || !mesh->GetNE()) { return NULL; }
2784  MFEM_VERIFY(i < mesh->GetNE(),
2785  "Invalid element id " << i << ", maximum allowed " << mesh->GetNE()-1);
2786 
2787  const FiniteElement *FE =
2789 
2790  if (NURBSext)
2791  {
2792  NURBSext->LoadFE(i, FE);
2793  }
2794  else
2795  {
2796 #ifdef MFEM_DEBUG
2797  // consistency check: fec->GetOrder() and FE->GetOrder() should return
2798  // the same value (for standard, constant-order spaces)
2799  if (!IsVariableOrder() && FE->GetDim() > 0)
2800  {
2801  MFEM_ASSERT(FE->GetOrder() == fec->GetOrder(),
2802  "internal error: " <<
2803  FE->GetOrder() << " != " << fec->GetOrder());
2804  }
2805 #endif
2806  }
2807 
2808  return FE;
2809 }
2810 
2813 {
2814  MFEM_VERIFY(!orders_changed, msg_orders_changed);
2815 
2816  if (bdr_elem_dof)
2817  {
2818  bdr_elem_dof->GetRow(bel, dofs);
2819 
2821  {
2822  Array<int> Fo;
2823  bdr_elem_fos -> GetRow (bel, Fo);
2825  SetFaceOrientations(Fo);
2826  }
2827  return DoFTrans[mesh->GetBdrElementBaseGeometry(bel)];
2828  }
2829 
2830  Array<int> V, E, Eo, Fo; // TODO: LocalArray
2831  int F, oF;
2832 
2833  int dim = mesh->Dimension();
2834  auto geom = mesh->GetBdrElementGeometry(bel);
2835  int order = fec->GetOrder();
2836 
2837  if (IsVariableOrder()) // determine order from adjacent element
2838  {
2839  int elem, info;
2840  mesh->GetBdrElementAdjacentElement(bel, elem, info);
2841  order = elem_order[elem];
2842  }
2843 
2844  int nv = fec->GetNumDof(Geometry::POINT, order);
2845  int ne = (dim > 1) ? fec->GetNumDof(Geometry::SEGMENT, order) : 0;
2846  int nf = (dim > 2) ? fec->GetNumDof(geom, order) : 0;
2847 
2848  if (nv) { mesh->GetBdrElementVertices(bel, V); }
2849  if (ne) { mesh->GetBdrElementEdges(bel, E, Eo); }
2850  if (nf)
2851  {
2852  mesh->GetBdrElementFace(bel, &F, &oF);
2853 
2855  {
2856  Fo.Append(oF);
2858  SetFaceOrientations(Fo);
2859  }
2860  }
2861 
2862  dofs.SetSize(0);
2863  dofs.Reserve(nv*V.Size() + ne*E.Size() + nf);
2864 
2865  if (nv) // vertex DOFs
2866  {
2867  for (int i = 0; i < V.Size(); i++)
2868  {
2869  for (int j = 0; j < nv; j++)
2870  {
2871  dofs.Append(V[i]*nv + j);
2872  }
2873  }
2874  }
2875 
2876  if (ne) // edge DOFs
2877  {
2878  for (int i = 0; i < E.Size(); i++)
2879  {
2880  int ebase = IsVariableOrder() ? FindEdgeDof(E[i], ne) : E[i]*ne;
2881  const int *ind = fec->GetDofOrdering(Geometry::SEGMENT, order, Eo[i]);
2882 
2883  for (int j = 0; j < ne; j++)
2884  {
2885  dofs.Append(EncodeDof(nvdofs + ebase, ind[j]));
2886  }
2887  }
2888  }
2889 
2890  if (nf) // face DOFs
2891  {
2892  int fbase = (var_face_dofs.Size() > 0) ? FindFaceDof(F, nf) : F*nf;
2893  const int *ind = fec->GetDofOrdering(geom, order, oF);
2894 
2895  for (int j = 0; j < nf; j++)
2896  {
2897  dofs.Append(EncodeDof(nvdofs + nedofs + fbase, ind[j]));
2898  }
2899  }
2900 
2901  return DoFTrans[mesh->GetBdrElementBaseGeometry(bel)];
2902 }
2903 
2905  int variant) const
2906 {
2907  MFEM_VERIFY(!orders_changed, msg_orders_changed);
2908 
2909  // If face_dof is already built, use it.
2910  // If it is not and we have a NURBS space, build the face_dof and use it.
2911  if ((face_dof && variant == 0) ||
2912  (NURBSext && (BuildNURBSFaceToDofTable(), true)))
2913  {
2914  face_dof->GetRow(face, dofs);
2915  return fec->GetOrder();
2916  }
2917 
2918  int order, nf, fbase;
2919  int dim = mesh->Dimension();
2920  auto fgeom = (dim > 2) ? mesh->GetFaceGeometry(face) : Geometry::INVALID;
2921 
2922  if (var_face_dofs.Size() > 0) // variable orders or *mixed* faces
2923  {
2924  const int* beg = var_face_dofs.GetRow(face);
2925  const int* end = var_face_dofs.GetRow(face + 1);
2926  if (variant >= end - beg) { return -1; } // past last face DOFs
2927 
2928  fbase = beg[variant];
2929  nf = beg[variant+1] - fbase;
2930 
2931  order = !IsVariableOrder() ? fec->GetOrder() :
2932  var_face_orders[var_face_dofs.GetI()[face] + variant];
2933  MFEM_ASSERT(fec->GetNumDof(fgeom, order) == nf, "");
2934  }
2935  else
2936  {
2937  if (variant > 0) { return -1; }
2938  order = fec->GetOrder();
2939  nf = (dim > 2) ? fec->GetNumDof(fgeom, order) : 0;
2940  fbase = face*nf;
2941  }
2942 
2943  // for 1D, 2D and 3D faces
2944  int nv = fec->GetNumDof(Geometry::POINT, order);
2945  int ne = (dim > 1) ? fec->GetNumDof(Geometry::SEGMENT, order) : 0;
2946 
2947  Array<int> V, E, Eo;
2948  if (nv) { mesh->GetFaceVertices(face, V); }
2949  if (ne) { mesh->GetFaceEdges(face, E, Eo); }
2950 
2951  dofs.SetSize(0);
2952  dofs.Reserve(V.Size() * nv + E.Size() * ne + nf);
2953 
2954  if (nv) // vertex DOFs
2955  {
2956  for (int i = 0; i < V.Size(); i++)
2957  {
2958  for (int j = 0; j < nv; j++)
2959  {
2960  dofs.Append(V[i]*nv + j);
2961  }
2962  }
2963  }
2964  if (ne) // edge DOFs
2965  {
2966  for (int i = 0; i < E.Size(); i++)
2967  {
2968  int ebase = IsVariableOrder() ? FindEdgeDof(E[i], ne) : E[i]*ne;
2969  const int *ind = fec->GetDofOrdering(Geometry::SEGMENT, order, Eo[i]);
2970 
2971  for (int j = 0; j < ne; j++)
2972  {
2973  dofs.Append(EncodeDof(nvdofs + ebase, ind[j]));
2974  }
2975  }
2976  }
2977  for (int j = 0; j < nf; j++)
2978  {
2979  dofs.Append(nvdofs + nedofs + fbase + j);
2980  }
2981 
2982  return order;
2983 }
2984 
2986  int variant) const
2987 {
2988  MFEM_VERIFY(!orders_changed, msg_orders_changed);
2989 
2990  int order, ne, base;
2991  if (IsVariableOrder())
2992  {
2993  const int* beg = var_edge_dofs.GetRow(edge);
2994  const int* end = var_edge_dofs.GetRow(edge + 1);
2995  if (variant >= end - beg) { return -1; } // past last edge DOFs
2996 
2997  base = beg[variant];
2998  ne = beg[variant+1] - base;
2999 
3000  order = var_edge_orders[var_edge_dofs.GetI()[edge] + variant];
3001  MFEM_ASSERT(fec->GetNumDof(Geometry::SEGMENT, order) == ne, "");
3002  }
3003  else
3004  {
3005  if (variant > 0) { return -1; }
3006  order = fec->GetOrder();
3007  ne = fec->GetNumDof(Geometry::SEGMENT, order);
3008  base = edge*ne;
3009  }
3010 
3011  Array<int> V; // TODO: LocalArray
3012  int nv = fec->GetNumDof(Geometry::POINT, order);
3013  if (nv) { mesh->GetEdgeVertices(edge, V); }
3014 
3015  dofs.SetSize(0);
3016  dofs.Reserve(2*nv + ne);
3017 
3018  for (int i = 0; i < 2; i++)
3019  {
3020  for (int j = 0; j < nv; j++)
3021  {
3022  dofs.Append(V[i]*nv + j);
3023  }
3024  }
3025  for (int j = 0; j < ne; j++)
3026  {
3027  dofs.Append(nvdofs + base + j);
3028  }
3029 
3030  return order;
3031 }
3032 
3034 {
3035  int nv = fec->DofForGeometry(Geometry::POINT);
3036  dofs.SetSize(nv);
3037  for (int j = 0; j < nv; j++)
3038  {
3039  dofs[j] = i*nv+j;
3040  }
3041 }
3042 
3044 {
3045  MFEM_VERIFY(!orders_changed, msg_orders_changed);
3046 
3048  int base = bdofs ? bdofs[i] : i*nb;
3049 
3050  dofs.SetSize(nb);
3051  base += nvdofs + nedofs + nfdofs;
3052  for (int j = 0; j < nb; j++)
3053  {
3054  dofs[j] = base + j;
3055  }
3056 }
3057 
3059 {
3060  return fec->GetNumDof(mesh->GetElementGeometry(i),
3061  GetElementOrderImpl(i));
3062 }
3063 
3065 {
3066  MFEM_VERIFY(!IsVariableOrder(), "not implemented");
3067 
3069  dofs.SetSize (ne);
3070  for (int j = 0, k = nvdofs+i*ne; j < ne; j++, k++)
3071  {
3072  dofs[j] = k;
3073  }
3074 }
3075 
3077 {
3078  MFEM_VERIFY(!IsVariableOrder(), "not implemented");
3079 
3080  int nf, base;
3081  if (var_face_dofs.Size() > 0) // mixed faces
3082  {
3083  base = var_face_dofs.GetRow(i)[0];
3084  nf = var_face_dofs.GetRow(i)[1] - base;
3085  }
3086  else
3087  {
3088  auto geom = mesh->GetFaceGeometry(0);
3089  nf = fec->GetNumDof(geom, fec->GetOrder());
3090  base = i*nf;
3091  }
3092 
3093  dofs.SetSize(nf);
3094  for (int j = 0; j < nf; j++)
3095  {
3096  dofs[j] = nvdofs + nedofs + base + j;
3097  }
3098 }
3099 
3101 {
3102  int order = fec->GetOrder();
3103 
3104  if (IsVariableOrder()) // determine order from adjacent element
3105  {
3106  int elem, info;
3107  mesh->GetBdrElementAdjacentElement(i, elem, info);
3108  order = elem_order[elem];
3109  }
3110 
3111  const FiniteElement *BE;
3112  switch (mesh->Dimension())
3113  {
3114  case 1:
3115  BE = fec->GetFE(Geometry::POINT, order);
3116  break;
3117  case 2:
3118  BE = fec->GetFE(Geometry::SEGMENT, order);
3119  break;
3120  case 3:
3121  default:
3122  BE = fec->GetFE(mesh->GetBdrElementBaseGeometry(i), order);
3123  }
3124 
3125  if (NURBSext)
3126  {
3127  NURBSext->LoadBE(i, BE);
3128  }
3129 
3130  return BE;
3131 }
3132 
3134 {
3135  MFEM_VERIFY(!IsVariableOrder(), "not implemented");
3136 
3137  const FiniteElement *fe;
3138  switch (mesh->Dimension())
3139  {
3140  case 1:
3142  break;
3143  case 2:
3145  break;
3146  case 3:
3147  default:
3149  }
3150 
3151  if (NURBSext)
3152  {
3153  // Ensure 'face_to_be' is built:
3154  if (!face_dof) { BuildNURBSFaceToDofTable(); }
3155  MFEM_ASSERT(face_to_be[i] >= 0,
3156  "NURBS mesh: only boundary faces are supported!");
3157  NURBSext->LoadBE(face_to_be[i], fe);
3158  }
3159 
3160  return fe;
3161 }
3162 
3164  int variant) const
3165 {
3166  MFEM_ASSERT(mesh->Dimension() > 1, "No edges with mesh dimension < 2");
3167 
3168  int eo = IsVariableOrder() ? GetEdgeOrder(i, variant) : fec->GetOrder();
3169  return fec->GetFE(Geometry::SEGMENT, eo);
3170 }
3171 
3173 ::GetTraceElement(int i, Geometry::Type geom_type) const
3174 {
3175  return fec->TraceFiniteElementForGeometry(geom_type);
3176 }
3177 
3179 {
3180  Destroy();
3181 }
3182 
3184 {
3185  delete cR;
3186  delete cR_hp;
3187  delete cP;
3188  Th.Clear();
3189  L2E_nat.Clear();
3190  L2E_lex.Clear();
3191  for (int i = 0; i < E2Q_array.Size(); i++)
3192  {
3193  delete E2Q_array[i];
3194  }
3195  E2Q_array.SetSize(0);
3196  for (auto &x : L2F)
3197  {
3198  delete x.second;
3199  }
3200  for (int i = 0; i < E2IFQ_array.Size(); i++)
3201  {
3202  delete E2IFQ_array[i];
3203  }
3204  E2IFQ_array.SetSize(0);
3205  for (int i = 0; i < E2BFQ_array.Size(); i++)
3206  {
3207  delete E2BFQ_array[i];
3208  }
3209  E2BFQ_array.SetSize(0);
3210 
3211  DestroyDoFTrans();
3212 
3215 
3216  if (NURBSext)
3217  {
3218  if (own_ext) { delete NURBSext; }
3219  delete face_dof;
3221  }
3222  else
3223  {
3224  delete elem_dof;
3225  delete elem_fos;
3226  delete bdr_elem_dof;
3227  delete bdr_elem_fos;
3228  delete face_dof;
3229 
3230  delete [] bdofs;
3231  }
3233 }
3234 
3236 {
3237  for (int i = 0; i < DoFTrans.Size(); i++)
3238  {
3239  delete DoFTrans[i];
3240  }
3241  DoFTrans.SetSize(0);
3242 }
3243 
3245  const FiniteElementSpace &coarse_fes, OperatorHandle &T) const
3246 {
3247  // Assumptions: see the declaration of the method.
3248 
3249  if (T.Type() == Operator::MFEM_SPARSEMAT)
3250  {
3251  Mesh::GeometryList elem_geoms(*mesh);
3252 
3254  for (int i = 0; i < elem_geoms.Size(); i++)
3255  {
3256  GetLocalRefinementMatrices(coarse_fes, elem_geoms[i],
3257  localP[elem_geoms[i]]);
3258  }
3259  T.Reset(RefinementMatrix_main(coarse_fes.GetNDofs(),
3260  coarse_fes.GetElementToDofTable(),
3261  coarse_fes.
3263  localP));
3264  }
3265  else
3266  {
3267  T.Reset(new RefinementOperator(this, &coarse_fes));
3268  }
3269 }
3270 
3272  const FiniteElementSpace &coarse_fes, OperatorHandle &T) const
3273 {
3274  const SparseMatrix *coarse_P = coarse_fes.GetConformingProlongation();
3275 
3276  Operator::Type req_type = T.Type();
3277  GetTransferOperator(coarse_fes, T);
3278 
3279  if (req_type == Operator::MFEM_SPARSEMAT)
3280  {
3282  {
3283  T.Reset(mfem::Mult(*cR, *T.As<SparseMatrix>()));
3284  }
3285  if (coarse_P)
3286  {
3287  T.Reset(mfem::Mult(*T.As<SparseMatrix>(), *coarse_P));
3288  }
3289  }
3290  else
3291  {
3292  const int RP_case = bool(GetConformingRestriction()) + 2*bool(coarse_P);
3293  if (RP_case == 0) { return; }
3294  const bool owner = T.OwnsOperator();
3295  T.SetOperatorOwner(false);
3296  switch (RP_case)
3297  {
3298  case 1:
3299  T.Reset(new ProductOperator(cR, T.Ptr(), false, owner));
3300  break;
3301  case 2:
3302  T.Reset(new ProductOperator(T.Ptr(), coarse_P, owner, false));
3303  break;
3304  case 3:
3306  cR, T.Ptr(), coarse_P, false, owner, false));
3307  break;
3308  }
3309  }
3310 }
3311 
3313 {
3315 
3316  Array<char> new_order(mesh->GetNE());
3317  switch (mesh->GetLastOperation())
3318  {
3319  case Mesh::REFINE:
3320  {
3321  for (int i = 0; i < mesh->GetNE(); i++)
3322  {
3323  new_order[i] = elem_order[cf_tr.embeddings[i].parent];
3324  }
3325  break;
3326  }
3327  default:
3328  MFEM_ABORT("not implemented yet");
3329  }
3330 
3331  mfem::Swap(elem_order, new_order);
3332 }
3333 
3334 void FiniteElementSpace::Update(bool want_transform)
3335 {
3336  if (!orders_changed)
3337  {
3338  if (mesh->GetSequence() == mesh_sequence)
3339  {
3340  return; // mesh and space are in sync, no-op
3341  }
3342  if (want_transform && mesh->GetSequence() != mesh_sequence + 1)
3343  {
3344  MFEM_ABORT("Error in update sequence. Space needs to be updated after "
3345  "each mesh modification.");
3346  }
3347  }
3348  else
3349  {
3350  if (mesh->GetSequence() != mesh_sequence)
3351  {
3352  MFEM_ABORT("Updating space after both mesh change and element order "
3353  "change is not supported. Please update separately after "
3354  "each change.");
3355  }
3356  }
3357 
3358  if (NURBSext)
3359  {
3360  UpdateNURBS();
3361  return;
3362  }
3363 
3364  Table* old_elem_dof = NULL;
3365  Table* old_elem_fos = NULL;
3366  int old_ndofs;
3367  bool old_orders_changed = orders_changed;
3368 
3369  // save old DOF table
3370  if (want_transform)
3371  {
3372  old_elem_dof = elem_dof;
3373  old_elem_fos = elem_fos;
3374  elem_dof = NULL;
3375  elem_fos = NULL;
3376  old_ndofs = ndofs;
3377  }
3378 
3379  // update the 'elem_order' array if the mesh has changed
3381  {
3383  }
3384 
3385  Destroy(); // calls Th.Clear()
3386  Construct();
3388 
3389  if (want_transform)
3390  {
3391  MFEM_VERIFY(!old_orders_changed, "Interpolation for element order change "
3392  "is not implemented yet, sorry.");
3393 
3394  // calculate appropriate GridFunction transformation
3395  switch (mesh->GetLastOperation())
3396  {
3397  case Mesh::REFINE:
3398  {
3399  if (Th.Type() != Operator::MFEM_SPARSEMAT)
3400  {
3401  Th.Reset(new RefinementOperator(this, old_elem_dof,
3402  old_elem_fos, old_ndofs));
3403  // The RefinementOperator takes ownership of 'old_elem_dof', so
3404  // we no longer own it:
3405  old_elem_dof = NULL;
3406  old_elem_fos = NULL;
3407  }
3408  else
3409  {
3410  // calculate fully assembled matrix
3411  Th.Reset(RefinementMatrix(old_ndofs, old_elem_dof,
3412  old_elem_fos));
3413  }
3414  break;
3415  }
3416 
3417  case Mesh::DEREFINE:
3418  {
3420  Th.Reset(DerefinementMatrix(old_ndofs, old_elem_dof, old_elem_fos));
3421  if (cP && cR)
3422  {
3423  Th.SetOperatorOwner(false);
3425  false, false, true));
3426  }
3427  break;
3428  }
3429 
3430  default:
3431  break;
3432  }
3433 
3434  delete old_elem_dof;
3435  delete old_elem_fos;
3436  }
3437 }
3438 
3440 {
3441  mesh = new_mesh;
3442 }
3443 
3444 void FiniteElementSpace::Save(std::ostream &os) const
3445 {
3446  int fes_format = 90; // the original format, v0.9
3447  bool nurbs_unit_weights = false;
3448 
3449  // Determine the format that should be used.
3450  if (!NURBSext)
3451  {
3452  // TODO: if this is a variable-order FE space, use fes_format = 100.
3453  }
3454  else
3455  {
3456  const NURBSFECollection *nurbs_fec =
3457  dynamic_cast<const NURBSFECollection *>(fec);
3458  MFEM_VERIFY(nurbs_fec, "invalid FE collection");
3459  nurbs_fec->SetOrder(NURBSext->GetOrder());
3460  const double eps = 5e-14;
3461  nurbs_unit_weights = (NURBSext->GetWeights().Min() >= 1.0-eps &&
3462  NURBSext->GetWeights().Max() <= 1.0+eps);
3464  (NURBSext != mesh->NURBSext && !nurbs_unit_weights) ||
3465  (NURBSext->GetMaster().Size() != 0 ))
3466  {
3467  fes_format = 100; // v1.0 format
3468  }
3469  }
3470 
3471  os << (fes_format == 90 ?
3472  "FiniteElementSpace\n" : "MFEM FiniteElementSpace v1.0\n")
3473  << "FiniteElementCollection: " << fec->Name() << '\n'
3474  << "VDim: " << vdim << '\n'
3475  << "Ordering: " << ordering << '\n';
3476 
3477  if (fes_format == 100) // v1.0
3478  {
3479  if (!NURBSext)
3480  {
3481  // TODO: this is a variable-order FE space --> write 'element_orders'.
3482  }
3483  else if (NURBSext != mesh->NURBSext)
3484  {
3486  {
3487  os << "NURBS_order\n" << NURBSext->GetOrder() << '\n';
3488  }
3489  else
3490  {
3491  os << "NURBS_orders\n";
3492  // 1 = do not write the size, just the entries:
3493  NURBSext->GetOrders().Save(os, 1);
3494  }
3495  // If periodic BCs are given, write connectivity
3496  if (NURBSext->GetMaster().Size() != 0 )
3497  {
3498  os <<"NURBS_periodic\n";
3499  NURBSext->GetMaster().Save(os);
3500  NURBSext->GetSlave().Save(os);
3501  }
3502  // If the weights are not unit, write them to the output:
3503  if (!nurbs_unit_weights)
3504  {
3505  os << "NURBS_weights\n";
3506  NURBSext->GetWeights().Print(os, 1);
3507  }
3508  }
3509  os << "End: MFEM FiniteElementSpace v1.0\n";
3510  }
3511 }
3512 
3514 {
3515  string buff;
3516  int fes_format = 0, ord;
3517  FiniteElementCollection *r_fec;
3518 
3519  Destroy();
3520 
3521  input >> std::ws;
3522  getline(input, buff); // 'FiniteElementSpace'
3523  filter_dos(buff);
3524  if (buff == "FiniteElementSpace") { fes_format = 90; /* v0.9 */ }
3525  else if (buff == "MFEM FiniteElementSpace v1.0") { fes_format = 100; }
3526  else { MFEM_ABORT("input stream is not a FiniteElementSpace!"); }
3527  getline(input, buff, ' '); // 'FiniteElementCollection:'
3528  input >> std::ws;
3529  getline(input, buff);
3530  filter_dos(buff);
3531  r_fec = FiniteElementCollection::New(buff.c_str());
3532  getline(input, buff, ' '); // 'VDim:'
3533  input >> vdim;
3534  getline(input, buff, ' '); // 'Ordering:'
3535  input >> ord;
3536 
3537  NURBSFECollection *nurbs_fec = dynamic_cast<NURBSFECollection*>(r_fec);
3538  NURBSExtension *nurbs_ext = NULL;
3539  if (fes_format == 90) // original format, v0.9
3540  {
3541  if (nurbs_fec)
3542  {
3543  MFEM_VERIFY(m->NURBSext, "NURBS FE collection requires a NURBS mesh!");
3544  const int order = nurbs_fec->GetOrder();
3545  if (order != m->NURBSext->GetOrder() &&
3547  {
3548  nurbs_ext = new NURBSExtension(m->NURBSext, order);
3549  }
3550  }
3551  }
3552  else if (fes_format == 100) // v1.0
3553  {
3554  while (1)
3555  {
3556  skip_comment_lines(input, '#');
3557  MFEM_VERIFY(input.good(), "error reading FiniteElementSpace v1.0");
3558  getline(input, buff);
3559  filter_dos(buff);
3560  if (buff == "NURBS_order" || buff == "NURBS_orders")
3561  {
3562  MFEM_VERIFY(nurbs_fec,
3563  buff << ": NURBS FE collection is required!");
3564  MFEM_VERIFY(m->NURBSext, buff << ": NURBS mesh is required!");
3565  MFEM_VERIFY(!nurbs_ext, buff << ": order redefinition!");
3566  if (buff == "NURBS_order")
3567  {
3568  int order;
3569  input >> order;
3570  nurbs_ext = new NURBSExtension(m->NURBSext, order);
3571  }
3572  else
3573  {
3574  Array<int> orders;
3575  orders.Load(m->NURBSext->GetNKV(), input);
3576  nurbs_ext = new NURBSExtension(m->NURBSext, orders);
3577  }
3578  }
3579  else if (buff == "NURBS_periodic")
3580  {
3581  Array<int> master, slave;
3582  master.Load(input);
3583  slave.Load(input);
3584  nurbs_ext->ConnectBoundaries(master,slave);
3585  }
3586  else if (buff == "NURBS_weights")
3587  {
3588  MFEM_VERIFY(nurbs_ext, "NURBS_weights: NURBS_orders have to be "
3589  "specified before NURBS_weights!");
3590  nurbs_ext->GetWeights().Load(input, nurbs_ext->GetNDof());
3591  }
3592  else if (buff == "element_orders")
3593  {
3594  MFEM_VERIFY(!nurbs_fec, "section element_orders cannot be used "
3595  "with a NURBS FE collection");
3596  MFEM_ABORT("element_orders: not implemented yet!");
3597  }
3598  else if (buff == "End: MFEM FiniteElementSpace v1.0")
3599  {
3600  break;
3601  }
3602  else
3603  {
3604  MFEM_ABORT("unknown section: " << buff);
3605  }
3606  }
3607  }
3608 
3609  Constructor(m, nurbs_ext, r_fec, vdim, ord);
3610 
3611  return r_fec;
3612 }
3613 
3614 } // namespace mfem
SparseMatrix * RefinementMatrix(int old_ndofs, const Table *old_elem_dof, const Table *old_elem_fos)
Definition: fespace.cpp:1474
Abstract class for all finite elements.
Definition: fe_base.hpp:235
int GetOrder() const
Get the order of the NURBS collection: either a positive number, when using fixed order...
Definition: fe_coll.hpp:638
VDofTransformation VDoFTrans
Definition: fespace.hpp:152
Arbitrary order non-uniform rational B-splines (NURBS) finite elements.
Definition: fe_coll.hpp:606
Ordering::Type GetOrdering() const
Return the ordering method.
Definition: fespace.hpp:599
int Size() const
Return the logical size of the array.
Definition: array.hpp:138
int RowSize(const int i) const
Returns the number of elements in row i.
Definition: sparsemat.cpp:344
void SetSubVector(const Array< int > &dofs, const double value)
Set the entries listed in dofs to the given value.
Definition: vector.cpp:573
int GetVSize() const
Return the number of vector dofs, i.e. GetNDofs() x GetVDim().
Definition: fespace.hpp:587
void GetVertexVDofs(int i, Array< int > &vdofs) const
Definition: fespace.cpp:324
OpType * As() const
Return the Operator pointer statically cast to a specified OpType. Similar to the method Get()...
Definition: handle.hpp:104
const Vector & GetWeights() const
Definition: nurbs.hpp:386
SparseMatrix * RefinementMatrix_main(const int coarse_ndofs, const Table &coarse_elem_dof, const Table *coarse_elem_fos, const DenseTensor localP[]) const
Definition: fespace.cpp:1387
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:53
int GetNDofs() const
Returns number of degrees of freedom.
Definition: fespace.hpp:584
const FiniteElement * GetFE(Geometry::Type geom, int p) const
Variable order version of FiniteElementForGeometry().
Definition: fe_coll.hpp:165
int * GetJ()
Definition: table.hpp:114
int ndofs
Number of degrees of freedom. Number of unknowns is ndofs * vdim.
Definition: fespace.hpp:119
Class for an integration rule - an Array of IntegrationPoint.
Definition: intrules.hpp:90
int * bdofs
internal DOFs of elements if mixed/var-order; NULL otherwise
Definition: fespace.hpp:127
const Array< int > & GetMaster() const
Definition: nurbs.hpp:329
void GetElementInteriorVDofs(int i, Array< int > &vdofs) const
Definition: fespace.cpp:330
int DofToVDof(int dof, int vd, int ndofs=-1) const
Definition: fespace.cpp:251
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:5954
const SparseMatrix * GetConformingProlongation() const
The returned SparseMatrix is owned by the FiniteElementSpace.
Definition: fespace.cpp:1232
static void AddDependencies(SparseMatrix &deps, Array< int > &master_dofs, Array< int > &slave_dofs, DenseMatrix &I, int skipfirst=0)
Definition: fespace.cpp:758
const CoarseFineTransformations & GetDerefinementTransforms()
Definition: ncmesh.cpp:4401
virtual void Update(bool want_transform=true)
Reflect changes in the mesh: update number of DOFs, etc. Also, calculate GridFunction transformation ...
Definition: fespace.cpp:3334
void SetSize(int dim, int connections_per_row)
Set the size and the number of connections for the table.
Definition: table.cpp:124
bool IsVariableOrder() const
Returns true if the space contains elements of varying polynomial orders.
Definition: fespace.hpp:463
void LoadBE(int i, const FiniteElement *BE) const
Definition: nurbs.cpp:2934
void GetEdgeVertices(int i, Array< int > &vert) const
Returns the indices of the vertices of edge i.
Definition: mesh.cpp:6016
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:2038
Operator that extracts Face degrees of freedom for H1 FiniteElementSpaces.
void BuildElementToDofTable() const
Definition: fespace.cpp:342
void AddColumnsInRow(int r, int ncol)
Definition: table.hpp:78
int MakeDofTable(int ent_dim, const Array< int > &entity_orders, Table &entity_dofs, Array< char > *var_ent_order)
Definition: fespace.cpp:2566
void BuildNURBSFaceToDofTable() const
Generates partial face_dof table for a NURBS space.
Definition: fespace.cpp:2264
const FiniteElement * GetEdgeElement(int i, int variant=0) const
Returns pointer to the FiniteElement in the FiniteElementCollection associated with i&#39;th edge in the ...
Definition: fespace.cpp:3163
void MakeI(int nrows)
Next 7 methods are used together with the default constructor.
Definition: table.cpp:81
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:125
virtual void GetVertices(Array< int > &v) const =0
Returns element&#39;s vertices.
DerefinementOperator(const FiniteElementSpace *f_fes, const FiniteElementSpace *c_fes, BilinearFormIntegrator *mass_integ)
TODO: Implement DofTransformation support.
Definition: fespace.cpp:1879
Field is discontinuous across element interfaces.
Definition: fe_coll.hpp:48
static const int NumGeom
Definition: geom.hpp:42
Array< Slave > slaves
Definition: ncmesh.hpp:231
const FiniteElement * GetTraceElement(int i, Geometry::Type geom_type) const
Return the trace element from element &#39;i&#39; to the given &#39;geom_type&#39;.
Definition: fespace.cpp:3173
virtual void Finalize(int skip_zeros=1)
Finalize the matrix initialization, switching the storage format from LIL to CSR. ...
Definition: sparsemat.hpp:545
void GetBdrElementFace(int i, int *f, int *o) const
Return the index and the orientation of the face of bdr element i. (3D)
Definition: mesh.cpp:6171
int GetNumGeometries(int dim) const
Return the number of geometries of the given dimension present in the mesh.
Definition: mesh.cpp:5908
void SetSize(int s)
Resize the vector to size s.
Definition: vector.hpp:513
int GetNBE() const
Returns number of boundary elements.
Definition: mesh.hpp:926
Ordering::Type ordering
Definition: fespace.hpp:116
virtual DofTransformation * GetBdrElementDofs(int bel, Array< int > &dofs) const
Returns indices of degrees of freedom for boundary element &#39;bel&#39;.
Definition: fespace.cpp:2812
void SetElementOrder(int i, int p)
Sets the order of the i&#39;th finite element.
Definition: fespace.cpp:151
int * GetRowColumns(const int row)
Return a pointer to the column indices in a row.
Definition: sparsemat.cpp:391
static int DecodeDof(int dof)
Helpers to remove encoded sign from a DOF.
Definition: fespace.hpp:262
const T * HostRead() const
Shortcut for mfem::Read(a.GetMemory(), a.Size(), false).
Definition: array.hpp:308
void BooleanMult(const Array< int > &x, Array< int > &y) const
y = A * x, treating all entries as booleans (zero=false, nonzero=true).
Definition: sparsemat.cpp:1022
Lists all edges/faces in the nonconforming mesh.
Definition: ncmesh.hpp:227
void Mult(const Table &A, const Table &B, Table &C)
C = A * B (as boolean matrices)
Definition: table.cpp:475
int Width() const
Get the width (size of input) of the Operator. Synonym with NumCols().
Definition: operator.hpp:73
int SizeK() const
Definition: densemat.hpp:1001
static int MinOrder(VarOrderBits bits)
Return the minimum order (least significant bit set) in the bit mask.
Definition: fespace.cpp:2439
Pointer to an Operator of a specified type.
Definition: handle.hpp:33
Operator::Type Type() const
Get the currently set operator type id.
Definition: handle.hpp:99
virtual const FiniteElement * FiniteElementForGeometry(Geometry::Type GeomType) const =0
static constexpr int MaxVarOrder
Definition: fespace.hpp:221
void Copy(Array &copy) const
Create a copy of the internal array to the provided copy.
Definition: array.hpp:856
unsigned matrix
index into NCList::point_matrices[geom]
Definition: ncmesh.hpp:217
void GetSubVector(const Array< int > &dofs, Vector &elemvect) const
Extract entries listed in dofs to the output Vector elemvect.
Definition: vector.cpp:547
int GetNKV() const
Definition: nurbs.hpp:355
int GetOrder() const
Returns the order of the finite element. In the case of anisotropic orders, returns the maximum order...
Definition: fe_base.hpp:327
virtual 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:495
void GetFaceVertices(int i, Array< int > &vert) const
Returns the indices of the vertices of face i.
Definition: mesh.hpp:1127
Data type dense matrix using column-major storage.
Definition: densemat.hpp:23
int vdim
Vector dimension (number of unknowns per degree of freedom).
Definition: fespace.hpp:111
Geometry::Type Geom() const
Definition: ncmesh.hpp:194
void GetRow(int i, Array< int > &row) const
Return row i in array row (the Table must be finalized)
Definition: table.cpp:187
OperatorHandle L2E_lex
Definition: fespace.hpp:168
int GetNumElementInteriorDofs(int i) const
Definition: fespace.cpp:3058
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:40
int GetElementOrder(int i) const
Returns the order of the i&#39;th finite element.
Definition: fespace.cpp:178
int GetBdrAttribute(int i) const
Definition: fespace.hpp:661
Operator that extracts face degrees of freedom for L2 nonconforming spaces.
int GetBdrElementEdgeIndex(int i) const
Definition: mesh.cpp:6194
const SparseMatrix * GetHpConformingRestriction() const
The returned SparseMatrix is owned by the FiniteElementSpace.
Definition: fespace.cpp:1246
virtual void GetEssentialTrueDofs(const Array< int > &bdr_attr_is_ess, Array< int > &ess_tdof_list, int component=-1)
Get a list of essential true dofs, ess_tdof_list, corresponding to the boundary attributes marked in ...
Definition: fespace.cpp:564
int GetNE() const
Returns number of elements.
Definition: mesh.hpp:923
const Element * GetFace(int i) const
Definition: mesh.hpp:1048
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:2985
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:106
T Sum()
Return the sum of all the array entries using the &#39;+&#39;&#39; operator for class &#39;T&#39;.
Definition: array.cpp:115
MFEM_DEPRECATED void RebuildElementToDofTable()
(
Definition: fespace.cpp:431
Geometry::Type GetFaceBaseGeometry(int i) const
Definition: mesh.hpp:1066
bool operator<(const Pair< A, B > &p, const Pair< A, B > &q)
Comparison operator for class Pair, based on the first element only.
Definition: sort_pairs.hpp:36
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:1659
const FiniteElement * GetFaceElement(int i) const
Returns pointer to the FiniteElement in the FiniteElementCollection associated with i&#39;th face in the ...
Definition: fespace.cpp:3133
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, defined on a coarse mesh, to this FE space, defined on a refined mesh.
Definition: fespace.cpp:3271
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:783
FiniteElementCollection * Load(Mesh *m, std::istream &input)
Read a FiniteElementSpace from a stream. The returned FiniteElementCollection is owned by the caller...
Definition: fespace.cpp:3513
void AddRow(const int row, const Array< int > &cols, const Vector &srow)
Definition: sparsemat.cpp:3018
double * GetRowEntries(const int row)
Return a pointer to the entries in a row.
Definition: sparsemat.cpp:405
double * GetData() const
Return a pointer to the beginning of the Vector data.
Definition: vector.hpp:209
virtual void CopyProlongationAndRestriction(const FiniteElementSpace &fes, const Array< int > *perm)
Copies the prolongation and restriction matrices from fes.
Definition: fespace.cpp:100
const FiniteElementCollection * fec
Associated FE collection (not owned).
Definition: fespace.hpp:108
OperatorHandle Th
Transformation to apply to GridFunctions after space Update().
Definition: fespace.hpp:165
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:2904
Geometry::Type GetElementBaseGeometry(int i) const
Definition: mesh.hpp:1069
int Size_of_connections() const
Definition: table.hpp:98
void GetLocalDerefinementMatrices(Geometry::Type geom, DenseTensor &localR) const
Definition: fespace.cpp:2014
Geometry::Type GetBdrElementGeometry(int i) const
Definition: mesh.hpp:1060
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
void DeleteAll()
Delete the whole array.
Definition: array.hpp:846
int GetNDof() const
Definition: nurbs.hpp:365
void BooleanMultTranspose(const Array< int > &x, Array< int > &y) const
y = At * x, treating all entries as booleans (zero=false, nonzero=true).
Definition: sparsemat.cpp:1052
int GetOrder() const
Return the order (polynomial degree) of the FE collection, corresponding to the order/degree returned...
Definition: fe_coll.hpp:199
void AddConnections(int r, const int *c, int nc)
Definition: table.cpp:104
std::uint64_t VarOrderBits
Bit-mask representing a set of orders needed by an edge/face.
Definition: fespace.hpp:220
const NCList & GetFaceList()
Return the current list of conforming and nonconforming faces.
Definition: ncmesh.hpp:253
Array< int > dof_elem_array
Definition: fespace.hpp:145
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:598
DofTransformation * GetBdrElementVDofs(int i, Array< int > &vdofs) const
Returns indexes of degrees of freedom for i&#39;th boundary element.
Definition: fespace.cpp:297
void GetFaceInteriorDofs(int i, Array< int > &dofs) const
Definition: fespace.cpp:3076
virtual int DofForGeometry(Geometry::Type GeomType) const =0
virtual void UpdateMeshPointer(Mesh *new_mesh)
Definition: fespace.cpp:3439
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:638
const IntegrationRule * IntRule
Not owned.
int GetNumFaces() const
Return the number of faces (3D), edges (2D) or vertices (1D).
Definition: mesh.cpp:5376
int uni_fdof
of single face DOFs if all faces uniform; -1 otherwise
Definition: fespace.hpp:126
const SparseMatrix * GetConformingRestriction() const
The returned SparseMatrix is owned by the FiniteElementSpace.
Definition: fespace.cpp:1239
Geometry::Type GetGeomType() const
Returns the Geometry::Type of the reference element.
Definition: fe_base.hpp:320
ID for class SparseMatrix.
Definition: operator.hpp:259
const Array< int > & GetSlave() const
Definition: nurbs.hpp:331
virtual void Mult(const Vector &x, Vector &y) const
Operator application: y=A(x).
Definition: fespace.cpp:1981
void Load(std::istream **in, int np, int *dim)
Reads a vector from multiple files.
Definition: vector.cpp:57
int GetNE() const
Returns number of elements in the mesh.
Definition: fespace.hpp:614
void Set(const int i, const int j, const double val)
Definition: sparsemat.cpp:2764
long GetSequence() const
Definition: mesh.hpp:1664
void GetVertexDofs(int i, Array< int > &dofs) const
Definition: fespace.cpp:3033
void SetPointMat(const DenseMatrix &pm)
Set the underlying point matrix describing the transformation.
Definition: eltrans.hpp:401
void MultTranspose(const double *x, double *y) const
Multiply a vector with the transpose matrix.
Definition: densemat.cpp:201
General product operator: x -&gt; (A*B)(x) = A(B(x)).
Definition: operator.hpp:747
FaceType
Definition: mesh.hpp:45
void BuildBdrElementToDofTable() const
Definition: fespace.cpp:383
int HasFaceDofs(Geometry::Type geom, int p) const
Definition: fe_coll.cpp:25
ID for the base class Operator, i.e. any type.
Definition: operator.hpp:258
OpType * Is() const
Return the Operator pointer dynamically cast to a specified OpType.
Definition: handle.hpp:108
int FindFaceDof(int face, int ndof) const
Similar to FindEdgeDof, but used for mixed meshes too.
Definition: fespace.hpp:248
DofTransformation * GetElementVDofs(int i, Array< int > &vdofs) const
Returns indexes of degrees of freedom in array dofs for i&#39;th element.
Definition: fespace.cpp:281
int GetFaceOrder(int face, int variant=0) const
Returns the polynomial degree of the i&#39;th face finite element.
Definition: fespace.cpp:2649
double f(const Vector &xvec)
Definition: lor_mms.hpp:32
virtual int GetRow(const int row, Array< int > &cols, Vector &srow) const
Extract all column indices and values from a given row.
Definition: sparsemat.cpp:2931
Array< DofTransformation * > DoFTrans
Definition: fespace.hpp:151
virtual void Mult(const Vector &x, Vector &y) const
Operator application: y=A(x).
Definition: fespace.cpp:1586
void AddMult(const DenseMatrix &b, const DenseMatrix &c, DenseMatrix &a)
Matrix matrix multiplication. A += B * C.
Definition: densemat.cpp:2408
int GetNBE() const
Returns number of boundary elements in the mesh.
Definition: fespace.hpp:623
void MakeFromList(int nrows, const Array< Connection > &list)
Definition: table.cpp:279
bool orders_changed
True if at least one element order changed (variable-order space only).
Definition: fespace.hpp:197
DenseTensor point_matrices[Geometry::NumGeom]
Definition: ncmesh.hpp:77
Data type sparse matrix.
Definition: sparsemat.hpp:50
int Height() const
Get the height (size of output) of the Operator. Synonym with NumRows().
Definition: operator.hpp:67
int FindEdgeDof(int edge, int ndof) const
Definition: fespace.hpp:244
unsigned matrix
Definition: ncmesh.hpp:58
int Append(const T &el)
Append element &#39;el&#39; to array, resize if necessary.
Definition: array.hpp:751
Mesh * GetMesh() const
Returns the mesh.
Definition: fespace.hpp:441
Array< char > elem_order
Definition: fespace.hpp:123
Operator that extracts Face degrees of freedom for L2 spaces.
void GetVDofs(int vd, Array< int > &dofs, int ndofs=-1) const
Returns the indices of all of the VDofs for the specified dimension &#39;vd&#39;.
Definition: fespace.cpp:195
void mfem_error(const char *msg)
Function called when an error is encountered. Used by the macros MFEM_ABORT, MFEM_ASSERT, MFEM_VERIFY.
Definition: error.cpp:154
A class that performs interpolation from an E-vector to quadrature point values and/or derivatives (Q...
void SetDofTransformation(DofTransformation &doftrans)
Set or change the nested DofTransformation object.
Definition: doftrans.hpp:175
double b
Definition: lissajous.cpp:42
Type
Ordering methods:
Definition: fespace.hpp:33
SparseMatrix * cR
Conforming restriction matrix such that cR.cP=I.
Definition: fespace.hpp:159
void GetRow(int r, Vector &row) const
Definition: densemat.cpp:1276
const IntegrationRule * IntRule
Not owned.
SparseMatrix * D2Const_GlobalRestrictionMatrix(FiniteElementSpace *cfes)
Generate the global restriction matrix from a discontinuous FE space to the piecewise constant FE spa...
Definition: fespace.cpp:679
static const int NumVerts[NumGeom]
Definition: geom.hpp:49
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:647
A pair of objects.
Definition: sort_pairs.hpp:23
void GetBoundaryTrueDofs(Array< int > &boundary_dofs, int component=-1)
Get a list of all boundary true dofs, boundary_dofs. For spaces with &#39;vdim&#39; &gt; 1, the &#39;component&#39; param...
Definition: fespace.cpp:582
T Max() const
Find the maximal element in the array, using the comparison operator &lt; for class T.
Definition: array.cpp:68
void BuildConformingInterpolation() const
Calculate the cP and cR matrices for a nonconforming mesh.
Definition: fespace.cpp:928
Geometry::Type GetFaceGeometry(int i) const
Definition: mesh.hpp:1050
NURBSExtension * StealNURBSext()
Definition: fespace.cpp:2229
Array< DenseMatrix * > point_matrices[Geometry::NumGeom]
List of unique point matrices for each slave geometry.
Definition: ncmesh.hpp:234
void Reserve(int capacity)
Ensures that the allocated size is at least the given size.
Definition: array.hpp:156
Array< Embedding > embeddings
Fine element positions in their parents.
Definition: ncmesh.hpp:73
virtual const FiniteElement * TraceFiniteElementForGeometry(Geometry::Type GeomType) const
Definition: fe_coll.hpp:71
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:6206
bool IsDGSpace() const
Return whether or not the space is discontinuous (L2)
Definition: fespace.hpp:925
Array< int > dof_ldof_array
Definition: fespace.hpp:145
void SetSize(int i, int j, int k, MemoryType mt_=MemoryType::PRESERVE)
Definition: densemat.hpp:1005
const Array< int > & GetOrders() const
Read-only access to the orders of all knot vectors.
Definition: nurbs.hpp:350
bool Conforming() const
Definition: fespace.hpp:447
SparseMatrix * cP
Definition: fespace.hpp:157
int GetVDim() const
Returns vector dimension.
Definition: fespace.hpp:581
int Size() const
Returns the number of TYPE I elements.
Definition: table.hpp:92
const int * GetDofOrdering(Geometry::Type geom, int p, int ori) const
Variable order version of DofOrderForOrientation().
Definition: fe_coll.hpp:189
int GetNF() const
Returns number of faces (i.e. co-dimension 1 entities) in the mesh.
Definition: fespace.hpp:620
int Dimension() const
Definition: mesh.hpp:1006
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:258
virtual const FaceRestriction * GetFaceRestriction(ElementDofOrdering e_ordering, FaceType, L2FaceValues mul=L2FaceValues::DoubleValued) const
Return an Operator that converts L-vectors to E-vectors on each face.
Definition: fespace.cpp:1292
virtual void GetBoundaryClosure(const Array< int > &bdr_attr_is_ess, Array< int > &bdr_vertices, Array< int > &bdr_edges)
Definition: ncmesh.cpp:4966
Array< QuadratureInterpolator * > E2Q_array
Definition: fespace.hpp:184
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:639
A class that performs interpolation from a face E-vector to quadrature point values and/or derivative...
int GetNumBorderDofs(Geometry::Type geom, int order) const
Definition: fespace.cpp:894
Operator * Ptr() const
Access the underlying Operator pointer.
Definition: handle.hpp:87
void Add(const int i, const int j, const double val)
Definition: sparsemat.cpp:2783
Abstract base class that defines an interface for element restrictions.
Definition: restriction.hpp:25
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:903
OperatorHandle L2E_nat
The element restriction operators, see GetElementRestriction().
Definition: fespace.hpp:168
virtual DofTransformation * GetElementDofs(int elem, Array< int > &dofs) const
Returns indices of degrees of freedom of element &#39;elem&#39;.
Definition: fespace.cpp:2678
int GetNumDof(Geometry::Type geom, int p) const
Variable order version of DofForGeometry().
Definition: fe_coll.hpp:177
int slaves_end
slave faces
Definition: ncmesh.hpp:205
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:3244
int SizeI() const
Definition: densemat.hpp:999
void GetElementInteriorDofs(int i, Array< int > &dofs) const
Definition: fespace.cpp:3043
void GetLocalRefinementMatrices(Geometry::Type geom, DenseTensor &localP) const
Definition: fespace.cpp:1451
int GetOrder() const
If all orders are identical, return that number. Otherwise, return NURBSFECollection::VariableOrder.
Definition: nurbs.hpp:353
List of mesh geometries stored as Array&lt;Geometry::Type&gt;.
Definition: mesh.hpp:1092
DoF transformation implementation for the Nedelec basis on triangles.
Definition: doftrans.hpp:232
double Min() const
Returns the minimal element of the vector.
Definition: vector.cpp:1202
Type
Enumeration defining IDs for some classes derived from Operator.
Definition: operator.hpp:256
Abstract base class BilinearFormIntegrator.
Definition: bilininteg.hpp:35
void Swap(Array< T > &, Array< T > &)
Definition: array.hpp:630
Array< int > bdr_attributes
A list of all unique boundary attributes used by the Mesh.
Definition: mesh.hpp:270
void LoadFE(int i, const FiniteElement *FE) const
Definition: nurbs.cpp:2913
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:3363
void SetIdentityTransformation(Geometry::Type GeomType)
Set the FiniteElement Geometry for the reference elements being used.
Definition: eltrans.cpp:383
ComplexDenseMatrix * MultAtB(const ComplexDenseMatrix &A, const ComplexDenseMatrix &B)
Multiply the complex conjugate transpose of a matrix A with a matrix B. A^H*B.
Operator that converts FiniteElementSpace L-vectors to E-vectors.
Definition: restriction.hpp:36
void Print(std::ostream &out=mfem::out, int width=8) const
Prints vector to stream out.
Definition: vector.cpp:724
Nonconforming edge/face within a bigger edge/face.
Definition: ncmesh.hpp:214
Class FiniteElementSpace - responsible for providing FEM view of the mesh, mainly managing the set of...
Definition: fespace.hpp:96
int GetDof() const
Returns the number of degrees of freedom in the finite element.
Definition: fe_base.hpp:323
virtual ~FiniteElementSpace()
Definition: fespace.cpp:3178
bool OwnsOperator() const
Return true if the OperatorHandle owns the held Operator.
Definition: handle.hpp:117
virtual void AssembleElementMatrix(const FiniteElement &el, ElementTransformation &Trans, DenseMatrix &elmat)
Given a particular Finite Element computes the element matrix elmat.
Definition: bilininteg.cpp:123
Collection of finite elements from the same family in multiple dimensions. This class is used to matc...
Definition: fe_coll.hpp:26
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:710
virtual void TransformPrimal(double *v) const =0
void SetSize(int nsize)
Change the logical size of the array, keep existing entries.
Definition: array.hpp:679
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
void Transpose(const Table &A, Table &At, int ncols_A_)
Transpose a Table.
Definition: table.cpp:413
RefinementOperator(const FiniteElementSpace *fespace, Table *old_elem_dof, Table *old_elem_fos, int old_ndofs)
Definition: fespace.cpp:1494
void SetVDim(int vdim)
Set or change the vdim parameter.
Definition: doftrans.hpp:162
Array< char > var_face_orders
Definition: fespace.hpp:136
void Clear()
Clear the OperatorHandle, deleting the held Operator (if owned), while leaving the type id unchanged...
Definition: handle.hpp:124
Helper struct for defining a connectivity table, see Table::MakeFromList.
Definition: table.hpp:27
void Mult(const double *x, double *y) const
Matrix vector multiplication with the inverse of dense matrix.
Definition: densemat.cpp:3924
Geometry::Type GetElementGeometry(int i) const
Definition: mesh.hpp:1055
Table * GetElementDofTable()
Definition: nurbs.hpp:376
void MakeVDimMatrix(SparseMatrix &mat) const
Replicate &#39;mat&#39; in the vector dimension, according to vdim ordering mode.
Definition: fespace.cpp:1204
Table * GetBdrElementDofTable()
Definition: nurbs.hpp:377
The ordering method used when the number of unknowns per mesh node (vector dimension) is bigger than ...
Definition: fespace.hpp:29
void GetEdgeInteriorVDofs(int i, Array< int > &vdofs) const
Definition: fespace.cpp:336
void ShiftUpI()
Definition: table.cpp:115
Linear2DFiniteElement TriangleFE
Definition: fe.cpp:32
int GetNVariants(int entity, int index) const
Return number of possible DOF variants for edge/face (var. order spaces).
Definition: fespace.cpp:2665
const CoarseFineTransformations & GetRefinementTransforms()
Definition: mesh.cpp:9928
Operation GetLastOperation() const
Return type of last modification of the mesh.
Definition: mesh.hpp:1658
static FiniteElementCollection * New(const char *name)
Factory method: return a newly allocated FiniteElementCollection according to the given name...
Definition: fe_coll.cpp:51
T * HostWrite()
Shortcut for mfem::Write(a.GetMemory(), a.Size(), false).
Definition: array.hpp:316
bool Nonconforming() const
Definition: fespace.hpp:448
int SizeJ() const
Definition: densemat.hpp:1000
double a
Definition: lissajous.cpp:41
NURBSExtension * NURBSext
Optional NURBS mesh extension.
Definition: mesh.hpp:272
int GetNV() const
Returns number of vertices. Vertices are only at the corners of elements, where you would expect them...
Definition: mesh.hpp:920
int GetDegenerateFaceDofs(int index, Array< int > &dofs, Geometry::Type master_geom, int variant) const
Definition: fespace.cpp:852
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:630
virtual const char * Name() const
Definition: fe_coll.hpp:65
void SetOperatorOwner(bool own=true)
Set the ownership flag for the held Operator.
Definition: handle.hpp:120
A standard isoparametric element transformation.
Definition: eltrans.hpp:361
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:5932
Mesh * mesh
The mesh that FE space lives on (not owned).
Definition: fespace.hpp:105
void ReorderElementToDofTable()
Reorder the scalar DOFs based on the element ordering.
Definition: fespace.cpp:440
GridFunction interpolation operator applicable after mesh refinement.
Definition: fespace.hpp:298
void CalcEdgeFaceVarOrders(Array< VarOrderBits > &edge_orders, Array< VarOrderBits > &face_orders) const
Definition: fespace.cpp:2450
double Max() const
Returns the maximal element of the vector.
Definition: vector.cpp:902
const NCList & GetNCList(int entity)
Return vertex/edge/face list (entity = 0/1/2, respectively).
Definition: ncmesh.hpp:275
Array< FaceQuadratureInterpolator * > E2BFQ_array
Definition: fespace.hpp:186
const Table * GetElementToFaceOrientationTable() const
Definition: fespace.hpp:746
int GetNConformingDofs() const
Definition: fespace.cpp:1253
void ConnectBoundaries()
Definition: nurbs.cpp:1793
Table var_face_dofs
NOTE: also used for spaces with mixed faces.
Definition: fespace.hpp:132
Array< Master > masters
Definition: ncmesh.hpp:230
void GetFaceEdges(int i, Array< int > &edges, Array< int > &o) const
Definition: mesh.cpp:5986
void GetEdgeInteriorDofs(int i, Array< int > &dofs) const
Definition: fespace.cpp:3064
const QuadratureInterpolator * GetQuadratureInterpolator(const IntegrationRule &ir) const
Return a QuadratureInterpolator that interpolates E-vectors to quadrature point values and/or derivat...
Definition: fespace.cpp:1327
ElementDofOrdering
Constants describing the possible orderings of the DOFs in one element.
Definition: fespace.hpp:74
General triple product operator x -&gt; A*B*C*x, with ownership of the factors.
Definition: operator.hpp:811
void MakeJ()
Definition: table.cpp:91
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:112
int dim
Definition: ex24.cpp:53
Array< FaceQuadratureInterpolator * > E2IFQ_array
Definition: fespace.hpp:185
void BuildFaceToDofTable() const
Definition: fespace.cpp:405
void UpdateElementOrders()
Resize the elem_order array on mesh change.
Definition: fespace.cpp:3312
void SetFE(const FiniteElement *FE)
Set the element that will be used to compute the transformations.
Definition: eltrans.hpp:381
void OrientedPointMatrix(const Slave &slave, DenseMatrix &oriented_matrix) const
Return the point matrix oriented according to the master and slave edges.
Definition: ncmesh.cpp:3226
virtual const FiniteElement * GetFE(int i) const
Returns pointer to the FiniteElement in the FiniteElementCollection associated with i&#39;th element in t...
Definition: fespace.cpp:2781
int index(int i, int j, int nx, int ny)
Definition: life.cpp:235
Array< char > var_edge_orders
Definition: fespace.hpp:136
int GetEdgeOrder(int edge, int variant=0) const
Definition: fespace.cpp:2638
Lexicographic ordering for tensor-product FiniteElements.
virtual int GetNVertices() const =0
int parent
Coarse Element index in the coarse mesh.
Definition: ncmesh.hpp:52
FiniteElementSpace()
Default constructor: the object is invalid until initialized using the method Load().
Definition: fespace.cpp:59
const ElementRestrictionOperator * GetElementRestriction(ElementDofOrdering e_ordering) const
Return an Operator that converts L-vectors to E-vectors.
Definition: fespace.cpp:1259
void Constructor(Mesh *mesh, NURBSExtension *ext, const FiniteElementCollection *fec, int vdim=1, int ordering=Ordering::byNODES)
Help function for constructors + Load().
Definition: fespace.cpp:2139
NCMesh * ncmesh
Optional nonconforming mesh extension.
Definition: mesh.hpp:273
Geometry::Type GetBdrElementBaseGeometry(int i) const
Definition: mesh.hpp:1072
void GetFaceVDofs(int i, Array< int > &vdofs) const
Returns indexes of degrees of freedom for i&#39;th face element (2D and 3D).
Definition: fespace.cpp:312
NQPT x VDIM x NE (values) / NQPT x VDIM x DIM x NE (grads)
void SetRow(const int row, const Array< int > &cols, const Vector &srow)
Definition: sparsemat.cpp:2971
void GetEdgeVDofs(int i, Array< int > &vdofs) const
Returns indexes of degrees of freedom for i&#39;th edge.
Definition: fespace.cpp:318
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:617
int GetNEdges() const
Return the number of edges.
Definition: mesh.hpp:929
void filter_dos(std::string &line)
Check for, and remove, a trailing &#39;\r&#39; from and std::string.
Definition: text.hpp:45
MFEM_HOST_DEVICE void Set(const int height, const int width, const double alpha, const TA *Adata, TB *Bdata)
Compute B = alpha*A, where the matrices A and B are of size height x width with data Adata and Bdata...
Definition: kernels.hpp:326
void MakeRef(T *, int)
Make this Array a reference to a pointer.
Definition: array.hpp:864
int GetNFaces() const
Return the number of faces in a 3D mesh.
Definition: mesh.hpp:932
BiLinear2DFiniteElement QuadrilateralFE
Vector data type.
Definition: vector.hpp:60
const FiniteElementCollection * FEColl() const
Definition: fespace.hpp:601
void Mult(const double *x, double *y) const
Matrix vector multiplication.
Definition: densemat.cpp:173
std::tuple< bool, ElementDofOrdering, FaceType, L2FaceValues > key_face
The face restriction operators, see GetFaceRestriction().
Definition: fespace.hpp:170
Array< int > face_to_be
Definition: fespace.hpp:149
int * GetI()
Definition: table.hpp:113
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:750
Defines the coarse-fine transformations of all fine elements.
Definition: ncmesh.hpp:70
RefCoord s[3]
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:118
const NCList & GetEdgeList()
Return the current list of conforming and nonconforming edges.
Definition: ncmesh.hpp:260
SparseMatrix * cR_hp
A version of the conforming restriction matrix for variable-order spaces.
Definition: fespace.hpp:161
static bool DofFinalizable(int dof, const Array< bool > &finalized, const SparseMatrix &deps)
Definition: fespace.cpp:838
Class representing the storage layout of a QuadratureFunction.
Definition: qspace.hpp:92
void UseExternalData(double *d, int h, int w)
Change the data array and the size of the DenseMatrix.
Definition: densemat.hpp:80
int RowSize(int i) const
Definition: table.hpp:108
const FiniteElement * GetBE(int i) const
Returns pointer to the FiniteElement in the FiniteElementCollection associated with i&#39;th boundary fac...
Definition: fespace.cpp:3100
NURBSExtension * NURBSext
Definition: fespace.hpp:147
void SetSize(int s)
Change the size of the DenseMatrix to s x s.
Definition: densemat.hpp:105
Base class for operators that extracts Face degrees of freedom.
Abstract operator.
Definition: operator.hpp:24
const DenseMatrix & GetPointMat() const
Return the stored point matrix.
Definition: eltrans.hpp:404
void Swap(SparseMatrix &other)
Definition: sparsemat.cpp:4178
int index
Mesh number.
Definition: ncmesh.hpp:189
DoF transformation implementation for the Nedelec basis on tetrahedra.
Definition: doftrans.hpp:252
int GetElementOrderImpl(int i) const
Return element order: internal version of GetElementOrder without checks.
Definition: fespace.cpp:189
Rank 3 tensor (array of matrices)
Definition: densemat.hpp:953
void Save(std::ostream &out) const
Save finite element space to output stream out.
Definition: fespace.cpp:3444
Abstract data type element.
Definition: element.hpp:28
void BuildDofToArrays()
Initialize internal data that enables the use of the methods GetElementForDof() and GetLocalDofForDof...
Definition: fespace.cpp:460
Linear1DFiniteElement SegmentFE
Definition: segment.cpp:49
void GetBdrElementVertices(int i, Array< int > &v) const
Returns the indices of the vertices of boundary element i.
Definition: mesh.hpp:1113
Operator that converts L2 FiniteElementSpace L-vectors to E-vectors.
void GetElementVertices(int i, Array< int > &v) const
Returns the indices of the vertices of element i.
Definition: mesh.hpp:1109
DofTransformation * GetDofTransformation() const
Return the nested DofTransformation object.
Definition: doftrans.hpp:182
int FindDofs(const Table &var_dof_table, int row, int ndof) const
Search row of a DOF table for a DOF set of size &#39;ndof&#39;, return first DOF.
Definition: fespace.cpp:2621
static void AdjustVDofs(Array< int > &vdofs)
Definition: fespace.cpp:267
void SetType(Operator::Type tid)
Invoke Clear() and set a new type id.
Definition: handle.hpp:132
DoF transformation implementation for the Nedelec basis on wedge elements.
Definition: doftrans.hpp:272
const Element * GetBdrElement(int i) const
Definition: mesh.hpp:1044
Defines the position of a fine element within a coarse element.
Definition: ncmesh.hpp:49
void Reset(OpType *A, bool own_A=true)
Reset the OperatorHandle to the given OpType pointer, A.
Definition: handle.hpp:145
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:6148
const QuadratureSpace * qspace
Not owned.
void DofsToVDofs(Array< int > &dofs, int ndofs=-1) const
Definition: fespace.cpp:215
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:1356