Chaste Release::3.1
|
00001 /* 00002 00003 Copyright (c) 2005-2012, University of Oxford. 00004 All rights reserved. 00005 00006 University of Oxford means the Chancellor, Masters and Scholars of the 00007 University of Oxford, having an administrative office at Wellington 00008 Square, Oxford OX1 2JD, UK. 00009 00010 This file is part of Chaste. 00011 00012 Redistribution and use in source and binary forms, with or without 00013 modification, are permitted provided that the following conditions are met: 00014 * Redistributions of source code must retain the above copyright notice, 00015 this list of conditions and the following disclaimer. 00016 * Redistributions in binary form must reproduce the above copyright notice, 00017 this list of conditions and the following disclaimer in the documentation 00018 and/or other materials provided with the distribution. 00019 * Neither the name of the University of Oxford nor the names of its 00020 contributors may be used to endorse or promote products derived from this 00021 software without specific prior written permission. 00022 00023 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 00024 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 00025 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 00026 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 00027 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 00028 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 00029 GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 00030 HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 00031 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 00032 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 00033 00034 */ 00035 00036 #include <fstream> 00037 00038 // Must be included before any other serialization headers 00039 #include "CheckpointArchiveTypes.hpp" 00040 #include "CardiacSimulationArchiver.hpp" 00041 00042 #include "Exception.hpp" 00043 #include "ArchiveOpener.hpp" 00044 #include "OutputFileHandler.hpp" 00045 #include "ArchiveLocationInfo.hpp" 00046 #include "DistributedVectorFactory.hpp" 00047 #include "PetscTools.hpp" 00048 #include "FileFinder.hpp" 00049 00050 /* 00051 * Archiving extravaganza: 00052 * 00053 * Various objects are archived through a pointer to an abstract class. All the potential 00054 * concrete classes need to be included here, so they are registered with Boost. If not, 00055 * Boost (<1.37) won't be able to find the archiving methods of the concrete class and will 00056 * throw the following exception: 00057 * 00058 * terminate called after throwing an instance of 'boost::archive::archive_exception 00059 * what(): unregistered class 00060 * 00061 * No member variable is defined to be of any of these clases, so removing them won't 00062 * produce any compiler error. The exception above will occur at runtime. 00063 * 00064 * This might not be even necessary in certain cases, if the file is included implicitly by 00065 * another header file or by the test itself. It's safer though. 00066 */ 00067 #include "MonodomainProblem.hpp" 00068 #include "BidomainProblem.hpp" 00069 #include "BidomainWithBathProblem.hpp" 00070 #include "HeartConfigRelatedCellFactory.hpp" 00071 00072 00073 template<class PROBLEM_CLASS> 00074 void CardiacSimulationArchiver<PROBLEM_CLASS>::Save(PROBLEM_CLASS& rSimulationToArchive, 00075 const std::string& rDirectory, 00076 bool clearDirectory) 00077 { 00078 // Clear directory if requested (and make sure it exists) 00079 OutputFileHandler handler(rDirectory, clearDirectory); 00080 00081 // Nest the archive writing, so the ArchiveOpener goes out of scope before 00082 // the method ends. 00083 { 00084 // Open the archive files 00085 FileFinder dir(rDirectory, RelativeTo::ChasteTestOutput); 00086 ArchiveOpener<boost::archive::text_oarchive, std::ofstream> archive_opener(dir, "archive.arch"); 00087 boost::archive::text_oarchive* p_main_archive = archive_opener.GetCommonArchive(); 00088 00089 // And save 00090 PROBLEM_CLASS* const p_simulation_to_archive = &rSimulationToArchive; 00091 (*p_main_archive) & p_simulation_to_archive; 00092 } 00093 00094 // Write the info file 00095 if (PetscTools::AmMaster()) 00096 { 00097 std::string info_path = handler.GetOutputDirectoryFullPath() + "archive.info"; 00098 std::ofstream info_file(info_path.c_str()); 00099 if (!info_file.is_open()) 00100 { 00101 // Avoid deadlock... 00102 PetscTools::ReplicateBool(true); 00103 EXCEPTION("Unable to open archive information file: " + info_path); 00104 } 00105 PetscTools::ReplicateBool(false); 00106 unsigned archive_version = 0; 00107 info_file << PetscTools::GetNumProcs() << " " << archive_version; 00108 } 00109 else 00110 { 00111 bool master_threw = PetscTools::ReplicateBool(false); 00112 if (master_threw) 00113 { 00114 EXCEPTION("Unable to open archive information file"); 00115 } 00116 } 00117 // Make sure everything is written before any process continues. 00118 PetscTools::Barrier("CardiacSimulationArchiver::Save"); 00119 } 00120 00121 template<class PROBLEM_CLASS> 00122 PROBLEM_CLASS* CardiacSimulationArchiver<PROBLEM_CLASS>::Load(const std::string& rDirectory) 00123 { 00124 FileFinder directory(rDirectory, RelativeTo::ChasteTestOutput); 00125 return CardiacSimulationArchiver<PROBLEM_CLASS>::Migrate(directory); 00126 } 00127 00128 template<class PROBLEM_CLASS> 00129 PROBLEM_CLASS* CardiacSimulationArchiver<PROBLEM_CLASS>::Load(const FileFinder& rDirectory) 00130 { 00131 return CardiacSimulationArchiver<PROBLEM_CLASS>::Migrate(rDirectory); 00132 } 00133 00134 00135 template<class PROBLEM_CLASS> 00136 PROBLEM_CLASS* CardiacSimulationArchiver<PROBLEM_CLASS>::Migrate(const FileFinder& rDirectory) 00137 { 00138 // Check the directory exists 00139 std::string dir_path = rDirectory.GetAbsolutePath(); 00140 if (!rDirectory.IsDir() || !rDirectory.Exists()) 00141 { 00142 EXCEPTION("Checkpoint directory does not exist: " + dir_path); 00143 } 00144 assert(*(dir_path.end()-1) == '/'); // Paranoia 00145 // Load the info file 00146 std::string info_path = dir_path + "archive.info"; 00147 std::ifstream info_file(info_path.c_str()); 00148 if (!info_file.is_open()) 00149 { 00150 EXCEPTION("Unable to open archive information file: " + info_path); 00151 } 00152 unsigned num_procs, archive_version; 00153 info_file >> num_procs >> archive_version; 00154 00155 PROBLEM_CLASS *p_unarchived_simulation; 00156 00157 // Avoid the DistributedVectorFactory throwing a 'wrong number of processes' exception when loading, 00158 // and make it get the original DistributedVectorFactory from the archive so we can compare against 00159 // num_procs. 00160 DistributedVectorFactory::SetCheckNumberOfProcessesOnLoad(false); 00161 // Put what follows in a try-catch to make sure we reset this 00162 try 00163 { 00164 // Figure out which process-specific archive to load first. If we're loading on the same number of 00165 // processes, we must load our own one, or the mesh gets confused. Otherwise, start with 0 to make 00166 // sure it exists. 00167 unsigned initial_archive = num_procs == PetscTools::GetNumProcs() ? PetscTools::GetMyRank() : 0u; 00168 00169 // Load the master and initial process-specific archive files. 00170 // This will also set up ArchiveLocationInfo for us. 00171 ArchiveOpener<boost::archive::text_iarchive, std::ifstream> archive_opener(rDirectory, "archive.arch", initial_archive); 00172 boost::archive::text_iarchive* p_main_archive = archive_opener.GetCommonArchive(); 00173 (*p_main_archive) >> p_unarchived_simulation; 00174 00175 // Work out how many more process-specific files to load 00176 DistributedVectorFactory* p_factory = p_unarchived_simulation->rGetMesh().GetDistributedVectorFactory(); 00177 assert(p_factory != NULL); 00178 unsigned original_num_procs = p_factory->GetOriginalFactory()->GetNumProcs(); 00179 assert(original_num_procs == num_procs); // Paranoia 00180 00181 // Merge in the extra data 00182 for (unsigned archive_num=0; archive_num<original_num_procs; archive_num++) 00183 { 00184 if (archive_num != initial_archive) 00185 { 00186 std::string archive_path = ArchiveLocationInfo::GetProcessUniqueFilePath("archive.arch", archive_num); 00187 std::ifstream ifs(archive_path.c_str()); 00188 boost::archive::text_iarchive archive(ifs); 00189 p_unarchived_simulation->LoadExtraArchive(archive, archive_version); 00190 } 00191 } 00192 } 00193 catch (Exception &e) 00194 { 00195 DistributedVectorFactory::SetCheckNumberOfProcessesOnLoad(true); 00196 throw e; 00197 } 00198 00199 // Done. 00200 DistributedVectorFactory::SetCheckNumberOfProcessesOnLoad(true); 00201 return p_unarchived_simulation; 00202 } 00203 00204 // 00205 // Explicit instantiation 00206 // 00207 00208 template class CardiacSimulationArchiver<MonodomainProblem<1> >; 00209 template class CardiacSimulationArchiver<MonodomainProblem<2> >; 00210 template class CardiacSimulationArchiver<MonodomainProblem<3> >; 00211 00212 template class CardiacSimulationArchiver<BidomainProblem<1> >; 00213 template class CardiacSimulationArchiver<BidomainProblem<2> >; 00214 template class CardiacSimulationArchiver<BidomainProblem<3> >; 00215 00216 template class CardiacSimulationArchiver<BidomainWithBathProblem<1> >; 00217 template class CardiacSimulationArchiver<BidomainWithBathProblem<2> >; 00218 template class CardiacSimulationArchiver<BidomainWithBathProblem<3> >;