libMesh::HilbertSFCPartitioner Class Reference

#include <hilbert_sfc_partitioner.h>

Inheritance diagram for libMesh::HilbertSFCPartitioner:

Public Member Functions

 HilbertSFCPartitioner ()
 
virtual AutoPtr< Partitionerclone () const
 
void set_sfc_type (const std::string &sfc_type)
 
void partition (MeshBase &mesh, const unsigned int n)
 
void partition (MeshBase &mesh)
 
void repartition (MeshBase &mesh, const unsigned int n)
 
void repartition (MeshBase &mesh)
 
virtual void attach_weights (ErrorVector *)
 

Static Public Member Functions

static void partition_unpartitioned_elements (MeshBase &mesh)
 
static void partition_unpartitioned_elements (MeshBase &mesh, const unsigned int n)
 
static void set_parent_processor_ids (MeshBase &mesh)
 
static void set_node_processor_ids (MeshBase &mesh)
 

Protected Member Functions

virtual void _do_partition (MeshBase &mesh, const unsigned int n)
 
void single_partition (MeshBase &mesh)
 
virtual void _do_repartition (MeshBase &mesh, const unsigned int n)
 

Protected Attributes

ErrorVector_weights
 

Static Protected Attributes

static const dof_id_type communication_blocksize = 1000000
 

Detailed Description

The HilbertSFCPartitioner uses a Hilbert space filling curve to partition the elements.

Definition at line 40 of file hilbert_sfc_partitioner.h.

Constructor & Destructor Documentation

libMesh::HilbertSFCPartitioner::HilbertSFCPartitioner ( )
inline

Constructor.

Definition at line 47 of file hilbert_sfc_partitioner.h.

References libMesh::SFCPartitioner::set_sfc_type().

Referenced by clone().

48  {
49  this->set_sfc_type ("Hilbert");
50  }

Member Function Documentation

virtual void libMesh::HilbertSFCPartitioner::_do_partition ( MeshBase mesh,
const unsigned int  n 
)
inlineprotectedvirtual

Partition the MeshBase into n subdomains.

Reimplemented from libMesh::SFCPartitioner.

Definition at line 66 of file hilbert_sfc_partitioner.h.

References libMesh::SFCPartitioner::_do_partition().

virtual void libMesh::Partitioner::_do_repartition ( MeshBase mesh,
const unsigned int  n 
)
inlineprotectedvirtualinherited

This is the actual re-partitioning method which can be overloaded in derived classes. Note that the default behavior is to simply call the partition function.

Reimplemented in libMesh::ParmetisPartitioner.

Definition at line 156 of file partitioner.h.

References libMesh::Partitioner::_do_partition().

Referenced by libMesh::Partitioner::repartition().

157  { this->_do_partition (mesh, n); }
virtual void libMesh::Partitioner::attach_weights ( ErrorVector )
inlinevirtualinherited

Attach weights that can be used for partitioning. This ErrorVector should be exactly the same on every processor and should have mesh->max_elem_id() entries.

Reimplemented in libMesh::MetisPartitioner.

Definition at line 131 of file partitioner.h.

131 { libmesh_not_implemented(); }
virtual AutoPtr<Partitioner> libMesh::HilbertSFCPartitioner::clone ( ) const
inlinevirtual

Creates a new partitioner of this type and returns it in an AutoPtr.

Reimplemented from libMesh::SFCPartitioner.

Definition at line 56 of file hilbert_sfc_partitioner.h.

References HilbertSFCPartitioner().

56  {
57  AutoPtr<Partitioner> cloned_partitioner
58  (new HilbertSFCPartitioner());
59  return cloned_partitioner;
60  }
void libMesh::Partitioner::partition ( MeshBase mesh,
const unsigned int  n 
)
inherited

Partition the MeshBase into n parts. The partitioner currently does not modify the subdomain_id of each element. This number is reserved for things like material properties, etc.

Definition at line 55 of file partitioner.C.

