$extrastylesheet
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