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"
41namespace SparsityPattern
49 const std::vector<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)
337 this->
handle_vi_vj(element_dofs_i[vi], element_dofs_i[idx]);
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);
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());
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;
This proxy class acts like a container of indices from a single coupling row.
This class defines a coupling matrix.
dof_id_type first_dof(const processor_id_type proc) const
dof_id_type end_dof(const processor_id_type proc) const
This class handles the numbering of degrees of freedom on a mesh.
unsigned int n_variables() const override
GhostingFunctorIterator coupling_functors_begin() const
Beginning of range of coupling functors.
dof_id_type n_local_dofs(const unsigned int vn) const
void dof_indices(const Elem *const elem, std::vector< dof_id_type > &di) const
void find_connected_dofs(std::vector< dof_id_type > &elem_dofs) const
Finds all the DOFS associated with the element DOFs elem_dofs.
GhostingFunctorIterator coupling_functors_end() const
End of range of coupling functors.
static void merge_ghost_functor_outputs(GhostingFunctor::map_type &elements_to_ghost, CouplingMatricesSet &temporary_coupling_matrices, const GhostingFunctorIterator &gf_begin, const GhostingFunctorIterator &gf_end, const MeshBase::const_element_iterator &elems_begin, const MeshBase::const_element_iterator &elems_end, processor_id_type p)
bool local_index(dof_id_type dof_index) const
std::set< std::unique_ptr< CouplingMatrix >, Utility::CompareUnderlying > CouplingMatricesSet
static constexpr processor_id_type invalid_processor_id
An invalid processor_id to distinguish DoFs that have not been assigned to a processor.
This is the base class from which all geometric element types are derived.
unsigned int p_level() const
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 IntRange templated class is intended to make it easy to loop over integers which are indices of a...
An object whose state is distributed along a set of processors.
processor_id_type processor_id() const
const Parallel::Communicator & comm() const
Abstract base class to be used to add user-defined implicit degree of freedom couplings.
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.
This helper class can be called on multiple threads to compute the sparsity pattern (or graph) of the...
SparsityPattern::Graph sparsity_pattern
void join(const Build &other)
Combine the sparsity pattern in other with this object's sparsity pattern.
std::unordered_set< dof_id_type > hashed_dof_sets
If there are "spider" nodes in the mesh (i.e.
void apply_extra_sparsity_object(SparsityPattern::AugmentSparsityPattern &asp)
Let a user-provided AugmentSparsityPattern subclass modify our sparsity structure.
Build(const DofMap &dof_map_in, const CouplingMatrix *dof_coupling_in, const std::vector< 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)
void parallel_sync()
Send sparsity pattern data relevant to other processors to those processors, and receive and incorpor...
const StaticCondensationDofMap *const sc
void handle_vi_vj(const std::vector< dof_id_type > &element_dofs_i, const std::vector< dof_id_type > &element_dofs_j)
std::vector< dof_id_type > n_nz
void operator()(const ConstElemRange &range)
Add entries from a range of elements to this object's sparsity pattern.
std::size_t n_nonzeros() const
The total number of nonzeros in the global matrix.
SparsityPattern::NonlocalGraph nonlocal_pattern
std::vector< dof_id_type > dummy_vec
A dummy work vector to avoid repeated memory allocations.
const bool need_full_sparsity_pattern
void sorted_connected_dofs(const Elem *elem, std::vector< dof_id_type > &dofs_vi, unsigned int vi)
std::vector< dof_id_type > n_oz
A class holding degree of freedom information pertinent to static condensation.
const std::unordered_set< unsigned int > & uncondensed_vars() const
The StoredRange class defines a contiguous, divisible set of objects.
Dummy "splitting object" used to distinguish splitting constructors from copy constructors.
void push_parallel_vector_data(const Communicator &comm, MapToVectors &&data, const ActionFunctor &act_on_data)
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,...
void _dummy_function(void)
std::vector< dof_id_type, Threads::scalable_allocator< dof_id_type > > Row
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.
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 ...
The libMesh namespace provides an interface to certain functionality in the library.
const unsigned int invalid_uint
A number which is used quite often to represent an invalid or uninitialized value for an unsigned int...
uint8_t processor_id_type
The definition of the const_element_iterator struct.
Used to iterate over non-nullptr entries in a container.