References libMesh::Partitioner::_do_partition(), libMesh::ParallelObject::comm(), libMesh::MeshTools::libmesh_assert_valid_procids< Elem >(), libMesh::MeshTools::libmesh_assert_valid_remote_elems(), libMesh::libmesh_parallel_only(), mesh, std::min(), libMesh::MeshBase::n_active_elem(), libMesh::Partitioner::partition_unpartitioned_elements(), libMesh::MeshBase::redistribute(), libMesh::MeshBase::set_n_partitions(), libMesh::Partitioner::set_node_processor_ids(), libMesh::Partitioner::set_parent_processor_ids(), libMesh::Partitioner::single_partition(), and libMesh::MeshBase::update_post_partitioning().

Referenced by libMesh::MetisPartitioner::_do_partition(), libMesh::SFCPartitioner::_do_partition(), libMesh::ParmetisPartitioner::_do_repartition(), and libMesh::Partitioner::partition().

57 {
59 
60  // BSK - temporary fix while redistribution is integrated 6/26/2008
61  // Uncomment this to not repartition in parallel
62 // if (!mesh.is_serial())
63 // return;
64 
65  // we cannot partition into more pieces than we have
66  // active elements!
67  const unsigned int n_parts =
68  static_cast<unsigned int>
69  (std::min(mesh.n_active_elem(), static_cast<dof_id_type>(n)));
70 
71  // Set the number of partitions in the mesh
72  mesh.set_n_partitions()=n_parts;
73 
74  if (n_parts == 1)
75  {
76  this->single_partition (mesh);
77  return;
78  }
79 
80  // First assign a temporary partitioning to any unpartitioned elements
82 
83  // Call the partitioning function
84  this->_do_partition(mesh,n_parts);
85 
86  // Set the parent's processor ids
88 
89  // Redistribute elements if necessary, before setting node processor
90  // ids, to make sure those will be set consistently
91  mesh.redistribute();
92 
93 #ifdef DEBUG
95 
96  // Messed up elem processor_id()s can leave us without the child
97  // elements we need to restrict vectors on a distributed mesh
99 #endif
100 
101  // Set the node's processor ids
103 
104 #ifdef DEBUG
106 #endif
107 
108  // Give derived Mesh classes a chance to update any cached data to
109  // reflect the new partitioning
110  mesh.update_post_partitioning();
111 }
void libMesh::Partitioner::partition ( MeshBase mesh)
inherited

Partition the MeshBase into mesh.n_processors() parts. The partitioner currently does not modify the subdomain_id of each element. This number is reserved for things like material properties, etc.

Definition at line 48 of file partitioner.C.

References libMesh::ParallelObject::n_processors(), and libMesh::Partitioner::partition().

49 {
50  this->partition(mesh,mesh.n_processors());
51 }
void libMesh::Partitioner::partition_unpartitioned_elements ( MeshBase mesh)
staticinherited

This function

Definition at line 180 of file partitioner.C.

References libMesh::ParallelObject::n_processors().

Referenced by libMesh::Partitioner::partition(), and libMesh::Partitioner::repartition().

181 {
183 }
void libMesh::Partitioner::partition_unpartitioned_elements ( MeshBase mesh,
const unsigned int  n 
)
staticinherited

Definition at line 187 of file partitioner.C.

References libMesh::MeshTools::bounding_box(), libMesh::ParallelObject::comm(), end, libMesh::MeshCommunication::find_global_indices(), libMesh::MeshTools::n_elem(), libMesh::ParallelObject::n_processors(), libMesh::DofObject::processor_id(), libMesh::MeshBase::unpartitioned_elements_begin(), and libMesh::MeshBase::unpartitioned_elements_end().

