21 #include "libmesh/sparsity_pattern.h"
24 #include "libmesh/coupling_matrix.h"
25 #include "libmesh/dof_map.h"
26 #include "libmesh/elem.h"
27 #include "libmesh/ghosting_functor.h"
28 #include "libmesh/hashword.h"
29 #include "libmesh/parallel_algebra.h"
30 #include "libmesh/parallel.h"
31 #include "libmesh/parallel_sync.h"
32 #include "libmesh/utility.h"
35 #include "timpi/communicator.h"
40 namespace SparsityPattern
47 const CouplingMatrix * dof_coupling_in,
48 const std::set<GhostingFunctor *> & coupling_functors_in,
49 const bool implicit_neighbor_dofs_in,
50 const bool need_full_sparsity_pattern_in,
51 const bool calculate_constrained_in) :
52 ParallelObject(dof_map_in),
54 dof_coupling(dof_coupling_in),
55 coupling_functors(coupling_functors_in),
56 implicit_neighbor_dofs(implicit_neighbor_dofs_in),
57 need_full_sparsity_pattern(need_full_sparsity_pattern_in),
58 calculate_constrained(calculate_constrained_in),
68 ParallelObject(other),
69 dof_map(other.dof_map),
70 dof_coupling(other.dof_coupling),
71 coupling_functors(other.coupling_functors),
72 implicit_neighbor_dofs(other.implicit_neighbor_dofs),
73 need_full_sparsity_pattern(other.need_full_sparsity_pattern),
74 calculate_constrained(other.calculate_constrained),
75 hashed_dof_sets(other.hashed_dof_sets),
84 #if defined(__GNUC__) && (__GNUC__ < 4) && !defined(__INTEL_COMPILER)
93 std::vector<dof_id_type> & dofs_vi,
97 #ifdef LIBMESH_ENABLE_CONSTRAINTS
102 std::sort(dofs_vi.begin(), dofs_vi.end());
106 dofs_vi.erase(std::unique(dofs_vi.begin(), dofs_vi.end()), dofs_vi.end());
112 const std::vector<dof_id_type> & element_dofs_j)
114 const unsigned int n_dofs_on_element_i =
115 cast_int<unsigned int>(element_dofs_i.size());
121 std::vector<dof_id_type>
124 const unsigned int n_dofs_on_element_j =
125 cast_int<unsigned int>(element_dofs_j.size());
134 bool dofs_seen =
false;
135 if (n_dofs_on_element_j > 0 && n_dofs_on_element_i > 256)
137 auto hash_i = Utility::hashword(element_dofs_i);
138 auto hash_j = Utility::hashword(element_dofs_j);
139 auto final_hash = Utility::hashword2(hash_i, hash_j);
142 dofs_seen = !result.second;
148 if (n_dofs_on_element_j > 0 && !dofs_seen)
150 for (
unsigned int i=0; i<n_dofs_on_element_i; i++)
159 if ((ig >= first_dof_on_proc) &&
160 (ig < end_dof_on_proc))
166 libmesh_assert_greater_equal (ig, first_dof_on_proc);
181 row->insert(row->end(),
182 element_dofs_j.begin(),
183 element_dofs_j.end());
193 SparsityPattern::Row::iterator
194 low = std::lower_bound
195 (row->begin(), row->end(), element_dofs_j.front()),
196 high = std::upper_bound
197 (low, row->end(), element_dofs_j.back());
199 for (
unsigned int j=0; j<n_dofs_on_element_j; j++)
204 std::pair<SparsityPattern::Row::iterator,
205 SparsityPattern::Row::iterator>
206 pos = std::equal_range (low, high, jg);
209 if (pos.first == pos.second)
210 dofs_to_add.push_back(jg);
219 if (!dofs_to_add.empty())
221 const std::size_t old_size = row->size();
223 row->insert (row->end(),
228 (row->begin(), row->begin()+old_size,
255 std::vector<std::vector<dof_id_type> > element_dofs_i(n_var);
257 std::vector<const Elem *> coupled_neighbors;
258 for (
const auto & elem : range)
262 Elem *
const * elempp =
const_cast<Elem *
const *
>(&elem);
263 Elem *
const * elemend = elempp+1;
265 const MeshBase::const_element_iterator fake_elem_it =
266 MeshBase::const_element_iterator(elempp,
270 const MeshBase::const_element_iterator fake_elem_end =
271 MeshBase::const_element_iterator(elemend,
275 GhostingFunctor::map_type elements_to_couple;
279 temporary_coupling_matrices,
285 for (
unsigned int vi=0; vi<n_var; vi++)
288 for (
unsigned int vi=0; vi<n_var; vi++)
289 for (
const auto & [partner, ghost_coupling] : elements_to_couple)
295 libmesh_assert_equal_to (ghost_coupling->size(), n_var);
296 ConstCouplingRow ccr(vi, *ghost_coupling);
298 for (
const auto & idx : ccr)
301 this->
handle_vi_vj(element_dofs_i[vi], element_dofs_i[idx]);
304 std::vector<dof_id_type> partner_dofs;
312 for (
unsigned int vj = 0; vj != n_var; ++vj)
315 this->
handle_vi_vj(element_dofs_i[vi], element_dofs_i[vj]);
318 std::vector<dof_id_type> partner_dofs;
340 n_nz.resize (n_dofs_on_proc, 0);
341 n_oz.resize (n_dofs_on_proc, 0);
348 for (
const auto & df : row)
349 if ((df < first_dof_on_proc) || (df >= end_dof_on_proc))
389 else if (!their_row.empty())
391 my_row.insert (my_row.end(),
398 std::sort (my_row.begin(), my_row.end());
400 my_row.erase(std::unique (my_row.begin(), my_row.end()), my_row.end());
406 for (
const auto & df : my_row)
407 if ((df < first_dof_on_proc) || (df >= end_dof_on_proc))
415 n_nz[r] = std::min(
n_nz[r], n_dofs_on_proc);
417 n_oz[r] =std::min(
n_oz[r], static_cast<dof_id_type>(n_global_dofs-
n_nz[r]));
431 libmesh_assert (dbg_proc_id != this->processor_id());
437 libmesh_assert (!their_row.empty());
449 my_row.insert (my_row.end(),
456 std::sort (my_row.begin(), my_row.end());
458 my_row.erase(std::unique (my_row.begin(), my_row.end()), my_row.end());
471 parallel_object_only();
474 auto & comm = this->comm();
475 auto my_pid = comm.rank();
483 std::map<processor_id_type, std::vector<dof_id_type>> ids_to_send;
484 std::map<processor_id_type, std::vector<Row>> rows_to_send;
490 const auto dof_id = it->first;
491 auto & row = it->second;
497 ids_to_send[proc_id].push_back(dof_id);
500 rows_to_send[proc_id].push_back(std::move(row));
506 std::map<processor_id_type, std::vector<dof_id_type>> received_ids_map;
508 auto ids_action_functor =
511 const std::vector<dof_id_type> & received_ids)
513 received_ids_map.emplace(pid, received_ids);
516 Parallel::push_parallel_vector_data(this->comm(), ids_to_send,
519 auto rows_action_functor =
527 const std::vector<Row> & received_rows)
529 const std::vector<dof_id_type> & received_ids = libmesh_map_find(received_ids_map, pid);
531 std::size_t n_rows = received_rows.size();
532 libmesh_assert_equal_to(n_rows, received_ids.size());
534 for (
auto i : IntRange<std::size_t>(0, n_rows))
536 const auto r = received_ids[i];
539 const auto my_r = r - local_first_dof;
541 auto & their_row = received_rows[i];
548 libmesh_assert(!their_row.empty());
554 my_row.assign (their_row.begin(), their_row.end());
558 my_row.insert (my_row.end(),
565 std::sort (my_row.begin(), my_row.end());
567 my_row.erase(std::unique (my_row.begin(), my_row.end()), my_row.end());
573 for (
const auto & df : my_row)
574 if ((df < local_first_dof) || (df >= local_end_dof))
581 for (
const auto & df : their_row)
582 if ((df < local_first_dof) || (df >= local_end_dof))
587 n_nz[my_r] = std::min(
n_nz[my_r], n_dofs_on_proc);
589 static_cast<dof_id_type>(n_global_dofs-
n_nz[my_r]));
594 Parallel::push_parallel_vector_data(this->comm(), rows_to_send,
595 rows_action_functor);
SparsityPattern::Graph sparsity_pattern
This helper class can be called on multiple threads to compute the sparsity pattern (or graph) of the...
std::set< GhostingFunctor * >::const_iterator coupling_functors_begin() const
Beginning of range of coupling functors.
const bool need_full_sparsity_pattern
bool local_index(dof_id_type dof_index) const
void parallel_sync()
Send sparsity pattern data relevant to other processors to those processors, and receive and incorpor...
dof_id_type n_dofs() const
std::unordered_set< dof_id_type > hashed_dof_sets
Build(const DofMap &dof_map_in, const CouplingMatrix *dof_coupling_in, const std::set< GhostingFunctor * > &coupling_functors_in, const bool implicit_neighbor_dofs_in, const bool need_full_sparsity_pattern_in, const bool calculate_constrained_in=false)
Used to iterate over non-nullptr entries in a container.
uint8_t processor_id_type
dof_id_type n_dofs_on_processor(const processor_id_type proc) const
This class handles the numbering of degrees of freedom on a mesh.
std::vector< dof_id_type, Threads::scalable_allocator< dof_id_type > > Row
dof_id_type first_dof(const processor_id_type proc) const
dof_id_type end_dof(const processor_id_type proc) const
void join(const Build &other)
Combine the sparsity pattern in other with this object's sparsity pattern.
std::set< std::unique_ptr< CouplingMatrix >, Utility::CompareUnderlying > CouplingMatricesSet
static const processor_id_type invalid_processor_id
An invalid processor_id to distinguish DoFs that have not been assigned to a processor.
void sorted_connected_dofs(const Elem *elem, std::vector< dof_id_type > &dofs_vi, unsigned int vi)
void _dummy_function(void)
std::vector< dof_id_type > n_nz
void apply_extra_sparsity_object(SparsityPattern::AugmentSparsityPattern &asp)
Let a user-provided AugmentSparsityPattern subclass modify our sparsity structure.
SparsityPattern::NonlocalGraph nonlocal_pattern
unsigned int n_variables() const
static void merge_ghost_functor_outputs(GhostingFunctor::map_type &elements_to_ghost, CouplingMatricesSet &temporary_coupling_matrices, const std::set< GhostingFunctor * >::iterator &gf_begin, const std::set< GhostingFunctor * >::iterator &gf_end, const MeshBase::const_element_iterator &elems_begin, const MeshBase::const_element_iterator &elems_end, processor_id_type p)
void find_connected_dofs(std::vector< dof_id_type > &elem_dofs) const
Finds all the DOFS associated with the element DOFs elem_dofs.
void handle_vi_vj(const std::vector< dof_id_type > &element_dofs_i, const std::vector< dof_id_type > &element_dofs_j)
void operator()(const ConstElemRange &range)
Add entries from a range of elements to this object's sparsity pattern.
std::set< GhostingFunctor * >::const_iterator coupling_functors_end() const
End of range of coupling functors.
virtual void augment_sparsity_pattern(SparsityPattern::Graph &sparsity, std::vector< dof_id_type > &n_nz, std::vector< dof_id_type > &n_oz)=0
User-defined function to augment the sparsity pattern.
Abstract base class to be used to add user-defined implicit degree of freedom couplings.
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.
static void sort_row(const BidirectionalIterator begin, BidirectionalIterator middle, const BidirectionalIterator end)
Splices the two sorted ranges [begin,middle) and [middle,end) into one sorted range [begin...
std::vector< dof_id_type > n_oz