Line data Source code
1 : //* This file is part of the MOOSE framework
2 : //* https://mooseframework.inl.gov
3 : //*
4 : //* All rights reserved, see COPYRIGHT for full restrictions
5 : //* https://github.com/idaholab/moose/blob/master/COPYRIGHT
6 : //*
7 : //* Licensed under LGPL 2.1, please see LICENSE for details
8 : //* https://www.gnu.org/licenses/lgpl-2.1.html
9 :
10 : #include "Assembly.h"
11 :
12 : // MOOSE includes
13 : #include "SubProblem.h"
14 : #include "ArbitraryQuadrature.h"
15 : #include "SystemBase.h"
16 : #include "MooseTypes.h"
17 : #include "MooseMesh.h"
18 : #include "MooseVariableFE.h"
19 : #include "MooseVariableScalar.h"
20 : #include "XFEMInterface.h"
21 : #include "DisplacedSystem.h"
22 : #include "MooseMeshUtils.h"
23 :
24 : // libMesh
25 : #include "libmesh/coupling_matrix.h"
26 : #include "libmesh/dof_map.h"
27 : #include "libmesh/elem.h"
28 : #include "libmesh/equation_systems.h"
29 : #include "libmesh/fe_interface.h"
30 : #include "libmesh/node.h"
31 : #include "libmesh/quadrature_gauss.h"
32 : #include "libmesh/sparse_matrix.h"
33 : #include "libmesh/tensor_value.h"
34 : #include "libmesh/vector_value.h"
35 : #include "libmesh/fe.h"
36 :
37 : #include <algorithm>
38 :
39 : using namespace libMesh;
40 :
41 : template <typename P, typename C>
42 : void
43 1807666843 : coordTransformFactor(const SubProblem & s,
44 : const SubdomainID sub_id,
45 : const P & point,
46 : C & factor,
47 : const SubdomainID neighbor_sub_id)
48 : {
49 1807666843 : coordTransformFactor(s.mesh(), sub_id, point, factor, neighbor_sub_id);
50 1807666843 : }
51 :
52 : template <typename P, typename C>
53 : void
54 1810930003 : coordTransformFactor(const MooseMesh & mesh,
55 : const SubdomainID sub_id,
56 : const P & point,
57 : C & factor,
58 : const SubdomainID libmesh_dbg_var(neighbor_sub_id))
59 : {
60 : mooseAssert(neighbor_sub_id != libMesh::Elem::invalid_subdomain_id
61 : ? mesh.getCoordSystem(sub_id) == mesh.getCoordSystem(neighbor_sub_id)
62 : : true,
63 : "Coordinate systems must be the same between element and neighbor");
64 1810930003 : const auto coord_type = mesh.getCoordSystem(sub_id);
65 :
66 1810930003 : if (coord_type == Moose::COORD_RZ)
67 : {
68 3487480 : if (mesh.usingGeneralAxisymmetricCoordAxes())
69 : {
70 1041955 : const auto & axis = mesh.getGeneralAxisymmetricCoordAxis(sub_id);
71 1041955 : MooseMeshUtils::coordTransformFactorRZGeneral(point, axis, factor);
72 : }
73 : else
74 2445525 : MooseMeshUtils::coordTransformFactor(
75 : point, factor, coord_type, mesh.getAxisymmetricRadialCoord());
76 : }
77 : else
78 1807442523 : MooseMeshUtils::coordTransformFactor(point, factor, coord_type, libMesh::invalid_uint);
79 1810930003 : }
80 :
81 72852 : Assembly::Assembly(SystemBase & sys, THREAD_ID tid)
82 72852 : : _sys(sys),
83 145704 : _subproblem(_sys.subproblem()),
84 72852 : _displaced(dynamic_cast<DisplacedSystem *>(&sys) ? true : false),
85 72852 : _nonlocal_cm(_subproblem.nonlocalCouplingMatrix(_sys.number())),
86 72852 : _computing_residual(_subproblem.currentlyComputingResidual()),
87 72852 : _computing_jacobian(_subproblem.currentlyComputingJacobian()),
88 72852 : _computing_residual_and_jacobian(_subproblem.currentlyComputingResidualAndJacobian()),
89 72852 : _dof_map(_sys.dofMap()),
90 72852 : _tid(tid),
91 72852 : _mesh(sys.mesh()),
92 72852 : _mesh_dimension(_mesh.dimension()),
93 72852 : _helper_type(_mesh.hasSecondOrderElements() ? SECOND : FIRST, LAGRANGE),
94 72852 : _user_added_fe_of_helper_type(false),
95 72852 : _user_added_fe_face_of_helper_type(false),
96 72852 : _user_added_fe_face_neighbor_of_helper_type(false),
97 72852 : _user_added_fe_neighbor_of_helper_type(false),
98 72852 : _user_added_fe_lower_of_helper_type(false),
99 72852 : _building_helpers(false),
100 72852 : _current_qrule(nullptr),
101 72852 : _current_qrule_volume(nullptr),
102 72852 : _current_qrule_arbitrary(nullptr),
103 72852 : _coord_type(Moose::COORD_XYZ),
104 72852 : _current_qrule_face(nullptr),
105 72852 : _current_qface_arbitrary(nullptr),
106 72852 : _current_qrule_neighbor(nullptr),
107 72852 : _need_JxW_neighbor(false),
108 72852 : _qrule_msm(nullptr),
109 72852 : _custom_mortar_qrule(false),
110 72852 : _current_qrule_lower(nullptr),
111 :
112 72852 : _current_elem(nullptr),
113 72852 : _current_elem_volume(0),
114 72852 : _current_side(0),
115 72852 : _current_side_elem(nullptr),
116 72852 : _current_side_volume(0),
117 72852 : _current_neighbor_elem(nullptr),
118 72852 : _current_neighbor_side(0),
119 72852 : _current_neighbor_side_elem(nullptr),
120 72852 : _need_neighbor_elem_volume(false),
121 72852 : _current_neighbor_volume(0),
122 72852 : _current_node(nullptr),
123 72852 : _current_neighbor_node(nullptr),
124 72852 : _current_elem_volume_computed(false),
125 72852 : _current_side_volume_computed(false),
126 :
127 72852 : _current_lower_d_elem(nullptr),
128 72852 : _current_neighbor_lower_d_elem(nullptr),
129 72852 : _need_lower_d_elem_volume(false),
130 72852 : _need_neighbor_lower_d_elem_volume(false),
131 72852 : _need_dual(false),
132 :
133 72852 : _residual_vector_tags(_subproblem.getVectorTags(Moose::VECTOR_TAG_RESIDUAL)),
134 145704 : _cached_residual_values(2), // The 2 is for TIME and NONTIME
135 145704 : _cached_residual_rows(2), // The 2 is for TIME and NONTIME
136 72852 : _max_cached_residuals(0),
137 72852 : _max_cached_jacobians(0),
138 :
139 72852 : _block_diagonal_matrix(false),
140 72852 : _calculate_xyz(false),
141 72852 : _calculate_face_xyz(false),
142 72852 : _calculate_curvatures(false),
143 72852 : _calculate_ad_coord(false),
144 291408 : _have_p_refinement(false)
145 : {
146 72852 : const Order helper_order = _mesh.hasSecondOrderElements() ? SECOND : FIRST;
147 72852 : _building_helpers = true;
148 : // Build fe's for the helpers
149 72852 : buildFE(FEType(helper_order, LAGRANGE));
150 72852 : buildFaceFE(FEType(helper_order, LAGRANGE));
151 72852 : buildNeighborFE(FEType(helper_order, LAGRANGE));
152 72852 : buildFaceNeighborFE(FEType(helper_order, LAGRANGE));
153 72852 : buildLowerDFE(FEType(helper_order, LAGRANGE));
154 72852 : _building_helpers = false;
155 :
156 : // Build an FE helper object for this type for each dimension up to the dimension of the current
157 : // mesh
158 285263 : for (unsigned int dim = 0; dim <= _mesh_dimension; dim++)
159 : {
160 212411 : _holder_fe_helper[dim] = _fe[dim][FEType(helper_order, LAGRANGE)];
161 212411 : _holder_fe_face_helper[dim] = _fe_face[dim][FEType(helper_order, LAGRANGE)];
162 212411 : _holder_fe_face_neighbor_helper[dim] = _fe_face_neighbor[dim][FEType(helper_order, LAGRANGE)];
163 212411 : _holder_fe_neighbor_helper[dim] = _fe_neighbor[dim][FEType(helper_order, LAGRANGE)];
164 : }
165 :
166 212411 : for (unsigned int dim = 0; dim < _mesh_dimension; dim++)
167 139559 : _holder_fe_lower_helper[dim] = _fe_lower[dim][FEType(helper_order, LAGRANGE)];
168 :
169 : // request phi, dphi, xyz, JxW, etc. data
170 72852 : helpersRequestData();
171 :
172 : // For 3D mortar, mortar segments are always TRI3 elements so we want FIRST LAGRANGE regardless
173 : // of discretization
174 72852 : _fe_msm = (_mesh_dimension == 2)
175 145704 : ? FEGenericBase<Real>::build(_mesh_dimension - 1, FEType(helper_order, LAGRANGE))
176 72852 : : FEGenericBase<Real>::build(_mesh_dimension - 1, FEType(FIRST, LAGRANGE));
177 : // This FE object should not take part in p-refinement
178 72852 : _fe_msm->add_p_level_in_reinit(false);
179 72852 : _JxW_msm = &_fe_msm->get_JxW();
180 : // Prerequest xyz so that it is computed for _fe_msm so that it can be used for calculating
181 : // _coord_msm
182 72852 : _fe_msm->get_xyz();
183 :
184 72852 : _extra_elem_ids.resize(_mesh.getMesh().n_elem_integers() + 1);
185 72852 : _neighbor_extra_elem_ids.resize(_mesh.getMesh().n_elem_integers() + 1);
186 72852 : }
187 :
188 137198 : Assembly::~Assembly()
189 : {
190 269369 : for (unsigned int dim = 0; dim <= _mesh_dimension; dim++)
191 487943 : for (auto & it : _fe[dim])
192 287173 : delete it.second;
193 :
194 269369 : for (unsigned int dim = 0; dim <= _mesh_dimension; dim++)
195 487943 : for (auto & it : _fe_face[dim])
196 287173 : delete it.second;
197 :
198 269369 : for (unsigned int dim = 0; dim <= _mesh_dimension; dim++)
199 487943 : for (auto & it : _fe_neighbor[dim])
200 287173 : delete it.second;
201 :
202 269369 : for (unsigned int dim = 0; dim <= _mesh_dimension; dim++)
203 487943 : for (auto & it : _fe_face_neighbor[dim])
204 287173 : delete it.second;
205 :
206 200770 : for (unsigned int dim = 0; dim <= _mesh_dimension - 1; dim++)
207 315435 : for (auto & it : _fe_lower[dim])
208 183264 : delete it.second;
209 :
210 269369 : for (unsigned int dim = 0; dim <= _mesh_dimension; dim++)
211 204329 : for (auto & it : _vector_fe[dim])
212 3559 : delete it.second;
213 :
214 269369 : for (unsigned int dim = 0; dim <= _mesh_dimension; dim++)
215 204329 : for (auto & it : _vector_fe_face[dim])
216 3559 : delete it.second;
217 :
218 269369 : for (unsigned int dim = 0; dim <= _mesh_dimension; dim++)
219 204329 : for (auto & it : _vector_fe_neighbor[dim])
220 3559 : delete it.second;
221 :
222 269369 : for (unsigned int dim = 0; dim <= _mesh_dimension; dim++)
223 204329 : for (auto & it : _vector_fe_face_neighbor[dim])
224 3559 : delete it.second;
225 :
226 200770 : for (unsigned int dim = 0; dim <= _mesh_dimension - 1; dim++)
227 134126 : for (auto & it : _vector_fe_lower[dim])
228 1955 : delete it.second;
229 :
230 149997 : for (auto & it : _ad_grad_phi_data)
231 81398 : it.second.release();
232 :
233 70017 : for (auto & it : _ad_vector_grad_phi_data)
234 1418 : it.second.release();
235 :
236 145483 : for (auto & it : _ad_grad_phi_data_face)
237 76884 : it.second.release();
238 :
239 70017 : for (auto & it : _ad_vector_grad_phi_data_face)
240 1418 : it.second.release();
241 :
242 68599 : _current_physical_points.release();
243 :
244 68599 : _coord.release();
245 68599 : _coord_neighbor.release();
246 68599 : _coord_msm.release();
247 :
248 68599 : _ad_JxW.release();
249 68599 : _ad_q_points.release();
250 68599 : _ad_JxW_face.release();
251 68599 : _ad_normals.release();
252 68599 : _ad_q_points_face.release();
253 68599 : _curvatures.release();
254 68599 : _ad_curvatures.release();
255 68599 : _ad_coord.release();
256 :
257 68599 : delete _qrule_msm;
258 137198 : }
259 :
260 : const MooseArray<Real> &
261 107 : Assembly::JxWNeighbor() const
262 : {
263 107 : _need_JxW_neighbor = true;
264 107 : return _current_JxW_neighbor;
265 : }
266 :
267 : void
268 464414 : Assembly::buildFE(FEType type) const
269 : {
270 464414 : if (!_building_helpers && type == _helper_type)
271 208869 : _user_added_fe_of_helper_type = true;
272 :
273 464414 : if (!_fe_shape_data[type])
274 103187 : _fe_shape_data[type] = std::make_unique<FEShapeData>();
275 :
276 : // Build an FE object for this type for each dimension up to the dimension of the current mesh
277 1859384 : for (unsigned int dim = 0; dim <= _mesh_dimension; dim++)
278 : {
279 1394970 : if (!_fe[dim][type])
280 303391 : _fe[dim][type] = FEGenericBase<Real>::build(dim, type).release();
281 :
282 1394970 : _fe[dim][type]->get_phi();
283 1394970 : _fe[dim][type]->get_dphi();
284 : // Pre-request xyz. We have always computed xyz, but due to
285 : // recent optimizations in libmesh, we now need to explicity
286 : // request it, since apps (Yak) may rely on it being computed.
287 1394970 : _fe[dim][type]->get_xyz();
288 1394970 : if (_need_second_derivative.count(type))
289 72340 : _fe[dim][type]->get_d2phi();
290 : }
291 464414 : }
292 :
293 : void
294 439785 : Assembly::buildFaceFE(FEType type) const
295 : {
296 439785 : if (!_building_helpers && type == _helper_type)
297 203684 : _user_added_fe_face_of_helper_type = true;
298 :
299 439785 : if (!_fe_shape_data_face[type])
300 103187 : _fe_shape_data_face[type] = std::make_unique<FEShapeData>();
301 :
302 : // Build an FE object for this type for each dimension up to the dimension of the current mesh
303 1760808 : for (unsigned int dim = 0; dim <= _mesh_dimension; dim++)
304 : {
305 1321023 : if (!_fe_face[dim][type])
306 303391 : _fe_face[dim][type] = FEGenericBase<Real>::build(dim, type).release();
307 :
308 1321023 : _fe_face[dim][type]->get_phi();
309 1321023 : _fe_face[dim][type]->get_dphi();
310 1321023 : if (_need_second_derivative.count(type))
311 12838 : _fe_face[dim][type]->get_d2phi();
312 : }
313 439785 : }
314 :
315 : void
316 435549 : Assembly::buildNeighborFE(FEType type) const
317 : {
318 435549 : if (!_building_helpers && type == _helper_type)
319 203572 : _user_added_fe_neighbor_of_helper_type = true;
320 :
321 435549 : if (!_fe_shape_data_neighbor[type])
322 103187 : _fe_shape_data_neighbor[type] = std::make_unique<FEShapeData>();
323 :
324 : // Build an FE object for this type for each dimension up to the dimension of the current mesh
325 1743851 : for (unsigned int dim = 0; dim <= _mesh_dimension; dim++)
326 : {
327 1308302 : if (!_fe_neighbor[dim][type])
328 303391 : _fe_neighbor[dim][type] = FEGenericBase<Real>::build(dim, type).release();
329 :
330 1308302 : _fe_neighbor[dim][type]->get_phi();
331 1308302 : _fe_neighbor[dim][type]->get_dphi();
332 1308302 : if (_need_second_derivative_neighbor.count(type))
333 117 : _fe_neighbor[dim][type]->get_d2phi();
334 : }
335 435549 : }
336 :
337 : void
338 435549 : Assembly::buildFaceNeighborFE(FEType type) const
339 : {
340 435549 : if (!_building_helpers && type == _helper_type)
341 203572 : _user_added_fe_face_neighbor_of_helper_type = true;
342 :
343 435549 : if (!_fe_shape_data_face_neighbor[type])
344 103187 : _fe_shape_data_face_neighbor[type] = std::make_unique<FEShapeData>();
345 :
346 : // Build an FE object for this type for each dimension up to the dimension of the current mesh
347 1743851 : for (unsigned int dim = 0; dim <= _mesh_dimension; dim++)
348 : {
349 1308302 : if (!_fe_face_neighbor[dim][type])
350 303391 : _fe_face_neighbor[dim][type] = FEGenericBase<Real>::build(dim, type).release();
351 :
352 1308302 : _fe_face_neighbor[dim][type]->get_phi();
353 1308302 : _fe_face_neighbor[dim][type]->get_dphi();
354 1308302 : if (_need_second_derivative_neighbor.count(type))
355 117 : _fe_face_neighbor[dim][type]->get_d2phi();
356 : }
357 435549 : }
358 :
359 : void
360 769828 : Assembly::buildLowerDFE(FEType type) const
361 : {
362 769828 : if (!_building_helpers && type == _helper_type)
363 406604 : _user_added_fe_lower_of_helper_type = true;
364 :
365 769828 : if (!_fe_shape_data_lower[type])
366 98881 : _fe_shape_data_lower[type] = std::make_unique<FEShapeData>();
367 :
368 : // Build an FE object for this type for each dimension up to the dimension of
369 : // the current mesh minus one (because this is for lower-dimensional
370 : // elements!)
371 2331375 : for (unsigned int dim = 0; dim <= _mesh_dimension - 1; dim++)
372 : {
373 1561547 : if (!_fe_lower[dim][type])
374 193541 : _fe_lower[dim][type] = FEGenericBase<Real>::build(dim, type).release();
375 :
376 1561547 : _fe_lower[dim][type]->get_phi();
377 1561547 : _fe_lower[dim][type]->get_dphi();
378 1561547 : if (_need_second_derivative.count(type))
379 0 : _fe_lower[dim][type]->get_d2phi();
380 : }
381 769828 : }
382 :
383 : void
384 540 : Assembly::buildLowerDDualFE(FEType type) const
385 : {
386 540 : if (!_fe_shape_data_dual_lower[type])
387 135 : _fe_shape_data_dual_lower[type] = std::make_unique<FEShapeData>();
388 :
389 : // Build an FE object for this type for each dimension up to the dimension of
390 : // the current mesh minus one (because this is for lower-dimensional
391 : // elements!)
392 1672 : for (unsigned int dim = 0; dim <= _mesh_dimension - 1; dim++)
393 : {
394 1132 : if (!_fe_lower[dim][type])
395 0 : _fe_lower[dim][type] = FEGenericBase<Real>::build(dim, type).release();
396 :
397 1132 : _fe_lower[dim][type]->get_dual_phi();
398 1132 : _fe_lower[dim][type]->get_dual_dphi();
399 1132 : if (_need_second_derivative.count(type))
400 0 : _fe_lower[dim][type]->get_dual_d2phi();
401 : }
402 540 : }
403 :
404 : void
405 7480 : Assembly::buildVectorLowerDFE(FEType type) const
406 : {
407 7480 : if (!_vector_fe_shape_data_lower[type])
408 1458 : _vector_fe_shape_data_lower[type] = std::make_unique<VectorFEShapeData>();
409 :
410 : // Build an FE object for this type for each dimension up to the dimension of
411 : // the current mesh minus one (because this is for lower-dimensional
412 : // elements!)
413 7480 : unsigned int dim = ((type.family == LAGRANGE_VEC) || (type.family == MONOMIAL_VEC)) ? 0 : 2;
414 7480 : const auto ending_dim = cast_int<unsigned int>(_mesh_dimension - 1);
415 7480 : if (ending_dim < dim)
416 1552 : return;
417 17088 : for (; dim <= ending_dim; dim++)
418 : {
419 11160 : if (!_vector_fe_lower[dim][type])
420 2047 : _vector_fe_lower[dim][type] = FEVectorBase::build(dim, type).release();
421 :
422 11160 : _vector_fe_lower[dim][type]->get_phi();
423 11160 : _vector_fe_lower[dim][type]->get_dphi();
424 11160 : if (_need_second_derivative.count(type))
425 0 : _vector_fe_lower[dim][type]->get_d2phi();
426 : }
427 : }
428 :
429 : void
430 0 : Assembly::buildVectorDualLowerDFE(FEType type) const
431 : {
432 0 : if (!_vector_fe_shape_data_dual_lower[type])
433 0 : _vector_fe_shape_data_dual_lower[type] = std::make_unique<VectorFEShapeData>();
434 :
435 : // Build an FE object for this type for each dimension up to the dimension of
436 : // the current mesh minus one (because this is for lower-dimensional
437 : // elements!)
438 0 : unsigned int dim = ((type.family == LAGRANGE_VEC) || (type.family == MONOMIAL_VEC)) ? 0 : 2;
439 0 : const auto ending_dim = cast_int<unsigned int>(_mesh_dimension - 1);
440 0 : if (ending_dim < dim)
441 0 : return;
442 0 : for (; dim <= ending_dim; dim++)
443 : {
444 0 : if (!_vector_fe_lower[dim][type])
445 0 : _vector_fe_lower[dim][type] = FEVectorBase::build(dim, type).release();
446 :
447 0 : _vector_fe_lower[dim][type]->get_dual_phi();
448 0 : _vector_fe_lower[dim][type]->get_dual_dphi();
449 0 : if (_need_second_derivative.count(type))
450 0 : _vector_fe_lower[dim][type]->get_dual_d2phi();
451 : }
452 : }
453 :
454 : void
455 582393 : Assembly::buildVectorFE(const FEType type) const
456 : {
457 582393 : if (!_vector_fe_shape_data[type])
458 1458 : _vector_fe_shape_data[type] = std::make_unique<VectorFEShapeData>();
459 :
460 : // Note that NEDELEC_ONE and RAVIART_THOMAS elements can only be built for dimension > 2
461 : unsigned int min_dim;
462 582393 : if (type.family == NEDELEC_ONE || type.family == RAVIART_THOMAS ||
463 3086 : type.family == L2_RAVIART_THOMAS)
464 579439 : min_dim = 2;
465 : else
466 2954 : min_dim = 0;
467 :
468 : // Build an FE object for this type for each dimension from the min_dim up to the dimension of the
469 : // current mesh
470 1657435 : for (unsigned int dim = min_dim; dim <= _mesh_dimension; dim++)
471 : {
472 1075042 : if (!_vector_fe[dim][type])
473 3691 : _vector_fe[dim][type] = FEGenericBase<VectorValue<Real>>::build(dim, type).release();
474 :
475 1075042 : _vector_fe[dim][type]->get_phi();
476 1075042 : _vector_fe[dim][type]->get_dphi();
477 1075042 : if (_need_curl.count(type))
478 63886 : _vector_fe[dim][type]->get_curl_phi();
479 1075042 : if (_need_div.count(type))
480 1001408 : _vector_fe[dim][type]->get_div_phi();
481 1075042 : _vector_fe[dim][type]->get_xyz();
482 : }
483 582393 : }
484 :
485 : void
486 4493 : Assembly::buildVectorFaceFE(const FEType type) const
487 : {
488 4493 : if (!_vector_fe_shape_data_face[type])
489 1458 : _vector_fe_shape_data_face[type] = std::make_unique<VectorFEShapeData>();
490 :
491 : // Note that NEDELEC_ONE and RAVIART_THOMAS elements can only be built for dimension > 2
492 : unsigned int min_dim;
493 4493 : if (type.family == NEDELEC_ONE || type.family == RAVIART_THOMAS ||
494 2770 : type.family == L2_RAVIART_THOMAS)
495 1789 : min_dim = 2;
496 : else
497 2704 : min_dim = 0;
498 :
499 : // Build an FE object for this type for each dimension from the min_dim up to the dimension of the
500 : // current mesh
501 15250 : for (unsigned int dim = min_dim; dim <= _mesh_dimension; dim++)
502 : {
503 10757 : if (!_vector_fe_face[dim][type])
504 3691 : _vector_fe_face[dim][type] = FEGenericBase<VectorValue<Real>>::build(dim, type).release();
505 :
506 10757 : _vector_fe_face[dim][type]->get_phi();
507 10757 : _vector_fe_face[dim][type]->get_dphi();
508 10757 : if (_need_curl.count(type))
509 281 : _vector_fe_face[dim][type]->get_curl_phi();
510 10757 : if (_need_face_div.count(type))
511 728 : _vector_fe_face[dim][type]->get_div_phi();
512 : }
513 4493 : }
514 :
515 : void
516 3740 : Assembly::buildVectorNeighborFE(const FEType type) const
517 : {
518 3740 : if (!_vector_fe_shape_data_neighbor[type])
519 1458 : _vector_fe_shape_data_neighbor[type] = std::make_unique<VectorFEShapeData>();
520 :
521 : // Note that NEDELEC_ONE and RAVIART_THOMAS elements can only be built for dimension > 2
522 : unsigned int min_dim;
523 3740 : if (type.family == NEDELEC_ONE || type.family == RAVIART_THOMAS ||
524 2770 : type.family == L2_RAVIART_THOMAS)
525 1036 : min_dim = 2;
526 : else
527 2704 : min_dim = 0;
528 :
529 : // Build an FE object for this type for each dimension from the min_dim up to the dimension of the
530 : // current mesh
531 13488 : for (unsigned int dim = min_dim; dim <= _mesh_dimension; dim++)
532 : {
533 9748 : if (!_vector_fe_neighbor[dim][type])
534 3691 : _vector_fe_neighbor[dim][type] = FEGenericBase<VectorValue<Real>>::build(dim, type).release();
535 :
536 9748 : _vector_fe_neighbor[dim][type]->get_phi();
537 9748 : _vector_fe_neighbor[dim][type]->get_dphi();
538 9748 : if (_need_curl.count(type))
539 0 : _vector_fe_neighbor[dim][type]->get_curl_phi();
540 9748 : if (_need_neighbor_div.count(type))
541 0 : _vector_fe_neighbor[dim][type]->get_div_phi();
542 : }
543 3740 : }
544 :
545 : void
546 4493 : Assembly::buildVectorFaceNeighborFE(const FEType type) const
547 : {
548 4493 : if (!_vector_fe_shape_data_face_neighbor[type])
549 1458 : _vector_fe_shape_data_face_neighbor[type] = std::make_unique<VectorFEShapeData>();
550 :
551 : // Note that NEDELEC_ONE and RAVIART_THOMAS elements can only be built for dimension > 2
552 : unsigned int min_dim;
553 4493 : if (type.family == NEDELEC_ONE || type.family == RAVIART_THOMAS ||
554 2770 : type.family == L2_RAVIART_THOMAS)
555 1789 : min_dim = 2;
556 : else
557 2704 : min_dim = 0;
558 :
559 : // Build an FE object for this type for each dimension from the min_dim up to the dimension of the
560 : // current mesh
561 15250 : for (unsigned int dim = min_dim; dim <= _mesh_dimension; dim++)
562 : {
563 10757 : if (!_vector_fe_face_neighbor[dim][type])
564 3691 : _vector_fe_face_neighbor[dim][type] =
565 7382 : FEGenericBase<VectorValue<Real>>::build(dim, type).release();
566 :
567 10757 : _vector_fe_face_neighbor[dim][type]->get_phi();
568 10757 : _vector_fe_face_neighbor[dim][type]->get_dphi();
569 10757 : if (_need_curl.count(type))
570 281 : _vector_fe_face_neighbor[dim][type]->get_curl_phi();
571 10757 : if (_need_face_neighbor_div.count(type))
572 0 : _vector_fe_face_neighbor[dim][type]->get_div_phi();
573 : }
574 4493 : }
575 :
576 : void
577 90 : Assembly::bumpVolumeQRuleOrder(Order volume_order, SubdomainID block)
578 : {
579 90 : auto & qdefault = _qrules[Moose::ANY_BLOCK_ID];
580 : mooseAssert(qdefault.size() > 0, "default quadrature must be initialized before order bumps");
581 :
582 90 : unsigned int ndims = _mesh_dimension + 1; // must account for 0-dimensional quadrature.
583 90 : auto & qvec = _qrules[block];
584 90 : if (qvec.size() != ndims || !qvec[0].vol)
585 52 : createQRules(qdefault[0].vol->type(),
586 26 : qdefault[0].arbitrary_vol->get_order(),
587 : volume_order,
588 26 : qdefault[0].face->get_order(),
589 : block);
590 64 : else if (qvec[0].vol->get_order() < volume_order)
591 0 : createQRules(qvec[0].vol->type(),
592 0 : qvec[0].arbitrary_vol->get_order(),
593 : volume_order,
594 0 : qvec[0].face->get_order(),
595 : block);
596 : // otherwise do nothing - quadrature order is already as high as requested
597 90 : }
598 :
599 : void
600 15 : Assembly::bumpAllQRuleOrder(Order order, SubdomainID block)
601 : {
602 15 : auto & qdefault = _qrules[Moose::ANY_BLOCK_ID];
603 : mooseAssert(qdefault.size() > 0, "default quadrature must be initialized before order bumps");
604 :
605 15 : unsigned int ndims = _mesh_dimension + 1; // must account for 0-dimensional quadrature.
606 15 : auto & qvec = _qrules[block];
607 15 : if (qvec.size() != ndims || !qvec[0].vol)
608 13 : createQRules(qdefault[0].vol->type(), order, order, order, block);
609 2 : else if (qvec[0].vol->get_order() < order || qvec[0].face->get_order() < order)
610 0 : createQRules(qvec[0].vol->type(),
611 0 : std::max(order, qvec[0].arbitrary_vol->get_order()),
612 0 : std::max(order, qvec[0].vol->get_order()),
613 0 : std::max(order, qvec[0].face->get_order()),
614 : block);
615 : // otherwise do nothing - quadrature order is already as high as requested
616 15 : }
617 :
618 : void
619 72055 : Assembly::createQRules(QuadratureType type,
620 : Order order,
621 : Order volume_order,
622 : Order face_order,
623 : SubdomainID block,
624 : bool allow_negative_qweights)
625 : {
626 72055 : auto & qvec = _qrules[block];
627 72055 : unsigned int ndims = _mesh_dimension + 1; // must account for 0-dimensional quadrature.
628 72055 : if (qvec.size() != ndims)
629 72055 : qvec.resize(ndims);
630 :
631 281807 : for (unsigned int i = 0; i < qvec.size(); i++)
632 : {
633 209752 : int dim = i;
634 209752 : auto & q = qvec[dim];
635 209752 : q.vol = QBase::build(type, dim, volume_order);
636 209752 : q.vol->allow_rules_with_negative_weights = allow_negative_qweights;
637 209752 : q.face = QBase::build(type, dim - 1, face_order);
638 209752 : q.face->allow_rules_with_negative_weights = allow_negative_qweights;
639 209752 : q.fv_face = QBase::build(QMONOMIAL, dim - 1, CONSTANT);
640 209752 : q.fv_face->allow_rules_with_negative_weights = allow_negative_qweights;
641 209752 : q.neighbor = std::make_unique<ArbitraryQuadrature>(dim - 1, face_order);
642 209752 : q.neighbor->allow_rules_with_negative_weights = allow_negative_qweights;
643 209752 : q.arbitrary_vol = std::make_unique<ArbitraryQuadrature>(dim, order);
644 209752 : q.arbitrary_vol->allow_rules_with_negative_weights = allow_negative_qweights;
645 209752 : q.arbitrary_face = std::make_unique<ArbitraryQuadrature>(dim - 1, face_order);
646 209752 : q.arbitrary_face->allow_rules_with_negative_weights = allow_negative_qweights;
647 : }
648 :
649 72055 : delete _qrule_msm;
650 72055 : _custom_mortar_qrule = false;
651 72055 : _qrule_msm = QBase::build(type, _mesh_dimension - 1, face_order).release();
652 72055 : _qrule_msm->allow_rules_with_negative_weights = allow_negative_qweights;
653 72055 : _fe_msm->attach_quadrature_rule(_qrule_msm);
654 72055 : }
655 :
656 : void
657 227103 : Assembly::setVolumeQRule(QBase * qrule, unsigned int dim)
658 : {
659 227103 : _current_qrule = qrule;
660 :
661 227103 : if (qrule) // Don't set a NULL qrule
662 : {
663 547761 : for (auto & it : _fe[dim])
664 320658 : it.second->attach_quadrature_rule(qrule);
665 231216 : for (auto & it : _vector_fe[dim])
666 4113 : it.second->attach_quadrature_rule(qrule);
667 227103 : if (!_unique_fe_helper.empty())
668 : {
669 : mooseAssert(dim < _unique_fe_helper.size(), "We should not be indexing out of bounds");
670 219 : _unique_fe_helper[dim]->attach_quadrature_rule(qrule);
671 : }
672 : }
673 227103 : }
674 :
675 : void
676 1164478 : Assembly::setFaceQRule(QBase * qrule, unsigned int dim)
677 : {
678 1164478 : _current_qrule_face = qrule;
679 :
680 2912070 : for (auto & it : _fe_face[dim])
681 1747592 : it.second->attach_quadrature_rule(qrule);
682 1165037 : for (auto & it : _vector_fe_face[dim])
683 559 : it.second->attach_quadrature_rule(qrule);
684 1164478 : if (!_unique_fe_face_helper.empty())
685 : {
686 : mooseAssert(dim < _unique_fe_face_helper.size(), "We should not be indexing out of bounds");
687 197 : _unique_fe_face_helper[dim]->attach_quadrature_rule(qrule);
688 : }
689 1164478 : }
690 :
691 : void
692 564417 : Assembly::setLowerQRule(QBase * qrule, unsigned int dim)
693 : {
694 : // The lower-dimensional quadrature rule matches the face quadrature rule
695 564417 : setFaceQRule(qrule, dim);
696 :
697 564417 : _current_qrule_lower = qrule;
698 :
699 1406991 : for (auto & it : _fe_lower[dim])
700 842574 : it.second->attach_quadrature_rule(qrule);
701 564417 : for (auto & it : _vector_fe_lower[dim])
702 0 : it.second->attach_quadrature_rule(qrule);
703 564417 : if (!_unique_fe_lower_helper.empty())
704 : {
705 : mooseAssert(dim < _unique_fe_lower_helper.size(), "We should not be indexing out of bounds");
706 0 : _unique_fe_lower_helper[dim]->attach_quadrature_rule(qrule);
707 : }
708 564417 : }
709 :
710 : void
711 20616347 : Assembly::setNeighborQRule(QBase * qrule, unsigned int dim)
712 : {
713 20616347 : _current_qrule_neighbor = qrule;
714 :
715 61333988 : for (auto & it : _fe_face_neighbor[dim])
716 40717641 : it.second->attach_quadrature_rule(qrule);
717 20642164 : for (auto & it : _vector_fe_face_neighbor[dim])
718 25817 : it.second->attach_quadrature_rule(qrule);
719 20616347 : if (!_unique_fe_face_neighbor_helper.empty())
720 : {
721 : mooseAssert(dim < _unique_fe_face_neighbor_helper.size(),
722 : "We should not be indexing out of bounds");
723 68724 : _unique_fe_face_neighbor_helper[dim]->attach_quadrature_rule(qrule);
724 : }
725 20616347 : }
726 :
727 : void
728 62946 : Assembly::clearCachedQRules()
729 : {
730 62946 : _current_qrule = nullptr;
731 62946 : _current_qrule_face = nullptr;
732 62946 : _current_qrule_lower = nullptr;
733 62946 : _current_qrule_neighbor = nullptr;
734 62946 : }
735 :
736 : void
737 18 : Assembly::setMortarQRule(Order order)
738 : {
739 18 : if (order != _qrule_msm->get_order())
740 : {
741 : // If custom mortar qrule has not yet been specified
742 0 : if (!_custom_mortar_qrule)
743 : {
744 0 : _custom_mortar_qrule = true;
745 0 : const unsigned int dim = _qrule_msm->get_dim();
746 0 : const QuadratureType type = _qrule_msm->type();
747 0 : delete _qrule_msm;
748 :
749 0 : _qrule_msm = QBase::build(type, dim, order).release();
750 0 : _fe_msm->attach_quadrature_rule(_qrule_msm);
751 : }
752 : else
753 0 : mooseError("Mortar quadrature_order: ",
754 : order,
755 : " does not match previously specified quadrature_order: ",
756 0 : _qrule_msm->get_order(),
757 : ". Quadrature_order (when specified) must match for all mortar constraints.");
758 : }
759 18 : }
760 :
761 : void
762 385394707 : Assembly::reinitFE(const Elem * elem)
763 : {
764 385394707 : unsigned int dim = elem->dim();
765 :
766 862893924 : for (const auto & it : _fe[dim])
767 : {
768 477499241 : FEBase & fe = *it.second;
769 477499241 : const FEType & fe_type = it.first;
770 :
771 477499241 : _current_fe[fe_type] = &fe;
772 :
773 477499241 : FEShapeData & fesd = *_fe_shape_data[fe_type];
774 :
775 477499241 : fe.reinit(elem);
776 :
777 477499217 : fesd._phi.shallowCopy(const_cast<std::vector<std::vector<Real>> &>(fe.get_phi()));
778 477499217 : fesd._grad_phi.shallowCopy(
779 477499217 : const_cast<std::vector<std::vector<VectorValue<Real>>> &>(fe.get_dphi()));
780 477499217 : if (_need_second_derivative.count(fe_type))
781 57575 : fesd._second_phi.shallowCopy(
782 57575 : const_cast<std::vector<std::vector<TensorValue<Real>>> &>(fe.get_d2phi()));
783 : }
784 390250915 : for (const auto & it : _vector_fe[dim])
785 : {
786 4856232 : FEVectorBase & fe = *it.second;
787 4856232 : const FEType & fe_type = it.first;
788 :
789 4856232 : _current_vector_fe[fe_type] = &fe;
790 :
791 4856232 : VectorFEShapeData & fesd = *_vector_fe_shape_data[fe_type];
792 :
793 4856232 : fe.reinit(elem);
794 :
795 4856232 : fesd._phi.shallowCopy(const_cast<std::vector<std::vector<VectorValue<Real>>> &>(fe.get_phi()));
796 4856232 : fesd._grad_phi.shallowCopy(
797 4856232 : const_cast<std::vector<std::vector<TensorValue<Real>>> &>(fe.get_dphi()));
798 4856232 : if (_need_second_derivative.count(fe_type))
799 0 : fesd._second_phi.shallowCopy(
800 0 : const_cast<std::vector<std::vector<TypeNTensor<3, Real>>> &>(fe.get_d2phi()));
801 4856232 : if (_need_curl.count(fe_type))
802 2095820 : fesd._curl_phi.shallowCopy(
803 2095820 : const_cast<std::vector<std::vector<VectorValue<Real>>> &>(fe.get_curl_phi()));
804 4856232 : if (_need_div.count(fe_type))
805 824370 : fesd._div_phi.shallowCopy(const_cast<std::vector<std::vector<Real>> &>(fe.get_div_phi()));
806 : }
807 385394683 : if (!_unique_fe_helper.empty())
808 : {
809 : mooseAssert(dim < _unique_fe_helper.size(), "We should be in bounds here");
810 764430 : _unique_fe_helper[dim]->reinit(elem);
811 : }
812 :
813 : // During that last loop the helper objects will have been reinitialized as well
814 : // We need to dig out the q_points and JxW from it.
815 385394683 : _current_q_points.shallowCopy(
816 385394683 : const_cast<std::vector<Point> &>(_holder_fe_helper[dim]->get_xyz()));
817 385394683 : _current_JxW.shallowCopy(const_cast<std::vector<Real> &>(_holder_fe_helper[dim]->get_JxW()));
818 :
819 385394683 : if (_subproblem.haveADObjects())
820 : {
821 26894196 : auto n_qp = _current_qrule->n_points();
822 26894196 : resizeADMappingObjects(n_qp, dim);
823 26894196 : if (_displaced)
824 : {
825 529872 : const auto & qw = _current_qrule->get_weights();
826 2904422 : for (unsigned int qp = 0; qp != n_qp; qp++)
827 2374550 : computeSinglePointMapAD(elem, qw, qp, _holder_fe_helper[dim]);
828 : }
829 : else
830 : {
831 94174326 : for (unsigned qp = 0; qp < n_qp; ++qp)
832 67810002 : _ad_JxW[qp] = _current_JxW[qp];
833 26364324 : if (_calculate_xyz)
834 56976248 : for (unsigned qp = 0; qp < n_qp; ++qp)
835 44515734 : _ad_q_points[qp] = _current_q_points[qp];
836 : }
837 :
838 68363125 : for (const auto & it : _fe[dim])
839 : {
840 41468929 : FEBase & fe = *it.second;
841 41468929 : auto fe_type = it.first;
842 41468929 : auto num_shapes = FEInterface::n_shape_functions(fe_type, elem);
843 41468929 : auto & grad_phi = _ad_grad_phi_data[fe_type];
844 :
845 41468929 : grad_phi.resize(num_shapes);
846 167046946 : for (decltype(num_shapes) i = 0; i < num_shapes; ++i)
847 125578017 : grad_phi[i].resize(n_qp);
848 :
849 41468929 : if (_displaced)
850 818574 : computeGradPhiAD(elem, n_qp, grad_phi, &fe);
851 : else
852 : {
853 40650355 : const auto & regular_grad_phi = _fe_shape_data[fe_type]->_grad_phi;
854 163404378 : for (decltype(num_shapes) i = 0; i < num_shapes; ++i)
855 582567725 : for (unsigned qp = 0; qp < n_qp; ++qp)
856 459813702 : grad_phi[i][qp] = regular_grad_phi[i][qp];
857 : }
858 : }
859 29655532 : for (const auto & it : _vector_fe[dim])
860 : {
861 2761336 : FEVectorBase & fe = *it.second;
862 2761336 : auto fe_type = it.first;
863 2761336 : auto num_shapes = FEInterface::n_shape_functions(fe_type, elem);
864 2761336 : auto & grad_phi = _ad_vector_grad_phi_data[fe_type];
865 :
866 2761336 : grad_phi.resize(num_shapes);
867 16764904 : for (decltype(num_shapes) i = 0; i < num_shapes; ++i)
868 14003568 : grad_phi[i].resize(n_qp);
869 :
870 2761336 : if (_displaced)
871 0 : computeGradPhiAD(elem, n_qp, grad_phi, &fe);
872 : else
873 : {
874 2761336 : const auto & regular_grad_phi = _vector_fe_shape_data[fe_type]->_grad_phi;
875 16764904 : for (decltype(num_shapes) i = 0; i < num_shapes; ++i)
876 71678960 : for (unsigned qp = 0; qp < n_qp; ++qp)
877 57675392 : grad_phi[i][qp] = regular_grad_phi[i][qp];
878 : }
879 : }
880 : }
881 :
882 385394683 : auto n = numExtraElemIntegers();
883 389401269 : for (auto i : make_range(n))
884 4006586 : _extra_elem_ids[i] = _current_elem->get_extra_integer(i);
885 385394683 : _extra_elem_ids[n] = _current_elem->subdomain_id();
886 :
887 385394683 : if (_xfem != nullptr)
888 0 : modifyWeightsDueToXFEM(elem);
889 385394683 : }
890 :
891 : template <typename OutputType>
892 : void
893 943591 : Assembly::computeGradPhiAD(const Elem * elem,
894 : unsigned int n_qp,
895 : ADTemplateVariablePhiGradient<OutputType> & grad_phi,
896 : FEGenericBase<OutputType> * fe)
897 : {
898 : // This function relies on the fact that FE::reinit has already been called. FE::reinit will
899 : // importantly have already called FEMap::init_shape_functions which will have computed
900 : // these quantities at the integration/quadrature points: dphidxi,
901 : // dphideta, and dphidzeta (e.g. \nabla phi w.r.t. reference coordinates). These *phi* quantities
902 : // are independent of mesh displacements when using a quadrature rule.
903 : //
904 : // Note that a user could have specified custom integration points (e.g. independent of a
905 : // quadrature rule) which could very well depend on displacements. In that case even the *phi*
906 : // quantities from the above paragraph would be a function of the displacements and we would be
907 : // missing that derivative information in the calculations below
908 :
909 943591 : auto dim = elem->dim();
910 943591 : const auto & dphidxi = fe->get_dphidxi();
911 943591 : const auto & dphideta = fe->get_dphideta();
912 943591 : const auto & dphidzeta = fe->get_dphidzeta();
913 943591 : auto num_shapes = grad_phi.size();
914 :
915 943591 : switch (dim)
916 : {
917 0 : case 0:
918 : {
919 0 : for (decltype(num_shapes) i = 0; i < num_shapes; ++i)
920 0 : for (unsigned qp = 0; qp < n_qp; ++qp)
921 0 : grad_phi[i][qp] = 0;
922 0 : break;
923 : }
924 :
925 54074 : case 1:
926 : {
927 146121 : for (decltype(num_shapes) i = 0; i < num_shapes; ++i)
928 296031 : for (unsigned qp = 0; qp < n_qp; ++qp)
929 : {
930 203984 : grad_phi[i][qp].slice(0) = dphidxi[i][qp] * _ad_dxidx_map[qp];
931 203984 : grad_phi[i][qp].slice(1) = dphidxi[i][qp] * _ad_dxidy_map[qp];
932 203984 : grad_phi[i][qp].slice(2) = dphidxi[i][qp] * _ad_dxidz_map[qp];
933 : }
934 54074 : break;
935 : }
936 :
937 889517 : case 2:
938 : {
939 4247110 : for (decltype(num_shapes) i = 0; i < num_shapes; ++i)
940 19604835 : for (unsigned qp = 0; qp < n_qp; ++qp)
941 : {
942 32494484 : grad_phi[i][qp].slice(0) =
943 32494484 : dphidxi[i][qp] * _ad_dxidx_map[qp] + dphideta[i][qp] * _ad_detadx_map[qp];
944 32494484 : grad_phi[i][qp].slice(1) =
945 32494484 : dphidxi[i][qp] * _ad_dxidy_map[qp] + dphideta[i][qp] * _ad_detady_map[qp];
946 32494484 : grad_phi[i][qp].slice(2) =
947 32494484 : dphidxi[i][qp] * _ad_dxidz_map[qp] + dphideta[i][qp] * _ad_detadz_map[qp];
948 : }
949 889517 : break;
950 : }
951 :
952 0 : case 3:
953 : {
954 0 : for (decltype(num_shapes) i = 0; i < num_shapes; ++i)
955 0 : for (unsigned qp = 0; qp < n_qp; ++qp)
956 : {
957 0 : grad_phi[i][qp].slice(0) = dphidxi[i][qp] * _ad_dxidx_map[qp] +
958 0 : dphideta[i][qp] * _ad_detadx_map[qp] +
959 0 : dphidzeta[i][qp] * _ad_dzetadx_map[qp];
960 0 : grad_phi[i][qp].slice(1) = dphidxi[i][qp] * _ad_dxidy_map[qp] +
961 0 : dphideta[i][qp] * _ad_detady_map[qp] +
962 0 : dphidzeta[i][qp] * _ad_dzetady_map[qp];
963 0 : grad_phi[i][qp].slice(2) = dphidxi[i][qp] * _ad_dxidz_map[qp] +
964 0 : dphideta[i][qp] * _ad_detadz_map[qp] +
965 0 : dphidzeta[i][qp] * _ad_dzetadz_map[qp];
966 : }
967 0 : break;
968 : }
969 : }
970 943591 : }
971 :
972 : void
973 29735285 : Assembly::resizeADMappingObjects(unsigned int n_qp, unsigned int dim)
974 : {
975 29735285 : _ad_dxyzdxi_map.resize(n_qp);
976 29735285 : _ad_dxidx_map.resize(n_qp);
977 29735285 : _ad_dxidy_map.resize(n_qp); // 1D element may live in 2D ...
978 29735285 : _ad_dxidz_map.resize(n_qp); // ... or 3D
979 :
980 29735285 : if (dim > 1)
981 : {
982 19020234 : _ad_dxyzdeta_map.resize(n_qp);
983 19020234 : _ad_detadx_map.resize(n_qp);
984 19020234 : _ad_detady_map.resize(n_qp);
985 19020234 : _ad_detadz_map.resize(n_qp);
986 :
987 19020234 : if (dim > 2)
988 : {
989 1124286 : _ad_dxyzdzeta_map.resize(n_qp);
990 1124286 : _ad_dzetadx_map.resize(n_qp);
991 1124286 : _ad_dzetady_map.resize(n_qp);
992 1124286 : _ad_dzetadz_map.resize(n_qp);
993 : }
994 : }
995 :
996 29735285 : _ad_jac.resize(n_qp);
997 29735285 : _ad_JxW.resize(n_qp);
998 29735285 : if (_calculate_xyz)
999 14797885 : _ad_q_points.resize(n_qp);
1000 29735285 : }
1001 :
1002 : void
1003 2479403 : Assembly::computeSinglePointMapAD(const Elem * elem,
1004 : const std::vector<Real> & qw,
1005 : unsigned p,
1006 : FEBase * fe)
1007 : {
1008 : // This function relies on the fact that FE::reinit has already been called. FE::reinit will
1009 : // importantly have already called FEMap::init_reference_to_physical_map which will have computed
1010 : // these quantities at the integration/quadrature points: phi_map, dphidxi_map,
1011 : // dphideta_map, and dphidzeta_map (e.g. phi and \nabla phi w.r.t reference coordinates). *_map is
1012 : // used to denote that quantities are in reference to a mapping Lagrange FE object. The FE<Dim,
1013 : // LAGRANGE> objects used for mapping will in general have an order matching the order of the
1014 : // mesh. These *phi*_map quantities are independent of mesh displacements when using a quadrature
1015 : // rule.
1016 : //
1017 : // Note that a user could have specified custom integration points (e.g. independent of a
1018 : // quadrature rule) which could very well depend on displacements. In that case even the *phi*_map
1019 : // quantities from the above paragraph would be a function of the displacements and we would be
1020 : // missing that derivative information in the calculations below
1021 : //
1022 : // Important quantities calculated by this method:
1023 : // - _ad_JxW;
1024 : // - _ad_q_points;
1025 : // And the following quantities are important because they are used in the computeGradPhiAD method
1026 : // to calculate the shape function gradients with respect to the physical coordinates
1027 : // dphi/dphys = dphi/dref * dref/dphys:
1028 : // - _ad_dxidx_map;
1029 : // - _ad_dxidy_map;
1030 : // - _ad_dxidz_map;
1031 : // - _ad_detadx_map;
1032 : // - _ad_detady_map;
1033 : // - _ad_detadz_map;
1034 : // - _ad_dzetadx_map;
1035 : // - _ad_dzetady_map;
1036 : // - _ad_dzetadz_map;
1037 : //
1038 : // Some final notes. This method will be called both when we are reinit'ing in the volume and on
1039 : // faces. When reinit'ing on faces, computation of _ad_JxW will be garbage because we will be
1040 : // using dummy quadrature weights. _ad_q_points computation is also currently extraneous during
1041 : // face reinit because we compute _ad_q_points_face in the computeFaceMap method. However,
1042 : // computation of dref/dphys is absolutely necessary (and the reason we call this method for the
1043 : // face case) for both volume and face reinit
1044 :
1045 2479403 : auto dim = elem->dim();
1046 2479403 : const auto & elem_nodes = elem->get_nodes();
1047 2479403 : auto num_shapes = FEInterface::n_shape_functions(fe->get_fe_type(), elem);
1048 2479403 : const auto & phi_map = fe->get_fe_map().get_phi_map();
1049 2479403 : const auto & dphidxi_map = fe->get_fe_map().get_dphidxi_map();
1050 2479403 : const auto & dphideta_map = fe->get_fe_map().get_dphideta_map();
1051 2479403 : const auto & dphidzeta_map = fe->get_fe_map().get_dphidzeta_map();
1052 2479403 : const auto sys_num = _sys.number();
1053 : const bool do_derivatives =
1054 2479403 : ADReal::do_derivatives && _sys.number() == _subproblem.currentNlSysNum();
1055 :
1056 2479403 : switch (dim)
1057 : {
1058 0 : case 0:
1059 : {
1060 0 : _ad_jac[p] = 1.0;
1061 0 : _ad_JxW[p] = qw[p];
1062 0 : if (_calculate_xyz)
1063 0 : _ad_q_points[p] = *elem_nodes[0];
1064 0 : break;
1065 : }
1066 :
1067 64315 : case 1:
1068 : {
1069 64315 : if (_calculate_xyz)
1070 10897 : _ad_q_points[p].zero();
1071 :
1072 64315 : _ad_dxyzdxi_map[p].zero();
1073 :
1074 204297 : for (std::size_t i = 0; i < num_shapes; i++)
1075 : {
1076 : libmesh_assert(elem_nodes[i]);
1077 139982 : const Node & node = *elem_nodes[i];
1078 139982 : libMesh::VectorValue<ADReal> elem_point = node;
1079 139982 : if (do_derivatives)
1080 59314 : for (const auto & [disp_num, direction] : _disp_numbers_and_directions)
1081 2417 : if (node.n_dofs(sys_num, disp_num))
1082 4834 : Moose::derivInsert(
1083 2417 : elem_point(direction).derivatives(), node.dof_number(sys_num, disp_num, 0), 1.);
1084 :
1085 139982 : _ad_dxyzdxi_map[p].add_scaled(elem_point, dphidxi_map[i][p]);
1086 :
1087 139982 : if (_calculate_xyz)
1088 28562 : _ad_q_points[p].add_scaled(elem_point, phi_map[i][p]);
1089 139982 : }
1090 :
1091 64315 : _ad_jac[p] = _ad_dxyzdxi_map[p].norm();
1092 :
1093 64315 : if (_ad_jac[p].value() <= -TOLERANCE * TOLERANCE)
1094 : {
1095 : static bool failing = false;
1096 0 : if (!failing)
1097 : {
1098 0 : failing = true;
1099 0 : elem->print_info(libMesh::err);
1100 0 : libmesh_error_msg("ERROR: negative Jacobian " << _ad_jac[p].value() << " at point index "
1101 : << p << " in element " << elem->id());
1102 : }
1103 : else
1104 0 : return;
1105 : }
1106 :
1107 64315 : const auto jacm2 = 1. / _ad_jac[p] / _ad_jac[p];
1108 64315 : _ad_dxidx_map[p] = jacm2 * _ad_dxyzdxi_map[p](0);
1109 64315 : _ad_dxidy_map[p] = jacm2 * _ad_dxyzdxi_map[p](1);
1110 64315 : _ad_dxidz_map[p] = jacm2 * _ad_dxyzdxi_map[p](2);
1111 :
1112 64315 : _ad_JxW[p] = _ad_jac[p] * qw[p];
1113 :
1114 64315 : break;
1115 64315 : }
1116 :
1117 2415088 : case 2:
1118 : {
1119 2415088 : if (_calculate_xyz)
1120 1641366 : _ad_q_points[p].zero();
1121 2415088 : _ad_dxyzdxi_map[p].zero();
1122 2415088 : _ad_dxyzdeta_map[p].zero();
1123 :
1124 14715816 : for (std::size_t i = 0; i < num_shapes; i++)
1125 : {
1126 : libmesh_assert(elem_nodes[i]);
1127 12300728 : const Node & node = *elem_nodes[i];
1128 12300728 : libMesh::VectorValue<ADReal> elem_point = node;
1129 12300728 : if (do_derivatives)
1130 1662013 : for (const auto & [disp_num, direction] : _disp_numbers_and_directions)
1131 125346 : if (node.n_dofs(sys_num, disp_num))
1132 250692 : Moose::derivInsert(
1133 125346 : elem_point(direction).derivatives(), node.dof_number(sys_num, disp_num, 0), 1.);
1134 :
1135 12300728 : _ad_dxyzdxi_map[p].add_scaled(elem_point, dphidxi_map[i][p]);
1136 12300728 : _ad_dxyzdeta_map[p].add_scaled(elem_point, dphideta_map[i][p]);
1137 :
1138 12300728 : if (_calculate_xyz)
1139 9637714 : _ad_q_points[p].add_scaled(elem_point, phi_map[i][p]);
1140 12300728 : }
1141 :
1142 2415088 : const auto &dx_dxi = _ad_dxyzdxi_map[p](0), &dx_deta = _ad_dxyzdeta_map[p](0),
1143 2415088 : &dy_dxi = _ad_dxyzdxi_map[p](1), &dy_deta = _ad_dxyzdeta_map[p](1),
1144 2415088 : &dz_dxi = _ad_dxyzdxi_map[p](2), &dz_deta = _ad_dxyzdeta_map[p](2);
1145 :
1146 2415088 : const auto g11 = (dx_dxi * dx_dxi + dy_dxi * dy_dxi + dz_dxi * dz_dxi);
1147 :
1148 2415088 : const auto g12 = (dx_dxi * dx_deta + dy_dxi * dy_deta + dz_dxi * dz_deta);
1149 :
1150 2415088 : const auto & g21 = g12;
1151 :
1152 2415088 : const auto g22 = (dx_deta * dx_deta + dy_deta * dy_deta + dz_deta * dz_deta);
1153 :
1154 2415088 : auto det = (g11 * g22 - g12 * g21);
1155 :
1156 2415088 : if (det.value() <= -TOLERANCE * TOLERANCE)
1157 : {
1158 : static bool failing = false;
1159 0 : if (!failing)
1160 : {
1161 0 : failing = true;
1162 0 : elem->print_info(libMesh::err);
1163 0 : libmesh_error_msg("ERROR: negative Jacobian " << det << " at point index " << p
1164 : << " in element " << elem->id());
1165 : }
1166 : else
1167 0 : return;
1168 : }
1169 2415088 : else if (det.value() <= 0.)
1170 0 : det.value() = TOLERANCE * TOLERANCE;
1171 :
1172 2415088 : const auto inv_det = 1. / det;
1173 : using std::sqrt;
1174 2415088 : _ad_jac[p] = sqrt(det);
1175 :
1176 2415088 : _ad_JxW[p] = _ad_jac[p] * qw[p];
1177 :
1178 2415088 : const auto g11inv = g22 * inv_det;
1179 2415088 : const auto g12inv = -g12 * inv_det;
1180 2415088 : const auto g21inv = -g21 * inv_det;
1181 2415088 : const auto g22inv = g11 * inv_det;
1182 :
1183 2415088 : _ad_dxidx_map[p] = g11inv * dx_dxi + g12inv * dx_deta;
1184 2415088 : _ad_dxidy_map[p] = g11inv * dy_dxi + g12inv * dy_deta;
1185 2415088 : _ad_dxidz_map[p] = g11inv * dz_dxi + g12inv * dz_deta;
1186 :
1187 2415088 : _ad_detadx_map[p] = g21inv * dx_dxi + g22inv * dx_deta;
1188 2415088 : _ad_detady_map[p] = g21inv * dy_dxi + g22inv * dy_deta;
1189 2415088 : _ad_detadz_map[p] = g21inv * dz_dxi + g22inv * dz_deta;
1190 :
1191 2415088 : break;
1192 12075440 : }
1193 :
1194 0 : case 3:
1195 : {
1196 0 : if (_calculate_xyz)
1197 0 : _ad_q_points[p].zero();
1198 0 : _ad_dxyzdxi_map[p].zero();
1199 0 : _ad_dxyzdeta_map[p].zero();
1200 0 : _ad_dxyzdzeta_map[p].zero();
1201 :
1202 0 : for (std::size_t i = 0; i < num_shapes; i++)
1203 : {
1204 : libmesh_assert(elem_nodes[i]);
1205 0 : const Node & node = *elem_nodes[i];
1206 0 : libMesh::VectorValue<ADReal> elem_point = node;
1207 0 : if (do_derivatives)
1208 0 : for (const auto & [disp_num, direction] : _disp_numbers_and_directions)
1209 0 : if (node.n_dofs(sys_num, disp_num))
1210 0 : Moose::derivInsert(
1211 0 : elem_point(direction).derivatives(), node.dof_number(sys_num, disp_num, 0), 1.);
1212 :
1213 0 : _ad_dxyzdxi_map[p].add_scaled(elem_point, dphidxi_map[i][p]);
1214 0 : _ad_dxyzdeta_map[p].add_scaled(elem_point, dphideta_map[i][p]);
1215 0 : _ad_dxyzdzeta_map[p].add_scaled(elem_point, dphidzeta_map[i][p]);
1216 :
1217 0 : if (_calculate_xyz)
1218 0 : _ad_q_points[p].add_scaled(elem_point, phi_map[i][p]);
1219 0 : }
1220 :
1221 0 : const auto &dx_dxi = _ad_dxyzdxi_map[p](0), &dy_dxi = _ad_dxyzdxi_map[p](1),
1222 0 : &dz_dxi = _ad_dxyzdxi_map[p](2), &dx_deta = _ad_dxyzdeta_map[p](0),
1223 0 : &dy_deta = _ad_dxyzdeta_map[p](1), &dz_deta = _ad_dxyzdeta_map[p](2),
1224 0 : &dx_dzeta = _ad_dxyzdzeta_map[p](0), &dy_dzeta = _ad_dxyzdzeta_map[p](1),
1225 0 : &dz_dzeta = _ad_dxyzdzeta_map[p](2);
1226 :
1227 0 : _ad_jac[p] = (dx_dxi * (dy_deta * dz_dzeta - dz_deta * dy_dzeta) +
1228 0 : dy_dxi * (dz_deta * dx_dzeta - dx_deta * dz_dzeta) +
1229 0 : dz_dxi * (dx_deta * dy_dzeta - dy_deta * dx_dzeta));
1230 :
1231 0 : if (_ad_jac[p].value() <= -TOLERANCE * TOLERANCE)
1232 : {
1233 : static bool failing = false;
1234 0 : if (!failing)
1235 : {
1236 0 : failing = true;
1237 0 : elem->print_info(libMesh::err);
1238 0 : libmesh_error_msg("ERROR: negative Jacobian " << _ad_jac[p].value() << " at point index "
1239 : << p << " in element " << elem->id());
1240 : }
1241 : else
1242 0 : return;
1243 : }
1244 :
1245 0 : _ad_JxW[p] = _ad_jac[p] * qw[p];
1246 :
1247 0 : const auto inv_jac = 1. / _ad_jac[p];
1248 :
1249 0 : _ad_dxidx_map[p] = (dy_deta * dz_dzeta - dz_deta * dy_dzeta) * inv_jac;
1250 0 : _ad_dxidy_map[p] = (dz_deta * dx_dzeta - dx_deta * dz_dzeta) * inv_jac;
1251 0 : _ad_dxidz_map[p] = (dx_deta * dy_dzeta - dy_deta * dx_dzeta) * inv_jac;
1252 :
1253 0 : _ad_detadx_map[p] = (dz_dxi * dy_dzeta - dy_dxi * dz_dzeta) * inv_jac;
1254 0 : _ad_detady_map[p] = (dx_dxi * dz_dzeta - dz_dxi * dx_dzeta) * inv_jac;
1255 0 : _ad_detadz_map[p] = (dy_dxi * dx_dzeta - dx_dxi * dy_dzeta) * inv_jac;
1256 :
1257 0 : _ad_dzetadx_map[p] = (dy_dxi * dz_deta - dz_dxi * dy_deta) * inv_jac;
1258 0 : _ad_dzetady_map[p] = (dz_dxi * dx_deta - dx_dxi * dz_deta) * inv_jac;
1259 0 : _ad_dzetadz_map[p] = (dx_dxi * dy_deta - dy_dxi * dx_deta) * inv_jac;
1260 :
1261 0 : break;
1262 0 : }
1263 :
1264 0 : default:
1265 0 : libmesh_error_msg("Invalid dim = " << dim);
1266 : }
1267 : }
1268 :
1269 : void
1270 9110361 : Assembly::reinitFEFace(const Elem * elem, unsigned int side)
1271 : {
1272 9110361 : unsigned int dim = elem->dim();
1273 :
1274 26373602 : for (const auto & it : _fe_face[dim])
1275 : {
1276 17263241 : FEBase & fe_face = *it.second;
1277 17263241 : const FEType & fe_type = it.first;
1278 17263241 : FEShapeData & fesd = *_fe_shape_data_face[fe_type];
1279 17263241 : fe_face.reinit(elem, side);
1280 17263241 : _current_fe_face[fe_type] = &fe_face;
1281 :
1282 17263241 : fesd._phi.shallowCopy(const_cast<std::vector<std::vector<Real>> &>(fe_face.get_phi()));
1283 17263241 : fesd._grad_phi.shallowCopy(
1284 17263241 : const_cast<std::vector<std::vector<VectorValue<Real>>> &>(fe_face.get_dphi()));
1285 17263241 : if (_need_second_derivative.count(fe_type))
1286 15136 : fesd._second_phi.shallowCopy(
1287 15136 : const_cast<std::vector<std::vector<TensorValue<Real>>> &>(fe_face.get_d2phi()));
1288 : }
1289 10609564 : for (const auto & it : _vector_fe_face[dim])
1290 : {
1291 1499203 : FEVectorBase & fe_face = *it.second;
1292 1499203 : const FEType & fe_type = it.first;
1293 :
1294 1499203 : _current_vector_fe_face[fe_type] = &fe_face;
1295 :
1296 1499203 : VectorFEShapeData & fesd = *_vector_fe_shape_data_face[fe_type];
1297 :
1298 1499203 : fe_face.reinit(elem, side);
1299 :
1300 1499203 : fesd._phi.shallowCopy(
1301 1499203 : const_cast<std::vector<std::vector<VectorValue<Real>>> &>(fe_face.get_phi()));
1302 1499203 : fesd._grad_phi.shallowCopy(
1303 1499203 : const_cast<std::vector<std::vector<TensorValue<Real>>> &>(fe_face.get_dphi()));
1304 1499203 : if (_need_second_derivative.count(fe_type))
1305 0 : fesd._second_phi.shallowCopy(
1306 0 : const_cast<std::vector<std::vector<TypeNTensor<3, Real>>> &>(fe_face.get_d2phi()));
1307 1499203 : if (_need_curl.count(fe_type))
1308 418745 : fesd._curl_phi.shallowCopy(
1309 418745 : const_cast<std::vector<std::vector<VectorValue<Real>>> &>(fe_face.get_curl_phi()));
1310 1499203 : if (_need_face_div.count(fe_type))
1311 52224 : fesd._div_phi.shallowCopy(
1312 52224 : const_cast<std::vector<std::vector<Real>> &>(fe_face.get_div_phi()));
1313 : }
1314 9110361 : if (!_unique_fe_face_helper.empty())
1315 : {
1316 : mooseAssert(dim < _unique_fe_face_helper.size(), "We should be in bounds here");
1317 113670 : _unique_fe_face_helper[dim]->reinit(elem, side);
1318 : }
1319 :
1320 : // During that last loop the helper objects will have been reinitialized as well
1321 : // We need to dig out the q_points and JxW from it.
1322 9110361 : _current_q_points_face.shallowCopy(
1323 9110361 : const_cast<std::vector<Point> &>(_holder_fe_face_helper[dim]->get_xyz()));
1324 9110361 : _current_JxW_face.shallowCopy(
1325 9110361 : const_cast<std::vector<Real> &>(_holder_fe_face_helper[dim]->get_JxW()));
1326 9110361 : _current_normals.shallowCopy(
1327 9110361 : const_cast<std::vector<Point> &>(_holder_fe_face_helper[dim]->get_normals()));
1328 :
1329 9110361 : _mapped_normals.resize(_current_normals.size(), Eigen::Map<RealDIMValue>(nullptr));
1330 30337888 : for (unsigned int i = 0; i < _current_normals.size(); i++)
1331 : // Note: this does NOT do any allocation. It is "reconstructing" the object in place
1332 21227527 : new (&_mapped_normals[i]) Eigen::Map<RealDIMValue>(const_cast<Real *>(&_current_normals[i](0)));
1333 :
1334 9110361 : if (_calculate_curvatures)
1335 416 : _curvatures.shallowCopy(
1336 416 : const_cast<std::vector<Real> &>(_holder_fe_face_helper[dim]->get_curvatures()));
1337 :
1338 9110361 : computeADFace(*elem, side);
1339 :
1340 9110361 : if (_xfem != nullptr)
1341 0 : modifyFaceWeightsDueToXFEM(elem, side);
1342 :
1343 9110361 : auto n = numExtraElemIntegers();
1344 9254581 : for (auto i : make_range(n))
1345 144220 : _extra_elem_ids[i] = _current_elem->get_extra_integer(i);
1346 9110361 : _extra_elem_ids[n] = _current_elem->subdomain_id();
1347 9110361 : }
1348 :
1349 : void
1350 52499 : Assembly::computeFaceMap(const Elem & elem, const unsigned int side, const std::vector<Real> & qw)
1351 : {
1352 : // Important quantities calculated by this method:
1353 : // - _ad_JxW_face
1354 : // - _ad_q_points_face
1355 : // - _ad_normals
1356 : // - _ad_curvatures
1357 :
1358 52499 : const Elem & side_elem = _compute_face_map_side_elem_builder(elem, side);
1359 52499 : const auto dim = elem.dim();
1360 52499 : const auto n_qp = qw.size();
1361 52499 : const auto & dpsidxi_map = _holder_fe_face_helper[dim]->get_fe_map().get_dpsidxi();
1362 52499 : const auto & dpsideta_map = _holder_fe_face_helper[dim]->get_fe_map().get_dpsideta();
1363 52499 : const auto & psi_map = _holder_fe_face_helper[dim]->get_fe_map().get_psi();
1364 52499 : std::vector<std::vector<Real>> const * d2psidxi2_map = nullptr;
1365 52499 : std::vector<std::vector<Real>> const * d2psidxideta_map = nullptr;
1366 52499 : std::vector<std::vector<Real>> const * d2psideta2_map = nullptr;
1367 52499 : const auto sys_num = _sys.number();
1368 52499 : const bool do_derivatives = ADReal::do_derivatives && sys_num == _subproblem.currentNlSysNum();
1369 :
1370 52499 : if (_calculate_curvatures)
1371 : {
1372 0 : d2psidxi2_map = &_holder_fe_face_helper[dim]->get_fe_map().get_d2psidxi2();
1373 0 : d2psidxideta_map = &_holder_fe_face_helper[dim]->get_fe_map().get_d2psidxideta();
1374 0 : d2psideta2_map = &_holder_fe_face_helper[dim]->get_fe_map().get_d2psideta2();
1375 : }
1376 :
1377 52499 : switch (dim)
1378 : {
1379 279 : case 1:
1380 : {
1381 279 : if (!n_qp)
1382 0 : break;
1383 :
1384 279 : if (side_elem.node_id(0) == elem.node_id(0))
1385 279 : _ad_normals[0] = Point(-1.);
1386 : else
1387 0 : _ad_normals[0] = Point(1.);
1388 :
1389 279 : VectorValue<ADReal> side_point;
1390 279 : if (_calculate_face_xyz)
1391 : {
1392 279 : const Node & node = side_elem.node_ref(0);
1393 279 : side_point = node;
1394 :
1395 279 : if (do_derivatives)
1396 126 : for (const auto & [disp_num, direction] : _disp_numbers_and_directions)
1397 126 : Moose::derivInsert(
1398 63 : side_point(direction).derivatives(), node.dof_number(sys_num, disp_num, 0), 1.);
1399 : }
1400 :
1401 558 : for (const auto p : make_range(n_qp))
1402 : {
1403 279 : if (_calculate_face_xyz)
1404 : {
1405 279 : _ad_q_points_face[p].zero();
1406 279 : _ad_q_points_face[p].add_scaled(side_point, psi_map[0][p]);
1407 : }
1408 :
1409 279 : _ad_normals[p] = _ad_normals[0];
1410 279 : _ad_JxW_face[p] = 1.0 * qw[p];
1411 : }
1412 :
1413 279 : break;
1414 279 : }
1415 :
1416 52220 : case 2:
1417 : {
1418 52220 : _ad_dxyzdxi_map.resize(n_qp);
1419 52220 : if (_calculate_curvatures)
1420 0 : _ad_d2xyzdxi2_map.resize(n_qp);
1421 :
1422 156794 : for (const auto p : make_range(n_qp))
1423 104574 : _ad_dxyzdxi_map[p].zero();
1424 52220 : if (_calculate_face_xyz)
1425 88704 : for (const auto p : make_range(n_qp))
1426 59136 : _ad_q_points_face[p].zero();
1427 52220 : if (_calculate_curvatures)
1428 0 : for (const auto p : make_range(n_qp))
1429 0 : _ad_d2xyzdxi2_map[p].zero();
1430 :
1431 : const auto n_mapping_shape_functions =
1432 52220 : FE<2, LAGRANGE>::n_dofs(&side_elem, side_elem.default_order());
1433 :
1434 181994 : for (unsigned int i = 0; i < n_mapping_shape_functions; i++)
1435 : {
1436 129774 : const Node & node = side_elem.node_ref(i);
1437 129774 : VectorValue<ADReal> side_point = node;
1438 :
1439 129774 : if (do_derivatives)
1440 40698 : for (const auto & [disp_num, direction] : _disp_numbers_and_directions)
1441 0 : Moose::derivInsert(
1442 0 : side_point(direction).derivatives(), node.dof_number(sys_num, disp_num, 0), 1.);
1443 :
1444 389724 : for (const auto p : make_range(n_qp))
1445 259950 : _ad_dxyzdxi_map[p].add_scaled(side_point, dpsidxi_map[i][p]);
1446 129774 : if (_calculate_face_xyz)
1447 253008 : for (const auto p : make_range(n_qp))
1448 168672 : _ad_q_points_face[p].add_scaled(side_point, psi_map[i][p]);
1449 129774 : if (_calculate_curvatures)
1450 0 : for (const auto p : make_range(n_qp))
1451 0 : _ad_d2xyzdxi2_map[p].add_scaled(side_point, (*d2psidxi2_map)[i][p]);
1452 129774 : }
1453 :
1454 156794 : for (const auto p : make_range(n_qp))
1455 : {
1456 104574 : _ad_normals[p] =
1457 209148 : (VectorValue<ADReal>(_ad_dxyzdxi_map[p](1), -_ad_dxyzdxi_map[p](0), 0.)).unit();
1458 104574 : const auto the_jac = _ad_dxyzdxi_map[p].norm();
1459 104574 : _ad_JxW_face[p] = the_jac * qw[p];
1460 104574 : if (_calculate_curvatures)
1461 : {
1462 0 : const auto numerator = _ad_d2xyzdxi2_map[p] * _ad_normals[p];
1463 0 : const auto denominator = _ad_dxyzdxi_map[p].norm_sq();
1464 : libmesh_assert_not_equal_to(denominator, 0);
1465 0 : _ad_curvatures[p] = numerator / denominator;
1466 0 : }
1467 104574 : }
1468 :
1469 52220 : break;
1470 : }
1471 :
1472 0 : case 3:
1473 : {
1474 0 : _ad_dxyzdxi_map.resize(n_qp);
1475 0 : _ad_dxyzdeta_map.resize(n_qp);
1476 0 : if (_calculate_curvatures)
1477 : {
1478 0 : _ad_d2xyzdxi2_map.resize(n_qp);
1479 0 : _ad_d2xyzdxideta_map.resize(n_qp);
1480 0 : _ad_d2xyzdeta2_map.resize(n_qp);
1481 : }
1482 :
1483 0 : for (const auto p : make_range(n_qp))
1484 : {
1485 0 : _ad_dxyzdxi_map[p].zero();
1486 0 : _ad_dxyzdeta_map[p].zero();
1487 : }
1488 0 : if (_calculate_face_xyz)
1489 0 : for (const auto p : make_range(n_qp))
1490 0 : _ad_q_points_face[p].zero();
1491 0 : if (_calculate_curvatures)
1492 0 : for (const auto p : make_range(n_qp))
1493 : {
1494 0 : _ad_d2xyzdxi2_map[p].zero();
1495 0 : _ad_d2xyzdxideta_map[p].zero();
1496 0 : _ad_d2xyzdeta2_map[p].zero();
1497 : }
1498 :
1499 : const unsigned int n_mapping_shape_functions =
1500 0 : FE<3, LAGRANGE>::n_dofs(&side_elem, side_elem.default_order());
1501 :
1502 0 : for (unsigned int i = 0; i < n_mapping_shape_functions; i++)
1503 : {
1504 0 : const Node & node = side_elem.node_ref(i);
1505 0 : VectorValue<ADReal> side_point = node;
1506 :
1507 0 : if (do_derivatives)
1508 0 : for (const auto & [disp_num, direction] : _disp_numbers_and_directions)
1509 0 : Moose::derivInsert(
1510 0 : side_point(direction).derivatives(), node.dof_number(sys_num, disp_num, 0), 1.);
1511 :
1512 0 : for (const auto p : make_range(n_qp))
1513 : {
1514 0 : _ad_dxyzdxi_map[p].add_scaled(side_point, dpsidxi_map[i][p]);
1515 0 : _ad_dxyzdeta_map[p].add_scaled(side_point, dpsideta_map[i][p]);
1516 : }
1517 0 : if (_calculate_face_xyz)
1518 0 : for (const auto p : make_range(n_qp))
1519 0 : _ad_q_points_face[p].add_scaled(side_point, psi_map[i][p]);
1520 0 : if (_calculate_curvatures)
1521 0 : for (const auto p : make_range(n_qp))
1522 : {
1523 0 : _ad_d2xyzdxi2_map[p].add_scaled(side_point, (*d2psidxi2_map)[i][p]);
1524 0 : _ad_d2xyzdxideta_map[p].add_scaled(side_point, (*d2psidxideta_map)[i][p]);
1525 0 : _ad_d2xyzdeta2_map[p].add_scaled(side_point, (*d2psideta2_map)[i][p]);
1526 : }
1527 0 : }
1528 :
1529 0 : for (const auto p : make_range(n_qp))
1530 : {
1531 0 : _ad_normals[p] = _ad_dxyzdxi_map[p].cross(_ad_dxyzdeta_map[p]).unit();
1532 :
1533 0 : const auto &dxdxi = _ad_dxyzdxi_map[p](0), &dxdeta = _ad_dxyzdeta_map[p](0),
1534 0 : &dydxi = _ad_dxyzdxi_map[p](1), &dydeta = _ad_dxyzdeta_map[p](1),
1535 0 : &dzdxi = _ad_dxyzdxi_map[p](2), &dzdeta = _ad_dxyzdeta_map[p](2);
1536 :
1537 0 : const auto g11 = (dxdxi * dxdxi + dydxi * dydxi + dzdxi * dzdxi);
1538 :
1539 0 : const auto g12 = (dxdxi * dxdeta + dydxi * dydeta + dzdxi * dzdeta);
1540 :
1541 0 : const auto & g21 = g12;
1542 :
1543 0 : const auto g22 = (dxdeta * dxdeta + dydeta * dydeta + dzdeta * dzdeta);
1544 :
1545 : using std::sqrt;
1546 0 : const auto the_jac = sqrt(g11 * g22 - g12 * g21);
1547 :
1548 0 : _ad_JxW_face[p] = the_jac * qw[p];
1549 :
1550 0 : if (_calculate_curvatures)
1551 : {
1552 0 : const auto L = -_ad_d2xyzdxi2_map[p] * _ad_normals[p];
1553 0 : const auto M = -_ad_d2xyzdxideta_map[p] * _ad_normals[p];
1554 0 : const auto N = -_ad_d2xyzdeta2_map[p] * _ad_normals[p];
1555 0 : const auto E = _ad_dxyzdxi_map[p].norm_sq();
1556 0 : const auto F = _ad_dxyzdxi_map[p] * _ad_dxyzdeta_map[p];
1557 0 : const auto G = _ad_dxyzdeta_map[p].norm_sq();
1558 :
1559 0 : const auto numerator = E * N - 2. * F * M + G * L;
1560 0 : const auto denominator = E * G - F * F;
1561 : libmesh_assert_not_equal_to(denominator, 0.);
1562 0 : _ad_curvatures[p] = 0.5 * numerator / denominator;
1563 0 : }
1564 0 : }
1565 :
1566 0 : break;
1567 : }
1568 :
1569 0 : default:
1570 0 : mooseError("Invalid dimension dim = ", dim);
1571 : }
1572 52499 : }
1573 :
1574 : void
1575 3920245 : Assembly::reinitFEFaceNeighbor(const Elem * neighbor, const std::vector<Point> & reference_points)
1576 : {
1577 3920245 : unsigned int neighbor_dim = neighbor->dim();
1578 :
1579 : // reinit neighbor face
1580 11556638 : for (const auto & it : _fe_face_neighbor[neighbor_dim])
1581 : {
1582 7636393 : FEBase & fe_face_neighbor = *it.second;
1583 7636393 : FEType fe_type = it.first;
1584 7636393 : FEShapeData & fesd = *_fe_shape_data_face_neighbor[fe_type];
1585 :
1586 7636393 : fe_face_neighbor.reinit(neighbor, &reference_points);
1587 :
1588 7636393 : _current_fe_face_neighbor[fe_type] = &fe_face_neighbor;
1589 :
1590 7636393 : fesd._phi.shallowCopy(const_cast<std::vector<std::vector<Real>> &>(fe_face_neighbor.get_phi()));
1591 7636393 : fesd._grad_phi.shallowCopy(
1592 7636393 : const_cast<std::vector<std::vector<RealGradient>> &>(fe_face_neighbor.get_dphi()));
1593 7636393 : if (_need_second_derivative_neighbor.count(fe_type))
1594 8640 : fesd._second_phi.shallowCopy(
1595 8640 : const_cast<std::vector<std::vector<TensorValue<Real>>> &>(fe_face_neighbor.get_d2phi()));
1596 : }
1597 3946062 : for (const auto & it : _vector_fe_face_neighbor[neighbor_dim])
1598 : {
1599 25817 : FEVectorBase & fe_face_neighbor = *it.second;
1600 25817 : const FEType & fe_type = it.first;
1601 :
1602 25817 : _current_vector_fe_face_neighbor[fe_type] = &fe_face_neighbor;
1603 :
1604 25817 : VectorFEShapeData & fesd = *_vector_fe_shape_data_face_neighbor[fe_type];
1605 :
1606 25817 : fe_face_neighbor.reinit(neighbor, &reference_points);
1607 :
1608 25817 : fesd._phi.shallowCopy(
1609 25817 : const_cast<std::vector<std::vector<VectorValue<Real>>> &>(fe_face_neighbor.get_phi()));
1610 25817 : fesd._grad_phi.shallowCopy(
1611 25817 : const_cast<std::vector<std::vector<TensorValue<Real>>> &>(fe_face_neighbor.get_dphi()));
1612 25817 : if (_need_second_derivative.count(fe_type))
1613 0 : fesd._second_phi.shallowCopy(const_cast<std::vector<std::vector<TypeNTensor<3, Real>>> &>(
1614 0 : fe_face_neighbor.get_d2phi()));
1615 25817 : if (_need_curl.count(fe_type))
1616 105 : fesd._curl_phi.shallowCopy(const_cast<std::vector<std::vector<VectorValue<Real>>> &>(
1617 105 : fe_face_neighbor.get_curl_phi()));
1618 25817 : if (_need_face_neighbor_div.count(fe_type))
1619 0 : fesd._div_phi.shallowCopy(
1620 0 : const_cast<std::vector<std::vector<Real>> &>(fe_face_neighbor.get_div_phi()));
1621 : }
1622 3920245 : if (!_unique_fe_face_neighbor_helper.empty())
1623 : {
1624 : mooseAssert(neighbor_dim < _unique_fe_face_neighbor_helper.size(),
1625 : "We should be in bounds here");
1626 68724 : _unique_fe_face_neighbor_helper[neighbor_dim]->reinit(neighbor, &reference_points);
1627 : }
1628 :
1629 3920245 : _current_q_points_face_neighbor.shallowCopy(
1630 3920245 : const_cast<std::vector<Point> &>(_holder_fe_face_neighbor_helper[neighbor_dim]->get_xyz()));
1631 3920245 : }
1632 :
1633 : void
1634 19880 : Assembly::reinitFENeighbor(const Elem * neighbor, const std::vector<Point> & reference_points)
1635 : {
1636 19880 : unsigned int neighbor_dim = neighbor->dim();
1637 :
1638 : // reinit neighbor face
1639 39760 : for (const auto & it : _fe_neighbor[neighbor_dim])
1640 : {
1641 19880 : FEBase & fe_neighbor = *it.second;
1642 19880 : FEType fe_type = it.first;
1643 19880 : FEShapeData & fesd = *_fe_shape_data_neighbor[fe_type];
1644 :
1645 19880 : fe_neighbor.reinit(neighbor, &reference_points);
1646 :
1647 19880 : _current_fe_neighbor[fe_type] = &fe_neighbor;
1648 :
1649 19880 : fesd._phi.shallowCopy(const_cast<std::vector<std::vector<Real>> &>(fe_neighbor.get_phi()));
1650 19880 : fesd._grad_phi.shallowCopy(
1651 19880 : const_cast<std::vector<std::vector<RealGradient>> &>(fe_neighbor.get_dphi()));
1652 19880 : if (_need_second_derivative_neighbor.count(fe_type))
1653 0 : fesd._second_phi.shallowCopy(
1654 0 : const_cast<std::vector<std::vector<TensorValue<Real>>> &>(fe_neighbor.get_d2phi()));
1655 : }
1656 19880 : for (const auto & it : _vector_fe_neighbor[neighbor_dim])
1657 : {
1658 0 : FEVectorBase & fe_neighbor = *it.second;
1659 0 : const FEType & fe_type = it.first;
1660 :
1661 0 : _current_vector_fe_neighbor[fe_type] = &fe_neighbor;
1662 :
1663 0 : VectorFEShapeData & fesd = *_vector_fe_shape_data_neighbor[fe_type];
1664 :
1665 0 : fe_neighbor.reinit(neighbor, &reference_points);
1666 :
1667 0 : fesd._phi.shallowCopy(
1668 0 : const_cast<std::vector<std::vector<VectorValue<Real>>> &>(fe_neighbor.get_phi()));
1669 0 : fesd._grad_phi.shallowCopy(
1670 0 : const_cast<std::vector<std::vector<TensorValue<Real>>> &>(fe_neighbor.get_dphi()));
1671 0 : if (_need_second_derivative.count(fe_type))
1672 0 : fesd._second_phi.shallowCopy(
1673 0 : const_cast<std::vector<std::vector<TypeNTensor<3, Real>>> &>(fe_neighbor.get_d2phi()));
1674 0 : if (_need_curl.count(fe_type))
1675 0 : fesd._curl_phi.shallowCopy(
1676 0 : const_cast<std::vector<std::vector<VectorValue<Real>>> &>(fe_neighbor.get_curl_phi()));
1677 0 : if (_need_neighbor_div.count(fe_type))
1678 0 : fesd._div_phi.shallowCopy(
1679 0 : const_cast<std::vector<std::vector<Real>> &>(fe_neighbor.get_div_phi()));
1680 : }
1681 19880 : if (!_unique_fe_neighbor_helper.empty())
1682 : {
1683 : mooseAssert(neighbor_dim < _unique_fe_neighbor_helper.size(), "We should be in bounds here");
1684 0 : _unique_fe_neighbor_helper[neighbor_dim]->reinit(neighbor, &reference_points);
1685 : }
1686 19880 : }
1687 :
1688 : void
1689 3940125 : Assembly::reinitNeighbor(const Elem * neighbor, const std::vector<Point> & reference_points)
1690 : {
1691 3940125 : unsigned int neighbor_dim = neighbor->dim();
1692 : mooseAssert(_current_neighbor_subdomain_id == neighbor->subdomain_id(),
1693 : "Neighbor subdomain ID has not been correctly set");
1694 :
1695 : ArbitraryQuadrature * neighbor_rule =
1696 3940125 : qrules(neighbor_dim, _current_neighbor_subdomain_id).neighbor.get();
1697 3940125 : neighbor_rule->setPoints(reference_points);
1698 3940125 : setNeighborQRule(neighbor_rule, neighbor_dim);
1699 :
1700 3940125 : _current_neighbor_elem = neighbor;
1701 : mooseAssert(_current_neighbor_subdomain_id == _current_neighbor_elem->subdomain_id(),
1702 : "current neighbor subdomain has been set incorrectly");
1703 :
1704 : // Calculate the volume of the neighbor
1705 3940125 : if (_need_neighbor_elem_volume)
1706 : {
1707 2205452 : unsigned int dim = neighbor->dim();
1708 2205452 : FEBase & fe = *_holder_fe_neighbor_helper[dim];
1709 2205452 : QBase * qrule = qrules(dim).vol.get();
1710 :
1711 2205452 : fe.attach_quadrature_rule(qrule);
1712 2205452 : fe.reinit(neighbor);
1713 :
1714 2205452 : const std::vector<Real> & JxW = fe.get_JxW();
1715 2205452 : MooseArray<Point> q_points;
1716 2205452 : q_points.shallowCopy(const_cast<std::vector<Point> &>(fe.get_xyz()));
1717 :
1718 2205452 : setCoordinateTransformation(qrule, q_points, _coord_neighbor, _current_neighbor_subdomain_id);
1719 :
1720 2205452 : _current_neighbor_volume = 0.;
1721 17540623 : for (unsigned int qp = 0; qp < qrule->n_points(); qp++)
1722 15335171 : _current_neighbor_volume += JxW[qp] * _coord_neighbor[qp];
1723 2205452 : }
1724 :
1725 3940125 : auto n = numExtraElemIntegers();
1726 4021205 : for (auto i : make_range(n))
1727 81080 : _neighbor_extra_elem_ids[i] = _current_neighbor_elem->get_extra_integer(i);
1728 3940125 : _neighbor_extra_elem_ids[n] = _current_neighbor_elem->subdomain_id();
1729 3940125 : }
1730 :
1731 : template <typename Points, typename Coords>
1732 : void
1733 412622227 : Assembly::setCoordinateTransformation(const QBase * qrule,
1734 : const Points & q_points,
1735 : Coords & coord,
1736 : SubdomainID sub_id)
1737 : {
1738 :
1739 : mooseAssert(qrule, "The quadrature rule is null in Assembly::setCoordinateTransformation");
1740 412622227 : auto n_points = qrule->n_points();
1741 : mooseAssert(n_points == q_points.size(),
1742 : "The number of points in the quadrature rule doesn't match the number of passed-in "
1743 : "points in Assembly::setCoordinateTransformation");
1744 :
1745 : // Make sure to honor the name of this method and set the _coord_type member because users may
1746 : // make use of the const Moose::CoordinateSystem & coordTransformation() { return _coord_type; }
1747 : // API. MaterialBase for example uses it
1748 412622227 : _coord_type = _subproblem.getCoordSystem(sub_id);
1749 :
1750 412622227 : coord.resize(n_points);
1751 2220289070 : for (unsigned int qp = 0; qp < n_points; qp++)
1752 1807666843 : coordTransformFactor(_subproblem, sub_id, q_points[qp], coord[qp]);
1753 412622227 : }
1754 :
1755 : void
1756 385394683 : Assembly::computeCurrentElemVolume()
1757 : {
1758 385394683 : if (_current_elem_volume_computed)
1759 0 : return;
1760 :
1761 385394683 : setCoordinateTransformation(
1762 385394683 : _current_qrule, _current_q_points, _coord, _current_elem->subdomain_id());
1763 385394683 : if (_calculate_ad_coord)
1764 12786190 : setCoordinateTransformation(
1765 12786190 : _current_qrule, _ad_q_points, _ad_coord, _current_elem->subdomain_id());
1766 :
1767 385394683 : _current_elem_volume = 0.;
1768 2099969563 : for (unsigned int qp = 0; qp < _current_qrule->n_points(); qp++)
1769 1714574880 : _current_elem_volume += _current_JxW[qp] * _coord[qp];
1770 :
1771 385394683 : _current_elem_volume_computed = true;
1772 : }
1773 :
1774 : void
1775 9110361 : Assembly::computeCurrentFaceVolume()
1776 : {
1777 9110361 : if (_current_side_volume_computed)
1778 0 : return;
1779 :
1780 9110361 : setCoordinateTransformation(
1781 9110361 : _current_qrule_face, _current_q_points_face, _coord, _current_elem->subdomain_id());
1782 9110361 : if (_calculate_ad_coord)
1783 1994365 : setCoordinateTransformation(
1784 1994365 : _current_qrule_face, _ad_q_points_face, _ad_coord, _current_elem->subdomain_id());
1785 :
1786 9110361 : _current_side_volume = 0.;
1787 30337888 : for (unsigned int qp = 0; qp < _current_qrule_face->n_points(); qp++)
1788 21227527 : _current_side_volume += _current_JxW_face[qp] * _coord[qp];
1789 :
1790 9110361 : _current_side_volume_computed = true;
1791 : }
1792 :
1793 : void
1794 362544 : Assembly::reinitAtPhysical(const Elem * elem, const std::vector<Point> & physical_points)
1795 : {
1796 362544 : _current_elem = elem;
1797 362544 : _current_neighbor_elem = nullptr;
1798 : mooseAssert(_current_subdomain_id == _current_elem->subdomain_id(),
1799 : "current subdomain has been set incorrectly");
1800 362544 : _current_elem_volume_computed = false;
1801 :
1802 362544 : FEMap::inverse_map(elem->dim(), elem, physical_points, _temp_reference_points);
1803 :
1804 362544 : reinit(elem, _temp_reference_points);
1805 :
1806 : // Save off the physical points
1807 362544 : _current_physical_points = physical_points;
1808 362544 : }
1809 :
1810 : void
1811 385107527 : Assembly::setVolumeQRule(const Elem * const elem)
1812 : {
1813 385107527 : unsigned int elem_dimension = elem->dim();
1814 385107527 : _current_qrule_volume = qrules(elem_dimension).vol.get();
1815 : // Make sure the qrule is the right one
1816 385107527 : if (_current_qrule != _current_qrule_volume)
1817 196509 : setVolumeQRule(_current_qrule_volume, elem_dimension);
1818 385107527 : }
1819 :
1820 : void
1821 385032163 : Assembly::reinit(const Elem * elem)
1822 : {
1823 385032163 : _current_elem = elem;
1824 385032163 : _current_neighbor_elem = nullptr;
1825 : mooseAssert(_current_subdomain_id == _current_elem->subdomain_id(),
1826 : "current subdomain has been set incorrectly");
1827 385032163 : _current_elem_volume_computed = false;
1828 385032163 : setVolumeQRule(elem);
1829 385032163 : reinitFE(elem);
1830 :
1831 385032139 : computeCurrentElemVolume();
1832 385032139 : }
1833 :
1834 : void
1835 362544 : Assembly::reinit(const Elem * elem, const std::vector<Point> & reference_points)
1836 : {
1837 362544 : _current_elem = elem;
1838 362544 : _current_neighbor_elem = nullptr;
1839 : mooseAssert(_current_subdomain_id == _current_elem->subdomain_id(),
1840 : "current subdomain has been set incorrectly");
1841 362544 : _current_elem_volume_computed = false;
1842 :
1843 362544 : unsigned int elem_dimension = _current_elem->dim();
1844 :
1845 362544 : _current_qrule_arbitrary = qrules(elem_dimension).arbitrary_vol.get();
1846 :
1847 : // Make sure the qrule is the right one
1848 362544 : if (_current_qrule != _current_qrule_arbitrary)
1849 30594 : setVolumeQRule(_current_qrule_arbitrary, elem_dimension);
1850 :
1851 362544 : _current_qrule_arbitrary->setPoints(reference_points);
1852 :
1853 362544 : reinitFE(elem);
1854 :
1855 362544 : computeCurrentElemVolume();
1856 362544 : }
1857 :
1858 : void
1859 17673279 : Assembly::reinitFVFace(const FaceInfo & fi)
1860 : {
1861 17673279 : _current_elem = &fi.elem();
1862 17673279 : _current_neighbor_elem = fi.neighborPtr();
1863 17673279 : _current_side = fi.elemSideID();
1864 17673279 : _current_neighbor_side = fi.neighborSideID();
1865 : mooseAssert(_current_subdomain_id == _current_elem->subdomain_id(),
1866 : "current subdomain has been set incorrectly");
1867 :
1868 17673279 : _current_elem_volume_computed = false;
1869 17673279 : _current_side_volume_computed = false;
1870 :
1871 17673279 : prepareResidual();
1872 17673279 : prepareNeighbor();
1873 17673279 : prepareJacobianBlock();
1874 :
1875 17673279 : unsigned int dim = _current_elem->dim();
1876 17673279 : if (_current_qrule_face != qrules(dim).fv_face.get())
1877 : {
1878 4216 : setFaceQRule(qrules(dim).fv_face.get(), dim);
1879 : // The order of the element that is used for initing here doesn't matter since this will just
1880 : // be used for constant monomials (which only need a single integration point)
1881 4216 : if (dim == 3)
1882 11 : _current_qrule_face->init(QUAD4, /* p_level = */ 0, /* simple_type_only = */ true);
1883 : else
1884 4205 : _current_qrule_face->init(EDGE2, /* p_level = */ 0, /* simple_type_only = */ true);
1885 : }
1886 :
1887 17673279 : _current_side_elem = &_current_side_elem_builder(*_current_elem, _current_side);
1888 :
1889 : mooseAssert(_current_qrule_face->n_points() == 1,
1890 : "Our finite volume quadrature rule should always yield a single point");
1891 :
1892 : // We've initialized the reference points. Now we need to compute the physical location of the
1893 : // quadrature points. We do not do any FE initialization so we cannot simply copy over FE
1894 : // results like we do in reinitFEFace. Instead we handle the computation of the physical
1895 : // locations manually
1896 17673279 : _current_q_points_face.resize(1);
1897 17673279 : const auto & ref_points = _current_qrule_face->get_points();
1898 17673279 : const auto & ref_point = ref_points[0];
1899 17673279 : auto physical_point = FEMap::map(_current_side_elem->dim(), _current_side_elem, ref_point);
1900 17673279 : _current_q_points_face[0] = physical_point;
1901 :
1902 17673279 : if (_current_neighbor_elem)
1903 : {
1904 : mooseAssert(_current_neighbor_subdomain_id == _current_neighbor_elem->subdomain_id(),
1905 : "current neighbor subdomain has been set incorrectly");
1906 : // Now handle the neighbor qrule/qpoints
1907 : ArbitraryQuadrature * const neighbor_rule =
1908 16092122 : qrules(_current_neighbor_elem->dim(), _current_neighbor_subdomain_id).neighbor.get();
1909 : // Here we are setting a reference point that is correct for the neighbor *side* element. It
1910 : // would be wrong if this reference point is used for a volumetric FE reinit with the neighbor
1911 16092122 : neighbor_rule->setPoints(ref_points);
1912 16092122 : setNeighborQRule(neighbor_rule, _current_neighbor_elem->dim());
1913 16092122 : _current_q_points_face_neighbor.resize(1);
1914 16092122 : _current_q_points_face_neighbor[0] = std::move(physical_point);
1915 : }
1916 17673279 : }
1917 :
1918 : QBase *
1919 9110361 : Assembly::qruleFace(const Elem * elem, unsigned int side)
1920 : {
1921 18410035 : return qruleFaceHelper<QBase>(elem, side, [](QRules & q) { return q.face.get(); });
1922 : }
1923 :
1924 : ArbitraryQuadrature *
1925 584100 : Assembly::qruleArbitraryFace(const Elem * elem, unsigned int side)
1926 : {
1927 1168200 : return qruleFaceHelper<ArbitraryQuadrature>(
1928 1752300 : elem, side, [](QRules & q) { return q.arbitrary_face.get(); });
1929 : }
1930 :
1931 : void
1932 9110361 : Assembly::setFaceQRule(const Elem * const elem, const unsigned int side)
1933 : {
1934 9110361 : const auto elem_dimension = elem->dim();
1935 : //// Make sure the qrule is the right one
1936 9110361 : auto rule = qruleFace(elem, side);
1937 9110361 : if (_current_qrule_face != rule)
1938 11745 : setFaceQRule(rule, elem_dimension);
1939 9110361 : }
1940 :
1941 : void
1942 9110361 : Assembly::reinit(const Elem * const elem, const unsigned int side)
1943 : {
1944 9110361 : _current_elem = elem;
1945 9110361 : _current_neighbor_elem = nullptr;
1946 : mooseAssert(_current_subdomain_id == _current_elem->subdomain_id(),
1947 : "current subdomain has been set incorrectly");
1948 9110361 : _current_side = side;
1949 9110361 : _current_elem_volume_computed = false;
1950 9110361 : _current_side_volume_computed = false;
1951 :
1952 9110361 : _current_side_elem = &_current_side_elem_builder(*elem, side);
1953 :
1954 9110361 : setFaceQRule(elem, side);
1955 9110361 : reinitFEFace(elem, side);
1956 :
1957 9110361 : computeCurrentFaceVolume();
1958 9110361 : }
1959 :
1960 : void
1961 0 : Assembly::reinit(const Elem * elem, unsigned int side, const std::vector<Point> & reference_points)
1962 : {
1963 0 : _current_elem = elem;
1964 0 : _current_neighbor_elem = nullptr;
1965 : mooseAssert(_current_subdomain_id == _current_elem->subdomain_id(),
1966 : "current subdomain has been set incorrectly");
1967 0 : _current_side = side;
1968 0 : _current_elem_volume_computed = false;
1969 0 : _current_side_volume_computed = false;
1970 :
1971 0 : unsigned int elem_dimension = _current_elem->dim();
1972 :
1973 0 : _current_qrule_arbitrary_face = qruleArbitraryFace(elem, side);
1974 :
1975 : // Make sure the qrule is the right one
1976 0 : if (_current_qrule_face != _current_qrule_arbitrary_face)
1977 0 : setFaceQRule(_current_qrule_arbitrary_face, elem_dimension);
1978 :
1979 0 : _current_qrule_arbitrary->setPoints(reference_points);
1980 :
1981 0 : _current_side_elem = &_current_side_elem_builder(*elem, side);
1982 :
1983 0 : reinitFEFace(elem, side);
1984 :
1985 0 : computeCurrentFaceVolume();
1986 0 : }
1987 :
1988 : void
1989 100790072 : Assembly::reinit(const Node * node)
1990 : {
1991 100790072 : _current_node = node;
1992 100790072 : _current_neighbor_node = NULL;
1993 100790072 : }
1994 :
1995 : void
1996 3771719 : Assembly::reinitElemAndNeighbor(const Elem * elem,
1997 : unsigned int side,
1998 : const Elem * neighbor,
1999 : unsigned int neighbor_side,
2000 : const std::vector<Point> * neighbor_reference_points)
2001 : {
2002 3771719 : _current_neighbor_side = neighbor_side;
2003 :
2004 3771719 : reinit(elem, side);
2005 :
2006 3771719 : unsigned int neighbor_dim = neighbor->dim();
2007 :
2008 3771719 : if (neighbor_reference_points)
2009 64800 : _current_neighbor_ref_points = *neighbor_reference_points;
2010 : else
2011 3706919 : FEMap::inverse_map(
2012 7413838 : neighbor_dim, neighbor, _current_q_points_face.stdVector(), _current_neighbor_ref_points);
2013 :
2014 3771719 : _current_neighbor_side_elem = &_current_neighbor_side_elem_builder(*neighbor, neighbor_side);
2015 :
2016 3771719 : reinitFEFaceNeighbor(neighbor, _current_neighbor_ref_points);
2017 3771719 : reinitNeighbor(neighbor, _current_neighbor_ref_points);
2018 3771719 : }
2019 :
2020 : void
2021 584100 : Assembly::reinitElemFaceRef(const Elem * elem,
2022 : unsigned int elem_side,
2023 : Real tolerance,
2024 : const std::vector<Point> * const pts,
2025 : const std::vector<Real> * const weights)
2026 : {
2027 584100 : _current_elem = elem;
2028 :
2029 584100 : unsigned int elem_dim = elem->dim();
2030 :
2031 : // Attach the quadrature rules
2032 584100 : if (pts)
2033 : {
2034 584100 : auto face_rule = qruleArbitraryFace(elem, elem_side);
2035 584100 : face_rule->setPoints(*pts);
2036 584100 : setFaceQRule(face_rule, elem_dim);
2037 : }
2038 : else
2039 : {
2040 0 : auto rule = qruleFace(elem, elem_side);
2041 0 : if (_current_qrule_face != rule)
2042 0 : setFaceQRule(rule, elem_dim);
2043 : }
2044 :
2045 : // reinit face
2046 1461224 : for (const auto & it : _fe_face[elem_dim])
2047 : {
2048 877124 : FEBase & fe_face = *it.second;
2049 877124 : FEType fe_type = it.first;
2050 877124 : FEShapeData & fesd = *_fe_shape_data_face[fe_type];
2051 :
2052 877124 : fe_face.reinit(elem, elem_side, tolerance, pts, weights);
2053 :
2054 877124 : _current_fe_face[fe_type] = &fe_face;
2055 :
2056 877124 : fesd._phi.shallowCopy(const_cast<std::vector<std::vector<Real>> &>(fe_face.get_phi()));
2057 877124 : fesd._grad_phi.shallowCopy(
2058 877124 : const_cast<std::vector<std::vector<RealGradient>> &>(fe_face.get_dphi()));
2059 877124 : if (_need_second_derivative_neighbor.count(fe_type))
2060 0 : fesd._second_phi.shallowCopy(
2061 0 : const_cast<std::vector<std::vector<TensorValue<Real>>> &>(fe_face.get_d2phi()));
2062 : }
2063 584100 : for (const auto & it : _vector_fe_face[elem_dim])
2064 : {
2065 0 : FEVectorBase & fe_face = *it.second;
2066 0 : const FEType & fe_type = it.first;
2067 :
2068 0 : _current_vector_fe_face[fe_type] = &fe_face;
2069 :
2070 0 : VectorFEShapeData & fesd = *_vector_fe_shape_data_face[fe_type];
2071 :
2072 0 : fe_face.reinit(elem, elem_side, tolerance, pts, weights);
2073 :
2074 0 : fesd._phi.shallowCopy(
2075 0 : const_cast<std::vector<std::vector<VectorValue<Real>>> &>(fe_face.get_phi()));
2076 0 : fesd._grad_phi.shallowCopy(
2077 0 : const_cast<std::vector<std::vector<TensorValue<Real>>> &>(fe_face.get_dphi()));
2078 0 : if (_need_second_derivative.count(fe_type))
2079 0 : fesd._second_phi.shallowCopy(
2080 0 : const_cast<std::vector<std::vector<TypeNTensor<3, Real>>> &>(fe_face.get_d2phi()));
2081 0 : if (_need_curl.count(fe_type))
2082 0 : fesd._curl_phi.shallowCopy(
2083 0 : const_cast<std::vector<std::vector<VectorValue<Real>>> &>(fe_face.get_curl_phi()));
2084 0 : if (_need_face_div.count(fe_type))
2085 0 : fesd._div_phi.shallowCopy(
2086 0 : const_cast<std::vector<std::vector<Real>> &>(fe_face.get_div_phi()));
2087 : }
2088 584100 : if (!_unique_fe_face_helper.empty())
2089 : {
2090 : mooseAssert(elem_dim < _unique_fe_face_helper.size(), "We should be in bounds here");
2091 0 : _unique_fe_face_helper[elem_dim]->reinit(elem, elem_side, tolerance, pts, weights);
2092 : }
2093 :
2094 : // During that last loop the helper objects will have been reinitialized
2095 584100 : _current_q_points_face.shallowCopy(
2096 584100 : const_cast<std::vector<Point> &>(_holder_fe_face_helper[elem_dim]->get_xyz()));
2097 584100 : _current_normals.shallowCopy(
2098 584100 : const_cast<std::vector<Point> &>(_holder_fe_face_helper[elem_dim]->get_normals()));
2099 584100 : _current_tangents.shallowCopy(const_cast<std::vector<std::vector<Point>> &>(
2100 584100 : _holder_fe_face_helper[elem_dim]->get_tangents()));
2101 : // Note that if the user did pass in points and not weights to this method, JxW will be garbage
2102 : // and should not be used
2103 584100 : _current_JxW_face.shallowCopy(
2104 584100 : const_cast<std::vector<Real> &>(_holder_fe_face_helper[elem_dim]->get_JxW()));
2105 584100 : if (_calculate_curvatures)
2106 0 : _curvatures.shallowCopy(
2107 0 : const_cast<std::vector<Real> &>(_holder_fe_face_helper[elem_dim]->get_curvatures()));
2108 :
2109 584100 : computeADFace(*elem, elem_side);
2110 584100 : }
2111 :
2112 : void
2113 9694461 : Assembly::computeADFace(const Elem & elem, const unsigned int side)
2114 : {
2115 9694461 : const auto dim = elem.dim();
2116 :
2117 9694461 : if (_subproblem.haveADObjects())
2118 : {
2119 2841089 : auto n_qp = _current_qrule_face->n_points();
2120 2841089 : resizeADMappingObjects(n_qp, dim);
2121 2841089 : _ad_normals.resize(n_qp);
2122 2841089 : _ad_JxW_face.resize(n_qp);
2123 2841089 : if (_calculate_face_xyz)
2124 2011695 : _ad_q_points_face.resize(n_qp);
2125 2841089 : if (_calculate_curvatures)
2126 416 : _ad_curvatures.resize(n_qp);
2127 :
2128 2841089 : if (_displaced)
2129 : {
2130 52499 : const auto & qw = _current_qrule_face->get_weights();
2131 52499 : computeFaceMap(elem, side, qw);
2132 52499 : const std::vector<Real> dummy_qw(n_qp, 1.);
2133 :
2134 157352 : for (unsigned int qp = 0; qp != n_qp; qp++)
2135 104853 : computeSinglePointMapAD(&elem, dummy_qw, qp, _holder_fe_face_helper[dim]);
2136 52499 : }
2137 : else
2138 : {
2139 10581383 : for (unsigned qp = 0; qp < n_qp; ++qp)
2140 : {
2141 7792793 : _ad_JxW_face[qp] = _current_JxW_face[qp];
2142 7792793 : _ad_normals[qp] = _current_normals[qp];
2143 : }
2144 2788590 : if (_calculate_face_xyz)
2145 6191912 : for (unsigned qp = 0; qp < n_qp; ++qp)
2146 4210064 : _ad_q_points_face[qp] = _current_q_points_face[qp];
2147 2788590 : if (_calculate_curvatures)
2148 832 : for (unsigned qp = 0; qp < n_qp; ++qp)
2149 416 : _ad_curvatures[qp] = _curvatures[qp];
2150 : }
2151 :
2152 7526774 : for (const auto & it : _fe_face[dim])
2153 : {
2154 4685685 : FEBase & fe = *it.second;
2155 4685685 : auto fe_type = it.first;
2156 4685685 : auto num_shapes = FEInterface::n_shape_functions(fe_type, &elem);
2157 4685685 : auto & grad_phi = _ad_grad_phi_data_face[fe_type];
2158 :
2159 4685685 : grad_phi.resize(num_shapes);
2160 36243049 : for (decltype(num_shapes) i = 0; i < num_shapes; ++i)
2161 31557364 : grad_phi[i].resize(n_qp);
2162 :
2163 4685685 : const auto & regular_grad_phi = _fe_shape_data_face[fe_type]->_grad_phi;
2164 :
2165 4685685 : if (_displaced)
2166 125017 : computeGradPhiAD(&elem, n_qp, grad_phi, &fe);
2167 : else
2168 35492386 : for (decltype(num_shapes) i = 0; i < num_shapes; ++i)
2169 145696693 : for (unsigned qp = 0; qp < n_qp; ++qp)
2170 114764975 : grad_phi[i][qp] = regular_grad_phi[i][qp];
2171 : }
2172 3269427 : for (const auto & it : _vector_fe_face[dim])
2173 : {
2174 428338 : FEVectorBase & fe = *it.second;
2175 428338 : auto fe_type = it.first;
2176 428338 : auto num_shapes = FEInterface::n_shape_functions(fe_type, &elem);
2177 428338 : auto & grad_phi = _ad_vector_grad_phi_data_face[fe_type];
2178 :
2179 428338 : grad_phi.resize(num_shapes);
2180 2255050 : for (decltype(num_shapes) i = 0; i < num_shapes; ++i)
2181 1826712 : grad_phi[i].resize(n_qp);
2182 :
2183 428338 : const auto & regular_grad_phi = _vector_fe_shape_data_face[fe_type]->_grad_phi;
2184 :
2185 428338 : if (_displaced)
2186 0 : computeGradPhiAD(&elem, n_qp, grad_phi, &fe);
2187 : else
2188 2255050 : for (decltype(num_shapes) i = 0; i < num_shapes; ++i)
2189 5589456 : for (unsigned qp = 0; qp < n_qp; ++qp)
2190 3762744 : grad_phi[i][qp] = regular_grad_phi[i][qp];
2191 : }
2192 : }
2193 9694461 : }
2194 :
2195 : void
2196 584100 : Assembly::reinitNeighborFaceRef(const Elem * neighbor,
2197 : unsigned int neighbor_side,
2198 : Real tolerance,
2199 : const std::vector<Point> * const pts,
2200 : const std::vector<Real> * const weights)
2201 : {
2202 584100 : _current_neighbor_elem = neighbor;
2203 :
2204 584100 : unsigned int neighbor_dim = neighbor->dim();
2205 :
2206 : ArbitraryQuadrature * neighbor_rule =
2207 584100 : qrules(neighbor_dim, neighbor->subdomain_id()).neighbor.get();
2208 584100 : neighbor_rule->setPoints(*pts);
2209 :
2210 : // Attach this quadrature rule to all the _fe_face_neighbor FE objects. This
2211 : // has to have garbage quadrature weights but that's ok because we never
2212 : // actually use the JxW coming from these FE reinit'd objects, e.g. we use the
2213 : // JxW coming from the element face reinit for DGKernels or we use the JxW
2214 : // coming from reinit of the mortar segment element in the case of mortar
2215 584100 : setNeighborQRule(neighbor_rule, neighbor_dim);
2216 :
2217 : // reinit neighbor face
2218 1461224 : for (const auto & it : _fe_face_neighbor[neighbor_dim])
2219 : {
2220 877124 : FEBase & fe_face_neighbor = *it.second;
2221 877124 : FEType fe_type = it.first;
2222 877124 : FEShapeData & fesd = *_fe_shape_data_face_neighbor[fe_type];
2223 :
2224 877124 : fe_face_neighbor.reinit(neighbor, neighbor_side, tolerance, pts, weights);
2225 :
2226 877124 : _current_fe_face_neighbor[fe_type] = &fe_face_neighbor;
2227 :
2228 877124 : fesd._phi.shallowCopy(const_cast<std::vector<std::vector<Real>> &>(fe_face_neighbor.get_phi()));
2229 877124 : fesd._grad_phi.shallowCopy(
2230 877124 : const_cast<std::vector<std::vector<RealGradient>> &>(fe_face_neighbor.get_dphi()));
2231 877124 : if (_need_second_derivative_neighbor.count(fe_type))
2232 0 : fesd._second_phi.shallowCopy(
2233 0 : const_cast<std::vector<std::vector<TensorValue<Real>>> &>(fe_face_neighbor.get_d2phi()));
2234 : }
2235 584100 : for (const auto & it : _vector_fe_face_neighbor[neighbor_dim])
2236 : {
2237 0 : FEVectorBase & fe_face_neighbor = *it.second;
2238 0 : const FEType & fe_type = it.first;
2239 :
2240 0 : _current_vector_fe_face_neighbor[fe_type] = &fe_face_neighbor;
2241 :
2242 0 : VectorFEShapeData & fesd = *_vector_fe_shape_data_face_neighbor[fe_type];
2243 :
2244 0 : fe_face_neighbor.reinit(neighbor, neighbor_side, tolerance, pts, weights);
2245 :
2246 0 : fesd._phi.shallowCopy(
2247 0 : const_cast<std::vector<std::vector<VectorValue<Real>>> &>(fe_face_neighbor.get_phi()));
2248 0 : fesd._grad_phi.shallowCopy(
2249 0 : const_cast<std::vector<std::vector<TensorValue<Real>>> &>(fe_face_neighbor.get_dphi()));
2250 0 : if (_need_second_derivative.count(fe_type))
2251 0 : fesd._second_phi.shallowCopy(const_cast<std::vector<std::vector<TypeNTensor<3, Real>>> &>(
2252 0 : fe_face_neighbor.get_d2phi()));
2253 0 : if (_need_curl.count(fe_type))
2254 0 : fesd._curl_phi.shallowCopy(const_cast<std::vector<std::vector<VectorValue<Real>>> &>(
2255 0 : fe_face_neighbor.get_curl_phi()));
2256 0 : if (_need_face_neighbor_div.count(fe_type))
2257 0 : fesd._div_phi.shallowCopy(
2258 0 : const_cast<std::vector<std::vector<Real>> &>(fe_face_neighbor.get_div_phi()));
2259 : }
2260 584100 : if (!_unique_fe_face_neighbor_helper.empty())
2261 : {
2262 : mooseAssert(neighbor_dim < _unique_fe_face_neighbor_helper.size(),
2263 : "We should be in bounds here");
2264 0 : _unique_fe_face_neighbor_helper[neighbor_dim]->reinit(
2265 : neighbor, neighbor_side, tolerance, pts, weights);
2266 : }
2267 : // During that last loop the helper objects will have been reinitialized as well
2268 : // We need to dig out the q_points from it
2269 584100 : _current_q_points_face_neighbor.shallowCopy(
2270 584100 : const_cast<std::vector<Point> &>(_holder_fe_face_neighbor_helper[neighbor_dim]->get_xyz()));
2271 584100 : }
2272 :
2273 : void
2274 4057 : Assembly::reinitDual(const Elem * elem,
2275 : const std::vector<Point> & pts,
2276 : const std::vector<Real> & JxW)
2277 : {
2278 4057 : const unsigned int elem_dim = elem->dim();
2279 : mooseAssert(elem_dim == _mesh_dimension - 1,
2280 : "Dual shape functions should only be computed on lower dimensional face elements");
2281 :
2282 8390 : for (const auto & it : _fe_lower[elem_dim])
2283 : {
2284 4333 : FEBase & fe_lower = *it.second;
2285 : // We use customized quadrature rule for integration along the mortar segment elements
2286 4333 : fe_lower.set_calculate_default_dual_coeff(false);
2287 4333 : fe_lower.reinit_dual_shape_coeffs(elem, pts, JxW);
2288 : }
2289 4057 : }
2290 :
2291 : void
2292 600003 : Assembly::reinitLowerDElem(const Elem * elem,
2293 : const std::vector<Point> * const pts,
2294 : const std::vector<Real> * const weights)
2295 : {
2296 600003 : _current_lower_d_elem = elem;
2297 :
2298 600003 : const unsigned int elem_dim = elem->dim();
2299 : mooseAssert(elem_dim < _mesh_dimension,
2300 : "The lower dimensional element should truly be a lower dimensional element");
2301 :
2302 600003 : if (pts)
2303 : {
2304 : // Lower rule matches the face rule for the higher dimensional element
2305 564004 : ArbitraryQuadrature * lower_rule = qrules(elem_dim + 1).arbitrary_face.get();
2306 :
2307 : // This also sets the quadrature weights to unity
2308 564004 : lower_rule->setPoints(*pts);
2309 :
2310 564004 : if (weights)
2311 0 : lower_rule->setWeights(*weights);
2312 :
2313 564004 : setLowerQRule(lower_rule, elem_dim);
2314 : }
2315 35999 : else if (_current_qrule_lower != qrules(elem_dim + 1).face.get())
2316 413 : setLowerQRule(qrules(elem_dim + 1).face.get(), elem_dim);
2317 :
2318 1527006 : for (const auto & it : _fe_lower[elem_dim])
2319 : {
2320 927003 : FEBase & fe_lower = *it.second;
2321 927003 : FEType fe_type = it.first;
2322 :
2323 927003 : fe_lower.reinit(elem);
2324 :
2325 927003 : if (FEShapeData * fesd = _fe_shape_data_lower[fe_type].get())
2326 : {
2327 927003 : fesd->_phi.shallowCopy(const_cast<std::vector<std::vector<Real>> &>(fe_lower.get_phi()));
2328 927003 : fesd->_grad_phi.shallowCopy(
2329 927003 : const_cast<std::vector<std::vector<RealGradient>> &>(fe_lower.get_dphi()));
2330 927003 : if (_need_second_derivative_neighbor.count(fe_type))
2331 0 : fesd->_second_phi.shallowCopy(
2332 0 : const_cast<std::vector<std::vector<TensorValue<Real>>> &>(fe_lower.get_d2phi()));
2333 : }
2334 :
2335 : // Dual shape functions need to be computed after primal basis being initialized
2336 927003 : if (FEShapeData * fesd = _fe_shape_data_dual_lower[fe_type].get())
2337 : {
2338 12142 : fesd->_phi.shallowCopy(const_cast<std::vector<std::vector<Real>> &>(fe_lower.get_dual_phi()));
2339 12142 : fesd->_grad_phi.shallowCopy(
2340 12142 : const_cast<std::vector<std::vector<RealGradient>> &>(fe_lower.get_dual_dphi()));
2341 12142 : if (_need_second_derivative_neighbor.count(fe_type))
2342 0 : fesd->_second_phi.shallowCopy(
2343 0 : const_cast<std::vector<std::vector<TensorValue<Real>>> &>(fe_lower.get_dual_d2phi()));
2344 : }
2345 : }
2346 600003 : if (!_unique_fe_lower_helper.empty())
2347 : {
2348 : mooseAssert(elem_dim < _unique_fe_lower_helper.size(), "We should be in bounds here");
2349 0 : _unique_fe_lower_helper[elem_dim]->reinit(elem);
2350 : }
2351 :
2352 600003 : if (!_need_lower_d_elem_volume)
2353 190241 : return;
2354 :
2355 409762 : if (pts && !weights)
2356 : {
2357 : // We only have dummy weights so the JxWs computed during our FE reinits are meaningless and
2358 : // we cannot use them
2359 :
2360 813188 : if (_subproblem.getCoordSystem(elem->subdomain_id()) == Moose::CoordinateSystemType::COORD_XYZ)
2361 : // We are in a Cartesian coordinate system and we can just use the element volume method
2362 : // which has fast computation for certain element types
2363 406594 : _current_lower_d_elem_volume = elem->volume();
2364 : else
2365 : // We manually compute the volume taking the curvilinear coordinate transformations into
2366 : // account
2367 0 : _current_lower_d_elem_volume = elementVolume(elem);
2368 : }
2369 : else
2370 : {
2371 : // During that last loop the helper objects will have been reinitialized as well
2372 3168 : FEBase & helper_fe = *_holder_fe_lower_helper[elem_dim];
2373 3168 : const auto & physical_q_points = helper_fe.get_xyz();
2374 3168 : const auto & JxW = helper_fe.get_JxW();
2375 3168 : MooseArray<Real> coord;
2376 3168 : setCoordinateTransformation(
2377 3168 : _current_qrule_lower, physical_q_points, coord, elem->subdomain_id());
2378 3168 : _current_lower_d_elem_volume = 0;
2379 46944 : for (const auto qp : make_range(_current_qrule_lower->n_points()))
2380 43776 : _current_lower_d_elem_volume += JxW[qp] * coord[qp];
2381 3168 : }
2382 : }
2383 :
2384 : void
2385 564004 : Assembly::reinitNeighborLowerDElem(const Elem * elem)
2386 : {
2387 : mooseAssert(elem->dim() < _mesh_dimension,
2388 : "You should be calling reinitNeighborLowerDElem on a lower dimensional element");
2389 :
2390 564004 : _current_neighbor_lower_d_elem = elem;
2391 :
2392 564004 : if (!_need_neighbor_lower_d_elem_volume)
2393 157410 : return;
2394 :
2395 406594 : if (_subproblem.getCoordSystem(elem->subdomain_id()) == Moose::CoordinateSystemType::COORD_XYZ)
2396 : // We are in a Cartesian coordinate system and we can just use the element volume method which
2397 : // has fast computation for certain element types
2398 406594 : _current_neighbor_lower_d_elem_volume = elem->volume();
2399 : else
2400 : // We manually compute the volume taking the curvilinear coordinate transformations into
2401 : // account
2402 0 : _current_neighbor_lower_d_elem_volume = elementVolume(elem);
2403 : }
2404 :
2405 : void
2406 1128008 : Assembly::reinitMortarElem(const Elem * elem)
2407 : {
2408 : mooseAssert(elem->dim() == _mesh_dimension - 1,
2409 : "You should be calling reinitMortarElem on a lower dimensional element");
2410 :
2411 1128008 : _fe_msm->reinit(elem);
2412 1128008 : _msm_elem = elem;
2413 :
2414 1128008 : MooseArray<Point> array_q_points;
2415 1128008 : array_q_points.shallowCopy(const_cast<std::vector<Point> &>(_fe_msm->get_xyz()));
2416 1128008 : setCoordinateTransformation(_qrule_msm, array_q_points, _coord_msm, elem->subdomain_id());
2417 1128008 : }
2418 :
2419 : void
2420 148526 : Assembly::reinitNeighborAtPhysical(const Elem * neighbor,
2421 : unsigned int neighbor_side,
2422 : const std::vector<Point> & physical_points)
2423 : {
2424 148526 : unsigned int neighbor_dim = neighbor->dim();
2425 148526 : FEMap::inverse_map(neighbor_dim, neighbor, physical_points, _current_neighbor_ref_points);
2426 :
2427 148526 : if (_need_JxW_neighbor)
2428 : {
2429 : mooseAssert(
2430 : physical_points.size() == 1,
2431 : "If reinitializing with more than one point, then I am dubious of your use case. Perhaps "
2432 : "you are performing a DG type method and you are reinitializing using points from the "
2433 : "element face. In such a case your neighbor JxW must have its index order 'match' the "
2434 : "element JxW index order, e.g. imagining a vertical 1D face with two quadrature points, "
2435 : "if "
2436 : "index 0 for elem JxW corresponds to the 'top' quadrature point, then index 0 for "
2437 : "neighbor "
2438 : "JxW must also correspond to the 'top' quadrature point. And libMesh/MOOSE has no way to "
2439 : "guarantee that with multiple quadrature points.");
2440 :
2441 97230 : _current_neighbor_side_elem = &_current_neighbor_side_elem_builder(*neighbor, neighbor_side);
2442 :
2443 : // With a single point our size-1 JxW should just be the element volume
2444 97230 : _current_JxW_neighbor.resize(1);
2445 97230 : _current_JxW_neighbor[0] = _current_neighbor_side_elem->volume();
2446 : }
2447 :
2448 148526 : reinitFEFaceNeighbor(neighbor, _current_neighbor_ref_points);
2449 148526 : reinitNeighbor(neighbor, _current_neighbor_ref_points);
2450 :
2451 : // Save off the physical points
2452 148526 : _current_physical_points = physical_points;
2453 148526 : }
2454 :
2455 : void
2456 19880 : Assembly::reinitNeighborAtPhysical(const Elem * neighbor,
2457 : const std::vector<Point> & physical_points)
2458 : {
2459 19880 : unsigned int neighbor_dim = neighbor->dim();
2460 19880 : FEMap::inverse_map(neighbor_dim, neighbor, physical_points, _current_neighbor_ref_points);
2461 :
2462 19880 : reinitFENeighbor(neighbor, _current_neighbor_ref_points);
2463 19880 : reinitNeighbor(neighbor, _current_neighbor_ref_points);
2464 : // Save off the physical points
2465 19880 : _current_physical_points = physical_points;
2466 19880 : }
2467 :
2468 : void
2469 68960 : Assembly::init(const CouplingMatrix * cm)
2470 : {
2471 68960 : _cm = cm;
2472 :
2473 68960 : unsigned int n_vars = _sys.nVariables();
2474 :
2475 68960 : _cm_ss_entry.clear();
2476 68960 : _cm_sf_entry.clear();
2477 68960 : _cm_fs_entry.clear();
2478 68960 : _cm_ff_entry.clear();
2479 :
2480 68960 : auto & vars = _sys.getVariables(_tid);
2481 :
2482 68960 : _block_diagonal_matrix = true;
2483 136006 : for (auto & ivar : vars)
2484 : {
2485 67046 : auto i = ivar->number();
2486 67046 : if (i >= _component_block_diagonal.size())
2487 67046 : _component_block_diagonal.resize(i + 1, true);
2488 :
2489 67046 : auto ivar_start = _cm_ff_entry.size();
2490 135793 : for (unsigned int k = 0; k < ivar->count(); ++k)
2491 : {
2492 68747 : unsigned int iv = i + k;
2493 160387 : for (const auto & j : ConstCouplingRow(iv, *_cm))
2494 : {
2495 91640 : if (_sys.isScalarVariable(j))
2496 : {
2497 1151 : auto & jvar = _sys.getScalarVariable(_tid, j);
2498 1151 : _cm_fs_entry.push_back(std::make_pair(ivar, &jvar));
2499 1151 : _block_diagonal_matrix = false;
2500 : }
2501 : else
2502 : {
2503 90489 : auto & jvar = _sys.getVariable(_tid, j);
2504 90489 : auto pair = std::make_pair(ivar, &jvar);
2505 90489 : auto c = ivar_start;
2506 : // check if the pair has been pushed or not
2507 90489 : bool has_pair = false;
2508 117587 : for (; c < _cm_ff_entry.size(); ++c)
2509 32935 : if (_cm_ff_entry[c] == pair)
2510 : {
2511 5837 : has_pair = true;
2512 5837 : break;
2513 : }
2514 90489 : if (!has_pair)
2515 84652 : _cm_ff_entry.push_back(pair);
2516 : // only set having diagonal matrix to false when ivar and jvar numbers are different
2517 : // Note: for array variables, since we save the entire local Jacobian of all components,
2518 : // even there are couplings among components of the same array variable, we still
2519 : // do not set the flag to false.
2520 90489 : if (i != jvar.number())
2521 20036 : _block_diagonal_matrix = false;
2522 70453 : else if (iv != j)
2523 1706 : _component_block_diagonal[i] = false;
2524 : }
2525 : }
2526 : }
2527 : }
2528 :
2529 68960 : auto & scalar_vars = _sys.getScalarVariables(_tid);
2530 :
2531 70407 : for (auto & ivar : scalar_vars)
2532 : {
2533 1447 : auto i = ivar->number();
2534 1447 : if (i >= _component_block_diagonal.size())
2535 1383 : _component_block_diagonal.resize(i + 1, true);
2536 :
2537 4261 : for (const auto & j : ConstCouplingRow(i, *_cm))
2538 2814 : if (_sys.isScalarVariable(j))
2539 : {
2540 1663 : auto & jvar = _sys.getScalarVariable(_tid, j);
2541 1663 : _cm_ss_entry.push_back(std::make_pair(ivar, &jvar));
2542 : }
2543 : else
2544 : {
2545 1151 : auto & jvar = _sys.getVariable(_tid, j);
2546 1151 : _cm_sf_entry.push_back(std::make_pair(ivar, &jvar));
2547 : }
2548 : }
2549 :
2550 68960 : if (_block_diagonal_matrix && scalar_vars.size() != 0)
2551 409 : _block_diagonal_matrix = false;
2552 :
2553 68960 : auto num_vector_tags = _residual_vector_tags.size();
2554 :
2555 68960 : _sub_Re.resize(num_vector_tags);
2556 68960 : _sub_Rn.resize(num_vector_tags);
2557 68960 : _sub_Rl.resize(num_vector_tags);
2558 244924 : for (MooseIndex(_sub_Re) i = 0; i < _sub_Re.size(); i++)
2559 : {
2560 175964 : _sub_Re[i].resize(n_vars);
2561 175964 : _sub_Rn[i].resize(n_vars);
2562 175964 : _sub_Rl[i].resize(n_vars);
2563 : }
2564 :
2565 68960 : _cached_residual_values.resize(num_vector_tags);
2566 68960 : _cached_residual_rows.resize(num_vector_tags);
2567 :
2568 68960 : auto num_matrix_tags = _subproblem.numMatrixTags();
2569 :
2570 68960 : _cached_jacobian_values.resize(num_matrix_tags);
2571 68960 : _cached_jacobian_rows.resize(num_matrix_tags);
2572 68960 : _cached_jacobian_cols.resize(num_matrix_tags);
2573 :
2574 : // Element matrices
2575 68960 : _sub_Kee.resize(num_matrix_tags);
2576 68960 : _sub_Keg.resize(num_matrix_tags);
2577 68960 : _sub_Ken.resize(num_matrix_tags);
2578 68960 : _sub_Kne.resize(num_matrix_tags);
2579 68960 : _sub_Knn.resize(num_matrix_tags);
2580 68960 : _sub_Kll.resize(num_matrix_tags);
2581 68960 : _sub_Kle.resize(num_matrix_tags);
2582 68960 : _sub_Kln.resize(num_matrix_tags);
2583 68960 : _sub_Kel.resize(num_matrix_tags);
2584 68960 : _sub_Knl.resize(num_matrix_tags);
2585 :
2586 68960 : _jacobian_block_used.resize(num_matrix_tags);
2587 68960 : _jacobian_block_neighbor_used.resize(num_matrix_tags);
2588 68960 : _jacobian_block_lower_used.resize(num_matrix_tags);
2589 68960 : _jacobian_block_nonlocal_used.resize(num_matrix_tags);
2590 :
2591 209340 : for (MooseIndex(num_matrix_tags) tag = 0; tag < num_matrix_tags; tag++)
2592 : {
2593 140380 : _sub_Keg[tag].resize(n_vars);
2594 140380 : _sub_Ken[tag].resize(n_vars);
2595 140380 : _sub_Kne[tag].resize(n_vars);
2596 140380 : _sub_Knn[tag].resize(n_vars);
2597 140380 : _sub_Kee[tag].resize(n_vars);
2598 140380 : _sub_Kll[tag].resize(n_vars);
2599 140380 : _sub_Kle[tag].resize(n_vars);
2600 140380 : _sub_Kln[tag].resize(n_vars);
2601 140380 : _sub_Kel[tag].resize(n_vars);
2602 140380 : _sub_Knl[tag].resize(n_vars);
2603 :
2604 140380 : _jacobian_block_used[tag].resize(n_vars);
2605 140380 : _jacobian_block_neighbor_used[tag].resize(n_vars);
2606 140380 : _jacobian_block_lower_used[tag].resize(n_vars);
2607 140380 : _jacobian_block_nonlocal_used[tag].resize(n_vars);
2608 284495 : for (MooseIndex(n_vars) i = 0; i < n_vars; ++i)
2609 : {
2610 144115 : if (!_block_diagonal_matrix)
2611 : {
2612 32700 : _sub_Kee[tag][i].resize(n_vars);
2613 32700 : _sub_Keg[tag][i].resize(n_vars);
2614 32700 : _sub_Ken[tag][i].resize(n_vars);
2615 32700 : _sub_Kne[tag][i].resize(n_vars);
2616 32700 : _sub_Knn[tag][i].resize(n_vars);
2617 32700 : _sub_Kll[tag][i].resize(n_vars);
2618 32700 : _sub_Kle[tag][i].resize(n_vars);
2619 32700 : _sub_Kln[tag][i].resize(n_vars);
2620 32700 : _sub_Kel[tag][i].resize(n_vars);
2621 32700 : _sub_Knl[tag][i].resize(n_vars);
2622 :
2623 32700 : _jacobian_block_used[tag][i].resize(n_vars);
2624 32700 : _jacobian_block_neighbor_used[tag][i].resize(n_vars);
2625 32700 : _jacobian_block_lower_used[tag][i].resize(n_vars);
2626 32700 : _jacobian_block_nonlocal_used[tag][i].resize(n_vars);
2627 : }
2628 : else
2629 : {
2630 111415 : _sub_Kee[tag][i].resize(1);
2631 111415 : _sub_Keg[tag][i].resize(1);
2632 111415 : _sub_Ken[tag][i].resize(1);
2633 111415 : _sub_Kne[tag][i].resize(1);
2634 111415 : _sub_Knn[tag][i].resize(1);
2635 111415 : _sub_Kll[tag][i].resize(1);
2636 111415 : _sub_Kle[tag][i].resize(1);
2637 111415 : _sub_Kln[tag][i].resize(1);
2638 111415 : _sub_Kel[tag][i].resize(1);
2639 111415 : _sub_Knl[tag][i].resize(1);
2640 :
2641 111415 : _jacobian_block_used[tag][i].resize(1);
2642 111415 : _jacobian_block_neighbor_used[tag][i].resize(1);
2643 111415 : _jacobian_block_lower_used[tag][i].resize(1);
2644 111415 : _jacobian_block_nonlocal_used[tag][i].resize(1);
2645 : }
2646 : }
2647 : }
2648 68960 : }
2649 :
2650 : void
2651 63 : Assembly::initNonlocalCoupling()
2652 : {
2653 63 : _cm_nonlocal_entry.clear();
2654 :
2655 63 : auto & vars = _sys.getVariables(_tid);
2656 :
2657 189 : for (auto & ivar : vars)
2658 : {
2659 126 : auto i = ivar->number();
2660 126 : auto ivar_start = _cm_nonlocal_entry.size();
2661 252 : for (unsigned int k = 0; k < ivar->count(); ++k)
2662 : {
2663 126 : unsigned int iv = i + k;
2664 216 : for (const auto & j : ConstCouplingRow(iv, _nonlocal_cm))
2665 90 : if (!_sys.isScalarVariable(j))
2666 : {
2667 90 : auto & jvar = _sys.getVariable(_tid, j);
2668 90 : auto pair = std::make_pair(ivar, &jvar);
2669 90 : auto c = ivar_start;
2670 : // check if the pair has been pushed or not
2671 90 : bool has_pair = false;
2672 117 : for (; c < _cm_nonlocal_entry.size(); ++c)
2673 27 : if (_cm_nonlocal_entry[c] == pair)
2674 : {
2675 0 : has_pair = true;
2676 0 : break;
2677 : }
2678 90 : if (!has_pair)
2679 90 : _cm_nonlocal_entry.push_back(pair);
2680 : }
2681 : }
2682 : }
2683 63 : }
2684 :
2685 : void
2686 73225995 : Assembly::prepareJacobianBlock()
2687 : {
2688 179459825 : for (const auto & it : _cm_ff_entry)
2689 : {
2690 106233830 : MooseVariableFEBase & ivar = *(it.first);
2691 106233830 : MooseVariableFEBase & jvar = *(it.second);
2692 :
2693 106233830 : unsigned int vi = ivar.number();
2694 106233830 : unsigned int vj = jvar.number();
2695 :
2696 106233830 : const bool array_block_diagonal_purely_diagonal = vi == vj && _component_block_diagonal[vi];
2697 106233830 : auto num_cols = jvar.dofIndices().size();
2698 106233830 : if (array_block_diagonal_purely_diagonal)
2699 84043802 : num_cols /= jvar.count();
2700 :
2701 321343238 : for (MooseIndex(_jacobian_block_used) tag = 0; tag < _jacobian_block_used.size(); tag++)
2702 : {
2703 215109408 : jacobianBlock(vi, vj, LocalDataKey{}, tag).resize(ivar.dofIndices().size(), num_cols);
2704 215109408 : jacobianBlockUsed(tag, vi, vj, false);
2705 : }
2706 : }
2707 73225995 : }
2708 :
2709 : void
2710 403038943 : Assembly::prepareResidual()
2711 : {
2712 403038943 : const std::vector<MooseVariableFEBase *> & vars = _sys.getVariables(_tid);
2713 840914451 : for (const auto & var : vars)
2714 1641760533 : for (auto & tag_Re : _sub_Re)
2715 1203885025 : tag_Re[var->number()].resize(var->dofIndices().size());
2716 403038943 : }
2717 :
2718 : void
2719 550746 : Assembly::prepare()
2720 : {
2721 550746 : prepareJacobianBlock();
2722 550746 : prepareResidual();
2723 550746 : }
2724 :
2725 : void
2726 8824 : Assembly::prepareNonlocal()
2727 : {
2728 17862 : for (const auto & it : _cm_nonlocal_entry)
2729 : {
2730 9038 : MooseVariableFEBase & ivar = *(it.first);
2731 9038 : MooseVariableFEBase & jvar = *(it.second);
2732 :
2733 9038 : unsigned int vi = ivar.number();
2734 9038 : unsigned int vj = jvar.number();
2735 :
2736 9038 : const bool array_block_diagonal_purely_diagonal = vi == vj && _component_block_diagonal[vi];
2737 9038 : auto num_cols = jvar.allDofIndices().size();
2738 9038 : if (array_block_diagonal_purely_diagonal)
2739 334 : num_cols /= jvar.count();
2740 :
2741 27114 : for (MooseIndex(_jacobian_block_nonlocal_used) tag = 0;
2742 27114 : tag < _jacobian_block_nonlocal_used.size();
2743 : tag++)
2744 : {
2745 18076 : jacobianBlockNonlocal(vi, vj, LocalDataKey{}, tag).resize(ivar.dofIndices().size(), num_cols);
2746 18076 : jacobianBlockNonlocalUsed(tag, vi, vj, false);
2747 : }
2748 : }
2749 8824 : }
2750 :
2751 : void
2752 1338 : Assembly::prepareVariable(MooseVariableFEBase * var)
2753 : {
2754 5054 : for (const auto & it : _cm_ff_entry)
2755 : {
2756 3716 : MooseVariableFEBase & ivar = *(it.first);
2757 3716 : MooseVariableFEBase & jvar = *(it.second);
2758 :
2759 3716 : unsigned int vi = ivar.number();
2760 3716 : unsigned int vj = jvar.number();
2761 :
2762 3716 : const bool array_block_diagonal_purely_diagonal = vi == vj && _component_block_diagonal[vi];
2763 3716 : auto num_cols = jvar.dofIndices().size();
2764 3716 : if (array_block_diagonal_purely_diagonal)
2765 2444 : num_cols /= jvar.count();
2766 :
2767 3716 : if (vi == var->number() || vj == var->number())
2768 : {
2769 7830 : for (MooseIndex(_jacobian_block_used) tag = 0; tag < _jacobian_block_used.size(); tag++)
2770 : {
2771 5220 : jacobianBlock(vi, vj, LocalDataKey{}, tag).resize(ivar.dofIndices().size(), num_cols);
2772 5220 : jacobianBlockUsed(tag, vi, vj, false);
2773 : }
2774 : }
2775 : }
2776 :
2777 4650 : for (auto & tag_Re : _sub_Re)
2778 3312 : tag_Re[var->number()].resize(var->dofIndices().size());
2779 1338 : }
2780 :
2781 : void
2782 0 : Assembly::prepareVariableNonlocal(MooseVariableFEBase * var)
2783 : {
2784 0 : for (const auto & it : _cm_nonlocal_entry)
2785 : {
2786 0 : MooseVariableFEBase & ivar = *(it.first);
2787 0 : MooseVariableFEBase & jvar = *(it.second);
2788 :
2789 0 : unsigned int vi = ivar.number();
2790 0 : unsigned int vj = jvar.number();
2791 :
2792 0 : const bool array_block_diagonal_purely_diagonal = vi == vj && _component_block_diagonal[vi];
2793 0 : auto num_cols = jvar.dofIndices().size();
2794 0 : if (array_block_diagonal_purely_diagonal)
2795 0 : num_cols /= jvar.count();
2796 :
2797 0 : if (vi == var->number() || vj == var->number())
2798 : {
2799 0 : for (MooseIndex(_jacobian_block_nonlocal_used) tag = 0;
2800 0 : tag < _jacobian_block_nonlocal_used.size();
2801 : tag++)
2802 : {
2803 0 : jacobianBlockNonlocal(vi, vj, LocalDataKey{}, tag)
2804 0 : .resize(ivar.dofIndices().size(), num_cols);
2805 0 : jacobianBlockNonlocalUsed(tag, vi, vj);
2806 : }
2807 : }
2808 : }
2809 0 : }
2810 :
2811 : void
2812 22206913 : Assembly::prepareNeighbor()
2813 : {
2814 59793369 : for (const auto & it : _cm_ff_entry)
2815 : {
2816 37586456 : MooseVariableFEBase & ivar = *(it.first);
2817 37586456 : MooseVariableFEBase & jvar = *(it.second);
2818 :
2819 37586456 : unsigned int vi = ivar.number();
2820 37586456 : unsigned int vj = jvar.number();
2821 :
2822 37586456 : const bool array_block_diagonal_purely_diagonal = vi == vj && _component_block_diagonal[vi];
2823 37586456 : const auto dofs_divisor = array_block_diagonal_purely_diagonal ? jvar.count() : 1;
2824 :
2825 112766856 : for (MooseIndex(_jacobian_block_neighbor_used) tag = 0;
2826 112766856 : tag < _jacobian_block_neighbor_used.size();
2827 : tag++)
2828 : {
2829 75180400 : jacobianBlockNeighbor(Moose::ElementNeighbor, vi, vj, LocalDataKey{}, tag)
2830 75180400 : .resize(ivar.dofIndices().size(), jvar.dofIndicesNeighbor().size() / dofs_divisor);
2831 :
2832 75180400 : jacobianBlockNeighbor(Moose::NeighborElement, vi, vj, LocalDataKey{}, tag)
2833 75180400 : .resize(ivar.dofIndicesNeighbor().size(), jvar.dofIndices().size() / dofs_divisor);
2834 :
2835 75180400 : jacobianBlockNeighbor(Moose::NeighborNeighbor, vi, vj, LocalDataKey{}, tag)
2836 75180400 : .resize(ivar.dofIndicesNeighbor().size(),
2837 75180400 : jvar.dofIndicesNeighbor().size() / dofs_divisor);
2838 :
2839 75180400 : jacobianBlockNeighborUsed(tag, vi, vj, false);
2840 : }
2841 : }
2842 :
2843 22206913 : const std::vector<MooseVariableFEBase *> & vars = _sys.getVariables(_tid);
2844 48891739 : for (const auto & var : vars)
2845 93195727 : for (auto & tag_Rn : _sub_Rn)
2846 66510901 : tag_Rn[var->number()].resize(var->dofIndicesNeighbor().size());
2847 22206913 : }
2848 :
2849 : void
2850 600003 : Assembly::prepareLowerD()
2851 : {
2852 2802079 : for (const auto & it : _cm_ff_entry)
2853 : {
2854 2202076 : MooseVariableFEBase & ivar = *(it.first);
2855 2202076 : MooseVariableFEBase & jvar = *(it.second);
2856 :
2857 2202076 : unsigned int vi = ivar.number();
2858 2202076 : unsigned int vj = jvar.number();
2859 :
2860 2202076 : const bool array_block_diagonal_purely_diagonal = vi == vj && _component_block_diagonal[vi];
2861 2202076 : const auto dofs_divisor = array_block_diagonal_purely_diagonal ? jvar.count() : 1;
2862 :
2863 6606228 : for (MooseIndex(_jacobian_block_lower_used) tag = 0; tag < _jacobian_block_lower_used.size();
2864 : tag++)
2865 : {
2866 : // To cover all possible cases we should have 9 combinations below for every 2-permutation
2867 : // of Lower,Secondary,Primary. However, 4 cases will in general be covered by calls to
2868 : // prepare() and prepareNeighbor(). These calls will cover SecondarySecondary
2869 : // (ElementElement), SecondaryPrimary (ElementNeighbor), PrimarySecondary (NeighborElement),
2870 : // and PrimaryPrimary (NeighborNeighbor). With these covered we only need to prepare the 5
2871 : // remaining below
2872 :
2873 : // derivatives w.r.t. lower dimensional residuals
2874 4404152 : jacobianBlockMortar(Moose::LowerLower, vi, vj, LocalDataKey{}, tag)
2875 4404152 : .resize(ivar.dofIndicesLower().size(), jvar.dofIndicesLower().size() / dofs_divisor);
2876 :
2877 4404152 : jacobianBlockMortar(Moose::LowerSecondary, vi, vj, LocalDataKey{}, tag)
2878 4404152 : .resize(ivar.dofIndicesLower().size(), jvar.dofIndices().size() / dofs_divisor);
2879 :
2880 4404152 : jacobianBlockMortar(Moose::LowerPrimary, vi, vj, LocalDataKey{}, tag)
2881 4404152 : .resize(ivar.dofIndicesLower().size(), jvar.dofIndicesNeighbor().size() / dofs_divisor);
2882 :
2883 : // derivatives w.r.t. interior secondary residuals
2884 4404152 : jacobianBlockMortar(Moose::SecondaryLower, vi, vj, LocalDataKey{}, tag)
2885 4404152 : .resize(ivar.dofIndices().size(), jvar.dofIndicesLower().size() / dofs_divisor);
2886 :
2887 : // derivatives w.r.t. interior primary residuals
2888 4404152 : jacobianBlockMortar(Moose::PrimaryLower, vi, vj, LocalDataKey{}, tag)
2889 4404152 : .resize(ivar.dofIndicesNeighbor().size(), jvar.dofIndicesLower().size() / dofs_divisor);
2890 :
2891 4404152 : jacobianBlockLowerUsed(tag, vi, vj, false);
2892 : }
2893 : }
2894 :
2895 600003 : const std::vector<MooseVariableFEBase *> & vars = _sys.getVariables(_tid);
2896 1709955 : for (const auto & var : vars)
2897 3404396 : for (auto & tag_Rl : _sub_Rl)
2898 2294444 : tag_Rl[var->number()].resize(var->dofIndicesLower().size());
2899 600003 : }
2900 :
2901 : void
2902 0 : Assembly::prepareBlock(unsigned int ivar,
2903 : unsigned int jvar,
2904 : const std::vector<dof_id_type> & dof_indices)
2905 : {
2906 0 : const auto & iv = _sys.getVariable(_tid, ivar);
2907 0 : const auto & jv = _sys.getVariable(_tid, jvar);
2908 0 : const unsigned int ivn = iv.number();
2909 0 : const unsigned int jvn = jv.number();
2910 0 : const unsigned int icount = iv.count();
2911 0 : unsigned int jcount = jv.count();
2912 0 : if (ivn == jvn && _component_block_diagonal[ivn])
2913 0 : jcount = 1;
2914 :
2915 0 : for (MooseIndex(_jacobian_block_used) tag = 0; tag < _jacobian_block_used.size(); tag++)
2916 : {
2917 0 : jacobianBlock(ivn, jvn, LocalDataKey{}, tag)
2918 0 : .resize(dof_indices.size() * icount, dof_indices.size() * jcount);
2919 0 : jacobianBlockUsed(tag, ivn, jvn, false);
2920 : }
2921 :
2922 0 : for (auto & tag_Re : _sub_Re)
2923 0 : tag_Re[ivn].resize(dof_indices.size() * icount);
2924 0 : }
2925 :
2926 : void
2927 0 : Assembly::prepareBlockNonlocal(unsigned int ivar,
2928 : unsigned int jvar,
2929 : const std::vector<dof_id_type> & idof_indices,
2930 : const std::vector<dof_id_type> & jdof_indices)
2931 : {
2932 0 : const auto & iv = _sys.getVariable(_tid, ivar);
2933 0 : const auto & jv = _sys.getVariable(_tid, jvar);
2934 0 : const unsigned int ivn = iv.number();
2935 0 : const unsigned int jvn = jv.number();
2936 0 : const unsigned int icount = iv.count();
2937 0 : unsigned int jcount = jv.count();
2938 0 : if (ivn == jvn && _component_block_diagonal[ivn])
2939 0 : jcount = 1;
2940 :
2941 0 : for (MooseIndex(_jacobian_block_nonlocal_used) tag = 0;
2942 0 : tag < _jacobian_block_nonlocal_used.size();
2943 : tag++)
2944 : {
2945 0 : jacobianBlockNonlocal(ivn, jvn, LocalDataKey{}, tag)
2946 0 : .resize(idof_indices.size() * icount, jdof_indices.size() * jcount);
2947 :
2948 0 : jacobianBlockNonlocalUsed(tag, ivn, jvn, false);
2949 : }
2950 0 : }
2951 :
2952 : void
2953 8711897 : Assembly::prepareScalar()
2954 : {
2955 8711897 : const std::vector<MooseVariableScalar *> & vars = _sys.getScalarVariables(_tid);
2956 8978216 : for (const auto & ivar : vars)
2957 : {
2958 266319 : auto idofs = ivar->dofIndices().size();
2959 :
2960 1052029 : for (auto & tag_Re : _sub_Re)
2961 785710 : tag_Re[ivar->number()].resize(idofs);
2962 :
2963 680436 : for (const auto & jvar : vars)
2964 : {
2965 414117 : auto jdofs = jvar->dofIndices().size();
2966 :
2967 1245629 : for (MooseIndex(_jacobian_block_used) tag = 0; tag < _jacobian_block_used.size(); tag++)
2968 : {
2969 831512 : jacobianBlock(ivar->number(), jvar->number(), LocalDataKey{}, tag).resize(idofs, jdofs);
2970 831512 : jacobianBlockUsed(tag, ivar->number(), jvar->number(), false);
2971 : }
2972 : }
2973 : }
2974 8711897 : }
2975 :
2976 : void
2977 185626 : Assembly::prepareOffDiagScalar()
2978 : {
2979 185626 : const std::vector<MooseVariableFEBase *> & vars = _sys.getVariables(_tid);
2980 185626 : const std::vector<MooseVariableScalar *> & scalar_vars = _sys.getScalarVariables(_tid);
2981 :
2982 376665 : for (const auto & ivar : scalar_vars)
2983 : {
2984 191039 : auto idofs = ivar->dofIndices().size();
2985 :
2986 474044 : for (const auto & jvar : vars)
2987 : {
2988 283005 : auto jdofs = jvar->dofIndices().size() * jvar->count();
2989 849015 : for (MooseIndex(_jacobian_block_used) tag = 0; tag < _jacobian_block_used.size(); tag++)
2990 : {
2991 566010 : jacobianBlock(ivar->number(), jvar->number(), LocalDataKey{}, tag).resize(idofs, jdofs);
2992 566010 : jacobianBlockUsed(tag, ivar->number(), jvar->number(), false);
2993 :
2994 566010 : jacobianBlock(jvar->number(), ivar->number(), LocalDataKey{}, tag).resize(jdofs, idofs);
2995 566010 : jacobianBlockUsed(tag, jvar->number(), ivar->number(), false);
2996 : }
2997 : }
2998 : }
2999 185626 : }
3000 :
3001 : template <typename T>
3002 : void
3003 126180081 : Assembly::copyShapes(MooseVariableField<T> & v)
3004 : {
3005 126180081 : phi(v).shallowCopy(v.phi());
3006 126180081 : gradPhi(v).shallowCopy(v.gradPhi());
3007 126180081 : if (v.computingSecond())
3008 23852 : secondPhi(v).shallowCopy(v.secondPhi());
3009 126180081 : }
3010 :
3011 : void
3012 126180081 : Assembly::copyShapes(unsigned int var)
3013 : {
3014 126180081 : auto & v = _sys.getVariable(_tid, var);
3015 126180081 : if (v.fieldType() == Moose::VarFieldType::VAR_FIELD_STANDARD)
3016 : {
3017 123799331 : auto & v = _sys.getActualFieldVariable<Real>(_tid, var);
3018 123799331 : copyShapes(v);
3019 : }
3020 2380750 : else if (v.fieldType() == Moose::VarFieldType::VAR_FIELD_ARRAY)
3021 : {
3022 562980 : auto & v = _sys.getActualFieldVariable<RealEigenVector>(_tid, var);
3023 562980 : copyShapes(v);
3024 : }
3025 1817770 : else if (v.fieldType() == Moose::VarFieldType::VAR_FIELD_VECTOR)
3026 : {
3027 1817770 : auto & v = _sys.getActualFieldVariable<RealVectorValue>(_tid, var);
3028 1817770 : copyShapes(v);
3029 1817770 : if (v.computingCurl())
3030 50508 : curlPhi(v).shallowCopy(v.curlPhi());
3031 1817770 : if (v.computingDiv())
3032 494208 : divPhi(v).shallowCopy(v.divPhi());
3033 : }
3034 : else
3035 0 : mooseError("Unsupported variable field type!");
3036 126180081 : }
3037 :
3038 : template <typename T>
3039 : void
3040 611444 : Assembly::copyFaceShapes(MooseVariableField<T> & v)
3041 : {
3042 611444 : phiFace(v).shallowCopy(v.phiFace());
3043 611444 : gradPhiFace(v).shallowCopy(v.gradPhiFace());
3044 611444 : if (v.computingSecond())
3045 4088 : secondPhiFace(v).shallowCopy(v.secondPhiFace());
3046 611444 : }
3047 :
3048 : void
3049 611444 : Assembly::copyFaceShapes(unsigned int var)
3050 : {
3051 611444 : auto & v = _sys.getVariable(_tid, var);
3052 611444 : if (v.fieldType() == Moose::VarFieldType::VAR_FIELD_STANDARD)
3053 : {
3054 542102 : auto & v = _sys.getActualFieldVariable<Real>(_tid, var);
3055 542102 : copyFaceShapes(v);
3056 : }
3057 69342 : else if (v.fieldType() == Moose::VarFieldType::VAR_FIELD_ARRAY)
3058 : {
3059 12810 : auto & v = _sys.getActualFieldVariable<RealEigenVector>(_tid, var);
3060 12810 : copyFaceShapes(v);
3061 : }
3062 56532 : else if (v.fieldType() == Moose::VarFieldType::VAR_FIELD_VECTOR)
3063 : {
3064 56532 : auto & v = _sys.getActualFieldVariable<RealVectorValue>(_tid, var);
3065 56532 : copyFaceShapes(v);
3066 56532 : if (v.computingCurl())
3067 6380 : _vector_curl_phi_face.shallowCopy(v.curlPhi());
3068 56532 : if (v.computingDiv())
3069 26112 : _vector_div_phi_face.shallowCopy(v.divPhi());
3070 : }
3071 : else
3072 0 : mooseError("Unsupported variable field type!");
3073 611444 : }
3074 :
3075 : template <typename T>
3076 : void
3077 187886 : Assembly::copyNeighborShapes(MooseVariableField<T> & v)
3078 : {
3079 187886 : if (v.usesPhiNeighbor())
3080 : {
3081 187886 : phiFaceNeighbor(v).shallowCopy(v.phiFaceNeighbor());
3082 187886 : phiNeighbor(v).shallowCopy(v.phiNeighbor());
3083 : }
3084 187886 : if (v.usesGradPhiNeighbor())
3085 : {
3086 187886 : gradPhiFaceNeighbor(v).shallowCopy(v.gradPhiFaceNeighbor());
3087 187886 : gradPhiNeighbor(v).shallowCopy(v.gradPhiNeighbor());
3088 : }
3089 187886 : if (v.usesSecondPhiNeighbor())
3090 : {
3091 0 : secondPhiFaceNeighbor(v).shallowCopy(v.secondPhiFaceNeighbor());
3092 0 : secondPhiNeighbor(v).shallowCopy(v.secondPhiNeighbor());
3093 : }
3094 187886 : }
3095 :
3096 : void
3097 187886 : Assembly::copyNeighborShapes(unsigned int var)
3098 : {
3099 187886 : auto & v = _sys.getVariable(_tid, var);
3100 187886 : if (v.fieldType() == Moose::VarFieldType::VAR_FIELD_STANDARD)
3101 : {
3102 184164 : auto & v = _sys.getActualFieldVariable<Real>(_tid, var);
3103 184164 : copyNeighborShapes(v);
3104 : }
3105 3722 : else if (v.fieldType() == Moose::VarFieldType::VAR_FIELD_ARRAY)
3106 : {
3107 3456 : auto & v = _sys.getActualFieldVariable<RealEigenVector>(_tid, var);
3108 3456 : copyNeighborShapes(v);
3109 : }
3110 266 : else if (v.fieldType() == Moose::VarFieldType::VAR_FIELD_VECTOR)
3111 : {
3112 266 : auto & v = _sys.getActualFieldVariable<RealVectorValue>(_tid, var);
3113 266 : copyNeighborShapes(v);
3114 : }
3115 : else
3116 0 : mooseError("Unsupported variable field type!");
3117 187886 : }
3118 :
3119 : DenseMatrix<Number> &
3120 226256578 : Assembly::jacobianBlockNeighbor(
3121 : Moose::DGJacobianType type, unsigned int ivar, unsigned int jvar, LocalDataKey, TagID tag)
3122 : {
3123 226256578 : if (type == Moose::ElementElement)
3124 0 : jacobianBlockUsed(tag, ivar, jvar, true);
3125 : else
3126 226256578 : jacobianBlockNeighborUsed(tag, ivar, jvar, true);
3127 :
3128 226256578 : if (_block_diagonal_matrix)
3129 : {
3130 120082487 : switch (type)
3131 : {
3132 0 : default:
3133 : case Moose::ElementElement:
3134 0 : return _sub_Kee[tag][ivar][0];
3135 40028856 : case Moose::ElementNeighbor:
3136 40028856 : return _sub_Ken[tag][ivar][0];
3137 40022515 : case Moose::NeighborElement:
3138 40022515 : return _sub_Kne[tag][ivar][0];
3139 40031116 : case Moose::NeighborNeighbor:
3140 40031116 : return _sub_Knn[tag][ivar][0];
3141 : }
3142 : }
3143 : else
3144 : {
3145 106174091 : switch (type)
3146 : {
3147 0 : default:
3148 : case Moose::ElementElement:
3149 0 : return _sub_Kee[tag][ivar][jvar];
3150 35391593 : case Moose::ElementNeighbor:
3151 35391593 : return _sub_Ken[tag][ivar][jvar];
3152 35390905 : case Moose::NeighborElement:
3153 35390905 : return _sub_Kne[tag][ivar][jvar];
3154 35391593 : case Moose::NeighborNeighbor:
3155 35391593 : return _sub_Knn[tag][ivar][jvar];
3156 : }
3157 : }
3158 : }
3159 :
3160 : DenseMatrix<Number> &
3161 22761044 : Assembly::jacobianBlockMortar(Moose::ConstraintJacobianType type,
3162 : unsigned int ivar,
3163 : unsigned int jvar,
3164 : LocalDataKey,
3165 : TagID tag)
3166 : {
3167 22761044 : jacobianBlockLowerUsed(tag, ivar, jvar, true);
3168 22761044 : if (_block_diagonal_matrix)
3169 : {
3170 1897800 : switch (type)
3171 : {
3172 323576 : default:
3173 : case Moose::LowerLower:
3174 323576 : return _sub_Kll[tag][ivar][0];
3175 323192 : case Moose::LowerSecondary:
3176 323192 : return _sub_Kle[tag][ivar][0];
3177 323000 : case Moose::LowerPrimary:
3178 323000 : return _sub_Kln[tag][ivar][0];
3179 351376 : case Moose::SecondaryLower:
3180 351376 : return _sub_Kel[tag][ivar][0];
3181 56368 : case Moose::SecondarySecondary:
3182 56368 : return _sub_Kee[tag][ivar][0];
3183 56368 : case Moose::SecondaryPrimary:
3184 56368 : return _sub_Ken[tag][ivar][0];
3185 351184 : case Moose::PrimaryLower:
3186 351184 : return _sub_Knl[tag][ivar][0];
3187 56368 : case Moose::PrimarySecondary:
3188 56368 : return _sub_Kne[tag][ivar][0];
3189 56368 : case Moose::PrimaryPrimary:
3190 56368 : return _sub_Knn[tag][ivar][0];
3191 : }
3192 : }
3193 : else
3194 : {
3195 20863244 : switch (type)
3196 : {
3197 4154188 : default:
3198 : case Moose::LowerLower:
3199 4154188 : return _sub_Kll[tag][ivar][jvar];
3200 4153308 : case Moose::LowerSecondary:
3201 4153308 : return _sub_Kle[tag][ivar][jvar];
3202 4145740 : case Moose::LowerPrimary:
3203 4145740 : return _sub_Kln[tag][ivar][jvar];
3204 4155468 : case Moose::SecondaryLower:
3205 4155468 : return _sub_Kel[tag][ivar][jvar];
3206 26660 : case Moose::SecondarySecondary:
3207 26660 : return _sub_Kee[tag][ivar][jvar];
3208 26660 : case Moose::SecondaryPrimary:
3209 26660 : return _sub_Ken[tag][ivar][jvar];
3210 4147900 : case Moose::PrimaryLower:
3211 4147900 : return _sub_Knl[tag][ivar][jvar];
3212 26660 : case Moose::PrimarySecondary:
3213 26660 : return _sub_Kne[tag][ivar][jvar];
3214 26660 : case Moose::PrimaryPrimary:
3215 26660 : return _sub_Knn[tag][ivar][jvar];
3216 : }
3217 : }
3218 : }
3219 :
3220 : void
3221 970203856 : Assembly::processLocalResidual(DenseVector<Number> & res_block,
3222 : std::vector<dof_id_type> & dof_indices,
3223 : const std::vector<Real> & scaling_factor)
3224 : {
3225 : mooseAssert(res_block.size() == dof_indices.size(),
3226 : "The size of residual and degree of freedom container must be the same");
3227 :
3228 : // For an array variable, ndof is the number of dofs of the zero-th component and
3229 : // ntdof is the number of dofs of all components.
3230 : // For standard or vector variables, ndof will be the same as ntdof.
3231 970203856 : const auto ntdof = res_block.size();
3232 970203856 : const auto count = scaling_factor.size();
3233 970203856 : const auto ndof = ntdof / count;
3234 970203856 : if (count > 1)
3235 : {
3236 4392932 : unsigned int p = 0;
3237 13718346 : for (MooseIndex(count) j = 0; j < count; ++j)
3238 52453508 : for (MooseIndex(ndof) i = 0; i < ndof; ++i)
3239 43128094 : res_block(p++) *= scaling_factor[j];
3240 : }
3241 : else
3242 : {
3243 965810924 : if (scaling_factor[0] != 1.0)
3244 4268837 : res_block *= scaling_factor[0];
3245 : }
3246 :
3247 970203856 : _dof_map.constrain_element_vector(res_block, dof_indices, false);
3248 970203856 : }
3249 :
3250 : void
3251 13691991 : Assembly::addResidualBlock(NumericVector<Number> & residual,
3252 : DenseVector<Number> & res_block,
3253 : const std::vector<dof_id_type> & dof_indices,
3254 : const std::vector<Real> & scaling_factor)
3255 : {
3256 13691991 : if (dof_indices.size() > 0 && res_block.size())
3257 : {
3258 7007030 : _temp_dof_indices = dof_indices;
3259 7007030 : _tmp_Re = res_block;
3260 7007030 : processLocalResidual(_tmp_Re, _temp_dof_indices, scaling_factor);
3261 7007030 : residual.add_vector(_tmp_Re, _temp_dof_indices);
3262 : }
3263 13691991 : }
3264 :
3265 : void
3266 1032307164 : Assembly::cacheResidualBlock(std::vector<Real> & cached_residual_values,
3267 : std::vector<dof_id_type> & cached_residual_rows,
3268 : DenseVector<Number> & res_block,
3269 : const std::vector<dof_id_type> & dof_indices,
3270 : const std::vector<Real> & scaling_factor)
3271 : {
3272 1032307164 : if (dof_indices.size() > 0 && res_block.size())
3273 : {
3274 963196826 : _temp_dof_indices = dof_indices;
3275 963196826 : _tmp_Re = res_block;
3276 963196826 : processLocalResidual(_tmp_Re, _temp_dof_indices, scaling_factor);
3277 :
3278 4915160637 : for (MooseIndex(_tmp_Re) i = 0; i < _tmp_Re.size(); i++)
3279 : {
3280 3951963811 : cached_residual_values.push_back(_tmp_Re(i));
3281 3951963811 : cached_residual_rows.push_back(_temp_dof_indices[i]);
3282 : }
3283 : }
3284 :
3285 1032307164 : res_block.zero();
3286 1032307164 : }
3287 :
3288 : void
3289 0 : Assembly::setResidualBlock(NumericVector<Number> & residual,
3290 : DenseVector<Number> & res_block,
3291 : const std::vector<dof_id_type> & dof_indices,
3292 : const std::vector<Real> & scaling_factor)
3293 : {
3294 0 : if (dof_indices.size() > 0)
3295 : {
3296 0 : std::vector<dof_id_type> di(dof_indices);
3297 0 : _tmp_Re = res_block;
3298 0 : processLocalResidual(_tmp_Re, di, scaling_factor);
3299 0 : residual.insert(_tmp_Re, di);
3300 0 : }
3301 0 : }
3302 :
3303 : void
3304 786387 : Assembly::addResidual(const VectorTag & vector_tag)
3305 : {
3306 : mooseAssert(vector_tag._type == Moose::VECTOR_TAG_RESIDUAL,
3307 : "Non-residual tag in Assembly::addResidual");
3308 :
3309 786387 : auto & tag_Re = _sub_Re[vector_tag._type_id];
3310 786387 : NumericVector<Number> & residual = _sys.getVector(vector_tag._id);
3311 786387 : const std::vector<MooseVariableFEBase *> & vars = _sys.getVariables(_tid);
3312 2264954 : for (const auto & var : vars)
3313 1478567 : addResidualBlock(residual, tag_Re[var->number()], var->dofIndices(), var->arrayScalingFactor());
3314 786387 : }
3315 :
3316 : void
3317 271389 : Assembly::addResidual(GlobalDataKey, const std::vector<VectorTag> & vector_tags)
3318 : {
3319 1057776 : for (const auto & vector_tag : vector_tags)
3320 786387 : if (_sys.hasVector(vector_tag._id))
3321 786387 : addResidual(vector_tag);
3322 271389 : }
3323 :
3324 : void
3325 5011955 : Assembly::addResidualNeighbor(const VectorTag & vector_tag)
3326 : {
3327 : mooseAssert(vector_tag._type == Moose::VECTOR_TAG_RESIDUAL,
3328 : "Non-residual tag in Assembly::addResidualNeighbor");
3329 :
3330 5011955 : auto & tag_Rn = _sub_Rn[vector_tag._type_id];
3331 5011955 : NumericVector<Number> & residual = _sys.getVector(vector_tag._id);
3332 5011955 : const std::vector<MooseVariableFEBase *> & vars = _sys.getVariables(_tid);
3333 11036874 : for (const auto & var : vars)
3334 6024919 : addResidualBlock(
3335 6024919 : residual, tag_Rn[var->number()], var->dofIndicesNeighbor(), var->arrayScalingFactor());
3336 5011955 : }
3337 :
3338 : void
3339 2046393 : Assembly::addResidualNeighbor(GlobalDataKey, const std::vector<VectorTag> & vector_tags)
3340 : {
3341 7058348 : for (const auto & vector_tag : vector_tags)
3342 5011955 : if (_sys.hasVector(vector_tag._id))
3343 5011955 : addResidualNeighbor(vector_tag);
3344 2046393 : }
3345 :
3346 : void
3347 4985617 : Assembly::addResidualLower(const VectorTag & vector_tag)
3348 : {
3349 : mooseAssert(vector_tag._type == Moose::VECTOR_TAG_RESIDUAL,
3350 : "Non-residual tag in Assembly::addResidualLower");
3351 :
3352 4985617 : auto & tag_Rl = _sub_Rl[vector_tag._type_id];
3353 4985617 : NumericVector<Number> & residual = _sys.getVector(vector_tag._id);
3354 4985617 : const std::vector<MooseVariableFEBase *> & vars = _sys.getVariables(_tid);
3355 10977796 : for (const auto & var : vars)
3356 5992179 : addResidualBlock(
3357 5992179 : residual, tag_Rl[var->number()], var->dofIndicesLower(), var->arrayScalingFactor());
3358 4985617 : }
3359 :
3360 : void
3361 2028936 : Assembly::addResidualLower(GlobalDataKey, const std::vector<VectorTag> & vector_tags)
3362 : {
3363 7014553 : for (const auto & vector_tag : vector_tags)
3364 4985617 : if (_sys.hasVector(vector_tag._id))
3365 4985617 : addResidualLower(vector_tag);
3366 2028936 : }
3367 :
3368 : // private method, so no key required
3369 : void
3370 145140 : Assembly::addResidualScalar(const VectorTag & vector_tag)
3371 : {
3372 : mooseAssert(vector_tag._type == Moose::VECTOR_TAG_RESIDUAL,
3373 : "Non-residual tag in Assembly::addResidualScalar");
3374 :
3375 : // add the scalar variables residuals
3376 145140 : auto & tag_Re = _sub_Re[vector_tag._type_id];
3377 145140 : NumericVector<Number> & residual = _sys.getVector(vector_tag._id);
3378 145140 : const std::vector<MooseVariableScalar *> & vars = _sys.getScalarVariables(_tid);
3379 341466 : for (const auto & var : vars)
3380 196326 : addResidualBlock(residual, tag_Re[var->number()], var->dofIndices(), var->arrayScalingFactor());
3381 145140 : }
3382 :
3383 : void
3384 48426 : Assembly::addResidualScalar(GlobalDataKey, const std::vector<VectorTag> & vector_tags)
3385 : {
3386 193566 : for (const auto & vector_tag : vector_tags)
3387 145140 : if (_sys.hasVector(vector_tag._id))
3388 145140 : addResidualScalar(vector_tag);
3389 48426 : }
3390 :
3391 : void
3392 321282928 : Assembly::cacheResidual(GlobalDataKey, const std::vector<VectorTag> & tags)
3393 : {
3394 321282928 : const std::vector<MooseVariableFEBase *> & vars = _sys.getVariables(_tid);
3395 673291306 : for (const auto & var : vars)
3396 1310646489 : for (const auto & vector_tag : tags)
3397 958638111 : if (_sys.hasVector(vector_tag._id))
3398 958638111 : cacheResidualBlock(_cached_residual_values[vector_tag._type_id],
3399 958638111 : _cached_residual_rows[vector_tag._type_id],
3400 958638111 : _sub_Re[vector_tag._type_id][var->number()],
3401 958638111 : var->dofIndices(),
3402 958638111 : var->arrayScalingFactor());
3403 321282928 : }
3404 :
3405 : // private method, so no key required
3406 : void
3407 70092390 : Assembly::cacheResidual(dof_id_type dof, Real value, TagID tag_id)
3408 : {
3409 70092390 : const VectorTag & tag = _subproblem.getVectorTag(tag_id);
3410 :
3411 70092390 : _cached_residual_values[tag._type_id].push_back(value);
3412 70092390 : _cached_residual_rows[tag._type_id].push_back(dof);
3413 70092390 : }
3414 :
3415 : // private method, so no key required
3416 : void
3417 69656283 : Assembly::cacheResidual(dof_id_type dof, Real value, const std::set<TagID> & tags)
3418 : {
3419 139748673 : for (auto & tag : tags)
3420 70092390 : cacheResidual(dof, value, tag);
3421 69656283 : }
3422 :
3423 : void
3424 0 : Assembly::cacheResidualNodes(const DenseVector<Number> & res,
3425 : const std::vector<dof_id_type> & dof_index,
3426 : LocalDataKey,
3427 : TagID tag)
3428 : {
3429 : // Add the residual value and dof_index to cached_residual_values and cached_residual_rows
3430 : // respectively.
3431 : // This is used by NodalConstraint.C to cache the residual calculated for primary and secondary
3432 : // node.
3433 0 : const VectorTag & vector_tag = _subproblem.getVectorTag(tag);
3434 0 : for (MooseIndex(dof_index) i = 0; i < dof_index.size(); ++i)
3435 : {
3436 0 : _cached_residual_values[vector_tag._type_id].push_back(res(i));
3437 0 : _cached_residual_rows[vector_tag._type_id].push_back(dof_index[i]);
3438 : }
3439 0 : }
3440 :
3441 : void
3442 25452135 : Assembly::cacheResidualNeighbor(GlobalDataKey, const std::vector<VectorTag> & tags)
3443 : {
3444 25452135 : const std::vector<MooseVariableFEBase *> & vars = _sys.getVariables(_tid);
3445 55149414 : for (const auto & var : vars)
3446 101998852 : for (const auto & vector_tag : tags)
3447 72301573 : if (_sys.hasVector(vector_tag._id))
3448 72301573 : cacheResidualBlock(_cached_residual_values[vector_tag._type_id],
3449 72301573 : _cached_residual_rows[vector_tag._type_id],
3450 72301573 : _sub_Rn[vector_tag._type_id][var->number()],
3451 72301573 : var->dofIndicesNeighbor(),
3452 72301573 : var->arrayScalingFactor());
3453 25452135 : }
3454 :
3455 : void
3456 373958 : Assembly::cacheResidualLower(GlobalDataKey, const std::vector<VectorTag> & tags)
3457 : {
3458 373958 : const std::vector<MooseVariableFEBase *> & vars = _sys.getVariables(_tid);
3459 1042142 : for (const auto & var : vars)
3460 2035664 : for (const auto & vector_tag : tags)
3461 1367480 : if (_sys.hasVector(vector_tag._id))
3462 1367480 : cacheResidualBlock(_cached_residual_values[vector_tag._type_id],
3463 1367480 : _cached_residual_rows[vector_tag._type_id],
3464 1367480 : _sub_Rl[vector_tag._type_id][var->number()],
3465 1367480 : var->dofIndicesLower(),
3466 1367480 : var->arrayScalingFactor());
3467 373958 : }
3468 :
3469 : void
3470 42340558 : Assembly::addCachedResiduals(GlobalDataKey, const std::vector<VectorTag> & tags)
3471 : {
3472 152825785 : for (const auto & vector_tag : tags)
3473 : {
3474 110485227 : if (!_sys.hasVector(vector_tag._id))
3475 : {
3476 0 : _cached_residual_values[vector_tag._type_id].clear();
3477 0 : _cached_residual_rows[vector_tag._type_id].clear();
3478 0 : continue;
3479 : }
3480 110485227 : addCachedResidualDirectly(_sys.getVector(vector_tag._id), GlobalDataKey{}, vector_tag);
3481 : }
3482 42340558 : }
3483 :
3484 : void
3485 11367 : Assembly::clearCachedResiduals(GlobalDataKey)
3486 : {
3487 44257 : for (const auto & vector_tag : _residual_vector_tags)
3488 32890 : clearCachedResiduals(vector_tag);
3489 11367 : }
3490 :
3491 : // private method, so no key required
3492 : void
3493 101832346 : Assembly::clearCachedResiduals(const VectorTag & vector_tag)
3494 : {
3495 101832346 : auto & values = _cached_residual_values[vector_tag._type_id];
3496 101832346 : auto & rows = _cached_residual_rows[vector_tag._type_id];
3497 :
3498 : mooseAssert(values.size() == rows.size(),
3499 : "Number of cached residuals and number of rows must match!");
3500 :
3501 : // Keep track of the largest size so we can use it to reserve and avoid
3502 : // as much dynamic allocation as possible
3503 101832346 : if (_max_cached_residuals < values.size())
3504 41760 : _max_cached_residuals = values.size();
3505 :
3506 : // Clear both vectors (keeps the capacity the same)
3507 101832346 : values.clear();
3508 101832346 : rows.clear();
3509 : // And then reserve: use 2 as a fudge factor to *really* avoid dynamic allocation!
3510 101832346 : values.reserve(_max_cached_residuals * 2);
3511 101832346 : rows.reserve(_max_cached_residuals * 2);
3512 101832346 : }
3513 :
3514 : void
3515 110506678 : Assembly::addCachedResidualDirectly(NumericVector<Number> & residual,
3516 : GlobalDataKey,
3517 : const VectorTag & vector_tag)
3518 : {
3519 110506678 : const auto & values = _cached_residual_values[vector_tag._type_id];
3520 110506678 : const auto & rows = _cached_residual_rows[vector_tag._type_id];
3521 :
3522 : mooseAssert(values.size() == rows.size(),
3523 : "Number of cached residuals and number of rows must match!");
3524 :
3525 110506678 : if (!values.empty())
3526 : {
3527 101799456 : residual.add_vector(values, rows);
3528 101799456 : clearCachedResiduals(vector_tag);
3529 : }
3530 110506678 : }
3531 :
3532 : void
3533 0 : Assembly::setResidual(NumericVector<Number> & residual, GlobalDataKey, const VectorTag & vector_tag)
3534 : {
3535 0 : auto & tag_Re = _sub_Re[vector_tag._type_id];
3536 0 : const std::vector<MooseVariableFEBase *> & vars = _sys.getVariables(_tid);
3537 0 : for (const auto & var : vars)
3538 0 : setResidualBlock(residual, tag_Re[var->number()], var->dofIndices(), var->arrayScalingFactor());
3539 0 : }
3540 :
3541 : void
3542 0 : Assembly::setResidualNeighbor(NumericVector<Number> & residual,
3543 : GlobalDataKey,
3544 : const VectorTag & vector_tag)
3545 : {
3546 0 : auto & tag_Rn = _sub_Rn[vector_tag._type_id];
3547 0 : const std::vector<MooseVariableFEBase *> & vars = _sys.getVariables(_tid);
3548 0 : for (const auto & var : vars)
3549 0 : setResidualBlock(
3550 0 : residual, tag_Rn[var->number()], var->dofIndicesNeighbor(), var->arrayScalingFactor());
3551 0 : }
3552 :
3553 : // private method, so no key required
3554 : void
3555 432160 : Assembly::addJacobianBlock(SparseMatrix<Number> & jacobian,
3556 : DenseMatrix<Number> & jac_block,
3557 : const MooseVariableBase & ivar,
3558 : const MooseVariableBase & jvar,
3559 : const std::vector<dof_id_type> & idof_indices,
3560 : const std::vector<dof_id_type> & jdof_indices)
3561 : {
3562 432160 : if (idof_indices.size() == 0 || jdof_indices.size() == 0)
3563 86478 : return;
3564 345682 : if (jac_block.n() == 0 || jac_block.m() == 0)
3565 0 : return;
3566 :
3567 345682 : const auto & scaling_factors = ivar.arrayScalingFactor();
3568 345682 : const unsigned int iv = ivar.number();
3569 345682 : const unsigned int jv = jvar.number();
3570 :
3571 705092 : for (unsigned int i = 0; i < ivar.count(); ++i)
3572 : {
3573 873841 : for (const auto & jt : ConstCouplingRow(iv + i, *_cm))
3574 : {
3575 514431 : if (jt < jv || jt >= jv + jvar.count())
3576 129485 : continue;
3577 384946 : unsigned int j = jt - jv;
3578 :
3579 384946 : auto di = ivar.componentDofIndices(idof_indices, i);
3580 384946 : auto dj = jvar.componentDofIndices(jdof_indices, j);
3581 384946 : auto indof = di.size();
3582 384946 : auto jndof = dj.size();
3583 :
3584 384946 : unsigned int jj = j;
3585 384946 : if (iv == jv && _component_block_diagonal[iv])
3586 : // here i must be equal to j
3587 309123 : jj = 0;
3588 :
3589 384946 : auto sub = jac_block.sub_matrix(i * indof, indof, jj * jndof, jndof);
3590 384946 : if (scaling_factors[i] != 1.0)
3591 5216 : sub *= scaling_factors[i];
3592 :
3593 : // If we're computing the jacobian for automatically scaling variables we do not want
3594 : // to constrain the element matrix because it introduces 1s on the diagonal for the
3595 : // constrained dofs
3596 384946 : if (!_sys.computingScalingJacobian())
3597 384890 : _dof_map.constrain_element_matrix(sub, di, dj, false);
3598 :
3599 384946 : jacobian.add_matrix(sub, di, dj);
3600 384946 : }
3601 : }
3602 : }
3603 :
3604 : // private method, so no key required
3605 : void
3606 58335441 : Assembly::cacheJacobianBlock(const DenseMatrix<Number> & jac_block,
3607 : const MooseVariableBase & ivar,
3608 : const MooseVariableBase & jvar,
3609 : const std::vector<dof_id_type> & idof_indices,
3610 : const std::vector<dof_id_type> & jdof_indices,
3611 : TagID tag)
3612 : {
3613 58335441 : if (idof_indices.size() == 0 || jdof_indices.size() == 0)
3614 390862 : return;
3615 57944579 : if (jac_block.n() == 0 || jac_block.m() == 0)
3616 0 : return;
3617 57944579 : if (!_sys.hasMatrix(tag))
3618 0 : return;
3619 :
3620 57944579 : auto & scaling_factors = ivar.arrayScalingFactor();
3621 57944579 : const unsigned int iv = ivar.number();
3622 57944579 : const unsigned int jv = jvar.number();
3623 :
3624 116135744 : for (unsigned int i = 0; i < ivar.count(); ++i)
3625 : {
3626 144310786 : for (const auto & jt : ConstCouplingRow(iv + i, *_cm))
3627 : {
3628 86119621 : if (jt < jv || jt >= jv + jvar.count())
3629 27828776 : continue;
3630 58290845 : unsigned int j = jt - jv;
3631 :
3632 58290845 : auto di = ivar.componentDofIndices(idof_indices, i);
3633 58290845 : auto dj = jvar.componentDofIndices(jdof_indices, j);
3634 58290845 : auto indof = di.size();
3635 58290845 : auto jndof = dj.size();
3636 :
3637 58290845 : unsigned int jj = j;
3638 58290845 : if (iv == jv && _component_block_diagonal[iv])
3639 : // here i must be equal to j
3640 48660161 : jj = 0;
3641 :
3642 58290845 : auto sub = jac_block.sub_matrix(i * indof, indof, jj * jndof, jndof);
3643 58290845 : if (scaling_factors[i] != 1.0)
3644 1558874 : sub *= scaling_factors[i];
3645 :
3646 : // If we're computing the jacobian for automatically scaling variables we do not want
3647 : // to constrain the element matrix because it introduces 1s on the diagonal for the
3648 : // constrained dofs
3649 58290845 : if (!_sys.computingScalingJacobian())
3650 58094679 : _dof_map.constrain_element_matrix(sub, di, dj, false);
3651 :
3652 318449156 : for (MooseIndex(di) i = 0; i < di.size(); i++)
3653 1601078944 : for (MooseIndex(dj) j = 0; j < dj.size(); j++)
3654 : {
3655 1340920633 : _cached_jacobian_values[tag].push_back(sub(i, j));
3656 1340920633 : _cached_jacobian_rows[tag].push_back(di[i]);
3657 1340920633 : _cached_jacobian_cols[tag].push_back(dj[j]);
3658 : }
3659 58290845 : }
3660 : }
3661 : }
3662 :
3663 : // private method, so no key required
3664 : void
3665 634 : Assembly::cacheJacobianBlockNonzero(const DenseMatrix<Number> & jac_block,
3666 : const MooseVariableBase & ivar,
3667 : const MooseVariableBase & jvar,
3668 : const std::vector<dof_id_type> & idof_indices,
3669 : const std::vector<dof_id_type> & jdof_indices,
3670 : TagID tag)
3671 : {
3672 634 : if (idof_indices.size() == 0 || jdof_indices.size() == 0)
3673 0 : return;
3674 634 : if (jac_block.n() == 0 || jac_block.m() == 0)
3675 0 : return;
3676 634 : if (!_sys.hasMatrix(tag))
3677 0 : return;
3678 :
3679 634 : auto & scaling_factor = ivar.arrayScalingFactor();
3680 :
3681 1268 : for (unsigned int i = 0; i < ivar.count(); ++i)
3682 : {
3683 634 : unsigned int iv = ivar.number();
3684 1862 : for (const auto & jt : ConstCouplingRow(iv + i, *_cm))
3685 : {
3686 1228 : unsigned int jv = jvar.number();
3687 1228 : if (jt < jv || jt >= jv + jvar.count())
3688 594 : continue;
3689 634 : unsigned int j = jt - jv;
3690 :
3691 634 : auto di = ivar.componentDofIndices(idof_indices, i);
3692 634 : auto dj = jvar.componentDofIndices(jdof_indices, j);
3693 634 : auto indof = di.size();
3694 634 : auto jndof = dj.size();
3695 :
3696 634 : unsigned int jj = j;
3697 634 : if (iv == jv && _component_block_diagonal[iv])
3698 : // here i must be equal to j
3699 152 : jj = 0;
3700 :
3701 634 : auto sub = jac_block.sub_matrix(i * indof, indof, jj * jndof, jndof);
3702 634 : if (scaling_factor[i] != 1.0)
3703 284 : sub *= scaling_factor[i];
3704 :
3705 634 : _dof_map.constrain_element_matrix(sub, di, dj, false);
3706 :
3707 3122 : for (MooseIndex(di) i = 0; i < di.size(); i++)
3708 195472 : for (MooseIndex(dj) j = 0; j < dj.size(); j++)
3709 192984 : if (sub(i, j) != 0.0) // no storage allocated for unimplemented jacobian terms,
3710 : // maintaining maximum sparsity possible
3711 : {
3712 25528 : _cached_jacobian_values[tag].push_back(sub(i, j));
3713 25528 : _cached_jacobian_rows[tag].push_back(di[i]);
3714 25528 : _cached_jacobian_cols[tag].push_back(dj[j]);
3715 : }
3716 634 : }
3717 : }
3718 : }
3719 :
3720 : void
3721 2952760 : Assembly::cacheJacobianBlock(const DenseMatrix<Number> & jac_block,
3722 : const std::vector<dof_id_type> & idof_indices,
3723 : const std::vector<dof_id_type> & jdof_indices,
3724 : Real scaling_factor,
3725 : LocalDataKey,
3726 : const std::set<TagID> & tags)
3727 : {
3728 : const auto has_matrix =
3729 5905520 : std::any_of(tags.begin(), tags.end(), [this](const auto tag) { return _sys.hasMatrix(tag); });
3730 :
3731 : // Work on a reusable Assembly-owned copy so callers retain their local matrix. This also lets us
3732 : // apply constraints and scaling once before caching the same block to every requested matrix tag.
3733 2952760 : if ((idof_indices.size() > 0) && (jdof_indices.size() > 0) && jac_block.n() && jac_block.m() &&
3734 : has_matrix)
3735 : {
3736 2932066 : _row_indices.assign(idof_indices.begin(), idof_indices.end());
3737 2932066 : _column_indices.assign(jdof_indices.begin(), jdof_indices.end());
3738 2932066 : _element_matrix = jac_block;
3739 :
3740 : // If we're computing the jacobian for automatically scaling variables we do not want to
3741 : // constrain the element matrix because it introduces 1s on the diagonal for the constrained
3742 : // dofs
3743 2932066 : if (!_sys.computingScalingJacobian())
3744 2932066 : _dof_map.constrain_element_matrix(_element_matrix, _row_indices, _column_indices, false);
3745 :
3746 2932066 : if (scaling_factor != 1.0)
3747 6664 : _element_matrix *= scaling_factor;
3748 :
3749 17329961 : for (const auto i : index_range(_row_indices))
3750 95087812 : for (const auto j : index_range(_column_indices))
3751 80689917 : cacheJacobian(
3752 161379834 : _row_indices[i], _column_indices[j], _element_matrix(i, j), LocalDataKey{}, tags);
3753 : }
3754 2952760 : }
3755 :
3756 : Real
3757 0 : Assembly::elementVolume(const Elem * elem) const
3758 : {
3759 0 : FEType fe_type(elem->default_order(), LAGRANGE);
3760 0 : std::unique_ptr<FEBase> fe(FEBase::build(elem->dim(), fe_type));
3761 :
3762 : // references to the quadrature points and weights
3763 0 : const std::vector<Real> & JxW = fe->get_JxW();
3764 0 : const std::vector<Point> & q_points = fe->get_xyz();
3765 :
3766 : // The default quadrature rule should integrate the mass matrix,
3767 : // thus it should be plenty to compute the volume
3768 0 : QGauss qrule(elem->dim(), fe_type.default_quadrature_order());
3769 0 : fe->attach_quadrature_rule(&qrule);
3770 0 : fe->reinit(elem);
3771 :
3772 : // perform a sanity check to ensure that size of quad rule and size of q_points is
3773 : // identical
3774 : mooseAssert(qrule.n_points() == q_points.size(),
3775 : "The number of points in the quadrature rule doesn't match the number of passed-in "
3776 : "points in Assembly::setCoordinateTransformation");
3777 :
3778 : // compute the coordinate transformation
3779 0 : Real vol = 0;
3780 0 : for (unsigned int qp = 0; qp < qrule.n_points(); ++qp)
3781 : {
3782 : Real coord;
3783 0 : coordTransformFactor(_subproblem, elem->subdomain_id(), q_points[qp], coord);
3784 0 : vol += JxW[qp] * coord;
3785 : }
3786 0 : return vol;
3787 0 : }
3788 :
3789 : void
3790 21504 : Assembly::saveLocalADArray(std::vector<ADReal> & re,
3791 : unsigned int i,
3792 : unsigned int ntest,
3793 : const ADRealEigenVector & v) const
3794 : {
3795 64512 : for (unsigned int j = 0; j < v.size(); ++j, i += ntest)
3796 43008 : re[i] += v(j);
3797 21504 : }
3798 :
3799 : void
3800 3450273 : Assembly::addCachedJacobian(GlobalDataKey)
3801 : {
3802 : #ifndef NDEBUG
3803 : if (!_subproblem.checkNonlocalCouplingRequirement())
3804 : {
3805 : mooseAssert(_cached_jacobian_rows.size() == _cached_jacobian_cols.size(),
3806 : "Error: Cached data sizes MUST be the same!");
3807 : for (MooseIndex(_cached_jacobian_rows) i = 0; i < _cached_jacobian_rows.size(); i++)
3808 : mooseAssert(_cached_jacobian_rows[i].size() == _cached_jacobian_cols[i].size(),
3809 : "Error: Cached data sizes MUST be the same for a given tag!");
3810 : }
3811 : #endif
3812 :
3813 10422651 : for (MooseIndex(_cached_jacobian_rows) i = 0; i < _cached_jacobian_rows.size(); i++)
3814 6972381 : if (_sys.hasMatrix(i))
3815 1560136186 : for (MooseIndex(_cached_jacobian_rows[i]) j = 0; j < _cached_jacobian_rows[i].size(); j++)
3816 3113340136 : _sys.getMatrix(i).add(_cached_jacobian_rows[i][j],
3817 1556670068 : _cached_jacobian_cols[i][j],
3818 1556670068 : _cached_jacobian_values[i][j]);
3819 :
3820 10422648 : for (MooseIndex(_cached_jacobian_rows) i = 0; i < _cached_jacobian_rows.size(); i++)
3821 : {
3822 6972378 : if (!_sys.hasMatrix(i))
3823 3506260 : continue;
3824 :
3825 3466118 : if (_max_cached_jacobians < _cached_jacobian_values[i].size())
3826 42697 : _max_cached_jacobians = _cached_jacobian_values[i].size();
3827 :
3828 : // Try to be more efficient from now on
3829 : // The 2 is just a fudge factor to keep us from having to grow the vector during assembly
3830 3466118 : _cached_jacobian_values[i].clear();
3831 3466118 : _cached_jacobian_values[i].reserve(_max_cached_jacobians * 2);
3832 :
3833 3466118 : _cached_jacobian_rows[i].clear();
3834 3466118 : _cached_jacobian_rows[i].reserve(_max_cached_jacobians * 2);
3835 :
3836 3466118 : _cached_jacobian_cols[i].clear();
3837 3466118 : _cached_jacobian_cols[i].reserve(_max_cached_jacobians * 2);
3838 : }
3839 3450270 : }
3840 :
3841 : inline void
3842 101576 : Assembly::addJacobianCoupledVarPair(const MooseVariableBase & ivar, const MooseVariableBase & jvar)
3843 : {
3844 101576 : auto i = ivar.number();
3845 101576 : auto j = jvar.number();
3846 305704 : for (MooseIndex(_jacobian_block_used) tag = 0; tag < _jacobian_block_used.size(); tag++)
3847 204128 : if (jacobianBlockUsed(tag, i, j) && _sys.hasMatrix(tag))
3848 53074 : addJacobianBlock(_sys.getMatrix(tag),
3849 106148 : jacobianBlock(i, j, LocalDataKey{}, tag),
3850 : ivar,
3851 : jvar,
3852 53074 : ivar.dofIndices(),
3853 53074 : jvar.dofIndices());
3854 101576 : }
3855 :
3856 : void
3857 37615 : Assembly::addJacobian(GlobalDataKey)
3858 : {
3859 110943 : for (const auto & it : _cm_ff_entry)
3860 73328 : addJacobianCoupledVarPair(*it.first, *it.second);
3861 :
3862 37615 : for (const auto & it : _cm_sf_entry)
3863 0 : addJacobianCoupledVarPair(*it.first, *it.second);
3864 :
3865 37615 : for (const auto & it : _cm_fs_entry)
3866 0 : addJacobianCoupledVarPair(*it.first, *it.second);
3867 37615 : }
3868 :
3869 : void
3870 0 : Assembly::addJacobianNonlocal(GlobalDataKey)
3871 : {
3872 0 : for (const auto & it : _cm_nonlocal_entry)
3873 : {
3874 0 : auto ivar = it.first;
3875 0 : auto jvar = it.second;
3876 0 : auto i = ivar->number();
3877 0 : auto j = jvar->number();
3878 0 : for (MooseIndex(_jacobian_block_nonlocal_used) tag = 0;
3879 0 : tag < _jacobian_block_nonlocal_used.size();
3880 : tag++)
3881 0 : if (jacobianBlockNonlocalUsed(tag, i, j) && _sys.hasMatrix(tag))
3882 0 : addJacobianBlock(_sys.getMatrix(tag),
3883 0 : jacobianBlockNonlocal(i, j, LocalDataKey{}, tag),
3884 : *ivar,
3885 : *jvar,
3886 0 : ivar->dofIndices(),
3887 : jvar->allDofIndices());
3888 : }
3889 0 : }
3890 :
3891 : void
3892 7896 : Assembly::addJacobianNeighbor(GlobalDataKey)
3893 : {
3894 37181 : for (const auto & it : _cm_ff_entry)
3895 : {
3896 29285 : auto ivar = it.first;
3897 29285 : auto jvar = it.second;
3898 29285 : auto i = ivar->number();
3899 29285 : auto j = jvar->number();
3900 88239 : for (MooseIndex(_jacobian_block_neighbor_used) tag = 0;
3901 88239 : tag < _jacobian_block_neighbor_used.size();
3902 : tag++)
3903 58954 : if (jacobianBlockNeighborUsed(tag, i, j) && _sys.hasMatrix(tag))
3904 : {
3905 21952 : addJacobianBlock(_sys.getMatrix(tag),
3906 21952 : jacobianBlockNeighbor(Moose::ElementNeighbor, i, j, LocalDataKey{}, tag),
3907 : *ivar,
3908 : *jvar,
3909 21952 : ivar->dofIndices(),
3910 21952 : jvar->dofIndicesNeighbor());
3911 :
3912 21952 : addJacobianBlock(_sys.getMatrix(tag),
3913 21952 : jacobianBlockNeighbor(Moose::NeighborElement, i, j, LocalDataKey{}, tag),
3914 : *ivar,
3915 : *jvar,
3916 21952 : ivar->dofIndicesNeighbor(),
3917 21952 : jvar->dofIndices());
3918 :
3919 21952 : addJacobianBlock(_sys.getMatrix(tag),
3920 43904 : jacobianBlockNeighbor(Moose::NeighborNeighbor, i, j, LocalDataKey{}, tag),
3921 : *ivar,
3922 : *jvar,
3923 21952 : ivar->dofIndicesNeighbor(),
3924 21952 : jvar->dofIndicesNeighbor());
3925 : }
3926 : }
3927 7896 : }
3928 :
3929 : void
3930 112176 : Assembly::addJacobianNeighborLowerD(GlobalDataKey)
3931 : {
3932 287463 : for (const auto & it : _cm_ff_entry)
3933 : {
3934 175287 : auto ivar = it.first;
3935 175287 : auto jvar = it.second;
3936 175287 : auto i = ivar->number();
3937 175287 : auto j = jvar->number();
3938 530949 : for (MooseIndex(_jacobian_block_lower_used) tag = 0; tag < _jacobian_block_lower_used.size();
3939 : tag++)
3940 355662 : if (jacobianBlockLowerUsed(tag, i, j) && _sys.hasMatrix(tag))
3941 : {
3942 7836 : addJacobianBlock(_sys.getMatrix(tag),
3943 7836 : jacobianBlockMortar(Moose::LowerLower, i, j, LocalDataKey{}, tag),
3944 : *ivar,
3945 : *jvar,
3946 7836 : ivar->dofIndicesLower(),
3947 7836 : jvar->dofIndicesLower());
3948 :
3949 7836 : addJacobianBlock(_sys.getMatrix(tag),
3950 7836 : jacobianBlockMortar(Moose::LowerSecondary, i, j, LocalDataKey{}, tag),
3951 : *ivar,
3952 : *jvar,
3953 7836 : ivar->dofIndicesLower(),
3954 7836 : jvar->dofIndicesNeighbor());
3955 :
3956 7836 : addJacobianBlock(_sys.getMatrix(tag),
3957 7836 : jacobianBlockMortar(Moose::LowerPrimary, i, j, LocalDataKey{}, tag),
3958 : *ivar,
3959 : *jvar,
3960 7836 : ivar->dofIndicesLower(),
3961 7836 : jvar->dofIndices());
3962 :
3963 7836 : addJacobianBlock(_sys.getMatrix(tag),
3964 7836 : jacobianBlockMortar(Moose::SecondaryLower, i, j, LocalDataKey{}, tag),
3965 : *ivar,
3966 : *jvar,
3967 7836 : ivar->dofIndicesNeighbor(),
3968 7836 : jvar->dofIndicesLower());
3969 :
3970 7836 : addJacobianBlock(_sys.getMatrix(tag),
3971 15672 : jacobianBlockMortar(Moose::PrimaryLower, i, j, LocalDataKey{}, tag),
3972 : *ivar,
3973 : *jvar,
3974 7836 : ivar->dofIndices(),
3975 7836 : jvar->dofIndicesLower());
3976 : }
3977 :
3978 530949 : for (MooseIndex(_jacobian_block_neighbor_used) tag = 0;
3979 530949 : tag < _jacobian_block_neighbor_used.size();
3980 : tag++)
3981 355662 : if (jacobianBlockNeighborUsed(tag, i, j) && _sys.hasMatrix(tag))
3982 : {
3983 84646 : addJacobianBlock(_sys.getMatrix(tag),
3984 84646 : jacobianBlockNeighbor(Moose::ElementNeighbor, i, j, LocalDataKey{}, tag),
3985 : *ivar,
3986 : *jvar,
3987 84646 : ivar->dofIndices(),
3988 84646 : jvar->dofIndicesNeighbor());
3989 :
3990 84646 : addJacobianBlock(_sys.getMatrix(tag),
3991 84646 : jacobianBlockNeighbor(Moose::NeighborElement, i, j, LocalDataKey{}, tag),
3992 : *ivar,
3993 : *jvar,
3994 84646 : ivar->dofIndicesNeighbor(),
3995 84646 : jvar->dofIndices());
3996 :
3997 84646 : addJacobianBlock(_sys.getMatrix(tag),
3998 169292 : jacobianBlockNeighbor(Moose::NeighborNeighbor, i, j, LocalDataKey{}, tag),
3999 : *ivar,
4000 : *jvar,
4001 84646 : ivar->dofIndicesNeighbor(),
4002 84646 : jvar->dofIndicesNeighbor());
4003 : }
4004 : }
4005 112176 : }
4006 :
4007 : void
4008 4888 : Assembly::addJacobianLowerD(GlobalDataKey)
4009 : {
4010 42320 : for (const auto & it : _cm_ff_entry)
4011 : {
4012 37432 : auto ivar = it.first;
4013 37432 : auto jvar = it.second;
4014 37432 : auto i = ivar->number();
4015 37432 : auto j = jvar->number();
4016 112296 : for (MooseIndex(_jacobian_block_lower_used) tag = 0; tag < _jacobian_block_lower_used.size();
4017 : tag++)
4018 74864 : if (jacobianBlockLowerUsed(tag, i, j) && _sys.hasMatrix(tag))
4019 : {
4020 6704 : addJacobianBlock(_sys.getMatrix(tag),
4021 6704 : jacobianBlockMortar(Moose::LowerLower, i, j, LocalDataKey{}, tag),
4022 : *ivar,
4023 : *jvar,
4024 6704 : ivar->dofIndicesLower(),
4025 6704 : jvar->dofIndicesLower());
4026 :
4027 6704 : addJacobianBlock(_sys.getMatrix(tag),
4028 6704 : jacobianBlockMortar(Moose::LowerSecondary, i, j, LocalDataKey{}, tag),
4029 : *ivar,
4030 : *jvar,
4031 6704 : ivar->dofIndicesLower(),
4032 6704 : jvar->dofIndices());
4033 :
4034 6704 : addJacobianBlock(_sys.getMatrix(tag),
4035 13408 : jacobianBlockMortar(Moose::SecondaryLower, i, j, LocalDataKey{}, tag),
4036 : *ivar,
4037 : *jvar,
4038 6704 : ivar->dofIndices(),
4039 6704 : jvar->dofIndicesLower());
4040 : }
4041 : }
4042 4888 : }
4043 :
4044 : void
4045 48176134 : Assembly::cacheJacobian(GlobalDataKey)
4046 : {
4047 118591179 : for (const auto & it : _cm_ff_entry)
4048 70415045 : cacheJacobianCoupledVarPair(*it.first, *it.second);
4049 :
4050 48434874 : for (const auto & it : _cm_fs_entry)
4051 258740 : cacheJacobianCoupledVarPair(*it.first, *it.second);
4052 :
4053 48434874 : for (const auto & it : _cm_sf_entry)
4054 258740 : cacheJacobianCoupledVarPair(*it.first, *it.second);
4055 48176134 : }
4056 :
4057 : // private method, so no key required
4058 : void
4059 70932525 : Assembly::cacheJacobianCoupledVarPair(const MooseVariableBase & ivar,
4060 : const MooseVariableBase & jvar)
4061 : {
4062 70932525 : auto i = ivar.number();
4063 70932525 : auto j = jvar.number();
4064 214786131 : for (MooseIndex(_jacobian_block_used) tag = 0; tag < _jacobian_block_used.size(); tag++)
4065 143853606 : if (jacobianBlockUsed(tag, i, j) && _sys.hasMatrix(tag))
4066 57908442 : cacheJacobianBlock(jacobianBlock(i, j, LocalDataKey{}, tag),
4067 : ivar,
4068 : jvar,
4069 57908442 : ivar.dofIndices(),
4070 57908442 : jvar.dofIndices(),
4071 : tag);
4072 70932525 : }
4073 :
4074 : void
4075 4404 : Assembly::cacheJacobianNonlocal(GlobalDataKey)
4076 : {
4077 8912 : for (const auto & it : _cm_nonlocal_entry)
4078 : {
4079 4508 : auto ivar = it.first;
4080 4508 : auto jvar = it.second;
4081 4508 : auto i = ivar->number();
4082 4508 : auto j = jvar->number();
4083 13524 : for (MooseIndex(_jacobian_block_nonlocal_used) tag = 0;
4084 13524 : tag < _jacobian_block_nonlocal_used.size();
4085 : tag++)
4086 9016 : if (jacobianBlockNonlocalUsed(tag, i, j) && _sys.hasMatrix(tag))
4087 1268 : cacheJacobianBlockNonzero(jacobianBlockNonlocal(i, j, LocalDataKey{}, tag),
4088 : *ivar,
4089 : *jvar,
4090 634 : ivar->dofIndices(),
4091 : jvar->allDofIndices(),
4092 : tag);
4093 : }
4094 4404 : }
4095 :
4096 : void
4097 9409 : Assembly::cacheJacobianNeighbor(GlobalDataKey)
4098 : {
4099 32642 : for (const auto & it : _cm_ff_entry)
4100 : {
4101 23233 : auto ivar = it.first;
4102 23233 : auto jvar = it.second;
4103 23233 : auto i = ivar->number();
4104 23233 : auto j = jvar->number();
4105 :
4106 69699 : for (MooseIndex(_jacobian_block_neighbor_used) tag = 0;
4107 69699 : tag < _jacobian_block_neighbor_used.size();
4108 : tag++)
4109 46466 : if (jacobianBlockNeighborUsed(tag, i, j) && _sys.hasMatrix(tag))
4110 : {
4111 7717 : cacheJacobianBlock(jacobianBlockNeighbor(Moose::ElementNeighbor, i, j, LocalDataKey{}, tag),
4112 : *ivar,
4113 : *jvar,
4114 7717 : ivar->dofIndices(),
4115 7717 : jvar->dofIndicesNeighbor(),
4116 : tag);
4117 7717 : cacheJacobianBlock(jacobianBlockNeighbor(Moose::NeighborElement, i, j, LocalDataKey{}, tag),
4118 : *ivar,
4119 : *jvar,
4120 7717 : ivar->dofIndicesNeighbor(),
4121 7717 : jvar->dofIndices(),
4122 : tag);
4123 30868 : cacheJacobianBlock(
4124 7717 : jacobianBlockNeighbor(Moose::NeighborNeighbor, i, j, LocalDataKey{}, tag),
4125 : *ivar,
4126 : *jvar,
4127 7717 : ivar->dofIndicesNeighbor(),
4128 7717 : jvar->dofIndicesNeighbor(),
4129 : tag);
4130 : }
4131 : }
4132 9409 : }
4133 :
4134 : void
4135 191698 : Assembly::cacheJacobianMortar(GlobalDataKey)
4136 : {
4137 886858 : for (const auto & it : _cm_ff_entry)
4138 : {
4139 695160 : auto ivar = it.first;
4140 695160 : auto jvar = it.second;
4141 695160 : auto i = ivar->number();
4142 695160 : auto j = jvar->number();
4143 2085480 : for (MooseIndex(_jacobian_block_lower_used) tag = 0; tag < _jacobian_block_lower_used.size();
4144 : tag++)
4145 1390320 : if (jacobianBlockLowerUsed(tag, i, j) && _sys.hasMatrix(tag))
4146 : {
4147 44872 : cacheJacobianBlock(jacobianBlockMortar(Moose::LowerLower, i, j, LocalDataKey{}, tag),
4148 : *ivar,
4149 : *jvar,
4150 44872 : ivar->dofIndicesLower(),
4151 44872 : jvar->dofIndicesLower(),
4152 : tag);
4153 :
4154 44872 : cacheJacobianBlock(jacobianBlockMortar(Moose::LowerSecondary, i, j, LocalDataKey{}, tag),
4155 : *ivar,
4156 : *jvar,
4157 44872 : ivar->dofIndicesLower(),
4158 44872 : jvar->dofIndices(),
4159 : tag);
4160 :
4161 44872 : cacheJacobianBlock(jacobianBlockMortar(Moose::LowerPrimary, i, j, LocalDataKey{}, tag),
4162 : *ivar,
4163 : *jvar,
4164 44872 : ivar->dofIndicesLower(),
4165 44872 : jvar->dofIndicesNeighbor(),
4166 : tag);
4167 :
4168 44872 : cacheJacobianBlock(jacobianBlockMortar(Moose::SecondaryLower, i, j, LocalDataKey{}, tag),
4169 : *ivar,
4170 : *jvar,
4171 44872 : ivar->dofIndices(),
4172 44872 : jvar->dofIndicesLower(),
4173 : tag);
4174 :
4175 179488 : cacheJacobianBlock(
4176 44872 : jacobianBlockMortar(Moose::SecondarySecondary, i, j, LocalDataKey{}, tag),
4177 : *ivar,
4178 : *jvar,
4179 44872 : ivar->dofIndices(),
4180 44872 : jvar->dofIndices(),
4181 : tag);
4182 :
4183 44872 : cacheJacobianBlock(jacobianBlockMortar(Moose::SecondaryPrimary, i, j, LocalDataKey{}, tag),
4184 : *ivar,
4185 : *jvar,
4186 44872 : ivar->dofIndices(),
4187 44872 : jvar->dofIndicesNeighbor(),
4188 : tag);
4189 :
4190 44872 : cacheJacobianBlock(jacobianBlockMortar(Moose::PrimaryLower, i, j, LocalDataKey{}, tag),
4191 : *ivar,
4192 : *jvar,
4193 44872 : ivar->dofIndicesNeighbor(),
4194 44872 : jvar->dofIndicesLower(),
4195 : tag);
4196 :
4197 44872 : cacheJacobianBlock(jacobianBlockMortar(Moose::PrimarySecondary, i, j, LocalDataKey{}, tag),
4198 : *ivar,
4199 : *jvar,
4200 44872 : ivar->dofIndicesNeighbor(),
4201 44872 : jvar->dofIndices(),
4202 : tag);
4203 :
4204 44872 : cacheJacobianBlock(jacobianBlockMortar(Moose::PrimaryPrimary, i, j, LocalDataKey{}, tag),
4205 : *ivar,
4206 : *jvar,
4207 44872 : ivar->dofIndicesNeighbor(),
4208 44872 : jvar->dofIndicesNeighbor(),
4209 : tag);
4210 : }
4211 : }
4212 191698 : }
4213 :
4214 : void
4215 70832 : Assembly::addJacobianBlockTags(SparseMatrix<Number> & jacobian,
4216 : unsigned int ivar,
4217 : unsigned int jvar,
4218 : const DofMap & dof_map,
4219 : std::vector<dof_id_type> & dof_indices,
4220 : GlobalDataKey,
4221 : const std::set<TagID> & tags)
4222 : {
4223 184848 : for (auto tag : tags)
4224 114016 : addJacobianBlock(jacobian, ivar, jvar, dof_map, dof_indices, GlobalDataKey{}, tag);
4225 70832 : }
4226 :
4227 : void
4228 114016 : Assembly::addJacobianBlock(SparseMatrix<Number> & jacobian,
4229 : unsigned int ivar,
4230 : unsigned int jvar,
4231 : const DofMap & dof_map,
4232 : std::vector<dof_id_type> & dof_indices,
4233 : GlobalDataKey,
4234 : TagID tag)
4235 : {
4236 114016 : if (dof_indices.size() == 0)
4237 0 : return;
4238 114016 : if (!(*_cm)(ivar, jvar))
4239 0 : return;
4240 :
4241 114016 : auto & iv = _sys.getVariable(_tid, ivar);
4242 114016 : auto & jv = _sys.getVariable(_tid, jvar);
4243 114016 : auto & scaling_factor = iv.arrayScalingFactor();
4244 :
4245 114016 : const unsigned int ivn = iv.number();
4246 114016 : const unsigned int jvn = jv.number();
4247 114016 : auto & ke = jacobianBlock(ivn, jvn, LocalDataKey{}, tag);
4248 :
4249 : // It is guaranteed by design iv.number <= ivar since iv is obtained
4250 : // through SystemBase::getVariable with ivar.
4251 : // Most of times ivar will just be equal to iv.number except for array variables,
4252 : // where ivar could be a number for a component of an array variable but calling
4253 : // getVariable will return the array variable that has the number of the 0th component.
4254 : // It is the same for jvar.
4255 114016 : const unsigned int i = ivar - ivn;
4256 114016 : const unsigned int j = jvar - jvn;
4257 :
4258 : // DoF indices are independently given
4259 114016 : auto di = dof_indices;
4260 114016 : auto dj = dof_indices;
4261 :
4262 114016 : auto indof = di.size();
4263 114016 : auto jndof = dj.size();
4264 :
4265 114016 : unsigned int jj = j;
4266 114016 : if (ivar == jvar && _component_block_diagonal[ivn])
4267 109568 : jj = 0;
4268 :
4269 114016 : auto sub = ke.sub_matrix(i * indof, indof, jj * jndof, jndof);
4270 : // If we're computing the jacobian for automatically scaling variables we do not want to
4271 : // constrain the element matrix because it introduces 1s on the diagonal for the constrained
4272 : // dofs
4273 114016 : if (!_sys.computingScalingJacobian())
4274 114016 : dof_map.constrain_element_matrix(sub, di, dj, false);
4275 :
4276 114016 : if (scaling_factor[i] != 1.0)
4277 0 : sub *= scaling_factor[i];
4278 :
4279 114016 : jacobian.add_matrix(sub, di, dj);
4280 114016 : }
4281 :
4282 : void
4283 0 : Assembly::addJacobianBlockNonlocal(SparseMatrix<Number> & jacobian,
4284 : const unsigned int ivar,
4285 : const unsigned int jvar,
4286 : const DofMap & dof_map,
4287 : const std::vector<dof_id_type> & idof_indices,
4288 : const std::vector<dof_id_type> & jdof_indices,
4289 : GlobalDataKey,
4290 : const TagID tag)
4291 : {
4292 0 : if (idof_indices.size() == 0 || jdof_indices.size() == 0)
4293 0 : return;
4294 0 : if (jacobian.n() == 0 || jacobian.m() == 0)
4295 0 : return;
4296 0 : if (!(*_cm)(ivar, jvar))
4297 0 : return;
4298 :
4299 0 : auto & iv = _sys.getVariable(_tid, ivar);
4300 0 : auto & jv = _sys.getVariable(_tid, jvar);
4301 0 : auto & scaling_factor = iv.arrayScalingFactor();
4302 :
4303 0 : const unsigned int ivn = iv.number();
4304 0 : const unsigned int jvn = jv.number();
4305 0 : auto & keg = jacobianBlockNonlocal(ivn, jvn, LocalDataKey{}, tag);
4306 :
4307 : // It is guaranteed by design iv.number <= ivar since iv is obtained
4308 : // through SystemBase::getVariable with ivar.
4309 : // Most of times ivar will just be equal to iv.number except for array variables,
4310 : // where ivar could be a number for a component of an array variable but calling
4311 : // getVariable will return the array variable that has the number of the 0th component.
4312 : // It is the same for jvar.
4313 0 : const unsigned int i = ivar - ivn;
4314 0 : const unsigned int j = jvar - jvn;
4315 :
4316 : // DoF indices are independently given
4317 0 : auto di = idof_indices;
4318 0 : auto dj = jdof_indices;
4319 :
4320 0 : auto indof = di.size();
4321 0 : auto jndof = dj.size();
4322 :
4323 0 : unsigned int jj = j;
4324 0 : if (ivar == jvar && _component_block_diagonal[ivn])
4325 0 : jj = 0;
4326 :
4327 0 : auto sub = keg.sub_matrix(i * indof, indof, jj * jndof, jndof);
4328 : // If we're computing the jacobian for automatically scaling variables we do not want to
4329 : // constrain the element matrix because it introduces 1s on the diagonal for the constrained
4330 : // dofs
4331 0 : if (!_sys.computingScalingJacobian())
4332 0 : dof_map.constrain_element_matrix(sub, di, dj, false);
4333 :
4334 0 : if (scaling_factor[i] != 1.0)
4335 0 : sub *= scaling_factor[i];
4336 :
4337 0 : jacobian.add_matrix(sub, di, dj);
4338 0 : }
4339 :
4340 : void
4341 0 : Assembly::addJacobianBlockNonlocalTags(SparseMatrix<Number> & jacobian,
4342 : const unsigned int ivar,
4343 : const unsigned int jvar,
4344 : const DofMap & dof_map,
4345 : const std::vector<dof_id_type> & idof_indices,
4346 : const std::vector<dof_id_type> & jdof_indices,
4347 : GlobalDataKey,
4348 : const std::set<TagID> & tags)
4349 : {
4350 0 : for (auto tag : tags)
4351 0 : addJacobianBlockNonlocal(
4352 0 : jacobian, ivar, jvar, dof_map, idof_indices, jdof_indices, GlobalDataKey{}, tag);
4353 0 : }
4354 :
4355 : void
4356 1536 : Assembly::addJacobianNeighbor(SparseMatrix<Number> & jacobian,
4357 : const unsigned int ivar,
4358 : const unsigned int jvar,
4359 : const DofMap & dof_map,
4360 : std::vector<dof_id_type> & dof_indices,
4361 : std::vector<dof_id_type> & neighbor_dof_indices,
4362 : GlobalDataKey,
4363 : const TagID tag)
4364 : {
4365 1536 : if (dof_indices.size() == 0 && neighbor_dof_indices.size() == 0)
4366 0 : return;
4367 1536 : if (!(*_cm)(ivar, jvar))
4368 0 : return;
4369 :
4370 1536 : auto & iv = _sys.getVariable(_tid, ivar);
4371 1536 : auto & jv = _sys.getVariable(_tid, jvar);
4372 1536 : auto & scaling_factor = iv.arrayScalingFactor();
4373 :
4374 1536 : const unsigned int ivn = iv.number();
4375 1536 : const unsigned int jvn = jv.number();
4376 1536 : auto & ken = jacobianBlockNeighbor(Moose::ElementNeighbor, ivn, jvn, LocalDataKey{}, tag);
4377 1536 : auto & kne = jacobianBlockNeighbor(Moose::NeighborElement, ivn, jvn, LocalDataKey{}, tag);
4378 1536 : auto & knn = jacobianBlockNeighbor(Moose::NeighborNeighbor, ivn, jvn, LocalDataKey{}, tag);
4379 :
4380 : // It is guaranteed by design iv.number <= ivar since iv is obtained
4381 : // through SystemBase::getVariable with ivar.
4382 : // Most of times ivar will just be equal to iv.number except for array variables,
4383 : // where ivar could be a number for a component of an array variable but calling
4384 : // getVariable will return the array variable that has the number of the 0th component.
4385 : // It is the same for jvar.
4386 1536 : const unsigned int i = ivar - ivn;
4387 1536 : const unsigned int j = jvar - jvn;
4388 : // DoF indices are independently given
4389 1536 : auto dc = dof_indices;
4390 1536 : auto dn = neighbor_dof_indices;
4391 1536 : auto cndof = dc.size();
4392 1536 : auto nndof = dn.size();
4393 :
4394 1536 : unsigned int jj = j;
4395 1536 : if (ivar == jvar && _component_block_diagonal[ivn])
4396 1536 : jj = 0;
4397 :
4398 1536 : auto suben = ken.sub_matrix(i * cndof, cndof, jj * nndof, nndof);
4399 1536 : auto subne = kne.sub_matrix(i * nndof, nndof, jj * cndof, cndof);
4400 1536 : auto subnn = knn.sub_matrix(i * nndof, nndof, jj * nndof, nndof);
4401 :
4402 : // If we're computing the jacobian for automatically scaling variables we do not want to
4403 : // constrain the element matrix because it introduces 1s on the diagonal for the constrained
4404 : // dofs
4405 1536 : if (!_sys.computingScalingJacobian())
4406 : {
4407 1536 : dof_map.constrain_element_matrix(suben, dc, dn, false);
4408 1536 : dof_map.constrain_element_matrix(subne, dn, dc, false);
4409 1536 : dof_map.constrain_element_matrix(subnn, dn, dn, false);
4410 : }
4411 :
4412 1536 : if (scaling_factor[i] != 1.0)
4413 : {
4414 0 : suben *= scaling_factor[i];
4415 0 : subne *= scaling_factor[i];
4416 0 : subnn *= scaling_factor[i];
4417 : }
4418 :
4419 1536 : jacobian.add_matrix(suben, dc, dn);
4420 1536 : jacobian.add_matrix(subne, dn, dc);
4421 1536 : jacobian.add_matrix(subnn, dn, dn);
4422 1536 : }
4423 :
4424 : void
4425 768 : Assembly::addJacobianNeighborTags(SparseMatrix<Number> & jacobian,
4426 : const unsigned int ivar,
4427 : const unsigned int jvar,
4428 : const DofMap & dof_map,
4429 : std::vector<dof_id_type> & dof_indices,
4430 : std::vector<dof_id_type> & neighbor_dof_indices,
4431 : GlobalDataKey,
4432 : const std::set<TagID> & tags)
4433 : {
4434 2304 : for (const auto tag : tags)
4435 1536 : addJacobianNeighbor(
4436 3072 : jacobian, ivar, jvar, dof_map, dof_indices, neighbor_dof_indices, GlobalDataKey{}, tag);
4437 768 : }
4438 :
4439 : void
4440 11603 : Assembly::addJacobianScalar(GlobalDataKey)
4441 : {
4442 26924 : for (const auto & it : _cm_ss_entry)
4443 15321 : addJacobianCoupledVarPair(*it.first, *it.second);
4444 11603 : }
4445 :
4446 : void
4447 30002 : Assembly::addJacobianOffDiagScalar(unsigned int ivar, GlobalDataKey)
4448 : {
4449 30002 : const std::vector<MooseVariableFEBase *> & vars = _sys.getVariables(_tid);
4450 30002 : MooseVariableScalar & var_i = _sys.getScalarVariable(_tid, ivar);
4451 42929 : for (const auto & var_j : vars)
4452 12927 : addJacobianCoupledVarPair(var_i, *var_j);
4453 30002 : }
4454 :
4455 : void
4456 223982165 : Assembly::cacheJacobian(
4457 : numeric_index_type i, numeric_index_type j, Real value, LocalDataKey, TagID tag)
4458 : {
4459 223982165 : _cached_jacobian_rows[tag].push_back(i);
4460 223982165 : _cached_jacobian_cols[tag].push_back(j);
4461 223982165 : _cached_jacobian_values[tag].push_back(value);
4462 223982165 : }
4463 :
4464 : void
4465 223928421 : Assembly::cacheJacobian(numeric_index_type i,
4466 : numeric_index_type j,
4467 : Real value,
4468 : LocalDataKey,
4469 : const std::set<TagID> & tags)
4470 : {
4471 463141763 : for (auto tag : tags)
4472 239213342 : if (_sys.hasMatrix(tag))
4473 223982165 : cacheJacobian(i, j, value, LocalDataKey{}, tag);
4474 223928421 : }
4475 :
4476 : void
4477 397598 : Assembly::setCachedJacobian(GlobalDataKey)
4478 : {
4479 1204621 : for (MooseIndex(_cached_jacobian_rows) tag = 0; tag < _cached_jacobian_rows.size(); tag++)
4480 807023 : if (_sys.hasMatrix(tag))
4481 : {
4482 : // First zero the rows (including the diagonals) to prepare for
4483 : // setting the cached values.
4484 398999 : _sys.getMatrix(tag).zero_rows(_cached_jacobian_rows[tag], 0.0);
4485 :
4486 : // TODO: Use SparseMatrix::set_values() for efficiency
4487 8649349 : for (MooseIndex(_cached_jacobian_values) i = 0; i < _cached_jacobian_values[tag].size(); ++i)
4488 16500700 : _sys.getMatrix(tag).set(_cached_jacobian_rows[tag][i],
4489 8250350 : _cached_jacobian_cols[tag][i],
4490 8250350 : _cached_jacobian_values[tag][i]);
4491 : }
4492 :
4493 397598 : clearCachedJacobian();
4494 397598 : }
4495 :
4496 : void
4497 0 : Assembly::zeroCachedJacobian(GlobalDataKey)
4498 : {
4499 0 : for (MooseIndex(_cached_jacobian_rows) tag = 0; tag < _cached_jacobian_rows.size(); tag++)
4500 0 : if (_sys.hasMatrix(tag))
4501 0 : _sys.getMatrix(tag).zero_rows(_cached_jacobian_rows[tag], 0.0);
4502 :
4503 0 : clearCachedJacobian();
4504 0 : }
4505 :
4506 : void
4507 397598 : Assembly::clearCachedJacobian()
4508 : {
4509 1204621 : for (MooseIndex(_cached_jacobian_rows) tag = 0; tag < _cached_jacobian_rows.size(); tag++)
4510 : {
4511 807023 : _cached_jacobian_rows[tag].clear();
4512 807023 : _cached_jacobian_cols[tag].clear();
4513 807023 : _cached_jacobian_values[tag].clear();
4514 : }
4515 397598 : }
4516 :
4517 : void
4518 0 : Assembly::modifyWeightsDueToXFEM(const Elem * elem)
4519 : {
4520 : mooseAssert(_xfem != nullptr, "This function should not be called if xfem is inactive");
4521 :
4522 0 : if (_current_qrule == _current_qrule_arbitrary)
4523 0 : return;
4524 :
4525 0 : MooseArray<Real> xfem_weight_multipliers;
4526 0 : if (_xfem->getXFEMWeights(xfem_weight_multipliers, elem, _current_qrule, _current_q_points))
4527 : {
4528 : mooseAssert(xfem_weight_multipliers.size() == _current_JxW.size(),
4529 : "Size of weight multipliers in xfem doesn't match number of quadrature points");
4530 0 : for (unsigned i = 0; i < xfem_weight_multipliers.size(); i++)
4531 0 : _current_JxW[i] = _current_JxW[i] * xfem_weight_multipliers[i];
4532 :
4533 0 : xfem_weight_multipliers.release();
4534 : }
4535 0 : }
4536 :
4537 : void
4538 0 : Assembly::modifyFaceWeightsDueToXFEM(const Elem * elem, unsigned int side)
4539 : {
4540 : mooseAssert(_xfem != nullptr, "This function should not be called if xfem is inactive");
4541 :
4542 0 : if (_current_qrule_face == _current_qrule_arbitrary)
4543 0 : return;
4544 :
4545 0 : MooseArray<Real> xfem_face_weight_multipliers;
4546 0 : if (_xfem->getXFEMFaceWeights(
4547 0 : xfem_face_weight_multipliers, elem, _current_qrule_face, _current_q_points_face, side))
4548 : {
4549 : mooseAssert(xfem_face_weight_multipliers.size() == _current_JxW_face.size(),
4550 : "Size of weight multipliers in xfem doesn't match number of quadrature points");
4551 0 : for (unsigned i = 0; i < xfem_face_weight_multipliers.size(); i++)
4552 0 : _current_JxW_face[i] = _current_JxW_face[i] * xfem_face_weight_multipliers[i];
4553 :
4554 0 : xfem_face_weight_multipliers.release();
4555 : }
4556 0 : }
4557 :
4558 : void
4559 450 : Assembly::hasScalingVector()
4560 : {
4561 900 : _scaling_vector = &_sys.getVector("scaling_factors");
4562 450 : }
4563 :
4564 : void
4565 0 : Assembly::modifyArbitraryWeights(const std::vector<Real> & weights)
4566 : {
4567 : mooseAssert(_current_qrule == _current_qrule_arbitrary, "Rule should be arbitrary");
4568 : mooseAssert(weights.size() == _current_physical_points.size(), "Size mismatch");
4569 :
4570 0 : for (MooseIndex(weights.size()) i = 0; i < weights.size(); ++i)
4571 0 : _current_JxW[i] = weights[i];
4572 0 : }
4573 :
4574 : template <>
4575 : const typename OutputTools<VectorValue<Real>>::VariablePhiValue &
4576 1870 : Assembly::fePhi<VectorValue<Real>>(FEType type) const
4577 : {
4578 1870 : buildVectorFE(type);
4579 1870 : return _vector_fe_shape_data[type]->_phi;
4580 : }
4581 :
4582 : template <>
4583 : const typename OutputTools<VectorValue<Real>>::VariablePhiGradient &
4584 1870 : Assembly::feGradPhi<VectorValue<Real>>(FEType type) const
4585 : {
4586 1870 : buildVectorFE(type);
4587 1870 : return _vector_fe_shape_data[type]->_grad_phi;
4588 : }
4589 :
4590 : template <>
4591 : const typename OutputTools<VectorValue<Real>>::VariablePhiSecond &
4592 0 : Assembly::feSecondPhi<VectorValue<Real>>(FEType type) const
4593 : {
4594 0 : _need_second_derivative.insert(type);
4595 0 : buildVectorFE(type);
4596 0 : return _vector_fe_shape_data[type]->_second_phi;
4597 : }
4598 :
4599 : template <>
4600 : const typename OutputTools<VectorValue<Real>>::VariablePhiValue &
4601 3740 : Assembly::fePhiLower<VectorValue<Real>>(FEType type) const
4602 : {
4603 3740 : buildVectorLowerDFE(type);
4604 3740 : return _vector_fe_shape_data_lower[type]->_phi;
4605 : }
4606 :
4607 : template <>
4608 : const typename OutputTools<VectorValue<Real>>::VariablePhiValue &
4609 0 : Assembly::feDualPhiLower<VectorValue<Real>>(FEType type) const
4610 : {
4611 0 : buildVectorDualLowerDFE(type);
4612 0 : return _vector_fe_shape_data_dual_lower[type]->_phi;
4613 : }
4614 :
4615 : template <>
4616 : const typename OutputTools<VectorValue<Real>>::VariablePhiGradient &
4617 3740 : Assembly::feGradPhiLower<VectorValue<Real>>(FEType type) const
4618 : {
4619 3740 : buildVectorLowerDFE(type);
4620 3740 : return _vector_fe_shape_data_lower[type]->_grad_phi;
4621 : }
4622 :
4623 : template <>
4624 : const typename OutputTools<VectorValue<Real>>::VariablePhiGradient &
4625 0 : Assembly::feGradDualPhiLower<VectorValue<Real>>(FEType type) const
4626 : {
4627 0 : buildVectorDualLowerDFE(type);
4628 0 : return _vector_fe_shape_data_dual_lower[type]->_grad_phi;
4629 : }
4630 :
4631 : template <>
4632 : const typename OutputTools<VectorValue<Real>>::VariablePhiValue &
4633 1870 : Assembly::fePhiFace<VectorValue<Real>>(FEType type) const
4634 : {
4635 1870 : buildVectorFaceFE(type);
4636 1870 : return _vector_fe_shape_data_face[type]->_phi;
4637 : }
4638 :
4639 : template <>
4640 : const typename OutputTools<VectorValue<Real>>::VariablePhiGradient &
4641 1870 : Assembly::feGradPhiFace<VectorValue<Real>>(FEType type) const
4642 : {
4643 1870 : buildVectorFaceFE(type);
4644 1870 : return _vector_fe_shape_data_face[type]->_grad_phi;
4645 : }
4646 :
4647 : template <>
4648 : const typename OutputTools<VectorValue<Real>>::VariablePhiSecond &
4649 0 : Assembly::feSecondPhiFace<VectorValue<Real>>(FEType type) const
4650 : {
4651 0 : _need_second_derivative.insert(type);
4652 0 : buildVectorFaceFE(type);
4653 :
4654 : // If we're building for a face we probably need to build for a
4655 : // neighbor while _need_second_derivative is set;
4656 : // onInterface/reinitNeighbor/etc don't distinguish
4657 0 : buildVectorFaceNeighborFE(type);
4658 :
4659 0 : return _vector_fe_shape_data_face[type]->_second_phi;
4660 : }
4661 :
4662 : template <>
4663 : const typename OutputTools<VectorValue<Real>>::VariablePhiValue &
4664 1870 : Assembly::fePhiNeighbor<VectorValue<Real>>(FEType type) const
4665 : {
4666 1870 : buildVectorNeighborFE(type);
4667 1870 : return _vector_fe_shape_data_neighbor[type]->_phi;
4668 : }
4669 :
4670 : template <>
4671 : const typename OutputTools<VectorValue<Real>>::VariablePhiGradient &
4672 1870 : Assembly::feGradPhiNeighbor<VectorValue<Real>>(FEType type) const
4673 : {
4674 1870 : buildVectorNeighborFE(type);
4675 1870 : return _vector_fe_shape_data_neighbor[type]->_grad_phi;
4676 : }
4677 :
4678 : template <>
4679 : const typename OutputTools<VectorValue<Real>>::VariablePhiSecond &
4680 0 : Assembly::feSecondPhiNeighbor<VectorValue<Real>>(FEType type) const
4681 : {
4682 0 : _need_second_derivative_neighbor.insert(type);
4683 0 : buildVectorNeighborFE(type);
4684 0 : return _vector_fe_shape_data_neighbor[type]->_second_phi;
4685 : }
4686 :
4687 : template <>
4688 : const typename OutputTools<VectorValue<Real>>::VariablePhiValue &
4689 1870 : Assembly::fePhiFaceNeighbor<VectorValue<Real>>(FEType type) const
4690 : {
4691 1870 : buildVectorFaceNeighborFE(type);
4692 1870 : return _vector_fe_shape_data_face_neighbor[type]->_phi;
4693 : }
4694 :
4695 : template <>
4696 : const typename OutputTools<VectorValue<Real>>::VariablePhiGradient &
4697 1870 : Assembly::feGradPhiFaceNeighbor<VectorValue<Real>>(FEType type) const
4698 : {
4699 1870 : buildVectorFaceNeighborFE(type);
4700 1870 : return _vector_fe_shape_data_face_neighbor[type]->_grad_phi;
4701 : }
4702 :
4703 : template <>
4704 : const typename OutputTools<VectorValue<Real>>::VariablePhiSecond &
4705 0 : Assembly::feSecondPhiFaceNeighbor<VectorValue<Real>>(FEType type) const
4706 : {
4707 0 : _need_second_derivative_neighbor.insert(type);
4708 0 : buildVectorFaceNeighborFE(type);
4709 0 : return _vector_fe_shape_data_face_neighbor[type]->_second_phi;
4710 : }
4711 :
4712 : template <>
4713 : const typename OutputTools<VectorValue<Real>>::VariablePhiCurl &
4714 57237 : Assembly::feCurlPhi<VectorValue<Real>>(FEType type) const
4715 : {
4716 57237 : _need_curl.insert(type);
4717 57237 : buildVectorFE(type);
4718 57237 : return _vector_fe_shape_data[type]->_curl_phi;
4719 : }
4720 :
4721 : template <>
4722 : const typename OutputTools<VectorValue<Real>>::VariablePhiCurl &
4723 207 : Assembly::feCurlPhiFace<VectorValue<Real>>(FEType type) const
4724 : {
4725 207 : _need_curl.insert(type);
4726 207 : buildVectorFaceFE(type);
4727 :
4728 : // If we're building for a face we probably need to build for a
4729 : // neighbor while _need_curl is set;
4730 : // onInterface/reinitNeighbor/etc don't distinguish
4731 207 : buildVectorFaceNeighborFE(type);
4732 :
4733 207 : return _vector_fe_shape_data_face[type]->_curl_phi;
4734 : }
4735 :
4736 : template <>
4737 : const typename OutputTools<VectorValue<Real>>::VariablePhiCurl &
4738 0 : Assembly::feCurlPhiNeighbor<VectorValue<Real>>(FEType type) const
4739 : {
4740 0 : _need_curl.insert(type);
4741 0 : buildVectorNeighborFE(type);
4742 0 : return _vector_fe_shape_data_neighbor[type]->_curl_phi;
4743 : }
4744 :
4745 : template <>
4746 : const typename OutputTools<VectorValue<Real>>::VariablePhiCurl &
4747 0 : Assembly::feCurlPhiFaceNeighbor<VectorValue<Real>>(FEType type) const
4748 : {
4749 0 : _need_curl.insert(type);
4750 0 : buildVectorFaceNeighborFE(type);
4751 :
4752 0 : return _vector_fe_shape_data_face_neighbor[type]->_curl_phi;
4753 : }
4754 :
4755 : template <>
4756 : const typename OutputTools<VectorValue<Real>>::VariablePhiDivergence &
4757 521416 : Assembly::feDivPhi<VectorValue<Real>>(FEType type) const
4758 : {
4759 521416 : _need_div.insert(type);
4760 521416 : buildVectorFE(type);
4761 521416 : return _vector_fe_shape_data[type]->_div_phi;
4762 : }
4763 :
4764 : template <>
4765 : const typename OutputTools<VectorValue<Real>>::VariablePhiDivergence &
4766 546 : Assembly::feDivPhiFace<VectorValue<Real>>(FEType type) const
4767 : {
4768 546 : _need_face_div.insert(type);
4769 546 : buildVectorFaceFE(type);
4770 :
4771 : // If we're building for a face we probably need to build for a
4772 : // neighbor while _need_face_div is set;
4773 : // onInterface/reinitNeighbor/etc don't distinguish
4774 546 : buildVectorFaceNeighborFE(type);
4775 :
4776 546 : return _vector_fe_shape_data_face[type]->_div_phi;
4777 : }
4778 :
4779 : template <>
4780 : const typename OutputTools<VectorValue<Real>>::VariablePhiDivergence &
4781 0 : Assembly::feDivPhiNeighbor<VectorValue<Real>>(FEType type) const
4782 : {
4783 0 : _need_neighbor_div.insert(type);
4784 0 : buildVectorNeighborFE(type);
4785 0 : return _vector_fe_shape_data_neighbor[type]->_div_phi;
4786 : }
4787 :
4788 : template <>
4789 : const typename OutputTools<VectorValue<Real>>::VariablePhiDivergence &
4790 0 : Assembly::feDivPhiFaceNeighbor<VectorValue<Real>>(FEType type) const
4791 : {
4792 0 : _need_face_neighbor_div.insert(type);
4793 0 : buildVectorFaceNeighborFE(type);
4794 0 : return _vector_fe_shape_data_face_neighbor[type]->_div_phi;
4795 : }
4796 :
4797 : const MooseArray<ADReal> &
4798 26 : Assembly::adCurvatures() const
4799 : {
4800 26 : _calculate_curvatures = true;
4801 26 : const Order helper_order = _mesh.hasSecondOrderElements() ? SECOND : FIRST;
4802 26 : const FEType helper_type(helper_order, LAGRANGE);
4803 : // Must prerequest the second derivatives. Sadly because there is only one
4804 : // _need_second_derivative map for both volumetric and face FE objects we must request both here
4805 26 : feSecondPhi<Real>(helper_type);
4806 26 : feSecondPhiFace<Real>(helper_type);
4807 26 : return _ad_curvatures;
4808 : }
4809 :
4810 : void
4811 73112 : Assembly::helpersRequestData()
4812 : {
4813 286316 : for (unsigned int dim = 0; dim <= _mesh_dimension; dim++)
4814 : {
4815 213204 : _holder_fe_helper[dim]->get_phi();
4816 213204 : _holder_fe_helper[dim]->get_dphi();
4817 213204 : _holder_fe_helper[dim]->get_xyz();
4818 213204 : _holder_fe_helper[dim]->get_JxW();
4819 :
4820 213204 : _holder_fe_face_helper[dim]->get_phi();
4821 213204 : _holder_fe_face_helper[dim]->get_dphi();
4822 213204 : _holder_fe_face_helper[dim]->get_xyz();
4823 213204 : _holder_fe_face_helper[dim]->get_JxW();
4824 213204 : _holder_fe_face_helper[dim]->get_normals();
4825 :
4826 213204 : _holder_fe_face_neighbor_helper[dim]->get_xyz();
4827 213204 : _holder_fe_face_neighbor_helper[dim]->get_JxW();
4828 213204 : _holder_fe_face_neighbor_helper[dim]->get_normals();
4829 :
4830 213204 : _holder_fe_neighbor_helper[dim]->get_xyz();
4831 213204 : _holder_fe_neighbor_helper[dim]->get_JxW();
4832 : }
4833 :
4834 213204 : for (unsigned int dim = 0; dim < _mesh_dimension; dim++)
4835 : {
4836 : // We need these computations in order to compute correct lower-d element volumes in
4837 : // curvilinear coordinates
4838 140092 : _holder_fe_lower_helper[dim]->get_xyz();
4839 140092 : _holder_fe_lower_helper[dim]->get_JxW();
4840 : }
4841 73112 : }
4842 :
4843 : void
4844 260 : Assembly::havePRefinement(const std::unordered_set<FEFamily> & disable_families)
4845 : {
4846 260 : if (_have_p_refinement)
4847 : // Already performed tasks for p-refinement
4848 0 : return;
4849 :
4850 260 : const Order helper_order = _mesh.hasSecondOrderElements() ? SECOND : FIRST;
4851 260 : const FEType helper_type(helper_order, LAGRANGE);
4852 : auto process_fe =
4853 2600 : [&disable_families](const unsigned int num_dimensionalities, auto & fe_container)
4854 : {
4855 2600 : if (!disable_families.empty())
4856 8034 : for (const auto dim : make_range(num_dimensionalities))
4857 : {
4858 5954 : auto fe_container_it = fe_container.find(dim);
4859 5954 : if (fe_container_it != fe_container.end())
4860 11897 : for (auto & [fe_type, fe_ptr] : fe_container_it->second)
4861 8008 : if (disable_families.count(fe_type.family))
4862 2847 : fe_ptr->add_p_level_in_reinit(false);
4863 : }
4864 2860 : };
4865 1300 : auto process_fe_and_helpers = [process_fe, &helper_type](auto & unique_helper_container,
4866 : auto & helper_container,
4867 : const unsigned int num_dimensionalities,
4868 : const bool user_added_helper_type,
4869 : auto & fe_container)
4870 : {
4871 1300 : unique_helper_container.resize(num_dimensionalities);
4872 5005 : for (const auto dim : make_range(num_dimensionalities))
4873 : {
4874 3705 : auto & unique_helper = unique_helper_container[dim];
4875 3705 : unique_helper = FEGenericBase<Real>::build(dim, helper_type);
4876 : // don't participate in p-refinement
4877 3705 : unique_helper->add_p_level_in_reinit(false);
4878 3705 : helper_container[dim] = unique_helper.get();
4879 :
4880 : // If the user did not request the helper type then we should erase it from our FE container
4881 : // so that they're not penalized (in the "we should be able to do p-refinement sense") for
4882 : // our perhaps silly helpers
4883 3705 : if (!user_added_helper_type)
4884 : {
4885 2730 : auto & fe_container_dim = libmesh_map_find(fe_container, dim);
4886 2730 : auto fe_it = fe_container_dim.find(helper_type);
4887 : mooseAssert(fe_it != fe_container_dim.end(), "We should have the helper type");
4888 2730 : delete fe_it->second;
4889 2730 : fe_container_dim.erase(fe_it);
4890 : }
4891 : }
4892 :
4893 1300 : process_fe(num_dimensionalities, fe_container);
4894 1300 : };
4895 :
4896 : // Handle scalar field families
4897 260 : process_fe_and_helpers(_unique_fe_helper,
4898 260 : _holder_fe_helper,
4899 260 : _mesh_dimension + 1,
4900 260 : _user_added_fe_of_helper_type,
4901 260 : _fe);
4902 260 : process_fe_and_helpers(_unique_fe_face_helper,
4903 260 : _holder_fe_face_helper,
4904 260 : _mesh_dimension + 1,
4905 260 : _user_added_fe_face_of_helper_type,
4906 260 : _fe_face);
4907 260 : process_fe_and_helpers(_unique_fe_face_neighbor_helper,
4908 260 : _holder_fe_face_neighbor_helper,
4909 260 : _mesh_dimension + 1,
4910 260 : _user_added_fe_face_neighbor_of_helper_type,
4911 260 : _fe_face_neighbor);
4912 260 : process_fe_and_helpers(_unique_fe_neighbor_helper,
4913 260 : _holder_fe_neighbor_helper,
4914 260 : _mesh_dimension + 1,
4915 260 : _user_added_fe_neighbor_of_helper_type,
4916 260 : _fe_neighbor);
4917 260 : process_fe_and_helpers(_unique_fe_lower_helper,
4918 260 : _holder_fe_lower_helper,
4919 : _mesh_dimension,
4920 260 : _user_added_fe_lower_of_helper_type,
4921 260 : _fe_lower);
4922 : // Handle vector field families
4923 260 : process_fe(_mesh_dimension + 1, _vector_fe);
4924 260 : process_fe(_mesh_dimension + 1, _vector_fe_face);
4925 260 : process_fe(_mesh_dimension + 1, _vector_fe_neighbor);
4926 260 : process_fe(_mesh_dimension + 1, _vector_fe_face_neighbor);
4927 260 : process_fe(_mesh_dimension, _vector_fe_lower);
4928 :
4929 260 : helpersRequestData();
4930 :
4931 260 : _have_p_refinement = true;
4932 : }
4933 :
4934 : template void coordTransformFactor<Point, Real>(const SubProblem & s,
4935 : SubdomainID sub_id,
4936 : const Point & point,
4937 : Real & factor,
4938 : SubdomainID neighbor_sub_id);
4939 : template void coordTransformFactor<ADPoint, ADReal>(const SubProblem & s,
4940 : SubdomainID sub_id,
4941 : const ADPoint & point,
4942 : ADReal & factor,
4943 : SubdomainID neighbor_sub_id);
4944 : template void coordTransformFactor<Point, Real>(const MooseMesh & mesh,
4945 : SubdomainID sub_id,
4946 : const Point & point,
4947 : Real & factor,
4948 : SubdomainID neighbor_sub_id);
4949 : template void coordTransformFactor<ADPoint, ADReal>(const MooseMesh & mesh,
4950 : SubdomainID sub_id,
4951 : const ADPoint & point,
4952 : ADReal & factor,
4953 : SubdomainID neighbor_sub_id);
4954 :
4955 : template <>
4956 : const MooseArray<Moose::GenericType<Point, false>> &
4957 34 : Assembly::genericQPoints<false>() const
4958 : {
4959 34 : return qPoints();
4960 : }
4961 :
4962 : template <>
4963 : const MooseArray<Moose::GenericType<Point, true>> &
4964 10 : Assembly::genericQPoints<true>() const
4965 : {
4966 10 : return adQPoints();
4967 : }
|