189 {
190  MeshBase::element_iterator it = mesh.unpartitioned_elements_begin();
191  const MeshBase::element_iterator end = mesh.unpartitioned_elements_end();
192 
193  const dof_id_type n_unpartitioned_elements = MeshTools::n_elem (it, end);
194 
195  // the unpartitioned elements must exist on all processors. If the range is empty on one
196  // it is empty on all, and we can quit right here.
197  if (!n_unpartitioned_elements) return;
198 
199  // find the target subdomain sizes
200  std::vector<dof_id_type> subdomain_bounds(mesh.n_processors());
201 
202  for (processor_id_type pid=0; pid<mesh.n_processors(); pid++)
203  {
204  dof_id_type tgt_subdomain_size = 0;
205 
206  // watch out for the case that n_subdomains < n_processors
207  if (pid < n_subdomains)
208  {
209  tgt_subdomain_size = n_unpartitioned_elements/n_subdomains;
210 
211  if (pid < n_unpartitioned_elements%n_subdomains)
212  tgt_subdomain_size++;
213 
214  }
215 
216  //libMesh::out << "pid, #= " << pid << ", " << tgt_subdomain_size << std::endl;
217  if (pid == 0)
218  subdomain_bounds[0] = tgt_subdomain_size;
219  else
220  subdomain_bounds[pid] = subdomain_bounds[pid-1] + tgt_subdomain_size;
221  }
222 
223  libmesh_assert_equal_to (subdomain_bounds.back(), n_unpartitioned_elements);
224 
225  // create the unique mapping for all unpartitioned elements independent of partitioning
226  // determine the global indexing for all the unpartitoned elements
227  std::vector<dof_id_type> global_indices;
228 
229  // Calling this on all processors a unique range in [0,n_unpartitioned_elements) is constructed.
230  // Only the indices for the elements we pass in are returned in the array.
231  MeshCommunication().find_global_indices (mesh.comm(),
233  global_indices);
234 
235  for (dof_id_type cnt=0; it != end; ++it)
236  {
237  Elem *elem = *it;
238 
239  libmesh_assert_less (cnt, global_indices.size());
240  const dof_id_type global_index =
241  global_indices[cnt++];
242 
243  libmesh_assert_less (global_index, subdomain_bounds.back());
244  libmesh_assert_less (global_index, n_unpartitioned_elements);
245 
246  const processor_id_type subdomain_id =
247  libmesh_cast_int<processor_id_type>
248  (std::distance(subdomain_bounds.begin(),
249  std::upper_bound(subdomain_bounds.begin(),
250  subdomain_bounds.end(),
251  global_index)));
252  libmesh_assert_less (subdomain_id, n_subdomains);
253 
254  elem->processor_id() = subdomain_id;
255  //libMesh::out << "assigning " << global_index << " to " << subdomain_id << std::endl;
256  }
257 }
void libMesh::Partitioner::repartition ( MeshBase mesh,
const unsigned int  n 
)
inherited

Repartitions the MeshBase into n parts. This is required since some partitoning algorithms can repartition more efficiently than computing a new partitioning from scratch. The default behavior is to simply call this->partition(mesh,n)

Definition at line 122 of file partitioner.C.

References libMesh::Partitioner::_do_repartition(), std::min(), libMesh::MeshBase::n_active_elem(), libMesh::Partitioner::partition_unpartitioned_elements(), libMesh::MeshBase::set_n_partitions(), libMesh::Partitioner::set_node_processor_ids(), libMesh::Partitioner::set_parent_processor_ids(), and libMesh::Partitioner::single_partition().

Referenced by libMesh::Partitioner::repartition().

124 {
125  // we cannot partition into more pieces than we have
126  // active elements!
127  const unsigned int n_parts =
128  static_cast<unsigned int>
129  (std::min(mesh.n_active_elem(), static_cast<dof_id_type>(n)));
130 
131  // Set the number of partitions in the mesh
132  mesh.set_n_partitions()=n_parts;
133 
134  if (n_parts == 1)
135  {
136  this->single_partition (mesh);
137  return;
138  }
139 
140  // First assign a temporary partitioning to any unpartitioned elements
142 
143  // Call the partitioning function
144  this->_do_repartition(mesh,n_parts);
145 
146  // Set the parent's processor ids
148 
149  // Set the node's processor ids
151 }
void libMesh::Partitioner::repartition ( MeshBase mesh)
inherited

Repartitions the MeshBase into mesh.n_processors() parts. This is required since some partitoning algorithms can repartition more efficiently than computing a new partitioning from scratch.

Definition at line 115 of file partitioner.C.

References libMesh::ParallelObject::n_processors(), and libMesh::Partitioner::repartition().

