MFEM  v4.2.0
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-2020, 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/libceed/ceed.hpp"
18 #include "fem.hpp"
19 
20 #include <cmath>
21 #include <cstdarg>
22 #include <limits>
23 
24 using namespace std;
25 
26 namespace mfem
27 {
28 
29 template <> void Ordering::
30 DofsToVDofs<Ordering::byNODES>(int ndofs, int vdim, Array<int> &dofs)
31 {
32  // static method
33  int size = dofs.Size();
34  dofs.SetSize(size*vdim);
35  for (int vd = 1; vd < vdim; vd++)
36  {
37  for (int i = 0; i < size; i++)
38  {
39  dofs[i+size*vd] = Map<byNODES>(ndofs, vdim, dofs[i], vd);
40  }
41  }
42 }
43 
44 template <> void Ordering::
45 DofsToVDofs<Ordering::byVDIM>(int ndofs, int vdim, Array<int> &dofs)
46 {
47  // static method
48  int size = dofs.Size();
49  dofs.SetSize(size*vdim);
50  for (int vd = vdim-1; vd >= 0; vd--)
51  {
52  for (int i = 0; i < size; i++)
53  {
54  dofs[i+size*vd] = Map<byVDIM>(ndofs, vdim, dofs[i], vd);
55  }
56  }
57 }
58 
59 
60 FiniteElementSpace::FiniteElementSpace()
61  : mesh(NULL), fec(NULL), vdim(0), ordering(Ordering::byNODES),
62  ndofs(0), nvdofs(0), nedofs(0), nfdofs(0), nbdofs(0),
63  fdofs(NULL), bdofs(NULL),
64  elem_dof(NULL), bdrElem_dof(NULL), face_dof(NULL),
65  NURBSext(NULL), own_ext(false),
66  cP(NULL), cR(NULL), cP_is_set(false),
67  Th(Operator::ANY_TYPE),
68  sequence(0)
69 { }
70 
72  Mesh *mesh,
73  const FiniteElementCollection *fec)
74 {
75  mesh = mesh ? mesh : orig.mesh;
76  fec = fec ? fec : orig.fec;
77  NURBSExtension *NURBSext = NULL;
78  if (orig.NURBSext && orig.NURBSext != orig.mesh->NURBSext)
79  {
80 #ifdef MFEM_USE_MPI
81  ParNURBSExtension *pNURBSext =
82  dynamic_cast<ParNURBSExtension *>(orig.NURBSext);
83  if (pNURBSext)
84  {
85  NURBSext = new ParNURBSExtension(*pNURBSext);
86  }
87  else
88 #endif
89  {
90  NURBSext = new NURBSExtension(*orig.NURBSext);
91  }
92  }
93  Constructor(mesh, NURBSext, fec, orig.vdim, orig.ordering);
94 }
95 
97 {
99  return fec->FiniteElementForGeometry(GeomType)->GetOrder();
100 }
101 
103 {
104  Geometry::Type GeomType = mesh->GetFaceBaseGeometry(i);
105  return fec->FiniteElementForGeometry(GeomType)->GetOrder();
106 }
107 
108 void FiniteElementSpace::DofsToVDofs (Array<int> &dofs, int ndofs) const
109 {
110  if (vdim == 1) { return; }
111  if (ndofs < 0) { ndofs = this->ndofs; }
112 
114  {
115  Ordering::DofsToVDofs<Ordering::byNODES>(ndofs, vdim, dofs);
116  }
117  else
118  {
119  Ordering::DofsToVDofs<Ordering::byVDIM>(ndofs, vdim, dofs);
120  }
121 }
122 
123 void FiniteElementSpace::DofsToVDofs(int vd, Array<int> &dofs, int ndofs) const
124 {
125  if (vdim == 1) { return; }
126  if (ndofs < 0) { ndofs = this->ndofs; }
127 
129  {
130  for (int i = 0; i < dofs.Size(); i++)
131  {
132  dofs[i] = Ordering::Map<Ordering::byNODES>(ndofs, vdim, dofs[i], vd);
133  }
134  }
135  else
136  {
137  for (int i = 0; i < dofs.Size(); i++)
138  {
139  dofs[i] = Ordering::Map<Ordering::byVDIM>(ndofs, vdim, dofs[i], vd);
140  }
141  }
142 }
143 
144 int FiniteElementSpace::DofToVDof(int dof, int vd, int ndofs) const
145 {
146  if (vdim == 1) { return dof; }
147  if (ndofs < 0) { ndofs = this->ndofs; }
148 
150  {
151  return Ordering::Map<Ordering::byNODES>(ndofs, vdim, dof, vd);
152  }
153  else
154  {
155  return Ordering::Map<Ordering::byVDIM>(ndofs, vdim, dof, vd);
156  }
157 }
158 
159 // static function
161 {
162  int n = vdofs.Size(), *vdof = vdofs;
163  for (int i = 0; i < n; i++)
164  {
165  int j;
166  if ((j = vdof[i]) < 0)
167  {
168  vdof[i] = -1-j;
169  }
170  }
171 }
172 
174 {
175  GetElementDofs(i, vdofs);
176  DofsToVDofs(vdofs);
177 }
178 
180 {
181  GetBdrElementDofs(i, vdofs);
182  DofsToVDofs(vdofs);
183 }
184 
186 {
187  GetFaceDofs(i, vdofs);
188  DofsToVDofs(vdofs);
189 }
190 
192 {
193  GetEdgeDofs(i, vdofs);
194  DofsToVDofs(vdofs);
195 }
196 
198 {
199  GetVertexDofs(i, vdofs);
200  DofsToVDofs(vdofs);
201 }
202 
204 {
205  GetElementInteriorDofs(i, vdofs);
206  DofsToVDofs(vdofs);
207 }
208 
210 {
211  GetEdgeInteriorDofs(i, vdofs);
212  DofsToVDofs(vdofs);
213 }
214 
216 {
217  if (elem_dof) { return; }
218 
219  Table *el_dof = new Table;
220  Array<int> dofs;
221  el_dof -> MakeI (mesh -> GetNE());
222  for (int i = 0; i < mesh -> GetNE(); i++)
223  {
224  GetElementDofs (i, dofs);
225  el_dof -> AddColumnsInRow (i, dofs.Size());
226  }
227  el_dof -> MakeJ();
228  for (int i = 0; i < mesh -> GetNE(); i++)
229  {
230  GetElementDofs (i, dofs);
231  el_dof -> AddConnections (i, (int *)dofs, dofs.Size());
232  }
233  el_dof -> ShiftUpI();
234  elem_dof = el_dof;
235 }
236 
238 {
239  if (bdrElem_dof) { return; }
240 
241  Table *bel_dof = new Table;
242  Array<int> dofs;
243  bel_dof->MakeI(mesh->GetNBE());
244  for (int i = 0; i < mesh->GetNBE(); i++)
245  {
246  GetBdrElementDofs(i, dofs);
247  bel_dof->AddColumnsInRow(i, dofs.Size());
248  }
249  bel_dof->MakeJ();
250  for (int i = 0; i < mesh->GetNBE(); i++)
251  {
252  GetBdrElementDofs(i, dofs);
253  bel_dof->AddConnections(i, (int *)dofs, dofs.Size());
254  }
255  bel_dof->ShiftUpI();
256  bdrElem_dof = bel_dof;
257 }
258 
260 {
261  // Here, "face" == (dim-1)-dimensional mesh entity.
262 
263  if (face_dof) { return; }
264 
265  if (NURBSext) { BuildNURBSFaceToDofTable(); return; }
266 
267  Table *fc_dof = new Table;
268  Array<int> dofs;
269  fc_dof->MakeI(mesh->GetNumFaces());
270  for (int i = 0; i < fc_dof->Size(); i++)
271  {
272  GetFaceDofs(i, dofs);
273  fc_dof->AddColumnsInRow(i, dofs.Size());
274  }
275  fc_dof->MakeJ();
276  for (int i = 0; i < fc_dof->Size(); i++)
277  {
278  GetFaceDofs(i, dofs);
279  fc_dof->AddConnections(i, (int *)dofs, dofs.Size());
280  }
281  fc_dof->ShiftUpI();
282  face_dof = fc_dof;
283 }
284 
286 {
287  delete elem_dof;
288  elem_dof = NULL;
290 }
291 
293 {
294  Array<int> dof_marker(ndofs);
295 
296  dof_marker = -1;
297 
298  int *J = elem_dof->GetJ(), nnz = elem_dof->Size_of_connections();
299  for (int k = 0, dof_counter = 0; k < nnz; k++)
300  {
301  const int sdof = J[k]; // signed dof
302  const int dof = (sdof < 0) ? -1-sdof : sdof;
303  int new_dof = dof_marker[dof];
304  if (new_dof < 0)
305  {
306  dof_marker[dof] = new_dof = dof_counter++;
307  }
308  J[k] = (sdof < 0) ? -1-new_dof : new_dof; // preserve the sign of sdof
309  }
310 }
311 
313 {
314  if (dof_elem_array.Size()) { return; }
315 
317 
320  dof_elem_array = -1;
321  for (int i = 0; i < mesh -> GetNE(); i++)
322  {
323  const int *dofs = elem_dof -> GetRow(i);
324  const int n = elem_dof -> RowSize(i);
325  for (int j = 0; j < n; j++)
326  {
327  if (dof_elem_array[dofs[j]] < 0)
328  {
329  dof_elem_array[dofs[j]] = i;
330  dof_ldof_array[dofs[j]] = j;
331  }
332  }
333  }
334 }
335 
336 static void mark_dofs(const Array<int> &dofs, Array<int> &mark_array)
337 {
338  for (int i = 0; i < dofs.Size(); i++)
339  {
340  int k = dofs[i];
341  if (k < 0) { k = -1 - k; }
342  mark_array[k] = -1;
343  }
344 }
345 
347  Array<int> &ess_vdofs,
348  int component) const
349 {
350  Array<int> vdofs, dofs;
351 
352  ess_vdofs.SetSize(GetVSize());
353  ess_vdofs = 0;
354 
355  for (int i = 0; i < GetNBE(); i++)
356  {
357  if (bdr_attr_is_ess[GetBdrAttribute(i)-1])
358  {
359  if (component < 0)
360  {
361  // Mark all components.
362  GetBdrElementVDofs(i, vdofs);
363  mark_dofs(vdofs, ess_vdofs);
364  }
365  else
366  {
367  GetBdrElementDofs(i, dofs);
368  for (int d = 0; d < dofs.Size(); d++)
369  { dofs[d] = DofToVDof(dofs[d], component); }
370  mark_dofs(dofs, ess_vdofs);
371  }
372  }
373  }
374 
375  // mark possible hidden boundary edges in a non-conforming mesh, also
376  // local DOFs affected by boundary elements on other processors
377  if (Nonconforming())
378  {
379  Array<int> bdr_verts, bdr_edges;
380  mesh->ncmesh->GetBoundaryClosure(bdr_attr_is_ess, bdr_verts, bdr_edges);
381 
382  for (int i = 0; i < bdr_verts.Size(); i++)
383  {
384  if (component < 0)
385  {
386  GetVertexVDofs(bdr_verts[i], vdofs);
387  mark_dofs(vdofs, ess_vdofs);
388  }
389  else
390  {
391  GetVertexDofs(bdr_verts[i], dofs);
392  for (int d = 0; d < dofs.Size(); d++)
393  { dofs[d] = DofToVDof(dofs[d], component); }
394  mark_dofs(dofs, ess_vdofs);
395  }
396  }
397  for (int i = 0; i < bdr_edges.Size(); i++)
398  {
399  if (component < 0)
400  {
401  GetEdgeVDofs(bdr_edges[i], vdofs);
402  mark_dofs(vdofs, ess_vdofs);
403  }
404  else
405  {
406  GetEdgeDofs(bdr_edges[i], dofs);
407  for (int d = 0; d < dofs.Size(); d++)
408  { dofs[d] = DofToVDof(dofs[d], component); }
409  mark_dofs(dofs, ess_vdofs);
410  }
411  }
412  }
413 }
414 
416  Array<int> &ess_tdof_list,
417  int component)
418 {
419  Array<int> ess_vdofs, ess_tdofs;
420  GetEssentialVDofs(bdr_attr_is_ess, ess_vdofs, component);
422  if (!R)
423  {
424  ess_tdofs.MakeRef(ess_vdofs);
425  }
426  else
427  {
428  R->BooleanMult(ess_vdofs, ess_tdofs);
429  }
430  MarkerToList(ess_tdofs, ess_tdof_list);
431 }
432 
433 // static method
435  Array<int> &list)
436 {
437  int num_marked = 0;
438  marker.HostRead(); // make sure we can read the array on host
439  for (int i = 0; i < marker.Size(); i++)
440  {
441  if (marker[i]) { num_marked++; }
442  }
443  list.SetSize(0);
444  list.HostWrite();
445  list.Reserve(num_marked);
446  for (int i = 0; i < marker.Size(); i++)
447  {
448  if (marker[i]) { list.Append(i); }
449  }
450 }
451 
452 // static method
453 void FiniteElementSpace::ListToMarker(const Array<int> &list, int marker_size,
454  Array<int> &marker, int mark_val)
455 {
456  list.HostRead(); // make sure we can read the array on host
457  marker.SetSize(marker_size);
458  marker.HostWrite();
459  marker = 0;
460  for (int i = 0; i < list.Size(); i++)
461  {
462  marker[list[i]] = mark_val;
463  }
464 }
465 
467  Array<int> &cdofs)
468 {
470  if (cP) { cP->BooleanMultTranspose(dofs, cdofs); }
471  else { dofs.Copy(cdofs); }
472 }
473 
475  Array<int> &dofs)
476 {
478  if (cR) { cR->BooleanMultTranspose(cdofs, dofs); }
479  else { cdofs.Copy(dofs); }
480 }
481 
482 SparseMatrix *
484 {
485  int i, j;
486  Array<int> d_vdofs, c_vdofs;
487  SparseMatrix *R;
488 
489  R = new SparseMatrix (cfes -> GetVSize(), GetVSize());
490 
491  for (i = 0; i < mesh -> GetNE(); i++)
492  {
493  this -> GetElementVDofs (i, d_vdofs);
494  cfes -> GetElementVDofs (i, c_vdofs);
495 
496 #ifdef MFEM_DEBUG
497  if (d_vdofs.Size() != c_vdofs.Size())
498  {
499  mfem_error ("FiniteElementSpace::D2C_GlobalRestrictionMatrix (...)");
500  }
501 #endif
502 
503  for (j = 0; j < d_vdofs.Size(); j++)
504  {
505  R -> Set (c_vdofs[j], d_vdofs[j], 1.0);
506  }
507  }
508 
509  R -> Finalize();
510 
511  return R;
512 }
513 
514 SparseMatrix *
516 {
517  int i, j;
518  Array<int> d_dofs, c_dofs;
519  SparseMatrix *R;
520 
521  R = new SparseMatrix (cfes -> GetNDofs(), ndofs);
522 
523  for (i = 0; i < mesh -> GetNE(); i++)
524  {
525  this -> GetElementDofs (i, d_dofs);
526  cfes -> GetElementDofs (i, c_dofs);
527 
528 #ifdef MFEM_DEBUG
529  if (c_dofs.Size() != 1)
530  mfem_error ("FiniteElementSpace::"
531  "D2Const_GlobalRestrictionMatrix (...)");
532 #endif
533 
534  for (j = 0; j < d_dofs.Size(); j++)
535  {
536  R -> Set (c_dofs[0], d_dofs[j], 1.0);
537  }
538  }
539 
540  R -> Finalize();
541 
542  return R;
543 }
544 
545 SparseMatrix *
547 {
548  SparseMatrix *R;
549  DenseMatrix loc_restr;
550  Array<int> l_dofs, h_dofs, l_vdofs, h_vdofs;
551 
552  int vdim = lfes->GetVDim();
553  R = new SparseMatrix (vdim * lfes -> GetNDofs(), vdim * ndofs);
554 
555  Geometry::Type cached_geom = Geometry::INVALID;
556  const FiniteElement *h_fe = NULL;
557  const FiniteElement *l_fe = NULL;
559 
560  for (int i = 0; i < mesh -> GetNE(); i++)
561  {
562  this -> GetElementDofs (i, h_dofs);
563  lfes -> GetElementDofs (i, l_dofs);
564 
565  // Assuming 'loc_restr' depends only on the Geometry::Type.
567  if (geom != cached_geom)
568  {
569  h_fe = this -> GetFE (i);
570  l_fe = lfes -> GetFE (i);
572  h_fe->Project(*l_fe, T, loc_restr);
573  cached_geom = geom;
574  }
575 
576  for (int vd = 0; vd < vdim; vd++)
577  {
578  l_dofs.Copy(l_vdofs);
579  lfes->DofsToVDofs(vd, l_vdofs);
580 
581  h_dofs.Copy(h_vdofs);
582  this->DofsToVDofs(vd, h_vdofs);
583 
584  R -> SetSubMatrix (l_vdofs, h_vdofs, loc_restr, 1);
585  }
586  }
587 
588  R -> Finalize();
589 
590  return R;
591 }
592 
593 void
595  Array<int>& slave_dofs, DenseMatrix& I)
596 {
597  for (int i = 0; i < slave_dofs.Size(); i++)
598  {
599  int sdof = slave_dofs[i];
600  if (!deps.RowSize(sdof)) // not processed yet?
601  {
602  for (int j = 0; j < master_dofs.Size(); j++)
603  {
604  double coef = I(i, j);
605  if (std::abs(coef) > 1e-12)
606  {
607  int mdof = master_dofs[j];
608  if (mdof != sdof && mdof != (-1-sdof))
609  {
610  deps.Add(sdof, mdof, coef);
611  }
612  }
613  }
614  }
615  }
616 }
617 
618 bool FiniteElementSpace::DofFinalizable(int dof, const Array<bool>& finalized,
619  const SparseMatrix& deps)
620 {
621  const int* dep = deps.GetRowColumns(dof);
622  int ndep = deps.RowSize(dof);
623 
624  // are all constraining DOFs finalized?
625  for (int i = 0; i < ndep; i++)
626  {
627  if (!finalized[dep[i]]) { return false; }
628  }
629  return true;
630 }
631 
633  Geometry::Type master_geom) const
634 {
635  // In NC meshes with prisms/tets, a special constraint occurs where a
636  // prism/tet edge is slave to another element's face. Rather than introduce a
637  // new edge-face constraint type, we handle such cases as degenerate
638  // face-face constraints, where the point-matrix rectangle has zero height.
639  // This method returns DOFs for the first edge of the rectangle, duplicated
640  // in the orthogonal direction, to resemble DOFs for a quadrilateral face.
641  // The extra DOFs are ignored by FiniteElementSpace::AddDependencies.
642 
643  Array<int> edof;
644  GetEdgeDofs(-1 - index, edof);
645 
648  int nn = 2*nv + ne;
649 
650  dofs.SetSize(nn*nn);
651  if (!dofs.Size()) { return; }
652 
653  dofs = edof[0];
654 
655  // copy first two vertex DOFs
656  for (int i = 0; i < nv; i++)
657  {
658  dofs[i] = edof[i];
659  dofs[nv+i] = edof[nv+i];
660  }
661  // copy first edge DOFs
662  int face_vert = Geometry::NumVerts[master_geom];
663  for (int i = 0; i < ne; i++)
664  {
665  dofs[face_vert*nv + i] = edof[2*nv + i];
666  }
667 }
668 
669 void
671  Geometry::Type master_geom) const
672 {
673  switch (entity)
674  {
675  case 0: GetVertexDofs(index, dofs); break;
676  case 1: GetEdgeDofs(index, dofs); break;
677  case 2: (index >= 0) ? GetFaceDofs(index, dofs)
678  /* */ : GetDegenerateFaceDofs(index, dofs, master_geom);
679  }
680 }
681 
682 
684 {
685 #ifdef MFEM_USE_MPI
686  MFEM_VERIFY(dynamic_cast<const ParFiniteElementSpace*>(this) == NULL,
687  "This method should not be used with a ParFiniteElementSpace!");
688 #endif
689 
690  if (cP_is_set) { return; }
691  cP_is_set = true;
692 
693  // For each slave DOF, the dependency matrix will contain a row that
694  // expresses the slave DOF as a linear combination of its immediate master
695  // DOFs. Rows of independent DOFs will remain empty.
696  SparseMatrix deps(ndofs);
697 
698  // collect local edge/face dependencies
699  for (int entity = 1; entity <= 2; entity++)
700  {
701  const NCMesh::NCList &list = mesh->ncmesh->GetNCList(entity);
702  if (!list.masters.Size()) { continue; }
703 
704  Array<int> master_dofs, slave_dofs;
705 
707  DenseMatrix I;
708 
709  // loop through all master edges/faces, constrain their slave edges/faces
710  for (int mi = 0; mi < list.masters.Size(); mi++)
711  {
712  const NCMesh::Master &master = list.masters[mi];
713 
714  GetEntityDofs(entity, master.index, master_dofs);
715  if (!master_dofs.Size()) { continue; }
716 
717  const FiniteElement* fe = fec->FiniteElementForGeometry(master.Geom());
718  if (!fe) { continue; }
719 
720  switch (master.geom)
721  {
722  case Geometry::SQUARE: T.SetFE(&QuadrilateralFE); break;
723  case Geometry::TRIANGLE: T.SetFE(&TriangleFE); break;
724  case Geometry::SEGMENT: T.SetFE(&SegmentFE); break;
725  default: MFEM_ABORT("unsupported geometry");
726  }
727 
728  for (int si = master.slaves_begin; si < master.slaves_end; si++)
729  {
730  const NCMesh::Slave &slave = list.slaves[si];
731  GetEntityDofs(entity, slave.index, slave_dofs, master.Geom());
732  if (!slave_dofs.Size()) { continue; }
733 
734  list.OrientedPointMatrix(slave, T.GetPointMat());
735  fe->GetLocalInterpolation(T, I);
736 
737  // make each slave DOF dependent on all master DOFs
738  AddDependencies(deps, master_dofs, slave_dofs, I);
739  }
740  }
741  }
742 
743  deps.Finalize();
744 
745  // DOFs that stayed independent are true DOFs
746  int n_true_dofs = 0;
747  for (int i = 0; i < ndofs; i++)
748  {
749  if (!deps.RowSize(i)) { n_true_dofs++; }
750  }
751 
752  // if all dofs are true dofs leave cP and cR NULL
753  if (n_true_dofs == ndofs)
754  {
755  cP = cR = NULL; // will be treated as identities
756  return;
757  }
758 
759  // create the conforming restriction matrix cR
760  int *cR_J;
761  {
762  int *cR_I = Memory<int>(n_true_dofs+1);
763  double *cR_A = Memory<double>(n_true_dofs);
764  cR_J = Memory<int>(n_true_dofs);
765  for (int i = 0; i < n_true_dofs; i++)
766  {
767  cR_I[i] = i;
768  cR_A[i] = 1.0;
769  }
770  cR_I[n_true_dofs] = n_true_dofs;
771  cR = new SparseMatrix(cR_I, cR_J, cR_A, n_true_dofs, ndofs);
772  }
773 
774  // create the conforming prolongation matrix cP
775  cP = new SparseMatrix(ndofs, n_true_dofs);
776 
777  Array<bool> finalized(ndofs);
778  finalized = false;
779 
780  // put identity in the restriction and prolongation matrices for true DOFs
781  for (int i = 0, true_dof = 0; i < ndofs; i++)
782  {
783  if (!deps.RowSize(i))
784  {
785  cR_J[true_dof] = i;
786  cP->Add(i, true_dof++, 1.0);
787  finalized[i] = true;
788  }
789  }
790 
791  // Now calculate cP rows of slave DOFs as combinations of cP rows of their
792  // master DOFs. It is possible that some slave DOFs depend on DOFs that are
793  // themselves slaves. Here we resolve such indirect constraints by first
794  // calculating rows of the cP matrix for DOFs whose master DOF cP rows are
795  // already known (in the first iteration these are the true DOFs). In the
796  // second iteration, slaves of slaves can be 'finalized' (given a row in the
797  // cP matrix), in the third iteration slaves of slaves of slaves, etc.
798  bool finished;
799  int n_finalized = n_true_dofs;
800  Array<int> cols;
801  Vector srow;
802  do
803  {
804  finished = true;
805  for (int dof = 0; dof < ndofs; dof++)
806  {
807  if (!finalized[dof] && DofFinalizable(dof, finalized, deps))
808  {
809  const int* dep_col = deps.GetRowColumns(dof);
810  const double* dep_coef = deps.GetRowEntries(dof);
811  int n_dep = deps.RowSize(dof);
812 
813  for (int j = 0; j < n_dep; j++)
814  {
815  cP->GetRow(dep_col[j], cols, srow);
816  srow *= dep_coef[j];
817  cP->AddRow(dof, cols, srow);
818  }
819 
820  finalized[dof] = true;
821  n_finalized++;
822  finished = false;
823  }
824  }
825  }
826  while (!finished);
827 
828  // if everything is consistent (mesh, face orientations, etc.), we should
829  // be able to finalize all slave DOFs, otherwise it's a serious error
830  if (n_finalized != ndofs)
831  {
832  MFEM_ABORT("Error creating cP matrix.");
833  }
834 
835  cP->Finalize();
836 
837  if (vdim > 1)
838  {
839  MakeVDimMatrix(*cP);
840  MakeVDimMatrix(*cR);
841  }
842 
843  if (Device::IsEnabled()) { cP->BuildTranspose(); }
844 }
845 
847 {
848  if (vdim == 1) { return; }
849 
850  int height = mat.Height();
851  int width = mat.Width();
852 
853  SparseMatrix *vmat = new SparseMatrix(vdim*height, vdim*width);
854 
855  Array<int> dofs, vdofs;
856  Vector srow;
857  for (int i = 0; i < height; i++)
858  {
859  mat.GetRow(i, dofs, srow);
860  for (int vd = 0; vd < vdim; vd++)
861  {
862  dofs.Copy(vdofs);
863  DofsToVDofs(vd, vdofs, width);
864  vmat->SetRow(DofToVDof(i, vd, height), vdofs, srow);
865  }
866  }
867  vmat->Finalize();
868 
869  mat.Swap(*vmat);
870  delete vmat;
871 }
872 
873 
875 {
876  if (Conforming()) { return NULL; }
878  return cP;
879 }
880 
882 {
883  if (Conforming()) { return NULL; }
885  return cR;
886 }
887 
889 {
891  return P ? (P->Width() / vdim) : ndofs;
892 }
893 
895  ElementDofOrdering e_ordering) const
896 {
897  // Check if we have a discontinuous space using the FE collection:
898  if (IsDGSpace())
899  {
900  if (L2E_nat.Ptr() == NULL)
901  {
902  L2E_nat.Reset(new L2ElementRestriction(*this));
903  }
904  return L2E_nat.Ptr();
905  }
906  if (e_ordering == ElementDofOrdering::LEXICOGRAPHIC)
907  {
908  if (L2E_lex.Ptr() == NULL)
909  {
910  L2E_lex.Reset(new ElementRestriction(*this, e_ordering));
911  }
912  return L2E_lex.Ptr();
913  }
914  // e_ordering == ElementDofOrdering::NATIVE
915  if (L2E_nat.Ptr() == NULL)
916  {
917  L2E_nat.Reset(new ElementRestriction(*this, e_ordering));
918  }
919  return L2E_nat.Ptr();
920 }
921 
923  ElementDofOrdering e_ordering, FaceType type, L2FaceValues mul) const
924 {
925  const bool is_dg_space = IsDGSpace();
926  const L2FaceValues m = (is_dg_space && mul==L2FaceValues::DoubleValued) ?
928  key_face key = std::make_tuple(is_dg_space, e_ordering, type, m);
929  auto itr = L2F.find(key);
930  if (itr != L2F.end())
931  {
932  return itr->second;
933  }
934  else
935  {
936  Operator* res;
937  if (is_dg_space)
938  {
939  res = new L2FaceRestriction(*this, e_ordering, type, m);
940  }
941  else
942  {
943  res = new H1FaceRestriction(*this, e_ordering, type);
944  }
945  L2F[key] = res;
946  return res;
947  }
948 }
949 
951  const IntegrationRule &ir) const
952 {
953  for (int i = 0; i < E2Q_array.Size(); i++)
954  {
955  const QuadratureInterpolator *qi = E2Q_array[i];
956  if (qi->IntRule == &ir) { return qi; }
957  }
958 
959  QuadratureInterpolator *qi = new QuadratureInterpolator(*this, ir);
960  E2Q_array.Append(qi);
961  return qi;
962 }
963 
965  const QuadratureSpace &qs) const
966 {
967  for (int i = 0; i < E2Q_array.Size(); i++)
968  {
969  const QuadratureInterpolator *qi = E2Q_array[i];
970  if (qi->qspace == &qs) { return qi; }
971  }
972 
973  QuadratureInterpolator *qi = new QuadratureInterpolator(*this, qs);
974  E2Q_array.Append(qi);
975  return qi;
976 }
977 
980  const IntegrationRule &ir, FaceType type) const
981 {
982  if (type==FaceType::Interior)
983  {
984  for (int i = 0; i < E2IFQ_array.Size(); i++)
985  {
987  if (qi->IntRule == &ir) { return qi; }
988  }
989 
991  type);
992  E2IFQ_array.Append(qi);
993  return qi;
994  }
995  else //Boundary
996  {
997  for (int i = 0; i < E2BFQ_array.Size(); i++)
998  {
1000  if (qi->IntRule == &ir) { return qi; }
1001  }
1002 
1004  type);
1005  E2BFQ_array.Append(qi);
1006  return qi;
1007  }
1008 }
1009 
1011  const int coarse_ndofs, const Table &coarse_elem_dof,
1012  const DenseTensor localP[]) const
1013 {
1014  MFEM_VERIFY(mesh->GetLastOperation() == Mesh::REFINE, "");
1015 
1016  Array<int> dofs, coarse_dofs, coarse_vdofs;
1017  Vector row;
1018 
1019  Mesh::GeometryList elem_geoms(*mesh);
1020 
1021  SparseMatrix *P;
1022  if (elem_geoms.Size() == 1)
1023  {
1024  const int coarse_ldof = localP[elem_geoms[0]].SizeJ();
1025  P = new SparseMatrix(GetVSize(), coarse_ndofs*vdim, coarse_ldof);
1026  }
1027  else
1028  {
1029  P = new SparseMatrix(GetVSize(), coarse_ndofs*vdim);
1030  }
1031 
1032  Array<int> mark(P->Height());
1033  mark = 0;
1034 
1036 
1037  for (int k = 0; k < mesh->GetNE(); k++)
1038  {
1039  const Embedding &emb = rtrans.embeddings[k];
1041  const DenseMatrix &lP = localP[geom](emb.matrix);
1042  const int fine_ldof = localP[geom].SizeI();
1043 
1044  elem_dof->GetRow(k, dofs);
1045  coarse_elem_dof.GetRow(emb.parent, coarse_dofs);
1046 
1047  for (int vd = 0; vd < vdim; vd++)
1048  {
1049  coarse_dofs.Copy(coarse_vdofs);
1050  DofsToVDofs(vd, coarse_vdofs, coarse_ndofs);
1051 
1052  for (int i = 0; i < fine_ldof; i++)
1053  {
1054  int r = DofToVDof(dofs[i], vd);
1055  int m = (r >= 0) ? r : (-1 - r);
1056 
1057  if (!mark[m])
1058  {
1059  lP.GetRow(i, row);
1060  P->SetRow(r, coarse_vdofs, row);
1061  mark[m] = 1;
1062  }
1063  }
1064  }
1065  }
1066 
1067  MFEM_ASSERT(mark.Sum() == P->Height(), "Not all rows of P set.");
1068  if (elem_geoms.Size() != 1) { P->Finalize(); }
1069  return P;
1070 }
1071 
1073  Geometry::Type geom, DenseTensor &localP) const
1074 {
1075  const FiniteElement *fe = fec->FiniteElementForGeometry(geom);
1076 
1078  const DenseTensor &pmats = rtrans.point_matrices[geom];
1079 
1080  int nmat = pmats.SizeK();
1081  int ldof = fe->GetDof();
1082 
1084  isotr.SetIdentityTransformation(geom);
1085 
1086  // calculate local interpolation matrices for all refinement types
1087  localP.SetSize(ldof, ldof, nmat);
1088  for (int i = 0; i < nmat; i++)
1089  {
1090  isotr.SetPointMat(pmats(i));
1091  fe->GetLocalInterpolation(isotr, localP(i));
1092  }
1093 }
1094 
1096  const Table* old_elem_dof)
1097 {
1098  MFEM_VERIFY(GetNE() >= old_elem_dof->Size(),
1099  "Previous mesh is not coarser.");
1100 
1101  Mesh::GeometryList elem_geoms(*mesh);
1102 
1104  for (int i = 0; i < elem_geoms.Size(); i++)
1105  {
1106  GetLocalRefinementMatrices(elem_geoms[i], localP[elem_geoms[i]]);
1107  }
1108 
1109  return RefinementMatrix_main(old_ndofs, *old_elem_dof, localP);
1110 }
1111 
1113 (const FiniteElementSpace* fespace, Table* old_elem_dof, int old_ndofs)
1114  : fespace(fespace)
1115  , old_elem_dof(old_elem_dof)
1116 {
1117  MFEM_VERIFY(fespace->GetNE() >= old_elem_dof->Size(),
1118  "Previous mesh is not coarser.");
1119 
1120  width = old_ndofs * fespace->GetVDim();
1121  height = fespace->GetVSize();
1122 
1123  Mesh::GeometryList elem_geoms(*fespace->GetMesh());
1124 
1125  for (int i = 0; i < elem_geoms.Size(); i++)
1126  {
1127  fespace->GetLocalRefinementMatrices(elem_geoms[i], localP[elem_geoms[i]]);
1128  }
1129 }
1130 
1132  const FiniteElementSpace *fespace, const FiniteElementSpace *coarse_fes)
1133  : Operator(fespace->GetVSize(), coarse_fes->GetVSize()),
1134  fespace(fespace), old_elem_dof(NULL)
1135 {
1136  Mesh::GeometryList elem_geoms(*fespace->GetMesh());
1137 
1138  for (int i = 0; i < elem_geoms.Size(); i++)
1139  {
1140  fespace->GetLocalRefinementMatrices(*coarse_fes, elem_geoms[i],
1141  localP[elem_geoms[i]]);
1142  }
1143 
1144  // Make a copy of the coarse elem_dof Table.
1145  old_elem_dof = new Table(coarse_fes->GetElementToDofTable());
1146 }
1147 
1149 {
1150  delete old_elem_dof;
1151 }
1152 
1154 ::Mult(const Vector &x, Vector &y) const
1155 {
1156  Mesh* mesh = fespace->GetMesh();
1157  const CoarseFineTransformations &rtrans = mesh->GetRefinementTransforms();
1158 
1159  Array<int> dofs, vdofs, old_dofs, old_vdofs;
1160 
1161  int vdim = fespace->GetVDim();
1162  int old_ndofs = width / vdim;
1163 
1164  Vector subY, subX;
1165 
1166  for (int k = 0; k < mesh->GetNE(); k++)
1167  {
1168  const Embedding &emb = rtrans.embeddings[k];
1169  const Geometry::Type geom = mesh->GetElementBaseGeometry(k);
1170  const DenseMatrix &lP = localP[geom](emb.matrix);
1171 
1172  subY.SetSize(lP.Height());
1173 
1174  fespace->GetElementDofs(k, dofs);
1175  old_elem_dof->GetRow(emb.parent, old_dofs);
1176 
1177  for (int vd = 0; vd < vdim; vd++)
1178  {
1179  dofs.Copy(vdofs);
1180  fespace->DofsToVDofs(vd, vdofs);
1181  old_dofs.Copy(old_vdofs);
1182  fespace->DofsToVDofs(vd, old_vdofs, old_ndofs);
1183  x.GetSubVector(old_vdofs, subX);
1184  lP.Mult(subX, subY);
1185  y.SetSubVector(vdofs, subY);
1186  }
1187  }
1188 }
1189 
1191 ::MultTranspose(const Vector &x, Vector &y) const
1192 {
1193  y = 0.0;
1194 
1195  Mesh* mesh = fespace->GetMesh();
1196  const CoarseFineTransformations &rtrans = mesh->GetRefinementTransforms();
1197 
1198  Array<char> processed(fespace->GetVSize());
1199  processed = 0;
1200 
1201  Array<int> f_dofs, c_dofs, f_vdofs, c_vdofs;
1202 
1203  int vdim = fespace->GetVDim();
1204  int old_ndofs = width / vdim;
1205 
1206  Vector subY, subX;
1207 
1208  for (int k = 0; k < mesh->GetNE(); k++)
1209  {
1210  const Embedding &emb = rtrans.embeddings[k];
1211  const Geometry::Type geom = mesh->GetElementBaseGeometry(k);
1212  const DenseMatrix &lP = localP[geom](emb.matrix);
1213 
1214  fespace->GetElementDofs(k, f_dofs);
1215  old_elem_dof->GetRow(emb.parent, c_dofs);
1216 
1217  subY.SetSize(lP.Width());
1218 
1219  for (int vd = 0; vd < vdim; vd++)
1220  {
1221  f_dofs.Copy(f_vdofs);
1222  fespace->DofsToVDofs(vd, f_vdofs);
1223  c_dofs.Copy(c_vdofs);
1224  fespace->DofsToVDofs(vd, c_vdofs, old_ndofs);
1225 
1226  x.GetSubVector(f_vdofs, subX);
1227 
1228  for (int p = 0; p < f_dofs.Size(); ++p)
1229  {
1230  if (processed[DecodeDof(f_dofs[p])])
1231  {
1232  subX[p] = 0.0;
1233  }
1234  }
1235 
1236  lP.MultTranspose(subX, subY);
1237  y.AddElementVector(c_vdofs, subY);
1238  }
1239 
1240  for (int p = 0; p < f_dofs.Size(); ++p)
1241  {
1242  processed[DecodeDof(f_dofs[p])] = 1;
1243  }
1244  }
1245 }
1246 
1248  const FiniteElementSpace *f_fes, const FiniteElementSpace *c_fes,
1249  BilinearFormIntegrator *mass_integ)
1250  : Operator(c_fes->GetVSize(), f_fes->GetVSize()),
1251  fine_fes(f_fes)
1252 {
1253  MFEM_VERIFY(c_fes->GetOrdering() == f_fes->GetOrdering() &&
1254  c_fes->GetVDim() == f_fes->GetVDim(),
1255  "incompatible coarse and fine FE spaces");
1256 
1258  Mesh *f_mesh = f_fes->GetMesh();
1259  const CoarseFineTransformations &rtrans = f_mesh->GetRefinementTransforms();
1260 
1261  Mesh::GeometryList elem_geoms(*f_mesh);
1263  for (int gi = 0; gi < elem_geoms.Size(); gi++)
1264  {
1265  const Geometry::Type geom = elem_geoms[gi];
1266  DenseTensor &lP = localP[geom], &lM = localM[geom];
1267  const FiniteElement *fine_fe =
1268  f_fes->fec->FiniteElementForGeometry(geom);
1269  const FiniteElement *coarse_fe =
1270  c_fes->fec->FiniteElementForGeometry(geom);
1271  const DenseTensor &pmats = rtrans.point_matrices[geom];
1272 
1273  lP.SetSize(fine_fe->GetDof(), coarse_fe->GetDof(), pmats.SizeK());
1274  lM.SetSize(fine_fe->GetDof(), fine_fe->GetDof(), pmats.SizeK());
1275  emb_tr.SetIdentityTransformation(geom);
1276  for (int i = 0; i < pmats.SizeK(); i++)
1277  {
1278  emb_tr.SetPointMat(pmats(i));
1279  // Get the local interpolation matrix for this refinement type
1280  fine_fe->GetTransferMatrix(*coarse_fe, emb_tr, lP(i));
1281  // Get the local mass matrix for this refinement type
1282  mass_integ->AssembleElementMatrix(*fine_fe, emb_tr, lM(i));
1283  }
1284  }
1285 
1286  Table ref_type_to_matrix;
1287  rtrans.GetCoarseToFineMap(*f_mesh, coarse_to_fine, coarse_to_ref_type,
1288  ref_type_to_matrix, ref_type_to_geom);
1289  MFEM_ASSERT(coarse_to_fine.Size() == c_fes->GetNE(), "");
1290 
1291  const int total_ref_types = ref_type_to_geom.Size();
1292  int num_ref_types[Geometry::NumGeom], num_fine_elems[Geometry::NumGeom];
1293  Array<int> ref_type_to_coarse_elem_offset(total_ref_types);
1294  ref_type_to_fine_elem_offset.SetSize(total_ref_types);
1295  std::fill(num_ref_types, num_ref_types+Geometry::NumGeom, 0);
1296  std::fill(num_fine_elems, num_fine_elems+Geometry::NumGeom, 0);
1297  for (int i = 0; i < total_ref_types; i++)
1298  {
1299  Geometry::Type g = ref_type_to_geom[i];
1300  ref_type_to_coarse_elem_offset[i] = num_ref_types[g];
1301  ref_type_to_fine_elem_offset[i] = num_fine_elems[g];
1302  num_ref_types[g]++;
1303  num_fine_elems[g] += ref_type_to_matrix.RowSize(i);
1304  }
1305  DenseTensor localPtMP[Geometry::NumGeom];
1306  for (int g = 0; g < Geometry::NumGeom; g++)
1307  {
1308  if (num_ref_types[g] == 0) { continue; }
1309  const int fine_dofs = localP[g].SizeI();
1310  const int coarse_dofs = localP[g].SizeJ();
1311  localPtMP[g].SetSize(coarse_dofs, coarse_dofs, num_ref_types[g]);
1312  localR[g].SetSize(coarse_dofs, fine_dofs, num_fine_elems[g]);
1313  }
1314  for (int i = 0; i < total_ref_types; i++)
1315  {
1316  Geometry::Type g = ref_type_to_geom[i];
1317  DenseMatrix &lPtMP = localPtMP[g](ref_type_to_coarse_elem_offset[i]);
1318  int lR_offset = ref_type_to_fine_elem_offset[i]; // offset in localR[g]
1319  const int *mi = ref_type_to_matrix.GetRow(i);
1320  const int nm = ref_type_to_matrix.RowSize(i);
1321  lPtMP = 0.0;
1322  for (int s = 0; s < nm; s++)
1323  {
1324  DenseMatrix &lP = localP[g](mi[s]);
1325  DenseMatrix &lM = localM[g](mi[s]);
1326  DenseMatrix &lR = localR[g](lR_offset+s);
1327  MultAtB(lP, lM, lR); // lR = lP^T lM
1328  AddMult(lR, lP, lPtMP); // lPtMP += lP^T lM lP
1329  }
1330  DenseMatrixInverse lPtMP_inv(lPtMP);
1331  for (int s = 0; s < nm; s++)
1332  {
1333  DenseMatrix &lR = localR[g](lR_offset+s);
1334  lPtMP_inv.Mult(lR); // lR <- (P^T M P)^{-1} P^T M
1335  }
1336  }
1337 
1338  // Make a copy of the coarse element-to-dof Table.
1339  coarse_elem_dof = new Table(c_fes->GetElementToDofTable());
1340 }
1341 
1343 {
1344  delete coarse_elem_dof;
1345 }
1346 
1348 ::Mult(const Vector &x, Vector &y) const
1349 {
1350  Array<int> c_vdofs, f_vdofs;
1351  Vector loc_x, loc_y;
1352  DenseMatrix loc_x_mat, loc_y_mat;
1353  const int vdim = fine_fes->GetVDim();
1354  const int coarse_ndofs = height/vdim;
1355  for (int coarse_el = 0; coarse_el < coarse_to_fine.Size(); coarse_el++)
1356  {
1357  coarse_elem_dof->GetRow(coarse_el, c_vdofs);
1358  fine_fes->DofsToVDofs(c_vdofs, coarse_ndofs);
1359  loc_y.SetSize(c_vdofs.Size());
1360  loc_y = 0.0;
1361  loc_y_mat.UseExternalData(loc_y.GetData(), c_vdofs.Size()/vdim, vdim);
1362  const int ref_type = coarse_to_ref_type[coarse_el];
1363  const Geometry::Type geom = ref_type_to_geom[ref_type];
1364  const int *fine_elems = coarse_to_fine.GetRow(coarse_el);
1365  const int num_fine_elems = coarse_to_fine.RowSize(coarse_el);
1366  const int lR_offset = ref_type_to_fine_elem_offset[ref_type];
1367  for (int s = 0; s < num_fine_elems; s++)
1368  {
1369  const DenseMatrix &lR = localR[geom](lR_offset+s);
1370  fine_fes->GetElementVDofs(fine_elems[s], f_vdofs);
1371  x.GetSubVector(f_vdofs, loc_x);
1372  loc_x_mat.UseExternalData(loc_x.GetData(), f_vdofs.Size()/vdim, vdim);
1373  AddMult(lR, loc_x_mat, loc_y_mat);
1374  }
1375  y.SetSubVector(c_vdofs, loc_y);
1376  }
1377 }
1378 
1380  DenseTensor &localR) const
1381 {
1382  const FiniteElement *fe = fec->FiniteElementForGeometry(geom);
1383 
1384  const CoarseFineTransformations &dtrans =
1386  const DenseTensor &pmats = dtrans.point_matrices[geom];
1387 
1388  const int nmat = pmats.SizeK();
1389  const int ldof = fe->GetDof();
1390 
1392  isotr.SetIdentityTransformation(geom);
1393 
1394  // calculate local restriction matrices for all refinement types
1395  localR.SetSize(ldof, ldof, nmat);
1396  for (int i = 0; i < nmat; i++)
1397  {
1398  isotr.SetPointMat(pmats(i));
1399  fe->GetLocalRestriction(isotr, localR(i));
1400  }
1401 }
1402 
1404  const Table* old_elem_dof)
1405 {
1406  MFEM_VERIFY(Nonconforming(), "Not implemented for conforming meshes.");
1407  MFEM_VERIFY(old_ndofs, "Missing previous (finer) space.");
1408  MFEM_VERIFY(ndofs <= old_ndofs, "Previous space is not finer.");
1409 
1410  Array<int> dofs, old_dofs, old_vdofs;
1411  Vector row;
1412 
1413  Mesh::GeometryList elem_geoms(*mesh);
1414 
1416  for (int i = 0; i < elem_geoms.Size(); i++)
1417  {
1418  GetLocalDerefinementMatrices(elem_geoms[i], localR[elem_geoms[i]]);
1419  }
1420 
1421  SparseMatrix *R = (elem_geoms.Size() != 1)
1422  ? new SparseMatrix(ndofs*vdim, old_ndofs*vdim) // variable row size
1423  : new SparseMatrix(ndofs*vdim, old_ndofs*vdim,
1424  localR[elem_geoms[0]].SizeI());
1425 
1426  Array<int> mark(R->Height());
1427  mark = 0;
1428 
1429  const CoarseFineTransformations &dtrans =
1431 
1432  MFEM_ASSERT(dtrans.embeddings.Size() == old_elem_dof->Size(), "");
1433 
1434  int num_marked = 0;
1435  for (int k = 0; k < dtrans.embeddings.Size(); k++)
1436  {
1437  const Embedding &emb = dtrans.embeddings[k];
1439  DenseMatrix &lR = localR[geom](emb.matrix);
1440 
1441  elem_dof->GetRow(emb.parent, dofs);
1442  old_elem_dof->GetRow(k, old_dofs);
1443 
1444  for (int vd = 0; vd < vdim; vd++)
1445  {
1446  old_dofs.Copy(old_vdofs);
1447  DofsToVDofs(vd, old_vdofs, old_ndofs);
1448 
1449  for (int i = 0; i < lR.Height(); i++)
1450  {
1451  if (!std::isfinite(lR(i, 0))) { continue; }
1452 
1453  int r = DofToVDof(dofs[i], vd);
1454  int m = (r >= 0) ? r : (-1 - r);
1455 
1456  if (!mark[m])
1457  {
1458  lR.GetRow(i, row);
1459  R->SetRow(r, old_vdofs, row);
1460  mark[m] = 1;
1461  num_marked++;
1462  }
1463  }
1464  }
1465  }
1466 
1467  MFEM_VERIFY(num_marked == R->Height(),
1468  "internal error: not all rows of R were set.");
1469 
1470  R->Finalize(); // no-op if fixed width
1471  return R;
1472 }
1473 
1475  const FiniteElementSpace &coarse_fes, Geometry::Type geom,
1476  DenseTensor &localP) const
1477 {
1478  // Assumptions: see the declaration of the method.
1479 
1480  const FiniteElement *fine_fe = fec->FiniteElementForGeometry(geom);
1481  const FiniteElement *coarse_fe =
1482  coarse_fes.fec->FiniteElementForGeometry(geom);
1483 
1485  const DenseTensor &pmats = rtrans.point_matrices[geom];
1486 
1487  int nmat = pmats.SizeK();
1488 
1490  isotr.SetIdentityTransformation(geom);
1491 
1492  // Calculate the local interpolation matrices for all refinement types
1493  localP.SetSize(fine_fe->GetDof(), coarse_fe->GetDof(), nmat);
1494  for (int i = 0; i < nmat; i++)
1495  {
1496  isotr.SetPointMat(pmats(i));
1497  fine_fe->GetTransferMatrix(*coarse_fe, isotr, localP(i));
1498  }
1499 }
1500 
1503  int vdim, int ordering)
1504 {
1505  this->mesh = mesh;
1506  this->fec = fec;
1507  this->vdim = vdim;
1508  this->ordering = (Ordering::Type) ordering;
1509 
1510  elem_dof = NULL;
1511  face_dof = NULL;
1512  sequence = mesh->GetSequence();
1514 
1515  const NURBSFECollection *nurbs_fec =
1516  dynamic_cast<const NURBSFECollection *>(fec);
1517  if (nurbs_fec)
1518  {
1519  if (!mesh->NURBSext)
1520  {
1521  mfem_error("FiniteElementSpace::FiniteElementSpace :\n"
1522  " NURBS FE space requires NURBS mesh.");
1523  }
1524 
1525  if (NURBSext == NULL)
1526  {
1527  this->NURBSext = mesh->NURBSext;
1528  own_ext = 0;
1529  }
1530  else
1531  {
1532  this->NURBSext = NURBSext;
1533  own_ext = 1;
1534  }
1535  UpdateNURBS();
1536  cP = cR = NULL;
1537  cP_is_set = false;
1538  }
1539  else
1540  {
1541  this->NURBSext = NULL;
1542  own_ext = 0;
1543  Construct();
1544  }
1546 }
1547 
1549 {
1550  if (NURBSext && !own_ext)
1551  {
1552  mfem_error("FiniteElementSpace::StealNURBSext");
1553  }
1554  own_ext = 0;
1555 
1556  return NURBSext;
1557 }
1558 
1560 {
1561  MFEM_VERIFY(NURBSext, "NURBSExt not defined.");
1562 
1563  nvdofs = 0;
1564  nedofs = 0;
1565  nfdofs = 0;
1566  nbdofs = 0;
1567  fdofs = NULL;
1568  bdofs = NULL;
1569 
1570  delete face_dof;
1571  face_dof = NULL;
1573 
1574  dynamic_cast<const NURBSFECollection *>(fec)->Reset();
1575 
1576  ndofs = NURBSext->GetNDof();
1579 }
1580 
1582 {
1583  if (face_dof) { return; }
1584 
1585  const int dim = mesh->Dimension();
1586 
1587  // Find bdr to face mapping
1589  face_to_be = -1;
1590  for (int b = 0; b < GetNBE(); b++)
1591  {
1592  int f = mesh->GetBdrElementEdgeIndex(b);
1593  face_to_be[f] = b;
1594  }
1595 
1596  // Loop over faces in correct order, to prevent a sort
1597  // Sort will destroy orientation info in ordering of dofs
1598  Array<Connection> face_dof_list;
1599  Array<int> row;
1600  for (int f = 0; f < GetNF(); f++)
1601  {
1602  int b = face_to_be[f];
1603  if (b == -1) { continue; }
1604  // FIXME: this assumes the boundary element and the face element have the
1605  // same orientation.
1606  if (dim > 1)
1607  {
1608  const Element *fe = mesh->GetFace(f);
1609  const Element *be = mesh->GetBdrElement(b);
1610  const int nv = be->GetNVertices();
1611  const int *fv = fe->GetVertices();
1612  const int *bv = be->GetVertices();
1613  for (int i = 0; i < nv; i++)
1614  {
1615  MFEM_VERIFY(fv[i] == bv[i],
1616  "non-matching face and boundary elements detected!");
1617  }
1618  }
1619  GetBdrElementDofs(b, row);
1620  Connection conn(f,0);
1621  for (int i = 0; i < row.Size(); i++)
1622  {
1623  conn.to = row[i];
1624  face_dof_list.Append(conn);
1625  }
1626  }
1627  face_dof = new Table(GetNF(), face_dof_list);
1628 }
1629 
1631 {
1632  // This method should be used only for non-NURBS spaces.
1633  MFEM_VERIFY(!NURBSext, "internal error");
1634 
1635  elem_dof = NULL;
1636  bdrElem_dof = NULL;
1637  face_dof = NULL;
1638 
1639  ndofs = 0;
1640  nedofs = nfdofs = nbdofs = 0;
1641  bdofs = NULL;
1642  fdofs = NULL;
1643  cP = NULL;
1644  cR = NULL;
1645  cP_is_set = false;
1646  // 'Th' is initialized/destroyed before this method is called.
1647 
1649 
1650  if (mesh->Dimension() > 1)
1651  {
1653  }
1654 
1655  if (mesh->GetNFaces() > 0)
1656  {
1657  bool have_face_dofs = false;
1658  for (int g = Geometry::DimStart[2]; g < Geometry::DimStart[3]; g++)
1659  {
1660  if (mesh->HasGeometry(Geometry::Type(g)) &&
1662  {
1663  have_face_dofs = true;
1664  break;
1665  }
1666  }
1667  if (have_face_dofs)
1668  {
1669  fdofs = new int[mesh->GetNFaces()+1];
1670  fdofs[0] = 0;
1671  for (int i = 0; i < mesh->GetNFaces(); i++)
1672  {
1674  fdofs[i+1] = nfdofs;
1675  }
1676  }
1677  }
1678 
1679  if (mesh->Dimension() > 0)
1680  {
1681  bdofs = new int[mesh->GetNE()+1];
1682  bdofs[0] = 0;
1683  for (int i = 0; i < mesh->GetNE(); i++)
1684  {
1686  bdofs[i+1] = nbdofs;
1687  }
1688  }
1689 
1690  ndofs = nvdofs + nedofs + nfdofs + nbdofs;
1691 
1692  // Do not build elem_dof Table here: in parallel it has to be constructed
1693  // later.
1694 }
1695 
1697 {
1698  if (elem_dof)
1699  {
1700  elem_dof -> GetRow (i, dofs);
1701  }
1702  else
1703  {
1704  Array<int> V, E, Eo, F, Fo;
1705  int k, j, nv, ne, nf, nb, nfd, nd, dim;
1706  const int *ind;
1707 
1708  dim = mesh->Dimension();
1710  ne = (dim > 1) ? ( fec->DofForGeometry(Geometry::SEGMENT) ) : ( 0 );
1711  nb = (dim > 0) ? fec->DofForGeometry(mesh->GetElementBaseGeometry(i)) : 0;
1712  if (nv > 0)
1713  {
1714  mesh->GetElementVertices(i, V);
1715  }
1716  if (ne > 0)
1717  {
1718  mesh->GetElementEdges(i, E, Eo);
1719  }
1720  nfd = 0;
1721  if (dim == 3)
1722  {
1724  {
1725  mesh->GetElementFaces(i, F, Fo);
1726  for (k = 0; k < F.Size(); k++)
1727  {
1728  nfd += fec->DofForGeometry(mesh->GetFaceBaseGeometry(F[k]));
1729  }
1730  }
1731  }
1732  nd = V.Size() * nv + E.Size() * ne + nfd + nb;
1733  dofs.SetSize(nd);
1734  if (nv > 0)
1735  {
1736  for (k = 0; k < V.Size(); k++)
1737  {
1738  for (j = 0; j < nv; j++)
1739  {
1740  dofs[k*nv+j] = V[k]*nv+j;
1741  }
1742  }
1743  nv *= V.Size();
1744  }
1745  if (ne > 0)
1746  {
1747  // if (dim > 1)
1748  for (k = 0; k < E.Size(); k++)
1749  {
1751  for (j = 0; j < ne; j++)
1752  {
1753  if (ind[j] < 0)
1754  {
1755  dofs[nv+k*ne+j] = -1 - ( nvdofs+E[k]*ne+(-1-ind[j]) );
1756  }
1757  else
1758  {
1759  dofs[nv+k*ne+j] = nvdofs+E[k]*ne+ind[j];
1760  }
1761  }
1762  }
1763  }
1764  ne = nv + ne * E.Size();
1765  if (nfd > 0)
1766  // if (dim == 3)
1767  {
1768  for (k = 0; k < F.Size(); k++)
1769  {
1771  Fo[k]);
1773  for (j = 0; j < nf; j++)
1774  {
1775  if (ind[j] < 0)
1776  {
1777  dofs[ne+j] = -1 - ( nvdofs+nedofs+fdofs[F[k]]+(-1-ind[j]) );
1778  }
1779  else
1780  {
1781  dofs[ne+j] = nvdofs+nedofs+fdofs[F[k]]+ind[j];
1782  }
1783  }
1784  ne += nf;
1785  }
1786  }
1787  if (nb > 0)
1788  {
1789  k = nvdofs + nedofs + nfdofs + bdofs[i];
1790  for (j = 0; j < nb; j++)
1791  {
1792  dofs[ne+j] = k + j;
1793  }
1794  }
1795  }
1796 }
1797 
1799 {
1800  if (i < 0 || !mesh->GetNE()) { return NULL; }
1801  MFEM_VERIFY(i < mesh->GetNE(),
1802  "Invalid element id " << i << ", maximum allowed " << mesh->GetNE()-1);
1803 
1804  const FiniteElement *FE =
1806 
1807  if (NURBSext)
1808  {
1809  NURBSext->LoadFE(i, FE);
1810  }
1811 
1812  return FE;
1813 }
1814 
1816 {
1817  if (bdrElem_dof)
1818  {
1819  bdrElem_dof->GetRow(i, dofs);
1820  }
1821  else
1822  {
1823  Array<int> V, E, Eo;
1824  int k, j, nv, ne, nf, nd, iF, oF, dim;
1825  const int *ind;
1826 
1827  dim = mesh->Dimension();
1829  if (nv > 0)
1830  {
1831  mesh->GetBdrElementVertices(i, V);
1832  }
1833  ne = (dim > 1) ? ( fec->DofForGeometry(Geometry::SEGMENT) ) : ( 0 );
1834  if (ne > 0)
1835  {
1836  mesh->GetBdrElementEdges(i, E, Eo);
1837  }
1838  nd = V.Size() * nv + E.Size() * ne;
1839  nf = (dim == 3) ? (fec->DofForGeometry(
1840  mesh->GetBdrElementBaseGeometry(i))) : (0);
1841  if (nf > 0)
1842  {
1843  nd += nf;
1844  mesh->GetBdrElementFace(i, &iF, &oF);
1845  }
1846  dofs.SetSize(nd);
1847  if (nv > 0)
1848  {
1849  for (k = 0; k < V.Size(); k++)
1850  {
1851  for (j = 0; j < nv; j++)
1852  {
1853  dofs[k*nv+j] = V[k]*nv+j;
1854  }
1855  }
1856  nv *= V.Size();
1857  }
1858  if (ne > 0)
1859  {
1860  // if (dim > 1)
1861  for (k = 0; k < E.Size(); k++)
1862  {
1864  for (j = 0; j < ne; j++)
1865  {
1866  if (ind[j] < 0)
1867  {
1868  dofs[nv+k*ne+j] = -1 - ( nvdofs+E[k]*ne+(-1-ind[j]) );
1869  }
1870  else
1871  {
1872  dofs[nv+k*ne+j] = nvdofs+E[k]*ne+ind[j];
1873  }
1874  }
1875  }
1876  }
1877  if (nf > 0)
1878  // if (dim == 3)
1879  {
1880  ne = nv + ne * E.Size();
1881  ind = fec->DofOrderForOrientation(
1883  for (j = 0; j < nf; j++)
1884  {
1885  if (ind[j] < 0)
1886  {
1887  dofs[ne+j] = -1 - ( nvdofs+nedofs+fdofs[iF]+(-1-ind[j]) );
1888  }
1889  else
1890  {
1891  dofs[ne+j] = nvdofs+nedofs+fdofs[iF]+ind[j];
1892  }
1893  }
1894  }
1895  }
1896 }
1897 
1899 {
1900  // If face_dof is already built, use it.
1901  // If it is not and we have a NURBS space, build the face_dof and use it.
1902  if (face_dof || (NURBSext && (BuildNURBSFaceToDofTable(), true)))
1903  {
1904  face_dof->GetRow(i, dofs);
1905  }
1906  else
1907  {
1908  int j, k, nv, ne, nf, nd, dim = mesh->Dimension();
1909  Array<int> V, E, Eo;
1910  const int *ind;
1911 
1912  // for 1D, 2D and 3D faces
1914  ne = (dim > 1) ? fec->DofForGeometry(Geometry::SEGMENT) : 0;
1915  if (nv > 0)
1916  {
1917  mesh->GetFaceVertices(i, V);
1918  }
1919  if (ne > 0)
1920  {
1921  mesh->GetFaceEdges(i, E, Eo);
1922  }
1923  nf = (fdofs) ? (fdofs[i+1]-fdofs[i]) : (0);
1924  nd = V.Size() * nv + E.Size() * ne + nf;
1925  dofs.SetSize(nd);
1926  if (nv > 0)
1927  {
1928  for (k = 0; k < V.Size(); k++)
1929  {
1930  for (j = 0; j < nv; j++)
1931  {
1932  dofs[k*nv+j] = V[k]*nv+j;
1933  }
1934  }
1935  }
1936  nv *= V.Size();
1937  if (ne > 0)
1938  {
1939  for (k = 0; k < E.Size(); k++)
1940  {
1942  for (j = 0; j < ne; j++)
1943  {
1944  if (ind[j] < 0)
1945  {
1946  dofs[nv+k*ne+j] = -1 - ( nvdofs+E[k]*ne+(-1-ind[j]) );
1947  }
1948  else
1949  {
1950  dofs[nv+k*ne+j] = nvdofs+E[k]*ne+ind[j];
1951  }
1952  }
1953  }
1954  }
1955  ne = nv + ne * E.Size();
1956  if (nf > 0)
1957  {
1958  for (j = nvdofs+nedofs+fdofs[i], k = 0; k < nf; j++, k++)
1959  {
1960  dofs[ne+k] = j;
1961  }
1962  }
1963  }
1964 }
1965 
1967 {
1968  int j, k, nv, ne;
1969  Array<int> V;
1970 
1972  if (nv > 0)
1973  {
1974  mesh->GetEdgeVertices(i, V);
1975  }
1977  dofs.SetSize(2*nv+ne);
1978  if (nv > 0)
1979  {
1980  for (k = 0; k < 2; k++)
1981  {
1982  for (j = 0; j < nv; j++)
1983  {
1984  dofs[k*nv+j] = V[k]*nv+j;
1985  }
1986  }
1987  }
1988  nv *= 2;
1989  for (j = 0, k = nvdofs+i*ne; j < ne; j++, k++)
1990  {
1991  dofs[nv+j] = k;
1992  }
1993 }
1994 
1996 {
1997  int j, nv;
1998 
2000  dofs.SetSize(nv);
2001  for (j = 0; j < nv; j++)
2002  {
2003  dofs[j] = i*nv+j;
2004  }
2005 }
2006 
2008 {
2009  int j, k, nb;
2010  if (mesh->Dimension() == 0) { dofs.SetSize(0); return; }
2011  nb = fec -> DofForGeometry (mesh -> GetElementBaseGeometry (i));
2012  dofs.SetSize (nb);
2013  k = nvdofs + nedofs + nfdofs + bdofs[i];
2014  for (j = 0; j < nb; j++)
2015  {
2016  dofs[j] = k + j;
2017  }
2018 }
2019 
2021 {
2022  int j, k, ne;
2023 
2024  ne = fec -> DofForGeometry (Geometry::SEGMENT);
2025  dofs.SetSize (ne);
2026  for (j = 0, k = nvdofs+i*ne; j < ne; j++, k++)
2027  {
2028  dofs[j] = k;
2029  }
2030 }
2031 
2033 {
2034  int j, k, nf;
2035 
2036  nf = (fdofs) ? (fdofs[i+1]-fdofs[i]) : (0);
2037  dofs.SetSize (nf);
2038  if (nf > 0)
2039  {
2040  for (j = 0, k = nvdofs+nedofs+fdofs[i]; j < nf; j++, k++)
2041  {
2042  dofs[j] = k;
2043  }
2044  }
2045 }
2046 
2048 {
2049  const FiniteElement *BE;
2050 
2051  switch ( mesh->Dimension() )
2052  {
2053  case 1:
2055  break;
2056  case 2:
2058  break;
2059  case 3:
2060  default:
2063  }
2064 
2065  if (NURBSext)
2066  {
2067  NURBSext->LoadBE(i, BE);
2068  }
2069 
2070  return BE;
2071 }
2072 
2074 {
2075  const FiniteElement *fe;
2076 
2077  switch (mesh->Dimension())
2078  {
2079  case 1:
2081  break;
2082  case 2:
2084  break;
2085  case 3:
2086  default:
2088  }
2089 
2090  if (NURBSext)
2091  {
2092  // Ensure 'face_to_be' is built:
2093  if (!face_dof) { BuildNURBSFaceToDofTable(); }
2094  MFEM_ASSERT(face_to_be[i] >= 0,
2095  "NURBS mesh: only boundary faces are supported!");
2096  NURBSext->LoadBE(face_to_be[i], fe);
2097  }
2098 
2099  return fe;
2100 }
2101 
2103 {
2104  MFEM_ASSERT(mesh->Dimension() > 1, "No edges with a mesh dimension < 2");
2106 }
2107 
2109  int i, Geometry::Type geom_type) const
2110 {
2111  return fec->TraceFiniteElementForGeometry(geom_type);
2112 }
2113 
2115 {
2116  Destroy();
2117 }
2118 
2120 {
2121  delete cR;
2122  delete cP;
2123  Th.Clear();
2124  L2E_nat.Clear();
2125  L2E_lex.Clear();
2126  for (int i = 0; i < E2Q_array.Size(); i++)
2127  {
2128  delete E2Q_array[i];
2129  }
2130  E2Q_array.SetSize(0);
2131  for (auto &x : L2F)
2132  {
2133  delete x.second;
2134  }
2135  for (int i = 0; i < E2IFQ_array.Size(); i++)
2136  {
2137  delete E2IFQ_array[i];
2138  }
2139  E2IFQ_array.SetSize(0);
2140  for (int i = 0; i < E2BFQ_array.Size(); i++)
2141  {
2142  delete E2BFQ_array[i];
2143  }
2144  E2BFQ_array.SetSize(0);
2145 
2148 
2149  if (NURBSext)
2150  {
2151  if (own_ext) { delete NURBSext; }
2152  delete face_dof;
2154  }
2155  else
2156  {
2157  delete elem_dof;
2158  delete bdrElem_dof;
2159  delete face_dof;
2160 
2161  delete [] bdofs;
2162  delete [] fdofs;
2163  }
2164  RemoveCeedBasisAndRestriction(this);
2165 }
2166 
2168  const FiniteElementSpace &coarse_fes, OperatorHandle &T) const
2169 {
2170  // Assumptions: see the declaration of the method.
2171 
2172  if (T.Type() == Operator::MFEM_SPARSEMAT)
2173  {
2174  Mesh::GeometryList elem_geoms(*mesh);
2175 
2177  for (int i = 0; i < elem_geoms.Size(); i++)
2178  {
2179  GetLocalRefinementMatrices(coarse_fes, elem_geoms[i],
2180  localP[elem_geoms[i]]);
2181  }
2182  T.Reset(RefinementMatrix_main(coarse_fes.GetNDofs(),
2183  coarse_fes.GetElementToDofTable(),
2184  localP));
2185  }
2186  else
2187  {
2188  T.Reset(new RefinementOperator(this, &coarse_fes));
2189  }
2190 }
2191 
2193  const FiniteElementSpace &coarse_fes, OperatorHandle &T) const
2194 {
2195  const SparseMatrix *coarse_P = coarse_fes.GetConformingProlongation();
2196 
2197  Operator::Type req_type = T.Type();
2198  GetTransferOperator(coarse_fes, T);
2199 
2200  if (req_type == Operator::MFEM_SPARSEMAT)
2201  {
2203  {
2204  T.Reset(mfem::Mult(*cR, *T.As<SparseMatrix>()));
2205  }
2206  if (coarse_P)
2207  {
2208  T.Reset(mfem::Mult(*T.As<SparseMatrix>(), *coarse_P));
2209  }
2210  }
2211  else
2212  {
2213  const int RP_case = bool(GetConformingRestriction()) + 2*bool(coarse_P);
2214  if (RP_case == 0) { return; }
2215  const bool owner = T.OwnsOperator();
2216  T.SetOperatorOwner(false);
2217  switch (RP_case)
2218  {
2219  case 1:
2220  T.Reset(new ProductOperator(cR, T.Ptr(), false, owner));
2221  break;
2222  case 2:
2223  T.Reset(new ProductOperator(T.Ptr(), coarse_P, owner, false));
2224  break;
2225  case 3:
2227  cR, T.Ptr(), coarse_P, false, owner, false));
2228  break;
2229  }
2230  }
2231 }
2232 
2233 void FiniteElementSpace::Update(bool want_transform)
2234 {
2235  if (mesh->GetSequence() == sequence)
2236  {
2237  return; // mesh and space are in sync, no-op
2238  }
2239  if (want_transform && mesh->GetSequence() != sequence + 1)
2240  {
2241  MFEM_ABORT("Error in update sequence. Space needs to be updated after "
2242  "each mesh modification.");
2243  }
2244  sequence = mesh->GetSequence();
2245 
2246  if (NURBSext)
2247  {
2248  UpdateNURBS();
2249  return;
2250  }
2251 
2252  Table* old_elem_dof = NULL;
2253  int old_ndofs;
2254 
2255  // save old DOF table
2256  if (want_transform)
2257  {
2258  old_elem_dof = elem_dof;
2259  elem_dof = NULL;
2260  old_ndofs = ndofs;
2261  }
2262 
2263  Destroy(); // calls Th.Clear()
2264  Construct();
2266 
2267  if (want_transform)
2268  {
2269  // calculate appropriate GridFunction transformation
2270  switch (mesh->GetLastOperation())
2271  {
2272  case Mesh::REFINE:
2273  {
2274  if (Th.Type() != Operator::MFEM_SPARSEMAT)
2275  {
2276  Th.Reset(new RefinementOperator(this, old_elem_dof, old_ndofs));
2277  // The RefinementOperator takes ownership of 'old_elem_dof', so
2278  // we no longer own it:
2279  old_elem_dof = NULL;
2280  }
2281  else
2282  {
2283  // calculate fully assembled matrix
2284  Th.Reset(RefinementMatrix(old_ndofs, old_elem_dof));
2285  }
2286  break;
2287  }
2288 
2289  case Mesh::DEREFINE:
2290  {
2292  Th.Reset(DerefinementMatrix(old_ndofs, old_elem_dof));
2293  if (cP && cR)
2294  {
2295  Th.SetOperatorOwner(false);
2297  false, false, true));
2298  }
2299  break;
2300  }
2301 
2302  default:
2303  break;
2304  }
2305 
2306  delete old_elem_dof;
2307  }
2308 }
2309 
2310 void FiniteElementSpace::Save(std::ostream &out) const
2311 {
2312  int fes_format = 90; // the original format, v0.9
2313  bool nurbs_unit_weights = false;
2314 
2315  // Determine the format that should be used.
2316  if (!NURBSext)
2317  {
2318  // TODO: if this is a variable-order FE space, use fes_format = 100.
2319  }
2320  else
2321  {
2322  const NURBSFECollection *nurbs_fec =
2323  dynamic_cast<const NURBSFECollection *>(fec);
2324  MFEM_VERIFY(nurbs_fec, "invalid FE collection");
2325  nurbs_fec->SetOrder(NURBSext->GetOrder());
2326  const double eps = 5e-14;
2327  nurbs_unit_weights = (NURBSext->GetWeights().Min() >= 1.0-eps &&
2328  NURBSext->GetWeights().Max() <= 1.0+eps);
2330  (NURBSext != mesh->NURBSext && !nurbs_unit_weights) ||
2331  (NURBSext->GetMaster().Size() != 0 ))
2332  {
2333  fes_format = 100; // v1.0 format
2334  }
2335  }
2336 
2337  out << (fes_format == 90 ?
2338  "FiniteElementSpace\n" : "MFEM FiniteElementSpace v1.0\n")
2339  << "FiniteElementCollection: " << fec->Name() << '\n'
2340  << "VDim: " << vdim << '\n'
2341  << "Ordering: " << ordering << '\n';
2342 
2343  if (fes_format == 100) // v1.0
2344  {
2345  if (!NURBSext)
2346  {
2347  // TODO: this is a variable-order FE space --> write 'element_orders'.
2348  }
2349  else if (NURBSext != mesh->NURBSext)
2350  {
2352  {
2353  out << "NURBS_order\n" << NURBSext->GetOrder() << '\n';
2354  }
2355  else
2356  {
2357  out << "NURBS_orders\n";
2358  // 1 = do not write the size, just the entries:
2359  NURBSext->GetOrders().Save(out, 1);
2360  }
2361  // If periodic BCs are given, write connectivity
2362  if (NURBSext->GetMaster().Size() != 0 )
2363  {
2364  out <<"NURBS_periodic\n";
2365  NURBSext->GetMaster().Save(out);
2366  NURBSext->GetSlave().Save(out);
2367  }
2368  // If the weights are not unit, write them to the output:
2369  if (!nurbs_unit_weights)
2370  {
2371  out << "NURBS_weights\n";
2372  NURBSext->GetWeights().Print(out, 1);
2373  }
2374  }
2375  out << "End: MFEM FiniteElementSpace v1.0\n";
2376  }
2377 }
2378 
2380 {
2381  string buff;
2382  int fes_format = 0, ord;
2383  FiniteElementCollection *r_fec;
2384 
2385  Destroy();
2386 
2387  input >> std::ws;
2388  getline(input, buff); // 'FiniteElementSpace'
2389  filter_dos(buff);
2390  if (buff == "FiniteElementSpace") { fes_format = 90; /* v0.9 */ }
2391  else if (buff == "MFEM FiniteElementSpace v1.0") { fes_format = 100; }
2392  else { MFEM_ABORT("input stream is not a FiniteElementSpace!"); }
2393  getline(input, buff, ' '); // 'FiniteElementCollection:'
2394  input >> std::ws;
2395  getline(input, buff);
2396  filter_dos(buff);
2397  r_fec = FiniteElementCollection::New(buff.c_str());
2398  getline(input, buff, ' '); // 'VDim:'
2399  input >> vdim;
2400  getline(input, buff, ' '); // 'Ordering:'
2401  input >> ord;
2402 
2403  NURBSFECollection *nurbs_fec = dynamic_cast<NURBSFECollection*>(r_fec);
2404  NURBSExtension *NURBSext = NULL;
2405  if (fes_format == 90) // original format, v0.9
2406  {
2407  if (nurbs_fec)
2408  {
2409  MFEM_VERIFY(m->NURBSext, "NURBS FE collection requires a NURBS mesh!");
2410  const int order = nurbs_fec->GetOrder();
2411  if (order != m->NURBSext->GetOrder() &&
2413  {
2414  NURBSext = new NURBSExtension(m->NURBSext, order);
2415  }
2416  }
2417  }
2418  else if (fes_format == 100) // v1.0
2419  {
2420  while (1)
2421  {
2422  skip_comment_lines(input, '#');
2423  MFEM_VERIFY(input.good(), "error reading FiniteElementSpace v1.0");
2424  getline(input, buff);
2425  filter_dos(buff);
2426  if (buff == "NURBS_order" || buff == "NURBS_orders")
2427  {
2428  MFEM_VERIFY(nurbs_fec,
2429  buff << ": NURBS FE collection is required!");
2430  MFEM_VERIFY(m->NURBSext, buff << ": NURBS mesh is required!");
2431  MFEM_VERIFY(!NURBSext, buff << ": order redefinition!");
2432  if (buff == "NURBS_order")
2433  {
2434  int order;
2435  input >> order;
2436  NURBSext = new NURBSExtension(m->NURBSext, order);
2437  }
2438  else
2439  {
2440  Array<int> orders;
2441  orders.Load(m->NURBSext->GetNKV(), input);
2442  NURBSext = new NURBSExtension(m->NURBSext, orders);
2443  }
2444  }
2445  else if (buff == "NURBS_periodic")
2446  {
2447  Array<int> master, slave;
2448  master.Load(input);
2449  slave.Load(input);
2450  NURBSext->ConnectBoundaries(master,slave);
2451  }
2452  else if (buff == "NURBS_weights")
2453  {
2454  MFEM_VERIFY(NURBSext, "NURBS_weights: NURBS_orders have to be "
2455  "specified before NURBS_weights!");
2456  NURBSext->GetWeights().Load(input, NURBSext->GetNDof());
2457  }
2458  else if (buff == "element_orders")
2459  {
2460  MFEM_VERIFY(!nurbs_fec, "section element_orders cannot be used "
2461  "with a NURBS FE collection");
2462  MFEM_ABORT("element_orders: not implemented yet!");
2463  }
2464  else if (buff == "End: MFEM FiniteElementSpace v1.0")
2465  {
2466  break;
2467  }
2468  else
2469  {
2470  MFEM_ABORT("unknown section: " << buff);
2471  }
2472  }
2473  }
2474 
2475  Constructor(m, NURBSext, r_fec, vdim, ord);
2476 
2477  return r_fec;
2478 }
2479 
2480 
2482 {
2483  // protected method
2484  int offset = 0;
2485  const int num_elem = mesh->GetNE();
2486  element_offsets = new int[num_elem + 1];
2487  for (int g = 0; g < Geometry::NumGeom; g++)
2488  {
2489  int_rule[g] = NULL;
2490  }
2491  for (int i = 0; i < num_elem; i++)
2492  {
2493  element_offsets[i] = offset;
2494  int geom = mesh->GetElementBaseGeometry(i);
2495  if (int_rule[geom] == NULL)
2496  {
2497  int_rule[geom] = &IntRules.Get(geom, order);
2498  }
2499  offset += int_rule[geom]->GetNPoints();
2500  }
2501  element_offsets[num_elem] = size = offset;
2502 }
2503 
2504 QuadratureSpace::QuadratureSpace(Mesh *mesh_, std::istream &in)
2505  : mesh(mesh_)
2506 {
2507  const char *msg = "invalid input stream";
2508  string ident;
2509 
2510  in >> ident; MFEM_VERIFY(ident == "QuadratureSpace", msg);
2511  in >> ident; MFEM_VERIFY(ident == "Type:", msg);
2512  in >> ident;
2513  if (ident == "default_quadrature")
2514  {
2515  in >> ident; MFEM_VERIFY(ident == "Order:", msg);
2516  in >> order;
2517  }
2518  else
2519  {
2520  MFEM_ABORT("unknown QuadratureSpace type: " << ident);
2521  return;
2522  }
2523 
2524  Construct();
2525 }
2526 
2527 void QuadratureSpace::Save(std::ostream &out) const
2528 {
2529  out << "QuadratureSpace\n"
2530  << "Type: default_quadrature\n"
2531  << "Order: " << order << '\n';
2532 }
2533 
2534 
2536  FiniteElementSpace &ran_fes_)
2537  : dom_fes(dom_fes_), ran_fes(ran_fes_),
2538  oper_type(Operator::ANY_TYPE),
2539  fw_t_oper(), bw_t_oper()
2540 {
2541 #ifdef MFEM_USE_MPI
2542  const bool par_dom = dynamic_cast<ParFiniteElementSpace*>(&dom_fes);
2543  const bool par_ran = dynamic_cast<ParFiniteElementSpace*>(&ran_fes);
2544  MFEM_VERIFY(par_dom == par_ran, "the domain and range FE spaces must both"
2545  " be either serial or parallel");
2546  parallel = par_dom;
2547 #endif
2548 }
2549 
2551  FiniteElementSpace &fes_in, FiniteElementSpace &fes_out,
2552  const Operator &oper, OperatorHandle &t_oper)
2553 {
2554  if (t_oper.Ptr())
2555  {
2556  return *t_oper.Ptr();
2557  }
2558 
2559  if (!Parallel())
2560  {
2561  const SparseMatrix *in_cP = fes_in.GetConformingProlongation();
2562  const SparseMatrix *out_cR = fes_out.GetConformingRestriction();
2564  {
2565  const SparseMatrix *mat = dynamic_cast<const SparseMatrix *>(&oper);
2566  MFEM_VERIFY(mat != NULL, "Operator is not a SparseMatrix");
2567  if (!out_cR)
2568  {
2569  t_oper.Reset(const_cast<SparseMatrix*>(mat), false);
2570  }
2571  else
2572  {
2573  t_oper.Reset(mfem::Mult(*out_cR, *mat));
2574  }
2575  if (in_cP)
2576  {
2577  t_oper.Reset(mfem::Mult(*t_oper.As<SparseMatrix>(), *in_cP));
2578  }
2579  }
2580  else if (oper_type == Operator::ANY_TYPE)
2581  {
2582  const int RP_case = bool(out_cR) + 2*bool(in_cP);
2583  switch (RP_case)
2584  {
2585  case 0:
2586  t_oper.Reset(const_cast<Operator*>(&oper), false);
2587  break;
2588  case 1:
2589  t_oper.Reset(
2590  new ProductOperator(out_cR, &oper, false, false));
2591  break;
2592  case 2:
2593  t_oper.Reset(
2594  new ProductOperator(&oper, in_cP, false, false));
2595  break;
2596  case 3:
2597  t_oper.Reset(
2599  out_cR, &oper, in_cP, false, false, false));
2600  break;
2601  }
2602  }
2603  else
2604  {
2605  MFEM_ABORT("Operator::Type is not supported: " << oper_type);
2606  }
2607  }
2608  else // Parallel() == true
2609  {
2610 #ifdef MFEM_USE_MPI
2611  const SparseMatrix *out_R = fes_out.GetRestrictionMatrix();
2613  {
2614  const ParFiniteElementSpace *pfes_in =
2615  dynamic_cast<const ParFiniteElementSpace *>(&fes_in);
2616  const ParFiniteElementSpace *pfes_out =
2617  dynamic_cast<const ParFiniteElementSpace *>(&fes_out);
2618  const SparseMatrix *sp_mat = dynamic_cast<const SparseMatrix *>(&oper);
2619  const HypreParMatrix *hy_mat;
2620  if (sp_mat)
2621  {
2622  SparseMatrix *RA = mfem::Mult(*out_R, *sp_mat);
2623  t_oper.Reset(pfes_in->Dof_TrueDof_Matrix()->
2624  LeftDiagMult(*RA, pfes_out->GetTrueDofOffsets()));
2625  delete RA;
2626  }
2627  else if ((hy_mat = dynamic_cast<const HypreParMatrix *>(&oper)))
2628  {
2629  HypreParMatrix *RA =
2630  hy_mat->LeftDiagMult(*out_R, pfes_out->GetTrueDofOffsets());
2631  t_oper.Reset(mfem::ParMult(RA, pfes_in->Dof_TrueDof_Matrix()));
2632  delete RA;
2633  }
2634  else
2635  {
2636  MFEM_ABORT("unknown Operator type");
2637  }
2638  }
2639  else if (oper_type == Operator::ANY_TYPE)
2640  {
2641  t_oper.Reset(new TripleProductOperator(
2642  out_R, &oper, fes_in.GetProlongationMatrix(),
2643  false, false, false));
2644  }
2645  else
2646  {
2647  MFEM_ABORT("Operator::Type is not supported: " << oper_type);
2648  }
2649 #endif
2650  }
2651 
2652  return *t_oper.Ptr();
2653 }
2654 
2655 
2657 {
2658  if (own_mass_integ) { delete mass_integ; }
2659 }
2660 
2662  BilinearFormIntegrator *mass_integ_, bool own_mass_integ_)
2663 {
2664  if (own_mass_integ) { delete mass_integ; }
2665 
2666  mass_integ = mass_integ_;
2667  own_mass_integ = own_mass_integ_;
2668 }
2669 
2671 {
2672  if (F.Ptr())
2673  {
2674  return *F.Ptr();
2675  }
2676 
2677  // Construct F
2679  {
2681  }
2682  else if (oper_type == Operator::MFEM_SPARSEMAT)
2683  {
2684  Mesh::GeometryList elem_geoms(*ran_fes.GetMesh());
2685 
2687  for (int i = 0; i < elem_geoms.Size(); i++)
2688  {
2690  localP[elem_geoms[i]]);
2691  }
2694  }
2695  else
2696  {
2697  MFEM_ABORT("Operator::Type is not supported: " << oper_type);
2698  }
2699 
2700  return *F.Ptr();
2701 }
2702 
2704 {
2705  if (B.Ptr())
2706  {
2707  return *B.Ptr();
2708  }
2709 
2710  // Construct B, if not set, define a suitable mass_integ
2711  if (!mass_integ && ran_fes.GetNE() > 0)
2712  {
2713  const FiniteElement *f_fe_0 = ran_fes.GetFE(0);
2714  const int map_type = f_fe_0->GetMapType();
2715  if (map_type == FiniteElement::VALUE ||
2716  map_type == FiniteElement::INTEGRAL)
2717  {
2718  mass_integ = new MassIntegrator;
2719  }
2720  else if (map_type == FiniteElement::H_DIV ||
2721  map_type == FiniteElement::H_CURL)
2722  {
2724  }
2725  else
2726  {
2727  MFEM_ABORT("unknown type of FE space");
2728  }
2729  own_mass_integ = true;
2730  }
2732  {
2734  &ran_fes, &dom_fes, mass_integ));
2735  }
2736  else
2737  {
2738  MFEM_ABORT("Operator::Type is not supported: " << oper_type);
2739  }
2740 
2741  return *B.Ptr();
2742 }
2743 
2744 
2746  const FiniteElementSpace &fes_ho_, const FiniteElementSpace &fes_lor_)
2747  : Operator(fes_lor_.GetVSize(), fes_ho_.GetVSize()),
2748  fes_ho(fes_ho_),
2749  fes_lor(fes_lor_)
2750 {
2751  Mesh *mesh_ho = fes_ho.GetMesh();
2752  MFEM_VERIFY(mesh_ho->GetNumGeometries(mesh_ho->Dimension()) <= 1,
2753  "mixed meshes are not supported");
2754 
2755  // If the local mesh is empty, skip all computations
2756  if (mesh_ho->GetNE() == 0) { return; }
2757 
2758  const FiniteElement *fe_lor = fes_lor.GetFE(0);
2759  const FiniteElement *fe_ho = fes_ho.GetFE(0);
2760  ndof_lor = fe_lor->GetDof();
2761  ndof_ho = fe_ho->GetDof();
2762 
2763  const int nel_lor = fes_lor.GetNE();
2764  const int nel_ho = fes_ho.GetNE();
2765 
2766  nref = nel_lor/nel_ho;
2767 
2768  // Construct the mapping from HO to LOR
2769  // ho2lor.GetRow(iho) will give all the LOR elements contained in iho
2770  ho2lor.SetSize(nel_ho, nref);
2771  const CoarseFineTransformations &cf_tr =
2772  fes_lor.GetMesh()->GetRefinementTransforms();
2773  for (int ilor=0; ilor<nel_lor; ++ilor)
2774  {
2775  int iho = cf_tr.embeddings[ilor].parent;
2776  ho2lor.AddConnection(iho, ilor);
2777  }
2778  ho2lor.ShiftUpI();
2779 
2780  // R will contain the restriction (L^2 projection operator) defined on
2781  // each coarse HO element (and corresponding patch of LOR elements)
2782  R.SetSize(ndof_lor*nref, ndof_ho, nel_ho);
2783  // P will contain the corresponding prolongation operator
2784  P.SetSize(ndof_ho, ndof_lor*nref, nel_ho);
2785 
2786  DenseMatrix Minv_lor(ndof_lor*nref, ndof_lor*nref);
2787  DenseMatrix M_mixed(ndof_lor*nref, ndof_ho);
2788 
2789  MassIntegrator mi;
2790  DenseMatrix M_lor_el(ndof_lor, ndof_lor);
2791  DenseMatrixInverse Minv_lor_el(&M_lor_el);
2792  DenseMatrix M_lor(ndof_lor*nref, ndof_lor*nref);
2793  DenseMatrix M_mixed_el(ndof_lor, ndof_ho);
2794 
2795  Minv_lor = 0.0;
2796  M_lor = 0.0;
2797 
2798  DenseMatrix RtMlor(ndof_ho, ndof_lor*nref);
2799  DenseMatrix RtMlorR(ndof_ho, ndof_ho);
2800  DenseMatrixInverse RtMlorR_inv(&RtMlorR);
2801 
2803  IsoparametricTransformation &emb_tr = ip_tr.Transf;
2804 
2805  Vector shape_ho(ndof_ho);
2806  Vector shape_lor(ndof_lor);
2807 
2808  const Geometry::Type geom = fe_ho->GetGeomType();
2809  const DenseTensor &pmats = cf_tr.point_matrices[geom];
2810  emb_tr.SetIdentityTransformation(geom);
2811 
2812  for (int iho=0; iho<nel_ho; ++iho)
2813  {
2814  for (int iref=0; iref<nref; ++iref)
2815  {
2816  // Assemble the low-order refined mass matrix and invert locally
2817  int ilor = ho2lor.GetRow(iho)[iref];
2818  ElementTransformation *el_tr = fes_lor.GetElementTransformation(ilor);
2819  mi.AssembleElementMatrix(*fe_lor, *el_tr, M_lor_el);
2820  M_lor.CopyMN(M_lor_el, iref*ndof_lor, iref*ndof_lor);
2821  Minv_lor_el.Factor();
2822  Minv_lor_el.GetInverseMatrix(M_lor_el);
2823  // Insert into the diagonal of the patch LOR mass matrix
2824  Minv_lor.CopyMN(M_lor_el, iref*ndof_lor, iref*ndof_lor);
2825 
2826  // Now assemble the block-row of the mixed mass matrix associated
2827  // with integrating HO functions against LOR functions on the LOR
2828  // sub-element.
2829 
2830  // Create the transformation that embeds the fine low-order element
2831  // within the coarse high-order element in reference space
2832  emb_tr.SetPointMat(pmats(cf_tr.embeddings[ilor].matrix));
2833 
2834  int order = fe_lor->GetOrder() + fe_ho->GetOrder() + el_tr->OrderW();
2835  const IntegrationRule *ir = &IntRules.Get(geom, order);
2836  M_mixed_el = 0.0;
2837  for (int i = 0; i < ir->GetNPoints(); i++)
2838  {
2839  const IntegrationPoint &ip_lor = ir->IntPoint(i);
2840  IntegrationPoint ip_ho;
2841  ip_tr.Transform(ip_lor, ip_ho);
2842  fe_lor->CalcShape(ip_lor, shape_lor);
2843  fe_ho->CalcShape(ip_ho, shape_ho);
2844  el_tr->SetIntPoint(&ip_lor);
2845  // For now we use the geometry information from the LOR space
2846  // which means we won't be mass conservative if the mesh is curved
2847  double w = el_tr->Weight()*ip_lor.weight;
2848  shape_lor *= w;
2849  AddMultVWt(shape_lor, shape_ho, M_mixed_el);
2850  }
2851  M_mixed.CopyMN(M_mixed_el, iref*ndof_lor, 0);
2852  }
2853  mfem::Mult(Minv_lor, M_mixed, R(iho));
2854 
2855  mfem::MultAtB(R(iho), M_lor, RtMlor);
2856  mfem::Mult(RtMlor, R(iho), RtMlorR);
2857  RtMlorR_inv.Factor();
2858  RtMlorR_inv.Mult(RtMlor, P(iho));
2859  }
2860 }
2861 
2863  const Vector &x, Vector &y) const
2864 {
2865  int vdim = fes_ho.GetVDim();
2866  Array<int> vdofs;
2867  DenseMatrix xel_mat(ndof_ho, vdim);
2868  DenseMatrix yel_mat(ndof_lor*nref, vdim);
2869  for (int iho=0; iho<fes_ho.GetNE(); ++iho)
2870  {
2871  fes_ho.GetElementVDofs(iho, vdofs);
2872  x.GetSubVector(vdofs, xel_mat.GetData());
2873  mfem::Mult(R(iho), xel_mat, yel_mat);
2874  // Place result correctly into the low-order vector
2875  for (int iref=0; iref<nref; ++iref)
2876  {
2877  int ilor = ho2lor.GetRow(iho)[iref];
2878  for (int vd=0; vd<vdim; ++vd)
2879  {
2880  fes_lor.GetElementDofs(ilor, vdofs);
2881  fes_lor.DofsToVDofs(vd, vdofs);
2882  y.SetSubVector(vdofs, &yel_mat(iref*ndof_lor,vd));
2883  }
2884  }
2885  }
2886 }
2887 
2889  const Vector &x, Vector &y) const
2890 {
2891  int vdim = fes_ho.GetVDim();
2892  Array<int> vdofs;
2893  DenseMatrix xel_mat(ndof_lor*nref, vdim);
2894  DenseMatrix yel_mat(ndof_ho, vdim);
2895  for (int iho=0; iho<fes_ho.GetNE(); ++iho)
2896  {
2897  // Extract the LOR DOFs
2898  for (int iref=0; iref<nref; ++iref)
2899  {
2900  int ilor = ho2lor.GetRow(iho)[iref];
2901  for (int vd=0; vd<vdim; ++vd)
2902  {
2903  fes_lor.GetElementDofs(ilor, vdofs);
2904  fes_lor.DofsToVDofs(vd, vdofs);
2905  x.GetSubVector(vdofs, &xel_mat(iref*ndof_lor, vd));
2906  }
2907  }
2908  // Locally prolongate
2909  mfem::Mult(P(iho), xel_mat, yel_mat);
2910  // Place the result in the HO vector
2911  fes_ho.GetElementVDofs(iho, vdofs);
2912  y.SetSubVector(vdofs, yel_mat.GetData());
2913  }
2914 }
2915 
2917 {
2918  if (!F) { F = new L2Projection(dom_fes, ran_fes); }
2919  return *F;
2920 }
2921 
2923 {
2924  if (!B)
2925  {
2926  if (!F) { F = new L2Projection(dom_fes, ran_fes); }
2927  B = new L2Prolongation(*F);
2928  }
2929  return *B;
2930 }
2931 
2932 } // namespace mfem
int GetNPoints() const
Returns the number of the points in the integration rule.
Definition: intrules.hpp:245
Abstract class for all finite elements.
Definition: fe.hpp:235
int GetOrder() const
Get the order of the NURBS collection: either a positive number, when using fixed order...
Definition: fe_coll.hpp:403
Arbitrary order non-uniform rational B-splines (NURBS) finite elements.
Definition: fe_coll.hpp:372
const Operator & MakeTrueOperator(FiniteElementSpace &fes_in, FiniteElementSpace &fes_out, const Operator &oper, OperatorHandle &t_oper)
Definition: fespace.cpp:2550
Ordering::Type GetOrdering() const
Return the ordering method.
Definition: fespace.hpp:412
int Size() const
Return the logical size of the array.
Definition: array.hpp:124
void GetFaceEdges(int i, Array< int > &, Array< int > &) const
Definition: mesh.cpp:4775
int RowSize(const int i) const
Returns the number of elements in row i.
Definition: sparsemat.cpp:296
void SetSubVector(const Array< int > &dofs, const double value)
Set the entries listed in dofs to the given value.
Definition: vector.cpp:521
int GetVSize() const
Return the number of vector dofs, i.e. GetNDofs() x GetVDim().
Definition: fespace.hpp:400
void GetVertexVDofs(int i, Array< int > &vdofs) const
Definition: fespace.cpp:197
void Add(const int i, const int j, const double a)
Definition: sparsemat.cpp:2493
OpType * As() const
Return the Operator pointer statically cast to a specified OpType. Similar to the method Get()...
Definition: handle.hpp:96
const Vector & GetWeights() const
Definition: nurbs.hpp:381
void AddMultVWt(const Vector &v, const Vector &w, DenseMatrix &VWt)
VWt += v w^t.
Definition: densemat.cpp:2778
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
void BuildTranspose() const
Build and store internally the transpose of this matrix which will be used in the methods AddMultTran...
Definition: sparsemat.cpp:773
int GetNDofs() const
Returns number of degrees of freedom.
Definition: fespace.hpp:397
int * GetJ()
Definition: table.hpp:114
int ndofs
Number of degrees of freedom. Number of unknowns is ndofs * vdim.
Definition: fespace.hpp:108
L2FaceValues
Definition: restriction.hpp:26
Class for an integration rule - an Array of IntegrationPoint.
Definition: intrules.hpp:90
const Array< int > & GetMaster() const
Definition: nurbs.hpp:324
void GetElementInteriorVDofs(int i, Array< int > &vdofs) const
Definition: fespace.cpp:203
int DofToVDof(int dof, int vd, int ndofs=-1) const
Definition: fespace.cpp:144
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:4743
const SparseMatrix * GetConformingProlongation() const
The returned SparseMatrix is owned by the FiniteElementSpace.
Definition: fespace.cpp:874
const CoarseFineTransformations & GetDerefinementTransforms()
Definition: ncmesh.cpp:4060
virtual void Update(bool want_transform=true)
Reflect changes in the mesh: update number of DOFs, etc. Also, calculate GridFunction transformation ...
Definition: fespace.cpp:2233
void SetSize(int dim, int connections_per_row)
Set the size and the number of connections for the table.
Definition: table.cpp:128
virtual int OrderW() const =0
Return the order of the determinant of the Jacobian (weight) of the transformation.
void LoadBE(int i, const FiniteElement *BE) const
Definition: nurbs.cpp:2934
const IntegrationRule & Get(int GeomType, int Order)
Returns an integration rule for given GeomType and Order.
Definition: intrules.cpp:915
void GetEdgeVertices(int i, Array< int > &vert) const
Returns the indices of the vertices of edge i.
Definition: mesh.cpp:4805
Operator that extracts Face degrees of freedom.
BilinearFormIntegrator * mass_integ
Ownership depends on own_mass_integ.
Definition: fespace.hpp:873
void BuildElementToDofTable() const
Definition: fespace.cpp:215
void AddColumnsInRow(int r, int ncol)
Definition: table.hpp:78
void BuildNURBSFaceToDofTable() const
Generates partial face_dof table for a NURBS space.
Definition: fespace.cpp:1581
void MakeI(int nrows)
Next 7 methods are used together with the default constructor.
Definition: table.cpp:85
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.cpp:130
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)
Definition: fespace.cpp:1247
void Prolongate(const Vector &x, Vector &y) const
Definition: fespace.cpp:2888
static const int NumGeom
Definition: geom.hpp:41
FiniteElementSpace & dom_fes
Domain FE space.
Definition: fespace.hpp:781
Array< Slave > slaves
Definition: ncmesh.hpp:196
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:2108
virtual void Finalize(int skip_zeros=1)
Finalize the matrix initialization, switching the storage format from LIL to CSR. ...
Definition: sparsemat.hpp:460
int GetNumGeometries(int dim) const
Return the number of geometries of the given dimension present in the mesh.
Definition: mesh.cpp:4697
HypreParMatrix * LeftDiagMult(const SparseMatrix &D, HYPRE_Int *row_starts=NULL) const
Multiply the HypreParMatrix on the left by a block-diagonal parallel matrix D and return the result a...
Definition: hypre.cpp:1081
void SetSize(int s)
Resize the vector to size s.
Definition: vector.hpp:459
SparseMatrix * RefinementMatrix(int old_ndofs, const Table *old_elem_dof)
Definition: fespace.cpp:1095
int GetNBE() const
Returns number of boundary elements.
Definition: mesh.hpp:740
SparseMatrix * DerefinementMatrix(int old_ndofs, const Table *old_elem_dof)
Calculate GridFunction restriction matrix after mesh derefinement.
Definition: fespace.cpp:1403
void GetElementVDofs(int i, Array< int > &vdofs) const
Returns indexes of degrees of freedom in array dofs for i&#39;th element.
Definition: fespace.cpp:173
Ordering::Type ordering
Definition: fespace.hpp:105
const Geometry::Type geom
Definition: ex1.cpp:40
int * GetRowColumns(const int row)
Return a pointer to the column indices in a row.
Definition: sparsemat.cpp:343
static int DecodeDof(int dof)
Helpers to remove encoded sign from a DOF.
Definition: fespace.hpp:173
const T * HostRead() const
Shortcut for mfem::Read(a.GetMemory(), a.Size(), false).
Definition: array.hpp:294
SparseMatrix * RefinementMatrix_main(const int coarse_ndofs, const Table &coarse_elem_dof, const DenseTensor localP[]) const
Definition: fespace.cpp:1010
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:831
Lists all edges/faces in the nonconforming mesh.
Definition: ncmesh.hpp:192
void Mult(const Table &A, const Table &B, Table &C)
C = A * B (as boolean matrices)
Definition: table.cpp:476
int Width() const
Get the width (size of input) of the Operator. Synonym with NumCols().
Definition: operator.hpp:71
void GetElementFaces(int i, Array< int > &, Array< int > &) const
Return the indices and the orientations of all faces of element i.
Definition: mesh.cpp:4937
int SizeK() const
Definition: densemat.hpp:767
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:91
virtual const FiniteElement * FiniteElementForGeometry(Geometry::Type GeomType) const =0
void SetIntPoint(const IntegrationPoint *ip)
Set the integration point ip that weights and Jacobians will be evaluated at.
Definition: eltrans.hpp:85
void Copy(Array &copy) const
Create a copy of the internal array to the provided copy.
Definition: array.hpp:831
void GetSubVector(const Array< int > &dofs, Vector &elemvect) const
Extract entries listed in dofs to the output Vector elemvect.
Definition: vector.cpp:495
int GetFaceOrder(int i) const
Returns the order of the i&#39;th face finite element.
Definition: fespace.cpp:102
int GetNKV() const
Definition: nurbs.hpp:350
int GetOrder() const
Returns the order of the finite element. In the case of anisotropic orders, returns the maximum order...
Definition: fe.hpp:319
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:346
void GetFaceVertices(int i, Array< int > &vert) const
Returns the indices of the vertices of face i.
Definition: mesh.hpp:896
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:100
Geometry::Type Geom() const
Definition: ncmesh.hpp:160
void GetRow(int i, Array< int > &row) const
Return row i in array row (the Table must be finalized)
Definition: table.cpp:191
OperatorHandle L2E_lex
Definition: fespace.hpp:135
Operator::Type oper_type
Desired Operator::Type for the construction of all operators defined by the underlying transfer algor...
Definition: fespace.hpp:787
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 GetBdrAttribute(int i) const
Definition: fespace.hpp:474
int GetBdrElementEdgeIndex(int i) const
Definition: mesh.cpp:4998
void SetSize(int i, int j, int k)
Definition: densemat.hpp:771
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:415
int GetNE() const
Returns number of elements.
Definition: mesh.hpp:737
const Element * GetFace(int i) const
Definition: mesh.hpp:827
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.cpp:111
void GetDegenerateFaceDofs(int index, Array< int > &dofs, Geometry::Type master_geom) const
Definition: fespace.cpp:632
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
Geometry::Type GetFaceBaseGeometry(int i) const
Definition: mesh.hpp:829
Abstract parallel finite element space.
Definition: pfespace.hpp:28
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:1191
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:2073
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:2192
int GetMapType() const
Returns the FiniteElement::MapType of the element describing how reference functions are mapped to ph...
Definition: fe.hpp:341
void GetInverseMatrix(DenseMatrix &Ainv) const
Compute and return the inverse matrix in Ainv.
Definition: densemat.cpp:3249
FiniteElementCollection * Load(Mesh *m, std::istream &input)
Read a FiniteElementSpace from a stream. The returned FiniteElementCollection is owned by the caller...
Definition: fespace.cpp:2379
virtual const Operator & ForwardOperator()
Return an Operator that transfers GridFunctions from the domain FE space to GridFunctions in the rang...
Definition: fespace.cpp:2916
void Factor()
Factor the current DenseMatrix, *a.
Definition: densemat.cpp:3237
int HasFaceDofs(Geometry::Type GeomType) const
Definition: fe_coll.cpp:25
static bool IsEnabled()
Return true if any backend other than Backend::CPU is enabled.
Definition: device.hpp:237
double * GetData() const
Returns the matrix data array.
Definition: densemat.hpp:100
void AddRow(const int row, const Array< int > &cols, const Vector &srow)
Definition: sparsemat.cpp:2716
double * GetRowEntries(const int row)
Return a pointer to the entries in a row.
Definition: sparsemat.cpp:357
double * GetData() const
Return a pointer to the beginning of the Vector data.
Definition: vector.hpp:169
const FiniteElementCollection * fec
Associated FE collection (not owned).
Definition: fespace.hpp:97
OperatorHandle Th
Transformation to apply to GridFunctions after space Update().
Definition: fespace.hpp:132
HypreParMatrix * ParMult(const HypreParMatrix *A, const HypreParMatrix *B, bool own_matrix)
Definition: hypre.cpp:1623
Geometry::Type GetElementBaseGeometry(int i) const
Definition: mesh.hpp:834
int Size_of_connections() const
Definition: table.hpp:98
void GetLocalDerefinementMatrices(Geometry::Type geom, DenseTensor &localR) const
Definition: fespace.cpp:1379
bool HasGeometry(Geometry::Type geom) const
Return true iff the given geom is encountered in the mesh. Geometries of dimensions lower than Dimens...
Definition: mesh.hpp:846
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:28
void DeleteAll()
Delete the whole array.
Definition: array.hpp:821
int GetNDof() const
Definition: nurbs.hpp:360
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:861
void AddConnections(int r, const int *c, int nc)
Definition: table.cpp:108
Array< int > dof_elem_array
Definition: fespace.hpp:118
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:434
void GetFaceInteriorDofs(int i, Array< int > &dofs) const
Definition: fespace.cpp:2032
Derefinement operator, used by the friend class InterpolationGridTransfer.
Definition: fespace.hpp:220
virtual int DofForGeometry(Geometry::Type GeomType) const =0
virtual void GetFaceDofs(int i, Array< int > &dofs) const
Returns the indexes of the degrees of freedom for i&#39;th face including the dofs for the edges and the ...
Definition: fespace.cpp:1898
FiniteElementSpace & ran_fes
Range FE space.
Definition: fespace.hpp:782
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:474
const IntegrationRule * IntRule
Not owned.
const Operator * GetElementRestriction(ElementDofOrdering e_ordering) const
Return an Operator that converts L-vectors to E-vectors.
Definition: fespace.cpp:894
int GetNumFaces() const
Return the number of faces (3D), edges (2D) or vertices (1D).
Definition: mesh.cpp:4184
const SparseMatrix * GetConformingRestriction() const
The returned SparseMatrix is owned by the FiniteElementSpace.
Definition: fespace.cpp:881
Geometry::Type GetGeomType() const
Returns the Geometry::Type of the reference element.
Definition: fe.hpp:312
ID for class SparseMatrix.
Definition: operator.hpp:240
const Array< int > & GetSlave() const
Definition: nurbs.hpp:326
virtual void Mult(const Vector &x, Vector &y) const
Operator application: y=A(x).
Definition: fespace.cpp:1348
void Load(std::istream **in, int np, int *dim)
Reads a vector from multiple files.
Definition: vector.cpp:53
int GetNE() const
Returns number of elements in the mesh.
Definition: fespace.hpp:427
IntegrationPoint & IntPoint(int i)
Returns a reference to the i-th integration point.
Definition: intrules.hpp:248
long GetSequence() const
Definition: mesh.hpp:1227
void GetVertexDofs(int i, Array< int > &dofs) const
Definition: fespace.cpp:1995
virtual const Operator & BackwardOperator()
Return an Operator that transfers GridFunctions from the range FE space back to GridFunctions in the ...
Definition: fespace.cpp:2703
void SetPointMat(const DenseMatrix &pm)
Set the underlying point matrix describing the transformation.
Definition: eltrans.hpp:388
virtual void AssembleElementMatrix(const FiniteElement &el, ElementTransformation &Trans, DenseMatrix &elmat)
Definition: bilininteg.cpp:891
void MultTranspose(const double *x, double *y) const
Multiply a vector with the transpose matrix.
Definition: densemat.cpp:203
General product operator: x -&gt; (A*B)(x) = A(B(x)).
Definition: operator.hpp:722
FaceType
Definition: mesh.hpp:45
void BuildBdrElementToDofTable() const
Definition: fespace.cpp:237
ID for the base class Operator, i.e. any type.
Definition: operator.hpp:239
const FiniteElement * GetEdgeElement(int i) const
Returns pointer to the FiniteElement in the FiniteElementCollection associated with i&#39;th edge in the ...
Definition: fespace.cpp:2102
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:2629
virtual void Mult(const Vector &x, Vector &y) const
Operator application: y=A(x).
Definition: fespace.cpp:1154
void AddMult(const DenseMatrix &b, const DenseMatrix &c, DenseMatrix &a)
Matrix matrix multiplication. A += B * C.
Definition: densemat.cpp:2059
int GetNBE() const
Returns number of boundary elements in the mesh.
Definition: fespace.hpp:436
DenseTensor point_matrices[Geometry::NumGeom]
Matrices for IsoparametricTransformation organized by Geometry::Type.
Definition: ncmesh.hpp:63
Data type sparse matrix.
Definition: sparsemat.hpp:46
int Height() const
Get the height (size of output) of the Operator. Synonym with NumRows().
Definition: operator.hpp:65
int Append(const T &el)
Append element &#39;el&#39; to array, resize if necessary.
Definition: array.hpp:726
Mesh * GetMesh() const
Returns the mesh.
Definition: fespace.hpp:314
Operator that extracts Face degrees of freedom.
OperatorHandle F
Forward, coarse-to-fine, operator.
Definition: fespace.hpp:876
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:153
A class that performs interpolation from an E-vector to quadrature point values and/or derivatives (Q...
GridTransfer(FiniteElementSpace &dom_fes_, FiniteElementSpace &ran_fes_)
Definition: fespace.cpp:2535
double b
Definition: lissajous.cpp:42
Type
Ordering methods:
Definition: fespace.hpp:32
SparseMatrix * cR
Conforming restriction matrix such that cR.cP=I.
Definition: fespace.hpp:128
void GetRow(int r, Vector &row) const
Definition: densemat.cpp:1273
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:515
static const int NumVerts[NumGeom]
Definition: geom.hpp:48
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:483
void AddConnection(int r, int c)
Definition: table.hpp:80
void GetCoarseToFineMap(const Mesh &fine_mesh, Table &coarse_to_fine, Array< int > &coarse_to_ref_type, Table &ref_type_to_matrix, Array< Geometry::Type > &ref_type_to_geom) const
Definition: ncmesh.cpp:4149
virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const =0
Evaluate the values of all shape functions of a scalar finite element in reference space at the given...
HypreParMatrix * Dof_TrueDof_Matrix() const
The true dof-to-dof interpolation matrix.
Definition: pfespace.hpp:281
virtual const Operator * GetProlongationMatrix() const
The returned Operator is owned by the FiniteElementSpace.
Definition: fespace.hpp:330
virtual void GetElementDofs(int i, Array< int > &dofs) const
Returns indexes of degrees of freedom in array dofs for i&#39;th element.
Definition: fespace.cpp:1696
void BuildConformingInterpolation() const
Calculate the cP and cR matrices for a nonconforming mesh.
Definition: fespace.cpp:683
NURBSExtension * StealNURBSext()
Definition: fespace.cpp:1548
void Reserve(int capacity)
Ensures that the allocated size is at least the given size.
Definition: array.hpp:142
Array< Embedding > embeddings
Fine element positions in their parents.
Definition: ncmesh.hpp:65
virtual const FiniteElement * TraceFiniteElementForGeometry(Geometry::Type GeomType) const
Definition: fe_coll.hpp:67
L2Projection(const FiniteElementSpace &fes_ho_, const FiniteElementSpace &fes_lor_)
Definition: fespace.cpp:2745
static void AddDependencies(SparseMatrix &deps, Array< int > &master_dofs, Array< int > &slave_dofs, DenseMatrix &I)
Definition: fespace.cpp:594
bool IsDGSpace() const
Return whether or not the space is discontinuous (L2)
Definition: fespace.hpp:710
Array< int > dof_ldof_array
Definition: fespace.hpp:118
double Weight()
Return the weight of the Jacobian matrix of the transformation at the currently set IntegrationPoint...
Definition: eltrans.hpp:123
const Array< int > & GetOrders() const
Read-only access to the orders of all knot vectors.
Definition: nurbs.hpp:345
bool Conforming() const
Definition: fespace.hpp:320
SparseMatrix * cP
Definition: fespace.hpp:126
int GetVDim() const
Returns vector dimension.
Definition: fespace.hpp:389
int Size() const
Returns the number of TYPE I elements.
Definition: table.hpp:92
int GetNF() const
Returns number of faces (i.e. co-dimension 1 entities) in the mesh.
Definition: fespace.hpp:433
int Dimension() const
Definition: mesh.hpp:788
virtual void GetBoundaryClosure(const Array< int > &bdr_attr_is_ess, Array< int > &bdr_vertices, Array< int > &bdr_edges)
Definition: ncmesh.cpp:4709
Array< QuadratureInterpolator * > E2Q_array
Definition: fespace.hpp:151
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:587
A class that performs interpolation from a face E-vector to quadrature point values and/or derivative...
void GetEdgeDofs(int i, Array< int > &dofs) const
Returns the indexes of the degrees of freedom for i&#39;th edge including the dofs for the vertices of th...
Definition: fespace.cpp:1966
Operator * Ptr() const
Access the underlying Operator pointer.
Definition: handle.hpp:82
OperatorHandle L2E_nat
The element restriction operators, see GetElementRestriction().
Definition: fespace.hpp:135
int slaves_end
slave faces
Definition: ncmesh.hpp:170
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:2167
int SizeI() const
Definition: densemat.hpp:765
OperatorHandle B
Backward, fine-to-coarse, operator.
Definition: fespace.hpp:877
void GetElementInteriorDofs(int i, Array< int > &dofs) const
Definition: fespace.cpp:2007
void GetLocalRefinementMatrices(Geometry::Type geom, DenseTensor &localP) const
Definition: fespace.cpp:1072
int GetOrder() const
If all orders are identical, return that number. Otherwise, return NURBSFECollection::VariableOrder.
Definition: nurbs.hpp:348
List of mesh geometries stored as Array&lt;Geometry::Type&gt;.
Definition: mesh.hpp:861
virtual const Operator & BackwardOperator()
Return an Operator that transfers GridFunctions from the range FE space back to GridFunctions in the ...
Definition: fespace.cpp:2922
virtual const Operator * 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:922
void GetBdrElementFace(int i, int *, int *) const
Return the index and the orientation of the face of bdr element i. (3D)
Definition: mesh.cpp:4975
void SetMassIntegrator(BilinearFormIntegrator *mass_integ_, bool own_mass_integ_=true)
Assign a mass integrator to be used in the construction of the backward, fine-to-coarse, transfer operator.
Definition: fespace.cpp:2661
double Min() const
Returns the minimal element of the vector.
Definition: vector.cpp:1105
ElementTransformation * GetElementTransformation(int i) const
Returns ElementTransformation for the i-th element.
Definition: fespace.hpp:460
Type
Enumeration defining IDs for some classes derived from Operator.
Definition: operator.hpp:237
virtual const int * DofOrderForOrientation(Geometry::Type GeomType, int Or) const =0
Returns an array, say p, that maps a local permuted index i to a local base index: base_i = p[i]...
Abstract base class BilinearFormIntegrator.
Definition: bilininteg.hpp:31
RefinementOperator(const FiniteElementSpace *fespace, Table *old_elem_dof, int old_ndofs)
Definition: fespace.cpp:1113
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:2764
void SetIdentityTransformation(Geometry::Type GeomType)
Set the FiniteElement Geometry for the reference elements being used.
Definition: eltrans.cpp:371
Operator that converts FiniteElementSpace L-vectors to E-vectors.
Definition: restriction.hpp:31
void Print(std::ostream &out=mfem::out, int width=8) const
Prints vector to stream out.
Definition: vector.cpp:672
Nonconforming edge/face within a bigger edge/face.
Definition: ncmesh.hpp:179
Class FiniteElementSpace - responsible for providing FEM view of the mesh, mainly managing the set of...
Definition: fespace.hpp:87
int GetDof() const
Returns the number of degrees of freedom in the finite element.
Definition: fe.hpp:315
virtual ~FiniteElementSpace()
Definition: fespace.cpp:2114
bool OwnsOperator() const
Return true if the OperatorHandle owns the held Operator.
Definition: handle.hpp:109
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:546
void SetSize(int nsize)
Change the logical size of the array, keep existing entries.
Definition: array.hpp:654
L2Prolongation * B
Backward, fine-to-coarse, operator.
Definition: fespace.hpp:969
void Transform(const IntegrationPoint &, IntegrationPoint &)
Definition: eltrans.cpp:533
int GetOrder(int i) const
Returns the order of the i&#39;th finite element.
Definition: fespace.cpp:96
void Save(std::ostream &out) const
Write the QuadratureSpace to the stream out.
Definition: fespace.cpp:2527
void Clear()
Clear the OperatorHandle, deleting the held Operator (if owned), while leaving the type id unchanged...
Definition: handle.hpp:116
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:3277
Table * GetElementDofTable()
Definition: nurbs.hpp:371
void MakeVDimMatrix(SparseMatrix &mat) const
Replicate &#39;mat&#39; in the vector dimension, according to vdim ordering mode.
Definition: fespace.cpp:846
Table * GetBdrElementDofTable()
Definition: nurbs.hpp:372
bool own_mass_integ
Ownership flag for mass_integ.
Definition: fespace.hpp:874
The ordering method used when the number of unknowns per mesh node (vector dimension) is bigger than ...
Definition: fespace.hpp:28
void GetEdgeInteriorVDofs(int i, Array< int > &vdofs) const
Definition: fespace.cpp:209
void GetEntityDofs(int entity, int index, Array< int > &dofs, Geometry::Type master_geom=Geometry::INVALID) const
Helper to get vertex, edge or face DOFs (entity=0,1,2 resp.).
Definition: fespace.cpp:670
void ShiftUpI()
Definition: table.cpp:119
Linear2DFiniteElement TriangleFE
Definition: fe.cpp:12833
const CoarseFineTransformations & GetRefinementTransforms()
Definition: mesh.cpp:8494
L2Projection * F
Forward, coarse-to-fine, operator.
Definition: fespace.hpp:968
Operation GetLastOperation() const
Return type of last modification of the mesh.
Definition: mesh.hpp:1221
static FiniteElementCollection * New(const char *name)
Factory method: return a newly allocated FiniteElementCollection according to the given name...
Definition: fe_coll.cpp:47
T * HostWrite()
Shortcut for mfem::Write(a.GetMemory(), a.Size(), false).
Definition: array.hpp:302
bool Nonconforming() const
Definition: fespace.hpp:321
int SizeJ() const
Definition: densemat.hpp:766
virtual void GetBdrElementDofs(int i, Array< int > &dofs) const
Returns indexes of degrees of freedom for i&#39;th boundary element.
Definition: fespace.cpp:1815
NURBSExtension * NURBSext
Optional NURBS mesh extension.
Definition: mesh.hpp:203
int GetNV() const
Returns number of vertices. Vertices are only at the corners of elements, where you would expect them...
Definition: mesh.hpp:734
virtual const Operator & ForwardOperator()
Return an Operator that transfers GridFunctions from the domain FE space to GridFunctions in the rang...
Definition: fespace.cpp:2670
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:466
virtual const char * Name() const
Definition: fe_coll.hpp:61
Class for integration point with weight.
Definition: intrules.hpp:25
void SetOperatorOwner(bool own=true)
Set the ownership flag for the held Operator.
Definition: handle.hpp:112
bool Parallel() const
Definition: fespace.hpp:795
A standard isoparametric element transformation.
Definition: eltrans.hpp:348
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:4721
Mesh * mesh
The mesh that FE space lives on (not owned).
Definition: fespace.hpp:94
void ReorderElementToDofTable()
Reorder the scalar DOFs based on the element ordering.
Definition: fespace.cpp:292
GridFunction interpolation operator applicable after mesh refinement.
Definition: fespace.hpp:201
double Max() const
Returns the maximal element of the vector.
Definition: vector.cpp:832
static const int DimStart[MaxDim+2]
Definition: geom.hpp:47
const NCList & GetNCList(int entity)
Return vertex/edge/face list (entity = 0/1/2, respectively).
Definition: ncmesh.hpp:240
Array< FaceQuadratureInterpolator * > E2BFQ_array
Definition: fespace.hpp:153
int GetNConformingDofs() const
Definition: fespace.cpp:888
void ConnectBoundaries()
Definition: nurbs.cpp:1793
Array< Master > masters
Definition: ncmesh.hpp:195
void GetEdgeInteriorDofs(int i, Array< int > &dofs) const
Definition: fespace.cpp:2020
const QuadratureInterpolator * GetQuadratureInterpolator(const IntegrationRule &ir) const
Return a QuadratureInterpolator that interpolates E-vectors to quadrature point values and/or derivat...
Definition: fespace.cpp:950
ElementDofOrdering
Constants describing the possible orderings of the DOFs in one element.
Definition: fespace.hpp:65
General triple product operator x -&gt; A*B*C*x, with ownership of the factors.
Definition: operator.hpp:769
void MakeJ()
Definition: table.cpp:95
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.cpp:117
int dim
Definition: ex24.cpp:53
Array< FaceQuadratureInterpolator * > E2IFQ_array
Definition: fespace.hpp:152
void BuildFaceToDofTable() const
Definition: fespace.cpp:259
void SetFE(const FiniteElement *FE)
Set the element that will be used to compute the transformations.
Definition: eltrans.hpp:368
signed char geom
Geometry::Type (faces only) (char to save RAM)
Definition: ncmesh.hpp:158
void OrientedPointMatrix(const Slave &slave, DenseMatrix &oriented_matrix) const
Return the point matrix oriented according to the master and slave edges.
Definition: ncmesh.cpp:2883
IsoparametricTransformation Transf
Definition: eltrans.hpp:451
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:1798
int index(int i, int j, int nx, int ny)
Definition: life.cpp:241
Lexicographic ordering for tensor-product FiniteElements.
virtual int GetNVertices() const =0
int parent
Element index in the coarse mesh.
Definition: ncmesh.hpp:49
FiniteElementSpace()
Default constructor: the object is invalid until initialized using the method Load().
Definition: fespace.cpp:60
QuadratureSpace(Mesh *mesh_, int order_)
Create a QuadratureSpace based on the global rules from IntRules.
Definition: fespace.hpp:748
void Constructor(Mesh *mesh, NURBSExtension *ext, const FiniteElementCollection *fec, int vdim=1, int ordering=Ordering::byNODES)
Help function for constructors + Load().
Definition: fespace.cpp:1501
NCMesh * ncmesh
Optional non-conforming mesh extension.
Definition: mesh.hpp:204
Geometry::Type GetBdrElementBaseGeometry(int i) const
Definition: mesh.hpp:839
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:185
void SetRow(const int row, const Array< int > &cols, const Vector &srow)
Definition: sparsemat.cpp:2669
void GetEdgeVDofs(int i, Array< int > &vdofs) const
Returns indexes of degrees of freedom for i&#39;th edge.
Definition: fespace.cpp:191
HYPRE_Int * GetTrueDofOffsets() const
Definition: pfespace.hpp:248
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:453
virtual void Mult(const Vector &x, Vector &y) const
Perform the L2 projection onto the LOR space.
Definition: fespace.cpp:2862
int GetNEdges() const
Return the number of edges.
Definition: mesh.hpp:743
void filter_dos(std::string &line)
Check for, and remove, a trailing &#39;\r&#39; from and std::string.
Definition: text.hpp:42
void MakeRef(T *, int)
Make this Array a reference to a pointer.
Definition: array.hpp:839
int GetNFaces() const
Return the number of faces in a 3D mesh.
Definition: mesh.hpp:746
BiLinear2DFiniteElement QuadrilateralFE
void MultAtB(const DenseMatrix &A, const DenseMatrix &B, DenseMatrix &AtB)
Multiply the transpose of a matrix A with a matrix B: At*B.
Definition: densemat.cpp:2650
Vector data type.
Definition: vector.hpp:51
void Mult(const double *x, double *y) const
Matrix vector multiplication.
Definition: densemat.cpp:175
std::tuple< bool, ElementDofOrdering, FaceType, L2FaceValues > key_face
The face restriction operators, see GetFaceRestriction().
Definition: fespace.hpp:137
ID for class HypreParMatrix.
Definition: operator.hpp:241
Array< int > face_to_be
Definition: fespace.hpp:116
void CopyMN(const DenseMatrix &A, int m, int n, int Aro, int Aco)
Copy the m x n submatrix of A at row/col offsets Aro/Aco to *this.
Definition: densemat.cpp:1536
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:543
Defines the coarse-fine transformations of all fine elements.
Definition: ncmesh.hpp:60
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.cpp:123
static bool DofFinalizable(int dof, const Array< bool > &finalized, const SparseMatrix &deps)
Definition: fespace.cpp:618
Class representing the storage layout of a QuadratureFunction.
Definition: fespace.hpp:728
void UseExternalData(double *d, int h, int w)
Change the data array and the size of the DenseMatrix.
Definition: densemat.hpp:65
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:2047
NURBSExtension * NURBSext
Definition: fespace.hpp:120
void GetBdrElementVDofs(int i, Array< int > &vdofs) const
Returns indexes of degrees of freedom for i&#39;th boundary element.
Definition: fespace.cpp:179
OutStream out(std::cout)
Global stream used by the library for standard output. Initially it uses the same std::streambuf as s...
Definition: globals.hpp:66
Abstract operator.
Definition: operator.hpp:24
Wrapper for hypre&#39;s ParCSR matrix class.
Definition: hypre.hpp:181
virtual const SparseMatrix * GetRestrictionMatrix() const
The returned SparseMatrix is owned by the FiniteElementSpace.
Definition: fespace.hpp:334
const DenseMatrix & GetPointMat() const
Return the stored point matrix.
Definition: eltrans.hpp:391
void Swap(SparseMatrix &other)
Definition: sparsemat.cpp:3882
int index
Mesh number.
Definition: ncmesh.hpp:155
Rank 3 tensor (array of matrices)
Definition: densemat.hpp:728
IntegrationRules IntRules(0, Quadrature1D::GaussLegendre)
A global object with all integration rules (defined in intrules.cpp)
Definition: intrules.hpp:378
void Save(std::ostream &out) const
Save finite element space to output stream out.
Definition: fespace.cpp:2310
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:312
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:882
Operator that converts L2 FiniteElementSpace L-vectors to E-vectors.
Definition: restriction.hpp:84
void GetElementVertices(int i, Array< int > &v) const
Returns the indices of the vertices of element i.
Definition: mesh.hpp:878
static void AdjustVDofs(Array< int > &vdofs)
Definition: fespace.cpp:160
void SetType(Operator::Type tid)
Invoke Clear() and set a new type id.
Definition: handle.hpp:124
const Element * GetBdrElement(int i) const
Definition: mesh.hpp:823
Defines the position of a fine element within a coarse element.
Definition: ncmesh.hpp:46
void Reset(OpType *A, bool own_A=true)
Reset the OperatorHandle to the given OpType pointer, A.
Definition: handle.hpp:137
int matrix
Index into the DenseTensor corresponding to the parent Geometry::Type stored in CoarseFineTransformat...
Definition: ncmesh.hpp:52
double f(const Vector &p)
const QuadratureSpace * qspace
Not owned.
void DofsToVDofs(Array< int > &dofs, int ndofs=-1) const
Definition: fespace.cpp:108
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:979