$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 #include <iostream> 00022 #include <iomanip> 00023 #include <cstdio> 00024 #include <vector> 00025 #include <string> 00026 00027 // Local includes 00028 #include "libmesh/xdr_io.h" 00029 #include "libmesh/legacy_xdr_io.h" 00030 #include "libmesh/xdr_cxx.h" 00031 #include "libmesh/enum_xdr_mode.h" 00032 #include "libmesh/mesh_base.h" 00033 #include "libmesh/node.h" 00034 #include "libmesh/elem.h" 00035 #include "libmesh/boundary_info.h" 00036 #include "libmesh/parallel.h" 00037 #include "libmesh/mesh_tools.h" 00038 #include "libmesh/partitioner.h" 00039 #include "libmesh/libmesh_logging.h" 00040 00041 namespace libMesh 00042 { 00043 00044 //----------------------------------------------- 00045 // anonymous namespace for implementation details 00046 namespace { 00047 struct DofBCData 00048 { 00049 dof_id_type dof_id; 00050 unsigned short int side; 00051 boundary_id_type bc_id; 00052 00053 // Default constructor 00054 DofBCData (dof_id_type dof_id_in=0, 00055 unsigned short int side_in=0, 00056 boundary_id_type bc_id_in=0) : 00057 dof_id(dof_id_in), 00058 side(side_in), 00059 bc_id(bc_id_in) 00060 {} 00061 00062 // comparison operator 00063 bool operator < (const DofBCData &other) const 00064 { 00065 if (this->dof_id == other.dof_id) 00066 return (this->side < other.side); 00067 00068 return this->dof_id < other.dof_id; 00069 } 00070 }; 00071 00072 // comparison operator 00073 bool operator < (const unsigned int &other_dof_id, 00074 const DofBCData &dof_bc) 00075 { 00076 return other_dof_id < dof_bc.dof_id; 00077 } 00078 00079 bool operator < (const DofBCData &dof_bc, 00080 const unsigned int &other_dof_id) 00081 00082 { 00083 return dof_bc.dof_id < other_dof_id; 00084 } 00085 00086 00087 // For some reason SunStudio does not seem to accept the above 00088 // comparison functions for use in 00089 // std::equal_range (ElemBCData::iterator, ElemBCData::iterator, unsigned int); 00090 #if defined(__SUNPRO_CC) || defined(__PGI) 00091 struct CompareIntDofBCData 00092 { 00093 bool operator()(const unsigned int &other_dof_id, 00094 const DofBCData &dof_bc) 00095 { 00096 return other_dof_id < dof_bc.dof_id; 00097 } 00098 00099 bool operator()(const DofBCData &dof_bc, 00100 const unsigned int &other_dof_id) 00101 { 00102 return dof_bc.dof_id < other_dof_id; 00103 } 00104 }; 00105 #endif 00106 } 00107 00108 00109 00110 // ------------------------------------------------------------ 00111 // XdrIO static data 00112 const std::size_t XdrIO::io_blksize = 128000; 00113 00114 00115 00116 // ------------------------------------------------------------ 00117 // XdrIO members 00118 XdrIO::XdrIO (MeshBase& mesh, const bool binary_in) : 00119 MeshInput<MeshBase> (mesh,/* is_parallel_format = */ true), 00120 MeshOutput<MeshBase>(mesh,/* is_parallel_format = */ true), 00121 ParallelObject (mesh), 00122 _binary (binary_in), 00123 _legacy (false), 00124 _write_serial (false), 00125 _write_parallel (false), 00126 #ifdef LIBMESH_ENABLE_UNIQUE_ID 00127 _write_unique_id (true), 00128 #else 00129 _write_unique_id (false), 00130 #endif 00131 _field_width (4), // In 0.7.0, all fields are 4 bytes, in 0.9.2 they can vary 00132 _version ("libMesh-0.9.2+"), 00133 _bc_file_name ("n/a"), 00134 _partition_map_file ("n/a"), 00135 _subdomain_map_file ("n/a"), 00136 _p_level_file ("n/a") 00137 { 00138 } 00139 00140 00141 00142 XdrIO::XdrIO (const MeshBase& mesh, const bool binary_in) : 00143 MeshOutput<MeshBase>(mesh,/* is_parallel_format = */ true), 00144 ParallelObject (mesh), 00145 _binary (binary_in) 00146 { 00147 } 00148 00149 00150 00151 XdrIO::~XdrIO () 00152 { 00153 } 00154 00155 00156 00157 void XdrIO::write (const std::string& name) 00158 { 00159 if (this->legacy()) 00160 { 00161 libmesh_deprecated(); 00162 00163 // We don't support writing parallel files in the legacy format 00164 libmesh_assert(!this->_write_parallel); 00165 00166 LegacyXdrIO(MeshOutput<MeshBase>::mesh(), this->binary()).write(name); 00167 return; 00168 } 00169 00170 Xdr io ((this->processor_id() == 0) ? name : "", this->binary() ? ENCODE : WRITE); 00171 00172 START_LOG("write()","XdrIO"); 00173 00174 // convenient reference to our mesh 00175 const MeshBase &mesh = MeshOutput<MeshBase>::mesh(); 00176 00177 header_id_type 00178 n_elem = mesh.n_elem(), 00179 n_nodes = mesh.n_nodes(); 00180 00181 libmesh_assert(n_elem == mesh.n_elem()); 00182 libmesh_assert(n_nodes == mesh.n_nodes()); 00183 00184 header_id_type n_bcs = 00185 cast_int<header_id_type>(mesh.get_boundary_info().n_boundary_conds()); 00186 header_id_type n_nodesets = 00187 cast_int<header_id_type>(mesh.get_boundary_info().n_nodeset_conds()); 00188 unsigned int 00189 n_p_levels = MeshTools::n_p_levels (mesh); 00190 00191 bool write_parallel_files = this->write_parallel(); 00192 00193 //------------------------------------------------------------- 00194 // For all the optional files -- the default file name is "n/a". 00195 // However, the user may specify an optional external file. 00196 00197 // If there are BCs and the user has not already provided a 00198 // file name then write to "." 00199 if ((n_bcs || n_nodesets) && 00200 this->boundary_condition_file_name() == "n/a") 00201 this->boundary_condition_file_name() = "."; 00202 00203 // If there are more than one subdomains and the user has not specified an 00204 // external file then write the subdomain mapping to the default file "." 00205 if ((mesh.n_subdomains() > 0) && 00206 (this->subdomain_map_file_name() == "n/a")) 00207 this->subdomain_map_file_name() = "."; 00208 00209 // In general we don't write the partition information. 00210 00211 // If we have p levels and the user has not already provided 00212 // a file name then write to "." 00213 if ((n_p_levels > 1) && 00214 (this->polynomial_level_file_name() == "n/a")) 00215 this->polynomial_level_file_name() = "."; 00216 00217 // write the header 00218 if (this->processor_id() == 0) 00219 { 00220 std::string full_ver = this->version() + (write_parallel_files ? " parallel" : ""); 00221 io.data (full_ver); 00222 00223 io.data (n_elem, "# number of elements"); 00224 io.data (n_nodes, "# number of nodes"); 00225 00226 io.data (this->boundary_condition_file_name(), "# boundary condition specification file"); 00227 io.data (this->subdomain_map_file_name(), "# subdomain id specification file"); 00228 io.data (this->partition_map_file_name(), "# processor id specification file"); 00229 io.data (this->polynomial_level_file_name(), "# p-level specification file"); 00230 00231 // Version 0.9.2+ introduces sizes for each type 00232 header_id_type write_size = sizeof(xdr_id_type), zero_size = 0; 00233 00234 const bool 00235 write_p_level = ("." == this->polynomial_level_file_name()), 00236 write_partitioning = ("." == this->partition_map_file_name()), 00237 write_subdomain_id = ("." == this->subdomain_map_file_name()), 00238 write_bcs = ("." == this->boundary_condition_file_name()); 00239 00240 io.data (write_size, "# type size"); 00241 io.data (_write_unique_id ? write_size : zero_size, "# uid size"); 00242 io.data (write_partitioning ? write_size : zero_size, "# pid size"); 00243 io.data (write_subdomain_id ? write_size : zero_size, "# sid size"); 00244 io.data (write_p_level ? write_size : zero_size, "# p-level size"); 00245 // Boundary Condition sizes 00246 io.data (write_bcs ? write_size : zero_size, "# eid size"); // elem id 00247 io.data (write_bcs ? write_size : zero_size, "# side size "); // side number 00248 io.data (write_bcs ? write_size : zero_size, "# bid size"); // boundary id 00249 } 00250 00251 if (write_parallel_files) 00252 { 00253 // Parallel xdr mesh files aren't implemented yet; until they 00254 // are we'll just warn the user and write a serial file. 00255 libMesh::out << "Warning! Parallel xda/xdr is not yet implemented.\n"; 00256 libMesh::out << "Writing a serialized file instead." << std::endl; 00257 00258 // write subdomain names 00259 this->write_serialized_subdomain_names(io); 00260 00261 // write connectivity 00262 this->write_serialized_connectivity (io, n_elem); 00263 00264 // write the nodal locations 00265 this->write_serialized_nodes (io, n_nodes); 00266 00267 // write the boundary condition information 00268 this->write_serialized_bcs (io, n_bcs); 00269 00270 // write the nodeset information 00271 this->write_serialized_nodesets (io, n_nodesets); 00272 } 00273 else 00274 { 00275 // write subdomain names 00276 this->write_serialized_subdomain_names(io); 00277 00278 // write connectivity 00279 this->write_serialized_connectivity (io, n_elem); 00280 00281 // write the nodal locations 00282 this->write_serialized_nodes (io, n_nodes); 00283 00284 // write the boundary condition information 00285 this->write_serialized_bcs (io, n_bcs); 00286 00287 // write the nodeset information 00288 this->write_serialized_nodesets (io, n_nodesets); 00289 } 00290 00291 if(mesh.get_boundary_info().n_edge_conds() > 0) 00292 { 00293 libMesh::out << "Warning: Mesh contains edge boundary IDs, but these " 00294 << "are not supported by the XDR format." 00295 << std::endl; 00296 } 00297 00298 STOP_LOG("write()","XdrIO"); 00299 00300 // pause all processes until the writing ends -- this will 00301 // protect for the pathological case where a write is 00302 // followed immediately by a read. The write must be 00303 // guaranteed to complete first. 00304 io.close(); 00305 this->comm().barrier(); 00306 } 00307 00308 00309 00310 void XdrIO::write_serialized_subdomain_names(Xdr &io) const 00311 { 00312 if (this->processor_id() == 0) 00313 { 00314 const MeshBase &mesh = MeshOutput<MeshBase>::mesh(); 00315 00316 const std::map<subdomain_id_type, std::string> & subdomain_map = mesh.get_subdomain_name_map(); 00317 00318 std::vector<header_id_type> subdomain_ids; subdomain_ids.reserve(subdomain_map.size()); 00319 std::vector<std::string> subdomain_names; subdomain_names.reserve(subdomain_map.size()); 00320 00321 // We need to loop over the map and make sure that there aren't any invalid entries. Since we 00322 // return writable references in mesh_base, it's possible for the user to leave some entity names 00323 // blank. We can't write those to the XDA file. 00324 header_id_type n_subdomain_names = 0; 00325 std::map<subdomain_id_type, std::string>::const_iterator it_end = subdomain_map.end(); 00326 for (std::map<subdomain_id_type, std::string>::const_iterator it = subdomain_map.begin(); it != it_end; ++it) 00327 { 00328 if (!it->second.empty()) 00329 { 00330 n_subdomain_names++; 00331 subdomain_ids.push_back(it->first); 00332 subdomain_names.push_back(it->second); 00333 } 00334 } 00335 00336 io.data(n_subdomain_names, "# subdomain id to name map"); 00337 // Write out the ids and names in two vectors 00338 if (n_subdomain_names) 00339 { 00340 io.data(subdomain_ids); 00341 io.data(subdomain_names); 00342 } 00343 } 00344 } 00345 00346 00347 00348 void XdrIO::write_serialized_connectivity (Xdr &io, const dof_id_type libmesh_dbg_var(n_elem)) const 00349 { 00350 libmesh_assert (io.writing()); 00351 00352 const bool 00353 write_p_level = ("." == this->polynomial_level_file_name()), 00354 write_partitioning = ("." == this->partition_map_file_name()), 00355 write_subdomain_id = ("." == this->subdomain_map_file_name()); 00356 00357 // convenient reference to our mesh 00358 const MeshBase &mesh = MeshOutput<MeshBase>::mesh(); 00359 libmesh_assert_equal_to (n_elem, mesh.n_elem()); 00360 00361 // We will only write active elements and their parents. 00362 const unsigned int n_active_levels = MeshTools::n_active_levels (mesh); 00363 std::vector<xdr_id_type> n_global_elem_at_level(n_active_levels); 00364 00365 MeshBase::const_element_iterator it = mesh.local_elements_end(), end=it; 00366 00367 // Find the number of local and global elements at each level 00368 #ifndef NDEBUG 00369 xdr_id_type tot_n_elem = 0; 00370 #endif 00371 for (unsigned int level=0; level<n_active_levels; level++) 00372 { 00373 it = mesh.local_level_elements_begin(level); 00374 end = mesh.local_level_elements_end(level); 00375 00376 n_global_elem_at_level[level] = MeshTools::n_elem(it, end); 00377 00378 this->comm().sum(n_global_elem_at_level[level]); 00379 #ifndef NDEBUG 00380 tot_n_elem += n_global_elem_at_level[level]; 00381 #endif 00382 libmesh_assert_less_equal (n_global_elem_at_level[level], n_elem); 00383 libmesh_assert_less_equal (tot_n_elem, n_elem); 00384 } 00385 00386 std::vector<xdr_id_type> 00387 xfer_conn, recv_conn; 00388 std::vector<dof_id_type> 00389 n_elem_on_proc(this->n_processors()), processor_offsets(this->n_processors()); 00390 std::vector<xdr_id_type> output_buffer; 00391 std::vector<std::size_t> 00392 xfer_buf_sizes(this->n_processors()); 00393 00394 #ifdef LIBMESH_ENABLE_AMR 00395 typedef std::map<dof_id_type, std::pair<processor_id_type, dof_id_type> > id_map_type; 00396 id_map_type parent_id_map, child_id_map; 00397 #endif 00398 00399 dof_id_type my_next_elem=0, next_global_elem=0; 00400 00401 //------------------------------------------- 00402 // First write the level-0 elements directly. 00403 it = mesh.local_level_elements_begin(0); 00404 end = mesh.local_level_elements_end(0); 00405 for (; it != end; ++it, ++my_next_elem) 00406 { 00407 pack_element (xfer_conn, *it); 00408 #ifdef LIBMESH_ENABLE_AMR 00409 parent_id_map[(*it)->id()] = std::make_pair(this->processor_id(), 00410 my_next_elem); 00411 #endif 00412 } 00413 xfer_conn.push_back(my_next_elem); // toss in the number of elements transferred. 00414 00415 std::size_t my_size = xfer_conn.size(); 00416 this->comm().gather (0, my_next_elem, n_elem_on_proc); 00417 this->comm().gather (0, my_size, xfer_buf_sizes); 00418 00419 processor_offsets[0] = 0; 00420 for (unsigned int pid=1; pid<this->n_processors(); pid++) 00421 processor_offsets[pid] = processor_offsets[pid-1] + n_elem_on_proc[pid-1]; 00422 00423 // All processors send their xfer buffers to processor 0. 00424 // Processor 0 will receive the data and write out the elements. 00425 if (this->processor_id() == 0) 00426 { 00427 // Write the number of elements at this level. 00428 { 00429 std::string comment = "# n_elem at level 0", legend = ", [ type "; 00430 if (_write_unique_id) 00431 legend += "uid "; 00432 if (write_partitioning) 00433 legend += "pid "; 00434 if (write_subdomain_id) 00435 legend += "sid "; 00436 if (write_p_level) 00437 legend += "p_level "; 00438 legend += "(n0 ... nN-1) ]"; 00439 comment += legend; 00440 io.data (n_global_elem_at_level[0], comment.c_str()); 00441 } 00442 00443 for (unsigned int pid=0; pid<this->n_processors(); pid++) 00444 { 00445 recv_conn.resize(xfer_buf_sizes[pid]); 00446 if (pid == 0) 00447 recv_conn = xfer_conn; 00448 else 00449 this->comm().receive (pid, recv_conn); 00450 00451 // at a minimum, the buffer should contain the number of elements, 00452 // which could be 0. 00453 libmesh_assert (!recv_conn.empty()); 00454 00455 { 00456 const xdr_id_type n_elem_received = recv_conn.back(); 00457 std::vector<xdr_id_type>::const_iterator recv_conn_iter = recv_conn.begin(); 00458 00459 for (xdr_id_type elem=0; elem<n_elem_received; elem++, next_global_elem++) 00460 { 00461 output_buffer.clear(); 00462 const xdr_id_type n_nodes = *recv_conn_iter; ++recv_conn_iter; 00463 output_buffer.push_back(*recv_conn_iter); /* type */ ++recv_conn_iter; 00464 00465 if (_write_unique_id) 00466 output_buffer.push_back(*recv_conn_iter); /* unique_id */ ++recv_conn_iter; 00467 00468 if (write_partitioning) 00469 output_buffer.push_back(*recv_conn_iter); /* processor id */ ++recv_conn_iter; 00470 00471 if (write_subdomain_id) 00472 output_buffer.push_back(*recv_conn_iter); /* subdomain id */ ++recv_conn_iter; 00473 00474 #ifdef LIBMESH_ENABLE_AMR 00475 if (write_p_level) 00476 output_buffer.push_back(*recv_conn_iter); /* p level */ ++recv_conn_iter; 00477 #endif 00478 for (dof_id_type node=0; node<n_nodes; node++, ++recv_conn_iter) 00479 output_buffer.push_back(*recv_conn_iter); 00480 00481 io.data_stream 00482 (&output_buffer[0], 00483 cast_int<unsigned int>(output_buffer.size()), 00484 cast_int<unsigned int>(output_buffer.size())); 00485 } 00486 } 00487 } 00488 } 00489 else 00490 this->comm().send (0, xfer_conn); 00491 00492 #ifdef LIBMESH_ENABLE_AMR 00493 //-------------------------------------------------------------------- 00494 // Next write the remaining elements indirectly through their parents. 00495 // This will insure that the children are written in the proper order 00496 // so they can be reconstructed properly. 00497 for (unsigned int level=1; level<n_active_levels; level++) 00498 { 00499 xfer_conn.clear(); 00500 00501 it = mesh.local_level_elements_begin(level-1); 00502 end = mesh.local_level_elements_end (level-1); 00503 00504 dof_id_type my_n_elem_written_at_level = 0; 00505 for (; it != end; ++it) 00506 if (!(*it)->active()) // we only want the parents elements at this level, and 00507 { // there is no direct iterator for this obscure use 00508 const Elem *parent = *it; 00509 id_map_type::iterator pos = parent_id_map.find(parent->id()); 00510 libmesh_assert (pos != parent_id_map.end()); 00511 const processor_id_type parent_pid = pos->second.first; 00512 const dof_id_type parent_id = pos->second.second; 00513 parent_id_map.erase(pos); 00514 00515 for (unsigned int c=0; c<parent->n_children(); c++, my_next_elem++) 00516 { 00517 const Elem *child = parent->child(c); 00518 pack_element (xfer_conn, child, parent_id, parent_pid); 00519 00520 // this aproach introduces the possibility that we write 00521 // non-local elements. These elements may well be parents 00522 // at the next step 00523 child_id_map[child->id()] = std::make_pair (child->processor_id(), 00524 my_n_elem_written_at_level++); 00525 } 00526 } 00527 xfer_conn.push_back(my_n_elem_written_at_level); 00528 my_size = xfer_conn.size(); 00529 this->comm().gather (0, my_size, xfer_buf_sizes); 00530 00531 // Processor 0 will receive the data and write the elements. 00532 if (this->processor_id() == 0) 00533 { 00534 // Write the number of elements at this level. 00535 { 00536 char buf[80]; 00537 std::sprintf(buf, "# n_elem at level %u", level); 00538 std::string comment(buf), legend = ", [ type "; 00539 00540 if (_write_unique_id) 00541 legend += "uid "; 00542 legend += "parent "; 00543 if (write_partitioning) 00544 legend += "pid "; 00545 if (write_subdomain_id) 00546 legend += "sid "; 00547 if (write_p_level) 00548 legend += "p_level "; 00549 legend += "(n0 ... nN-1) ]"; 00550 comment += legend; 00551 io.data (n_global_elem_at_level[level], comment.c_str()); 00552 } 00553 00554 for (unsigned int pid=0; pid<this->n_processors(); pid++) 00555 { 00556 recv_conn.resize(xfer_buf_sizes[pid]); 00557 if (pid == 0) 00558 recv_conn = xfer_conn; 00559 else 00560 this->comm().receive (pid, recv_conn); 00561 00562 // at a minimum, the buffer should contain the number of elements, 00563 // which could be 0. 00564 libmesh_assert (!recv_conn.empty()); 00565 00566 { 00567 const xdr_id_type n_elem_received = recv_conn.back(); 00568 std::vector<xdr_id_type>::const_iterator recv_conn_iter = recv_conn.begin(); 00569 00570 for (xdr_id_type elem=0; elem<n_elem_received; elem++, next_global_elem++) 00571 { 00572 output_buffer.clear(); 00573 const xdr_id_type n_nodes = *recv_conn_iter; ++recv_conn_iter; 00574 output_buffer.push_back(*recv_conn_iter); /* type */ ++recv_conn_iter; 00575 if (_write_unique_id) 00576 output_buffer.push_back(*recv_conn_iter); /* unique_id */ ++recv_conn_iter; 00577 00578 const xdr_id_type parent_local_id = *recv_conn_iter; ++recv_conn_iter; 00579 const xdr_id_type parent_pid = *recv_conn_iter; ++recv_conn_iter; 00580 00581 output_buffer.push_back (parent_local_id+processor_offsets[parent_pid]); 00582 00583 if (write_partitioning) 00584 output_buffer.push_back(*recv_conn_iter); /* processor id */ ++recv_conn_iter; 00585 00586 if (write_subdomain_id) 00587 output_buffer.push_back(*recv_conn_iter); /* subdomain id */ ++recv_conn_iter; 00588 00589 if (write_p_level) 00590 output_buffer.push_back(*recv_conn_iter); /* p level */ ++recv_conn_iter; 00591 00592 for (xdr_id_type node=0; node<n_nodes; node++, ++recv_conn_iter) 00593 output_buffer.push_back(*recv_conn_iter); 00594 00595 io.data_stream 00596 (&output_buffer[0], 00597 cast_int<unsigned int>(output_buffer.size()), 00598 cast_int<unsigned int>(output_buffer.size())); 00599 } 00600 } 00601 } 00602 } 00603 else 00604 this->comm().send (0, xfer_conn); 00605 00606 // update the processor_offsets 00607 processor_offsets[0] = processor_offsets.back() + n_elem_on_proc.back(); 00608 this->comm().gather (0, my_n_elem_written_at_level, n_elem_on_proc); 00609 for (unsigned int pid=1; pid<this->n_processors(); pid++) 00610 processor_offsets[pid] = processor_offsets[pid-1] + n_elem_on_proc[pid-1]; 00611 00612 // Now, at the next level we will again iterate over local parents. However, 00613 // those parents may have been written by other processors (at this step), 00614 // so we need to gather them into our *_id_maps. 00615 { 00616 std::vector<std::vector<dof_id_type> > requested_ids(this->n_processors()); 00617 std::vector<dof_id_type> request_to_fill; 00618 00619 it = mesh.local_level_elements_begin(level); 00620 end = mesh.local_level_elements_end(level); 00621 00622 for (; it!=end; ++it) 00623 if (!child_id_map.count((*it)->id())) 00624 { 00625 libmesh_assert_not_equal_to ((*it)->parent()->processor_id(), this->processor_id()); 00626 requested_ids[(*it)->parent()->processor_id()].push_back((*it)->id()); 00627 } 00628 00629 // Next set the child_ids 00630 for (unsigned int p=1; p != this->n_processors(); ++p) 00631 { 00632 // Trade my requests with processor procup and procdown 00633 unsigned int procup = (this->processor_id() + p) % 00634 this->n_processors(); 00635 unsigned int procdown = (this->n_processors() + 00636 this->processor_id() - p) % 00637 this->n_processors(); 00638 00639 this->comm().send_receive(procup, requested_ids[procup], 00640 procdown, request_to_fill); 00641 00642 // Fill those requests by overwriting the requested ids 00643 for (std::size_t i=0; i<request_to_fill.size(); i++) 00644 { 00645 libmesh_assert (child_id_map.count(request_to_fill[i])); 00646 libmesh_assert_equal_to (child_id_map[request_to_fill[i]].first, procdown); 00647 00648 request_to_fill[i] = child_id_map[request_to_fill[i]].second; 00649 } 00650 00651 // Trade back the results 00652 std::vector<dof_id_type> filled_request; 00653 this->comm().send_receive(procdown, request_to_fill, 00654 procup, filled_request); 00655 00656 libmesh_assert_equal_to (filled_request.size(), requested_ids[procup].size()); 00657 00658 for (std::size_t i=0; i<filled_request.size(); i++) 00659 child_id_map[requested_ids[procup][i]] = 00660 std::make_pair (procup, 00661 filled_request[i]); 00662 } 00663 // overwrite the parent_id_map with the child_id_map, but 00664 // use std::map::swap() for efficiency. 00665 parent_id_map.swap(child_id_map); child_id_map.clear(); 00666 } 00667 } 00668 #endif // LIBMESH_ENABLE_AMR 00669 if (this->processor_id() == 0) 00670 libmesh_assert_equal_to (next_global_elem, n_elem); 00671 00672 } 00673 00674 00675 00676 void XdrIO::write_serialized_nodes (Xdr &io, const dof_id_type n_nodes) const 00677 { 00678 // convenient reference to our mesh 00679 const MeshBase &mesh = MeshOutput<MeshBase>::mesh(); 00680 libmesh_assert_equal_to (n_nodes, mesh.n_nodes()); 00681 00682 std::vector<dof_id_type> xfer_ids; 00683 std::vector<Real> xfer_coords, &coords=xfer_coords; 00684 00685 std::vector<std::vector<dof_id_type> > recv_ids (this->n_processors());; 00686 std::vector<std::vector<Real> > recv_coords(this->n_processors()); 00687 00688 std::size_t n_written=0; 00689 00690 for (std::size_t blk=0, last_node=0; last_node<n_nodes; blk++) 00691 { 00692 const std::size_t first_node = blk*io_blksize; 00693 last_node = std::min((blk+1)*io_blksize, std::size_t(n_nodes)); 00694 00695 // Build up the xfer buffers on each processor 00696 MeshBase::const_node_iterator 00697 it = mesh.local_nodes_begin(), 00698 end = mesh.local_nodes_end(); 00699 00700 xfer_ids.clear(); xfer_coords.clear(); 00701 00702 for (; it!=end; ++it) 00703 if (((*it)->id() >= first_node) && // node in [first_node, last_node) 00704 ((*it)->id() < last_node)) 00705 { 00706 xfer_ids.push_back((*it)->id()); 00707 const Point &p = **it; 00708 xfer_coords.push_back(p(0)); 00709 #if LIBMESH_DIM > 1 00710 xfer_coords.push_back(p(1)); 00711 #endif 00712 #if LIBMESH_DIM > 2 00713 xfer_coords.push_back(p(2)); 00714 #endif 00715 } 00716 00717 //------------------------------------- 00718 // Send the xfer buffers to processor 0 00719 std::vector<std::size_t> ids_size, coords_size; 00720 00721 const std::size_t my_ids_size = xfer_ids.size(); 00722 00723 // explicitly gather ids_size 00724 this->comm().gather (0, my_ids_size, ids_size); 00725 00726 // infer coords_size on processor 0 00727 if (this->processor_id() == 0) 00728 { 00729 coords_size.reserve(this->n_processors()); 00730 for (std::size_t p=0; p<ids_size.size(); p++) 00731 coords_size.push_back(LIBMESH_DIM*ids_size[p]); 00732 } 00733 00734 // We will have lots of simultaneous receives if we are 00735 // processor 0, so let's use nonblocking receives. 00736 std::vector<Parallel::Request> 00737 id_request_handles(this->n_processors()-1), 00738 coord_request_handles(this->n_processors()-1); 00739 00740 Parallel::MessageTag 00741 id_tag = mesh.comm().get_unique_tag(1234), 00742 coord_tag = mesh.comm().get_unique_tag(1235); 00743 00744 // Post the receives -- do this on processor 0 only. 00745 if (this->processor_id() == 0) 00746 { 00747 for (unsigned int pid=0; pid<this->n_processors(); pid++) 00748 { 00749 recv_ids[pid].resize(ids_size[pid]); 00750 recv_coords[pid].resize(coords_size[pid]); 00751 00752 if (pid == 0) 00753 { 00754 recv_ids[0] = xfer_ids; 00755 recv_coords[0] = xfer_coords; 00756 } 00757 else 00758 { 00759 this->comm().receive (pid, recv_ids[pid], 00760 id_request_handles[pid-1], 00761 id_tag); 00762 this->comm().receive (pid, recv_coords[pid], 00763 coord_request_handles[pid-1], 00764 coord_tag); 00765 } 00766 } 00767 } 00768 else 00769 { 00770 // Send -- do this on all other processors. 00771 this->comm().send(0, xfer_ids, id_tag); 00772 this->comm().send(0, xfer_coords, coord_tag); 00773 } 00774 00775 // ------------------------------------------------------- 00776 // Receive the messages and write the output on processor 0. 00777 if (this->processor_id() == 0) 00778 { 00779 // Wait for all the receives to complete. We have no 00780 // need for the statuses since we already know the 00781 // buffer sizes. 00782 Parallel::wait (id_request_handles); 00783 Parallel::wait (coord_request_handles); 00784 00785 // Write the coordinates in this block. 00786 std::size_t tot_id_size=0; 00787 #ifndef NDEBUG 00788 std::size_t tot_coord_size=0; 00789 #endif 00790 for (unsigned int pid=0; pid<this->n_processors(); pid++) 00791 { 00792 tot_id_size += recv_ids[pid].size(); 00793 #ifndef NDEBUG 00794 tot_coord_size += recv_coords[pid].size(); 00795 #endif 00796 } 00797 00798 libmesh_assert_less_equal 00799 (tot_id_size, std::min(io_blksize, std::size_t(n_nodes))); 00800 libmesh_assert_equal_to (tot_coord_size, LIBMESH_DIM*tot_id_size); 00801 00802 coords.resize (3*tot_id_size); 00803 for (unsigned int pid=0; pid<this->n_processors(); pid++) 00804 for (std::size_t idx=0; idx<recv_ids[pid].size(); idx++) 00805 { 00806 const std::size_t local_idx = recv_ids[pid][idx] - first_node; 00807 libmesh_assert_less ((3*local_idx+2), coords.size()); 00808 libmesh_assert_less ((LIBMESH_DIM*idx+LIBMESH_DIM-1), recv_coords[pid].size()); 00809 00810 coords[3*local_idx+0] = recv_coords[pid][LIBMESH_DIM*idx+0]; 00811 #if LIBMESH_DIM > 1 00812 coords[3*local_idx+1] = recv_coords[pid][LIBMESH_DIM*idx+1]; 00813 #else 00814 coords[3*local_idx+1] = 0.; 00815 #endif 00816 #if LIBMESH_DIM > 2 00817 coords[3*local_idx+2] = recv_coords[pid][LIBMESH_DIM*idx+2]; 00818 #else 00819 coords[3*local_idx+2] = 0.; 00820 #endif 00821 00822 n_written++; 00823 } 00824 00825 io.data_stream (coords.empty() ? NULL : &coords[0], 00826 cast_int<unsigned int>(coords.size()), 3); 00827 } 00828 } 00829 if (this->processor_id() == 0) 00830 libmesh_assert_equal_to (n_written, n_nodes); 00831 } 00832 00833 00834 00835 void XdrIO::write_serialized_bcs (Xdr &io, const header_id_type n_bcs) const 00836 { 00837 libmesh_assert (io.writing()); 00838 00839 // convenient reference to our mesh 00840 const MeshBase &mesh = MeshOutput<MeshBase>::mesh(); 00841 00842 // and our boundary info object 00843 const BoundaryInfo &boundary_info = mesh.get_boundary_info(); 00844 00845 // Version 0.9.2+ introduces entity names 00846 write_serialized_bc_names(io, boundary_info, true); // sideset names 00847 00848 header_id_type n_bcs_out = n_bcs; 00849 if (this->processor_id() == 0) 00850 io.data (n_bcs_out, "# number of boundary conditions"); 00851 n_bcs_out = 0; 00852 00853 if (!n_bcs) return; 00854 00855 std::vector<xdr_id_type> xfer_bcs, recv_bcs; 00856 std::vector<std::size_t> bc_sizes(this->n_processors()); 00857 00858 // Boundary conditions are only specified for level-0 elements 00859 MeshBase::const_element_iterator 00860 it = mesh.local_level_elements_begin(0), 00861 end = mesh.local_level_elements_end(0); 00862 00863 dof_id_type n_local_level_0_elem=0; 00864 for (; it!=end; ++it, n_local_level_0_elem++) 00865 { 00866 const Elem *elem = *it; 00867 00868 for (unsigned short s=0; s<elem->n_sides(); s++) 00869 // We're supporting boundary ids on internal sides now 00870 //if (elem->neighbor(s) == NULL) 00871 { 00872 const std::vector<boundary_id_type>& bc_ids = 00873 boundary_info.boundary_ids (elem, s); 00874 for (std::vector<boundary_id_type>::const_iterator id_it=bc_ids.begin(); id_it!=bc_ids.end(); ++id_it) 00875 { 00876 const boundary_id_type bc_id = *id_it; 00877 if (bc_id != BoundaryInfo::invalid_id) 00878 { 00879 xfer_bcs.push_back (n_local_level_0_elem); 00880 xfer_bcs.push_back (s) ; 00881 xfer_bcs.push_back (bc_id); 00882 } 00883 } 00884 } 00885 } 00886 00887 xfer_bcs.push_back(n_local_level_0_elem); 00888 std::size_t my_size = xfer_bcs.size(); 00889 this->comm().gather (0, my_size, bc_sizes); 00890 00891 // All processors send their xfer buffers to processor 0 00892 // Processor 0 will receive all buffers and write out the bcs 00893 if (this->processor_id() == 0) 00894 { 00895 dof_id_type elem_offset = 0; 00896 for (unsigned int pid=0; pid<this->n_processors(); pid++) 00897 { 00898 recv_bcs.resize(bc_sizes[pid]); 00899 if (pid == 0) 00900 recv_bcs = xfer_bcs; 00901 else 00902 this->comm().receive (pid, recv_bcs); 00903 00904 const dof_id_type my_n_local_level_0_elem 00905 = cast_int<dof_id_type>(recv_bcs.back()); 00906 recv_bcs.pop_back(); 00907 00908 for (std::size_t idx=0; idx<recv_bcs.size(); idx += 3, n_bcs_out++) 00909 recv_bcs[idx+0] += elem_offset; 00910 00911 io.data_stream (recv_bcs.empty() ? NULL : &recv_bcs[0], 00912 cast_int<unsigned int>(recv_bcs.size()), 3); 00913 elem_offset += my_n_local_level_0_elem; 00914 } 00915 libmesh_assert_equal_to (n_bcs, n_bcs_out); 00916 } 00917 else 00918 this->comm().send (0, xfer_bcs); 00919 } 00920 00921 00922 00923 void XdrIO::write_serialized_nodesets (Xdr &io, const header_id_type n_nodesets) const 00924 { 00925 libmesh_assert (io.writing()); 00926 00927 // convenient reference to our mesh 00928 const MeshBase &mesh = MeshOutput<MeshBase>::mesh(); 00929 00930 // and our boundary info object 00931 const BoundaryInfo &boundary_info = mesh.get_boundary_info(); 00932 00933 // Version 0.9.2+ introduces entity names 00934 write_serialized_bc_names(io, boundary_info, false); // nodeset names 00935 00936 header_id_type n_nodesets_out = n_nodesets; 00937 if (this->processor_id() == 0) 00938 io.data (n_nodesets_out, "# number of nodesets"); 00939 n_nodesets_out = 0; 00940 00941 if (!n_nodesets) return; 00942 00943 std::vector<xdr_id_type> xfer_bcs, recv_bcs; 00944 std::vector<std::size_t> bc_sizes(this->n_processors()); 00945 00946 MeshBase::const_node_iterator 00947 it = mesh.local_nodes_begin(), 00948 end = mesh.local_nodes_end(); 00949 00950 dof_id_type n_node=0; 00951 for (; it!=end; ++it) 00952 { 00953 const Node *node = *it; 00954 const std::vector<boundary_id_type>& nodeset_ids = 00955 boundary_info.boundary_ids (node); 00956 for (std::vector<boundary_id_type>::const_iterator id_it=nodeset_ids.begin(); id_it!=nodeset_ids.end(); ++id_it) 00957 { 00958 const boundary_id_type bc_id = *id_it; 00959 if (bc_id != BoundaryInfo::invalid_id) 00960 { 00961 xfer_bcs.push_back ((*it)->id()); 00962 xfer_bcs.push_back (bc_id); 00963 } 00964 } 00965 } 00966 00967 xfer_bcs.push_back(n_node); 00968 std::size_t my_size = xfer_bcs.size(); 00969 this->comm().gather (0, my_size, bc_sizes); 00970 00971 // All processors send their xfer buffers to processor 0 00972 // Processor 0 will receive all buffers and write out the bcs 00973 if (this->processor_id() == 0) 00974 { 00975 dof_id_type node_offset = 0; 00976 for (unsigned int pid=0; pid<this->n_processors(); pid++) 00977 { 00978 recv_bcs.resize(bc_sizes[pid]); 00979 if (pid == 0) 00980 recv_bcs = xfer_bcs; 00981 else 00982 this->comm().receive (pid, recv_bcs); 00983 00984 const dof_id_type my_n_node = 00985 cast_int<dof_id_type>(recv_bcs.back()); 00986 recv_bcs.pop_back(); 00987 00988 for (std::size_t idx=0; idx<recv_bcs.size(); idx += 2, n_nodesets_out++) 00989 recv_bcs[idx+0] += node_offset; 00990 00991 io.data_stream (recv_bcs.empty() ? NULL : &recv_bcs[0], 00992 cast_int<unsigned int>(recv_bcs.size()), 2); 00993 node_offset += my_n_node; 00994 } 00995 libmesh_assert_equal_to (n_nodesets, n_nodesets_out); 00996 } 00997 else 00998 this->comm().send (0, xfer_bcs); 00999 } 01000 01001 01002 01003 void XdrIO::write_serialized_bc_names (Xdr &io, const BoundaryInfo & info, bool is_sideset) const 01004 { 01005 if (this->processor_id() == 0) 01006 { 01007 const std::map<boundary_id_type, std::string> & boundary_map = is_sideset ? 01008 info.get_sideset_name_map() : info.get_nodeset_name_map(); 01009 01010 std::vector<header_id_type> boundary_ids; boundary_ids.reserve(boundary_map.size()); 01011 std::vector<std::string> boundary_names; boundary_names.reserve(boundary_map.size()); 01012 01013 // We need to loop over the map and make sure that there aren't any invalid entries. Since we 01014 // return writable references in boundary_info, it's possible for the user to leave some entity names 01015 // blank. We can't write those to the XDA file. 01016 header_id_type n_boundary_names = 0; 01017 std::map<boundary_id_type, std::string>::const_iterator it_end = boundary_map.end(); 01018 for (std::map<boundary_id_type, std::string>::const_iterator it = boundary_map.begin(); it != it_end; ++it) 01019 { 01020 if (!it->second.empty()) 01021 { 01022 n_boundary_names++; 01023 boundary_ids.push_back(it->first); 01024 boundary_names.push_back(it->second); 01025 } 01026 } 01027 01028 if (is_sideset) 01029 io.data(n_boundary_names, "# sideset id to name map"); 01030 else 01031 io.data(n_boundary_names, "# nodeset id to name map"); 01032 // Write out the ids and names in two vectors 01033 if (n_boundary_names) 01034 { 01035 io.data(boundary_ids); 01036 io.data(boundary_names); 01037 } 01038 } 01039 } 01040 01041 01042 01043 void XdrIO::read (const std::string& name) 01044 { 01045 // Only open the file on processor 0 -- this is especially important because 01046 // there may be an underlying bzip/bunzip going on, and multiple simultaneous 01047 // calls will produce a race condition. 01048 Xdr io (this->processor_id() == 0 ? name : "", this->binary() ? DECODE : READ); 01049 01050 // convenient reference to our mesh 01051 MeshBase &mesh = MeshInput<MeshBase>::mesh(); 01052 01053 // get the version string. 01054 if (this->processor_id() == 0) 01055 io.data (this->version()); 01056 this->comm().broadcast (this->version()); 01057 01058 // note that for "legacy" files the first entry is an 01059 // integer -- not a string at all. 01060 this->legacy() = !(this->version().find("libMesh") < this->version().size()); 01061 01062 // Check for a legacy version format. 01063 if (this->legacy()) 01064 { 01065 io.close(); 01066 LegacyXdrIO(mesh, this->binary()).read(name); 01067 return; 01068 } 01069 01070 START_LOG("read()","XdrIO"); 01071 01072 std::vector<header_id_type> meta_data(10, sizeof(xdr_id_type)); 01073 // type_size, uid_size, pid_size, sid_size, p_level_size, eid_size, side_size, bid_size; 01074 header_id_type pos=0; 01075 01076 const bool is_version_0_9_2 = this->version().find("0.9.2") != std::string::npos ? true : false; 01077 01078 if (this->processor_id() == 0) 01079 { 01080 io.data (meta_data[pos++]); 01081 io.data (meta_data[pos++]); 01082 io.data (this->boundary_condition_file_name()); // libMesh::out << "bc_file=" << this->boundary_condition_file_name() << std::endl; 01083 io.data (this->subdomain_map_file_name()); // libMesh::out << "sid_file=" << this->subdomain_map_file_name() << std::endl; 01084 io.data (this->partition_map_file_name()); // libMesh::out << "pid_file=" << this->partition_map_file_name() << std::endl; 01085 io.data (this->polynomial_level_file_name()); // libMesh::out << "pl_file=" << this->polynomial_level_file_name() << std::endl; 01086 01087 if (is_version_0_9_2) 01088 { 01089 io.data (meta_data[pos++], "# type size"); 01090 io.data (meta_data[pos++], "# uid size"); 01091 io.data (meta_data[pos++], "# pid size"); 01092 io.data (meta_data[pos++], "# sid size"); 01093 io.data (meta_data[pos++], "# p-level size"); 01094 // Boundary Condition sizes 01095 io.data (meta_data[pos++], "# eid size"); // elem id 01096 io.data (meta_data[pos++], "# side size "); // side number 01097 io.data (meta_data[pos++], "# bid size"); // boundary id 01098 } 01099 } 01100 01101 // broadcast the n_elems, n_nodes, and size information 01102 this->comm().broadcast (meta_data); 01103 01104 this->comm().broadcast (this->boundary_condition_file_name()); 01105 this->comm().broadcast (this->subdomain_map_file_name()); 01106 this->comm().broadcast (this->partition_map_file_name()); 01107 this->comm().broadcast (this->polynomial_level_file_name()); 01108 01109 // Tell the mesh how many nodes/elements to expect. Depending on the mesh type, 01110 // this may allow for efficient adding of nodes/elements. 01111 header_id_type n_elem = meta_data[0]; 01112 header_id_type n_nodes = meta_data[1]; 01113 01114 mesh.reserve_elem(n_elem); 01115 mesh.reserve_nodes(n_nodes); 01116 01117 // Our mesh is pre-partitioned as it's created 01118 this->set_n_partitions(this->n_processors()); 01119 01125 if (is_version_0_9_2) 01126 _field_width = meta_data[2]; 01127 01128 if (_field_width == 4) 01129 { 01130 uint32_t type_size = 0; 01131 01132 // read subdomain names 01133 this->read_serialized_subdomain_names(io); 01134 01135 // read connectivity 01136 this->read_serialized_connectivity (io, n_elem, meta_data, type_size); 01137 01138 // read the nodal locations 01139 this->read_serialized_nodes (io, n_nodes); 01140 01141 // read the boundary conditions 01142 this->read_serialized_bcs (io, type_size); 01143 01144 if (is_version_0_9_2) 01145 // read the nodesets 01146 this->read_serialized_nodesets (io, type_size); 01147 } 01148 else if (_field_width == 8) 01149 { 01150 uint64_t type_size = 0; 01151 01152 // read subdomain names 01153 this->read_serialized_subdomain_names(io); 01154 01155 // read connectivity 01156 this->read_serialized_connectivity (io, n_elem, meta_data, type_size); 01157 01158 // read the nodal locations 01159 this->read_serialized_nodes (io, n_nodes); 01160 01161 // read the boundary conditions 01162 this->read_serialized_bcs (io, type_size); 01163 01164 if (is_version_0_9_2) 01165 // read the nodesets 01166 this->read_serialized_nodesets (io, type_size); 01167 } 01168 01169 01170 STOP_LOG("read()","XdrIO"); 01171 01172 // set the node processor ids 01173 Partitioner::set_node_processor_ids(mesh); 01174 } 01175 01176 01177 01178 void XdrIO::read_serialized_subdomain_names(Xdr &io) 01179 { 01180 const bool read_entity_info = this->version().find("0.9.2") != std::string::npos ? true : false; 01181 if (read_entity_info) 01182 { 01183 MeshBase &mesh = MeshInput<MeshBase>::mesh(); 01184 01185 unsigned int n_subdomain_names = 0; 01186 std::vector<header_id_type> subdomain_ids; 01187 std::vector<std::string> subdomain_names; 01188 01189 // Read the sideset names 01190 if (this->processor_id() == 0) 01191 { 01192 io.data(n_subdomain_names); 01193 01194 subdomain_ids.resize(n_subdomain_names); 01195 subdomain_names.resize(n_subdomain_names); 01196 01197 if (n_subdomain_names) 01198 { 01199 io.data(subdomain_ids); 01200 io.data(subdomain_names); 01201 } 01202 } 01203 01204 // Broadcast the subdomain names to all processors 01205 this->comm().broadcast(n_subdomain_names); 01206 if (n_subdomain_names == 0) 01207 return; 01208 01209 subdomain_ids.resize(n_subdomain_names); 01210 subdomain_names.resize(n_subdomain_names); 01211 this->comm().broadcast(subdomain_ids); 01212 this->comm().broadcast(subdomain_names); 01213 01214 // Reassemble the named subdomain information 01215 std::map<subdomain_id_type, std::string> & subdomain_map = mesh.set_subdomain_name_map(); 01216 01217 for (unsigned int i=0; i<n_subdomain_names; ++i) 01218 subdomain_map.insert(std::make_pair(subdomain_ids[i], subdomain_names[i])); 01219 } 01220 } 01221 01222 01223 template <typename T> 01224 void XdrIO::read_serialized_connectivity (Xdr &io, const dof_id_type n_elem, std::vector<header_id_type> & sizes, T) 01225 { 01226 libmesh_assert (io.reading()); 01227 01228 if (!n_elem) return; 01229 01230 const bool 01231 read_p_level = ("." == this->polynomial_level_file_name()), 01232 read_partitioning = ("." == this->partition_map_file_name()), 01233 read_subdomain_id = ("." == this->subdomain_map_file_name()); 01234 01235 // convenient reference to our mesh 01236 MeshBase &mesh = MeshInput<MeshBase>::mesh(); 01237 01238 // Keep track of what kinds of elements this file contains 01239 elems_of_dimension.clear(); 01240 elems_of_dimension.resize(4, false); 01241 01242 std::vector<T> conn, input_buffer(100 /* oversized ! */); 01243 01244 int level=-1; 01245 01246 // Version 0.9.2+ introduces unique ids 01247 const size_t unique_id_size_index = 3; 01248 const bool read_unique_id = this->version().find("0.9.2") != std::string::npos && 01249 sizes[unique_id_size_index] ? true : false; 01250 01251 T n_elem_at_level=0, n_processed_at_level=0; 01252 for (dof_id_type blk=0, first_elem=0, last_elem=0; 01253 last_elem<n_elem; blk++) 01254 { 01255 first_elem = cast_int<dof_id_type>(blk*io_blksize); 01256 last_elem = cast_int<dof_id_type>(std::min(cast_int<std::size_t>((blk+1)*io_blksize), 01257 cast_int<std::size_t>(n_elem))); 01258 01259 conn.clear(); 01260 01261 if (this->processor_id() == 0) 01262 for (dof_id_type e=first_elem; e<last_elem; e++, n_processed_at_level++) 01263 { 01264 if (n_processed_at_level == n_elem_at_level) 01265 { 01266 // get the number of elements to read at this level 01267 io.data (n_elem_at_level); 01268 n_processed_at_level = 0; 01269 level++; 01270 } 01271 01272 unsigned int pos = 0; 01273 // get the element type, 01274 io.data_stream (&input_buffer[pos++], 1); 01275 01276 if (read_unique_id) 01277 io.data_stream (&input_buffer[pos++], 1); 01278 // Older versions won't have this field at all (no increment on pos) 01279 01280 // maybe the parent 01281 if (level) 01282 io.data_stream (&input_buffer[pos++], 1); 01283 else 01284 // We can't always fit DofObject::invalid_id in an 01285 // xdr_id_type 01286 input_buffer[pos++] = static_cast<T>(-1); 01287 01288 // maybe the processor id 01289 if (read_partitioning) 01290 io.data_stream (&input_buffer[pos++], 1); 01291 else 01292 input_buffer[pos++] = 0; 01293 01294 // maybe the subdomain id 01295 if (read_subdomain_id) 01296 io.data_stream (&input_buffer[pos++], 1); 01297 else 01298 input_buffer[pos++] = 0; 01299 01300 // maybe the p level 01301 if (read_p_level) 01302 io.data_stream (&input_buffer[pos++], 1); 01303 else 01304 input_buffer[pos++] = 0; 01305 01306 // and all the nodes 01307 libmesh_assert_less (pos+Elem::type_to_n_nodes_map[input_buffer[0]], input_buffer.size()); 01308 io.data_stream (&input_buffer[pos], Elem::type_to_n_nodes_map[input_buffer[0]]); 01309 conn.insert (conn.end(), 01310 input_buffer.begin(), 01311 input_buffer.begin() + pos + Elem::type_to_n_nodes_map[input_buffer[0]]); 01312 } 01313 01314 std::size_t conn_size = conn.size(); 01315 this->comm().broadcast(conn_size); 01316 conn.resize (conn_size); 01317 this->comm().broadcast (conn); 01318 01319 // All processors now have the connectivity for this block. 01320 typename std::vector<T>::const_iterator it = conn.begin(); 01321 for (dof_id_type e=first_elem; e<last_elem; e++) 01322 { 01323 const ElemType elem_type = static_cast<ElemType>(*it); ++it; 01324 #ifdef LIBMESH_ENABLE_UNIQUE_ID 01325 unique_id_type unique_id = 0; 01326 #endif 01327 if (read_unique_id) 01328 { 01329 #ifdef LIBMESH_ENABLE_UNIQUE_ID 01330 unique_id = cast_int<unique_id_type>(*it); 01331 #endif 01332 ++it; 01333 } 01334 const dof_id_type parent_id = 01335 (*it == static_cast<T>(-1)) ? 01336 DofObject::invalid_id : 01337 cast_int<dof_id_type>(*it); 01338 ++it; 01339 const processor_id_type proc_id = 01340 cast_int<processor_id_type>(*it); 01341 ++it; 01342 const subdomain_id_type subdomain_id = 01343 cast_int<subdomain_id_type>(*it); 01344 ++it; 01345 #ifdef LIBMESH_ENABLE_AMR 01346 const unsigned int p_level = 01347 cast_int<unsigned int>(*it); 01348 #endif 01349 ++it; 01350 01351 Elem *parent = 01352 (parent_id == DofObject::invalid_id) ? NULL : mesh.elem(parent_id); 01353 01354 Elem *elem = Elem::build (elem_type, parent).release(); 01355 01356 elem->set_id() = e; 01357 #ifdef LIBMESH_ENABLE_UNIQUE_ID 01358 elem->set_unique_id() = unique_id; 01359 #endif 01360 elem->processor_id() = proc_id; 01361 elem->subdomain_id() = subdomain_id; 01362 #ifdef LIBMESH_ENABLE_AMR 01363 elem->hack_p_level(p_level); 01364 01365 if (parent) 01366 { 01367 parent->add_child(elem); 01368 parent->set_refinement_flag (Elem::INACTIVE); 01369 elem->set_refinement_flag (Elem::JUST_REFINED); 01370 } 01371 #endif 01372 01373 for (unsigned int n=0; n<elem->n_nodes(); n++, ++it) 01374 { 01375 const dof_id_type global_node_number = 01376 cast_int<dof_id_type>(*it); 01377 01378 elem->set_node(n) = 01379 mesh.add_point (Point(), global_node_number); 01380 } 01381 01382 elems_of_dimension[elem->dim()] = true; 01383 mesh.add_elem(elem); 01384 } 01385 } 01386 01387 // Set the mesh dimension to the largest encountered for an element 01388 for (unsigned char i=0; i!=4; ++i) 01389 if (elems_of_dimension[i]) 01390 mesh.set_mesh_dimension(i); 01391 01392 #if LIBMESH_DIM < 3 01393 if (mesh.mesh_dimension() > LIBMESH_DIM) 01394 libmesh_error_msg("Cannot open dimension " \ 01395 << mesh.mesh_dimension() \ 01396 << " mesh file when configured without " \ 01397 << mesh.mesh_dimension() \ 01398 << "D support."); 01399 #endif 01400 } 01401 01402 01403 01404 void XdrIO::read_serialized_nodes (Xdr &io, const dof_id_type n_nodes) 01405 { 01406 libmesh_assert (io.reading()); 01407 01408 // convenient reference to our mesh 01409 MeshBase &mesh = MeshInput<MeshBase>::mesh(); 01410 01411 if (!mesh.n_nodes()) return; 01412 01413 // At this point the elements have been read from file and placeholder nodes 01414 // have been assigned. These nodes, however, do not have the proper (x,y,z) 01415 // locations. This method will read all the nodes from disk, and each processor 01416 // can then grab the individual values it needs. 01417 01418 // build up a list of the nodes contained in our local mesh. These are the nodes 01419 // stored on the local processor whose (x,y,z) values need to be corrected. 01420 std::vector<dof_id_type> needed_nodes; needed_nodes.reserve (mesh.n_nodes()); 01421 { 01422 MeshBase::node_iterator 01423 it = mesh.nodes_begin(), 01424 end = mesh.nodes_end(); 01425 01426 for (; it!=end; ++it) 01427 needed_nodes.push_back((*it)->id()); 01428 01429 std::sort (needed_nodes.begin(), needed_nodes.end()); 01430 01431 // We should not have any duplicate node->id()s 01432 libmesh_assert (std::unique(needed_nodes.begin(), needed_nodes.end()) == needed_nodes.end()); 01433 } 01434 01435 // Get the nodes in blocks. 01436 std::vector<Real> coords; 01437 std::pair<std::vector<dof_id_type>::iterator, 01438 std::vector<dof_id_type>::iterator> pos; 01439 pos.first = needed_nodes.begin(); 01440 01441 for (std::size_t blk=0, first_node=0, last_node=0; last_node<n_nodes; blk++) 01442 { 01443 first_node = blk*io_blksize; 01444 last_node = std::min((blk+1)*io_blksize, std::size_t(n_nodes)); 01445 01446 coords.resize(3*(last_node - first_node)); 01447 01448 if (this->processor_id() == 0) 01449 io.data_stream (coords.empty() ? NULL : &coords[0], 01450 cast_int<unsigned int>(coords.size())); 01451 01452 // For large numbers of processors the majority of processors at any given 01453 // block may not actually need these data. It may be worth profiling this, 01454 // although it is expected that disk IO will be the bottleneck 01455 this->comm().broadcast (coords); 01456 01457 for (std::size_t n=first_node, idx=0; n<last_node; n++, idx+=3) 01458 { 01459 // first see if we need this node. use pos.first as a smart lower 01460 // bound, this will ensure that the size of the searched range 01461 // decreases as we match nodes. 01462 pos = std::equal_range (pos.first, needed_nodes.end(), n); 01463 01464 if (pos.first != pos.second) // we need this node. 01465 { 01466 libmesh_assert_equal_to (*pos.first, n); 01467 mesh.node(cast_int<dof_id_type>(n)) = 01468 Point (coords[idx+0], 01469 coords[idx+1], 01470 coords[idx+2]); 01471 01472 } 01473 } 01474 } 01475 } 01476 01477 01478 01479 template <typename T> 01480 void XdrIO::read_serialized_bcs (Xdr &io, T) 01481 { 01482 if (this->boundary_condition_file_name() == "n/a") return; 01483 01484 libmesh_assert (io.reading()); 01485 01486 // convenient reference to our mesh 01487 MeshBase &mesh = MeshInput<MeshBase>::mesh(); 01488 01489 // and our boundary info object 01490 BoundaryInfo &boundary_info = mesh.get_boundary_info(); 01491 01492 // Version 0.9.2+ introduces unique ids 01493 read_serialized_bc_names(io, boundary_info, true); // sideset names 01494 01495 std::vector<DofBCData> dof_bc_data; 01496 std::vector<T> input_buffer; 01497 01498 header_id_type n_bcs=0; 01499 if (this->processor_id() == 0) 01500 io.data (n_bcs); 01501 this->comm().broadcast (n_bcs); 01502 01503 for (std::size_t blk=0, first_bc=0, last_bc=0; last_bc<n_bcs; blk++) 01504 { 01505 first_bc = blk*io_blksize; 01506 last_bc = std::min((blk+1)*io_blksize, std::size_t(n_bcs)); 01507 01508 input_buffer.resize (3*(last_bc - first_bc)); 01509 01510 if (this->processor_id() == 0) 01511 io.data_stream (input_buffer.empty() ? NULL : &input_buffer[0], 01512 cast_int<unsigned int>(input_buffer.size())); 01513 01514 this->comm().broadcast (input_buffer); 01515 dof_bc_data.clear(); dof_bc_data.reserve (input_buffer.size()/3); 01516 01517 // convert the input_buffer to DofBCData to facilitate searching 01518 for (std::size_t idx=0; idx<input_buffer.size(); idx+=3) 01519 dof_bc_data.push_back 01520 (DofBCData(cast_int<dof_id_type>(input_buffer[idx+0]), 01521 cast_int<unsigned short>(input_buffer[idx+1]), 01522 cast_int<boundary_id_type>(input_buffer[idx+2]))); 01523 input_buffer.clear(); 01524 // note that while the files *we* write should already be sorted by 01525 // element id this is not necessarily guaranteed. 01526 std::sort (dof_bc_data.begin(), dof_bc_data.end()); 01527 01528 MeshBase::const_element_iterator 01529 it = mesh.level_elements_begin(0), 01530 end = mesh.level_elements_end(0); 01531 01532 // Look for BCs in this block for all the level-0 elements we have 01533 // (not just local ones). Do this by finding all the entries 01534 // in dof_bc_data whose elem_id match the ID of the current element. 01535 // We cannot rely on NULL neighbors at this point since the neighbor 01536 // data structure has not been initialized. 01537 for (std::pair<std::vector<DofBCData>::iterator, 01538 std::vector<DofBCData>::iterator> pos; it!=end; ++it) 01539 #if defined(__SUNPRO_CC) || defined(__PGI) 01540 for (pos = std::equal_range (dof_bc_data.begin(), dof_bc_data.end(), (*it)->id(), CompareIntDofBCData()); 01541 pos.first != pos.second; ++pos.first) 01542 #else 01543 for (pos = std::equal_range (dof_bc_data.begin(), dof_bc_data.end(), (*it)->id()); 01544 pos.first != pos.second; ++pos.first) 01545 #endif 01546 { 01547 libmesh_assert_equal_to (pos.first->dof_id, (*it)->id()); 01548 libmesh_assert_less (pos.first->side, (*it)->n_sides()); 01549 01550 boundary_info.add_side (*it, pos.first->side, pos.first->bc_id); 01551 } 01552 } 01553 } 01554 01555 01556 01557 template <typename T> 01558 void XdrIO::read_serialized_nodesets (Xdr &io, T) 01559 { 01560 if (this->boundary_condition_file_name() == "n/a") return; 01561 01562 libmesh_assert (io.reading()); 01563 01564 // convenient reference to our mesh 01565 MeshBase &mesh = MeshInput<MeshBase>::mesh(); 01566 01567 // and our boundary info object 01568 BoundaryInfo &boundary_info = mesh.get_boundary_info(); 01569 01570 // Version 0.9.2+ introduces unique ids 01571 read_serialized_bc_names(io, boundary_info, false); // nodeset names 01572 01573 // TODO: Make a data object that works with both the element and nodal bcs 01574 std::vector<DofBCData> node_bc_data; 01575 std::vector<T> input_buffer; 01576 01577 header_id_type n_nodesets=0; 01578 if (this->processor_id() == 0) 01579 io.data (n_nodesets); 01580 this->comm().broadcast (n_nodesets); 01581 01582 for (std::size_t blk=0, first_bc=0, last_bc=0; last_bc<n_nodesets; blk++) 01583 { 01584 first_bc = blk*io_blksize; 01585 last_bc = std::min((blk+1)*io_blksize, std::size_t(n_nodesets)); 01586 01587 input_buffer.resize (2*(last_bc - first_bc)); 01588 01589 if (this->processor_id() == 0) 01590 io.data_stream (input_buffer.empty() ? NULL : &input_buffer[0], 01591 cast_int<unsigned int>(input_buffer.size())); 01592 01593 this->comm().broadcast (input_buffer); 01594 node_bc_data.clear(); node_bc_data.reserve (input_buffer.size()/2); 01595 01596 // convert the input_buffer to DofBCData to facilitate searching 01597 for (std::size_t idx=0; idx<input_buffer.size(); idx+=2) 01598 node_bc_data.push_back 01599 (DofBCData(cast_int<dof_id_type>(input_buffer[idx+0]), 01600 0, 01601 cast_int<boundary_id_type>(input_buffer[idx+1]))); 01602 input_buffer.clear(); 01603 // note that while the files *we* write should already be sorted by 01604 // node id this is not necessarily guaranteed. 01605 std::sort (node_bc_data.begin(), node_bc_data.end()); 01606 01607 MeshBase::const_node_iterator 01608 it = mesh.nodes_begin(), 01609 end = mesh.nodes_end(); 01610 01611 // Look for BCs in this block for all nodes we have 01612 // (not just local ones). Do this by finding all the entries 01613 // in node_bc_data whose dof_id(node_id) match the ID of the current node. 01614 for (std::pair<std::vector<DofBCData>::iterator, 01615 std::vector<DofBCData>::iterator> pos; it!=end; ++it) 01616 #if defined(__SUNPRO_CC) || defined(__PGI) 01617 for (pos = std::equal_range (node_bc_data.begin(), node_bc_data.end(), (*it)->id(), CompareIntDofBCData()); 01618 pos.first != pos.second; ++pos.first) 01619 #else 01620 for (pos = std::equal_range (node_bc_data.begin(), node_bc_data.end(), (*it)->id()); 01621 pos.first != pos.second; ++pos.first) 01622 #endif 01623 { 01624 // Note: dof_id from ElmeBCData is being used to hold node_id here 01625 libmesh_assert_equal_to (pos.first->dof_id, (*it)->id()); 01626 01627 boundary_info.add_node (*it, pos.first->bc_id); 01628 } 01629 } 01630 } 01631 01632 01633 01634 void XdrIO::read_serialized_bc_names(Xdr &io, BoundaryInfo & info, bool is_sideset) 01635 { 01636 const bool read_entity_info = this->version().find("0.9.2") != std::string::npos ? true : false; 01637 if (read_entity_info) 01638 { 01639 header_id_type n_boundary_names = 0; 01640 std::vector<header_id_type> boundary_ids; 01641 std::vector<std::string> boundary_names; 01642 01643 // Read the sideset names 01644 if (this->processor_id() == 0) 01645 { 01646 io.data(n_boundary_names); 01647 01648 boundary_ids.resize(n_boundary_names); 01649 boundary_names.resize(n_boundary_names); 01650 01651 if (n_boundary_names) 01652 { 01653 io.data(boundary_ids); 01654 io.data(boundary_names); 01655 } 01656 } 01657 01658 // Broadcast the boundary names to all processors 01659 this->comm().broadcast(n_boundary_names); 01660 if (n_boundary_names == 0) 01661 return; 01662 01663 boundary_ids.resize(n_boundary_names); 01664 boundary_names.resize(n_boundary_names); 01665 this->comm().broadcast(boundary_ids); 01666 this->comm().broadcast(boundary_names); 01667 01668 // Reassemble the named boundary information 01669 std::map<boundary_id_type, std::string> & boundary_map = is_sideset ? 01670 info.set_sideset_name_map() : info.set_nodeset_name_map(); 01671 01672 for (unsigned int i=0; i<n_boundary_names; ++i) 01673 boundary_map.insert(std::make_pair(boundary_ids[i], boundary_names[i])); 01674 } 01675 } 01676 01677 01678 01679 void XdrIO::pack_element (std::vector<xdr_id_type> &conn, const Elem *elem, 01680 const dof_id_type parent_id, const dof_id_type parent_pid) const 01681 { 01682 libmesh_assert(elem); 01683 libmesh_assert_equal_to (elem->n_nodes(), Elem::type_to_n_nodes_map[elem->type()]); 01684 01685 conn.push_back(elem->n_nodes()); 01686 01687 conn.push_back (elem->type()); 01688 01689 // In version 0.7.0+ "id" is stored but it not used. In version 0.9.2+ 01690 // we will store unique_id instead, therefore there is no need to 01691 // check for the older version when writing the unique_id. 01692 conn.push_back (elem->unique_id()); 01693 01694 if (parent_id != DofObject::invalid_id) 01695 { 01696 conn.push_back (parent_id); 01697 libmesh_assert_not_equal_to (parent_pid, DofObject::invalid_id); 01698 conn.push_back (parent_pid); 01699 } 01700 01701 conn.push_back (elem->processor_id()); 01702 conn.push_back (elem->subdomain_id()); 01703 01704 #ifdef LIBMESH_ENABLE_AMR 01705 conn.push_back (elem->p_level()); 01706 #endif 01707 01708 for (unsigned int n=0; n<elem->n_nodes(); n++) 01709 conn.push_back (elem->node(n)); 01710 } 01711 01712 } // namespace libMesh