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