libMesh
sparsity_pattern.C
Go to the documentation of this file.
1 // The libMesh Finite Element Library.
2 // Copyright (C) 2002-2019 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/sparsity_pattern.h"
22 
23 // libMesh includes
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 
32 // TIMPI includes
33 #include "timpi/communicator.h"
34 
35 
36 namespace libMesh
37 {
38 namespace SparsityPattern
39 {
40 
41 //-------------------------------------------------------
42 // we need to implement these constructors here so that
43 // a full DofMap definition is available.
44 Build::Build (const MeshBase & mesh_in,
45  const DofMap & dof_map_in,
46  const CouplingMatrix * dof_coupling_in,
47  const std::set<GhostingFunctor *> & coupling_functors_in,
48  const bool implicit_neighbor_dofs_in,
49  const bool need_full_sparsity_pattern_in) :
50  ParallelObject(dof_map_in),
51  mesh(mesh_in),
52  dof_map(dof_map_in),
53  dof_coupling(dof_coupling_in),
54  coupling_functors(coupling_functors_in),
55  implicit_neighbor_dofs(implicit_neighbor_dofs_in),
56  need_full_sparsity_pattern(need_full_sparsity_pattern_in),
57  sparsity_pattern(),
58  nonlocal_pattern(),
59  n_nz(),
60  n_oz()
61 {}
62 
63 
64 
66  ParallelObject(other),
67  mesh(other.mesh),
68  dof_map(other.dof_map),
69  dof_coupling(other.dof_coupling),
70  coupling_functors(other.coupling_functors),
71  implicit_neighbor_dofs(other.implicit_neighbor_dofs),
72  need_full_sparsity_pattern(other.need_full_sparsity_pattern),
73  hashed_dof_sets(other.hashed_dof_sets),
74  sparsity_pattern(),
75  nonlocal_pattern(),
76  n_nz(),
77  n_oz()
78 {}
79 
80 
81 
82 #if defined(__GNUC__) && (__GNUC__ < 4) && !defined(__INTEL_COMPILER)
83 
84 void _dummy_function(void) {}
85 
86 #endif
87 
88 
89 
91  std::vector<dof_id_type> & dofs_vi,
92  unsigned int vi)
93 {
94  dof_map.dof_indices (elem, dofs_vi, vi);
95 #ifdef LIBMESH_ENABLE_CONSTRAINTS
96  dof_map.find_connected_dofs (dofs_vi);
97 #endif
98  // We can be more efficient if we sort the element DOFs into
99  // increasing order
100  std::sort(dofs_vi.begin(), dofs_vi.end());
101 }
102 
103 
104 
105 void Build::handle_vi_vj(const std::vector<dof_id_type> & element_dofs_i,
106  const std::vector<dof_id_type> & element_dofs_j)
107 {
108  const unsigned int n_dofs_on_element_i =
109  cast_int<unsigned int>(element_dofs_i.size());
110 
111  const processor_id_type proc_id = mesh.processor_id();
112  const dof_id_type first_dof_on_proc = dof_map.first_dof(proc_id);
113  const dof_id_type end_dof_on_proc = dof_map.end_dof(proc_id);
114 
115  std::vector<dof_id_type>
116  dofs_to_add;
117 
118  const unsigned int n_dofs_on_element_j =
119  cast_int<unsigned int>(element_dofs_j.size());
120 
121  // It only makes sense to compute hashes and see if we can skip
122  // doing work when there are a "large" amount of DOFs for a given
123  // element. The cutoff for "large" is somewhat arbitrarily chosen
124  // based on a test case with a spider node that resulted in O(10^3)
125  // entries in element_dofs_i for O(10^3) elements. Making this
126  // number larger will disable the hashing optimization in more
127  // cases.
128  bool dofs_seen = false;
129  if (n_dofs_on_element_j > 0 && n_dofs_on_element_i > 256)
130  {
131  auto hash_i = Utility::hashword(element_dofs_i);
132  auto hash_j = Utility::hashword(element_dofs_j);
133  auto final_hash = Utility::hashword2(hash_i, hash_j);
134  auto result = hashed_dof_sets.insert(final_hash);
135  // if insert failed, we have already seen these dofs
136  dofs_seen = !result.second;
137  }
138 
139  // there might be 0 dofs for the other variable on the same element
140  // (when subdomain variables do not overlap) and that's when we do
141  // not do anything
142  if (n_dofs_on_element_j > 0 && !dofs_seen)
143  {
144  for (unsigned int i=0; i<n_dofs_on_element_i; i++)
145  {
146  const dof_id_type ig = element_dofs_i[i];
147 
148  SparsityPattern::Row * row;
149 
150  // We save non-local row components for now so we can
151  // communicate them to other processors later.
152 
153  if ((ig >= first_dof_on_proc) &&
154  (ig < end_dof_on_proc))
155  {
156  // This is what I mean
157  // libmesh_assert_greater_equal ((ig - first_dof_on_proc), 0);
158  // but do the test like this because ig and
159  // first_dof_on_proc are unsigned ints
160  libmesh_assert_greater_equal (ig, first_dof_on_proc);
161  libmesh_assert_less (ig, (sparsity_pattern.size() +
162  first_dof_on_proc));
163 
164  row = &sparsity_pattern[ig - first_dof_on_proc];
165  }
166  else
167  {
168  row = &nonlocal_pattern[ig];
169  }
170 
171  // If the row is empty we will add *all*
172  // the element j DOFs, so just do that.
173  if (row->empty())
174  {
175  row->insert(row->end(),
176  element_dofs_j.begin(),
177  element_dofs_j.end());
178  }
179  else
180  {
181  // Build a list of the DOF indices not found in the
182  // sparsity pattern
183  dofs_to_add.clear();
184 
185  // Cache iterators. Low will move forward, subsequent
186  // searches will be on smaller ranges
187  SparsityPattern::Row::iterator
188  low = std::lower_bound
189  (row->begin(), row->end(), element_dofs_j.front()),
190  high = std::upper_bound
191  (low, row->end(), element_dofs_j.back());
192 
193  for (unsigned int j=0; j<n_dofs_on_element_j; j++)
194  {
195  const dof_id_type jg = element_dofs_j[j];
196 
197  // See if jg is in the sorted range
198  std::pair<SparsityPattern::Row::iterator,
199  SparsityPattern::Row::iterator>
200  pos = std::equal_range (low, high, jg);
201 
202  // Must add jg if it wasn't found
203  if (pos.first == pos.second)
204  dofs_to_add.push_back(jg);
205 
206  // pos.first is now a valid lower bound for any
207  // remaining element j DOFs. (That's why we sorted them.)
208  // Use it for the next search
209  low = pos.first;
210  }
211 
212  // Add to the sparsity pattern
213  if (!dofs_to_add.empty())
214  {
215  const std::size_t old_size = row->size();
216 
217  row->insert (row->end(),
218  dofs_to_add.begin(),
219  dofs_to_add.end());
220 
222  (row->begin(), row->begin()+old_size,
223  row->end());
224  }
225  }
226  } // End dofs-of-var-i loop
227  } // End if-dofs-of-var-j
228 }
229 
230 
231 
233 {
234  // Compute the sparsity structure of the global matrix. This can be
235  // fed into a PetscMatrix to allocate exactly the number of nonzeros
236  // necessary to store the matrix. This algorithm should be linear
237  // in the (# of elements)*(# nodes per element)
238  const processor_id_type proc_id = mesh.processor_id();
239  const dof_id_type n_dofs_on_proc = dof_map.n_dofs_on_processor(proc_id);
240  const dof_id_type first_dof_on_proc = dof_map.first_dof(proc_id);
241  const dof_id_type end_dof_on_proc = dof_map.end_dof(proc_id);
242 
243  sparsity_pattern.resize(n_dofs_on_proc);
244 
245  // Handle dof coupling specified by library and user coupling functors
246  {
247  const unsigned int n_var = dof_map.n_variables();
248 
249  std::vector<std::vector<dof_id_type> > element_dofs_i(n_var);
250 
251  std::vector<const Elem *> coupled_neighbors;
252  for (const auto & elem : range)
253  {
254  // Make some fake element iterators defining a range
255  // pointing to only this element.
256  Elem * const * elempp = const_cast<Elem * const *>(&elem);
257  Elem * const * elemend = elempp+1;
258 
259  const MeshBase::const_element_iterator fake_elem_it =
261  elemend,
263 
264  const MeshBase::const_element_iterator fake_elem_end =
266  elemend,
268 
269  GhostingFunctor::map_type elements_to_couple;
270 
271  // Man, I wish we had guaranteed unique_ptr availability...
272  std::set<CouplingMatrix *> temporary_coupling_matrices;
273 
274  dof_map.merge_ghost_functor_outputs(elements_to_couple,
275  temporary_coupling_matrices,
278  fake_elem_it,
279  fake_elem_end,
281  for (unsigned int vi=0; vi<n_var; vi++)
282  this->sorted_connected_dofs(elem, element_dofs_i[vi], vi);
283 
284  for (unsigned int vi=0; vi<n_var; vi++)
285  for (const auto & pr : elements_to_couple)
286  {
287  const Elem * const partner = pr.first;
288  const CouplingMatrix * ghost_coupling = pr.second;
289 
290  // Loop over coupling matrix row variables if we have a
291  // coupling matrix, or all variables if not.
292  if (ghost_coupling)
293  {
294  libmesh_assert_equal_to (ghost_coupling->size(), n_var);
295  ConstCouplingRow ccr(vi, *ghost_coupling);
296 
297  for (const auto & idx : ccr)
298  {
299  if (partner == elem)
300  this->handle_vi_vj(element_dofs_i[vi], element_dofs_i[idx]);
301  else
302  {
303  std::vector<dof_id_type> partner_dofs;
304  this->sorted_connected_dofs(partner, partner_dofs, idx);
305  this->handle_vi_vj(element_dofs_i[vi], partner_dofs);
306  }
307  }
308  }
309  else
310  {
311  for (unsigned int vj = 0; vj != n_var; ++vj)
312  {
313  if (partner == elem)
314  this->handle_vi_vj(element_dofs_i[vi], element_dofs_i[vj]);
315  else
316  {
317  std::vector<dof_id_type> partner_dofs;
318  this->sorted_connected_dofs(partner, partner_dofs, vj);
319  this->handle_vi_vj(element_dofs_i[vi], partner_dofs);
320  }
321  }
322  }
323  } // End ghosted element loop
324 
325  for (auto & mat : temporary_coupling_matrices)
326  delete mat;
327 
328  } // End range element loop
329  } // End ghosting functor section
330 
331  // Now a new chunk of sparsity structure is built for all of the
332  // DOFs connected to our rows of the matrix.
333 
334  // If we're building a full sparsity pattern, then we've got
335  // complete rows to work with, so we can just count them from
336  // scratch.
338  {
339  n_nz.clear();
340  n_oz.clear();
341  }
342 
343  n_nz.resize (n_dofs_on_proc, 0);
344  n_oz.resize (n_dofs_on_proc, 0);
345 
346  for (dof_id_type i=0; i<n_dofs_on_proc; i++)
347  {
348  // Get the row of the sparsity pattern
350 
351  for (const auto & df : row)
352  if ((df < first_dof_on_proc) || (df >= end_dof_on_proc))
353  n_oz[i]++;
354  else
355  n_nz[i]++;
356 
357  // If we're not building a full sparsity pattern, then we want
358  // to avoid overcounting these entries as much as possible.
360  row.clear();
361  }
362 }
363 
364 
365 
367 {
368  const processor_id_type proc_id = mesh.processor_id();
369  const dof_id_type n_global_dofs = dof_map.n_dofs();
370  const dof_id_type n_dofs_on_proc = dof_map.n_dofs_on_processor(proc_id);
371  const dof_id_type first_dof_on_proc = dof_map.first_dof(proc_id);
372  const dof_id_type end_dof_on_proc = dof_map.end_dof(proc_id);
373 
374  libmesh_assert_equal_to (sparsity_pattern.size(), other.sparsity_pattern.size());
375  libmesh_assert_equal_to (n_nz.size(), sparsity_pattern.size());
376  libmesh_assert_equal_to (n_oz.size(), sparsity_pattern.size());
377 
378  for (dof_id_type r=0; r<n_dofs_on_proc; r++)
379  {
380  // increment the number of on and off-processor nonzeros in this row
381  // (note this will be an upper bound unless we need the full sparsity pattern)
383  {
385  const SparsityPattern::Row & their_row = other.sparsity_pattern[r];
386 
387  // simple copy if I have no dofs
388  if (my_row.empty())
389  my_row = their_row;
390 
391  // otherwise add their DOFs to mine, resort, and re-unique the row
392  else if (!their_row.empty()) // do nothing for the trivial case where
393  { // their row is empty
394  my_row.insert (my_row.end(),
395  their_row.begin(),
396  their_row.end());
397 
398  // We cannot use SparsityPattern::sort_row() here because it expects
399  // the [begin,middle) [middle,end) to be non-overlapping. This is not
400  // necessarily the case here, so use std::sort()
401  std::sort (my_row.begin(), my_row.end());
402 
403  my_row.erase(std::unique (my_row.begin(), my_row.end()), my_row.end());
404  }
405 
406  // fix the number of on and off-processor nonzeros in this row
407  n_nz[r] = n_oz[r] = 0;
408 
409  for (const auto & df : my_row)
410  if ((df < first_dof_on_proc) || (df >= end_dof_on_proc))
411  n_oz[r]++;
412  else
413  n_nz[r]++;
414  }
415  else
416  {
417  n_nz[r] += other.n_nz[r];
418  n_nz[r] = std::min(n_nz[r], n_dofs_on_proc);
419  n_oz[r] += other.n_oz[r];
420  n_oz[r] =std::min(n_oz[r], static_cast<dof_id_type>(n_global_dofs-n_nz[r]));
421  }
422  }
423 
424  // Move nonlocal row information to ourselves; the other thread
425  // won't need it in the map after that.
426  for (const auto & p : other.nonlocal_pattern)
427  {
428 #ifndef NDEBUG
429  const dof_id_type dof_id = p.first;
430 
431  processor_id_type dbg_proc_id = 0;
432  while (dof_id >= dof_map.end_dof(dbg_proc_id))
433  dbg_proc_id++;
434  libmesh_assert (dbg_proc_id != this->processor_id());
435 #endif
436 
437  const SparsityPattern::Row & their_row = p.second;
438 
439  // We should have no empty values in a map
440  libmesh_assert (!their_row.empty());
441 
442  NonlocalGraph::iterator my_it = nonlocal_pattern.find(p.first);
443  if (my_it == nonlocal_pattern.end())
444  {
445  // nonlocal_pattern[it->first].swap(their_row);
446  nonlocal_pattern[p.first] = their_row;
447  }
448  else
449  {
450  SparsityPattern::Row & my_row = my_it->second;
451 
452  my_row.insert (my_row.end(),
453  their_row.begin(),
454  their_row.end());
455 
456  // We cannot use SparsityPattern::sort_row() here because it expects
457  // the [begin,middle) [middle,end) to be non-overlapping. This is not
458  // necessarily the case here, so use std::sort()
459  std::sort (my_row.begin(), my_row.end());
460 
461  my_row.erase(std::unique (my_row.begin(), my_row.end()), my_row.end());
462  }
463  }
464 
465  // Combine the other thread's hashed_dof_sets with ours.
466  hashed_dof_sets.insert(other.hashed_dof_sets.begin(),
467  other.hashed_dof_sets.end());
468 }
469 
470 
471 
473 {
474  parallel_object_only();
476 
477  auto & comm = this->comm();
478  auto pid = comm.rank();
479  auto num_procs = comm.size();
480 
481  auto dof_tag = comm.get_unique_tag();
482  auto row_tag = comm.get_unique_tag();
483 
484  const auto n_global_dofs = dof_map.n_dofs();
485  const auto n_dofs_on_proc = dof_map.n_dofs_on_processor(pid);
486  const auto local_first_dof = dof_map.first_dof();
487  const auto local_end_dof = dof_map.end_dof();
488 
489  // The data to send
490  std::map<processor_id_type, std::pair<std::vector<dof_id_type>, std::vector<Row>>> data_to_send;
491 
492  // True/false if we're sending to that processor
493  std::vector<char> will_send_to(num_procs);
494 
495  processor_id_type num_sends = 0;
496 
497  // Loop over the nonlocal rows and transform them into the new datastructure
498  NonlocalGraph::iterator it = nonlocal_pattern.begin();
499  while (it != nonlocal_pattern.end())
500  {
501  const auto dof_id = it->first;
502  auto & row = it->second;
503 
504  processor_id_type proc_id = 0;
505  while (dof_id >= dof_map.end_dof(proc_id))
506  proc_id++;
507 
508  // Count the unique sends
509  if (!will_send_to[proc_id])
510  num_sends++;
511 
512  will_send_to[proc_id] = true;
513 
514  // rhs [] on purpose
515  auto & proc_data = data_to_send[proc_id];
516 
517  proc_data.first.push_back(dof_id);
518 
519  // Note this invalidates the data in nonlocal_pattern
520  proc_data.second.emplace_back(std::move(row));
521 
522  // Might as well remove it since it's invalidated anyway
523  it = nonlocal_pattern.erase(it);
524  }
525 
526  // Tell everyone about where everyone will send to
527  comm.alltoall(will_send_to);
528 
529  // will_send_to now represents who we'll receive from
530  // give it a good name
531  auto & will_receive_from = will_send_to;
532 
533  std::vector<Parallel::Request> dof_sends(num_sends);
534  std::vector<Parallel::Request> row_sends(num_sends);
535 
536  // Post all of the sends
537  processor_id_type current_send = 0;
538  for (auto & proc_data : data_to_send)
539  {
540  auto proc_id = proc_data.first;
541 
542  auto & dofs = proc_data.second.first;
543  auto & rows = proc_data.second.second;
544 
545  comm.send(proc_id, dofs, dof_sends[current_send], dof_tag);
546  comm.send(proc_id, rows, row_sends[current_send], row_tag);
547 
548  current_send++;
549  }
550 
551  // Figure out how many receives we're going to have and make a
552  // quick list of who's sending
553  processor_id_type num_receives = 0;
554  std::vector<processor_id_type> receiving_from;
555  for (processor_id_type proc_id = 0; proc_id < num_procs; proc_id++)
556  {
557  auto will = will_receive_from[proc_id];
558 
559  if (will)
560  {
561  num_receives++;
562  receiving_from.push_back(proc_id);
563  }
564  }
565 
566  // Post the receives and handle the data
567  for (auto proc_id : receiving_from)
568  {
569  std::vector<dof_id_type> in_dofs;
570  std::vector<Row> in_rows;
571 
572  // Receive dofs
573  comm.receive(proc_id, in_dofs, dof_tag);
574  comm.receive(proc_id, in_rows, row_tag);
575 
576  const std::size_t n_rows = in_dofs.size();
577  for (std::size_t i = 0; i != n_rows; ++i)
578  {
579  const auto r = in_dofs[i];
580  const auto my_r = r - local_first_dof;
581 
582  auto & their_row = in_rows[i];
583 
585  {
586  auto & my_row = sparsity_pattern[my_r];
587 
588  // They wouldn't have sent an empty row
589  libmesh_assert(!their_row.empty());
590 
591  // We can end up with an empty row on a dof that touches our
592  // inactive elements but not our active ones
593  if (my_row.empty())
594  {
595  my_row.assign (their_row.begin(), their_row.end());
596  }
597  else
598  {
599  my_row.insert (my_row.end(),
600  their_row.begin(),
601  their_row.end());
602 
603  // We cannot use SparsityPattern::sort_row() here because it expects
604  // the [begin,middle) [middle,end) to be non-overlapping. This is not
605  // necessarily the case here, so use std::sort()
606  std::sort (my_row.begin(), my_row.end());
607 
608  my_row.erase(std::unique (my_row.begin(), my_row.end()), my_row.end());
609  }
610 
611  // fix the number of on and off-processor nonzeros in this row
612  n_nz[my_r] = n_oz[my_r] = 0;
613 
614  for (const auto & df : my_row)
615  if ((df < local_first_dof) || (df >= local_end_dof))
616  n_oz[my_r]++;
617  else
618  n_nz[my_r]++;
619  }
620  else
621  {
622  for (const auto & df : their_row)
623  if ((df < local_first_dof) || (df >= local_end_dof))
624  n_oz[my_r]++;
625  else
626  n_nz[my_r]++;
627 
628  n_nz[my_r] = std::min(n_nz[my_r], n_dofs_on_proc);
629  n_oz[my_r] = std::min(n_oz[my_r],
630  static_cast<dof_id_type>(n_global_dofs-n_nz[my_r]));
631  }
632  }
633  }
634 
635  // We should have sent everything at this point.
637 
638  // Make sure to cleanup requests
639  Parallel::wait(dof_sends);
640  Parallel::wait(row_sends);
641 }
642 
643 
644 } // namespace SparsityPattern
645 } // namespace libMesh
libMesh::dof_id_type
uint8_t dof_id_type
Definition: id_types.h:67
libMesh::SparsityPattern::Row
std::vector< dof_id_type, Threads::scalable_allocator< dof_id_type > > Row
Definition: sparsity_pattern.h:51
libMesh::SparsityPattern::Build::sorted_connected_dofs
void sorted_connected_dofs(const Elem *elem, std::vector< dof_id_type > &dofs_vi, unsigned int vi)
Definition: sparsity_pattern.C:90
libMesh::SparsityPattern::_dummy_function
void _dummy_function(void)
Dummy function that does nothing but can be used to prohibit compiler optimization in some situations...
Definition: sparsity_pattern.C:84
libMesh::DofMap::dof_indices
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:1967
libMesh::SparsityPattern::Build::handle_vi_vj
void handle_vi_vj(const std::vector< dof_id_type > &element_dofs_i, const std::vector< dof_id_type > &element_dofs_j)
Definition: sparsity_pattern.C:105
libMesh::SparsityPattern::Build::nonlocal_pattern
SparsityPattern::NonlocalGraph nonlocal_pattern
Definition: sparsity_pattern.h:112
libMesh::SparsityPattern::Build::dof_map
const DofMap & dof_map
Definition: sparsity_pattern.h:85
libMesh::DofMap::n_dofs
dof_id_type n_dofs() const
Definition: dof_map.h:625
libMesh
The libMesh namespace provides an interface to certain functionality in the library.
Definition: factoryfunction.C:55
libMesh::DofMap::coupling_functors_begin
std::set< GhostingFunctor * >::const_iterator coupling_functors_begin() const
Beginning of range of coupling functors.
Definition: dof_map.h:329
libMesh::ParallelObject::comm
const Parallel::Communicator & comm() const
Definition: parallel_object.h:94
libMesh::DofMap::n_variables
unsigned int n_variables() const
Definition: dof_map.h:592
libMesh::Threads::split
Dummy "splitting object" used to distinguish splitting constructors from copy constructors.
Definition: threads_none.h:63
libMesh::GhostingFunctor::map_type
std::unordered_map< const Elem *, const CouplingMatrix * > map_type
What elements do we care about and what variables do we care about on each element?
Definition: ghosting_functor.h:171
libMesh::SparsityPattern::Build::hashed_dof_sets
std::unordered_set< dof_id_type > hashed_dof_sets
Definition: sparsity_pattern.h:100
mesh
MeshBase & mesh
Definition: mesh_communication.C:1257
libMesh::SparsityPattern::Build::sparsity_pattern
SparsityPattern::Graph sparsity_pattern
Definition: sparsity_pattern.h:111
libMesh::DofMap::first_dof
dof_id_type first_dof(const processor_id_type proc) const
Definition: dof_map.h:650
libMesh::SparsityPattern::sort_row
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,...
libMesh::SparsityPattern::Build::parallel_sync
void parallel_sync()
Definition: sparsity_pattern.C:472
libMesh::SparsityPattern::Build::n_oz
std::vector< dof_id_type > n_oz
Definition: sparsity_pattern.h:115
libMesh::libmesh_assert
libmesh_assert(ctx)
libMesh::SparsityPattern::Build
This helper class can be called on multiple threads to compute the sparsity pattern (or graph) of the...
Definition: sparsity_pattern.h:81
libMesh::MeshBase
This is the MeshBase class.
Definition: mesh_base.h:78
libMesh::CouplingMatrix::size
unsigned int size() const
Definition: coupling_matrix.h:605
libMesh::ParallelObject::processor_id
processor_id_type processor_id() const
Definition: parallel_object.h:106
libMesh::processor_id_type
uint8_t processor_id_type
Definition: id_types.h:104
libMesh::DofMap::find_connected_dofs
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:2773
libMesh::Utility::hashword2
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.
Definition: hashword.h:210
libMesh::MeshTools::Generation::Private::idx
unsigned int idx(const ElemType type, const unsigned int nx, const unsigned int i, const unsigned int j)
A useful inline function which replaces the macros used previously.
Definition: mesh_generation.C:72
libMesh::SparsityPattern::Build::operator()
void operator()(const ConstElemRange &range)
Definition: sparsity_pattern.C:232
libMesh::MeshBase::const_element_iterator
The definition of the const_element_iterator struct.
Definition: mesh_base.h:1891
libMesh::SparsityPattern::Build::need_full_sparsity_pattern
const bool need_full_sparsity_pattern
Definition: sparsity_pattern.h:89
libMesh::DofMap::n_dofs_on_processor
dof_id_type n_dofs_on_processor(const processor_id_type proc) const
Definition: dof_map.h:641
libMesh::Utility::hashword
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 ...
Definition: hashword.h:153
libMesh::DofMap::coupling_functors_end
std::set< GhostingFunctor * >::const_iterator coupling_functors_end() const
End of range of coupling functors.
Definition: dof_map.h:335
libMesh::SparsityPattern::Build::n_nz
std::vector< dof_id_type > n_nz
Definition: sparsity_pattern.h:114
libMesh::DofMap
This class handles the numbering of degrees of freedom on a mesh.
Definition: dof_map.h:176
libMesh::SparsityPattern::Build::Build
Build(const MeshBase &mesh_in, 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)
Definition: sparsity_pattern.C:44
libMesh::StoredRange
The StoredRange class defines a contiguous, divisible set of objects.
Definition: stored_range.h:52
libMesh::DofObject::invalid_processor_id
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:432
libMesh::Elem
This is the base class from which all geometric element types are derived.
Definition: elem.h:100
libMesh::ConstCouplingRow
This proxy class acts like a container of indices from a single coupling row.
Definition: coupling_matrix.h:337
libMesh::CouplingMatrix
This class defines a coupling matrix.
Definition: coupling_matrix.h:54
libMesh::SparsityPattern::Build::join
void join(const Build &other)
Definition: sparsity_pattern.C:366
libMesh::ParallelObject
An object whose state is distributed along a set of processors.
Definition: parallel_object.h:55
communicator.h
libMesh::SparsityPattern::Build::mesh
const MeshBase & mesh
Definition: sparsity_pattern.h:84
libMesh::Predicates::NotNull
Used to iterate over non-nullptr entries in a container.
Definition: multi_predicates.h:137
libMesh::DofMap::end_dof
dof_id_type end_dof(const processor_id_type proc) const
Definition: dof_map.h:692
libMesh::DofMap::merge_ghost_functor_outputs
static void merge_ghost_functor_outputs(GhostingFunctor::map_type &elements_to_ghost, std::set< CouplingMatrix * > &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