libMesh::SparsityPattern::Build Class Reference
#include <sparsity_pattern.h>
Public Member Functions | |
| Build (const MeshBase &mesh_in, const DofMap &dof_map_in, const CouplingMatrix *dof_coupling_in, const bool implicit_neighbor_dofs_in, const bool need_full_sparsity_pattern_in) | |
| Build (Build &other, Threads::split) | |
| void | operator() (const ConstElemRange &range) |
| void | join (const Build &other) |
| void | parallel_sync () |
Public Attributes | |
| SparsityPattern::Graph | sparsity_pattern |
| SparsityPattern::NonlocalGraph | nonlocal_pattern |
| std::vector< dof_id_type > | n_nz |
| std::vector< dof_id_type > | n_oz |
Private Attributes | |
| const MeshBase & | mesh |
| const DofMap & | dof_map |
| const CouplingMatrix * | dof_coupling |
| const bool | implicit_neighbor_dofs |
| const bool | need_full_sparsity_pattern |
Detailed Description
This helper class can be called on multiple threads to compute the sparsity pattern (or graph) of the sparse matrix resulting from the discretization. This pattern may be used directly by a particular sparse matrix format (e.g. LaspackMatrix) or indirectly (e.g. PetscMatrix). In the latter case the number of nonzeros per row of the matrix is needed for efficient preallocation. In this case it suffices to provide estimate (but bounding) values, and in this case the threaded method can take some short-cuts for efficiency.
Definition at line 78 of file sparsity_pattern.h.
Constructor & Destructor Documentation
| libMesh::SparsityPattern::Build::Build | ( | const MeshBase & | mesh_in, | |
| const DofMap & | dof_map_in, | |||
| const CouplingMatrix * | dof_coupling_in, | |||
| const bool | implicit_neighbor_dofs_in, | |||
| const bool | need_full_sparsity_pattern_in | |||
| ) | [inline] |
Definition at line 95 of file sparsity_pattern.h.
00099 : 00100 mesh(mesh_in), 00101 dof_map(dof_map_in), 00102 dof_coupling(dof_coupling_in), 00103 implicit_neighbor_dofs(implicit_neighbor_dofs_in), 00104 need_full_sparsity_pattern(need_full_sparsity_pattern_in), 00105 sparsity_pattern(), 00106 nonlocal_pattern(), 00107 n_nz(), 00108 n_oz() 00109 {}
| libMesh::SparsityPattern::Build::Build | ( | Build & | other, | |
| Threads::split | ||||
| ) | [inline] |
Definition at line 111 of file sparsity_pattern.h.
00111 : 00112 mesh(other.mesh), 00113 dof_map(other.dof_map), 00114 dof_coupling(other.dof_coupling), 00115 implicit_neighbor_dofs(other.implicit_neighbor_dofs), 00116 need_full_sparsity_pattern(other.need_full_sparsity_pattern), 00117 sparsity_pattern(), 00118 nonlocal_pattern(), 00119 n_nz(), 00120 n_oz() 00121 {}
Member Function Documentation
| void libMesh::SparsityPattern::Build::join | ( | const Build & | other | ) |
Definition at line 2542 of file dof_map.C.
References dof_map, libMesh::DofMap::end_dof(), libMesh::DofMap::first_dof(), std::min(), libMesh::DofMap::n_dofs(), libMesh::DofMap::n_dofs_on_processor(), n_nz, n_oz, need_full_sparsity_pattern, nonlocal_pattern, libMesh::processor_id(), libMesh::MeshBase::processor_id(), and sparsity_pattern.
02543 { 02544 const processor_id_type proc_id = mesh.processor_id(); 02545 const dof_id_type n_global_dofs = dof_map.n_dofs(); 02546 const dof_id_type n_dofs_on_proc = dof_map.n_dofs_on_processor(proc_id); 02547 const dof_id_type first_dof_on_proc = dof_map.first_dof(proc_id); 02548 const dof_id_type end_dof_on_proc = dof_map.end_dof(proc_id); 02549 02550 libmesh_assert_equal_to (sparsity_pattern.size(), other.sparsity_pattern.size()); 02551 libmesh_assert_equal_to (n_nz.size(), sparsity_pattern.size()); 02552 libmesh_assert_equal_to (n_oz.size(), sparsity_pattern.size()); 02553 02554 for (dof_id_type r=0; r<n_dofs_on_proc; r++) 02555 { 02556 // increment the number of on and off-processor nonzeros in this row 02557 // (note this will be an upper bound unless we need the full sparsity pattern) 02558 if (need_full_sparsity_pattern) 02559 { 02560 SparsityPattern::Row &my_row = sparsity_pattern[r]; 02561 const SparsityPattern::Row &their_row = other.sparsity_pattern[r]; 02562 02563 // simple copy if I have no dofs 02564 if (my_row.empty()) 02565 my_row = their_row; 02566 02567 // otherwise add their DOFs to mine, resort, and re-unique the row 02568 else if (!their_row.empty()) // do nothing for the trivial case where 02569 { // their row is empty 02570 my_row.insert (my_row.end(), 02571 their_row.begin(), 02572 their_row.end()); 02573 02574 // We cannot use SparsityPattern::sort_row() here because it expects 02575 // the [begin,middle) [middle,end) to be non-overlapping. This is not 02576 // necessarily the case here, so use std::sort() 02577 std::sort (my_row.begin(), my_row.end()); 02578 02579 my_row.erase(std::unique (my_row.begin(), my_row.end()), my_row.end()); 02580 } 02581 02582 // fix the number of on and off-processor nonzeros in this row 02583 n_nz[r] = n_oz[r] = 0; 02584 02585 for (std::size_t j=0; j<my_row.size(); j++) 02586 if ((my_row[j] < first_dof_on_proc) || (my_row[j] >= end_dof_on_proc)) 02587 n_oz[r]++; 02588 else 02589 n_nz[r]++; 02590 } 02591 else 02592 { 02593 n_nz[r] += other.n_nz[r]; 02594 n_nz[r] = std::min(n_nz[r], n_dofs_on_proc); 02595 n_oz[r] += other.n_oz[r]; 02596 n_oz[r] =std::min(n_oz[r], static_cast<dof_id_type>(n_global_dofs-n_nz[r])); 02597 } 02598 } 02599 02600 // Move nonlocal row information to ourselves; the other thread 02601 // won't need it in the map after that. 02602 NonlocalGraph::const_iterator it = other.nonlocal_pattern.begin(); 02603 for (; it != other.nonlocal_pattern.end(); ++it) 02604 { 02605 const dof_id_type dof_id = it->first; 02606 02607 #ifndef NDEBUG 02608 processor_id_type dbg_proc_id = 0; 02609 while (dof_id >= dof_map.end_dof(dbg_proc_id)) 02610 dbg_proc_id++; 02611 libmesh_assert (dbg_proc_id != libMesh::processor_id()); 02612 #endif 02613 02614 const SparsityPattern::Row &their_row = it->second; 02615 02616 // We should have no empty values in a map 02617 libmesh_assert (!their_row.empty()); 02618 02619 NonlocalGraph::iterator my_it = nonlocal_pattern.find(it->first); 02620 if (my_it == nonlocal_pattern.end()) 02621 { 02622 // nonlocal_pattern[it->first].swap(their_row); 02623 nonlocal_pattern[it->first] = their_row; 02624 } 02625 else 02626 { 02627 SparsityPattern::Row &my_row = my_it->second; 02628 02629 my_row.insert (my_row.end(), 02630 their_row.begin(), 02631 their_row.end()); 02632 02633 // We cannot use SparsityPattern::sort_row() here because it expects 02634 // the [begin,middle) [middle,end) to be non-overlapping. This is not 02635 // necessarily the case here, so use std::sort() 02636 std::sort (my_row.begin(), my_row.end()); 02637 02638 my_row.erase(std::unique (my_row.begin(), my_row.end()), my_row.end()); 02639 } 02640 } 02641 }
| void libMesh::SparsityPattern::Build::operator() | ( | const ConstElemRange & | range | ) |
Definition at line 2154 of file dof_map.C.
References libMesh::Elem::active_family_tree_by_neighbor(), libMesh::StoredRange< iterator_type, object_type >::begin(), dof_coupling, libMesh::DofMap::dof_indices(), dof_map, libMesh::CouplingMatrix::empty(), libMesh::StoredRange< iterator_type, object_type >::end(), libMesh::DofMap::end_dof(), libMesh::DofMap::find_connected_dofs(), libMesh::DofMap::first_dof(), implicit_neighbor_dofs, libMesh::DofMap::n_dofs_on_processor(), n_nz, n_oz, libMesh::Elem::n_sides(), libMesh::DofMap::n_variables(), need_full_sparsity_pattern, libMesh::Elem::neighbor(), nonlocal_pattern, libMesh::MeshBase::processor_id(), libMesh::CouplingMatrix::size(), libMesh::SparsityPattern::sort_row(), and sparsity_pattern.
02155 { 02156 // Compute the sparsity structure of the global matrix. This can be 02157 // fed into a PetscMatrix to allocate exacly the number of nonzeros 02158 // necessary to store the matrix. This algorithm should be linear 02159 // in the (# of elements)*(# nodes per element) 02160 const processor_id_type proc_id = mesh.processor_id(); 02161 const dof_id_type n_dofs_on_proc = dof_map.n_dofs_on_processor(proc_id); 02162 const dof_id_type first_dof_on_proc = dof_map.first_dof(proc_id); 02163 const dof_id_type end_dof_on_proc = dof_map.end_dof(proc_id); 02164 02165 sparsity_pattern.resize(n_dofs_on_proc); 02166 02167 // If the user did not explicitly specify the DOF coupling 02168 // then all the DOFS are coupled to each other. Furthermore, 02169 // we can take a shortcut and do this more quickly here. So 02170 // we use an if-test. 02171 if ((dof_coupling == NULL) || (dof_coupling->empty())) 02172 { 02173 std::vector<dof_id_type> 02174 element_dofs, 02175 neighbor_dofs, 02176 dofs_to_add; 02177 02178 std::vector<const Elem*> active_neighbors; 02179 02180 for (ConstElemRange::const_iterator elem_it = range.begin() ; elem_it != range.end(); ++elem_it) 02181 { 02182 const Elem* const elem = *elem_it; 02183 02184 // Get the global indices of the DOFs with support on this element 02185 dof_map.dof_indices (elem, element_dofs); 02186 #ifdef LIBMESH_ENABLE_CONSTRAINTS 02187 dof_map.find_connected_dofs (element_dofs); 02188 #endif 02189 02190 // We can be more efficient if we sort the element DOFs 02191 // into increasing order 02192 std::sort(element_dofs.begin(), element_dofs.end()); 02193 02194 const unsigned int n_dofs_on_element = 02195 libmesh_cast_int<unsigned int>(element_dofs.size()); 02196 02197 for (unsigned int i=0; i<n_dofs_on_element; i++) 02198 { 02199 const dof_id_type ig = element_dofs[i]; 02200 02201 SparsityPattern::Row *row; 02202 02203 // We save non-local row components for now so we can 02204 // communicate them to other processors later. 02205 02206 if ((ig >= first_dof_on_proc) && 02207 (ig < end_dof_on_proc)) 02208 { 02209 // This is what I mean 02210 // libmesh_assert_greater_equal ((ig - first_dof_on_proc), 0); 02211 // but do the test like this because ig and 02212 // first_dof_on_proc are unsigned ints 02213 libmesh_assert_greater_equal (ig, first_dof_on_proc); 02214 libmesh_assert_less ((ig - first_dof_on_proc), sparsity_pattern.size()); 02215 02216 row = &sparsity_pattern[ig - first_dof_on_proc]; 02217 } 02218 else 02219 { 02220 row = &nonlocal_pattern[ig]; 02221 } 02222 02223 // If the row is empty we will add *all* the element DOFs, 02224 // so just do that. 02225 if (row->empty()) 02226 { 02227 row->insert(row->end(), 02228 element_dofs.begin(), 02229 element_dofs.end()); 02230 } 02231 else 02232 { 02233 // Build a list of the DOF indices not found in the 02234 // sparsity pattern 02235 dofs_to_add.clear(); 02236 02237 // Cache iterators. Low will move forward, subsequent 02238 // searches will be on smaller ranges 02239 SparsityPattern::Row::iterator 02240 low = std::lower_bound (row->begin(), row->end(), element_dofs.front()), 02241 high = std::upper_bound (low, row->end(), element_dofs.back()); 02242 02243 for (unsigned int j=0; j<n_dofs_on_element; j++) 02244 { 02245 const dof_id_type jg = element_dofs[j]; 02246 02247 // See if jg is in the sorted range 02248 std::pair<SparsityPattern::Row::iterator, 02249 SparsityPattern::Row::iterator> 02250 pos = std::equal_range (low, high, jg); 02251 02252 // Must add jg if it wasn't found 02253 if (pos.first == pos.second) 02254 dofs_to_add.push_back(jg); 02255 02256 // pos.first is now a valid lower bound for any 02257 // remaining element DOFs. (That's why we sorted them.) 02258 // Use it for the next search 02259 low = pos.first; 02260 } 02261 02262 // Add to the sparsity pattern 02263 if (!dofs_to_add.empty()) 02264 { 02265 const std::size_t old_size = row->size(); 02266 02267 row->insert (row->end(), 02268 dofs_to_add.begin(), 02269 dofs_to_add.end()); 02270 02271 SparsityPattern::sort_row 02272 (row->begin(), row->begin()+old_size, row->end()); 02273 } 02274 } 02275 02276 // Now (possibly) add dofs from neighboring elements 02277 // TODO:[BSK] optimize this like above! 02278 if (implicit_neighbor_dofs) 02279 for (unsigned int s=0; s<elem->n_sides(); s++) 02280 if (elem->neighbor(s) != NULL) 02281 { 02282 const Elem* const neighbor_0 = elem->neighbor(s); 02283 #ifdef LIBMESH_ENABLE_AMR 02284 neighbor_0->active_family_tree_by_neighbor(active_neighbors,elem); 02285 #else 02286 active_neighbors.clear(); 02287 active_neighbors.push_back(neighbor_0); 02288 #endif 02289 02290 for (std::size_t a=0; a != active_neighbors.size(); ++a) 02291 { 02292 const Elem *neighbor = active_neighbors[a]; 02293 02294 dof_map.dof_indices (neighbor, neighbor_dofs); 02295 #ifdef LIBMESH_ENABLE_CONSTRAINTS 02296 dof_map.find_connected_dofs (neighbor_dofs); 02297 #endif 02298 const std::size_t n_dofs_on_neighbor = neighbor_dofs.size(); 02299 02300 for (std::size_t j=0; j<n_dofs_on_neighbor; j++) 02301 { 02302 const dof_id_type jg = neighbor_dofs[j]; 02303 02304 // See if jg is in the sorted range 02305 std::pair<SparsityPattern::Row::iterator, 02306 SparsityPattern::Row::iterator> 02307 pos = std::equal_range (row->begin(), row->end(), jg); 02308 02309 // Insert jg if it wasn't found 02310 if (pos.first == pos.second) 02311 row->insert (pos.first, jg); 02312 } 02313 } 02314 } 02315 } 02316 } 02317 } 02318 02319 // This is what we do in the case that the user has specified 02320 // explicit DOF coupling. 02321 else 02322 { 02323 libmesh_assert(dof_coupling); 02324 libmesh_assert_equal_to (dof_coupling->size(), 02325 dof_map.n_variables()); 02326 02327 const unsigned int n_var = dof_map.n_variables(); 02328 02329 std::vector<dof_id_type> 02330 element_dofs_i, 02331 element_dofs_j, 02332 neighbor_dofs, 02333 dofs_to_add; 02334 02335 02336 std::vector<const Elem*> active_neighbors; 02337 for (ConstElemRange::const_iterator elem_it = range.begin() ; elem_it != range.end(); ++elem_it) 02338 for (unsigned int vi=0; vi<n_var; vi++) 02339 { 02340 const Elem* const elem = *elem_it; 02341 02342 // Find element dofs for variable vi 02343 dof_map.dof_indices (elem, element_dofs_i, vi); 02344 #ifdef LIBMESH_ENABLE_CONSTRAINTS 02345 dof_map.find_connected_dofs (element_dofs_i); 02346 #endif 02347 02348 // We can be more efficient if we sort the element DOFs 02349 // into increasing order 02350 std::sort(element_dofs_i.begin(), element_dofs_i.end()); 02351 const unsigned int n_dofs_on_element_i = 02352 libmesh_cast_int<unsigned int>(element_dofs_i.size()); 02353 02354 for (unsigned int vj=0; vj<n_var; vj++) 02355 if ((*dof_coupling)(vi,vj)) // If vi couples to vj 02356 { 02357 // Find element dofs for variable vj, note that 02358 // if vi==vj we already have the dofs. 02359 if (vi != vj) 02360 { 02361 dof_map.dof_indices (elem, element_dofs_j, vj); 02362 #ifdef LIBMESH_ENABLE_CONSTRAINTS 02363 dof_map.find_connected_dofs (element_dofs_j); 02364 #endif 02365 02366 // We can be more efficient if we sort the element DOFs 02367 // into increasing order 02368 std::sort (element_dofs_j.begin(), element_dofs_j.end()); 02369 } 02370 else 02371 element_dofs_j = element_dofs_i; 02372 02373 const unsigned int n_dofs_on_element_j = 02374 libmesh_cast_int<unsigned int>(element_dofs_j.size()); 02375 02376 // there might be 0 dofs for the other variable on the same element (when subdomain variables do not overlap) and that's when we do not do anything 02377 if (n_dofs_on_element_j > 0) 02378 { 02379 for (unsigned int i=0; i<n_dofs_on_element_i; i++) 02380 { 02381 const dof_id_type ig = element_dofs_i[i]; 02382 02383 SparsityPattern::Row *row; 02384 02385 // We save non-local row components for now so we can 02386 // communicate them to other processors later. 02387 02388 if ((ig >= first_dof_on_proc) && 02389 (ig < end_dof_on_proc)) 02390 { 02391 // This is what I mean 02392 // libmesh_assert_greater_equal ((ig - first_dof_on_proc), 0); 02393 // but do the test like this because ig and 02394 // first_dof_on_proc are unsigned ints 02395 libmesh_assert_greater_equal (ig, first_dof_on_proc); 02396 libmesh_assert_less (ig, (sparsity_pattern.size() + 02397 first_dof_on_proc)); 02398 02399 row = &sparsity_pattern[ig - first_dof_on_proc]; 02400 } 02401 else 02402 { 02403 row = &nonlocal_pattern[ig]; 02404 } 02405 02406 // If the row is empty we will add *all* the element j DOFs, 02407 // so just do that. 02408 if (row->empty()) 02409 { 02410 row->insert(row->end(), 02411 element_dofs_j.begin(), 02412 element_dofs_j.end()); 02413 } 02414 else 02415 { 02416 // Build a list of the DOF indices not found in the 02417 // sparsity pattern 02418 dofs_to_add.clear(); 02419 02420 // Cache iterators. Low will move forward, subsequent 02421 // searches will be on smaller ranges 02422 SparsityPattern::Row::iterator 02423 low = std::lower_bound 02424 (row->begin(), row->end(), element_dofs_j.front()), 02425 high = std::upper_bound 02426 (low, row->end(), element_dofs_j.back()); 02427 02428 for (unsigned int j=0; j<n_dofs_on_element_j; j++) 02429 { 02430 const dof_id_type jg = element_dofs_j[j]; 02431 02432 // See if jg is in the sorted range 02433 std::pair<SparsityPattern::Row::iterator, 02434 SparsityPattern::Row::iterator> 02435 pos = std::equal_range (low, high, jg); 02436 02437 // Must add jg if it wasn't found 02438 if (pos.first == pos.second) 02439 dofs_to_add.push_back(jg); 02440 02441 // pos.first is now a valid lower bound for any 02442 // remaining element j DOFs. (That's why we sorted them.) 02443 // Use it for the next search 02444 low = pos.first; 02445 } 02446 02447 // Add to the sparsity pattern 02448 if (!dofs_to_add.empty()) 02449 { 02450 const std::size_t old_size = row->size(); 02451 02452 row->insert (row->end(), 02453 dofs_to_add.begin(), 02454 dofs_to_add.end()); 02455 02456 SparsityPattern::sort_row 02457 (row->begin(), row->begin()+old_size, 02458 row->end()); 02459 } 02460 } 02461 // Now (possibly) add dofs from neighboring elements 02462 // TODO:[BSK] optimize this like above! 02463 if (implicit_neighbor_dofs) 02464 for (unsigned int s=0; s<elem->n_sides(); s++) 02465 if (elem->neighbor(s) != NULL) 02466 { 02467 const Elem* const neighbor_0 = elem->neighbor(s); 02468 #ifdef LIBMESH_ENABLE_AMR 02469 neighbor_0->active_family_tree_by_neighbor(active_neighbors,elem); 02470 #else 02471 active_neighbors.clear(); 02472 active_neighbors.push_back(neighbor_0); 02473 #endif 02474 02475 for (std::size_t a=0; a != active_neighbors.size(); ++a) 02476 { 02477 const Elem *neighbor = active_neighbors[a]; 02478 02479 dof_map.dof_indices (neighbor, neighbor_dofs); 02480 #ifdef LIBMESH_ENABLE_CONSTRAINTS 02481 dof_map.find_connected_dofs (neighbor_dofs); 02482 #endif 02483 const unsigned int n_dofs_on_neighbor = 02484 libmesh_cast_int<unsigned int>(neighbor_dofs.size()); 02485 02486 for (unsigned int j=0; j<n_dofs_on_neighbor; j++) 02487 { 02488 const dof_id_type jg = neighbor_dofs[j]; 02489 02490 // See if jg is in the sorted range 02491 std::pair<SparsityPattern::Row::iterator, 02492 SparsityPattern::Row::iterator> 02493 pos = std::equal_range (row->begin(), row->end(), jg); 02494 02495 // Insert jg if it wasn't found 02496 if (pos.first == pos.second) 02497 row->insert (pos.first, jg); 02498 } 02499 } 02500 } 02501 } 02502 } 02503 } 02504 } 02505 } 02506 02507 // Now a new chunk of sparsity structure is built for all of the 02508 // DOFs connected to our rows of the matrix. 02509 02510 // If we're building a full sparsity pattern, then we've got 02511 // complete rows to work with, so we can just count them from 02512 // scratch. 02513 if (need_full_sparsity_pattern) 02514 { 02515 n_nz.clear(); 02516 n_oz.clear(); 02517 } 02518 02519 n_nz.resize (n_dofs_on_proc, 0); 02520 n_oz.resize (n_dofs_on_proc, 0); 02521 02522 for (dof_id_type i=0; i<n_dofs_on_proc; i++) 02523 { 02524 // Get the row of the sparsity pattern 02525 SparsityPattern::Row &row = sparsity_pattern[i]; 02526 02527 for (dof_id_type j=0; j<row.size(); j++) 02528 if ((row[j] < first_dof_on_proc) || (row[j] >= end_dof_on_proc)) 02529 n_oz[i]++; 02530 else 02531 n_nz[i]++; 02532 02533 // If we're not building a full sparsity pattern, then we want 02534 // to avoid overcounting these entries as much as possible. 02535 if (!need_full_sparsity_pattern) 02536 row.clear(); 02537 } 02538 }
| void libMesh::SparsityPattern::Build::parallel_sync | ( | ) |
Definition at line 2645 of file dof_map.C.
References libMesh::CommWorld, dof_map, libMesh::DofMap::end_dof(), libMesh::DofMap::first_dof(), std::min(), libMesh::DofMap::n_dofs(), libMesh::DofMap::n_dofs_on_processor(), n_nz, n_oz, libMesh::n_processors(), need_full_sparsity_pattern, nonlocal_pattern, libMesh::processor_id(), libMesh::Parallel::Communicator::send_receive(), sparsity_pattern, and libMesh::Parallel::Communicator::verify().
02646 { 02647 parallel_only(); 02648 CommWorld.verify(need_full_sparsity_pattern); 02649 02650 const dof_id_type n_global_dofs = dof_map.n_dofs(); 02651 const dof_id_type n_dofs_on_proc = dof_map.n_dofs_on_processor(libMesh::processor_id()); 02652 const dof_id_type local_first_dof = dof_map.first_dof(); 02653 const dof_id_type local_end_dof = dof_map.end_dof(); 02654 02655 // Trade sparsity rows with other processors 02656 for (processor_id_type p=1; p != libMesh::n_processors(); ++p) 02657 { 02658 // Push to processor procup while receiving from procdown 02659 processor_id_type procup = (libMesh::processor_id() + p) % 02660 libMesh::n_processors(); 02661 processor_id_type procdown = (libMesh::n_processors() + 02662 libMesh::processor_id() - p) % 02663 libMesh::n_processors(); 02664 02665 // Pack the sparsity pattern rows to push to procup 02666 std::vector<dof_id_type> pushed_row_ids, 02667 pushed_row_ids_to_me; 02668 std::vector<std::vector<dof_id_type> > pushed_rows, 02669 pushed_rows_to_me; 02670 02671 // Move nonlocal row information to a structure to send it from; 02672 // we don't need it in the map after that. 02673 NonlocalGraph::iterator it = nonlocal_pattern.begin(); 02674 while (it != nonlocal_pattern.end()) 02675 { 02676 const dof_id_type dof_id = it->first; 02677 processor_id_type proc_id = 0; 02678 while (dof_id >= dof_map.end_dof(proc_id)) 02679 proc_id++; 02680 02681 libmesh_assert (proc_id != libMesh::processor_id()); 02682 02683 if (proc_id == procup) 02684 { 02685 pushed_row_ids.push_back(dof_id); 02686 02687 // We can't just do the swap trick here, thanks to the 02688 // differing vector allocators? 02689 pushed_rows.push_back(std::vector<dof_id_type>()); 02690 pushed_rows.back().assign 02691 (it->second.begin(), it->second.end()); 02692 02693 nonlocal_pattern.erase(it++); 02694 } 02695 else 02696 ++it; 02697 } 02698 02699 CommWorld.send_receive(procup, pushed_row_ids, 02700 procdown, pushed_row_ids_to_me); 02701 CommWorld.send_receive(procup, pushed_rows, 02702 procdown, pushed_rows_to_me); 02703 pushed_row_ids.clear(); 02704 pushed_rows.clear(); 02705 02706 const std::size_t n_rows = pushed_row_ids_to_me.size(); 02707 for (std::size_t i=0; i != n_rows; ++i) 02708 { 02709 const dof_id_type r = pushed_row_ids_to_me[i]; 02710 const dof_id_type my_r = r - local_first_dof; 02711 02712 std::vector<dof_id_type> &their_row = pushed_rows_to_me[i]; 02713 02714 if (need_full_sparsity_pattern) 02715 { 02716 SparsityPattern::Row &my_row = 02717 sparsity_pattern[my_r]; 02718 02719 // They wouldn't have sent an empty row 02720 libmesh_assert(!their_row.empty()); 02721 02722 // We can end up with an empty row on a dof that touches our 02723 // inactive elements but not our active ones 02724 if (my_row.empty()) 02725 { 02726 my_row.assign (their_row.begin(), 02727 their_row.end()); 02728 } 02729 else 02730 { 02731 my_row.insert (my_row.end(), 02732 their_row.begin(), 02733 their_row.end()); 02734 02735 // We cannot use SparsityPattern::sort_row() here because it expects 02736 // the [begin,middle) [middle,end) to be non-overlapping. This is not 02737 // necessarily the case here, so use std::sort() 02738 std::sort (my_row.begin(), my_row.end()); 02739 02740 my_row.erase(std::unique (my_row.begin(), my_row.end()), my_row.end()); 02741 } 02742 02743 // fix the number of on and off-processor nonzeros in this row 02744 n_nz[my_r] = n_oz[my_r] = 0; 02745 02746 for (std::size_t j=0; j<my_row.size(); j++) 02747 if ((my_row[j] < local_first_dof) || (my_row[j] >= local_end_dof)) 02748 n_oz[my_r]++; 02749 else 02750 n_nz[my_r]++; 02751 } 02752 else 02753 { 02754 for (std::size_t j=0; j<their_row.size(); j++) 02755 if ((their_row[j] < local_first_dof) || (their_row[j] >= local_end_dof)) 02756 n_oz[my_r]++; 02757 else 02758 n_nz[my_r]++; 02759 02760 n_nz[my_r] = std::min(n_nz[my_r], n_dofs_on_proc); 02761 n_oz[my_r] = std::min(n_oz[my_r], 02762 static_cast<dof_id_type>(n_global_dofs-n_nz[my_r])); 02763 } 02764 } 02765 } 02766 02767 // We should have sent everything at this point. 02768 libmesh_assert (nonlocal_pattern.empty()); 02769 }
Member Data Documentation
const CouplingMatrix* libMesh::SparsityPattern::Build::dof_coupling [private] |
Definition at line 83 of file sparsity_pattern.h.
Referenced by operator()().
const DofMap& libMesh::SparsityPattern::Build::dof_map [private] |
Definition at line 82 of file sparsity_pattern.h.
Referenced by join(), operator()(), and parallel_sync().
const bool libMesh::SparsityPattern::Build::implicit_neighbor_dofs [private] |
Definition at line 84 of file sparsity_pattern.h.
Referenced by operator()().
const MeshBase& libMesh::SparsityPattern::Build::mesh [private] |
Definition at line 81 of file sparsity_pattern.h.
| std::vector<dof_id_type> libMesh::SparsityPattern::Build::n_nz |
Definition at line 92 of file sparsity_pattern.h.
Referenced by join(), operator()(), and parallel_sync().
| std::vector<dof_id_type> libMesh::SparsityPattern::Build::n_oz |
Definition at line 93 of file sparsity_pattern.h.
Referenced by join(), operator()(), and parallel_sync().
const bool libMesh::SparsityPattern::Build::need_full_sparsity_pattern [private] |
Definition at line 85 of file sparsity_pattern.h.
Referenced by join(), operator()(), and parallel_sync().
Definition at line 90 of file sparsity_pattern.h.
Referenced by join(), operator()(), and parallel_sync().
Definition at line 89 of file sparsity_pattern.h.
Referenced by join(), operator()(), and parallel_sync().
The documentation for this class was generated from the following files:
Site Created By: libMesh Developers
Last modified: February 05 2013 19:55:49 UTC
Hosted By: