libMesh
fe_base.C
Go to the documentation of this file.
1 // The libMesh Finite Element Library.
2 // Copyright (C) 2002-2019 Benjamin S. Kirk, John W. Peterson, Roy H. Stogner
3 
4 // This library is free software; you can redistribute it and/or
5 // modify it under the terms of the GNU Lesser General Public
6 // License as published by the Free Software Foundation; either
7 // version 2.1 of the License, or (at your option) any later version.
8 
9 // This library is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 // Lesser General Public License for more details.
13 
14 // You should have received a copy of the GNU Lesser General Public
15 // License along with this library; if not, write to the Free Software
16 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 
18 
19 
20 // Local includes
21 #include "libmesh/fe.h"
22 #include "libmesh/inf_fe.h"
23 #include "libmesh/libmesh_logging.h"
24 #include "libmesh/auto_ptr.h" // libmesh_make_unique
25 // For projection code:
26 #include "libmesh/boundary_info.h"
27 #include "libmesh/mesh_base.h"
28 #include "libmesh/dense_matrix.h"
29 #include "libmesh/dense_vector.h"
30 #include "libmesh/dof_map.h"
31 #include "libmesh/elem.h"
32 #include "libmesh/fe_interface.h"
33 #include "libmesh/numeric_vector.h"
34 #include "libmesh/periodic_boundary_base.h"
35 #include "libmesh/periodic_boundaries.h"
36 #include "libmesh/quadrature.h"
37 #include "libmesh/quadrature_gauss.h"
38 #include "libmesh/tensor_value.h"
39 #include "libmesh/threads.h"
40 #include "libmesh/fe_type.h"
41 
42 // Anonymous namespace, for a helper function for periodic boundary
43 // constraint calculations
44 namespace
45 {
46 using namespace libMesh;
47 
48 #ifdef LIBMESH_ENABLE_PERIODIC
49 
50 // Find the "primary" element around a boundary point:
51 const Elem * primary_boundary_point_neighbor(const Elem * elem,
52  const Point & p,
53  const BoundaryInfo & boundary_info,
54  const std::set<boundary_id_type> & boundary_ids)
55 {
56  // If we don't find a better alternative, the user will have
57  // provided the primary element
58  const Elem * primary = elem;
59 
60  // Container to catch boundary IDs passed back by BoundaryInfo.
61  std::vector<boundary_id_type> bc_ids;
62 
63  // Pull object out of the loop to reduce heap operations
64  std::unique_ptr<const Elem> periodic_side;
65 
66  std::set<const Elem *> point_neighbors;
67  elem->find_point_neighbors(p, point_neighbors);
68  for (const auto & pt_neighbor : point_neighbors)
69  {
70  // If this point neighbor isn't at least
71  // as coarse as the current primary elem, or if it is at
72  // the same level but has a lower id, then
73  // we won't defer to it.
74  if ((pt_neighbor->level() > primary->level()) ||
75  (pt_neighbor->level() == primary->level() &&
76  pt_neighbor->id() < primary->id()))
77  continue;
78 
79  // Otherwise, we will defer to the point neighbor, but only if
80  // one of its sides is on a relevant boundary and that side
81  // contains this vertex
82  bool vertex_on_periodic_side = false;
83  for (auto ns : pt_neighbor->side_index_range())
84  {
85  boundary_info.boundary_ids (pt_neighbor, ns, bc_ids);
86 
87  bool on_relevant_boundary = false;
88  for (const auto & id : boundary_ids)
89  if (std::find(bc_ids.begin(), bc_ids.end(), id) != bc_ids.end())
90  on_relevant_boundary = true;
91 
92  if (!on_relevant_boundary)
93  continue;
94 
95  pt_neighbor->build_side_ptr(periodic_side, ns);
96  if (!periodic_side->contains_point(p))
97  continue;
98 
99  vertex_on_periodic_side = true;
100  break;
101  }
102 
103  if (vertex_on_periodic_side)
104  primary = pt_neighbor;
105  }
106 
107  return primary;
108 }
109 
110 // Find the "primary" element around a boundary edge:
111 const Elem * primary_boundary_edge_neighbor(const Elem * elem,
112  const Point & p1,
113  const Point & p2,
114  const BoundaryInfo & boundary_info,
115  const std::set<boundary_id_type> & boundary_ids)
116 {
117  // If we don't find a better alternative, the user will have
118  // provided the primary element
119  const Elem * primary = elem;
120 
121  std::set<const Elem *> edge_neighbors;
122  elem->find_edge_neighbors(p1, p2, edge_neighbors);
123 
124  // Container to catch boundary IDs handed back by BoundaryInfo
125  std::vector<boundary_id_type> bc_ids;
126 
127  // Pull object out of the loop to reduce heap operations
128  std::unique_ptr<const Elem> periodic_side;
129 
130  for (const auto & e_neighbor : edge_neighbors)
131  {
132  // If this edge neighbor isn't at least
133  // as coarse as the current primary elem, or if it is at
134  // the same level but has a lower id, then
135  // we won't defer to it.
136  if ((e_neighbor->level() > primary->level()) ||
137  (e_neighbor->level() == primary->level() &&
138  e_neighbor->id() < primary->id()))
139  continue;
140 
141  // Otherwise, we will defer to the edge neighbor, but only if
142  // one of its sides is on this periodic boundary and that
143  // side contains this edge
144  bool vertex_on_periodic_side = false;
145  for (auto ns : e_neighbor->side_index_range())
146  {
147  boundary_info.boundary_ids (e_neighbor, ns, bc_ids);
148 
149  bool on_relevant_boundary = false;
150  for (const auto & id : boundary_ids)
151  if (std::find(bc_ids.begin(), bc_ids.end(), id) != bc_ids.end())
152  on_relevant_boundary = true;
153 
154  if (!on_relevant_boundary)
155  continue;
156 
157  e_neighbor->build_side_ptr(periodic_side, ns);
158  if (!(periodic_side->contains_point(p1) &&
159  periodic_side->contains_point(p2)))
160  continue;
161 
162  vertex_on_periodic_side = true;
163  break;
164  }
165 
166  if (vertex_on_periodic_side)
167  primary = e_neighbor;
168  }
169 
170  return primary;
171 }
172 
173 #endif // LIBMESH_ENABLE_PERIODIC
174 
175 }
176 
177 namespace libMesh
178 {
179 
180 
181 
182 // ------------------------------------------------------------
183 // FEBase class members
184 template <>
185 std::unique_ptr<FEGenericBase<Real>>
186 FEGenericBase<Real>::build (const unsigned int dim,
187  const FEType & fet)
188 {
189  switch (dim)
190  {
191  // 0D
192  case 0:
193  {
194  switch (fet.family)
195  {
196  case CLOUGH:
197  return libmesh_make_unique<FE<0,CLOUGH>>(fet);
198 
199  case HERMITE:
200  return libmesh_make_unique<FE<0,HERMITE>>(fet);
201 
202  case LAGRANGE:
203  return libmesh_make_unique<FE<0,LAGRANGE>>(fet);
204 
205  case L2_LAGRANGE:
206  return libmesh_make_unique<FE<0,L2_LAGRANGE>>(fet);
207 
208  case HIERARCHIC:
209  return libmesh_make_unique<FE<0,HIERARCHIC>>(fet);
210 
211  case L2_HIERARCHIC:
212  return libmesh_make_unique<FE<0,L2_HIERARCHIC>>(fet);
213 
214  case MONOMIAL:
215  return libmesh_make_unique<FE<0,MONOMIAL>>(fet);
216 
217 #ifdef LIBMESH_ENABLE_HIGHER_ORDER_SHAPES
218  case SZABAB:
219  return libmesh_make_unique<FE<0,SZABAB>>(fet);
220 
221  case BERNSTEIN:
222  return libmesh_make_unique<FE<0,BERNSTEIN>>(fet);
223 
224  case RATIONAL_BERNSTEIN:
225  return libmesh_make_unique<FE<0,RATIONAL_BERNSTEIN>>(fet);
226 #endif
227 
228  case XYZ:
229  return libmesh_make_unique<FEXYZ<0>>(fet);
230 
231  case SCALAR:
232  return libmesh_make_unique<FEScalar<0>>(fet);
233 
234  default:
235  libmesh_error_msg("ERROR: Bad FEType.family= " << fet.family);
236  }
237  }
238  // 1D
239  case 1:
240  {
241  switch (fet.family)
242  {
243  case CLOUGH:
244  return libmesh_make_unique<FE<1,CLOUGH>>(fet);
245 
246  case HERMITE:
247  return libmesh_make_unique<FE<1,HERMITE>>(fet);
248 
249  case LAGRANGE:
250  return libmesh_make_unique<FE<1,LAGRANGE>>(fet);
251 
252  case L2_LAGRANGE:
253  return libmesh_make_unique<FE<1,L2_LAGRANGE>>(fet);
254 
255  case HIERARCHIC:
256  return libmesh_make_unique<FE<1,HIERARCHIC>>(fet);
257 
258  case L2_HIERARCHIC:
259  return libmesh_make_unique<FE<1,L2_HIERARCHIC>>(fet);
260 
261  case MONOMIAL:
262  return libmesh_make_unique<FE<1,MONOMIAL>>(fet);
263 
264 #ifdef LIBMESH_ENABLE_HIGHER_ORDER_SHAPES
265  case SZABAB:
266  return libmesh_make_unique<FE<1,SZABAB>>(fet);
267 
268  case BERNSTEIN:
269  return libmesh_make_unique<FE<1,BERNSTEIN>>(fet);
270 
271  case RATIONAL_BERNSTEIN:
272  return libmesh_make_unique<FE<1,RATIONAL_BERNSTEIN>>(fet);
273 #endif
274 
275  case XYZ:
276  return libmesh_make_unique<FEXYZ<1>>(fet);
277 
278  case SCALAR:
279  return libmesh_make_unique<FEScalar<1>>(fet);
280 
281  default:
282  libmesh_error_msg("ERROR: Bad FEType.family= " << fet.family);
283  }
284  }
285 
286 
287  // 2D
288  case 2:
289  {
290  switch (fet.family)
291  {
292  case CLOUGH:
293  return libmesh_make_unique<FE<2,CLOUGH>>(fet);
294 
295  case HERMITE:
296  return libmesh_make_unique<FE<2,HERMITE>>(fet);
297 
298  case LAGRANGE:
299  return libmesh_make_unique<FE<2,LAGRANGE>>(fet);
300 
301  case L2_LAGRANGE:
302  return libmesh_make_unique<FE<2,L2_LAGRANGE>>(fet);
303 
304  case HIERARCHIC:
305  return libmesh_make_unique<FE<2,HIERARCHIC>>(fet);
306 
307  case L2_HIERARCHIC:
308  return libmesh_make_unique<FE<2,L2_HIERARCHIC>>(fet);
309 
310  case MONOMIAL:
311  return libmesh_make_unique<FE<2,MONOMIAL>>(fet);
312 
313 #ifdef LIBMESH_ENABLE_HIGHER_ORDER_SHAPES
314  case SZABAB:
315  return libmesh_make_unique<FE<2,SZABAB>>(fet);
316 
317  case BERNSTEIN:
318  return libmesh_make_unique<FE<2,BERNSTEIN>>(fet);
319 
320  case RATIONAL_BERNSTEIN:
321  return libmesh_make_unique<FE<2,RATIONAL_BERNSTEIN>>(fet);
322 #endif
323 
324  case XYZ:
325  return libmesh_make_unique<FEXYZ<2>>(fet);
326 
327  case SCALAR:
328  return libmesh_make_unique<FEScalar<2>>(fet);
329 
330  case SUBDIVISION:
331  return libmesh_make_unique<FESubdivision>(fet);
332 
333  default:
334  libmesh_error_msg("ERROR: Bad FEType.family= " << fet.family);
335  }
336  }
337 
338 
339  // 3D
340  case 3:
341  {
342  switch (fet.family)
343  {
344  case CLOUGH:
345  libmesh_error_msg("ERROR: Clough-Tocher elements currently only support 1D and 2D");
346 
347  case HERMITE:
348  return libmesh_make_unique<FE<3,HERMITE>>(fet);
349 
350  case LAGRANGE:
351  return libmesh_make_unique<FE<3,LAGRANGE>>(fet);
352 
353  case L2_LAGRANGE:
354  return libmesh_make_unique<FE<3,L2_LAGRANGE>>(fet);
355 
356  case HIERARCHIC:
357  return libmesh_make_unique<FE<3,HIERARCHIC>>(fet);
358 
359  case L2_HIERARCHIC:
360  return libmesh_make_unique<FE<3,L2_HIERARCHIC>>(fet);
361 
362  case MONOMIAL:
363  return libmesh_make_unique<FE<3,MONOMIAL>>(fet);
364 
365 #ifdef LIBMESH_ENABLE_HIGHER_ORDER_SHAPES
366  case SZABAB:
367  return libmesh_make_unique<FE<3,SZABAB>>(fet);
368 
369  case BERNSTEIN:
370  return libmesh_make_unique<FE<3,BERNSTEIN>>(fet);
371 
372  case RATIONAL_BERNSTEIN:
373  return libmesh_make_unique<FE<3,RATIONAL_BERNSTEIN>>(fet);
374 #endif
375 
376  case XYZ:
377  return libmesh_make_unique<FEXYZ<3>>(fet);
378 
379  case SCALAR:
380  return libmesh_make_unique<FEScalar<3>>(fet);
381 
382  default:
383  libmesh_error_msg("ERROR: Bad FEType.family= " << fet.family);
384  }
385  }
386 
387  default:
388  libmesh_error_msg("Invalid dimension dim = " << dim);
389  }
390 }
391 
392 
393 
394 template <>
395 std::unique_ptr<FEGenericBase<RealGradient>>
397  const FEType & fet)
398 {
399  switch (dim)
400  {
401  // 0D
402  case 0:
403  {
404  switch (fet.family)
405  {
406  case LAGRANGE_VEC:
407  return libmesh_make_unique<FELagrangeVec<0>>(fet);
408 
409  case MONOMIAL_VEC:
410  return libmesh_make_unique<FEMonomialVec<0>>(fet);
411 
412  default:
413  libmesh_error_msg("ERROR: Bad FEType.family= " << fet.family);
414  }
415  }
416  case 1:
417  {
418  switch (fet.family)
419  {
420  case LAGRANGE_VEC:
421  return libmesh_make_unique<FELagrangeVec<1>>(fet);
422 
423  case MONOMIAL_VEC:
424  return libmesh_make_unique<FEMonomialVec<1>>(fet);
425 
426  default:
427  libmesh_error_msg("ERROR: Bad FEType.family= " << fet.family);
428  }
429  }
430  case 2:
431  {
432  switch (fet.family)
433  {
434  case LAGRANGE_VEC:
435  return libmesh_make_unique<FELagrangeVec<2>>(fet);
436 
437  case MONOMIAL_VEC:
438  return libmesh_make_unique<FEMonomialVec<2>>(fet);
439 
440  case NEDELEC_ONE:
441  return libmesh_make_unique<FENedelecOne<2>>(fet);
442 
443  default:
444  libmesh_error_msg("ERROR: Bad FEType.family= " << fet.family);
445  }
446  }
447  case 3:
448  {
449  switch (fet.family)
450  {
451  case LAGRANGE_VEC:
452  return libmesh_make_unique<FELagrangeVec<3>>(fet);
453 
454  case MONOMIAL_VEC:
455  return libmesh_make_unique<FEMonomialVec<3>>(fet);
456 
457  case NEDELEC_ONE:
458  return libmesh_make_unique<FENedelecOne<3>>(fet);
459 
460  default:
461  libmesh_error_msg("ERROR: Bad FEType.family= " << fet.family);
462  }
463  }
464 
465  default:
466  libmesh_error_msg("Invalid dimension dim = " << dim);
467  } // switch(dim)
468 }
469 
470 
471 
472 
473 
474 
475 
476 #ifdef LIBMESH_ENABLE_INFINITE_ELEMENTS
477 
478 
479 template <>
480 std::unique_ptr<FEGenericBase<Real>>
482  const FEType & fet)
483 {
484  switch (dim)
485  {
486 
487  // 1D
488  case 1:
489  {
490  switch (fet.radial_family)
491  {
492  case INFINITE_MAP:
493  libmesh_error_msg("ERROR: Can't build an infinite element with FEFamily = " << fet.radial_family);
494 
495  case JACOBI_20_00:
496  {
497  switch (fet.inf_map)
498  {
499  case CARTESIAN:
500  return libmesh_make_unique<InfFE<1,JACOBI_20_00,CARTESIAN>>(fet);
501 
502  default:
503  libmesh_error_msg("ERROR: Can't build an infinite element with InfMapType = " << fet.inf_map);
504  }
505  }
506 
507  case JACOBI_30_00:
508  {
509  switch (fet.inf_map)
510  {
511  case CARTESIAN:
512  return libmesh_make_unique<InfFE<1,JACOBI_30_00,CARTESIAN>>(fet);
513 
514  default:
515  libmesh_error_msg("ERROR: Can't build an infinite element with InfMapType = " << fet.inf_map);
516  }
517  }
518 
519  case LEGENDRE:
520  {
521  switch (fet.inf_map)
522  {
523  case CARTESIAN:
524  return libmesh_make_unique<InfFE<1,LEGENDRE,CARTESIAN>>(fet);
525 
526  default:
527  libmesh_error_msg("ERROR: Can't build an infinite element with InfMapType = " << fet.inf_map);
528  }
529  }
530 
531  case LAGRANGE:
532  {
533  switch (fet.inf_map)
534  {
535  case CARTESIAN:
536  return libmesh_make_unique<InfFE<1,LAGRANGE,CARTESIAN>>(fet);
537 
538  default:
539  libmesh_error_msg("ERROR: Can't build an infinite element with InfMapType = " << fet.inf_map);
540  }
541  }
542 
543  default:
544  libmesh_error_msg("ERROR: Bad FEType.radial_family= " << fet.radial_family);
545  }
546  }
547 
548 
549 
550 
551  // 2D
552  case 2:
553  {
554  switch (fet.radial_family)
555  {
556  case INFINITE_MAP:
557  libmesh_error_msg("ERROR: Can't build an infinite element with FEFamily = " << fet.radial_family);
558 
559  case JACOBI_20_00:
560  {
561  switch (fet.inf_map)
562  {
563  case CARTESIAN:
564  return libmesh_make_unique<InfFE<2,JACOBI_20_00,CARTESIAN>>(fet);
565 
566  default:
567  libmesh_error_msg("ERROR: Don't build an infinite element with InfMapType = " << fet.inf_map);
568  }
569  }
570 
571  case JACOBI_30_00:
572  {
573  switch (fet.inf_map)
574  {
575  case CARTESIAN:
576  return libmesh_make_unique<InfFE<2,JACOBI_30_00,CARTESIAN>>(fet);
577 
578  default:
579  libmesh_error_msg("ERROR: Don't build an infinite element with InfMapType = " << fet.inf_map);
580  }
581  }
582 
583  case LEGENDRE:
584  {
585  switch (fet.inf_map)
586  {
587  case CARTESIAN:
588  return libmesh_make_unique<InfFE<2,LEGENDRE,CARTESIAN>>(fet);
589 
590  default:
591  libmesh_error_msg("ERROR: Don't build an infinite element with InfMapType = " << fet.inf_map);
592  }
593  }
594 
595  case LAGRANGE:
596  {
597  switch (fet.inf_map)
598  {
599  case CARTESIAN:
600  return libmesh_make_unique<InfFE<2,LAGRANGE,CARTESIAN>>(fet);
601 
602  default:
603  libmesh_error_msg("ERROR: Don't build an infinite element with InfMapType = " << fet.inf_map);
604  }
605  }
606 
607  default:
608  libmesh_error_msg("ERROR: Bad FEType.radial_family= " << fet.radial_family);
609  }
610  }
611 
612 
613 
614 
615  // 3D
616  case 3:
617  {
618  switch (fet.radial_family)
619  {
620  case INFINITE_MAP:
621  libmesh_error_msg("ERROR: Don't build an infinite element with FEFamily = " << fet.radial_family);
622 
623  case JACOBI_20_00:
624  {
625  switch (fet.inf_map)
626  {
627  case CARTESIAN:
628  return libmesh_make_unique<InfFE<3,JACOBI_20_00,CARTESIAN>>(fet);
629 
630  default:
631  libmesh_error_msg("ERROR: Don't build an infinite element with InfMapType = " << fet.inf_map);
632  }
633  }
634 
635  case JACOBI_30_00:
636  {
637  switch (fet.inf_map)
638  {
639  case CARTESIAN:
640  return libmesh_make_unique<InfFE<3,JACOBI_30_00,CARTESIAN>>(fet);
641 
642  default:
643  libmesh_error_msg("ERROR: Don't build an infinite element with InfMapType = " << fet.inf_map);
644  }
645  }
646 
647  case LEGENDRE:
648  {
649  switch (fet.inf_map)
650  {
651  case CARTESIAN:
652  return libmesh_make_unique<InfFE<3,LEGENDRE,CARTESIAN>>(fet);
653 
654  default:
655  libmesh_error_msg("ERROR: Don't build an infinite element with InfMapType = " << fet.inf_map);
656  }
657  }
658 
659  case LAGRANGE:
660  {
661  switch (fet.inf_map)
662  {
663  case CARTESIAN:
664  return libmesh_make_unique<InfFE<3,LAGRANGE,CARTESIAN>>(fet);
665 
666  default:
667  libmesh_error_msg("ERROR: Don't build an infinite element with InfMapType = " << fet.inf_map);
668  }
669  }
670 
671  default:
672  libmesh_error_msg("ERROR: Bad FEType.radial_family= " << fet.radial_family);
673  }
674  }
675 
676  default:
677  libmesh_error_msg("Invalid dimension dim = " << dim);
678  }
679 }
680 
681 
682 
683 template <>
684 std::unique_ptr<FEGenericBase<RealGradient>>
686  const FEType & )
687 {
688  // No vector types defined... YET.
689  libmesh_not_implemented();
690  return std::unique_ptr<FEVectorBase>();
691 }
692 
693 #endif // ifdef LIBMESH_ENABLE_INFINITE_ELEMENTS
694 
695 
696 template <typename OutputType>
698  const std::vector<Point> & qp)
699 {
700  //-------------------------------------------------------------------------
701  // Compute the shape function values (and derivatives)
702  // at the Quadrature points. Note that the actual values
703  // have already been computed via init_shape_functions
704 
705  // Start logging the shape function computation
706  LOG_SCOPE("compute_shape_functions()", "FE");
707 
708  this->determine_calculations();
709 
710  if (calculate_phi)
711  this->_fe_trans->map_phi(this->dim, elem, qp, (*this), this->phi);
712 
713  if (calculate_dphi)
714  this->_fe_trans->map_dphi(this->dim, elem, qp, (*this), this->dphi,
715  this->dphidx, this->dphidy, this->dphidz);
716 
717 #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
718  if (calculate_d2phi)
719  this->_fe_trans->map_d2phi(this->dim, qp, (*this), this->d2phi,
720  this->d2phidx2, this->d2phidxdy, this->d2phidxdz,
721  this->d2phidy2, this->d2phidydz, this->d2phidz2);
722 #endif //LIBMESH_ENABLE_SECOND_DERIVATIVES
723 
724  // Only compute curl for vector-valued elements
725  if (calculate_curl_phi && TypesEqual<OutputType,RealGradient>::value)
726  this->_fe_trans->map_curl(this->dim, elem, qp, (*this), this->curl_phi);
727 
728  // Only compute div for vector-valued elements
729  if (calculate_div_phi && TypesEqual<OutputType,RealGradient>::value)
730  this->_fe_trans->map_div(this->dim, elem, qp, (*this), this->div_phi);
731 }
732 
733 
734 template <typename OutputType>
735 void FEGenericBase<OutputType>::print_phi(std::ostream & os) const
736 {
737  for (auto i : index_range(phi))
738  for (auto j : index_range(phi[i]))
739  os << " phi[" << i << "][" << j << "]=" << phi[i][j] << std::endl;
740 }
741 
742 
743 
744 
745 template <typename OutputType>
746 void FEGenericBase<OutputType>::print_dphi(std::ostream & os) const
747 {
748  for (auto i : index_range(dphi))
749  for (auto j : index_range(dphi[i]))
750  os << " dphi[" << i << "][" << j << "]=" << dphi[i][j];
751 }
752 
753 
754 
755 template <typename OutputType>
757 {
758  this->calculations_started = true;
759 
760  // If the user forgot to request anything, we'll be safe and
761  // calculate everything:
762 #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
763  if (!this->calculate_phi && !this->calculate_dphi &&
764  !this->calculate_d2phi && !this->calculate_curl_phi &&
765  !this->calculate_div_phi && !this->calculate_map)
766  {
767  this->calculate_phi = this->calculate_dphi = this->calculate_d2phi = this->calculate_dphiref = true;
768  if (FEInterface::field_type(fe_type.family) == TYPE_VECTOR)
769  {
770  this->calculate_curl_phi = true;
771  this->calculate_div_phi = true;
772  }
773  }
774 #else
775  if (!this->calculate_phi && !this->calculate_dphi &&
776  !this->calculate_curl_phi && !this->calculate_div_phi &&
777  !this->calculate_map)
778  {
779  this->calculate_phi = this->calculate_dphi = this->calculate_dphiref = true;
780  if (FEInterface::field_type(fe_type.family) == TYPE_VECTOR)
781  {
782  this->calculate_curl_phi = true;
783  this->calculate_div_phi = true;
784  }
785  }
786 #endif // LIBMESH_ENABLE_SECOND_DERIVATIVES
787 
788  // Request whichever terms are necessary from the FEMap
789  if (this->calculate_phi)
790  this->_fe_trans->init_map_phi(*this);
791 
792  if (this->calculate_dphiref)
793  this->_fe_trans->init_map_dphi(*this);
794 
795 #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
796  if (this->calculate_d2phi)
797  this->_fe_trans->init_map_d2phi(*this);
798 #endif //LIBMESH_ENABLE_SECOND_DERIVATIVES
799 }
800 
801 
802 
803 #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
804 
805 
806 template <typename OutputType>
807 void FEGenericBase<OutputType>::print_d2phi(std::ostream & os) const
808 {
809  for (auto i : index_range(dphi))
810  for (auto j : index_range(dphi[i]))
811  os << " d2phi[" << i << "][" << j << "]=" << d2phi[i][j];
812 }
813 
814 #endif
815 
816 
817 
818 #ifdef LIBMESH_ENABLE_AMR
819 
820 template <typename OutputType>
821 void
823  const DofMap & dof_map,
824  const Elem * elem,
825  DenseVector<Number> & Ue,
826  const unsigned int var,
827  const bool use_old_dof_indices)
828 {
829  // Side/edge local DOF indices
830  std::vector<unsigned int> new_side_dofs, old_side_dofs;
831 
832  // FIXME: what about 2D shells in 3D space?
833  unsigned int dim = elem->dim();
834 
835  // Cache n_children(); it's a virtual call but it's const.
836  const unsigned int n_children = elem->n_children();
837 
838  // We use local FE objects for now
839  // FIXME: we should use more, external objects instead for efficiency
840  const FEType & base_fe_type = dof_map.variable_type(var);
841  std::unique_ptr<FEGenericBase<OutputShape>> fe
842  (FEGenericBase<OutputShape>::build(dim, base_fe_type));
843  std::unique_ptr<FEGenericBase<OutputShape>> fe_coarse
844  (FEGenericBase<OutputShape>::build(dim, base_fe_type));
845 
846  std::unique_ptr<QBase> qrule (base_fe_type.default_quadrature_rule(dim));
847  std::unique_ptr<QBase> qedgerule (base_fe_type.default_quadrature_rule(1));
848  std::unique_ptr<QBase> qsiderule (base_fe_type.default_quadrature_rule(dim-1));
849  std::vector<Point> coarse_qpoints;
850 
851  // The values of the shape functions at the quadrature
852  // points
853  const std::vector<std::vector<OutputShape>> & phi_values =
854  fe->get_phi();
855  const std::vector<std::vector<OutputShape>> & phi_coarse =
856  fe_coarse->get_phi();
857 
858  // The gradients of the shape functions at the quadrature
859  // points on the child element.
860  const std::vector<std::vector<OutputGradient>> * dphi_values =
861  nullptr;
862  const std::vector<std::vector<OutputGradient>> * dphi_coarse =
863  nullptr;
864 
865  const FEContinuity cont = fe->get_continuity();
866 
867  if (cont == C_ONE)
868  {
869  const std::vector<std::vector<OutputGradient>> &
870  ref_dphi_values = fe->get_dphi();
871  dphi_values = &ref_dphi_values;
872  const std::vector<std::vector<OutputGradient>> &
873  ref_dphi_coarse = fe_coarse->get_dphi();
874  dphi_coarse = &ref_dphi_coarse;
875  }
876 
877  // The Jacobian * quadrature weight at the quadrature points
878  const std::vector<Real> & JxW =
879  fe->get_JxW();
880 
881  // The XYZ locations of the quadrature points on the
882  // child element
883  const std::vector<Point> & xyz_values =
884  fe->get_xyz();
885 
886 
887 
888  FEType fe_type = base_fe_type, temp_fe_type;
889  const ElemType elem_type = elem->type();
890  fe_type.order = static_cast<Order>(fe_type.order +
891  elem->max_descendant_p_level());
892 
893  // Number of nodes on parent element
894  const unsigned int n_nodes = elem->n_nodes();
895 
896  // Number of dofs on parent element
897  const unsigned int new_n_dofs =
898  FEInterface::n_dofs(dim, fe_type, elem_type);
899 
900  // Fixed vs. free DoFs on edge/face projections
901  std::vector<char> dof_is_fixed(new_n_dofs, false); // bools
902  std::vector<int> free_dof(new_n_dofs, 0);
903 
906  Ue.resize(new_n_dofs); Ue.zero();
907 
908 
909  // When coarsening, in general, we need a series of
910  // projections to ensure a unique and continuous
911  // solution. We start by interpolating nodes, then
912  // hold those fixed and project edges, then
913  // hold those fixed and project faces, then
914  // hold those fixed and project interiors
915 
916  // Copy node values first
917  {
918  std::vector<dof_id_type> node_dof_indices;
919  if (use_old_dof_indices)
920  dof_map.old_dof_indices (elem, node_dof_indices, var);
921  else
922  dof_map.dof_indices (elem, node_dof_indices, var);
923 
924  unsigned int current_dof = 0;
925  for (unsigned int n=0; n!= n_nodes; ++n)
926  {
927  // FIXME: this should go through the DofMap,
928  // not duplicate dof_indices code badly!
929  const unsigned int my_nc =
931  elem_type, n);
932  if (!elem->is_vertex(n))
933  {
934  current_dof += my_nc;
935  continue;
936  }
937 
938  temp_fe_type = base_fe_type;
939  // We're assuming here that child n shares vertex n,
940  // which is wrong on non-simplices right now
941  // ... but this code isn't necessary except on elements
942  // where p refinement creates more vertex dofs; we have
943  // no such elements yet.
944  /*
945  if (elem->child_ptr(n)->p_level() < elem->p_level())
946  {
947  temp_fe_type.order =
948  static_cast<Order>(temp_fe_type.order +
949  elem->child_ptr(n)->p_level());
950  }
951  */
952  const unsigned int nc =
953  FEInterface::n_dofs_at_node (dim, temp_fe_type,
954  elem_type, n);
955  for (unsigned int i=0; i!= nc; ++i)
956  {
957  Ue(current_dof) =
958  old_vector(node_dof_indices[current_dof]);
959  dof_is_fixed[current_dof] = true;
960  current_dof++;
961  }
962  }
963  }
964 
965  // In 3D, project any edge values next
966  if (dim > 2 && cont != DISCONTINUOUS)
967  for (auto e : elem->edge_index_range())
968  {
969  FEInterface::dofs_on_edge(elem, dim, fe_type,
970  e, new_side_dofs);
971 
972  const unsigned int n_new_side_dofs =
973  cast_int<unsigned int>(new_side_dofs.size());
974 
975  // Some edge dofs are on nodes and already
976  // fixed, others are free to calculate
977  unsigned int free_dofs = 0;
978  for (unsigned int i=0; i != n_new_side_dofs; ++i)
979  if (!dof_is_fixed[new_side_dofs[i]])
980  free_dof[free_dofs++] = i;
981  Ke.resize (free_dofs, free_dofs); Ke.zero();
982  Fe.resize (free_dofs); Fe.zero();
983  // The new edge coefficients
984  DenseVector<Number> Uedge(free_dofs);
985 
986  // Add projection terms from each child sharing
987  // this edge
988  for (unsigned int c=0; c != n_children; ++c)
989  {
990  if (!elem->is_child_on_edge(c,e))
991  continue;
992  const Elem * child = elem->child_ptr(c);
993 
994  std::vector<dof_id_type> child_dof_indices;
995  if (use_old_dof_indices)
996  dof_map.old_dof_indices (child,
997  child_dof_indices, var);
998  else
999  dof_map.dof_indices (child,
1000  child_dof_indices, var);
1001  const unsigned int child_n_dofs =
1002  cast_int<unsigned int>
1003  (child_dof_indices.size());
1004 
1005  temp_fe_type = base_fe_type;
1006  temp_fe_type.order =
1007  static_cast<Order>(temp_fe_type.order +
1008  child->p_level());
1009 
1011  temp_fe_type, e, old_side_dofs);
1012 
1013  // Initialize both child and parent FE data
1014  // on the child's edge
1015  fe->attach_quadrature_rule (qedgerule.get());
1016  fe->edge_reinit (child, e);
1017  const unsigned int n_qp = qedgerule->n_points();
1018 
1019  FEMap::inverse_map (dim, elem, xyz_values,
1020  coarse_qpoints);
1021 
1022  fe_coarse->reinit(elem, &coarse_qpoints);
1023 
1024  // Loop over the quadrature points
1025  for (unsigned int qp=0; qp<n_qp; qp++)
1026  {
1027  // solution value at the quadrature point
1028  OutputNumber fineval = libMesh::zero;
1029  // solution grad at the quadrature point
1030  OutputNumberGradient finegrad;
1031 
1032  // Sum the solution values * the DOF
1033  // values at the quadrature point to
1034  // get the solution value and gradient.
1035  for (unsigned int i=0; i<child_n_dofs;
1036  i++)
1037  {
1038  fineval +=
1039  (old_vector(child_dof_indices[i])*
1040  phi_values[i][qp]);
1041  if (cont == C_ONE)
1042  finegrad += (*dphi_values)[i][qp] *
1043  old_vector(child_dof_indices[i]);
1044  }
1045 
1046  // Form edge projection matrix
1047  for (unsigned int sidei=0, freei=0; sidei != n_new_side_dofs; ++sidei)
1048  {
1049  unsigned int i = new_side_dofs[sidei];
1050  // fixed DoFs aren't test functions
1051  if (dof_is_fixed[i])
1052  continue;
1053  for (unsigned int sidej=0, freej=0; sidej != n_new_side_dofs; ++sidej)
1054  {
1055  unsigned int j =
1056  new_side_dofs[sidej];
1057  if (dof_is_fixed[j])
1058  Fe(freei) -=
1059  TensorTools::inner_product(phi_coarse[i][qp],
1060  phi_coarse[j][qp]) *
1061  JxW[qp] * Ue(j);
1062  else
1063  Ke(freei,freej) +=
1064  TensorTools::inner_product(phi_coarse[i][qp],
1065  phi_coarse[j][qp]) *
1066  JxW[qp];
1067  if (cont == C_ONE)
1068  {
1069  if (dof_is_fixed[j])
1070  Fe(freei) -=
1071  TensorTools::inner_product((*dphi_coarse)[i][qp],
1072  (*dphi_coarse)[j][qp]) *
1073  JxW[qp] * Ue(j);
1074  else
1075  Ke(freei,freej) +=
1076  TensorTools::inner_product((*dphi_coarse)[i][qp],
1077  (*dphi_coarse)[j][qp]) *
1078  JxW[qp];
1079  }
1080  if (!dof_is_fixed[j])
1081  freej++;
1082  }
1083  Fe(freei) += TensorTools::inner_product(phi_coarse[i][qp],
1084  fineval) * JxW[qp];
1085  if (cont == C_ONE)
1086  Fe(freei) +=
1087  TensorTools::inner_product(finegrad, (*dphi_coarse)[i][qp]) * JxW[qp];
1088  freei++;
1089  }
1090  }
1091  }
1092  Ke.cholesky_solve(Fe, Uedge);
1093 
1094  // Transfer new edge solutions to element
1095  for (unsigned int i=0; i != free_dofs; ++i)
1096  {
1097  Number & ui = Ue(new_side_dofs[free_dof[i]]);
1099  std::abs(ui - Uedge(i)) < TOLERANCE);
1100  ui = Uedge(i);
1101  dof_is_fixed[new_side_dofs[free_dof[i]]] = true;
1102  }
1103  }
1104 
1105  // Project any side values (edges in 2D, faces in 3D)
1106  if (dim > 1 && cont != DISCONTINUOUS)
1107  for (auto s : elem->side_index_range())
1108  {
1109  FEInterface::dofs_on_side(elem, dim, fe_type,
1110  s, new_side_dofs);
1111 
1112  const unsigned int n_new_side_dofs =
1113  cast_int<unsigned int>(new_side_dofs.size());
1114 
1115  // Some side dofs are on nodes/edges and already
1116  // fixed, others are free to calculate
1117  unsigned int free_dofs = 0;
1118  for (unsigned int i=0; i != n_new_side_dofs; ++i)
1119  if (!dof_is_fixed[new_side_dofs[i]])
1120  free_dof[free_dofs++] = i;
1121  Ke.resize (free_dofs, free_dofs); Ke.zero();
1122  Fe.resize (free_dofs); Fe.zero();
1123  // The new side coefficients
1124  DenseVector<Number> Uside(free_dofs);
1125 
1126  // Add projection terms from each child sharing
1127  // this side
1128  for (unsigned int c=0; c != n_children; ++c)
1129  {
1130  if (!elem->is_child_on_side(c,s))
1131  continue;
1132  const Elem * child = elem->child_ptr(c);
1133 
1134  std::vector<dof_id_type> child_dof_indices;
1135  if (use_old_dof_indices)
1136  dof_map.old_dof_indices (child,
1137  child_dof_indices, var);
1138  else
1139  dof_map.dof_indices (child,
1140  child_dof_indices, var);
1141  const unsigned int child_n_dofs =
1142  cast_int<unsigned int>
1143  (child_dof_indices.size());
1144 
1145  temp_fe_type = base_fe_type;
1146  temp_fe_type.order =
1147  static_cast<Order>(temp_fe_type.order +
1148  child->p_level());
1149 
1151  temp_fe_type, s, old_side_dofs);
1152 
1153  // Initialize both child and parent FE data
1154  // on the child's side
1155  fe->attach_quadrature_rule (qsiderule.get());
1156  fe->reinit (child, s);
1157  const unsigned int n_qp = qsiderule->n_points();
1158 
1159  FEMap::inverse_map (dim, elem, xyz_values,
1160  coarse_qpoints);
1161 
1162  fe_coarse->reinit(elem, &coarse_qpoints);
1163 
1164  // Loop over the quadrature points
1165  for (unsigned int qp=0; qp<n_qp; qp++)
1166  {
1167  // solution value at the quadrature point
1168  OutputNumber fineval = libMesh::zero;
1169  // solution grad at the quadrature point
1170  OutputNumberGradient finegrad;
1171 
1172  // Sum the solution values * the DOF
1173  // values at the quadrature point to
1174  // get the solution value and gradient.
1175  for (unsigned int i=0; i<child_n_dofs;
1176  i++)
1177  {
1178  fineval +=
1179  old_vector(child_dof_indices[i]) *
1180  phi_values[i][qp];
1181  if (cont == C_ONE)
1182  finegrad += (*dphi_values)[i][qp] *
1183  old_vector(child_dof_indices[i]);
1184  }
1185 
1186  // Form side projection matrix
1187  for (unsigned int sidei=0, freei=0; sidei != n_new_side_dofs; ++sidei)
1188  {
1189  unsigned int i = new_side_dofs[sidei];
1190  // fixed DoFs aren't test functions
1191  if (dof_is_fixed[i])
1192  continue;
1193  for (unsigned int sidej=0, freej=0; sidej != n_new_side_dofs; ++sidej)
1194  {
1195  unsigned int j =
1196  new_side_dofs[sidej];
1197  if (dof_is_fixed[j])
1198  Fe(freei) -=
1199  TensorTools::inner_product(phi_coarse[i][qp],
1200  phi_coarse[j][qp]) *
1201  JxW[qp] * Ue(j);
1202  else
1203  Ke(freei,freej) +=
1204  TensorTools::inner_product(phi_coarse[i][qp],
1205  phi_coarse[j][qp]) *
1206  JxW[qp];
1207  if (cont == C_ONE)
1208  {
1209  if (dof_is_fixed[j])
1210  Fe(freei) -=
1211  TensorTools::inner_product((*dphi_coarse)[i][qp],
1212  (*dphi_coarse)[j][qp]) *
1213  JxW[qp] * Ue(j);
1214  else
1215  Ke(freei,freej) +=
1216  TensorTools::inner_product((*dphi_coarse)[i][qp],
1217  (*dphi_coarse)[j][qp]) *
1218  JxW[qp];
1219  }
1220  if (!dof_is_fixed[j])
1221  freej++;
1222  }
1223  Fe(freei) += TensorTools::inner_product(fineval, phi_coarse[i][qp]) * JxW[qp];
1224  if (cont == C_ONE)
1225  Fe(freei) +=
1226  TensorTools::inner_product(finegrad, (*dphi_coarse)[i][qp]) * JxW[qp];
1227  freei++;
1228  }
1229  }
1230  }
1231  Ke.cholesky_solve(Fe, Uside);
1232 
1233  // Transfer new side solutions to element
1234  for (unsigned int i=0; i != free_dofs; ++i)
1235  {
1236  Number & ui = Ue(new_side_dofs[free_dof[i]]);
1238  std::abs(ui - Uside(i)) < TOLERANCE);
1239  ui = Uside(i);
1240  dof_is_fixed[new_side_dofs[free_dof[i]]] = true;
1241  }
1242  }
1243 
1244  // Project the interior values, finally
1245 
1246  // Some interior dofs are on nodes/edges/sides and
1247  // already fixed, others are free to calculate
1248  unsigned int free_dofs = 0;
1249  for (unsigned int i=0; i != new_n_dofs; ++i)
1250  if (!dof_is_fixed[i])
1251  free_dof[free_dofs++] = i;
1252  Ke.resize (free_dofs, free_dofs); Ke.zero();
1253  Fe.resize (free_dofs); Fe.zero();
1254  // The new interior coefficients
1255  DenseVector<Number> Uint(free_dofs);
1256 
1257  // Add projection terms from each child
1258  for (auto & child : elem->child_ref_range())
1259  {
1260  std::vector<dof_id_type> child_dof_indices;
1261  if (use_old_dof_indices)
1262  dof_map.old_dof_indices (&child,
1263  child_dof_indices, var);
1264  else
1265  dof_map.dof_indices (&child,
1266  child_dof_indices, var);
1267  const unsigned int child_n_dofs =
1268  cast_int<unsigned int>
1269  (child_dof_indices.size());
1270 
1271  // Initialize both child and parent FE data
1272  // on the child's quadrature points
1273  fe->attach_quadrature_rule (qrule.get());
1274  fe->reinit (&child);
1275  const unsigned int n_qp = qrule->n_points();
1276 
1277  FEMap::inverse_map (dim, elem, xyz_values, coarse_qpoints);
1278 
1279  fe_coarse->reinit(elem, &coarse_qpoints);
1280 
1281  // Loop over the quadrature points
1282  for (unsigned int qp=0; qp<n_qp; qp++)
1283  {
1284  // solution value at the quadrature point
1285  OutputNumber fineval = libMesh::zero;
1286  // solution grad at the quadrature point
1287  OutputNumberGradient finegrad;
1288 
1289  // Sum the solution values * the DOF
1290  // values at the quadrature point to
1291  // get the solution value and gradient.
1292  for (unsigned int i=0; i<child_n_dofs; i++)
1293  {
1294  fineval +=
1295  (old_vector(child_dof_indices[i]) *
1296  phi_values[i][qp]);
1297  if (cont == C_ONE)
1298  finegrad += (*dphi_values)[i][qp] *
1299  old_vector(child_dof_indices[i]);
1300  }
1301 
1302  // Form interior projection matrix
1303  for (unsigned int i=0, freei=0;
1304  i != new_n_dofs; ++i)
1305  {
1306  // fixed DoFs aren't test functions
1307  if (dof_is_fixed[i])
1308  continue;
1309  for (unsigned int j=0, freej=0; j !=
1310  new_n_dofs; ++j)
1311  {
1312  if (dof_is_fixed[j])
1313  Fe(freei) -=
1314  TensorTools::inner_product(phi_coarse[i][qp],
1315  phi_coarse[j][qp]) *
1316  JxW[qp] * Ue(j);
1317  else
1318  Ke(freei,freej) +=
1319  TensorTools::inner_product(phi_coarse[i][qp],
1320  phi_coarse[j][qp]) *
1321  JxW[qp];
1322  if (cont == C_ONE)
1323  {
1324  if (dof_is_fixed[j])
1325  Fe(freei) -=
1326  TensorTools::inner_product((*dphi_coarse)[i][qp],
1327  (*dphi_coarse)[j][qp]) *
1328  JxW[qp] * Ue(j);
1329  else
1330  Ke(freei,freej) +=
1331  TensorTools::inner_product((*dphi_coarse)[i][qp],
1332  (*dphi_coarse)[j][qp]) *
1333  JxW[qp];
1334  }
1335  if (!dof_is_fixed[j])
1336  freej++;
1337  }
1338  Fe(freei) += TensorTools::inner_product(phi_coarse[i][qp], fineval) *
1339  JxW[qp];
1340  if (cont == C_ONE)
1341  Fe(freei) += TensorTools::inner_product(finegrad, (*dphi_coarse)[i][qp]) * JxW[qp];
1342  freei++;
1343  }
1344  }
1345  }
1346  Ke.cholesky_solve(Fe, Uint);
1347 
1348  // Transfer new interior solutions to element
1349  for (unsigned int i=0; i != free_dofs; ++i)
1350  {
1351  Number & ui = Ue(free_dof[i]);
1353  std::abs(ui - Uint(i)) < TOLERANCE);
1354  ui = Uint(i);
1355  // We should be fixing all dofs by now; no need to keep track of
1356  // that unless we're debugging
1357 #ifndef NDEBUG
1358  dof_is_fixed[free_dof[i]] = true;
1359 #endif
1360  }
1361 
1362 #ifndef NDEBUG
1363  // Make sure every DoF got reached!
1364  for (unsigned int i=0; i != new_n_dofs; ++i)
1365  libmesh_assert(dof_is_fixed[i]);
1366 #endif
1367 }
1368 
1369 
1370 
1371 template <typename OutputType>
1372 void
1374  const DofMap & dof_map,
1375  const Elem * elem,
1376  DenseVector<Number> & Ue,
1377  const bool use_old_dof_indices)
1378 {
1379  Ue.resize(0);
1380 
1381  for (unsigned int v=0; v != dof_map.n_variables(); ++v)
1382  {
1383  DenseVector<Number> Usub;
1384 
1385  coarsened_dof_values(old_vector, dof_map, elem, Usub,
1386  v, use_old_dof_indices);
1387 
1388  Ue.append (Usub);
1389  }
1390 }
1391 
1392 
1393 
1394 template <typename OutputType>
1395 void
1397  DofMap & dof_map,
1398  const unsigned int variable_number,
1399  const Elem * elem)
1400 {
1401  libmesh_assert(elem);
1402 
1403  const unsigned int Dim = elem->dim();
1404 
1405  // Only constrain elements in 2,3D.
1406  if (Dim == 1)
1407  return;
1408 
1409  // Only constrain active elements with this method
1410  if (!elem->active())
1411  return;
1412 
1413  const Variable & var = dof_map.variable(variable_number);
1414  const FEType & base_fe_type = var.type();
1415 
1416  // Construct FE objects for this element and its neighbors.
1417  std::unique_ptr<FEGenericBase<OutputShape>> my_fe
1418  (FEGenericBase<OutputShape>::build(Dim, base_fe_type));
1419  const FEContinuity cont = my_fe->get_continuity();
1420 
1421  // We don't need to constrain discontinuous elements
1422  if (cont == DISCONTINUOUS)
1423  return;
1424  libmesh_assert (cont == C_ZERO || cont == C_ONE);
1425 
1426  std::unique_ptr<FEGenericBase<OutputShape>> neigh_fe
1427  (FEGenericBase<OutputShape>::build(Dim, base_fe_type));
1428 
1429  QGauss my_qface(Dim-1, base_fe_type.default_quadrature_order());
1430  my_fe->attach_quadrature_rule (&my_qface);
1431  std::vector<Point> neigh_qface;
1432 
1433  const std::vector<Real> & JxW = my_fe->get_JxW();
1434  const std::vector<Point> & q_point = my_fe->get_xyz();
1435  const std::vector<std::vector<OutputShape>> & phi = my_fe->get_phi();
1436  const std::vector<std::vector<OutputShape>> & neigh_phi =
1437  neigh_fe->get_phi();
1438  const std::vector<Point> * face_normals = nullptr;
1439  const std::vector<std::vector<OutputGradient>> * dphi = nullptr;
1440  const std::vector<std::vector<OutputGradient>> * neigh_dphi = nullptr;
1441 
1442  std::vector<dof_id_type> my_dof_indices, neigh_dof_indices;
1443  std::vector<unsigned int> my_side_dofs, neigh_side_dofs;
1444 
1445  if (cont != C_ZERO)
1446  {
1447  const std::vector<Point> & ref_face_normals =
1448  my_fe->get_normals();
1449  face_normals = &ref_face_normals;
1450  const std::vector<std::vector<OutputGradient>> & ref_dphi =
1451  my_fe->get_dphi();
1452  dphi = &ref_dphi;
1453  const std::vector<std::vector<OutputGradient>> & ref_neigh_dphi =
1454  neigh_fe->get_dphi();
1455  neigh_dphi = &ref_neigh_dphi;
1456  }
1457 
1458  DenseMatrix<Real> Ke;
1459  DenseVector<Real> Fe;
1460  std::vector<DenseVector<Real>> Ue;
1461 
1462  // Look at the element faces. Check to see if we need to
1463  // build constraints.
1464  for (auto s : elem->side_index_range())
1465  {
1466  // Get pointers to the element's neighbor.
1467  const Elem * neigh = elem->neighbor_ptr(s);
1468 
1469  if (!neigh)
1470  continue;
1471 
1472  if (!var.active_on_subdomain(neigh->subdomain_id()))
1473  continue;
1474 
1475  // h refinement constraints:
1476  // constrain dofs shared between
1477  // this element and ones coarser
1478  // than this element.
1479  if (neigh->level() < elem->level())
1480  {
1481  unsigned int s_neigh = neigh->which_neighbor_am_i(elem);
1482  libmesh_assert_less (s_neigh, neigh->n_neighbors());
1483 
1484  // Find the minimum p level; we build the h constraint
1485  // matrix with this and then constrain away all higher p
1486  // DoFs.
1487  libmesh_assert(neigh->active());
1488  const unsigned int min_p_level =
1489  std::min(elem->p_level(), neigh->p_level());
1490 
1491  // we may need to make the FE objects reinit with the
1492  // minimum shared p_level
1493  const unsigned int old_elem_level = elem->p_level();
1494  if (elem->p_level() != min_p_level)
1495  my_fe->set_fe_order(my_fe->get_fe_type().order.get_order() - old_elem_level + min_p_level);
1496  const unsigned int old_neigh_level = neigh->p_level();
1497  if (old_neigh_level != min_p_level)
1498  neigh_fe->set_fe_order(neigh_fe->get_fe_type().order.get_order() - old_neigh_level + min_p_level);
1499 
1500  my_fe->reinit(elem, s);
1501 
1502  // This function gets called element-by-element, so there
1503  // will be a lot of memory allocation going on. We can
1504  // at least minimize this for the case of the dof indices
1505  // by efficiently preallocating the requisite storage.
1506  // n_nodes is not necessarily n_dofs, but it is better
1507  // than nothing!
1508  my_dof_indices.reserve (elem->n_nodes());
1509  neigh_dof_indices.reserve (neigh->n_nodes());
1510 
1511  dof_map.dof_indices (elem, my_dof_indices,
1512  variable_number,
1513  min_p_level);
1514  dof_map.dof_indices (neigh, neigh_dof_indices,
1515  variable_number,
1516  min_p_level);
1517 
1518  const unsigned int n_qp = my_qface.n_points();
1519 
1520  FEMap::inverse_map (Dim, neigh, q_point, neigh_qface);
1521 
1522  neigh_fe->reinit(neigh, &neigh_qface);
1523 
1524  // We're only concerned with DOFs whose values (and/or first
1525  // derivatives for C1 elements) are supported on side nodes
1526  FEType elem_fe_type = base_fe_type;
1527  if (old_elem_level != min_p_level)
1528  elem_fe_type.order = base_fe_type.order.get_order() - old_elem_level + min_p_level;
1529  FEType neigh_fe_type = base_fe_type;
1530  if (old_neigh_level != min_p_level)
1531  neigh_fe_type.order = base_fe_type.order.get_order() - old_neigh_level + min_p_level;
1532  FEInterface::dofs_on_side(elem, Dim, elem_fe_type, s, my_side_dofs);
1533  FEInterface::dofs_on_side(neigh, Dim, neigh_fe_type, s_neigh, neigh_side_dofs);
1534 
1535  const unsigned int n_side_dofs =
1536  cast_int<unsigned int>(my_side_dofs.size());
1537  libmesh_assert_equal_to (n_side_dofs, neigh_side_dofs.size());
1538 
1539 #ifndef NDEBUG
1540  for (auto i : my_side_dofs)
1541  libmesh_assert_less(i, my_dof_indices.size());
1542  for (auto i : neigh_side_dofs)
1543  libmesh_assert_less(i, neigh_dof_indices.size());
1544 #endif
1545 
1546  Ke.resize (n_side_dofs, n_side_dofs);
1547  Ue.resize(n_side_dofs);
1548 
1549  // Form the projection matrix, (inner product of fine basis
1550  // functions against fine test functions)
1551  for (unsigned int is = 0; is != n_side_dofs; ++is)
1552  {
1553  const unsigned int i = my_side_dofs[is];
1554  for (unsigned int js = 0; js != n_side_dofs; ++js)
1555  {
1556  const unsigned int j = my_side_dofs[js];
1557  for (unsigned int qp = 0; qp != n_qp; ++qp)
1558  {
1559  Ke(is,js) += JxW[qp] * TensorTools::inner_product(phi[i][qp], phi[j][qp]);
1560  if (cont != C_ZERO)
1561  Ke(is,js) += JxW[qp] *
1562  TensorTools::inner_product((*dphi)[i][qp] *
1563  (*face_normals)[qp],
1564  (*dphi)[j][qp] *
1565  (*face_normals)[qp]);
1566  }
1567  }
1568  }
1569 
1570  // Form the right hand sides, (inner product of coarse basis
1571  // functions against fine test functions)
1572  for (unsigned int is = 0; is != n_side_dofs; ++is)
1573  {
1574  const unsigned int i = neigh_side_dofs[is];
1575  Fe.resize (n_side_dofs);
1576  for (unsigned int js = 0; js != n_side_dofs; ++js)
1577  {
1578  const unsigned int j = my_side_dofs[js];
1579  for (unsigned int qp = 0; qp != n_qp; ++qp)
1580  {
1581  Fe(js) += JxW[qp] *
1582  TensorTools::inner_product(neigh_phi[i][qp],
1583  phi[j][qp]);
1584  if (cont != C_ZERO)
1585  Fe(js) += JxW[qp] *
1586  TensorTools::inner_product((*neigh_dphi)[i][qp] *
1587  (*face_normals)[qp],
1588  (*dphi)[j][qp] *
1589  (*face_normals)[qp]);
1590  }
1591  }
1592  Ke.cholesky_solve(Fe, Ue[is]);
1593  }
1594 
1595  for (unsigned int js = 0; js != n_side_dofs; ++js)
1596  {
1597  const unsigned int j = my_side_dofs[js];
1598  const dof_id_type my_dof_g = my_dof_indices[j];
1599  libmesh_assert_not_equal_to (my_dof_g, DofObject::invalid_id);
1600 
1601  // Hunt for "constraining against myself" cases before
1602  // we bother creating a constraint row
1603  bool self_constraint = false;
1604  for (unsigned int is = 0; is != n_side_dofs; ++is)
1605  {
1606  const unsigned int i = neigh_side_dofs[is];
1607  const dof_id_type their_dof_g = neigh_dof_indices[i];
1608  libmesh_assert_not_equal_to (their_dof_g, DofObject::invalid_id);
1609 
1610  if (their_dof_g == my_dof_g)
1611  {
1612 #ifndef NDEBUG
1613  const Real their_dof_value = Ue[is](js);
1614  libmesh_assert_less (std::abs(their_dof_value-1.),
1615  10*TOLERANCE);
1616 
1617  for (unsigned int k = 0; k != n_side_dofs; ++k)
1618  libmesh_assert(k == is ||
1619  std::abs(Ue[k](js)) <
1620  10*TOLERANCE);
1621 #endif
1622 
1623  self_constraint = true;
1624  break;
1625  }
1626  }
1627 
1628  if (self_constraint)
1629  continue;
1630 
1631  DofConstraintRow * constraint_row;
1632 
1633  // we may be running constraint methods concurrently
1634  // on multiple threads, so we need a lock to
1635  // ensure that this constraint is "ours"
1636  {
1637  Threads::spin_mutex::scoped_lock lock(Threads::spin_mtx);
1638 
1639  if (dof_map.is_constrained_dof(my_dof_g))
1640  continue;
1641 
1642  constraint_row = &(constraints[my_dof_g]);
1643  libmesh_assert(constraint_row->empty());
1644  }
1645 
1646  for (unsigned int is = 0; is != n_side_dofs; ++is)
1647  {
1648  const unsigned int i = neigh_side_dofs[is];
1649  const dof_id_type their_dof_g = neigh_dof_indices[i];
1650  libmesh_assert_not_equal_to (their_dof_g, DofObject::invalid_id);
1651  libmesh_assert_not_equal_to (their_dof_g, my_dof_g);
1652 
1653  const Real their_dof_value = Ue[is](js);
1654 
1655  if (std::abs(their_dof_value) < 10*TOLERANCE)
1656  continue;
1657 
1658  constraint_row->insert(std::make_pair(their_dof_g,
1659  their_dof_value));
1660  }
1661  }
1662 
1663  my_fe->set_fe_order(my_fe->get_fe_type().order.get_order() + old_elem_level - min_p_level);
1664  neigh_fe->set_fe_order(neigh_fe->get_fe_type().order.get_order() + old_neigh_level - min_p_level);
1665  }
1666 
1667  // p refinement constraints:
1668  // constrain dofs shared between
1669  // active elements and neighbors with
1670  // lower polynomial degrees
1671  const unsigned int min_p_level =
1672  neigh->min_p_level_by_neighbor(elem, elem->p_level());
1673  if (min_p_level < elem->p_level())
1674  {
1675  // Adaptive p refinement of non-hierarchic bases will
1676  // require more coding
1677  libmesh_assert(my_fe->is_hierarchic());
1678  dof_map.constrain_p_dofs(variable_number, elem,
1679  s, min_p_level);
1680  }
1681  }
1682 }
1683 
1684 #endif // #ifdef LIBMESH_ENABLE_AMR
1685 
1686 
1687 
1688 #ifdef LIBMESH_ENABLE_PERIODIC
1689 template <typename OutputType>
1690 void
1693  DofMap & dof_map,
1694  const PeriodicBoundaries & boundaries,
1695  const MeshBase & mesh,
1696  const PointLocatorBase * point_locator,
1697  const unsigned int variable_number,
1698  const Elem * elem)
1699 {
1700  // Only bother if we truly have periodic boundaries
1701  if (boundaries.empty())
1702  return;
1703 
1704  libmesh_assert(elem);
1705 
1706  // Only constrain active elements with this method
1707  if (!elem->active())
1708  return;
1709 
1710  const unsigned int Dim = elem->dim();
1711 
1712  // We need sys_number and variable_number for DofObject methods
1713  // later
1714  const unsigned int sys_number = dof_map.sys_number();
1715 
1716  const FEType & base_fe_type = dof_map.variable_type(variable_number);
1717 
1718  // Construct FE objects for this element and its pseudo-neighbors.
1719  std::unique_ptr<FEGenericBase<OutputShape>> my_fe
1720  (FEGenericBase<OutputShape>::build(Dim, base_fe_type));
1721  const FEContinuity cont = my_fe->get_continuity();
1722 
1723  // We don't need to constrain discontinuous elements
1724  if (cont == DISCONTINUOUS)
1725  return;
1726  libmesh_assert (cont == C_ZERO || cont == C_ONE);
1727 
1728  // We'll use element size to generate relative tolerances later
1729  const Real primary_hmin = elem->hmin();
1730 
1731  std::unique_ptr<FEGenericBase<OutputShape>> neigh_fe
1732  (FEGenericBase<OutputShape>::build(Dim, base_fe_type));
1733 
1734  QGauss my_qface(Dim-1, base_fe_type.default_quadrature_order());
1735  my_fe->attach_quadrature_rule (&my_qface);
1736  std::vector<Point> neigh_qface;
1737 
1738  const std::vector<Real> & JxW = my_fe->get_JxW();
1739  const std::vector<Point> & q_point = my_fe->get_xyz();
1740  const std::vector<std::vector<OutputShape>> & phi = my_fe->get_phi();
1741  const std::vector<std::vector<OutputShape>> & neigh_phi =
1742  neigh_fe->get_phi();
1743  const std::vector<Point> * face_normals = nullptr;
1744  const std::vector<std::vector<OutputGradient>> * dphi = nullptr;
1745  const std::vector<std::vector<OutputGradient>> * neigh_dphi = nullptr;
1746  std::vector<dof_id_type> my_dof_indices, neigh_dof_indices;
1747  std::vector<unsigned int> my_side_dofs, neigh_side_dofs;
1748 
1749  if (cont != C_ZERO)
1750  {
1751  const std::vector<Point> & ref_face_normals =
1752  my_fe->get_normals();
1753  face_normals = &ref_face_normals;
1754  const std::vector<std::vector<OutputGradient>> & ref_dphi =
1755  my_fe->get_dphi();
1756  dphi = &ref_dphi;
1757  const std::vector<std::vector<OutputGradient>> & ref_neigh_dphi =
1758  neigh_fe->get_dphi();
1759  neigh_dphi = &ref_neigh_dphi;
1760  }
1761 
1762  DenseMatrix<Real> Ke;
1763  DenseVector<Real> Fe;
1764  std::vector<DenseVector<Real>> Ue;
1765 
1766  // Container to catch the boundary ids that BoundaryInfo hands us.
1767  std::vector<boundary_id_type> bc_ids;
1768 
1769  // Look at the element faces. Check to see if we need to
1770  // build constraints.
1771  const unsigned short int max_ns = elem->n_sides();
1772  for (unsigned short int s = 0; s != max_ns; ++s)
1773  {
1774  if (elem->neighbor_ptr(s))
1775  continue;
1776 
1777  mesh.get_boundary_info().boundary_ids (elem, s, bc_ids);
1778 
1779  for (const auto & boundary_id : bc_ids)
1780  {
1781  const PeriodicBoundaryBase * periodic = boundaries.boundary(boundary_id);
1782  if (periodic && periodic->is_my_variable(variable_number))
1783  {
1784  libmesh_assert(point_locator);
1785 
1786  // Get pointers to the element's neighbor.
1787  const Elem * neigh = boundaries.neighbor(boundary_id, *point_locator, elem, s);
1788 
1789  if (neigh == nullptr)
1790  libmesh_error_msg("PeriodicBoundaries point locator object returned nullptr!");
1791 
1792  // periodic (and possibly h refinement) constraints:
1793  // constrain dofs shared between
1794  // this element and ones as coarse
1795  // as or coarser than this element.
1796  if (neigh->level() <= elem->level())
1797  {
1798  unsigned int s_neigh =
1800  libmesh_assert_not_equal_to (s_neigh, libMesh::invalid_uint);
1801 
1802 #ifdef LIBMESH_ENABLE_AMR
1803  // Find the minimum p level; we build the h constraint
1804  // matrix with this and then constrain away all higher p
1805  // DoFs.
1806  libmesh_assert(neigh->active());
1807  const unsigned int min_p_level =
1808  std::min(elem->p_level(), neigh->p_level());
1809 
1810  // we may need to make the FE objects reinit with the
1811  // minimum shared p_level
1812  // FIXME - I hate using const_cast<> and avoiding
1813  // accessor functions; there's got to be a
1814  // better way to do this!
1815  const unsigned int old_elem_level = elem->p_level();
1816  if (old_elem_level != min_p_level)
1817  (const_cast<Elem *>(elem))->hack_p_level(min_p_level);
1818  const unsigned int old_neigh_level = neigh->p_level();
1819  if (old_neigh_level != min_p_level)
1820  (const_cast<Elem *>(neigh))->hack_p_level(min_p_level);
1821 #endif // #ifdef LIBMESH_ENABLE_AMR
1822 
1823  // We can do a projection with a single integration,
1824  // due to the assumption of nested finite element
1825  // subspaces.
1826  // FIXME: it might be more efficient to do nodes,
1827  // then edges, then side, to reduce the size of the
1828  // Cholesky factorization(s)
1829  my_fe->reinit(elem, s);
1830 
1831  dof_map.dof_indices (elem, my_dof_indices,
1832  variable_number);
1833  dof_map.dof_indices (neigh, neigh_dof_indices,
1834  variable_number);
1835 
1836  // We use neigh_dof_indices_all_variables in the case that the
1837  // periodic boundary condition involves mappings between multiple
1838  // variables.
1839  std::vector<std::vector<dof_id_type>> neigh_dof_indices_all_variables;
1840  if(periodic->has_transformation_matrix())
1841  {
1842  const std::set<unsigned int> & variables = periodic->get_variables();
1843  neigh_dof_indices_all_variables.resize(variables.size());
1844  unsigned int index = 0;
1845  for(unsigned int var : variables)
1846  {
1847  dof_map.dof_indices (neigh, neigh_dof_indices_all_variables[index],
1848  var);
1849  index++;
1850  }
1851  }
1852 
1853  const unsigned int n_qp = my_qface.n_points();
1854 
1855  // Translate the quadrature points over to the
1856  // neighbor's boundary
1857  std::vector<Point> neigh_point(q_point.size());
1858  for (auto i : index_range(neigh_point))
1859  neigh_point[i] = periodic->get_corresponding_pos(q_point[i]);
1860 
1861  FEMap::inverse_map (Dim, neigh, neigh_point,
1862  neigh_qface);
1863 
1864  neigh_fe->reinit(neigh, &neigh_qface);
1865 
1866  // We're only concerned with DOFs whose values (and/or first
1867  // derivatives for C1 elements) are supported on side nodes
1868  FEInterface::dofs_on_side(elem, Dim, base_fe_type, s, my_side_dofs);
1869  FEInterface::dofs_on_side(neigh, Dim, base_fe_type, s_neigh, neigh_side_dofs);
1870 
1871  // We're done with functions that examine Elem::p_level(),
1872  // so let's unhack those levels
1873 #ifdef LIBMESH_ENABLE_AMR
1874  if (elem->p_level() != old_elem_level)
1875  (const_cast<Elem *>(elem))->hack_p_level(old_elem_level);
1876  if (neigh->p_level() != old_neigh_level)
1877  (const_cast<Elem *>(neigh))->hack_p_level(old_neigh_level);
1878 #endif // #ifdef LIBMESH_ENABLE_AMR
1879 
1880  const unsigned int n_side_dofs =
1881  cast_int<unsigned int>
1882  (my_side_dofs.size());
1883  libmesh_assert_equal_to (n_side_dofs, neigh_side_dofs.size());
1884 
1885  Ke.resize (n_side_dofs, n_side_dofs);
1886  Ue.resize(n_side_dofs);
1887 
1888  // Form the projection matrix, (inner product of fine basis
1889  // functions against fine test functions)
1890  for (unsigned int is = 0; is != n_side_dofs; ++is)
1891  {
1892  const unsigned int i = my_side_dofs[is];
1893  for (unsigned int js = 0; js != n_side_dofs; ++js)
1894  {
1895  const unsigned int j = my_side_dofs[js];
1896  for (unsigned int qp = 0; qp != n_qp; ++qp)
1897  {
1898  Ke(is,js) += JxW[qp] *
1899  TensorTools::inner_product(phi[i][qp],
1900  phi[j][qp]);
1901  if (cont != C_ZERO)
1902  Ke(is,js) += JxW[qp] *
1903  TensorTools::inner_product((*dphi)[i][qp] *
1904  (*face_normals)[qp],
1905  (*dphi)[j][qp] *
1906  (*face_normals)[qp]);
1907  }
1908  }
1909  }
1910 
1911  // Form the right hand sides, (inner product of coarse basis
1912  // functions against fine test functions)
1913  for (unsigned int is = 0; is != n_side_dofs; ++is)
1914  {
1915  const unsigned int i = neigh_side_dofs[is];
1916  Fe.resize (n_side_dofs);
1917  for (unsigned int js = 0; js != n_side_dofs; ++js)
1918  {
1919  const unsigned int j = my_side_dofs[js];
1920  for (unsigned int qp = 0; qp != n_qp; ++qp)
1921  {
1922  Fe(js) += JxW[qp] *
1923  TensorTools::inner_product(neigh_phi[i][qp],
1924  phi[j][qp]);
1925  if (cont != C_ZERO)
1926  Fe(js) += JxW[qp] *
1927  TensorTools::inner_product((*neigh_dphi)[i][qp] *
1928  (*face_normals)[qp],
1929  (*dphi)[j][qp] *
1930  (*face_normals)[qp]);
1931  }
1932  }
1933  Ke.cholesky_solve(Fe, Ue[is]);
1934  }
1935 
1936  // Make sure we're not adding recursive constraints
1937  // due to the redundancy in the way we add periodic
1938  // boundary constraints
1939  //
1940  // In order for this to work while threaded or on
1941  // distributed meshes, we need a rigorous way to
1942  // avoid recursive constraints. Here it is:
1943  //
1944  // For vertex DoFs, if there is a "prior" element
1945  // (i.e. a coarser element or an equally refined
1946  // element with a lower id) on this boundary which
1947  // contains the vertex point, then we will avoid
1948  // generating constraints; the prior element (or
1949  // something prior to it) may do so. If we are the
1950  // most prior (or "primary") element on this
1951  // boundary sharing this point, then we look at the
1952  // boundary periodic to us, we find the primary
1953  // element there, and if that primary is coarser or
1954  // equal-but-lower-id, then our vertex dofs are
1955  // constrained in terms of that element.
1956  //
1957  // For edge DoFs, if there is a coarser element
1958  // on this boundary sharing this edge, then we will
1959  // avoid generating constraints (we will be
1960  // constrained indirectly via AMR constraints
1961  // connecting us to the coarser element's DoFs). If
1962  // we are the coarsest element sharing this edge,
1963  // then we generate constraints if and only if we
1964  // are finer than the coarsest element on the
1965  // boundary periodic to us sharing the corresponding
1966  // periodic edge, or if we are at equal level but
1967  // our edge nodes have higher ids than the periodic
1968  // edge nodes (sorted from highest to lowest, then
1969  // compared lexicographically)
1970  //
1971  // For face DoFs, we generate constraints if we are
1972  // finer than our periodic neighbor, or if we are at
1973  // equal level but our element id is higher than its
1974  // element id.
1975  //
1976  // If the primary neighbor is also the current elem
1977  // (a 1-element-thick mesh) then we choose which
1978  // vertex dofs to constrain via lexicographic
1979  // ordering on point locations
1980 
1981  // FIXME: This code doesn't yet properly handle
1982  // cases where multiple different periodic BCs
1983  // intersect.
1984  std::set<dof_id_type> my_constrained_dofs;
1985 
1986  // Container to catch boundary IDs handed back by BoundaryInfo.
1987  std::vector<boundary_id_type> new_bc_ids;
1988 
1989  for (auto n : elem->node_index_range())
1990  {
1991  if (!elem->is_node_on_side(n,s))
1992  continue;
1993 
1994  const Node & my_node = elem->node_ref(n);
1995 
1996  if (elem->is_vertex(n))
1997  {
1998  // Find all boundary ids that include this
1999  // point and have periodic boundary
2000  // conditions for this variable
2001  std::set<boundary_id_type> point_bcids;
2002 
2003  for (unsigned int new_s = 0;
2004  new_s != max_ns; ++new_s)
2005  {
2006  if (!elem->is_node_on_side(n,new_s))
2007  continue;
2008 
2009  mesh.get_boundary_info().boundary_ids (elem, s, new_bc_ids);
2010 
2011  for (const auto & new_boundary_id : new_bc_ids)
2012  {
2013  const PeriodicBoundaryBase * new_periodic = boundaries.boundary(new_boundary_id);
2014  if (new_periodic && new_periodic->is_my_variable(variable_number))
2015  point_bcids.insert(new_boundary_id);
2016  }
2017  }
2018 
2019  // See if this vertex has point neighbors to
2020  // defer to
2021  if (primary_boundary_point_neighbor
2022  (elem, my_node, mesh.get_boundary_info(), point_bcids)
2023  != elem)
2024  continue;
2025 
2026  // Find the complementary boundary id set
2027  std::set<boundary_id_type> point_pairedids;
2028  for (const auto & new_boundary_id : point_bcids)
2029  {
2030  const PeriodicBoundaryBase * new_periodic = boundaries.boundary(new_boundary_id);
2031  point_pairedids.insert(new_periodic->pairedboundary);
2032  }
2033 
2034  // What do we want to constrain against?
2035  const Elem * primary_elem = nullptr;
2036  const Elem * main_neigh = nullptr;
2037  Point main_pt = my_node,
2038  primary_pt = my_node;
2039 
2040  for (const auto & new_boundary_id : point_bcids)
2041  {
2042  // Find the corresponding periodic point and
2043  // its primary neighbor
2044  const PeriodicBoundaryBase * new_periodic = boundaries.boundary(new_boundary_id);
2045 
2046  const Point neigh_pt =
2047  new_periodic->get_corresponding_pos(my_node);
2048 
2049  // If the point is getting constrained
2050  // to itself by this PBC then we don't
2051  // generate any constraints
2052  if (neigh_pt.absolute_fuzzy_equals
2053  (my_node, primary_hmin*TOLERANCE))
2054  continue;
2055 
2056  // Otherwise we'll have a constraint in
2057  // one direction or another
2058  if (!primary_elem)
2059  primary_elem = elem;
2060 
2061  const Elem * primary_neigh =
2062  primary_boundary_point_neighbor(neigh, neigh_pt,
2064  point_pairedids);
2065 
2066  libmesh_assert(primary_neigh);
2067 
2068  if (new_boundary_id == boundary_id)
2069  {
2070  main_neigh = primary_neigh;
2071  main_pt = neigh_pt;
2072  }
2073 
2074  // Finer elements will get constrained in
2075  // terms of coarser neighbors, not the
2076  // other way around
2077  if ((primary_neigh->level() > primary_elem->level()) ||
2078 
2079  // For equal-level elements, the one with
2080  // higher id gets constrained in terms of
2081  // the one with lower id
2082  (primary_neigh->level() == primary_elem->level() &&
2083  primary_neigh->id() > primary_elem->id()) ||
2084 
2085  // On a one-element-thick mesh, we compare
2086  // points to see what side gets constrained
2087  (primary_neigh == primary_elem &&
2088  (neigh_pt > primary_pt)))
2089  continue;
2090 
2091  primary_elem = primary_neigh;
2092  primary_pt = neigh_pt;
2093  }
2094 
2095  if (!primary_elem ||
2096  primary_elem != main_neigh ||
2097  primary_pt != main_pt)
2098  continue;
2099  }
2100  else if (elem->is_edge(n))
2101  {
2102  // Find which edge we're on
2103  unsigned int e=0, ne = elem->n_edges();
2104  for (; e != ne; ++e)
2105  {
2106  if (elem->is_node_on_edge(n,e))
2107  break;
2108  }
2109  libmesh_assert_less (e, elem->n_edges());
2110 
2111  // Find the edge end nodes
2112  const Node
2113  * e1 = nullptr,
2114  * e2 = nullptr;
2115  for (auto nn : elem->node_index_range())
2116  {
2117  if (nn == n)
2118  continue;
2119 
2120  if (elem->is_node_on_edge(nn, e))
2121  {
2122  if (e1 == nullptr)
2123  {
2124  e1 = elem->node_ptr(nn);
2125  }
2126  else
2127  {
2128  e2 = elem->node_ptr(nn);
2129  break;
2130  }
2131  }
2132  }
2133  libmesh_assert (e1 && e2);
2134 
2135  // Find all boundary ids that include this
2136  // edge and have periodic boundary
2137  // conditions for this variable
2138  std::set<boundary_id_type> edge_bcids;
2139 
2140  for (unsigned int new_s = 0;
2141  new_s != max_ns; ++new_s)
2142  {
2143  if (!elem->is_node_on_side(n,new_s))
2144  continue;
2145 
2146  // We're reusing the new_bc_ids vector created outside the loop over nodes.
2147  mesh.get_boundary_info().boundary_ids (elem, s, new_bc_ids);
2148 
2149  for (const auto & new_boundary_id : new_bc_ids)
2150  {
2151  const PeriodicBoundaryBase * new_periodic = boundaries.boundary(new_boundary_id);
2152  if (new_periodic && new_periodic->is_my_variable(variable_number))
2153  edge_bcids.insert(new_boundary_id);
2154  }
2155  }
2156 
2157 
2158  // See if this edge has neighbors to defer to
2159  if (primary_boundary_edge_neighbor
2160  (elem, *e1, *e2, mesh.get_boundary_info(), edge_bcids)
2161  != elem)
2162  continue;
2163 
2164  // Find the complementary boundary id set
2165  std::set<boundary_id_type> edge_pairedids;
2166  for (const auto & new_boundary_id : edge_bcids)
2167  {
2168  const PeriodicBoundaryBase * new_periodic = boundaries.boundary(new_boundary_id);
2169  edge_pairedids.insert(new_periodic->pairedboundary);
2170  }
2171 
2172  // What do we want to constrain against?
2173  const Elem * primary_elem = nullptr;
2174  const Elem * main_neigh = nullptr;
2175  Point main_pt1 = *e1,
2176  main_pt2 = *e2,
2177  primary_pt1 = *e1,
2178  primary_pt2 = *e2;
2179 
2180  for (const auto & new_boundary_id : edge_bcids)
2181  {
2182  // Find the corresponding periodic edge and
2183  // its primary neighbor
2184  const PeriodicBoundaryBase * new_periodic = boundaries.boundary(new_boundary_id);
2185 
2186  Point neigh_pt1 = new_periodic->get_corresponding_pos(*e1),
2187  neigh_pt2 = new_periodic->get_corresponding_pos(*e2);
2188 
2189  // If the edge is getting constrained
2190  // to itself by this PBC then we don't
2191  // generate any constraints
2192  if (neigh_pt1.absolute_fuzzy_equals
2193  (*e1, primary_hmin*TOLERANCE) &&
2194  neigh_pt2.absolute_fuzzy_equals
2195  (*e2, primary_hmin*TOLERANCE))
2196  continue;
2197 
2198  // Otherwise we'll have a constraint in
2199  // one direction or another
2200  if (!primary_elem)
2201  primary_elem = elem;
2202 
2203  const Elem * primary_neigh = primary_boundary_edge_neighbor
2204  (neigh, neigh_pt1, neigh_pt2,
2205  mesh.get_boundary_info(), edge_pairedids);
2206 
2207  libmesh_assert(primary_neigh);
2208 
2209  if (new_boundary_id == boundary_id)
2210  {
2211  main_neigh = primary_neigh;
2212  main_pt1 = neigh_pt1;
2213  main_pt2 = neigh_pt2;
2214  }
2215 
2216  // If we have a one-element thick mesh,
2217  // we'll need to sort our points to get a
2218  // consistent ordering rule
2219  //
2220  // Use >= in this test to make sure that,
2221  // for angular constraints, no node gets
2222  // constrained to itself.
2223  if (primary_neigh == primary_elem)
2224  {
2225  if (primary_pt1 > primary_pt2)
2226  std::swap(primary_pt1, primary_pt2);
2227  if (neigh_pt1 > neigh_pt2)
2228  std::swap(neigh_pt1, neigh_pt2);
2229 
2230  if (neigh_pt2 >= primary_pt2)
2231  continue;
2232  }
2233 
2234  // Otherwise:
2235  // Finer elements will get constrained in
2236  // terms of coarser ones, not the other way
2237  // around
2238  if ((primary_neigh->level() > primary_elem->level()) ||
2239 
2240  // For equal-level elements, the one with
2241  // higher id gets constrained in terms of
2242  // the one with lower id
2243  (primary_neigh->level() == primary_elem->level() &&
2244  primary_neigh->id() > primary_elem->id()))
2245  continue;
2246 
2247  primary_elem = primary_neigh;
2248  primary_pt1 = neigh_pt1;
2249  primary_pt2 = neigh_pt2;
2250  }
2251 
2252  if (!primary_elem ||
2253  primary_elem != main_neigh ||
2254  primary_pt1 != main_pt1 ||
2255  primary_pt2 != main_pt2)
2256  continue;
2257  }
2258  else if (elem->is_face(n))
2259  {
2260  // If we have a one-element thick mesh,
2261  // use the ordering of the face node and its
2262  // periodic counterpart to determine what
2263  // gets constrained
2264  if (neigh == elem)
2265  {
2266  const Point neigh_pt =
2267  periodic->get_corresponding_pos(my_node);
2268  if (neigh_pt > my_node)
2269  continue;
2270  }
2271 
2272  // Otherwise:
2273  // Finer elements will get constrained in
2274  // terms of coarser ones, not the other way
2275  // around
2276  if ((neigh->level() > elem->level()) ||
2277 
2278  // For equal-level elements, the one with
2279  // higher id gets constrained in terms of
2280  // the one with lower id
2281  (neigh->level() == elem->level() &&
2282  neigh->id() > elem->id()))
2283  continue;
2284  }
2285 
2286  // If we made it here without hitting a continue
2287  // statement, then we're at a node whose dofs
2288  // should be constrained by this element's
2289  // calculations.
2290  const unsigned int n_comp =
2291  my_node.n_comp(sys_number, variable_number);
2292 
2293  for (unsigned int i=0; i != n_comp; ++i)
2294  my_constrained_dofs.insert
2295  (my_node.dof_number
2296  (sys_number, variable_number, i));
2297  }
2298 
2299  // FIXME: old code for disambiguating periodic BCs:
2300  // this is not threadsafe nor safe to run on a
2301  // non-serialized mesh.
2302  /*
2303  std::vector<bool> recursive_constraint(n_side_dofs, false);
2304 
2305  for (unsigned int is = 0; is != n_side_dofs; ++is)
2306  {
2307  const unsigned int i = neigh_side_dofs[is];
2308  const dof_id_type their_dof_g = neigh_dof_indices[i];
2309  libmesh_assert_not_equal_to (their_dof_g, DofObject::invalid_id);
2310 
2311  {
2312  Threads::spin_mutex::scoped_lock lock(Threads::spin_mtx);
2313 
2314  if (!dof_map.is_constrained_dof(their_dof_g))
2315  continue;
2316  }
2317 
2318  DofConstraintRow & their_constraint_row =
2319  constraints[their_dof_g].first;
2320 
2321  for (unsigned int js = 0; js != n_side_dofs; ++js)
2322  {
2323  const unsigned int j = my_side_dofs[js];
2324  const dof_id_type my_dof_g = my_dof_indices[j];
2325  libmesh_assert_not_equal_to (my_dof_g, DofObject::invalid_id);
2326 
2327  if (their_constraint_row.count(my_dof_g))
2328  recursive_constraint[js] = true;
2329  }
2330  }
2331  */
2332 
2333  for (unsigned int js = 0; js != n_side_dofs; ++js)
2334  {
2335  // FIXME: old code path
2336  // if (recursive_constraint[js])
2337  // continue;
2338 
2339  const unsigned int j = my_side_dofs[js];
2340  const dof_id_type my_dof_g = my_dof_indices[j];
2341  libmesh_assert_not_equal_to (my_dof_g, DofObject::invalid_id);
2342 
2343  // FIXME: new code path
2344  if (!my_constrained_dofs.count(my_dof_g))
2345  continue;
2346 
2347  DofConstraintRow * constraint_row;
2348 
2349  // we may be running constraint methods concurrently
2350  // on multiple threads, so we need a lock to
2351  // ensure that this constraint is "ours"
2352  {
2353  Threads::spin_mutex::scoped_lock lock(Threads::spin_mtx);
2354 
2355  if (dof_map.is_constrained_dof(my_dof_g))
2356  continue;
2357 
2358  constraint_row = &(constraints[my_dof_g]);
2359  libmesh_assert(constraint_row->empty());
2360  }
2361 
2362  for (unsigned int is = 0; is != n_side_dofs; ++is)
2363  {
2364  const unsigned int i = neigh_side_dofs[is];
2365  const dof_id_type their_dof_g = neigh_dof_indices[i];
2366  libmesh_assert_not_equal_to (their_dof_g, DofObject::invalid_id);
2367 
2368  // Periodic constraints should never be
2369  // self-constraints
2370  // libmesh_assert_not_equal_to (their_dof_g, my_dof_g);
2371 
2372  const Real their_dof_value = Ue[is](js);
2373 
2374  if (their_dof_g == my_dof_g)
2375  {
2376  libmesh_assert_less (std::abs(their_dof_value-1.), 1.e-5);
2377  for (unsigned int k = 0; k != n_side_dofs; ++k)
2378  libmesh_assert(k == is || std::abs(Ue[k](js)) < 1.e-5);
2379  continue;
2380  }
2381 
2382  if (std::abs(their_dof_value) < 10*TOLERANCE)
2383  continue;
2384 
2385  if(!periodic->has_transformation_matrix())
2386  {
2387  constraint_row->insert(std::make_pair(their_dof_g,
2388  their_dof_value));
2389  }
2390  else
2391  {
2392  // In this case the current variable is constrained in terms of other variables.
2393  // We assume that all variables in this constraint have the same FE type (this
2394  // is asserted below), and hence we can create the constraint row contribution
2395  // by multiplying their_dof_value by the corresponding row of the transformation
2396  // matrix.
2397 
2398  const std::set<unsigned int> & variables = periodic->get_variables();
2399  neigh_dof_indices_all_variables.resize(variables.size());
2400  unsigned int index = 0;
2401  for(unsigned int other_var : variables)
2402  {
2403  libmesh_assert_msg(base_fe_type == dof_map.variable_type(other_var), "FE types must match for all variables involved in constraint");
2404 
2405  Real var_weighting = periodic->get_transformation_matrix()(variable_number, other_var);
2406  constraint_row->insert(std::make_pair(neigh_dof_indices_all_variables[index][i],
2407  var_weighting*their_dof_value));
2408  index++;
2409  }
2410  }
2411 
2412  }
2413  }
2414  }
2415  // p refinement constraints:
2416  // constrain dofs shared between
2417  // active elements and neighbors with
2418  // lower polynomial degrees
2419 #ifdef LIBMESH_ENABLE_AMR
2420  const unsigned int min_p_level =
2421  neigh->min_p_level_by_neighbor(elem, elem->p_level());
2422  if (min_p_level < elem->p_level())
2423  {
2424  // Adaptive p refinement of non-hierarchic bases will
2425  // require more coding
2426  libmesh_assert(my_fe->is_hierarchic());
2427  dof_map.constrain_p_dofs(variable_number, elem,
2428  s, min_p_level);
2429  }
2430 #endif // #ifdef LIBMESH_ENABLE_AMR
2431  }
2432  }
2433  }
2434 }
2435 
2436 #endif // LIBMESH_ENABLE_PERIODIC
2437 
2438 // ------------------------------------------------------------
2439 // Explicit instantiations
2440 template class FEGenericBase<Real>;
2441 template class FEGenericBase<RealGradient>;
2442 
2443 } // namespace libMesh
libMesh::FEGenericBase::print_d2phi
void print_d2phi(std::ostream &os) const
Prints the value of each shape function's second derivatives at each quadrature point.
Definition: fe_base.C:807
libMesh::DofConstraints
The constraint matrix storage format.
Definition: dof_map.h:105
libMesh::C_ONE
Definition: enum_fe_family.h:80
libMesh::FEType::inf_map
InfMapType inf_map
The coordinate mapping type of the infinite element.
Definition: fe_type.h:257
libMesh::Elem::find_point_neighbors
void find_point_neighbors(const Point &p, std::set< const Elem * > &neighbor_set) const
This function finds all active elements (including this one) which are in the same manifold as this e...
Definition: elem.C:560
libMesh::dof_id_type
uint8_t dof_id_type
Definition: id_types.h:67
libMesh::Number
Real Number
Definition: libmesh_common.h:195
libMesh::BoundaryInfo::boundary_ids
std::vector< boundary_id_type > boundary_ids(const Node *node) const
Definition: boundary_info.C:985
libMesh::Elem::child_ptr
const Elem * child_ptr(unsigned int i) const
Definition: elem.h:2567
libMesh::FEType::radial_family
FEFamily radial_family
The type of approximation in radial direction.
Definition: fe_type.h:249
libMesh::BoundaryInfo
The BoundaryInfo class contains information relevant to boundary conditions including storing faces,...
Definition: boundary_info.h:57
libMesh::PeriodicBoundaryBase::has_transformation_matrix
bool has_transformation_matrix() const
Definition: periodic_boundary_base.C:76
libMesh::Elem::is_node_on_side
virtual bool is_node_on_side(const unsigned int n, const unsigned int s) const =0
libMesh::PeriodicBoundaries
We're using a class instead of a typedef to allow forward declarations and future flexibility.
Definition: periodic_boundaries.h:51
libMesh::Elem::n_edges
virtual unsigned int n_edges() const =0
libMesh::OrderWrapper::get_order
int get_order() const
Explicitly request the order as an int.
Definition: fe_type.h:77
libMesh::invalid_uint
const unsigned int invalid_uint
A number which is used quite often to represent an invalid or uninitialized value.
Definition: libmesh.h:249
libMesh::FEGenericBase::compute_periodic_constraints
static void compute_periodic_constraints(DofConstraints &constraints, DofMap &dof_map, const PeriodicBoundaries &boundaries, const MeshBase &mesh, const PointLocatorBase *point_locator, const unsigned int variable_number, const Elem *elem)
Computes the constraint matrix contributions (for meshes with periodic boundary conditions) correspon...
Definition: fe_base.C:1692
libMesh::PeriodicBoundaryBase::get_corresponding_pos
virtual Point get_corresponding_pos(const Point &pt) const =0
This function should be overridden by derived classes to define how one finds corresponding nodes on ...
libMesh::CLOUGH
Definition: enum_fe_family.h:53
libMesh::MeshBase::get_boundary_info
const BoundaryInfo & get_boundary_info() const
The information about boundary ids on the mesh.
Definition: mesh_base.h:132
libMesh::FEType::family
FEFamily family
The type of finite element.
Definition: fe_type.h:203
libMesh::DenseVector::append
void append(const DenseVector< T2 > &other_vector)
Append additional entries to (resizing, but unchanging) the vector.
Definition: dense_vector.h:367
libMesh::QGauss
This class implements specific orders of Gauss quadrature.
Definition: quadrature_gauss.h:39
libMesh::DofMap::dof_indices
void dof_indices(const Elem *const elem, std::vector< dof_id_type > &di) const
Fills the vector di with the global degree of freedom indices for the element.
Definition: dof_map.C:1967
libMesh::Elem::find_edge_neighbors
void find_edge_neighbors(const Point &p1, const Point &p2, std::set< const Elem * > &neighbor_set) const
This function finds all active elements in the same manifold as this element which touch the current ...
Definition: elem.C:646
libMesh::Elem::level
unsigned int level() const
Definition: elem.h:2478
libMesh::L2_HIERARCHIC
Definition: enum_fe_family.h:40
libMesh::Elem::child_ref_range
SimpleRange< ChildRefIter > child_ref_range()
Returns a range with all children of a parent element, usable in range-based for loops.
Definition: elem.h:1839
libMesh::Elem::n_nodes
virtual unsigned int n_nodes() const =0
libMesh::INFINITE_MAP
Definition: enum_fe_family.h:48
libMesh::Elem::edge_index_range
IntRange< unsigned short > edge_index_range() const
Definition: elem.h:2179
libMesh::Elem::n_neighbors
unsigned int n_neighbors() const
Definition: elem.h:631
libMesh::HERMITE
Definition: enum_fe_family.h:54
libMesh::FEInterface::n_dofs_at_node
static unsigned int n_dofs_at_node(const unsigned int dim, const FEType &fe_t, const ElemType t, const unsigned int n)
Definition: fe_interface.C:503
libMesh::PeriodicBoundaryBase
The base class for defining periodic boundaries.
Definition: periodic_boundary_base.h:48
libMesh::index_range
IntRange< std::size_t > index_range(const std::vector< T > &vec)
Helper function that returns an IntRange<std::size_t> representing all the indices of the passed-in v...
Definition: int_range.h:106
libMesh
The libMesh namespace provides an interface to certain functionality in the library.
Definition: factoryfunction.C:55
libMesh::Elem::dim
virtual unsigned short dim() const =0
libMesh::DenseVector::zero
virtual void zero() override
Set every element in the vector to 0.
Definition: dense_vector.h:379
libMesh::JACOBI_20_00
Definition: enum_fe_family.h:49
libMesh::XYZ
Definition: enum_fe_family.h:46
libMesh::FEGenericBase
This class forms the foundation from which generic finite elements may be derived.
Definition: exact_error_estimator.h:39
libMesh::TOLERANCE
static const Real TOLERANCE
Definition: libmesh_common.h:128
libMesh::DenseMatrix< Real >
libMesh::DofMap::n_variables
unsigned int n_variables() const
Definition: dof_map.h:592
libMesh::MONOMIAL_VEC
Definition: enum_fe_family.h:62
libMesh::Elem::p_level
unsigned int p_level() const
Definition: elem.h:2512
libMesh::Elem::node_index_range
IntRange< unsigned short > node_index_range() const
Definition: elem.h:2170
libMesh::Variable::type
const FEType & type() const
Definition: variable.h:119
mesh
MeshBase & mesh
Definition: mesh_communication.C:1257
libMesh::DofMap::is_constrained_dof
bool is_constrained_dof(const dof_id_type dof) const
Definition: dof_map.h:1962
libMesh::Elem::is_child_on_edge
virtual bool is_child_on_edge(const unsigned int c, const unsigned int e) const
Definition: elem.C:1646
libMesh::Elem::active
bool active() const
Definition: elem.h:2345
libMesh::FEGenericBase::build_InfFE
static std::unique_ptr< FEGenericBase > build_InfFE(const unsigned int dim, const FEType &type)
Builds a specific infinite element type.
dim
unsigned int dim
Definition: adaptivity_ex3.C:113
libMesh::DenseMatrix::resize
void resize(const unsigned int new_m, const unsigned int new_n)
Resize the matrix.
Definition: dense_matrix.h:822
libMesh::VectorValue
This class defines a vector in LIBMESH_DIM dimensional Real or Complex space.
Definition: exact_solution.h:54
libMesh::DofMap::old_dof_indices
void old_dof_indices(const Elem &elem, unsigned int n, std::vector< dof_id_type > &di, const unsigned int vn) const
Appends to the vector di the old global degree of freedom indices for elem.node_ref(n),...
Definition: dof_map.C:2258
libMesh::PeriodicBoundaries::boundary
PeriodicBoundaryBase * boundary(boundary_id_type id)
Definition: periodic_boundaries.C:40
libMesh::CARTESIAN
Definition: enum_inf_map_type.h:35
libMesh::NumericVector< Number >
libMesh::zero
const Number zero
.
Definition: libmesh.h:243
libMesh::SZABAB
Definition: enum_fe_family.h:44
libMesh::DofObject::dof_number
dof_id_type dof_number(const unsigned int s, const unsigned int var, const unsigned int comp) const
Definition: dof_object.h:956
libMesh::libmesh_assert
libmesh_assert(ctx)
libMesh::MeshBase
This is the MeshBase class.
Definition: mesh_base.h:78
std::abs
MetaPhysicL::DualNumber< T, D > abs(const MetaPhysicL::DualNumber< T, D > &in)
libMesh::JACOBI_30_00
Definition: enum_fe_family.h:50
libMesh::FEMap::inverse_map
static Point inverse_map(const unsigned int dim, const Elem *elem, const Point &p, const Real tolerance=TOLERANCE, const bool secure=true)
Definition: fe_map.C:1622
libMesh::DofMap::sys_number
unsigned int sys_number() const
Definition: dof_map.h:1876
libMesh::DofObject::n_comp
unsigned int n_comp(const unsigned int s, const unsigned int var) const
Definition: dof_object.h:926
libMesh::DofMap::variable
const Variable & variable(const unsigned int c) const
Definition: dof_map.h:1894
libMesh::Threads::spin_mtx
spin_mutex spin_mtx
A convenient spin mutex object which can be used for obtaining locks.
Definition: threads.C:29
libMesh::FEGenericBase::build
static std::unique_ptr< FEGenericBase > build(const unsigned int dim, const FEType &type)
Builds a specific finite element type.
libMesh::DofObject::invalid_id
static const dof_id_type invalid_id
An invalid id to distinguish an uninitialized DofObject.
Definition: dof_object.h:421
libMesh::BoundaryInfo::side_with_boundary_id
unsigned int side_with_boundary_id(const Elem *const elem, const boundary_id_type boundary_id) const
Definition: boundary_info.C:1527
libMesh::Point
A Point defines a location in LIBMESH_DIM dimensional Real space.
Definition: point.h:38
libMesh::FEInterface::dofs_on_edge
static void dofs_on_edge(const Elem *const elem, const unsigned int dim, const FEType &fe_t, unsigned int e, std::vector< unsigned int > &di)
Fills the vector di with the local degree of freedom indices associated with edge e of element elem A...
Definition: fe_interface.C:566
libMesh::Variable
This class defines the notion of a variable in the system.
Definition: variable.h:49
libMesh::DISCONTINUOUS
Definition: enum_fe_family.h:78
libMesh::C_ZERO
Definition: enum_fe_family.h:79
libMesh::Node
A Node is like a Point, but with more information.
Definition: node.h:52
libMesh::LEGENDRE
Definition: enum_fe_family.h:51
libMesh::TensorTools::inner_product
boostcopy::enable_if_c< ScalarTraits< T >::value &&ScalarTraits< T2 >::value, typename CompareTypes< T, T2 >::supertype >::type inner_product(const T &a, const T2 &b)
Definition: tensor_tools.h:62
libMesh::DofMap::constrain_p_dofs
void constrain_p_dofs(unsigned int var, const Elem *elem, unsigned int s, unsigned int p)
Constrains degrees of freedom on side s of element elem which correspond to variable number var and t...
Definition: dof_map_constraints.C:4325
libMesh::FEInterface::n_dofs
static unsigned int n_dofs(const unsigned int dim, const FEType &fe_t, const ElemType t)
Definition: fe_interface.C:472
libMesh::DofMap::variable_type
const FEType & variable_type(const unsigned int c) const
Definition: dof_map.h:1924
libMesh::FEType::default_quadrature_rule
std::unique_ptr< QBase > default_quadrature_rule(const unsigned int dim, const int extraorder=0) const
Definition: fe_type.C:31
libMesh::RATIONAL_BERNSTEIN
Definition: enum_fe_family.h:64
libMesh::BERNSTEIN
Definition: enum_fe_family.h:43
libMesh::PeriodicBoundaryBase::is_my_variable
bool is_my_variable(unsigned int var_num) const
Definition: periodic_boundary_base.C:68
n_nodes
const dof_id_type n_nodes
Definition: tecplot_io.C:68
libMesh::Elem::is_child_on_side
virtual bool is_child_on_side(const unsigned int c, const unsigned int s) const =0
libMesh::FEGenericBase::print_dphi
void print_dphi(std::ostream &os) const
Prints the value of each shape function's derivative at each quadrature point.
Definition: fe_base.C:746
libMesh::Elem::is_node_on_edge
virtual bool is_node_on_edge(const unsigned int n, const unsigned int e) const =0
libMesh::FEGenericBase::coarsened_dof_values
static void coarsened_dof_values(const NumericVector< Number > &global_vector, const DofMap &dof_map, const Elem *coarse_elem, DenseVector< Number > &coarse_dofs, const unsigned int var, const bool use_old_dof_indices=false)
Creates a local projection on coarse_elem, based on the DoF values in global_vector for it's children...
Definition: fe_base.C:822
libMesh::FEGenericBase< FEOutputType< T >::type >::OutputNumber
TensorTools::MakeNumber< OutputShape >::type OutputNumber
Definition: fe_base.h:122
libMesh::is
PetscErrorCode PetscInt const PetscInt IS * is
Definition: petsc_dm_wrapper.C:60
libMesh::DenseMatrix::zero
virtual void zero() override
Set every element in the matrix to 0.
Definition: dense_matrix.h:838
libMesh::HIERARCHIC
Definition: enum_fe_family.h:37
libMesh::MONOMIAL
Definition: enum_fe_family.h:39
libMesh::PeriodicBoundaryBase::get_transformation_matrix
const DenseMatrix< Real > & get_transformation_matrix() const
Get the transformation matrix, if it is defined.
Definition: periodic_boundary_base.C:83
libMesh::FEInterface::dofs_on_side
static void dofs_on_side(const Elem *const elem, const unsigned int dim, const FEType &fe_t, unsigned int s, std::vector< unsigned int > &di)
Fills the vector di with the local degree of freedom indices associated with side s of element elem A...
Definition: fe_interface.C:553
libMesh::DenseMatrix::cholesky_solve
void cholesky_solve(const DenseVector< T2 > &b, DenseVector< T2 > &x)
For symmetric positive definite (SPD) matrices.
Definition: dense_matrix_impl.h:947
libMesh::Elem::max_descendant_p_level
unsigned int max_descendant_p_level() const
Definition: elem.h:2650
libMesh::DenseVector::resize
void resize(const unsigned int n)
Resize the vector.
Definition: dense_vector.h:355
libMesh::FEGenericBase::compute_shape_functions
virtual void compute_shape_functions(const Elem *elem, const std::vector< Point > &qp)
After having updated the jacobian and the transformation from local to global coordinates in FEAbstra...
Definition: fe_base.C:697
swap
void swap(Iterator &lhs, Iterator &rhs)
swap, used to implement op=
Definition: variant_filter_iterator.h:478
libMesh::Elem::is_edge
virtual bool is_edge(const unsigned int i) const =0
libMesh::FEType
class FEType hides (possibly multiple) FEFamily and approximation orders, thereby enabling specialize...
Definition: fe_type.h:178
libMesh::FEType::order
OrderWrapper order
The approximation order of the element.
Definition: fe_type.h:197
libMesh::Elem::n_children
virtual unsigned int n_children() const =0
libMesh::PeriodicBoundaries::neighbor
const Elem * neighbor(boundary_id_type boundary_id, const PointLocatorBase &point_locator, const Elem *e, unsigned int side) const
Definition: periodic_boundaries.C:61
libMesh::DofMap
This class handles the numbering of degrees of freedom on a mesh.
Definition: dof_map.h:176
libMesh::Elem::hmin
virtual Real hmin() const
Definition: elem.C:359
libMesh::FEInterface::field_type
static FEFieldType field_type(const FEType &fe_type)
Definition: fe_interface.C:1683
libMesh::NEDELEC_ONE
Definition: enum_fe_family.h:61
libMesh::Elem::subdomain_id
subdomain_id_type subdomain_id() const
Definition: elem.h:2069
libMesh::DofObject::id
dof_id_type id() const
Definition: dof_object.h:767
libMesh::FEGenericBase::compute_proj_constraints
static void compute_proj_constraints(DofConstraints &constraints, DofMap &dof_map, const unsigned int variable_number, const Elem *elem)
Computes the constraint matrix contributions (for non-conforming adapted meshes) corresponding to var...
Definition: fe_base.C:1396
libMesh::TYPE_VECTOR
Definition: enum_fe_family.h:94
libMesh::FEGenericBase::print_phi
void print_phi(std::ostream &os) const
Prints the value of each shape function at each quadrature point.
Definition: fe_base.C:735
libMesh::Elem::side_index_range
IntRange< unsigned short > side_index_range() const
Definition: elem.h:2188
libMesh::Elem::is_vertex
virtual bool is_vertex(const unsigned int i) const =0
libMesh::Elem::min_p_level_by_neighbor
unsigned int min_p_level_by_neighbor(const Elem *neighbor, unsigned int current_min) const
Definition: elem.C:1663
libMesh::Elem
This is the base class from which all geometric element types are derived.
Definition: elem.h:100
libMesh::Elem::is_face
virtual bool is_face(const unsigned int i) const =0
libMesh::PeriodicBoundaryBase::get_variables
const std::set< unsigned int > & get_variables() const
Get the set of variables for this periodic boundary condition.
Definition: periodic_boundary_base.C:108
libMesh::L2_LAGRANGE
Definition: enum_fe_family.h:41
libMesh::FEGenericBase::determine_calculations
void determine_calculations()
Determine which values are to be calculated, for both the FE itself and for the FEMap.
Definition: fe_base.C:756
libMesh::LAGRANGE_VEC
Definition: enum_fe_family.h:60
libMesh::LAGRANGE
Definition: enum_fe_family.h:36
libMesh::SCALAR
Definition: enum_fe_family.h:58
libMesh::SUBDIVISION
Definition: enum_fe_family.h:55
libMesh::Elem::neighbor_ptr
const Elem * neighbor_ptr(unsigned int i) const
Definition: elem.h:2085
libMesh::Elem::node_ref
const Node & node_ref(const unsigned int i) const
Definition: elem.h:2031
libMesh::Real
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
Definition: libmesh_common.h:121
libMesh::PeriodicBoundaryBase::pairedboundary
boundary_id_type pairedboundary
Definition: periodic_boundary_base.h:58
libMesh::Variable::active_on_subdomain
bool active_on_subdomain(subdomain_id_type sid) const
Definition: variable.h:136
libMesh::FEType::default_quadrature_order
Order default_quadrature_order() const
Definition: fe_type.h:353
libMesh::FEContinuity
FEContinuity
Definition: enum_fe_family.h:77
libMesh::Elem::n_sides
virtual unsigned int n_sides() const =0
libMesh::Elem::node_ptr
const Node * node_ptr(const unsigned int i) const
Definition: elem.h:2009
libMesh::PointLocatorBase
This is the base class for point locators.
Definition: point_locator_base.h:62
libMesh::DofConstraintRow
std::map< dof_id_type, Real, std::less< dof_id_type >, Threads::scalable_allocator< std::pair< const dof_id_type, Real > > > DofConstraintRow
A row of the Dof constraint matrix.
Definition: dof_map.h:97
libMesh::Elem::type
virtual ElemType type() const =0
libMesh::Elem::which_neighbor_am_i
unsigned int which_neighbor_am_i(const Elem *e) const
This function tells you which neighbor e is.
Definition: elem.h:2323
libMesh::TypesEqual
Definition: compare_types.h:51
libMesh::DenseVector< Number >
libMesh::ElemType
ElemType
Defines an enum for geometric element types.
Definition: enum_elem_type.h:33
libMesh::TypeVector::absolute_fuzzy_equals
bool absolute_fuzzy_equals(const TypeVector< T > &rhs, Real tol=TOLERANCE) const
Definition: type_vector.h:1017