$extrastylesheet
legacy_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 
00024 #include <vector>
00025 #include <string>
00026 
00027 // Local includes
00028 #include "libmesh/legacy_xdr_io.h"
00029 #include "libmesh/mesh_base.h"
00030 #include "libmesh/mesh_data.h"
00031 #include "libmesh/mesh_tools.h" // MeshTools::n_levels(mesh)
00032 #include "libmesh/parallel.h"   // - which makes write parallel-only
00033 #include "libmesh/cell_hex27.h" // Needed for MGF-style Hex27 meshes
00034 #include "libmesh/boundary_info.h"
00035 #include "libmesh/libmesh_logging.h"
00036 #include "libmesh/xdr_mgf.h"
00037 #include "libmesh/xdr_mesh.h"
00038 #include "libmesh/xdr_mhead.h"
00039 #include "libmesh/xdr_soln.h"
00040 #include "libmesh/xdr_shead.h"
00041 
00042 #ifdef LIBMESH_USE_COMPLEX_NUMBERS
00043 #include "libmesh/utility.h"
00044 #endif
00045 
00046 
00047 namespace libMesh
00048 {
00049 
00050 
00051 
00052 
00053 
00054 
00055 // ------------------------------------------------------------
00056 // LegacyXdrIO members
00057 LegacyXdrIO::LegacyXdrIO (MeshBase& mesh, const bool binary_in) :
00058   MeshInput<MeshBase> (mesh),
00059   MeshOutput<MeshBase>(mesh),
00060   _binary (binary_in)
00061 {
00062 }
00063 
00064 
00065 
00066 
00067 LegacyXdrIO::LegacyXdrIO (const MeshBase& mesh, const bool binary_in) :
00068   MeshOutput<MeshBase>(mesh),
00069   _binary (binary_in)
00070 {
00071 }
00072 
00073 
00074 
00075 
00076 LegacyXdrIO::~LegacyXdrIO ()
00077 {
00078 }
00079 
00080 
00081 
00082 
00083 bool & LegacyXdrIO::binary ()
00084 {
00085   return _binary;
00086 }
00087 
00088 
00089 
00090 
00091 bool LegacyXdrIO::binary () const
00092 {
00093   return _binary;
00094 }
00095 
00096 
00097 
00098 void LegacyXdrIO::read (const std::string& name)
00099 {
00100   // This is a serial-only process for now;
00101   // the Mesh should be read on processor 0 and
00102   // broadcast later
00103   if (MeshOutput<MeshBase>::mesh().processor_id() != 0)
00104     return;
00105 
00106   if (this->binary())
00107     this->read_binary (name);
00108   else
00109     this->read_ascii  (name);
00110 }
00111 
00112 
00113 
00114 void LegacyXdrIO::read_mgf (const std::string& name)
00115 {
00116   if (this->binary())
00117     this->read_binary (name, LegacyXdrIO::MGF);
00118   else
00119     this->read_ascii  (name, LegacyXdrIO::MGF);
00120 }
00121 
00122 
00123 
00124 void LegacyXdrIO::write (const std::string& name)
00125 {
00126   if (this->binary())
00127     this->write_binary (name);
00128   else
00129     this->write_ascii  (name);
00130 }
00131 
00132 
00133 
00134 void LegacyXdrIO::write_mgf (const std::string& name)
00135 {
00136   if (this->binary())
00137     this->write_binary (name, LegacyXdrIO::MGF);
00138   else
00139     this->write_ascii  (name, LegacyXdrIO::MGF);
00140 }
00141 
00142 
00143 
00144 void LegacyXdrIO::read_mgf_soln (const std::string& name,
00145                                  std::vector<Number>& soln,
00146                                  std::vector<std::string>& var_names) const
00147 {
00148   libmesh_deprecated();
00149 
00150 #ifdef LIBMESH_USE_COMPLEX_NUMBERS
00151 
00152   // buffer for writing separately
00153   std::vector<Real> real_soln;
00154   std::vector<Real> imag_soln;
00155 
00156   Utility::prepare_complex_data (soln, real_soln, imag_soln);
00157 
00158   this->read_soln (Utility::complex_filename(name, 0),
00159                    real_soln,
00160                    var_names);
00161 
00162   this->read_soln (Utility::complex_filename(name, 1),
00163                    imag_soln,
00164                    var_names);
00165 
00166 #else
00167 
00168   this->read_soln (name, soln, var_names);
00169 
00170 #endif
00171 }
00172 
00173 
00174 
00175 void LegacyXdrIO::write_mgf_soln (const std::string& name,
00176                                   std::vector<Number>& soln,
00177                                   std::vector<std::string>& var_names) const
00178 {
00179   libmesh_deprecated();
00180 
00181 #ifdef LIBMESH_USE_COMPLEX_NUMBERS
00182 
00183   // buffer for writing separately
00184   std::vector<Real> real_soln;
00185   std::vector<Real> imag_soln;
00186 
00187   Utility::prepare_complex_data (soln, real_soln, imag_soln);
00188 
00189   this->write_soln (Utility::complex_filename(name, 0),
00190                     real_soln,
00191                     var_names);
00192 
00193   this->write_soln (Utility::complex_filename(name, 1),
00194                     imag_soln,
00195                     var_names);
00196 
00197 #else
00198 
00199   this->write_soln (name, soln, var_names);
00200 
00201 #endif
00202 }
00203 
00204 
00205 
00206 void LegacyXdrIO::read_ascii (const std::string& name, const LegacyXdrIO::FileFormat originator)
00207 {
00208   // get a writeable reference to the underlying mesh
00209   MeshBase& mesh = MeshInput<MeshBase>::mesh();
00210 
00211   // clear any existing mesh data
00212   mesh.clear();
00213 
00214   // read the mesh
00215   this->read_mesh (name, originator);
00216 }
00217 
00218 
00219 
00220 #ifndef LIBMESH_HAVE_XDR
00221 void LegacyXdrIO::read_binary (const std::string& name, const LegacyXdrIO::FileFormat)
00222 {
00223 
00224   libMesh::err << "WARNING: Compiled without XDR binary support.\n"
00225                << "Will try ASCII instead" << std::endl << std::endl;
00226 
00227   this->read_ascii (name);
00228 }
00229 #else
00230 void LegacyXdrIO::read_binary (const std::string& name, const LegacyXdrIO::FileFormat originator)
00231 {
00232   // get a writeable reference to the underlying mesh
00233   MeshBase& mesh = MeshInput<MeshBase>::mesh();
00234 
00235   // clear any existing mesh data
00236   mesh.clear();
00237 
00238   // read the mesh
00239   this->read_mesh (name, originator);
00240 }
00241 #endif
00242 
00243 
00244 
00245 void LegacyXdrIO::write_ascii (const std::string& name, const LegacyXdrIO::FileFormat originator)
00246 {
00247   this->write_mesh (name, originator);
00248 }
00249 
00250 
00251 
00252 #ifndef LIBMESH_HAVE_XDR
00253 void LegacyXdrIO::write_binary (const std::string& name, const LegacyXdrIO::FileFormat)
00254 {
00255   libMesh::err << "WARNING: Compiled without XDR binary support.\n"
00256                << "Will try ASCII instead" << std::endl << std::endl;
00257 
00258   this->write_ascii (name);
00259 }
00260 #else
00261 void LegacyXdrIO::write_binary (const std::string& name, const LegacyXdrIO::FileFormat originator)
00262 {
00263   this->write_mesh (name, originator);
00264 }
00265 #endif
00266 
00267 
00268 
00269 void LegacyXdrIO::read_mesh (const std::string& name,
00270                              const LegacyXdrIO::FileFormat originator,
00271                              MeshData* mesh_data)
00272 {
00273   // This is a serial-only process for now;
00274   // the Mesh should be read on processor 0 and
00275   // broadcast later
00276   libmesh_assert_equal_to (MeshOutput<MeshBase>::mesh().processor_id(), 0);
00277 
00278   // get a writeable reference to the mesh
00279   MeshBase& mesh = MeshInput<MeshBase>::mesh();
00280 
00281   // clear any data in the mesh
00282   mesh.clear();
00283 
00284   // Keep track of what kinds of elements this file contains
00285   elems_of_dimension.clear();
00286   elems_of_dimension.resize(4, false);
00287 
00288   // Create an XdrMESH object.
00289   XdrMESH m;
00290 
00291   // Create a pointer
00292   // to an XdrMESH file
00293   // header.
00294   XdrMHEAD mh;
00295 
00296   // Open the XDR file for reading.
00297   // Note 1: Provide an additional argument
00298   // to specify the dimension.
00299   //
00300   // Note 2: Has to do the right thing for
00301   // both binary and ASCII files.
00302   m.set_orig_flag(originator);
00303   m.init((this->binary() ? XdrMGF::DECODE : XdrMGF::R_ASCII), name.c_str(), 0); // mesh files are always number 0 ...
00304 
00305   // From here on, things depend
00306   // on whether we are reading or
00307   // writing!  First, we define
00308   // header variables that may
00309   // be read OR written.
00310   unsigned int              n_blocks = 0;
00311   unsigned int              n_levels = 0;
00312 
00313   if (m.get_orig_flag() == LegacyXdrIO::LIBM)
00314     n_levels = m.get_num_levels();
00315 
00316 
00317   std::vector<ElemType>     etypes;
00318   std::vector<unsigned int> neeb;
00319 
00320   // Get the information from
00321   // the header, and place it
00322   // in the header pointer.
00323   m.header(&mh);
00324 
00325   // Read information from the
00326   // file header.  This depends on
00327   // whether its a libMesh or MGF mesh.
00328   const int numElem     = mh.getNumEl();
00329   const int numNodes    = mh.getNumNodes();
00330   const int totalWeight = mh.getSumWghts();
00331   const int numBCs      = mh.getNumBCs();
00332 
00333   // If a libMesh-type mesh, read the augmented mesh information
00334   if ((m.get_orig_flag() == LegacyXdrIO::DEAL) || (m.get_orig_flag() == LegacyXdrIO::LIBM))
00335     {
00336       // Read augmented header
00337       n_blocks = mh.get_n_blocks();
00338 
00339       etypes.resize(n_blocks);
00340       mh.get_block_elt_types(etypes);
00341 
00342       mh.get_num_elem_each_block(neeb);
00343     }
00344 
00345 
00346 
00347   // Read the connectivity
00348   std::vector<int> conn;
00349 
00350   // Now that we know the
00351   // number of nodes and elements,
00352   // we can resize the
00353   // appropriate vectors if we are
00354   // reading information in.
00355   mesh.reserve_nodes (numNodes);
00356   mesh.reserve_elem  (numElem);
00357 
00358   // Each element stores two extra
00359   // locations: one which tells
00360   // what type of element it is,
00361   // and one which tells how many
00362   // nodes it has. Therefore,
00363   // the total number of nodes
00364   // (totalWeight) must be augmented
00365   // by 2 times the number of elements
00366   // in order to read in the entire
00367   // connectivity array.
00368 
00369   // Note: This section now depends on
00370   // whether we are reading an old-style libMesh,
00371   // MGF, or a new-style libMesh mesh.
00372   if (m.get_orig_flag() == LegacyXdrIO::DEAL)
00373     {
00374       conn.resize(totalWeight);
00375       m.Icon(&conn[0], 1, totalWeight);
00376     }
00377 
00378   else if (m.get_orig_flag() == LegacyXdrIO::MGF)
00379     {
00380       conn.resize(totalWeight+(2*numElem));
00381       m.Icon(&conn[0], 1, totalWeight+(2*numElem));
00382     }
00383 
00384   else if (m.get_orig_flag() == LegacyXdrIO::LIBM)
00385     {
00386       conn.resize(totalWeight);
00387       m.Icon(&conn[0], 1, totalWeight);
00388     }
00389 
00390   else
00391     {
00392       // I don't know what type of mesh it is.
00393       libmesh_error_msg("Unrecognized flag " << m.get_orig_flag());
00394     }
00395 
00396   // read in the nodal coordinates and form points.
00397   {
00398     std::vector<Real> coords(numNodes*3); // Always use three coords per node
00399     m.coord(&coords[0], 3, numNodes);
00400 
00401 
00402 
00403     // Form Nodes out of
00404     // the coordinates.  If the
00405     // MeshData object is active,
00406     // add the nodes and ids also
00407     // to its map.
00408     for (int innd=0; innd<numNodes; ++innd)
00409       {
00410         Node* node = mesh.add_point (Point(coords[0+innd*3],
00411                                            coords[1+innd*3],
00412                                            coords[2+innd*3]), innd);
00413 
00414         if (mesh_data != NULL)
00415           if (mesh_data->active())
00416             {
00417               // add the id to the MeshData, so that
00418               // it knows the foreign id, even when
00419               // the underlying mesh got re-numbered,
00420               // refined, elements/nodes added...
00421               mesh_data->add_foreign_node_id(node, innd);
00422             }
00423       }
00424   }
00425 
00426 
00427 
00428   // Build the elements.
00429   // Note: If the originator was MGF, we don't
00430   // have to do much checking ...
00431   // all the elements are Hex27.
00432   // If the originator was
00433   // this code, we have to loop over
00434   // et and neeb to read in all the
00435   // elements correctly.
00436   //
00437   // (This used to be before the coords block, but it
00438   // had to change now that elements store pointers to
00439   // nodes.  The nodes must exist before we assign them to
00440   // the elements. BSK, 1/13/2003)
00441   if ((m.get_orig_flag() == LegacyXdrIO::DEAL) || (m.get_orig_flag() == LegacyXdrIO::LIBM))
00442     {
00443       // This map keeps track of elements we've previously
00444       // constructed, to avoid O(n) lookup times for parent pointers
00445       // and to enable elements to be added in ascending ID order
00446       std::map<unsigned int, Elem*> parents;
00447 
00448       {
00449         unsigned int lastConnIndex = 0;
00450         unsigned int lastFaceIndex = 0;
00451 
00452         // Keep track of Element ids in MGF-style meshes;
00453         unsigned int next_elem_id = 0;
00454 
00455         for (unsigned int level=0; level<=n_levels; level++)
00456           {
00457             for (unsigned int idx=0; idx<n_blocks; idx++)
00458               {
00459                 for (unsigned int e=lastFaceIndex; e<lastFaceIndex+neeb[level*n_blocks+idx]; e++)
00460                   {
00461                     // Build a temporary element of the right type, so we know how
00462                     // connectivity entries will be on the line for this element.
00463                     UniquePtr<Elem> temp_elem = Elem::build(etypes[idx]);
00464 
00465                     // A pointer to the element which will eventually be added to the mesh.
00466                     Elem* elem;
00467 
00468                     // New-style libMesh mesh
00469                     if (m.get_orig_flag() == LegacyXdrIO::LIBM)
00470                       {
00471                         unsigned int self_ID   = conn[lastConnIndex + temp_elem->n_nodes()];
00472 
00473 #ifdef LIBMESH_ENABLE_AMR
00474                         unsigned int parent_ID = conn[lastConnIndex + temp_elem->n_nodes()+1];
00475 
00476                         if (level > 0)
00477                           {
00478                             // Do a linear search for the parent
00479                             Elem* my_parent;
00480 
00481                             // Search for parent in the parents map (log(n))
00482                             START_LOG("log(n) search for parent", "LegacyXdrIO::read_mesh");
00483                             std::map<unsigned int, Elem*>::iterator it = parents.find(parent_ID);
00484                             STOP_LOG("log(n) search for parent", "LegacyXdrIO::read_mesh");
00485 
00486                             // If the parent was not previously added, we cannot continue.
00487                             if (it == parents.end())
00488                               libmesh_error_msg("Parent element with ID " << parent_ID << " not found.");
00489 
00490                             // Set the my_parent pointer
00491                             my_parent = (*it).second;
00492 
00493                             // my_parent is now INACTIVE, since he has children
00494                             my_parent->set_refinement_flag(Elem::INACTIVE);
00495 
00496                             // Now that we know the parent, build the child
00497                             elem = Elem::build(etypes[idx],my_parent).release();
00498 
00499                             // The new child is marked as JUST_REFINED
00500                             elem->set_refinement_flag(Elem::JUST_REFINED);
00501 
00502                             // Tell the parent about his new child
00503                             my_parent->add_child(elem);
00504 
00505                             // sanity check
00506                             libmesh_assert_equal_to (my_parent->type(), elem->type());
00507                           }
00508 
00509                         // Add level-0 elements to the mesh
00510                         else
00511 #endif // #ifdef LIBMESH_ENABLE_AMR
00512                           {
00513                             elem = Elem::build(etypes[idx]).release();
00514                           }
00515 
00516                         // Assign the newly-added element's ID so that future
00517                         // children which may be added can find it correctly.
00518                         elem->set_id() = self_ID;
00519 
00520                         // Add this element to the map, it may be a parent for a future element
00521                         START_LOG("insert elem into map", "LegacyXdrIO::read_mesh");
00522                         parents[self_ID] = elem;
00523                         STOP_LOG("insert elem into map", "LegacyXdrIO::read_mesh");
00524                       }
00525 
00526                     // MGF-style meshes
00527                     else
00528                       {
00529                         elem = Elem::build(etypes[idx]).release();
00530                         elem->set_id(next_elem_id++);
00531 
00532                         elems_of_dimension[elem->dim()] = true;
00533 
00534                         mesh.add_elem(elem);
00535                       }
00536 
00537                     // Add elements with the same id as in libMesh.
00538                     // Provided the data files that MeshData reads
00539                     // were only written with MeshData, then this
00540                     // should work properly.  This is an inline
00541                     // function, so that for disabled MeshData, this
00542                     // should not induce too much cost
00543                     if (mesh_data != NULL)
00544                       mesh_data->add_foreign_elem_id (elem, e);
00545 
00546                     // Set the node pointers of the newly-created element
00547                     for (unsigned int innd=0; innd < elem->n_nodes(); innd++)
00548                       {
00549                         elem->set_node(innd) = mesh.node_ptr(conn[innd+lastConnIndex]);
00550                       }
00551 
00552                     lastConnIndex += (m.get_orig_flag() == LegacyXdrIO::LIBM) ? (elem->n_nodes()+2) : elem->n_nodes();
00553                   }
00554                 lastFaceIndex += neeb[idx];
00555               }
00556           }
00557       }
00558 
00559       if (m.get_orig_flag() == LegacyXdrIO::LIBM)
00560         {
00561           {
00562             // Iterate in ascending elem ID order
00563             unsigned int next_elem_id = 0;
00564             for (std::map<unsigned int, Elem *>::iterator i =
00565                    parents.begin();
00566                  i != parents.end(); ++i)
00567               {
00568                 Elem *elem = i->second;
00569                 if (elem)
00570                   {
00571                     elem->set_id(next_elem_id++);
00572 
00573                     elems_of_dimension[elem->dim()] = true;
00574 
00575                     mesh.add_elem(elem);
00576                   }
00577                 else
00578                   // We can probably handle this, but we don't expect it
00579                   libmesh_error_msg("Unexpected NULL elem encountered while reading libmesh XDR file.");
00580               }
00581           }
00582         }
00583     }
00584 
00585   // MGF-style (1) Hex27 mesh
00586   else if (m.get_orig_flag() == LegacyXdrIO::MGF)
00587     {
00588 
00589 #ifdef DEBUG
00590       if (mesh_data != NULL)
00591         if (mesh_data->active())
00592           libmesh_error_msg("ERROR: MeshData not implemented for MGF-style mesh.");
00593 #endif
00594 
00595       for (int ielm=0; ielm < numElem; ++ielm)
00596         {
00597           Elem* elem = new Hex27;
00598           elem->set_id(ielm);
00599 
00600           elems_of_dimension[elem->dim()] = true;
00601 
00602           mesh.add_elem(elem);
00603 
00604           for (int innd=0; innd < 27; ++innd)
00605             elem->set_node(innd) = mesh.node_ptr(conn[innd+2+(27+2)*ielm]);
00606         }
00607     }
00608 
00609   // Set the mesh dimension to the largest encountered for an element
00610   for (unsigned char i=0; i!=4; ++i)
00611     if (elems_of_dimension[i])
00612       mesh.set_mesh_dimension(i);
00613 
00614 #if LIBMESH_DIM < 3
00615   if (mesh.mesh_dimension() > LIBMESH_DIM)
00616     libmesh_error_msg("Cannot open dimension "              \
00617                       << mesh.mesh_dimension()                          \
00618                       << " mesh file when configured without "          \
00619                       << mesh.mesh_dimension()                          \
00620                       << "D support." );
00621 #endif
00622 
00623   // tell the MeshData object that we are finished
00624   // reading data
00625   if (mesh_data != NULL)
00626     mesh_data->close_foreign_id_maps ();
00627 
00628   // Free memory used in
00629   // the connectivity
00630   // vector.
00631   conn.clear();
00632 
00633 
00634   // If we are reading,
00635   // read in the BCs
00636   // from the mesh file,
00637   // otherwise write the
00638   // boundary conditions
00639   // if the BoundaryInfo
00640   // object exists.
00641   if (numBCs > 0)
00642     {
00643       std::vector<int> bcs(numBCs*3);
00644 
00645       // Read the BCs from the XDR file
00646       m.BC(&bcs[0], numBCs);
00647 
00648       // Add to the boundary_info
00649       for (int ibc=0; ibc < numBCs; ibc++)
00650         mesh.get_boundary_info().add_side
00651           (cast_int<dof_id_type>(bcs[0+ibc*3]),
00652            cast_int<unsigned short>(bcs[1+ibc*3]),
00653            cast_int<boundary_id_type>(bcs[2+ibc*3]));
00654     }
00655 }
00656 
00657 
00658 
00659 void LegacyXdrIO::write_mesh (const std::string& name,
00660                               const LegacyXdrIO::FileFormat originator)
00661 {
00662   // get a read-only reference to the mesh
00663   const MeshBase& mesh = MeshOutput<MeshBase>::mesh();
00664 
00665   // n_levels is a parallel-only method
00666   libmesh_parallel_only(mesh.comm());
00667   const unsigned int          n_levels = MeshTools::n_levels(mesh);
00668 
00669   // The Legacy Xdr IO code only works if we have a serialized mesh
00670   libmesh_assert (mesh.is_serial());
00671 
00672   // In which case only processor 0 needs to do any writing
00673   if (MeshOutput<MeshBase>::mesh().processor_id() != 0)
00674     return;
00675 
00676   // Create an XdrMESH object.
00677   XdrMESH m;
00678 
00679   // Create a pointer
00680   // to an XdrMESH file
00681   // header.
00682   XdrMHEAD mh;
00683 
00684   // Open the XDR file for writing.
00685   // Note 1: Provide an additional argument
00686   // to specify the dimension.
00687   //
00688   // Note 2: Has to do the right thing for
00689   // both binary and ASCII files.
00690   m.set_orig_flag(originator);
00691 
00692   // From here on, things depend
00693   // on whether we are reading or
00694   // writing!  First, we define
00695   // header variables that may
00696   // be read OR written.
00697   std::vector<unsigned int> neeb;
00698   std::vector<ElemType> etypes;
00699 
00700 
00701   int n_non_subactive = 0;
00702   int non_subactive_weight = 0;
00703 
00704   // This map will associate
00705   // the distance from the beginning of the set
00706   // to each node ID with the node ID itself.
00707   std::map<dof_id_type, dof_id_type> node_map;
00708 
00709   {
00710     // For each non-subactive element:
00711     // 1.) Increment the number of non subactive elements
00712     // 2.) Accumulate the total weight
00713     // 3.) Add the node ids to a set of non subactive node ids
00714     std::set<dof_id_type> not_subactive_node_ids;
00715     MeshBase::const_element_iterator el = mesh.elements_begin();
00716     const MeshBase::const_element_iterator end_el = mesh.elements_end();
00717     for( ; el != end_el; ++el)
00718       {
00719         const Elem* elem = (*el);
00720         if(!elem->subactive())
00721           {
00722             n_non_subactive++;
00723             non_subactive_weight += elem->n_nodes();
00724 
00725             for (unsigned int n=0; n<elem->n_nodes(); ++n)
00726               not_subactive_node_ids.insert(elem->node(n));
00727           }
00728       }
00729 
00730     // Now that the set is built, most of the hard work is done.  We build
00731     // the map next and let the set go out of scope.
00732     std::set<dof_id_type>::iterator it = not_subactive_node_ids.begin();
00733     const std::set<dof_id_type>::iterator end = not_subactive_node_ids.end();
00734     dof_id_type cnt=0;
00735     for (; it!=end; ++it)
00736       node_map[*it] = cnt++;
00737   }
00738 
00739 
00740   const int numElem = n_non_subactive;
00741   const int numBCs  =
00742     cast_int<int>(mesh.get_boundary_info().n_boundary_conds());
00743 
00744   // Fill the etypes vector with all of the element types found in the mesh
00745   MeshTools::elem_types(mesh, etypes);
00746 
00747   // store number of elements in each block at each refinement level
00748   neeb.resize((n_levels+1)*etypes.size());
00749 
00750   // Store a variable for the number of element types
00751   const unsigned int n_el_types =
00752     cast_int<unsigned int>(etypes.size());
00753 
00754   m.set_num_levels(n_levels);
00755 
00756   // The last argument is zero because mesh files are always number 0 ...
00757   m.init((this->binary() ? XdrMGF::ENCODE : XdrMGF::W_ASCII), name.c_str(), 0);
00758 
00759   // Loop over all levels and all element types to set the entries of neeb
00760   for(unsigned int level=0; level<=n_levels; level++)
00761     for (unsigned int el_type=0; el_type<n_el_types; el_type++)
00762       neeb[level*n_el_types + el_type] =
00763         MeshTools::n_non_subactive_elem_of_type_at_level(mesh, etypes[el_type], level);
00764   // gotta change this function name!!!
00765 
00766 
00767   // Now we check to see if we're doing
00768   // MGF-style headers or libMesh-style
00769   // "augmented" headers.  An
00770   // augmented header contains
00771   // information about mesh blocks,
00772   // allowing us to optimize storage
00773   // and minimize IO requirements
00774   // for these meshes.
00775   if ((m.get_orig_flag() == LegacyXdrIO::DEAL) || (m.get_orig_flag() == LegacyXdrIO::LIBM))
00776     {
00777       mh.set_n_blocks(cast_int<unsigned int>(etypes.size()));
00778       mh.set_block_elt_types(etypes);
00779       mh.set_num_elem_each_block(neeb);
00780     }
00781   else
00782     libmesh_assert_equal_to (etypes.size(), 1);
00783 
00784   mh.setNumEl(numElem);
00785   mh.setNumNodes(cast_int<int>(node_map.size()));
00786   mh.setStrSize(65536);
00787 
00788   // set a local variable for the total weight of the mesh
00789   int totalWeight =0;
00790 
00791   if (m.get_orig_flag() == LegacyXdrIO::DEAL)  // old-style LibMesh
00792     totalWeight=MeshTools::total_weight(mesh);
00793 
00794   else if (m.get_orig_flag() == LegacyXdrIO::MGF) // MGF-style
00795     totalWeight = MeshTools::total_weight(mesh)+2*numElem;
00796 
00797   else if (m.get_orig_flag() == LegacyXdrIO::LIBM) // new-style LibMesh
00798     totalWeight = non_subactive_weight+2*numElem;
00799 
00800   else
00801     libmesh_error_msg("Unrecognized flag " << m.get_orig_flag());
00802 
00803   // Set the total weight in the header
00804   mh.setSumWghts(totalWeight);
00805 
00806   mh.setNumBCs(numBCs);
00807   mh.setId("Id String");       // You can put whatever you want, it will be ignored
00808   mh.setTitle("Title String"); // You can put whatever you want, it will be ignored
00809 
00810   // Put the information
00811   // in the XDR file.
00812   m.header(&mh);
00813 
00814 
00815   // Write the connectivity
00816   {
00817     std::vector<int> conn;
00818     LegacyXdrIO::FileFormat orig_type = m.get_orig_flag();
00819 
00820     // Resize the connectivity vector to hold all the connectivity for the mesh
00821     conn.resize(totalWeight);
00822 
00823     unsigned int lastConnIndex = 0;
00824     unsigned int nn = 0;
00825 
00826     // Loop over levels and types again, write connectivity information to conn.
00827     for (unsigned int level=0; level<=n_levels; level++)
00828       for (unsigned int idx=0; idx<etypes.size(); idx++)
00829         {
00830           nn = lastConnIndex = 0;
00831 
00832           for (unsigned int e=0; e<mesh.n_elem(); e++)
00833             if ((mesh.elem(e)->type()  == etypes[idx]) &&
00834                 (mesh.elem(e)->level() == level)       &&
00835                 !mesh.elem(e)->subactive())
00836               {
00837                 int nstart=0;
00838 
00839                 if (orig_type == LegacyXdrIO::DEAL)
00840                   nn = mesh.elem(e)->n_nodes();
00841 
00842                 else if (orig_type == LegacyXdrIO::MGF)
00843                   {
00844                     nstart=2; // ignore the 27 and 0 entries
00845                     nn = mesh.elem(e)->n_nodes()+2;
00846                     conn[lastConnIndex + 0] = 27;
00847                     conn[lastConnIndex + 1] = 0;
00848                   }
00849 
00850                 else if (orig_type == LegacyXdrIO::LIBM) // LIBMESH format
00851                   nn = mesh.elem(e)->n_nodes() + 2;
00852 
00853                 else
00854                   libmesh_error_msg("Unrecognized orig_type = " << orig_type);
00855 
00856                 // Loop over the connectivity entries for this element and write to conn.
00857                 START_LOG("set connectivity", "LegacyXdrIO::write_mesh");
00858                 const unsigned int loopmax = (orig_type==LegacyXdrIO::LIBM) ? nn-2 : nn;
00859                 for (unsigned int n=nstart; n<loopmax; n++)
00860                   {
00861                     unsigned int connectivity_value=0;
00862 
00863                     // old-style Libmesh and MGF meshes
00864                     if (orig_type != LegacyXdrIO::LIBM)
00865                       connectivity_value = mesh.elem(e)->node(n-nstart);
00866 
00867                     // new-style libMesh meshes: compress the connectivity entries to account for
00868                     // subactive nodes that will not be in the mesh we write out.
00869                     else
00870                       {
00871                         std::map<dof_id_type, dof_id_type>::iterator pos =
00872                           node_map.find(mesh.elem(e)->node(n-nstart));
00873 
00874                         libmesh_assert (pos != node_map.end());
00875 
00876                         connectivity_value = (*pos).second;
00877                       }
00878                     conn[lastConnIndex + n] = connectivity_value;
00879                   }
00880                 STOP_LOG("set connectivity", "LegacyXdrIO::write_mesh");
00881 
00882                 // In the case of an adaptive mesh, set last 2 entries to this ID and parent ID
00883                 if (orig_type == LegacyXdrIO::LIBM)
00884                   {
00885                     int self_ID = mesh.elem(e)->id();
00886                     int parent_ID = -1;
00887                     if(level != 0)
00888                       parent_ID = mesh.elem(e)->parent()->id();
00889 
00890                     // Self ID is the second-to-last entry, Parent ID is the last
00891                     // entry on each connectivity line
00892                     conn[lastConnIndex+nn-2] = self_ID;
00893                     conn[lastConnIndex+nn-1] = parent_ID;
00894                   }
00895 
00896                 lastConnIndex += nn;
00897               }
00898 
00899           // Send conn to the XDR file.  If there are no elements of this level and type,
00900           // then nn will be zero, and we there is no connectivity to write.
00901           if (nn != 0)
00902             m.Icon(&conn[0], nn, lastConnIndex/nn);
00903         }
00904   }
00905 
00906   // create the vector of coords and send
00907   // it to the XDR file.
00908   {
00909     std::vector<Real> coords;
00910 
00911     coords.resize(3*node_map.size());
00912     int lastIndex=0;
00913 
00914     std::map<dof_id_type,dof_id_type>::iterator it = node_map.begin();
00915     const std::map<dof_id_type,dof_id_type>::iterator end = node_map.end();
00916     for (; it != end; ++it)
00917       {
00918         const Point& p = mesh.node((*it).first);
00919 
00920         coords[lastIndex+0] = p(0);
00921         coords[lastIndex+1] = p(1);
00922         coords[lastIndex+2] = p(2);
00923         lastIndex += 3;
00924       }
00925 
00926     // Put the nodes in the XDR file
00927     m.coord(&coords[0], 3, cast_int<int>(node_map.size()));
00928   }
00929 
00930 
00931   // write the
00932   // boundary conditions
00933   // if the BoundaryInfo
00934   // object exists.
00935   if (numBCs > 0)
00936     {
00937       std::vector<int> bcs(numBCs*3);
00938 
00939       //libMesh::out << "numBCs=" << numBCs << std::endl;
00940 
00941       //libMesh::out << "Preparing to write boundary conditions." << std::endl;
00942       std::vector<dof_id_type> elem_list;
00943       std::vector<unsigned short int> side_list;
00944       std::vector<boundary_id_type> elem_id_list;
00945 
00946       mesh.get_boundary_info().build_side_list (elem_list, side_list, elem_id_list);
00947 
00948       for (int ibc=0;  ibc<numBCs; ibc++)
00949         {
00950           bcs[0+ibc*3] = elem_list[ibc];
00951           bcs[1+ibc*3] = side_list[ibc];
00952           bcs[2+ibc*3] = elem_id_list[ibc];
00953         }
00954 
00955       // Put the BCs in the XDR file
00956       m.BC(&bcs[0], numBCs);
00957     }
00958 }
00959 
00960 
00961 
00962 void LegacyXdrIO::read_soln (const std::string& name,
00963                              std::vector<Real>& soln,
00964                              std::vector<std::string>& var_names) const
00965 {
00966   // Create an XdrSOLN object.
00967   XdrSOLN s;
00968 
00969   // Create an XdrSHEAD object.
00970   XdrSHEAD sh;
00971 
00972   // Open the XDR file for
00973   // reading or writing.
00974   // Note 1: Provide an additional argument
00975   // to specify the dimension.
00976   //
00977   // Note 2: Has to do the right thing for
00978   // both binary and ASCII files.
00979   s.init((this->binary() ? XdrMGF::DECODE : XdrMGF::R_ASCII), name.c_str(), 0); // mesh files are always number 0 ...
00980 
00981   // From here on, things depend
00982   // on whether we are reading or
00983   // writing!  First, we define
00984   // header variables that may
00985   // be read OR written.
00986   int         numVar      = 0;
00987   int         numNodes    = 0;
00988   const char* varNames;
00989 
00990   // Get the information from
00991   // the header, and place it
00992   // in the header pointer.
00993   s.header(&sh);
00994 
00995   // Read information from the
00996   // file header.  This depends on
00997   // whether its a libMesh or MGF mesh.
00998   numVar   = sh.getWrtVar();
00999   numNodes = sh.getNumNodes();
01000   varNames = sh.getVarTitle();
01001 
01002   // Get the variable names
01003   {
01004     var_names.resize(numVar);
01005 
01006     const char* p = varNames;
01007 
01008     for (int i=0; i<numVar; i++)
01009       {
01010         var_names[i] = p;
01011         p += std::strlen(p) + 1;
01012       }
01013   }
01014 
01015   // Read the soln vector
01016   soln.resize(numVar*numNodes);
01017 
01018   s.values(&soln[0], numNodes);
01019 }
01020 
01021 
01022 
01023 void LegacyXdrIO::write_soln (const std::string& name,
01024                               std::vector<Real>& soln,
01025                               std::vector<std::string>& var_names) const
01026 {
01027   // get a read-only reference to the mesh
01028   const MeshBase& mesh = MeshOutput<MeshBase>::mesh();
01029 
01030   // Create an XdrSOLN object.
01031   XdrSOLN s;
01032 
01033   // Create an XdrSHEAD object.
01034   XdrSHEAD sh;
01035 
01036   // Open the XDR file for
01037   // reading or writing.
01038   // Note 1: Provide an additional argument
01039   // to specify the dimension.
01040   //
01041   // Note 2: Has to do the right thing for
01042   // both binary and ASCII files.
01043   s.init((this->binary() ? XdrMGF::ENCODE : XdrMGF::W_ASCII), name.c_str(), 0); // mesh files are always number 0 ...
01044 
01045   // Build the header
01046   sh.setWrtVar(cast_int<int>(var_names.size()));
01047   sh.setNumVar(cast_int<int>(var_names.size()));
01048   sh.setNumNodes(cast_int<int>(mesh.n_nodes()));
01049   sh.setNumBCs(cast_int<int>(mesh.get_boundary_info().n_boundary_conds()));
01050   sh.setMeshCnt(0);
01051   sh.setKstep(0);
01052   sh.setTime(0.);
01053   sh.setStrSize(65536);
01054   sh.setId("Id String");               // Ignored
01055   sh.setTitle("Title String");          // Ignored
01056   sh.setUserTitle("User Title String"); // Ignored
01057 
01058   // create the variable array
01059   {
01060     std::string var_title;
01061 
01062     for (unsigned int var=0; var<var_names.size(); var++)
01063       {
01064         for (unsigned int c=0; c<var_names[var].size(); c++)
01065           var_title += var_names[var][c];
01066 
01067         var_title += '\0';
01068       }
01069 
01070     sh.setVarTitle(var_title.c_str(), cast_int<int>(var_title.size()));
01071   }
01072 
01073   // Put the informationin the XDR file.
01074   s.header(&sh); // Needs to work for both types of file
01075 
01076   // Write the solution vector
01077   libmesh_assert_equal_to (soln.size(), var_names.size()*mesh.n_nodes());
01078 
01079   s.values(&soln[0], mesh.n_nodes());
01080 }
01081 
01082 } // namespace libMesh