21#include "libmesh/dof_map.h"
24#include "libmesh/coupling_matrix.h"
25#include "libmesh/default_coupling.h"
26#include "libmesh/dense_matrix.h"
27#include "libmesh/dense_vector_base.h"
28#include "libmesh/dirichlet_boundaries.h"
29#include "libmesh/enum_to_string.h"
30#include "libmesh/fe_type.h"
31#include "libmesh/fe_base.h"
32#include "libmesh/ghosting_functor.h"
33#include "libmesh/int_range.h"
34#include "libmesh/mesh_base.h"
35#include "libmesh/mesh_tools.h"
36#include "libmesh/numeric_vector.h"
37#include "libmesh/periodic_boundary_base.h"
38#include "libmesh/periodic_boundaries.h"
39#include "libmesh/sparse_matrix.h"
40#include "libmesh/sparsity_pattern.h"
41#include "libmesh/threads.h"
42#include "libmesh/static_condensation_dof_map.h"
43#include "libmesh/system.h"
44#include "libmesh/parallel_fe_type.h"
55#include <unordered_map>
62std::unique_ptr<SparsityPattern::Build>
64 const bool calculate_constrained,
65 const bool use_condensed_system)
const
69 LOG_SCOPE(
"build_sparsity()",
"DofMap");
85 if (use_condensed_system)
99 auto sp = std::make_unique<SparsityPattern::Build>
103 implicit_neighbor_dofs,
105 calculate_constrained,
109 mesh.active_local_elements_end()), *sp);
113 libmesh_assert_equal_to (sp->get_sparsity_pattern().size(), this->n_local_dofs());
121 libMesh::out <<
"WARNING: You have specified both an extra sparsity function and object.\n"
122 <<
" Are you sure this is what you meant to do??"
141 _dof_coupling(nullptr),
142 _error_on_constraint_loop(false),
143 _constrained_sparsity_construction(false),
146 _variable_group_numbers(),
152 _augment_sparsity_pattern(nullptr),
153 _extra_sparsity_function(nullptr),
154 _extra_sparsity_context(nullptr),
155 _augment_send_list(nullptr),
156 _extra_send_list_function(nullptr),
157 _extra_send_list_context(nullptr),
160 need_full_sparsity_pattern(false),
162#ifdef LIBMESH_ENABLE_AMR
163 , _first_old_scalar_df()
165#ifdef LIBMESH_ENABLE_CONSTRAINTS
167 , _stashed_dof_constraints()
168 , _primal_constraint_values()
169 , _adjoint_constraint_values()
171#ifdef LIBMESH_ENABLE_NODE_CONSTRAINTS
172 , _node_constraints()
174#ifdef LIBMESH_ENABLE_PERIODIC
177#ifdef LIBMESH_ENABLE_DIRICHLET
179 , _adjoint_dirichlet_boundaries()
181 , _implicit_neighbor_dofs_initialized(false),
182 _implicit_neighbor_dofs(false),
183 _verify_dirichlet_bc_consistency(true),
192#ifdef LIBMESH_ENABLE_PERIODIC
215#ifdef LIBMESH_ENABLE_PERIODIC
242 parallel_object_only();
261 (!
_sp->get_n_nz().empty() ||
262 !
_sp->get_n_oz().empty());
263 this->
comm().
max(computed_sparsity_already);
305 return mesh.node_ptr(i);
312 return mesh.elem_ptr(i);
317template <
typename iterator_type>
319 iterator_type objects_end,
321 dofobject_accessor objects)
324 parallel_object_only();
328 std::unordered_map<processor_id_type, dof_id_type> ghost_objects_from_proc;
330 iterator_type it = objects_begin;
332 for (; it != objects_end; ++it)
341 ghost_objects_from_proc[obj_procid]++;
346 std::map<processor_id_type, std::vector<dof_id_type>>
351 for (
auto [p, size] : ghost_objects_from_proc)
354 requested_ids[p].reserve(size);
357 for (it = objects_begin; it != objects_end; ++it)
366 if (ghost_objects_from_proc.count(p))
367 libmesh_assert_equal_to (requested_ids[p].size(), ghost_objects_from_proc[p]);
373 typedef std::vector<dof_id_type> datum;
375 auto gather_functor =
376 [
this, &
mesh, &objects]
378 const std::vector<dof_id_type> & ids,
379 std::vector<datum> & data)
386 const std::size_t query_size = ids.size();
388 data.resize(query_size);
389 for (
auto & d : data)
390 d.resize(2 * n_var_groups);
392 for (std::size_t i=0; i != query_size; ++i)
396 libmesh_assert_equal_to (requested->
processor_id(), this->processor_id());
397 libmesh_assert_equal_to (requested->
n_var_groups(sys_num), n_var_groups);
398 for (
unsigned int vg=0; vg != n_var_groups; ++vg)
400 unsigned int n_comp_g =
402 data[i][vg] = n_comp_g;
406 data[i][n_var_groups+vg] = my_first_dof;
411 auto action_functor =
412 [
this, &
mesh, &objects]
414 const std::vector<dof_id_type> & ids,
415 const std::vector<datum> & data)
426 libmesh_assert_equal_to (requested->
processor_id(), pid);
427 for (
unsigned int vg=0; vg != n_var_groups; ++vg)
429 unsigned int n_comp_g =
430 cast_int<unsigned int>(data[i][vg]);
434 dof_id_type my_first_dof = data[i][n_var_groups+vg];
437 (sys_num, vg, my_first_dof);
443 datum * ex =
nullptr;
445 (this->
comm(), requested_ids, gather_functor, action_functor, ex);
449 for (it = objects_begin; it != objects_end; ++it)
454 for (
unsigned int v=0; v != num_variables; ++v)
456 unsigned int n_comp =
470 const std::map<
const Node *, std::set<subdomain_id_type>> &
471 constraining_subdomains)
475 LOG_SCOPE(
"reinit()",
"DofMap");
478 const bool constraining_subdomains_empty =
479 constraining_subdomains.empty();
494 unsigned int standard_n_levels =
510 std::vector<unsigned int> n_vars_per_group; n_vars_per_group.reserve (n_var_groups);
512 for (
unsigned int vg=0; vg<n_var_groups; vg++)
513 n_vars_per_group.push_back (this->variable_group(vg).n_variables());
515#ifdef LIBMESH_ENABLE_AMR
520 for (
auto & node :
mesh.node_ptr_range())
522 node->clear_old_dof_object();
527 (
mesh.element_stored_range(),
530 for (Elem * elem : range)
532 elem->clear_old_dof_object();
533 libmesh_assert (!elem->get_old_dof_object());
541 for (
auto & elem :
mesh.element_ptr_range())
547 for (
Node & node : elem->node_ref_range())
548 if (node.get_old_dof_object() == nullptr)
549 if (node.has_dofs(sys_num))
550 node.set_old_dof_object();
554 if (elem->has_dofs(sys_num))
555 elem->set_old_dof_object();
567 for (
auto & node :
mesh.node_ptr_range())
568 node->set_n_vars_per_group(sys_num, n_vars_per_group);
573 [sys_num, n_vars_per_group](
const ElemRange & range)
575 for (Elem * elem : range)
576 elem->set_n_vars_per_group(sys_num, n_vars_per_group);
580 this->_n_SCALAR_dofs = 0;
584 for (
unsigned int vg=0; vg<n_var_groups; vg++)
586 const VariableGroup & vg_description = this->variable_group(vg);
588 const unsigned int n_var_in_group = vg_description.n_variables();
589 const FEType & base_fe_type = vg_description.type();
591 const bool add_p_level = base_fe_type.p_refinement;
595 if (base_fe_type.family ==
SCALAR)
597 this->_n_SCALAR_dofs += base_fe_type.order.get_order()*n_var_in_group;
602 const bool extra_hanging_dofs =
606 for (
auto & elem :
mesh.active_element_ptr_range())
614 const bool active_on_elem =
615 vg_description.active_on_subdomain(elem->subdomain_id());
619 if (!active_on_elem && constraining_subdomains_empty)
622 FEType fe_type = base_fe_type;
626 libmesh_error_msg_if(base_fe_type.order.get_order() >
628 "ERROR: Finite element "
630 <<
" on geometric element "
632 <<
"\nonly supports FEInterface::max_order = "
634 <<
", not fe_type.order = "
635 << base_fe_type.order);
637#ifdef LIBMESH_ENABLE_AMR
640 if (base_fe_type.order + add_p_level*elem->p_level() >
646 <<
" on geometric element "
648 <<
"could not be p refined past FEInterface::max_order = "
653 -
int(base_fe_type.order));
658 for (
auto n : elem->node_index_range())
660 Node & node = elem->node_ref(n);
665 bool active_on_node = active_on_elem;
667 if (
auto it = constraining_subdomains.find(&node);
668 it != constraining_subdomains.end())
669 for (
auto s : it->second)
670 if (vg_description.active_on_subdomain(s))
672 active_on_node =
true;
679 if (elem->is_vertex(n))
681 const unsigned int old_node_dofs =
682 node.n_comp_group(sys_num, vg);
684 const unsigned int vertex_dofs =
689 if (vertex_dofs > old_node_dofs)
691 node.set_n_comp_group(sys_num, vg,
696 node.set_vg_dof_base(sys_num, vg,
714 for (
auto & elem :
mesh.active_element_ptr_range())
722 const bool active_on_elem =
723 vg_description.active_on_subdomain(elem->subdomain_id());
727 if (!active_on_elem && constraining_subdomains_empty)
731 for (
auto n : elem->node_index_range())
733 Node & node = elem->node_ref(n);
738 bool active_on_node = active_on_elem;
740 if (
auto it = constraining_subdomains.find(&node);
741 it != constraining_subdomains.end())
742 for (
auto s : it->second)
743 if (vg_description.active_on_subdomain(s))
745 active_on_node =
true;
752 const unsigned int old_node_dofs =
753 node.n_comp_group(sys_num, vg);
755 const unsigned int vertex_dofs = old_node_dofs?
756 cast_int<unsigned int>(node.vg_dof_base (sys_num,vg)):0;
758 const unsigned int new_node_dofs =
762 if (elem->is_vertex(n))
764 libmesh_assert_greater_equal (old_node_dofs, vertex_dofs);
774 libmesh_assert_greater_equal (vertex_dofs, new_node_dofs);
783 node.set_n_comp_group(sys_num, vg,
788 node.set_vg_dof_base(sys_num, vg, 0);
794 else if (vertex_dofs == 0)
796 if (new_node_dofs > old_node_dofs)
798 node.set_n_comp_group(sys_num, vg,
801 node.set_vg_dof_base(sys_num, vg,
808 else if (extra_hanging_dofs)
810 if (new_node_dofs > old_node_dofs - vertex_dofs)
812 node.set_n_comp_group(sys_num, vg,
813 vertex_dofs + new_node_dofs);
815 node.set_vg_dof_base(sys_num, vg,
823 libmesh_assert_greater_equal (old_node_dofs, vertex_dofs);
824 if (new_node_dofs > old_node_dofs)
826 node.set_n_comp_group(sys_num, vg,
829 node.set_vg_dof_base (sys_num, vg,
836 const unsigned int dofs_per_elem =
839 elem->set_n_comp_group(sys_num, vg, dofs_per_elem);
851 this->invalidate_dofs(
mesh);
858 const unsigned int sys_num = this->sys_number();
861 for (
auto & node :
mesh.node_ptr_range())
862 node->invalidate_dofs(sys_num);
865 for (
auto & elem :
mesh.active_element_ptr_range())
866 elem->invalidate_dofs(sys_num);
882 _dof_coupling =
nullptr;
886 for (
const auto & gf : _coupling_functors)
889 _mesh.remove_ghosting_functor(*gf);
891 this->_coupling_functors.clear();
895 _default_coupling->set_dof_coupling(this->_dof_coupling);
896 _default_coupling->set_n_levels(this->use_coupled_neighbor_dofs(this->_mesh));
898 this->add_coupling_functor(*_default_coupling);
903 for (
const auto & gf : _algebraic_ghosting_functors)
906 _mesh.remove_ghosting_functor(*gf);
908 this->_algebraic_ghosting_functors.clear();
913 _default_evaluating->set_n_levels(1);
914 this->add_algebraic_ghosting_functor(*_default_evaluating);
917 this->_shared_functors.clear();
920 _variable_groups.clear();
922 _variable_group_numbers.clear();
923 _array_variables.clear();
924 _first_scalar_df.clear();
925 this->clear_send_list();
926 this->clear_sparsity();
927 need_full_sparsity_pattern =
false;
929#ifdef LIBMESH_ENABLE_AMR
931 _dof_constraints.clear();
932 _stashed_dof_constraints.clear();
933 _primal_constraint_values.clear();
934 _adjoint_constraint_values.clear();
936 _first_old_df.clear();
938 _first_old_scalar_df.clear();
952 parallel_object_only();
955 LOG_SCOPE(
"distribute_dofs()",
"DofMap");
965 libmesh_assert_less (proc_id, n_proc);
970 const std::map<const Node *, std::set<subdomain_id_type>>
971 constraining_subdomains =
972 this->calculate_constraining_subdomains();
976 constraining_subdomains);
988 this->clear_send_list();
992 this->distribute_local_dofs_node_major
993 (next_free_dof,
mesh, constraining_subdomains);
995 this->distribute_local_dofs_var_major
996 (next_free_dof,
mesh, constraining_subdomains);
999 const auto n_dofs = this->compute_dof_info(next_free_dof);
1003 this->invalidate_dofs(
mesh);
1005 next_free_dof = _first_df[proc_id];
1008 if (node_major_dofs)
1009 this->distribute_local_dofs_node_major
1010 (next_free_dof,
mesh, constraining_subdomains);
1012 this->distribute_local_dofs_var_major
1013 (next_free_dof,
mesh, constraining_subdomains);
1015 libmesh_assert_equal_to (next_free_dof, _end_df[proc_id]);
1023 if (this->n_processors() > 1)
1025 this->set_nonlocal_dof_objects(
mesh.nodes_begin(),
1027 mesh, &DofMap::node_ptr);
1029 this->set_nonlocal_dof_objects(
mesh.elements_begin(),
1030 mesh.elements_end(),
1031 mesh, &DofMap::elem_ptr);
1037 sys_num = this->sys_number();
1041 MeshTools::libmesh_assert_valid_dof_ids(
mesh, sys_num);
1044 for (
auto & node :
mesh.node_ptr_range())
1053 libmesh_assert_greater_equal (dofid, this->first_dof(obj_proc_id));
1054 libmesh_assert_less (dofid, this->end_dof(obj_proc_id));
1058 for (
auto & elem :
mesh.element_ptr_range())
1067 libmesh_assert_greater_equal (dofid, this->first_dof(obj_proc_id));
1068 libmesh_assert_less (dofid, this->end_dof(obj_proc_id));
1075#ifdef LIBMESH_ENABLE_AMR
1076 _first_old_scalar_df = _first_scalar_df;
1078 _first_scalar_df.clear();
1079 _first_scalar_df.resize(this->n_variables(), DofObject::invalid_id);
1080 dof_id_type current_SCALAR_dof_index = n_dofs - n_SCALAR_dofs();
1086 for (
auto v :
make_range(this->n_variables()))
1087 if (this->variable(v).type().family ==
SCALAR)
1089 _first_scalar_df[v] = current_SCALAR_dof_index;
1090 current_SCALAR_dof_index += this->variable(v).type().order.get_order();
1094 for (
const auto & gf : _algebraic_ghosting_functors)
1097 gf->dofmap_reinit();
1100 for (
const auto & gf : _coupling_functors)
1103 gf->dofmap_reinit();
1109 this->add_neighbors_to_send_list(
mesh);
1120template <
typename T, std::enable_if_t<std::is_same_v<T, dof_
id_type> ||
1121 std::is_same_v<T, std::vector<dof_
id_type>>,
int>>
1122void DofMap::local_variable_indices(T & idx,
1124 unsigned int var_num)
const
1129 if constexpr (std::is_same_v<T, dof_id_type>)
1131 else if constexpr (std::is_same_v<T, std::vector<dof_id_type>>)
1138 const unsigned int sys_num = this->sys_number();
1142 if (this->variable_type(var_num).family !=
SCALAR)
1144 const Variable & var(this->variable(var_num));
1146 for (
auto & elem :
mesh.active_local_element_ptr_range())
1153 const unsigned int n_nodes = elem->n_nodes();
1156 for (
unsigned int n=0; n<
n_nodes; n++)
1158 const Node & node = elem->node_ref(n);
1163 const unsigned int n_comp = node.
n_comp(sys_num, var_num);
1164 for(
unsigned int i=0; i<n_comp; i++)
1169 if constexpr (std::is_same_v<T, dof_id_type>)
1171 if (idx == 0 || index > greatest)
1172 { idx++; greatest = index; }
1174 else if constexpr (std::is_same_v<T, std::vector<dof_id_type>>)
1176 if (idx.empty() || index > idx.back())
1177 idx.push_back(index);
1183 const unsigned int n_comp = elem->n_comp(sys_num, var_num);
1184 for (
unsigned int i=0; i<n_comp; i++)
1186 const dof_id_type index = elem->dof_number(sys_num,var_num,i);
1188 if constexpr (std::is_same_v<T, dof_id_type>)
1190 if (idx == 0 || index > greatest)
1191 { idx++; greatest = index; }
1193 else if constexpr (std::is_same_v<T, std::vector<dof_id_type>>)
1195 if (idx.empty() || index > idx.back())
1196 idx.push_back(index);
1210 for (
const auto & node :
mesh.local_node_ptr_range())
1214 const unsigned int n_comp = node->n_comp(sys_num, var_num);
1215 for (
unsigned int i=0; i<n_comp; i++)
1217 const dof_id_type index = node->dof_number(sys_num,var_num,i);
1219 if constexpr (std::is_same_v<T, dof_id_type>)
1221 if (idx == 0 || index > greatest)
1222 { idx++; greatest = index; }
1224 else if constexpr (std::is_same_v<T, std::vector<dof_id_type>>)
1226 if (idx.empty() || index > idx.back())
1227 idx.push_back(index);
1234 else if (this->processor_id() == (this->n_processors()-1))
1236 std::vector<dof_id_type> di_scalar;
1237 this->SCALAR_dof_indices(di_scalar,var_num);
1239 if constexpr (std::is_same_v<T, dof_id_type>)
1240 idx += std::distance(di_scalar.begin(), di_scalar.end());
1241 else if constexpr (std::is_same_v<T, std::vector<dof_id_type>>)
1242 idx.insert(idx.end(), di_scalar.begin(), di_scalar.end());
1246template void DofMap::local_variable_indices(
dof_id_type &,
1248 unsigned int)
const;
1250template void DofMap::local_variable_indices(std::vector<dof_id_type> &,
1252 unsigned int)
const;
1255std::map<const Node *, std::set<subdomain_id_type>>
1256DofMap::calculate_constraining_subdomains()
1258 std::map<const Node *, std::set<subdomain_id_type>> constraining_subdomains;
1259 const auto & constraint_rows = _mesh.get_constraint_rows();
1264 if (!constraint_rows.empty())
1265 for (
auto & elem : _mesh.active_element_ptr_range())
1269 for (
const Node & node : elem->node_ref_range())
1271 if (
auto it = constraint_rows.find(&node);
1272 it != constraint_rows.end())
1274 for (
const auto & [pr, val] : it->second)
1276 const Node * spline_node =
1277 pr.first->node_ptr(pr.second);
1279 constraining_subdomains[spline_node].insert(sbdid);
1285 return constraining_subdomains;
1289void DofMap::distribute_local_dofs_node_major
1292 const std::map<
const Node *, std::set<subdomain_id_type>> &
1293 constraining_subdomains)
1295 const unsigned int sys_num = this->sys_number();
1296 const unsigned int n_var_groups = this->n_variable_groups();
1299 const bool constraining_subdomains_empty =
1300 constraining_subdomains.empty();
1307 for (
auto & elem :
mesh.active_local_element_ptr_range())
1311 const unsigned int n_nodes = elem->n_nodes();
1316 for (
unsigned int n=0; n<
n_nodes; n++)
1318 Node & node = elem->node_ref(n);
1320 for (
unsigned vg=0; vg<n_var_groups; vg++)
1322 const VariableGroup & vg_description(this->variable_group(vg));
1327 bool active_on_node =
1331 if (!active_on_node && !constraining_subdomains_empty)
1332 if (
auto it = constraining_subdomains.find(&node);
1333 it != constraining_subdomains.end())
1334 for (
auto s : it->second)
1337 active_on_node =
true;
1348 DofObject::invalid_id))
1361 for (
unsigned vg=0; vg<n_var_groups; vg++)
1363 const VariableGroup & vg_description(this->variable_group(vg));
1367 if (elem->n_comp_group(sys_num,vg) > 0)
1369 libmesh_assert_equal_to (elem->vg_dof_base(sys_num,vg),
1370 DofObject::invalid_id);
1372 elem->set_vg_dof_base(sys_num,
1377 elem->n_comp_group(sys_num,vg));
1391 for (
auto & node :
mesh.local_node_ptr_range())
1392 for (
unsigned vg=0; vg<n_var_groups; vg++)
1394 const VariableGroup & vg_description(this->variable_group(vg));
1396 if (node->n_comp_group(sys_num,vg))
1397 if (node->vg_dof_base(sys_num,vg) == DofObject::invalid_id)
1399 node->set_vg_dof_base (sys_num,
1404 node->n_comp(sys_num,vg));
1408 this->distribute_scalar_dofs(next_free_dof);
1411 this->assert_no_nodes_missed(
mesh);
1417void DofMap::distribute_local_dofs_var_major
1420 const std::map<
const Node *, std::set<subdomain_id_type>> &
1421 constraining_subdomains)
1423 const unsigned int sys_num = this->sys_number();
1424 const unsigned int n_var_groups = this->n_variable_groups();
1427 const bool constraining_subdomains_empty =
1428 constraining_subdomains.empty();
1435 for (
unsigned vg=0; vg<n_var_groups; vg++)
1437 const VariableGroup & vg_description(this->variable_group(vg));
1439 const unsigned int n_vars_in_group = vg_description.
n_variables();
1445 for (
auto & elem :
mesh.active_local_element_ptr_range())
1451 const bool active_on_elem =
1456 if (!active_on_elem && constraining_subdomains_empty)
1459 const unsigned int n_nodes = elem->n_nodes();
1462 for (
unsigned int n=0; n<
n_nodes; n++)
1464 Node & node = elem->node_ref(n);
1466 bool active_on_node = active_on_elem;
1467 if (!active_on_node)
1468 if (
auto it = constraining_subdomains.find(&node);
1469 it != constraining_subdomains.end())
1470 for (
auto s : it->second)
1473 active_on_node =
true;
1477 if (!active_on_node)
1485 DofObject::invalid_id))
1489 next_free_dof += (n_vars_in_group*
1495 if (elem->n_comp_group(sys_num,vg) > 0)
1497 libmesh_assert_equal_to (elem->vg_dof_base(sys_num,vg),
1498 DofObject::invalid_id);
1500 elem->set_vg_dof_base(sys_num,
1504 next_free_dof += (n_vars_in_group*
1505 elem->n_comp_group(sys_num,vg));
1517 for (
auto & node :
mesh.local_node_ptr_range())
1518 if (node->n_comp_group(sys_num,vg))
1519 if (node->vg_dof_base(sys_num,vg) == DofObject::invalid_id)
1521 node->set_vg_dof_base (sys_num,
1525 next_free_dof += (n_vars_in_group*
1526 node->n_comp_group(sys_num,vg));
1530 this->distribute_scalar_dofs(next_free_dof);
1533 this->assert_no_nodes_missed(
mesh);
1541 this->_n_SCALAR_dofs = 0;
1542 for (
auto vg :
make_range(this->n_variable_groups()))
1544 const VariableGroup & vg_description(this->variable_group(vg));
1548 this->_n_SCALAR_dofs += (vg_description.
n_variables()*
1556 if (this->processor_id() == (this->n_processors()-1))
1557 next_free_dof += _n_SCALAR_dofs;
1565 MeshTools::libmesh_assert_valid_procids<Node>(
mesh);
1567 for (
auto & node :
mesh.local_node_ptr_range())
1569 unsigned int n_var_g = node->n_var_groups(this->sys_number());
1570 for (
unsigned int vg=0; vg != n_var_g; ++vg)
1572 unsigned int n_comp_g =
1573 node->n_comp_group(this->sys_number(), vg);
1575 node->vg_dof_base(this->sys_number(), vg) : 0;
1576 libmesh_assert_not_equal_to (my_first_dof, DofObject::invalid_id);
1593 for (
const auto & gf :
as_range(gf_begin, gf_end))
1598 (*gf)(elems_begin, elems_end, p, more_elements_to_ghost);
1603#if defined(LIBMESH_ENABLE_DEPRECATED) && defined(LIBMESH_ENABLE_AMR)
1604 std::vector<std::pair<const Elem*, const CouplingMatrix*>> children_to_couple;
1605 for (
auto it = more_elements_to_ghost.begin();
1606 it != more_elements_to_ghost.end();)
1608 const Elem * elem = it->first;
1611 libmesh_deprecated();
1612 std::vector<const Elem*> children_to_ghost;
1615 for (
const Elem * child : children_to_ghost)
1616 if (child->processor_id() != p)
1617 children_to_couple.emplace_back(child, it->second);
1619 it = more_elements_to_ghost.erase(it);
1624 more_elements_to_ghost.insert(children_to_couple.begin(),
1625 children_to_couple.end());
1628 for (
const auto & [elem, elem_cm] : more_elements_to_ghost)
1634 if (
const auto existing_it = elements_to_ghost.find(elem);
1635 existing_it == elements_to_ghost.end())
1636 elements_to_ghost.emplace(elem, elem_cm);
1639 if (existing_it->second)
1646 if (temporary_coupling_matrices.empty() ||
1647 !temporary_coupling_matrices.count(existing_it->second))
1653 auto result_pr = temporary_coupling_matrices.insert(std::make_unique<CouplingMatrix>(*existing_it->second));
1654 existing_it->second = result_pr.first->get();
1670 if (
const auto temp_it = temporary_coupling_matrices.find(existing_it->second);
1671 temp_it != temporary_coupling_matrices.end())
1672 temporary_coupling_matrices.erase(temp_it);
1674 existing_it->second =
nullptr;
1689 LOG_SCOPE(
"add_neighbors_to_send_list()",
"DofMap");
1692 if (this->n_processors() == 1)
1695 const unsigned int n_var = this->n_variables();
1698 =
mesh.active_local_elements_begin();
1700 =
mesh.active_local_elements_end();
1708 this->merge_ghost_functor_outputs(elements_to_send,
1709 temporary_coupling_matrices,
1710 this->algebraic_ghosting_functors_begin(),
1711 this->algebraic_ghosting_functors_end(),
1712 local_elem_it, local_elem_end,
mesh.processor_id());
1714 this->merge_ghost_functor_outputs(elements_to_send,
1715 temporary_coupling_matrices,
1716 this->coupling_functors_begin(),
1717 this->coupling_functors_end(),
1718 local_elem_it, local_elem_end,
mesh.processor_id());
1723 std::map<const CouplingMatrix *, std::vector<unsigned int>>
1724 column_variable_lists;
1726 for (
const auto & [partner, ghost_coupling] : elements_to_send)
1729 libmesh_assert_not_equal_to
1730 (partner->processor_id(), this->processor_id());
1737 libmesh_assert_equal_to (ghost_coupling->size(), n_var);
1740 std::map<const CouplingMatrix *, std::vector<unsigned int>>::const_iterator
1741 column_variable_list = column_variable_lists.find(ghost_coupling);
1744 if (column_variable_list == column_variable_lists.end())
1746 auto inserted_variable_list_pair =
1747 column_variable_lists.emplace(ghost_coupling, std::vector<unsigned int>());
1748 column_variable_list = inserted_variable_list_pair.first;
1750 std::vector<unsigned int> & new_variable_list =
1751 inserted_variable_list_pair.first->second;
1753 std::vector<unsigned char> has_variable(n_var,
false);
1755 for (
unsigned int vi = 0; vi != n_var; ++vi)
1759 for (
const auto & vj : ccr)
1760 has_variable[vj] =
true;
1762 for (
unsigned int vj = 0; vj != n_var; ++vj)
1764 if (has_variable[vj])
1765 new_variable_list.push_back(vj);
1769 const std::vector<unsigned int> & variable_list =
1770 column_variable_list->second;
1772 for (
const auto & vj : variable_list)
1774 std::vector<dof_id_type> di;
1775 this->dof_indices (partner, di, vj);
1779 if (d != DofObject::invalid_id &&
1780 !this->local_index(d))
1782 libmesh_assert_less(d, this->n_dofs());
1783 _send_list.push_back(d);
1789 std::vector<dof_id_type> di;
1790 this->dof_indices (partner, di);
1793 for (
const auto & dof : di)
1794 if (dof != DofObject::invalid_id &&
1795 !this->local_index(dof))
1797 libmesh_assert_less(dof, this->n_dofs());
1798 _send_list.push_back(dof);
1805 temporary_coupling_matrices.clear();
1815 for ( ; local_elem_it != local_elem_end; ++local_elem_it)
1817 const Elem * elem = *local_elem_it;
1819 std::vector<dof_id_type> di;
1820 this->dof_indices (elem, di);
1823 for (
const auto & dof : di)
1824 if (dof != DofObject::invalid_id &&
1825 !this->local_index(dof))
1827 libmesh_assert_less(dof, this->n_dofs());
1828 _send_list.push_back(dof);
1835void DofMap::prepare_send_list ()
1837 LOG_SCOPE(
"prepare_send_list()",
"DofMap");
1840 if (this->n_processors() == 1)
1844 if (_extra_send_list_function)
1846 if (_augment_send_list)
1849 libMesh::out <<
"WARNING: You have specified both an extra send list function and object.\n"
1850 <<
" Are you sure this is what you meant to do??"
1854 _extra_send_list_function(_send_list, _extra_send_list_context);
1857 if (_augment_send_list)
1858 _augment_send_list->augment_send_list (_send_list);
1863 std::sort(_send_list.begin(), _send_list.end());
1866 std::vector<dof_id_type>::iterator new_end =
1867 std::unique (_send_list.begin(), _send_list.end());
1871 std::vector<dof_id_type> (_send_list.begin(), new_end).swap (_send_list);
1874 libmesh_assert(_send_list.empty() || _send_list.back() < this->n_dofs());
1879 this->clear_send_list();
1880 this->add_neighbors_to_send_list(
mesh);
1882#ifdef LIBMESH_ENABLE_CONSTRAINTS
1886 this->process_constraints(
mesh);
1888 this->prepare_send_list();
1891void DofMap::set_implicit_neighbor_dofs(
bool implicit_neighbor_dofs)
1893 _implicit_neighbor_dofs_initialized =
true;
1894 _implicit_neighbor_dofs = implicit_neighbor_dofs;
1897void DofMap::set_verify_dirichlet_bc_consistency(
bool val)
1899 _verify_dirichlet_bc_consistency = val;
1903bool DofMap::use_coupled_neighbor_dofs(
const MeshBase & )
const
1907 bool implicit_neighbor_dofs =
1914 if (implicit_neighbor_dofs)
1930 if (_implicit_neighbor_dofs_initialized)
1932 implicit_neighbor_dofs = _implicit_neighbor_dofs;
1936 if (!implicit_neighbor_dofs)
1944 bool all_discontinuous_dofs =
true;
1948 if (FEInterface::get_continuity(this->variable_type(var)) !=
DISCONTINUOUS)
1949 all_discontinuous_dofs =
false;
1951 if (all_discontinuous_dofs)
1952 implicit_neighbor_dofs =
true;
1955 return implicit_neighbor_dofs;
1962 _sp = this->build_sparsity(
mesh, this->_constrained_sparsity_construction);
1967 for (
const auto & mat : _matrices)
1969 mat->attach_sparsity_pattern (*_sp);
1970 if (need_full_sparsity_pattern)
1971 mat->update_sparsity_pattern (_sp->get_sparsity_pattern());
1975 if (!need_full_sparsity_pattern)
1976 _sp->clear_full_sparsity();
1981void DofMap::clear_sparsity()
1988void DofMap::remove_default_ghosting()
1990 this->remove_coupling_functor(this->default_coupling());
1991 this->remove_algebraic_ghosting_functor(this->default_algebraic_ghosting());
1996void DofMap::add_default_ghosting()
1998 this->add_coupling_functor(this->default_coupling());
1999 this->add_algebraic_ghosting_functor(this->default_algebraic_ghosting());
2009#ifdef LIBMESH_ENABLE_DEPRECATED
2010 _coupling_functors.erase
2011 (std::remove(_coupling_functors.begin(),
2012 _coupling_functors.end(),
2014 _coupling_functors.end());
2019 _coupling_functors.end(),
2020 &coupling_functor) ==
2021 _coupling_functors.end());
2023 _coupling_functors.push_back(&coupling_functor);
2026 _mesh.add_ghosting_functor(coupling_functor);
2034 auto raw_it = std::find(_coupling_functors.begin(),
2035 _coupling_functors.end(), &coupling_functor);
2037#ifndef LIBMESH_ENABLE_DEPRECATED
2042 if (raw_it != _coupling_functors.end())
2044 _coupling_functors.erase(raw_it);
2048 _coupling_functors.end(),
2049 &coupling_functor) ==
2050 _coupling_functors.end());
2052 _mesh.remove_ghosting_functor(coupling_functor);
2054 if (
const auto it = _shared_functors.find(&coupling_functor);
2055 it != _shared_functors.end())
2056 _shared_functors.erase(it);
2066#ifdef LIBMESH_ENABLE_DEPRECATED
2067 _algebraic_ghosting_functors.erase
2068 (std::remove(_algebraic_ghosting_functors.begin(),
2069 _algebraic_ghosting_functors.end(),
2070 &evaluable_functor),
2071 _algebraic_ghosting_functors.end());
2076 _algebraic_ghosting_functors.end(),
2077 &evaluable_functor) ==
2078 _algebraic_ghosting_functors.end());
2080 _algebraic_ghosting_functors.push_back(&evaluable_functor);
2081 evaluable_functor.
set_mesh(&_mesh);
2083 _mesh.add_ghosting_functor(evaluable_functor);
2091 auto raw_it = std::find(_algebraic_ghosting_functors.begin(),
2092 _algebraic_ghosting_functors.end(),
2093 &evaluable_functor);
2095#ifndef LIBMESH_ENABLE_DEPRECATED
2100 if (raw_it != _algebraic_ghosting_functors.end())
2102 _algebraic_ghosting_functors.erase(raw_it);
2106 _algebraic_ghosting_functors.end(),
2107 &evaluable_functor) ==
2108 _algebraic_ghosting_functors.end());
2110 _mesh.remove_ghosting_functor(evaluable_functor);
2112 if (
const auto it = _shared_functors.find(&evaluable_functor);
2113 it != _shared_functors.end())
2114 _shared_functors.erase(it);
2120 const std::vector<dof_id_type> & dof_indices_in,
2123 const unsigned int n_original_dofs = dof_indices_in.size();
2125#ifdef LIBMESH_ENABLE_AMR
2128 libmesh_assert_equal_to (dof_indices_in.size(), Ue.
size());
2129 bool has_constrained_dofs =
false;
2131 for (
unsigned int il=0; il != n_original_dofs; ++il)
2135 if (this->is_constrained_dof (ig)) has_constrained_dofs =
true;
2137 libmesh_assert_less (ig, Ug.
size());
2145 if (has_constrained_dofs)
2148 std::vector<dof_id_type> constrained_dof_indices(dof_indices_in);
2153 this->build_constraint_matrix_and_vector (C, H, constrained_dof_indices);
2155 libmesh_assert_equal_to (dof_indices_in.size(), C.
m());
2156 libmesh_assert_equal_to (constrained_dof_indices.size(), C.
n());
2162 for (
unsigned int i=0; i != n_original_dofs; i++)
2166 const unsigned int n_constrained =
2167 cast_int<unsigned int>(constrained_dof_indices.size());
2168 for (
unsigned int j=0; j<n_constrained; j++)
2170 const dof_id_type jg = constrained_dof_indices[j];
2178 Ue.
el(i) += C(i,j)*Ug(jg);
2187 libmesh_assert_equal_to (n_original_dofs, Ue.
size());
2189 for (
unsigned int il=0; il<n_original_dofs; il++)
2201void DofMap::dof_indices (
const Elem *
const elem,
2202 std::vector<dof_id_type> & di)
const
2222 const unsigned int n_var_groups = this->n_variable_groups();
2226 std::size_t tot_size = 0;
2238 std::vector<const Node *> elem_nodes;
2239 MeshTools::Subdivision::find_one_ring(sd_elem, elem_nodes);
2242 for (
unsigned int vg=0; vg<n_var_groups; vg++)
2245 const unsigned int vars_in_group = var.
n_variables();
2250 for (
unsigned int vig=0; vig != vars_in_group; ++vig)
2255 std::vector<dof_id_type> di_new;
2256 this->SCALAR_dof_indices(di_new,var.
number(vig));
2257 di.insert( di.end(), di_new.begin(), di_new.end());
2261 for (
unsigned int vig=0; vig != vars_in_group; ++vig)
2263 _dof_indices(*elem, elem->
p_level(), di, vg, vig,
2265 cast_int<unsigned int>(elem_nodes.size()),
2280 for (
unsigned int vg=0; vg<n_var_groups; vg++)
2283 const unsigned int vars_in_group = var.
n_variables();
2289 for (
unsigned int vig=0; vig != vars_in_group; ++vig)
2294 std::vector<dof_id_type> di_new;
2295 this->SCALAR_dof_indices(di_new,var.
number(vig));
2296 di.insert( di.end(), di_new.begin(), di_new.end());
2300 for (
unsigned int vig=0; vig != vars_in_group; ++vig)
2302 _dof_indices(*elem, elem->
p_level(), di, vg, vig,
2312 libmesh_assert_equal_to (tot_size, di.size());
2317void DofMap::dof_indices (
const Elem *
const elem,
2318 std::vector<dof_id_type> & di,
2319 const unsigned int vn,
2327 std::vector<dof_id_type> & dof_indices,
2328 const std::vector<dof_id_type> & scalar_dof_indices) {
2329 dof_indices.insert(dof_indices.end(), scalar_dof_indices.begin(), scalar_dof_indices.end());
2334 std::vector<dof_id_type> & dof_indices,
2335 const dof_id_type dof) { dof_indices.push_back(dof); },
2339void DofMap::array_dof_indices(
const Elem *
const elem,
2340 std::vector<dof_id_type> & di,
2341 const unsigned int vn,
2344 auto dof_indices_functor = [elem, p_level,
this](std::vector<dof_id_type> & functor_di,
2345 const unsigned int functor_vn) {
2346 this->dof_indices(elem, functor_di, functor_vn, p_level);
2348 this->array_dof_indices(dof_indices_functor, di, vn);
2351void DofMap::array_dof_indices(
const Node *
const node,
2352 std::vector<dof_id_type> & di,
2353 const unsigned int vn)
const
2355 auto dof_indices_functor = [node,
this](std::vector<dof_id_type> & functor_di,
2356 const unsigned int functor_vn) {
2357 this->dof_indices(node, functor_di, functor_vn);
2359 this->array_dof_indices(dof_indices_functor, di, vn);
2362void DofMap::dof_indices (
const Node *
const node,
2363 std::vector<dof_id_type> & di)
const
2378 const unsigned int n_var_groups = this->n_variable_groups();
2379 const unsigned int sys_num = this->sys_number();
2382 for (
unsigned int vg=0; vg<n_var_groups; vg++)
2385 const unsigned int vars_in_group = var.
n_variables();
2389 for (
unsigned int vig=0; vig != vars_in_group; ++vig)
2391 std::vector<dof_id_type> di_new;
2392 this->SCALAR_dof_indices(di_new,var.
number(vig));
2393 di.insert( di.end(), di_new.begin(), di_new.end());
2399 for (
unsigned int vig=0; vig != vars_in_group; ++vig)
2401 for (
int i=0; i != n_comp; ++i)
2404 node->
dof_number(sys_num, vg, vig, i, n_comp);
2405 libmesh_assert_not_equal_to
2406 (d, DofObject::invalid_id);
2415void DofMap::dof_indices (
const Node *
const node,
2416 std::vector<dof_id_type> & di,
2417 const unsigned int vn)
const
2421 this->dof_indices(node, di);
2438 const unsigned int sys_num = this->sys_number();
2441 const unsigned int vg = this->_variable_group_numbers[vn];
2446 std::vector<dof_id_type> di_new;
2447 this->SCALAR_dof_indices(di_new,vn);
2448 di.insert( di.end(), di_new.begin(), di_new.end());
2452 const unsigned int vig = vn - var.
number();
2454 for (
int i=0; i != n_comp; ++i)
2457 node->
dof_number(sys_num, vg, vig, i, n_comp);
2458 libmesh_assert_not_equal_to
2459 (d, DofObject::invalid_id);
2466void DofMap::dof_indices (
const Elem & elem,
2468 std::vector<dof_id_type> & di,
2469 const unsigned int vn)
const
2471 this->_node_dof_indices(elem, n, elem.
node_ref(n), di, vn);
2476#ifdef LIBMESH_ENABLE_AMR
2478void DofMap::old_dof_indices (
const Elem & elem,
2480 std::vector<dof_id_type> & di,
2481 const unsigned int vn)
const
2484 this->_node_dof_indices(elem, n, old_obj, di, vn);
2491void DofMap::_node_dof_indices (
const Elem & elem,
2494 std::vector<dof_id_type> & di,
2495 const unsigned int vn)
const
2507 const unsigned int sys_num = this->sys_number();
2508 const auto [vg, vig] =
2510 const unsigned int n_comp = obj.
n_comp_group(sys_num,vg);
2514 const bool extra_hanging_dofs =
2515 FEInterface::extra_hanging_dofs(fe_type);
2523 const unsigned int nc =
2524 FEInterface::n_dofs_at_node(fe_type, &elem, n, add_p_level);
2530 if (extra_hanging_dofs && nc && !elem.
is_vertex(n))
2532 const int dof_offset = n_comp - nc;
2540 di.resize(di.size() + nc, DofObject::invalid_id);
2543 for (
unsigned int i = dof_offset; i != n_comp; ++i)
2547 libmesh_assert_not_equal_to (d, DofObject::invalid_id);
2558 const unsigned int good_nc =
2559 std::min(
static_cast<unsigned int>(n_comp), nc);
2560 for (
unsigned int i=0; i != good_nc; ++i)
2564 libmesh_assert_not_equal_to (d, DofObject::invalid_id);
2567 for (
unsigned int i=good_nc; i != nc; ++i)
2568 di.push_back(DofObject::invalid_id);
2573DofMap::_dof_indices(
const Elem & elem,
2575 std::vector<dof_id_type> & di,
2576 const unsigned int vg,
2577 const unsigned int vig,
2578 const Node *
const * nodes,
2580 const unsigned int v
2583 std::size_t & tot_size
2601 std::vector<dof_id_type> & functor_di,
2602 const dof_id_type dof) { functor_di.push_back(dof); });
2605void DofMap::SCALAR_dof_indices (std::vector<dof_id_type> & di,
2606 const unsigned int vn,
2607#ifdef LIBMESH_ENABLE_AMR
2621#ifdef LIBMESH_ENABLE_AMR
2624 libmesh_assert_greater_equal(n_old_dofs(), n_SCALAR_dofs());
2627 this->_first_old_scalar_df[vn] : this->_first_scalar_df[vn];
2632 libmesh_assert_not_equal_to(my_idx, DofObject::invalid_id);
2635 const int n_dofs_vn = this->variable(vn).type().order.get_order();
2637 di.resize(n_dofs_vn);
2638 for (
int i = 0; i != n_dofs_vn; ++i)
2647 if (!this->local_index(dof_index))
2651 if (!std::binary_search(_send_list.begin(), _send_list.end(), dof_index))
2660bool DofMap::all_semilocal_indices (
const std::vector<dof_id_type> & dof_indices_in)
const
2663 for (
const auto & di : dof_indices_in)
2664 if (!this->semilocal_index(di))
2672template <
typename DofObjectSub
class>
2673bool DofMap::is_evaluable(
const DofObjectSubclass & obj,
2674 unsigned int var_num)
const
2677 if (obj.processor_id() == this->processor_id())
2680 std::vector<dof_id_type> di;
2683 this->dof_indices(&obj, di);
2685 this->dof_indices(&obj, di, var_num);
2687 return this->all_semilocal_indices(di);
2692#ifdef LIBMESH_ENABLE_AMR
2694void DofMap::old_dof_indices (
const Elem *
const elem,
2695 std::vector<dof_id_type> & di,
2696 const unsigned int vn)
const
2706 const unsigned int sys_num = this->sys_number();
2707 const unsigned int n_var_groups = this->n_variable_groups();
2708#ifdef LIBMESH_ENABLE_INFINITE_ELEMENTS
2709 const bool is_inf = elem->
infinite();
2723 std::vector<const Node *> elem_nodes;
2724 const Node *
const * nodes_ptr;
2730 MeshTools::Subdivision::find_one_ring(sd_elem, elem_nodes);
2731 nodes_ptr = elem_nodes.data();
2732 n_nodes = cast_int<unsigned int>(elem_nodes.size());
2742 for (
unsigned int vg=0; vg<n_var_groups; vg++)
2745 const unsigned int vars_in_group = var.
n_variables();
2747 for (
unsigned int vig=0; vig<vars_in_group; vig++)
2749 const unsigned int v = var.
number(vig);
2757 std::vector<dof_id_type> di_new;
2758 this->SCALAR_dof_indices(di_new,v,
true);
2759 di.insert( di.end(), di_new.begin(), di_new.end());
2772 int p_adjustment = 0;
2775 libmesh_assert_greater (elem->
p_level(), 0);
2782 p_adjustment *= add_p_level;
2785 int extra_order =
int(add_p_level*elem->
p_level()) + p_adjustment;
2787 const bool extra_hanging_dofs =
2788 FEInterface::extra_hanging_dofs(fe_type);
2790 const FEInterface::n_dofs_at_node_ptr ndan =
2791 FEInterface::n_dofs_at_node_function(fe_type, elem);
2794 for (
unsigned int n=0; n<
n_nodes; n++)
2796 const Node * node = nodes_ptr[n];
2803 const unsigned int nc =
2804#ifdef LIBMESH_ENABLE_INFINITE_ELEMENTS
2806 FEInterface::n_dofs_at_node(var.
type(), extra_order, elem, n) :
2808 ndan (type, var.
type().
order + extra_order, n);
2810 const int n_comp = old_dof_obj.
n_comp_group(sys_num,vg);
2816 if (extra_hanging_dofs && !elem->
is_vertex(n))
2818 const int dof_offset = n_comp - nc;
2826 Elem::JUST_COARSENED);
2827 di.resize(di.size() + nc, DofObject::invalid_id);
2830 for (
int i=n_comp-1; i>=dof_offset; i--)
2833 old_dof_obj.
dof_number(sys_num, vg, vig, i, n_comp);
2852 const unsigned int old_nc =
2853 std::min(
static_cast<unsigned int>(n_comp), nc);
2854 for (
unsigned int i=0; i != old_nc; ++i)
2857 old_dof_obj.
dof_number(sys_num, vg, vig, i, n_comp);
2859 libmesh_assert_not_equal_to (d, DofObject::invalid_id);
2863 for (
unsigned int i=old_nc; i != nc; ++i)
2864 di.push_back(DofObject::invalid_id);
2869 const unsigned int nc =
2870 FEInterface::n_dofs_per_elem(fe_type, extra_order, elem);
2876 const unsigned int n_comp =
2879 if (old_dof_obj.
n_systems() > sys_num &&
2883 for (
unsigned int i=0; i<nc; i++)
2886 old_dof_obj.
dof_number(sys_num, vg, vig, i, n_comp);
2901 di.resize(di.size() + nc, DofObject::invalid_id);
2913#ifdef LIBMESH_ENABLE_CONSTRAINTS
2915void DofMap::find_connected_dofs (std::vector<dof_id_type> & elem_dofs)
const
2917 typedef std::set<dof_id_type> RCSet;
2920 RCSet dof_set (elem_dofs.begin(), elem_dofs.end());
2929 for (
const auto & dof : elem_dofs)
2930 if (this->is_constrained_dof(dof))
2933 DofConstraints::const_iterator
2934 pos = _dof_constraints.find(dof);
2947 for (
const auto & pr : constraint_row)
2948 if (!dof_set.count (pr.first))
2950 dof_set.insert (pr.first);
2962 elem_dofs.insert (elem_dofs.end(),
2963 dof_set.begin(), dof_set.end());
2969 this->find_connected_dofs (elem_dofs);
2978void DofMap::print_info(std::ostream & os)
const
2980 os << this->get_info();
2985std::string DofMap::get_info()
const
2987 std::ostringstream os;
2992 const char * may_equal =
" <= ";
2996 for (
const auto & mat : _matrices)
2997 if (mat->need_full_sparsity_pattern())
3001 long double avg_n_nz = 0, avg_n_oz = 0;
3005 for (
const auto & val : _sp->get_n_nz())
3007 max_n_nz = std::max(max_n_nz, val);
3011 std::size_t n_nz_size = _sp->get_n_nz().size();
3013 this->comm().max(max_n_nz);
3014 this->comm().sum(avg_n_nz);
3015 this->comm().sum(n_nz_size);
3017 avg_n_nz /= std::max(n_nz_size,std::size_t(1));
3019 for (
const auto & val : _sp->get_n_oz())
3021 max_n_oz = std::max(max_n_oz, val);
3025 std::size_t n_oz_size = _sp->get_n_oz().size();
3027 this->comm().max(max_n_oz);
3028 this->comm().sum(avg_n_oz);
3029 this->comm().sum(n_oz_size);
3031 avg_n_oz /= std::max(n_oz_size,std::size_t(1));
3034 os <<
" DofMap Sparsity\n Average On-Processor Bandwidth"
3035 << may_equal << avg_n_nz <<
'\n';
3037 os <<
" Average Off-Processor Bandwidth"
3038 << may_equal << avg_n_oz <<
'\n';
3040 os <<
" Maximum On-Processor Bandwidth"
3041 << may_equal << max_n_nz <<
'\n';
3043 os <<
" Maximum Off-Processor Bandwidth"
3044 << may_equal << max_n_oz << std::endl;
3046#ifdef LIBMESH_ENABLE_CONSTRAINTS
3048 std::size_t n_constraints = 0, max_constraint_length = 0,
3050 long double avg_constraint_length = 0.;
3052 for (
const auto & [constrained_dof, row] : _dof_constraints)
3055 if (!this->local_index(constrained_dof))
3058 std::size_t rowsize = row.size();
3060 max_constraint_length = std::max(max_constraint_length,
3062 avg_constraint_length += rowsize;
3065 if (_primal_constraint_values.count(constrained_dof))
3069 this->comm().sum(n_constraints);
3070 this->comm().sum(n_rhss);
3071 this->comm().sum(avg_constraint_length);
3072 this->comm().max(max_constraint_length);
3074 os <<
" DofMap Constraints\n Number of DoF Constraints = "
3078 <<
" Number of Heterogenous Constraints= " << n_rhss;
3081 avg_constraint_length /= n_constraints;
3084 <<
" Average DoF Constraint Length= " << avg_constraint_length;
3087#ifdef LIBMESH_ENABLE_NODE_CONSTRAINTS
3088 std::size_t n_node_constraints = 0, max_node_constraint_length = 0,
3090 long double avg_node_constraint_length = 0.;
3092 for (
const auto & [node, pr] : _node_constraints)
3095 if (node->processor_id() != this->processor_id())
3099 std::size_t rowsize = row.size();
3101 max_node_constraint_length = std::max(max_node_constraint_length,
3103 avg_node_constraint_length += rowsize;
3104 n_node_constraints++;
3106 if (pr.second !=
Point(0))
3110 this->comm().sum(n_node_constraints);
3111 this->comm().sum(n_node_rhss);
3112 this->comm().sum(avg_node_constraint_length);
3113 this->comm().max(max_node_constraint_length);
3115 os <<
"\n Number of Node Constraints = " << n_node_constraints;
3118 <<
" Number of Heterogenous Node Constraints= " << n_node_rhss;
3119 if (n_node_constraints)
3121 avg_node_constraint_length /= n_node_constraints;
3122 os <<
"\n Maximum Node Constraint Length= " << max_node_constraint_length
3124 <<
" Average Node Constraint Length= " << avg_node_constraint_length;
3137 _sc = std::make_unique<StaticCondensationDofMap>(
mesh, sys, *
this);
3140void DofMap::reinit_static_condensation()
3146unsigned int DofMap::add_variable(
System & sys,
3147 std::string_view var,
3149 const std::set<subdomain_id_type> *
const active_subdomains)
3151 parallel_object_only();
3155 libmesh_assert(this->comm().verify((active_subdomains ==
nullptr)));
3157 if (active_subdomains)
3163 if (this->variable_name(v) == var)
3165 if (this->variable_type(v) == type)
3172 const Variable & existing_var = this->variable(v);
3176 bool check1 = (!active_subdomains || active_subdomains->empty()) &&
3182 (active_subdomains && (*active_subdomains == existing_var.
active_subdomains()));
3185 if (check1 || check2)
3186 return _variables[v].number();
3189 libmesh_error_msg(
"ERROR: incompatible variable "
3190 << var <<
" has already been added for this system!");
3195 if (this->n_variable_groups())
3203 bool should_be_in_vg = this->identify_variable_groups();
3208 const std::set<subdomain_id_type> *
const their_active_subdomains(
3212 if (vg.
type() != type)
3213 should_be_in_vg =
false;
3216 if (their_active_subdomains &&
3217 (!active_subdomains || (active_subdomains && active_subdomains->empty())))
3218 should_be_in_vg =
false;
3221 if (!their_active_subdomains && (active_subdomains && !active_subdomains->empty()))
3222 should_be_in_vg =
false;
3224 if (their_active_subdomains && active_subdomains)
3226 if (*their_active_subdomains != *active_subdomains)
3227 should_be_in_vg =
false;
3231 if (should_be_in_vg)
3233 const unsigned int vn = this->
n_vars();
3235 std::string varstr(var);
3237 _variable_numbers[varstr] = vn;
3238 vg.
append(std::move(varstr));
3240 const unsigned int vgn = _variable_groups.size() - 1;
3241 _variable_group_numbers.push_back(vgn);
3242 _var_to_vg.emplace(vn, vgn);
3249 return this->add_variables(
3250 sys, std::vector<std::string>(1, std::string(var)), type, active_subdomains);
3253unsigned int DofMap::add_variables(
System & sys,
3254 const std::vector<std::string> & vars,
3256 const std::set<subdomain_id_type> *
const active_subdomains)
3258 parallel_object_only();
3264 libmesh_assert(this->comm().verify((active_subdomains ==
nullptr)));
3266 if (active_subdomains)
3271 for (
auto ovar : vars)
3276 if (this->variable_name(v) == ovar)
3278 if (this->variable_type(v) == type)
3279 return _variables[v].number();
3281 libmesh_error_msg(
"ERROR: incompatible variable "
3282 << ovar <<
" has already been added for this system!");
3286 if (this->n_variable_groups())
3294 bool should_be_in_vg = this->identify_variable_groups();
3299 const std::set<subdomain_id_type> *
const their_active_subdomains(
3303 if (vg.
type() != type)
3304 should_be_in_vg =
false;
3307 if (their_active_subdomains &&
3308 (!active_subdomains || (active_subdomains && active_subdomains->empty())))
3309 should_be_in_vg =
false;
3312 if (!their_active_subdomains && (active_subdomains && !active_subdomains->empty()))
3313 should_be_in_vg =
false;
3315 if (their_active_subdomains && active_subdomains)
3317 if (*their_active_subdomains != *active_subdomains)
3318 should_be_in_vg =
false;
3322 if (should_be_in_vg)
3324 unsigned int vn = this->
n_vars();
3325 const unsigned int vgn = _variable_groups.size() - 1;
3327 for (
auto ovar : vars)
3334 _variable_numbers[ovar] = vn;
3335 _variable_group_numbers.push_back(vgn);
3336 _var_to_vg.emplace(vn, vgn);
3342 const unsigned int curr_n_vars = this->
n_vars();
3344 const unsigned int next_first_component = this->n_components(sys.
get_mesh());
3348 _variable_groups.push_back(
3349 (active_subdomains ==
nullptr)
3350 ?
VariableGroup(&sys, vars, curr_n_vars, next_first_component, type)
3351 :
VariableGroup(&sys, vars, curr_n_vars, next_first_component, type, *active_subdomains));
3354 const unsigned int vgn = _variable_groups.size() - 1;
3359 const unsigned int vn = curr_n_vars + v;
3360 _variables.push_back(vg(v));
3361 _variable_numbers[vars[v]] = vn;
3362 _variable_group_numbers.push_back(vgn);
3363 _var_to_vg.emplace(vn, vgn);
3366 libmesh_assert_equal_to((curr_n_vars + vars.size()), this->n_vars());
3374 return cast_int<unsigned int>(curr_n_vars + vars.size() - 1);
3377unsigned int DofMap::add_variable_array (
System & sys,
3378 const std::vector<std::string> & vars,
3380 const std::set<subdomain_id_type> *
const active_subdomains)
3382 const unsigned int count = cast_int<unsigned int>(vars.size());
3383 const unsigned int last_var = this->add_variables(sys, vars, type, active_subdomains);
3384 const unsigned int first_var = last_var + 1 - count;
3385 _array_variables.push_back({first_var, first_var + count});
3389void DofMap::get_all_variable_numbers(std::vector<unsigned int> & all_variable_numbers)
const
3391 all_variable_numbers.resize(
n_vars());
3393 unsigned int count = 0;
3394 for (
auto vn : _variable_numbers)
3395 all_variable_numbers[count++] = vn.second;
3398template LIBMESH_EXPORT
bool DofMap::is_evaluable<Elem>(
const Elem &,
unsigned int)
const;
3399template LIBMESH_EXPORT
bool DofMap::is_evaluable<Node>(
const Node &,
unsigned int)
const;
void ErrorVector unsigned int
void max(const T &r, T &o, Request &req) const
This proxy class acts like a container of indices from a single coupling row.
This class defines a coupling matrix.
This class implements the default algebraic coupling in libMesh: elements couple to themselves,...
Defines a dense matrix for use in Finite Element-type computations.
Defines an abstract dense vector base class for use in Finite Element-type computations.
virtual void zero()=0
Set every element in the vector to 0.
virtual T el(const unsigned int i) const =0
virtual unsigned int size() const =0
Defines a dense vector for use in Finite Element-type computations.
We're using a class instead of a typedef to allow forward declarations and future flexibility.
This base class provides a minimal set of interfaces for satisfying user requests for.
void reinit(MeshBase &mesh, const std::map< const Node *, std::set< subdomain_id_type > > &constraining_subdomains)
Reinitialize the underlying data structures conformal to the current mesh.
unsigned int n_variable_groups() const
bool use_coupled_neighbor_dofs(const MeshBase &mesh) const
Tells other library functions whether or not this problem includes coupling between dofs in neighbori...
virtual void clear() override
Free all new memory associated with the object, but restore its original state, with the mesh pointer...
void * _extra_sparsity_context
A pointer associated with the extra sparsity that can optionally be passed in.
std::vector< GhostingFunctor * >::const_iterator GhostingFunctorIterator
Iterator type for coupling and algebraic ghosting functor ranges.
bool is_attached(SparseMatrix< Number > &matrix)
Matrices should not be attached more than once.
std::unique_ptr< DefaultCoupling > _default_evaluating
The default algebraic GhostingFunctor, used to implement standard libMesh send_list construction.
void update_sparsity_pattern(SparseMatrix< Number > &matrix) const
Additional matrices may be be temporarily initialized by this DofMap.
bool computed_sparsity_already() const
Returns true iff a sparsity pattern has already been computed.
void set_error_on_cyclic_constraint(bool error_on_cyclic_constraint)
Specify whether or not we perform an extra (opt-mode enabled) check for constraint loops.
void(* _extra_sparsity_function)(SparsityPattern::Graph &, std::vector< dof_id_type > &n_nz, std::vector< dof_id_type > &n_oz, void *)
A function pointer to a function to call to add extra entries to the sparsity pattern.
void set_nonlocal_dof_objects(iterator_type objects_begin, iterator_type objects_end, MeshBase &mesh, dofobject_accessor objects)
Helper function for distributing dofs in parallel.
unsigned int sys_number() const
std::vector< GhostingFunctor * > _coupling_functors
The list of all GhostingFunctor objects to be used when coupling degrees of freedom in matrix sparsit...
SparsityPattern::AugmentSparsityPattern * _augment_sparsity_pattern
Function object to call to add extra entries to the sparsity pattern.
void add_algebraic_ghosting_functor(GhostingFunctor &evaluable_functor, bool to_mesh=true)
Adds a functor which can specify algebraic ghosting requirements for use with distributed vectors.
void attach_matrix(SparseMatrix< Number > &matrix)
Additional matrices may be attached to this DofMap.
bool need_full_sparsity_pattern
Default false; set to true if any attached matrix requires a full sparsity pattern.
std::vector< SparseMatrix< Number > * > _matrices
Additional matrices handled by this object.
std::unique_ptr< SparsityPattern::Build > _sp
The sparsity pattern of the global matrix.
CouplingMatrix * _dof_coupling
Degree of freedom coupling.
bool is_periodic_boundary(const boundary_id_type boundaryid) const
std::unique_ptr< PeriodicBoundaries > _periodic_boundaries
Data structure containing periodic boundaries.
std::unique_ptr< DefaultCoupling > _default_coupling
The default coupling GhostingFunctor, used to implement standard libMesh sparsity pattern constructio...
std::set< std::unique_ptr< CouplingMatrix >, Utility::CompareUnderlying > CouplingMatricesSet
bool has_static_condensation() const
Checks whether we have static condensation.
MeshBase & _mesh
The mesh that system uses.
DofObject * node_ptr(MeshBase &mesh, dof_id_type i) const
DofMap(const unsigned int sys_number, MeshBase &mesh)
Constructor.
DofObject * elem_ptr(MeshBase &mesh, dof_id_type i) const
void add_coupling_functor(GhostingFunctor &coupling_functor, bool to_mesh=true)
Adds a functor which can specify coupling requirements for creation of sparse matrices.
std::unique_ptr< SparsityPattern::Build > build_sparsity(const MeshBase &mesh, bool calculate_constrained=false, bool use_condensed_system=false) const
Builds a sparsity pattern for matrices using the current degree-of-freedom numbering and coupling.
bool _error_on_constraint_loop
This flag indicates whether or not we do an opt-mode check for the presence of constraint loops,...
void set_error_on_constraint_loop(bool error_on_constraint_loop)
std::unique_ptr< StaticCondensationDofMap > _sc
Static condensation class.
The DofObject defines an abstract base class for objects that have degrees of freedom associated with...
dof_id_type vg_dof_base(const unsigned int s, const unsigned int vg) const
VariableGroup DoF indices are indexed as id = base + var_in_vg*ncomp + comp This method allows for di...
unsigned int n_systems() const
unsigned int n_comp(const unsigned int s, const unsigned int var) const
unsigned int n_comp_group(const unsigned int s, const unsigned int vg) const
void set_n_comp_group(const unsigned int s, const unsigned int vg, const unsigned int ncomp)
Sets the number of components for VariableGroup vg of system s associated with this DofObject.
dof_id_type dof_number(const unsigned int s, const unsigned int var, const unsigned int comp) const
std::pair< unsigned int, unsigned int > var_to_vg_and_offset(const unsigned int s, const unsigned int var) const
processor_id_type processor_id() const
unsigned int n_var_groups(const unsigned int s) const
static constexpr dof_id_type invalid_id
An invalid id to distinguish an uninitialized DofObject.
DofObject * get_old_dof_object()
Pointer accessor for previously public old_dof_object.
DofObject & get_old_dof_object_ref()
As above, but do not use in situations where the old_dof_object may be nullptr, since this function a...
void set_vg_dof_base(const unsigned int s, const unsigned int vg, const dof_id_type db)
VariableGroup DoF indices are indexed as id = base + var_in_vg*ncomp + comp This method allows for di...
static constexpr processor_id_type invalid_processor_id
An invalid processor_id to distinguish DoFs that have not been assigned to a processor.
unsigned int n_vars(const unsigned int s, const unsigned int vg) const
bool has_dofs(const unsigned int s=libMesh::invalid_uint) const
This is the base class from which all geometric element types are derived.
RefinementState refinement_flag() const
const Node & node_ref(const unsigned int i) const
virtual unsigned int n_nodes() const =0
subdomain_id_type subdomain_id() const
void active_family_tree(std::vector< const Elem * > &active_family, bool reset=true) const
Same as the family_tree() member, but only adds the active children.
const Node *const * get_nodes() const
virtual bool is_vertex(const unsigned int i) const =0
virtual ElemType type() const =0
unsigned int p_level() const
RefinementState p_refinement_flag() const
virtual bool infinite() const =0
static unsigned int n_dofs_at_node(const unsigned int dim, const FEType &fe_t, const ElemType t, const unsigned int n)
static unsigned int max_order(const FEType &fe_t, const ElemType &el_t)
static unsigned int n_dofs_per_elem(const unsigned int dim, const FEType &fe_t, const ElemType t)
static bool extra_hanging_dofs(const FEType &fe_t)
class FEType hides (possibly multiple) FEFamily and approximation orders, thereby enabling specialize...
OrderWrapper order
The approximation order of the element (at 0 p-refinement level).
bool p_refinement
Whether or not the finite elements for this type increase their p refinement level on geometric eleme...
FEFamily family
The type of finite element.
This abstract base class defines the interface by which library code and user code can report associa...
virtual void set_mesh(const MeshBase *mesh)
It should be called after cloning a ghosting functor.
std::map< const Elem *, const CouplingMatrix *, CompareDofObjectsByPIDAndThenID > map_type
What elements do we care about and what variables do we care about on each element?
This is the MeshBase class.
const ElemRange & element_stored_range()
void remove_ghosting_functor(GhostingFunctor &ghosting_functor)
Removes a functor which was previously added to the set of ghosting functors.
A Node is like a Point, but with more information.
Provides a uniform interface to vector storage schemes for different linear algebra libraries.
virtual numeric_index_type last_local_index() const =0
virtual numeric_index_type size() const =0
virtual numeric_index_type first_local_index() const =0
int get_order() const
Explicitly request the order as an int.
processor_id_type processor_id() const
const Parallel::Communicator & comm() const
processor_id_type n_processors() const
We're using a class instead of a typedef to allow forward declarations and future flexibility.
A Point defines a location in LIBMESH_DIM dimensional Real space.
virtual void update_sparsity_pattern(const SparsityPattern::Graph &)
Updates the matrix sparsity pattern.
void attach_dof_map(const DofMap &dof_map)
Set a pointer to the DofMap to use.
virtual bool need_full_sparsity_pattern() const
void attach_sparsity_pattern(const SparsityPattern::Build &sp)
Set a pointer to a sparsity pattern to use.
A class holding degree of freedom information pertinent to static condensation.
The StoredRange class defines a contiguous, divisible set of objects.
Manages consistently variables, degrees of freedom, and coefficient vectors.
bool is_initialized() const
const MeshBase & get_mesh() const
The Tri3Subdivision element is a three-noded subdivision surface shell element used in mechanics calc...
This class defines a logically grouped set of variables in the system.
unsigned int n_variables() const
unsigned int number(unsigned int v) const
void append(std::string var_name)
Appends a variable to the group.
This class defines the notion of a variable in the system.
const std::set< subdomain_id_type > & active_subdomains() const
bool active_on_subdomain(subdomain_id_type sid) const
bool implicitly_active() const
const FEType & type() const
void pull_parallel_vector_data(const Communicator &comm, const MapToVectors &queries, GatherFunctor &gather_data, const ActionFunctor &act_on_data, const datum *example)
void parallel_reduce(const Range &range, Body &body, unsigned int n_threads=libMesh::n_threads())
Execute the provided reduction operation in parallel on the specified range.
void parallel_for(const Range &range, const Body &body, unsigned int n_threads=libMesh::n_threads())
Execute the provided function object in parallel on the specified range.
std::string enum_to_string(const T e)
The libMesh namespace provides an interface to certain functionality in the library.
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.
SimpleRange< IndexType > as_range(const std::pair< IndexType, IndexType > &p)
Helper function that allows us to treat a homogenous pair as a range.
auto index_range(const T &sizable)
Helper function that returns an IntRange<std::size_t> representing all the indices of the passed-in v...
ElemType
Defines an enum for geometric element types.
const unsigned int invalid_uint
A number which is used quite often to represent an invalid or uninitialized value for an unsigned int...
StoredRange< MeshBase::element_iterator, Elem * > ElemRange
T command_line_next(std::string name, T default_value)
Use GetPot's search()/next() functions to get following arguments from the command line.
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.
bool on_command_line(std::string arg)
uint8_t processor_id_type
IntRange< T > make_range(T beg, T end)
The 2-parameter make_range() helper function returns an IntRange<T> when both input parameters are of...
The definition of the const_element_iterator struct.
const dof_id_type n_nodes