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" 33 #include "libmesh/static_condensation_dof_map.h" 41 namespace SparsityPattern
49 const std::set<GhostingFunctor *> & coupling_functors_in,
50 const bool implicit_neighbor_dofs_in,
51 const bool need_full_sparsity_pattern_in,
52 const bool calculate_constrained_in,
56 dof_coupling(dof_coupling_in),
57 coupling_functors(coupling_functors_in),
58 implicit_neighbor_dofs(implicit_neighbor_dofs_in),
59 need_full_sparsity_pattern(need_full_sparsity_pattern_in),
60 calculate_constrained(calculate_constrained_in),
72 dof_map(other.dof_map),
73 dof_coupling(other.dof_coupling),
74 coupling_functors(other.coupling_functors),
75 implicit_neighbor_dofs(other.implicit_neighbor_dofs),
76 need_full_sparsity_pattern(other.need_full_sparsity_pattern),
77 calculate_constrained(other.calculate_constrained),
79 hashed_dof_sets(other.hashed_dof_sets),
88 #if defined(__GNUC__) && (__GNUC__ < 4) && !defined(__INTEL_COMPILER) 97 std::vector<dof_id_type> & dofs_vi,
106 auto total_and_uncondensed_from_scalar_dofs_functor =
107 [&dofs_vi](
const Elem & ,
108 std::vector<dof_id_type> & dof_indices,
109 const std::vector<dof_id_type> & scalar_dof_indices)
111 dof_indices.insert(dof_indices.end(), scalar_dof_indices.begin(), scalar_dof_indices.end());
112 dofs_vi.insert(dofs_vi.end(), scalar_dof_indices.begin(), scalar_dof_indices.end());
115 auto total_and_uncondensed_from_field_dofs_functor =
116 [&dofs_vi,
this](
const Elem & functor_elem,
117 const unsigned int node_num,
118 const unsigned int var_num,
119 std::vector<dof_id_type> & dof_indices,
122 dof_indices.push_back(field_dof);
124 (node_num !=
invalid_uint && !functor_elem.is_internal(node_num)))
125 dofs_vi.push_back(field_dof);
131 total_and_uncondensed_from_scalar_dofs_functor,
132 total_and_uncondensed_from_field_dofs_functor,
138 #ifdef LIBMESH_ENABLE_CONSTRAINTS 143 std::sort(dofs_vi.begin(), dofs_vi.end());
147 dofs_vi.erase(std::unique(dofs_vi.begin(), dofs_vi.end()), dofs_vi.end());
153 const std::vector<dof_id_type> & element_dofs_j)
155 const unsigned int n_dofs_on_element_i =
156 cast_int<unsigned int>(element_dofs_i.size());
162 std::vector<dof_id_type>
165 const unsigned int n_dofs_on_element_j =
166 cast_int<unsigned int>(element_dofs_j.size());
175 bool dofs_seen =
false;
176 if (n_dofs_on_element_j > 0 && n_dofs_on_element_i > 256)
183 dofs_seen = !result.second;
189 if (n_dofs_on_element_j > 0 && !dofs_seen)
191 for (
unsigned int i=0; i<n_dofs_on_element_i; i++)
200 if ((ig >= first_dof_on_proc) &&
201 (ig < end_dof_on_proc))
207 libmesh_assert_greater_equal (ig, first_dof_on_proc);
222 row->insert(row->end(),
223 element_dofs_j.begin(),
224 element_dofs_j.end());
234 SparsityPattern::Row::iterator
235 low = std::lower_bound
236 (row->begin(), row->end(), element_dofs_j.front()),
237 high = std::upper_bound
238 (low, row->end(), element_dofs_j.back());
240 for (
unsigned int j=0; j<n_dofs_on_element_j; j++)
245 std::pair<SparsityPattern::Row::iterator,
246 SparsityPattern::Row::iterator>
247 pos = std::equal_range (low, high, jg);
250 if (pos.first == pos.second)
251 dofs_to_add.push_back(jg);
260 if (!dofs_to_add.empty())
262 const std::size_t old_size = row->size();
264 row->insert (row->end(),
269 (row->begin(), row->begin()+old_size,
291 std::vector<std::vector<dof_id_type> > element_dofs_i(n_var);
293 std::vector<const Elem *> coupled_neighbors;
294 for (
const auto & elem : range)
298 Elem *
const * elempp =
const_cast<Elem *
const *
>(&elem);
299 Elem *
const * elemend = elempp+1;
315 temporary_coupling_matrices,
321 for (
unsigned int vi=0; vi<n_var; vi++)
324 for (
unsigned int vi=0; vi<n_var; vi++)
325 for (
const auto & [partner, ghost_coupling] : elements_to_couple)
331 libmesh_assert_equal_to (ghost_coupling->size(), n_var);
334 for (
const auto &
idx : ccr)
340 std::vector<dof_id_type> partner_dofs;
348 for (
unsigned int vj = 0; vj != n_var; ++vj)
351 this->
handle_vi_vj(element_dofs_i[vi], element_dofs_i[vj]);
354 std::vector<dof_id_type> partner_dofs;
383 else if (!their_row.empty())
385 my_row.insert (my_row.end(),
392 std::sort (my_row.begin(), my_row.end());
394 my_row.erase(std::unique (my_row.begin(), my_row.end()), my_row.end());
426 my_row.insert (my_row.end(),
433 std::sort (my_row.begin(), my_row.end());
435 my_row.erase(std::unique (my_row.begin(), my_row.end()), my_row.end());
448 parallel_object_only();
455 std::map<processor_id_type, std::vector<dof_id_type>> ids_to_send;
456 std::map<processor_id_type, std::vector<Row>> rows_to_send;
462 const auto dof_id = it->first;
463 auto & row = it->second;
469 ids_to_send[proc_id].push_back(dof_id);
472 rows_to_send[proc_id].push_back(std::move(row));
478 std::map<processor_id_type, std::vector<dof_id_type>> received_ids_map;
480 auto ids_action_functor =
483 const std::vector<dof_id_type> & received_ids)
485 received_ids_map.emplace(pid, received_ids);
488 Parallel::push_parallel_vector_data(this->
comm(), ids_to_send,
491 auto rows_action_functor =
496 const std::vector<Row> & received_rows)
498 const std::vector<dof_id_type> & received_ids = libmesh_map_find(received_ids_map, pid);
500 std::size_t n_rows = received_rows.size();
501 libmesh_assert_equal_to(n_rows, received_ids.size());
505 const auto r = received_ids[i];
508 const auto my_r = r - local_first_dof;
510 auto & their_row = received_rows[i];
521 my_row.assign (their_row.begin(), their_row.end());
525 my_row.insert (my_row.end(),
532 std::sort (my_row.begin(), my_row.end());
534 my_row.erase(std::unique (my_row.begin(), my_row.end()), my_row.end());
540 Parallel::push_parallel_vector_data(this->
comm(), rows_to_send,
541 rows_action_functor);
551 n_nz.resize (n_dofs_on_proc, 0);
552 n_oz.resize (n_dofs_on_proc, 0);
562 for (
const auto & df : row)
563 if ((df < first_dof_on_proc) || (df >= end_dof_on_proc))
591 std::size_t total_nonzeros = 0;
592 for (
auto nnzi :
n_nz)
593 total_nonzeros += nnzi;
594 for (
auto nozi :
n_oz)
595 total_nonzeros += nozi;
597 this->
comm().
sum(total_nonzeros);
598 return total_nonzeros;
void find_connected_dofs(std::vector< dof_id_type > &elem_dofs) const
Finds all the DOFS associated with the element DOFs elem_dofs.
SparsityPattern::Graph sparsity_pattern
A class holding degree of freedom information pertinent to static condensation.
dof_id_type end_dof(const processor_id_type proc) const
std::set< GhostingFunctor * >::const_iterator coupling_functors_begin() const
Beginning of range of coupling functors.
This helper class can be called on multiple threads to compute the sparsity pattern (or graph) of the...
const unsigned int invalid_uint
A number which is used quite often to represent an invalid or uninitialized value for an unsigned int...
The IntRange templated class is intended to make it easy to loop over integers which are indices of a...
void dof_indices(const Elem *const elem, std::vector< dof_id_type > &di) const
The definition of the const_element_iterator struct.
Dummy "splitting object" used to distinguish splitting constructors from copy constructors.
std::size_t n_nonzeros() const
The total number of nonzeros in the global matrix.
This is the base class from which all geometric element types are derived.
const Parallel::Communicator & comm() const
This proxy class acts like a container of indices from a single coupling row.
unsigned int p_level() const
const bool need_full_sparsity_pattern
std::map< const Elem *, const CouplingMatrix *, CompareDofObjectsByPIDAndThenID > map_type
What elements do we care about and what variables do we care about on each element?
The StoredRange class defines a contiguous, divisible set of objects.
The libMesh namespace provides an interface to certain functionality in the library.
dof_id_type n_local_dofs(const unsigned int vn) const
void parallel_sync()
Send sparsity pattern data relevant to other processors to those processors, and receive and incorpor...
std::unordered_set< dof_id_type > hashed_dof_sets
If there are "spider" nodes in the mesh (i.e.
Used to iterate over non-nullptr entries in a container.
uint8_t processor_id_type
This class handles the numbering of degrees of freedom on a mesh.
std::vector< dof_id_type > dummy_vec
A dummy work vector to avoid repeated memory allocations.
std::vector< dof_id_type, Threads::scalable_allocator< dof_id_type > > Row
uint32_t hashword(const uint32_t *k, size_t length, uint32_t initval=0)
The hashword function takes an array of uint32_t's of length 'length' and computes a single key from ...
void join(const Build &other)
Combine the sparsity pattern in other with this object's sparsity pattern.
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)
const std::unordered_set< unsigned int > & uncondensed_vars() const
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.
unsigned int n_variables() const override
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
An object whose state is distributed along a set of processors.
void apply_extra_sparsity_object(SparsityPattern::AugmentSparsityPattern &asp)
Let a user-provided AugmentSparsityPattern subclass modify our sparsity structure.
SparsityPattern::NonlocalGraph nonlocal_pattern
const StaticCondensationDofMap *const sc
uint32_t hashword2(const uint32_t &first, const uint32_t &second, uint32_t initval=0)
This is a hard-coded version of hashword for hashing exactly 2 numbers.
std::set< GhostingFunctor * >::const_iterator coupling_functors_end() const
End of range of coupling functors.
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.
dof_id_type first_dof(const processor_id_type proc) const
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.
processor_id_type processor_id() const
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, const StaticCondensationDofMap *sc=nullptr)
Abstract base class to be used to add user-defined implicit degree of freedom couplings.
bool local_index(dof_id_type dof_index) const
This class defines a coupling matrix.
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