116 {
117  this->repartition(mesh,mesh.n_processors());
118 }
void libMesh::Partitioner::set_node_processor_ids ( MeshBase mesh)
staticinherited

This function is called after partitioning to set the processor IDs for the nodes. By definition, a Node's processor ID is the minimum processor ID for all of the elements which share the node.

Definition at line 439 of file partitioner.C.

References libMesh::MeshBase::active_elements_begin(), libMesh::MeshBase::active_elements_end(), libMesh::ParallelObject::comm(), libMesh::Elem::get_node(), libMesh::DofObject::id(), libMesh::DofObject::invalid_processor_id, libMesh::DofObject::invalidate_processor_id(), libMesh::libmesh_assert(), libMesh::MeshTools::libmesh_assert_valid_procids< Node >(), libMesh::libmesh_parallel_only(), mesh, std::min(), libMesh::MeshTools::n_elem(), libMesh::Elem::n_nodes(), libMesh::MeshBase::n_partitions(), libMesh::ParallelObject::n_processors(), libMesh::MeshBase::node_ptr(), libMesh::MeshBase::nodes_begin(), libMesh::MeshBase::nodes_end(), libMesh::MeshBase::not_active_elements_begin(), libMesh::MeshBase::not_active_elements_end(), libMesh::ParallelObject::processor_id(), libMesh::DofObject::processor_id(), libMesh::Parallel::Communicator::send_receive(), libMesh::START_LOG(), libMesh::STOP_LOG(), libMesh::MeshBase::subactive_elements_begin(), libMesh::MeshBase::subactive_elements_end(), libMesh::MeshBase::unpartitioned_elements_begin(), and libMesh::MeshBase::unpartitioned_elements_end().

Referenced by libMesh::UnstructuredMesh::all_first_order(), libMesh::Partitioner::partition(), libMesh::XdrIO::read(), libMesh::Partitioner::repartition(), and libMesh::BoundaryInfo::sync().

