libMesh::SFCPartitioner Class Reference

#include <sfc_partitioner.h>

Inheritance diagram for libMesh::SFCPartitioner:

List of all members.

Public Member Functions

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

Static Public Member Functions

static void partition_unpartitioned_elements (MeshBase &mesh, const unsigned int n=libMesh::n_processors())
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

Private Attributes

std::string _sfc_type

Detailed Description

The SFCPartitioner uses a Hilbert or Morton-ordered space filling curve to partition the elements.

Definition at line 41 of file sfc_partitioner.h.


Constructor & Destructor Documentation

libMesh::SFCPartitioner::SFCPartitioner (  )  [inline]

Constructor. Sets the default space filling curve type to "Hilbert".

Definition at line 49 of file sfc_partitioner.h.

Referenced by clone().

00049                     :
00050     _sfc_type ("Hilbert")
00051   {}


Member Function Documentation

void libMesh::SFCPartitioner::_do_partition ( MeshBase mesh,
const unsigned int  n 
) [protected, virtual]

Partition the MeshBase into n subdomains.

Implements libMesh::Partitioner.

Reimplemented in libMesh::HilbertSFCPartitioner, and libMesh::MortonSFCPartitioner.

Definition at line 45 of file sfc_partitioner.C.

References _sfc_type, libMesh::MeshBase::active_elements_begin(), libMesh::MeshBase::active_elements_end(), libMesh::Elem::centroid(), libMesh::err, libMesh::DofObject::id(), libMesh::invalid_uint, libMesh::MeshBase::n_active_elem(), libMesh::MeshBase::n_elem(), libMesh::MeshTools::n_elem(), libMesh::Partitioner::partition(), and libMesh::Partitioner::single_partition().

00047 {
00048 
00049   libmesh_assert_greater (n, 0);
00050 
00051   // Check for an easy return
00052   if (n == 1)
00053     {
00054       this->single_partition (mesh);
00055       return;
00056     }
00057 
00058 // What to do if the sfcurves library IS NOT present
00059 #ifndef LIBMESH_HAVE_SFCURVES
00060 
00061   libmesh_here();
00062   libMesh::err << "ERROR: The library has been built without"    << std::endl
00063                 << "Space Filling Curve support.  Using a linear" << std::endl
00064                 << "partitioner instead!" << std::endl;
00065 
00066   LinearPartitioner lp;
00067 
00068   lp.partition (mesh, n);
00069 
00070 // What to do if the sfcurves library IS present
00071 #else
00072 
00073   START_LOG("sfc_partition()", "SFCPartitioner");
00074 
00075   const dof_id_type n_active_elem = mesh.n_active_elem();
00076   const dof_id_type n_elem        = mesh.n_elem();
00077 
00078   // the forward_map maps the active element id
00079   // into a contiguous block of indices
00080   std::vector<dof_id_type>
00081     forward_map (n_elem, libMesh::invalid_uint);
00082 
00083   // the reverse_map maps the contiguous ids back
00084   // to active elements
00085   std::vector<Elem*> reverse_map (n_active_elem, NULL);
00086 
00087   int size = static_cast<int>(n_active_elem);
00088   std::vector<double> x      (size);
00089   std::vector<double> y      (size);
00090   std::vector<double> z      (size);
00091   std::vector<int>    table  (size);
00092 
00093 
00094   // We need to map the active element ids into a
00095   // contiguous range.
00096   {
00097 //     active_elem_iterator       elem_it (mesh.elements_begin());
00098 //     const active_elem_iterator elem_end(mesh.elements_end());
00099 
00100     MeshBase::element_iterator       elem_it  = mesh.active_elements_begin();
00101     const MeshBase::element_iterator elem_end = mesh.active_elements_end();
00102 
00103     dof_id_type el_num = 0;
00104 
00105     for (; elem_it != elem_end; ++elem_it)
00106       {
00107         libmesh_assert_less ((*elem_it)->id(), forward_map.size());
00108         libmesh_assert_less (el_num, reverse_map.size());
00109 
00110         forward_map[(*elem_it)->id()] = el_num;
00111         reverse_map[el_num]           = *elem_it;
00112         el_num++;
00113       }
00114     libmesh_assert_equal_to (el_num, n_active_elem);
00115   }
00116 
00117 
00118   // Get the centroid for each active element
00119   {
00120 //     const_active_elem_iterator       elem_it (mesh.const_elements_begin());
00121 //     const const_active_elem_iterator elem_end(mesh.const_elements_end());
00122 
00123     MeshBase::element_iterator       elem_it  = mesh.active_elements_begin();
00124     const MeshBase::element_iterator elem_end = mesh.active_elements_end();
00125 
00126     for (; elem_it != elem_end; ++elem_it)
00127       {
00128         const Elem* elem = *elem_it;
00129 
00130         libmesh_assert_less (elem->id(), forward_map.size());
00131 
00132         const Point p = elem->centroid();
00133 
00134         x[forward_map[elem->id()]] = p(0);
00135         y[forward_map[elem->id()]] = p(1);
00136         z[forward_map[elem->id()]] = p(2);
00137       }
00138   }
00139 
00140   // build the space-filling curve
00141   if (_sfc_type == "Hilbert")
00142     Sfc::hilbert (&x[0], &y[0], &z[0], &size, &table[0]);
00143 
00144   else if (_sfc_type == "Morton")
00145     Sfc::morton  (&x[0], &y[0], &z[0], &size, &table[0]);
00146 
00147   else
00148     {
00149       libmesh_here();
00150       libMesh::err << "ERROR: Unknown type: " << _sfc_type << std::endl
00151                     << " Valid types are"                   << std::endl
00152                     << "  \"Hilbert\""                      << std::endl
00153                     << "  \"Morton\""                       << std::endl
00154                     << " "                                  << std::endl
00155                     << "Proceeding with a Hilbert curve."   << std::endl;
00156 
00157       Sfc::hilbert (&x[0], &y[0], &z[0], &size, &table[0]);
00158     }
00159 
00160 
00161   // Assign the partitioning to the active elements
00162   {
00163 //      {
00164 //        std::ofstream out ("sfc.dat");
00165 //        out << "variables=x,y,z" << std::endl;
00166 //        out << "zone f=point" << std::endl;
00167 
00168 //        for (unsigned int i=0; i<n_active_elem; i++)
00169 //      out << x[i] << " "
00170 //          << y[i] << " "
00171 //          << z[i] << std::endl;
00172 //      }
00173 
00174     const dof_id_type blksize = (n_active_elem+n-1)/n;
00175 
00176     for (dof_id_type i=0; i<n_active_elem; i++)
00177       {
00178         libmesh_assert_less (static_cast<unsigned int>(table[i]-1), reverse_map.size());
00179 
00180         Elem* elem = reverse_map[table[i]-1];
00181 
00182         elem->processor_id() = libmesh_cast_int<processor_id_type>
00183           (i/blksize);
00184       }
00185   }
00186 
00187   STOP_LOG("sfc_partition()", "SFCPartitioner");
00188 
00189 #endif
00190 
00191 }

