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