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