virtual void libMesh::Partitioner::_do_repartition ( MeshBase mesh,
const unsigned int  n 
) [inline, protected, virtual, inherited]

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 143 of file partitioner.h.

References libMesh::Partitioner::_do_partition().

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

00144                                                       { this->_do_partition (mesh, n); }

virtual void libMesh::Partitioner::attach_weights ( ErrorVector  )  [inline, virtual, inherited]

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 118 of file partitioner.h.

00118 { libmesh_not_implemented(); }

virtual AutoPtr<Partitioner> libMesh::SFCPartitioner::clone (  )  const [inline, virtual]

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

Implements libMesh::Partitioner.

Reimplemented in libMesh::HilbertSFCPartitioner, and libMesh::MortonSFCPartitioner.

Definition at line 57 of file sfc_partitioner.h.

References SFCPartitioner().

00057                                               {
00058     AutoPtr<Partitioner> cloned_partitioner
00059       (new SFCPartitioner());
00060     return cloned_partitioner;
00061   }

void libMesh::Partitioner::partition ( MeshBase mesh,
const unsigned int  n = libMesh::n_processors() 
) [inherited]

Partition the MeshBase into n parts. If the user does not specify a number of pieces into which the mesh should be partitioned, then the default behavior of the partitioner is to partition according to the number of processors defined in libMesh::n_processors(). 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::Partitioner::_do_partition(), libMesh::MeshTools::libmesh_assert_valid_procids< Elem >(), libMesh::MeshTools::libmesh_assert_valid_remote_elems(), 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 _do_partition(), libMesh::MetisPartitioner::_do_partition(), and libMesh::ParmetisPartitioner::_do_repartition().