440 {
441  START_LOG("set_node_processor_ids()","Partitioner");
442 
443  // This function must be run on all processors at once
444  libmesh_parallel_only(mesh.comm());
445 
446  // If we have any unpartitioned elements at this
447  // stage there is a problem
448  libmesh_assert (MeshTools::n_elem(mesh.unpartitioned_elements_begin(),
449  mesh.unpartitioned_elements_end()) == 0);
450 
451 
452 // const dof_id_type orig_n_local_nodes = mesh.n_local_nodes();
453 
454 // libMesh::err << "[" << mesh.processor_id() << "]: orig_n_local_nodes="
455 // << orig_n_local_nodes << std::endl;
456 
457  // Build up request sets. Each node is currently owned by a processor because
458  // it is connected to an element owned by that processor. However, during the
459  // repartitioning phase that element may have been assigned a new processor id, but
460  // it is still resident on the original processor. We need to know where to look
461  // for new ids before assigning new ids, otherwise we may be asking the wrong processors
462  // for the wrong information.
463  //
464  // The only remaining issue is what to do with unpartitioned nodes. Since they are required
465  // to live on all processors we can simply rely on ourselves to number them properly.
466  std::vector<std::vector<dof_id_type> >
467  requested_node_ids(mesh.n_processors());
468 
469  // Loop over all the nodes, count the ones on each processor. We can skip ourself
470  std::vector<dof_id_type> ghost_nodes_from_proc(mesh.n_processors(), 0);
471 
472  MeshBase::node_iterator node_it = mesh.nodes_begin();
473  const MeshBase::node_iterator node_end = mesh.nodes_end();
474 
475  for (; node_it != node_end; ++node_it)
476  {
477  Node *node = *node_it;
478  libmesh_assert(node);
479  const processor_id_type current_pid = node->processor_id();
480  if (current_pid != mesh.processor_id() &&
481  current_pid != DofObject::invalid_processor_id)
482  {
483  libmesh_assert_less (current_pid, ghost_nodes_from_proc.size());
484  ghost_nodes_from_proc[current_pid]++;
485  }
486  }
487 
488  // We know how many objects live on each processor, so reserve()
489  // space for each.
490  for (processor_id_type pid=0; pid != mesh.n_processors(); ++pid)
491  requested_node_ids[pid].reserve(ghost_nodes_from_proc[pid]);
492 
493  // We need to get the new pid for each node from the processor
494  // which *currently* owns the node. We can safely skip ourself
495  for (node_it = mesh.nodes_begin(); node_it != node_end; ++node_it)
496  {
497  Node *node = *node_it;
498  libmesh_assert(node);
499  const processor_id_type current_pid = node->processor_id();
500  if (current_pid != mesh.processor_id() &&
501  current_pid != DofObject::invalid_processor_id)
502  {
503  libmesh_assert_less (current_pid, requested_node_ids.size());
504  libmesh_assert_less (requested_node_ids[current_pid].size(),
505  ghost_nodes_from_proc[current_pid]);
506  requested_node_ids[current_pid].push_back(node->id());
507  }
508 
509  // Unset any previously-set node processor ids
510  node->invalidate_processor_id();
511  }
512 
513  // Loop over all the active elements
514  MeshBase::element_iterator elem_it = mesh.active_elements_begin();
515  const MeshBase::element_iterator elem_end = mesh.active_elements_end();
516 
517  for ( ; elem_it != elem_end; ++elem_it)
518  {
519  Elem* elem = *elem_it;
520  libmesh_assert(elem);
521 
522  libmesh_assert_not_equal_to (elem->processor_id(), DofObject::invalid_processor_id);
523 
524  // For each node, set the processor ID to the min of
525  // its current value and this Element's processor id.
526  //
527  // TODO: we would probably get better parallel partitioning if
528  // we did something like "min for even numbered nodes, max for
529  // odd numbered". We'd need to be careful about how that would
530  // affect solution ordering for I/O, though.
531  for (unsigned int n=0; n<elem->n_nodes(); ++n)
532  elem->get_node(n)->processor_id() = std::min(elem->get_node(n)->processor_id(),
533  elem->processor_id());
534  }
535 
536  // And loop over the subactive elements, but don't reassign
537  // nodes that are already active on another processor.
538  MeshBase::element_iterator sub_it = mesh.subactive_elements_begin();
539  const MeshBase::element_iterator sub_end = mesh.subactive_elements_end();
540 
541  for ( ; sub_it != sub_end; ++sub_it)
542  {
543  Elem* elem = *sub_it;
544  libmesh_assert(elem);
545 
546  libmesh_assert_not_equal_to (elem->processor_id(), DofObject::invalid_processor_id);
547 
548  for (unsigned int n=0; n<elem->n_nodes(); ++n)
549  if (elem->get_node(n)->processor_id() == DofObject::invalid_processor_id)
550  elem->get_node(n)->processor_id() = elem->processor_id();
551  }
552 
553  // Same for the inactive elements -- we will have already gotten most of these
554  // nodes, *except* for the case of a parent with a subset of children which are
555  // ghost elements. In that case some of the parent nodes will not have been
556  // properly handled yet
557  MeshBase::element_iterator not_it = mesh.not_active_elements_begin();
558  const MeshBase::element_iterator not_end = mesh.not_active_elements_end();
559 
560  for ( ; not_it != not_end; ++not_it)
561  {
562  Elem* elem = *not_it;
563  libmesh_assert(elem);
564 
565  libmesh_assert_not_equal_to (elem->processor_id(), DofObject::invalid_processor_id);
566 
567  for (unsigned int n=0; n<elem->n_nodes(); ++n)
568  if (elem->get_node(n)->processor_id() == DofObject::invalid_processor_id)
569  elem->get_node(n)->processor_id() = elem->processor_id();
570  }
571 
572  // We can't assert that all nodes are connected to elements, because
573  // a ParallelMesh with NodeConstraints might have pulled in some
574  // remote nodes solely for evaluating those constraints.
575  // MeshTools::libmesh_assert_connected_nodes(mesh);
576 
577  // For such nodes, we'll do a sanity check later when making sure
578  // that we successfully reset their processor ids to something
579  // valid.
580 
581  // Next set node ids from other processors, excluding self
582  for (processor_id_type p=1; p != mesh.n_processors(); ++p)
583  {
584  // Trade my requests with processor procup and procdown
585  processor_id_type procup = (mesh.processor_id() + p) %
586  mesh.n_processors();
587  processor_id_type procdown = (mesh.n_processors() +
588  mesh.processor_id() - p) %
589  mesh.n_processors();
590  std::vector<dof_id_type> request_to_fill;
591  mesh.comm().send_receive(procup, requested_node_ids[procup],
592  procdown, request_to_fill);
593 
594  // Fill those requests in-place
595  for (std::size_t i=0; i != request_to_fill.size(); ++i)
596  {
597  Node *node = mesh.node_ptr(request_to_fill[i]);
598  libmesh_assert(node);
599  const processor_id_type new_pid = node->processor_id();
600  libmesh_assert_not_equal_to (new_pid, DofObject::invalid_processor_id);
601  libmesh_assert_less (new_pid, mesh.n_partitions()); // this is the correct test --
602  request_to_fill[i] = new_pid; // the number of partitions may
603  } // not equal the number of processors
604 
605  // Trade back the results
606  std::vector<dof_id_type> filled_request;
607  mesh.comm().send_receive(procdown, request_to_fill,
608  procup, filled_request);
609  libmesh_assert_equal_to (filled_request.size(), requested_node_ids[procup].size());
610 
611  // And copy the id changes we've now been informed of
612  for (std::size_t i=0; i != filled_request.size(); ++i)
613  {
614  Node *node = mesh.node_ptr(requested_node_ids[procup][i]);
615  libmesh_assert(node);
616  libmesh_assert_less (filled_request[i], mesh.n_partitions()); // this is the correct test --
617  node->processor_id(filled_request[i]); // the number of partitions may
618  } // not equal the number of processors
619  }
620 
621 #ifdef DEBUG
623 #endif
624 
625  STOP_LOG("set_node_processor_ids()","Partitioner");
626 }
void libMesh::Partitioner::set_parent_processor_ids ( MeshBase mesh)
staticinherited

