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