libmesh解析
本工作只是尝试解析原libmesh的代码,供学习使用
 全部  命名空间 文件 函数 变量 类型定义 枚举 枚举值 友元 
dof_map.C
浏览该文件的文档.
1 // The libMesh Finite Element Library.
2 // Copyright (C) 2002-2023 Benjamin S. Kirk, John W. Peterson, Roy H. Stogner
3 
4 // This library is free software; you can redistribute it and/or
5 // modify it under the terms of the GNU Lesser General Public
6 // License as published by the Free Software Foundation; either
7 // version 2.1 of the License, or (at your option) any later version.
8 
9 // This library is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 // Lesser General Public License for more details.
13 
14 // You should have received a copy of the GNU Lesser General Public
15 // License along with this library; if not, write to the Free Software
16 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 
18 
19 
20 // Local includes
21 #include "libmesh/dof_map.h"
22 
23 // libMesh includes
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/elem.h"
30 #include "libmesh/enum_to_string.h"
31 #include "libmesh/fe_interface.h"
32 #include "libmesh/fe_type.h"
33 #include "libmesh/fe_base.h" // FEBase::build() for continuity test
34 #include "libmesh/ghosting_functor.h"
35 #include "libmesh/int_range.h"
36 #include "libmesh/libmesh_logging.h"
37 #include "libmesh/mesh_base.h"
38 #include "libmesh/mesh_subdivision_support.h"
39 #include "libmesh/mesh_tools.h"
40 #include "libmesh/numeric_vector.h"
41 #include "libmesh/periodic_boundary_base.h"
42 #include "libmesh/periodic_boundaries.h"
43 #include "libmesh/sparse_matrix.h"
44 #include "libmesh/sparsity_pattern.h"
45 #include "libmesh/threads.h"
46 
47 // TIMPI includes
48 #include "timpi/parallel_implementation.h"
49 #include "timpi/parallel_sync.h"
50 
51 // C++ Includes
52 #include <algorithm> // for std::fill, std::equal_range, std::max, std::lower_bound, etc.
53 #include <memory>
54 #include <set>
55 #include <sstream>
56 #include <unordered_map>
57 
58 namespace libMesh
59 {
60 
61 // ------------------------------------------------------------
62 // DofMap member functions
63 std::unique_ptr<SparsityPattern::Build>
64 DofMap::build_sparsity (const MeshBase & mesh,
65  bool calculate_constrained) const
66 {
67  libmesh_assert (mesh.is_prepared());
68 
69  LOG_SCOPE("build_sparsity()", "DofMap");
70 
71  // Compute the sparsity structure of the global matrix. This can be
72  // fed into a PetscMatrix to allocate exactly the number of nonzeros
73  // necessary to store the matrix. This algorithm should be linear
74  // in the (# of elements)*(# nodes per element)
75 
76  // We can be more efficient in the threaded sparsity pattern assembly
77  // if we don't need the exact pattern. For some sparse matrix formats
78  // a good upper bound will suffice.
79 
80  // See if we need to include sparsity pattern entries for coupling
81  // between neighbor dofs
82  bool implicit_neighbor_dofs = this->use_coupled_neighbor_dofs(mesh);
83 
84  // We can compute the sparsity pattern in parallel on multiple
85  // threads. The goal is for each thread to compute the full sparsity
86  // pattern for a subset of elements. These sparsity patterns can
87  // be efficiently merged in the SparsityPattern::Build::join()
88  // method, especially if there is not too much overlap between them.
89  // Even better, if the full sparsity pattern is not needed then
90  // the number of nonzeros per row can be estimated from the
91  // sparsity patterns created on each thread.
92  auto sp = std::make_unique<SparsityPattern::Build>
93  (*this,
94  this->_dof_coupling,
95  this->_coupling_functors,
96  implicit_neighbor_dofs,
98  calculate_constrained);
99 
100  Threads::parallel_reduce (ConstElemRange (mesh.active_local_elements_begin(),
101  mesh.active_local_elements_end()), *sp);
102 
103  sp->parallel_sync();
104 
105 #ifndef NDEBUG
106  // Avoid declaring these variables unless asserts are enabled.
107  const processor_id_type proc_id = mesh.processor_id();
108  const dof_id_type n_dofs_on_proc = this->n_dofs_on_processor(proc_id);
109 #endif
110  libmesh_assert_equal_to (sp->get_sparsity_pattern().size(), n_dofs_on_proc);
111 
112  // Check to see if we have any extra stuff to add to the sparsity_pattern
114  {
116  {
117  libmesh_here();
118  libMesh::out << "WARNING: You have specified both an extra sparsity function and object.\n"
119  << " Are you sure this is what you meant to do??"
120  << std::endl;
121  }
122 
123  sp->apply_extra_sparsity_function(_extra_sparsity_function,
125  }
126 
128  sp->apply_extra_sparsity_object(*_augment_sparsity_pattern);
129 
130  return sp;
131 }
132 
133 
134 
135 DofMap::DofMap(const unsigned int number,
136  MeshBase & mesh) :
137  ParallelObject (mesh.comm()),
138  _dof_coupling(nullptr),
139  _error_on_constraint_loop(false),
140  _constrained_sparsity_construction(false),
141  _variables(),
142  _variable_groups(),
143  _variable_group_numbers(),
144  _sys_number(number),
145  _mesh(mesh),
146  _matrices(),
147  _first_df(),
148  _end_df(),
149  _first_scalar_df(),
150  _send_list(),
151  _augment_sparsity_pattern(nullptr),
152  _extra_sparsity_function(nullptr),
153  _extra_sparsity_context(nullptr),
154  _augment_send_list(nullptr),
155  _extra_send_list_function(nullptr),
156  _extra_send_list_context(nullptr),
157  _default_coupling(std::make_unique<DefaultCoupling>()),
158  _default_evaluating(std::make_unique<DefaultCoupling>()),
159  need_full_sparsity_pattern(false),
160  _n_dfs(0),
161  _n_SCALAR_dofs(0)
162 #ifdef LIBMESH_ENABLE_AMR
163  , _n_old_dfs(0),
164  _first_old_df(),
165  _end_old_df(),
166  _first_old_scalar_df()
167 #endif
168 #ifdef LIBMESH_ENABLE_CONSTRAINTS
169  , _dof_constraints()
170  , _stashed_dof_constraints()
171  , _primal_constraint_values()
172  , _adjoint_constraint_values()
173 #endif
174 #ifdef LIBMESH_ENABLE_NODE_CONSTRAINTS
175  , _node_constraints()
176 #endif
177 #ifdef LIBMESH_ENABLE_PERIODIC
178  , _periodic_boundaries(std::make_unique<PeriodicBoundaries>())
179 #endif
180 #ifdef LIBMESH_ENABLE_DIRICHLET
181  , _dirichlet_boundaries(std::make_unique<DirichletBoundaries>())
182  , _adjoint_dirichlet_boundaries()
183 #endif
184  , _implicit_neighbor_dofs_initialized(false),
185  _implicit_neighbor_dofs(false),
186  _verify_dirichlet_bc_consistency(true)
187 {
188  _matrices.clear();
189 
190  _default_coupling->set_mesh(&_mesh);
191  _default_evaluating->set_mesh(&_mesh);
192  _default_evaluating->set_n_levels(1);
193 
194 #ifdef LIBMESH_ENABLE_PERIODIC
195  _default_coupling->set_periodic_boundaries(_periodic_boundaries.get());
196  _default_evaluating->set_periodic_boundaries(_periodic_boundaries.get());
197 #endif
198 
201 }
202 
203 
204 
205 // Destructor
207 {
208  this->clear();
209 
210  // clear() resets all but the default DofMap-based functors. We
211  // need to remove those from the mesh too before we die.
212  _mesh.remove_ghosting_functor(*_default_coupling);
213  _mesh.remove_ghosting_functor(*_default_evaluating);
214 }
215 
216 
217 #ifdef LIBMESH_ENABLE_PERIODIC
218 
219 bool DofMap::is_periodic_boundary (const boundary_id_type boundaryid) const
220 {
221  if (_periodic_boundaries->count(boundaryid) != 0)
222  return true;
223 
224  return false;
225 }
226 
227 #endif
228 
229 
230 
231 // void DofMap::add_variable (const Variable & var)
232 // {
233 // libmesh_not_implemented();
234 // _variables.push_back (var);
235 // }
236 
237 
238 void DofMap::set_error_on_cyclic_constraint(bool error_on_cyclic_constraint)
239 {
240  // This function will eventually be officially libmesh_deprecated();
241  // Call DofMap::set_error_on_constraint_loop() instead.
242  set_error_on_constraint_loop(error_on_cyclic_constraint);
243 }
244 
245 void DofMap::set_error_on_constraint_loop(bool error_on_constraint_loop)
246 {
247  _error_on_constraint_loop = error_on_constraint_loop;
248 }
249 
250 
251 
253 {
254  // Ensure that we are not duplicating an existing entry in _variable_groups
255  if (std::find(_variable_groups.begin(), _variable_groups.end(), var_group) == _variable_groups.end())
256  {
257  const unsigned int vg = cast_int<unsigned int>(_variable_groups.size());
258 
259  _variable_groups.push_back(std::move(var_group));
260 
261  VariableGroup & new_var_group = _variable_groups.back();
262 
263  for (auto var : make_range(new_var_group.n_variables()))
264  {
265  auto var_instance = new_var_group(var);
266  const auto vn = var_instance.number();
267  _variables.push_back (std::move(var_instance));
268  _variable_group_numbers.push_back (vg);
269  _var_to_vg.emplace(vn, vg);
270  }
271  }
272  // End if check for var_group in _variable_groups
273 
274 }
275 
276 
277 
279 {
280  parallel_object_only();
281 
282  // We shouldn't be trying to re-attach the same matrices repeatedly
283  libmesh_assert (std::find(_matrices.begin(), _matrices.end(),
284  &matrix) == _matrices.end());
285 
286  _matrices.push_back(&matrix);
287 
288  this->update_sparsity_pattern(matrix);
289 
290  if (matrix.need_full_sparsity_pattern())
292 }
293 
294 
295 
297 {
299  (!_sp->get_n_nz().empty() ||
300  !_sp->get_n_oz().empty());
301  this->comm().max(computed_sparsity_already);
303 }
304 
305 
306 
308 {
309  matrix.attach_dof_map (*this);
310 
311  // If we've already computed sparsity, then it's too late
312  // to wait for "compute_sparsity" to help with sparse matrix
313  // initialization, and we need to handle this matrix individually
314  if (this->computed_sparsity_already())
315  {
316  libmesh_assert(_sp.get());
317 
318  if (matrix.need_full_sparsity_pattern())
319  {
320  // We'd better have already computed the full sparsity
321  // pattern if we need it here
322  libmesh_assert(need_full_sparsity_pattern);
323 
324  matrix.update_sparsity_pattern (_sp->get_sparsity_pattern());
325  }
326 
327  matrix.attach_sparsity_pattern(*_sp);
328  }
329 }
330 
331 
332 
334 {
335  return (std::find(_matrices.begin(), _matrices.end(),
336  &matrix) != _matrices.end());
337 }
338 
339 
340 
341 DofObject * DofMap::node_ptr(MeshBase & mesh, dof_id_type i) const
342 {
343  return mesh.node_ptr(i);
344 }
345 
346 
347 
348 DofObject * DofMap::elem_ptr(MeshBase & mesh, dof_id_type i) const
349 {
350  return mesh.elem_ptr(i);
351 }
352 
353 
354 
355 template <typename iterator_type>
356 void DofMap::set_nonlocal_dof_objects(iterator_type objects_begin,
357  iterator_type objects_end,
358  MeshBase & mesh,
359  dofobject_accessor objects)
360 {
361  // This function must be run on all processors at once
362  parallel_object_only();
363 
364  // First, iterate over local objects to find out how many
365  // are on each processor
366  std::unordered_map<processor_id_type, dof_id_type> ghost_objects_from_proc;
367 
368  iterator_type it = objects_begin;
369 
370  for (; it != objects_end; ++it)
371  {
372  DofObject * obj = *it;
373 
374  if (obj)
375  {
376  processor_id_type obj_procid = obj->processor_id();
377  // We'd better be completely partitioned by now
378  libmesh_assert_not_equal_to (obj_procid, DofObject::invalid_processor_id);
379  ghost_objects_from_proc[obj_procid]++;
380  }
381  }
382 
383  // Request sets to send to each processor
384  std::map<processor_id_type, std::vector<dof_id_type>>
385  requested_ids;
386 
387  // We know how many of our objects live on each processor, so
388  // reserve() space for requests from each.
389  for (auto [p, size] : ghost_objects_from_proc)
390  {
391  if (p != this->processor_id())
392  requested_ids[p].reserve(size);
393  }
394 
395  for (it = objects_begin; it != objects_end; ++it)
396  {
397  DofObject * obj = *it;
399  requested_ids[obj->processor_id()].push_back(obj->id());
400  }
401 #ifdef DEBUG
402  for (auto p : make_range(this->n_processors()))
403  {
404  if (ghost_objects_from_proc.count(p))
405  libmesh_assert_equal_to (requested_ids[p].size(), ghost_objects_from_proc[p]);
406  else
407  libmesh_assert(!requested_ids.count(p));
408  }
409 #endif
410 
411  typedef std::vector<dof_id_type> datum;
412 
413  auto gather_functor =
414  [this, &mesh, &objects]
416  const std::vector<dof_id_type> & ids,
417  std::vector<datum> & data)
418  {
419  // Fill those requests
420  const unsigned int
421  sys_num = this->sys_number(),
422  n_var_groups = this->n_variable_groups();
423 
424  const std::size_t query_size = ids.size();
425 
426  data.resize(query_size);
427  for (auto & d : data)
428  d.resize(2 * n_var_groups);
429 
430  for (std::size_t i=0; i != query_size; ++i)
431  {
432  DofObject * requested = (this->*objects)(mesh, ids[i]);
433  libmesh_assert(requested);
434  libmesh_assert_equal_to (requested->processor_id(), this->processor_id());
435  libmesh_assert_equal_to (requested->n_var_groups(sys_num), n_var_groups);
436  for (unsigned int vg=0; vg != n_var_groups; ++vg)
437  {
438  unsigned int n_comp_g =
439  requested->n_comp_group(sys_num, vg);
440  data[i][vg] = n_comp_g;
441  dof_id_type my_first_dof = n_comp_g ?
442  requested->vg_dof_base(sys_num, vg) : 0;
443  libmesh_assert_not_equal_to (my_first_dof, DofObject::invalid_id);
444  data[i][n_var_groups+vg] = my_first_dof;
445  }
446  }
447  };
448 
449  auto action_functor =
450  [this, &mesh, &objects]
451  (processor_id_type libmesh_dbg_var(pid),
452  const std::vector<dof_id_type> & ids,
453  const std::vector<datum> & data)
454  {
455  const unsigned int
456  sys_num = this->sys_number(),
457  n_var_groups = this->n_variable_groups();
458 
459  // Copy the id changes we've now been informed of
460  for (auto i : index_range(ids))
461  {
462  DofObject * requested = (this->*objects)(mesh, ids[i]);
463  libmesh_assert(requested);
464  libmesh_assert_equal_to (requested->processor_id(), pid);
465  for (unsigned int vg=0; vg != n_var_groups; ++vg)
466  {
467  unsigned int n_comp_g =
468  cast_int<unsigned int>(data[i][vg]);
469  requested->set_n_comp_group(sys_num, vg, n_comp_g);
470  if (n_comp_g)
471  {
472  dof_id_type my_first_dof = data[i][n_var_groups+vg];
473  libmesh_assert_not_equal_to (my_first_dof, DofObject::invalid_id);
474  requested->set_vg_dof_base
475  (sys_num, vg, my_first_dof);
476  }
477  }
478  }
479  };
480 
481  datum * ex = nullptr;
482  Parallel::pull_parallel_vector_data
483  (this->comm(), requested_ids, gather_functor, action_functor, ex);
484 
485 #ifdef DEBUG
486  // Double check for invalid dofs
487  for (it = objects_begin; it != objects_end; ++it)
488  {
489  DofObject * obj = *it;
490  libmesh_assert (obj);
491  unsigned int num_variables = obj->n_vars(this->sys_number());
492  for (unsigned int v=0; v != num_variables; ++v)
493  {
494  unsigned int n_comp =
495  obj->n_comp(this->sys_number(), v);
496  dof_id_type my_first_dof = n_comp ?
497  obj->dof_number(this->sys_number(), v, 0) : 0;
498  libmesh_assert_not_equal_to (my_first_dof, DofObject::invalid_id);
499  }
500  }
501 #endif
502 }
503 
504 
505 
506 void DofMap::reinit(MeshBase & mesh)
507 {
508  libmesh_assert (mesh.is_prepared());
509 
510  LOG_SCOPE("reinit()", "DofMap");
511 
512  // We ought to reconfigure our default coupling functor.
513  //
514  // The user might have removed it from our coupling functors set,
515  // but if so, who cares, this reconfiguration is cheap.
516 
517  // Avoid calling set_dof_coupling() with an empty/non-nullptr
518  // _dof_coupling matrix which may happen when there are actually no
519  // variables on the system.
520  if (this->_dof_coupling && this->_dof_coupling->empty() && !this->n_variables())
521  this->_dof_coupling = nullptr;
522  _default_coupling->set_dof_coupling(this->_dof_coupling);
523 
524  // By default we may want 0 or 1 levels of coupling
525  unsigned int standard_n_levels =
526  this->use_coupled_neighbor_dofs(mesh);
527  _default_coupling->set_n_levels
528  (std::max(_default_coupling->n_levels(), standard_n_levels));
529 
530  // But we *don't* want to restrict to a CouplingMatrix unless the
531  // user does so manually; the original libMesh behavior was to put
532  // ghost indices on the send_list regardless of variable.
533  //_default_evaluating->set_dof_coupling(this->_dof_coupling);
534 
535  const unsigned int
536  sys_num = this->sys_number(),
537  n_var_groups = this->n_variable_groups();
538 
539  // The DofObjects need to know how many variable groups we have, and
540  // how many variables there are in each group.
541  std::vector<unsigned int> n_vars_per_group; n_vars_per_group.reserve (n_var_groups);
542 
543  for (unsigned int vg=0; vg<n_var_groups; vg++)
544  n_vars_per_group.push_back (this->variable_group(vg).n_variables());
545 
546 #ifdef LIBMESH_ENABLE_AMR
547 
548  //------------------------------------------------------------
549  // Clear the old_dof_objects for all the nodes
550  // and elements so that we can overwrite them
551  for (auto & node : mesh.node_ptr_range())
552  {
553  node->clear_old_dof_object();
554  libmesh_assert (!node->get_old_dof_object());
555  }
556 
557  for (auto & elem : mesh.element_ptr_range())
558  {
559  elem->clear_old_dof_object();
560  libmesh_assert (!elem->get_old_dof_object());
561  }
562 
563 
564  //------------------------------------------------------------
565  // Set the old_dof_objects for the elements that
566  // weren't just created, if these old dof objects
567  // had variables
568  for (auto & elem : mesh.element_ptr_range())
569  {
570  // Skip the elements that were just refined
571  if (elem->refinement_flag() == Elem::JUST_REFINED)
572  continue;
573 
574  for (Node & node : elem->node_ref_range())
575  if (node.get_old_dof_object() == nullptr)
576  if (node.has_dofs(sys_num))
577  node.set_old_dof_object();
578 
579  libmesh_assert (!elem->get_old_dof_object());
580 
581  if (elem->has_dofs(sys_num))
582  elem->set_old_dof_object();
583  }
584 
585 #endif // #ifdef LIBMESH_ENABLE_AMR
586 
587 
588  //------------------------------------------------------------
589  // Then set the number of variables for each \p DofObject
590  // equal to n_variables() for this system. This will
591  // handle new \p DofObjects that may have just been created
592 
593  // All the nodes
594  for (auto & node : mesh.node_ptr_range())
595  node->set_n_vars_per_group(sys_num, n_vars_per_group);
596 
597  // All the elements
598  for (auto & elem : mesh.element_ptr_range())
599  elem->set_n_vars_per_group(sys_num, n_vars_per_group);
600 
601  // Zero _n_SCALAR_dofs, it will be updated below.
602  this->_n_SCALAR_dofs = 0;
603 
604  //------------------------------------------------------------
605  // Next allocate space for the DOF indices
606  for (unsigned int vg=0; vg<n_var_groups; vg++)
607  {
608  const VariableGroup & vg_description = this->variable_group(vg);
609 
610  const unsigned int n_var_in_group = vg_description.n_variables();
611  const FEType & base_fe_type = vg_description.type();
612 
613  const bool add_p_level =
614 #ifdef LIBMESH_ENABLE_AMR
615  !_dont_p_refine.count(vg);
616 #else
617  false;
618 #endif
619 
620  // Don't need to loop over elements for a SCALAR variable
621  // Just increment _n_SCALAR_dofs
622  if (base_fe_type.family == SCALAR)
623  {
624  this->_n_SCALAR_dofs += base_fe_type.order.get_order()*n_var_in_group;
625  continue;
626  }
627 
628  // This should be constant even on p-refined elements
629  const bool extra_hanging_dofs =
630  FEInterface::extra_hanging_dofs(base_fe_type);
631 
632  // For all the active elements, count vertex degrees of freedom.
633  for (auto & elem : mesh.active_element_ptr_range())
634  {
635  libmesh_assert(elem);
636 
637  // Skip the numbering if this variable is
638  // not active on this element's subdomain
639  if (!vg_description.active_on_subdomain(elem->subdomain_id()))
640  continue;
641 
642  FEType fe_type = base_fe_type;
643 
644  const ElemType type = elem->type();
645 
646  libmesh_error_msg_if(base_fe_type.order.get_order() >
647  int(FEInterface::max_order(base_fe_type,type)),
648  "ERROR: Finite element "
649  << Utility::enum_to_string(base_fe_type.family)
650  << " on geometric element "
651  << Utility::enum_to_string(type)
652  << "\nonly supports FEInterface::max_order = "
653  << FEInterface::max_order(base_fe_type,type)
654  << ", not fe_type.order = "
655  << base_fe_type.order);
656 
657 #ifdef LIBMESH_ENABLE_AMR
658  // Make sure we haven't done more p refinement than we can
659  // handle
660  if (add_p_level*elem->p_level() + base_fe_type.order >
661  FEInterface::max_order(base_fe_type, type))
662  {
663 # ifdef DEBUG
664  libMesh::err << "WARNING: Finite element "
665  << Utility::enum_to_string(base_fe_type.family)
666  << " on geometric element "
667  << Utility::enum_to_string(type) << std::endl
668  << "could not be p refined past FEInterface::max_order = "
669  << FEInterface::max_order(base_fe_type,type)
670  << std::endl;
671 # endif
672  elem->set_p_level(FEInterface::max_order(base_fe_type,type)
673  - base_fe_type.order);
674  }
675 #endif
676 
677  // Allocate the vertex DOFs
678  for (auto n : elem->node_index_range())
679  {
680  Node & node = elem->node_ref(n);
681 
682  if (elem->is_vertex(n))
683  {
684  const unsigned int old_node_dofs =
685  node.n_comp_group(sys_num, vg);
686 
687  const unsigned int vertex_dofs =
688  std::max(FEInterface::n_dofs_at_node(fe_type, elem, n, add_p_level),
689  old_node_dofs);
690 
691  // Some discontinuous FEs have no vertex dofs
692  if (vertex_dofs > old_node_dofs)
693  {
694  node.set_n_comp_group(sys_num, vg,
695  vertex_dofs);
696 
697  // Abusing dof_number to set a "this is a
698  // vertex" flag
699  node.set_vg_dof_base(sys_num, vg,
700  vertex_dofs);
701 
702  // libMesh::out << "sys_num,vg,old_node_dofs,vertex_dofs="
703  // << sys_num << ","
704  // << vg << ","
705  // << old_node_dofs << ","
706  // << vertex_dofs << '\n',
707  // node.debug_buffer();
708 
709  // libmesh_assert_equal_to (vertex_dofs, node.n_comp(sys_num, vg));
710  // libmesh_assert_equal_to (vertex_dofs, node.vg_dof_base(sys_num, vg));
711  }
712  }
713  }
714  } // done counting vertex dofs
715 
716  // count edge & face dofs next
717  for (auto & elem : mesh.active_element_ptr_range())
718  {
719  libmesh_assert(elem);
720 
721  // Skip the numbering if this variable is
722  // not active on this element's subdomain
723  if (!vg_description.active_on_subdomain(elem->subdomain_id()))
724  continue;
725 
726  // Allocate the edge and face DOFs
727  for (auto n : elem->node_index_range())
728  {
729  Node & node = elem->node_ref(n);
730 
731  const unsigned int old_node_dofs =
732  node.n_comp_group(sys_num, vg);
733 
734  const unsigned int vertex_dofs = old_node_dofs?
735  cast_int<unsigned int>(node.vg_dof_base (sys_num,vg)):0;
736 
737  const unsigned int new_node_dofs =
738  FEInterface::n_dofs_at_node(base_fe_type, elem, n, add_p_level);
739 
740  // We've already allocated vertex DOFs
741  if (elem->is_vertex(n))
742  {
743  libmesh_assert_greater_equal (old_node_dofs, vertex_dofs);
744  // //if (vertex_dofs < new_node_dofs)
745  // libMesh::out << "sys_num,vg,old_node_dofs,vertex_dofs,new_node_dofs="
746  // << sys_num << ","
747  // << vg << ","
748  // << old_node_dofs << ","
749  // << vertex_dofs << ","
750  // << new_node_dofs << '\n',
751  // node.debug_buffer();
752 
753  libmesh_assert_greater_equal (vertex_dofs, new_node_dofs);
754  }
755  // We need to allocate the rest
756  else
757  {
758  // If this has no dofs yet, it needs no vertex
759  // dofs, so we just give it edge or face dofs
760  if (!old_node_dofs)
761  {
762  node.set_n_comp_group(sys_num, vg,
763  new_node_dofs);
764  // Abusing dof_number to set a "this has no
765  // vertex dofs" flag
766  if (new_node_dofs)
767  node.set_vg_dof_base(sys_num, vg, 0);
768  }
769 
770  // If this has dofs, but has no vertex dofs,
771  // it may still need more edge or face dofs if
772  // we're p-refined.
773  else if (vertex_dofs == 0)
774  {
775  if (new_node_dofs > old_node_dofs)
776  {
777  node.set_n_comp_group(sys_num, vg,
778  new_node_dofs);
779 
780  node.set_vg_dof_base(sys_num, vg,
781  vertex_dofs);
782  }
783  }
784  // If this is another element's vertex,
785  // add more (non-overlapping) edge/face dofs if
786  // necessary
787  else if (extra_hanging_dofs)
788  {
789  if (new_node_dofs > old_node_dofs - vertex_dofs)
790  {
791  node.set_n_comp_group(sys_num, vg,
792  vertex_dofs + new_node_dofs);
793 
794  node.set_vg_dof_base(sys_num, vg,
795  vertex_dofs);
796  }
797  }
798  // If this is another element's vertex, add any
799  // (overlapping) edge/face dofs if necessary
800  else
801  {
802  libmesh_assert_greater_equal (old_node_dofs, vertex_dofs);
803  if (new_node_dofs > old_node_dofs)
804  {
805  node.set_n_comp_group(sys_num, vg,
806  new_node_dofs);
807 
808  node.set_vg_dof_base (sys_num, vg,
809  vertex_dofs);
810  }
811  }
812  }
813  }
814  // Allocate the element DOFs
815  const unsigned int dofs_per_elem =
816  FEInterface::n_dofs_per_elem(base_fe_type, elem, add_p_level);
817 
818  elem->set_n_comp_group(sys_num, vg, dofs_per_elem);
819 
820  }
821  } // end loop over variable groups
822 
823  // Calling DofMap::reinit() by itself makes little sense,
824  // so we won't bother with nonlocal DofObjects.
825  // Those will be fixed by distribute_dofs
826 
827  //------------------------------------------------------------
828  // Finally, clear all the current DOF indices
829  // (distribute_dofs expects them cleared!)
830  this->invalidate_dofs(mesh);
831 }
832 
833 
834 
835 void DofMap::invalidate_dofs(MeshBase & mesh) const
836 {
837  const unsigned int sys_num = this->sys_number();
838 
839  // All the nodes
840  for (auto & node : mesh.node_ptr_range())
841  node->invalidate_dofs(sys_num);
842 
843  // All the active elements.
844  for (auto & elem : mesh.active_element_ptr_range())
845  elem->invalidate_dofs(sys_num);
846 }
847 
848 
849 
851 {
852  // we don't want to clear
853  // the coupling matrix!
854  // It should not change...
855  //_dof_coupling->clear();
856  //
857  // But it would be inconsistent to leave our coupling settings
858  // through a clear()...
859  _dof_coupling = nullptr;
860 
861  // Reset ghosting functor statuses
862  {
863  for (const auto & gf : _coupling_functors)
864  {
865  libmesh_assert(gf);
866  _mesh.remove_ghosting_functor(*gf);
867  }
868  this->_coupling_functors.clear();
869 
870  // Go back to default coupling
871 
872  _default_coupling->set_dof_coupling(this->_dof_coupling);
873  _default_coupling->set_n_levels(this->use_coupled_neighbor_dofs(this->_mesh));
874 
876  }
877 
878 
879  {
880  for (const auto & gf : _algebraic_ghosting_functors)
881  {
882  libmesh_assert(gf);
883  _mesh.remove_ghosting_functor(*gf);
884  }
885  this->_algebraic_ghosting_functors.clear();
886 
887  // Go back to default send_list generation
888 
889  // _default_evaluating->set_dof_coupling(this->_dof_coupling);
890  _default_evaluating->set_n_levels(1);
892  }
893 
894  this->_shared_functors.clear();
895 
896  _variables.clear();
897  _variable_groups.clear();
898  _var_to_vg.clear();
899  _variable_group_numbers.clear();
900  _first_df.clear();
901  _end_df.clear();
902  _first_scalar_df.clear();
903  this->clear_send_list();
904  this->clear_sparsity();
906 
907 #ifdef LIBMESH_ENABLE_AMR
908 
909  _dof_constraints.clear();
910  _stashed_dof_constraints.clear();
913  _n_old_dfs = 0;
914  _first_old_df.clear();
915  _end_old_df.clear();
916  _first_old_scalar_df.clear();
917 
918 #endif
919 
920  _matrices.clear();
921 
922  _n_dfs = 0;
923 }
924 
925 
926 
927 std::size_t DofMap::distribute_dofs (MeshBase & mesh)
928 {
929  // This function must be run on all processors at once
930  parallel_object_only();
931 
932  // Log how long it takes to distribute the degrees of freedom
933  LOG_SCOPE("distribute_dofs()", "DofMap");
934 
935  libmesh_assert (mesh.is_prepared());
936 
937  const processor_id_type proc_id = this->processor_id();
938  const processor_id_type n_proc = this->n_processors();
939 
940  // libmesh_assert_greater (this->n_variables(), 0);
941  libmesh_assert_less (proc_id, n_proc);
942 
943  // re-init in case the mesh has changed
944  this->reinit(mesh);
945 
946  // By default distribute variables in a
947  // var-major fashion, but allow run-time
948  // specification
949  bool node_major_dofs = libMesh::on_command_line ("--node-major-dofs");
950 
951  // The DOF counter, will be incremented as we encounter
952  // new degrees of freedom
953  dof_id_type next_free_dof = 0;
954 
955  // Clear the send list before we rebuild it
956  this->clear_send_list();
957 
958  // Set temporary DOF indices on this processor
959  if (node_major_dofs)
960  this->distribute_local_dofs_node_major (next_free_dof, mesh);
961  else
962  this->distribute_local_dofs_var_major (next_free_dof, mesh);
963 
964  // Get DOF counts on all processors
965  std::vector<dof_id_type> dofs_on_proc(n_proc, 0);
966  this->comm().allgather(next_free_dof, dofs_on_proc);
967 
968  // Resize and fill the _first_df and _end_df arrays
969 #ifdef LIBMESH_ENABLE_AMR
972 #endif
973 
974  _first_df.resize(n_proc);
975  _end_df.resize (n_proc);
976 
977  // Get DOF offsets
978  _first_df[0] = 0;
979  for (processor_id_type i=1; i < n_proc; ++i)
980  _first_df[i] = _end_df[i-1] = _first_df[i-1] + dofs_on_proc[i-1];
981  _end_df[n_proc-1] = _first_df[n_proc-1] + dofs_on_proc[n_proc-1];
982 
983  // Clear all the current DOF indices
984  // (distribute_dofs expects them cleared!)
985  this->invalidate_dofs(mesh);
986 
987  next_free_dof = _first_df[proc_id];
988 
989  // Set permanent DOF indices on this processor
990  if (node_major_dofs)
991  this->distribute_local_dofs_node_major (next_free_dof, mesh);
992  else
993  this->distribute_local_dofs_var_major (next_free_dof, mesh);
994 
995  libmesh_assert_equal_to (next_free_dof, _end_df[proc_id]);
996 
997  //------------------------------------------------------------
998  // At this point, all n_comp and dof_number values on local
999  // DofObjects should be correct, but a DistributedMesh might have
1000  // incorrect values on non-local DofObjects. Let's request the
1001  // correct values from each other processor.
1002 
1003  if (this->n_processors() > 1)
1004  {
1005  this->set_nonlocal_dof_objects(mesh.nodes_begin(),
1006  mesh.nodes_end(),
1007  mesh, &DofMap::node_ptr);
1008 
1009  this->set_nonlocal_dof_objects(mesh.elements_begin(),
1010  mesh.elements_end(),
1011  mesh, &DofMap::elem_ptr);
1012  }
1013 
1014 #ifdef DEBUG
1015  {
1016  const unsigned int
1017  sys_num = this->sys_number();
1018 
1019  // Processors should all agree on DoF ids for the newly numbered
1020  // system.
1021  MeshTools::libmesh_assert_valid_dof_ids(mesh, sys_num);
1022 
1023  // DoF processor ids should match DofObject processor ids
1024  for (auto & node : mesh.node_ptr_range())
1025  {
1026  DofObject const * const dofobj = node;
1027  const processor_id_type obj_proc_id = dofobj->processor_id();
1028 
1029  for (auto v : make_range(dofobj->n_vars(sys_num)))
1030  for (auto c : make_range(dofobj->n_comp(sys_num,v)))
1031  {
1032  const dof_id_type dofid = dofobj->dof_number(sys_num,v,c);
1033  libmesh_assert_greater_equal (dofid, this->first_dof(obj_proc_id));
1034  libmesh_assert_less (dofid, this->end_dof(obj_proc_id));
1035  }
1036  }
1037 
1038  for (auto & elem : mesh.element_ptr_range())
1039  {
1040  DofObject const * const dofobj = elem;
1041  const processor_id_type obj_proc_id = dofobj->processor_id();
1042 
1043  for (auto v : make_range(dofobj->n_vars(sys_num)))
1044  for (auto c : make_range(dofobj->n_comp(sys_num,v)))
1045  {
1046  const dof_id_type dofid = dofobj->dof_number(sys_num,v,c);
1047  libmesh_assert_greater_equal (dofid, this->first_dof(obj_proc_id));
1048  libmesh_assert_less (dofid, this->end_dof(obj_proc_id));
1049  }
1050  }
1051  }
1052 #endif
1053 
1054  // Set the total number of degrees of freedom, then start finding
1055  // SCALAR degrees of freedom
1056 #ifdef LIBMESH_ENABLE_AMR
1057  _n_old_dfs = _n_dfs;
1059 #endif
1060  _n_dfs = _end_df[n_proc-1];
1061  _first_scalar_df.clear();
1063  dof_id_type current_SCALAR_dof_index = n_dofs() - n_SCALAR_dofs();
1064 
1065  // Calculate and cache the initial DoF indices for SCALAR variables.
1066  // This is an O(N_vars) calculation so we want to do it once per
1067  // renumbering rather than once per SCALAR_dof_indices() call
1068 
1069  for (auto v : make_range(this->n_variables()))
1070  if (this->variable(v).type().family == SCALAR)
1071  {
1072  _first_scalar_df[v] = current_SCALAR_dof_index;
1073  current_SCALAR_dof_index += this->variable(v).type().order.get_order();
1074  }
1075 
1076  // Allow our GhostingFunctor objects to reinit if necessary
1077  for (const auto & gf : _algebraic_ghosting_functors)
1078  {
1079  libmesh_assert(gf);
1080  gf->dofmap_reinit();
1081  }
1082 
1083  for (const auto & gf : _coupling_functors)
1084  {
1085  libmesh_assert(gf);
1086  gf->dofmap_reinit();
1087  }
1088 
1089  // Note that in the add_neighbors_to_send_list nodes on processor
1090  // boundaries that are shared by multiple elements are added for
1091  // each element.
1092  this->add_neighbors_to_send_list(mesh);
1093 
1094  // Here we used to clean up that data structure; now System and
1095  // EquationSystems call that for us, after we've added constraint
1096  // dependencies to the send_list too.
1097  // this->sort_send_list ();
1098 
1099  // Return total number of DOFs across all procs. We compute and
1100  // return this as a std::size_t so that we can detect situations in
1101  // which the total number of DOFs across all procs would exceed the
1102  // capability of the underlying NumericVector representation to
1103  // index into it correctly (std::size_t is the largest unsigned
1104  // type, so no NumericVector representation can exceed it).
1105  return std::accumulate(dofs_on_proc.begin(), dofs_on_proc.end(), static_cast<std::size_t>(0));
1106 }
1107 
1108 
1109 void DofMap::local_variable_indices(std::vector<dof_id_type> & idx,
1110  const MeshBase & mesh,
1111  unsigned int var_num) const
1112 {
1113  // Count dofs in the *exact* order that distribute_dofs numbered
1114  // them, so that we can assume ascending indices and use push_back
1115  // instead of find+insert.
1116 
1117  const unsigned int sys_num = this->sys_number();
1118 
1119  // If this isn't a SCALAR variable, we need to find all its field
1120  // dofs on the mesh
1121  if (this->variable_type(var_num).family != SCALAR)
1122  {
1123  const Variable & var(this->variable(var_num));
1124 
1125  for (auto & elem : mesh.active_local_element_ptr_range())
1126  {
1127  if (!var.active_on_subdomain(elem->subdomain_id()))
1128  continue;
1129 
1130  // Only count dofs connected to active
1131  // elements on this processor.
1132  const unsigned int n_nodes = elem->n_nodes();
1133 
1134  // First get any new nodal DOFS
1135  for (unsigned int n=0; n<n_nodes; n++)
1136  {
1137  const Node & node = elem->node_ref(n);
1138 
1139  if (node.processor_id() != this->processor_id())
1140  continue;
1141 
1142  const unsigned int n_comp = node.n_comp(sys_num, var_num);
1143  for(unsigned int i=0; i<n_comp; i++)
1144  {
1145  const dof_id_type index = node.dof_number(sys_num,var_num,i);
1146  libmesh_assert (this->local_index(index));
1147 
1148  if (idx.empty() || index > idx.back())
1149  idx.push_back(index);
1150  }
1151  }
1152 
1153  // Next get any new element DOFS
1154  const unsigned int n_comp = elem->n_comp(sys_num, var_num);
1155  for (unsigned int i=0; i<n_comp; i++)
1156  {
1157  const dof_id_type index = elem->dof_number(sys_num,var_num,i);
1158  if (idx.empty() || index > idx.back())
1159  idx.push_back(index);
1160  }
1161  } // done looping over elements
1162 
1163 
1164  // we may have missed assigning DOFs to nodes that we own
1165  // but to which we have no connected elements matching our
1166  // variable restriction criterion. this will happen, for example,
1167  // if variable V is restricted to subdomain S. We may not own
1168  // any elements which live in S, but we may own nodes which are
1169  // *connected* to elements which do. in this scenario these nodes
1170  // will presently have unnumbered DOFs. we need to take care of
1171  // them here since we own them and no other processor will touch them.
1172  for (const auto & node : mesh.local_node_ptr_range())
1173  {
1174  libmesh_assert(node);
1175 
1176  const unsigned int n_comp = node->n_comp(sys_num, var_num);
1177  for (unsigned int i=0; i<n_comp; i++)
1178  {
1179  const dof_id_type index = node->dof_number(sys_num,var_num,i);
1180  if (idx.empty() || index > idx.back())
1181  idx.push_back(index);
1182  }
1183  }
1184  }
1185  // Otherwise, count up the SCALAR dofs, if we're on the processor
1186  // that holds this SCALAR variable
1187  else if (this->processor_id() == (this->n_processors()-1))
1188  {
1189  std::vector<dof_id_type> di_scalar;
1190  this->SCALAR_dof_indices(di_scalar,var_num);
1191  idx.insert( idx.end(), di_scalar.begin(), di_scalar.end());
1192  }
1193 }
1194 
1195 
1197  MeshBase & mesh)
1198 {
1199  const unsigned int sys_num = this->sys_number();
1200  const unsigned int n_var_groups = this->n_variable_groups();
1201 
1202  // Our numbering here must be kept consistent with the numbering
1203  // scheme assumed by DofMap::local_variable_indices!
1204 
1205  //-------------------------------------------------------------------------
1206  // First count and assign temporary numbers to local dofs
1207  for (auto & elem : mesh.active_local_element_ptr_range())
1208  {
1209  // Only number dofs connected to active
1210  // elements on this processor.
1211  const unsigned int n_nodes = elem->n_nodes();
1212 
1213  // First number the nodal DOFS
1214  for (unsigned int n=0; n<n_nodes; n++)
1215  {
1216  Node & node = elem->node_ref(n);
1217 
1218  for (unsigned vg=0; vg<n_var_groups; vg++)
1219  {
1220  const VariableGroup & vg_description(this->variable_group(vg));
1221 
1222  if ((vg_description.type().family != SCALAR) &&
1223  (vg_description.active_on_subdomain(elem->subdomain_id())))
1224  {
1225  // assign dof numbers (all at once) if this is
1226  // our node and if they aren't already there
1227  if ((node.n_comp_group(sys_num,vg) > 0) &&
1228  (node.processor_id() == this->processor_id()) &&
1229  (node.vg_dof_base(sys_num,vg) ==
1231  {
1232  node.set_vg_dof_base(sys_num, vg,
1233  next_free_dof);
1234  next_free_dof += (vg_description.n_variables()*
1235  node.n_comp_group(sys_num,vg));
1236  //node.debug_buffer();
1237  }
1238  }
1239  }
1240  }
1241 
1242  // Now number the element DOFS
1243  for (unsigned vg=0; vg<n_var_groups; vg++)
1244  {
1245  const VariableGroup & vg_description(this->variable_group(vg));
1246 
1247  if ((vg_description.type().family != SCALAR) &&
1248  (vg_description.active_on_subdomain(elem->subdomain_id())))
1249  if (elem->n_comp_group(sys_num,vg) > 0)
1250  {
1251  libmesh_assert_equal_to (elem->vg_dof_base(sys_num,vg),
1253 
1254  elem->set_vg_dof_base(sys_num,
1255  vg,
1256  next_free_dof);
1257 
1258  next_free_dof += (vg_description.n_variables()*
1259  elem->n_comp(sys_num,vg));
1260  }
1261  }
1262  } // done looping over elements
1263 
1264 
1265  // we may have missed assigning DOFs to nodes that we own
1266  // but to which we have no connected elements matching our
1267  // variable restriction criterion. this will happen, for example,
1268  // if variable V is restricted to subdomain S. We may not own
1269  // any elements which live in S, but we may own nodes which are
1270  // *connected* to elements which do. in this scenario these nodes
1271  // will presently have unnumbered DOFs. we need to take care of
1272  // them here since we own them and no other processor will touch them.
1273  for (auto & node : mesh.local_node_ptr_range())
1274  for (unsigned vg=0; vg<n_var_groups; vg++)
1275  {
1276  const VariableGroup & vg_description(this->variable_group(vg));
1277 
1278  if (node->n_comp_group(sys_num,vg))
1279  if (node->vg_dof_base(sys_num,vg) == DofObject::invalid_id)
1280  {
1281  node->set_vg_dof_base (sys_num,
1282  vg,
1283  next_free_dof);
1284 
1285  next_free_dof += (vg_description.n_variables()*
1286  node->n_comp(sys_num,vg));
1287  }
1288  }
1289 
1290  this->distribute_scalar_dofs(next_free_dof);
1291 
1292 #ifdef DEBUG
1293  this->assert_no_nodes_missed(mesh);
1294 #endif // DEBUG
1295 }
1296 
1297 
1298 
1300  MeshBase & mesh)
1301 {
1302  const unsigned int sys_num = this->sys_number();
1303  const unsigned int n_var_groups = this->n_variable_groups();
1304 
1305  // Our numbering here must be kept consistent with the numbering
1306  // scheme assumed by DofMap::local_variable_indices!
1307 
1308  //-------------------------------------------------------------------------
1309  // First count and assign temporary numbers to local dofs
1310  for (unsigned vg=0; vg<n_var_groups; vg++)
1311  {
1312  const VariableGroup & vg_description(this->variable_group(vg));
1313 
1314  const unsigned int n_vars_in_group = vg_description.n_variables();
1315 
1316  // Skip the SCALAR dofs
1317  if (vg_description.type().family == SCALAR)
1318  continue;
1319 
1320  for (auto & elem : mesh.active_local_element_ptr_range())
1321  {
1322  // Only number dofs connected to active elements on this
1323  // processor and only variables which are active on on this
1324  // element's subdomain.
1325  if (!vg_description.active_on_subdomain(elem->subdomain_id()))
1326  continue;
1327 
1328  const unsigned int n_nodes = elem->n_nodes();
1329 
1330  // First number the nodal DOFS
1331  for (unsigned int n=0; n<n_nodes; n++)
1332  {
1333  Node & node = elem->node_ref(n);
1334 
1335  // assign dof numbers (all at once) if this is
1336  // our node and if they aren't already there
1337  if ((node.n_comp_group(sys_num,vg) > 0) &&
1338  (node.processor_id() == this->processor_id()) &&
1339  (node.vg_dof_base(sys_num,vg) ==
1341  {
1342  node.set_vg_dof_base(sys_num, vg, next_free_dof);
1343 
1344  next_free_dof += (n_vars_in_group*
1345  node.n_comp_group(sys_num,vg));
1346  }
1347  }
1348 
1349  // Now number the element DOFS
1350  if (elem->n_comp_group(sys_num,vg) > 0)
1351  {
1352  libmesh_assert_equal_to (elem->vg_dof_base(sys_num,vg),
1354 
1355  elem->set_vg_dof_base(sys_num,
1356  vg,
1357  next_free_dof);
1358 
1359  next_free_dof += (n_vars_in_group*
1360  elem->n_comp_group(sys_num,vg));
1361  }
1362  } // end loop on elements
1363 
1364  // we may have missed assigning DOFs to nodes that we own
1365  // but to which we have no connected elements matching our
1366  // variable restriction criterion. this will happen, for example,
1367  // if variable V is restricted to subdomain S. We may not own
1368  // any elements which live in S, but we may own nodes which are
1369  // *connected* to elements which do. in this scenario these nodes
1370  // will presently have unnumbered DOFs. we need to take care of
1371  // them here since we own them and no other processor will touch them.
1372  for (auto & node : mesh.local_node_ptr_range())
1373  if (node->n_comp_group(sys_num,vg))
1374  if (node->vg_dof_base(sys_num,vg) == DofObject::invalid_id)
1375  {
1376  node->set_vg_dof_base (sys_num,
1377  vg,
1378  next_free_dof);
1379 
1380  next_free_dof += (n_vars_in_group*
1381  node->n_comp_group(sys_num,vg));
1382  }
1383  } // end loop on variable groups
1384 
1385  this->distribute_scalar_dofs(next_free_dof);
1386 
1387 #ifdef DEBUG
1388  this->assert_no_nodes_missed(mesh);
1389 #endif
1390 }
1391 
1392 
1393 
1395 {
1396  this->_n_SCALAR_dofs = 0;
1397  for (auto vg : make_range(this->n_variable_groups()))
1398  {
1399  const VariableGroup & vg_description(this->variable_group(vg));
1400 
1401  if (vg_description.type().family == SCALAR)
1402  {
1403  this->_n_SCALAR_dofs += (vg_description.n_variables()*
1404  vg_description.type().order.get_order());
1405  continue;
1406  }
1407  }
1408 
1409  // Only increment next_free_dof if we're on the processor
1410  // that holds this SCALAR variable
1411  if (this->processor_id() == (this->n_processors()-1))
1412  next_free_dof += _n_SCALAR_dofs;
1413 }
1414 
1415 
1416 
1417 #ifdef DEBUG
1418 void DofMap::assert_no_nodes_missed(MeshBase & mesh)
1419 {
1420  MeshTools::libmesh_assert_valid_procids<Node>(mesh);
1421 
1422  for (auto & node : mesh.local_node_ptr_range())
1423  {
1424  unsigned int n_var_g = node->n_var_groups(this->sys_number());
1425  for (unsigned int vg=0; vg != n_var_g; ++vg)
1426  {
1427  unsigned int n_comp_g =
1428  node->n_comp_group(this->sys_number(), vg);
1429  dof_id_type my_first_dof = n_comp_g ?
1430  node->vg_dof_base(this->sys_number(), vg) : 0;
1431  libmesh_assert_not_equal_to (my_first_dof, DofObject::invalid_id);
1432  }
1433  }
1434 }
1435 #endif // DEBUG
1436 
1437 
1438 void
1439 DofMap::
1440 merge_ghost_functor_outputs(GhostingFunctor::map_type & elements_to_ghost,
1441  CouplingMatricesSet & temporary_coupling_matrices,
1442  const std::set<GhostingFunctor *>::iterator & gf_begin,
1443  const std::set<GhostingFunctor *>::iterator & gf_end,
1444  const MeshBase::const_element_iterator & elems_begin,
1445  const MeshBase::const_element_iterator & elems_end,
1447 {
1448  for (const auto & gf : as_range(gf_begin, gf_end))
1449  {
1450  GhostingFunctor::map_type more_elements_to_ghost;
1451 
1452  libmesh_assert(gf);
1453  (*gf)(elems_begin, elems_end, p, more_elements_to_ghost);
1454 
1455  // A GhostingFunctor should only return active elements, but
1456  // I forgot to *document* that, so let's go as easy as we
1457  // can on functors that return inactive elements.
1458 #if defined(LIBMESH_ENABLE_DEPRECATED) && defined(LIBMESH_ENABLE_AMR)
1459  std::vector<std::pair<const Elem*, const CouplingMatrix*>> children_to_couple;
1460  for (auto it = more_elements_to_ghost.begin();
1461  it != more_elements_to_ghost.end();)
1462  {
1463  const Elem * elem = it->first;
1464  if (!elem->active())
1465  {
1466  libmesh_deprecated();
1467  std::vector<const Elem*> children_to_ghost;
1468  elem->active_family_tree(children_to_ghost,
1469  /*reset=*/ false);
1470  for (const Elem * child : children_to_ghost)
1471  if (child->processor_id() != p)
1472  children_to_couple.emplace_back(child, it->second);
1473 
1474  it = more_elements_to_ghost.erase(it);
1475  }
1476  else
1477  ++it;
1478  }
1479  more_elements_to_ghost.insert(children_to_couple.begin(),
1480  children_to_couple.end());
1481 #endif
1482 
1483  for (const auto & [elem, elem_cm] : more_elements_to_ghost)
1484  {
1485  // At this point we should only have active elements, even
1486  // if we had to fix up gf output to get here.
1487  libmesh_assert(elem->active());
1488 
1489  GhostingFunctor::map_type::iterator existing_it =
1490  elements_to_ghost.find (elem);
1491 
1492  if (existing_it == elements_to_ghost.end())
1493  elements_to_ghost.emplace(elem, elem_cm);
1494  else
1495  {
1496  if (existing_it->second)
1497  {
1498  if (elem_cm)
1499  {
1500  // If this isn't already a temporary
1501  // then we need to make one so we'll
1502  // have a non-const matrix to merge
1503  if (temporary_coupling_matrices.empty() ||
1504  !temporary_coupling_matrices.count(existing_it->second))
1505  {
1506  // Make copy. This just calls the
1507  // compiler-generated copy constructor
1508  // because the CouplingMatrix class does not
1509  // define a custom copy constructor.
1510  auto result_pr = temporary_coupling_matrices.insert(std::make_unique<CouplingMatrix>(*existing_it->second));
1511  existing_it->second = result_pr.first->get();
1512  }
1513 
1514  // Merge elem_cm into existing CouplingMatrix
1515  const_cast<CouplingMatrix &>(*existing_it->second) &= *elem_cm;
1516  }
1517  else // elem_cm == nullptr
1518  {
1519  // Any existing_it matrix merged with a full
1520  // matrix (symbolized as nullptr) gives another
1521  // full matrix (symbolizable as nullptr).
1522 
1523  // So if existing_it->second is a temporary then
1524  // we don't need it anymore; we might as well
1525  // remove it to keep the set of temporaries
1526  // small.
1527  auto temp_it = temporary_coupling_matrices.find(existing_it->second);
1528  if (temp_it != temporary_coupling_matrices.end())
1529  temporary_coupling_matrices.erase(temp_it);
1530 
1531  existing_it->second = nullptr;
1532  }
1533  }
1534  // else we have a nullptr already, then we have a full
1535  // coupling matrix, already, and merging with anything
1536  // else won't change that, so we're done.
1537  }
1538  }
1539  }
1540 }
1541 
1542 
1543 
1545 {
1546  LOG_SCOPE("add_neighbors_to_send_list()", "DofMap");
1547 
1548  // Return immediately if there's no ghost data
1549  if (this->n_processors() == 1)
1550  return;
1551 
1552  const unsigned int n_var = this->n_variables();
1553 
1554  MeshBase::const_element_iterator local_elem_it
1555  = mesh.active_local_elements_begin();
1556  const MeshBase::const_element_iterator local_elem_end
1557  = mesh.active_local_elements_end();
1558 
1559  GhostingFunctor::map_type elements_to_send;
1560  DofMap::CouplingMatricesSet temporary_coupling_matrices;
1561 
1562  // We need to add dofs to the send list if they've been directly
1563  // requested by an algebraic ghosting functor or they've been
1564  // indirectly requested by a coupling functor.
1565  this->merge_ghost_functor_outputs(elements_to_send,
1566  temporary_coupling_matrices,
1569  local_elem_it, local_elem_end, mesh.processor_id());
1570 
1571  this->merge_ghost_functor_outputs(elements_to_send,
1572  temporary_coupling_matrices,
1573  this->coupling_functors_begin(),
1574  this->coupling_functors_end(),
1575  local_elem_it, local_elem_end, mesh.processor_id());
1576 
1577  // Making a list of non-zero coupling matrix columns is an
1578  // O(N_var^2) operation. We cache it so we only have to do it once
1579  // per CouplingMatrix and not once per element.
1580  std::map<const CouplingMatrix *, std::vector<unsigned int>>
1581  column_variable_lists;
1582 
1583  for (const auto & [partner, ghost_coupling] : elements_to_send)
1584  {
1585  // We asked ghosting functors not to give us local elements
1586  libmesh_assert_not_equal_to
1587  (partner->processor_id(), this->processor_id());
1588 
1589  // Loop over any present coupling matrix column variables if we
1590  // have a coupling matrix, or just add all variables to
1591  // send_list if not.
1592  if (ghost_coupling)
1593  {
1594  libmesh_assert_equal_to (ghost_coupling->size(), n_var);
1595 
1596  // Try to find a cached list of column variables.
1597  std::map<const CouplingMatrix *, std::vector<unsigned int>>::const_iterator
1598  column_variable_list = column_variable_lists.find(ghost_coupling);
1599 
1600  // If we didn't find it, then we need to create it.
1601  if (column_variable_list == column_variable_lists.end())
1602  {
1603  auto inserted_variable_list_pair =
1604  column_variable_lists.emplace(ghost_coupling, std::vector<unsigned int>());
1605  column_variable_list = inserted_variable_list_pair.first;
1606 
1607  std::vector<unsigned int> & new_variable_list =
1608  inserted_variable_list_pair.first->second;
1609 
1610  std::vector<unsigned char> has_variable(n_var, false);
1611 
1612  for (unsigned int vi = 0; vi != n_var; ++vi)
1613  {
1614  ConstCouplingRow ccr(vi, *ghost_coupling);
1615 
1616  for (const auto & vj : ccr)
1617  has_variable[vj] = true;
1618  }
1619  for (unsigned int vj = 0; vj != n_var; ++vj)
1620  {
1621  if (has_variable[vj])
1622  new_variable_list.push_back(vj);
1623  }
1624  }
1625 
1626  const std::vector<unsigned int> & variable_list =
1627  column_variable_list->second;
1628 
1629  for (const auto & vj : variable_list)
1630  {
1631  std::vector<dof_id_type> di;
1632  this->dof_indices (partner, di, vj);
1633 
1634  // Insert the remote DOF indices into the send list
1635  for (auto d : di)
1636  if (d != DofObject::invalid_id &&
1637  !this->local_index(d))
1638  {
1639  libmesh_assert_less(d, this->n_dofs());
1640  _send_list.push_back(d);
1641  }
1642  }
1643  }
1644  else
1645  {
1646  std::vector<dof_id_type> di;
1647  this->dof_indices (partner, di);
1648 
1649  // Insert the remote DOF indices into the send list
1650  for (const auto & dof : di)
1651  if (dof != DofObject::invalid_id &&
1652  !this->local_index(dof))
1653  {
1654  libmesh_assert_less(dof, this->n_dofs());
1655  _send_list.push_back(dof);
1656  }
1657  }
1658 
1659  }
1660 
1661  // We're now done with any merged coupling matrices we had to create.
1662  temporary_coupling_matrices.clear();
1663 
1664  //-------------------------------------------------------------------------
1665  // Our coupling functors added dofs from neighboring elements to the
1666  // send list, but we may still need to add non-local dofs from local
1667  // elements.
1668  //-------------------------------------------------------------------------
1669 
1670  // Loop over the active local elements, adding all active elements
1671  // that neighbor an active local element to the send list.
1672  for ( ; local_elem_it != local_elem_end; ++local_elem_it)
1673  {
1674  const Elem * elem = *local_elem_it;
1675 
1676  std::vector<dof_id_type> di;
1677  this->dof_indices (elem, di);
1678 
1679  // Insert the remote DOF indices into the send list
1680  for (const auto & dof : di)
1681  if (dof != DofObject::invalid_id &&
1682  !this->local_index(dof))
1683  {
1684  libmesh_assert_less(dof, this->n_dofs());
1685  _send_list.push_back(dof);
1686  }
1687  }
1688 }
1689 
1690 
1691 
1693 {
1694  LOG_SCOPE("prepare_send_list()", "DofMap");
1695 
1696  // Return immediately if there's no ghost data
1697  if (this->n_processors() == 1)
1698  return;
1699 
1700  // Check to see if we have any extra stuff to add to the send_list
1702  {
1703  if (_augment_send_list)
1704  {
1705  libmesh_here();
1706  libMesh::out << "WARNING: You have specified both an extra send list function and object.\n"
1707  << " Are you sure this is what you meant to do??"
1708  << std::endl;
1709  }
1710 
1712  }
1713 
1714  if (_augment_send_list)
1716 
1717  // First sort the send list. After this
1718  // duplicated elements will be adjacent in the
1719  // vector
1720  std::sort(_send_list.begin(), _send_list.end());
1721 
1722  // Now use std::unique to remove duplicate entries
1723  std::vector<dof_id_type>::iterator new_end =
1724  std::unique (_send_list.begin(), _send_list.end());
1725 
1726  // Remove the end of the send_list. Use the "swap trick"
1727  // from Effective STL
1728  std::vector<dof_id_type> (_send_list.begin(), new_end).swap (_send_list);
1729 
1730  // Make sure the send list has nothing invalid in it.
1731  libmesh_assert(_send_list.empty() || _send_list.back() < this->n_dofs());
1732 }
1733 
1734 void DofMap::reinit_send_list (MeshBase & mesh)
1735 {
1736  this->clear_send_list();
1737  this->add_neighbors_to_send_list(mesh);
1738 
1739 #ifdef LIBMESH_ENABLE_CONSTRAINTS
1740  // This is assuming that we only need to recommunicate
1741  // the constraints and no new ones have been added since
1742  // a previous call to reinit_constraints.
1743  this->process_constraints(mesh);
1744 #endif
1745  this->prepare_send_list();
1746 }
1747 
1748 void DofMap::set_implicit_neighbor_dofs(bool implicit_neighbor_dofs)
1749 {
1751  _implicit_neighbor_dofs = implicit_neighbor_dofs;
1752 }
1753 
1755 {
1757 }
1758 
1759 
1760 bool DofMap::use_coupled_neighbor_dofs(const MeshBase & /*mesh*/) const
1761 {
1762  // If we were asked on the command line, then we need to
1763  // include sensitivities between neighbor degrees of freedom
1764  bool implicit_neighbor_dofs =
1765  libMesh::on_command_line ("--implicit-neighbor-dofs");
1766 
1767  // If the user specifies --implicit-neighbor-dofs 0, then
1768  // presumably he knows what he is doing and we won't try to
1769  // automatically turn it on even when all the variables are
1770  // discontinuous.
1771  if (implicit_neighbor_dofs)
1772  {
1773  // No flag provided defaults to 'true'
1774  int flag = 1;
1775  flag = libMesh::command_line_next ("--implicit-neighbor-dofs", flag);
1776 
1777  if (!flag)
1778  {
1779  // The user said --implicit-neighbor-dofs 0, so he knows
1780  // what he is doing and really doesn't want it.
1781  return false;
1782  }
1783  }
1784 
1785  // Possibly override the commandline option, if set_implicit_neighbor_dofs
1786  // has been called.
1788  {
1789  implicit_neighbor_dofs = _implicit_neighbor_dofs;
1790 
1791  // Again, if the user explicitly says implicit_neighbor_dofs = false,
1792  // then we return here.
1793  if (!implicit_neighbor_dofs)
1794  return false;
1795  }
1796 
1797  // Look at all the variables in this system. If every one is
1798  // discontinuous then the user must be doing DG/FVM, so be nice
1799  // and force implicit_neighbor_dofs=true.
1800  {
1801  bool all_discontinuous_dofs = true;
1802 
1803  for (auto var : make_range(this->n_variables()))
1804  if (FEInterface::get_continuity(this->variable_type(var)) != DISCONTINUOUS)
1805  all_discontinuous_dofs = false;
1806 
1807  if (all_discontinuous_dofs)
1808  implicit_neighbor_dofs = true;
1809  }
1810 
1811  return implicit_neighbor_dofs;
1812 }
1813 
1814 
1815 
1816 void DofMap::compute_sparsity(const MeshBase & mesh)
1817 {
1819 
1820  // It is possible that some \p SparseMatrix implementations want to
1821  // see the sparsity pattern before we throw it away. If so, we
1822  // share a view of its arrays, and we pass it in to the matrices.
1823  for (const auto & mat : _matrices)
1824  {
1825  mat->attach_sparsity_pattern (*_sp);
1827  mat->update_sparsity_pattern (_sp->get_sparsity_pattern());
1828  }
1829  // If we don't need the full sparsity pattern anymore, free the
1830  // parts of it we don't need.
1832  _sp->clear_full_sparsity();
1833 }
1834 
1835 
1836 
1838 {
1839  _sp.reset();
1840 }
1841 
1842 
1843 
1845 {
1848 }
1849 
1850 
1851 
1853 {
1854  this->add_coupling_functor(this->default_coupling());
1856 }
1857 
1858 
1859 
1860 void
1861 DofMap::add_coupling_functor(GhostingFunctor & coupling_functor,
1862  bool to_mesh)
1863 {
1864  _coupling_functors.insert(&coupling_functor);
1865  coupling_functor.set_mesh(&_mesh);
1866  if (to_mesh)
1867  _mesh.add_ghosting_functor(coupling_functor);
1868 }
1869 
1870 
1871 
1872 void
1873 DofMap::remove_coupling_functor(GhostingFunctor & coupling_functor)
1874 {
1875  _coupling_functors.erase(&coupling_functor);
1876  _mesh.remove_ghosting_functor(coupling_functor);
1877 
1878  auto it = _shared_functors.find(&coupling_functor);
1879  if (it != _shared_functors.end())
1880  _shared_functors.erase(it);
1881 }
1882 
1883 
1884 
1885 void
1886 DofMap::add_algebraic_ghosting_functor(GhostingFunctor & evaluable_functor,
1887  bool to_mesh)
1888 {
1889  _algebraic_ghosting_functors.insert(&evaluable_functor);
1890  evaluable_functor.set_mesh(&_mesh);
1891  if (to_mesh)
1892  _mesh.add_ghosting_functor(evaluable_functor);
1893 }
1894 
1895 
1896 
1897 void
1898 DofMap::remove_algebraic_ghosting_functor(GhostingFunctor & evaluable_functor)
1899 {
1900  _algebraic_ghosting_functors.erase(&evaluable_functor);
1901  _mesh.remove_ghosting_functor(evaluable_functor);
1902 
1903  auto it = _shared_functors.find(&evaluable_functor);
1904  if (it != _shared_functors.end())
1905  _shared_functors.erase(it);
1906 }
1907 
1908 
1909 
1911  const std::vector<dof_id_type> & dof_indices_in,
1912  DenseVectorBase<Number> & Ue) const
1913 {
1914  const unsigned int n_original_dofs = dof_indices_in.size();
1915 
1916 #ifdef LIBMESH_ENABLE_AMR
1917 
1918  // Trivial mapping
1919  libmesh_assert_equal_to (dof_indices_in.size(), Ue.size());
1920  bool has_constrained_dofs = false;
1921 
1922  for (unsigned int il=0; il != n_original_dofs; ++il)
1923  {
1924  const dof_id_type ig = dof_indices_in[il];
1925 
1926  if (this->is_constrained_dof (ig)) has_constrained_dofs = true;
1927 
1928  libmesh_assert_less (ig, Ug.size());
1929 
1930  Ue.el(il) = Ug(ig);
1931  }
1932 
1933  // If the element has any constrained DOFs then we need
1934  // to account for them in the mapping. This will handle
1935  // the case that the input vector is not constrained.
1936  if (has_constrained_dofs)
1937  {
1938  // Copy the input DOF indices.
1939  std::vector<dof_id_type> constrained_dof_indices(dof_indices_in);
1940 
1943 
1944  this->build_constraint_matrix_and_vector (C, H, constrained_dof_indices);
1945 
1946  libmesh_assert_equal_to (dof_indices_in.size(), C.m());
1947  libmesh_assert_equal_to (constrained_dof_indices.size(), C.n());
1948 
1949  // zero-out Ue
1950  Ue.zero();
1951 
1952  // compute Ue = C Ug, with proper mapping.
1953  for (unsigned int i=0; i != n_original_dofs; i++)
1954  {
1955  Ue.el(i) = H(i);
1956 
1957  const unsigned int n_constrained =
1958  cast_int<unsigned int>(constrained_dof_indices.size());
1959  for (unsigned int j=0; j<n_constrained; j++)
1960  {
1961  const dof_id_type jg = constrained_dof_indices[j];
1962 
1963  // If Ug is a serial or ghosted vector, then this assert is
1964  // overzealous. If Ug is a parallel vector, then this assert
1965  // is redundant.
1966  // libmesh_assert ((jg >= Ug.first_local_index()) &&
1967  // (jg < Ug.last_local_index()));
1968 
1969  Ue.el(i) += C(i,j)*Ug(jg);
1970  }
1971  }
1972  }
1973 
1974 #else
1975 
1976  // Trivial mapping
1977 
1978  libmesh_assert_equal_to (n_original_dofs, Ue.size());
1979 
1980  for (unsigned int il=0; il<n_original_dofs; il++)
1981  {
1982  const dof_id_type ig = dof_indices_in[il];
1983 
1984  libmesh_assert ((ig >= Ug.first_local_index()) && (ig < Ug.last_local_index()));
1985 
1986  Ue.el(il) = Ug(ig);
1987  }
1988 
1989 #endif
1990 }
1991 
1992 void DofMap::dof_indices (const Elem * const elem,
1993  std::vector<dof_id_type> & di) const
1994 {
1995  // We now allow elem==nullptr to request just SCALAR dofs
1996  // libmesh_assert(elem);
1997 
1998  // If we are asking for current indices on an element, it ought to
1999  // be an active element (or a Side proxy, which also thinks it's
2000  // active)
2001  libmesh_assert(!elem || elem->active());
2002 
2003  LOG_SCOPE("dof_indices()", "DofMap");
2004 
2005  // Clear the DOF indices vector
2006  di.clear();
2007 
2008  const unsigned int n_var_groups = this->n_variable_groups();
2009 
2010 #ifdef DEBUG
2011  // Check that sizes match in DEBUG mode
2012  std::size_t tot_size = 0;
2013 #endif
2014 
2015  if (elem && elem->type() == TRI3SUBDIVISION)
2016  {
2017  // Subdivision surface FE require the 1-ring around elem
2018  const Tri3Subdivision * sd_elem = static_cast<const Tri3Subdivision *>(elem);
2019 
2020  // Ghost subdivision elements have no real dofs
2021  if (!sd_elem->is_ghost())
2022  {
2023  // Determine the nodes contributing to element elem
2024  std::vector<const Node *> elem_nodes;
2025  MeshTools::Subdivision::find_one_ring(sd_elem, elem_nodes);
2026 
2027  // Get the dof numbers
2028  for (unsigned int vg=0; vg<n_var_groups; vg++)
2029  {
2030  const VariableGroup & var = this->variable_group(vg);
2031  const unsigned int vars_in_group = var.n_variables();
2032 
2033  if (var.type().family == SCALAR &&
2034  var.active_on_subdomain(elem->subdomain_id()))
2035  {
2036  for (unsigned int vig=0; vig != vars_in_group; ++vig)
2037  {
2038 #ifdef DEBUG
2039  tot_size += var.type().order;
2040 #endif
2041  std::vector<dof_id_type> di_new;
2042  this->SCALAR_dof_indices(di_new,var.number(vig));
2043  di.insert( di.end(), di_new.begin(), di_new.end());
2044  }
2045  }
2046  else
2047  for (unsigned int vig=0; vig != vars_in_group; ++vig)
2048  {
2049  _dof_indices(*elem, elem->p_level(), di, vg, vig,
2050  elem_nodes.data(),
2051  cast_int<unsigned int>(elem_nodes.size())
2052 #ifdef DEBUG
2053  , var.number(vig), tot_size
2054 #endif
2055  );
2056  }
2057  }
2058  }
2059 
2060  return;
2061  }
2062 
2063  // Get the dof numbers for each variable
2064  const unsigned int n_nodes = elem ? elem->n_nodes() : 0;
2065  for (unsigned int vg=0; vg<n_var_groups; vg++)
2066  {
2067  const VariableGroup & var = this->variable_group(vg);
2068  const unsigned int vars_in_group = var.n_variables();
2069 
2070  if (var.type().family == SCALAR &&
2071  (!elem ||
2072  var.active_on_subdomain(elem->subdomain_id())))
2073  {
2074  for (unsigned int vig=0; vig != vars_in_group; ++vig)
2075  {
2076 #ifdef DEBUG
2077  tot_size += var.type().order;
2078 #endif
2079  std::vector<dof_id_type> di_new;
2080  this->SCALAR_dof_indices(di_new,var.number(vig));
2081  di.insert( di.end(), di_new.begin(), di_new.end());
2082  }
2083  }
2084  else if (elem)
2085  for (unsigned int vig=0; vig != vars_in_group; ++vig)
2086  {
2087  _dof_indices(*elem, elem->p_level(), di, vg, vig,
2088  elem->get_nodes(), n_nodes
2089 #ifdef DEBUG
2090  , var.number(vig), tot_size
2091 #endif
2092  );
2093  }
2094  }
2095 
2096 #ifdef DEBUG
2097  libmesh_assert_equal_to (tot_size, di.size());
2098 #endif
2099 }
2100 
2101 
2102 void DofMap::dof_indices (const Elem * const elem,
2103  std::vector<dof_id_type> & di,
2104  const unsigned int vn,
2105  int p_level) const
2106 {
2107  // We now allow elem==nullptr to request just SCALAR dofs
2108  // libmesh_assert(elem);
2109 
2110  LOG_SCOPE("dof_indices()", "DofMap");
2111 
2112  // Clear the DOF indices vector
2113  di.clear();
2114 
2115  // Use the default p refinement level?
2116  if (p_level == -12345)
2117  p_level = elem ? elem->p_level() : 0;
2118 
2119  const unsigned int vg = this->_variable_group_numbers[vn];
2120  const VariableGroup & var = this->variable_group(vg);
2121  const unsigned int vig = vn - var.number();
2122 
2123 #ifdef DEBUG
2124  // Check that sizes match in DEBUG mode
2125  std::size_t tot_size = 0;
2126 #endif
2127 
2128  if (elem && elem->type() == TRI3SUBDIVISION)
2129  {
2130  // Subdivision surface FE require the 1-ring around elem
2131  const Tri3Subdivision * sd_elem = static_cast<const Tri3Subdivision *>(elem);
2132 
2133  // Ghost subdivision elements have no real dofs
2134  if (!sd_elem->is_ghost())
2135  {
2136  // Determine the nodes contributing to element elem
2137  std::vector<const Node *> elem_nodes;
2138  MeshTools::Subdivision::find_one_ring(sd_elem, elem_nodes);
2139 
2140  _dof_indices(*elem, p_level, di, vg, vig, elem_nodes.data(),
2141  cast_int<unsigned int>(elem_nodes.size())
2142 #ifdef DEBUG
2143  , vn, tot_size
2144 #endif
2145  );
2146  }
2147 
2148  return;
2149  }
2150 
2151  // Get the dof numbers
2152  if (var.type().family == SCALAR &&
2153  (!elem ||
2154  var.active_on_subdomain(elem->subdomain_id())))
2155  {
2156 #ifdef DEBUG
2157  tot_size += var.type().order;
2158 #endif
2159  std::vector<dof_id_type> di_new;
2160  this->SCALAR_dof_indices(di_new,vn);
2161  di.insert( di.end(), di_new.begin(), di_new.end());
2162  }
2163  else if (elem)
2164  _dof_indices(*elem, p_level, di, vg, vig, elem->get_nodes(),
2165  elem->n_nodes()
2166 #ifdef DEBUG
2167  , vn, tot_size
2168 #endif
2169  );
2170 
2171 #ifdef DEBUG
2172  libmesh_assert_equal_to (tot_size, di.size());
2173 #endif
2174 }
2175 
2176 
2177 void DofMap::dof_indices (const Node * const node,
2178  std::vector<dof_id_type> & di) const
2179 {
2180  // We allow node==nullptr to request just SCALAR dofs
2181  // libmesh_assert(elem);
2182 
2183  LOG_SCOPE("dof_indices(Node)", "DofMap");
2184 
2185  // Clear the DOF indices vector
2186  di.clear();
2187 
2188  const unsigned int n_var_groups = this->n_variable_groups();
2189  const unsigned int sys_num = this->sys_number();
2190 
2191  // Get the dof numbers
2192  for (unsigned int vg=0; vg<n_var_groups; vg++)
2193  {
2194  const VariableGroup & var = this->variable_group(vg);
2195  const unsigned int vars_in_group = var.n_variables();
2196 
2197  if (var.type().family == SCALAR)
2198  {
2199  for (unsigned int vig=0; vig != vars_in_group; ++vig)
2200  {
2201  std::vector<dof_id_type> di_new;
2202  this->SCALAR_dof_indices(di_new,var.number(vig));
2203  di.insert( di.end(), di_new.begin(), di_new.end());
2204  }
2205  }
2206  else
2207  {
2208  const int n_comp = node->n_comp_group(sys_num,vg);
2209  for (unsigned int vig=0; vig != vars_in_group; ++vig)
2210  {
2211  for (int i=0; i != n_comp; ++i)
2212  {
2213  const dof_id_type d =
2214  node->dof_number(sys_num, vg, vig, i, n_comp);
2215  libmesh_assert_not_equal_to
2216  (d, DofObject::invalid_id);
2217  di.push_back(d);
2218  }
2219  }
2220  }
2221  }
2222 }
2223 
2224 
2225 void DofMap::dof_indices (const Node * const node,
2226  std::vector<dof_id_type> & di,
2227  const unsigned int vn) const
2228 {
2229  if (vn == libMesh::invalid_uint)
2230  {
2231  this->dof_indices(node, di);
2232  return;
2233  }
2234 
2235  // We allow node==nullptr to request just SCALAR dofs
2236  // libmesh_assert(elem);
2237 
2238  LOG_SCOPE("dof_indices(Node)", "DofMap");
2239 
2240  // Clear the DOF indices vector
2241  di.clear();
2242 
2243  const unsigned int sys_num = this->sys_number();
2244 
2245  // Get the dof numbers
2246  const unsigned int vg = this->_variable_group_numbers[vn];
2247  const VariableGroup & var = this->variable_group(vg);
2248 
2249  if (var.type().family == SCALAR)
2250  {
2251  std::vector<dof_id_type> di_new;
2252  this->SCALAR_dof_indices(di_new,vn);
2253  di.insert( di.end(), di_new.begin(), di_new.end());
2254  }
2255  else
2256  {
2257  const unsigned int vig = vn - var.number();
2258  const int n_comp = node->n_comp_group(sys_num,vg);
2259  for (int i=0; i != n_comp; ++i)
2260  {
2261  const dof_id_type d =
2262  node->dof_number(sys_num, vg, vig, i, n_comp);
2263  libmesh_assert_not_equal_to
2264  (d, DofObject::invalid_id);
2265  di.push_back(d);
2266  }
2267  }
2268 }
2269 
2270 
2271 void DofMap::dof_indices (const Elem & elem,
2272  unsigned int n,
2273  std::vector<dof_id_type> & di,
2274  const unsigned int vn) const
2275 {
2276  this->_node_dof_indices(elem, n, elem.node_ref(n), di, vn);
2277 }
2278 
2279 
2280 
2281 #ifdef LIBMESH_ENABLE_AMR
2282 
2283 void DofMap::old_dof_indices (const Elem & elem,
2284  unsigned int n,
2285  std::vector<dof_id_type> & di,
2286  const unsigned int vn) const
2287 {
2288  const DofObject & old_obj = elem.node_ref(n).get_old_dof_object_ref();
2289  this->_node_dof_indices(elem, n, old_obj, di, vn);
2290 }
2291 
2292 #endif // LIBMESH_ENABLE_AMR
2293 
2294 
2295 
2296 void DofMap::_node_dof_indices (const Elem & elem,
2297  unsigned int n,
2298  const DofObject & obj,
2299  std::vector<dof_id_type> & di,
2300  const unsigned int vn) const
2301 {
2302  // Half of this is a cut and paste of _dof_indices code below, but
2303  // duplication actually seems cleaner than creating a helper
2304  // function with a million arguments and hoping the compiler inlines
2305  // it properly into one of our most highly trafficked functions.
2306 
2307  LOG_SCOPE("_node_dof_indices()", "DofMap");
2308 
2309  const unsigned int sys_num = this->sys_number();
2310  const auto [vg, vig] =
2311  obj.var_to_vg_and_offset(sys_num,vn);
2312  const unsigned int n_comp = obj.n_comp_group(sys_num,vg);
2313 
2314  const VariableGroup & var = this->variable_group(vg);
2315  FEType fe_type = var.type();
2316  const bool extra_hanging_dofs =
2317  FEInterface::extra_hanging_dofs(fe_type);
2318 
2319  const bool add_p_level =
2320 #ifdef LIBMESH_ENABLE_AMR
2321  !_dont_p_refine.count(vg);
2322 #else
2323  false;
2324 #endif
2325 
2326  // There is a potential problem with h refinement. Imagine a
2327  // quad9 that has a linear FE on it. Then, on the hanging side,
2328  // it can falsely identify a DOF at the mid-edge node. This is why
2329  // we go through FEInterface instead of obj->n_comp() directly.
2330  const unsigned int nc =
2331  FEInterface::n_dofs_at_node(fe_type, &elem, n, add_p_level);
2332 
2333  // If this is a non-vertex on a hanging node with extra
2334  // degrees of freedom, we use the non-vertex dofs (which
2335  // come in reverse order starting from the end, to
2336  // simplify p refinement)
2337  if (extra_hanging_dofs && nc && !elem.is_vertex(n))
2338  {
2339  const int dof_offset = n_comp - nc;
2340 
2341  // We should never have fewer dofs than necessary on a
2342  // node unless we're getting indices on a parent element,
2343  // and we should never need the indices on such a node
2344  if (dof_offset < 0)
2345  {
2346  libmesh_assert(!elem.active());
2347  di.resize(di.size() + nc, DofObject::invalid_id);
2348  }
2349  else
2350  for (unsigned int i = dof_offset; i != n_comp; ++i)
2351  {
2352  const dof_id_type d =
2353  obj.dof_number(sys_num, vg, vig, i, n_comp);
2354  libmesh_assert_not_equal_to (d, DofObject::invalid_id);
2355  di.push_back(d);
2356  }
2357  }
2358  // If this is a vertex or an element without extra hanging
2359  // dofs, our dofs come in forward order coming from the
2360  // beginning. But we still might not have all those dofs, in cases
2361  // where a subdomain-restricted variable just had its subdomain
2362  // expanded.
2363  else
2364  {
2365  const unsigned int good_nc =
2366  std::min(static_cast<unsigned int>(n_comp), nc);
2367  for (unsigned int i=0; i != good_nc; ++i)
2368  {
2369  const dof_id_type d =
2370  obj.dof_number(sys_num, vg, vig, i, n_comp);
2371  libmesh_assert_not_equal_to (d, DofObject::invalid_id);
2372  di.push_back(d);
2373  }
2374  for (unsigned int i=good_nc; i != nc; ++i)
2375  di.push_back(DofObject::invalid_id);
2376  }
2377 }
2378 
2379 
2380 
2381 void DofMap::_dof_indices (const Elem & elem,
2382  int p_level,
2383  std::vector<dof_id_type> & di,
2384  const unsigned int vg,
2385  const unsigned int vig,
2386  const Node * const * nodes,
2387  unsigned int n_nodes
2388 #ifdef DEBUG
2389  ,
2390  const unsigned int v,
2391  std::size_t & tot_size
2392 #endif
2393  ) const
2394 {
2395  const VariableGroup & var = this->variable_group(vg);
2396 
2397  if (var.active_on_subdomain(elem.subdomain_id()))
2398  {
2399  const ElemType type = elem.type();
2400  const unsigned int sys_num = this->sys_number();
2401 #ifdef LIBMESH_ENABLE_INFINITE_ELEMENTS
2402  const bool is_inf = elem.infinite();
2403 #endif
2404 
2405  const bool extra_hanging_dofs =
2406  FEInterface::extra_hanging_dofs(var.type());
2407 
2408  FEType fe_type = var.type();
2409 
2410  const bool add_p_level =
2411 #ifdef LIBMESH_ENABLE_AMR
2412  !_dont_p_refine.count(vg);
2413 #else
2414  false;
2415 #endif
2416 
2417 #ifdef DEBUG
2418  // The number of dofs per element is non-static for subdivision FE
2419  if (var.type().family == SUBDIVISION)
2420  tot_size += n_nodes;
2421  else
2422  // FIXME: Is the passed-in p_level just elem.p_level()? If so,
2423  // this seems redundant.
2424  tot_size += FEInterface::n_dofs(fe_type, add_p_level*p_level, &elem);
2425 #endif
2426 
2427  // The total Order is not required when getting the function
2428  // pointer, it is only needed when the function is called (see
2429  // below).
2430  const FEInterface::n_dofs_at_node_ptr ndan =
2431  FEInterface::n_dofs_at_node_function(fe_type, &elem);
2432 
2433  // Get the node-based DOF numbers
2434  for (unsigned int n=0; n != n_nodes; n++)
2435  {
2436  const Node & node = *nodes[n];
2437 
2438  // Cache the intermediate lookups that are common to every
2439  // component
2440 #ifdef DEBUG
2441  const std::pair<unsigned int, unsigned int>
2442  vg_and_offset = node.var_to_vg_and_offset(sys_num,v);
2443  libmesh_assert_equal_to (vg, vg_and_offset.first);
2444  libmesh_assert_equal_to (vig, vg_and_offset.second);
2445 #endif
2446  const unsigned int n_comp = node.n_comp_group(sys_num,vg);
2447 
2448  // There is a potential problem with h refinement. Imagine a
2449  // quad9 that has a linear FE on it. Then, on the hanging side,
2450  // it can falsely identify a DOF at the mid-edge node. This is why
2451  // we go through FEInterface instead of node.n_comp() directly.
2452  const unsigned int nc =
2453 #ifdef LIBMESH_ENABLE_INFINITE_ELEMENTS
2454  is_inf ?
2455  FEInterface::n_dofs_at_node(fe_type, add_p_level*p_level, &elem, n) :
2456 #endif
2457  ndan (type, static_cast<Order>(fe_type.order + add_p_level*p_level), n);
2458 
2459  // If this is a non-vertex on a hanging node with extra
2460  // degrees of freedom, we use the non-vertex dofs (which
2461  // come in reverse order starting from the end, to
2462  // simplify p refinement)
2463  if (extra_hanging_dofs && !elem.is_vertex(n))
2464  {
2465  const int dof_offset = n_comp - nc;
2466 
2467  // We should never have fewer dofs than necessary on a
2468  // node unless we're getting indices on a parent element,
2469  // and we should never need the indices on such a node
2470  if (dof_offset < 0)
2471  {
2472  libmesh_assert(!elem.active());
2473  di.resize(di.size() + nc, DofObject::invalid_id);
2474  }
2475  else
2476  for (int i=int(n_comp)-1; i>=dof_offset; i--)
2477  {
2478  const dof_id_type d =
2479  node.dof_number(sys_num, vg, vig, i, n_comp);
2480  libmesh_assert_not_equal_to (d, DofObject::invalid_id);
2481  di.push_back(d);
2482  }
2483  }
2484  // If this is a vertex or an element without extra hanging
2485  // dofs, our dofs come in forward order coming from the
2486  // beginning
2487  else
2488  {
2489  // We have a good component index only if it's being
2490  // used on this FE type (nc) *and* it's available on
2491  // this DofObject (n_comp).
2492  const unsigned int good_nc = std::min(n_comp, nc);
2493  for (unsigned int i=0; i!=good_nc; ++i)
2494  {
2495  const dof_id_type d =
2496  node.dof_number(sys_num, vg, vig, i, n_comp);
2497  libmesh_assert_not_equal_to (d, DofObject::invalid_id);
2498  libmesh_assert_less (d, this->n_dofs());
2499  di.push_back(d);
2500  }
2501 
2502  // With fewer good component indices than we need, e.g.
2503  // due to subdomain expansion, the remaining expected
2504  // indices are marked invalid.
2505  if (n_comp < nc)
2506  for (unsigned int i=n_comp; i!=nc; ++i)
2507  di.push_back(DofObject::invalid_id);
2508  }
2509  }
2510 
2511  // If there are any element-based DOF numbers, get them
2512  const unsigned int nc = FEInterface::n_dofs_per_elem(fe_type, add_p_level*p_level, &elem);
2513 
2514  // We should never have fewer dofs than necessary on an
2515  // element unless we're getting indices on a parent element
2516  // (and we should never need those indices) or off-domain for a
2517  // subdomain-restricted variable (where invalid_id is the
2518  // correct thing to return)
2519  if (nc != 0)
2520  {
2521  const unsigned int n_comp = elem.n_comp_group(sys_num,vg);
2522  if (elem.n_systems() > sys_num && nc <= n_comp)
2523  {
2524  for (unsigned int i=0; i<nc; i++)
2525  {
2526  const dof_id_type d =
2527  elem.dof_number(sys_num, vg, vig, i, n_comp);
2528  libmesh_assert_not_equal_to (d, DofObject::invalid_id);
2529 
2530  di.push_back(d);
2531  }
2532  }
2533  else
2534  {
2535  libmesh_assert(!elem.active() || fe_type.family == LAGRANGE || fe_type.family == SUBDIVISION);
2536  di.resize(di.size() + nc, DofObject::invalid_id);
2537  }
2538  }
2539  }
2540 }
2541 
2542 
2543 
2544 void DofMap::SCALAR_dof_indices (std::vector<dof_id_type> & di,
2545  const unsigned int vn,
2546 #ifdef LIBMESH_ENABLE_AMR
2547  const bool old_dofs
2548 #else
2549  const bool
2550 #endif
2551  ) const
2552 {
2553  LOG_SCOPE("SCALAR_dof_indices()", "DofMap");
2554 
2555  libmesh_assert(this->variable(vn).type().family == SCALAR);
2556 
2557 #ifdef LIBMESH_ENABLE_AMR
2558  // If we're asking for old dofs then we'd better have some
2559  if (old_dofs)
2560  libmesh_assert_greater_equal(n_old_dofs(), n_SCALAR_dofs());
2561 
2562  dof_id_type my_idx = old_dofs ?
2563  this->_first_old_scalar_df[vn] : this->_first_scalar_df[vn];
2564 #else
2565  dof_id_type my_idx = this->_first_scalar_df[vn];
2566 #endif
2567 
2568  libmesh_assert_not_equal_to(my_idx, DofObject::invalid_id);
2569 
2570  // The number of SCALAR dofs comes from the variable order
2571  const int n_dofs_vn = this->variable(vn).type().order.get_order();
2572 
2573  di.resize(n_dofs_vn);
2574  for (int i = 0; i != n_dofs_vn; ++i)
2575  di[i] = my_idx++;
2576 }
2577 
2578 
2579 
2580 bool DofMap::semilocal_index (dof_id_type dof_index) const
2581 {
2582  // If it's not in the local indices
2583  if (!this->local_index(dof_index))
2584  {
2585  // and if it's not in the ghost indices, then we're not
2586  // semilocal
2587  if (!std::binary_search(_send_list.begin(), _send_list.end(), dof_index))
2588  return false;
2589  }
2590 
2591  return true;
2592 }
2593 
2594 
2595 
2596 bool DofMap::all_semilocal_indices (const std::vector<dof_id_type> & dof_indices_in) const
2597 {
2598  // We're all semilocal unless we find a counterexample
2599  for (const auto & di : dof_indices_in)
2600  if (!this->semilocal_index(di))
2601  return false;
2602 
2603  return true;
2604 }
2605 
2606 
2607 
2608 template <typename DofObjectSubclass>
2609 bool DofMap::is_evaluable(const DofObjectSubclass & obj,
2610  unsigned int var_num) const
2611 {
2612  // Everything is evaluable on a local object
2613  if (obj.processor_id() == this->processor_id())
2614  return true;
2615 
2616  std::vector<dof_id_type> di;
2617 
2618  if (var_num == libMesh::invalid_uint)
2619  this->dof_indices(&obj, di);
2620  else
2621  this->dof_indices(&obj, di, var_num);
2622 
2623  return this->all_semilocal_indices(di);
2624 }
2625 
2626 
2627 
2628 #ifdef LIBMESH_ENABLE_AMR
2629 
2630 void DofMap::old_dof_indices (const Elem * const elem,
2631  std::vector<dof_id_type> & di,
2632  const unsigned int vn) const
2633 {
2634  LOG_SCOPE("old_dof_indices()", "DofMap");
2635 
2636  libmesh_assert(elem);
2637 
2638  const ElemType type = elem->type();
2639  const unsigned int sys_num = this->sys_number();
2640  const unsigned int n_var_groups = this->n_variable_groups();
2641 #ifdef LIBMESH_ENABLE_INFINITE_ELEMENTS
2642  const bool is_inf = elem->infinite();
2643 #endif
2644 
2645  // If we have dof indices stored on the elem, and there's no chance
2646  // that we only have those indices because we were just p refined,
2647  // then we should have old dof indices too.
2648  libmesh_assert(!elem->has_dofs(sys_num) ||
2649  elem->p_refinement_flag() == Elem::JUST_REFINED ||
2650  elem->get_old_dof_object());
2651 
2652  // Clear the DOF indices vector.
2653  di.clear();
2654 
2655  // Determine the nodes contributing to element elem
2656  std::vector<const Node *> elem_nodes;
2657  const Node * const * nodes_ptr;
2658  unsigned int n_nodes;
2659  if (elem->type() == TRI3SUBDIVISION)
2660  {
2661  // Subdivision surface FE require the 1-ring around elem
2662  const Tri3Subdivision * sd_elem = static_cast<const Tri3Subdivision *>(elem);
2663  MeshTools::Subdivision::find_one_ring(sd_elem, elem_nodes);
2664  nodes_ptr = elem_nodes.data();
2665  n_nodes = cast_int<unsigned int>(elem_nodes.size());
2666  }
2667  else
2668  {
2669  // All other FE use only the nodes of elem itself
2670  nodes_ptr = elem->get_nodes();
2671  n_nodes = elem->n_nodes();
2672  }
2673 
2674  // Get the dof numbers
2675  for (unsigned int vg=0; vg<n_var_groups; vg++)
2676  {
2677  const VariableGroup & var = this->variable_group(vg);
2678  const unsigned int vars_in_group = var.n_variables();
2679 
2680  for (unsigned int vig=0; vig<vars_in_group; vig++)
2681  {
2682  const unsigned int v = var.number(vig);
2683  if ((vn == v) || (vn == libMesh::invalid_uint))
2684  {
2685  if (var.type().family == SCALAR &&
2686  (!elem ||
2687  var.active_on_subdomain(elem->subdomain_id())))
2688  {
2689  // We asked for this variable, so add it to the vector.
2690  std::vector<dof_id_type> di_new;
2691  this->SCALAR_dof_indices(di_new,v,true);
2692  di.insert( di.end(), di_new.begin(), di_new.end());
2693  }
2694  else
2695  if (var.active_on_subdomain(elem->subdomain_id()))
2696  { // Do this for all the variables if one was not specified
2697  // or just for the specified variable
2698 
2699  FEType fe_type = var.type();
2700  const bool add_p_level =
2701 #ifdef LIBMESH_ENABLE_AMR
2702  !_dont_p_refine.count(vg);
2703 #else
2704  false;
2705 #endif
2706  // Increase the polynomial order on p refined elements,
2707  // but make sure you get the right polynomial order for
2708  // the OLD degrees of freedom
2709  int p_adjustment = 0;
2710  if (elem->p_refinement_flag() == Elem::JUST_REFINED)
2711  {
2712  libmesh_assert_greater (elem->p_level(), 0);
2713  p_adjustment = -1;
2714  }
2715  else if (elem->p_refinement_flag() == Elem::JUST_COARSENED)
2716  {
2717  p_adjustment = 1;
2718  }
2719  p_adjustment *= add_p_level;
2720 
2721  // Compute the net amount of "extra" order, including Elem::p_level()
2722  int extra_order = int(add_p_level*elem->p_level()) + p_adjustment;
2723 
2724  const bool extra_hanging_dofs =
2725  FEInterface::extra_hanging_dofs(fe_type);
2726 
2727  const FEInterface::n_dofs_at_node_ptr ndan =
2728  FEInterface::n_dofs_at_node_function(fe_type, elem);
2729 
2730  // Get the node-based DOF numbers
2731  for (unsigned int n=0; n<n_nodes; n++)
2732  {
2733  const Node * node = nodes_ptr[n];
2734  const DofObject & old_dof_obj = node->get_old_dof_object_ref();
2735 
2736  // There is a potential problem with h refinement. Imagine a
2737  // quad9 that has a linear FE on it. Then, on the hanging side,
2738  // it can falsely identify a DOF at the mid-edge node. This is why
2739  // we call FEInterface instead of node->n_comp() directly.
2740  const unsigned int nc =
2741 #ifdef LIBMESH_ENABLE_INFINITE_ELEMENTS
2742  is_inf ?
2743  FEInterface::n_dofs_at_node(var.type(), extra_order, elem, n) :
2744 #endif
2745  ndan (type, static_cast<Order>(var.type().order + extra_order), n);
2746 
2747  const int n_comp = old_dof_obj.n_comp_group(sys_num,vg);
2748 
2749  // If this is a non-vertex on a hanging node with extra
2750  // degrees of freedom, we use the non-vertex dofs (which
2751  // come in reverse order starting from the end, to
2752  // simplify p refinement)
2753  if (extra_hanging_dofs && !elem->is_vertex(n))
2754  {
2755  const int dof_offset = n_comp - nc;
2756 
2757  // We should never have fewer dofs than necessary on a
2758  // node unless we're getting indices on a parent element
2759  // or a just-coarsened element
2760  if (dof_offset < 0)
2761  {
2762  libmesh_assert(!elem->active() || elem->refinement_flag() ==
2763  Elem::JUST_COARSENED);
2764  di.resize(di.size() + nc, DofObject::invalid_id);
2765  }
2766  else
2767  for (int i=n_comp-1; i>=dof_offset; i--)
2768  {
2769  const dof_id_type d =
2770  old_dof_obj.dof_number(sys_num, vg, vig, i, n_comp);
2771 
2772  // On a newly-expanded subdomain, we
2773  // may have some DoFs that didn't
2774  // exist in the old system, in which
2775  // case we can't assert this:
2776  // libmesh_assert_not_equal_to (d, DofObject::invalid_id);
2777 
2778  di.push_back(d);
2779  }
2780  }
2781  // If this is a vertex or an element without extra hanging
2782  // dofs, our dofs come in forward order coming from the
2783  // beginning. But we still might not have all
2784  // those dofs on the old_dof_obj, in cases
2785  // where a subdomain-restricted variable just
2786  // had its subdomain expanded.
2787  else
2788  {
2789  const unsigned int old_nc =
2790  std::min(static_cast<unsigned int>(n_comp), nc);
2791  for (unsigned int i=0; i != old_nc; ++i)
2792  {
2793  const dof_id_type d =
2794  old_dof_obj.dof_number(sys_num, vg, vig, i, n_comp);
2795 
2796  libmesh_assert_not_equal_to (d, DofObject::invalid_id);
2797 
2798  di.push_back(d);
2799  }
2800  for (unsigned int i=old_nc; i != nc; ++i)
2801  di.push_back(DofObject::invalid_id);
2802  }
2803  }
2804 
2805  // If there are any element-based DOF numbers, get them
2806  const unsigned int nc =
2807  FEInterface::n_dofs_per_elem(fe_type, extra_order, elem);
2808 
2809  if (nc != 0)
2810  {
2811  const DofObject & old_dof_obj = elem->get_old_dof_object_ref();
2812 
2813  const unsigned int n_comp =
2814  old_dof_obj.n_comp_group(sys_num,vg);
2815 
2816  if (old_dof_obj.n_systems() > sys_num &&
2817  nc <= n_comp)
2818  {
2819 
2820  for (unsigned int i=0; i<nc; i++)
2821  {
2822  const dof_id_type d =
2823  old_dof_obj.dof_number(sys_num, vg, vig, i, n_comp);
2824 
2825  di.push_back(d);
2826  }
2827  }
2828  else
2829  {
2830  // We should never have fewer dofs than
2831  // necessary on an element unless we're
2832  // getting indices on a parent element, a
2833  // just-coarsened element ... or a
2834  // subdomain-restricted variable with a
2835  // just-expanded subdomain
2836  // libmesh_assert(!elem->active() || fe_type.family == LAGRANGE ||
2837  // elem->refinement_flag() == Elem::JUST_COARSENED);
2838  di.resize(di.size() + nc, DofObject::invalid_id);
2839  }
2840  }
2841  }
2842  }
2843  } // end loop over variables within group
2844  } // end loop over variable groups
2845 }
2846 
2847 #endif // LIBMESH_ENABLE_AMR
2848 
2849 
2850 #ifdef LIBMESH_ENABLE_CONSTRAINTS
2851 
2852 void DofMap::find_connected_dofs (std::vector<dof_id_type> & elem_dofs) const
2853 {
2854  typedef std::set<dof_id_type> RCSet;
2855 
2856  // First insert the DOFS we already depend on into the set.
2857  RCSet dof_set (elem_dofs.begin(), elem_dofs.end());
2858 
2859  bool done = true;
2860 
2861  // Next insert any dofs those might be constrained in terms
2862  // of. Note that in this case we may not be done: Those may
2863  // in turn depend on others. So, we need to repeat this process
2864  // in that case until the system depends only on unconstrained
2865  // degrees of freedom.
2866  for (const auto & dof : elem_dofs)
2867  if (this->is_constrained_dof(dof))
2868  {
2869  // If the DOF is constrained
2870  DofConstraints::const_iterator
2871  pos = _dof_constraints.find(dof);
2872 
2873  libmesh_assert (pos != _dof_constraints.end());
2874 
2875  const DofConstraintRow & constraint_row = pos->second;
2876 
2877  // adaptive p refinement currently gives us lots of empty constraint
2878  // rows - we should optimize those DoFs away in the future. [RHS]
2879  //libmesh_assert (!constraint_row.empty());
2880 
2881  // Add the DOFs this dof is constrained in terms of.
2882  // note that these dofs might also be constrained, so
2883  // we will need to call this function recursively.
2884  for (const auto & pr : constraint_row)
2885  if (!dof_set.count (pr.first))
2886  {
2887  dof_set.insert (pr.first);
2888  done = false;
2889  }
2890  }
2891 
2892 
2893  // If not done then we need to do more work
2894  // (obviously :-) )!
2895  if (!done)
2896  {
2897  // Fill the vector with the contents of the set
2898  elem_dofs.clear();
2899  elem_dofs.insert (elem_dofs.end(),
2900  dof_set.begin(), dof_set.end());
2901 
2902 
2903  // May need to do this recursively. It is possible
2904  // that we just replaced a constrained DOF with another
2905  // constrained DOF.
2906  this->find_connected_dofs (elem_dofs);
2907 
2908  } // end if (!done)
2909 }
2910 
2911 #endif // LIBMESH_ENABLE_CONSTRAINTS
2912 
2913 
2914 
2915 void DofMap::print_info(std::ostream & os) const
2916 {
2917  os << this->get_info();
2918 }
2919 
2920 
2921 
2922 std::string DofMap::get_info() const
2923 {
2924  std::ostringstream os;
2925 
2926  // If we didn't calculate the exact sparsity pattern, the threaded
2927  // sparsity pattern assembly may have just given us an upper bound
2928  // on sparsity.
2929  const char * may_equal = " <= ";
2930 
2931  // If we calculated the exact sparsity pattern, then we can report
2932  // exact bandwidth figures:
2933  for (const auto & mat : _matrices)
2934  if (mat->need_full_sparsity_pattern())
2935  may_equal = " = ";
2936 
2937  dof_id_type max_n_nz = 0, max_n_oz = 0;
2938  long double avg_n_nz = 0, avg_n_oz = 0;
2939 
2940  if (_sp)
2941  {
2942  for (const auto & val : _sp->get_n_nz())
2943  {
2944  max_n_nz = std::max(max_n_nz, val);
2945  avg_n_nz += val;
2946  }
2947 
2948  std::size_t n_nz_size = _sp->get_n_nz().size();
2949 
2950  this->comm().max(max_n_nz);
2951  this->comm().sum(avg_n_nz);
2952  this->comm().sum(n_nz_size);
2953 
2954  avg_n_nz /= std::max(n_nz_size,std::size_t(1));
2955 
2956  for (const auto & val : _sp->get_n_oz())
2957  {
2958  max_n_oz = std::max(max_n_oz, val);
2959  avg_n_oz += val;
2960  }
2961 
2962  std::size_t n_oz_size = _sp->get_n_oz().size();
2963 
2964  this->comm().max(max_n_oz);
2965  this->comm().sum(avg_n_oz);
2966  this->comm().sum(n_oz_size);
2967 
2968  avg_n_oz /= std::max(n_oz_size,std::size_t(1));
2969  }
2970 
2971  os << " DofMap Sparsity\n Average On-Processor Bandwidth"
2972  << may_equal << avg_n_nz << '\n';
2973 
2974  os << " Average Off-Processor Bandwidth"
2975  << may_equal << avg_n_oz << '\n';
2976 
2977  os << " Maximum On-Processor Bandwidth"
2978  << may_equal << max_n_nz << '\n';
2979 
2980  os << " Maximum Off-Processor Bandwidth"
2981  << may_equal << max_n_oz << std::endl;
2982 
2983 #ifdef LIBMESH_ENABLE_CONSTRAINTS
2984 
2985  std::size_t n_constraints = 0, max_constraint_length = 0,
2986  n_rhss = 0;
2987  long double avg_constraint_length = 0.;
2988 
2989  for (const auto & [constrained_dof, row] : _dof_constraints)
2990  {
2991  // Only count local constraints, then sum later
2992  if (!this->local_index(constrained_dof))
2993  continue;
2994 
2995  std::size_t rowsize = row.size();
2996 
2997  max_constraint_length = std::max(max_constraint_length,
2998  rowsize);
2999  avg_constraint_length += rowsize;
3000  n_constraints++;
3001 
3002  if (_primal_constraint_values.count(constrained_dof))
3003  n_rhss++;
3004  }
3005 
3006  this->comm().sum(n_constraints);
3007  this->comm().sum(n_rhss);
3008  this->comm().sum(avg_constraint_length);
3009  this->comm().max(max_constraint_length);
3010 
3011  os << " DofMap Constraints\n Number of DoF Constraints = "
3012  << n_constraints;
3013  if (n_rhss)
3014  os << '\n'
3015  << " Number of Heterogenous Constraints= " << n_rhss;
3016  if (n_constraints)
3017  {
3018  avg_constraint_length /= n_constraints;
3019 
3020  os << '\n'
3021  << " Average DoF Constraint Length= " << avg_constraint_length;
3022  }
3023 
3024 #ifdef LIBMESH_ENABLE_NODE_CONSTRAINTS
3025  std::size_t n_node_constraints = 0, max_node_constraint_length = 0,
3026  n_node_rhss = 0;
3027  long double avg_node_constraint_length = 0.;
3028 
3029  for (const auto & [node, pr] : _node_constraints)
3030  {
3031  // Only count local constraints, then sum later
3032  if (node->processor_id() != this->processor_id())
3033  continue;
3034 
3035  const NodeConstraintRow & row = pr.first;
3036  std::size_t rowsize = row.size();
3037 
3038  max_node_constraint_length = std::max(max_node_constraint_length,
3039  rowsize);
3040  avg_node_constraint_length += rowsize;
3041  n_node_constraints++;
3042 
3043  if (pr.second != Point(0))
3044  n_node_rhss++;
3045  }
3046 
3047  this->comm().sum(n_node_constraints);
3048  this->comm().sum(n_node_rhss);
3049  this->comm().sum(avg_node_constraint_length);
3050  this->comm().max(max_node_constraint_length);
3051 
3052  os << "\n Number of Node Constraints = " << n_node_constraints;
3053  if (n_node_rhss)
3054  os << '\n'
3055  << " Number of Heterogenous Node Constraints= " << n_node_rhss;
3056  if (n_node_constraints)
3057  {
3058  avg_node_constraint_length /= n_node_constraints;
3059  os << "\n Maximum Node Constraint Length= " << max_node_constraint_length
3060  << '\n'
3061  << " Average Node Constraint Length= " << avg_node_constraint_length;
3062  }
3063 #endif // LIBMESH_ENABLE_NODE_CONSTRAINTS
3064 
3065  os << std::endl;
3066 
3067 #endif // LIBMESH_ENABLE_CONSTRAINTS
3068 
3069  return os.str();
3070 }
3071 
3072 
3073 template LIBMESH_EXPORT bool DofMap::is_evaluable<Elem>(const Elem &, unsigned int) const;
3074 template LIBMESH_EXPORT bool DofMap::is_evaluable<Node>(const Node &, unsigned int) const;
3075 
3076 } // namespace libMesh
std::vector< VariableGroup > _variable_groups
The finite element type for each variable group.
Definition: dof_map.h:1844
unsigned int n_comp_group(const unsigned int s, const unsigned int vg) const
Definition: dof_object.h:1008
std::unique_ptr< SparsityPattern::Build > _sp
The sparsity pattern of the global matrix.
Definition: dof_map.h:1983
DofObject * elem_ptr(MeshBase &mesh, dof_id_type i) const
Definition: dof_map.C:348
T command_line_next(std::string name, T value)
Use GetPot&#39;s search()/next() functions to get following arguments from the command line...
Definition: libmesh.C:937
bool _implicit_neighbor_dofs_initialized
Bools to indicate if we override the –implicit_neighbor_dofs commandline options. ...
Definition: dof_map.h:2073
void distribute_local_dofs_node_major(dof_id_type &next_free_dof, MeshBase &mesh)
Distributes the global degrees of freedom for dofs on this processor.
Definition: dof_map.C:1196
const FEType & type() const
Definition: variable.h:140
bool _implicit_neighbor_dofs
Definition: dof_map.h:2074
std::string get_info() const
Gets summary info about the sparsity bandwidth and constraints.
Definition: dof_map.C:2922
void _node_dof_indices(const Elem &elem, unsigned int n, const DofObject &obj, std::vector< dof_id_type > &di, const unsigned int vn) const
Helper function that implements the element-nodal versions of dof_indices and old_dof_indices.
Definition: dof_map.C:2296
void print_info(std::ostream &os=libMesh::out) const
Prints summary info about the sparsity bandwidth and constraints.
Definition: dof_map.C:2915
DefaultCoupling & default_coupling()
Default coupling functor.
Definition: dof_map.h:356
void old_dof_indices(const Elem &elem, unsigned int n, std::vector< dof_id_type > &di, const unsigned int vn) const
Appends to the vector di the old global degree of freedom indices for elem.node_ref(n), for one variable vn.
Definition: dof_map.C:2283
std::set< GhostingFunctor * >::const_iterator algebraic_ghosting_functors_begin() const
Beginning of range of algebraic ghosting functors.
Definition: dof_map.h:406
~DofMap()
Destructor.
Definition: dof_map.C:206
unsigned int n() const
返回矩阵的列维度。
const unsigned int invalid_uint
A number which is used quite often to represent an invalid or uninitialized value for an unsigned int...
Definition: libmesh.h:254
bool _error_on_constraint_loop
This flag indicates whether or not we do an opt-mode check for the presence of constraint loops...
Definition: dof_map.h:1828
unsigned int n_vars(const unsigned int s, const unsigned int vg) const
Definition: dof_object.h:960
void * _extra_sparsity_context
A pointer associated with the extra sparsity that can optionally be passed in.
Definition: dof_map.h:1910
const FEType & variable_type(const unsigned int c) const
Definition: dof_map.h:2141
std::size_t distribute_dofs(MeshBase &)
Distribute dofs on the current mesh.
Definition: dof_map.C:927
void set_implicit_neighbor_dofs(bool implicit_neighbor_dofs)
Allow the implicit_neighbor_dofs flag to be set programmatically.
Definition: dof_map.C:1748
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 ...
void add_default_ghosting()
Add the default functor(s) for coupling and algebraic ghosting.
Definition: dof_map.C:1852
We&#39;re using a class instead of a typedef to allow forward declarations and future flexibility...
virtual numeric_index_type size() const =0
获取向量的大小。
std::set< GhostingFunctor * >::const_iterator coupling_functors_begin() const
Beginning of range of coupling functors.
Definition: dof_map.h:344
void _dof_indices(const Elem &elem, int p_level, std::vector< dof_id_type > &di, const unsigned int vg, const unsigned int vig, const Node *const *nodes, unsigned int n_nodes#ifdef DEBUG, const unsigned int v, std::size_t &tot_size#endif) const
Helper function that gets the dof indices on the current element for a non-SCALAR type variable...
Definition: dof_map.C:2381
std::vector< dof_id_type > _send_list
A list containing all the global DOF indices that affect the solution on my processor.
Definition: dof_map.h:1893
void set_verify_dirichlet_bc_consistency(bool val)
Set the _verify_dirichlet_bc_consistency flag.
Definition: dof_map.C:1754
bool is_attached(SparseMatrix< Number > &matrix)
Matrices should not be attached more than once.
Definition: dof_map.C:333
void attach_matrix(SparseMatrix< Number > &matrix)
Additional matrices may be attached to this DofMap.
Definition: dof_map.C:278
DofObject * node_ptr(MeshBase &mesh, dof_id_type i) const
Definition: dof_map.C:341
void clear_send_list()
Clears the _send_list vector.
Definition: dof_map.h:485
DefaultCoupling & default_algebraic_ghosting()
Default algebraic ghosting functor.
Definition: dof_map.h:418
dof_id_type dof_number(const unsigned int s, const unsigned int var, const unsigned int comp) const
Definition: dof_object.h:1025
bool computed_sparsity_already() const
Returns true iff a sparsity pattern has already been computed.
Definition: dof_map.C:296
void attach_sparsity_pattern(const SparsityPattern::Build &sp)
设置要使用的稀疏性模式的指针。在矩阵需要比系统中的大(或更小以提高效率)的模式, 或者在 DofMap 未计算系统稀疏性模式的情况下使用。
Definition: sparse_matrix.C:68
提供了不同线性代数库的向量存储方案的统一接口。
Definition: dof_map.h:67
std::set< GhostingFunctor * > _algebraic_ghosting_functors
The list of all GhostingFunctor objects to be used when distributing ghosted vectors.
Definition: dof_map.h:1951
std::vector< dof_id_type > _end_old_df
Last old DOF index (plus 1) on processor p.
Definition: dof_map.h:2011
std::pair< unsigned int, unsigned int > var_to_vg_and_offset(const unsigned int s, const unsigned int var) const
Definition: dof_object.h:1193
void local_variable_indices(std::vector< dof_id_type > &idx, const MeshBase &mesh, unsigned int var_num) const
Fills an array of those dof indices which belong to the given variable number and live on the current...
Definition: dof_map.C:1109
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...
Definition: dof_object.h:1290
void invalidate_dofs(MeshBase &mesh) const
Invalidates all active DofObject dofs for this system.
Definition: dof_map.C:835
virtual void augment_send_list(std::vector< dof_id_type > &send_list)=0
User-defined function to augment the send list.
bool local_index(dof_id_type dof_index) const
Definition: dof_map.h:831
const Variable & variable(const unsigned int c) const
Definition: dof_map.h:2111
dof_id_type n_dofs() const
Definition: dof_map.h:659
virtual void zero()=0
将向量中的每个元素设置为0。由于派生类中的存储方法可能不同,需要将其声明为纯虚函数。
void set_error_on_constraint_loop(bool error_on_constraint_loop)
Definition: dof_map.C:245
const VariableGroup & variable_group(const unsigned int c) const
Definition: dof_map.h:2101
void add_coupling_functor(GhostingFunctor &coupling_functor, bool to_mesh=true)
Adds a functor which can specify coupling requirements for creation of sparse matrices.
Definition: dof_map.C:1861
std::vector< dof_id_type > _first_old_df
First old DOF index on processor p.
Definition: dof_map.h:2006
uint8_t processor_id_type
Definition: id_types.h:104
std::vector< dof_id_type > _first_scalar_df
First DOF index for SCALAR variable v, or garbage for non-SCALAR variable v.
Definition: dof_map.h:1887
dof_id_type n_dofs_on_processor(const processor_id_type proc) const
Definition: dof_map.h:675
AdjointDofConstraintValues _adjoint_constraint_values
Definition: dof_map.h:2034
bool _constrained_sparsity_construction
This flag indicates whether or not we explicitly take constraint equations into account when computin...
Definition: dof_map.h:1834
AugmentSendList * _augment_send_list
Function object to call to add extra entries to the send list.
Definition: dof_map.h:1915
bool need_full_sparsity_pattern
Default false; set to true if any attached matrix requires a full sparsity pattern.
Definition: dof_map.h:1976
这是一个通用的稀疏矩阵类。该类包含了必须在派生类中覆盖的纯虚拟成员。 使用一个公共的基类允许从不同的求解器包中以不同的格式统一访问稀疏矩阵。
Definition: dof_map.h:66
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...
Definition: dof_object.h:1310
void reinit_send_list(MeshBase &mesh)
Clears the _send_list vector and then rebuilds it.
Definition: dof_map.C:1734
bool is_constrained_dof(const dof_id_type dof) const
Definition: dof_map.h:2179
std::unordered_map< unsigned int, unsigned int > _var_to_vg
A map from variable number to variable group number.
Definition: dof_map.h:1854
This class defines the notion of a variable in the system.
Definition: variable.h:49
void add_neighbors_to_send_list(MeshBase &mesh)
Adds entries to the _send_list vector corresponding to DoFs on elements neighboring the current proce...
Definition: dof_map.C:1544
std::vector< dof_id_type > _first_old_scalar_df
First old DOF index for SCALAR variable v, or garbage for non-SCALAR variable v.
Definition: dof_map.h:2017
int8_t boundary_id_type
Definition: id_types.h:51
dof_id_type _n_SCALAR_dofs
The total number of SCALAR dofs associated to all SCALAR variables.
Definition: dof_map.h:1994
void assert_no_nodes_missed(MeshBase &mesh)
Definition: dof_map.C:1418
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.
Definition: dof_map.C:356
unsigned int m() const
返回矩阵的行维度。
std::set< std::unique_ptr< CouplingMatrix >, Utility::CompareUnderlying > CouplingMatricesSet
Definition: dof_map.h:1742
unsigned int number(unsigned int v) const
Definition: variable.h:294
virtual unsigned int size() const =0
static const processor_id_type invalid_processor_id
An invalid processor_id to distinguish DoFs that have not been assigned to a processor.
Definition: dof_object.h:488
bool is_periodic_boundary(const boundary_id_type boundaryid) const
Definition: dof_map.C:219
unsigned int n_var_groups(const unsigned int s) const
Definition: dof_object.h:950
unsigned int n_variables() const
Definition: variable.h:256
void add_variable_group(VariableGroup var_group)
Add an unknown of order order and finite element type type to the system of equations.
Definition: dof_map.C:252
We&#39;re using a class instead of a typedef to allow forward declarations and future flexibility...
bool active_on_subdomain(subdomain_id_type sid) const
Definition: variable.h:157
virtual bool need_full_sparsity_pattern() const
void clear()
Free all new memory associated with the object, but restore its original state, with the mesh pointer...
Definition: dof_map.C:850
static const dof_id_type invalid_id
An invalid id to distinguish an uninitialized DofObject.
Definition: dof_object.h:477
DofConstraints _dof_constraints
Data structure containing DOF constraints.
Definition: dof_map.h:2030
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...
Definition: dof_map.C:64
OStreamProxy out
void reinit(MeshBase &mesh)
Reinitialize the underlying data structures conformal to the current mesh.
Definition: dof_map.C:506
DofMap(const unsigned int sys_number, MeshBase &mesh)
Constructor.
Definition: dof_map.C:135
CouplingMatrix * _dof_coupling
Degree of freedom coupling.
Definition: dof_map.h:1589
unsigned int n_variable_groups() const
Definition: dof_map.h:613
unsigned int sys_number() const
Definition: dof_map.h:2093
void * _extra_send_list_context
A pointer associated with the extra send list that can optionally be passed in.
Definition: dof_map.h:1925
This class defines a logically grouped set of variables in the system.
Definition: variable.h:193
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...
Definition: dof_object.C:397
bool semilocal_index(dof_id_type dof_index) const
Definition: dof_map.C:2580
void update_sparsity_pattern(SparseMatrix< Number > &matrix) const
Additional matrices may be be temporarily initialized by this DofMap.
Definition: dof_map.C:307
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...
Definition: dof_object.h:104
std::set< GhostingFunctor * >::const_iterator algebraic_ghosting_functors_end() const
End of range of algebraic ghosting functors.
Definition: dof_map.h:412
std::vector< SparseMatrix< Number > * > _matrices
Additional matrices handled by this object.
Definition: dof_map.h:1871
dof_id_type end_dof() const
Definition: dof_map.h:711
void attach_dof_map(const DofMap &dof_map)
设置要使用的 DofMap 的指针。如果不使用单独的稀疏性模式, 则使用来自 DofMap 的模式。
Definition: sparse_matrix.C:58
void distribute_scalar_dofs(dof_id_type &next_free_dof)
Definition: dof_map.C:1394
unsigned int n_variables() const
Definition: dof_map.h:621
virtual numeric_index_type first_local_index() const =0
获取实际存储在该处理器上的第一个向量元素的索引。
std::unique_ptr< PeriodicBoundaries > _periodic_boundaries
Data structure containing periodic boundaries.
Definition: dof_map.h:2050
OStreamProxy err
void SCALAR_dof_indices(std::vector< dof_id_type > &di, const unsigned int vn, const bool old_dofs=false) const
Fills the vector di with the global degree of freedom indices corresponding to the SCALAR variable vn...
Definition: dof_map.C:2544
void remove_coupling_functor(GhostingFunctor &coupling_functor)
Removes a functor which was previously added to the set of coupling functors, from both this DofMap a...
Definition: dof_map.C:1873
virtual void update_sparsity_pattern(const SparsityPattern::Graph &)
更新矩阵的稀疏性模式。当您的 SparseMatrix&lt;T&gt; 实现不需要此数据时, 只需不覆盖此方法。
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)
Definition: dof_map.C:1440
dof_id_type n_old_dofs() const
Definition: dof_map.h:1539
bool _verify_dirichlet_bc_consistency
Flag which determines whether we should do some additional checking of the consistency of the Dirichl...
Definition: dof_map.h:2086
std::unique_ptr< DefaultCoupling > _default_coupling
The default coupling GhostingFunctor, used to implement standard libMesh sparsity pattern constructio...
Definition: dof_map.h:1933
DofConstraintValueMap _primal_constraint_values
Definition: dof_map.h:2032
std::vector< Variable > _variables
The finite element type for each variable.
Definition: dof_map.h:1839
DofConstraints _stashed_dof_constraints
Definition: dof_map.h:2030
void remove_default_ghosting()
Remove any default ghosting functor(s).
Definition: dof_map.C:1844
SparsityPattern::AugmentSparsityPattern * _augment_sparsity_pattern
Function object to call to add extra entries to the sparsity pattern.
Definition: dof_map.h:1898
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.
Definition: dof_map.h:90
The DofObject defines an abstract base class for objects that have degrees of freedom associated with...
Definition: dof_object.h:54
dof_id_type _n_old_dfs
Total number of degrees of freedom on old dof objects.
Definition: dof_map.h:2001
void clear_sparsity()
Clears the sparsity pattern.
Definition: dof_map.C:1837
bool all_semilocal_indices(const std::vector< dof_id_type > &dof_indices) const
Definition: dof_map.C:2596
std::set< GhostingFunctor * > _coupling_functors
The list of all GhostingFunctor objects to be used when coupling degrees of freedom in matrix sparsit...
Definition: dof_map.h:1964
std::unordered_set< unsigned int > _dont_p_refine
A container of variable groups that we should not p-refine.
Definition: dof_map.h:2022
std::vector< dof_id_type > _end_df
Last DOF index (plus 1) on processor p.
Definition: dof_map.h:1881
dof_id_type n_SCALAR_dofs() const
Definition: dof_map.h:664
std::vector< dof_id_type > _first_df
First DOF index on processor p.
Definition: dof_map.h:1876
定义用于有限元计算的抽象稠密向量基类。 可以从这个类派生出特定的稠密向量,例如 DenseSubVectors。
Definition: dof_map.h:63
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.
Definition: dof_map.h:138
MeshBase & _mesh
The mesh that system uses.
Definition: dof_map.h:1864
void find_connected_dofs(std::vector< dof_id_type > &elem_dofs) const
Finds all the DOFS associated with the element DOFs elem_dofs.
Definition: dof_map.C:2852
void prepare_send_list()
Takes the _send_list vector (which may have duplicate entries) and sorts it.
Definition: dof_map.C:1692
定义用于有限元计算的稠密向量类。该类基本上是为了补充 DenseMatrix 类而设计的。 它相对于 std::vector 具有额外的功能,使其在有限元中特别有用,特别是对于方程组。 所有重写的虚拟函...
Definition: dof_map.h:64
bool on_command_line(std::string arg)
Definition: libmesh.C:872
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.
Definition: dof_map.h:1903
std::unique_ptr< DefaultCoupling > _default_evaluating
The default algebraic GhostingFunctor, used to implement standard libMesh send_list construction...
Definition: dof_map.h:1941
void(* _extra_send_list_function)(std::vector< dof_id_type > &, void *)
A function pointer to a function to call to add extra entries to the send list.
Definition: dof_map.h:1920
std::vector< unsigned int > _variable_group_numbers
The variable group number for each variable.
Definition: dof_map.h:1849
std::map< GhostingFunctor *, std::shared_ptr< GhostingFunctor > > _shared_functors
Hang on to references to any GhostingFunctor objects we were passed in shared_ptr form...
Definition: dof_map.h:1970
std::set< GhostingFunctor * >::const_iterator coupling_functors_end() const
End of range of coupling functors.
Definition: dof_map.h:350
void remove_algebraic_ghosting_functor(GhostingFunctor &evaluable_functor)
Removes a functor which was previously added to the set of algebraic ghosting functors, from both this DofMap and from the underlying mesh.
Definition: dof_map.C:1898
unsigned int n_comp(const unsigned int s, const unsigned int var) const
Definition: dof_object.h:995
void compute_sparsity(const MeshBase &)
Computes the sparsity pattern for the matrices corresponding to proc_id and sends that data to Linear...
Definition: dof_map.C:1816
dof_id_type id() const
Definition: dof_object.h:823
unsigned int n_systems() const
Definition: dof_object.h:930
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...
Definition: dof_map.C:1886
virtual T el(const unsigned int i) const =0
定义用于有限元类型计算的密集矩阵。 用于在求和成全局矩阵之前存储单元刚度矩阵。所有被覆盖的虚函数都记录在dense_matrix_base.h中。
Definition: dof_map.h:65
bool use_coupled_neighbor_dofs(const MeshBase &mesh) const
Tells other library functions whether or not this problem includes coupling between dofs in neighbori...
Definition: dof_map.C:1760
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...
Definition: dof_map.C:238
void extract_local_vector(const NumericVector< Number > &Ug, const std::vector< dof_id_type > &dof_indices, DenseVectorBase< Number > &Ue) const
Builds the local element vector Ue from the global vector Ug, accounting for any constrained degrees ...
Definition: dof_map.C:1910
bool is_evaluable(const DofObjectSubclass &obj, unsigned int var_num=libMesh::invalid_uint) const
Definition: dof_map.C:2609
virtual numeric_index_type last_local_index() const =0
获取实际存储在该处理器上的最后一个向量元素的索引+1。
void distribute_local_dofs_var_major(dof_id_type &next_free_dof, MeshBase &mesh)
Distributes the global degrees of freedom, for dofs on this processor.
Definition: dof_map.C:1299
dof_id_type first_dof() const
Definition: dof_map.h:687
uint8_t dof_id_type
Definition: id_types.h:67
dof_id_type _n_dfs
Total number of degrees of freedom.
Definition: dof_map.h:1988
processor_id_type processor_id() const
Definition: dof_object.h:898
NodeConstraints _node_constraints
Data structure containing DofObject constraints.
Definition: dof_map.h:2041
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.
Definition: dof_map.C:1992