CardiacSimulationArchiver.hpp

00001 /*
00002 
00003 Copyright (C) University of Oxford, 2005-2010
00004 
00005 University of Oxford means the Chancellor, Masters and Scholars of the
00006 University of Oxford, having an administrative office at Wellington
00007 Square, Oxford OX1 2JD, UK.
00008 
00009 This file is part of Chaste.
00010 
00011 Chaste is free software: you can redistribute it and/or modify it
00012 under the terms of the GNU Lesser General Public License as published
00013 by the Free Software Foundation, either version 2.1 of the License, or
00014 (at your option) any later version.
00015 
00016 Chaste is distributed in the hope that it will be useful, but WITHOUT
00017 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
00018 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
00019 License for more details. The offer of Chaste under the terms of the
00020 License is subject to the License being interpreted in accordance with
00021 English Law and subject to any action against the University of Oxford
00022 being under the jurisdiction of the English Courts.
00023 
00024 You should have received a copy of the GNU Lesser General Public License
00025 along with Chaste. If not, see <http://www.gnu.org/licenses/>.
00026 
00027 */
00028 
00029 #ifndef CARDIACSIMULATIONARCHIVER_HPP_
00030 #define CARDIACSIMULATIONARCHIVER_HPP_
00031 
00032 #include <string>
00033 #include <fstream>
00034 
00035 // Must be included before any other serialisation headers
00036 #include "CheckpointArchiveTypes.hpp"
00037 
00038 #include "Exception.hpp"
00039 #include "ArchiveOpener.hpp"
00040 #include "OutputFileHandler.hpp"
00041 #include "ArchiveLocationInfo.hpp"
00042 #include "DistributedVectorFactory.hpp"
00043 #include "PetscTools.hpp"
00044 
00050 template<class PROBLEM_CLASS>
00051 class CardiacSimulationArchiver
00052 {
00053 public:
00064     static void Save(PROBLEM_CLASS& simulationToArchive, const std::string& rDirectory, bool clearDirectory=true);
00065 
00066 
00078     static PROBLEM_CLASS* Load(const std::string& rDirectory);
00079 
00080 
00098     static PROBLEM_CLASS* Migrate(const std::string &rDirectory);
00099 };
00100 
00101 
00102 template<class PROBLEM_CLASS>
00103 void CardiacSimulationArchiver<PROBLEM_CLASS>::Save(PROBLEM_CLASS& simulationToArchive,
00104                                                     const std::string &rDirectory,
00105                                                     bool clearDirectory)
00106 {
00107     // Clear directory if requested (and make sure it exists)
00108     OutputFileHandler handler(rDirectory, clearDirectory);
00109 
00110     // Nest the archive writing, so the ArchiveOpener goes out of scope before
00111     // the method ends.
00112     {
00113         // Open the archive files
00114         ArchiveOpener<boost::archive::text_oarchive, std::ofstream> archive_opener(rDirectory, "archive.arch", true);
00115         boost::archive::text_oarchive* p_main_archive = archive_opener.GetCommonArchive();
00116 
00117         // And save
00118         PROBLEM_CLASS* const p_simulation_to_archive = &simulationToArchive;
00119         (*p_main_archive) & p_simulation_to_archive;
00120     }
00121 
00122     // Write the info file
00123     if (PetscTools::AmMaster())
00124     {
00125         std::string info_path = handler.GetOutputDirectoryFullPath() + "archive.info";
00126         std::ofstream info_file(info_path.c_str());
00127         if (!info_file.is_open())
00128         {
00129             // Avoid deadlock...
00130             PetscTools::ReplicateBool(true);
00131             EXCEPTION("Unable to open archive information file: " + info_path);
00132         }
00133         PetscTools::ReplicateBool(false);
00134         unsigned archive_version = 0; 
00135         info_file << PetscTools::GetNumProcs() << " " << archive_version;
00136     }
00137     else
00138     {
00139         bool master_threw = PetscTools::ReplicateBool(false);
00140         if (master_threw)
00141         {
00142             EXCEPTION("Unable to open archive information file");
00143         }
00144     }
00145     // Make sure everything is written before any process continues.
00146     PetscTools::Barrier("CardiacSimulationArchiver::Save");
00147 }
00148 
00149 template<class PROBLEM_CLASS>
00150 PROBLEM_CLASS* CardiacSimulationArchiver<PROBLEM_CLASS>::Load(const std::string &rDirectory)
00151 {
00152     return CardiacSimulationArchiver<PROBLEM_CLASS>::Migrate(rDirectory);
00153 }
00154 
00155 
00156 template<class PROBLEM_CLASS>
00157 PROBLEM_CLASS* CardiacSimulationArchiver<PROBLEM_CLASS>::Migrate(const std::string &rDirectory)
00158 {
00159     // Load the info file
00160     OutputFileHandler handler(rDirectory, false);
00161     std::string info_path = handler.GetOutputDirectoryFullPath() + "archive.info";
00162     std::ifstream info_file(info_path.c_str());
00163     if (!info_file.is_open())
00164     {
00165         EXCEPTION("Unable to open archive information file: " + info_path);
00166     }
00167     unsigned num_procs, archive_version;
00168     info_file >> num_procs >> archive_version;
00169 
00170     PROBLEM_CLASS *p_unarchived_simulation;
00171 
00172     // Avoid the DistributedVectorFactory throwing a 'wrong number of processes' exception when loading,
00173     // and make it get the original DistributedVectorFactory from the archive so we can compare against
00174     // num_procs.
00175     DistributedVectorFactory::SetCheckNumberOfProcessesOnLoad(false);
00176     // Put what follows in a try-catch to make sure we reset this
00177     try
00178     {
00179         if (num_procs == PetscTools::GetNumProcs())
00180         {
00181             // We're not actually doing a migrate, and will re-use exactly the same mesh
00182             // partitioning etc. from before, so don't need any of the LoadExtraArchive
00183             // magic.  Indeed, we mustn't use it, or the mesh will get confused about
00184             // which nodes it owns.
00185             ArchiveOpener<boost::archive::text_iarchive, std::ifstream> archive_opener(rDirectory, "archive.arch", true);
00186             boost::archive::text_iarchive* p_main_archive = archive_opener.GetCommonArchive();
00187             (*p_main_archive) >> p_unarchived_simulation;
00188 
00189             // Paranoia checks
00190             DistributedVectorFactory* p_factory = p_unarchived_simulation->rGetMesh().GetDistributedVectorFactory();
00191             assert(p_factory != NULL);
00192             unsigned original_num_procs = p_factory->GetOriginalFactory()->GetNumProcs();
00193             if (original_num_procs != num_procs)
00194             {
00195                 NEVER_REACHED;
00196                 //assert(original_num_procs == num_procs);
00197             }
00198         }
00199         else
00200         {
00201             // We are migrating, and must re-distribute nodes, cells, etc.
00202 
00203             // Load the master and process-0 archive files.
00204             // This will also set up ArchiveLocationInfo for us.
00205             ArchiveOpener<boost::archive::text_iarchive, std::ifstream> archive_opener(rDirectory, "archive.arch", true, 0u);
00206             boost::archive::text_iarchive* p_main_archive = archive_opener.GetCommonArchive();
00207             (*p_main_archive) >> p_unarchived_simulation;
00208 
00209             // Work out how many more files to load
00210             DistributedVectorFactory* p_factory = p_unarchived_simulation->rGetMesh().GetDistributedVectorFactory();
00211             assert(p_factory != NULL);
00212             unsigned original_num_procs = p_factory->GetOriginalFactory()->GetNumProcs();
00213             assert(original_num_procs == num_procs); // Paranoia
00214 
00215             // Merge in the extra data
00216             for (unsigned archive_num=1; archive_num<original_num_procs; archive_num++)
00217             {
00218                 std::string archive_path = ArchiveLocationInfo::GetProcessUniqueFilePath("archive.arch", archive_num);
00219                 std::ifstream ifs(archive_path.c_str());
00220                 boost::archive::text_iarchive archive(ifs);
00221                 p_unarchived_simulation->LoadExtraArchive(archive, archive_version);
00222             }
00223         }
00224     }
00225     catch (Exception &e)
00226     {
00227         DistributedVectorFactory::SetCheckNumberOfProcessesOnLoad(true);
00228         throw e;
00229     }
00230 
00231     // Done.
00232     DistributedVectorFactory::SetCheckNumberOfProcessesOnLoad(true);
00233     return p_unarchived_simulation;
00234 }
00235 
00236 #endif /*CARDIACSIMULATIONARCHIVER_HPP_*/

Generated by  doxygen 1.6.2