1 // The libMesh Finite Element Library.
2 // Copyright (C) 2002-2020 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 // Local includes
19 #include "libmesh/dof_map.h"
20 #include "libmesh/fe.h"
21 #include "libmesh/fe_interface.h"
22 #include "libmesh/elem.h"
23 #include "libmesh/tensor_value.h"
24 
25 
26 namespace libMesh
27 {
28 
29 
30 LIBMESH_DEFAULT_VECTORIZED_FE(0,MONOMIAL_VEC)
31 LIBMESH_DEFAULT_VECTORIZED_FE(1,MONOMIAL_VEC)
32 LIBMESH_DEFAULT_VECTORIZED_FE(2,MONOMIAL_VEC)
33 LIBMESH_DEFAULT_VECTORIZED_FE(3,MONOMIAL_VEC)
34 
35 
36 // ------------------------------------------------------------
37 // Vector monomial specific implementations
38 
39 // Anonymous namespace for local helper functions
40 namespace
41 {
42 void
monomial_vec_nodal_soln(const Elem * elem,const Order order,const std::vector<Number> & elem_soln,const int dim,std::vector<Number> & nodal_soln)43 monomial_vec_nodal_soln(const Elem * elem,
44                         const Order order,
45                         const std::vector<Number> & elem_soln,
46                         const int dim,
47                         std::vector<Number> & nodal_soln)
48 {
49   const unsigned int n_nodes = elem->n_nodes();
50 
51   const ElemType elem_type = elem->type();
52 
53   nodal_soln.resize(dim * n_nodes);
54 
55   const Order totalorder = static_cast<Order>(order + elem->p_level());
56 
57   switch (totalorder)
58   {
59       // Constant shape functions
60     case CONSTANT:
61     {
62       switch (dim)
63       {
64         case 2:
65         {
66           libmesh_assert_equal_to(elem_soln.size(), 2);
67           for (unsigned int n = 0; n < n_nodes; n++)
68           {
69             nodal_soln[2 * n] = elem_soln[0];
70             nodal_soln[1 + 2 * n] = elem_soln[1];
71           }
72           return;
73         }
74         case 3:
75         {
76           libmesh_assert_equal_to(elem_soln.size(), 3);
77           for (unsigned int n = 0; n < n_nodes; n++)
78           {
79             nodal_soln[3 * n] = elem_soln[0];
80             nodal_soln[1 + 3 * n] = elem_soln[1];
81             nodal_soln[2 + 3 * n] = elem_soln[2];
82           }
83           return;
84         }
85         default:
86           libmesh_error_msg(
87               "The monomial_vec_nodal_soln helper should only be called for 2 and 3 dimensions");
88       }
89     }
90 
91     // For other orders, do interpolation at the nodes
92     // explicitly.
93     default:
94     {
95       // FEType object to be passed to various FEInterface functions below.
96       FEType fe_type(order, MONOMIAL);
97 
98       const unsigned int n_sf = FEInterface::n_shape_functions(fe_type, elem);
99 
100       std::vector<Point> refspace_nodes;
101       FEBase::get_refspace_nodes(elem_type, refspace_nodes);
102       libmesh_assert_equal_to(refspace_nodes.size(), n_nodes);
103       libmesh_assert_equal_to(elem_soln.size(), n_sf * dim);
104 
105       for (unsigned int d = 0; d < static_cast<unsigned int>(dim); d++)
106         for (unsigned int n = 0; n < n_nodes; n++)
107         {
108 
109           // Zero before summation
110           nodal_soln[d + dim * n] = 0;
111 
112           // u_i = Sum (alpha_i phi_i)
113           for (unsigned int i = 0; i < n_sf; i++)
114             nodal_soln[d + dim * n] += elem_soln[d + dim * i] *
115                                        FEInterface::shape(fe_type, elem, i, refspace_nodes[n]);
116         }
117 
118       return;
119     } // default
120   }   // switch
121 }
122 } // anonymous namespace
123 
124 // Do full-specialization for every dimension, instead
125 // of explicit instantiation at the end of this file.
126 // This could be macro-ified so that it fits on one line...
127 template <>
128 void
nodal_soln(const Elem * elem,const Order order,const std::vector<Number> & elem_soln,std::vector<Number> & nodal_soln)129 FE<0, MONOMIAL_VEC>::nodal_soln(const Elem * elem,
130                                 const Order order,
131                                 const std::vector<Number> & elem_soln,
132                                 std::vector<Number> & nodal_soln)
133 {
134   FE<0, MONOMIAL>::nodal_soln(elem, order, elem_soln, nodal_soln);
135 }
136 
137 template <>
138 void
nodal_soln(const Elem * elem,const Order order,const std::vector<Number> & elem_soln,std::vector<Number> & nodal_soln)139 FE<1, MONOMIAL_VEC>::nodal_soln(const Elem * elem,
140                                 const Order order,
141                                 const std::vector<Number> & elem_soln,
142                                 std::vector<Number> & nodal_soln)
143 {
144   FE<1, MONOMIAL>::nodal_soln(elem, order, elem_soln, nodal_soln);
145 }
146 
147 template <>
148 void
nodal_soln(const Elem * elem,const Order order,const std::vector<Number> & elem_soln,std::vector<Number> & nodal_soln)149 FE<2, MONOMIAL_VEC>::nodal_soln(const Elem * elem,
150                                 const Order order,
151                                 const std::vector<Number> & elem_soln,
152                                 std::vector<Number> & nodal_soln)
153 {
154   monomial_vec_nodal_soln(elem, order, elem_soln, 2 /*dimension*/, nodal_soln);
155 }
156 
157 template <>
158 void
nodal_soln(const Elem * elem,const Order order,const std::vector<Number> & elem_soln,std::vector<Number> & nodal_soln)159 FE<3, MONOMIAL_VEC>::nodal_soln(const Elem * elem,
160                                 const Order order,
161                                 const std::vector<Number> & elem_soln,
162                                 std::vector<Number> & nodal_soln)
163 {
164   monomial_vec_nodal_soln(elem, order, elem_soln, 3 /*dimension*/, nodal_soln);
165 }
166 
167 // Specialize for shape function routines by leveraging scalar MONOMIAL elements
168 
169 // 0-D
170 template <>
171 RealVectorValue
shape(const ElemType type,const Order order,const unsigned int i,const Point & p)172 FE<0, MONOMIAL_VEC>::shape(const ElemType type,
173                            const Order order,
174                            const unsigned int i,
175                            const Point & p)
176 {
177   Real value = FE<0, MONOMIAL>::shape(type, order, i, p);
178   return libMesh::RealVectorValue(value);
179 }
180 template <>
181 RealVectorValue
shape_deriv(const ElemType type,const Order order,const unsigned int i,const unsigned int j,const Point & p)182 FE<0, MONOMIAL_VEC>::shape_deriv(const ElemType type,
183                                  const Order order,
184                                  const unsigned int i,
185                                  const unsigned int j,
186                                  const Point & p)
187 {
188   Real value = FE<0, MONOMIAL>::shape_deriv(type, order, i, j, p);
189   return libMesh::RealVectorValue(value);
190 }
191 
192 #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
193 
194 template <>
195 RealVectorValue
shape_second_deriv(const ElemType type,const Order order,const unsigned int i,const unsigned int j,const Point & p)196 FE<0, MONOMIAL_VEC>::shape_second_deriv(const ElemType type,
197                                         const Order order,
198                                         const unsigned int i,
199                                         const unsigned int j,
200                                         const Point & p)
201 {
202   Real value = FE<0, MONOMIAL>::shape_second_deriv(type, order, i, j, p);
203   return libMesh::RealVectorValue(value);
204 }
205 #endif
206 
207 // 1-D
208 template <>
209 RealVectorValue
shape(const ElemType type,const Order order,const unsigned int i,const Point & p)210 FE<1, MONOMIAL_VEC>::shape(const ElemType type,
211                            const Order order,
212                            const unsigned int i,
213                            const Point & p)
214 {
215   Real value = FE<1, MONOMIAL>::shape(type, order, i, p);
216   return libMesh::RealVectorValue(value);
217 }
218 template <>
219 RealVectorValue
shape_deriv(const ElemType type,const Order order,const unsigned int i,const unsigned int j,const Point & p)220 FE<1, MONOMIAL_VEC>::shape_deriv(const ElemType type,
221                                  const Order order,
222                                  const unsigned int i,
223                                  const unsigned int j,
224                                  const Point & p)
225 {
226   Real value = FE<1, MONOMIAL>::shape_deriv(type, order, i, j, p);
227   return libMesh::RealVectorValue(value);
228 }
229 #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
230 template <>
231 RealVectorValue
shape_second_deriv(const ElemType type,const Order order,const unsigned int i,const unsigned int j,const Point & p)232 FE<1, MONOMIAL_VEC>::shape_second_deriv(const ElemType type,
233                                         const Order order,
234                                         const unsigned int i,
235                                         const unsigned int j,
236                                         const Point & p)
237 {
238   Real value = FE<1, MONOMIAL>::shape_second_deriv(type, order, i, j, p);
239   return libMesh::RealVectorValue(value);
240 }
241 
242 #endif
243 
244 // 2-D
245 template <>
246 RealVectorValue
shape(const ElemType type,const Order order,const unsigned int i,const Point & p)247 FE<2, MONOMIAL_VEC>::shape(const ElemType type,
248                            const Order order,
249                            const unsigned int i,
250                            const Point & p)
251 {
252   Real value = FE<2, MONOMIAL>::shape(type, order, i / 2, p);
253 
254   switch (i % 2)
255   {
256     case 0:
257       return libMesh::RealVectorValue(value);
258 
259     case 1:
260       return libMesh::RealVectorValue(Real(0), value);
261 
262     default:
263       libmesh_error_msg("i%2 must be either 0 or 1!");
264   }
265 
266   // dummy
267   return libMesh::RealVectorValue();
268 }
269 template <>
270 RealVectorValue
shape_deriv(const ElemType type,const Order order,const unsigned int i,const unsigned int j,const Point & p)271 FE<2, MONOMIAL_VEC>::shape_deriv(const ElemType type,
272                                  const Order order,
273                                  const unsigned int i,
274                                  const unsigned int j,
275                                  const Point & p)
276 {
277   Real value = FE<2, MONOMIAL>::shape_deriv(type, order, i / 2, j, p);
278 
279   switch (i % 2)
280   {
281     case 0:
282       return libMesh::RealVectorValue(value);
283 
284     case 1:
285       return libMesh::RealVectorValue(Real(0), value);
286 
287     default:
288       libmesh_error_msg("i%2 must be either 0 or 1!");
289   }
290 
291   // dummy
292   return libMesh::RealVectorValue();
293 }
294 
295 #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
296 template <>
297 RealVectorValue
shape_second_deriv(const ElemType type,const Order order,const unsigned int i,const unsigned int j,const Point & p)298 FE<2, MONOMIAL_VEC>::shape_second_deriv(const ElemType type,
299                                         const Order order,
300                                         const unsigned int i,
301                                         const unsigned int j,
302                                         const Point & p)
303 {
304   Real value = FE<2, MONOMIAL>::shape_second_deriv(type, order, i / 2, j, p);
305 
306   switch (i % 2)
307   {
308     case 0:
309       return libMesh::RealVectorValue(value);
310 
311     case 1:
312       return libMesh::RealVectorValue(Real(0), value);
313 
314     default:
315       libmesh_error_msg("i%2 must be either 0 or 1!");
316   }
317 
318   // dummy
319   return libMesh::RealVectorValue();
320 }
321 
322 #endif
323 
324 // 3-D
325 template <>
326 RealVectorValue
shape(const ElemType type,const Order order,const unsigned int i,const Point & p)327 FE<3, MONOMIAL_VEC>::shape(const ElemType type,
328                            const Order order,
329                            const unsigned int i,
330                            const Point & p)
331 {
332   Real value = FE<3, MONOMIAL>::shape(type, order, i / 3, p);
333 
334   switch (i % 3)
335   {
336     case 0:
337       return libMesh::RealVectorValue(value);
338 
339     case 1:
340       return libMesh::RealVectorValue(Real(0), value);
341 
342     case 2:
343       return libMesh::RealVectorValue(Real(0), Real(0), value);
344 
345     default:
346       libmesh_error_msg("i%3 must be 0, 1, or 2!");
347   }
348 
349   // dummy
350   return libMesh::RealVectorValue();
351 }
352 template <>
353 RealVectorValue
shape_deriv(const ElemType type,const Order order,const unsigned int i,const unsigned int j,const Point & p)354 FE<3, MONOMIAL_VEC>::shape_deriv(const ElemType type,
355                                  const Order order,
356                                  const unsigned int i,
357                                  const unsigned int j,
358                                  const Point & p)
359 {
360   Real value = FE<3, MONOMIAL>::shape_deriv(type, order, i / 3, j, p);
361 
362   switch (i % 3)
363   {
364     case 0:
365       return libMesh::RealVectorValue(value);
366 
367     case 1:
368       return libMesh::RealVectorValue(Real(0), value);
369 
370     case 2:
371       return libMesh::RealVectorValue(Real(0), Real(0), value);
372 
373     default:
374       libmesh_error_msg("i%3 must be 0, 1, or 2!");
375   }
376 
377   // dummy
378   return libMesh::RealVectorValue();
379 }
380 
381 #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
382 
383 template <>
384 RealVectorValue
shape_second_deriv(const ElemType type,const Order order,const unsigned int i,const unsigned int j,const Point & p)385 FE<3, MONOMIAL_VEC>::shape_second_deriv(const ElemType type,
386                                         const Order order,
387                                         const unsigned int i,
388                                         const unsigned int j,
389                                         const Point & p)
390 {
391   Real value = FE<3, MONOMIAL>::shape_second_deriv(type, order, i / 3, j, p);
392 
393   switch (i % 3)
394   {
395     case 0:
396       return libMesh::RealVectorValue(value);
397 
398     case 1:
399       return libMesh::RealVectorValue(Real(0), value);
400 
401     case 2:
402       return libMesh::RealVectorValue(Real(0), Real(0), value);
403 
404     default:
405       libmesh_error_msg("i%3 must be 0, 1, or 2!");
406   }
407 
408   // dummy
409   return libMesh::RealVectorValue();
410 }
411 
412 #endif
413 
414 // 0-D
415 template <>
416 RealVectorValue
shape(const Elem * elem,const Order order,const unsigned int i,const Point & p,const bool add_p_level)417 FE<0, MONOMIAL_VEC>::shape(const Elem * elem,
418                            const Order order,
419                            const unsigned int i,
420                            const Point & p,
421                            const bool add_p_level)
422 {
423   Real value =
424       FE<0, MONOMIAL>::shape(elem->type(), static_cast<Order>(order + add_p_level * elem->p_level()), i, p);
425   return libMesh::RealVectorValue(value);
426 }
427 template <>
428 RealVectorValue
shape_deriv(const Elem * elem,const Order order,const unsigned int i,const unsigned int j,const Point & p,const bool add_p_level)429 FE<0, MONOMIAL_VEC>::shape_deriv(const Elem * elem,
430                                  const Order order,
431                                  const unsigned int i,
432                                  const unsigned int j,
433                                  const Point & p,
434                                  const bool add_p_level)
435 {
436   Real value = FE<0, MONOMIAL>::shape_deriv(
437       elem->type(), static_cast<Order>(order + add_p_level * elem->p_level()), i, j, p);
438   return libMesh::RealVectorValue(value);
439 }
440 
441 #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
442 
443 template <>
444 RealVectorValue
shape_second_deriv(const Elem * elem,const Order order,const unsigned int i,const unsigned int j,const Point & p,const bool add_p_level)445 FE<0, MONOMIAL_VEC>::shape_second_deriv(const Elem * elem,
446                                         const Order order,
447                                         const unsigned int i,
448                                         const unsigned int j,
449                                         const Point & p,
450                                         const bool add_p_level)
451 {
452   Real value = FE<0, MONOMIAL>::shape_second_deriv(
453       elem->type(), static_cast<Order>(order + add_p_level * elem->p_level()), i, j, p);
454   return libMesh::RealVectorValue(value);
455 }
456 
457 #endif
458 
459 // 1-D
460 template <>
461 RealVectorValue
shape(const Elem * elem,const Order order,const unsigned int i,const Point & p,const bool add_p_level)462 FE<1, MONOMIAL_VEC>::shape(const Elem * elem,
463                            const Order order,
464                            const unsigned int i,
465                            const Point & p,
466                            const bool add_p_level)
467 {
468   Real value =
469       FE<1, MONOMIAL>::shape(elem->type(), static_cast<Order>(order + add_p_level * elem->p_level()), i, p);
470   return libMesh::RealVectorValue(value);
471 }
472 template <>
473 RealVectorValue
shape_deriv(const Elem * elem,const Order order,const unsigned int i,const unsigned int j,const Point & p,const bool add_p_level)474 FE<1, MONOMIAL_VEC>::shape_deriv(const Elem * elem,
475                                  const Order order,
476                                  const unsigned int i,
477                                  const unsigned int j,
478                                  const Point & p,
479                                  const bool add_p_level)
480 {
481   Real value = FE<1, MONOMIAL>::shape_deriv(
482       elem->type(), static_cast<Order>(order + add_p_level * elem->p_level()), i, j, p);
483   return libMesh::RealVectorValue(value);
484 }
485 
486 #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
487 template <>
488 RealVectorValue
shape_second_deriv(const Elem * elem,const Order order,const unsigned int i,const unsigned int j,const Point & p,const bool add_p_level)489 FE<1, MONOMIAL_VEC>::shape_second_deriv(const Elem * elem,
490                                         const Order order,
491                                         const unsigned int i,
492                                         const unsigned int j,
493                                         const Point & p,
494                                         const bool add_p_level)
495 {
496   Real value = FE<1, MONOMIAL>::shape_second_deriv(
497       elem->type(), static_cast<Order>(order + add_p_level * elem->p_level()), i, j, p);
498   return libMesh::RealVectorValue(value);
499 }
500 
501 #endif
502 
503 // 2-D
504 template <>
505 RealVectorValue
shape(const Elem * elem,const Order order,const unsigned int i,const Point & p,const bool add_p_level)506 FE<2, MONOMIAL_VEC>::shape(const Elem * elem,
507                            const Order order,
508                            const unsigned int i,
509                            const Point & p,
510                            const bool add_p_level)
511 {
512   Real value =
513       FE<2, MONOMIAL>::shape(elem->type(), static_cast<Order>(order + add_p_level * elem->p_level()), i / 2, p);
514 
515   switch (i % 2)
516   {
517     case 0:
518       return libMesh::RealVectorValue(value);
519 
520     case 1:
521       return libMesh::RealVectorValue(Real(0), value);
522 
523     default:
524       libmesh_error_msg("i%2 must be either 0 or 1!");
525   }
526 
527   // dummy
528   return libMesh::RealVectorValue();
529 }
530 template <>
531 RealVectorValue
shape_deriv(const Elem * elem,const Order order,const unsigned int i,const unsigned int j,const Point & p,const bool add_p_level)532 FE<2, MONOMIAL_VEC>::shape_deriv(const Elem * elem,
533                                  const Order order,
534                                  const unsigned int i,
535                                  const unsigned int j,
536                                  const Point & p,
537                                  const bool add_p_level)
538 {
539   Real value = FE<2, MONOMIAL>::shape_deriv(
540       elem->type(), static_cast<Order>(order + add_p_level * elem->p_level()), i / 2, j, p);
541 
542   switch (i % 2)
543   {
544     case 0:
545       return libMesh::RealVectorValue(value);
546 
547     case 1:
548       return libMesh::RealVectorValue(Real(0), value);
549 
550     default:
551       libmesh_error_msg("i%2 must be either 0 or 1!");
552   }
553 
554   // dummy
555   return libMesh::RealVectorValue();
556 }
557 
558 #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
559 template <>
560 RealVectorValue
shape_second_deriv(const Elem * elem,const Order order,const unsigned int i,const unsigned int j,const Point & p,const bool add_p_level)561 FE<2, MONOMIAL_VEC>::shape_second_deriv(const Elem * elem,
562                                         const Order order,
563                                         const unsigned int i,
564                                         const unsigned int j,
565                                         const Point & p,
566                                         const bool add_p_level)
567 {
568   Real value = FE<2, MONOMIAL>::shape_second_deriv(
569       elem->type(), static_cast<Order>(order + add_p_level * elem->p_level()), i / 2, j, p);
570 
571   switch (i % 2)
572   {
573     case 0:
574       return libMesh::RealVectorValue(value);
575 
576     case 1:
577       return libMesh::RealVectorValue(Real(0), value);
578 
579     default:
580       libmesh_error_msg("i%2 must be either 0 or 1!");
581   }
582 
583   // dummy
584   return libMesh::RealVectorValue();
585 }
586 
587 #endif
588 
589 // 3-D
590 template <>
591 RealVectorValue
shape(const Elem * elem,const Order order,const unsigned int i,const Point & p,const bool add_p_level)592 FE<3, MONOMIAL_VEC>::shape(const Elem * elem,
593                            const Order order,
594                            const unsigned int i,
595                            const Point & p,
596                            const bool add_p_level)
597 {
598   Real value =
599       FE<3, MONOMIAL>::shape(elem->type(), static_cast<Order>(order + add_p_level * elem->p_level()), i / 3, p);
600 
601   switch (i % 3)
602   {
603     case 0:
604       return libMesh::RealVectorValue(value);
605 
606     case 1:
607       return libMesh::RealVectorValue(Real(0), value);
608 
609     case 2:
610       return libMesh::RealVectorValue(Real(0), Real(0), value);
611 
612     default:
613       libmesh_error_msg("i%3 must be 0, 1, or 2!");
614   }
615 
616   // dummy
617   return libMesh::RealVectorValue();
618 }
619 template <>
620 RealVectorValue
shape_deriv(const Elem * elem,const Order order,const unsigned int i,const unsigned int j,const Point & p,const bool add_p_level)621 FE<3, MONOMIAL_VEC>::shape_deriv(const Elem * elem,
622                                  const Order order,
623                                  const unsigned int i,
624                                  const unsigned int j,
625                                  const Point & p,
626                                  const bool add_p_level)
627 {
628   Real value = FE<3, MONOMIAL>::shape_deriv(
629       elem->type(), static_cast<Order>(order + add_p_level * elem->p_level()), i / 3, j, p);
630 
631   switch (i % 3)
632   {
633     case 0:
634       return libMesh::RealVectorValue(value);
635 
636     case 1:
637       return libMesh::RealVectorValue(Real(0), value);
638 
639     case 2:
640       return libMesh::RealVectorValue(Real(0), Real(0), value);
641 
642     default:
643       libmesh_error_msg("i%3 must be 0, 1, or 2!");
644   }
645 
646   // dummy
647   return libMesh::RealVectorValue();
648 }
649 
650 #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
651 
652 template <>
653 RealVectorValue
shape_second_deriv(const Elem * elem,const Order order,const unsigned int i,const unsigned int j,const Point & p,const bool add_p_level)654 FE<3, MONOMIAL_VEC>::shape_second_deriv(const Elem * elem,
655                                         const Order order,
656                                         const unsigned int i,
657                                         const unsigned int j,
658                                         const Point & p,
659                                         const bool add_p_level)
660 {
661   Real value = FE<3, MONOMIAL>::shape_second_deriv(
662       elem->type(), static_cast<Order>(order + add_p_level * elem->p_level()), i / 3, j, p);
663 
664   switch (i % 3)
665   {
666     case 0:
667       return libMesh::RealVectorValue(value);
668 
669     case 1:
670       return libMesh::RealVectorValue(Real(0), value);
671 
672     case 2:
673       return libMesh::RealVectorValue(Real(0), Real(0), value);
674 
675     default:
676       libmesh_error_msg("i%3 must be 0, 1, or 2!");
677   }
678 
679   // dummy
680   return libMesh::RealVectorValue();
681 }
682 
683 #endif
684 
685 // Do full-specialization for every dimension, instead
686 // of explicit instantiation at the end of this function.
687 // This could be macro-ified.
688 template <>
689 unsigned int
n_dofs(const ElemType t,const Order o)690 FE<0, MONOMIAL_VEC>::n_dofs(const ElemType t, const Order o)
691 {
692   return FE<0, MONOMIAL>::n_dofs(t, o);
693 }
694 template <>
695 unsigned int
n_dofs(const ElemType t,const Order o)696 FE<1, MONOMIAL_VEC>::n_dofs(const ElemType t, const Order o)
697 {
698   return FE<1, MONOMIAL>::n_dofs(t, o);
699 }
700 template <>
701 unsigned int
n_dofs(const ElemType t,const Order o)702 FE<2, MONOMIAL_VEC>::n_dofs(const ElemType t, const Order o)
703 {
704   return 2 * FE<2, MONOMIAL>::n_dofs(t, o);
705 }
706 template <>
707 unsigned int
n_dofs(const ElemType t,const Order o)708 FE<3, MONOMIAL_VEC>::n_dofs(const ElemType t, const Order o)
709 {
710   return 3 * FE<3, MONOMIAL>::n_dofs(t, o);
711 }
712 
713 template <>
714 unsigned int
n_dofs_at_node(const ElemType,const Order,const unsigned int)715 FE<0, MONOMIAL_VEC>::n_dofs_at_node(const ElemType, const Order, const unsigned int)
716 {
717   return 0;
718 }
719 template <>
720 unsigned int
n_dofs_at_node(const ElemType,const Order,const unsigned int)721 FE<1, MONOMIAL_VEC>::n_dofs_at_node(const ElemType, const Order, const unsigned int)
722 {
723   return 0;
724 }
725 template <>
726 unsigned int
n_dofs_at_node(const ElemType,const Order,const unsigned int)727 FE<2, MONOMIAL_VEC>::n_dofs_at_node(const ElemType, const Order, const unsigned int)
728 {
729   return 0;
730 }
731 template <>
732 unsigned int
n_dofs_at_node(const ElemType,const Order,const unsigned int)733 FE<3, MONOMIAL_VEC>::n_dofs_at_node(const ElemType, const Order, const unsigned int)
734 {
735   return 0;
736 }
737 
738 template <>
739 unsigned int
n_dofs_per_elem(const ElemType t,const Order o)740 FE<0, MONOMIAL_VEC>::n_dofs_per_elem(const ElemType t, const Order o)
741 {
742   return FE<0, MONOMIAL>::n_dofs_per_elem(t, o);
743 }
744 template <>
745 unsigned int
n_dofs_per_elem(const ElemType t,const Order o)746 FE<1, MONOMIAL_VEC>::n_dofs_per_elem(const ElemType t, const Order o)
747 {
748   return FE<1, MONOMIAL>::n_dofs_per_elem(t, o);
749 }
750 template <>
751 unsigned int
n_dofs_per_elem(const ElemType t,const Order o)752 FE<2, MONOMIAL_VEC>::n_dofs_per_elem(const ElemType t, const Order o)
753 {
754   return 2 * FE<2, MONOMIAL>::n_dofs_per_elem(t, o);
755 }
756 template <>
757 unsigned int
n_dofs_per_elem(const ElemType t,const Order o)758 FE<3, MONOMIAL_VEC>::n_dofs_per_elem(const ElemType t, const Order o)
759 {
760   return 3 * FE<3, MONOMIAL>::n_dofs_per_elem(t, o);
761 }
762 
763 // Monomial FEMs are always C^0 continuous
764 template <>
765 FEContinuity
get_continuity()766 FE<0, MONOMIAL_VEC>::get_continuity() const
767 {
768   return DISCONTINUOUS;
769 }
770 template <>
771 FEContinuity
get_continuity()772 FE<1, MONOMIAL_VEC>::get_continuity() const
773 {
774   return DISCONTINUOUS;
775 }
776 template <>
777 FEContinuity
get_continuity()778 FE<2, MONOMIAL_VEC>::get_continuity() const
779 {
780   return DISCONTINUOUS;
781 }
782 template <>
783 FEContinuity
get_continuity()784 FE<3, MONOMIAL_VEC>::get_continuity() const
785 {
786   return DISCONTINUOUS;
787 }
788 
789 // Monomial FEMs are not hierarchic
790 template <>
791 bool
is_hierarchic()792 FE<0, MONOMIAL_VEC>::is_hierarchic() const
793 {
794   return true;
795 }
796 template <>
797 bool
is_hierarchic()798 FE<1, MONOMIAL_VEC>::is_hierarchic() const
799 {
800   return true;
801 }
802 template <>
803 bool
is_hierarchic()804 FE<2, MONOMIAL_VEC>::is_hierarchic() const
805 {
806   return true;
807 }
808 template <>
809 bool
is_hierarchic()810 FE<3, MONOMIAL_VEC>::is_hierarchic() const
811 {
812   return true;
813 }
814 
815 // Monomial FEM shapes do not need reinit (is this always true?)
816 template <>
817 bool
shapes_need_reinit()818 FE<0, MONOMIAL_VEC>::shapes_need_reinit() const
819 {
820   return false;
821 }
822 template <>
823 bool
shapes_need_reinit()824 FE<1, MONOMIAL_VEC>::shapes_need_reinit() const
825 {
826   return false;
827 }
828 template <>
829 bool
shapes_need_reinit()830 FE<2, MONOMIAL_VEC>::shapes_need_reinit() const
831 {
832   return false;
833 }
834 template <>
835 bool
shapes_need_reinit()836 FE<3, MONOMIAL_VEC>::shapes_need_reinit() const
837 {
838   return false;
839 }
840 
841 // we only need instantiations of this function for
842 // Dim==2 and 3. There are no constraints for discontinuous elements, so
843 // we do nothing.
844 #ifdef LIBMESH_ENABLE_AMR
845 template <>
846 void
compute_constraints(DofConstraints &,DofMap &,const unsigned int,const Elem *)847 FE<2, MONOMIAL_VEC>::compute_constraints(DofConstraints &,
848                                          DofMap &,
849                                          const unsigned int,
850                                          const Elem *)
851 {
852 }
853 
854 template <>
855 void
compute_constraints(DofConstraints &,DofMap &,const unsigned int,const Elem *)856 FE<3, MONOMIAL_VEC>::compute_constraints(DofConstraints &,
857                                          DofMap &,
858                                          const unsigned int,
859                                          const Elem *)
860 {
861 }
862 #endif // LIBMESH_ENABLE_AMR
863 
864 } // namespace libMesh
865