parallel_elem.C
Go to the documentation of this file.00001 // The libMesh Finite Element Library. 00002 // Copyright (C) 2002-2012 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 static const unsigned int header_size = 10; 00035 00036 static const int elem_magic_header = 987654321; 00037 } 00038 00039 00040 namespace libMesh 00041 { 00042 00043 #ifdef LIBMESH_HAVE_MPI 00044 00045 namespace Parallel 00046 { 00047 00048 template <> 00049 unsigned int packed_size (const Elem*, 00050 std::vector<int>::const_iterator in) 00051 { 00052 #ifndef NDEBUG 00053 const int packed_header = *in++; 00054 libmesh_assert_equal_to (packed_header, elem_magic_header); 00055 #endif 00056 00057 // int 0: level 00058 const unsigned int level = 00059 static_cast<unsigned int>(*in); 00060 00061 // int 4: element type 00062 const int typeint = *(in+4); 00063 libmesh_assert_greater_equal (typeint, 0); 00064 libmesh_assert_less (typeint, INVALID_ELEM); 00065 const ElemType type = 00066 static_cast<ElemType>(typeint); 00067 00068 const unsigned int n_nodes = 00069 Elem::type_to_n_nodes_map[type]; 00070 00071 const unsigned int n_sides = 00072 Elem::type_to_n_sides_map[type]; 00073 00074 const unsigned int pre_indexing_size = 00075 header_size + n_nodes + n_sides; 00076 00077 const unsigned int indexing_size = 00078 DofObject::unpackable_indexing_size(in+pre_indexing_size); 00079 00080 unsigned int total_packed_bc_data = 0; 00081 if (level == 0) 00082 { 00083 for (unsigned int s = 0; s != n_sides; ++s) 00084 { 00085 const int n_bcs = 00086 *(in + pre_indexing_size + indexing_size + 00087 total_packed_bc_data++); 00088 libmesh_assert_greater_equal (n_bcs, 0); 00089 total_packed_bc_data += n_bcs; 00090 } 00091 } 00092 00093 return 00094 #ifndef NDEBUG 00095 1 + // Account for magic header 00096 #endif 00097 pre_indexing_size + indexing_size + total_packed_bc_data; 00098 } 00099 00100 00101 00102 template <> 00103 unsigned int packable_size (const Elem* elem, const MeshBase* mesh) 00104 { 00105 unsigned int total_packed_bcs = 0; 00106 if (elem->level() == 0) 00107 { 00108 total_packed_bcs += elem->n_sides(); 00109 for (unsigned int s = 0; s != elem->n_sides(); ++s) 00110 total_packed_bcs += mesh->boundary_info->n_boundary_ids(elem,s); 00111 } 00112 00113 return 00114 #ifndef NDEBUG 00115 1 + // add an int for the magic header when testing 00116 #endif 00117 header_size + elem->n_nodes() + 00118 elem->n_neighbors() + 00119 elem->packed_indexing_size() + total_packed_bcs; 00120 } 00121 00122 00123 00124 template <> 00125 unsigned int packable_size (const Elem* elem, const ParallelMesh* mesh) 00126 { 00127 return packable_size(elem, static_cast<const MeshBase*>(mesh)); 00128 } 00129 00130 00131 00132 template <> 00133 void pack (const Elem* elem, 00134 std::vector<int>& data, 00135 const MeshBase* mesh) 00136 { 00137 libmesh_assert(elem); 00138 00139 // This should be redundant when used with Parallel::pack_range() 00140 // data.reserve (data.size() + Parallel::packable_size(elem, mesh)); 00141 00142 #ifndef NDEBUG 00143 data.push_back (elem_magic_header); 00144 #endif 00145 00146 #ifdef LIBMESH_ENABLE_AMR 00147 data.push_back (static_cast<int>(elem->level())); 00148 data.push_back (static_cast<int>(elem->p_level())); 00149 data.push_back (static_cast<int>(elem->refinement_flag())); 00150 data.push_back (static_cast<int>(elem->p_refinement_flag())); 00151 #else 00152 data.push_back (0); 00153 data.push_back (0); 00154 data.push_back (0); 00155 data.push_back (0); 00156 #endif 00157 data.push_back (static_cast<int>(elem->type())); 00158 data.push_back (elem->processor_id()); 00159 data.push_back (elem->subdomain_id()); 00160 data.push_back (elem->id()); 00161 00162 #ifdef LIBMESH_ENABLE_AMR 00163 // use parent_ID of -1 to indicate a level 0 element 00164 if (elem->level() == 0) 00165 { 00166 data.push_back(-1); 00167 data.push_back(-1); 00168 } 00169 else 00170 { 00171 data.push_back(elem->parent()->id()); 00172 data.push_back(elem->parent()->which_child_am_i(elem)); 00173 } 00174 #else 00175 data.push_back (-1); 00176 data.push_back (-1); 00177 #endif 00178 00179 for (unsigned int n=0; n<elem->n_nodes(); n++) 00180 data.push_back (elem->node(n)); 00181 00182 for (unsigned int n=0; n<elem->n_neighbors(); n++) 00183 { 00184 const Elem *neigh = elem->neighbor(n); 00185 if (neigh) 00186 data.push_back (neigh->id()); 00187 else 00188 data.push_back (-1); 00189 } 00190 00191 #ifndef NDEBUG 00192 const int start_indices = data.size(); 00193 #endif 00194 // Add any DofObject indices 00195 elem->pack_indexing(std::back_inserter(data)); 00196 00197 libmesh_assert(elem->packed_indexing_size() == 00198 DofObject::unpackable_indexing_size(data.begin() + 00199 start_indices)); 00200 00201 libmesh_assert_equal_to (elem->packed_indexing_size(), 00202 data.size() - start_indices); 00203 00204 00205 // If this is a coarse element, 00206 // Add any element side boundary condition ids 00207 if (elem->level() == 0) 00208 for (unsigned int s = 0; s != elem->n_sides(); ++s) 00209 { 00210 std::vector<boundary_id_type> bcs = 00211 mesh->boundary_info->boundary_ids(elem, s); 00212 00213 data.push_back(bcs.size()); 00214 00215 for(unsigned int bc_it=0; bc_it < bcs.size(); bc_it++) 00216 data.push_back(bcs[bc_it]); 00217 } 00218 } 00219 00220 00221 00222 template <> 00223 void pack (const Elem* elem, 00224 std::vector<int>& data, 00225 const ParallelMesh* mesh) 00226 { 00227 pack(elem, data, static_cast<const MeshBase*>(mesh)); 00228 } 00229 00230 00231 00232 // FIXME - this needs serious work to be 64-bit compatible 00233 template <> 00234 void unpack(std::vector<int>::const_iterator in, 00235 Elem** out, 00236 MeshBase* mesh) 00237 { 00238 #ifndef NDEBUG 00239 const std::vector<int>::const_iterator original_in = in; 00240 00241 const int incoming_header = *in++; 00242 libmesh_assert_equal_to (incoming_header, elem_magic_header); 00243 #endif 00244 00245 // int 0: level 00246 const unsigned int level = 00247 static_cast<unsigned int>(*in++); 00248 00249 #ifdef LIBMESH_ENABLE_AMR 00250 // int 1: p level 00251 const unsigned int p_level = 00252 static_cast<unsigned int>(*in++); 00253 00254 // int 2: refinement flag 00255 const int rflag = *in++; 00256 libmesh_assert_greater_equal (rflag, 0); 00257 libmesh_assert_less (rflag, Elem::INVALID_REFINEMENTSTATE); 00258 const Elem::RefinementState refinement_flag = 00259 static_cast<Elem::RefinementState>(rflag); 00260 00261 // int 3: p refinement flag 00262 const int pflag = *in++; 00263 libmesh_assert_greater_equal (pflag, 0); 00264 libmesh_assert_less (pflag, Elem::INVALID_REFINEMENTSTATE); 00265 const Elem::RefinementState p_refinement_flag = 00266 static_cast<Elem::RefinementState>(pflag); 00267 #else 00268 in += 3; 00269 #endif // LIBMESH_ENABLE_AMR 00270 00271 // int 4: element type 00272 const int typeint = *in++; 00273 libmesh_assert_greater_equal (typeint, 0); 00274 libmesh_assert_less (typeint, INVALID_ELEM); 00275 const ElemType type = 00276 static_cast<ElemType>(typeint); 00277 00278 const unsigned int n_nodes = 00279 Elem::type_to_n_nodes_map[type]; 00280 00281 // int 5: processor id 00282 const unsigned int processor_id = 00283 static_cast<unsigned int>(*in++); 00284 libmesh_assert (processor_id < libMesh::n_processors() || 00285 processor_id == DofObject::invalid_processor_id); 00286 00287 // int 6: subdomain id 00288 const unsigned int subdomain_id = 00289 static_cast<unsigned int>(*in++); 00290 00291 // int 7: dof object id 00292 const dof_id_type id = 00293 static_cast<dof_id_type>(*in++); 00294 libmesh_assert_not_equal_to (id, DofObject::invalid_id); 00295 00296 #ifdef LIBMESH_ENABLE_AMR 00297 // int 8: parent dof object id 00298 const dof_id_type parent_id = 00299 static_cast<dof_id_type>(*in++); 00300 libmesh_assert (level == 0 || parent_id != DofObject::invalid_id); 00301 libmesh_assert (level != 0 || parent_id == DofObject::invalid_id); 00302 00303 // int 9: local child id 00304 const unsigned int which_child_am_i = 00305 static_cast<unsigned int>(*in++); 00306 #else 00307 in += 2; 00308 #endif // LIBMESH_ENABLE_AMR 00309 00310 // Make sure we don't miscount above when adding the "magic" header 00311 // plus the real data header 00312 libmesh_assert_equal_to (in - original_in, header_size + 1); 00313 00314 Elem *elem = mesh->query_elem(id); 00315 00316 // if we already have this element, make sure its 00317 // properties match, and update any missing neighbor 00318 // links, but then go on 00319 if (elem) 00320 { 00321 libmesh_assert_equal_to (elem->level(), level); 00322 libmesh_assert_equal_to (elem->id(), id); 00323 libmesh_assert_equal_to (elem->processor_id(), processor_id); 00324 libmesh_assert_equal_to (elem->subdomain_id(), subdomain_id); 00325 libmesh_assert_equal_to (elem->type(), type); 00326 libmesh_assert_equal_to (elem->n_nodes(), n_nodes); 00327 00328 #ifndef NDEBUG 00329 // All our nodes should be correct 00330 for (unsigned int i=0; i != n_nodes; ++i) 00331 libmesh_assert(elem->node(i) == 00332 static_cast<unsigned int>(*in++)); 00333 #else 00334 in += n_nodes; 00335 #endif 00336 00337 #ifdef LIBMESH_ENABLE_AMR 00338 libmesh_assert_equal_to (elem->p_level(), p_level); 00339 libmesh_assert_equal_to (elem->refinement_flag(), refinement_flag); 00340 libmesh_assert_equal_to (elem->p_refinement_flag(), p_refinement_flag); 00341 00342 libmesh_assert (!level || elem->parent() != NULL); 00343 libmesh_assert (!level || elem->parent()->id() == parent_id); 00344 libmesh_assert (!level || elem->parent()->child(which_child_am_i) == elem); 00345 #endif 00346 00347 // Our neighbor links should be "close to" correct - we may have 00348 // to update them, but we can check for some inconsistencies. 00349 for (unsigned int n=0; n != elem->n_neighbors(); ++n) 00350 { 00351 const dof_id_type neighbor_id = 00352 static_cast<dof_id_type>(*in++); 00353 00354 // If the sending processor sees a domain boundary here, 00355 // we'd better agree. 00356 if (neighbor_id == DofObject::invalid_id) 00357 { 00358 libmesh_assert (!(elem->neighbor(n))); 00359 continue; 00360 } 00361 00362 // If the sending processor has a remote_elem neighbor here, 00363 // then all we know is that we'd better *not* have a domain 00364 // boundary. 00365 if (neighbor_id == remote_elem->id()) 00366 { 00367 libmesh_assert(elem->neighbor(n)); 00368 continue; 00369 } 00370 00371 Elem *neigh = mesh->query_elem(neighbor_id); 00372 00373 // The sending processor sees a neighbor here, so if we 00374 // don't have that neighboring element, then we'd better 00375 // have a remote_elem signifying that fact. 00376 if (!neigh) 00377 { 00378 libmesh_assert_equal_to (elem->neighbor(n), remote_elem); 00379 continue; 00380 } 00381 00382 // The sending processor has a neighbor here, and we have 00383 // that element, but that does *NOT* mean we're already 00384 // linking to it. Perhaps we initially received both elem 00385 // and neigh from processors on which their mutual link was 00386 // remote? 00387 libmesh_assert(elem->neighbor(n) == neigh || 00388 elem->neighbor(n) == remote_elem); 00389 00390 // If the link was originally remote, we should update it, 00391 // and make sure the appropriate parts of its family link 00392 // back to us. 00393 if (elem->neighbor(n) == remote_elem) 00394 { 00395 elem->set_neighbor(n, neigh); 00396 00397 elem->make_links_to_me_local(n); 00398 } 00399 } 00400 00401 // FIXME: We should add some debug mode tests to ensure that the 00402 // encoded indexing and boundary conditions are consistent. 00403 } 00404 else 00405 { 00406 // We don't already have the element, so we need to create it. 00407 00408 // Find the parent if necessary 00409 Elem *parent = NULL; 00410 #ifdef LIBMESH_ENABLE_AMR 00411 // Find a child element's parent 00412 if (level > 0) 00413 { 00414 // Note that we must be very careful to construct the send 00415 // connectivity so that parents are encountered before 00416 // children. If we get here and can't find the parent that 00417 // is a fatal error. 00418 parent = mesh->elem(parent_id); 00419 } 00420 // Or assert that the sending processor sees no parent 00421 else 00422 libmesh_assert_equal_to (parent_id, static_cast<unsigned int>(-1)); 00423 #else 00424 // No non-level-0 elements without AMR 00425 libmesh_assert_equal_to (level, 0); 00426 #endif 00427 00428 elem = Elem::build(type,parent).release(); 00429 libmesh_assert (elem); 00430 00431 #ifdef LIBMESH_ENABLE_AMR 00432 if (level != 0) 00433 { 00434 // Since this is a newly created element, the parent must 00435 // have previously thought of this child as a remote element. 00436 libmesh_assert_equal_to (parent->child(which_child_am_i), remote_elem); 00437 00438 parent->add_child(elem, which_child_am_i); 00439 } 00440 00441 // Assign the refinement flags and levels 00442 elem->set_p_level(p_level); 00443 elem->set_refinement_flag(refinement_flag); 00444 elem->set_p_refinement_flag(p_refinement_flag); 00445 libmesh_assert_equal_to (elem->level(), level); 00446 00447 // If this element definitely should have children, assign 00448 // remote_elem to all of them for now, for consistency. Later 00449 // unpacked elements may overwrite that. 00450 if (!elem->active()) 00451 for (unsigned int c=0; c != elem->n_children(); ++c) 00452 elem->add_child(const_cast<RemoteElem*>(remote_elem), c); 00453 00454 #endif // LIBMESH_ENABLE_AMR 00455 00456 // Assign the IDs 00457 elem->subdomain_id() = subdomain_id; 00458 elem->processor_id() = processor_id; 00459 elem->set_id() = id; 00460 00461 // Assign the connectivity 00462 libmesh_assert_equal_to (elem->n_nodes(), n_nodes); 00463 00464 for (unsigned int n=0; n != n_nodes; n++) 00465 elem->set_node(n) = 00466 mesh->node_ptr 00467 (static_cast<unsigned int>(*in++)); 00468 00469 for (unsigned int n=0; n<elem->n_neighbors(); n++) 00470 { 00471 const dof_id_type neighbor_id = 00472 static_cast<dof_id_type>(*in++); 00473 00474 if (neighbor_id == DofObject::invalid_id) 00475 continue; 00476 00477 // We may be unpacking an element that was a ghost element on the 00478 // sender, in which case the element's neighbors may not all be 00479 // known by the packed element. We'll have to set such 00480 // neighbors to remote_elem ourselves and wait for a later 00481 // packed element to give us better information. 00482 if (neighbor_id == remote_elem->id()) 00483 { 00484 elem->set_neighbor(n, const_cast<RemoteElem*>(remote_elem)); 00485 continue; 00486 } 00487 00488 // If we don't have the neighbor element, then it's a 00489 // remote_elem until we get it. 00490 Elem *neigh = mesh->query_elem(neighbor_id); 00491 if (!neigh) 00492 { 00493 elem->set_neighbor(n, const_cast<RemoteElem*>(remote_elem)); 00494 continue; 00495 } 00496 00497 // If we have the neighbor element, then link to it, and 00498 // make sure the appropriate parts of its family link back 00499 // to us. 00500 elem->set_neighbor(n, neigh); 00501 00502 elem->make_links_to_me_local(n); 00503 } 00504 00505 elem->unpack_indexing(in); 00506 } 00507 00508 in += elem->packed_indexing_size(); 00509 00510 // If this is a coarse element, 00511 // add any element side boundary condition ids 00512 if (level == 0) 00513 for (unsigned int s = 0; s != elem->n_sides(); ++s) 00514 { 00515 const int num_bcs = *in++; 00516 libmesh_assert_greater_equal (num_bcs, 0); 00517 00518 for(int bc_it=0; bc_it < num_bcs; bc_it++) 00519 mesh->boundary_info->add_side (elem, s, *in++); 00520 } 00521 00522 // Return the new element 00523 *out = elem; 00524 } 00525 00526 00527 00528 template <> 00529 void unpack(std::vector<int>::const_iterator in, 00530 Elem** out, 00531 ParallelMesh* mesh) 00532 { 00533 unpack(in, out, static_cast<MeshBase*>(mesh)); 00534 } 00535 00536 } // namespace Parallel 00537 00538 #endif // LIBMESH_HAVE_MPI 00539 00540 } // namespace libMesh
Site Created By: libMesh Developers
Last modified: February 05 2013 19:54:48 UTC
Hosted By: