$extrastylesheet
parallel_node.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/mesh_base.h"
00025 #include "libmesh/node.h"
00026 #include "libmesh/parallel.h"
00027 #include "libmesh/parallel_mesh.h"
00028 
00029 // Helper functions in anonymous namespace
00030 
00031 namespace
00032 {
00033 using namespace libMesh;
00034 
00035 #ifdef LIBMESH_ENABLE_UNIQUE_ID
00036 static const unsigned int header_size = 3;
00037 #else
00038 static const unsigned int header_size = 2;
00039 #endif
00040 
00041 // use "(a+b-1)/b" trick to get a/b to round up
00042 static const unsigned int idtypes_per_Real =
00043   (sizeof(Real) + sizeof(largest_id_type) - 1) / sizeof(largest_id_type);
00044 
00045 static const largest_id_type node_magic_header = 1234567890;
00046 }
00047 
00048 
00049 namespace libMesh
00050 {
00051 
00052 #ifdef LIBMESH_HAVE_MPI
00053 
00054 namespace Parallel
00055 {
00056 
00057 template <>
00058 unsigned int packable_size (const Node* node, const MeshBase* mesh)
00059 {
00060   return
00061 #ifndef NDEBUG
00062     1 + // add an int for the magic header when testing
00063 #endif
00064     header_size + LIBMESH_DIM*idtypes_per_Real +
00065     node->packed_indexing_size() +
00066     1 + mesh->get_boundary_info().n_boundary_ids(node);
00067 }
00068 
00069 
00070 
00071 template <>
00072 unsigned int packed_size (const Node*,
00073                           const std::vector<largest_id_type>::const_iterator in)
00074 {
00075   const unsigned int pre_indexing_size =
00076 #ifndef NDEBUG
00077     1 + // add an int for the magic header when testing
00078 #endif
00079     header_size + LIBMESH_DIM*idtypes_per_Real;
00080 
00081   const unsigned int indexing_size =
00082     DofObject::unpackable_indexing_size(in+pre_indexing_size);
00083 
00084   const int n_bcs = cast_int<int>
00085     (*(in + pre_indexing_size + indexing_size));
00086   libmesh_assert_greater_equal (n_bcs, 0);
00087 
00088   return pre_indexing_size + indexing_size + 1 + n_bcs;
00089 }
00090 
00091 
00092 
00093 template <>
00094 unsigned int packed_size (const Node* n,
00095                           const std::vector<largest_id_type>::iterator in)
00096 {
00097   return packed_size(n, std::vector<largest_id_type>::const_iterator(in));
00098 }
00099 
00100 
00101 
00102 template <>
00103 unsigned int packable_size (const Node* node, const ParallelMesh* mesh)
00104 {
00105   return packable_size(node, static_cast<const MeshBase*>(mesh));
00106 }
00107 
00108 
00109 
00110 template <>
00111 void pack (const Node* node,
00112            std::vector<largest_id_type>& data,
00113            const MeshBase* mesh)
00114 {
00115   libmesh_assert(node);
00116 
00117   // This should be redundant when used with Parallel::pack_range()
00118   // data.reserve (data.size() + Parallel::packable_size(node, mesh));
00119 
00120 #ifndef NDEBUG
00121   data.push_back (node_magic_header);
00122 #endif
00123 
00124   data.push_back (static_cast<largest_id_type>(node->processor_id()));
00125   data.push_back (static_cast<largest_id_type>(node->id()));
00126 
00127 #ifdef LIBMESH_ENABLE_UNIQUE_ID
00128   if (node->valid_unique_id())
00129     data.push_back (static_cast<largest_id_type>(node->unique_id()));
00130   else
00131     // OK to send invalid unique id, we must not own this DOF
00132     data.push_back (static_cast<largest_id_type>(DofObject::invalid_unique_id));
00133 #endif
00134 
00135   // use "(a+b-1)/b" trick to get a/b to round up
00136   static const unsigned int idtypes_per_Real =
00137     (sizeof(Real) + sizeof(largest_id_type) - 1) / sizeof(largest_id_type);
00138 
00139   for (unsigned int i=0; i != LIBMESH_DIM; ++i)
00140     {
00141       const largest_id_type* Real_as_idtypes =
00142         reinterpret_cast<const largest_id_type*>(&((*node)(i)));
00143       for (unsigned int j=0; j != idtypes_per_Real; ++j)
00144         {
00145           data.push_back(Real_as_idtypes[j]);
00146         }
00147     }
00148 
00149 #ifndef NDEBUG
00150   const std::size_t start_indices = data.size();
00151 #endif
00152   // Add any DofObject indices
00153   node->pack_indexing(std::back_inserter(data));
00154 
00155   libmesh_assert(node->packed_indexing_size() ==
00156                  DofObject::unpackable_indexing_size(data.begin() +
00157                                                      start_indices));
00158 
00159   libmesh_assert_equal_to (node->packed_indexing_size(),
00160                            data.size() - start_indices);
00161 
00162   // Add any nodal boundary condition ids
00163   std::vector<boundary_id_type> bcs =
00164     mesh->get_boundary_info().boundary_ids(node);
00165 
00166   libmesh_assert(bcs.size() < std::numeric_limits<largest_id_type>::max());
00167 
00168   data.push_back(bcs.size());
00169 
00170   for (std::size_t bc_it=0; bc_it < bcs.size(); bc_it++)
00171     data.push_back(bcs[bc_it]);
00172 }
00173 
00174 
00175 
00176 template <>
00177 void pack (const Node* node,
00178            std::vector<largest_id_type>& data,
00179            const ParallelMesh* mesh)
00180 {
00181   pack(node, data, static_cast<const MeshBase*>(mesh));
00182 }
00183 
00184 
00185 
00186 template <>
00187 void unpack (std::vector<largest_id_type>::const_iterator in,
00188              Node** out,
00189              MeshBase* mesh)
00190 {
00191 #ifndef NDEBUG
00192   const std::vector<largest_id_type>::const_iterator original_in = in;
00193   const largest_id_type incoming_header = *in++;
00194   libmesh_assert_equal_to (incoming_header, node_magic_header);
00195 #endif
00196 
00197   const processor_id_type processor_id = cast_int<processor_id_type>(*in++);
00198   libmesh_assert(processor_id == DofObject::invalid_processor_id ||
00199                  processor_id < mesh->n_processors());
00200 
00201   const dof_id_type id = cast_int<dof_id_type>(*in++);
00202 
00203 #ifdef LIBMESH_ENABLE_UNIQUE_ID
00204   const unique_id_type unique_id = cast_int<unique_id_type>(*in++);
00205 #endif
00206 
00207   Node *node = mesh->query_node_ptr(id);
00208 
00209   if (node)
00210     {
00211       libmesh_assert_equal_to (node->processor_id(), processor_id);
00212 
00213       // We currently don't communicate mesh motion via packed Nodes,
00214       // so it should be safe to assume (and assert) that Node
00215       // locations are consistent between processors
00216 #ifndef NDEBUG
00217       for (unsigned int i=0; i != LIBMESH_DIM; ++i)
00218         {
00219           const Real* idtypes_as_Real = reinterpret_cast<const Real*>(&(*in));
00220           libmesh_assert_equal_to ((*node)(i), *idtypes_as_Real);
00221           in += idtypes_per_Real;
00222         }
00223 #else
00224       in += LIBMESH_DIM * idtypes_per_Real;
00225 #endif // !NDEBUG
00226 
00227       if (!node->has_dofs())
00228         {
00229           node->unpack_indexing(in);
00230           libmesh_assert_equal_to (DofObject::unpackable_indexing_size(in),
00231                                    node->packed_indexing_size());
00232           in += node->packed_indexing_size();
00233         }
00234       else
00235         {
00236           // FIXME: We should add some debug mode tests to ensure that
00237           // the encoded indexing is consistent
00238           in += DofObject::unpackable_indexing_size(in);
00239         }
00240 
00241       *out = node;
00242     }
00243   else
00244     {
00245       // If we don't already have it, we need to allocate it
00246       node = new Node();
00247 
00248       for (unsigned int i=0; i != LIBMESH_DIM; ++i)
00249         {
00250           const Real* idtypes_as_Real = reinterpret_cast<const Real*>(&(*in));
00251           (*node)(i) = *idtypes_as_Real;
00252           in += idtypes_per_Real;
00253         }
00254 
00255       node->set_id() = id;
00256 #ifdef LIBMESH_ENABLE_UNIQUE_ID
00257       node->set_unique_id() = unique_id;
00258 #endif
00259       node->processor_id() = processor_id;
00260 
00261       node->unpack_indexing(in);
00262       libmesh_assert_equal_to (DofObject::unpackable_indexing_size(in),
00263                                node->packed_indexing_size());
00264       in += node->packed_indexing_size();
00265     }
00266 
00267   // FIXME: We should add some debug mode tests to ensure that the
00268   // encoded boundary conditions are consistent
00269 
00270   // Add any nodal boundary condition ids
00271   const largest_id_type num_bcs = *in++;
00272   // libmesh_assert_greater_equal (num_bcs, 0);
00273 
00274   for(largest_id_type bc_it=0; bc_it < num_bcs; bc_it++)
00275     mesh->get_boundary_info().add_node
00276       (node, cast_int<boundary_id_type>(*in++));
00277 
00278   *out = node;
00279 
00280 #ifndef NDEBUG
00281   libmesh_assert (in - original_in ==
00282                   cast_int<int>
00283                   (Parallel::packed_size(node, original_in)));
00284 #endif
00285 }
00286 
00287 
00288 
00289 template <>
00290 void unpack (std::vector<largest_id_type>::const_iterator in,
00291              Node** out,
00292              ParallelMesh* mesh)
00293 {
00294   unpack(in, out, static_cast<MeshBase*>(mesh));
00295 }
00296 
00297 } // namespace Parallel
00298 
00299 #endif // #ifdef LIBMESH_HAVE_MPI
00300 
00301 } // namespace libMesh