This function is called after partitioning to set the processor IDs for the inactive parent elements. A Parent's processor ID is the same as its first child.

Definition at line 261 of file partitioner.C.

References libMesh::Elem::active_family_tree(), libMesh::Elem::child(), libMesh::Partitioner::communication_blocksize, end, libMesh::DofObject::id(), libMesh::DofObject::invalid_processor_id, libMesh::DofObject::invalidate_processor_id(), libMesh::Elem::is_remote(), libMesh::libmesh_assert(), libMesh::libmesh_parallel_only(), mesh, std::min(), libMesh::Elem::n_children(), libMesh::MeshTools::n_elem(), libMesh::Elem::parent(), libMesh::processor_id(), libMesh::DofObject::processor_id(), libMesh::START_LOG(), libMesh::STOP_LOG(), and libMesh::Elem::total_family_tree().

Referenced by libMesh::Partitioner::partition(), and libMesh::Partitioner::repartition().

266 {
267  START_LOG("set_parent_processor_ids()","Partitioner");
268 
269 #ifdef LIBMESH_ENABLE_AMR
270 
271  // If the mesh is serial we have access to all the elements,
272  // in particular all the active ones. We can therefore set
273  // the parent processor ids indirecly through their children, and
274  // set the subactive processor ids while examining their active
275  // ancestors.
276  // By convention a parent is assigned to the minimum processor
277  // of all its children, and a subactive is assigned to the processor
278  // of its active ancestor.
279  if (mesh.is_serial())
280  {
281  // Loop over all the active elements in the mesh
282  MeshBase::element_iterator it = mesh.active_elements_begin();
283  const MeshBase::element_iterator end = mesh.active_elements_end();
284 
285  for ( ; it!=end; ++it)
286  {
287  Elem *child = *it;
288 
289  // First set descendents
290 
291  std::vector<const Elem*> subactive_family;
292  child->total_family_tree(subactive_family);
293  for (unsigned int i = 0; i != subactive_family.size(); ++i)
294  const_cast<Elem*>(subactive_family[i])->processor_id() = child->processor_id();
295 
296  // Then set ancestors
297 
298  Elem *parent = child->parent();
299 
300  while (parent)
301  {
302  // invalidate the parent id, otherwise the min below
303  // will not work if the current parent id is less
304  // than all the children!
305  parent->invalidate_processor_id();
306 
307  for(unsigned int c=0; c<parent->n_children(); c++)
308  {
309  child = parent->child(c);
310  libmesh_assert(child);
311  libmesh_assert(!child->is_remote());
312  libmesh_assert_not_equal_to (child->processor_id(), DofObject::invalid_processor_id);
313  parent->processor_id() = std::min(parent->processor_id(),
314  child->processor_id());
315  }
316  parent = parent->parent();
317  }
318  }
319  }
320 
321  // When the mesh is parallel we cannot guarantee that parents have access to
322  // all their children.
323  else
324  {
325  // Setting subactive processor ids is easy: we can guarantee
326  // that children have access to all their parents.
327 
328  // Loop over all the active elements in the mesh
329  MeshBase::element_iterator it = mesh.active_elements_begin();
330  const MeshBase::element_iterator end = mesh.active_elements_end();
331 
332  for ( ; it!=end; ++it)
333  {
334  Elem *child = *it;
335 
336  std::vector<const Elem*> subactive_family;
337  child->total_family_tree(subactive_family);
338  for (unsigned int i = 0; i != subactive_family.size(); ++i)
339  const_cast<Elem*>(subactive_family[i])->processor_id() = child->processor_id();
340  }
341 
342  // When the mesh is parallel we cannot guarantee that parents have access to
343  // all their children.
344 
345  // We will use a brute-force approach here. Each processor finds its parent
346  // elements and sets the parent pid to the minimum of its
347  // semilocal descendants.
348  // A global reduction is then performed to make sure the true minimum is found.
349  // As noted, this is required because we cannot guarantee that a parent has
350  // access to all its children on any single processor.
351  libmesh_parallel_only(mesh.comm());
352  libmesh_assert(MeshTools::n_elem(mesh.unpartitioned_elements_begin(),
353  mesh.unpartitioned_elements_end()) == 0);
354 
355  const dof_id_type max_elem_id = mesh.max_elem_id();
356 
357  std::vector<processor_id_type>
358  parent_processor_ids (std::min(communication_blocksize,
359  max_elem_id));
360 
361  for (dof_id_type blk=0, last_elem_id=0; last_elem_id<max_elem_id; blk++)
362  {
363  last_elem_id =
364  std::min(static_cast<dof_id_type>((blk+1)*communication_blocksize),
365  max_elem_id);
366  const dof_id_type first_elem_id = blk*communication_blocksize;
367 
368  std::fill (parent_processor_ids.begin(),
369  parent_processor_ids.end(),
371 
372  // first build up local contributions to parent_processor_ids
373  MeshBase::element_iterator not_it = mesh.ancestor_elements_begin();
374  const MeshBase::element_iterator not_end = mesh.ancestor_elements_end();
375 
376  bool have_parent_in_block = false;
377 
378  for ( ; not_it != not_end; ++not_it)
379  {
380  Elem *parent = *not_it;
381 
382  const dof_id_type parent_idx = parent->id();
383  libmesh_assert_less (parent_idx, max_elem_id);
384 
385  if ((parent_idx >= first_elem_id) &&
386  (parent_idx < last_elem_id))
387  {
388  have_parent_in_block = true;
390 
391  std::vector<const Elem*> active_family;
392  parent->active_family_tree(active_family);
393  for (unsigned int i = 0; i != active_family.size(); ++i)
394  parent_pid = std::min (parent_pid, active_family[i]->processor_id());
395 
396  const dof_id_type packed_idx = parent_idx - first_elem_id;
397  libmesh_assert_less (packed_idx, parent_processor_ids.size());
398 
399  parent_processor_ids[packed_idx] = parent_pid;
400  }
401  }
402 
403  // then find the global minimum
404  mesh.comm().min (parent_processor_ids);
405 
406  // and assign the ids, if we have a parent in this block.
407  if (have_parent_in_block)
408  for (not_it = mesh.ancestor_elements_begin();
409  not_it != not_end; ++not_it)
410  {
411  Elem *parent = *not_it;
412 
413  const dof_id_type parent_idx = parent->id();
414 
415  if ((parent_idx >= first_elem_id) &&
416  (parent_idx < last_elem_id))
417  {
418  const dof_id_type packed_idx = parent_idx - first_elem_id;
419  libmesh_assert_less (packed_idx, parent_processor_ids.size());
420 
421  const processor_id_type parent_pid =
422  parent_processor_ids[packed_idx];
423 
424  libmesh_assert_not_equal_to (parent_pid, DofObject::invalid_processor_id);
425 
426  parent->processor_id() = parent_pid;
427  }
428  }
429  }
430  }
431 
432 #endif // LIBMESH_ENABLE_AMR
433 
434  STOP_LOG("set_parent_processor_ids()","Partitioner");
435 }
void libMesh::SFCPartitioner::set_sfc_type ( const std::string &  sfc_type)
inlineinherited

Sets the type of space-filling curve to use. Valid types are "Hilbert" (the default) and "Morton"

Definition at line 94 of file sfc_partitioner.h.

References libMesh::SFCPartitioner::_sfc_type, and libMesh::libmesh_assert().

Referenced by HilbertSFCPartitioner(), and libMesh::MortonSFCPartitioner::MortonSFCPartitioner().

95 {
96  libmesh_assert ((sfc_type == "Hilbert") ||
97  (sfc_type == "Morton"));
98 
99  _sfc_type = sfc_type;
100 }
void libMesh::Partitioner::single_partition ( MeshBase mesh)
protectedinherited

Trivially "partitions" the mesh for one processor. Simply loops through the elements and assigns all of them to processor 0. Is is provided as a separate function so that derived classes may use it without reimplementing it.

Definition at line 157 of file partitioner.C.

References libMesh::MeshBase::elements_begin(), libMesh::MeshBase::elements_end(), libMesh::MeshBase::nodes_begin(), libMesh::MeshBase::nodes_end(), libMesh::START_LOG(), and libMesh::STOP_LOG().

Referenced by libMesh::MetisPartitioner::_do_partition(), libMesh::LinearPartitioner::_do_partition(), libMesh::SFCPartitioner::_do_partition(), libMesh::CentroidPartitioner::_do_partition(), libMesh::ParmetisPartitioner::_do_repartition(), libMesh::Partitioner::partition(), and libMesh::Partitioner::repartition().

158 {
159  START_LOG("single_partition()","Partitioner");
160 
161  // Loop over all the elements and assign them to processor 0.
162  MeshBase::element_iterator elem_it = mesh.elements_begin();
163  const MeshBase::element_iterator elem_end = mesh.elements_end();
164 
165  for ( ; elem_it != elem_end; ++elem_it)
166  (*elem_it)->processor_id() = 0;
167 
168  // For a single partition, all the nodes are on processor 0
169  MeshBase::node_iterator node_it = mesh.nodes_begin();
170  const MeshBase::node_iterator node_end = mesh.nodes_end();
171 
172  for ( ; node_it != node_end; ++node_it)
173  (*node_it)->processor_id() = 0;
174 
175  STOP_LOG("single_partition()","Partitioner");
176 }

Member Data Documentation

ErrorVector* libMesh::Partitioner::_weights
protectedinherited

The weights that might be used for partitioning.

Definition at line 168 of file partitioner.h.

Referenced by libMesh::MetisPartitioner::_do_partition(), and libMesh::MetisPartitioner::attach_weights().

const dof_id_type libMesh::Partitioner::communication_blocksize = 1000000
staticprotectedinherited

The blocksize to use when doing blocked parallel communication. This limits the maximum vector size which can be used in a single communication step.

Definition at line 163 of file partitioner.h.

Referenced by libMesh::Partitioner::set_parent_processor_ids().


The documentation for this class was generated from the following file:

Site Created By: libMesh Developers
Last modified: February 07 2014 16:58:01 UTC

Hosted By:
SourceForge.net Logo