00050 {
00051   parallel_only();
00052 
00053   // BSK - temporary fix while redistribution is integrated 6/26/2008
00054   // Uncomment this to not repartition in parallel
00055 //   if (!mesh.is_serial())
00056 //     return;
00057 
00058   // we cannot partition into more pieces than we have
00059   // active elements!
00060   const unsigned int n_parts =
00061     static_cast<unsigned int>
00062       (std::min(mesh.n_active_elem(), static_cast<dof_id_type>(n)));
00063 
00064   // Set the number of partitions in the mesh
00065   mesh.set_n_partitions()=n_parts;
00066 
00067   if (n_parts == 1)
00068     {
00069       this->single_partition (mesh);
00070       return;
00071     }
00072 
00073   // First assign a temporary partitioning to any unpartitioned elements
00074   Partitioner::partition_unpartitioned_elements(mesh, n_parts);
00075 
00076   // Call the partitioning function
00077   this->_do_partition(mesh,n_parts);
00078 
00079   // Set the parent's processor ids
00080   Partitioner::set_parent_processor_ids(mesh);
00081 
00082   // Redistribute elements if necessary, before setting node processor
00083   // ids, to make sure those will be set consistently
00084   mesh.redistribute();
00085 
00086 #ifdef DEBUG
00087   MeshTools::libmesh_assert_valid_remote_elems(mesh);
00088 
00089   // Messed up elem processor_id()s can leave us without the child
00090   // elements we need to restrict vectors on a distributed mesh
00091   MeshTools::libmesh_assert_valid_procids<Elem>(mesh);
00092 #endif
00093 
00094   // Set the node's processor ids
00095   Partitioner::set_node_processor_ids(mesh);
00096 
00097 #ifdef DEBUG
00098   MeshTools::libmesh_assert_valid_procids<Elem>(mesh);
00099 #endif
00100 
00101   // Give derived Mesh classes a chance to update any cached data to
00102   // reflect the new partitioning
00103   mesh.update_post_partitioning();
00104 }

void libMesh::Partitioner::partition_unpartitioned_elements ( MeshBase mesh,
const unsigned int  n = libMesh::n_processors() 
) [static, inherited]

This function

Definition at line 168 of file partitioner.C.

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

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

00170 {
00171   MeshBase::element_iterator       it  = mesh.unpartitioned_elements_begin();
00172   const MeshBase::element_iterator end = mesh.unpartitioned_elements_end();
00173 
00174   const dof_id_type n_unpartitioned_elements = MeshTools::n_elem (it, end);
00175 
00176   // the unpartitioned elements must exist on all processors. If the range is empty on one
00177   // it is empty on all, and we can quit right here.
00178   if (!n_unpartitioned_elements) return;
00179 
00180   // find the target subdomain sizes
00181   std::vector<dof_id_type> subdomain_bounds(libMesh::n_processors());
00182 
00183   for (processor_id_type pid=0; pid<libMesh::n_processors(); pid++)
00184     {
00185       dof_id_type tgt_subdomain_size = 0;
00186 
00187       // watch out for the case that n_subdomains < n_processors
00188       if (pid < n_subdomains)
00189         {
00190           tgt_subdomain_size = n_unpartitioned_elements/n_subdomains;
00191 
00192           if (pid < n_unpartitioned_elements%n_subdomains)
00193             tgt_subdomain_size++;
00194 
00195         }
00196 
00197       //libMesh::out << "pid, #= " << pid << ", " << tgt_subdomain_size << std::endl;
00198       if (pid == 0)
00199         subdomain_bounds[0] = tgt_subdomain_size;
00200       else
00201         subdomain_bounds[pid] = subdomain_bounds[pid-1] + tgt_subdomain_size;
00202     }
00203 
00204   libmesh_assert_equal_to (subdomain_bounds.back(), n_unpartitioned_elements);
00205 
00206   // create the unique mapping for all unpartitioned elements independent of partitioning
00207   // determine the global indexing for all the unpartitoned elements
00208   std::vector<dof_id_type> global_indices;
00209 
00210   // Calling this on all processors a unique range in [0,n_unpartitioned_elements) is constructed.
00211   // Only the indices for the elements we pass in are returned in the array.
00212   MeshCommunication().find_global_indices (MeshTools::bounding_box(mesh), it, end,
00213                                            global_indices);
00214 
00215   for (dof_id_type cnt=0; it != end; ++it)
00216     {
00217       Elem *elem = *it;
00218 
00219       libmesh_assert_less (cnt, global_indices.size());
00220       const dof_id_type global_index =
00221         global_indices[cnt++];
00222 
00223       libmesh_assert_less (global_index, subdomain_bounds.back());
00224       libmesh_assert_less (global_index, n_unpartitioned_elements);
00225 
00226       const processor_id_type subdomain_id =
00227         libmesh_cast_int<processor_id_type>
00228         (std::distance(subdomain_bounds.begin(),
00229                        std::upper_bound(subdomain_bounds.begin(),
00230                                         subdomain_bounds.end(),
00231                                         global_index)));
00232       libmesh_assert_less (subdomain_id, n_subdomains);
00233 
00234       elem->processor_id() = subdomain_id;
00235       //libMesh::out << "assigning " << global_index << " to " << subdomain_id << std::endl;
00236     }
00237 }

