19 #include "libmesh/dof_map.h"
22 #include "libmesh/boundary_info.h"
23 #include "libmesh/dense_matrix.h"
24 #include "libmesh/dense_vector.h"
25 #include "libmesh/dirichlet_boundaries.h"
26 #include "libmesh/elem.h"
27 #include "libmesh/elem_range.h"
28 #include "libmesh/fe_base.h"
29 #include "libmesh/fe_interface.h"
30 #include "libmesh/fe_type.h"
31 #include "libmesh/function_base.h"
32 #include "libmesh/int_range.h"
33 #include "libmesh/libmesh_logging.h"
34 #include "libmesh/linear_solver.h"
35 #include "libmesh/mesh_base.h"
36 #include "libmesh/null_output_iterator.h"
37 #include "libmesh/mesh_tools.h"
38 #include "libmesh/nonlinear_implicit_system.h"
39 #include "libmesh/numeric_vector.h"
40 #include "libmesh/parallel_algebra.h"
41 #include "libmesh/parallel_elem.h"
42 #include "libmesh/parallel_node.h"
43 #include "libmesh/periodic_boundaries.h"
44 #include "libmesh/periodic_boundary.h"
45 #include "libmesh/periodic_boundary_base.h"
46 #include "libmesh/point_locator_base.h"
47 #include "libmesh/quadrature.h"
48 #include "libmesh/raw_accessor.h"
49 #include "libmesh/sparse_matrix.h"
50 #include "libmesh/system.h"
51 #include "libmesh/tensor_tools.h"
52 #include "libmesh/threads.h"
53 #include "libmesh/enum_to_string.h"
54 #include "libmesh/coupling_matrix.h"
57 #include "timpi/parallel_implementation.h"
58 #include "timpi/parallel_sync.h"
68 #include <unordered_set>
73 using namespace libMesh;
75 class ComputeConstraints
80 #ifdef LIBMESH_ENABLE_PERIODIC
83 const MeshBase & mesh,
84 const unsigned int variable_number) :
85 _constraints(constraints),
87 #ifdef LIBMESH_ENABLE_PERIODIC
88 _periodic_boundaries(periodic_boundaries),
91 _variable_number(variable_number)
94 void operator()(
const ConstElemRange & range)
const
96 const Variable & var_description = _dof_map.variable(_variable_number);
98 #ifdef LIBMESH_ENABLE_PERIODIC
99 std::unique_ptr<PointLocatorBase> point_locator;
100 const bool have_periodic_boundaries =
101 !_periodic_boundaries.empty();
102 if (have_periodic_boundaries && !range.empty())
103 point_locator = _mesh.sub_point_locator();
106 for (
const auto & elem : range)
109 #ifdef LIBMESH_ENABLE_AMR
110 FEInterface::compute_constraints (_constraints,
115 #ifdef LIBMESH_ENABLE_PERIODIC
119 if (have_periodic_boundaries)
120 FEInterface::compute_periodic_constraints (_constraints,
122 _periodic_boundaries,
134 #ifdef LIBMESH_ENABLE_PERIODIC
137 const MeshBase & _mesh;
138 const unsigned int _variable_number;
143 #ifdef LIBMESH_ENABLE_NODE_CONSTRAINTS
144 class ComputeNodeConstraints
148 #ifdef LIBMESH_ENABLE_PERIODIC
151 const MeshBase & mesh) :
152 _node_constraints(node_constraints),
153 #ifdef LIBMESH_ENABLE_PERIODIC
154 _periodic_boundaries(periodic_boundaries),
159 void operator()(
const ConstElemRange & range)
const
161 #ifdef LIBMESH_ENABLE_PERIODIC
162 std::unique_ptr<PointLocatorBase> point_locator;
163 bool have_periodic_boundaries = !_periodic_boundaries.empty();
164 if (have_periodic_boundaries && !range.empty())
165 point_locator = _mesh.sub_point_locator();
168 for (
const auto & elem : range)
170 #ifdef LIBMESH_ENABLE_AMR
171 FEBase::compute_node_constraints (_node_constraints, elem);
173 #ifdef LIBMESH_ENABLE_PERIODIC
177 if (have_periodic_boundaries)
178 FEBase::compute_periodic_node_constraints (_node_constraints,
179 _periodic_boundaries,
189 #ifdef LIBMESH_ENABLE_PERIODIC
192 const MeshBase & _mesh;
194 #endif // LIBMESH_ENABLE_NODE_CONSTRAINTS
197 #ifdef LIBMESH_ENABLE_DIRICHLET
208 AddConstraint(
DofMap & dof_map_in) : dof_map(dof_map_in) {}
212 const Number constraint_rhs)
const = 0;
215 class AddPrimalConstraint :
public AddConstraint
218 AddPrimalConstraint(
DofMap & dof_map_in) : AddConstraint(dof_map_in) {}
222 const Number constraint_rhs)
const
224 if (!dof_map.is_constrained_dof(dof_number))
225 dof_map.add_constraint_row (dof_number, constraint_row,
226 constraint_rhs,
true);
230 class AddAdjointConstraint :
public AddConstraint
233 const unsigned int qoi_index;
236 AddAdjointConstraint(
DofMap & dof_map_in,
unsigned int qoi_index_in)
237 : AddConstraint(dof_map_in), qoi_index(qoi_index_in) {}
241 const Number constraint_rhs)
const
243 dof_map.add_adjoint_constraint_row
244 (qoi_index, dof_number, constraint_row, constraint_rhs,
256 class ConstrainDirichlet
260 const MeshBase & mesh;
264 const AddConstraint & add_fn;
268 const FEMContext * c,
278 return std::numeric_limits<Real>::quiet_NaN();
285 const FEMContext * c,
295 return std::numeric_limits<Number>::quiet_NaN();
308 struct SingleElemBoundaryInfo
310 SingleElemBoundaryInfo(
const BoundaryInfo & bi,
311 const std::map<
boundary_id_type, std::set<std::pair<unsigned int, DirichletBoundary *>>> & ordered_map_in) :
313 boundary_id_to_ordered_dirichlet_boundaries(ordered_map_in),
320 const BoundaryInfo & boundary_info;
321 const std::map<boundary_id_type, std::set<std::pair<unsigned int, DirichletBoundary *>>> & boundary_id_to_ordered_dirichlet_boundaries;
324 unsigned short n_sides;
325 unsigned short n_edges;
326 unsigned short n_nodes;
331 std::map<const DirichletBoundary *, std::vector<bool>> is_boundary_node_map;
332 std::map<const DirichletBoundary *, std::vector<bool>> is_boundary_side_map;
333 std::map<const DirichletBoundary *, std::vector<bool>> is_boundary_edge_map;
334 std::map<const DirichletBoundary *, std::vector<bool>> is_boundary_shellface_map;
336 std::map<const DirichletBoundary *, std::vector<bool>> is_boundary_nodeset_map;
340 std::set<std::pair<unsigned int, DirichletBoundary *>> ordered_dbs;
349 bool reinit(
const Elem * elem_in)
353 n_sides = elem->n_sides();
354 n_edges = elem->n_edges();
355 n_nodes = elem->n_nodes();
358 is_boundary_node_map.clear();
359 is_boundary_side_map.clear();
360 is_boundary_edge_map.clear();
361 is_boundary_shellface_map.clear();
362 is_boundary_nodeset_map.clear();
369 bool has_dirichlet_constraint =
false;
373 std::vector<boundary_id_type> ids_vec;
375 for (
unsigned char s = 0; s != n_sides; ++s)
378 boundary_info.boundary_ids (elem, s, ids_vec);
380 bool do_this_side =
false;
381 for (
const auto & bc_id : ids_vec)
383 auto it = boundary_id_to_ordered_dirichlet_boundaries.find(bc_id);
384 if (it != boundary_id_to_ordered_dirichlet_boundaries.end())
389 ordered_dbs.insert(it->second.begin(), it->second.end());
392 for (
const auto & db_pair : it->second)
399 auto pr = is_boundary_side_map.emplace(db_pair.second, std::vector<bool>(n_sides,
false));
400 pr.first->second[s] =
true;
408 has_dirichlet_constraint =
true;
411 for (
unsigned int n = 0; n != n_nodes; ++n)
412 if (elem->is_node_on_side(n,s))
419 for (
const auto & db_pair : ordered_dbs)
423 auto side_it = is_boundary_side_map.find(db_pair.second);
424 if (side_it != is_boundary_side_map.end() && side_it->second[s])
426 auto pr = is_boundary_node_map.emplace(db_pair.second, std::vector<bool>(n_nodes,
false));
427 pr.first->second[n] =
true;
433 for (
unsigned int e = 0; e != n_edges; ++e)
434 if (elem->is_edge_on_side(e,s))
441 for (
const auto & db_pair : ordered_dbs)
445 auto side_it = is_boundary_side_map.find(db_pair.second);
446 if (side_it != is_boundary_side_map.end() && side_it->second[s])
448 auto pr = is_boundary_edge_map.emplace(db_pair.second, std::vector<bool>(n_edges,
false));
449 pr.first->second[e] =
true;
457 for (
unsigned int n=0; n != n_nodes; ++n)
459 boundary_info.boundary_ids (elem->node_ptr(n), ids_vec);
461 for (
const auto & bc_id : ids_vec)
463 auto it = boundary_id_to_ordered_dirichlet_boundaries.find(bc_id);
464 if (it != boundary_id_to_ordered_dirichlet_boundaries.end())
467 ordered_dbs.insert(it->second.begin(), it->second.end());
470 for (
const auto & db_pair : it->second)
472 auto pr = is_boundary_node_map.emplace(db_pair.second, std::vector<bool>(n_nodes,
false));
473 pr.first->second[n] =
true;
475 auto pr2 = is_boundary_nodeset_map.emplace(db_pair.second, std::vector<bool>(n_nodes,
false));
476 pr2.first->second[n] =
true;
479 has_dirichlet_constraint =
true;
486 for (
unsigned short e=0; e != n_edges; ++e)
488 boundary_info.edge_boundary_ids (elem, e, ids_vec);
490 bool do_this_side =
false;
491 for (
const auto & bc_id : ids_vec)
493 auto it = boundary_id_to_ordered_dirichlet_boundaries.find(bc_id);
494 if (it != boundary_id_to_ordered_dirichlet_boundaries.end())
499 ordered_dbs.insert(it->second.begin(), it->second.end());
502 for (
const auto & db_pair : it->second)
504 auto pr = is_boundary_edge_map.emplace(db_pair.second, std::vector<bool>(n_edges,
false));
505 pr.first->second[e] =
true;
513 has_dirichlet_constraint =
true;
516 for (
unsigned int n = 0; n != n_nodes; ++n)
517 if (elem->is_node_on_edge(n,e))
524 for (
const auto & db_pair : ordered_dbs)
528 auto edge_it = is_boundary_edge_map.find(db_pair.second);
529 if (edge_it != is_boundary_edge_map.end() && edge_it->second[e])
531 auto pr = is_boundary_node_map.emplace(db_pair.second, std::vector<bool>(n_nodes,
false));
532 pr.first->second[n] =
true;
540 for (
unsigned short shellface=0; shellface != 2; ++shellface)
542 boundary_info.shellface_boundary_ids (elem, shellface, ids_vec);
543 bool do_this_shellface =
false;
545 for (
const auto & bc_id : ids_vec)
547 auto it = boundary_id_to_ordered_dirichlet_boundaries.find(bc_id);
548 if (it != boundary_id_to_ordered_dirichlet_boundaries.end())
550 has_dirichlet_constraint =
true;
551 do_this_shellface =
true;
554 ordered_dbs.insert(it->second.begin(), it->second.end());
557 for (
const auto & db_pair : it->second)
559 auto pr = is_boundary_shellface_map.emplace(db_pair.second, std::vector<bool>(2,
false));
560 pr.first->second[shellface] =
true;
565 if (do_this_shellface)
568 for (
unsigned int n = 0; n != n_nodes; ++n)
569 for (
const auto & db_pair : ordered_dbs)
573 auto side_it = is_boundary_shellface_map.find(db_pair.second);
574 if (side_it != is_boundary_shellface_map.end() && side_it->second[shellface])
576 auto pr = is_boundary_node_map.emplace(db_pair.second, std::vector<bool>(n_nodes,
false));
577 pr.first->second[n] =
true;
583 return has_dirichlet_constraint;
590 template<
typename OutputType>
591 void apply_lagrange_dirichlet_impl(
const SingleElemBoundaryInfo & sebi,
594 FEMContext & fem_context)
const
597 const Elem * elem = sebi.elem;
607 const System * f_system = dirichlet.
f_system;
610 libmesh_assert(f || f_fem);
611 libmesh_assert(!(f && f_fem));
614 libmesh_assert(!(f && f_system));
615 libmesh_assert(!(f_fem && !f_system));
622 const FEType & fe_type = variable.
type();
625 unsigned int n_vec_dim = FEInterface::n_vec_dim(mesh, fe_type);
627 const unsigned int var_component =
631 const unsigned int var = variable.
number();
637 std::unique_ptr<FEMContext> context;
640 libmesh_assert(f_system);
641 if (f_system->current_local_solution->initialized())
643 context = std::make_unique<FEMContext>
650 if (f_system && context.get())
651 context->pre_fe_reinit(*f_system, elem);
654 fem_context.pre_fe_reinit(fem_context.get_system(), elem);
657 const std::vector<dof_id_type> & dof_indices =
658 fem_context.get_dof_indices(var);
661 const unsigned int n_dofs =
662 cast_int<unsigned int>(dof_indices.size());
665 std::vector<char> dof_is_fixed(n_dofs,
false);
677 unsigned int current_dof = 0;
678 for (
unsigned int n=0; n!= sebi.n_nodes; ++n)
683 const unsigned int nc =
684 FEInterface::n_dofs_at_node (fe_type, elem, n);
693 auto is_boundary_node_it = sebi.is_boundary_node_map.find(&dirichlet);
694 const bool is_boundary_node =
695 (is_boundary_node_it != sebi.is_boundary_node_map.end() &&
696 is_boundary_node_it->second[n]);
699 auto is_boundary_nodeset_it = sebi.is_boundary_nodeset_map.find(&dirichlet);
700 const bool is_boundary_nodeset =
701 (is_boundary_nodeset_it != sebi.is_boundary_nodeset_map.end() &&
702 is_boundary_nodeset_it->second[n]);
705 if ( !(is_boundary_node || is_boundary_nodeset) )
712 libmesh_assert_equal_to (nc, n_vec_dim);
713 for (
unsigned int c = 0; c < n_vec_dim; c++)
716 f_component(f, f_fem, context.get(), var_component+c,
717 elem->point(n), time);
718 dof_is_fixed[current_dof+c] =
true;
720 current_dof += n_vec_dim;
725 Threads::spin_mutex::scoped_lock lock(Threads::spin_mtx);
727 for (
unsigned int i = 0; i < n_dofs; i++)
731 add_fn (dof_indices[i], empty_row, Ue(i));
739 template<
typename OutputType>
740 void apply_dirichlet_impl(
const SingleElemBoundaryInfo & sebi,
743 FEMContext & fem_context)
const
746 const Elem * elem = sebi.elem;
753 typedef OutputType OutputShape;
766 const System * f_system = dirichlet.
f_system;
769 libmesh_assert(f || f_fem);
770 libmesh_assert(!(f && f_fem));
773 libmesh_assert(!(f && f_system));
774 libmesh_assert(!(f_fem && !f_system));
786 const unsigned int dim = mesh.mesh_dimension();
789 const FEType & fe_type = variable.
type();
792 unsigned int n_vec_dim = FEInterface::n_vec_dim(mesh, fe_type);
794 const unsigned int var_component =
798 const unsigned int var = variable.
number();
801 FEContinuity cont = FEInterface::get_continuity(fe_type);
804 if ((cont == C_ONE) && (fe_type.family != SUBDIVISION))
807 libmesh_assert(g || g_fem);
811 libmesh_assert(!(g && g_fem));
812 libmesh_assert(!(f && g_fem));
813 libmesh_assert(!(f_fem && g));
820 std::unique_ptr<FEMContext> context;
823 libmesh_assert(f_system);
824 if (f_system->current_local_solution->initialized())
826 context = std::make_unique<FEMContext>
847 if (f_system && context.get())
848 context->pre_fe_reinit(*f_system, elem);
851 fem_context.pre_fe_reinit(fem_context.get_system(), elem);
854 const std::vector<dof_id_type> & dof_indices =
855 fem_context.get_dof_indices(var);
858 const unsigned int n_dofs =
859 cast_int<unsigned int>(dof_indices.size());
862 std::vector<char> dof_is_fixed(n_dofs,
false);
863 std::vector<int> free_dof(n_dofs, 0);
878 unsigned int current_dof = 0;
879 for (
unsigned int n=0; n!= sebi.n_nodes; ++n)
886 const unsigned int nc =
887 FEInterface::n_dofs_at_node (fe_type, elem, n);
893 auto is_boundary_node_it = sebi.is_boundary_node_map.find(&dirichlet);
899 const bool not_boundary_node =
900 (is_boundary_node_it == sebi.is_boundary_node_map.end() ||
901 !is_boundary_node_it->second[n]);
904 auto is_boundary_nodeset_it = sebi.is_boundary_nodeset_map.find(&dirichlet);
905 const bool not_boundary_nodeset =
906 (is_boundary_nodeset_it == sebi.is_boundary_nodeset_map.end() ||
907 !is_boundary_nodeset_it->second[n]);
909 if ((!elem->is_vertex(n) || not_boundary_node) &&
910 not_boundary_nodeset)
915 if (cont == DISCONTINUOUS)
917 libmesh_assert_equal_to (nc, 0);
921 else if ((cont == C_ZERO) || (fe_type.family == SUBDIVISION))
923 libmesh_assert_equal_to (nc, n_vec_dim);
924 for (
unsigned int c = 0; c < n_vec_dim; c++)
927 f_component(f, f_fem, context.get(), var_component+c,
928 elem->point(n), time);
929 dof_is_fixed[current_dof+c] =
true;
931 current_dof += n_vec_dim;
934 else if (fe_type.family == HERMITE)
937 f_component(f, f_fem, context.get(), var_component,
938 elem->point(n), time);
939 dof_is_fixed[current_dof] =
true;
942 g_component(g, g_fem, context.get(), var_component,
943 elem->point(n), time);
945 Ue(current_dof) = grad(0);
946 dof_is_fixed[current_dof] =
true;
951 Point nxminus = elem->point(n),
952 nxplus = elem->point(n);
956 g_component(g, g_fem, context.get(), var_component,
959 g_component(g, g_fem, context.get(), var_component,
962 Ue(current_dof) = grad(1);
963 dof_is_fixed[current_dof] =
true;
966 Ue(current_dof) = (gxplus(1) - gxminus(1))
968 dof_is_fixed[current_dof] =
true;
974 Ue(current_dof) = grad(2);
975 dof_is_fixed[current_dof] =
true;
978 Ue(current_dof) = (gxplus(2) - gxminus(2))
980 dof_is_fixed[current_dof] =
true;
983 Point nyminus = elem->point(n),
984 nyplus = elem->point(n);
988 g_component(g, g_fem, context.get(), var_component,
991 g_component(g, g_fem, context.get(), var_component,
994 Ue(current_dof) = (gyplus(2) - gyminus(2))
996 dof_is_fixed[current_dof] =
true;
999 Point nxmym = elem->point(n),
1000 nxmyp = elem->point(n),
1001 nxpym = elem->point(n),
1002 nxpyp = elem->point(n);
1012 g_component(g, g_fem, context.get(), var_component,
1015 g_component(g, g_fem, context.get(), var_component,
1018 g_component(g, g_fem, context.get(), var_component,
1021 g_component(g, g_fem, context.get(), var_component,
1023 Number gxzplus = (gxpyp(2) - gxmyp(2))
1025 Number gxzminus = (gxpym(2) - gxmym(2))
1028 Ue(current_dof) = (gxzplus - gxzminus)
1030 dof_is_fixed[current_dof] =
true;
1038 else if (cont == C_ONE)
1040 libmesh_assert_equal_to (nc, 1 + dim);
1042 f_component(f, f_fem, context.get(), var_component,
1043 elem->point(n), time);
1044 dof_is_fixed[current_dof] =
true;
1047 g_component(g, g_fem, context.get(), var_component,
1048 elem->point(n), time);
1049 for (
unsigned int i=0; i!= dim; ++i)
1051 Ue(current_dof) = grad(i);
1052 dof_is_fixed[current_dof] =
true;
1057 libmesh_error_msg(
"Unknown continuity cont = " << cont);
1061 if (dim > 2 && cont != DISCONTINUOUS)
1066 FEGenericBase<OutputType> * edge_fe =
nullptr;
1067 fem_context.get_edge_fe(var, edge_fe);
1077 const std::vector<std::vector<OutputShape>> & phi = edge_fe->get_phi();
1078 const std::vector<Point> & xyz_values = edge_fe->get_xyz();
1079 const std::vector<Real> & JxW = edge_fe->get_JxW();
1082 const std::vector<std::vector<OutputGradient>> * dphi =
nullptr;
1083 if ((cont == C_ONE) && (fe_type.family != SUBDIVISION))
1085 const std::vector<std::vector<OutputGradient>> & ref_dphi = edge_fe->get_dphi();
1090 std::vector<unsigned int> edge_dofs;
1096 auto is_boundary_edge_it = sebi.is_boundary_edge_map.find(&dirichlet);
1098 for (
unsigned int e=0; e != sebi.n_edges; ++e)
1100 if (is_boundary_edge_it == sebi.is_boundary_edge_map.end() ||
1101 !is_boundary_edge_it->second[e])
1104 FEInterface::dofs_on_edge(elem, dim, fe_type, e,
1107 const unsigned int n_edge_dofs =
1108 cast_int<unsigned int>(edge_dofs.size());
1112 unsigned int free_dofs = 0;
1113 for (
unsigned int i=0; i != n_edge_dofs; ++i)
1114 if (!dof_is_fixed[edge_dofs[i]])
1115 free_dof[free_dofs++] = i;
1127 edge_fe->edge_reinit(elem, e);
1128 const unsigned int n_qp = fem_context.get_edge_qrule().n_points();
1131 for (
unsigned int qp=0; qp<n_qp; qp++)
1134 OutputNumber fineval(0);
1137 for (
unsigned int c = 0; c < n_vec_dim; c++)
1139 f_component(f, f_fem, context.get(), var_component+c,
1140 xyz_values[qp], time);
1143 OutputNumberGradient finegrad;
1146 unsigned int g_rank;
1147 switch( FEInterface::field_type( fe_type ) )
1160 libmesh_error_msg(
"Unknown field type!");
1164 for (
unsigned int c = 0; c < n_vec_dim; c++)
1165 for (
unsigned int d = 0; d < g_rank; d++)
1166 g_accessor(c + d*dim ) =
1167 g_component(g, g_fem, context.get(), var_component,
1168 xyz_values[qp], time)(c);
1171 for (
unsigned int sidei=0, freei=0; sidei != n_edge_dofs; ++sidei)
1173 unsigned int i = edge_dofs[sidei];
1175 if (dof_is_fixed[i])
1177 for (
unsigned int sidej=0, freej=0; sidej != n_edge_dofs; ++sidej)
1179 unsigned int j = edge_dofs[sidej];
1180 if (dof_is_fixed[j])
1181 Fe(freei) -= phi[i][qp] * phi[j][qp] *
1184 Ke(freei,freej) += phi[i][qp] *
1185 phi[j][qp] * JxW[qp];
1188 if (dof_is_fixed[j])
1189 Fe(freei) -= ((*dphi)[i][qp].contract((*dphi)[j][qp]) ) *
1192 Ke(freei,freej) += ((*dphi)[i][qp].contract((*dphi)[j][qp]))
1195 if (!dof_is_fixed[j])
1198 Fe(freei) += phi[i][qp] * fineval * JxW[qp];
1200 Fe(freei) += (finegrad.contract( (*dphi)[i][qp]) ) *
1209 for (
unsigned int i=0; i != free_dofs; ++i)
1211 Number & ui = Ue(edge_dofs[free_dof[i]]);
1215 dof_is_fixed[edge_dofs[free_dof[i]]] =
true;
1221 if (dim > 1 && cont != DISCONTINUOUS)
1223 FEGenericBase<OutputType> * side_fe =
nullptr;
1224 fem_context.get_side_fe(var, side_fe);
1234 const std::vector<std::vector<OutputShape>> & phi = side_fe->get_phi();
1235 const std::vector<Point> & xyz_values = side_fe->get_xyz();
1236 const std::vector<Real> & JxW = side_fe->get_JxW();
1239 const std::vector<std::vector<OutputGradient>> * dphi =
nullptr;
1240 if ((cont == C_ONE) && (fe_type.family != SUBDIVISION))
1242 const std::vector<std::vector<OutputGradient>> & ref_dphi = side_fe->get_dphi();
1247 std::vector<unsigned int> side_dofs;
1253 auto is_boundary_side_it = sebi.is_boundary_side_map.find(&dirichlet);
1255 for (
unsigned int s=0; s != sebi.n_sides; ++s)
1257 if (is_boundary_side_it == sebi.is_boundary_side_map.end() ||
1258 !is_boundary_side_it->second[s])
1261 FEInterface::dofs_on_side(elem, dim, fe_type, s,
1264 const unsigned int n_side_dofs =
1265 cast_int<unsigned int>(side_dofs.size());
1269 unsigned int free_dofs = 0;
1270 for (
unsigned int i=0; i != n_side_dofs; ++i)
1271 if (!dof_is_fixed[side_dofs[i]])
1272 free_dof[free_dofs++] = i;
1284 side_fe->reinit(elem, s);
1285 const unsigned int n_qp = fem_context.get_side_qrule().n_points();
1288 for (
unsigned int qp=0; qp<n_qp; qp++)
1291 OutputNumber fineval(0);
1294 for (
unsigned int c = 0; c < n_vec_dim; c++)
1296 f_component(f, f_fem, context.get(), var_component+c,
1297 xyz_values[qp], time);
1300 OutputNumberGradient finegrad;
1303 unsigned int g_rank;
1304 switch( FEInterface::field_type( fe_type ) )
1317 libmesh_error_msg(
"Unknown field type!");
1321 for (
unsigned int c = 0; c < n_vec_dim; c++)
1322 for (
unsigned int d = 0; d < g_rank; d++)
1323 g_accessor(c + d*dim ) =
1324 g_component(g, g_fem, context.get(), var_component,
1325 xyz_values[qp], time)(c);
1328 for (
unsigned int sidei=0, freei=0; sidei != n_side_dofs; ++sidei)
1330 unsigned int i = side_dofs[sidei];
1332 if (dof_is_fixed[i])
1334 for (
unsigned int sidej=0, freej=0; sidej != n_side_dofs; ++sidej)
1336 unsigned int j = side_dofs[sidej];
1337 if (dof_is_fixed[j])
1338 Fe(freei) -= phi[i][qp] * phi[j][qp] *
1341 Ke(freei,freej) += phi[i][qp] *
1342 phi[j][qp] * JxW[qp];
1345 if (dof_is_fixed[j])
1346 Fe(freei) -= ((*dphi)[i][qp].contract((*dphi)[j][qp])) *
1349 Ke(freei,freej) += ((*dphi)[i][qp].contract((*dphi)[j][qp]))
1352 if (!dof_is_fixed[j])
1355 Fe(freei) += (fineval * phi[i][qp]) * JxW[qp];
1357 Fe(freei) += (finegrad.contract((*dphi)[i][qp])) *
1366 for (
unsigned int i=0; i != free_dofs; ++i)
1368 Number & ui = Ue(side_dofs[free_dof[i]]);
1374 dof_is_fixed[side_dofs[free_dof[i]]] =
true;
1380 if (dim == 2 && cont != DISCONTINUOUS)
1382 FEGenericBase<OutputType> * fe =
nullptr;
1383 fem_context.get_element_fe(var, fe, dim);
1393 const std::vector<std::vector<OutputShape>> & phi = fe->get_phi();
1394 const std::vector<Point> & xyz_values = fe->get_xyz();
1395 const std::vector<Real> & JxW = fe->get_JxW();
1398 const std::vector<std::vector<OutputGradient>> * dphi =
nullptr;
1399 if ((cont == C_ONE) && (fe_type.family != SUBDIVISION))
1401 const std::vector<std::vector<OutputGradient>> & ref_dphi = fe->get_dphi();
1409 auto is_boundary_shellface_it = sebi.is_boundary_shellface_map.find(&dirichlet);
1411 for (
unsigned int shellface=0; shellface != 2; ++shellface)
1413 if (is_boundary_shellface_it == sebi.is_boundary_shellface_map.end() ||
1414 !is_boundary_shellface_it->second[shellface])
1418 std::vector<unsigned int> shellface_dofs(n_dofs);
1419 std::iota(shellface_dofs.begin(), shellface_dofs.end(), 0);
1423 unsigned int free_dofs = 0;
1424 for (
unsigned int i=0; i != n_dofs; ++i)
1425 if (!dof_is_fixed[shellface_dofs[i]])
1426 free_dof[free_dofs++] = i;
1439 const unsigned int n_qp = fem_context.get_element_qrule().n_points();
1442 for (
unsigned int qp=0; qp<n_qp; qp++)
1445 OutputNumber fineval(0);
1448 for (
unsigned int c = 0; c < n_vec_dim; c++)
1450 f_component(f, f_fem, context.get(), var_component+c,
1451 xyz_values[qp], time);
1454 OutputNumberGradient finegrad;
1457 unsigned int g_rank;
1458 switch( FEInterface::field_type( fe_type ) )
1471 libmesh_error_msg(
"Unknown field type!");
1475 for (
unsigned int c = 0; c < n_vec_dim; c++)
1476 for (
unsigned int d = 0; d < g_rank; d++)
1477 g_accessor(c + d*dim ) =
1478 g_component(g, g_fem, context.get(), var_component,
1479 xyz_values[qp], time)(c);
1482 for (
unsigned int shellfacei=0, freei=0;
1483 shellfacei != n_dofs; ++shellfacei)
1485 unsigned int i = shellface_dofs[shellfacei];
1487 if (dof_is_fixed[i])
1489 for (
unsigned int shellfacej=0, freej=0;
1490 shellfacej != n_dofs; ++shellfacej)
1492 unsigned int j = shellface_dofs[shellfacej];
1493 if (dof_is_fixed[j])
1494 Fe(freei) -= phi[i][qp] * phi[j][qp] *
1497 Ke(freei,freej) += phi[i][qp] *
1498 phi[j][qp] * JxW[qp];
1501 if (dof_is_fixed[j])
1502 Fe(freei) -= ((*dphi)[i][qp].contract((*dphi)[j][qp])) *
1505 Ke(freei,freej) += ((*dphi)[i][qp].contract((*dphi)[j][qp]))
1508 if (!dof_is_fixed[j])
1511 Fe(freei) += (fineval * phi[i][qp]) * JxW[qp];
1513 Fe(freei) += (finegrad.contract((*dphi)[i][qp])) *
1522 for (
unsigned int i=0; i != free_dofs; ++i)
1524 Number & ui = Ue(shellface_dofs[free_dof[i]]);
1528 dof_is_fixed[shellface_dofs[free_dof[i]]] =
true;
1535 Threads::spin_mutex::scoped_lock lock(Threads::spin_mtx);
1537 for (
unsigned int i = 0; i < n_dofs; i++)
1541 add_fn (dof_indices[i], empty_row, Ue(i));
1547 ConstrainDirichlet (
DofMap & dof_map_in,
1548 const MeshBase & mesh_in,
1551 const AddConstraint & add_in) :
1552 dof_map(dof_map_in),
1555 dirichlets(dirichlets_in),
1559 ConstrainDirichlet (ConstrainDirichlet &&) =
default;
1560 ConstrainDirichlet (
const ConstrainDirichlet &) =
default;
1564 ConstrainDirichlet & operator= (
const ConstrainDirichlet &) =
delete;
1565 ConstrainDirichlet & operator= (ConstrainDirichlet &&) =
delete;
1567 void operator()(
const ConstElemRange & range)
const
1579 System * system =
nullptr;
1584 std::map<boundary_id_type, std::set<std::pair<unsigned int, DirichletBoundary *>>>
1585 boundary_id_to_ordered_dirichlet_boundaries;
1587 for (
auto dirichlet_id : index_range(dirichlets))
1590 const auto & dirichlet = dirichlets[dirichlet_id];
1593 for (
const auto & b_id : dirichlet->
b)
1594 boundary_id_to_ordered_dirichlet_boundaries[b_id].emplace(dirichlet_id, dirichlet.get());
1596 for (
const auto & var : dirichlet->
variables)
1598 const Variable & variable = dof_map.variable(var);
1599 auto current_system = variable.
system();
1602 system = current_system;
1604 libmesh_error_msg_if(current_system != system,
1605 "All variables should be defined on the same System");
1614 libmesh_error_msg_if(!system,
"Valid System not found for any Variables.");
1621 auto fem_context = std::make_unique<FEMContext>
1622 (*system,
nullptr,
false);
1627 fem_context->set_algebraic_type(FEMContext::DOFS_ONLY);
1630 const BoundaryInfo & boundary_info = mesh.get_boundary_info();
1633 SingleElemBoundaryInfo sebi(boundary_info, boundary_id_to_ordered_dirichlet_boundaries);
1636 for (
const auto & elem : range)
1640 if (!elem->active())
1644 bool has_dirichlet_constraint = sebi.reinit(elem);
1647 if (!has_dirichlet_constraint)
1650 for (
const auto & db_pair : sebi.ordered_dbs)
1653 const auto & dirichlet = db_pair.second;
1656 for (
const auto & var : dirichlet->
variables)
1658 const Variable & variable = dof_map.variable(var);
1662 libmesh_assert_equal_to(variable.
number(), var);
1664 const FEType & fe_type = variable.
type();
1666 if (fe_type.family == SCALAR)
1669 switch( FEInterface::field_type( fe_type ) )
1676 if (fe_type.family == LAGRANGE)
1677 this->apply_lagrange_dirichlet_impl<Real>( sebi, variable, *dirichlet, *fem_context );
1679 this->apply_dirichlet_impl<Real>( sebi, variable, *dirichlet, *fem_context );
1684 this->apply_dirichlet_impl<RealGradient>( sebi, variable, *dirichlet, *fem_context );
1688 libmesh_error_msg(
"Unknown field type!");
1698 #endif // LIBMESH_ENABLE_DIRICHLET
1711 #ifdef LIBMESH_ENABLE_CONSTRAINTS
1716 parallel_object_only();
1719 this->comm().sum(nc_dofs);
1726 const DofConstraints::const_iterator lower =
1731 return cast_int<dof_id_type>(std::distance(lower, upper));
1738 parallel_object_only();
1740 LOG_SCOPE(
"create_dof_constraints()",
"DofMap");
1742 libmesh_assert (mesh.is_prepared());
1748 MeshTools::libmesh_assert_valid_boundary_ids(mesh);
1754 bool constraint_rows_empty = mesh.get_constraint_rows().empty();
1755 this->comm().min(constraint_rows_empty);
1760 const bool possible_local_constraints =
false
1762 || !constraint_rows_empty
1763 #ifdef LIBMESH_ENABLE_AMR
1764 || mesh.mesh_dimension() > 1
1766 #ifdef LIBMESH_ENABLE_PERIODIC
1769 #ifdef LIBMESH_ENABLE_DIRICHLET
1775 bool possible_global_constraints = possible_local_constraints;
1776 #if defined(LIBMESH_ENABLE_PERIODIC) || defined(LIBMESH_ENABLE_DIRICHLET) || defined(LIBMESH_ENABLE_AMR)
1777 libmesh_assert(this->comm().verify(mesh.is_serial()));
1779 this->comm().max(possible_global_constraints);
1787 #ifdef LIBMESH_ENABLE_CONSTRAINTS
1792 #ifdef LIBMESH_ENABLE_NODE_CONSTRAINTS
1796 if (!possible_global_constraints)
1805 ConstElemRange range (mesh.local_elements_begin(),
1806 mesh.local_elements_end());
1817 #ifdef LIBMESH_ENABLE_PERIODIC
1820 this->comm().max(need_point_locator);
1822 if (need_point_locator)
1823 mesh.sub_point_locator();
1826 #ifdef LIBMESH_ENABLE_NODE_CONSTRAINTS
1827 Threads::parallel_for (range,
1829 #ifdef LIBMESH_ENABLE_PERIODIC
1833 #endif // LIBMESH_ENABLE_NODE_CONSTRAINTS
1839 for (
unsigned int variable_number=0; variable_number<n_vars;
1840 ++variable_number, range.reset())
1841 Threads::parallel_for (range,
1844 #ifdef LIBMESH_ENABLE_PERIODIC
1845 *_periodic_boundaries,
1850 #ifdef LIBMESH_ENABLE_DIRICHLET
1866 Threads::parallel_for
1868 ConstrainDirichlet(*
this, mesh, time, *_dirichlet_boundaries,
1869 AddPrimalConstraint(*
this)));
1881 Threads::parallel_for
1883 ConstrainDirichlet(*
this, mesh, time, adb_q,
1884 AddAdjointConstraint(*
this, qoi_index)));
1888 #endif // LIBMESH_ENABLE_DIRICHLET
1892 if (!constraint_rows_empty)
1908 const auto & constraint_rows = mesh.get_constraint_rows();
1913 bool constraint_rows_empty = constraint_rows.empty();
1914 this->comm().min(constraint_rows_empty);
1915 libmesh_assert(!constraint_rows_empty);
1919 libmesh_experimental();
1923 #ifdef LIBMESH_ENABLE_PERIODIC
1925 "Periodic boundary conditions are not yet implemented for spline meshes");
1930 std::unique_ptr<SparsityPattern::Build> sp;
1931 std::unique_ptr<SparseMatrix<Number>> mat;
1933 const unsigned int n_adjoint_rhs =
1937 std::vector<std::unique_ptr<NumericVector<Number>>>
1938 solve_rhs(n_adjoint_rhs+1);
1943 std::set<dof_id_type> my_dirichlet_spline_dofs;
1946 std::unordered_set<dof_id_type> was_previously_constrained;
1948 const unsigned int sys_num = this->
sys_number();
1949 for (
auto & node_row : constraint_rows)
1951 const Node * node = node_row.first;
1952 libmesh_assert(node == mesh.node_ptr(node->id()));
1957 if (node->processor_id() != mesh.processor_id())
1960 for (
auto var_num : IntRange<unsigned int>(0, this->
n_variables()))
1962 const FEFamily & fe_family = this->
variable_type(var_num).family;
1965 if (fe_family != LAGRANGE &&
1966 fe_family != RATIONAL_BERNSTEIN)
1972 node->dof_number(sys_num, var_num, 0);
1973 for (
const auto & [pr, val] : node_row.second)
1975 const Elem * spline_elem = pr.first;
1976 libmesh_assert(spline_elem == mesh.elem_ptr(spline_elem->id()));
1978 const Node & spline_node =
1979 spline_elem->node_ref(pr.second);
1982 spline_node.dof_number(sys_num, var_num, 0);
1983 dc_row[spline_dof_id] = val;
1989 was_previously_constrained.insert(constrained_id);
1993 for (
auto & row_entry : dc_row)
1994 my_dirichlet_spline_dofs.insert(row_entry.first);
2013 if (this->comm().size() > 1)
2017 their_dirichlet_spline_dofs;
2022 libmesh_assert(std::is_sorted(my_dirichlet_spline_dofs.begin(),
2023 my_dirichlet_spline_dofs.end()));
2024 processor_id_type destination_pid = 0;
2025 for (
auto d : my_dirichlet_spline_dofs)
2027 libmesh_assert_less(d, this->
end_dof(this->comm().size()-1));
2028 while (d >= this->
end_dof(destination_pid))
2031 if (destination_pid != this->processor_id())
2032 their_dirichlet_spline_dofs[destination_pid].push_back(d);
2035 auto receive_dof_functor =
2036 [& my_dirichlet_spline_dofs]
2038 const std::vector<dof_id_type> & dofs)
2040 my_dirichlet_spline_dofs.insert(dofs.begin(), dofs.end());
2043 Parallel::push_parallel_vector_data
2044 (this->comm(), their_dirichlet_spline_dofs, receive_dof_functor);
2054 bool important_prior_constraints =
2055 !was_previously_constrained.empty();
2056 this->comm().max(important_prior_constraints);
2058 if (important_prior_constraints)
2064 for (
auto q : IntRange<unsigned int>(0, n_adjoint_rhs+1))
2074 mat->attach_dof_map(*
this);
2076 mat->attach_sparsity_pattern(*sp);
2079 for (
auto & node_row : constraint_rows)
2081 const Node * node = node_row.first;
2082 libmesh_assert(node == mesh.node_ptr(node->id()));
2084 for (
auto var_num : IntRange<unsigned int>(0, this->
n_variables()))
2086 const FEFamily & fe_family = this->
variable_type(var_num).family;
2089 if (fe_family != LAGRANGE &&
2090 fe_family != RATIONAL_BERNSTEIN)
2094 node->dof_number(sys_num, var_num, 0);
2096 if (was_previously_constrained.count(constrained_id))
2098 for (
auto q : IntRange<int>(0, n_adjoint_rhs+1))
2102 std::vector<dof_id_type>
dof_indices(1, constrained_id);
2110 DofConstraintValueMap::const_iterator rhsit =
2111 vals.find(constrained_id);
2112 F(0) = (rhsit == vals.end()) ? 0 : rhsit->second;
2115 if (rhsit != vals.end())
2119 (K, F, dof_indices,
false, q ? (q-1) : -1);
2121 mat->add_matrix(K, dof_indices);
2122 solve_rhs[q]->add_vector(F, dof_indices);
2133 if (!was_previously_constrained.count(d) &&
2134 !my_dirichlet_spline_dofs.count(d))
2139 std::unique_ptr<LinearSolver<Number>> linear_solver =
2140 LinearSolver<Number>::build(this->comm());
2142 std::unique_ptr<NumericVector<Number>> projected_vals =
2149 for (
auto sd : my_dirichlet_spline_dofs)
2153 for (
auto q : IntRange<unsigned int>(0, n_adjoint_rhs+1))
2158 const unsigned int max_its = 5000;
2160 linear_solver->solve(*mat, *projected_vals,
2161 *(solve_rhs[q]), tol, max_its);
2167 for (
auto sd : my_dirichlet_spline_dofs)
2170 Number constraint_rhs = (*projected_vals)(sd);
2172 std::pair<DofConstraintValueMap::iterator, bool> rhs_it =
2173 vals.emplace(sd, constraint_rhs);
2175 rhs_it.first->second = constraint_rhs;
2185 const Number constraint_rhs,
2186 const bool forbid_constraint_overwrite)
2189 libmesh_error_msg_if(forbid_constraint_overwrite && this->
is_constrained_dof(dof_number),
2190 "ERROR: DOF " << dof_number <<
" was already constrained!");
2192 libmesh_assert_less(dof_number, this->
n_dofs());
2196 libmesh_assert_msg(!constraint_row.count(dof_number),
2197 "Error: constraint_row for dof " << dof_number <<
2198 " should not contain an entry for dof " << dof_number);
2201 for (
const auto & pr : constraint_row)
2202 libmesh_assert_less(pr.first, this->n_dofs());
2206 std::pair<DofConstraints::iterator, bool> it =
2209 it.first->second = constraint_row;
2211 std::pair<DofConstraintValueMap::iterator, bool> rhs_it =
2214 rhs_it.first->second = constraint_rhs;
2221 const Number constraint_rhs,
2222 const bool forbid_constraint_overwrite)
2225 if (forbid_constraint_overwrite)
2228 "ERROR: DOF " << dof_number <<
" has no corresponding primal constraint!");
2253 std::pair<DofConstraintValueMap::iterator, bool> rhs_it =
2256 rhs_it.first->second = constraint_rhs;
2263 bool print_nonlocal)
const
2265 parallel_object_only();
2267 std::string local_constraints =
2270 if (this->processor_id())
2272 this->comm().send(0, local_constraints);
2276 os <<
"Processor 0:\n";
2277 os << local_constraints;
2279 for (
auto p : IntRange<processor_id_type>(1, this->n_processors()))
2281 this->comm().receive(p, local_constraints);
2282 os <<
"Processor " << p <<
":\n";
2283 os << local_constraints;
2290 std::ostringstream os;
2291 #ifdef LIBMESH_ENABLE_NODE_CONSTRAINTS
2297 os <<
"Node Constraints:"
2303 if (!print_nonlocal &&
2304 node->processor_id() != this->processor_id())
2308 const Point & offset = pr.second;
2310 os <<
"Constraints for Node id " << node->id()
2313 for (
const auto & [cnode, val] : row)
2314 os <<
" (" << cnode->id() <<
"," << val <<
")\t";
2316 os <<
"rhs: " << offset;
2320 #endif // LIBMESH_ENABLE_NODE_CONSTRAINTS
2327 os <<
"DoF Constraints:"
2336 DofConstraintValueMap::const_iterator rhsit =
2341 os <<
"Constraints for DoF " << i
2344 for (
const auto & item : row)
2345 os <<
" (" << item.first <<
"," << item.second <<
")\t";
2347 os <<
"rhs: " << rhs;
2351 for (
unsigned int qoi_index = 0,
2353 qoi_index != n_qois; ++qoi_index)
2355 os <<
"Adjoint " << qoi_index <<
" DoF rhs values:"
2358 AdjointDofConstraintValues::const_iterator adjoint_map_it =
2362 for (
const auto [i, rhs] : adjoint_map_it->second)
2368 os <<
"RHS for DoF " << i
2381 std::vector<dof_id_type> & elem_dofs,
2382 bool asymmetric_constraint_rows)
const
2384 libmesh_assert_equal_to (elem_dofs.size(), matrix.
m());
2385 libmesh_assert_equal_to (elem_dofs.size(), matrix.
n());
2397 LOG_SCOPE(
"constrain_elem_matrix()",
"DofMap");
2400 if ((C.
m() == matrix.
m()) &&
2401 (C.
n() == elem_dofs.size()))
2408 libmesh_assert_equal_to (matrix.
m(), matrix.
n());
2409 libmesh_assert_equal_to (matrix.
m(), elem_dofs.size());
2410 libmesh_assert_equal_to (matrix.
n(), elem_dofs.size());
2413 for (
unsigned int i=0,
2414 n_elem_dofs = cast_int<unsigned int>(elem_dofs.size());
2415 i != n_elem_dofs; i++)
2419 for (
auto j : make_range(matrix.
n()))
2424 if (asymmetric_constraint_rows)
2426 DofConstraints::const_iterator
2439 for (
const auto & item : constraint_row)
2440 for (
unsigned int j=0; j != n_elem_dofs; j++)
2441 if (elem_dofs[j] == item.first)
2442 matrix(i,j) = -item.second;
2452 std::vector<dof_id_type> & elem_dofs,
2453 bool asymmetric_constraint_rows)
const
2455 libmesh_assert_equal_to (elem_dofs.size(), matrix.
m());
2456 libmesh_assert_equal_to (elem_dofs.size(), matrix.
n());
2457 libmesh_assert_equal_to (elem_dofs.size(), rhs.
size());
2469 LOG_SCOPE(
"cnstrn_elem_mat_vec()",
"DofMap");
2472 if ((C.
m() == matrix.
m()) &&
2473 (C.
n() == elem_dofs.size()))
2480 libmesh_assert_equal_to (matrix.
m(), matrix.
n());
2481 libmesh_assert_equal_to (matrix.
m(), elem_dofs.size());
2482 libmesh_assert_equal_to (matrix.
n(), elem_dofs.size());
2485 for (
unsigned int i=0,
2486 n_elem_dofs = cast_int<unsigned int>(elem_dofs.size());
2487 i != n_elem_dofs; i++)
2490 for (
auto j : make_range(matrix.
n()))
2499 if (asymmetric_constraint_rows)
2501 DofConstraints::const_iterator
2511 for (
const auto & item : constraint_row)
2512 for (
unsigned int j=0; j != n_elem_dofs; j++)
2513 if (elem_dofs[j] == item.first)
2514 matrix(i,j) = -item.second;
2531 std::vector<dof_id_type> & elem_dofs,
2532 bool asymmetric_constraint_rows,
2533 int qoi_index)
const
2535 libmesh_assert_equal_to (elem_dofs.size(), matrix.
m());
2536 libmesh_assert_equal_to (elem_dofs.size(), matrix.
n());
2537 libmesh_assert_equal_to (elem_dofs.size(), rhs.
size());
2550 LOG_SCOPE(
"hetero_cnstrn_elem_mat_vec()",
"DofMap");
2553 if ((C.
m() == matrix.
m()) &&
2554 (C.
n() == elem_dofs.size()))
2562 const AdjointDofConstraintValues::const_iterator
2565 rhs_values = &it->second;
2581 libmesh_assert_equal_to (matrix.
m(), matrix.
n());
2582 libmesh_assert_equal_to (matrix.
m(), elem_dofs.size());
2583 libmesh_assert_equal_to (matrix.
n(), elem_dofs.size());
2585 for (
unsigned int i=0,
2586 n_elem_dofs = cast_int<unsigned int>(elem_dofs.size());
2587 i != n_elem_dofs; i++)
2593 for (
auto j : make_range(matrix.
n()))
2602 if (asymmetric_constraint_rows)
2604 DofConstraints::const_iterator
2611 for (
const auto & item : constraint_row)
2612 for (
unsigned int j=0; j != n_elem_dofs; j++)
2613 if (elem_dofs[j] == item.first)
2614 matrix(i,j) = -item.second;
2618 const DofConstraintValueMap::const_iterator valpos =
2619 rhs_values->find(dof_id);
2621 rhs(i) = (valpos == rhs_values->end()) ?
2637 std::vector<dof_id_type> & elem_dofs,
2640 libmesh_assert_equal_to (elem_dofs.size(), matrix.
m());
2641 libmesh_assert_equal_to (elem_dofs.size(), matrix.
n());
2642 libmesh_assert_equal_to (elem_dofs.size(), rhs.
size());
2644 libmesh_assert (solution_local.
type() == SERIAL ||
2645 solution_local.
type() == GHOSTED);
2648 if (this->_dof_constraints.empty())
2657 this->build_constraint_matrix_and_vector (C, H, elem_dofs);
2659 LOG_SCOPE(
"hetero_cnstrn_elem_jac_res()",
"DofMap");
2662 if ((C.
m() != matrix.
m()) ||
2663 (C.
n() != elem_dofs.size()))
2674 libmesh_assert_equal_to (matrix.
m(), matrix.
n());
2675 libmesh_assert_equal_to (matrix.
m(), elem_dofs.size());
2676 libmesh_assert_equal_to (matrix.
n(), elem_dofs.size());
2678 for (
unsigned int i=0,
2679 n_elem_dofs = cast_int<unsigned int>(elem_dofs.size());
2680 i != n_elem_dofs; i++)
2684 const DofConstraints::const_iterator
2685 pos = _dof_constraints.find(dof_id);
2687 if (pos != _dof_constraints.end())
2689 for (
auto j : make_range(matrix.
n()))
2700 for (
const auto & item : constraint_row)
2701 for (
unsigned int j=0; j != n_elem_dofs; j++)
2702 if (elem_dofs[j] == item.first)
2703 matrix(i,j) = -item.second;
2705 const DofConstraintValueMap::const_iterator valpos =
2706 _primal_constraint_values.find(dof_id);
2708 Number & rhs_val = rhs(i);
2709 rhs_val = (valpos == _primal_constraint_values.end()) ?
2710 0 : -valpos->second;
2711 for (
const auto & [constraining_dof, coef] : constraint_row)
2712 rhs_val -= coef * solution_local(constraining_dof);
2713 rhs_val += solution_local(dof_id);
2721 std::vector<dof_id_type> & elem_dofs,
2724 libmesh_assert_equal_to (elem_dofs.size(), rhs.
size());
2726 libmesh_assert (solution_local.
type() == SERIAL ||
2727 solution_local.
type() == GHOSTED);
2730 if (this->_dof_constraints.empty())
2738 this->build_constraint_matrix_and_vector (C, H, elem_dofs);
2740 LOG_SCOPE(
"hetero_cnstrn_elem_res()",
"DofMap");
2743 if ((C.
m() != rhs.
size()) ||
2744 (C.
n() != elem_dofs.size()))
2751 for (
unsigned int i=0,
2752 n_elem_dofs = cast_int<unsigned int>(elem_dofs.size());
2753 i != n_elem_dofs; i++)
2757 const DofConstraints::const_iterator
2758 pos = _dof_constraints.find(dof_id);
2760 if (pos != _dof_constraints.end())
2767 const DofConstraintValueMap::const_iterator valpos =
2768 _primal_constraint_values.find(dof_id);
2770 Number & rhs_val = rhs(i);
2771 rhs_val = (valpos == _primal_constraint_values.end()) ?
2772 0 : -valpos->second;
2773 for (
const auto & [constraining_dof, coef] : constraint_row)
2774 rhs_val -= coef * solution_local(constraining_dof);
2775 rhs_val += solution_local(dof_id);
2783 std::vector<dof_id_type> & elem_dofs,
2786 libmesh_assert_equal_to (elem_dofs.size(), rhs.
size());
2788 libmesh_assert (solution_local.
type() == SERIAL ||
2789 solution_local.
type() == GHOSTED);
2792 if (this->_dof_constraints.empty())
2798 this->build_constraint_matrix (C, elem_dofs);
2800 LOG_SCOPE(
"cnstrn_elem_residual()",
"DofMap");
2803 if (C.
n() != elem_dofs.size())
2810 for (
unsigned int i=0,
2811 n_elem_dofs = cast_int<unsigned int>(elem_dofs.size());
2812 i != n_elem_dofs; i++)
2816 const DofConstraints::const_iterator
2817 pos = _dof_constraints.find(dof_id);
2819 if (pos != _dof_constraints.end())
2826 Number & rhs_val = rhs(i);
2828 for (
const auto & [constraining_dof, coef] : constraint_row)
2829 rhs_val -= coef * solution_local(constraining_dof);
2830 rhs_val += solution_local(dof_id);
2838 std::vector<dof_id_type> & elem_dofs,
2839 bool asymmetric_constraint_rows,
2840 int qoi_index)
const
2842 libmesh_assert_equal_to (elem_dofs.size(), matrix.
m());
2843 libmesh_assert_equal_to (elem_dofs.size(), matrix.
n());
2844 libmesh_assert_equal_to (elem_dofs.size(), rhs.
size());
2857 LOG_SCOPE(
"hetero_cnstrn_elem_vec()",
"DofMap");
2860 if ((C.
m() == matrix.
m()) &&
2861 (C.
n() == elem_dofs.size()))
2869 const AdjointDofConstraintValues::const_iterator
2872 rhs_values = &it->second;
2884 for (
unsigned int i=0,
2885 n_elem_dofs = cast_int<unsigned int>(elem_dofs.size());
2886 i != n_elem_dofs; i++)
2895 if (asymmetric_constraint_rows && rhs_values)
2897 const DofConstraintValueMap::const_iterator valpos =
2898 rhs_values->find(dof_id);
2900 rhs(i) = (valpos == rhs_values->end()) ?
2915 std::vector<dof_id_type> & row_dofs,
2916 std::vector<dof_id_type> & col_dofs,
2917 bool asymmetric_constraint_rows)
const
2919 libmesh_assert_equal_to (row_dofs.size(), matrix.
m());
2920 libmesh_assert_equal_to (col_dofs.size(), matrix.
n());
2933 std::vector<dof_id_type> orig_row_dofs(row_dofs);
2934 std::vector<dof_id_type> orig_col_dofs(col_dofs);
2939 LOG_SCOPE(
"constrain_elem_matrix()",
"DofMap");
2941 row_dofs = orig_row_dofs;
2942 col_dofs = orig_col_dofs;
2944 bool constraint_found =
false;
2948 if ((R.
m() == matrix.
m()) &&
2949 (R.
n() == row_dofs.size()))
2952 constraint_found =
true;
2955 if ((C.
m() == matrix.
n()) &&
2956 (C.
n() == col_dofs.size()))
2959 constraint_found =
true;
2963 if (constraint_found)
2965 libmesh_assert_equal_to (matrix.
m(), row_dofs.size());
2966 libmesh_assert_equal_to (matrix.
n(), col_dofs.size());
2969 for (
unsigned int i=0,
2970 n_row_dofs = cast_int<unsigned int>(row_dofs.size());
2971 i != n_row_dofs; i++)
2974 for (
auto j : make_range(matrix.
n()))
2976 if (row_dofs[i] != col_dofs[j])
2982 if (asymmetric_constraint_rows)
2984 DofConstraints::const_iterator
2991 libmesh_assert (!constraint_row.empty());
2993 for (
const auto & item : constraint_row)
2994 for (
unsigned int j=0,
2995 n_col_dofs = cast_int<unsigned int>(col_dofs.size());
2996 j != n_col_dofs; j++)
2997 if (col_dofs[j] == item.first)
2998 matrix(i,j) = -item.second;
3007 std::vector<dof_id_type> & row_dofs,
3010 libmesh_assert_equal_to (rhs.
size(), row_dofs.size());
3021 LOG_SCOPE(
"constrain_elem_vector()",
"DofMap");
3024 if ((R.
m() == rhs.
size()) &&
3025 (R.
n() == row_dofs.size()))
3031 libmesh_assert_equal_to (row_dofs.size(), rhs.
size());
3033 for (
unsigned int i=0,
3034 n_row_dofs = cast_int<unsigned int>(row_dofs.size());
3035 i != n_row_dofs; i++)
3050 std::vector<dof_id_type> & row_dofs,
3053 libmesh_assert_equal_to (v.
size(), row_dofs.size());
3054 libmesh_assert_equal_to (w.
size(), row_dofs.size());
3065 LOG_SCOPE(
"cnstrn_elem_dyad_mat()",
"DofMap");
3068 if ((R.
m() == v.
size()) &&
3069 (R.
n() == row_dofs.size()))
3079 libmesh_assert_equal_to (row_dofs.size(), v.
size());
3080 libmesh_assert_equal_to (row_dofs.size(), w.
size());
3084 for (
unsigned int i=0,
3085 n_row_dofs = cast_int<unsigned int>(row_dofs.size());
3086 i != n_row_dofs; i++)
3115 bool homogeneous)
const
3117 parallel_object_only();
3122 LOG_SCOPE(
"enforce_constraints_exactly()",
"DofMap");
3125 v = system.solution.
get();
3129 std::unique_ptr<NumericVector<Number>> v_built;
3130 if (v->
type() == SERIAL)
3137 i<v_built->last_local_index(); i++)
3138 v_built->set(i, (*v)(i));
3140 v_global = v_built.
get();
3143 libmesh_assert (v_local->
closed());
3145 else if (v->
type() == PARALLEL)
3153 v_local = v_built.
get();
3157 else if (v->
type() == GHOSTED)
3163 libmesh_error_msg(
"ERROR: Unsupported NumericVector type == " << Utility::enum_to_string(v->
type()));
3168 libmesh_assert(v_local);
3169 libmesh_assert(v_global);
3170 libmesh_assert_equal_to (
this, &(system.get_dof_map()));
3180 DofConstraintValueMap::const_iterator rhsit =
3183 exact_value = rhsit->second;
3185 for (
const auto & [dof, val] : constraint_row)
3186 exact_value += val * (*v_local)(dof);
3188 v_global->
set(constrained_dof, exact_value);
3193 if (v->
type() == SERIAL)
3206 bool homogeneous)
const
3208 parallel_object_only();
3216 solution = system.solution.
get();
3219 std::unique_ptr<NumericVector<Number>> solution_built;
3220 if (solution->
type() == SERIAL || solution->
type() == GHOSTED)
3221 solution_local = solution;
3222 else if (solution->
type() == PARALLEL)
3228 solution_built->close();
3229 solution_local = solution_built.
get();
3232 libmesh_error_msg(
"ERROR: Unsupported NumericVector type == " << Utility::enum_to_string(solution->
type()));
3236 libmesh_assert(solution_local);
3237 libmesh_assert_equal_to (
this, &(system.get_dof_map()));
3245 for (
const auto & [dof, val] : constraint_row)
3246 exact_value -= val * (*solution_local)(dof);
3247 exact_value += (*solution_local)(constrained_dof);
3250 DofConstraintValueMap::const_iterator rhsit =
3253 exact_value += rhsit->second;
3256 rhs->
set(constrained_dof, exact_value);
3263 parallel_object_only();
3269 jac = system.matrix;
3271 libmesh_assert_equal_to (
this, &(system.get_dof_map()));
3278 for (
const auto & j : constraint_row)
3279 jac->
set(constrained_dof, j.first, -j.second);
3280 jac->
set(constrained_dof, constrained_dof, 1);
3286 unsigned int q)
const
3288 parallel_object_only();
3293 LOG_SCOPE(
"enforce_adjoint_constraints_exactly()",
"DofMap");
3297 std::unique_ptr<NumericVector<Number>> v_built;
3298 if (v.
type() == SERIAL)
3305 i<v_built->last_local_index(); i++)
3306 v_built->set(i, v(i));
3308 v_global = v_built.
get();
3311 libmesh_assert (v_local->
closed());
3313 else if (v.
type() == PARALLEL)
3320 v_local = v_built.
get();
3324 else if (v.
type() == GHOSTED)
3330 libmesh_error_msg(
"ERROR: Unknown v.type() == " << v.
type());
3335 libmesh_assert(v_local);
3336 libmesh_assert(v_global);
3339 const AdjointDofConstraintValues::const_iterator
3343 nullptr : &adjoint_constraint_map_it->second;
3353 const DofConstraintValueMap::const_iterator
3354 adjoint_constraint_it =
3355 constraint_map->find(constrained_dof);
3356 if (adjoint_constraint_it != constraint_map->end())
3357 exact_value = adjoint_constraint_it->second;
3360 for (
const auto & j : constraint_row)
3361 exact_value += j.second * (*v_local)(j.first);
3363 v_global->
set(constrained_dof, exact_value);
3368 if (v.
type() == SERIAL)
3380 std::pair<Real, Real>
3385 v = system.solution.
get();
3389 libmesh_assert (vec.
closed());
3391 Real max_absolute_error = 0., max_relative_error = 0.;
3393 const MeshBase & mesh = system.get_mesh();
3395 libmesh_assert_equal_to (
this, &(system.get_dof_map()));
3398 std::vector<dof_id_type> local_dof_indices;
3400 for (
const auto & elem : mesh.active_local_element_ptr_range())
3403 std::vector<dof_id_type> raw_dof_indices = local_dof_indices;
3414 libmesh_assert_equal_to (C.
m(), raw_dof_indices.size());
3415 libmesh_assert_equal_to (C.
n(), local_dof_indices.size());
3417 for (
auto i : make_range(C.
m()))
3426 DofConstraints::const_iterator
3433 DofConstraintValueMap::const_iterator rhsit =
3436 exact_value = rhsit->second;
3438 for (
auto j : make_range(C.
n()))
3440 if (local_dof_indices[j] != global_dof)
3441 exact_value += C(i,j) *
3442 vec(local_dof_indices[j]);
3445 max_absolute_error = std::max(max_absolute_error,
3446 std::abs(vec(global_dof) - exact_value));
3447 max_relative_error = std::max(max_relative_error,
3448 std::abs(vec(global_dof) - exact_value)
3454 return std::pair<Real, Real>(max_absolute_error, max_relative_error);
3460 std::vector<dof_id_type> & elem_dofs,
3461 const bool called_recursively)
const
3463 LOG_SCOPE_IF(
"build_constraint_matrix()",
"DofMap", !called_recursively);
3466 typedef std::set<dof_id_type> RCSet;
3469 bool we_have_constraints =
false;
3476 for (
const auto & dof : elem_dofs)
3479 we_have_constraints =
true;
3482 DofConstraints::const_iterator
3492 for (
const auto & item : constraint_row)
3493 dof_set.insert (item.first);
3498 if (!we_have_constraints)
3501 for (
const auto & dof : elem_dofs)
3502 dof_set.erase (dof);
3510 if (!dof_set.empty() ||
3511 !called_recursively)
3513 const unsigned int old_size =
3514 cast_int<unsigned int>(elem_dofs.size());
3517 elem_dofs.insert(elem_dofs.end(),
3518 dof_set.begin(), dof_set.end());
3523 cast_int<unsigned int>(elem_dofs.size()));
3526 for (
unsigned int i=0; i != old_size; i++)
3530 DofConstraints::const_iterator
3540 for (
const auto & item : constraint_row)
3541 for (
unsigned int j=0,
3542 n_elem_dofs = cast_int<unsigned int>(elem_dofs.size());
3543 j != n_elem_dofs; j++)
3544 if (elem_dofs[j] == item.first)
3545 C(i,j) = item.second;
3559 if ((C.
n() == Cnew.
m()) &&
3560 (Cnew.
n() == elem_dofs.size()))
3563 libmesh_assert_equal_to (C.
n(), elem_dofs.size());
3571 std::vector<dof_id_type> & elem_dofs,
3573 const bool called_recursively)
const
3575 LOG_SCOPE_IF(
"build_constraint_matrix_and_vector()",
"DofMap", !called_recursively);
3578 typedef std::set<dof_id_type> RCSet;
3581 bool we_have_constraints =
false;
3588 for (
const auto & dof : elem_dofs)
3591 we_have_constraints =
true;
3594 DofConstraints::const_iterator
3604 for (
const auto & item : constraint_row)
3605 dof_set.insert (item.first);
3610 if (!we_have_constraints)
3613 for (
const auto & dof : elem_dofs)
3614 dof_set.erase (dof);
3622 if (!dof_set.empty() ||
3623 !called_recursively)
3630 const AdjointDofConstraintValues::const_iterator
3633 rhs_values = &it->second;
3636 const unsigned int old_size =
3637 cast_int<unsigned int>(elem_dofs.size());
3640 elem_dofs.insert(elem_dofs.end(),
3641 dof_set.begin(), dof_set.end());
3646 cast_int<unsigned int>(elem_dofs.size()));
3650 for (
unsigned int i=0; i != old_size; i++)
3654 DofConstraints::const_iterator
3664 for (
const auto & item : constraint_row)
3665 for (
unsigned int j=0,
3666 n_elem_dofs = cast_int<unsigned int>(elem_dofs.size());
3667 j != n_elem_dofs; j++)
3668 if (elem_dofs[j] == item.first)
3669 C(i,j) = item.second;
3673 DofConstraintValueMap::const_iterator rhsit =
3674 rhs_values->find(elem_dofs[i]);
3675 if (rhsit != rhs_values->end())
3676 H(i) = rhsit->second;
3693 if ((C.
n() == Cnew.
m()) &&
3694 (Cnew.
n() == elem_dofs.size()))
3703 libmesh_assert_equal_to (C.
n(), elem_dofs.size());
3711 parallel_object_only();
3714 if (this->n_processors() == 1)
3720 #ifdef LIBMESH_ENABLE_NODE_CONSTRAINTS
3722 #endif // LIBMESH_ENABLE_NODE_CONSTRAINTS
3724 this->comm().max(has_constraints);
3725 if (!has_constraints)
3730 const unsigned int max_qoi_num =
3734 #ifdef LIBMESH_ENABLE_NODE_CONSTRAINTS
3736 std::vector<Parallel::Request> packed_range_sends;
3740 Parallel::MessageTag range_tag = this->comm().get_unique_tag();
3743 const bool dist_mesh = !mesh.is_serial();
3750 std::map<processor_id_type, std::set<dof_id_type>> pushed_ids;
3752 #ifdef LIBMESH_ENABLE_NODE_CONSTRAINTS
3753 std::map<processor_id_type, std::set<dof_id_type>> pushed_node_ids;
3756 const unsigned int sys_num = this->
sys_number();
3759 for (
auto & elem : as_range(mesh.active_not_local_elements_begin(),
3760 mesh.active_not_local_elements_end()))
3762 const unsigned short n_nodes = elem->n_nodes();
3775 const unsigned int n_vars = elem->n_vars(sys_num);
3776 for (
unsigned int v=0; v != n_vars; ++v)
3778 const unsigned int n_comp = elem->n_comp(sys_num,v);
3779 for (
unsigned int c=0; c != n_comp; ++c)
3781 const unsigned int id =
3782 elem->dof_number(sys_num,v,c);
3784 pushed_ids[elem->processor_id()].insert(
id);
3789 for (
unsigned short n = 0; n != n_nodes; ++n)
3791 const Node & node = elem->node_ref(n);
3792 const unsigned int n_vars = node.n_vars(sys_num);
3793 for (
unsigned int v=0; v != n_vars; ++v)
3795 const unsigned int n_comp = node.n_comp(sys_num,v);
3796 for (
unsigned int c=0; c != n_comp; ++c)
3798 const unsigned int id =
3799 node.dof_number(sys_num,v,c);
3801 pushed_ids[elem->processor_id()].insert(
id);
3806 #ifdef LIBMESH_ENABLE_NODE_CONSTRAINTS
3807 for (
unsigned short n = 0; n != n_nodes; ++n)
3809 pushed_node_ids[elem->processor_id()].insert(elem->node_id(n));
3815 std::map<processor_id_type, std::vector<dof_id_type>>
3816 pushed_id_vecs, received_id_vecs;
3817 for (
auto & p : pushed_ids)
3818 pushed_id_vecs[p.first].assign(p.second.begin(), p.second.end());
3820 std::map<processor_id_type, std::vector<std::vector<std::pair<dof_id_type,Real>>>>
3821 pushed_keys_vals, received_keys_vals;
3822 std::map<processor_id_type, std::vector<std::vector<Number>>> pushed_rhss, received_rhss;
3823 for (
auto & p : pushed_id_vecs)
3825 auto & keys_vals = pushed_keys_vals[p.first];
3826 keys_vals.reserve(p.second.size());
3828 auto & rhss = pushed_rhss[p.first];
3829 rhss.reserve(p.second.size());
3830 for (
auto & pushed_id : p.second)
3833 keys_vals.emplace_back(row.begin(), row.end());
3835 rhss.push_back(std::vector<Number>(max_qoi_num+1));
3836 std::vector<Number> & rhs = rhss.back();
3837 DofConstraintValueMap::const_iterator rhsit =
3842 for (
unsigned int q = 0; q != max_qoi_num; ++q)
3844 AdjointDofConstraintValues::const_iterator adjoint_map_it =
3851 adjoint_map_it->second;
3853 DofConstraintValueMap::const_iterator adj_rhsit =
3854 constraint_map.find(pushed_id);
3857 (adj_rhsit == constraint_map.end()) ?
3858 0 : adj_rhsit->second;
3863 auto ids_action_functor =
3864 [& received_id_vecs]
3866 const std::vector<dof_id_type> & data)
3868 received_id_vecs[pid] = data;
3871 Parallel::push_parallel_vector_data
3872 (this->comm(), pushed_id_vecs, ids_action_functor);
3874 auto keys_vals_action_functor =
3875 [& received_keys_vals]
3877 const std::vector<std::vector<std::pair<dof_id_type,Real>>> & data)
3879 received_keys_vals[pid] = data;
3882 Parallel::push_parallel_vector_data
3883 (this->comm(), pushed_keys_vals, keys_vals_action_functor);
3885 auto rhss_action_functor =
3888 const std::vector<std::vector<Number>> & data)
3890 received_rhss[pid] = data;
3893 Parallel::push_parallel_vector_data
3894 (this->comm(), pushed_rhss, rhss_action_functor);
3899 #ifdef LIBMESH_ENABLE_NODE_CONSTRAINTS
3900 std::map<processor_id_type, std::vector<dof_id_type>>
3901 pushed_node_id_vecs, received_node_id_vecs;
3902 for (
auto & p : pushed_node_ids)
3903 pushed_node_id_vecs[p.first].assign(p.second.begin(), p.second.end());
3905 std::map<processor_id_type, std::vector<std::vector<std::pair<dof_id_type,Real>>>>
3906 pushed_node_keys_vals, received_node_keys_vals;
3907 std::map<processor_id_type, std::vector<Point>> pushed_offsets, received_offsets;
3909 for (
auto & p : pushed_node_id_vecs)
3915 std::set<const Node *> nodes_requested;
3917 auto & node_keys_vals = pushed_node_keys_vals[pid];
3918 node_keys_vals.reserve(p.second.size());
3920 auto & offsets = pushed_offsets[pid];
3921 offsets.reserve(p.second.size());
3923 for (
auto & pushed_node_id : p.second)
3925 const Node * node = mesh.node_ptr(pushed_node_id);
3927 const std::size_t row_size = row.size();
3928 node_keys_vals.push_back
3929 (std::vector<std::pair<dof_id_type,Real>>());
3930 std::vector<std::pair<dof_id_type,Real>> & this_node_kv =
3931 node_keys_vals.back();
3932 this_node_kv.reserve(row_size);
3933 for (
const auto & j : row)
3935 this_node_kv.emplace_back(j.first->id(), j.second);
3940 if (j.first->processor_id() != pid && dist_mesh)
3941 nodes_requested.insert(j.first);
3953 packed_range_sends.push_back(Parallel::Request());
3954 this->comm().send_packed_range
3955 (pid, &mesh, nodes_requested.begin(), nodes_requested.end(),
3956 packed_range_sends.back(), range_tag);
3960 auto node_ids_action_functor =
3961 [& received_node_id_vecs]
3963 const std::vector<dof_id_type> & data)
3965 received_node_id_vecs[pid] = data;
3968 Parallel::push_parallel_vector_data
3969 (this->comm(), pushed_node_id_vecs, node_ids_action_functor);
3971 auto node_keys_vals_action_functor =
3972 [& received_node_keys_vals]
3974 const std::vector<std::vector<std::pair<dof_id_type,Real>>> & data)
3976 received_node_keys_vals[pid] = data;
3979 Parallel::push_parallel_vector_data
3980 (this->comm(), pushed_node_keys_vals,
3981 node_keys_vals_action_functor);
3983 auto node_offsets_action_functor =
3984 [& received_offsets]
3986 const std::vector<Point> & data)
3988 received_offsets[pid] = data;
3991 Parallel::push_parallel_vector_data
3992 (this->comm(), pushed_offsets, node_offsets_action_functor);
3997 for (
auto & [pid, pushed_ids_to_me] : received_id_vecs)
3999 libmesh_assert(received_keys_vals.count(pid));
4000 libmesh_assert(received_rhss.count(pid));
4001 const auto & pushed_keys_vals_to_me = received_keys_vals.at(pid);
4002 const auto & pushed_rhss_to_me = received_rhss.at(pid);
4004 libmesh_assert_equal_to (pushed_ids_to_me.size(),
4005 pushed_keys_vals_to_me.size());
4006 libmesh_assert_equal_to (pushed_ids_to_me.size(),
4007 pushed_rhss_to_me.size());
4009 for (
auto i : index_range(pushed_ids_to_me))
4018 for (
auto & kv : pushed_keys_vals_to_me[i])
4020 libmesh_assert_less(kv.first, this->n_dofs());
4021 row[kv.first] = kv.second;
4024 const Number primal_rhs = pushed_rhss_to_me[i][max_qoi_num];
4027 libmesh_assert(pushed_keys_vals_to_me[i].empty());
4029 if (primal_rhs !=
Number(0))
4034 for (
unsigned int q = 0; q != max_qoi_num; ++q)
4036 AdjointDofConstraintValues::iterator adjoint_map_it =
4039 const Number adj_rhs = pushed_rhss_to_me[i][q];
4050 adjoint_map_it->second;
4052 if (adj_rhs !=
Number(0))
4053 constraint_map[constrained] = adj_rhs;
4055 constraint_map.erase(constrained);
4061 #ifdef LIBMESH_ENABLE_NODE_CONSTRAINTS
4063 for (
auto & [pid, pushed_node_ids_to_me] : received_node_id_vecs)
4068 this->comm().receive_packed_range
4069 (pid, &mesh, null_output_iterator<Node>(),
4070 (Node**)
nullptr, range_tag);
4072 libmesh_assert(received_node_keys_vals.count(pid));
4073 libmesh_assert(received_offsets.count(pid));
4074 const auto & pushed_node_keys_vals_to_me = received_node_keys_vals.at(pid);
4075 const auto & pushed_offsets_to_me = received_offsets.at(pid);
4077 libmesh_assert_equal_to (pushed_node_ids_to_me.size(),
4078 pushed_node_keys_vals_to_me.size());
4079 libmesh_assert_equal_to (pushed_node_ids_to_me.size(),
4080 pushed_offsets_to_me.size());
4082 for (
auto i : index_range(pushed_node_ids_to_me))
4084 dof_id_type constrained_id = pushed_node_ids_to_me[i];
4088 const Node * constrained = mesh.node_ptr(constrained_id);
4092 for (
auto & kv : pushed_node_keys_vals_to_me[i])
4094 const Node * key_node = mesh.node_ptr(kv.first);
4095 libmesh_assert(key_node);
4096 row[key_node] = kv.second;
4102 #endif // LIBMESH_ENABLE_NODE_CONSTRAINTS
4109 typedef std::set<dof_id_type> DoF_RCSet;
4110 DoF_RCSet unexpanded_dofs;
4113 unexpanded_dofs.insert(i.first);
4119 #ifdef LIBMESH_ENABLE_NODE_CONSTRAINTS
4120 typedef std::set<const Node *> Node_RCSet;
4121 Node_RCSet unexpanded_nodes;
4124 unexpanded_nodes.insert(i.first);
4128 bool unexpanded_set_nonempty = !unexpanded_nodes.empty();
4129 this->comm().max(unexpanded_set_nonempty);
4131 while (unexpanded_set_nonempty)
4134 parallel_object_only();
4137 Node_RCSet node_request_set;
4140 std::map<processor_id_type, std::vector<dof_id_type>>
4144 std::map<processor_id_type, dof_id_type> node_ids_on_proc;
4147 for (
const auto & i : unexpanded_nodes)
4150 for (
const auto & j : row)
4152 const Node *
const node = j.first;
4153 libmesh_assert(node);
4157 if ((node->processor_id() != this->processor_id()) &&
4158 !_node_constraints.count(node))
4159 node_request_set.insert(node);
4165 unexpanded_nodes.clear();
4168 for (
const auto & node : node_request_set)
4170 libmesh_assert(node);
4171 libmesh_assert_less (node->processor_id(), this->n_processors());
4172 node_ids_on_proc[node->processor_id()]++;
4175 for (
auto pair : node_ids_on_proc)
4176 requested_node_ids[pair.first].reserve(pair.second);
4179 for (
const auto & node : node_request_set)
4180 requested_node_ids[node->processor_id()].push_back(node->id());
4182 typedef std::vector<std::pair<dof_id_type, Real>> row_datum;
4184 auto node_row_gather_functor =
4188 & packed_range_sends,
4191 const std::vector<dof_id_type> & ids,
4192 std::vector<row_datum> & data)
4196 std::set<const Node *> nodes_requested;
4199 const std::size_t query_size = ids.size();
4201 data.resize(query_size);
4202 for (std::size_t i=0; i != query_size; ++i)
4205 const Node * constrained_node = mesh.node_ptr(constrained_id);
4206 if (_node_constraints.count(constrained_node))
4209 std::size_t row_size = row.size();
4210 data[i].reserve(row_size);
4211 for (
const auto & j : row)
4213 const Node * node = j.first;
4214 data[i].emplace_back(node->id(), j.second);
4219 if (node->processor_id() != pid && dist_mesh)
4220 nodes_requested.insert(node);
4244 packed_range_sends.push_back(Parallel::Request());
4245 this->comm().send_packed_range
4246 (pid, &mesh, nodes_requested.begin(), nodes_requested.end(),
4247 packed_range_sends.back(), range_tag);
4251 typedef Point node_rhs_datum;
4253 auto node_rhs_gather_functor =
4257 const std::vector<dof_id_type> & ids,
4258 std::vector<node_rhs_datum> & data)
4261 const std::size_t query_size = ids.size();
4263 data.resize(query_size);
4264 for (std::size_t i=0; i != query_size; ++i)
4267 const Node * constrained_node = mesh.node_ptr(constrained_id);
4268 if (_node_constraints.count(constrained_node))
4269 data[i] = _node_constraints[constrained_node].second;
4271 data[i](0) = std::numeric_limits<Real>::quiet_NaN();
4275 auto node_row_action_functor =
4282 const std::vector<dof_id_type> & ids,
4283 const std::vector<row_datum> & data)
4288 this->comm().receive_packed_range
4289 (pid, &mesh, null_output_iterator<Node>(),
4290 (Node**)
nullptr, range_tag);
4293 const std::size_t query_size = ids.size();
4295 for (std::size_t i=0; i != query_size; ++i)
4301 if (data[i].empty())
4303 const Node * constrained_node = mesh.node_ptr(constrained_id);
4309 const Node * constrained_node = mesh.node_ptr(constrained_id);
4312 for (
auto & pair : data[i])
4314 const Node * key_node =
4315 mesh.node_ptr(pair.first);
4316 libmesh_assert(key_node);
4317 row[key_node] = pair.second;
4321 unexpanded_nodes.insert(constrained_node);
4326 auto node_rhs_action_functor =
4330 const std::vector<dof_id_type> & ids,
4331 const std::vector<node_rhs_datum> & data)
4334 const std::size_t query_size = ids.size();
4336 for (std::size_t i=0; i != query_size; ++i)
4339 const Node * constrained_node = mesh.node_ptr(constrained_id);
4342 _node_constraints[constrained_node].second = data[i];
4344 _node_constraints.erase(constrained_node);
4349 row_datum * node_row_ex =
nullptr;
4350 Parallel::pull_parallel_vector_data
4351 (this->comm(), requested_node_ids, node_row_gather_functor,
4352 node_row_action_functor, node_row_ex);
4355 node_rhs_datum * node_rhs_ex =
nullptr;
4356 Parallel::pull_parallel_vector_data
4357 (this->comm(), requested_node_ids, node_rhs_gather_functor,
4358 node_rhs_action_functor, node_rhs_ex);
4363 unexpanded_set_nonempty = !unexpanded_nodes.empty();
4364 this->comm().max(unexpanded_set_nonempty);
4366 Parallel::wait(packed_range_sends);
4367 #endif // LIBMESH_ENABLE_NODE_CONSTRAINTS
4391 const unsigned int max_qoi_num =
4396 typedef std::set<dof_id_type> RCSet;
4397 RCSet unexpanded_set;
4400 unexpanded_set.insert(i.first);
4402 while (!unexpanded_set.empty())
4403 for (RCSet::iterator i = unexpanded_set.begin();
4404 i != unexpanded_set.end(); )
4407 DofConstraints::iterator
4408 pos = _dof_constraints.find(*i);
4410 libmesh_assert (pos != _dof_constraints.end());
4414 DofConstraintValueMap::iterator rhsit =
4420 std::vector<DofConstraintValueMap::iterator> adjoint_rhs_iterators;
4421 adjoint_rhs_iterators.resize(max_qoi_num);
4424 std::vector<Number> adjoint_constraint_rhs(max_qoi_num, 0.0);
4429 const std::size_t q = adjoint_map.first;
4430 adjoint_rhs_iterators[q] = adjoint_map.second.find(*i);
4432 adjoint_constraint_rhs[q] =
4433 (adjoint_rhs_iterators[q] == adjoint_map.second.end()) ?
4434 0 : adjoint_rhs_iterators[q]->second;
4437 std::vector<dof_id_type> constraints_to_expand;
4439 for (
const auto & item : constraint_row)
4440 if (item.first != *i && this->is_constrained_dof(item.first))
4442 unexpanded_set.insert(item.first);
4443 constraints_to_expand.push_back(item.first);
4446 for (
const auto & expandable : constraints_to_expand)
4448 const Real this_coef = constraint_row[expandable];
4450 DofConstraints::const_iterator
4451 subpos = _dof_constraints.find(expandable);
4453 libmesh_assert (subpos != _dof_constraints.end());
4457 for (
const auto & item : subconstraint_row)
4460 libmesh_assert(item.first != expandable);
4461 constraint_row[item.first] += item.second * this_coef;
4464 DofConstraintValueMap::const_iterator subrhsit =
4467 constraint_rhs += subrhsit->second * this_coef;
4470 for (
const auto & adjoint_map : _adjoint_constraint_values)
4472 const std::size_t q = adjoint_map.first;
4474 DofConstraintValueMap::const_iterator adjoint_subrhsit =
4475 adjoint_map.second.find(expandable);
4477 if (adjoint_subrhsit != adjoint_map.second.end())
4478 adjoint_constraint_rhs[q] += adjoint_subrhsit->second * this_coef;
4481 constraint_row.erase(expandable);
4486 if (constraint_rhs !=
Number(0))
4493 if (constraint_rhs !=
Number(0))
4494 rhsit->second = constraint_rhs;
4500 for (
auto & adjoint_map : _adjoint_constraint_values)
4502 const std::size_t q = adjoint_map.first;
4504 if(adjoint_rhs_iterators[q] == adjoint_map.second.end())
4506 if (adjoint_constraint_rhs[q] !=
Number(0))
4507 (adjoint_map.second)[*i] = adjoint_constraint_rhs[q];
4509 adjoint_map.second.erase(*i);
4513 if (adjoint_constraint_rhs[q] !=
Number(0))
4514 adjoint_rhs_iterators[q]->second = adjoint_constraint_rhs[q];
4516 adjoint_map.second.erase(adjoint_rhs_iterators[q]);
4520 if (constraints_to_expand.empty())
4521 i = unexpanded_set.erase(i);
4538 #ifdef LIBMESH_ENABLE_CONSTRAINTS
4548 typedef std::set<dof_id_type> RCSet;
4549 RCSet unexpanded_set;
4555 for (
const auto & i : dof_constraints_copy)
4556 unexpanded_set.insert(i.first);
4558 while (!unexpanded_set.empty())
4559 for (RCSet::iterator i = unexpanded_set.begin();
4560 i != unexpanded_set.end(); )
4563 DofConstraints::iterator
4564 pos = dof_constraints_copy.find(*i);
4566 libmesh_assert (pos != dof_constraints_copy.end());
4576 std::vector<dof_id_type> constraints_to_expand;
4578 for (
const auto & item : constraint_row)
4579 if (item.first != *i && this->is_constrained_dof(item.first))
4581 unexpanded_set.insert(item.first);
4582 constraints_to_expand.push_back(item.first);
4585 for (
const auto & expandable : constraints_to_expand)
4587 const Real this_coef = constraint_row[expandable];
4589 DofConstraints::const_iterator
4590 subpos = dof_constraints_copy.find(expandable);
4592 libmesh_assert (subpos != dof_constraints_copy.end());
4596 for (
const auto & item : subconstraint_row)
4598 libmesh_error_msg_if(item.first == expandable,
"Constraint loop detected");
4600 constraint_row[item.first] += item.second * this_coef;
4609 constraint_row.erase(expandable);
4628 if (constraints_to_expand.empty())
4629 i = unexpanded_set.erase(i);
4650 parallel_object_only();
4653 if (this->n_processors() == 1)
4659 #ifdef LIBMESH_ENABLE_NODE_CONSTRAINTS
4661 #endif // LIBMESH_ENABLE_NODE_CONSTRAINTS
4663 this->comm().max(has_constraints);
4664 if (!has_constraints)
4669 Parallel::MessageTag range_tag = this->comm().get_unique_tag();
4671 #ifdef LIBMESH_ENABLE_NODE_CONSTRAINTS
4672 std::map<processor_id_type, std::set<dof_id_type>> pushed_node_ids;
4673 #endif // LIBMESH_ENABLE_NODE_CONSTRAINTS
4675 std::map<processor_id_type, std::set<dof_id_type>> pushed_ids;
4681 while (constrained >=
_end_df[constrained_proc_id])
4682 constrained_proc_id++;
4684 if (constrained_proc_id != this->processor_id())
4687 for (
auto & j : row)
4692 while (constraining >=
_end_df[constraining_proc_id])
4693 constraining_proc_id++;
4695 if (constraining_proc_id != this->processor_id() &&
4696 constraining_proc_id != constrained_proc_id)
4697 pushed_ids[constraining_proc_id].insert(constrained);
4704 std::vector<std::vector<std::pair<dof_id_type, Real>>>>
4705 pushed_keys_vals, pushed_keys_vals_to_me;
4707 std::map<processor_id_type, std::vector<std::pair<dof_id_type, Number>>>
4708 pushed_ids_rhss, pushed_ids_rhss_to_me;
4717 for (
const auto & [pid, pid_ids] : pushed_ids)
4719 const std::size_t ids_size = pid_ids.size();
4720 std::vector<std::vector<std::pair<dof_id_type, Real>>> &
4721 keys_vals = pushed_keys_vals[pid];
4722 std::vector<std::pair<dof_id_type,Number>> &
4723 ids_rhss = pushed_ids_rhss[pid];
4724 keys_vals.resize(ids_size);
4725 ids_rhss.resize(ids_size);
4728 std::set<dof_id_type>::const_iterator it;
4729 for (push_i = 0, it = pid_ids.begin();
4730 it != pid_ids.end(); ++push_i, ++it)
4734 keys_vals[push_i].assign(row.begin(), row.end());
4736 DofConstraintValueMap::const_iterator rhsit =
4738 ids_rhss[push_i].first = constrained;
4739 ids_rhss[push_i].second =
4748 auto ids_rhss_action_functor =
4749 [& pushed_ids_rhss_to_me]
4750 (processor_id_type pid,
4751 const std::vector<std::pair<dof_id_type, Number>> & data)
4753 pushed_ids_rhss_to_me[pid] = data;
4756 auto keys_vals_action_functor =
4757 [& pushed_keys_vals_to_me]
4758 (processor_id_type pid,
4759 const std::vector<std::vector<std::pair<dof_id_type, Real>>> & data)
4761 pushed_keys_vals_to_me[pid] = data;
4764 Parallel::push_parallel_vector_data
4765 (this->comm(), pushed_ids_rhss, ids_rhss_action_functor);
4766 Parallel::push_parallel_vector_data
4767 (this->comm(), pushed_keys_vals, keys_vals_action_functor);
4770 auto receive_dof_constraints =
4772 & pushed_ids_rhss_to_me,
4773 & pushed_keys_vals_to_me]
4776 for (
const auto & [pid, ids_rhss] : pushed_ids_rhss_to_me)
4778 const auto & keys_vals = pushed_keys_vals_to_me[pid];
4780 libmesh_assert_equal_to
4781 (ids_rhss.size(), keys_vals.size());
4784 for (
auto i : index_range(ids_rhss))
4793 for (
auto & key_val : keys_vals[i])
4795 libmesh_assert_less(key_val.first, this->n_dofs());
4796 row[key_val.first] = key_val.second;
4798 if (ids_rhss[i].second !=
Number(0))
4808 receive_dof_constraints();
4810 #ifdef LIBMESH_ENABLE_NODE_CONSTRAINTS
4814 const Node * constrained = i.first;
4816 if (constrained->processor_id() != this->processor_id())
4820 for (
auto & j : row)
4822 const Node * constraining = j.first;
4824 if (constraining->processor_id() != this->processor_id() &&
4825 constraining->processor_id() != constrained->processor_id())
4826 pushed_node_ids[constraining->processor_id()].insert(constrained->id());
4832 std::vector<std::vector<std::pair<dof_id_type,Real>>>>
4833 pushed_node_keys_vals, pushed_node_keys_vals_to_me;
4834 std::map<processor_id_type, std::vector<std::pair<dof_id_type, Point>>>
4835 pushed_node_ids_offsets, pushed_node_ids_offsets_to_me;
4836 std::map<processor_id_type, std::vector<const Node *>> pushed_node_vecs;
4838 for (
const auto & [pid, pid_ids]: pushed_node_ids)
4840 const std::size_t ids_size = pid_ids.size();
4841 std::vector<std::vector<std::pair<dof_id_type,Real>>> &
4842 keys_vals = pushed_node_keys_vals[pid];
4843 std::vector<std::pair<dof_id_type, Point>> &
4844 ids_offsets = pushed_node_ids_offsets[pid];
4845 keys_vals.resize(ids_size);
4846 ids_offsets.resize(ids_size);
4847 std::set<Node *> nodes;
4850 std::set<dof_id_type>::const_iterator it;
4851 for (push_i = 0, it = pid_ids.begin();
4852 it != pid_ids.end(); ++push_i, ++it)
4854 Node * constrained = mesh.node_ptr(*it);
4856 if (constrained->processor_id() != pid)
4857 nodes.insert(constrained);
4860 std::size_t row_size = row.size();
4861 keys_vals[push_i].reserve(row_size);
4862 for (
const auto & j : row)
4864 Node * constraining =
const_cast<Node *
>(j.first);
4866 keys_vals[push_i].emplace_back(constraining->id(), j.second);
4868 if (constraining->processor_id() != pid)
4869 nodes.insert(constraining);
4872 ids_offsets[push_i].first = *it;
4873 ids_offsets[push_i].second = _node_constraints[constrained].second;
4876 if (!mesh.is_serial())
4878 auto & pid_nodes = pushed_node_vecs[pid];
4879 pid_nodes.assign(nodes.begin(), nodes.end());
4883 auto node_ids_offsets_action_functor =
4884 [& pushed_node_ids_offsets_to_me]
4885 (processor_id_type pid,
4886 const std::vector<std::pair<dof_id_type, Point>> & data)
4888 pushed_node_ids_offsets_to_me[pid] = data;
4891 auto node_keys_vals_action_functor =
4892 [& pushed_node_keys_vals_to_me]
4893 (processor_id_type pid,
4894 const std::vector<std::vector<std::pair<dof_id_type, Real>>> & data)
4896 pushed_node_keys_vals_to_me[pid] = data;
4900 Parallel::push_parallel_vector_data
4901 (this->comm(), pushed_node_ids_offsets, node_ids_offsets_action_functor);
4902 Parallel::push_parallel_vector_data
4903 (this->comm(), pushed_node_keys_vals, node_keys_vals_action_functor);
4909 auto null_node_functor = [](
processor_id_type,
const std::vector<const Node *> &){};
4911 if (!mesh.is_serial())
4912 Parallel::push_parallel_packed_range
4913 (this->comm(), pushed_node_vecs, &mesh, null_node_functor);
4915 for (
const auto & [pid, ids_offsets] : pushed_node_ids_offsets_to_me)
4917 const auto & keys_vals = pushed_node_keys_vals_to_me[pid];
4919 libmesh_assert_equal_to
4920 (ids_offsets.size(), keys_vals.size());
4923 for (
auto i : index_range(ids_offsets))
4925 dof_id_type constrained_id = ids_offsets[i].first;
4929 const Node * constrained = mesh.node_ptr(constrained_id);
4933 for (
auto & key_val : keys_vals[i])
4935 const Node * key_node = mesh.node_ptr(key_val.first);
4936 row[key_node] = key_val.second;
4938 _node_constraints[constrained].second =
4939 ids_offsets[i].second;
4943 #endif // LIBMESH_ENABLE_NODE_CONSTRAINTS
4956 typedef std::map<dof_id_type, std::set<dof_id_type>> DofConstrainsMap;
4957 DofConstrainsMap dof_id_constrains;
4959 for (
const auto & [constrained, row] : _dof_constraints)
4961 for (
const auto & j : row)
4966 while (constraining >=
_end_df[constraining_proc_id])
4967 constraining_proc_id++;
4969 if (constraining_proc_id == this->processor_id())
4970 dof_id_constrains[constraining].insert(constrained);
4978 for (
const auto & elem : as_range(mesh.active_not_local_elements_begin(),
4979 mesh.active_not_local_elements_end()))
4981 std::vector<dof_id_type> my_dof_indices;
4984 for (
const auto & dof : my_dof_indices)
4986 DofConstrainsMap::const_iterator dcmi = dof_id_constrains.find(dof);
4987 if (dcmi != dof_id_constrains.end())
4989 for (
const auto & constrained : dcmi->second)
4992 while (constrained >=
_end_df[the_constrained_proc_id])
4993 the_constrained_proc_id++;
4995 const processor_id_type elemproc = elem->processor_id();
4996 if (elemproc != the_constrained_proc_id)
4997 pushed_ids[elemproc].insert(constrained);
5003 pushed_ids_rhss.clear();
5004 pushed_ids_rhss_to_me.clear();
5005 pushed_keys_vals.clear();
5006 pushed_keys_vals_to_me.clear();
5011 Parallel::push_parallel_vector_data
5012 (this->comm(), pushed_ids_rhss, ids_rhss_action_functor);
5013 Parallel::push_parallel_vector_data
5014 (this->comm(), pushed_keys_vals, keys_vals_action_functor);
5016 receive_dof_constraints();
5024 GhostingFunctor::map_type elements_to_couple;
5028 (elements_to_couple,
5029 temporary_coupling_matrices,
5032 mesh.active_local_elements_begin(),
5033 mesh.active_local_elements_end(),
5034 this->processor_id());
5037 std::set<dof_id_type> requested_dofs;
5039 for (
const auto & pr : elements_to_couple)
5041 const Elem * elem = pr.first;
5044 std::vector<dof_id_type> element_dofs;
5047 for (
auto dof : element_dofs)
5048 requested_dofs.insert(dof);
5056 std::set<dof_id_type> & unexpanded_dofs,
5059 typedef std::set<dof_id_type> DoF_RCSet;
5063 const unsigned int max_qoi_num =
5069 bool unexpanded_set_nonempty = !unexpanded_dofs.empty();
5070 this->comm().max(unexpanded_set_nonempty);
5072 while (unexpanded_set_nonempty)
5075 parallel_object_only();
5078 DoF_RCSet dof_request_set;
5081 std::map<processor_id_type, std::vector<dof_id_type>>
5085 std::map<processor_id_type, dof_id_type>
5089 for (
const auto & unexpanded_dof : unexpanded_dofs)
5091 DofConstraints::const_iterator
5100 dof_request_set.insert(unexpanded_dof);
5108 for (
const auto & j : row)
5116 dof_request_set.insert(constraining_dof);
5122 unexpanded_dofs.clear();
5126 for (
const auto & i : dof_request_set)
5130 dof_ids_on_proc[proc_id]++;
5133 for (
auto & pair : dof_ids_on_proc)
5135 requested_dof_ids[pair.first].reserve(pair.second);
5140 for (
const auto & i : dof_request_set)
5144 requested_dof_ids[proc_id].push_back(i);
5147 typedef std::vector<std::pair<dof_id_type, Real>> row_datum;
5149 typedef std::vector<Number> rhss_datum;
5151 auto row_gather_functor =
5154 const std::vector<dof_id_type> & ids,
5155 std::vector<row_datum> & data)
5158 const std::size_t query_size = ids.size();
5160 data.resize(query_size);
5161 for (std::size_t i=0; i != query_size; ++i)
5167 std::size_t row_size = row.size();
5168 data[i].reserve(row_size);
5169 for (
const auto & j : row)
5171 data[i].push_back(j);
5199 auto rhss_gather_functor =
5203 const std::vector<dof_id_type> & ids,
5204 std::vector<rhss_datum> & data)
5207 const std::size_t query_size = ids.size();
5209 data.resize(query_size);
5210 for (std::size_t i=0; i != query_size; ++i)
5216 DofConstraintValueMap::const_iterator rhsit =
5222 for (
unsigned int q = 0; q != max_qoi_num; ++q)
5224 AdjointDofConstraintValues::const_iterator adjoint_map_it =
5229 data[i].push_back(0);
5234 adjoint_map_it->second;
5236 DofConstraintValueMap::const_iterator adj_rhsit =
5237 constraint_map.find(constrained);
5239 ((adj_rhsit == constraint_map.end()) ?
5240 0 : adj_rhsit->second);
5246 auto row_action_functor =
5250 const std::vector<dof_id_type> & ids,
5251 const std::vector<row_datum> & data)
5254 const std::size_t query_size = ids.size();
5256 for (std::size_t i=0; i != query_size; ++i)
5262 if (data[i].empty())
5271 for (
auto & pair : data[i])
5273 libmesh_assert_less(pair.first, this->n_dofs());
5274 row[pair.first] = pair.second;
5278 unexpanded_dofs.insert(constrained);
5283 auto rhss_action_functor =
5287 const std::vector<dof_id_type> & ids,
5288 const std::vector<rhss_datum> & data)
5291 const std::size_t query_size = ids.size();
5293 for (std::size_t i=0; i != query_size; ++i)
5295 if (!data[i].empty())
5298 if (data[i][0] !=
Number(0))
5303 for (
unsigned int q = 0; q != max_qoi_num; ++q)
5305 AdjointDofConstraintValues::iterator adjoint_map_it =
5309 data[i][q+1] ==
Number(0))
5317 adjoint_map_it->second;
5319 if (data[i][q+1] !=
Number(0))
5320 constraint_map[constrained] =
5323 constraint_map.erase(constrained);
5331 row_datum * row_ex =
nullptr;
5332 Parallel::pull_parallel_vector_data
5333 (this->comm(), requested_dof_ids, row_gather_functor,
5334 row_action_functor, row_ex);
5337 rhss_datum * rhs_ex =
nullptr;
5338 Parallel::pull_parallel_vector_data
5339 (this->comm(), requested_dof_ids, rhss_gather_functor,
5340 rhss_action_functor, rhs_ex);
5344 unexpanded_set_nonempty = !unexpanded_dofs.empty();
5345 this->comm().max(unexpanded_set_nonempty);
5352 parallel_object_only();
5355 if (this->n_processors() == 1)
5361 this->comm().max(has_constraints);
5362 if (!has_constraints)
5371 for (
const auto & j : constraint_row)
5386 #endif // LIBMESH_ENABLE_CONSTRAINTS
5389 #ifdef LIBMESH_ENABLE_AMR
5399 libmesh_assert_greater (elem->p_level(), p);
5400 libmesh_assert_less (s, elem->n_sides());
5402 const unsigned int sys_num = this->
sys_number();
5405 const unsigned int n_nodes = elem->n_nodes();
5406 for (
unsigned int n = 0; n != n_nodes; ++n)
5407 if (elem->is_node_on_side(n, s))
5409 const Node & node = elem->node_ref(n);
5410 const unsigned int low_nc =
5411 FEInterface::n_dofs_at_node (fe_type, p, elem, n);
5412 const unsigned int high_nc =
5413 FEInterface::n_dofs_at_node (fe_type, elem, n);
5418 Threads::spin_mutex::scoped_lock lock(Threads::spin_mtx);
5420 if (elem->is_vertex(n))
5424 for (
unsigned int i = low_nc; i != high_nc; ++i)
5432 const unsigned int total_dofs = node.n_comp(sys_num, var);
5433 libmesh_assert_greater_equal (total_dofs, high_nc);
5436 for (
unsigned int j = low_nc; j != high_nc; ++j)
5438 const unsigned int i = total_dofs - j - 1;
5446 #endif // LIBMESH_ENABLE_AMR
5449 #ifdef LIBMESH_ENABLE_DIRICHLET
5457 unsigned int qoi_index)
5459 unsigned int old_size = cast_int<unsigned int>
5461 for (
unsigned int i = old_size; i <= qoi_index; ++i)
5466 (std::make_unique<DirichletBoundary>(dirichlet_boundary));
5490 unsigned int old_size = cast_int<unsigned int>
5492 for (
unsigned int i = old_size; i <= q; ++i)
5502 auto lam = [&boundary_to_remove](
const auto & bdy)
5503 {
return bdy->b == boundary_to_remove.
b && bdy->variables == boundary_to_remove.
variables;};
5514 unsigned int qoi_index)
5519 auto lam = [&boundary_to_remove](
const auto & bdy)
5520 {
return bdy->b == boundary_to_remove.
b && bdy->variables == boundary_to_remove.
variables;};
5535 const std::set<boundary_id_type>& mesh_side_bcids =
5536 mesh.get_boundary_info().get_boundary_ids();
5537 const std::set<boundary_id_type>& mesh_edge_bcids =
5538 mesh.get_boundary_info().get_edge_boundary_ids();
5539 const std::set<boundary_id_type>& mesh_node_bcids =
5540 mesh.get_boundary_info().get_node_boundary_ids();
5541 const std::set<boundary_id_type>& dbc_bcids = boundary.
b;
5544 libmesh_assert(mesh.comm().verify(dbc_bcids.size()));
5546 for (
const auto & bc_id : dbc_bcids)
5549 libmesh_assert(mesh.comm().verify(bc_id));
5551 bool found_bcid = (mesh_side_bcids.find(bc_id) != mesh_side_bcids.end() ||
5552 mesh_edge_bcids.find(bc_id) != mesh_edge_bcids.end() ||
5553 mesh_node_bcids.find(bc_id) != mesh_node_bcids.end());
5558 mesh.comm().max(found_bcid);
5560 libmesh_error_msg_if(!found_bcid,
5561 "Could not find Dirichlet boundary id " << bc_id <<
" in mesh!");
5565 #endif // LIBMESH_ENABLE_DIRICHLET
5568 #ifdef LIBMESH_ENABLE_PERIODIC
5575 if (!existing_boundary)
5585 existing_boundary->
merge(periodic_boundary);
5589 libmesh_assert(inverse_boundary);
5590 inverse_boundary->
merge(periodic_boundary);
void remove_adjoint_dirichlet_boundary(const DirichletBoundary &dirichlet_boundary, unsigned int q)
Removes from the system the specified Dirichlet boundary for the adjoint equation defined by Quantity...
std::unique_ptr< FEMFunctionBase< Gradient > > g_fem
virtual bool closed() const
检查向量是否已经关闭并准备好进行计算。
void add_adjoint_dirichlet_boundary(const DirichletBoundary &dirichlet_boundary, unsigned int q)
Adds a copy of the specified Dirichlet boundary to the system, corresponding to the adjoint problem d...
const FEType & type() const
virtual Output component(unsigned int i, const Point &p, Real time=0.)
unsigned int n() const
返回矩阵的列维度。
std::unique_ptr< FunctionBase< Number > > f
void scatter_constraints(MeshBase &)
Sends constraint equations to constraining processors.
void add_periodic_boundary(const PeriodicBoundaryBase &periodic_boundary)
Adds a copy of the specified periodic boundary to the system.
bool _error_on_constraint_loop
This flag indicates whether or not we do an opt-mode check for the presence of constraint loops...
virtual void zero() overridefinal
将矩阵的所有元素设置为0,并重置任何可能先前设置的分解标志。 这允许例如计算新的LU分解,同时重用相同的存储空间。
void add_adjoint_constraint_row(const unsigned int qoi_index, const dof_id_type dof_number, const DofConstraintRow &constraint_row, const Number constraint_rhs, const bool forbid_constraint_overwrite)
Adds a copy of the user-defined row to the constraint matrix, using an inhomogeneous right-hand-side ...
void process_mesh_constraint_rows(const MeshBase &mesh)
Adds any spline constraints from the Mesh to our DoF constraints.
const FEType & variable_type(const unsigned int c) const
dof_id_type n_constrained_dofs() const
static constexpr Real TOLERANCE
void build_constraint_matrix_and_vector(DenseMatrix< Number > &C, DenseVector< Number > &H, std::vector< dof_id_type > &elem_dofs, int qoi_index=-1, const bool called_recursively=false) const
Build the constraint matrix C and the forcing vector H associated with the element degree of freedom ...
Real jacobian_tolerance
Defaults to zero, but can be set to a custom small negative value to try and avoid spurious zero (or ...
We're using a class instead of a typedef to allow forward declarations and future flexibility...
void check_dirichlet_bcid_consistency(const MeshBase &mesh, const DirichletBoundary &boundary) const
Check that all the ids in dirichlet_bcids are actually present in the mesh.
void vector_mult_transpose(DenseVector< T > &dest, const DenseVector< T > &arg) const
执行矩阵-向量乘法,dest := (*this)^T * arg。
virtual numeric_index_type size() const =0
获取向量的大小。
void resize(const unsigned int n)
调整向量的大小。将所有元素设置为0。
void remove_dirichlet_boundary(const DirichletBoundary &dirichlet_boundary)
Removes the specified Dirichlet boundary from the system.
std::set< GhostingFunctor * >::const_iterator coupling_functors_begin() const
Beginning of range of coupling functors.
std::vector< dof_id_type > _send_list
A list containing all the global DOF indices that affect the solution on my processor.
void constrain_element_vector(DenseVector< Number > &rhs, std::vector< dof_id_type > &dofs, bool asymmetric_constraint_rows=true) const
Constrains the element vector.
void enforce_constraints_on_jacobian(const NonlinearImplicitSystem &system, SparseMatrix< Number > *jac) const
boundary_id_type pairedboundary
void gather_constraints(MeshBase &mesh, std::set< dof_id_type > &unexpanded_dofs, bool look_for_constrainees)
Helper function for querying about constraint equations on other processors.
std::unique_ptr< DirichletBoundaries > _dirichlet_boundaries
Data structure containing Dirichlet functions.
This class allows one to associate Dirichlet boundary values with a given set of mesh boundary ids an...
The Node constraint storage format.
std::vector< unsigned int > variables
此类定义了LIBMESH_DIM维的实数或复数空间中的向量。
bool local_index(dof_id_type dof_index) const
dof_id_type n_dofs() const
static std::unique_ptr< SparseMatrix< T > > build(const Parallel::Communicator &comm, const SolverPackage solver_package=libMesh::default_solver_package(), const MatrixBuildType matrix_build_type=MatrixBuildType::AUTOMATIC)
使用由 solver_package 指定的线性求解器包构建一个 SparseMatrix<T>。
unsigned int first_scalar_number() const
uint8_t processor_id_type
virtual void set(const numeric_index_type i, const numeric_index_type j, const T value)=0
设置元素 (i,j) 为 value .
AdjointDofConstraintValues _adjoint_constraint_values
void check_for_constraint_loops()
unsigned int number() const
bool has_adjoint_dirichlet_boundaries(unsigned int q) const
void merge(const PeriodicBoundaryBase &pb)
ADRealEigenVector< T, D, asd > abs(const ADRealEigenVector< T, D, asd > &)
计算自动微分实数向量的绝对值。
这是一个通用的稀疏矩阵类。该类包含了必须在派生类中覆盖的纯虚拟成员。 使用一个公共的基类允许从不同的求解器包中以不同的格式统一访问稀疏矩阵。
This class handles the numbering of degrees of freedom on a mesh.
std::unique_ptr< FEMFunctionBase< Number > > f_fem
const DirichletBoundaries * get_adjoint_dirichlet_boundaries(unsigned int q) const
boundary_id_type myboundary
The boundary ID of this boundary and its counterpart.
bool is_constrained_dof(const dof_id_type dof) const
void print_dof_constraints(std::ostream &os=libMesh::out, bool print_nonlocal=false) const
Prints (from processor 0) all DoF and Node constraints.
bool is_constrained_node(const Node *node) const
This class defines the notion of a variable in the system.
std::string get_local_constraints(bool print_nonlocal=false) const
Gets a string reporting all DoF and Node constraints local to this processor.
void add_constraint_row(const dof_id_type dof_number, const DofConstraintRow &constraint_row, const Number constraint_rhs, const bool forbid_constraint_overwrite)
Adds a copy of the user-defined row to the constraint matrix, using an inhomogeneous right-hand-side ...
unsigned int m() const
返回矩阵的行维度。
std::set< std::unique_ptr< CouplingMatrix >, Utility::CompareUnderlying > CouplingMatricesSet
void enforce_constraints_exactly(const System &system, NumericVector< Number > *v=nullptr, bool homogeneous=false) const
Constrains the numeric vector v, which represents a solution defined on the mesh. ...
void vector_mult_add(DenseVector< T > &dest, const T factor, const DenseVector< T > &arg) const
执行缩放矩阵-向量乘法,结果存储在 dest 中。 dest += factor * (*this) * arg.
dof_id_type n_local_constrained_dofs() const
virtual void init_context(const FEMContext &)
准备上下文对象以供使用。
We're using a class instead of a typedef to allow forward declarations and future flexibility...
bool active_on_subdomain(subdomain_id_type sid) const
void constrain_element_matrix_and_vector(DenseMatrix< Number > &matrix, DenseVector< Number > &rhs, std::vector< dof_id_type > &elem_dofs, bool asymmetric_constraint_rows=true) const
Constrains the element matrix and vector.
static const dof_id_type invalid_id
An invalid id to distinguish an uninitialized DofObject.
void allgather_recursive_constraints(MeshBase &)
Gathers constraint equation dependencies from other processors.
void constrain_nothing(std::vector< dof_id_type > &dofs) const
Does not actually constrain anything, but modifies dofs in the same way as any of the constrain funct...
virtual void right_multiply(const DenseMatrixBase< T > &M2) overridefinal
右乘以矩阵 M2。
DofConstraints _dof_constraints
Data structure containing DOF constraints.
std::unique_ptr< SparsityPattern::Build > build_sparsity(const MeshBase &mesh, bool calculate_constrained=false) const
Builds a sparsity pattern for matrices using the current degree-of-freedom numbering and coupling...
void build_constraint_matrix(DenseMatrix< Number > &C, std::vector< dof_id_type > &elem_dofs, const bool called_recursively=false) const
Build the constraint matrix C associated with the element degree of freedom indices elem_dofs...
unsigned int sys_number() const
virtual std::unique_ptr< PeriodicBoundaryBase > clone(TransformationType t=FORWARD) const =0
If we want the DofMap to be able to make copies of references and store them in the underlying map...
virtual void zero() overridefinal
将向量中的每个元素设置为0。由于派生类中的存储方法可能不同,需要将其声明为纯虚函数。
virtual void close()=0
调用 NumericVector 的内部组装函数,确保值在处理器之间一致。
void constrain_element_residual(DenseVector< Number > &rhs, std::vector< dof_id_type > &elem_dofs, NumericVector< Number > &solution_local) const
Constrains the element residual.
static std::unique_ptr< NumericVector< T > > build(const Parallel::Communicator &comm, const SolverPackage solver_package=libMesh::default_solver_package())
构建一个 NumericVector 对象。
Storage for DofConstraint right hand sides for a particular problem.
dof_id_type end_dof() const
std::vector< std::unique_ptr< DirichletBoundaries > > _adjoint_dirichlet_boundaries
Data structure containing Dirichlet functions.
unsigned int n_variables() const
virtual numeric_index_type first_local_index() const =0
获取实际存储在该处理器上的第一个向量元素的索引。
std::unique_ptr< PeriodicBoundaries > _periodic_boundaries
Data structure containing periodic boundaries.
void heterogeneously_constrain_element_jacobian_and_residual(DenseMatrix< Number > &matrix, DenseVector< Number > &rhs, std::vector< dof_id_type > &elem_dofs, NumericVector< Number > &solution_local) const
Constrains the element Jacobian and residual.
void heterogeneously_constrain_element_residual(DenseVector< Number > &rhs, std::vector< dof_id_type > &elem_dofs, NumericVector< Number > &solution_local) const
Constrains the element residual.
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
void left_multiply_transpose(const DenseMatrix< T > &A)
用矩阵 A 的转置左乘。
void process_constraints(MeshBase &)
Postprocesses any constrained degrees of freedom to be constrained only in terms of unconstrained dof...
static void merge_ghost_functor_outputs(GhostingFunctor::map_type &elements_to_ghost, CouplingMatricesSet &temporary_coupling_matrices, const std::set< GhostingFunctor * >::iterator &gf_begin, const std::set< GhostingFunctor * >::iterator &gf_end, const MeshBase::const_element_iterator &elems_begin, const MeshBase::const_element_iterator &elems_end, processor_id_type p)
void constrain_element_matrix(DenseMatrix< Number > &matrix, std::vector< dof_id_type > &elem_dofs, bool asymmetric_constraint_rows=true) const
Constrains the element matrix.
std::pair< Real, Real > max_constraint_error(const System &system, NumericVector< Number > *v=nullptr) const
Tests the constrained degrees of freedom on the numeric vector v, which represents a solution defined...
std::unique_ptr< FunctionBase< Gradient > > g
bool _verify_dirichlet_bc_consistency
Flag which determines whether we should do some additional checking of the consistency of the Dirichl...
void add_constraints_to_send_list()
Adds entries to the _send_list vector corresponding to DoFs which are dependencies for constraint equ...
virtual void get(const std::vector< numeric_index_type > &index, T *values) const
一次访问多个组件。 values 将 *不会* 重新分配空间;它应该已经具有足够的空间。 默认实现对每个索引调用 operator() ,但某些实现可能在此处提供更快的方法。 ...
DofConstraintValueMap _primal_constraint_values
virtual numeric_index_type local_size() const =0
获取向量的本地大小,即 index_stop - index_start。
dof_id_type n_local_dofs() const
virtual Output component(const FEMContext &, unsigned int i, const Point &p, Real time=0.)
返回坐标p和时间time的向量分量i。
ParallelType type() const
获取向量的类型。
void resize(const unsigned int new_m, const unsigned int new_n)
调整矩阵的大小,并调用 zero() 方法。
std::map< dof_id_type, Real, std::less< dof_id_type >, Threads::scalable_allocator< std::pair< const dof_id_type, Real > > > DofConstraintRow
A row of the Dof constraint matrix.
void heterogeneously_constrain_element_vector(const DenseMatrix< Number > &matrix, DenseVector< Number > &rhs, std::vector< dof_id_type > &elem_dofs, bool asymmetric_constraint_rows=true, int qoi_index=-1) const
Constrains the element vector.
std::vector< dof_id_type > _end_df
Last DOF index (plus 1) on processor p.
void add_dirichlet_boundary(const DirichletBoundary &dirichlet_boundary)
Adds a copy of the specified Dirichlet boundary to the system.
The base class for defining periodic boundaries.
void create_dof_constraints(const MeshBase &, Real time=0)
Rebuilds the raw degree of freedom and DofObject constraints.
std::set< boundary_id_type > b
std::map< const Node *, Real, std::less< const Node * >, Threads::scalable_allocator< std::pair< const Node *const, Real > > > NodeConstraintRow
A row of the Node constraint mapping.
virtual void set(const numeric_index_type i, const T value)=0
设置 v(i) = value 。 请注意,此方法的库实现是线程安全的, 例如,将在写入向量之前锁定 _numeric_vector_mutex 。
void cholesky_solve(const DenseVector< T2 > &b, DenseVector< T2 > &x)
对于对称正定矩阵(SPD),进行Cholesky分解。 分解为 A = L L^T,比标准LU分解大约快两倍。 因此,如果事先知道矩阵是SPD,则可以使用此方法。如果矩阵不是SPD,则会生成错误。 Ch...
定义用于有限元计算的稠密向量类。该类基本上是为了补充 DenseMatrix 类而设计的。 它相对于 std::vector 具有额外的功能,使其在有限元中特别有用,特别是对于方程组。 所有重写的虚拟函...
std::set< GhostingFunctor * >::const_iterator coupling_functors_end() const
End of range of coupling functors.
FunctionBase是一个函数对象的基类,可以在某一点(可选地包括时间)进行评估。
void vector_mult(DenseVector< T > &dest, const DenseVector< T > &arg) const
执行矩阵-向量乘法,dest := (*this) * arg。
void constrain_element_dyad_matrix(DenseVector< Number > &v, DenseVector< Number > &w, std::vector< dof_id_type > &row_dofs, bool asymmetric_constraint_rows=true) const
Constrains a dyadic element matrix B = v w'.
FEMFunctionBase是一个基类,用户可以从中派生出“函数样式”的对象,以在FEMSystem中使用。
定义用于有限元类型计算的密集矩阵。 用于在求和成全局矩阵之前存储单元刚度矩阵。所有被覆盖的虚函数都记录在dense_matrix_base.h中。
const std::vector< dof_id_type > & get_send_list() const
virtual unsigned int size() const overridefinal
virtual numeric_index_type last_local_index() const =0
获取实际存储在该处理器上的最后一个向量元素的索引+1。
The constraint matrix storage format.
void heterogeneously_constrain_element_matrix_and_vector(DenseMatrix< Number > &matrix, DenseVector< Number > &rhs, std::vector< dof_id_type > &elem_dofs, bool asymmetric_constraint_rows=true, int qoi_index=-1) const
Constrains the element matrix and vector.
void enforce_adjoint_constraints_exactly(NumericVector< Number > &v, unsigned int q) const
Heterogeneously constrains the numeric vector v, which represents an adjoint solution defined on the ...
This class provides single index access to FieldType (i.e.
void constrain_p_dofs(unsigned int var, const Elem *elem, unsigned int s, unsigned int p)
Constrains degrees of freedom on side s of element elem which correspond to variable number var and t...
void check_for_cyclic_constraints()
Throw an error if we detect any constraint loops, i.e.
dof_id_type first_dof() const
void enforce_constraints_on_residual(const NonlinearImplicitSystem &system, NumericVector< Number > *rhs, NumericVector< Number > const *solution, bool homogeneous=true) const
NodeConstraints _node_constraints
Data structure containing DofObject constraints.
void dof_indices(const Elem *const elem, std::vector< dof_id_type > &di) const
Fills the vector di with the global degree of freedom indices for the element.
virtual void localize(std::vector< T > &v_local) const =0
创建全局向量的副本并存储在本地向量 v_local 中。