$extrastylesheet
parallel_elem.C
Go to the documentation of this file.
00001 // The libMesh Finite Element Library.
00002 // Copyright (C) 2002-2014 Benjamin S. Kirk, John W. Peterson, Roy H. Stogner
00003 
00004 // This library is free software; you can redistribute it and/or
00005 // modify it under the terms of the GNU Lesser General Public
00006 // License as published by the Free Software Foundation; either
00007 // version 2.1 of the License, or (at your option) any later version.
00008 
00009 // This library is distributed in the hope that it will be useful,
00010 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00011 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00012 // Lesser General Public License for more details.
00013 
00014 // You should have received a copy of the GNU Lesser General Public
00015 // License along with this library; if not, write to the Free Software
00016 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00017 
00018 
00019 
00020 // C++ includes
00021 
00022 // Local includes
00023 #include "libmesh/boundary_info.h"
00024 #include "libmesh/elem.h"
00025 #include "libmesh/mesh_base.h"
00026 #include "libmesh/parallel.h"
00027 #include "libmesh/parallel_mesh.h"
00028 #include "libmesh/remote_elem.h"
00029 
00030 // Helper functions in anonymous namespace
00031 
00032 namespace
00033 {
00034 using namespace libMesh;
00035 
00036 #ifdef LIBMESH_ENABLE_UNIQUE_ID
00037 static const unsigned int header_size = 11;
00038 #else
00039 static const unsigned int header_size = 10;
00040 #endif
00041 
00042 static const largest_id_type elem_magic_header = 987654321;
00043 }
00044 
00045 
00046 namespace libMesh
00047 {
00048 
00049 #ifdef LIBMESH_HAVE_MPI
00050 
00051 namespace Parallel
00052 {
00053 
00054 template <>
00055 unsigned int packed_size (const Elem*,
00056                           std::vector<largest_id_type>::const_iterator in)
00057 {
00058 #ifndef NDEBUG
00059   const largest_id_type packed_header = *in++;
00060   libmesh_assert_equal_to (packed_header, elem_magic_header);
00061 #endif
00062 
00063   // int 0: level
00064   const unsigned int level =
00065     cast_int<unsigned int>(*in);
00066 
00067   // int 4: element type
00068   const int typeint = cast_int<int>(*(in+4));
00069   libmesh_assert_greater_equal (typeint, 0);
00070   libmesh_assert_less (typeint, INVALID_ELEM);
00071   const ElemType type =
00072     cast_int<ElemType>(typeint);
00073 
00074   const unsigned int n_nodes =
00075     Elem::type_to_n_nodes_map[type];
00076 
00077   const unsigned int n_sides =
00078     Elem::type_to_n_sides_map[type];
00079 
00080   const unsigned int n_edges =
00081     Elem::type_to_n_edges_map[type];
00082 
00083   const unsigned int pre_indexing_size =
00084     header_size + n_nodes + n_sides;
00085 
00086   const unsigned int indexing_size =
00087     DofObject::unpackable_indexing_size(in+pre_indexing_size);
00088 
00089   unsigned int total_packed_bc_data = 0;
00090   if (level == 0)
00091     {
00092       for (unsigned int s = 0; s != n_sides; ++s)
00093         {
00094           const int n_bcs = cast_int<int>
00095             (*(in + pre_indexing_size + indexing_size +
00096                total_packed_bc_data++));
00097           libmesh_assert_greater_equal (n_bcs, 0);
00098           total_packed_bc_data += n_bcs;
00099         }
00100 
00101       for (unsigned int e = 0; e != n_edges; ++e)
00102         {
00103           const int n_bcs = cast_int<int>
00104             (*(in + pre_indexing_size + indexing_size +
00105                total_packed_bc_data++));
00106           libmesh_assert_greater_equal (n_bcs, 0);
00107           total_packed_bc_data += n_bcs;
00108         }
00109     }
00110 
00111   return
00112 #ifndef NDEBUG
00113     1 + // Account for magic header
00114 #endif
00115     pre_indexing_size + indexing_size + total_packed_bc_data;
00116 }
00117 
00118 
00119 
00120 template <>
00121 unsigned int packed_size (const Elem* e,
00122                           std::vector<largest_id_type>::iterator in)
00123 {
00124   return packed_size(e, std::vector<largest_id_type>::const_iterator(in));
00125 }
00126 
00127 
00128 
00129 template <>
00130 unsigned int packable_size (const Elem* elem, const MeshBase* mesh)
00131 {
00132   unsigned int total_packed_bcs = 0;
00133   if (elem->level() == 0)
00134     {
00135       total_packed_bcs += elem->n_sides();
00136       for (unsigned short s = 0; s != elem->n_sides(); ++s)
00137         total_packed_bcs +=
00138           mesh->get_boundary_info().n_boundary_ids(elem,s);
00139 
00140       total_packed_bcs += elem->n_edges();
00141       for (unsigned short e = 0; e != elem->n_edges(); ++e)
00142         total_packed_bcs +=
00143           mesh->get_boundary_info().n_edge_boundary_ids(elem,e);
00144     }
00145 
00146   return
00147 #ifndef NDEBUG
00148     1 + // add an int for the magic header when testing
00149 #endif
00150     header_size + elem->n_nodes() +
00151     elem->n_neighbors() +
00152     elem->packed_indexing_size() + total_packed_bcs;
00153 }
00154 
00155 
00156 
00157 template <>
00158 unsigned int packable_size (const Elem* elem, const ParallelMesh* mesh)
00159 {
00160   return packable_size(elem, static_cast<const MeshBase*>(mesh));
00161 }
00162 
00163 
00164 
00165 template <>
00166 void pack (const Elem* elem,
00167            std::vector<largest_id_type>& data,
00168            const MeshBase* mesh)
00169 {
00170   libmesh_assert(elem);
00171 
00172   // This should be redundant when used with Parallel::pack_range()
00173   // data.reserve (data.size() + Parallel::packable_size(elem, mesh));
00174 
00175 #ifndef NDEBUG
00176   data.push_back (elem_magic_header);
00177 #endif
00178 
00179 #ifdef LIBMESH_ENABLE_AMR
00180   data.push_back (static_cast<largest_id_type>(elem->level()));
00181   data.push_back (static_cast<largest_id_type>(elem->p_level()));
00182   data.push_back (static_cast<largest_id_type>(elem->refinement_flag()));
00183   data.push_back (static_cast<largest_id_type>(elem->p_refinement_flag()));
00184 #else
00185   data.push_back (0);
00186   data.push_back (0);
00187   data.push_back (0);
00188   data.push_back (0);
00189 #endif
00190   data.push_back (static_cast<largest_id_type>(elem->type()));
00191   data.push_back (elem->processor_id());
00192   data.push_back (elem->subdomain_id());
00193   data.push_back (elem->id());
00194 
00195 #ifdef LIBMESH_ENABLE_UNIQUE_ID
00196   if (elem->valid_unique_id())
00197     data.push_back (static_cast<largest_id_type>(elem->unique_id()));
00198   else
00199     // OK to send invalid unique id, we must not own this DOF
00200     data.push_back (static_cast<largest_id_type>(DofObject::invalid_unique_id));
00201 #endif
00202 
00203 #ifdef LIBMESH_ENABLE_AMR
00204   // use parent_ID of -1 to indicate a level 0 element
00205   if (elem->level() == 0)
00206     {
00207       data.push_back(-1);
00208       data.push_back(-1);
00209     }
00210   else
00211     {
00212       data.push_back(elem->parent()->id());
00213       data.push_back(elem->parent()->which_child_am_i(elem));
00214     }
00215 #else
00216   data.push_back (-1);
00217   data.push_back (-1);
00218 #endif
00219 
00220   for (unsigned int n=0; n<elem->n_nodes(); n++)
00221     data.push_back (elem->node(n));
00222 
00223   for (unsigned int n=0; n<elem->n_neighbors(); n++)
00224     {
00225       const Elem *neigh = elem->neighbor(n);
00226       if (neigh)
00227         data.push_back (neigh->id());
00228       else
00229         data.push_back (-1);
00230     }
00231 
00232 #ifndef NDEBUG
00233   const std::size_t start_indices = data.size();
00234 #endif
00235   // Add any DofObject indices
00236   elem->pack_indexing(std::back_inserter(data));
00237 
00238   libmesh_assert(elem->packed_indexing_size() ==
00239                  DofObject::unpackable_indexing_size(data.begin() +
00240                                                      start_indices));
00241 
00242   libmesh_assert_equal_to (elem->packed_indexing_size(),
00243                            data.size() - start_indices);
00244 
00245 
00246   // If this is a coarse element,
00247   // Add any element side boundary condition ids
00248   if (elem->level() == 0)
00249     {
00250       for (unsigned short s = 0; s != elem->n_sides(); ++s)
00251         {
00252           std::vector<boundary_id_type> bcs =
00253             mesh->get_boundary_info().boundary_ids(elem, s);
00254 
00255           data.push_back(bcs.size());
00256 
00257           for(unsigned int bc_it=0; bc_it < bcs.size(); bc_it++)
00258             data.push_back(bcs[bc_it]);
00259         }
00260 
00261       for (unsigned short e = 0; e != elem->n_edges(); ++e)
00262         {
00263           std::vector<boundary_id_type> bcs =
00264             mesh->get_boundary_info().edge_boundary_ids(elem, e);
00265 
00266           data.push_back(bcs.size());
00267 
00268           for(unsigned int bc_it=0; bc_it < bcs.size(); bc_it++)
00269             data.push_back(bcs[bc_it]);
00270         }
00271     }
00272 }
00273 
00274 
00275 
00276 template <>
00277 void pack (const Elem* elem,
00278            std::vector<largest_id_type>& data,
00279            const ParallelMesh* mesh)
00280 {
00281   pack(elem, data, static_cast<const MeshBase*>(mesh));
00282 }
00283 
00284 
00285 
00286 // FIXME - this needs serious work to be 64-bit compatible
00287 template <>
00288 void unpack(std::vector<largest_id_type>::const_iterator in,
00289             Elem** out,
00290             MeshBase* mesh)
00291 {
00292 #ifndef NDEBUG
00293   const std::vector<largest_id_type>::const_iterator original_in = in;
00294 
00295   const largest_id_type incoming_header = *in++;
00296   libmesh_assert_equal_to (incoming_header, elem_magic_header);
00297 #endif
00298 
00299   // int 0: level
00300   const unsigned int level =
00301     cast_int<unsigned int>(*in++);
00302 
00303 #ifdef LIBMESH_ENABLE_AMR
00304   // int 1: p level
00305   const unsigned int p_level =
00306     cast_int<unsigned int>(*in++);
00307 
00308   // int 2: refinement flag
00309   const int rflag = cast_int<int>(*in++);
00310   libmesh_assert_greater_equal (rflag, 0);
00311   libmesh_assert_less (rflag, Elem::INVALID_REFINEMENTSTATE);
00312   const Elem::RefinementState refinement_flag =
00313     cast_int<Elem::RefinementState>(rflag);
00314 
00315   // int 3: p refinement flag
00316   const int pflag = cast_int<int>(*in++);
00317   libmesh_assert_greater_equal (pflag, 0);
00318   libmesh_assert_less (pflag, Elem::INVALID_REFINEMENTSTATE);
00319   const Elem::RefinementState p_refinement_flag =
00320     cast_int<Elem::RefinementState>(pflag);
00321 #else
00322   in += 3;
00323 #endif // LIBMESH_ENABLE_AMR
00324 
00325   // int 4: element type
00326   const int typeint = cast_int<int>(*in++);
00327   libmesh_assert_greater_equal (typeint, 0);
00328   libmesh_assert_less (typeint, INVALID_ELEM);
00329   const ElemType type =
00330     cast_int<ElemType>(typeint);
00331 
00332   const unsigned int n_nodes =
00333     Elem::type_to_n_nodes_map[type];
00334 
00335   // int 5: processor id
00336   const processor_id_type processor_id =
00337     cast_int<processor_id_type>(*in++);
00338   libmesh_assert (processor_id < mesh->n_processors() ||
00339                   processor_id == DofObject::invalid_processor_id);
00340 
00341   // int 6: subdomain id
00342   const subdomain_id_type subdomain_id =
00343     cast_int<subdomain_id_type>(*in++);
00344 
00345   // int 7: dof object id
00346   const dof_id_type id =
00347     cast_int<dof_id_type>(*in++);
00348   libmesh_assert_not_equal_to (id, DofObject::invalid_id);
00349 
00350 #ifdef LIBMESH_ENABLE_UNIQUE_ID
00351   // int 8: dof object unique id
00352   const unique_id_type unique_id =
00353     cast_int<unique_id_type>(*in++);
00354 #endif
00355 
00356 #ifdef LIBMESH_ENABLE_AMR
00357   // int 9: parent dof object id.
00358   // Note: If level==0, then (*in) == (unsigned long long)(-1).  In
00359   // this case, the equality check in cast_int<unsigned>(*in) will
00360   // never succeed.  Therefore, we should only attempt the more
00361   // rigorous cast verification in cases where level != 0.
00362   const dof_id_type parent_id =
00363     (level == 0)
00364     ? static_cast<dof_id_type>(*in++)
00365     : cast_int<dof_id_type>(*in++);
00366   libmesh_assert (level == 0 || parent_id != DofObject::invalid_id);
00367   libmesh_assert (level != 0 || parent_id == DofObject::invalid_id);
00368 
00369   // int 10: local child id
00370   // Note: If level==0, then which_child_am_i is not valid, so don't
00371   // do the more rigorous cast verification.
00372   const unsigned int which_child_am_i =
00373     (level == 0)
00374     ? static_cast<unsigned int>(*in++)
00375     : cast_int<unsigned int>(*in++);
00376 #else
00377   in += 2;
00378 #endif // LIBMESH_ENABLE_AMR
00379 
00380   // Make sure we don't miscount above when adding the "magic" header
00381   // plus the real data header
00382   libmesh_assert_equal_to (in - original_in, header_size + 1);
00383 
00384   Elem *elem = mesh->query_elem(id);
00385 
00386   // if we already have this element, make sure its
00387   // properties match, and update any missing neighbor
00388   // links, but then go on
00389   if (elem)
00390     {
00391       libmesh_assert_equal_to (elem->level(), level);
00392       libmesh_assert_equal_to (elem->id(), id);
00393       //#ifdef LIBMESH_ENABLE_UNIQUE_ID
00394       // No check for unqiue id sanity
00395       //#endif
00396       libmesh_assert_equal_to (elem->processor_id(), processor_id);
00397       libmesh_assert_equal_to (elem->subdomain_id(), subdomain_id);
00398       libmesh_assert_equal_to (elem->type(), type);
00399       libmesh_assert_equal_to (elem->n_nodes(), n_nodes);
00400 
00401 #ifndef NDEBUG
00402       // All our nodes should be correct
00403       for (unsigned int i=0; i != n_nodes; ++i)
00404         libmesh_assert(elem->node(i) ==
00405                        cast_int<dof_id_type>(*in++));
00406 #else
00407       in += n_nodes;
00408 #endif
00409 
00410 #ifdef LIBMESH_ENABLE_AMR
00411       libmesh_assert_equal_to (elem->p_level(), p_level);
00412       libmesh_assert_equal_to (elem->refinement_flag(), refinement_flag);
00413       libmesh_assert_equal_to (elem->p_refinement_flag(), p_refinement_flag);
00414 
00415       libmesh_assert (!level || elem->parent() != NULL);
00416       libmesh_assert (!level || elem->parent()->id() == parent_id);
00417       libmesh_assert (!level || elem->parent()->child(which_child_am_i) == elem);
00418 #endif
00419 
00420       // Our neighbor links should be "close to" correct - we may have
00421       // to update them, but we can check for some inconsistencies.
00422       for (unsigned int n=0; n != elem->n_neighbors(); ++n)
00423         {
00424           // We can't cast_int here, since NULL neighbors have an ID
00425           // of (unsigned long long)(-1) which doesn't fit in an
00426           // unsigned.
00427           const dof_id_type neighbor_id =
00428             static_cast<dof_id_type>(*in++);
00429 
00430           // If the sending processor sees a domain boundary here,
00431           // we'd better agree.
00432           if (neighbor_id == DofObject::invalid_id)
00433             {
00434               libmesh_assert (!(elem->neighbor(n)));
00435               continue;
00436             }
00437 
00438           // If the sending processor has a remote_elem neighbor here,
00439           // then all we know is that we'd better *not* have a domain
00440           // boundary.
00441           if (neighbor_id == remote_elem->id())
00442             {
00443               libmesh_assert(elem->neighbor(n));
00444               continue;
00445             }
00446 
00447           Elem *neigh = mesh->query_elem(neighbor_id);
00448 
00449           // The sending processor sees a neighbor here, so if we
00450           // don't have that neighboring element, then we'd better
00451           // have a remote_elem signifying that fact.
00452           if (!neigh)
00453             {
00454               libmesh_assert_equal_to (elem->neighbor(n), remote_elem);
00455               continue;
00456             }
00457 
00458           // The sending processor has a neighbor here, and we have
00459           // that element, but that does *NOT* mean we're already
00460           // linking to it.  Perhaps we initially received both elem
00461           // and neigh from processors on which their mutual link was
00462           // remote?
00463           libmesh_assert(elem->neighbor(n) == neigh ||
00464                          elem->neighbor(n) == remote_elem);
00465 
00466           // If the link was originally remote, we should update it,
00467           // and make sure the appropriate parts of its family link
00468           // back to us.
00469           if (elem->neighbor(n) == remote_elem)
00470             {
00471               elem->set_neighbor(n, neigh);
00472 
00473               elem->make_links_to_me_local(n);
00474             }
00475         }
00476 
00477       // FIXME: We should add some debug mode tests to ensure that the
00478       // encoded indexing and boundary conditions are consistent.
00479     }
00480   else
00481     {
00482       // We don't already have the element, so we need to create it.
00483 
00484       // Find the parent if necessary
00485       Elem *parent = NULL;
00486 #ifdef LIBMESH_ENABLE_AMR
00487       // Find a child element's parent
00488       if (level > 0)
00489         {
00490           // Note that we must be very careful to construct the send
00491           // connectivity so that parents are encountered before
00492           // children.  If we get here and can't find the parent that
00493           // is a fatal error.
00494           parent = mesh->elem(parent_id);
00495         }
00496       // Or assert that the sending processor sees no parent
00497       else
00498         libmesh_assert_equal_to (parent_id, static_cast<dof_id_type>(-1));
00499 #else
00500       // No non-level-0 elements without AMR
00501       libmesh_assert_equal_to (level, 0);
00502 #endif
00503 
00504       elem = Elem::build(type,parent).release();
00505       libmesh_assert (elem);
00506 
00507 #ifdef LIBMESH_ENABLE_AMR
00508       if (level != 0)
00509         {
00510           // Since this is a newly created element, the parent must
00511           // have previously thought of this child as a remote element.
00512           libmesh_assert_equal_to (parent->child(which_child_am_i), remote_elem);
00513 
00514           parent->add_child(elem, which_child_am_i);
00515         }
00516 
00517       // Assign the refinement flags and levels
00518       elem->set_p_level(p_level);
00519       elem->set_refinement_flag(refinement_flag);
00520       elem->set_p_refinement_flag(p_refinement_flag);
00521       libmesh_assert_equal_to (elem->level(), level);
00522 
00523       // If this element definitely should have children, assign
00524       // remote_elem to all of them for now, for consistency.  Later
00525       // unpacked elements may overwrite that.
00526       if (!elem->active())
00527         for (unsigned int c=0; c != elem->n_children(); ++c)
00528           elem->add_child(const_cast<RemoteElem*>(remote_elem), c);
00529 
00530 #endif // LIBMESH_ENABLE_AMR
00531 
00532       // Assign the IDs
00533       elem->subdomain_id()  = subdomain_id;
00534       elem->processor_id()  = processor_id;
00535       elem->set_id()        = id;
00536 #ifdef LIBMESH_ENABLE_UNIQUE_ID
00537       elem->set_unique_id() = unique_id;
00538 #endif
00539 
00540       // Assign the connectivity
00541       libmesh_assert_equal_to (elem->n_nodes(), n_nodes);
00542 
00543       for (unsigned int n=0; n != n_nodes; n++)
00544         elem->set_node(n) =
00545           mesh->node_ptr
00546           (cast_int<dof_id_type>(*in++));
00547 
00548       for (unsigned int n=0; n<elem->n_neighbors(); n++)
00549         {
00550           // We can't cast_int here, since NULL neighbors have an ID
00551           // of (unsigned long long)(-1) which doesn't fit in an
00552           // unsigned.
00553           const dof_id_type neighbor_id =
00554             static_cast<dof_id_type>(*in++);
00555 
00556           if (neighbor_id == DofObject::invalid_id)
00557             continue;
00558 
00559           // We may be unpacking an element that was a ghost element on the
00560           // sender, in which case the element's neighbors may not all be
00561           // known by the packed element.  We'll have to set such
00562           // neighbors to remote_elem ourselves and wait for a later
00563           // packed element to give us better information.
00564           if (neighbor_id == remote_elem->id())
00565             {
00566               elem->set_neighbor(n, const_cast<RemoteElem*>(remote_elem));
00567               continue;
00568             }
00569 
00570           // If we don't have the neighbor element, then it's a
00571           // remote_elem until we get it.
00572           Elem *neigh = mesh->query_elem(neighbor_id);
00573           if (!neigh)
00574             {
00575               elem->set_neighbor(n, const_cast<RemoteElem*>(remote_elem));
00576               continue;
00577             }
00578 
00579           // If we have the neighbor element, then link to it, and
00580           // make sure the appropriate parts of its family link back
00581           // to us.
00582           elem->set_neighbor(n, neigh);
00583 
00584           elem->make_links_to_me_local(n);
00585         }
00586 
00587       elem->unpack_indexing(in);
00588     }
00589 
00590   in += elem->packed_indexing_size();
00591 
00592   // If this is a coarse element,
00593   // add any element side or edge boundary condition ids
00594   if (level == 0)
00595     {
00596       for (unsigned short s = 0; s != elem->n_sides(); ++s)
00597         {
00598           const boundary_id_type num_bcs =
00599             cast_int<boundary_id_type>(*in++);
00600 
00601           for(boundary_id_type bc_it=0; bc_it < num_bcs; bc_it++)
00602             mesh->get_boundary_info().add_side
00603               (elem, s, cast_int<boundary_id_type>(*in++));
00604         }
00605 
00606       for (unsigned short e = 0; e != elem->n_edges(); ++e)
00607         {
00608           const boundary_id_type num_bcs =
00609             cast_int<boundary_id_type>(*in++);
00610 
00611           for(boundary_id_type bc_it=0; bc_it < num_bcs; bc_it++)
00612             mesh->get_boundary_info().add_edge
00613               (elem, e, cast_int<boundary_id_type>(*in++));
00614         }
00615     }
00616 
00617   // Return the new element
00618   *out = elem;
00619 }
00620 
00621 
00622 
00623 template <>
00624 void unpack(std::vector<largest_id_type>::const_iterator in,
00625             Elem** out,
00626             ParallelMesh* mesh)
00627 {
00628   unpack(in, out, static_cast<MeshBase*>(mesh));
00629 }
00630 
00631 } // namespace Parallel
00632 
00633 #endif // LIBMESH_HAVE_MPI
00634 
00635 } // namespace libMesh