CardiacSimulationArchiver.cpp

00001 /*
00002 
00003 Copyright (C) University of Oxford, 2005-2011
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 #include <fstream>
00030 
00031 // Must be included before any other serialization headers
00032 #include "CheckpointArchiveTypes.hpp"
00033 #include "CardiacSimulationArchiver.hpp"
00034 
00035 #include "Exception.hpp"
00036 #include "ArchiveOpener.hpp"
00037 #include "OutputFileHandler.hpp"
00038 #include "ArchiveLocationInfo.hpp"
00039 #include "DistributedVectorFactory.hpp"
00040 #include "PetscTools.hpp"
00041 #include "FileFinder.hpp"
00042 
00043 /*
00044  * Archiving extravaganza:
00045  *
00046  * Various objects are archived through a pointer to an abstract class.  All the potential
00047  * concrete classes need to be included here, so they are registered with Boost.  If not,
00048  * Boost (<1.37) won't be able to find the archiving methods of the concrete class and will
00049  * throw the following exception:
00050  *
00051  *       terminate called after throwing an instance of 'boost::archive::archive_exception
00052  *       what():  unregistered class
00053  *
00054  * No member variable is defined to be of any of these clases, so removing them won't
00055  * produce any compiler error.  The exception above will occur at runtime.
00056  *
00057  * This might not be even necessary in certain cases, if the file is included implicitly by
00058  * another header file or by the test itself.  It's safer though.
00059  */
00060 #include "MonodomainProblem.hpp"
00061 #include "BidomainProblem.hpp"
00062 #include "BidomainWithBathProblem.hpp"
00063 #include "HeartConfigRelatedCellFactory.hpp"
00064 
00065 
00066 template<class PROBLEM_CLASS>
00067 void CardiacSimulationArchiver<PROBLEM_CLASS>::Save(PROBLEM_CLASS& rSimulationToArchive,
00068                                                     const std::string& rDirectory,
00069                                                     bool clearDirectory)
00070 {
00071     // Clear directory if requested (and make sure it exists)
00072     OutputFileHandler handler(rDirectory, clearDirectory);
00073 
00074     // Nest the archive writing, so the ArchiveOpener goes out of scope before
00075     // the method ends.
00076     {
00077         // Open the archive files
00078         FileFinder dir(rDirectory, RelativeTo::ChasteTestOutput);
00079         ArchiveOpener<boost::archive::text_oarchive, std::ofstream> archive_opener(dir, "archive.arch");
00080         boost::archive::text_oarchive* p_main_archive = archive_opener.GetCommonArchive();
00081 
00082         // And save
00083         PROBLEM_CLASS* const p_simulation_to_archive = &rSimulationToArchive;
00084         (*p_main_archive) & p_simulation_to_archive;
00085     }
00086 
00087     // Write the info file
00088     if (PetscTools::AmMaster())
00089     {
00090         std::string info_path = handler.GetOutputDirectoryFullPath() + "archive.info";
00091         std::ofstream info_file(info_path.c_str());
00092         if (!info_file.is_open())
00093         {
00094             // Avoid deadlock...
00095             PetscTools::ReplicateBool(true);
00096             EXCEPTION("Unable to open archive information file: " + info_path);
00097         }
00098         PetscTools::ReplicateBool(false);
00099         unsigned archive_version = 0; 
00100         info_file << PetscTools::GetNumProcs() << " " << archive_version;
00101     }
00102     else
00103     {
00104         bool master_threw = PetscTools::ReplicateBool(false);
00105         if (master_threw)
00106         {
00107             EXCEPTION("Unable to open archive information file");
00108         }
00109     }
00110     // Make sure everything is written before any process continues.
00111     PetscTools::Barrier("CardiacSimulationArchiver::Save");
00112 }
00113 
00114 template<class PROBLEM_CLASS>
00115 PROBLEM_CLASS* CardiacSimulationArchiver<PROBLEM_CLASS>::Load(const std::string& rDirectory)
00116 {
00117     FileFinder directory(rDirectory, RelativeTo::ChasteTestOutput);
00118     return CardiacSimulationArchiver<PROBLEM_CLASS>::Migrate(directory);
00119 }
00120 
00121 template<class PROBLEM_CLASS>
00122 PROBLEM_CLASS* CardiacSimulationArchiver<PROBLEM_CLASS>::Load(const FileFinder& rDirectory)
00123 {
00124     return CardiacSimulationArchiver<PROBLEM_CLASS>::Migrate(rDirectory);
00125 }
00126 
00127 
00128 template<class PROBLEM_CLASS>
00129 PROBLEM_CLASS* CardiacSimulationArchiver<PROBLEM_CLASS>::Migrate(const FileFinder& rDirectory)
00130 {
00131     // Check the directory exists
00132     std::string dir_path = rDirectory.GetAbsolutePath();
00133     if (!rDirectory.IsDir() || !rDirectory.Exists())
00134     {
00135         EXCEPTION("Checkpoint directory does not exist: " + dir_path);
00136     }
00137     assert(*(dir_path.end()-1) == '/'); // Paranoia
00138     // Load the info file
00139     std::string info_path = dir_path + "archive.info";
00140     std::ifstream info_file(info_path.c_str());
00141     if (!info_file.is_open())
00142     {
00143         EXCEPTION("Unable to open archive information file: " + info_path);
00144     }
00145     unsigned num_procs, archive_version;
00146     info_file >> num_procs >> archive_version;
00147 
00148     PROBLEM_CLASS *p_unarchived_simulation;
00149 
00150     // Avoid the DistributedVectorFactory throwing a 'wrong number of processes' exception when loading,
00151     // and make it get the original DistributedVectorFactory from the archive so we can compare against
00152     // num_procs.
00153     DistributedVectorFactory::SetCheckNumberOfProcessesOnLoad(false);
00154     // Put what follows in a try-catch to make sure we reset this
00155     try
00156     {
00157         // Figure out which process-specific archive to load first.  If we're loading on the same number of
00158         // processes, we must load our own one, or the mesh gets confused.  Otherwise, start with 0 to make
00159         // sure it exists.
00160         unsigned initial_archive = num_procs == PetscTools::GetNumProcs() ? PetscTools::GetMyRank() : 0u;
00161 
00162         // Load the master and initial process-specific archive files.
00163         // This will also set up ArchiveLocationInfo for us.
00164         ArchiveOpener<boost::archive::text_iarchive, std::ifstream> archive_opener(rDirectory, "archive.arch", initial_archive);
00165         boost::archive::text_iarchive* p_main_archive = archive_opener.GetCommonArchive();
00166         (*p_main_archive) >> p_unarchived_simulation;
00167 
00168         // Work out how many more process-specific files to load
00169         DistributedVectorFactory* p_factory = p_unarchived_simulation->rGetMesh().GetDistributedVectorFactory();
00170         assert(p_factory != NULL);
00171         unsigned original_num_procs = p_factory->GetOriginalFactory()->GetNumProcs();
00172         assert(original_num_procs == num_procs); // Paranoia
00173 
00174         // Merge in the extra data
00175         for (unsigned archive_num=0; archive_num<original_num_procs; archive_num++)
00176         {
00177             if (archive_num != initial_archive)
00178             {
00179                 std::string archive_path = ArchiveLocationInfo::GetProcessUniqueFilePath("archive.arch", archive_num);
00180                 std::ifstream ifs(archive_path.c_str());
00181                 boost::archive::text_iarchive archive(ifs);
00182                 p_unarchived_simulation->LoadExtraArchive(archive, archive_version);
00183             }
00184         }
00185     }
00186     catch (Exception &e)
00187     {
00188         DistributedVectorFactory::SetCheckNumberOfProcessesOnLoad(true);
00189         throw e;
00190     }
00191 
00192     // Done.
00193     DistributedVectorFactory::SetCheckNumberOfProcessesOnLoad(true);
00194     return p_unarchived_simulation;
00195 }
00196 
00197 //
00198 // Explicit instantiation
00199 //
00200 
00201 template class CardiacSimulationArchiver<MonodomainProblem<1> >;
00202 template class CardiacSimulationArchiver<MonodomainProblem<2> >;
00203 template class CardiacSimulationArchiver<MonodomainProblem<3> >;
00204 
00205 template class CardiacSimulationArchiver<BidomainProblem<1> >;
00206 template class CardiacSimulationArchiver<BidomainProblem<2> >;
00207 template class CardiacSimulationArchiver<BidomainProblem<3> >;
00208 
00209 template class CardiacSimulationArchiver<BidomainWithBathProblem<1> >;
00210 template class CardiacSimulationArchiver<BidomainWithBathProblem<2> >;
00211 template class CardiacSimulationArchiver<BidomainWithBathProblem<3> >;
Generated on Thu Dec 22 13:00:06 2011 for Chaste by  doxygen 1.6.3