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 #include "FileFinder.hpp"
00045 
00051 template<class PROBLEM_CLASS>
00052 class CardiacSimulationArchiver
00053 {
00054 public:
00065     static void Save(PROBLEM_CLASS& simulationToArchive, const std::string& rDirectory, bool clearDirectory=true);
00066 
00067 
00079     static PROBLEM_CLASS* Load(const std::string& rDirectory);
00080 
00091     static PROBLEM_CLASS* Load(const FileFinder& rDirectory);
00092 
00109     static PROBLEM_CLASS* Migrate(const FileFinder& rDirectory);
00110 };
00111 
00112 
00113 template<class PROBLEM_CLASS>
00114 void CardiacSimulationArchiver<PROBLEM_CLASS>::Save(PROBLEM_CLASS& simulationToArchive,
00115                                                     const std::string& rDirectory,
00116                                                     bool clearDirectory)
00117 {
00118     // Clear directory if requested (and make sure it exists)
00119     OutputFileHandler handler(rDirectory, clearDirectory);
00120 
00121     // Nest the archive writing, so the ArchiveOpener goes out of scope before
00122     // the method ends.
00123     {
00124         // Open the archive files
00125         FileFinder dir(rDirectory, RelativeTo::ChasteTestOutput);
00126         ArchiveOpener<boost::archive::text_oarchive, std::ofstream> archive_opener(dir, "archive.arch");
00127         boost::archive::text_oarchive* p_main_archive = archive_opener.GetCommonArchive();
00128 
00129         // And save
00130         PROBLEM_CLASS* const p_simulation_to_archive = &simulationToArchive;
00131         (*p_main_archive) & p_simulation_to_archive;
00132     }
00133 
00134     // Write the info file
00135     if (PetscTools::AmMaster())
00136     {
00137         std::string info_path = handler.GetOutputDirectoryFullPath() + "archive.info";
00138         std::ofstream info_file(info_path.c_str());
00139         if (!info_file.is_open())
00140         {
00141             // Avoid deadlock...
00142             PetscTools::ReplicateBool(true);
00143             EXCEPTION("Unable to open archive information file: " + info_path);
00144         }
00145         PetscTools::ReplicateBool(false);
00146         unsigned archive_version = 0; 
00147         info_file << PetscTools::GetNumProcs() << " " << archive_version;
00148     }
00149     else
00150     {
00151         bool master_threw = PetscTools::ReplicateBool(false);
00152         if (master_threw)
00153         {
00154             EXCEPTION("Unable to open archive information file");
00155         }
00156     }
00157     // Make sure everything is written before any process continues.
00158     PetscTools::Barrier("CardiacSimulationArchiver::Save");
00159 }
00160 
00161 template<class PROBLEM_CLASS>
00162 PROBLEM_CLASS* CardiacSimulationArchiver<PROBLEM_CLASS>::Load(const std::string& rDirectory)
00163 {
00164     FileFinder directory(rDirectory, RelativeTo::ChasteTestOutput);
00165     return CardiacSimulationArchiver<PROBLEM_CLASS>::Migrate(directory);
00166 }
00167 
00168 template<class PROBLEM_CLASS>
00169 PROBLEM_CLASS* CardiacSimulationArchiver<PROBLEM_CLASS>::Load(const FileFinder& rDirectory)
00170 {
00171     return CardiacSimulationArchiver<PROBLEM_CLASS>::Migrate(rDirectory);
00172 }
00173 
00174 
00175 template<class PROBLEM_CLASS>
00176 PROBLEM_CLASS* CardiacSimulationArchiver<PROBLEM_CLASS>::Migrate(const FileFinder& rDirectory)
00177 {
00178     // Check the directory exists
00179     std::string dir_path = rDirectory.GetAbsolutePath();
00180     if (!rDirectory.IsDir() || !rDirectory.Exists())
00181     {
00182         EXCEPTION("Checkpoint directory does not exist: " + dir_path);
00183     }
00184     assert(*(dir_path.end()-1) == '/'); // Paranoia
00185     // Load the info file
00186     std::string info_path = dir_path + "archive.info";
00187     std::ifstream info_file(info_path.c_str());
00188     if (!info_file.is_open())
00189     {
00190         EXCEPTION("Unable to open archive information file: " + info_path);
00191     }
00192     unsigned num_procs, archive_version;
00193     info_file >> num_procs >> archive_version;
00194 
00195     PROBLEM_CLASS *p_unarchived_simulation;
00196 
00197     // Avoid the DistributedVectorFactory throwing a 'wrong number of processes' exception when loading,
00198     // and make it get the original DistributedVectorFactory from the archive so we can compare against
00199     // num_procs.
00200     DistributedVectorFactory::SetCheckNumberOfProcessesOnLoad(false);
00201     // Put what follows in a try-catch to make sure we reset this
00202     try
00203     {
00204         if (num_procs == PetscTools::GetNumProcs())
00205         {
00206             // We're not actually doing a migrate, and will re-use exactly the same mesh
00207             // partitioning etc. from before, so don't need any of the LoadExtraArchive
00208             // magic.  Indeed, we mustn't use it, or the mesh will get confused about
00209             // which nodes it owns.
00210             ArchiveOpener<boost::archive::text_iarchive, std::ifstream> archive_opener(rDirectory, "archive.arch");
00211             boost::archive::text_iarchive* p_main_archive = archive_opener.GetCommonArchive();
00212             (*p_main_archive) >> p_unarchived_simulation;
00213 
00214             // Paranoia checks
00215             DistributedVectorFactory* p_factory = p_unarchived_simulation->rGetMesh().GetDistributedVectorFactory();
00216             assert(p_factory != NULL);
00217             unsigned original_num_procs = p_factory->GetOriginalFactory()->GetNumProcs();
00218             if (original_num_procs != num_procs)
00219             {
00220                 NEVER_REACHED;
00221                 //assert(original_num_procs == num_procs);
00222             }
00223         }
00224         else
00225         {
00226             // We are migrating, and must re-distribute nodes, cells, etc.
00227 
00228             // Load the master and process-0 archive files.
00229             // This will also set up ArchiveLocationInfo for us.
00230             ArchiveOpener<boost::archive::text_iarchive, std::ifstream> archive_opener(rDirectory, "archive.arch", 0u);
00231             boost::archive::text_iarchive* p_main_archive = archive_opener.GetCommonArchive();
00232             (*p_main_archive) >> p_unarchived_simulation;
00233 
00234             // Work out how many more files to load
00235             DistributedVectorFactory* p_factory = p_unarchived_simulation->rGetMesh().GetDistributedVectorFactory();
00236             assert(p_factory != NULL);
00237             unsigned original_num_procs = p_factory->GetOriginalFactory()->GetNumProcs();
00238             assert(original_num_procs == num_procs); // Paranoia
00239 
00240             // Merge in the extra data
00241             for (unsigned archive_num=1; archive_num<original_num_procs; archive_num++)
00242             {
00243                 std::string archive_path = ArchiveLocationInfo::GetProcessUniqueFilePath("archive.arch", archive_num);
00244                 std::ifstream ifs(archive_path.c_str());
00245                 boost::archive::text_iarchive archive(ifs);
00246                 p_unarchived_simulation->LoadExtraArchive(archive, archive_version);
00247             }
00248         }
00249     }
00250     catch (Exception &e)
00251     {
00252         DistributedVectorFactory::SetCheckNumberOfProcessesOnLoad(true);
00253         throw e;
00254     }
00255 
00256     // Done.
00257     DistributedVectorFactory::SetCheckNumberOfProcessesOnLoad(true);
00258     return p_unarchived_simulation;
00259 }
00260 
00261 #endif /*CARDIACSIMULATIONARCHIVER_HPP_*/

Generated on Mon Nov 1 12:35:17 2010 for Chaste by  doxygen 1.5.5