$extrastylesheet
equation_systems_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 #include "libmesh/libmesh_common.h"
00020 #include "libmesh/libmesh_logging.h"
00021 
00022 
00023 // C++ Includes
00024 #include <cstdio> // for std::sprintf
00025 #include <sstream>
00026 
00027 // Local Includes
00028 #include "libmesh/libmesh_version.h"
00029 #include "libmesh/equation_systems.h"
00030 #include "libmesh/mesh_base.h"
00031 #include "libmesh/mesh_tools.h"
00032 #include "libmesh/parallel_mesh.h"
00033 #include "libmesh/parallel.h"
00034 #include "libmesh/serial_mesh.h"
00035 #include "libmesh/xdr_cxx.h"
00036 #include "libmesh/mesh_refinement.h"
00037 
00038 namespace libMesh
00039 {
00040 
00041 // Forward Declarations
00042 
00043 // Anonymous namespace for implementation details.
00044 namespace {
00045 std::string local_file_name (const unsigned int processor_id,
00046                              const std::string &name)
00047 {
00048   std::string basename(name);
00049   char buf[256];
00050 
00051   if (basename.size() - basename.rfind(".bz2") == 4)
00052     {
00053       basename.erase(basename.end()-4, basename.end());
00054       std::sprintf(buf, "%s.%04u.bz2", basename.c_str(), processor_id);
00055     }
00056   else if (basename.size() - basename.rfind(".gz") == 3)
00057     {
00058       basename.erase(basename.end()-3, basename.end());
00059       std::sprintf(buf, "%s.%04u.gz", basename.c_str(), processor_id);
00060     }
00061   else
00062     std::sprintf(buf, "%s.%04u", basename.c_str(), processor_id);
00063 
00064   return std::string(buf);
00065 }
00066 }
00067 
00068 
00069 
00070 
00071 // ------------------------------------------------------------
00072 // EquationSystem class implementation
00073 template <typename InValType>
00074 void EquationSystems::read (const std::string& name,
00075                             const unsigned int read_flags,
00076                             bool partition_agnostic)
00077 {
00078   XdrMODE mode = READ;
00079   if (name.find(".xdr") != std::string::npos)
00080     mode = DECODE;
00081   this->read(name, mode, read_flags, partition_agnostic);
00082 
00083 #ifdef LIBMESH_ENABLE_AMR
00084   MeshRefinement mesh_refine(_mesh);
00085   mesh_refine.clean_refinement_flags();
00086 #endif
00087 }
00088 
00089 
00090 
00091 template <typename InValType>
00092 void EquationSystems::read (const std::string& name,
00093                             const XdrMODE mode,
00094                             const unsigned int read_flags,
00095                             bool partition_agnostic)
00096 {
00097 #ifdef LIBMESH_ENABLE_EXCEPTIONS
00098 
00099   // If we have exceptions enabled we can be considerate and try
00100   // to read old restart files which contain infinite element
00101   // information but do not have the " with infinite elements"
00102   // string in the version information.
00103 
00104   // First try the read the user requested
00105   try
00106     {
00107       this->_read_impl<InValType> (name, mode, read_flags, partition_agnostic);
00108     }
00109 
00110   // If that fails, try it again but explicitly request we look for infinite element info
00111   catch (...)
00112     {
00113       libMesh::out << "\n*********************************************************************\n"
00114                    << "READING THE FILE \"" << name << "\" FAILED.\n"
00115                    << "It is possible this file contains infinite element information,\n"
00116                    << "but the version string does not contain \" with infinite elements\"\n"
00117                    << "Let's try this again, but looking for infinite element information...\n"
00118                    << "*********************************************************************\n"
00119                    << std::endl;
00120 
00121       try
00122         {
00123           this->_read_impl<InValType> (name, mode, read_flags | EquationSystems::TRY_READ_IFEMS, partition_agnostic);
00124         }
00125 
00126       // If all that failed, we are out of ideas here...
00127       catch (...)
00128         {
00129           libMesh::out << "\n*********************************************************************\n"
00130                        << "Well, at least we tried!\n"
00131                        << "Good Luck!!\n"
00132                        << "*********************************************************************\n"
00133                        << std::endl;
00134           throw;
00135         }
00136     }
00137 
00138 #else
00139 
00140   // no exceptions - cross your fingers...
00141   this->_read_impl<InValType> (name, mode, read_flags, partition_agnostic);
00142 
00143 #endif // #ifdef LIBMESH_ENABLE_EXCEPTIONS
00144 
00145 #ifdef LIBMESH_ENABLE_AMR
00146   MeshRefinement mesh_refine(_mesh);
00147   mesh_refine.clean_refinement_flags();
00148 #endif
00149 }
00150 
00151 
00152 
00153 template <typename InValType>
00154 void EquationSystems::_read_impl (const std::string& name,
00155                                   const XdrMODE mode,
00156                                   const unsigned int read_flags,
00157                                   bool partition_agnostic)
00158 {
00222   // Set booleans from the read_flags argument
00223   const bool read_header          = read_flags & EquationSystems::READ_HEADER;
00224   const bool read_data            = read_flags & EquationSystems::READ_DATA;
00225   const bool read_additional_data = read_flags & EquationSystems::READ_ADDITIONAL_DATA;
00226   const bool read_legacy_format   = read_flags & EquationSystems::READ_LEGACY_FORMAT;
00227   const bool try_read_ifems       = read_flags & EquationSystems::TRY_READ_IFEMS;
00228   const bool read_basic_only      = read_flags & EquationSystems::READ_BASIC_ONLY;
00229   bool read_parallel_files  = false;
00230 
00231   std::map<std::string, System*> xda_systems;
00232 
00233   // This will unzip a file with .bz2 as the extension, otherwise it
00234   // simply returns the name if the file need not be unzipped.
00235   Xdr io ((this->processor_id() == 0) ? name : "", mode);
00236   libmesh_assert (io.reading());
00237 
00238   {
00239     // 1.)
00240     // Read the version header.
00241     std::string version = "legacy";
00242     if (!read_legacy_format)
00243       {
00244         if (this->processor_id() == 0) io.data(version);
00245         this->comm().broadcast(version);
00246 
00247         // All processors have the version header, if it does not contain
00248         // "libMesh" something then it is a legacy file.
00249         std::string::size_type lm_pos = version.find("libMesh");
00250         if (!(lm_pos < version.size()))
00251           {
00252             io.close();
00253 
00254             // Recursively call this read() function but with the
00255             // EquationSystems::READ_LEGACY_FORMAT bit set.
00256             this->read (name, mode, (read_flags | EquationSystems::READ_LEGACY_FORMAT), partition_agnostic);
00257             return;
00258           }
00259 
00260         // Figure out the libMesh version that created this file
00261         std::istringstream iss(version.substr(lm_pos + 8));
00262         int ver_major = 0, ver_minor = 0, ver_patch = 0;
00263         char dot;
00264         iss >> ver_major >> dot >> ver_minor >> dot >> ver_patch;
00265         io.set_version(LIBMESH_VERSION_ID(ver_major, ver_minor, ver_patch));
00266 
00267 
00268         read_parallel_files = (version.rfind(" parallel") < version.size());
00269 
00270         // If requested that we try to read infinite element information,
00271         // and the string " with infinite elements" is not in the version,
00272         // then tack it on.  This is for compatibility reading ifem
00273         // files written prior to 11/10/2008 - BSK
00274         if (try_read_ifems)
00275           if (!(version.rfind(" with infinite elements") < version.size()))
00276             version += " with infinite elements";
00277 
00278       }
00279     else
00280       libmesh_deprecated();
00281 
00282     START_LOG("read()","EquationSystems");
00283 
00284     // 2.)
00285     // Read the number of equation systems
00286     unsigned int n_sys=0;
00287     if (this->processor_id() == 0) io.data (n_sys);
00288     this->comm().broadcast(n_sys);
00289 
00290     for (unsigned int sys=0; sys<n_sys; sys++)
00291       {
00292         // 3.)
00293         // Read the name of the sys-th equation system
00294         std::string sys_name;
00295         if (this->processor_id() == 0) io.data (sys_name);
00296         this->comm().broadcast(sys_name);
00297 
00298         // 4.)
00299         // Read the type of the sys-th equation system
00300         std::string sys_type;
00301         if (this->processor_id() == 0) io.data (sys_type);
00302         this->comm().broadcast(sys_type);
00303 
00304         if (read_header)
00305           this->add_system (sys_type, sys_name);
00306 
00307         // 5.) - 9.)
00308         // Let System::read_header() do the job
00309         System& new_system = this->get_system(sys_name);
00310         new_system.read_header (io,
00311                                 version,
00312                                 read_header,
00313                                 read_additional_data,
00314                                 read_legacy_format);
00315 
00316         xda_systems.insert(std::make_pair(sys_name, &new_system));
00317 
00318         // If we're only creating "basic" systems, we need to tell
00319         // each system that before we call init() later.
00320         if (read_basic_only)
00321           new_system.set_basic_system_only();
00322       }
00323   }
00324 
00325 
00326 
00327   // Now we are ready to initialize the underlying data
00328   // structures. This will initialize the vectors for
00329   // storage, the dof_map, etc...
00330   if (read_header)
00331     this->init();
00332 
00333   // 10.) & 11.)
00334   // Read and set the numeric vector values
00335   if (read_data)
00336     {
00337       // the EquationSystems::read() method should look constant from the mesh
00338       // perspective, but we need to assign a temporary numbering to the nodes
00339       // and elements in the mesh, which requires that we abuse const_cast
00340       if (!read_legacy_format && partition_agnostic)
00341         {
00342           MeshBase &mesh = const_cast<MeshBase&>(this->get_mesh());
00343           MeshTools::Private::globally_renumber_nodes_and_elements(mesh);
00344         }
00345 
00346       Xdr local_io (read_parallel_files ? local_file_name(this->processor_id(),name) : "", mode);
00347 
00348       std::map<std::string, System*>::iterator
00349         pos = xda_systems.begin();
00350 
00351       for (; pos != xda_systems.end(); ++pos)
00352         if (read_legacy_format)
00353           {
00354             libmesh_deprecated();
00355             pos->second->read_legacy_data (io, read_additional_data);
00356           }
00357         else
00358           if (read_parallel_files)
00359             pos->second->read_parallel_data<InValType>   (local_io, read_additional_data);
00360           else
00361             pos->second->read_serialized_data<InValType> (io, read_additional_data);
00362 
00363 
00364       // Undo the temporary numbering.
00365       if (!read_legacy_format && partition_agnostic)
00366         _mesh.fix_broken_node_and_element_numbering();
00367     }
00368 
00369   STOP_LOG("read()","EquationSystems");
00370 
00371   // Localize each system's data
00372   this->update();
00373 }
00374 
00375 
00376 
00377 void EquationSystems::write(const std::string& name,
00378                             const unsigned int write_flags,
00379                             bool partition_agnostic) const
00380 {
00381   XdrMODE mode = WRITE;
00382   if (name.find(".xdr") != std::string::npos)
00383     mode = ENCODE;
00384   this->write(name, mode, write_flags, partition_agnostic);
00385 }
00386 
00387 
00388 
00389 void EquationSystems::write(const std::string& name,
00390                             const XdrMODE mode,
00391                             const unsigned int write_flags,
00392                             bool partition_agnostic) const
00393 {
00457   // the EquationSystems::write() method should look constant,
00458   // but we need to assign a temporary numbering to the nodes
00459   // and elements in the mesh, which requires that we abuse const_cast
00460   if(partition_agnostic)
00461     {
00462       MeshBase &mesh = const_cast<MeshBase&>(this->get_mesh());
00463       MeshTools::Private::globally_renumber_nodes_and_elements(mesh);
00464     }
00465 
00466   // set booleans from write_flags argument
00467   const bool write_data            = write_flags & EquationSystems::WRITE_DATA;
00468   const bool write_additional_data = write_flags & EquationSystems::WRITE_ADDITIONAL_DATA;
00469 
00470   // always write parallel files if we're instructed to write in
00471   // parallel
00472   const bool write_parallel_files  =
00473     (write_flags & EquationSystems::WRITE_PARALLEL_FILES) ||
00474     // but also write parallel files if we haven't been instructed to
00475     // write in serial and we're on a distributed mesh
00476     (!(write_flags & EquationSystems::WRITE_SERIAL_FILES) &&
00477      !this->get_mesh().is_serial());
00478 
00479   // New scope so that io will close before we try to zip the file
00480   {
00481     Xdr io((this->processor_id()==0) ? name : "", mode);
00482     libmesh_assert (io.writing());
00483 
00484     START_LOG("write()","EquationSystems");
00485 
00486     const unsigned int proc_id = this->processor_id();
00487     unsigned int n_sys         = this->n_systems();
00488 
00489     std::map<std::string, System*>::const_iterator
00490       pos = _systems.begin();
00491 
00492     // set the version number in the Xdr object
00493     io.set_version(LIBMESH_VERSION_ID(LIBMESH_MAJOR_VERSION,
00494                                       LIBMESH_MINOR_VERSION,
00495                                       LIBMESH_MICRO_VERSION));
00496 
00497     // Only write the header information
00498     // if we are processor 0.
00499     if (proc_id == 0)
00500       {
00501         std::string comment;
00502         char buf[256];
00503 
00504         // 1.)
00505         // Write the version header
00506         std::string version("libMesh-" + libMesh::get_io_compatibility_version());
00507         if (write_parallel_files) version += " parallel";
00508 
00509 #ifdef LIBMESH_ENABLE_INFINITE_ELEMENTS
00510         version += " with infinite elements";
00511 #endif
00512         io.data (version, "# File Format Identifier");
00513 
00514         // 2.)
00515         // Write the number of equation systems
00516         io.data (n_sys, "# No. of Equation Systems");
00517 
00518         while (pos != _systems.end())
00519           {
00520             // 3.)
00521             // Write the name of the sys_num-th system
00522             {
00523               const unsigned int sys_num = pos->second->number();
00524               std::string sys_name       = pos->first;
00525 
00526               comment =  "# Name, System No. ";
00527               std::sprintf(buf, "%u", sys_num);
00528               comment += buf;
00529 
00530               io.data (sys_name, comment.c_str());
00531             }
00532 
00533             // 4.)
00534             // Write the type of system handled
00535             {
00536               const unsigned int sys_num = pos->second->number();
00537               std::string sys_type       = pos->second->system_type();
00538 
00539               comment =  "# Type, System No. ";
00540               std::sprintf(buf, "%u", sys_num);
00541               comment += buf;
00542 
00543               io.data (sys_type, comment.c_str());
00544             }
00545 
00546             // 5.) - 9.)
00547             // Let System::write_header() do the job
00548             pos->second->write_header (io, version, write_additional_data);
00549 
00550             ++pos;
00551           }
00552       }
00553 
00554     // Start from the first system, again,
00555     // to write vectors to disk, if wanted
00556     if (write_data)
00557       {
00558         // open a parallel buffer if warranted.
00559         Xdr local_io (write_parallel_files ? local_file_name(this->processor_id(),name) : "", mode);
00560 
00561         for (pos = _systems.begin(); pos != _systems.end(); ++pos)
00562           {
00563             // 10.) + 11.)
00564             if (write_parallel_files)
00565               pos->second->write_parallel_data (local_io,write_additional_data);
00566             else
00567               pos->second->write_serialized_data (io,write_additional_data);
00568           }
00569       }
00570 
00571     STOP_LOG("write()","EquationSystems");
00572   }
00573 
00574   // the EquationSystems::write() method should look constant,
00575   // but we need to undo the temporary numbering of the nodes
00576   // and elements in the mesh, which requires that we abuse const_cast
00577   if(partition_agnostic)
00578     const_cast<MeshBase&>(_mesh).fix_broken_node_and_element_numbering();
00579 }
00580 
00581 
00582 
00583 // template specialization
00584 
00585 template void EquationSystems::read<Number> (const std::string& name, const unsigned int read_flags, bool partition_agnostic);
00586 template void EquationSystems::read<Number> (const std::string& name, const XdrMODE mode, const unsigned int read_flags, bool partition_agnostic);
00587 template void EquationSystems::_read_impl<Number> (const std::string& name, const XdrMODE mode, const unsigned int read_flags, bool partition_agnostic);
00588 #ifdef LIBMESH_USE_COMPLEX_NUMBERS
00589 template void EquationSystems::read<Real> (const std::string& name, const unsigned int read_flags, bool partition_agnostic);
00590 template void EquationSystems::read<Real> (const std::string& name, const XdrMODE mode, const unsigned int read_flags, bool partition_agnostic);
00591 template void EquationSystems::_read_impl<Real> (const std::string& name, const XdrMODE mode, const unsigned int read_flags, bool partition_agnostic);
00592 #endif
00593 
00594 } // namespace libMesh