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 auto num_shapes = FEInterface::n_shape_functions(fe->get_fe_type(), elem);
1083 const auto & phi_map = fe->get_fe_map().get_phi_map();
1084 const auto & dphidxi_map = fe->get_fe_map().get_dphidxi_map();
1085 const auto & dphideta_map = fe->get_fe_map().get_dphideta_map();
1086 const auto & dphidzeta_map = fe->get_fe_map().get_dphidzeta_map();
1087 const auto sys_num = _sys.number();
1088 const bool do_derivatives =
1089 ADReal::do_derivatives && _sys.number() == _subproblem.currentNlSysNum();
1090
1091 switch (dim)
1092 {
1093 case 0:
1094 {
1095 _ad_jac[p] = 1.0;
1096 _ad_JxW[p] = qw[p];
1097 if (_calculate_xyz)
1098 _ad_q_points[p] = *elem_nodes[0];
1099 break;
1100 }
1101
1102 case 1:
1103 {
1104 if (_calculate_xyz)
1105 _ad_q_points[p].zero();
1106
1107 _ad_dxyzdxi_map[p].zero();
1108
1109 for (std::size_t i = 0; i < num_shapes; i++)
1110 {
1111 libmesh_assert(elem_nodes[i]);
1112 const Node & node = *elem_nodes[i];
1114 if (do_derivatives)
1115 for (const auto & [disp_num, direction] : _disp_numbers_and_directions)
1116 if (node.n_dofs(sys_num, disp_num))
1118 elem_point(direction).derivatives(), node.dof_number(sys_num, disp_num, 0), 1.);
1119
1120 _ad_dxyzdxi_map[p].add_scaled(elem_point, dphidxi_map[i][p]);
1121
1122 if (_calculate_xyz)
1123 _ad_q_points[p].add_scaled(elem_point, phi_map[i][p]);
1124 }
1125
1126 _ad_jac[p] = _ad_dxyzdxi_map[p].norm();
1127
1128 if (_ad_jac[p].value() <= -TOLERANCE * TOLERANCE)
1129 {
1130 static bool failing = false;
1131 if (!failing)
1132 {
1133 failing = true;
1134 elem->print_info(libMesh::err);
1135 libmesh_error_msg("ERROR: negative Jacobian " << _ad_jac[p].value() << " at point index "
1136 << p << " in element " << elem->id());
1137 }
1138 else
1139 return;
1140 }
1141
1142 const auto jacm2 = 1. / _ad_jac[p] / _ad_jac[p];
1143 _ad_dxidx_map[p] = jacm2 * _ad_dxyzdxi_map[p](0);
1144 _ad_dxidy_map[p] = jacm2 * _ad_dxyzdxi_map[p](1);
1145 _ad_dxidz_map[p] = jacm2 * _ad_dxyzdxi_map[p](2);
1146
1147 _ad_JxW[p] = _ad_jac[p] * qw[p];
1148
1149 break;
1150 }
1151
1152 case 2:
1153 {
1154 if (_calculate_xyz)
1155 _ad_q_points[p].zero();
1156 _ad_dxyzdxi_map[p].zero();
1157 _ad_dxyzdeta_map[p].zero();
1158
1159 for (std::size_t i = 0; i < num_shapes; i++)
1160 {
1161 libmesh_assert(elem_nodes[i]);
1162 const Node & node = *elem_nodes[i];
1164 if (do_derivatives)
1165 for (const auto & [disp_num, direction] : _disp_numbers_and_directions)
1166 if (node.n_dofs(sys_num, disp_num))
1168 elem_point(direction).derivatives(), node.dof_number(sys_num, disp_num, 0), 1.);
1169
1170 _ad_dxyzdxi_map[p].add_scaled(elem_point, dphidxi_map[i][p]);
1171 _ad_dxyzdeta_map[p].add_scaled(elem_point, dphideta_map[i][p]);
1172
1173 if (_calculate_xyz)
1174 _ad_q_points[p].add_scaled(elem_point, phi_map[i][p]);
1175 }
1176
1177 const auto &dx_dxi = _ad_dxyzdxi_map[p](0), &dx_deta = _ad_dxyzdeta_map[p](0),
1178 &dy_dxi = _ad_dxyzdxi_map[p](1), &dy_deta = _ad_dxyzdeta_map[p](1),
1179 &dz_dxi = _ad_dxyzdxi_map[p](2), &dz_deta = _ad_dxyzdeta_map[p](2);
1180
1181 const auto g11 = (dx_dxi * dx_dxi + dy_dxi * dy_dxi + dz_dxi * dz_dxi);
1182
1183 const auto g12 = (dx_dxi * dx_deta + dy_dxi * dy_deta + dz_dxi * dz_deta);
1184
1185 const auto & g21 = g12;
1186
1187 const auto g22 = (dx_deta * dx_deta + dy_deta * dy_deta + dz_deta * dz_deta);
1188
1189 auto det = (g11 * g22 - g12 * g21);
1190
1191 if (det.value() <= -TOLERANCE * TOLERANCE)
1192 {
1193 static bool failing = false;
1194 if (!failing)
1195 {
1196 failing = true;
1197 elem->print_info(libMesh::err);
1198 libmesh_error_msg("ERROR: negative Jacobian " << det << " at point index " << p
1199 << " in element " << elem->id());
1200 }
1201 else
1202 return;
1203 }
1204 else if (det.value() <= 0.)
1205 det.value() = TOLERANCE * TOLERANCE;
1206
1207 const auto inv_det = 1. / det;
1208 using std::sqrt;
1209 _ad_jac[p] = sqrt(det);
1210
1211 _ad_JxW[p] = _ad_jac[p] * qw[p];
1212
1213 const auto g11inv = g22 * inv_det;
1214 const auto g12inv = -g12 * inv_det;
1215 const auto g21inv = -g21 * inv_det;
1216 const auto g22inv = g11 * inv_det;
1217
1218 _ad_dxidx_map[p] = g11inv * dx_dxi + g12inv * dx_deta;
1219 _ad_dxidy_map[p] = g11inv * dy_dxi + g12inv * dy_deta;
1220 _ad_dxidz_map[p] = g11inv * dz_dxi + g12inv * dz_deta;
1221
1222 _ad_detadx_map[p] = g21inv * dx_dxi + g22inv * dx_deta;
1223 _ad_detady_map[p] = g21inv * dy_dxi + g22inv * dy_deta;
1224 _ad_detadz_map[p] = g21inv * dz_dxi + g22inv * dz_deta;
1225
1226 break;
1227 }
1228
1229 case 3:
1230 {
1231 if (_calculate_xyz)
1232 _ad_q_points[p].zero();
1233 _ad_dxyzdxi_map[p].zero();
1234 _ad_dxyzdeta_map[p].zero();
1235 _ad_dxyzdzeta_map[p].zero();
1236
1237 for (std::size_t i = 0; i < num_shapes; i++)
1238 {
1239 libmesh_assert(elem_nodes[i]);
1240 const Node & node = *elem_nodes[i];
1242 if (do_derivatives)
1243 for (const auto & [disp_num, direction] : _disp_numbers_and_directions)
1244 if (node.n_dofs(sys_num, disp_num))
1246 elem_point(direction).derivatives(), node.dof_number(sys_num, disp_num, 0), 1.);
1247
1248 _ad_dxyzdxi_map[p].add_scaled(elem_point, dphidxi_map[i][p]);
1249 _ad_dxyzdeta_map[p].add_scaled(elem_point, dphideta_map[i][p]);
1250 _ad_dxyzdzeta_map[p].add_scaled(elem_point, dphidzeta_map[i][p]);
1251
1252 if (_calculate_xyz)
1253 _ad_q_points[p].add_scaled(elem_point, phi_map[i][p]);
1254 }
1255
1256 const auto &dx_dxi = _ad_dxyzdxi_map[p](0), &dy_dxi = _ad_dxyzdxi_map[p](1),
1257 &dz_dxi = _ad_dxyzdxi_map[p](2), &dx_deta = _ad_dxyzdeta_map[p](0),
1258 &dy_deta = _ad_dxyzdeta_map[p](1), &dz_deta = _ad_dxyzdeta_map[p](2),
1259 &dx_dzeta = _ad_dxyzdzeta_map[p](0), &dy_dzeta = _ad_dxyzdzeta_map[p](1),
1260 &dz_dzeta = _ad_dxyzdzeta_map[p](2);
1261
1262 _ad_jac[p] = (dx_dxi * (dy_deta * dz_dzeta - dz_deta * dy_dzeta) +
1263 dy_dxi * (dz_deta * dx_dzeta - dx_deta * dz_dzeta) +
1264 dz_dxi * (dx_deta * dy_dzeta - dy_deta * dx_dzeta));
1265
1266 if (_ad_jac[p].value() <= -TOLERANCE * TOLERANCE)
1267 {
1268 static bool failing = false;
1269 if (!failing)
1270 {
1271 failing = true;
1272 elem->print_info(libMesh::err);
1273 libmesh_error_msg("ERROR: negative Jacobian " << _ad_jac[p].value() << " at point index "
1274 << p << " in element " << elem->id());
1275 }
1276 else
1277 return;
1278 }
1279
1280 _ad_JxW[p] = _ad_jac[p] * qw[p];
1281
1282 const auto inv_jac = 1. / _ad_jac[p];
1283
1284 _ad_dxidx_map[p] = (dy_deta * dz_dzeta - dz_deta * dy_dzeta) * inv_jac;
1285 _ad_dxidy_map[p] = (dz_deta * dx_dzeta - dx_deta * dz_dzeta) * inv_jac;
1286 _ad_dxidz_map[p] = (dx_deta * dy_dzeta - dy_deta * dx_dzeta) * inv_jac;
1287
1288 _ad_detadx_map[p] = (dz_dxi * dy_dzeta - dy_dxi * dz_dzeta) * inv_jac;
1289 _ad_detady_map[p] = (dx_dxi * dz_dzeta - dz_dxi * dx_dzeta) * inv_jac;
1290 _ad_detadz_map[p] = (dy_dxi * dx_dzeta - dx_dxi * dy_dzeta) * inv_jac;
1291
1292 _ad_dzetadx_map[p] = (dy_dxi * dz_deta - dz_dxi * dy_deta) * inv_jac;
1293 _ad_dzetady_map[p] = (dz_dxi * dx_deta - dx_dxi * dz_deta) * inv_jac;
1294 _ad_dzetadz_map[p] = (dx_dxi * dy_deta - dy_dxi * dx_deta) * inv_jac;
1295
1296 break;
1297 }
1298
1299 default:
1300 libmesh_error_msg("Invalid dim = " << dim);
1301 }
1302}
1303
1304void
1305Assembly::reinitFEFace(const Elem * elem, unsigned int side)
1306{
1307 unsigned int dim = elem->dim();
1308
1309 for (const auto & it : _fe_face[dim])
1310 {
1311 FEBase & fe_face = *it.second;
1312 const FEType & fe_type = it.first;
1313 FEShapeData & fesd = *_fe_shape_data_face[fe_type];
1314 fe_face.reinit(elem, side);
1315 _current_fe_face[fe_type] = &fe_face;
1316
1317 fesd._phi.shallowCopy(const_cast<std::vector<std::vector<Real>> &>(fe_face.get_phi()));
1318 fesd._grad_phi.shallowCopy(
1319 const_cast<std::vector<std::vector<VectorValue<Real>>> &>(fe_face.get_dphi()));
1320 if (_need_second_derivative.count(fe_type))
1321 fesd._second_phi.shallowCopy(
1322 const_cast<std::vector<std::vector<TensorValue<Real>>> &>(fe_face.get_d2phi()));
1323 }
1324 for (const auto & it : _vector_fe_face[dim])
1325 {
1326 FEVectorBase & fe_face = *it.second;
1327 const FEType & fe_type = it.first;
1328
1329 _current_vector_fe_face[fe_type] = &fe_face;
1330
1332
1333 fe_face.reinit(elem, side);
1334
1335 fesd._phi.shallowCopy(
1336 const_cast<std::vector<std::vector<VectorValue<Real>>> &>(fe_face.get_phi()));
1337 fesd._grad_phi.shallowCopy(
1338 const_cast<std::vector<std::vector<TensorValue<Real>>> &>(fe_face.get_dphi()));
1339 if (_need_second_derivative.count(fe_type))
1340 fesd._second_phi.shallowCopy(
1341 const_cast<std::vector<std::vector<TypeNTensor<3, Real>>> &>(fe_face.get_d2phi()));
1342 if (_need_curl.count(fe_type))
1343 fesd._curl_phi.shallowCopy(
1344 const_cast<std::vector<std::vector<VectorValue<Real>>> &>(fe_face.get_curl_phi()));
1345 if (_need_face_div.count(fe_type))
1346 fesd._div_phi.shallowCopy(
1347 const_cast<std::vector<std::vector<Real>> &>(fe_face.get_div_phi()));
1348 }
1349 if (!_unique_fe_face_helper.empty())
1350 {
1351 mooseAssert(dim < _unique_fe_face_helper.size(), "We should be in bounds here");
1353 }
1354
1355 // During that last loop the helper objects will have been reinitialized as well
1356 // We need to dig out the q_points and JxW from it.
1358 const_cast<std::vector<Point> &>(_holder_fe_face_helper[dim]->get_xyz()));
1360 const_cast<std::vector<Real> &>(_holder_fe_face_helper[dim]->get_JxW()));
1362 const_cast<std::vector<Point> &>(_holder_fe_face_helper[dim]->get_normals()));
1363
1364 _mapped_normals.resize(_current_normals.size(), Eigen::Map<RealDIMValue>(nullptr));
1365 for (unsigned int i = 0; i < _current_normals.size(); i++)
1366 // Note: this does NOT do any allocation. It is "reconstructing" the object in place
1367 new (&_mapped_normals[i]) Eigen::Map<RealDIMValue>(const_cast<Real *>(&_current_normals[i](0)));
1368
1371 const_cast<std::vector<Real> &>(_holder_fe_face_helper[dim]->get_curvatures()));
1372
1374
1375 if (_xfem != nullptr)
1377
1378 auto n = numExtraElemIntegers();
1379 for (auto i : make_range(n))
1380 _extra_elem_ids[i] = _current_elem->get_extra_integer(i);
1381 _extra_elem_ids[n] = _current_elem->subdomain_id();
1382}
1383
1384void
1385Assembly::computeFaceMap(const Elem & elem, const unsigned int side, const std::vector<Real> & qw)
1386{
1387 // Important quantities calculated by this method:
1388 // - _ad_JxW_face
1389 // - _ad_q_points_face
1390 // - _ad_normals
1391 // - _ad_curvatures
1392
1393 const Elem & side_elem = _compute_face_map_side_elem_builder(elem, side);
1394 const auto dim = elem.dim();
1395 const auto n_qp = qw.size();
1396 const auto & dpsidxi_map = _holder_fe_face_helper[dim]->get_fe_map().get_dpsidxi();
1397 const auto & dpsideta_map = _holder_fe_face_helper[dim]->get_fe_map().get_dpsideta();
1398 const auto & psi_map = _holder_fe_face_helper[dim]->get_fe_map().get_psi();
1399 std::vector<std::vector<Real>> const * d2psidxi2_map = nullptr;
1400 std::vector<std::vector<Real>> const * d2psidxideta_map = nullptr;
1401 std::vector<std::vector<Real>> const * d2psideta2_map = nullptr;
1402 const auto sys_num = _sys.number();
1403 const bool do_derivatives = ADReal::do_derivatives && sys_num == _subproblem.currentNlSysNum();
1404
1406 {
1407 d2psidxi2_map = &_holder_fe_face_helper[dim]->get_fe_map().get_d2psidxi2();
1408 d2psidxideta_map = &_holder_fe_face_helper[dim]->get_fe_map().get_d2psidxideta();
1409 d2psideta2_map = &_holder_fe_face_helper[dim]->get_fe_map().get_d2psideta2();
1410 }
1411
1412 switch (dim)
1413 {
1414 case 1:
1415 {
1416 if (!n_qp)
1417 break;
1418
1419 if (side_elem.node_id(0) == elem.node_id(0))
1420 _ad_normals[0] = Point(-1.);
1421 else
1422 _ad_normals[0] = Point(1.);
1423
1424 VectorValue<ADReal> side_point;
1426 {
1427 const Node & node = side_elem.node_ref(0);
1428 side_point = node;
1429
1430 if (do_derivatives)
1431 for (const auto & [disp_num, direction] : _disp_numbers_and_directions)
1433 side_point(direction).derivatives(), node.dof_number(sys_num, disp_num, 0), 1.);
1434 }
1435
1436 for (const auto p : make_range(n_qp))
1437 {
1439 {
1440 _ad_q_points_face[p].zero();
1441 _ad_q_points_face[p].add_scaled(side_point, psi_map[0][p]);
1442 }
1443
1444 _ad_normals[p] = _ad_normals[0];
1445 _ad_JxW_face[p] = 1.0 * qw[p];
1446 }
1447
1448 break;
1449 }
1450
1451 case 2:
1452 {
1453 _ad_dxyzdxi_map.resize(n_qp);
1455 _ad_d2xyzdxi2_map.resize(n_qp);
1456
1457 for (const auto p : make_range(n_qp))
1458 _ad_dxyzdxi_map[p].zero();
1460 for (const auto p : make_range(n_qp))
1461 _ad_q_points_face[p].zero();
1463 for (const auto p : make_range(n_qp))
1464 _ad_d2xyzdxi2_map[p].zero();
1465
1466 const auto n_mapping_shape_functions =
1467 libMesh::FE<2, LAGRANGE>::n_dofs(&side_elem, side_elem.default_order());
1468
1469 for (unsigned int i = 0; i < n_mapping_shape_functions; i++)
1470 {
1471 const Node & node = side_elem.node_ref(i);
1472 VectorValue<ADReal> side_point = node;
1473
1474 if (do_derivatives)
1475 for (const auto & [disp_num, direction] : _disp_numbers_and_directions)
1477 side_point(direction).derivatives(), node.dof_number(sys_num, disp_num, 0), 1.);
1478
1479 for (const auto p : make_range(n_qp))
1480 _ad_dxyzdxi_map[p].add_scaled(side_point, dpsidxi_map[i][p]);
1482 for (const auto p : make_range(n_qp))
1483 _ad_q_points_face[p].add_scaled(side_point, psi_map[i][p]);
1485 for (const auto p : make_range(n_qp))
1486 _ad_d2xyzdxi2_map[p].add_scaled(side_point, (*d2psidxi2_map)[i][p]);
1487 }
1488
1489 for (const auto p : make_range(n_qp))
1490 {
1491 _ad_normals[p] =
1492 (VectorValue<ADReal>(_ad_dxyzdxi_map[p](1), -_ad_dxyzdxi_map[p](0), 0.)).unit();
1493 const auto the_jac = _ad_dxyzdxi_map[p].norm();
1494 _ad_JxW_face[p] = the_jac * qw[p];
1496 {
1497 const auto numerator = _ad_d2xyzdxi2_map[p] * _ad_normals[p];
1498 const auto denominator = _ad_dxyzdxi_map[p].norm_sq();
1499 libmesh_assert_not_equal_to(denominator, 0);
1500 _ad_curvatures[p] = numerator / denominator;
1501 }
1502 }
1503
1504 break;
1505 }
1506
1507 case 3:
1508 {
1509 _ad_dxyzdxi_map.resize(n_qp);
1510 _ad_dxyzdeta_map.resize(n_qp);
1512 {
1513 _ad_d2xyzdxi2_map.resize(n_qp);
1514 _ad_d2xyzdxideta_map.resize(n_qp);
1515 _ad_d2xyzdeta2_map.resize(n_qp);
1516 }
1517
1518 for (const auto p : make_range(n_qp))
1519 {
1520 _ad_dxyzdxi_map[p].zero();
1521 _ad_dxyzdeta_map[p].zero();
1522 }
1524 for (const auto p : make_range(n_qp))
1525 _ad_q_points_face[p].zero();
1527 for (const auto p : make_range(n_qp))
1528 {
1529 _ad_d2xyzdxi2_map[p].zero();
1530 _ad_d2xyzdxideta_map[p].zero();
1531 _ad_d2xyzdeta2_map[p].zero();
1532 }
1533
1534 const unsigned int n_mapping_shape_functions =
1535 libMesh::FE<3, LAGRANGE>::n_dofs(&side_elem, side_elem.default_order());
1536
1537 for (unsigned int i = 0; i < n_mapping_shape_functions; i++)
1538 {
1539 const Node & node = side_elem.node_ref(i);
1540 VectorValue<ADReal> side_point = node;
1541
1542 if (do_derivatives)
1543 for (const auto & [disp_num, direction] : _disp_numbers_and_directions)
1545 side_point(direction).derivatives(), node.dof_number(sys_num, disp_num, 0), 1.);
1546
1547 for (const auto p : make_range(n_qp))
1548 {
1549 _ad_dxyzdxi_map[p].add_scaled(side_point, dpsidxi_map[i][p]);
1550 _ad_dxyzdeta_map[p].add_scaled(side_point, dpsideta_map[i][p]);
1551 }
1553 for (const auto p : make_range(n_qp))
1554 _ad_q_points_face[p].add_scaled(side_point, psi_map[i][p]);
1556 for (const auto p : make_range(n_qp))
1557 {
1558 _ad_d2xyzdxi2_map[p].add_scaled(side_point, (*d2psidxi2_map)[i][p]);
1559 _ad_d2xyzdxideta_map[p].add_scaled(side_point, (*d2psidxideta_map)[i][p]);
1560 _ad_d2xyzdeta2_map[p].add_scaled(side_point, (*d2psideta2_map)[i][p]);
1561 }
1562 }
1563
1564 for (const auto p : make_range(n_qp))
1565 {
1566 _ad_normals[p] = _ad_dxyzdxi_map[p].cross(_ad_dxyzdeta_map[p]).unit();
1567
1568 const auto &dxdxi = _ad_dxyzdxi_map[p](0), &dxdeta = _ad_dxyzdeta_map[p](0),
1569 &dydxi = _ad_dxyzdxi_map[p](1), &dydeta = _ad_dxyzdeta_map[p](1),
1570 &dzdxi = _ad_dxyzdxi_map[p](2), &dzdeta = _ad_dxyzdeta_map[p](2);
1571
1572 const auto g11 = (dxdxi * dxdxi + dydxi * dydxi + dzdxi * dzdxi);
1573
1574 const auto g12 = (dxdxi * dxdeta + dydxi * dydeta + dzdxi * dzdeta);
1575
1576 const auto & g21 = g12;
1577
1578 const auto g22 = (dxdeta * dxdeta + dydeta * dydeta + dzdeta * dzdeta);
1579
1580 using std::sqrt;
1581 const auto the_jac = sqrt(g11 * g22 - g12 * g21);
1582
1583 _ad_JxW_face[p] = the_jac * qw[p];
1584
1586 {
1587 const auto L = -_ad_d2xyzdxi2_map[p] * _ad_normals[p];
1588 const auto M = -_ad_d2xyzdxideta_map[p] * _ad_normals[p];
1589 const auto N = -_ad_d2xyzdeta2_map[p] * _ad_normals[p];
1590 const auto E = _ad_dxyzdxi_map[p].norm_sq();
1591 const auto F = _ad_dxyzdxi_map[p] * _ad_dxyzdeta_map[p];
1592 const auto G = _ad_dxyzdeta_map[p].norm_sq();
1593
1594 const auto numerator = E * N - 2. * F * M + G * L;
1595 const auto denominator = E * G - F * F;
1596 libmesh_assert_not_equal_to(denominator, 0.);
1597 _ad_curvatures[p] = 0.5 * numerator / denominator;
1598 }
1599 }
1600
1601 break;
1602 }
1603
1604 default:
1605 mooseError("Invalid dimension dim = ", dim);
1606 }
1607}
1608
1609void
1610Assembly::reinitFEFaceNeighbor(const Elem * neighbor, const std::vector<Point> & reference_points)
1611{
1612 unsigned int neighbor_dim = neighbor->dim();
1613
1614 // reinit neighbor face
1615 for (const auto & it : _fe_face_neighbor[neighbor_dim])
1616 {
1617 FEBase & fe_face_neighbor = *it.second;
1618 FEType fe_type = it.first;
1619 FEShapeData & fesd = *_fe_shape_data_face_neighbor[fe_type];
1620
1621 fe_face_neighbor.reinit(neighbor, &reference_points);
1622
1623 _current_fe_face_neighbor[fe_type] = &fe_face_neighbor;
1624
1625 fesd._phi.shallowCopy(const_cast<std::vector<std::vector<Real>> &>(fe_face_neighbor.get_phi()));
1626 fesd._grad_phi.shallowCopy(
1627 const_cast<std::vector<std::vector<RealGradient>> &>(fe_face_neighbor.get_dphi()));
1628 if (_need_second_derivative_neighbor.count(fe_type))
1629 fesd._second_phi.shallowCopy(
1630 const_cast<std::vector<std::vector<TensorValue<Real>>> &>(fe_face_neighbor.get_d2phi()));
1631 }
1632 for (const auto & it : _vector_fe_face_neighbor[neighbor_dim])
1633 {
1634 FEVectorBase & fe_face_neighbor = *it.second;
1635 const FEType & fe_type = it.first;
1636
1637 _current_vector_fe_face_neighbor[fe_type] = &fe_face_neighbor;
1638
1640
1641 fe_face_neighbor.reinit(neighbor, &reference_points);
1642
1643 fesd._phi.shallowCopy(
1644 const_cast<std::vector<std::vector<VectorValue<Real>>> &>(fe_face_neighbor.get_phi()));
1645 fesd._grad_phi.shallowCopy(
1646 const_cast<std::vector<std::vector<TensorValue<Real>>> &>(fe_face_neighbor.get_dphi()));
1647 if (_need_second_derivative.count(fe_type))
1648 fesd._second_phi.shallowCopy(const_cast<std::vector<std::vector<TypeNTensor<3, Real>>> &>(
1649 fe_face_neighbor.get_d2phi()));
1650 if (_need_curl.count(fe_type))
1651 fesd._curl_phi.shallowCopy(const_cast<std::vector<std::vector<VectorValue<Real>>> &>(
1652 fe_face_neighbor.get_curl_phi()));
1653 if (_need_face_neighbor_div.count(fe_type))
1654 fesd._div_phi.shallowCopy(
1655 const_cast<std::vector<std::vector<Real>> &>(fe_face_neighbor.get_div_phi()));
1656 }
1658 {
1659 mooseAssert(neighbor_dim < _unique_fe_face_neighbor_helper.size(),
1660 "We should be in bounds here");
1661 _unique_fe_face_neighbor_helper[neighbor_dim]->reinit(neighbor, &reference_points);
1662 }
1663
1665 const_cast<std::vector<Point> &>(_holder_fe_face_neighbor_helper[neighbor_dim]->get_xyz()));
1666}
1667
1668void
1669Assembly::reinitFENeighbor(const Elem * neighbor, const std::vector<Point> & reference_points)
1670{
1671 unsigned int neighbor_dim = neighbor->dim();
1672
1673 // reinit neighbor face
1674 for (const auto & it : _fe_neighbor[neighbor_dim])
1675 {
1676 FEBase & fe_neighbor = *it.second;
1677 FEType fe_type = it.first;
1678 FEShapeData & fesd = *_fe_shape_data_neighbor[fe_type];
1679
1680 fe_neighbor.reinit(neighbor, &reference_points);
1681
1682 _current_fe_neighbor[fe_type] = &fe_neighbor;
1683
1684 fesd._phi.shallowCopy(const_cast<std::vector<std::vector<Real>> &>(fe_neighbor.get_phi()));
1685 fesd._grad_phi.shallowCopy(
1686 const_cast<std::vector<std::vector<RealGradient>> &>(fe_neighbor.get_dphi()));
1687 if (_need_second_derivative_neighbor.count(fe_type))
1688 fesd._second_phi.shallowCopy(
1689 const_cast<std::vector<std::vector<TensorValue<Real>>> &>(fe_neighbor.get_d2phi()));
1690 }
1691 for (const auto & it : _vector_fe_neighbor[neighbor_dim])
1692 {
1693 FEVectorBase & fe_neighbor = *it.second;
1694 const FEType & fe_type = it.first;
1695
1696 _current_vector_fe_neighbor[fe_type] = &fe_neighbor;
1697
1699
1700 fe_neighbor.reinit(neighbor, &reference_points);
1701
1702 fesd._phi.shallowCopy(
1703 const_cast<std::vector<std::vector<VectorValue<Real>>> &>(fe_neighbor.get_phi()));
1704 fesd._grad_phi.shallowCopy(
1705 const_cast<std::vector<std::vector<TensorValue<Real>>> &>(fe_neighbor.get_dphi()));
1706 if (_need_second_derivative.count(fe_type))
1707 fesd._second_phi.shallowCopy(
1708 const_cast<std::vector<std::vector<TypeNTensor<3, Real>>> &>(fe_neighbor.get_d2phi()));
1709 if (_need_curl.count(fe_type))
1710 fesd._curl_phi.shallowCopy(
1711 const_cast<std::vector<std::vector<VectorValue<Real>>> &>(fe_neighbor.get_curl_phi()));
1712 if (_need_neighbor_div.count(fe_type))
1713 fesd._div_phi.shallowCopy(
1714 const_cast<std::vector<std::vector<Real>> &>(fe_neighbor.get_div_phi()));
1715 }
1716 if (!_unique_fe_neighbor_helper.empty())
1717 {
1718 mooseAssert(neighbor_dim < _unique_fe_neighbor_helper.size(), "We should be in bounds here");
1719 _unique_fe_neighbor_helper[neighbor_dim]->reinit(neighbor, &reference_points);
1720 }
1721}
1722
1723void
1724Assembly::reinitNeighbor(const Elem * neighbor, const std::vector<Point> & reference_points)
1725{
1726 unsigned int neighbor_dim = neighbor->dim();
1727 mooseAssert(_current_neighbor_subdomain_id == neighbor->subdomain_id(),
1728 "Neighbor subdomain ID has not been correctly set");
1729
1730 ArbitraryQuadrature * neighbor_rule =
1731 qrules(neighbor_dim, _current_neighbor_subdomain_id).neighbor.get();
1732 neighbor_rule->setPoints(reference_points);
1733 setNeighborQRule(neighbor_rule, neighbor_dim);
1734
1736 mooseAssert(_current_neighbor_subdomain_id == _current_neighbor_elem->subdomain_id(),
1737 "current neighbor subdomain has been set incorrectly");
1738
1739 // Calculate the volume of the neighbor
1741 {
1742 unsigned int dim = neighbor->dim();
1743 FEBase & fe = *_holder_fe_neighbor_helper[dim];
1744 QBase * qrule = qrules(dim).vol.get();
1745
1746 fe.attach_quadrature_rule(qrule);
1747 fe.reinit(neighbor);
1748
1749 const std::vector<Real> & JxW = fe.get_JxW();
1750 MooseArray<Point> q_points;
1751 q_points.shallowCopy(const_cast<std::vector<Point> &>(fe.get_xyz()));
1752
1754
1756 for (unsigned int qp = 0; qp < qrule->n_points(); qp++)
1758 }
1759
1760 auto n = numExtraElemIntegers();
1761 for (auto i : make_range(n))
1762 _neighbor_extra_elem_ids[i] = _current_neighbor_elem->get_extra_integer(i);
1764}
1765
1766template <typename Points, typename Coords>
1767void
1769 const Points & q_points,
1770 Coords & coord,
1771 SubdomainID sub_id)
1772{
1773
1774 mooseAssert(qrule, "The quadrature rule is null in Assembly::setCoordinateTransformation");
1775 auto n_points = qrule->n_points();
1776 mooseAssert(n_points == q_points.size(),
1777 "The number of points in the quadrature rule doesn't match the number of passed-in "
1778 "points in Assembly::setCoordinateTransformation");
1779
1780 // Make sure to honor the name of this method and set the _coord_type member because users may
1781 // make use of the const Moose::CoordinateSystem & coordTransformation() { return _coord_type; }
1782 // API. MaterialBase for example uses it
1784
1785 coord.resize(n_points);
1786 for (unsigned int qp = 0; qp < n_points; qp++)
1787 coordTransformFactor(_subproblem, sub_id, q_points[qp], coord[qp]);
1788}
1789
1790void
1792{
1794 return;
1795
1801
1803 for (unsigned int qp = 0; qp < _current_qrule->n_points(); qp++)
1805
1807}
1808
1809void
1827
1828void
1829Assembly::reinitAtPhysical(const Elem * elem, const std::vector<Point> & physical_points)
1830{
1832 _current_neighbor_elem = nullptr;
1833 mooseAssert(_current_subdomain_id == _current_elem->subdomain_id(),
1834 "current subdomain has been set incorrectly");
1836
1837 FEMap::inverse_map(elem->dim(), elem, physical_points, _temp_reference_points);
1838
1840
1841 // Save off the physical points
1842 _current_physical_points = physical_points;
1843}
1844
1845void
1846Assembly::setVolumeQRule(const Elem * const elem)
1847{
1848 unsigned int elem_dimension = elem->dim();
1849 _current_qrule_volume = qrules(elem_dimension).vol.get();
1850 // Make sure the qrule is the right one
1852 setVolumeQRule(_current_qrule_volume, elem_dimension);
1853}
1854
1855void
1856Assembly::reinit(const Elem * elem)
1857{
1859 _current_neighbor_elem = nullptr;
1860 mooseAssert(_current_subdomain_id == _current_elem->subdomain_id(),
1861 "current subdomain has been set incorrectly");
1864 reinitFE(elem);
1865
1867}
1868
1869void
1870Assembly::reinit(const Elem * elem, const std::vector<Point> & reference_points)
1871{
1873 _current_neighbor_elem = nullptr;
1874 mooseAssert(_current_subdomain_id == _current_elem->subdomain_id(),
1875 "current subdomain has been set incorrectly");
1877
1878 unsigned int elem_dimension = _current_elem->dim();
1879
1880 _current_qrule_arbitrary = qrules(elem_dimension).arbitrary_vol.get();
1881
1882 // Make sure the qrule is the right one
1885
1886 _current_qrule_arbitrary->setPoints(reference_points);
1887
1888 reinitFE(elem);
1889
1891}
1892
1893void
1895{
1896 _current_elem = &fi.elem();
1900 mooseAssert(_current_subdomain_id == _current_elem->subdomain_id(),
1901 "current subdomain has been set incorrectly");
1902
1905
1909
1910 unsigned int dim = _current_elem->dim();
1911 if (_current_qrule_face != qrules(dim).fv_face.get())
1912 {
1913 setFaceQRule(qrules(dim).fv_face.get(), dim);
1914 // The order of the element that is used for initing here doesn't matter since this will just
1915 // be used for constant monomials (which only need a single integration point)
1916 if (dim == 3)
1917 _current_qrule_face->init(QUAD4, /* p_level = */ 0, /* simple_type_only = */ true);
1918 else
1919 _current_qrule_face->init(EDGE2, /* p_level = */ 0, /* simple_type_only = */ true);
1920 }
1921
1923
1924 mooseAssert(_current_qrule_face->n_points() == 1,
1925 "Our finite volume quadrature rule should always yield a single point");
1926
1927 // We've initialized the reference points. Now we need to compute the physical location of the
1928 // quadrature points. We do not do any FE initialization so we cannot simply copy over FE
1929 // results like we do in reinitFEFace. Instead we handle the computation of the physical
1930 // locations manually
1932 const auto & ref_points = _current_qrule_face->get_points();
1933 const auto & ref_point = ref_points[0];
1934 auto physical_point = FEMap::map(_current_side_elem->dim(), _current_side_elem, ref_point);
1935 _current_q_points_face[0] = physical_point;
1936
1938 {
1939 mooseAssert(_current_neighbor_subdomain_id == _current_neighbor_elem->subdomain_id(),
1940 "current neighbor subdomain has been set incorrectly");
1941 // Now handle the neighbor qrule/qpoints
1942 ArbitraryQuadrature * const neighbor_rule =
1944 // Here we are setting a reference point that is correct for the neighbor *side* element. It
1945 // would be wrong if this reference point is used for a volumetric FE reinit with the neighbor
1946 neighbor_rule->setPoints(ref_points);
1947 setNeighborQRule(neighbor_rule, _current_neighbor_elem->dim());
1949 _current_q_points_face_neighbor[0] = std::move(physical_point);
1950 }
1951}
1952
1953QBase *
1954Assembly::qruleFace(const Elem * elem, unsigned int side)
1955{
1956 return qruleFaceHelper<QBase>(elem, side, [](QRules & q) { return q.face.get(); });
1957}
1958
1960Assembly::qruleArbitraryFace(const Elem * elem, unsigned int side)
1961{
1962 return qruleFaceHelper<ArbitraryQuadrature>(
1963 elem, side, [](QRules & q) { return q.arbitrary_face.get(); });
1964}
1965
1966void
1967Assembly::setFaceQRule(const Elem * const elem, const unsigned int side)
1968{
1969 const auto elem_dimension = elem->dim();
1971 auto rule = qruleFace(elem, side);
1972 if (_current_qrule_face != rule)
1973 setFaceQRule(rule, elem_dimension);
1974}
1975
1976void
1977Assembly::reinit(const Elem * const elem, const unsigned int side)
1978{
1980 _current_neighbor_elem = nullptr;
1981 mooseAssert(_current_subdomain_id == _current_elem->subdomain_id(),
1982 "current subdomain has been set incorrectly");
1986
1988
1991
1993}
1994
1995void
1996Assembly::reinit(const Elem * elem, unsigned int side, const std::vector<Point> & reference_points)
1997{
1999 _current_neighbor_elem = nullptr;
2000 mooseAssert(_current_subdomain_id == _current_elem->subdomain_id(),
2001 "current subdomain has been set incorrectly");
2005
2006 unsigned int elem_dimension = _current_elem->dim();
2007
2009
2010 // Make sure the qrule is the right one
2013
2014 _current_qrule_arbitrary->setPoints(reference_points);
2015
2017
2019
2021}
2022
2023void
2024Assembly::reinit(const Node * node)
2025{
2028}
2029
2030void
2032 unsigned int side,
2033 const Elem * neighbor,
2034 unsigned int neighbor_side,
2035 const std::vector<Point> * neighbor_reference_points)
2036{
2037 _current_neighbor_side = neighbor_side;
2038
2039 reinit(elem, side);
2040
2041 unsigned int neighbor_dim = neighbor->dim();
2042
2043 if (neighbor_reference_points)
2044 _current_neighbor_ref_points = *neighbor_reference_points;
2045 else
2046 FEMap::inverse_map(
2048
2050
2053}
2054
2055void
2057 unsigned int elem_side,
2058 Real tolerance,
2059 const std::vector<Point> * const pts,
2060 const std::vector<Real> * const weights)
2061{
2063
2064 unsigned int elem_dim = elem->dim();
2065
2066 // Attach the quadrature rules
2067 if (pts)
2068 {
2069 auto face_rule = qruleArbitraryFace(elem, elem_side);
2070 face_rule->setPoints(*pts);
2071 setFaceQRule(face_rule, elem_dim);
2072 }
2073 else
2074 {
2075 auto rule = qruleFace(elem, elem_side);
2076 if (_current_qrule_face != rule)
2077 setFaceQRule(rule, elem_dim);
2078 }
2079
2080 // reinit face
2081 for (const auto & it : _fe_face[elem_dim])
2082 {
2083 FEBase & fe_face = *it.second;
2084 FEType fe_type = it.first;
2085 FEShapeData & fesd = *_fe_shape_data_face[fe_type];
2086
2087 fe_face.reinit(elem, elem_side, tolerance, pts, weights);
2088
2089 _current_fe_face[fe_type] = &fe_face;
2090
2091 fesd._phi.shallowCopy(const_cast<std::vector<std::vector<Real>> &>(fe_face.get_phi()));
2092 fesd._grad_phi.shallowCopy(
2093 const_cast<std::vector<std::vector<RealGradient>> &>(fe_face.get_dphi()));
2094 if (_need_second_derivative_neighbor.count(fe_type))
2095 fesd._second_phi.shallowCopy(
2096 const_cast<std::vector<std::vector<TensorValue<Real>>> &>(fe_face.get_d2phi()));
2097 }
2098 for (const auto & it : _vector_fe_face[elem_dim])
2099 {
2100 FEVectorBase & fe_face = *it.second;
2101 const FEType & fe_type = it.first;
2102
2103 _current_vector_fe_face[fe_type] = &fe_face;
2104
2106
2107 fe_face.reinit(elem, elem_side, tolerance, pts, weights);
2108
2109 fesd._phi.shallowCopy(
2110 const_cast<std::vector<std::vector<VectorValue<Real>>> &>(fe_face.get_phi()));
2111 fesd._grad_phi.shallowCopy(
2112 const_cast<std::vector<std::vector<TensorValue<Real>>> &>(fe_face.get_dphi()));
2113 if (_need_second_derivative.count(fe_type))
2114 fesd._second_phi.shallowCopy(
2115 const_cast<std::vector<std::vector<TypeNTensor<3, Real>>> &>(fe_face.get_d2phi()));
2116 if (_need_curl.count(fe_type))
2117 fesd._curl_phi.shallowCopy(
2118 const_cast<std::vector<std::vector<VectorValue<Real>>> &>(fe_face.get_curl_phi()));
2119 if (_need_face_div.count(fe_type))
2120 fesd._div_phi.shallowCopy(
2121 const_cast<std::vector<std::vector<Real>> &>(fe_face.get_div_phi()));
2122 }
2123 if (!_unique_fe_face_helper.empty())
2124 {
2125 mooseAssert(elem_dim < _unique_fe_face_helper.size(), "We should be in bounds here");
2126 _unique_fe_face_helper[elem_dim]->reinit(elem, elem_side, tolerance, pts, weights);
2127 }
2128
2129 // During that last loop the helper objects will have been reinitialized
2131 const_cast<std::vector<Point> &>(_holder_fe_face_helper[elem_dim]->get_xyz()));
2133 const_cast<std::vector<Point> &>(_holder_fe_face_helper[elem_dim]->get_normals()));
2134 _current_tangents.shallowCopy(const_cast<std::vector<std::vector<Point>> &>(
2135 _holder_fe_face_helper[elem_dim]->get_tangents()));
2136 // Note that if the user did pass in points and not weights to this method, JxW will be garbage
2137 // and should not be used
2139 const_cast<std::vector<Real> &>(_holder_fe_face_helper[elem_dim]->get_JxW()));
2142 const_cast<std::vector<Real> &>(_holder_fe_face_helper[elem_dim]->get_curvatures()));
2143
2144 computeADFace(*elem, elem_side);
2145}
2146
2147void
2148Assembly::computeADFace(const Elem & elem, const unsigned int side)
2149{
2150 const auto dim = elem.dim();
2151
2153 {
2154 auto n_qp = _current_qrule_face->n_points();
2156 _ad_normals.resize(n_qp);
2157 _ad_JxW_face.resize(n_qp);
2161 _ad_curvatures.resize(n_qp);
2162
2163 if (_displaced)
2164 {
2165 const auto & qw = _current_qrule_face->get_weights();
2166 computeFaceMap(elem, side, qw);
2167 const std::vector<Real> dummy_qw(n_qp, 1.);
2168
2169 for (unsigned int qp = 0; qp != n_qp; qp++)
2171 }
2172 else
2173 {
2174 for (unsigned qp = 0; qp < n_qp; ++qp)
2175 {
2177 _ad_normals[qp] = _current_normals[qp];
2178 }
2180 for (unsigned qp = 0; qp < n_qp; ++qp)
2183 for (unsigned qp = 0; qp < n_qp; ++qp)
2184 _ad_curvatures[qp] = _curvatures[qp];
2185 }
2186
2187 for (const auto & it : _fe_face[dim])
2188 {
2189 FEBase & fe = *it.second;
2190 auto fe_type = it.first;
2191 auto num_shapes = FEInterface::n_shape_functions(fe_type, &elem);
2192 auto & grad_phi = _ad_grad_phi_data_face[fe_type];
2193
2194 grad_phi.resize(num_shapes);
2195 for (decltype(num_shapes) i = 0; i < num_shapes; ++i)
2196 grad_phi[i].resize(n_qp);
2197
2198 const auto & regular_grad_phi = _fe_shape_data_face[fe_type]->_grad_phi;
2199
2200 if (_displaced)
2201 computeGradPhiAD(&elem, n_qp, grad_phi, &fe);
2202 else
2203 for (decltype(num_shapes) i = 0; i < num_shapes; ++i)
2204 for (unsigned qp = 0; qp < n_qp; ++qp)
2205 grad_phi[i][qp] = regular_grad_phi[i][qp];
2206 }
2207 for (const auto & it : _vector_fe_face[dim])
2208 {
2209 FEVectorBase & fe = *it.second;
2210 auto fe_type = it.first;
2211 auto num_shapes = FEInterface::n_shape_functions(fe_type, &elem);
2212 auto & grad_phi = _ad_vector_grad_phi_data_face[fe_type];
2213
2214 grad_phi.resize(num_shapes);
2215 for (decltype(num_shapes) i = 0; i < num_shapes; ++i)
2216 grad_phi[i].resize(n_qp);
2217
2218 const auto & regular_grad_phi = _vector_fe_shape_data_face[fe_type]->_grad_phi;
2219
2220 if (_displaced)
2221 computeGradPhiAD(&elem, n_qp, grad_phi, &fe);
2222 else
2223 for (decltype(num_shapes) i = 0; i < num_shapes; ++i)
2224 for (unsigned qp = 0; qp < n_qp; ++qp)
2225 grad_phi[i][qp] = regular_grad_phi[i][qp];
2226 }
2227 }
2228}
2229
2230void
2232 unsigned int neighbor_side,
2233 Real tolerance,
2234 const std::vector<Point> * const pts,
2235 const std::vector<Real> * const weights)
2236{
2238
2239 unsigned int neighbor_dim = neighbor->dim();
2240
2241 ArbitraryQuadrature * neighbor_rule =
2242 qrules(neighbor_dim, neighbor->subdomain_id()).neighbor.get();
2243 neighbor_rule->setPoints(*pts);
2244
2245 // Attach this quadrature rule to all the _fe_face_neighbor FE objects. This
2246 // has to have garbage quadrature weights but that's ok because we never
2247 // actually use the JxW coming from these FE reinit'd objects, e.g. we use the
2248 // JxW coming from the element face reinit for DGKernels or we use the JxW
2249 // coming from reinit of the mortar segment element in the case of mortar
2250 setNeighborQRule(neighbor_rule, neighbor_dim);
2251
2252 // reinit neighbor face
2253 for (const auto & it : _fe_face_neighbor[neighbor_dim])
2254 {
2255 FEBase & fe_face_neighbor = *it.second;
2256 FEType fe_type = it.first;
2257 FEShapeData & fesd = *_fe_shape_data_face_neighbor[fe_type];
2258
2259 fe_face_neighbor.reinit(neighbor, neighbor_side, tolerance, pts, weights);
2260
2261 _current_fe_face_neighbor[fe_type] = &fe_face_neighbor;
2262
2263 fesd._phi.shallowCopy(const_cast<std::vector<std::vector<Real>> &>(fe_face_neighbor.get_phi()));
2264 fesd._grad_phi.shallowCopy(
2265 const_cast<std::vector<std::vector<RealGradient>> &>(fe_face_neighbor.get_dphi()));
2266 if (_need_second_derivative_neighbor.count(fe_type))
2267 fesd._second_phi.shallowCopy(
2268 const_cast<std::vector<std::vector<TensorValue<Real>>> &>(fe_face_neighbor.get_d2phi()));
2269 }
2270 for (const auto & it : _vector_fe_face_neighbor[neighbor_dim])
2271 {
2272 FEVectorBase & fe_face_neighbor = *it.second;
2273 const FEType & fe_type = it.first;
2274
2275 _current_vector_fe_face_neighbor[fe_type] = &fe_face_neighbor;
2276
2278
2279 fe_face_neighbor.reinit(neighbor, neighbor_side, tolerance, pts, weights);
2280
2281 fesd._phi.shallowCopy(
2282 const_cast<std::vector<std::vector<VectorValue<Real>>> &>(fe_face_neighbor.get_phi()));
2283 fesd._grad_phi.shallowCopy(
2284 const_cast<std::vector<std::vector<TensorValue<Real>>> &>(fe_face_neighbor.get_dphi()));
2285 if (_need_second_derivative.count(fe_type))
2286 fesd._second_phi.shallowCopy(const_cast<std::vector<std::vector<TypeNTensor<3, Real>>> &>(
2287 fe_face_neighbor.get_d2phi()));
2288 if (_need_curl.count(fe_type))
2289 fesd._curl_phi.shallowCopy(const_cast<std::vector<std::vector<VectorValue<Real>>> &>(
2290 fe_face_neighbor.get_curl_phi()));
2291 if (_need_face_neighbor_div.count(fe_type))
2292 fesd._div_phi.shallowCopy(
2293 const_cast<std::vector<std::vector<Real>> &>(fe_face_neighbor.get_div_phi()));
2294 }
2296 {
2297 mooseAssert(neighbor_dim < _unique_fe_face_neighbor_helper.size(),
2298 "We should be in bounds here");
2299 _unique_fe_face_neighbor_helper[neighbor_dim]->reinit(
2300 neighbor, neighbor_side, tolerance, pts, weights);
2301 }
2302 // During that last loop the helper objects will have been reinitialized as well
2303 // We need to dig out the q_points from it
2305 const_cast<std::vector<Point> &>(_holder_fe_face_neighbor_helper[neighbor_dim]->get_xyz()));
2306}
2307
2308void
2309Assembly::reinitDual(const Elem * elem,
2310 const std::vector<Point> & pts,
2311 const std::vector<Real> & JxW)
2312{
2313 const unsigned int elem_dim = elem->dim();
2314 mooseAssert(elem_dim == _mesh_dimension - 1,
2315 "Dual shape functions should only be computed on lower dimensional face elements");
2316
2317 for (const auto & it : _fe_lower[elem_dim])
2318 {
2319 FEBase & fe_lower = *it.second;
2320 // We use customized quadrature rule for integration along the mortar segment elements
2321 fe_lower.set_calculate_default_dual_coeff(false);
2322 fe_lower.reinit_dual_shape_coeffs(elem, pts, JxW);
2323 }
2324}
2325
2326void
2328 const std::vector<Point> * const pts,
2329 const std::vector<Real> * const weights)
2330{
2332
2333 const unsigned int elem_dim = elem->dim();
2334 mooseAssert(elem_dim < _mesh_dimension,
2335 "The lower dimensional element should truly be a lower dimensional element");
2336
2337 if (pts)
2338 {
2339 // Lower rule matches the face rule for the higher dimensional element
2340 ArbitraryQuadrature * lower_rule = qrules(elem_dim + 1).arbitrary_face.get();
2341
2342 // This also sets the quadrature weights to unity
2343 lower_rule->setPoints(*pts);
2344
2345 if (weights)
2346 lower_rule->setWeights(*weights);
2347
2348 setLowerQRule(lower_rule, elem_dim);
2349 }
2350 else if (_current_qrule_lower != qrules(elem_dim + 1).face.get())
2351 setLowerQRule(qrules(elem_dim + 1).face.get(), elem_dim);
2352
2353 for (const auto & it : _fe_lower[elem_dim])
2354 {
2355 FEBase & fe_lower = *it.second;
2356 FEType fe_type = it.first;
2357
2358 fe_lower.reinit(elem);
2359
2360 if (FEShapeData * fesd = _fe_shape_data_lower[fe_type].get())
2361 {
2362 fesd->_phi.shallowCopy(const_cast<std::vector<std::vector<Real>> &>(fe_lower.get_phi()));
2363 fesd->_grad_phi.shallowCopy(
2364 const_cast<std::vector<std::vector<RealGradient>> &>(fe_lower.get_dphi()));
2365 if (_need_second_derivative_neighbor.count(fe_type))
2366 fesd->_second_phi.shallowCopy(
2367 const_cast<std::vector<std::vector<TensorValue<Real>>> &>(fe_lower.get_d2phi()));
2368 }
2369
2370 // Dual shape functions need to be computed after primal basis being initialized
2371 if (FEShapeData * fesd = _fe_shape_data_dual_lower[fe_type].get())
2372 {
2373 fesd->_phi.shallowCopy(const_cast<std::vector<std::vector<Real>> &>(fe_lower.get_dual_phi()));
2374 fesd->_grad_phi.shallowCopy(
2375 const_cast<std::vector<std::vector<RealGradient>> &>(fe_lower.get_dual_dphi()));
2376 if (_need_second_derivative_neighbor.count(fe_type))
2377 fesd->_second_phi.shallowCopy(
2378 const_cast<std::vector<std::vector<TensorValue<Real>>> &>(fe_lower.get_dual_d2phi()));
2379 }
2380 }
2381 if (!_unique_fe_lower_helper.empty())
2382 {
2383 mooseAssert(elem_dim < _unique_fe_lower_helper.size(), "We should be in bounds here");
2384 _unique_fe_lower_helper[elem_dim]->reinit(elem);
2385 }
2386
2388 return;
2389
2390 if (pts && !weights)
2391 {
2392 // We only have dummy weights so the JxWs computed during our FE reinits are meaningless and
2393 // we cannot use them
2394
2396 // We are in a Cartesian coordinate system and we can just use the element volume method
2397 // which has fast computation for certain element types
2399 else
2400 // We manually compute the volume taking the curvilinear coordinate transformations into
2401 // account
2403 }
2404 else
2405 {
2406 // During that last loop the helper objects will have been reinitialized as well
2407 FEBase & helper_fe = *_holder_fe_lower_helper[elem_dim];
2408 const auto & physical_q_points = helper_fe.get_xyz();
2409 const auto & JxW = helper_fe.get_JxW();
2410 MooseArray<Real> coord;
2412 _current_qrule_lower, physical_q_points, coord, elem->subdomain_id());
2414 for (const auto qp : make_range(_current_qrule_lower->n_points()))
2415 _current_lower_d_elem_volume += JxW[qp] * coord[qp];
2416 }
2417}
2418
2419void
2421{
2422 mooseAssert(elem->dim() < _mesh_dimension,
2423 "You should be calling reinitNeighborLowerDElem on a lower dimensional element");
2424
2426
2428 return;
2429
2431 // We are in a Cartesian coordinate system and we can just use the element volume method which
2432 // has fast computation for certain element types
2434 else
2435 // We manually compute the volume taking the curvilinear coordinate transformations into
2436 // account
2438}
2439
2440void
2442{
2443 mooseAssert(elem->dim() == _mesh_dimension - 1,
2444 "You should be calling reinitMortarElem on a lower dimensional element");
2445
2446 _fe_msm->reinit(elem);
2447 _msm_elem = elem;
2448
2449 MooseArray<Point> array_q_points;
2450 array_q_points.shallowCopy(const_cast<std::vector<Point> &>(_fe_msm->get_xyz()));
2451 setCoordinateTransformation(_qrule_msm, array_q_points, _coord_msm, elem->subdomain_id());
2452}
2453
2454void
2456 unsigned int neighbor_side,
2457 const std::vector<Point> & physical_points)
2458{
2459 unsigned int neighbor_dim = neighbor->dim();
2460 FEMap::inverse_map(neighbor_dim, neighbor, physical_points, _current_neighbor_ref_points);
2461
2463 {
2464 mooseAssert(
2465 physical_points.size() == 1,
2466 "If reinitializing with more than one point, then I am dubious of your use case. Perhaps "
2467 "you are performing a DG type method and you are reinitializing using points from the "
2468 "element face. In such a case your neighbor JxW must have its index order 'match' the "
2469 "element JxW index order, e.g. imagining a vertical 1D face with two quadrature points, "
2470 "if "
2471 "index 0 for elem JxW corresponds to the 'top' quadrature point, then index 0 for "
2472 "neighbor "
2473 "JxW must also correspond to the 'top' quadrature point. And libMesh/MOOSE has no way to "
2474 "guarantee that with multiple quadrature points.");
2475
2477
2478 // With a single point our size-1 JxW should just be the element volume
2481 }
2482
2485
2486 // Save off the physical points
2487 _current_physical_points = physical_points;
2488}
2489
2490void
2492 const std::vector<Point> & physical_points)
2493{
2494 unsigned int neighbor_dim = neighbor->dim();
2495 FEMap::inverse_map(neighbor_dim, neighbor, physical_points, _current_neighbor_ref_points);
2496
2499 // Save off the physical points
2500 _current_physical_points = physical_points;
2501}
2502
2503void
2504Assembly::init(const CouplingMatrix * cm)
2505{
2506 _cm = cm;
2507
2508 unsigned int n_vars = _sys.nVariables();
2509
2510 _cm_ss_entry.clear();
2511 _cm_sf_entry.clear();
2512 _cm_fs_entry.clear();
2513 _cm_ff_entry.clear();
2514
2515 auto & vars = _sys.getVariables(_tid);
2516
2518 for (auto & ivar : vars)
2519 {
2520 auto i = ivar->number();
2521 if (i >= _component_block_diagonal.size())
2522 _component_block_diagonal.resize(i + 1, true);
2523
2524 auto ivar_start = _cm_ff_entry.size();
2525 for (unsigned int k = 0; k < ivar->count(); ++k)
2526 {
2527 unsigned int iv = i + k;
2528 for (const auto & j : libMesh::ConstCouplingRow(iv, *_cm))
2529 {
2530 if (_sys.isScalarVariable(j))
2531 {
2532 auto & jvar = _sys.getScalarVariable(_tid, j);
2533 _cm_fs_entry.push_back(std::make_pair(ivar, &jvar));
2534 _block_diagonal_matrix = false;
2535 }
2536 else
2537 {
2538 auto & jvar = _sys.getVariable(_tid, j);
2539 auto pair = std::make_pair(ivar, &jvar);
2540 auto c = ivar_start;
2541 // check if the pair has been pushed or not
2542 bool has_pair = false;
2543 for (; c < _cm_ff_entry.size(); ++c)
2544 if (_cm_ff_entry[c] == pair)
2545 {
2546 has_pair = true;
2547 break;
2548 }
2549 if (!has_pair)
2550 _cm_ff_entry.push_back(pair);
2551 // only set having diagonal matrix to false when ivar and jvar numbers are different
2552 // Note: for array variables, since we save the entire local Jacobian of all components,
2553 // even there are couplings among components of the same array variable, we still
2554 // do not set the flag to false.
2555 if (i != jvar.number())
2556 _block_diagonal_matrix = false;
2557 else if (iv != j)
2558 _component_block_diagonal[i] = false;
2559 }
2560 }
2561 }
2562 }
2563
2564 auto & scalar_vars = _sys.getScalarVariables(_tid);
2565
2566 for (auto & ivar : scalar_vars)
2567 {
2568 auto i = ivar->number();
2569 if (i >= _component_block_diagonal.size())
2570 _component_block_diagonal.resize(i + 1, true);
2571
2572 for (const auto & j : libMesh::ConstCouplingRow(i, *_cm))
2573 if (_sys.isScalarVariable(j))
2574 {
2575 auto & jvar = _sys.getScalarVariable(_tid, j);
2576 _cm_ss_entry.push_back(std::make_pair(ivar, &jvar));
2577 }
2578 else
2579 {
2580 auto & jvar = _sys.getVariable(_tid, j);
2581 _cm_sf_entry.push_back(std::make_pair(ivar, &jvar));
2582 }
2583 }
2584
2585 if (_block_diagonal_matrix && scalar_vars.size() != 0)
2586 _block_diagonal_matrix = false;
2587
2588 auto num_vector_tags = _residual_vector_tags.size();
2589
2590 _sub_Re.resize(num_vector_tags);
2591 _sub_Rn.resize(num_vector_tags);
2592 _sub_Rl.resize(num_vector_tags);
2593 for (MooseIndex(_sub_Re) i = 0; i < _sub_Re.size(); i++)
2594 {
2595 _sub_Re[i].resize(n_vars);
2596 _sub_Rn[i].resize(n_vars);
2597 _sub_Rl[i].resize(n_vars);
2598 }
2599
2600 _cached_residual_values.resize(num_vector_tags);
2601 _cached_residual_rows.resize(num_vector_tags);
2602
2603 auto num_matrix_tags = _subproblem.numMatrixTags();
2604
2605 _cached_jacobian_values.resize(num_matrix_tags);
2606 _cached_jacobian_rows.resize(num_matrix_tags);
2607 _cached_jacobian_cols.resize(num_matrix_tags);
2608
2609 // Element matrices
2610 _sub_Kee.resize(num_matrix_tags);
2611 _sub_Keg.resize(num_matrix_tags);
2612 _sub_Ken.resize(num_matrix_tags);
2613 _sub_Kne.resize(num_matrix_tags);
2614 _sub_Knn.resize(num_matrix_tags);
2615 _sub_Kll.resize(num_matrix_tags);
2616 _sub_Kle.resize(num_matrix_tags);
2617 _sub_Kln.resize(num_matrix_tags);
2618 _sub_Kel.resize(num_matrix_tags);
2619 _sub_Knl.resize(num_matrix_tags);
2620
2621 _jacobian_block_used.resize(num_matrix_tags);
2622 _jacobian_block_neighbor_used.resize(num_matrix_tags);
2623 _jacobian_block_lower_used.resize(num_matrix_tags);
2624 _jacobian_block_nonlocal_used.resize(num_matrix_tags);
2625
2626 for (MooseIndex(num_matrix_tags) tag = 0; tag < num_matrix_tags; tag++)
2627 {
2628 _sub_Keg[tag].resize(n_vars);
2629 _sub_Ken[tag].resize(n_vars);
2630 _sub_Kne[tag].resize(n_vars);
2631 _sub_Knn[tag].resize(n_vars);
2632 _sub_Kee[tag].resize(n_vars);
2633 _sub_Kll[tag].resize(n_vars);
2634 _sub_Kle[tag].resize(n_vars);
2635 _sub_Kln[tag].resize(n_vars);
2636 _sub_Kel[tag].resize(n_vars);
2637 _sub_Knl[tag].resize(n_vars);
2638
2639 _jacobian_block_used[tag].resize(n_vars);
2640 _jacobian_block_neighbor_used[tag].resize(n_vars);
2641 _jacobian_block_lower_used[tag].resize(n_vars);
2642 _jacobian_block_nonlocal_used[tag].resize(n_vars);
2643 for (MooseIndex(n_vars) i = 0; i < n_vars; ++i)
2644 {
2646 {
2647 _sub_Kee[tag][i].resize(n_vars);
2648 _sub_Keg[tag][i].resize(n_vars);
2649 _sub_Ken[tag][i].resize(n_vars);
2650 _sub_Kne[tag][i].resize(n_vars);
2651 _sub_Knn[tag][i].resize(n_vars);
2652 _sub_Kll[tag][i].resize(n_vars);
2653 _sub_Kle[tag][i].resize(n_vars);
2654 _sub_Kln[tag][i].resize(n_vars);
2655 _sub_Kel[tag][i].resize(n_vars);
2656 _sub_Knl[tag][i].resize(n_vars);
2657
2658 _jacobian_block_used[tag][i].resize(n_vars);
2659 _jacobian_block_neighbor_used[tag][i].resize(n_vars);
2660 _jacobian_block_lower_used[tag][i].resize(n_vars);
2661 _jacobian_block_nonlocal_used[tag][i].resize(n_vars);
2662 }
2663 else
2664 {
2665 _sub_Kee[tag][i].resize(1);
2666 _sub_Keg[tag][i].resize(1);
2667 _sub_Ken[tag][i].resize(1);
2668 _sub_Kne[tag][i].resize(1);
2669 _sub_Knn[tag][i].resize(1);
2670 _sub_Kll[tag][i].resize(1);
2671 _sub_Kle[tag][i].resize(1);
2672 _sub_Kln[tag][i].resize(1);
2673 _sub_Kel[tag][i].resize(1);
2674 _sub_Knl[tag][i].resize(1);
2675
2676 _jacobian_block_used[tag][i].resize(1);
2677 _jacobian_block_neighbor_used[tag][i].resize(1);
2678 _jacobian_block_lower_used[tag][i].resize(1);
2679 _jacobian_block_nonlocal_used[tag][i].resize(1);
2680 }
2681 }
2682 }
2683}
2684
2685void
2687{
2688 _cm_nonlocal_entry.clear();
2689
2690 auto & vars = _sys.getVariables(_tid);
2691
2692 for (auto & ivar : vars)
2693 {
2694 auto i = ivar->number();
2695 auto ivar_start = _cm_nonlocal_entry.size();
2696 for (unsigned int k = 0; k < ivar->count(); ++k)
2697 {
2698 unsigned int iv = i + k;
2699 for (const auto & j : libMesh::ConstCouplingRow(iv, _nonlocal_cm))
2700 if (!_sys.isScalarVariable(j))
2701 {
2702 auto & jvar = _sys.getVariable(_tid, j);
2703 auto pair = std::make_pair(ivar, &jvar);
2704 auto c = ivar_start;
2705 // check if the pair has been pushed or not
2706 bool has_pair = false;
2707 for (; c < _cm_nonlocal_entry.size(); ++c)
2708 if (_cm_nonlocal_entry[c] == pair)
2709 {
2710 has_pair = true;
2711 break;
2712 }
2713 if (!has_pair)
2714 _cm_nonlocal_entry.push_back(pair);
2715 }
2716 }
2717 }
2718}
2719
2720void
2722{
2723 for (const auto & it : _cm_ff_entry)
2724 {
2725 MooseVariableFEBase & ivar = *(it.first);
2726 MooseVariableFEBase & jvar = *(it.second);
2727
2728 unsigned int vi = ivar.number();
2729 unsigned int vj = jvar.number();
2730
2731 const bool array_block_diagonal_purely_diagonal = vi == vj && _component_block_diagonal[vi];
2732 auto num_cols = jvar.dofIndices().size();
2733 if (array_block_diagonal_purely_diagonal)
2734 num_cols /= jvar.count();
2735
2736 for (MooseIndex(_jacobian_block_used) tag = 0; tag < _jacobian_block_used.size(); tag++)
2737 {
2738 jacobianBlock(vi, vj, LocalDataKey{}, tag).resize(ivar.dofIndices().size(), num_cols);
2739 jacobianBlockUsed(tag, vi, vj, false);
2740 }
2741 }
2742}
2743
2744void
2746{
2747 const std::vector<MooseVariableFEBase *> & vars = _sys.getVariables(_tid);
2748 for (const auto & var : vars)
2749 for (auto & tag_Re : _sub_Re)
2750 tag_Re[var->number()].resize(var->dofIndices().size());
2751}
2752
2753void
2759
2760void
2762{
2763 for (const auto & it : _cm_nonlocal_entry)
2764 {
2765 MooseVariableFEBase & ivar = *(it.first);
2766 MooseVariableFEBase & jvar = *(it.second);
2767
2768 unsigned int vi = ivar.number();
2769 unsigned int vj = jvar.number();
2770
2771 const bool array_block_diagonal_purely_diagonal = vi == vj && _component_block_diagonal[vi];
2772 auto num_cols = jvar.allDofIndices().size();
2773 if (array_block_diagonal_purely_diagonal)
2774 num_cols /= jvar.count();
2775
2776 for (MooseIndex(_jacobian_block_nonlocal_used) tag = 0;
2777 tag < _jacobian_block_nonlocal_used.size();
2778 tag++)
2779 {
2780 jacobianBlockNonlocal(vi, vj, LocalDataKey{}, tag).resize(ivar.dofIndices().size(), num_cols);
2781 jacobianBlockNonlocalUsed(tag, vi, vj, false);
2782 }
2783 }
2784}
2785
2786void
2788{
2789 for (const auto & it : _cm_ff_entry)
2790 {
2791 MooseVariableFEBase & ivar = *(it.first);
2792 MooseVariableFEBase & jvar = *(it.second);
2793
2794 unsigned int vi = ivar.number();
2795 unsigned int vj = jvar.number();
2796
2797 const bool array_block_diagonal_purely_diagonal = vi == vj && _component_block_diagonal[vi];
2798 auto num_cols = jvar.dofIndices().size();
2799 if (array_block_diagonal_purely_diagonal)
2800 num_cols /= jvar.count();
2801
2802 if (vi == var->number() || vj == var->number())
2803 {
2804 for (MooseIndex(_jacobian_block_used) tag = 0; tag < _jacobian_block_used.size(); tag++)
2805 {
2806 jacobianBlock(vi, vj, LocalDataKey{}, tag).resize(ivar.dofIndices().size(), num_cols);
2807 jacobianBlockUsed(tag, vi, vj, false);
2808 }
2809 }
2810 }
2811
2812 for (auto & tag_Re : _sub_Re)
2813 tag_Re[var->number()].resize(var->dofIndices().size());
2814}
2815
2816void
2818{
2819 for (const auto & it : _cm_nonlocal_entry)
2820 {
2821 MooseVariableFEBase & ivar = *(it.first);
2822 MooseVariableFEBase & jvar = *(it.second);
2823
2824 unsigned int vi = ivar.number();
2825 unsigned int vj = jvar.number();
2826
2827 const bool array_block_diagonal_purely_diagonal = vi == vj && _component_block_diagonal[vi];
2828 auto num_cols = jvar.dofIndices().size();
2829 if (array_block_diagonal_purely_diagonal)
2830 num_cols /= jvar.count();
2831
2832 if (vi == var->number() || vj == var->number())
2833 {
2834 for (MooseIndex(_jacobian_block_nonlocal_used) tag = 0;
2835 tag < _jacobian_block_nonlocal_used.size();
2836 tag++)
2837 {
2838 jacobianBlockNonlocal(vi, vj, LocalDataKey{}, tag)
2839 .resize(ivar.dofIndices().size(), num_cols);
2840 jacobianBlockNonlocalUsed(tag, vi, vj);
2841 }
2842 }
2843 }
2844}
2845
2846void
2848{
2849 for (const auto & it : _cm_ff_entry)
2850 {
2851 MooseVariableFEBase & ivar = *(it.first);
2852 MooseVariableFEBase & jvar = *(it.second);
2853
2854 unsigned int vi = ivar.number();
2855 unsigned int vj = jvar.number();
2856
2857 const bool array_block_diagonal_purely_diagonal = vi == vj && _component_block_diagonal[vi];
2858 const auto dofs_divisor = array_block_diagonal_purely_diagonal ? jvar.count() : 1;
2859
2860 for (MooseIndex(_jacobian_block_neighbor_used) tag = 0;
2861 tag < _jacobian_block_neighbor_used.size();
2862 tag++)
2863 {
2865 .resize(ivar.dofIndices().size(), jvar.dofIndicesNeighbor().size() / dofs_divisor);
2866
2868 .resize(ivar.dofIndicesNeighbor().size(), jvar.dofIndices().size() / dofs_divisor);
2869
2871 .resize(ivar.dofIndicesNeighbor().size(),
2872 jvar.dofIndicesNeighbor().size() / dofs_divisor);
2873
2874 jacobianBlockNeighborUsed(tag, vi, vj, false);
2875 }
2876 }
2877
2878 const std::vector<MooseVariableFEBase *> & vars = _sys.getVariables(_tid);
2879 for (const auto & var : vars)
2880 for (auto & tag_Rn : _sub_Rn)
2881 tag_Rn[var->number()].resize(var->dofIndicesNeighbor().size());
2882}
2883
2884void
2886{
2887 for (const auto & it : _cm_ff_entry)
2888 {
2889 MooseVariableFEBase & ivar = *(it.first);
2890 MooseVariableFEBase & jvar = *(it.second);
2891
2892 unsigned int vi = ivar.number();
2893 unsigned int vj = jvar.number();
2894
2895 const bool array_block_diagonal_purely_diagonal = vi == vj && _component_block_diagonal[vi];
2896 const auto dofs_divisor = array_block_diagonal_purely_diagonal ? jvar.count() : 1;
2897
2898 for (MooseIndex(_jacobian_block_lower_used) tag = 0; tag < _jacobian_block_lower_used.size();
2899 tag++)
2900 {
2901 // To cover all possible cases we should have 9 combinations below for every 2-permutation
2902 // of Lower,Secondary,Primary. However, 4 cases will in general be covered by calls to
2903 // prepare() and prepareNeighbor(). These calls will cover SecondarySecondary
2904 // (ElementElement), SecondaryPrimary (ElementNeighbor), PrimarySecondary (NeighborElement),
2905 // and PrimaryPrimary (NeighborNeighbor). With these covered we only need to prepare the 5
2906 // remaining below
2907
2908 // derivatives w.r.t. lower dimensional residuals
2910 .resize(ivar.dofIndicesLower().size(), jvar.dofIndicesLower().size() / dofs_divisor);
2911
2913 .resize(ivar.dofIndicesLower().size(), jvar.dofIndices().size() / dofs_divisor);
2914
2916 .resize(ivar.dofIndicesLower().size(), jvar.dofIndicesNeighbor().size() / dofs_divisor);
2917
2918 // derivatives w.r.t. interior secondary residuals
2920 .resize(ivar.dofIndices().size(), jvar.dofIndicesLower().size() / dofs_divisor);
2921
2922 // derivatives w.r.t. interior primary residuals
2924 .resize(ivar.dofIndicesNeighbor().size(), jvar.dofIndicesLower().size() / dofs_divisor);
2925
2926 jacobianBlockLowerUsed(tag, vi, vj, false);
2927 }
2928 }
2929
2930 const std::vector<MooseVariableFEBase *> & vars = _sys.getVariables(_tid);
2931 for (const auto & var : vars)
2932 for (auto & tag_Rl : _sub_Rl)
2933 tag_Rl[var->number()].resize(var->dofIndicesLower().size());
2934}
2935
2936void
2937Assembly::prepareBlock(unsigned int ivar,
2938 unsigned int jvar,
2939 const std::vector<dof_id_type> & dof_indices)
2940{
2941 const auto & iv = _sys.getVariable(_tid, ivar);
2942 const auto & jv = _sys.getVariable(_tid, jvar);
2943 const unsigned int ivn = iv.number();
2944 const unsigned int jvn = jv.number();
2945 const unsigned int icount = iv.count();
2946 unsigned int jcount = jv.count();
2947 if (ivn == jvn && _component_block_diagonal[ivn])
2948 jcount = 1;
2949
2950 for (MooseIndex(_jacobian_block_used) tag = 0; tag < _jacobian_block_used.size(); tag++)
2951 {
2952 jacobianBlock(ivn, jvn, LocalDataKey{}, tag)
2953 .resize(dof_indices.size() * icount, dof_indices.size() * jcount);
2954 jacobianBlockUsed(tag, ivn, jvn, false);
2955 }
2956
2957 for (auto & tag_Re : _sub_Re)
2958 tag_Re[ivn].resize(dof_indices.size() * icount);
2959}
2960
2961void
2963 unsigned int jvar,
2964 const std::vector<dof_id_type> & idof_indices,
2965 const std::vector<dof_id_type> & jdof_indices)
2966{
2967 const auto & iv = _sys.getVariable(_tid, ivar);
2968 const auto & jv = _sys.getVariable(_tid, jvar);
2969 const unsigned int ivn = iv.number();
2970 const unsigned int jvn = jv.number();
2971 const unsigned int icount = iv.count();
2972 unsigned int jcount = jv.count();
2973 if (ivn == jvn && _component_block_diagonal[ivn])
2974 jcount = 1;
2975
2976 for (MooseIndex(_jacobian_block_nonlocal_used) tag = 0;
2977 tag < _jacobian_block_nonlocal_used.size();
2978 tag++)
2979 {
2980 jacobianBlockNonlocal(ivn, jvn, LocalDataKey{}, tag)
2981 .resize(idof_indices.size() * icount, jdof_indices.size() * jcount);
2982
2983 jacobianBlockNonlocalUsed(tag, ivn, jvn, false);
2984 }
2985}
2986
2987void
2989{
2990 const std::vector<MooseVariableScalar *> & vars = _sys.getScalarVariables(_tid);
2991 for (const auto & ivar : vars)
2992 {
2993 auto idofs = ivar->dofIndices().size();
2994
2995 for (auto & tag_Re : _sub_Re)
2996 tag_Re[ivar->number()].resize(idofs);
2997
2998 for (const auto & jvar : vars)
2999 {
3000 auto jdofs = jvar->dofIndices().size();
3001
3002 for (MooseIndex(_jacobian_block_used) tag = 0; tag < _jacobian_block_used.size(); tag++)
3003 {
3004 jacobianBlock(ivar->number(), jvar->number(), LocalDataKey{}, tag).resize(idofs, jdofs);
3005 jacobianBlockUsed(tag, ivar->number(), jvar->number(), false);
3006 }
3007 }
3008 }
3009}
3010
3011void
3013{
3014 const std::vector<MooseVariableFEBase *> & vars = _sys.getVariables(_tid);
3015 const std::vector<MooseVariableScalar *> & scalar_vars = _sys.getScalarVariables(_tid);
3016
3017 for (const auto & ivar : scalar_vars)
3018 {
3019 auto idofs = ivar->dofIndices().size();
3020
3021 for (const auto & jvar : vars)
3022 {
3023 auto jdofs = jvar->dofIndices().size() * jvar->count();
3024 for (MooseIndex(_jacobian_block_used) tag = 0; tag < _jacobian_block_used.size(); tag++)
3025 {
3026 jacobianBlock(ivar->number(), jvar->number(), LocalDataKey{}, tag).resize(idofs, jdofs);
3027 jacobianBlockUsed(tag, ivar->number(), jvar->number(), false);
3028
3029 jacobianBlock(jvar->number(), ivar->number(), LocalDataKey{}, tag).resize(jdofs, idofs);
3030 jacobianBlockUsed(tag, jvar->number(), ivar->number(), false);
3031 }
3032 }
3033 }
3034}
3035
3036template <typename T>
3037void
3039{
3040 phi(v).shallowCopy(v.phi());
3041 gradPhi(v).shallowCopy(v.gradPhi());
3042 if (v.computingSecond())
3043 secondPhi(v).shallowCopy(v.secondPhi());
3044}
3045
3046void
3047Assembly::copyShapes(unsigned int var)
3048{
3049 auto & v = _sys.getVariable(_tid, var);
3050 if (v.fieldType() == Moose::VarFieldType::VAR_FIELD_STANDARD)
3051 {
3052 auto & v = _sys.getActualFieldVariable<Real>(_tid, var);
3053 copyShapes(v);
3054 }
3055 else if (v.fieldType() == Moose::VarFieldType::VAR_FIELD_ARRAY)
3056 {
3057 auto & v = _sys.getActualFieldVariable<RealEigenVector>(_tid, var);
3058 copyShapes(v);
3059 }
3060 else if (v.fieldType() == Moose::VarFieldType::VAR_FIELD_VECTOR)
3061 {
3062 auto & v = _sys.getActualFieldVariable<RealVectorValue>(_tid, var);
3063 copyShapes(v);
3064 if (v.computingCurl())
3065 curlPhi(v).shallowCopy(v.curlPhi());
3066 if (v.computingDiv())
3067 divPhi(v).shallowCopy(v.divPhi());
3068 }
3069 else
3070 mooseError("Unsupported variable field type!");
3071}
3072
3073template <typename T>
3074void
3076{
3077 phiFace(v).shallowCopy(v.phiFace());
3078 gradPhiFace(v).shallowCopy(v.gradPhiFace());
3079 if (v.computingSecond())
3080 secondPhiFace(v).shallowCopy(v.secondPhiFace());
3081}
3082
3083void
3085{
3086 auto & v = _sys.getVariable(_tid, var);
3087 if (v.fieldType() == Moose::VarFieldType::VAR_FIELD_STANDARD)
3088 {
3089 auto & v = _sys.getActualFieldVariable<Real>(_tid, var);
3090 copyFaceShapes(v);
3091 }
3092 else if (v.fieldType() == Moose::VarFieldType::VAR_FIELD_ARRAY)
3093 {
3094 auto & v = _sys.getActualFieldVariable<RealEigenVector>(_tid, var);
3095 copyFaceShapes(v);
3096 }
3097 else if (v.fieldType() == Moose::VarFieldType::VAR_FIELD_VECTOR)
3098 {
3099 auto & v = _sys.getActualFieldVariable<RealVectorValue>(_tid, var);
3100 copyFaceShapes(v);
3101 if (v.computingCurl())
3102 _vector_curl_phi_face.shallowCopy(v.curlPhi());
3103 if (v.computingDiv())
3104 _vector_div_phi_face.shallowCopy(v.divPhi());
3105 }
3106 else
3107 mooseError("Unsupported variable field type!");
3108}
3109
3110template <typename T>
3111void
3113{
3114 if (v.usesPhiNeighbor())
3115 {
3116 phiFaceNeighbor(v).shallowCopy(v.phiFaceNeighbor());
3117 phiNeighbor(v).shallowCopy(v.phiNeighbor());
3118 }
3119 if (v.usesGradPhiNeighbor())
3120 {
3121 gradPhiFaceNeighbor(v).shallowCopy(v.gradPhiFaceNeighbor());
3122 gradPhiNeighbor(v).shallowCopy(v.gradPhiNeighbor());
3123 }
3124 if (v.usesSecondPhiNeighbor())
3125 {
3126 secondPhiFaceNeighbor(v).shallowCopy(v.secondPhiFaceNeighbor());
3127 secondPhiNeighbor(v).shallowCopy(v.secondPhiNeighbor());
3128 }
3129}
3130
3131void
3133{
3134 auto & v = _sys.getVariable(_tid, var);
3135 if (v.fieldType() == Moose::VarFieldType::VAR_FIELD_STANDARD)
3136 {
3137 auto & v = _sys.getActualFieldVariable<Real>(_tid, var);
3139 }
3140 else if (v.fieldType() == Moose::VarFieldType::VAR_FIELD_ARRAY)
3141 {
3142 auto & v = _sys.getActualFieldVariable<RealEigenVector>(_tid, var);
3144 }
3145 else if (v.fieldType() == Moose::VarFieldType::VAR_FIELD_VECTOR)
3146 {
3147 auto & v = _sys.getActualFieldVariable<RealVectorValue>(_tid, var);
3149 }
3150 else
3151 mooseError("Unsupported variable field type!");
3152}
3153
3154DenseMatrix<Number> &
3156 Moose::DGJacobianType type, unsigned int ivar, unsigned int jvar, LocalDataKey, TagID tag)
3157{
3158 if (type == Moose::ElementElement)
3159 jacobianBlockUsed(tag, ivar, jvar, true);
3160 else
3161 jacobianBlockNeighborUsed(tag, ivar, jvar, true);
3162
3164 {
3165 switch (type)
3166 {
3167 default:
3169 return _sub_Kee[tag][ivar][0];
3171 return _sub_Ken[tag][ivar][0];
3173 return _sub_Kne[tag][ivar][0];
3175 return _sub_Knn[tag][ivar][0];
3176 }
3177 }
3178 else
3179 {
3180 switch (type)
3181 {
3182 default:
3184 return _sub_Kee[tag][ivar][jvar];
3186 return _sub_Ken[tag][ivar][jvar];
3188 return _sub_Kne[tag][ivar][jvar];
3190 return _sub_Knn[tag][ivar][jvar];
3191 }
3192 }
3193}
3194
3195DenseMatrix<Number> &
3197 unsigned int ivar,
3198 unsigned int jvar,
3200 TagID tag)
3201{
3202 jacobianBlockLowerUsed(tag, ivar, jvar, true);
3204 {
3205 switch (type)
3206 {
3207 default:
3208 case Moose::LowerLower:
3209 return _sub_Kll[tag][ivar][0];
3211 return _sub_Kle[tag][ivar][0];
3213 return _sub_Kln[tag][ivar][0];
3215 return _sub_Kel[tag][ivar][0];
3217 return _sub_Kee[tag][ivar][0];
3219 return _sub_Ken[tag][ivar][0];
3221 return _sub_Knl[tag][ivar][0];
3223 return _sub_Kne[tag][ivar][0];
3225 return _sub_Knn[tag][ivar][0];
3226 }
3227 }
3228 else
3229 {
3230 switch (type)
3231 {
3232 default:
3233 case Moose::LowerLower:
3234 return _sub_Kll[tag][ivar][jvar];
3236 return _sub_Kle[tag][ivar][jvar];
3238 return _sub_Kln[tag][ivar][jvar];
3240 return _sub_Kel[tag][ivar][jvar];
3242 return _sub_Kee[tag][ivar][jvar];
3244 return _sub_Ken[tag][ivar][jvar];
3246 return _sub_Knl[tag][ivar][jvar];
3248 return _sub_Kne[tag][ivar][jvar];
3250 return _sub_Knn[tag][ivar][jvar];
3251 }
3252 }
3253}
3254
3255void
3256Assembly::processLocalResidual(DenseVector<Number> & res_block,
3257 std::vector<dof_id_type> & dof_indices,
3258 const std::vector<Real> & scaling_factor)
3259{
3260 mooseAssert(res_block.size() == dof_indices.size(),
3261 "The size of residual and degree of freedom container must be the same");
3262
3263 // For an array variable, ndof is the number of dofs of the zero-th component and
3264 // ntdof is the number of dofs of all components.
3265 // For standard or vector variables, ndof will be the same as ntdof.
3266 const auto ntdof = res_block.size();
3267 const auto count = scaling_factor.size();
3268 const auto ndof = ntdof / count;
3269 if (count > 1)
3270 {
3271 unsigned int p = 0;
3272 for (MooseIndex(count) j = 0; j < count; ++j)
3273 for (MooseIndex(ndof) i = 0; i < ndof; ++i)
3274 res_block(p++) *= scaling_factor[j];
3275 }
3276 else
3277 {
3278 if (scaling_factor[0] != 1.0)
3279 res_block *= scaling_factor[0];
3280 }
3281
3282 _dof_map.constrain_element_vector(res_block, dof_indices, false);
3283}
3284
3285void
3286Assembly::addResidualBlock(NumericVector<Number> & residual,
3287 DenseVector<Number> & res_block,
3288 const std::vector<dof_id_type> & dof_indices,
3289 const std::vector<Real> & scaling_factor)
3290{
3291 if (dof_indices.size() > 0 && res_block.size())
3292 {
3293 _temp_dof_indices = dof_indices;
3294 _tmp_Re = res_block;
3296 residual.add_vector(_tmp_Re, _temp_dof_indices);
3297 }
3298}
3299
3300void
3301Assembly::cacheResidualBlock(std::vector<Real> & cached_residual_values,
3302 std::vector<dof_id_type> & cached_residual_rows,
3303 DenseVector<Number> & res_block,
3304 const std::vector<dof_id_type> & dof_indices,
3305 const std::vector<Real> & scaling_factor)
3306{
3307 if (dof_indices.size() > 0 && res_block.size())
3308 {
3309 _temp_dof_indices = dof_indices;
3310 _tmp_Re = res_block;
3312
3313 for (MooseIndex(_tmp_Re) i = 0; i < _tmp_Re.size(); i++)
3314 {
3315 cached_residual_values.push_back(_tmp_Re(i));
3316 cached_residual_rows.push_back(_temp_dof_indices[i]);
3317 }
3318 }
3319
3320 res_block.zero();
3321}
3322
3323void
3324Assembly::setResidualBlock(NumericVector<Number> & residual,
3325 DenseVector<Number> & res_block,
3326 const std::vector<dof_id_type> & dof_indices,
3327 const std::vector<Real> & scaling_factor)
3328{
3329 if (dof_indices.size() > 0)
3330 {
3331 std::vector<dof_id_type> di(dof_indices);
3332 _tmp_Re = res_block;
3333 processLocalResidual(_tmp_Re, di, scaling_factor);
3334 residual.insert(_tmp_Re, di);
3335 }
3336}
3337
3338void
3340{
3341 mooseAssert(vector_tag._type == Moose::VECTOR_TAG_RESIDUAL,
3342 "Non-residual tag in Assembly::addResidual");
3343
3344 auto & tag_Re = _sub_Re[vector_tag._type_id];
3345 NumericVector<Number> & residual = _sys.getVector(vector_tag._id);
3346 const std::vector<MooseVariableFEBase *> & vars = _sys.getVariables(_tid);
3347 for (const auto & var : vars)
3348 addResidualBlock(residual, tag_Re[var->number()], var->dofIndices(), var->arrayScalingFactor());
3349}
3350
3351void
3352Assembly::addResidual(GlobalDataKey, const std::vector<VectorTag> & vector_tags)
3353{
3354 for (const auto & vector_tag : vector_tags)
3355 if (_sys.hasVector(vector_tag._id))
3356 addResidual(vector_tag);
3357}
3358
3359void
3361{
3362 mooseAssert(vector_tag._type == Moose::VECTOR_TAG_RESIDUAL,
3363 "Non-residual tag in Assembly::addResidualNeighbor");
3364
3365 auto & tag_Rn = _sub_Rn[vector_tag._type_id];
3366 NumericVector<Number> & residual = _sys.getVector(vector_tag._id);
3367 const std::vector<MooseVariableFEBase *> & vars = _sys.getVariables(_tid);
3368 for (const auto & var : vars)
3370 residual, tag_Rn[var->number()], var->dofIndicesNeighbor(), var->arrayScalingFactor());
3371}
3372
3373void
3374Assembly::addResidualNeighbor(GlobalDataKey, const std::vector<VectorTag> & vector_tags)
3375{
3376 for (const auto & vector_tag : vector_tags)
3377 if (_sys.hasVector(vector_tag._id))
3378 addResidualNeighbor(vector_tag);
3379}
3380
3381void
3383{
3384 mooseAssert(vector_tag._type == Moose::VECTOR_TAG_RESIDUAL,
3385 "Non-residual tag in Assembly::addResidualLower");
3386
3387 auto & tag_Rl = _sub_Rl[vector_tag._type_id];
3388 NumericVector<Number> & residual = _sys.getVector(vector_tag._id);
3389 const std::vector<MooseVariableFEBase *> & vars = _sys.getVariables(_tid);
3390 for (const auto & var : vars)
3392 residual, tag_Rl[var->number()], var->dofIndicesLower(), var->arrayScalingFactor());
3393}
3394
3395void
3396Assembly::addResidualLower(GlobalDataKey, const std::vector<VectorTag> & vector_tags)
3397{
3398 for (const auto & vector_tag : vector_tags)
3399 if (_sys.hasVector(vector_tag._id))
3400 addResidualLower(vector_tag);
3401}
3402
3403// private method, so no key required
3404void
3406{
3407 mooseAssert(vector_tag._type == Moose::VECTOR_TAG_RESIDUAL,
3408 "Non-residual tag in Assembly::addResidualScalar");
3409
3410 // add the scalar variables residuals
3411 auto & tag_Re = _sub_Re[vector_tag._type_id];
3412 NumericVector<Number> & residual = _sys.getVector(vector_tag._id);
3413 const std::vector<MooseVariableScalar *> & vars = _sys.getScalarVariables(_tid);
3414 for (const auto & var : vars)
3415 addResidualBlock(residual, tag_Re[var->number()], var->dofIndices(), var->arrayScalingFactor());
3416}
3417
3418void
3419Assembly::addResidualScalar(GlobalDataKey, const std::vector<VectorTag> & vector_tags)
3420{
3421 for (const auto & vector_tag : vector_tags)
3422 if (_sys.hasVector(vector_tag._id))
3423 addResidualScalar(vector_tag);
3424}
3425
3426void
3427Assembly::cacheResidual(GlobalDataKey, const std::vector<VectorTag> & tags)
3428{
3429 const std::vector<MooseVariableFEBase *> & vars = _sys.getVariables(_tid);
3430 for (const auto & var : vars)
3431 for (const auto & vector_tag : tags)
3432 if (_sys.hasVector(vector_tag._id))
3433 cacheResidualBlock(_cached_residual_values[vector_tag._type_id],
3434 _cached_residual_rows[vector_tag._type_id],
3435 _sub_Re[vector_tag._type_id][var->number()],
3436 var->dofIndices(),
3437 var->arrayScalingFactor());
3438}
3439
3440// private method, so no key required
3441void
3442Assembly::cacheResidual(dof_id_type dof, Real value, TagID tag_id)
3443{
3444 const VectorTag & tag = _subproblem.getVectorTag(tag_id);
3445
3446 _cached_residual_values[tag._type_id].push_back(value);
3447 _cached_residual_rows[tag._type_id].push_back(dof);
3448}
3449
3450// private method, so no key required
3451void
3452Assembly::cacheResidual(dof_id_type dof, Real value, const std::set<TagID> & tags)
3453{
3454 for (auto & tag : tags)
3455 cacheResidual(dof, value, tag);
3456}
3457
3458void
3459Assembly::cacheResidualNodes(const DenseVector<Number> & res,
3460 const std::vector<dof_id_type> & dof_index,
3462 TagID tag)
3463{
3464 // Add the residual value and dof_index to cached_residual_values and cached_residual_rows
3465 // respectively.
3466 // This is used by NodalConstraint.C to cache the residual calculated for primary and secondary
3467 // node.
3468 const VectorTag & vector_tag = _subproblem.getVectorTag(tag);
3469 for (MooseIndex(dof_index) i = 0; i < dof_index.size(); ++i)
3470 {
3471 _cached_residual_values[vector_tag._type_id].push_back(res(i));
3472 _cached_residual_rows[vector_tag._type_id].push_back(dof_index[i]);
3473 }
3474}
3475
3476void
3477Assembly::cacheResidualNeighbor(GlobalDataKey, const std::vector<VectorTag> & tags)
3478{
3479 const std::vector<MooseVariableFEBase *> & vars = _sys.getVariables(_tid);
3480 for (const auto & var : vars)
3481 for (const auto & vector_tag : tags)
3482 if (_sys.hasVector(vector_tag._id))
3483 cacheResidualBlock(_cached_residual_values[vector_tag._type_id],
3484 _cached_residual_rows[vector_tag._type_id],
3485 _sub_Rn[vector_tag._type_id][var->number()],
3486 var->dofIndicesNeighbor(),
3487 var->arrayScalingFactor());
3488}
3489
3490void
3491Assembly::cacheResidualLower(GlobalDataKey, const std::vector<VectorTag> & tags)
3492{
3493 const std::vector<MooseVariableFEBase *> & vars = _sys.getVariables(_tid);
3494 for (const auto & var : vars)
3495 for (const auto & vector_tag : tags)
3496 if (_sys.hasVector(vector_tag._id))
3497 cacheResidualBlock(_cached_residual_values[vector_tag._type_id],
3498 _cached_residual_rows[vector_tag._type_id],
3499 _sub_Rl[vector_tag._type_id][var->number()],
3500 var->dofIndicesLower(),
3501 var->arrayScalingFactor());
3502}
3503
3504void
3505Assembly::addCachedResiduals(GlobalDataKey, const std::vector<VectorTag> & tags)
3506{
3507 for (const auto & vector_tag : tags)
3508 {
3509 if (!_sys.hasVector(vector_tag._id))
3510 {
3511 _cached_residual_values[vector_tag._type_id].clear();
3512 _cached_residual_rows[vector_tag._type_id].clear();
3513 continue;
3514 }
3515 addCachedResidualDirectly(_sys.getVector(vector_tag._id), GlobalDataKey{}, vector_tag);
3516 }
3517}
3518
3519void
3521{
3522 for (const auto & vector_tag : _residual_vector_tags)
3523 clearCachedResiduals(vector_tag);
3524}
3525
3526// private method, so no key required
3527void
3529{
3530 auto & values = _cached_residual_values[vector_tag._type_id];
3531 auto & rows = _cached_residual_rows[vector_tag._type_id];
3532
3533 mooseAssert(values.size() == rows.size(),
3534 "Number of cached residuals and number of rows must match!");
3535
3536 // Keep track of the largest size so we can use it to reserve and avoid
3537 // as much dynamic allocation as possible
3538 if (_max_cached_residuals < values.size())
3540
3541 // Clear both vectors (keeps the capacity the same)
3542 values.clear();
3543 rows.clear();
3544 // And then reserve: use 2 as a fudge factor to *really* avoid dynamic allocation!
3545 values.reserve(_max_cached_residuals * 2);
3546 rows.reserve(_max_cached_residuals * 2);
3547}
3548
3549void
3550Assembly::addCachedResidualDirectly(NumericVector<Number> & residual,
3552 const VectorTag & vector_tag)
3553{
3554 const auto & values = _cached_residual_values[vector_tag._type_id];
3555 const auto & rows = _cached_residual_rows[vector_tag._type_id];
3556
3557 mooseAssert(values.size() == rows.size(),
3558 "Number of cached residuals and number of rows must match!");
3559
3560 if (!values.empty())
3561 {
3562 residual.add_vector(values, rows);
3563 clearCachedResiduals(vector_tag);
3564 }
3565}
3566
3567void
3568Assembly::setResidual(NumericVector<Number> & residual, GlobalDataKey, const VectorTag & vector_tag)
3569{
3570 auto & tag_Re = _sub_Re[vector_tag._type_id];
3571 const std::vector<MooseVariableFEBase *> & vars = _sys.getVariables(_tid);
3572 for (const auto & var : vars)
3573 setResidualBlock(residual, tag_Re[var->number()], var->dofIndices(), var->arrayScalingFactor());
3574}
3575
3576void
3577Assembly::setResidualNeighbor(NumericVector<Number> & residual,
3579 const VectorTag & vector_tag)
3580{
3581 auto & tag_Rn = _sub_Rn[vector_tag._type_id];
3582 const std::vector<MooseVariableFEBase *> & vars = _sys.getVariables(_tid);
3583 for (const auto & var : vars)
3585 residual, tag_Rn[var->number()], var->dofIndicesNeighbor(), var->arrayScalingFactor());
3586}
3587
3588// private method, so no key required
3589void
3590Assembly::addJacobianBlock(SparseMatrix<Number> & jacobian,
3591 DenseMatrix<Number> & jac_block,
3592 const MooseVariableBase & ivar,
3593 const MooseVariableBase & jvar,
3594 const std::vector<dof_id_type> & idof_indices,
3595 const std::vector<dof_id_type> & jdof_indices)
3596{
3597 if (idof_indices.size() == 0 || jdof_indices.size() == 0)
3598 return;
3599 if (jac_block.n() == 0 || jac_block.m() == 0)
3600 return;
3601
3602 const auto & scaling_factors = ivar.arrayScalingFactor();
3603 const unsigned int iv = ivar.number();
3604 const unsigned int jv = jvar.number();
3605
3606 for (unsigned int i = 0; i < ivar.count(); ++i)
3607 {
3608 for (const auto & jt : libMesh::ConstCouplingRow(iv + i, *_cm))
3609 {
3610 if (jt < jv || jt >= jv + jvar.count())
3611 continue;
3612 unsigned int j = jt - jv;
3613
3614 auto di = ivar.componentDofIndices(idof_indices, i);
3615 auto dj = jvar.componentDofIndices(jdof_indices, j);
3616 auto indof = di.size();
3617 auto jndof = dj.size();
3618
3619 unsigned int jj = j;
3620 if (iv == jv && _component_block_diagonal[iv])
3621 // here i must be equal to j
3622 jj = 0;
3623
3624 auto sub = jac_block.sub_matrix(i * indof, indof, jj * jndof, jndof);
3625 if (scaling_factors[i] != 1.0)
3626 sub *= scaling_factors[i];
3627
3628 // If we're computing the jacobian for automatically scaling variables we do not want
3629 // to constrain the element matrix because it introduces 1s on the diagonal for the
3630 // constrained dofs
3632 _dof_map.constrain_element_matrix(sub, di, dj, false);
3633
3634 jacobian.add_matrix(sub, di, dj);
3635 }
3636 }
3637}
3638
3639// private method, so no key required
3640void
3641Assembly::cacheJacobianBlock(const DenseMatrix<Number> & jac_block,
3642 const MooseVariableBase & ivar,
3643 const MooseVariableBase & jvar,
3644 const std::vector<dof_id_type> & idof_indices,
3645 const std::vector<dof_id_type> & jdof_indices,
3646 TagID tag)
3647{
3648 if (idof_indices.size() == 0 || jdof_indices.size() == 0)
3649 return;
3650 if (jac_block.n() == 0 || jac_block.m() == 0)
3651 return;
3652 if (!_sys.hasMatrix(tag))
3653 return;
3654
3655 auto & scaling_factors = ivar.arrayScalingFactor();
3656 const unsigned int iv = ivar.number();
3657 const unsigned int jv = jvar.number();
3658
3659 for (unsigned int i = 0; i < ivar.count(); ++i)
3660 {
3661 for (const auto & jt : libMesh::ConstCouplingRow(iv + i, *_cm))
3662 {
3663 if (jt < jv || jt >= jv + jvar.count())
3664 continue;
3665 unsigned int j = jt - jv;
3666
3667 auto di = ivar.componentDofIndices(idof_indices, i);
3668 auto dj = jvar.componentDofIndices(jdof_indices, j);
3669 auto indof = di.size();
3670 auto jndof = dj.size();
3671
3672 unsigned int jj = j;
3673 if (iv == jv && _component_block_diagonal[iv])
3674 // here i must be equal to j
3675 jj = 0;
3676
3677 auto sub = jac_block.sub_matrix(i * indof, indof, jj * jndof, jndof);
3678 if (scaling_factors[i] != 1.0)
3679 sub *= scaling_factors[i];
3680
3681 // If we're computing the jacobian for automatically scaling variables we do not want
3682 // to constrain the element matrix because it introduces 1s on the diagonal for the
3683 // constrained dofs
3685 _dof_map.constrain_element_matrix(sub, di, dj, false);
3686
3687 for (MooseIndex(di) i = 0; i < di.size(); i++)
3688 for (MooseIndex(dj) j = 0; j < dj.size(); j++)
3689 {
3690 _cached_jacobian_values[tag].push_back(sub(i, j));
3691 _cached_jacobian_rows[tag].push_back(di[i]);
3692 _cached_jacobian_cols[tag].push_back(dj[j]);
3693 }
3694 }
3695 }
3696}
3697
3698// private method, so no key required
3699void
3700Assembly::cacheJacobianBlockNonzero(const DenseMatrix<Number> & jac_block,
3701 const MooseVariableBase & ivar,
3702 const MooseVariableBase & jvar,
3703 const std::vector<dof_id_type> & idof_indices,
3704 const std::vector<dof_id_type> & jdof_indices,
3705 TagID tag)
3706{
3707 if (idof_indices.size() == 0 || jdof_indices.size() == 0)
3708 return;
3709 if (jac_block.n() == 0 || jac_block.m() == 0)
3710 return;
3711 if (!_sys.hasMatrix(tag))
3712 return;
3713
3714 auto & scaling_factor = ivar.arrayScalingFactor();
3715
3716 for (unsigned int i = 0; i < ivar.count(); ++i)
3717 {
3718 unsigned int iv = ivar.number();
3719 for (const auto & jt : libMesh::ConstCouplingRow(iv + i, *_cm))
3720 {
3721 unsigned int jv = jvar.number();
3722 if (jt < jv || jt >= jv + jvar.count())
3723 continue;
3724 unsigned int j = jt - jv;
3725
3726 auto di = ivar.componentDofIndices(idof_indices, i);
3727 auto dj = jvar.componentDofIndices(jdof_indices, j);
3728 auto indof = di.size();
3729 auto jndof = dj.size();
3730
3731 unsigned int jj = j;
3732 if (iv == jv && _component_block_diagonal[iv])
3733 // here i must be equal to j
3734 jj = 0;
3735
3736 auto sub = jac_block.sub_matrix(i * indof, indof, jj * jndof, jndof);
3737 if (scaling_factor[i] != 1.0)
3738 sub *= scaling_factor[i];
3739
3740 _dof_map.constrain_element_matrix(sub, di, dj, false);
3741
3742 for (MooseIndex(di) i = 0; i < di.size(); i++)
3743 for (MooseIndex(dj) j = 0; j < dj.size(); j++)
3744 if (sub(i, j) != 0.0) // no storage allocated for unimplemented jacobian terms,
3745 // maintaining maximum sparsity possible
3746 {
3747 _cached_jacobian_values[tag].push_back(sub(i, j));
3748 _cached_jacobian_rows[tag].push_back(di[i]);
3749 _cached_jacobian_cols[tag].push_back(dj[j]);
3750 }
3751 }
3752 }
3753}
3754
3755void
3756Assembly::cacheJacobianBlock(const DenseMatrix<Number> & jac_block,
3757 const std::vector<dof_id_type> & idof_indices,
3758 const std::vector<dof_id_type> & jdof_indices,
3759 Real scaling_factor,
3761 const std::set<TagID> & tags)
3762{
3763 const auto has_matrix =
3764 std::any_of(tags.begin(), tags.end(), [this](const auto tag) { return _sys.hasMatrix(tag); });
3765
3766 // Work on a reusable Assembly-owned copy so callers retain their local matrix. This also lets us
3767 // apply constraints and scaling once before caching the same block to every requested matrix tag.
3768 if ((idof_indices.size() > 0) && (jdof_indices.size() > 0) && jac_block.n() && jac_block.m() &&
3769 has_matrix)
3770 {
3771 _row_indices.assign(idof_indices.begin(), idof_indices.end());
3772 _column_indices.assign(jdof_indices.begin(), jdof_indices.end());
3773 _element_matrix = jac_block;
3774
3775 // If we're computing the jacobian for automatically scaling variables we do not want to
3776 // constrain the element matrix because it introduces 1s on the diagonal for the constrained
3777 // dofs
3780
3781 if (scaling_factor != 1.0)
3782 _element_matrix *= scaling_factor;
3783
3784 for (const auto i : index_range(_row_indices))
3785 for (const auto j : index_range(_column_indices))
3788 }
3789}
3790
3791Real
3792Assembly::elementVolume(const Elem * elem) const
3793{
3794 FEType fe_type(elem->default_order(), LAGRANGE);
3795 std::unique_ptr<FEBase> fe(FEBase::build(elem->dim(), fe_type));
3796
3797 // references to the quadrature points and weights
3798 const std::vector<Real> & JxW = fe->get_JxW();
3799 const std::vector<Point> & q_points = fe->get_xyz();
3800
3801 // The default quadrature rule should integrate the mass matrix,
3802 // thus it should be plenty to compute the volume
3803 QGauss qrule(elem->dim(), fe_type.default_quadrature_order());
3804 fe->attach_quadrature_rule(&qrule);
3805 fe->reinit(elem);
3806
3807 // perform a sanity check to ensure that size of quad rule and size of q_points is
3808 // identical
3809 mooseAssert(qrule.n_points() == q_points.size(),
3810 "The number of points in the quadrature rule doesn't match the number of passed-in "
3811 "points in Assembly::setCoordinateTransformation");
3812
3813 // compute the coordinate transformation
3814 Real vol = 0;
3815 for (unsigned int qp = 0; qp < qrule.n_points(); ++qp)
3816 {
3817 Real coord;
3818 coordTransformFactor(_subproblem, elem->subdomain_id(), q_points[qp], coord);
3819 vol += JxW[qp] * coord;
3820 }
3821 return vol;
3822}
3823
3824void
3825Assembly::saveLocalADArray(std::vector<ADReal> & re,
3826 unsigned int i,
3827 unsigned int ntest,
3828 const ADRealEigenVector & v) const
3829{
3830 for (unsigned int j = 0; j < v.size(); ++j, i += ntest)
3831 re[i] += v(j);
3832}
3833
3834void
3836{
3837#ifndef NDEBUG
3839 {
3840 mooseAssert(_cached_jacobian_rows.size() == _cached_jacobian_cols.size(),
3841 "Error: Cached data sizes MUST be the same!");
3842 for (MooseIndex(_cached_jacobian_rows) i = 0; i < _cached_jacobian_rows.size(); i++)
3843 mooseAssert(_cached_jacobian_rows[i].size() == _cached_jacobian_cols[i].size(),
3844 "Error: Cached data sizes MUST be the same for a given tag!");
3845 }
3846#endif
3847
3848 for (MooseIndex(_cached_jacobian_rows) i = 0; i < _cached_jacobian_rows.size(); i++)
3849 if (_sys.hasMatrix(i))
3850 for (MooseIndex(_cached_jacobian_rows[i]) j = 0; j < _cached_jacobian_rows[i].size(); j++)
3854
3855 for (MooseIndex(_cached_jacobian_rows) i = 0; i < _cached_jacobian_rows.size(); i++)
3856 {
3857 if (!_sys.hasMatrix(i))
3858 continue;
3859
3862
3863 // Try to be more efficient from now on
3864 // The 2 is just a fudge factor to keep us from having to grow the vector during assembly
3865 _cached_jacobian_values[i].clear();
3867
3868 _cached_jacobian_rows[i].clear();
3870
3871 _cached_jacobian_cols[i].clear();
3873 }
3874}
3875
3876inline void
3878{
3879 auto i = ivar.number();
3880 auto j = jvar.number();
3881 for (MooseIndex(_jacobian_block_used) tag = 0; tag < _jacobian_block_used.size(); tag++)
3882 if (jacobianBlockUsed(tag, i, j) && _sys.hasMatrix(tag))
3884 jacobianBlock(i, j, LocalDataKey{}, tag),
3885 ivar,
3886 jvar,
3887 ivar.dofIndices(),
3888 jvar.dofIndices());
3889}
3890
3891void
3893{
3894 for (const auto & it : _cm_ff_entry)
3895 addJacobianCoupledVarPair(*it.first, *it.second);
3896
3897 for (const auto & it : _cm_sf_entry)
3898 addJacobianCoupledVarPair(*it.first, *it.second);
3899
3900 for (const auto & it : _cm_fs_entry)
3901 addJacobianCoupledVarPair(*it.first, *it.second);
3902}
3903
3904void
3906{
3907 for (const auto & it : _cm_nonlocal_entry)
3908 {
3909 auto ivar = it.first;
3910 auto jvar = it.second;
3911 auto i = ivar->number();
3912 auto j = jvar->number();
3913 for (MooseIndex(_jacobian_block_nonlocal_used) tag = 0;
3914 tag < _jacobian_block_nonlocal_used.size();
3915 tag++)
3916 if (jacobianBlockNonlocalUsed(tag, i, j) && _sys.hasMatrix(tag))
3918 jacobianBlockNonlocal(i, j, LocalDataKey{}, tag),
3919 *ivar,
3920 *jvar,
3921 ivar->dofIndices(),
3922 jvar->allDofIndices());
3923 }
3924}
3925
3926void
3928{
3929 for (const auto & it : _cm_ff_entry)
3930 {
3931 auto ivar = it.first;
3932 auto jvar = it.second;
3933 auto i = ivar->number();
3934 auto j = jvar->number();
3935 for (MooseIndex(_jacobian_block_neighbor_used) tag = 0;
3936 tag < _jacobian_block_neighbor_used.size();
3937 tag++)
3938 if (jacobianBlockNeighborUsed(tag, i, j) && _sys.hasMatrix(tag))
3939 {
3942 *ivar,
3943 *jvar,
3944 ivar->dofIndices(),
3945 jvar->dofIndicesNeighbor());
3946
3949 *ivar,
3950 *jvar,
3951 ivar->dofIndicesNeighbor(),
3952 jvar->dofIndices());
3953
3956 *ivar,
3957 *jvar,
3958 ivar->dofIndicesNeighbor(),
3959 jvar->dofIndicesNeighbor());
3960 }
3961 }
3962}
3963
3964void
3966{
3967 for (const auto & it : _cm_ff_entry)
3968 {
3969 auto ivar = it.first;
3970 auto jvar = it.second;
3971 auto i = ivar->number();
3972 auto j = jvar->number();
3973 for (MooseIndex(_jacobian_block_lower_used) tag = 0; tag < _jacobian_block_lower_used.size();
3974 tag++)
3975 if (jacobianBlockLowerUsed(tag, i, j) && _sys.hasMatrix(tag))
3976 {
3979 *ivar,
3980 *jvar,
3981 ivar->dofIndicesLower(),
3982 jvar->dofIndicesLower());
3983
3986 *ivar,
3987 *jvar,
3988 ivar->dofIndicesLower(),
3989 jvar->dofIndicesNeighbor());
3990
3993 *ivar,
3994 *jvar,
3995 ivar->dofIndicesLower(),
3996 jvar->dofIndices());
3997
4000 *ivar,
4001 *jvar,
4002 ivar->dofIndicesNeighbor(),
4003 jvar->dofIndicesLower());
4004
4007 *ivar,
4008 *jvar,
4009 ivar->dofIndices(),
4010 jvar->dofIndicesLower());
4011 }
4012
4013 for (MooseIndex(_jacobian_block_neighbor_used) tag = 0;
4014 tag < _jacobian_block_neighbor_used.size();
4015 tag++)
4016 if (jacobianBlockNeighborUsed(tag, i, j) && _sys.hasMatrix(tag))
4017 {
4020 *ivar,
4021 *jvar,
4022 ivar->dofIndices(),
4023 jvar->dofIndicesNeighbor());
4024
4027 *ivar,
4028 *jvar,
4029 ivar->dofIndicesNeighbor(),
4030 jvar->dofIndices());
4031
4034 *ivar,
4035 *jvar,
4036 ivar->dofIndicesNeighbor(),
4037 jvar->dofIndicesNeighbor());
4038 }
4039 }
4040}
4041
4042void
4044{
4045 for (const auto & it : _cm_ff_entry)
4046 {
4047 auto ivar = it.first;
4048 auto jvar = it.second;
4049 auto i = ivar->number();
4050 auto j = jvar->number();
4051 for (MooseIndex(_jacobian_block_lower_used) tag = 0; tag < _jacobian_block_lower_used.size();
4052 tag++)
4053 if (jacobianBlockLowerUsed(tag, i, j) && _sys.hasMatrix(tag))
4054 {
4057 *ivar,
4058 *jvar,
4059 ivar->dofIndicesLower(),
4060 jvar->dofIndicesLower());
4061
4064 *ivar,
4065 *jvar,
4066 ivar->dofIndicesLower(),
4067 jvar->dofIndices());
4068
4071 *ivar,
4072 *jvar,
4073 ivar->dofIndices(),
4074 jvar->dofIndicesLower());
4075 }
4076 }
4077}
4078
4079void
4081{
4082 for (const auto & it : _cm_ff_entry)
4083 cacheJacobianCoupledVarPair(*it.first, *it.second);
4084
4085 for (const auto & it : _cm_fs_entry)
4086 cacheJacobianCoupledVarPair(*it.first, *it.second);
4087
4088 for (const auto & it : _cm_sf_entry)
4089 cacheJacobianCoupledVarPair(*it.first, *it.second);
4090}
4091
4092// private method, so no key required
4093void
4095 const MooseVariableBase & jvar)
4096{
4097 auto i = ivar.number();
4098 auto j = jvar.number();
4099 for (MooseIndex(_jacobian_block_used) tag = 0; tag < _jacobian_block_used.size(); tag++)
4100 if (jacobianBlockUsed(tag, i, j) && _sys.hasMatrix(tag))
4102 ivar,
4103 jvar,
4104 ivar.dofIndices(),
4105 jvar.dofIndices(),
4106 tag);
4107}
4108
4109void
4111{
4112 for (const auto & it : _cm_nonlocal_entry)
4113 {
4114 auto ivar = it.first;
4115 auto jvar = it.second;
4116 auto i = ivar->number();
4117 auto j = jvar->number();
4118 for (MooseIndex(_jacobian_block_nonlocal_used) tag = 0;
4119 tag < _jacobian_block_nonlocal_used.size();
4120 tag++)
4121 if (jacobianBlockNonlocalUsed(tag, i, j) && _sys.hasMatrix(tag))
4123 *ivar,
4124 *jvar,
4125 ivar->dofIndices(),
4126 jvar->allDofIndices(),
4127 tag);
4128 }
4129}
4130
4131void
4133{
4134 for (const auto & it : _cm_ff_entry)
4135 {
4136 auto ivar = it.first;
4137 auto jvar = it.second;
4138 auto i = ivar->number();
4139 auto j = jvar->number();
4140
4141 for (MooseIndex(_jacobian_block_neighbor_used) tag = 0;
4142 tag < _jacobian_block_neighbor_used.size();
4143 tag++)
4144 if (jacobianBlockNeighborUsed(tag, i, j) && _sys.hasMatrix(tag))
4145 {
4147 *ivar,
4148 *jvar,
4149 ivar->dofIndices(),
4150 jvar->dofIndicesNeighbor(),
4151 tag);
4153 *ivar,
4154 *jvar,
4155 ivar->dofIndicesNeighbor(),
4156 jvar->dofIndices(),
4157 tag);
4160 *ivar,
4161 *jvar,
4162 ivar->dofIndicesNeighbor(),
4163 jvar->dofIndicesNeighbor(),
4164 tag);
4165 }
4166 }
4167}
4168
4169void
4171{
4172 for (const auto & it : _cm_ff_entry)
4173 {
4174 auto ivar = it.first;
4175 auto jvar = it.second;
4176 auto i = ivar->number();
4177 auto j = jvar->number();
4178 for (MooseIndex(_jacobian_block_lower_used) tag = 0; tag < _jacobian_block_lower_used.size();
4179 tag++)
4180 if (jacobianBlockLowerUsed(tag, i, j) && _sys.hasMatrix(tag))
4181 {
4183 *ivar,
4184 *jvar,
4185 ivar->dofIndicesLower(),
4186 jvar->dofIndicesLower(),
4187 tag);
4188
4190 *ivar,
4191 *jvar,
4192 ivar->dofIndicesLower(),
4193 jvar->dofIndices(),
4194 tag);
4195
4197 *ivar,
4198 *jvar,
4199 ivar->dofIndicesLower(),
4200 jvar->dofIndicesNeighbor(),
4201 tag);
4202
4204 *ivar,
4205 *jvar,
4206 ivar->dofIndices(),
4207 jvar->dofIndicesLower(),
4208 tag);
4209
4212 *ivar,
4213 *jvar,
4214 ivar->dofIndices(),
4215 jvar->dofIndices(),
4216 tag);
4217
4219 *ivar,
4220 *jvar,
4221 ivar->dofIndices(),
4222 jvar->dofIndicesNeighbor(),
4223 tag);
4224
4226 *ivar,
4227 *jvar,
4228 ivar->dofIndicesNeighbor(),
4229 jvar->dofIndicesLower(),
4230 tag);
4231
4233 *ivar,
4234 *jvar,
4235 ivar->dofIndicesNeighbor(),
4236 jvar->dofIndices(),
4237 tag);
4238
4240 *ivar,
4241 *jvar,
4242 ivar->dofIndicesNeighbor(),
4243 jvar->dofIndicesNeighbor(),
4244 tag);
4245 }
4246 }
4247}
4248
4249void
4250Assembly::addJacobianBlockTags(SparseMatrix<Number> & jacobian,
4251 unsigned int ivar,
4252 unsigned int jvar,
4253 const DofMap & dof_map,
4254 std::vector<dof_id_type> & dof_indices,
4256 const std::set<TagID> & tags)
4257{
4258 for (auto tag : tags)
4259 addJacobianBlock(jacobian, ivar, jvar, dof_map, dof_indices, GlobalDataKey{}, tag);
4260}
4261
4262void
4263Assembly::addJacobianBlock(SparseMatrix<Number> & jacobian,
4264 unsigned int ivar,
4265 unsigned int jvar,
4266 const DofMap & dof_map,
4267 std::vector<dof_id_type> & dof_indices,
4268 GlobalDataKey,
4269 TagID tag)
4270{
4271 if (dof_indices.size() == 0)
4272 return;
4273 if (!(*_cm)(ivar, jvar))
4274 return;
4275
4276 auto & iv = _sys.getVariable(_tid, ivar);
4277 auto & jv = _sys.getVariable(_tid, jvar);
4278 auto & scaling_factor = iv.arrayScalingFactor();
4279
4280 const unsigned int ivn = iv.number();
4281 const unsigned int jvn = jv.number();
4282 auto & ke = jacobianBlock(ivn, jvn, LocalDataKey{}, tag);
4283
4284 // It is guaranteed by design iv.number <= ivar since iv is obtained
4285 // through SystemBase::getVariable with ivar.
4286 // Most of times ivar will just be equal to iv.number except for array variables,
4287 // where ivar could be a number for a component of an array variable but calling
4288 // getVariable will return the array variable that has the number of the 0th component.
4289 // It is the same for jvar.
4290 const unsigned int i = ivar - ivn;
4291 const unsigned int j = jvar - jvn;
4292
4293 // DoF indices are independently given
4294 auto di = dof_indices;
4295 auto dj = dof_indices;
4296
4297 auto indof = di.size();
4298 auto jndof = dj.size();
4299
4300 unsigned int jj = j;
4301 if (ivar == jvar && _component_block_diagonal[ivn])
4302 jj = 0;
4303
4304 auto sub = ke.sub_matrix(i * indof, indof, jj * jndof, jndof);
4305 // If we're computing the jacobian for automatically scaling variables we do not want to
4306 // constrain the element matrix because it introduces 1s on the diagonal for the constrained
4307 // dofs
4309 dof_map.constrain_element_matrix(sub, di, dj, false);
4310
4311 if (scaling_factor[i] != 1.0)
4312 sub *= scaling_factor[i];
4313
4314 jacobian.add_matrix(sub, di, dj);
4315}
4316
4317void
4318Assembly::addJacobianBlockNonlocal(SparseMatrix<Number> & jacobian,
4319 const unsigned int ivar,
4320 const unsigned int jvar,
4321 const DofMap & dof_map,
4322 const std::vector<dof_id_type> & idof_indices,
4323 const std::vector<dof_id_type> & jdof_indices,
4325 const TagID tag)
4326{
4327 if (idof_indices.size() == 0 || jdof_indices.size() == 0)
4328 return;
4329 if (jacobian.n() == 0 || jacobian.m() == 0)
4330 return;
4331 if (!(*_cm)(ivar, jvar))
4332 return;
4333
4334 auto & iv = _sys.getVariable(_tid, ivar);
4335 auto & jv = _sys.getVariable(_tid, jvar);
4336 auto & scaling_factor = iv.arrayScalingFactor();
4337
4338 const unsigned int ivn = iv.number();
4339 const unsigned int jvn = jv.number();
4340 auto & keg = jacobianBlockNonlocal(ivn, jvn, LocalDataKey{}, tag);
4341
4342 // It is guaranteed by design iv.number <= ivar since iv is obtained
4343 // through SystemBase::getVariable with ivar.
4344 // Most of times ivar will just be equal to iv.number except for array variables,
4345 // where ivar could be a number for a component of an array variable but calling
4346 // getVariable will return the array variable that has the number of the 0th component.
4347 // It is the same for jvar.
4348 const unsigned int i = ivar - ivn;
4349 const unsigned int j = jvar - jvn;
4350
4351 // DoF indices are independently given
4352 auto di = idof_indices;
4353 auto dj = jdof_indices;
4354
4355 auto indof = di.size();
4356 auto jndof = dj.size();
4357
4358 unsigned int jj = j;
4359 if (ivar == jvar && _component_block_diagonal[ivn])
4360 jj = 0;
4361
4362 auto sub = keg.sub_matrix(i * indof, indof, jj * jndof, jndof);
4363 // If we're computing the jacobian for automatically scaling variables we do not want to
4364 // constrain the element matrix because it introduces 1s on the diagonal for the constrained
4365 // dofs
4367 dof_map.constrain_element_matrix(sub, di, dj, false);
4368
4369 if (scaling_factor[i] != 1.0)
4370 sub *= scaling_factor[i];
4371
4372 jacobian.add_matrix(sub, di, dj);
4373}
4374
4375void
4376Assembly::addJacobianBlockNonlocalTags(SparseMatrix<Number> & jacobian,
4377 const unsigned int ivar,
4378 const unsigned int jvar,
4379 const DofMap & dof_map,
4380 const std::vector<dof_id_type> & idof_indices,
4381 const std::vector<dof_id_type> & jdof_indices,
4383 const std::set<TagID> & tags)
4384{
4385 for (auto tag : tags)
4387 jacobian, ivar, jvar, dof_map, idof_indices, jdof_indices, GlobalDataKey{}, tag);
4388}
4389
4390void
4391Assembly::addJacobianNeighbor(SparseMatrix<Number> & jacobian,
4392 const unsigned int ivar,
4393 const unsigned int jvar,
4394 const DofMap & dof_map,
4395 std::vector<dof_id_type> & dof_indices,
4396 std::vector<dof_id_type> & neighbor_dof_indices,
4397 GlobalDataKey,
4398 const TagID tag)
4399{
4400 if (dof_indices.size() == 0 && neighbor_dof_indices.size() == 0)
4401 return;
4402 if (!(*_cm)(ivar, jvar))
4403 return;
4404
4405 auto & iv = _sys.getVariable(_tid, ivar);
4406 auto & jv = _sys.getVariable(_tid, jvar);
4407 auto & scaling_factor = iv.arrayScalingFactor();
4408
4409 const unsigned int ivn = iv.number();
4410 const unsigned int jvn = jv.number();
4411 auto & ken = jacobianBlockNeighbor(Moose::ElementNeighbor, ivn, jvn, LocalDataKey{}, tag);
4412 auto & kne = jacobianBlockNeighbor(Moose::NeighborElement, ivn, jvn, LocalDataKey{}, tag);
4413 auto & knn = jacobianBlockNeighbor(Moose::NeighborNeighbor, ivn, jvn, LocalDataKey{}, tag);
4414
4415 // It is guaranteed by design iv.number <= ivar since iv is obtained
4416 // through SystemBase::getVariable with ivar.
4417 // Most of times ivar will just be equal to iv.number except for array variables,
4418 // where ivar could be a number for a component of an array variable but calling
4419 // getVariable will return the array variable that has the number of the 0th component.
4420 // It is the same for jvar.
4421 const unsigned int i = ivar - ivn;
4422 const unsigned int j = jvar - jvn;
4423 // DoF indices are independently given
4424 auto dc = dof_indices;
4425 auto dn = neighbor_dof_indices;
4426 auto cndof = dc.size();
4427 auto nndof = dn.size();
4428
4429 unsigned int jj = j;
4430 if (ivar == jvar && _component_block_diagonal[ivn])
4431 jj = 0;
4432
4433 auto suben = ken.sub_matrix(i * cndof, cndof, jj * nndof, nndof);
4434 auto subne = kne.sub_matrix(i * nndof, nndof, jj * cndof, cndof);
4435 auto subnn = knn.sub_matrix(i * nndof, nndof, jj * nndof, nndof);
4436
4437 // If we're computing the jacobian for automatically scaling variables we do not want to
4438 // constrain the element matrix because it introduces 1s on the diagonal for the constrained
4439 // dofs
4441 {
4442 dof_map.constrain_element_matrix(suben, dc, dn, false);
4443 dof_map.constrain_element_matrix(subne, dn, dc, false);
4444 dof_map.constrain_element_matrix(subnn, dn, dn, false);
4445 }
4446
4447 if (scaling_factor[i] != 1.0)
4448 {
4449 suben *= scaling_factor[i];
4450 subne *= scaling_factor[i];
4451 subnn *= scaling_factor[i];
4452 }
4453
4454 jacobian.add_matrix(suben, dc, dn);
4455 jacobian.add_matrix(subne, dn, dc);
4456 jacobian.add_matrix(subnn, dn, dn);
4457}
4458
4459void
4460Assembly::addJacobianNeighborTags(SparseMatrix<Number> & jacobian,
4461 const unsigned int ivar,
4462 const unsigned int jvar,
4463 const DofMap & dof_map,
4464 std::vector<dof_id_type> & dof_indices,
4465 std::vector<dof_id_type> & neighbor_dof_indices,
4467 const std::set<TagID> & tags)
4468{
4469 for (const auto tag : tags)
4471 jacobian, ivar, jvar, dof_map, dof_indices, neighbor_dof_indices, GlobalDataKey{}, tag);
4472}
4473
4474void
4476{
4477 for (const auto & it : _cm_ss_entry)
4478 addJacobianCoupledVarPair(*it.first, *it.second);
4479}
4480
4481void
4483{
4484 for (const auto & it : _cm_sf_entry)
4485 if (it.first->number() == ivar)
4486 addJacobianCoupledVarPair(*it.first, *it.second);
4487}
4488
4489void
4491 numeric_index_type i, numeric_index_type j, Real value, LocalDataKey, TagID tag)
4492{
4493 _cached_jacobian_rows[tag].push_back(i);
4494 _cached_jacobian_cols[tag].push_back(j);
4495 _cached_jacobian_values[tag].push_back(value);
4496}
4497
4498void
4499Assembly::cacheJacobian(numeric_index_type i,
4500 numeric_index_type j,
4501 Real value,
4503 const std::set<TagID> & tags)
4504{
4505 for (auto tag : tags)
4506 if (_sys.hasMatrix(tag))
4507 cacheJacobian(i, j, value, LocalDataKey{}, tag);
4508}
4509
4510void
4512{
4513 for (MooseIndex(_cached_jacobian_rows) tag = 0; tag < _cached_jacobian_rows.size(); tag++)
4514 if (_sys.hasMatrix(tag))
4515 {
4516 // First zero the rows (including the diagonals) to prepare for
4517 // setting the cached values.
4519
4520 // TODO: Use SparseMatrix::set_values() for efficiency
4521 for (MooseIndex(_cached_jacobian_values) i = 0; i < _cached_jacobian_values[tag].size(); ++i)
4523 _cached_jacobian_cols[tag][i],
4524 _cached_jacobian_values[tag][i]);
4525 }
4526
4528}
4529
4530void
4532{
4533 for (MooseIndex(_cached_jacobian_rows) tag = 0; tag < _cached_jacobian_rows.size(); tag++)
4534 if (_sys.hasMatrix(tag))
4536
4538}
4539
4540void
4542{
4543 for (MooseIndex(_cached_jacobian_rows) tag = 0; tag < _cached_jacobian_rows.size(); tag++)
4544 {
4545 _cached_jacobian_rows[tag].clear();
4546 _cached_jacobian_cols[tag].clear();
4547 _cached_jacobian_values[tag].clear();
4548 }
4549}
4550
4551void
4553{
4554 mooseAssert(_xfem != nullptr, "This function should not be called if xfem is inactive");
4555
4557 return;
4558
4559 MooseArray<Real> xfem_weight_multipliers;
4560 if (_xfem->getXFEMWeights(xfem_weight_multipliers, elem, _current_qrule, _current_q_points))
4561 {
4562 mooseAssert(xfem_weight_multipliers.size() == _current_JxW.size(),
4563 "Size of weight multipliers in xfem doesn't match number of quadrature points");
4564 for (unsigned i = 0; i < xfem_weight_multipliers.size(); i++)
4565 _current_JxW[i] = _current_JxW[i] * xfem_weight_multipliers[i];
4566
4567 xfem_weight_multipliers.release();
4568 }
4569}
4570
4571void
4572Assembly::modifyFaceWeightsDueToXFEM(const Elem * elem, unsigned int side)
4573{
4574 mooseAssert(_xfem != nullptr, "This function should not be called if xfem is inactive");
4575
4577 return;
4578
4579 MooseArray<Real> xfem_face_weight_multipliers;
4580 if (_xfem->getXFEMFaceWeights(
4581 xfem_face_weight_multipliers, elem, _current_qrule_face, _current_q_points_face, side))
4582 {
4583 mooseAssert(xfem_face_weight_multipliers.size() == _current_JxW_face.size(),
4584 "Size of weight multipliers in xfem doesn't match number of quadrature points");
4585 for (unsigned i = 0; i < xfem_face_weight_multipliers.size(); i++)
4586 _current_JxW_face[i] = _current_JxW_face[i] * xfem_face_weight_multipliers[i];
4587
4588 xfem_face_weight_multipliers.release();
4589 }
4590}
4591
4592void
4594{
4595 _scaling_vector = &_sys.getVector("scaling_factors");
4596}
4597
4598void
4599Assembly::modifyArbitraryWeights(const std::vector<Real> & weights)
4600{
4601 mooseAssert(_current_qrule == _current_qrule_arbitrary, "Rule should be arbitrary");
4602 mooseAssert(weights.size() == _current_physical_points.size(), "Size mismatch");
4603
4604 for (MooseIndex(weights.size()) i = 0; i < weights.size(); ++i)
4605 _current_JxW[i] = weights[i];
4606}
4607
4608template <>
4610Assembly::fePhi<VectorValue<Real>>(FEType type) const
4611{
4612 buildVectorFE(type);
4613 return _vector_fe_shape_data[type]->_phi;
4614}
4615
4616template <>
4618Assembly::feGradPhi<VectorValue<Real>>(FEType type) const
4619{
4620 buildVectorFE(type);
4621 return _vector_fe_shape_data[type]->_grad_phi;
4622}
4623
4624template <>
4626Assembly::feSecondPhi<VectorValue<Real>>(FEType type) const
4627{
4628 _need_second_derivative.insert(type);
4629 buildVectorFE(type);
4630 return _vector_fe_shape_data[type]->_second_phi;
4631}
4632
4633template <>
4635Assembly::fePhiLower<VectorValue<Real>>(FEType type) const
4636{
4637 buildVectorLowerDFE(type);
4638 return _vector_fe_shape_data_lower[type]->_phi;
4639}
4640
4641template <>
4643Assembly::feDualPhiLower<VectorValue<Real>>(FEType type) const
4644{
4645 buildVectorDualLowerDFE(type);
4646 return _vector_fe_shape_data_dual_lower[type]->_phi;
4647}
4648
4649template <>
4651Assembly::feGradPhiLower<VectorValue<Real>>(FEType type) const
4652{
4653 buildVectorLowerDFE(type);
4654 return _vector_fe_shape_data_lower[type]->_grad_phi;
4655}
4656
4657template <>
4659Assembly::feGradDualPhiLower<VectorValue<Real>>(FEType type) const
4660{
4661 buildVectorDualLowerDFE(type);
4662 return _vector_fe_shape_data_dual_lower[type]->_grad_phi;
4663}
4664
4665template <>
4667Assembly::fePhiFace<VectorValue<Real>>(FEType type) const
4668{
4669 buildVectorFaceFE(type);
4670 return _vector_fe_shape_data_face[type]->_phi;
4671}
4672
4673template <>
4675Assembly::feGradPhiFace<VectorValue<Real>>(FEType type) const
4676{
4677 buildVectorFaceFE(type);
4678 return _vector_fe_shape_data_face[type]->_grad_phi;
4679}
4680
4681template <>
4683Assembly::feSecondPhiFace<VectorValue<Real>>(FEType type) const
4684{
4685 _need_second_derivative.insert(type);
4686 buildVectorFaceFE(type);
4687
4688 // If we're building for a face we probably need to build for a
4689 // neighbor while _need_second_derivative is set;
4690 // onInterface/reinitNeighbor/etc don't distinguish
4691 buildVectorFaceNeighborFE(type);
4692
4693 return _vector_fe_shape_data_face[type]->_second_phi;
4694}
4695
4696template <>
4698Assembly::fePhiNeighbor<VectorValue<Real>>(FEType type) const
4699{
4700 buildVectorNeighborFE(type);
4701 return _vector_fe_shape_data_neighbor[type]->_phi;
4702}
4703
4704template <>
4706Assembly::feGradPhiNeighbor<VectorValue<Real>>(FEType type) const
4707{
4708 buildVectorNeighborFE(type);
4709 return _vector_fe_shape_data_neighbor[type]->_grad_phi;
4710}
4711
4712template <>
4714Assembly::feSecondPhiNeighbor<VectorValue<Real>>(FEType type) const
4715{
4716 _need_second_derivative_neighbor.insert(type);
4717 buildVectorNeighborFE(type);
4718 return _vector_fe_shape_data_neighbor[type]->_second_phi;
4719}
4720
4721template <>
4723Assembly::fePhiFaceNeighbor<VectorValue<Real>>(FEType type) const
4724{
4725 buildVectorFaceNeighborFE(type);
4726 return _vector_fe_shape_data_face_neighbor[type]->_phi;
4727}
4728
4729template <>
4731Assembly::feGradPhiFaceNeighbor<VectorValue<Real>>(FEType type) const
4732{
4733 buildVectorFaceNeighborFE(type);
4734 return _vector_fe_shape_data_face_neighbor[type]->_grad_phi;
4735}
4736
4737template <>
4739Assembly::feSecondPhiFaceNeighbor<VectorValue<Real>>(FEType type) const
4740{
4741 _need_second_derivative_neighbor.insert(type);
4742 buildVectorFaceNeighborFE(type);
4743 return _vector_fe_shape_data_face_neighbor[type]->_second_phi;
4744}
4745
4746template <>
4748Assembly::feCurlPhi<VectorValue<Real>>(FEType type) const
4749{
4750 _need_curl.insert(type);
4751 buildVectorFE(type);
4752 return _vector_fe_shape_data[type]->_curl_phi;
4753}
4754
4755template <>
4757Assembly::feCurlPhiFace<VectorValue<Real>>(FEType type) const
4758{
4759 _need_curl.insert(type);
4760 buildVectorFaceFE(type);
4761
4762 // If we're building for a face we probably need to build for a
4763 // neighbor while _need_curl is set;
4764 // onInterface/reinitNeighbor/etc don't distinguish
4765 buildVectorFaceNeighborFE(type);
4766
4767 return _vector_fe_shape_data_face[type]->_curl_phi;
4768}
4769
4770template <>
4772Assembly::feCurlPhiNeighbor<VectorValue<Real>>(FEType type) const
4773{
4774 _need_curl.insert(type);
4775 buildVectorNeighborFE(type);
4776 return _vector_fe_shape_data_neighbor[type]->_curl_phi;
4777}
4778
4779template <>
4781Assembly::feCurlPhiFaceNeighbor<VectorValue<Real>>(FEType type) const
4782{
4783 _need_curl.insert(type);
4784 buildVectorFaceNeighborFE(type);
4785
4786 return _vector_fe_shape_data_face_neighbor[type]->_curl_phi;
4787}
4788
4789template <>
4791Assembly::feDivPhi<VectorValue<Real>>(FEType type) const
4792{
4793 _need_div.insert(type);
4794 buildVectorFE(type);
4795 return _vector_fe_shape_data[type]->_div_phi;
4796}
4797
4798template <>
4800Assembly::feDivPhiFace<VectorValue<Real>>(FEType type) const
4801{
4802 _need_face_div.insert(type);
4803 buildVectorFaceFE(type);
4804
4805 // If we're building for a face we probably need to build for a
4806 // neighbor while _need_face_div is set;
4807 // onInterface/reinitNeighbor/etc don't distinguish
4808 buildVectorFaceNeighborFE(type);
4809
4810 return _vector_fe_shape_data_face[type]->_div_phi;
4811}
4812
4813template <>
4815Assembly::feDivPhiNeighbor<VectorValue<Real>>(FEType type) const
4816{
4817 _need_neighbor_div.insert(type);
4818 buildVectorNeighborFE(type);
4819 return _vector_fe_shape_data_neighbor[type]->_div_phi;
4820}
4821
4822template <>
4824Assembly::feDivPhiFaceNeighbor<VectorValue<Real>>(FEType type) const
4825{
4826 _need_face_neighbor_div.insert(type);
4827 buildVectorFaceNeighborFE(type);
4828 return _vector_fe_shape_data_face_neighbor[type]->_div_phi;
4829}
4830
4831const MooseArray<ADReal> &
4833{
4834 _calculate_curvatures = true;
4835 // Must prerequest the second derivatives. Sadly because there is only one
4836 // _need_second_derivative map for both volumetric and face FE objects we must request both here
4837 feSecondPhi<Real>(_helper_type);
4838 feSecondPhiFace<Real>(_helper_type);
4839 return _ad_curvatures;
4840}
4841
4842void
4844{
4845 for (unsigned int dim = 0; dim <= _mesh_dimension; dim++)
4846 {
4847 _holder_fe_helper[dim]->get_phi();
4848 _holder_fe_helper[dim]->get_dphi();
4849 _holder_fe_helper[dim]->get_xyz();
4850 _holder_fe_helper[dim]->get_JxW();
4851
4852 _holder_fe_face_helper[dim]->get_phi();
4853 _holder_fe_face_helper[dim]->get_dphi();
4854 _holder_fe_face_helper[dim]->get_xyz();
4855 _holder_fe_face_helper[dim]->get_JxW();
4856 _holder_fe_face_helper[dim]->get_normals();
4857
4860 _holder_fe_face_neighbor_helper[dim]->get_normals();
4861
4862 _holder_fe_neighbor_helper[dim]->get_xyz();
4863 _holder_fe_neighbor_helper[dim]->get_JxW();
4864 }
4865
4866 for (unsigned int dim = 0; dim < _mesh_dimension; dim++)
4867 {
4868 // We need these computations in order to compute correct lower-d element volumes in
4869 // curvilinear coordinates
4870 _holder_fe_lower_helper[dim]->get_xyz();
4871 _holder_fe_lower_helper[dim]->get_JxW();
4872 }
4873}
4874
4875void
4877{
4879 // Already performed tasks for p-refinement
4880 return;
4881
4882 const auto helper_type = _helper_type;
4883 auto process_fe_and_helpers = [&helper_type](auto & unique_helper_container,
4884 auto & helper_container,
4885 const unsigned int num_dimensionalities,
4886 const bool user_added_helper_type,
4887 auto & fe_container)
4888 {
4889 unique_helper_container.resize(num_dimensionalities);
4890 for (const auto dim : make_range(num_dimensionalities))
4891 {
4892 auto & unique_helper = unique_helper_container[dim];
4893 unique_helper = FEGenericBase<Real>::build(dim, helper_type);
4894 // don't participate in p-refinement
4895 unique_helper->add_p_level_in_reinit(false);
4896 helper_container[dim] = unique_helper.get();
4897
4898 // If the user did not request the helper type then we should erase the original helper FE
4899 // from the ordinary FE container. The unique helper above replaces it for helper use.
4900 if (!user_added_helper_type)
4901 {
4902 auto & fe_container_dim = libmesh_map_find(fe_container, dim);
4903 auto fe_it = fe_container_dim.find(helper_type);
4904 mooseAssert(fe_it != fe_container_dim.end(), "We should have the helper type");
4905 delete fe_it->second;
4906 fe_container_dim.erase(fe_it);
4907 }
4908 }
4909 };
4910
4911 // Handle scalar field families
4912 process_fe_and_helpers(_unique_fe_helper,
4914 _mesh_dimension + 1,
4916 _fe);
4917 process_fe_and_helpers(_unique_fe_face_helper,
4919 _mesh_dimension + 1,
4921 _fe_face);
4922 process_fe_and_helpers(_unique_fe_face_neighbor_helper,
4924 _mesh_dimension + 1,
4927 process_fe_and_helpers(_unique_fe_neighbor_helper,
4929 _mesh_dimension + 1,
4931 _fe_neighbor);
4932 process_fe_and_helpers(_unique_fe_lower_helper,
4936 _fe_lower);
4937
4939
4941}
4942
4944 SubdomainID sub_id,
4945 const Point & point,
4946 Real & factor,
4947 SubdomainID neighbor_sub_id);
4949 SubdomainID sub_id,
4950 const ADPoint & point,
4951 ADReal & factor,
4952 SubdomainID neighbor_sub_id);
4954 SubdomainID sub_id,
4955 const Point & point,
4956 Real & factor,
4957 SubdomainID neighbor_sub_id);
4959 SubdomainID sub_id,
4960 const ADPoint & point,
4961 ADReal & factor,
4962 SubdomainID neighbor_sub_id);
4963
4964template <>
4966Assembly::genericQPoints<false>() const
4967{
4968 return qPoints();
4969}
4970
4971template <>
4973Assembly::genericQPoints<true>() const
4974{
4975 return adQPoints();
4976}
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:2734
VariablePhiGradient _grad_phi
Definition Assembly.h:2735
VariablePhiSecond _second_phi
Definition Assembly.h:2736
Key structure for APIs manipulating global vectors/matrices.
Definition Assembly.h:836
Key structure for APIs adding/caching local element residuals/Jacobians.
Definition Assembly.h:854
VectorVariablePhiValue _phi
Definition Assembly.h:2744
VectorVariablePhiGradient _grad_phi
Definition Assembly.h:2745
VectorVariablePhiSecond _second_phi
Definition Assembly.h:2746
VectorVariablePhiCurl _curl_phi
Definition Assembly.h:2747
VectorVariablePhiDivergence _div_phi
Definition Assembly.h:2748
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:1144
std::vector< std::vector< std::vector< DenseMatrix< Number > > > > _sub_Kll
dlower/dlower
Definition Assembly.h:2676
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:2805
void cacheJacobianNonlocal(GlobalDataKey)
Takes the values that are currently in _sub_Keg and appends them to the cached values.
Definition Assembly.C:4110
SystemBase & _sys
Definition Assembly.h:2299
std::map< unsigned int, FEBase * > _holder_fe_lower_helper
helper object for transforming coordinates for lower dimensional element quadrature points
Definition Assembly.h:2547
const VariablePhiSecond & secondPhiNeighbor(const MooseVariableField< Real > &) const
Definition Assembly.h:1346
std::vector< std::pair< MooseVariableScalar *, MooseVariableFieldBase * > > _cm_sf_entry
Entries in the coupling matrix for scalar variables vs field variables.
Definition Assembly.h:2322
void addJacobian(GlobalDataKey)
Adds all local Jacobian to the global Jacobian matrices.
Definition Assembly.C:3892
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:2262
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:3419
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:2760
MooseArray< Point > _current_q_points
The current list of quadrature points.
Definition Assembly.h:2405
const std::vector< Real > * _JxW_msm
A JxW for working on mortar segement elements.
Definition Assembly.h:2566
std::vector< std::vector< std::vector< DenseMatrix< Number > > > > _sub_Kee
Definition Assembly.h:2666
std::set< FEType > _need_face_neighbor_div
Definition Assembly.h:2858
void prepareLowerD()
Prepare the Jacobians and residuals for a lower dimensional element.
Definition Assembly.C:2885
void modifyWeightsDueToXFEM(const Elem *elem)
Update the integration weights for XFEM partial elements.
Definition Assembly.C:4552
void reinitFVFace(const FaceInfo &fi)
Definition Assembly.C:1894
std::vector< std::vector< DenseVector< Number > > > _sub_Re
Definition Assembly.h:2647
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:3477
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:2880
const VariablePhiValue & phiFace() const
Definition Assembly.h:1326
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:2836
std::vector< std::unique_ptr< FEBase > > _unique_fe_lower_helper
Definition Assembly.h:2360
MooseArray< Real > _coord_neighbor
The current coordinate transformation coefficients.
Definition Assembly.h:2558
const bool _displaced
Definition Assembly.h:2302
void reinitFEFaceNeighbor(const Elem *neighbor, const std::vector< Point > &reference_points)
Definition Assembly.C:1610
void reinitFENeighbor(const Elem *neighbor, const std::vector< Point > &reference_points)
Definition Assembly.C:1669
void prepareVariableNonlocal(MooseVariableFieldBase *var)
Definition Assembly.C:2817
void prepareBlock(unsigned int ivar, unsigned jvar, const std::vector< dof_id_type > &dof_indices)
Definition Assembly.C:2937
std::vector< ADReal > _ad_dzetady_map
Definition Assembly.h:2830
libMesh::QBase * _current_qrule_face
quadrature rule used on faces
Definition Assembly.h:2509
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:2802
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:2331
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:2226
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:3256
MooseArray< VectorValue< ADReal > > _ad_q_points
Definition Assembly.h:2822
bool _current_side_volume_computed
Boolean to indicate whether current element side volumes has been computed.
Definition Assembly.h:2615
MooseArray< Real > _current_JxW_face
The current transformed jacobian weights on a face.
Definition Assembly.h:2515
const FEType _helper_type
The finite element type of the FE helper classes.
Definition Assembly.h:2345
Real _current_elem_volume
Volume of the current element.
Definition Assembly.h:2589
const VectorVariablePhiDivergence & divPhi(const MooseVariableField< RealVectorValue > &) const
Definition Assembly.h:1380
void cacheJacobianCoupledVarPair(const MooseVariableBase &ivar, const MooseVariableBase &jvar)
Caches element matrix for ivar rows and jvar columns.
Definition Assembly.C:4094
bool _building_helpers
Whether we are currently building the FE classes for the helpers.
Definition Assembly.h:2363
void addJacobianScalar(GlobalDataKey)
Add Jacobians for pairs of scalar variables into the global Jacobian matrices.
Definition Assembly.C:4475
void setVolumeQRule(libMesh::QBase *qrule, unsigned int dim)
Set the qrule to be used for volume integration.
const VariablePhiGradient & gradPhi() const
Definition Assembly.h:1318
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:3700
MooseArray< Point > _current_physical_points
This will be filled up with the physical points passed into reinitAtPhysical() if it is called....
Definition Assembly.h:2633
void addJacobianLowerD(GlobalDataKey)
Add portions of the Jacobian of LowerLower, LowerSecondary, and SecondaryLower for boundary condition...
Definition Assembly.C:4043
libMesh::QBase * _current_qrule
The current current quadrature rule being used (could be either volumetric or arbitrary - for dirac k...
Definition Assembly.h:2397
const MooseArray< Point > & qPoints() const
Returns the reference to the quadrature points.
Definition Assembly.h:249
MooseArray< VectorValue< ADReal > > _ad_normals
Definition Assembly.h:2834
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:4482
void modifyArbitraryWeights(const std::vector< Real > &weights)
Modify the weights when using the arbitrary quadrature rule.
Definition Assembly.C:4599
void computeCurrentFaceVolume()
Definition Assembly.C:1810
const VariablePhiGradient & gradPhiFace() const
Definition Assembly.h:1328
bool _need_JxW_neighbor
Flag to indicate that JxW_neighbor is needed.
Definition Assembly.h:2554
bool _user_added_fe_of_helper_type
Whether user code requested a FEType the same as our _helper_type.
Definition Assembly.h:2348
std::map< FEType, ADTemplateVariablePhiGradient< RealVectorValue > > _ad_vector_grad_phi_data
Definition Assembly.h:2768
std::map< unsigned int, std::map< FEType, FEVectorBase * > > _vector_fe
Each dimension's actual vector fe objects indexed on type.
Definition Assembly.h:2391
MooseArray< ADReal > _ad_JxW_face
Definition Assembly.h:2833
bool _calculate_xyz
Definition Assembly.h:2844
const VariablePhiValue & phi() const
Definition Assembly.h:1311
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:2585
std::map< FEType, std::unique_ptr< VectorFEShapeData > > _vector_fe_shape_data_face
Definition Assembly.h:2761
const libMesh::CouplingMatrix & _nonlocal_cm
Definition Assembly.h:2306
Real _current_neighbor_volume
Volume of the current neighbor.
Definition Assembly.h:2607
bool _need_neighbor_lower_d_elem_volume
Whether we need to compute the neighboring lower dimensional element volume.
Definition Assembly.h:2626
Moose::CoordinateSystemType _coord_type
The coordinate system.
Definition Assembly.h:2409
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:2231
std::map< FEType, FEBase * > _current_fe_neighbor
The "neighbor" fe object that matches the current elem.
Definition Assembly.h:2373
std::map< unsigned int, std::map< FEType, FEBase * > > _fe_lower
FE objects for lower dimensional elements.
Definition Assembly.h:2543
std::vector< std::vector< DenseVector< Number > > > _sub_Rn
Definition Assembly.h:2648
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:2519
const libMesh::DofMap & _dof_map
DOF map.
Definition Assembly.h:2335
const VariablePhiSecond & secondPhiFace(const MooseVariableField< Real > &) const
Definition Assembly.h:1333
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:2534
void prepareScalar()
Definition Assembly.C:2988
std::set< FEType > _need_second_derivative_neighbor
Definition Assembly.h:2853
std::vector< std::vector< std::vector< DenseMatrix< Number > > > > _sub_Ken
jacobian contributions from the element and neighbor <Tag, ivar, jvar>
Definition Assembly.h:2670
std::vector< VectorValue< ADReal > > _ad_dxyzdxi_map
AD quantities.
Definition Assembly.h:2814
const MooseArray< ADReal > & adCurvatures() const
Definition Assembly.C:4832
bool _prepared_for_p_refinement
Whether helper FEs have been prepared for p-refinement.
Definition Assembly.h:2888
std::vector< std::unique_ptr< FEBase > > _unique_fe_face_neighbor_helper
Definition Assembly.h:2358
std::vector< Point > _temp_reference_points
Temporary work data for reinitAtPhysical()
Definition Assembly.h:2811
std::vector< std::pair< MooseVariableScalar *, MooseVariableScalar * > > _cm_ss_entry
Entries in the coupling matrix for scalar variables.
Definition Assembly.h:2324
const Elem * _current_lower_d_elem
The current lower dimensional element.
Definition Assembly.h:2618
unsigned int _current_side
The current side of the selected element (valid only when working with sides)
Definition Assembly.h:2591
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:1960
std::unordered_map< SubdomainID, std::vector< QRules > > _qrules
Holds quadrature rules for each dimension.
Definition Assembly.h:2446
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:1829
std::map< FEType, FEVectorBase * > _current_vector_fe
The "volume" vector fe object that matches the current elem.
Definition Assembly.h:2378
std::vector< VectorValue< ADReal > > _ad_dxyzdzeta_map
Definition Assembly.h:2816
std::unique_ptr< FEBase > _fe_msm
A FE object for working on mortar segement elements.
Definition Assembly.h:2568
std::vector< ADReal > _ad_detadx_map
Definition Assembly.h:2826
void addJacobianNonlocal(GlobalDataKey)
Adds non-local Jacobian to the global Jacobian matrices.
Definition Assembly.C:3905
const VariablePhiGradient & gradPhiNeighbor(const MooseVariableField< Real > &) const
Definition Assembly.h:1342
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:3374
void prepareNeighbor()
Definition Assembly.C:2847
const Elem *const & elem() const
Return the current element.
Definition Assembly.h:405
std::map< FEType, FEVectorBase * > _current_vector_fe_face_neighbor
The "neighbor face" vector fe object that matches the current elem.
Definition Assembly.h:2384
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:2455
const Node * _current_neighbor_node
The current neighboring node we are working with.
Definition Assembly.h:2611
std::vector< ADReal > _ad_dxidx_map
Definition Assembly.h:2823
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:2603
std::vector< ADReal > _ad_dxidz_map
Definition Assembly.h:2825
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:3491
std::map< unsigned int, std::map< FEType, FEVectorBase * > > _vector_fe_neighbor
Definition Assembly.h:2535
std::vector< std::vector< std::vector< DenseMatrix< Number > > > > _sub_Kle
dlower/dsecondary (or dlower/delement)
Definition Assembly.h:2678
MooseArray< ADReal > _ad_JxW
Definition Assembly.h:2821
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:3459
void copyFaceShapes(MooseVariableField< T > &v)
Definition Assembly.C:3075
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:3352
DenseVector< Number > _tmp_Re
auxiliary vector for scaling residuals (optimization to avoid expensive construction/destruction)
Definition Assembly.h:2653
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:3324
bool _calculate_ad_coord
Whether to calculate coord with AD.
Definition Assembly.h:2850
const libMesh::CouplingMatrix * _cm
Coupling matrices.
Definition Assembly.h:2305
VectorVariablePhiCurl _vector_curl_phi_face
Definition Assembly.h:2716
MooseArray< Point > _current_q_points_face
The current quadrature points on a face.
Definition Assembly.h:2513
std::map< FEType, std::unique_ptr< VectorFEShapeData > > _vector_fe_shape_data_neighbor
Definition Assembly.h:2762
void cacheJacobianNeighbor(GlobalDataKey)
Takes the values that are currently in the neighbor Dense Matrices and appends them to the cached val...
Definition Assembly.C:4132
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:3196
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:2327
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:4843
std::vector< std::vector< std::vector< DenseMatrix< Number > > > > _sub_Knn
jacobian contributions from the neighbor <Tag, ivar, jvar>
Definition Assembly.h:2674
const MooseArray< ADPoint > & adQPoints() const
Definition Assembly.h:386
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:2680
libMesh::QBase * _current_qrule_neighbor
quadrature rule used on neighbors
Definition Assembly.h:2550
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:2333
Real elementVolume(const Elem *elem) const
On-demand computation of volume element accounting for RZ/RSpherical.
Definition Assembly.C:3792
std::map< unsigned int, std::map< FEType, FEBase * > > _fe_neighbor
types of finite elements
Definition Assembly.h:2533
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:1355
const unsigned int & side() const
Returns the current side.
Definition Assembly.h:437
std::vector< VectorValue< ADReal > > _ad_d2xyzdeta2_map
Definition Assembly.h:2819
MooseArray< std::vector< Point > > _current_tangents
The current tangent vectors at the quadrature points.
Definition Assembly.h:2521
std::vector< std::unique_ptr< FEBase > > _unique_fe_face_helper
Definition Assembly.h:2357
std::map< FEType, FEBase * > _current_fe
The "volume" fe object that matches the current elem.
Definition Assembly.h:2369
const VectorVariablePhiCurl & curlPhi(const MooseVariableField< RealVectorValue > &) const
Definition Assembly.h:1376
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:2962
std::map< FEType, std::unique_ptr< FEShapeData > > _fe_shape_data_lower
Definition Assembly.h:2756
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:3756
std::vector< VectorValue< ADReal > > _ad_d2xyzdxideta_map
Definition Assembly.h:2818
std::vector< std::pair< unsigned int, unsigned short > > _disp_numbers_and_directions
Container of displacement numbers and directions.
Definition Assembly.h:2842
std::map< unsigned int, std::map< FEType, FEVectorBase * > > _vector_fe_face
types of vector finite elements
Definition Assembly.h:2503
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:4460
std::map< unsigned int, std::map< FEType, FEBase * > > _fe
Each dimension's actual fe objects indexed on type.
Definition Assembly.h:2389
std::set< FEType > _need_curl
Definition Assembly.h:2854
const VariablePhiSecond & secondPhiFaceNeighbor(const MooseVariableField< Real > &) const
Definition Assembly.h:1359
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:2356
unsigned int numExtraElemIntegers() const
Number of extra element integers Assembly tracked.
Definition Assembly.h:364
std::vector< std::pair< MooseVariableFieldBase *, MooseVariableFieldBase * > > _cm_ff_entry
Entries in the coupling matrix for field variables.
Definition Assembly.h:2318
std::vector< std::pair< MooseVariableFieldBase *, MooseVariableFieldBase * > > _cm_nonlocal_entry
Entries in the coupling matrix for field variables for nonlocal calculations.
Definition Assembly.h:2326
bool _current_elem_volume_computed
Boolean to indicate whether current element volumes has been computed.
Definition Assembly.h:2613
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:3550
std::map< unsigned int, std::map< FEType, FEBase * > > _fe_face
types of finite elements
Definition Assembly.h:2501
std::vector< ADReal > _ad_jac
Definition Assembly.h:2820
void addJacobianNeighbor(GlobalDataKey)
Add ElementNeighbor, NeighborElement, and NeighborNeighbor portions of the Jacobian for compute objec...
Definition Assembly.C:3927
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:3825
const std::vector< VectorTag > & _residual_vector_tags
The residual vector tags that Assembly could possibly contribute to.
Definition Assembly.h:2782
const Elem * _current_neighbor_elem
The current neighbor "element".
Definition Assembly.h:2597
VectorVariablePhiDivergence _vector_div_phi_face
Definition Assembly.h:2717
bool _user_added_fe_face_neighbor_of_helper_type
Definition Assembly.h:2350
std::vector< ADReal > _ad_dzetadx_map
Definition Assembly.h:2829
std::vector< dof_id_type > _column_indices
Definition Assembly.h:2885
const VariablePhiValue & phiNeighbor(const MooseVariableField< Real > &) const
Definition Assembly.h:1338
MooseMesh & _mesh
Definition Assembly.h:2339
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:3155
std::vector< ADReal > _ad_detadz_map
Definition Assembly.h:2828
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:1133
std::vector< dof_id_type > _temp_dof_indices
Temporary work vector to keep from reallocating it.
Definition Assembly.h:2808
std::vector< std::vector< std::vector< unsigned char > > > _jacobian_block_used
Flag that indicates if the jacobian block was used.
Definition Assembly.h:2328
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:2721
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:2280
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:3301
std::vector< VectorValue< ADReal > > _ad_dxyzdeta_map
Definition Assembly.h:2815
const Node * _current_node
The current node we are working with.
Definition Assembly.h:2609
std::map< FEType, ADTemplateVariablePhiGradient< RealVectorValue > > _ad_vector_grad_phi_data_face
Definition Assembly.h:2771
void cacheJacobianMortar(GlobalDataKey)
Cache all portions of the Jacobian, e.g.
Definition Assembly.C:4170
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:2337
bool _calculate_face_xyz
Definition Assembly.h:2845
std::vector< std::vector< std::vector< DenseMatrix< Number > > > > _sub_Kel
dsecondary/dlower (or delement/dlower)
Definition Assembly.h:2682
std::map< FEType, std::unique_ptr< VectorFEShapeData > > _vector_fe_shape_data_dual_lower
Definition Assembly.h:2765
MooseArray< Point > _current_normals
The current Normal vectors at the quadrature points.
Definition Assembly.h:2517
void cacheJacobian(GlobalDataKey)
Takes the values that are currently in _sub_Kee and appends them to the cached values.
Definition Assembly.C:4080
bool _calculate_curvatures
Definition Assembly.h:2846
std::vector< std::vector< Real > > _cached_residual_values
Values cached by calling cacheResidual() (the first vector is for TIME vs NONTIME)
Definition Assembly.h:2785
const Node *const & node() const
Returns the reference to the node.
Definition Assembly.h:536
std::vector< std::vector< dof_id_type > > _cached_jacobian_cols
Column where the corresponding cached value should go.
Definition Assembly.h:2797
ArbitraryQuadrature * _current_qrule_arbitrary
The current arbitrary quadrature rule used within the element interior.
Definition Assembly.h:2401
void computeADFace(const Elem &elem, const unsigned int side)
compute AD things on an element face
Definition Assembly.C:2148
libMesh::ElemSideBuilder _current_side_elem_builder
In place side element builder for _current_side_elem.
Definition Assembly.h:2864
void computeFaceMap(const Elem &elem, const unsigned int side, const std::vector< Real > &qw)
Definition Assembly.C:1385
std::map< unsigned int, std::map< FEType, FEVectorBase * > > _vector_fe_lower
Vector FE objects for lower dimensional elements.
Definition Assembly.h:2545
void setCachedJacobian(GlobalDataKey)
Sets previously-cached Jacobian values via SparseMatrix::set() calls.
Definition Assembly.C:4511
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:1954
void preparePRefinement()
Prepare helper FEs for p-refinement.
Definition Assembly.C:4876
std::vector< std::vector< DenseVector< Number > > > _sub_Rl
residual contributions for each variable from the lower dimensional element
Definition Assembly.h:2650
std::map< FEType, FEBase * > _current_fe_face
The "face" fe object that matches the current elem.
Definition Assembly.h:2371
void addCachedJacobian(GlobalDataKey)
Adds the values that have been cached by calling cacheJacobian() and or cacheJacobianNeighbor() to th...
Definition Assembly.C:3835
void reinit(const Elem *elem)
Reinitialize objects (JxW, q_points, ...) for an elements.
Definition Assembly.C:1856
std::vector< dof_id_type > _neighbor_extra_elem_ids
Extra element IDs of neighbor.
Definition Assembly.h:2526
libMesh::ElemSideBuilder _compute_face_map_side_elem_builder
In place side element builder for computeFaceMap()
Definition Assembly.h:2868
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:3427
void modifyFaceWeightsDueToXFEM(const Elem *elem, unsigned int side=0)
Update the face integration weights for XFEM partial elements.
Definition Assembly.C:4572
unsigned int _max_cached_residuals
Definition Assembly.h:2790
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:2366
std::map< unsigned int, FEBase * > _holder_fe_face_neighbor_helper
Definition Assembly.h:2540
std::set< FEType > _need_neighbor_div
Definition Assembly.h:2857
SubdomainID _current_neighbor_subdomain_id
The current neighbor subdomain ID.
Definition Assembly.h:2599
std::map< FEType, FEVectorBase * > _current_vector_fe_face
The "face" vector fe object that matches the current elem.
Definition Assembly.h:2380
bool _custom_mortar_qrule
Flag specifying whether a custom quadrature rule has been specified for mortar segment mesh.
Definition Assembly.h:2575
libMesh::ElemSideBuilder _current_neighbor_side_elem_builder
In place side element builder for _current_neighbor_side_elem.
Definition Assembly.h:2866
std::vector< std::vector< dof_id_type > > _cached_jacobian_rows
Row where the corresponding cached value should go.
Definition Assembly.h:2795
std::map< FEType, ADTemplateVariablePhiGradient< Real > > _ad_grad_phi_data_face
Definition Assembly.h:2769
MooseArray< ADReal > _ad_coord
The AD version of the current coordinate transformation coefficients.
Definition Assembly.h:2413
std::vector< std::unique_ptr< FEBase > > _unique_fe_neighbor_helper
Definition Assembly.h:2359
std::map< FEType, FEBase * > _current_fe_face_neighbor
The "neighbor face" fe object that matches the current elem.
Definition Assembly.h:2375
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:2754
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:2244
bool _need_lower_d_elem_volume
Whether we need to compute the lower dimensional element volume.
Definition Assembly.h:2622
std::map< FEType, std::unique_ptr< VectorFEShapeData > > _vector_fe_shape_data_face_neighbor
Definition Assembly.h:2763
QRules & qrules(unsigned int dim)
Definition Assembly.h:2477
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:2309
bool _need_neighbor_elem_volume
true is apps need to compute neighbor element volume
Definition Assembly.h:2605
std::vector< std::vector< std::vector< DenseMatrix< Number > > > > _sub_Keg
Definition Assembly.h:2667
SubProblem & _subproblem
Definition Assembly.h:2300
std::set< FEType > _need_face_div
Definition Assembly.h:2856
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:2031
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:3877
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:2056
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:4318
std::vector< std::pair< MooseVariableFieldBase *, MooseVariableScalar * > > _cm_fs_entry
Entries in the coupling matrix for field variables vs scalar variables.
Definition Assembly.h:2320
Real _current_side_volume
Volume of the current side element.
Definition Assembly.h:2595
void copyShapes(MooseVariableField< T > &v)
Definition Assembly.C:3038
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:3286
Real _current_neighbor_lower_d_elem_volume
The current neighboring lower dimensional element volume.
Definition Assembly.h:2628
MooseArray< Real > _coord
The current coordinate transformation coefficients.
Definition Assembly.h:2411
void prepare()
Definition Assembly.C:2754
std::map< FEType, std::unique_ptr< VectorFEShapeData > > _vector_fe_shape_data_lower
Definition Assembly.h:2764
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:2403
const MooseArray< Real > & JxW() const
Returns the reference to the transformed jacobian weights.
Definition Assembly.h:267
std::vector< std::vector< std::vector< unsigned char > > > _jacobian_block_nonlocal_used
Definition Assembly.h:2329
void prepareResidual()
Sizes and zeroes the residual for the current element.
Definition Assembly.C:2745
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:2351
void reinitFEFace(const Elem *elem, unsigned int side)
Just an internal helper function to reinit the face FE objects.
Definition Assembly.C:1305
std::map< unsigned int, FEBase * > _holder_fe_neighbor_helper
Each dimension's helper objects.
Definition Assembly.h:2539
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:4250
void reinitNeighborLowerDElem(const Elem *elem)
reinitialize a neighboring lower dimensional element
Definition Assembly.C:2420
void initNonlocalCoupling()
Create pair of variables requiring nonlocal jacobian contributions.
Definition Assembly.C:2686
MooseArray< ADReal > _ad_curvatures
Definition Assembly.h:2837
libMesh::QBase * _qrule_msm
A qrule object for working on mortar segement elements.
Definition Assembly.h:2573
unsigned int _max_cached_jacobians
Definition Assembly.h:2799
const Elem * _current_side_elem
The current "element" making up the side we are currently on.
Definition Assembly.h:2593
std::set< FEType > _need_div
Definition Assembly.h:2855
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:2788
std::map< FEType, ADTemplateVariablePhiGradient< Real > > _ad_grad_phi_data
Definition Assembly.h:2767
std::map< unsigned int, FEBase * > _holder_fe_helper
Each dimension's helper objects.
Definition Assembly.h:2393
MooseArray< Point > _current_q_points_face_neighbor
The current quadrature points on the neighbor face.
Definition Assembly.h:2552
std::vector< ADReal > _ad_dzetadz_map
Definition Assembly.h:2831
std::vector< ADReal > _ad_detady_map
Definition Assembly.h:2827
std::vector< std::vector< std::vector< DenseMatrix< Number > > > > _sub_Kne
jacobian contributions from the neighbor and element <Tag, ivar, jvar>
Definition Assembly.h:2672
const NumericVector< Real > * _scaling_vector
The map from global index to variable scaling factor.
Definition Assembly.h:2861
MooseArray< Real > _current_JxW
The current list of transformed jacobian weights.
Definition Assembly.h:2407
void zeroCachedJacobian(GlobalDataKey)
Zero out previously-cached Jacobian rows.
Definition Assembly.C:4531
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:2620
libMesh::QBase * _current_qrule_lower
quadrature rule used on lower dimensional elements.
Definition Assembly.h:2579
const VariablePhiValue & phiFaceNeighbor(const MooseVariableField< Real > &) const
Definition Assembly.h:1351
void clearCachedResiduals(GlobalDataKey)
Clears all of the residuals in _cached_residual_rows and _cached_residual_values.
Definition Assembly.C:3520
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:4376
void computeCurrentElemVolume()
Definition Assembly.C:1791
unsigned int _current_neighbor_side
The current side of the selected neighboring element (valid only when working with sides)
Definition Assembly.h:2601
std::vector< std::vector< std::vector< DenseMatrix< Number > > > > _sub_Knl
dprimary/dlower (or dneighbor/dlower)
Definition Assembly.h:2684
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:3396
MooseArray< VectorValue< ADReal > > _ad_q_points_face
Definition Assembly.h:2835
void reinitMortarElem(const Elem *elem)
reinitialize a mortar segment mesh element in order to get a proper JxW
Definition Assembly.C:2441
std::vector< VectorValue< ADReal > > _ad_d2xyzdxi2_map
Definition Assembly.h:2817
const Elem * _current_elem
The current "element" we are currently on.
Definition Assembly.h:2583
std::map< unsigned int, FEBase * > _holder_fe_face_helper
Each dimension's helper objects.
Definition Assembly.h:2505
std::map< unsigned int, std::map< FEType, FEVectorBase * > > _vector_fe_face_neighbor
Definition Assembly.h:2536
void reinitNeighbor(const Elem *neighbor, const std::vector< Point > &reference_points)
Reinitializes the neighbor side using reference coordinates.
Definition Assembly.C:1724
const Elem * _msm_elem
Definition Assembly.h:2870
libMesh::QBase * _current_qrule_volume
The current volumetric quadrature for the element.
Definition Assembly.h:2399
void addJacobianNeighborLowerD(GlobalDataKey)
Add all portions of the Jacobian except PrimaryPrimary, e.g.
Definition Assembly.C:3965
std::map< FEType, FEVectorBase * > _current_vector_fe_neighbor
The "neighbor" vector fe object that matches the current elem.
Definition Assembly.h:2382
MooseArray< Real > _coord_msm
The coordinate transformation coefficients evaluated on the quadrature points of the mortar segment m...
Definition Assembly.h:2561
Real _current_lower_d_elem_volume
The current lower dimensional element volume.
Definition Assembly.h:2624
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:3577
std::vector< std::vector< Real > > _cached_jacobian_values
Values cached by calling cacheJacobian()
Definition Assembly.h:2793
bool _user_added_fe_face_of_helper_type
Definition Assembly.h:2349
void clearCachedJacobian()
Clear any currently cached jacobians.
Definition Assembly.C:4541
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:2757
std::map< FEType, std::unique_ptr< FEShapeData > > _fe_shape_data
Shape function values, gradients, second derivatives for each FE type.
Definition Assembly.h:2752
std::vector< Point > _current_neighbor_ref_points
The current reference points on the neighbor element.
Definition Assembly.h:2891
void copyNeighborShapes(MooseVariableField< T > &v)
Definition Assembly.C:3112
std::set< FEType > _need_second_derivative
Definition Assembly.h:2852
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:2885
std::vector< dof_id_type > _extra_elem_ids
Extra element IDs.
Definition Assembly.h:2524
void hasScalingVector()
signals this object that a vector containing variable scaling factors should be used when doing resid...
Definition Assembly.C:4593
void addCachedResiduals(GlobalDataKey, const std::vector< VectorTag > &tags)
Pushes all cached residuals to the global residual vectors associated with each tag.
Definition Assembly.C:3505
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:2755
bool _user_added_fe_lower_of_helper_type
Definition Assembly.h:2352
MooseArray< Real > _current_JxW_neighbor
The current transformed jacobian weights on a neighbor's face.
Definition Assembly.h:2556
std::vector< ADReal > _ad_dxidy_map
Definition Assembly.h:2824
unsigned int _mesh_dimension
Definition Assembly.h:2341
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:3568
std::map< FEType, std::unique_ptr< FEShapeData > > _fe_shape_data_face
Definition Assembly.h:2753
const VariablePhiSecond & secondPhi() const
Definition Assembly.h:1320
const Elem *const & neighbor() const
Return the neighbor element.
Definition Assembly.h:461
void prepareOffDiagScalar()
Definition Assembly.C:3012
void prepareNonlocal()
Definition Assembly.C:2761
void prepareVariable(MooseVariableFieldBase *var)
Used for preparing the dense residual and jacobian blocks for one particular variable.
Definition Assembly.C:2787
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:150
virtual unsigned int numMatrixTags() const
The total number of tags.
Definition SubProblem.h:248
virtual void haveADObjects(bool have_ad_objects)
Method for setting whether we have any ad objects.
Definition SubProblem.h:775
virtual bool checkNonlocalCouplingRequirement() const =0
Moose::CoordinateSystemType getCoordSystem(SubdomainID sid) const
Base class for a system (of equations)
Definition SystemBase.h:87
virtual libMesh::SparseMatrix< Number > & getMatrix(TagID tag)
Get a raw SparseMatrix.
bool hasVector(const std::string &tag_name) const
Check if the named vector exists in the system.
Definition SystemBase.C:921
virtual unsigned int nVariables() const
Get the number of variables in this system.
Definition SystemBase.C:888
MooseVariableFieldBase & getVariable(THREAD_ID tid, const std::string &var_name) const
Gets a reference to a variable of with specified name.
Definition SystemBase.C:89
unsigned int number() const
Gets the number of this system.
virtual bool isScalarVariable(unsigned int var_name) const
Definition SystemBase.C:882
virtual NumericVector< Number > & getVector(const std::string &name)
Get a raw NumericVector by name.
Definition SystemBase.C:930
const std::vector< MooseVariableFieldBase * > & getVariables(THREAD_ID tid)
Definition SystemBase.h:779
MooseVariableField< T > & getActualFieldVariable(THREAD_ID tid, const std::string &var_name)
Returns a field variable pointer - this includes finite volume variables.
Definition SystemBase.C:117
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:144
virtual bool hasMatrix(TagID tag) const
Check if the tagged matrix exists in the system.
Definition SystemBase.h:388
const std::vector< MooseVariableScalar * > & getScalarVariables(THREAD_ID tid)
Definition SystemBase.h:786
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:2418
std::unique_ptr< ArbitraryQuadrature > arbitrary_vol
volume/elem (meshdim) custom points quadrature rule
Definition Assembly.h:2435
std::unique_ptr< ArbitraryQuadrature > neighbor
area/face (meshdim-1) custom points quadrature rule for DG
Definition Assembly.h:2439
std::unique_ptr< libMesh::QBase > vol
volume/elem (meshdim) quadrature rule
Definition Assembly.h:2429
std::unique_ptr< ArbitraryQuadrature > arbitrary_face
area/face (meshdim-1) custom points quadrature rule
Definition Assembly.h:2437
std::unique_ptr< libMesh::QBase > face
area/face (meshdim-1) quadrature rule
Definition Assembly.h:2431