$extrastylesheet
xdr_io.C
Go to the documentation of this file.
00001 // The libMesh Finite Element Library.
00002 // Copyright (C) 2002-2014 Benjamin S. Kirk, John W. Peterson, Roy H. Stogner
00003 
00004 // This library is free software; you can redistribute it and/or
00005 // modify it under the terms of the GNU Lesser General Public
00006 // License as published by the Free Software Foundation; either
00007 // version 2.1 of the License, or (at your option) any later version.
00008 
00009 // This library is distributed in the hope that it will be useful,
00010 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00011 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00012 // Lesser General Public License for more details.
00013 
00014 // You should have received a copy of the GNU Lesser General Public
00015 // License along with this library; if not, write to the Free Software
00016 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00017 
00018 
00019 
00020 // C++ includes
00021 #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