Line data Source code
1 : // The libMesh Finite Element Library.
2 : // Copyright (C) 2002-2025 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 : #include "libmesh/fem_context.h"
21 :
22 : #include "libmesh/boundary_info.h"
23 : #include "libmesh/diff_system.h"
24 : #include "libmesh/dof_map.h"
25 : #include "libmesh/elem.h"
26 : #include "libmesh/fe_base.h"
27 : #include "libmesh/fe_interface.h"
28 : #include "libmesh/libmesh_logging.h"
29 : #include "libmesh/mesh_base.h"
30 : #include "libmesh/numeric_vector.h"
31 : #include "libmesh/quadrature.h"
32 : #include "libmesh/system.h"
33 : #include "libmesh/time_solver.h"
34 : #include "libmesh/unsteady_solver.h" // For euler_residual
35 :
36 : namespace libMesh
37 : {
38 :
39 2011429 : FEMContext::FEMContext (const System & sys,
40 : const std::vector<unsigned int> * active_vars,
41 2011429 : bool allocate_local_matrices)
42 2011429 : : FEMContext(sys, sys.extra_quadrature_order, active_vars,
43 2011429 : allocate_local_matrices)
44 : {
45 2011429 : init_internal_data(sys);
46 2011429 : }
47 :
48 2011429 : FEMContext::FEMContext (const System & sys,
49 : int extra_quadrature_order,
50 : const std::vector<unsigned int> * active_vars,
51 2011429 : bool allocate_local_matrices)
52 : : DiffContext(sys, allocate_local_matrices),
53 1845671 : side(0), edge(0),
54 1845671 : _mesh_sys(nullptr),
55 1845671 : _mesh_x_var(0),
56 1845671 : _mesh_y_var(0),
57 1845671 : _mesh_z_var(0),
58 1845671 : _atype(CURRENT),
59 1845671 : _custom_solution(nullptr),
60 2011429 : _boundary_info(sys.get_mesh().get_boundary_info()),
61 1845671 : _elem(nullptr),
62 2011429 : _dim(cast_int<unsigned char>(sys.get_mesh().mesh_dimension())),
63 1845671 : _elem_dim(0), /* This will be reset in set_elem(). */
64 248637 : _elem_dims(sys.get_mesh().elem_dimensions()),
65 1845671 : _element_qrule(4),
66 1845671 : _side_qrule(4),
67 4022858 : _extra_quadrature_order(extra_quadrature_order)
68 : {
69 2011429 : if (active_vars)
70 : {
71 60959 : libmesh_assert(!active_vars->empty());
72 : auto vars_copy =
73 1641991 : std::make_unique<std::vector<unsigned int>>(*active_vars);
74 :
75 : // We want to do quick binary_search later
76 1581032 : std::sort(vars_copy->begin(), vars_copy->end());
77 :
78 1520073 : _active_vars = std::move(vars_copy);
79 1459114 : }
80 :
81 2011429 : init_internal_data(sys);
82 2011429 : }
83 :
84 :
85 :
86 4043675 : FEType FEMContext::find_hardest_fe_type()
87 : {
88 332896 : const System & sys = this->get_system();
89 : FEType hardest_fe_type =
90 3710779 : sys.variable_type(_active_vars ?
91 4043675 : (*_active_vars)[0] : 0);
92 :
93 5014029 : auto check_var = [&hardest_fe_type, &sys](unsigned int v)
94 : {
95 4813897 : FEType fe_type = sys.variable_type(v);
96 :
97 : // Make sure we find a non-SCALAR FE family, even in the case
98 : // where the first variable(s) weren't
99 4813897 : if (hardest_fe_type.family == SCALAR)
100 : {
101 0 : hardest_fe_type.family = fe_type.family;
102 0 : hardest_fe_type.order = fe_type.order;
103 : }
104 :
105 : // FIXME - we don't yet handle mixed finite elements from
106 : // different families which require different quadrature rules
107 : // libmesh_assert_equal_to (fe_type.family, hardest_fe_type.family);
108 :
109 : // We need to detect SCALAR's so we can prepare FE objects for
110 : // them, and so we don't mistake high order scalars as a reason
111 : // to crank up the quadrature order on other types.
112 4813897 : if (fe_type.family != SCALAR && fe_type.order > hardest_fe_type.order)
113 8520 : hardest_fe_type = fe_type;
114 8324664 : };
115 :
116 4043675 : if (_active_vars)
117 6625336 : for (auto v : *_active_vars)
118 3331734 : check_var(v);
119 : else
120 2232236 : for (auto v : make_range(sys.n_vars()))
121 1282151 : check_var(v);
122 :
123 4210123 : return hardest_fe_type;
124 : }
125 :
126 :
127 4043483 : void FEMContext::attach_quadrature_rules()
128 : {
129 332864 : const System & sys = this->get_system();
130 :
131 10573860 : auto attach_rules = [this, &sys](unsigned int v)
132 : {
133 9682744 : for (const auto & dim : _elem_dims)
134 : {
135 4869039 : FEType fe_type = sys.variable_type(v);
136 :
137 5070875 : _element_fe[dim][fe_type]->attach_quadrature_rule(_element_qrule[dim].get());
138 4869039 : if (dim)
139 4978243 : _side_fe[dim][fe_type]->attach_quadrature_rule(_side_qrule[dim].get());
140 4869039 : if (dim == 3)
141 1348840 : _edge_fe[fe_type]->attach_quadrature_rule(_edge_qrule.get());
142 : };
143 4277043 : };
144 :
145 4043483 : if (_active_vars)
146 6625336 : for (auto v : *_active_vars)
147 3463272 : attach_rules(v);
148 : else
149 2231852 : for (auto v : make_range(sys.n_vars()))
150 1350433 : attach_rules(v);
151 4043483 : }
152 :
153 :
154 :
155 4022858 : void FEMContext::use_default_quadrature_rules(int extra_quadrature_order)
156 : {
157 4022858 : _extra_quadrature_order = extra_quadrature_order;
158 :
159 4022858 : FEType hardest_fe_type = this->find_hardest_fe_type();
160 :
161 8070380 : for (const auto & dim : _elem_dims)
162 : {
163 : // Create an adequate quadrature rule
164 4047522 : _element_qrule[dim] =
165 7928414 : hardest_fe_type.default_quadrature_rule(dim, _extra_quadrature_order);
166 4047522 : if (dim)
167 3993644 : _side_qrule[dim] =
168 7987288 : hardest_fe_type.default_quadrature_rule(dim-1, _extra_quadrature_order);
169 4047522 : if (dim == 3)
170 2288570 : _edge_qrule = hardest_fe_type.default_quadrature_rule(1, _extra_quadrature_order);
171 : }
172 :
173 4022858 : this->attach_quadrature_rules();
174 4022858 : }
175 :
176 :
177 20625 : void FEMContext::use_unweighted_quadrature_rules(int extra_quadrature_order)
178 : {
179 20625 : _extra_quadrature_order = extra_quadrature_order;
180 :
181 20625 : FEType hardest_fe_type = this->find_hardest_fe_type();
182 :
183 41250 : for (const auto & dim : _elem_dims)
184 : {
185 : // Create an adequate quadrature rule
186 20625 : _element_qrule[dim] =
187 40576 : hardest_fe_type.unweighted_quadrature_rule(dim, _extra_quadrature_order);
188 20625 : _side_qrule[dim] =
189 40576 : hardest_fe_type.unweighted_quadrature_rule(dim-1, _extra_quadrature_order);
190 20625 : if (dim == 3)
191 2800 : _edge_qrule = hardest_fe_type.unweighted_quadrature_rule(1, _extra_quadrature_order);
192 : }
193 :
194 20625 : this->attach_quadrature_rules();
195 20625 : }
196 :
197 :
198 4022858 : void FEMContext::init_internal_data(const System & sys)
199 : {
200 : // Reserve space for the FEAbstract and QBase objects for each
201 : // element dimension possibility (0,1,2,3)
202 :
203 : // Note: we would simply resize() all four of these vectors, but
204 : // some compilers (ICC 19, MSVC) generate a diagnostic about copying
205 : // a std::unique_ptr in this case, so the following two lines are a
206 : // workaround.
207 4022858 : _element_fe = std::vector<std::map<FEType, std::unique_ptr<FEAbstract>>>(4);
208 4022858 : _side_fe = std::vector<std::map<FEType, std::unique_ptr<FEAbstract>>>(4);
209 4022858 : _element_fe_var.resize(4);
210 4022858 : _side_fe_var.resize(4);
211 :
212 : // We need to know which of our variables has the hardest
213 : // shape functions to numerically integrate.
214 :
215 165758 : unsigned int nv = sys.n_vars();
216 165758 : libmesh_assert (nv);
217 :
218 165758 : bool have_scalar = false;
219 :
220 4022858 : if (_active_vars)
221 : {
222 6625336 : for (auto v : *_active_vars)
223 3463272 : if (sys.variable_type(v).family == SCALAR)
224 : {
225 0 : have_scalar = true;
226 0 : break;
227 : }
228 : }
229 : else
230 : {
231 2186614 : for (auto v : make_range(sys.n_vars()))
232 1329808 : if (sys.variable_type(v).family == SCALAR)
233 : {
234 120 : have_scalar = true;
235 120 : break;
236 : }
237 : }
238 :
239 4022858 : if (have_scalar)
240 : // SCALAR FEs have dimension 0 by assumption
241 3988 : _elem_dims.insert(0);
242 :
243 4446090 : auto build_var_fe = [this, &sys](unsigned int dim,
244 16136082 : unsigned int i)
245 : {
246 4848414 : FEType fe_type = sys.variable_type(i);
247 201162 : const auto & dof_map = sys.get_dof_map();
248 4848414 : const bool add_p_level = dof_map.should_p_refine(dof_map.var_group_from_var_number(i));
249 :
250 5049576 : auto & element_fe = _element_fe[dim][fe_type];
251 5049576 : auto & side_fe = _side_fe[dim][fe_type];
252 4848414 : if (!element_fe)
253 : {
254 8585806 : element_fe = FEAbstract::build(dim, fe_type);
255 182182 : element_fe->add_p_level_in_reinit(add_p_level);
256 8585806 : side_fe = FEAbstract::build(dim, fe_type);
257 182182 : side_fe->add_p_level_in_reinit(add_p_level);
258 :
259 4383994 : if (dim == 3)
260 : {
261 1202380 : auto & edge_fe = _edge_fe[fe_type];
262 2362502 : edge_fe = FEAbstract::build(dim, fe_type);
263 42258 : edge_fe->add_p_level_in_reinit(add_p_level);
264 : }
265 : }
266 :
267 5250738 : _element_fe_var[dim][i] = element_fe.get();
268 5049576 : _side_fe_var[dim][i] = side_fe.get();
269 4848414 : if ((dim) == 3)
270 1347420 : _edge_fe_var[i] = _edge_fe[fe_type].get();
271 4259424 : };
272 :
273 8070380 : for (const auto & dim : _elem_dims)
274 : {
275 : // Create finite element objects
276 4214152 : _element_fe_var[dim].resize(nv);
277 4214152 : _side_fe_var[dim].resize(nv);
278 4047522 : if (dim == 3)
279 1164660 : _edge_fe_var.resize(nv);
280 :
281 4047522 : if (_active_vars)
282 6642272 : for (auto v : *_active_vars)
283 3471740 : build_var_fe(dim, v);
284 : else
285 2253664 : for (auto v : make_range(nv))
286 1376674 : build_var_fe(dim, v);
287 : }
288 :
289 4022858 : this->use_default_quadrature_rules(_extra_quadrature_order);
290 4022858 : }
291 :
292 2630136 : FEMContext::~FEMContext()
293 : {
294 6052466 : }
295 :
296 :
297 :
298 2459104 : bool FEMContext::has_side_boundary_id(boundary_id_type id) const
299 : {
300 2459104 : return _boundary_info.has_boundary_id(&(this->get_elem()), side, id);
301 : }
302 :
303 :
304 :
305 0 : void FEMContext::side_boundary_ids(std::vector<boundary_id_type> & vec_to_fill) const
306 : {
307 0 : _boundary_info.boundary_ids(&(this->get_elem()), side, vec_to_fill);
308 0 : }
309 :
310 :
311 :
312 : template<typename OutputType,
313 : typename FEMContext::FENeeded<OutputType>::value_getter fe_getter,
314 : FEMContext::diff_subsolution_getter subsolution_getter>
315 294654649 : void FEMContext::some_value(unsigned int var, unsigned int qp, OutputType & u) const
316 : {
317 : // Get local-to-global dof index lookup
318 25441762 : const unsigned int n_dofs = cast_int<unsigned int>
319 50883526 : (this->get_dof_indices(var).size());
320 :
321 : // Get current local coefficients
322 25441762 : const DenseSubVector<Number> & coef = (this->*subsolution_getter)(var);
323 25441762 : libmesh_assert_equal_to(coef.size(), n_dofs);
324 :
325 : // Get finite element object
326 25441762 : typename FENeeded<OutputType>::value_base * fe = nullptr;
327 25441762 : (this->*fe_getter)( var, fe, this->get_elem_dim() );
328 :
329 : // Get shape function values at quadrature point
330 : const std::vector<std::vector
331 25441762 : <typename FENeeded<OutputType>::value_shape>> & phi = fe->get_phi();
332 25441762 : libmesh_assert_equal_to(phi.size(), n_dofs);
333 :
334 : // Accumulate solution value
335 277865612 : u = 0.;
336 :
337 2396157597 : for (unsigned int l=0; l != n_dofs; l++)
338 : {
339 180017656 : libmesh_assert_less(qp, phi[l].size());
340 2640272731 : u += phi[l][qp] * coef(l);
341 : }
342 294654649 : }
343 :
344 :
345 :
346 : template<typename OutputType,
347 : typename FEMContext::FENeeded<OutputType>::grad_getter fe_getter,
348 : FEMContext::diff_subsolution_getter subsolution_getter>
349 276619954 : void FEMContext::some_gradient(unsigned int var, unsigned int qp, OutputType & du) const
350 : {
351 : // Get local-to-global dof index lookup
352 : const unsigned int n_dofs = cast_int<unsigned int>
353 48198696 : (this->get_dof_indices(var).size());
354 :
355 : // Get current local coefficients
356 24099348 : const DenseSubVector<Number> & coef = (this->*subsolution_getter)(var);
357 :
358 : // Get finite element object
359 24099348 : typename FENeeded<OutputType>::grad_base * fe = nullptr;
360 24099348 : (this->*fe_getter)( var, fe, this->get_elem_dim() );
361 :
362 : // Get shape function values at quadrature point
363 : const std::vector<std::vector
364 : <typename FENeeded<OutputType>::grad_base::OutputGradient>>
365 24099348 : & dphi = fe->get_dphi();
366 :
367 : // Accumulate solution derivatives
368 24099348 : du = 0;
369 :
370 2361339684 : for (unsigned int l=0; l != n_dofs; l++)
371 2264999090 : du.add_scaled(dphi[l][qp], coef(l));
372 :
373 300719302 : return;
374 : }
375 :
376 :
377 :
378 : #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
379 : template<typename OutputType,
380 : typename FEMContext::FENeeded<OutputType>::hess_getter fe_getter,
381 : FEMContext::diff_subsolution_getter subsolution_getter>
382 0 : void FEMContext::some_hessian(unsigned int var, unsigned int qp, OutputType & d2u) const
383 : {
384 : // Get local-to-global dof index lookup
385 : const unsigned int n_dofs = cast_int<unsigned int>
386 0 : (this->get_dof_indices(var).size());
387 :
388 : // Get current local coefficients
389 0 : const DenseSubVector<Number> & coef = (this->*subsolution_getter)(var);
390 :
391 : // Get finite element object
392 0 : typename FENeeded<OutputType>::hess_base * fe = nullptr;
393 0 : (this->*fe_getter)( var, fe, this->get_elem_dim() );
394 :
395 : // Get shape function values at quadrature point
396 : const std::vector<std::vector
397 : <typename FENeeded<OutputType>::hess_base::OutputTensor>>
398 0 : & d2phi = fe->get_d2phi();
399 :
400 : // Accumulate solution second derivatives
401 0 : d2u = 0.0;
402 :
403 0 : for (unsigned int l=0; l != n_dofs; l++)
404 0 : d2u.add_scaled(d2phi[l][qp], coef(l));
405 :
406 0 : return;
407 : }
408 : #endif
409 :
410 :
411 :
412 1856056 : Number FEMContext::interior_value(unsigned int var, unsigned int qp) const
413 : {
414 8269 : Number u;
415 :
416 330088 : this->interior_value( var, qp, u );
417 :
418 1856056 : return u;
419 : }
420 :
421 : template<typename OutputType>
422 100933416 : void FEMContext::interior_value(unsigned int var, unsigned int qp,
423 : OutputType & u) const
424 : {
425 17225536 : this->some_value<OutputType,
426 : &FEMContext::get_element_fe<typename TensorTools::MakeReal<OutputType>::type>,
427 85233848 : &DiffContext::get_elem_solution>(var, qp, u);
428 100933416 : }
429 :
430 :
431 : template<typename OutputType>
432 2173248 : void FEMContext::interior_values (unsigned int var,
433 : const NumericVector<Number> & _system_vector,
434 : std::vector<OutputType> & u_vals) const
435 : {
436 : typedef typename TensorTools::MakeReal<OutputType>::type OutputShape;
437 :
438 : // Get local-to-global dof index lookup
439 : const unsigned int n_dofs = cast_int<unsigned int>
440 395136 : (this->get_dof_indices(var).size());
441 :
442 : // Get current local coefficients
443 2173248 : const DenseSubVector<Number> & coef = get_localized_subvector(_system_vector, var);
444 :
445 : // Get the finite element object
446 197568 : FEGenericBase<OutputShape> * fe = nullptr;
447 197568 : this->get_element_fe<OutputShape>( var, fe, this->get_elem_dim() );
448 :
449 : // Get shape function values at quadrature point
450 197568 : const std::vector<std::vector<OutputShape>> & phi = fe->get_phi();
451 :
452 : // Loop over all the q_points on this element
453 12344640 : for (auto qp : index_range(u_vals))
454 : {
455 924672 : OutputType & u = u_vals[qp];
456 :
457 : // Compute the value at this q_point
458 10171392 : u = 0.;
459 :
460 50856960 : for (unsigned int l=0; l != n_dofs; l++)
461 51781632 : u += phi[l][qp] * coef(l);
462 : }
463 :
464 2370816 : return;
465 : }
466 :
467 116072874 : Gradient FEMContext::interior_gradient(unsigned int var,
468 : unsigned int qp) const
469 : {
470 10683804 : Gradient du;
471 :
472 21367608 : this->interior_gradient( var, qp, du );
473 :
474 116072874 : return du;
475 : }
476 :
477 :
478 :
479 : template<typename OutputType>
480 181914688 : void FEMContext::interior_gradient(unsigned int var,
481 : unsigned int qp,
482 : OutputType & du) const
483 : {
484 48198696 : this->some_gradient<OutputType,
485 : &FEMContext::get_element_fe<typename TensorTools::MakeReal
486 : <typename TensorTools::DecrementRank
487 : <OutputType>::type>::type>,
488 228421258 : &DiffContext::get_elem_solution>(var, qp, du);
489 181914688 : }
490 :
491 :
492 :
493 : template<typename OutputType>
494 0 : void FEMContext::interior_gradients(unsigned int var,
495 : const NumericVector<Number> & _system_vector,
496 : std::vector<OutputType> & du_vals) const
497 : {
498 : typedef typename TensorTools::MakeReal
499 : <typename TensorTools::DecrementRank<OutputType>::type>::type
500 : OutputShape;
501 :
502 : // Get local-to-global dof index lookup
503 : const unsigned int n_dofs = cast_int<unsigned int>
504 0 : (this->get_dof_indices(var).size());
505 :
506 : // Get current local coefficients
507 0 : const DenseSubVector<Number> & coef = get_localized_subvector(_system_vector, var);
508 :
509 : // Get finite element object
510 0 : FEGenericBase<OutputShape> * fe = nullptr;
511 0 : this->get_element_fe<OutputShape>( var, fe, this->get_elem_dim() );
512 :
513 : // Get shape function values at quadrature point
514 0 : const std::vector<std::vector<typename FEGenericBase<OutputShape>::OutputGradient>> & dphi = fe->get_dphi();
515 :
516 : // Loop over all the q_points in this finite element
517 0 : for (auto qp : index_range(du_vals))
518 : {
519 0 : OutputType & du = du_vals[qp];
520 :
521 : // Compute the gradient at this q_point
522 0 : du = 0;
523 :
524 0 : for (unsigned int l=0; l != n_dofs; l++)
525 0 : du.add_scaled(dphi[l][qp], coef(l));
526 : }
527 :
528 0 : return;
529 : }
530 :
531 : #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
532 0 : Tensor FEMContext::interior_hessian(unsigned int var, unsigned int qp) const
533 : {
534 0 : Tensor d2u;
535 :
536 0 : this->interior_hessian( var, qp, d2u );
537 :
538 0 : return d2u;
539 : }
540 :
541 : template<typename OutputType>
542 0 : void FEMContext::interior_hessian(unsigned int var, unsigned int qp,
543 : OutputType & d2u) const
544 : {
545 0 : this->some_hessian<OutputType,
546 : &FEMContext::get_element_fe
547 : <typename TensorTools::MakeReal
548 : <typename TensorTools::DecrementRank
549 : <typename TensorTools::DecrementRank
550 : <OutputType>::type>::type>::type>,
551 0 : &DiffContext::get_elem_solution>(var, qp, d2u);
552 0 : }
553 :
554 :
555 : template<typename OutputType>
556 0 : void FEMContext::interior_hessians(unsigned int var,
557 : const NumericVector<Number> & _system_vector,
558 : std::vector<OutputType> & d2u_vals) const
559 : {
560 : typedef typename TensorTools::DecrementRank<OutputType>::type Rank1Decrement;
561 : typedef typename TensorTools::DecrementRank<Rank1Decrement>::type Rank2Decrement;
562 : typedef typename TensorTools::MakeReal<Rank2Decrement>::type OutputShape;
563 :
564 : // Get local-to-global dof index lookup
565 : const unsigned int n_dofs = cast_int<unsigned int>
566 0 : (this->get_dof_indices(var).size());
567 :
568 : // Get current local coefficients
569 0 : const DenseSubVector<Number> & coef = get_localized_subvector(_system_vector, var);
570 :
571 : // Get finite element object
572 0 : FEGenericBase<OutputShape> * fe = nullptr;
573 0 : this->get_element_fe<OutputShape>( var, fe, this->get_elem_dim() );
574 :
575 : // Get shape function values at quadrature point
576 0 : const std::vector<std::vector<typename FEGenericBase<OutputShape>::OutputTensor>> & d2phi = fe->get_d2phi();
577 :
578 : // Loop over all the q_points in this finite element
579 0 : for (auto qp : index_range(d2u_vals))
580 : {
581 0 : OutputType & d2u = d2u_vals[qp];
582 :
583 : // Compute the gradient at this q_point
584 0 : d2u = 0;
585 :
586 0 : for (unsigned int l=0; l != n_dofs; l++)
587 0 : d2u.add_scaled(d2phi[l][qp], coef(l));
588 : }
589 :
590 0 : return;
591 : }
592 :
593 :
594 : #endif // ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
595 :
596 :
597 : template<typename OutputType>
598 1858560 : void FEMContext::interior_curl(unsigned int var, unsigned int qp,
599 : OutputType & curl_u) const
600 : {
601 : typedef typename TensorTools::MakeReal<OutputType>::type OutputShape;
602 :
603 : // Get local-to-global dof index lookup
604 : const unsigned int n_dofs = cast_int<unsigned int>
605 318080 : (this->get_dof_indices(var).size());
606 :
607 : // Get current local coefficients
608 159040 : libmesh_assert_greater (this->_elem_subsolutions.size(), var);
609 159040 : const DenseSubVector<Number> & coef = this->get_elem_solution(var);
610 :
611 : // Get finite element object
612 159040 : FEGenericBase<OutputShape> * fe = nullptr;
613 159040 : this->get_element_fe<OutputShape>( var, fe, this->get_elem_dim() );
614 :
615 : // Get shape function values at quadrature point
616 427200 : const std::vector<std::vector<typename FEGenericBase<OutputShape>::OutputShape>> & curl_phi = fe->get_curl_phi();
617 :
618 : // Accumulate solution curl
619 159040 : curl_u = 0.;
620 :
621 14846976 : for (unsigned int l=0; l != n_dofs; l++)
622 14099200 : curl_u.add_scaled(curl_phi[l][qp], coef(l));
623 :
624 2017600 : return;
625 : }
626 :
627 :
628 : template<typename OutputType>
629 0 : void FEMContext::interior_div(unsigned int var, unsigned int qp,
630 : OutputType & div_u) const
631 : {
632 : typedef typename
633 : TensorTools::IncrementRank
634 : <typename TensorTools::MakeReal<OutputType>::type>::type OutputShape;
635 :
636 : // Get local-to-global dof index lookup
637 : const unsigned int n_dofs = cast_int<unsigned int>
638 0 : (this->get_dof_indices(var).size());
639 :
640 : // Get current local coefficients
641 0 : libmesh_assert_greater (this->_elem_subsolutions.size(), var);
642 0 : const DenseSubVector<Number> & coef = this->get_elem_solution(var);
643 :
644 : // Get finite element object
645 0 : FEGenericBase<OutputShape> * fe = nullptr;
646 0 : this->get_element_fe<OutputShape>( var, fe, this->get_elem_dim() );
647 :
648 : // Get shape function values at quadrature point
649 0 : const std::vector<std::vector<typename FEGenericBase<OutputShape>::OutputDivergence>> & div_phi = fe->get_div_phi();
650 :
651 : // Accumulate solution curl
652 0 : div_u = 0.;
653 :
654 0 : for (unsigned int l=0; l != n_dofs; l++)
655 0 : div_u += div_phi[l][qp] * coef(l);
656 :
657 0 : return;
658 : }
659 :
660 :
661 3158417 : Number FEMContext::side_value(unsigned int var,
662 : unsigned int qp) const
663 : {
664 3158417 : Number u = 0.;
665 :
666 704662 : this->side_value( var, qp, u );
667 :
668 3158417 : return u;
669 : }
670 :
671 :
672 : template<typename OutputType>
673 950038 : void FEMContext::side_value(unsigned int var,
674 : unsigned int qp,
675 : OutputType & u) const
676 : {
677 747030 : this->some_value<OutputType,
678 : &FEMContext::get_side_fe<typename TensorTools::MakeReal<OutputType>::type>,
679 2656763 : &DiffContext::get_elem_solution>(var, qp, u);
680 950038 : }
681 :
682 :
683 : template<typename OutputType>
684 0 : void FEMContext::side_values(unsigned int var,
685 : const NumericVector<Number> & _system_vector,
686 : std::vector<OutputType> & u_vals) const
687 : {
688 : typedef typename TensorTools::MakeReal<OutputType>::type OutputShape;
689 :
690 : // Get local-to-global dof index lookup
691 : const unsigned int n_dofs = cast_int<unsigned int>
692 0 : (this->get_dof_indices(var).size());
693 :
694 : // Get current local coefficients
695 0 : const DenseSubVector<Number> & coef = get_localized_subvector(_system_vector, var);
696 :
697 : // Get the finite element object
698 0 : FEGenericBase<OutputShape> * the_side_fe = nullptr;
699 0 : this->get_side_fe<OutputShape>( var, the_side_fe, this->get_elem_dim() );
700 :
701 : // Get shape function values at quadrature point
702 0 : const std::vector<std::vector<OutputShape>> & phi = the_side_fe->get_phi();
703 :
704 : // Loop over all the q_points on this element
705 0 : for (auto qp : index_range(u_vals))
706 : {
707 0 : OutputType & u = u_vals[qp];
708 :
709 : // Compute the value at this q_point
710 0 : u = 0.;
711 :
712 0 : for (unsigned int l=0; l != n_dofs; l++)
713 0 : u += phi[l][qp] * coef(l);
714 : }
715 :
716 0 : return;
717 : }
718 :
719 3730974 : Gradient FEMContext::side_gradient(unsigned int var, unsigned int qp) const
720 : {
721 450201 : Gradient du;
722 :
723 3730974 : this->side_gradient( var, qp, du );
724 :
725 3730974 : return du;
726 : }
727 :
728 :
729 : template<typename OutputType>
730 3730974 : void FEMContext::side_gradient(unsigned int var, unsigned int qp,
731 : OutputType & du) const
732 : {
733 : typedef typename TensorTools::MakeReal
734 : <typename TensorTools::DecrementRank<OutputType>::type>::type
735 : OutputShape;
736 :
737 : // Get local-to-global dof index lookup
738 : const unsigned int n_dofs = cast_int<unsigned int>
739 900402 : (this->get_dof_indices(var).size());
740 :
741 : // Get current local coefficients
742 450201 : libmesh_assert_greater (this->_elem_subsolutions.size(), var);
743 450201 : const DenseSubVector<Number> & coef = this->get_elem_solution(var);
744 :
745 : // Get finite element object
746 450201 : FEGenericBase<OutputShape> * the_side_fe = nullptr;
747 450201 : this->get_side_fe<OutputShape>( var, the_side_fe, this->get_elem_dim() );
748 :
749 : // Get shape function values at quadrature point
750 450201 : const std::vector<std::vector<typename FEGenericBase<OutputShape>::OutputGradient>> & dphi = the_side_fe->get_dphi();
751 :
752 : // Accumulate solution derivatives
753 450201 : du = 0.;
754 :
755 20268154 : for (unsigned int l=0; l != n_dofs; l++)
756 18802241 : du.add_scaled(dphi[l][qp], coef(l));
757 :
758 4181175 : return;
759 : }
760 :
761 :
762 :
763 : template<typename OutputType>
764 0 : void FEMContext::side_gradients(unsigned int var,
765 : const NumericVector<Number> & _system_vector,
766 : std::vector<OutputType> & du_vals) const
767 : {
768 : typedef typename TensorTools::MakeReal
769 : <typename TensorTools::DecrementRank<OutputType>::type>::type
770 : OutputShape;
771 :
772 : // Get local-to-global dof index lookup
773 : const unsigned int n_dofs = cast_int<unsigned int>
774 0 : (this->get_dof_indices(var).size());
775 :
776 : // Get current local coefficients
777 0 : const DenseSubVector<Number> & coef = get_localized_subvector(_system_vector, var);
778 :
779 : // Get finite element object
780 0 : FEGenericBase<OutputShape> * the_side_fe = nullptr;
781 0 : this->get_side_fe<OutputShape>( var, the_side_fe, this->get_elem_dim() );
782 :
783 : // Get shape function values at quadrature point
784 0 : const std::vector<std::vector<typename FEGenericBase<OutputShape>::OutputGradient>> & dphi = the_side_fe->get_dphi();
785 :
786 : // Loop over all the q_points in this finite element
787 0 : for (auto qp : index_range(du_vals))
788 : {
789 0 : OutputType & du = du_vals[qp];
790 :
791 0 : du = 0;
792 :
793 : // Compute the gradient at this q_point
794 0 : for (unsigned int l=0; l != n_dofs; l++)
795 0 : du.add_scaled(dphi[l][qp], coef(l));
796 : }
797 :
798 0 : return;
799 : }
800 :
801 : #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
802 0 : Tensor FEMContext::side_hessian(unsigned int var,
803 : unsigned int qp) const
804 : {
805 0 : Tensor d2u;
806 :
807 0 : this->side_hessian( var, qp, d2u );
808 :
809 0 : return d2u;
810 : }
811 :
812 :
813 :
814 : template<typename OutputType>
815 0 : void FEMContext::side_hessian(unsigned int var,
816 : unsigned int qp,
817 : OutputType & d2u) const
818 : {
819 0 : this->some_hessian<OutputType,
820 : &FEMContext::get_side_fe
821 : <typename TensorTools::MakeReal
822 : <typename TensorTools::DecrementRank
823 : <typename TensorTools::DecrementRank
824 : <OutputType>::type>::type>::type>,
825 0 : &DiffContext::get_elem_solution>(var, qp, d2u);
826 0 : }
827 :
828 :
829 :
830 : template<typename OutputType>
831 0 : void FEMContext::side_hessians(unsigned int var,
832 : const NumericVector<Number> & _system_vector,
833 : std::vector<OutputType> & d2u_vals) const
834 : {
835 : typedef typename TensorTools::DecrementRank<OutputType>::type Rank1Decrement;
836 : typedef typename TensorTools::DecrementRank<Rank1Decrement>::type Rank2Decrement;
837 : typedef typename TensorTools::MakeReal<Rank2Decrement>::type OutputShape;
838 :
839 : // Get local-to-global dof index lookup
840 : const unsigned int n_dofs = cast_int<unsigned int>
841 0 : (this->get_dof_indices(var).size());
842 :
843 : // Get current local coefficients
844 0 : const DenseSubVector<Number> & coef = get_localized_subvector(_system_vector, var);
845 :
846 : // Get finite element object
847 0 : FEGenericBase<OutputShape> * the_side_fe = nullptr;
848 0 : this->get_side_fe<OutputShape>( var, the_side_fe, this->get_elem_dim() );
849 :
850 : // Get shape function values at quadrature point
851 0 : const std::vector<std::vector<typename FEGenericBase<OutputShape>::OutputTensor>> & d2phi = the_side_fe->get_d2phi();
852 :
853 : // Loop over all the q_points in this finite element
854 0 : for (auto qp : index_range(d2u_vals))
855 : {
856 0 : OutputType & d2u = d2u_vals[qp];
857 :
858 : // Compute the gradient at this q_point
859 0 : d2u = 0;
860 :
861 0 : for (unsigned int l=0; l != n_dofs; l++)
862 0 : d2u.add_scaled(d2phi[l][qp], coef(l));
863 : }
864 :
865 0 : return;
866 : }
867 :
868 :
869 :
870 : #endif // ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
871 :
872 :
873 :
874 61472 : Number FEMContext::point_value(unsigned int var, const Point & p) const
875 : {
876 61472 : Number u = 0.;
877 :
878 61472 : this->point_value( var, p, u );
879 :
880 61472 : return u;
881 : }
882 :
883 : template<typename OutputType>
884 4188878 : void FEMContext::point_value(unsigned int var,
885 : const Point & p,
886 : OutputType & u,
887 : const Real tolerance) const
888 : {
889 : typedef typename TensorTools::MakeReal<OutputType>::type OutputShape;
890 :
891 : // Get local-to-global dof index lookup
892 : const unsigned int n_dofs = cast_int<unsigned int>
893 701911 : (this->get_dof_indices(var).size());
894 :
895 : // Get current local coefficients
896 350949 : libmesh_assert_greater (this->_elem_subsolutions.size(), var);
897 350949 : const DenseSubVector<Number> & coef = this->get_elem_solution(var);
898 :
899 : // Get finite element object
900 350949 : FEGenericBase<OutputShape> * fe = nullptr;
901 350949 : this->get_element_fe<OutputShape>( var, fe, this->get_elem_dim() );
902 :
903 : // Build a FE for calculating u(p)
904 701911 : FEGenericBase<OutputShape> * fe_new =
905 3486967 : this->build_new_fe( fe, p, tolerance, 0 );
906 :
907 : // Get the values of the shape function derivatives
908 350949 : const std::vector<std::vector<OutputShape>> & phi = fe_new->get_phi();
909 :
910 3833272 : u = 0.;
911 :
912 60665451 : for (unsigned int l=0; l != n_dofs; l++)
913 65537787 : u += phi[l][0] * coef(l);
914 :
915 4539827 : return;
916 : }
917 :
918 :
919 :
920 61472 : Gradient FEMContext::point_gradient(unsigned int var, const Point & p) const
921 : {
922 5440 : Gradient grad_u;
923 :
924 61472 : this->point_gradient( var, p, grad_u );
925 :
926 61472 : return grad_u;
927 : }
928 :
929 :
930 :
931 : template<typename OutputType>
932 257174 : void FEMContext::point_gradient(unsigned int var,
933 : const Point & p,
934 : OutputType & grad_u,
935 : const Real tolerance) const
936 : {
937 : typedef typename TensorTools::MakeReal
938 : <typename TensorTools::DecrementRank<OutputType>::type>::type
939 : OutputShape;
940 :
941 : // Get local-to-global dof index lookup
942 : const unsigned int n_dofs = cast_int<unsigned int>
943 41699 : (this->get_dof_indices(var).size());
944 :
945 : // Get current local coefficients
946 20843 : libmesh_assert_greater (this->_elem_subsolutions.size(), var);
947 20843 : const DenseSubVector<Number> & coef = this->get_elem_solution(var);
948 :
949 : // Get finite element object
950 20843 : FEGenericBase<OutputShape> * fe = nullptr;
951 20843 : this->get_element_fe<OutputShape>( var, fe, this->get_elem_dim() );
952 :
953 : // Build a FE for calculating u(p)
954 41699 : FEGenericBase<OutputShape> * fe_new =
955 215475 : this->build_new_fe( fe, p, tolerance, 1 );
956 :
957 : // Get the values of the shape function derivatives
958 20843 : const std::vector<std::vector<typename FEGenericBase<OutputShape>::OutputGradient>> & dphi = fe_new->get_dphi();
959 :
960 20843 : grad_u = 0.0;
961 :
962 3134978 : for (unsigned int l=0; l != n_dofs; l++)
963 3109896 : grad_u.add_scaled(dphi[l][0], coef(l));
964 :
965 278017 : return;
966 : }
967 :
968 :
969 :
970 : #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
971 :
972 0 : Tensor FEMContext::point_hessian(unsigned int var, const Point & p) const
973 : {
974 0 : Tensor hess_u;
975 :
976 0 : this->point_hessian( var, p, hess_u );
977 :
978 0 : return hess_u;
979 : }
980 :
981 :
982 : template<typename OutputType>
983 39 : void FEMContext::point_hessian(unsigned int var,
984 : const Point & p,
985 : OutputType & hess_u,
986 : const Real tolerance) const
987 : {
988 : typedef typename TensorTools::DecrementRank<OutputType>::type Rank1Decrement;
989 : typedef typename TensorTools::DecrementRank<Rank1Decrement>::type Rank2Decrement;
990 : typedef typename TensorTools::MakeReal<Rank2Decrement>::type OutputShape;
991 :
992 : // Get local-to-global dof index lookup
993 : const unsigned int n_dofs = cast_int<unsigned int>
994 6 : (this->get_dof_indices(var).size());
995 :
996 : // Get current local coefficients
997 3 : libmesh_assert_greater (this->_elem_subsolutions.size(), var);
998 3 : const DenseSubVector<Number> & coef = this->get_elem_solution(var);
999 :
1000 : // Get finite element object
1001 3 : FEGenericBase<OutputShape> * fe = nullptr;
1002 3 : this->get_element_fe<OutputShape>( var, fe, this->get_elem_dim() );
1003 :
1004 : // Build a FE for calculating u(p)
1005 6 : FEGenericBase<OutputShape> * fe_new =
1006 33 : this->build_new_fe( fe, p, tolerance, 2 );
1007 :
1008 : // Get the values of the shape function derivatives
1009 3 : const std::vector<std::vector<typename FEGenericBase<OutputShape>::OutputTensor>> & d2phi = fe_new->get_d2phi();
1010 :
1011 3 : hess_u = 0.0;
1012 :
1013 351 : for (unsigned int l=0; l != n_dofs; l++)
1014 336 : hess_u.add_scaled(d2phi[l][0], coef(l));
1015 :
1016 42 : return;
1017 : }
1018 :
1019 : #endif // LIBMESH_ENABLE_SECOND_DERIVATIVES
1020 :
1021 :
1022 : template<typename OutputType>
1023 0 : void FEMContext::point_curl(unsigned int var,
1024 : const Point & p,
1025 : OutputType & curl_u,
1026 : const Real tolerance) const
1027 : {
1028 : typedef typename TensorTools::MakeReal<OutputType>::type OutputShape;
1029 :
1030 : // Get local-to-global dof index lookup
1031 : const unsigned int n_dofs = cast_int<unsigned int>
1032 0 : (this->get_dof_indices(var).size());
1033 :
1034 : // Get current local coefficients
1035 0 : libmesh_assert_greater (this->_elem_subsolutions.size(), var);
1036 0 : const DenseSubVector<Number> & coef = this->get_elem_solution(var);
1037 :
1038 : // Get finite element object
1039 0 : FEGenericBase<OutputShape> * fe = nullptr;
1040 0 : this->get_element_fe<OutputShape>( var, fe, this->get_elem_dim() );
1041 :
1042 : // Build a FE for calculating u(p)
1043 0 : FEGenericBase<OutputShape> * fe_new =
1044 0 : this->build_new_fe( fe, p, tolerance, 3 );
1045 :
1046 : // Get the values of the shape function derivatives
1047 0 : const std::vector<std::vector<typename FEGenericBase<OutputShape>::OutputShape>> & curl_phi = fe_new->get_curl_phi();
1048 :
1049 0 : curl_u = 0.0;
1050 :
1051 0 : for (unsigned int l=0; l != n_dofs; l++)
1052 0 : curl_u.add_scaled(curl_phi[l][0], coef(l));
1053 :
1054 0 : return;
1055 : }
1056 :
1057 :
1058 :
1059 0 : Number FEMContext::fixed_interior_value(unsigned int var, unsigned int qp) const
1060 : {
1061 0 : Number u = 0.;
1062 :
1063 0 : this->fixed_interior_value( var, qp, u );
1064 :
1065 0 : return u;
1066 : }
1067 :
1068 :
1069 :
1070 : template<typename OutputType>
1071 0 : void FEMContext::fixed_interior_value(unsigned int var, unsigned int qp,
1072 : OutputType & u) const
1073 : {
1074 0 : this->some_value<OutputType,
1075 : &FEMContext::get_element_fe
1076 : <typename TensorTools::MakeReal<OutputType>::type>,
1077 0 : &DiffContext::get_elem_fixed_solution>(var, qp, u);
1078 0 : }
1079 :
1080 :
1081 :
1082 0 : Gradient FEMContext::fixed_interior_gradient(unsigned int var, unsigned int qp) const
1083 : {
1084 0 : Gradient du;
1085 :
1086 0 : this->fixed_interior_gradient( var, qp, du );
1087 :
1088 0 : return du;
1089 : }
1090 :
1091 :
1092 : template<typename OutputType>
1093 0 : void FEMContext::fixed_interior_gradient(unsigned int var, unsigned int qp,
1094 : OutputType & du) const
1095 : {
1096 0 : this->some_gradient
1097 : <OutputType,
1098 : &FEMContext::get_element_fe
1099 : <typename TensorTools::MakeReal
1100 : <typename TensorTools::DecrementRank
1101 : <OutputType>::type>::type>,
1102 : &DiffContext::get_elem_fixed_solution>
1103 0 : (var, qp, du);
1104 0 : }
1105 :
1106 :
1107 :
1108 : #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
1109 0 : Tensor FEMContext::fixed_interior_hessian(unsigned int var, unsigned int qp) const
1110 : {
1111 0 : Tensor d2u;
1112 :
1113 0 : this->fixed_interior_hessian( var, qp, d2u );
1114 :
1115 0 : return d2u;
1116 : }
1117 :
1118 :
1119 : template<typename OutputType>
1120 0 : void FEMContext::fixed_interior_hessian(unsigned int var, unsigned int qp,
1121 : OutputType & d2u) const
1122 : {
1123 0 : this->some_hessian<OutputType,
1124 : &FEMContext::get_element_fe
1125 : <typename TensorTools::MakeReal
1126 : <typename TensorTools::DecrementRank
1127 : <typename TensorTools::DecrementRank
1128 : <OutputType>::type>::type>::type>,
1129 0 : &DiffContext::get_elem_fixed_solution>(var, qp, d2u);
1130 0 : }
1131 : #endif // ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
1132 :
1133 :
1134 :
1135 0 : Number FEMContext::fixed_side_value(unsigned int var, unsigned int qp) const
1136 : {
1137 0 : Number u = 0.;
1138 :
1139 0 : this->fixed_side_value( var, qp, u );
1140 :
1141 0 : return u;
1142 : }
1143 :
1144 :
1145 : template<typename OutputType>
1146 0 : void FEMContext::fixed_side_value(unsigned int var, unsigned int qp,
1147 : OutputType & u) const
1148 : {
1149 0 : this->some_value
1150 : <OutputType,
1151 : &FEMContext::get_side_fe
1152 : <typename TensorTools::MakeReal<OutputType>::type>,
1153 : &DiffContext::get_elem_fixed_solution>
1154 0 : (var, qp, u);
1155 0 : }
1156 :
1157 :
1158 :
1159 0 : Gradient FEMContext::fixed_side_gradient(unsigned int var, unsigned int qp) const
1160 : {
1161 0 : Gradient du;
1162 :
1163 0 : this->fixed_side_gradient( var, qp, du );
1164 :
1165 0 : return du;
1166 : }
1167 :
1168 :
1169 : template<typename OutputType>
1170 0 : void FEMContext::fixed_side_gradient(unsigned int var, unsigned int qp,
1171 : OutputType & du) const
1172 : {
1173 0 : this->some_gradient<OutputType,
1174 : &FEMContext::get_side_fe
1175 : <typename TensorTools::MakeReal
1176 : <typename TensorTools::DecrementRank
1177 : <OutputType>::type>::type>,
1178 0 : &DiffContext::get_elem_fixed_solution>(var, qp, du);
1179 0 : }
1180 :
1181 :
1182 :
1183 : #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
1184 0 : Tensor FEMContext::fixed_side_hessian(unsigned int var, unsigned int qp) const
1185 : {
1186 0 : Tensor d2u;
1187 :
1188 0 : this->fixed_side_hessian( var, qp, d2u );
1189 :
1190 0 : return d2u;
1191 : }
1192 :
1193 : template<typename OutputType>
1194 0 : void FEMContext::fixed_side_hessian(unsigned int var, unsigned int qp,
1195 : OutputType & d2u) const
1196 : {
1197 0 : this->some_hessian<OutputType,
1198 : &FEMContext::get_side_fe
1199 : <typename TensorTools::MakeReal
1200 : <typename TensorTools::DecrementRank
1201 : <typename TensorTools::DecrementRank
1202 : <OutputType>::type>::type>::type>,
1203 0 : &DiffContext::get_elem_fixed_solution>(var, qp, d2u);
1204 0 : }
1205 : #endif // ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
1206 :
1207 :
1208 :
1209 0 : Number FEMContext::fixed_point_value(unsigned int var, const Point & p) const
1210 : {
1211 0 : Number u = 0.;
1212 :
1213 0 : this->fixed_point_value( var, p, u );
1214 :
1215 0 : return u;
1216 : }
1217 :
1218 : template<typename OutputType>
1219 0 : void FEMContext::fixed_point_value(unsigned int var,
1220 : const Point & p,
1221 : OutputType & u,
1222 : const Real tolerance) const
1223 : {
1224 : typedef typename TensorTools::MakeReal<OutputType>::type OutputShape;
1225 :
1226 : // Get local-to-global dof index lookup
1227 : const unsigned int n_dofs = cast_int<unsigned int>
1228 0 : (this->get_dof_indices(var).size());
1229 :
1230 : // Get current local coefficients
1231 0 : libmesh_assert_greater (_elem_fixed_subsolutions.size(), var);
1232 0 : const DenseSubVector<Number> & coef = this->get_elem_fixed_solution(var);
1233 :
1234 : // Get finite element object
1235 0 : FEGenericBase<OutputShape> * fe = nullptr;
1236 0 : this->get_element_fe<OutputShape>( var, fe, this->get_elem_dim() );
1237 :
1238 : // Build a FE for calculating u(p)
1239 0 : FEGenericBase<OutputShape> * fe_new =
1240 0 : this->build_new_fe( fe, p, tolerance, 0 );
1241 :
1242 : // Get the values of the shape function derivatives
1243 0 : const std::vector<std::vector<OutputShape>> & phi = fe_new->get_phi();
1244 :
1245 0 : u = 0.;
1246 :
1247 0 : for (unsigned int l=0; l != n_dofs; l++)
1248 0 : u += phi[l][0] * coef(l);
1249 :
1250 0 : return;
1251 : }
1252 :
1253 :
1254 :
1255 0 : Gradient FEMContext::fixed_point_gradient(unsigned int var, const Point & p) const
1256 : {
1257 0 : Gradient grad_u;
1258 :
1259 0 : this->fixed_point_gradient( var, p, grad_u );
1260 :
1261 0 : return grad_u;
1262 : }
1263 :
1264 :
1265 :
1266 : template<typename OutputType>
1267 0 : void FEMContext::fixed_point_gradient(unsigned int var,
1268 : const Point & p,
1269 : OutputType & grad_u,
1270 : const Real tolerance) const
1271 : {
1272 : typedef typename TensorTools::MakeReal
1273 : <typename TensorTools::DecrementRank<OutputType>::type>::type
1274 : OutputShape;
1275 :
1276 : // Get local-to-global dof index lookup
1277 : const unsigned int n_dofs = cast_int<unsigned int>
1278 0 : (this->get_dof_indices(var).size());
1279 :
1280 : // Get current local coefficients
1281 0 : libmesh_assert_greater (_elem_fixed_subsolutions.size(), var);
1282 0 : const DenseSubVector<Number> & coef = this->get_elem_fixed_solution(var);
1283 :
1284 : // Get finite element object
1285 0 : FEGenericBase<OutputShape> * fe = nullptr;
1286 0 : this->get_element_fe<OutputShape>( var, fe, this->get_elem_dim() );
1287 :
1288 : // Build a FE for calculating u(p)
1289 0 : FEGenericBase<OutputShape> * fe_new =
1290 0 : this->build_new_fe( fe, p, tolerance, 1 );
1291 :
1292 : // Get the values of the shape function derivatives
1293 0 : const std::vector<std::vector<typename FEGenericBase<OutputShape>::OutputGradient>> & dphi = fe_new->get_dphi();
1294 :
1295 0 : grad_u = 0.0;
1296 :
1297 0 : for (unsigned int l=0; l != n_dofs; l++)
1298 0 : grad_u.add_scaled(dphi[l][0], coef(l));
1299 :
1300 0 : return;
1301 : }
1302 :
1303 :
1304 : #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
1305 :
1306 0 : Tensor FEMContext::fixed_point_hessian(unsigned int var, const Point & p) const
1307 : {
1308 0 : Tensor hess_u;
1309 :
1310 0 : this->fixed_point_hessian( var, p, hess_u );
1311 :
1312 0 : return hess_u;
1313 : }
1314 :
1315 :
1316 :
1317 : template<typename OutputType>
1318 0 : void FEMContext::fixed_point_hessian(unsigned int var,
1319 : const Point & p,
1320 : OutputType & hess_u,
1321 : const Real tolerance) const
1322 : {
1323 : typedef typename TensorTools::DecrementRank<OutputType>::type Rank1Decrement;
1324 : typedef typename TensorTools::DecrementRank<Rank1Decrement>::type Rank2Decrement;
1325 : typedef typename TensorTools::MakeReal<Rank2Decrement>::type OutputShape;
1326 :
1327 : // Get local-to-global dof index lookup
1328 : const unsigned int n_dofs = cast_int<unsigned int>
1329 0 : (this->get_dof_indices(var).size());
1330 :
1331 : // Get current local coefficients
1332 0 : libmesh_assert_greater (_elem_fixed_subsolutions.size(), var);
1333 0 : const DenseSubVector<Number> & coef = this->get_elem_fixed_solution(var);
1334 :
1335 : // Get finite element object
1336 0 : FEGenericBase<OutputShape> * fe = nullptr;
1337 0 : this->get_element_fe<OutputShape>( var, fe, this->get_elem_dim() );
1338 :
1339 : // Build a FE for calculating u(p)
1340 0 : FEGenericBase<OutputShape> * fe_new =
1341 0 : this->build_new_fe( fe, p, tolerance, 2 );
1342 :
1343 : // Get the values of the shape function derivatives
1344 0 : const std::vector<std::vector<typename FEGenericBase<OutputShape>::OutputTensor>> & d2phi = fe_new->get_d2phi();
1345 :
1346 0 : hess_u = 0.0;
1347 :
1348 0 : for (unsigned int l=0; l != n_dofs; l++)
1349 0 : hess_u.add_scaled(d2phi[l][0], coef(l));
1350 :
1351 0 : return;
1352 : }
1353 :
1354 : #endif // LIBMESH_ENABLE_SECOND_DERIVATIVES
1355 :
1356 :
1357 :
1358 : template<typename OutputType>
1359 149658848 : void FEMContext::interior_rate(unsigned int var, unsigned int qp,
1360 : OutputType & u) const
1361 : {
1362 26171416 : this->some_value<OutputType,
1363 : &FEMContext::get_element_fe
1364 : <typename TensorTools::MakeReal<OutputType>::type>,
1365 123487432 : &DiffContext::get_elem_solution_rate>(var, qp, u);
1366 149658848 : }
1367 :
1368 : template<typename OutputType>
1369 0 : void FEMContext::interior_rate_gradient(unsigned int var, unsigned int qp,
1370 : OutputType & dudot) const
1371 : {
1372 0 : this->some_gradient<OutputType,
1373 : &FEMContext::get_element_fe<typename TensorTools::MakeReal
1374 : <typename TensorTools::DecrementRank
1375 : <OutputType>::type>::type>,
1376 0 : &DiffContext::get_elem_solution_rate>(var, qp, dudot);
1377 0 : }
1378 :
1379 : template<typename OutputType>
1380 0 : void FEMContext::side_rate(unsigned int var, unsigned int qp,
1381 : OutputType & u) const
1382 : {
1383 0 : this->some_value<OutputType,
1384 : &FEMContext::get_side_fe
1385 : <typename TensorTools::MakeReal<OutputType>::type>,
1386 0 : &DiffContext::get_elem_solution_rate>(var, qp, u);
1387 0 : }
1388 :
1389 : template<typename OutputType>
1390 39132624 : void FEMContext::interior_accel(unsigned int var, unsigned int qp,
1391 : OutputType & u) const
1392 : {
1393 6739544 : this->some_value<OutputType,
1394 : &FEMContext::get_element_fe
1395 : <typename TensorTools::MakeReal<OutputType>::type>,
1396 32393080 : &DiffContext::get_elem_solution_accel>(var, qp, u);
1397 39132624 : }
1398 :
1399 :
1400 :
1401 : template<typename OutputType>
1402 0 : void FEMContext::side_accel(unsigned int var, unsigned int qp,
1403 : OutputType & u) const
1404 : {
1405 0 : this->some_value<OutputType,
1406 : &FEMContext::get_side_fe
1407 : <typename TensorTools::MakeReal<OutputType>::type>,
1408 0 : &DiffContext::get_elem_solution_accel>(var, qp, u);
1409 0 : }
1410 :
1411 :
1412 :
1413 39070656 : void FEMContext::elem_reinit(Real theta)
1414 : {
1415 : // Update the "time" variable of this context object
1416 39070656 : this->_update_time_from_system(theta);
1417 :
1418 : // Handle a moving element if necessary.
1419 39070656 : if (_mesh_sys)
1420 : {
1421 : // We assume that the ``default'' state
1422 : // of the mesh is its final, theta=1.0
1423 : // position, so we don't bother with
1424 : // mesh motion in that case.
1425 0 : if (theta != 1.0)
1426 : {
1427 : // FIXME - ALE is not threadsafe yet!
1428 0 : libmesh_assert_equal_to (libMesh::n_threads(), 1);
1429 :
1430 0 : elem_position_set(theta);
1431 : }
1432 0 : elem_fe_reinit();
1433 : }
1434 39070656 : }
1435 :
1436 :
1437 4215200 : void FEMContext::elem_side_reinit(Real theta)
1438 : {
1439 : // Update the "time" variable of this context object
1440 4215200 : this->_update_time_from_system(theta);
1441 :
1442 : // Handle a moving element if necessary
1443 4215200 : if (_mesh_sys)
1444 : {
1445 : // FIXME - not threadsafe yet!
1446 0 : elem_position_set(theta);
1447 0 : side_fe_reinit();
1448 : }
1449 4215200 : }
1450 :
1451 :
1452 0 : void FEMContext::elem_edge_reinit(Real theta)
1453 : {
1454 : // Update the "time" variable of this context object
1455 0 : this->_update_time_from_system(theta);
1456 :
1457 : // Handle a moving element if necessary
1458 0 : if (_mesh_sys)
1459 : {
1460 : // FIXME - not threadsafe yet!
1461 0 : elem_position_set(theta);
1462 0 : edge_fe_reinit();
1463 : }
1464 0 : }
1465 :
1466 :
1467 0 : void FEMContext::nonlocal_reinit(Real theta)
1468 : {
1469 : // Update the "time" variable of this context object
1470 0 : this->_update_time_from_system(theta);
1471 :
1472 : // We can reuse the Elem FE safely here.
1473 0 : elem_fe_reinit();
1474 0 : }
1475 :
1476 :
1477 39242438 : void FEMContext::elem_fe_reinit(const std::vector<Point> * const pts)
1478 : {
1479 : // Initialize all the interior FE objects on elem.
1480 : // Logging of FE::reinit is done in the FE functions
1481 : // We only reinit the FE objects for the current element
1482 : // dimension
1483 3517876 : const unsigned char dim = this->get_elem_dim();
1484 :
1485 3517876 : libmesh_assert( !_element_fe[dim].empty() );
1486 :
1487 82884452 : for (const auto & pr : _element_fe[dim])
1488 : {
1489 43642014 : if (this->has_elem())
1490 43642014 : pr.second->reinit(&(this->get_elem()), pts);
1491 : else
1492 : // If !this->has_elem(), then we assume we are dealing with a SCALAR variable
1493 0 : pr.second->reinit(nullptr);
1494 : }
1495 39242438 : }
1496 :
1497 :
1498 8409184 : void FEMContext::side_fe_reinit ()
1499 : {
1500 : // Initialize all the side FE objects on elem/side.
1501 : // Logging of FE::reinit is done in the FE functions
1502 : // We only reinit the FE objects for the current element
1503 : // dimension
1504 884732 : const unsigned char dim = this->get_elem_dim();
1505 :
1506 884732 : libmesh_assert( !_side_fe[dim].empty() );
1507 :
1508 17349955 : for (auto & pr : _side_fe[dim])
1509 8940771 : pr.second->reinit(&(this->get_elem()), this->get_side());
1510 8409184 : }
1511 :
1512 :
1513 :
1514 112614 : void FEMContext::edge_fe_reinit ()
1515 : {
1516 8130 : libmesh_assert_equal_to (this->get_elem_dim(), 3);
1517 :
1518 : // Initialize all the interior FE objects on elem/edge.
1519 : // Logging of FE::reinit is done in the FE functions
1520 263826 : for (auto & pr : _edge_fe)
1521 151212 : pr.second->edge_reinit(&(this->get_elem()), this->get_edge());
1522 112614 : }
1523 :
1524 :
1525 :
1526 576 : void FEMContext::elem_position_get()
1527 : {
1528 : // This is too expensive to call unless we've been asked to move the mesh
1529 0 : libmesh_assert (_mesh_sys);
1530 :
1531 : // This will probably break with threading when two contexts are
1532 : // operating on elements which share a node
1533 0 : libmesh_assert_equal_to (libMesh::n_threads(), 1);
1534 :
1535 : // If the coordinate data is in our own system, it's already
1536 : // been set up for us
1537 : // if (_mesh_sys == this->number())
1538 : // {
1539 576 : unsigned int n_nodes = this->get_elem().n_nodes();
1540 :
1541 : #ifndef NDEBUG
1542 0 : const unsigned char dim = this->get_elem_dim();
1543 :
1544 : // For simplicity we demand that mesh coordinates be stored
1545 : // in a format that allows a direct copy
1546 0 : libmesh_assert(this->get_mesh_x_var() == libMesh::invalid_uint ||
1547 : (this->get_element_fe(this->get_mesh_x_var(), dim)->get_fe_type().family
1548 : == FEMap::map_fe_type(this->get_elem()) &&
1549 : this->get_element_fe(this->get_mesh_x_var(), dim)->get_fe_type().order.get_order()
1550 : == this->get_elem().default_order()));
1551 0 : libmesh_assert(this->get_mesh_y_var() == libMesh::invalid_uint ||
1552 : (this->get_element_fe(this->get_mesh_y_var(), dim)->get_fe_type().family
1553 : == FEMap::map_fe_type(this->get_elem()) &&
1554 : this->get_element_fe(this->get_mesh_y_var(), dim)->get_fe_type().order.get_order()
1555 : == this->get_elem().default_order()));
1556 0 : libmesh_assert(this->get_mesh_z_var() == libMesh::invalid_uint ||
1557 : (this->get_element_fe(this->get_mesh_z_var(), dim)->get_fe_type().family
1558 : == FEMap::map_fe_type(this->get_elem()) &&
1559 : this->get_element_fe(this->get_mesh_z_var(), dim)->get_fe_type().order.get_order()
1560 : == this->get_elem().default_order()));
1561 : #endif
1562 :
1563 : // Get degree of freedom coefficients from point coordinates
1564 576 : if (this->get_mesh_x_var() != libMesh::invalid_uint)
1565 5184 : for (unsigned int i=0; i != n_nodes; ++i)
1566 4608 : (this->get_elem_solution(this->get_mesh_x_var()))(i) = this->get_elem().point(i)(0);
1567 :
1568 576 : if (this->get_mesh_y_var() != libMesh::invalid_uint)
1569 5184 : for (unsigned int i=0; i != n_nodes; ++i)
1570 4608 : (this->get_elem_solution(this->get_mesh_y_var()))(i) = this->get_elem().point(i)(1);
1571 :
1572 576 : if (this->get_mesh_z_var() != libMesh::invalid_uint)
1573 5184 : for (unsigned int i=0; i != n_nodes; ++i)
1574 4608 : (this->get_elem_solution(this->get_mesh_z_var()))(i) = this->get_elem().point(i)(2);
1575 : // }
1576 : // FIXME - If the coordinate data is not in our own system, someone
1577 : // had better get around to implementing that... - RHS
1578 : // else
1579 : // {
1580 : // libmesh_not_implemented();
1581 : // }
1582 576 : }
1583 :
1584 :
1585 :
1586 0 : void FEMContext::set_jacobian_tolerance(Real tol)
1587 : {
1588 0 : for (auto & m : _element_fe)
1589 0 : for (auto & pr : m)
1590 0 : pr.second->get_fe_map().set_jacobian_tolerance(tol);
1591 :
1592 0 : for (auto & m : _side_fe)
1593 0 : for (auto & pr : m)
1594 0 : pr.second->get_fe_map().set_jacobian_tolerance(tol);
1595 :
1596 0 : for (auto & pr : _edge_fe)
1597 0 : pr.second->get_fe_map().set_jacobian_tolerance(tol);
1598 0 : }
1599 :
1600 :
1601 :
1602 : // We can ignore the theta argument in the current use of this
1603 : // function, because elem_subsolutions will already have been set to
1604 : // the theta value.
1605 : //
1606 : // To enable loose mesh movement coupling things will need to change.
1607 23040 : void FEMContext::_do_elem_position_set(Real)
1608 : {
1609 : // This is too expensive to call unless we've been asked to move the mesh
1610 0 : libmesh_assert (_mesh_sys);
1611 :
1612 : // This will probably break with threading when two contexts are
1613 : // operating on elements which share a node
1614 0 : libmesh_assert_equal_to (libMesh::n_threads(), 1);
1615 :
1616 : // If the coordinate data is in our own system, it's already
1617 : // been set up for us, and we can ignore our input parameter theta
1618 : // if (_mesh_sys == this->number())
1619 : // {
1620 23040 : unsigned int n_nodes = this->get_elem().n_nodes();
1621 :
1622 : #ifndef NDEBUG
1623 0 : const unsigned char dim = this->get_elem_dim();
1624 :
1625 : // For simplicity we demand that mesh coordinates be stored
1626 : // in a format that allows a direct copy
1627 0 : libmesh_assert(this->get_mesh_x_var() == libMesh::invalid_uint ||
1628 : (this->get_element_fe(this->get_mesh_x_var(), dim)->get_fe_type().family
1629 : == FEMap::map_fe_type(this->get_elem()) &&
1630 : this->get_elem_solution(this->get_mesh_x_var()).size() == n_nodes));
1631 0 : libmesh_assert(this->get_mesh_y_var() == libMesh::invalid_uint ||
1632 : (this->get_element_fe(this->get_mesh_y_var(), dim)->get_fe_type().family
1633 : == FEMap::map_fe_type(this->get_elem()) &&
1634 : this->get_elem_solution(this->get_mesh_y_var()).size() == n_nodes));
1635 0 : libmesh_assert(this->get_mesh_z_var() == libMesh::invalid_uint ||
1636 : (this->get_element_fe(this->get_mesh_z_var(), dim)->get_fe_type().family
1637 : == FEMap::map_fe_type(this->get_elem()) &&
1638 : this->get_elem_solution(this->get_mesh_z_var()).size() == n_nodes));
1639 : #endif
1640 :
1641 : // Set the new point coordinates
1642 23040 : if (this->get_mesh_x_var() != libMesh::invalid_uint)
1643 207360 : for (unsigned int i=0; i != n_nodes; ++i)
1644 184320 : const_cast<Elem &>(this->get_elem()).point(i)(0) =
1645 163840 : libmesh_real(this->get_elem_solution(this->get_mesh_x_var())(i));
1646 :
1647 23040 : if (this->get_mesh_y_var() != libMesh::invalid_uint)
1648 207360 : for (unsigned int i=0; i != n_nodes; ++i)
1649 184320 : const_cast<Elem &>(this->get_elem()).point(i)(1) =
1650 163840 : libmesh_real(this->get_elem_solution(this->get_mesh_y_var())(i));
1651 :
1652 23040 : if (this->get_mesh_z_var() != libMesh::invalid_uint)
1653 207360 : for (unsigned int i=0; i != n_nodes; ++i)
1654 184320 : const_cast<Elem &>(this->get_elem()).point(i)(2) =
1655 163840 : libmesh_real(this->get_elem_solution(this->get_mesh_z_var())(i));
1656 : // }
1657 : // FIXME - If the coordinate data is not in our own system, someone
1658 : // had better get around to implementing that... - RHS
1659 : // else
1660 : // {
1661 : // libmesh_not_implemented();
1662 : // }
1663 23040 : }
1664 :
1665 :
1666 :
1667 :
1668 :
1669 : /*
1670 : void FEMContext::reinit(const FEMSystem & sys, Elem * e)
1671 : {
1672 : // Initialize our elem pointer, algebraic objects
1673 : this->pre_fe_reinit(e);
1674 :
1675 : // Moving the mesh may be necessary
1676 : // Reinitializing the FE objects is definitely necessary
1677 : this->elem_reinit(1.);
1678 : }
1679 : */
1680 :
1681 :
1682 :
1683 50595292 : void FEMContext::pre_fe_reinit(const System & sys, const Elem * e)
1684 : {
1685 50595292 : this->set_elem(e);
1686 :
1687 51207059 : if (algebraic_type() == CURRENT ||
1688 611767 : algebraic_type() == DOFS_ONLY)
1689 : {
1690 : // Initialize the per-element data for elem.
1691 47705305 : if (this->has_elem())
1692 47705305 : sys.get_dof_map().dof_indices (&(this->get_elem()), this->get_dof_indices());
1693 : else
1694 : // If !this->has_elem(), then we assume we are dealing with a SCALAR variable
1695 0 : sys.get_dof_map().dof_indices
1696 0 : (static_cast<Elem*>(nullptr), this->get_dof_indices());
1697 : }
1698 : #ifdef LIBMESH_ENABLE_AMR
1699 2895647 : else if (algebraic_type() == OLD ||
1700 5660 : algebraic_type() == OLD_DOFS_ONLY)
1701 : {
1702 : // Initialize the per-element data for elem.
1703 2889987 : if (this->has_elem())
1704 2889987 : sys.get_dof_map().old_dof_indices (&(this->get_elem()), this->get_dof_indices());
1705 : else
1706 : // If !this->has_elem(), then we assume we are dealing with a SCALAR variable
1707 0 : sys.get_dof_map().old_dof_indices
1708 0 : (static_cast<Elem*>(nullptr), this->get_dof_indices());
1709 : }
1710 : #endif // LIBMESH_ENABLE_AMR
1711 :
1712 : const unsigned int n_dofs = cast_int<unsigned int>
1713 9131695 : (this->get_dof_indices().size());
1714 4565839 : const unsigned int n_qoi = sys.n_qois();
1715 :
1716 55161131 : if (this->algebraic_type() != NONE &&
1717 97305922 : this->algebraic_type() != DOFS_ONLY &&
1718 4205450 : this->algebraic_type() != OLD_DOFS_ONLY)
1719 : {
1720 : // This also resizes elem_solution
1721 46286462 : if (_custom_solution == nullptr)
1722 43460254 : sys.current_local_solution->get(this->get_dof_indices(), this->get_elem_solution().get_values());
1723 : else
1724 2826208 : _custom_solution->get(this->get_dof_indices(), this->get_elem_solution().get_values());
1725 :
1726 46286462 : if (sys.use_fixed_solution)
1727 0 : this->get_elem_fixed_solution().resize(n_dofs);
1728 :
1729 : // Only make space for these if we're using DiffSystem
1730 : // This is assuming *only* DiffSystem is using elem_solution_rate/accel
1731 46286462 : const DifferentiableSystem * diff_system = dynamic_cast<const DifferentiableSystem *>(&sys);
1732 46286462 : if (diff_system)
1733 : {
1734 : // Now, we only need these if the solver is unsteady
1735 39767013 : if (!diff_system->get_time_solver().is_steady())
1736 : {
1737 32254786 : this->get_elem_solution_rate().resize(n_dofs);
1738 :
1739 : // We only need accel space if the TimeSolver is second order
1740 3201988 : const UnsteadySolver & time_solver = cast_ref<const UnsteadySolver &>(diff_system->get_time_solver());
1741 :
1742 35456812 : if (time_solver.time_order() >= 2 || !diff_system->get_second_order_vars().empty())
1743 829704 : this->get_elem_solution_accel().resize(n_dofs);
1744 : }
1745 : }
1746 :
1747 46286462 : if (algebraic_type() != OLD)
1748 : {
1749 : // These resize calls also zero out the residual and jacobian
1750 39506179 : this->get_elem_residual().resize(n_dofs);
1751 43460254 : if (this->_have_local_matrices)
1752 35598074 : this->get_elem_jacobian().resize(n_dofs, n_dofs);
1753 :
1754 43460254 : this->get_qoi_derivatives().resize(n_qoi);
1755 43460254 : this->_elem_qoi_subderivatives.resize(n_qoi);
1756 77587942 : for (std::size_t q=0; q != n_qoi; ++q)
1757 34127688 : (this->get_qoi_derivatives())[q].resize(n_dofs);
1758 : }
1759 : }
1760 :
1761 : // Initialize the per-variable data for elem.
1762 : {
1763 4565839 : unsigned int sub_dofs = 0;
1764 112358316 : for (auto i : make_range(sys.n_vars()))
1765 : {
1766 62432625 : if (algebraic_type() == CURRENT ||
1767 669601 : algebraic_type() == DOFS_ONLY)
1768 : {
1769 58651446 : if (this->has_elem())
1770 63889264 : sys.get_dof_map().dof_indices (&(this->get_elem()), this->get_dof_indices(i), i);
1771 : else
1772 : // If !this->has_elem(), then we assume we are dealing with a SCALAR variable
1773 0 : sys.get_dof_map().dof_indices
1774 0 : (static_cast<Elem*>(nullptr), this->get_dof_indices(i), i);
1775 : }
1776 : #ifdef LIBMESH_ENABLE_AMR
1777 3128458 : else if (algebraic_type() == OLD ||
1778 16880 : algebraic_type() == OLD_DOFS_ONLY)
1779 : {
1780 3111578 : if (this->has_elem())
1781 3111578 : sys.get_dof_map().old_dof_indices (&(this->get_elem()), this->get_dof_indices(i), i);
1782 : else
1783 : // If !this->has_elem(), then we assume we are dealing with a SCALAR variable
1784 0 : sys.get_dof_map().old_dof_indices
1785 0 : (static_cast<Elem*>(nullptr), this->get_dof_indices(i), i);
1786 : }
1787 : #endif // LIBMESH_ENABLE_AMR
1788 :
1789 67271759 : if (this->algebraic_type() != NONE &&
1790 119219445 : this->algebraic_type() != DOFS_ONLY &&
1791 5110058 : this->algebraic_type() != OLD_DOFS_ONLY)
1792 : {
1793 : const unsigned int n_dofs_var = cast_int<unsigned int>
1794 15279452 : (this->get_dof_indices(i).size());
1795 :
1796 :
1797 57626745 : if (!_active_vars ||
1798 4451366 : std::binary_search(_active_vars->begin(),
1799 : _active_vars->end(), i))
1800 : {
1801 15279534 : this->get_elem_solution(i).reposition
1802 5093178 : (sub_dofs, n_dofs_var);
1803 :
1804 : // Only make space for these if we're using DiffSystem
1805 : // This is assuming *only* DiffSystem is using elem_solution_rate/accel
1806 56867531 : const DifferentiableSystem * diff_system = dynamic_cast<const DifferentiableSystem *>(&sys);
1807 56867531 : if (diff_system)
1808 : {
1809 : // Now, we only need these if the solver is unsteady
1810 47931833 : if (!diff_system->get_time_solver().is_steady())
1811 : {
1812 11536452 : this->get_elem_solution_rate(i).reposition
1813 3845484 : (sub_dofs, n_dofs_var);
1814 :
1815 : // We only need accel space if the TimeSolver is second order
1816 3845484 : const UnsteadySolver & time_solver = cast_ref<const UnsteadySolver &>(diff_system->get_time_solver());
1817 :
1818 42982524 : if (time_solver.time_order() >= 2 || !diff_system->get_second_order_vars().empty())
1819 1108752 : this->get_elem_solution_accel(i).reposition
1820 369584 : (sub_dofs, n_dofs_var);
1821 : }
1822 : }
1823 :
1824 56867531 : if (sys.use_fixed_solution)
1825 0 : this->get_elem_fixed_solution(i).reposition
1826 0 : (sub_dofs, n_dofs_var);
1827 :
1828 56867531 : if (algebraic_type() != OLD)
1829 : {
1830 14517402 : this->get_elem_residual(i).reposition
1831 4839134 : (sub_dofs, n_dofs_var);
1832 :
1833 88171498 : for (std::size_t q=0; q != n_qoi; ++q)
1834 9320184 : this->get_qoi_derivatives(q,i).reposition
1835 3106728 : (sub_dofs, n_dofs_var);
1836 :
1837 53946166 : if (this->_have_local_matrices)
1838 : {
1839 68420787 : for (unsigned int j=0; j != i; ++j)
1840 : {
1841 : const unsigned int n_dofs_var_j =
1842 : cast_int<unsigned int>
1843 3221972 : (this->get_dof_indices(j).size());
1844 :
1845 4832958 : this->get_elem_jacobian(i,j).reposition
1846 3221972 : (sub_dofs, this->get_elem_residual(j).i_off(),
1847 : n_dofs_var, n_dofs_var_j);
1848 4832958 : this->get_elem_jacobian(j,i).reposition
1849 3221972 : (this->get_elem_residual(j).i_off(), sub_dofs,
1850 : n_dofs_var_j, n_dofs_var);
1851 : }
1852 13144740 : this->get_elem_jacobian(i,i).reposition
1853 4381580 : (sub_dofs, sub_dofs,
1854 : n_dofs_var,
1855 : n_dofs_var);
1856 : }
1857 : }
1858 : }
1859 :
1860 56867531 : sub_dofs += n_dofs_var;
1861 : }
1862 : }
1863 :
1864 13697534 : if (this->algebraic_type() != NONE &&
1865 8771289 : this->algebraic_type() != DOFS_ONLY &&
1866 13337128 : this->algebraic_type() != OLD &&
1867 3959732 : this->algebraic_type() != OLD_DOFS_ONLY)
1868 3954072 : libmesh_assert_equal_to (sub_dofs, n_dofs);
1869 : }
1870 :
1871 : // Now do the localization for the user requested vectors
1872 55161131 : if (this->algebraic_type() != NONE &&
1873 97305922 : this->algebraic_type() != DOFS_ONLY &&
1874 4205450 : this->algebraic_type() != OLD_DOFS_ONLY)
1875 : {
1876 4199790 : DiffContext::localized_vectors_iterator localized_vec_it = this->_localized_vectors.begin();
1877 4199790 : const DiffContext::localized_vectors_iterator localized_vec_end = this->_localized_vectors.end();
1878 :
1879 72321086 : for (; localized_vec_it != localized_vec_end; ++localized_vec_it)
1880 : {
1881 26034624 : const NumericVector<Number> & current_localized_vector = *localized_vec_it->first;
1882 2366784 : DenseVector<Number> & target_vector = localized_vec_it->second.first;
1883 :
1884 26034624 : current_localized_vector.get(this->get_dof_indices(), target_vector.get_values());
1885 :
1886 : // Initialize the per-variable data for elem.
1887 26034624 : unsigned int sub_dofs = 0;
1888 30768192 : auto init_localized_var_data = [this, localized_vec_it, &sub_dofs](unsigned int i)
1889 : {
1890 : const unsigned int n_dofs_var = cast_int<unsigned int>
1891 4733568 : (this->get_dof_indices(i).size());
1892 :
1893 : // This is redundant with earlier initialization, isn't it? - RHS
1894 : // sys.get_dof_map().dof_indices (&(this->get_elem()), this->get_dof_indices(i), i);
1895 :
1896 4733568 : localized_vec_it->second.second[i].reposition
1897 26034624 : (sub_dofs, n_dofs_var);
1898 :
1899 28401408 : sub_dofs += n_dofs_var;
1900 26034624 : };
1901 :
1902 26034624 : if (_active_vars)
1903 0 : for (auto v : *_active_vars)
1904 0 : init_localized_var_data(v);
1905 : else
1906 52069248 : for (auto v : make_range(sys.n_vars()))
1907 23667840 : init_localized_var_data(v);
1908 :
1909 2366784 : libmesh_assert_equal_to (sub_dofs, n_dofs);
1910 : }
1911 : }
1912 50595292 : }
1913 :
1914 50595292 : void FEMContext::set_elem( const Elem * e )
1915 : {
1916 50595292 : this->_elem = e;
1917 :
1918 : // If e is nullptr, we assume it's SCALAR and set _elem_dim to 0.
1919 50595292 : this->_elem_dim =
1920 50595292 : cast_int<unsigned char>(this->_elem ? this->_elem->dim() : 0);
1921 50595292 : }
1922 :
1923 43285856 : void FEMContext::_update_time_from_system(Real theta)
1924 : {
1925 : // Update the "time" variable based on the value of theta. For this
1926 : // to work, we need to know the value of deltat, a pointer to which is now
1927 : // stored by our parent DiffContext class. Note: get_deltat_value() will
1928 : // assert in debug mode if the requested pointer is nullptr.
1929 43285856 : const Real deltat = this->get_deltat_value();
1930 :
1931 43285856 : this->set_time(theta*(this->get_system_time() + deltat) + (1.-theta)*this->get_system_time());
1932 43285856 : }
1933 :
1934 :
1935 :
1936 : template<>
1937 : FEGenericBase<Real> *
1938 4500928 : FEMContext::cached_fe( const unsigned int elem_dim,
1939 : const FEType fe_type,
1940 : const int get_derivative_level ) const
1941 : {
1942 : #ifdef LIBMESH_ENABLE_INFINITE_ELEMENTS
1943 : const bool fe_needs_inf =
1944 1065694 : this->has_elem() && this->get_elem().infinite();
1945 : #endif
1946 :
1947 4816212 : if (!_real_fe ||
1948 1427065 : elem_dim != _real_fe->get_dim() ||
1949 5246138 : fe_type != _real_fe->get_fe_type() ||
1950 4422108 : get_derivative_level != _real_fe_derivative_level)
1951 : {
1952 78846 : _real_fe_derivative_level = get_derivative_level;
1953 :
1954 : _real_fe =
1955 : #ifdef LIBMESH_ENABLE_INFINITE_ELEMENTS
1956 29990 : fe_needs_inf ?
1957 : FEGenericBase<Real>::build_InfFE(elem_dim, fe_type) :
1958 : #endif
1959 133889 : FEGenericBase<Real>::build(elem_dim, fe_type);
1960 : }
1961 :
1962 : #ifdef LIBMESH_ENABLE_INFINITE_ELEMENTS
1963 1050699 : else if (fe_needs_inf && !_real_fe_is_inf)
1964 393 : _real_fe =
1965 637 : FEGenericBase<Real>::build_InfFE(elem_dim, fe_type);
1966 1050118 : else if (!fe_needs_inf && _real_fe_is_inf)
1967 : _real_fe =
1968 643 : FEGenericBase<Real>::build(elem_dim, fe_type);
1969 :
1970 1065694 : _real_fe_is_inf =
1971 1065694 : (this->has_elem() && this->get_elem().infinite());
1972 : #endif
1973 :
1974 4500928 : return _real_fe.get();
1975 : }
1976 :
1977 :
1978 : template<>
1979 : FEGenericBase<RealGradient> *
1980 64602 : FEMContext::cached_fe( const unsigned int elem_dim,
1981 : const FEType fe_type,
1982 : const int get_derivative_level ) const
1983 : {
1984 : #ifdef LIBMESH_ENABLE_INFINITE_ELEMENTS
1985 : const bool fe_needs_inf =
1986 13227 : this->has_elem() && this->get_elem().infinite();
1987 : #endif
1988 :
1989 65844 : if (!_real_grad_fe ||
1990 17097 : elem_dim != _real_grad_fe->get_dim() ||
1991 73344 : fe_type != _real_grad_fe->get_fe_type() ||
1992 61251 : get_derivative_level != _real_grad_fe_derivative_level)
1993 : {
1994 3351 : _real_grad_fe_derivative_level = get_derivative_level;
1995 :
1996 : _real_grad_fe =
1997 : #ifdef LIBMESH_ENABLE_INFINITE_ELEMENTS
1998 1002 : fe_needs_inf ?
1999 : FEGenericBase<RealGradient>::build_InfFE(elem_dim, fe_type) :
2000 : #endif
2001 5922 : FEGenericBase<RealGradient>::build(elem_dim, fe_type);
2002 : }
2003 :
2004 : #ifdef LIBMESH_ENABLE_INFINITE_ELEMENTS
2005 12726 : else if (fe_needs_inf && !_real_grad_fe_is_inf)
2006 0 : _real_grad_fe =
2007 0 : FEGenericBase<RealGradient>::build_InfFE(elem_dim, fe_type);
2008 12726 : else if (!fe_needs_inf && _real_grad_fe_is_inf)
2009 : _real_grad_fe =
2010 0 : FEGenericBase<RealGradient>::build(elem_dim, fe_type);
2011 :
2012 13227 : _real_grad_fe_is_inf =
2013 13227 : (this->has_elem() && this->get_elem().infinite());
2014 : #endif
2015 :
2016 64602 : return _real_grad_fe.get();
2017 : }
2018 :
2019 :
2020 :
2021 : template<typename OutputShape>
2022 : FEGenericBase<OutputShape> *
2023 4565530 : FEMContext::build_new_fe( const FEGenericBase<OutputShape>* fe,
2024 : const Point & p,
2025 : const Real tolerance,
2026 : const int get_derivative_level) const
2027 : {
2028 3868756 : FEType fe_type = fe->get_fe_type();
2029 :
2030 : // If we don't have an Elem to evaluate on, then the only functions
2031 : // we can sensibly evaluate are the scalar dofs which are the same
2032 : // everywhere.
2033 382147 : libmesh_assert(this->has_elem() || fe_type.family == SCALAR);
2034 :
2035 : #ifdef LIBMESH_ENABLE_AMR
2036 4565530 : const int add_p_level = fe->add_p_level_in_reinit();
2037 4925335 : if ((algebraic_type() == OLD) &&
2038 719636 : this->has_elem())
2039 : {
2040 4669708 : if (this->get_elem().p_refinement_flag() == Elem::JUST_REFINED)
2041 25572 : fe_type.order -= add_p_level;
2042 4003454 : else if (this->get_elem().p_refinement_flag() == Elem::JUST_COARSENED)
2043 152 : fe_type.order += add_p_level;
2044 : }
2045 : #endif // LIBMESH_ENABLE_AMR
2046 :
2047 4565530 : const unsigned int elem_dim = this->has_elem() ? this->get_elem().dim() : 0;
2048 :
2049 764320 : FEGenericBase<OutputShape>* fe_new =
2050 3801210 : cached_fe<OutputShape>(elem_dim, fe_type, get_derivative_level);
2051 : #ifdef LIBMESH_ENABLE_AMR
2052 382147 : fe_new->add_p_level_in_reinit(add_p_level);
2053 : #endif // LIBMESH_ENABLE_AMR
2054 :
2055 : // Map the physical co-ordinates to the master co-ordinates using the inverse_map from fe_interface.h
2056 : // Build a vector of point co-ordinates to send to reinit
2057 4565530 : Point master_point = this->has_elem() ?
2058 4565530 : FEMap::inverse_map (elem_dim, &this->get_elem(), p, tolerance) :
2059 : Point(0);
2060 :
2061 4565530 : std::vector<Point> coor(1, master_point);
2062 :
2063 4565530 : switch (get_derivative_level)
2064 : {
2065 10352 : case -1:
2066 10352 : fe_new->get_phi();
2067 10352 : fe_new->get_dphi();
2068 : #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
2069 10352 : fe_new->get_d2phi();
2070 : #endif
2071 20704 : fe_new->get_curl_phi();
2072 10352 : break;
2073 350949 : case 0:
2074 350949 : fe_new->get_phi();
2075 350949 : break;
2076 20843 : case 1:
2077 20843 : fe_new->get_dphi();
2078 20843 : break;
2079 3 : case 2:
2080 : #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
2081 3 : fe_new->get_d2phi();
2082 : #else
2083 : // here a different configuration is required.
2084 : libmesh_not_implemented();
2085 : #endif
2086 3 : break;
2087 0 : case 3:
2088 0 : fe_new->get_curl_phi();
2089 0 : break;
2090 0 : default:
2091 0 : libmesh_error();
2092 : }
2093 :
2094 : // Reinitialize the element and compute the shape function values at coor
2095 4565530 : if (this->has_elem())
2096 4565530 : fe_new->reinit (&this->get_elem(), &coor);
2097 : else
2098 : // If !this->has_elem(), then we assume we are dealing with a SCALAR variable
2099 0 : fe_new->reinit (nullptr, &coor);
2100 :
2101 4947677 : return fe_new;
2102 : }
2103 :
2104 :
2105 :
2106 :
2107 :
2108 : // Instantiate member function templates
2109 : template LIBMESH_EXPORT void FEMContext::interior_value<Number>(unsigned int, unsigned int, Number &) const;
2110 : template LIBMESH_EXPORT void FEMContext::interior_values<Number>(unsigned int, const NumericVector<Number> &,
2111 : std::vector<Number> &) const;
2112 : template LIBMESH_EXPORT void FEMContext::interior_value<Gradient>(unsigned int, unsigned int, Gradient &) const;
2113 : template LIBMESH_EXPORT void FEMContext::interior_values<Gradient>(unsigned int, const NumericVector<Number> &,
2114 : std::vector<Gradient> &) const;
2115 :
2116 : template LIBMESH_EXPORT void FEMContext::interior_gradient<Gradient>(unsigned int, unsigned int, Gradient &) const;
2117 : template LIBMESH_EXPORT void FEMContext::interior_gradients<Gradient>(unsigned int, const NumericVector<Number> &,
2118 : std::vector<Gradient> &) const;
2119 : template LIBMESH_EXPORT void FEMContext::interior_gradient<Tensor>(unsigned int, unsigned int, Tensor &) const;
2120 : template LIBMESH_EXPORT void FEMContext::interior_gradients<Tensor>(unsigned int, const NumericVector<Number> &,
2121 : std::vector<Tensor> &) const;
2122 :
2123 : #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
2124 : template LIBMESH_EXPORT void FEMContext::interior_hessian<Tensor>(unsigned int, unsigned int, Tensor &) const;
2125 : template LIBMESH_EXPORT void FEMContext::interior_hessians<Tensor>(unsigned int, const NumericVector<Number> &,
2126 : std::vector<Tensor> &) const;
2127 : //FIXME: Not everything is implemented yet for second derivatives of RealGradients
2128 : //template LIBMESH_EXPORT void FEMContext::interior_hessian<??>(unsigned int, unsigned int, ??&) const;
2129 : //template LIBMESH_EXPORT void FEMContext::interior_hessians<??>(unsigned int, const NumericVector<Number> &,
2130 : // std::vector<??> &) const;
2131 : #endif
2132 :
2133 : template LIBMESH_EXPORT void FEMContext::interior_curl<Gradient>(unsigned int, unsigned int, Gradient &) const;
2134 :
2135 : template LIBMESH_EXPORT void FEMContext::interior_div<Number>(unsigned int, unsigned int, Number &) const;
2136 :
2137 : template LIBMESH_EXPORT void FEMContext::side_value<Number>(unsigned int, unsigned int, Number &) const;
2138 : template LIBMESH_EXPORT void FEMContext::side_value<Gradient>(unsigned int, unsigned int, Gradient &) const;
2139 : template LIBMESH_EXPORT void FEMContext::side_values<Number>(unsigned int, const NumericVector<Number> &,
2140 : std::vector<Number> &) const;
2141 : template LIBMESH_EXPORT void FEMContext::side_values<Gradient>(unsigned int, const NumericVector<Number> &,
2142 : std::vector<Gradient> &) const;
2143 :
2144 : template LIBMESH_EXPORT void FEMContext::side_gradient<Gradient>(unsigned int, unsigned int, Gradient &) const;
2145 : template LIBMESH_EXPORT void FEMContext::side_gradients<Gradient>(unsigned int, const NumericVector<Number> &,
2146 : std::vector<Gradient> &) const;
2147 : template LIBMESH_EXPORT void FEMContext::side_gradient<Tensor>(unsigned int, unsigned int, Tensor &) const;
2148 : template LIBMESH_EXPORT void FEMContext::side_gradients<Tensor>(unsigned int, const NumericVector<Number> &,
2149 : std::vector<Tensor> &) const;
2150 :
2151 :
2152 : #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
2153 : template LIBMESH_EXPORT void FEMContext::side_hessian<Tensor>(unsigned int, unsigned int, Tensor &) const;
2154 : template LIBMESH_EXPORT void FEMContext::side_hessians<Tensor>(unsigned int, const NumericVector<Number> &,
2155 : std::vector<Tensor> &) const;
2156 : //FIXME: Not everything is implemented yet for second derivatives of RealGradients
2157 : //template LIBMESH_EXPORT void FEMContext::side_hessian<??>(unsigned int, unsigned int,
2158 : // ??&) const;
2159 : //template LIBMESH_EXPORT void FEMContext::side_hessians<??>(unsigned int, const NumericVector<Number> &,
2160 : // std::vector<??> &) const;
2161 : #endif
2162 :
2163 : template LIBMESH_EXPORT void FEMContext::point_value<Number>(unsigned int, const Point &, Number &, const Real) const;
2164 : template LIBMESH_EXPORT void FEMContext::point_value<Gradient>(unsigned int, const Point &, Gradient &, const Real) const;
2165 :
2166 : template LIBMESH_EXPORT void FEMContext::point_gradient<Gradient>(unsigned int, const Point &, Gradient &, const Real) const;
2167 : template LIBMESH_EXPORT void FEMContext::point_gradient<Tensor>(unsigned int, const Point &, Tensor &, const Real) const;
2168 :
2169 : #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
2170 : template LIBMESH_EXPORT void FEMContext::point_hessian<Tensor>(unsigned int, const Point &, Tensor &, const Real) const;
2171 : //FIXME: Not everything is implemented yet for second derivatives of RealGradients
2172 : //template LIBMESH_EXPORT void FEMContext::point_hessian<??>(unsigned int, const Point &, ??&) const;
2173 : #endif
2174 :
2175 : template LIBMESH_EXPORT void FEMContext::point_curl<Gradient>(unsigned int, const Point &, Gradient &, const Real) const;
2176 :
2177 : template LIBMESH_EXPORT void FEMContext::fixed_interior_value<Number>(unsigned int, unsigned int, Number &) const;
2178 : template LIBMESH_EXPORT void FEMContext::fixed_interior_value<Gradient>(unsigned int, unsigned int, Gradient &) const;
2179 :
2180 : template LIBMESH_EXPORT void FEMContext::fixed_interior_gradient<Gradient>(unsigned int, unsigned int, Gradient &) const;
2181 : template LIBMESH_EXPORT void FEMContext::fixed_interior_gradient<Tensor>(unsigned int, unsigned int, Tensor &) const;
2182 :
2183 : #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
2184 : template LIBMESH_EXPORT void FEMContext::fixed_interior_hessian<Tensor>(unsigned int, unsigned int, Tensor &) const;
2185 : //FIXME: Not everything is implemented yet for second derivatives of RealGradients
2186 : //template LIBMESH_EXPORT void FEMContext::fixed_interior_hessian<??>(unsigned int, unsigned int, ??&) const;
2187 : #endif
2188 :
2189 : template LIBMESH_EXPORT void FEMContext::fixed_side_value<Number>(unsigned int, unsigned int, Number &) const;
2190 : template LIBMESH_EXPORT void FEMContext::fixed_side_value<Gradient>(unsigned int, unsigned int, Gradient &) const;
2191 :
2192 : template LIBMESH_EXPORT void FEMContext::fixed_side_gradient<Gradient>(unsigned int, unsigned int, Gradient &) const;
2193 : template LIBMESH_EXPORT void FEMContext::fixed_side_gradient<Tensor>(unsigned int, unsigned int, Tensor &) const;
2194 :
2195 : #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
2196 : template LIBMESH_EXPORT void FEMContext::fixed_side_hessian<Tensor>(unsigned int, unsigned int, Tensor &) const;
2197 : //FIXME: Not everything is implemented yet for second derivatives of RealGradients
2198 : //template LIBMESH_EXPORT void FEMContext::fixed_side_hessian<??>(unsigned int, unsigned int, ??&) const;
2199 : #endif
2200 :
2201 : template LIBMESH_EXPORT void FEMContext::fixed_point_value<Number>(unsigned int, const Point &, Number &, const Real) const;
2202 : template LIBMESH_EXPORT void FEMContext::fixed_point_value<Gradient>(unsigned int, const Point &, Gradient &, const Real) const;
2203 :
2204 : template LIBMESH_EXPORT void FEMContext::fixed_point_gradient<Gradient>(unsigned int, const Point &, Gradient &, const Real) const;
2205 : template LIBMESH_EXPORT void FEMContext::fixed_point_gradient<Tensor>(unsigned int, const Point &, Tensor &, const Real) const;
2206 :
2207 : #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
2208 : template LIBMESH_EXPORT void FEMContext::fixed_point_hessian<Tensor>(unsigned int, const Point &, Tensor &, const Real) const;
2209 : //FIXME: Not everything is implemented yet for second derivatives of RealGradients
2210 : //template LIBMESH_EXPORT void FEMContext::fixed_point_hessian<??>(unsigned int, const Point &, ??&) const;
2211 : #endif
2212 :
2213 : template LIBMESH_EXPORT void FEMContext::interior_rate<Number>(unsigned int, unsigned int, Number &) const;
2214 : template LIBMESH_EXPORT void FEMContext::interior_rate<Gradient>(unsigned int, unsigned int, Gradient &) const;
2215 :
2216 : template LIBMESH_EXPORT void FEMContext::interior_rate_gradient<Gradient>(unsigned int, unsigned int, Gradient &) const;
2217 : template LIBMESH_EXPORT void FEMContext::interior_rate_gradient<Tensor>(unsigned int, unsigned int, Tensor &) const;
2218 :
2219 : template LIBMESH_EXPORT void FEMContext::side_rate<Number>(unsigned int, unsigned int, Number &) const;
2220 : template LIBMESH_EXPORT void FEMContext::side_rate<Gradient>(unsigned int, unsigned int, Gradient &) const;
2221 :
2222 : template LIBMESH_EXPORT void FEMContext::interior_accel<Number>(unsigned int, unsigned int, Number &) const;
2223 : template LIBMESH_EXPORT void FEMContext::interior_accel<Gradient>(unsigned int, unsigned int, Gradient &) const;
2224 :
2225 : template LIBMESH_EXPORT void FEMContext::side_accel<Number>(unsigned int, unsigned int, Number &) const;
2226 : template LIBMESH_EXPORT void FEMContext::side_accel<Gradient>(unsigned int, unsigned int, Gradient &) const;
2227 :
2228 : template LIBMESH_EXPORT FEGenericBase<Real> *
2229 : FEMContext::build_new_fe(const FEGenericBase<Real>*,
2230 : const Point &,
2231 : const Real,
2232 : const int) const;
2233 :
2234 : template LIBMESH_EXPORT FEGenericBase<RealGradient> *
2235 : FEMContext::build_new_fe(const FEGenericBase<RealGradient>*,
2236 : const Point &,
2237 : const Real,
2238 : const int) const;
2239 :
2240 : } // namespace libMesh
|