void libMesh::Partitioner::repartition ( MeshBase mesh,
const unsigned int  n = libMesh::n_processors() 
) [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(n)

Definition at line 110 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().

00112 {
00113   // we cannot partition into more pieces than we have
00114   // active elements!
00115   const unsigned int n_parts =
00116     static_cast<unsigned int>
00117       (std::min(mesh.n_active_elem(), static_cast<dof_id_type>(n)));
00118 
00119   // Set the number of partitions in the mesh
00120   mesh.set_n_partitions()=n_parts;
00121 
00122   if (n_parts == 1)
00123     {
00124       this->single_partition (mesh);
00125       return;
00126     }
00127 
00128   // First assign a temporary partitioning to any unpartitioned elements
00129   Partitioner::partition_unpartitioned_elements(mesh, n_parts);
00130 
00131   // Call the partitioning function
00132   this->_do_repartition(mesh,n_parts);
00133 
00134   // Set the parent's processor ids
00135   Partitioner::set_parent_processor_ids(mesh);
00136 
00137   // Set the node's processor ids
00138   Partitioner::set_node_processor_ids(mesh);
00139 }

void libMesh::Partitioner::set_node_processor_ids ( MeshBase mesh  )  [static, inherited]

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 419 of file partitioner.C.

References libMesh::MeshBase::active_elements_begin(), libMesh::MeshBase::active_elements_end(), libMesh::CommWorld, libMesh::Elem::get_node(), libMesh::DofObject::id(), libMesh::DofObject::invalid_processor_id, libMesh::DofObject::invalidate_processor_id(), libMesh::MeshTools::libmesh_assert_valid_procids< Node >(), std::min(), libMesh::MeshTools::n_elem(), libMesh::Elem::n_nodes(), libMesh::MeshBase::n_partitions(), libMesh::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::processor_id(), libMesh::DofObject::processor_id(), libMesh::Parallel::Communicator::send_receive(), 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().

00420 {
00421   START_LOG("set_node_processor_ids()","Partitioner");
00422 
00423   // This function must be run on all processors at once
00424   parallel_only();
00425 
00426   // If we have any unpartitioned elements at this
00427   // stage there is a problem
00428   libmesh_assert (MeshTools::n_elem(mesh.unpartitioned_elements_begin(),
00429                             mesh.unpartitioned_elements_end()) == 0);
00430 
00431 
00432 //   const dof_id_type orig_n_local_nodes = mesh.n_local_nodes();
00433 
00434 //   libMesh::err << "[" << libMesh::processor_id() << "]: orig_n_local_nodes="
00435 //          << orig_n_local_nodes << std::endl;
00436 
00437   // Build up request sets.  Each node is currently owned by a processor because
00438   // it is connected to an element owned by that processor.  However, during the
00439   // repartitioning phase that element may have been assigned a new processor id, but
00440   // it is still resident on the original processor.  We need to know where to look
00441   // for new ids before assigning new ids, otherwise we may be asking the wrong processors
00442   // for the wrong information.
00443   //
00444   // The only remaining issue is what to do with unpartitioned nodes.  Since they are required
00445   // to live on all processors we can simply rely on ourselves to number them properly.
00446   std::vector<std::vector<dof_id_type> >
00447     requested_node_ids(libMesh::n_processors());
00448 
00449   // Loop over all the nodes, count the ones on each processor.  We can skip ourself
00450   std::vector<dof_id_type> ghost_nodes_from_proc(libMesh::n_processors(), 0);
00451 
00452   MeshBase::node_iterator       node_it  = mesh.nodes_begin();
00453   const MeshBase::node_iterator node_end = mesh.nodes_end();
00454 
00455   for (; node_it != node_end; ++node_it)
00456     {
00457       Node *node = *node_it;
00458       libmesh_assert(node);
00459       const processor_id_type current_pid = node->processor_id();
00460       if (current_pid != libMesh::processor_id() &&
00461           current_pid != DofObject::invalid_processor_id)
00462         {
00463           libmesh_assert_less (current_pid, ghost_nodes_from_proc.size());
00464           ghost_nodes_from_proc[current_pid]++;
00465         }
00466     }
00467 
00468   // We know how many objects live on each processor, so reserve()
00469   // space for each.
00470   for (processor_id_type pid=0; pid != libMesh::n_processors(); ++pid)
00471     requested_node_ids[pid].reserve(ghost_nodes_from_proc[pid]);
00472 
00473   // We need to get the new pid for each node from the processor
00474   // which *currently* owns the node.  We can safely skip ourself
00475   for (node_it = mesh.nodes_begin(); node_it != node_end; ++node_it)
00476     {
00477       Node *node = *node_it;
00478       libmesh_assert(node);
00479       const processor_id_type current_pid = node->processor_id();
00480       if (current_pid != libMesh::processor_id() &&
00481           current_pid != DofObject::invalid_processor_id)
00482         {
00483           libmesh_assert_less (current_pid, requested_node_ids.size());
00484           libmesh_assert_less (requested_node_ids[current_pid].size(),
00485                               ghost_nodes_from_proc[current_pid]);
00486           requested_node_ids[current_pid].push_back(node->id());
00487         }
00488 
00489       // Unset any previously-set node processor ids
00490       node->invalidate_processor_id();
00491     }
00492 
00493   // Loop over all the active elements
00494   MeshBase::element_iterator       elem_it  = mesh.active_elements_begin();
00495   const MeshBase::element_iterator elem_end = mesh.active_elements_end();
00496 
00497   for ( ; elem_it != elem_end; ++elem_it)
00498     {
00499       Elem* elem = *elem_it;
00500       libmesh_assert(elem);
00501 
00502       libmesh_assert_not_equal_to (elem->processor_id(), DofObject::invalid_processor_id);
00503 
00504       // For each node, set the processor ID to the min of
00505       // its current value and this Element's processor id.
00506       //
00507       // TODO: we would probably get better parallel partitioning if
00508       // we did something like "min for even numbered nodes, max for
00509       // odd numbered".  We'd need to be careful about how that would
00510       // affect solution ordering for I/O, though.
00511       for (unsigned int n=0; n<elem->n_nodes(); ++n)
00512         elem->get_node(n)->processor_id() = std::min(elem->get_node(n)->processor_id(),
00513                                                      elem->processor_id());
00514     }
00515 
00516   // And loop over the subactive elements, but don't reassign
00517   // nodes that are already active on another processor.
00518   MeshBase::element_iterator       sub_it  = mesh.subactive_elements_begin();
00519   const MeshBase::element_iterator sub_end = mesh.subactive_elements_end();
00520 
00521   for ( ; sub_it != sub_end; ++sub_it)
00522     {
00523       Elem* elem = *sub_it;
00524       libmesh_assert(elem);
00525 
00526       libmesh_assert_not_equal_to (elem->processor_id(), DofObject::invalid_processor_id);
00527 
00528       for (unsigned int n=0; n<elem->n_nodes(); ++n)
00529         if (elem->get_node(n)->processor_id() == DofObject::invalid_processor_id)
00530           elem->get_node(n)->processor_id() = elem->processor_id();
00531     }
00532 
00533   // Same for the inactive elements -- we will have already gotten most of these
00534   // nodes, *except* for the case of a parent with a subset of children which are
00535   // ghost elements.  In that case some of the parent nodes will not have been
00536   // properly handled yet
00537   MeshBase::element_iterator       not_it  = mesh.not_active_elements_begin();
00538   const MeshBase::element_iterator not_end = mesh.not_active_elements_end();
00539 
00540   for ( ; not_it != not_end; ++not_it)
00541     {
00542       Elem* elem = *not_it;
00543       libmesh_assert(elem);
00544 
00545       libmesh_assert_not_equal_to (elem->processor_id(), DofObject::invalid_processor_id);
00546 
00547       for (unsigned int n=0; n<elem->n_nodes(); ++n)
00548         if (elem->get_node(n)->processor_id() == DofObject::invalid_processor_id)
00549           elem->get_node(n)->processor_id() = elem->processor_id();
00550     }
00551 
00552   // We can't assert that all nodes are connected to elements, because
00553   // a ParallelMesh with NodeConstraints might have pulled in some
00554   // remote nodes solely for evaluating those constraints.
00555   // MeshTools::libmesh_assert_connected_nodes(mesh);
00556 
00557   // For such nodes, we'll do a sanity check later when making sure
00558   // that we successfully reset their processor ids to something
00559   // valid.
00560 
00561   // Next set node ids from other processors, excluding self
00562   for (processor_id_type p=1; p != libMesh::n_processors(); ++p)
00563     {
00564       // Trade my requests with processor procup and procdown
00565       processor_id_type procup = (libMesh::processor_id() + p) %
00566                                   libMesh::n_processors();
00567       processor_id_type procdown = (libMesh::n_processors() +
00568                                     libMesh::processor_id() - p) %
00569                                     libMesh::n_processors();
00570       std::vector<dof_id_type> request_to_fill;
00571       CommWorld.send_receive(procup, requested_node_ids[procup],
00572                              procdown, request_to_fill);
00573 
00574       // Fill those requests in-place
00575       for (std::size_t i=0; i != request_to_fill.size(); ++i)
00576         {
00577           Node *node = mesh.node_ptr(request_to_fill[i]);
00578           libmesh_assert(node);
00579           const processor_id_type new_pid = node->processor_id();
00580           libmesh_assert_not_equal_to (new_pid, DofObject::invalid_processor_id);
00581           libmesh_assert_less (new_pid, mesh.n_partitions()); // this is the correct test --
00582           request_to_fill[i] = new_pid;           //  the number of partitions may
00583         }                                         //  not equal the number of processors
00584 
00585       // Trade back the results
00586       std::vector<dof_id_type> filled_request;
00587       CommWorld.send_receive(procdown, request_to_fill,
00588                              procup,   filled_request);
00589       libmesh_assert_equal_to (filled_request.size(), requested_node_ids[procup].size());
00590 
00591       // And copy the id changes we've now been informed of
00592       for (std::size_t i=0; i != filled_request.size(); ++i)
00593         {
00594           Node *node = mesh.node_ptr(requested_node_ids[procup][i]);
00595           libmesh_assert(node);
00596           libmesh_assert_less (filled_request[i], mesh.n_partitions()); // this is the correct test --
00597           node->processor_id(filled_request[i]);           //  the number of partitions may
00598         }                                                  //  not equal the number of processors
00599     }
00600 
00601 #ifdef DEBUG
00602   MeshTools::libmesh_assert_valid_procids<Node>(mesh);
00603 #endif
00604 
00605   STOP_LOG("set_node_processor_ids()","Partitioner");
00606 }

static void libMesh::Partitioner::set_parent_processor_ids ( MeshBase mesh  )  [static, inherited]

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.

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

void libMesh::SFCPartitioner::set_sfc_type ( const std::string &  sfc_type  )  [inline]

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 _sfc_type.

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

00095 {
00096   libmesh_assert ((sfc_type == "Hilbert") ||
00097           (sfc_type == "Morton"));
00098 
00099   _sfc_type = sfc_type;
00100 }

void libMesh::Partitioner::single_partition ( MeshBase mesh  )  [protected, inherited]

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 145 of file partitioner.C.

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

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

00146 {
00147   START_LOG("single_partition()","Partitioner");
00148 
00149   // Loop over all the elements and assign them to processor 0.
00150   MeshBase::element_iterator       elem_it  = mesh.elements_begin();
00151   const MeshBase::element_iterator elem_end = mesh.elements_end();
00152 
00153   for ( ; elem_it != elem_end; ++elem_it)
00154     (*elem_it)->processor_id() = 0;
00155 
00156   // For a single partition, all the nodes are on processor 0
00157   MeshBase::node_iterator       node_it  = mesh.nodes_begin();
00158   const MeshBase::node_iterator node_end = mesh.nodes_end();
00159 
00160   for ( ; node_it != node_end; ++node_it)
00161     (*node_it)->processor_id() = 0;
00162 
00163   STOP_LOG("single_partition()","Partitioner");
00164 }


Member Data Documentation

std::string libMesh::SFCPartitioner::_sfc_type [private]

The type of space-filling curve to use. Hilbert by default.

Definition at line 85 of file sfc_partitioner.h.

Referenced by _do_partition(), and set_sfc_type().

The weights that might be used for partitioning.

Definition at line 155 of file partitioner.h.

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

const dof_id_type libMesh::Partitioner::communication_blocksize = 1000000 [static, protected, inherited]

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 150 of file partitioner.h.


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

Site Created By: libMesh Developers
Last modified: February 05 2013 19:55:38 UTC

Hosted By:
SourceForge.net Logo