CellMLToSharedLibraryConverter.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 "CellMLToSharedLibraryConverter.hpp"
00030 
00031 #include <sstream>
00032 #include <unistd.h> // For getpid()
00033 #include <sys/stat.h> // For mkdir()
00034 #include <ctime>
00035 
00036 #include "Exception.hpp"
00037 #include "ChasteBuildRoot.hpp"
00038 #include "PetscTools.hpp"
00039 #include "DynamicModelLoaderRegistry.hpp"
00040 #include "GetCurrentWorkingDirectory.hpp"
00041 
00042 CellMLToSharedLibraryConverter::CellMLToSharedLibraryConverter(bool preserveGeneratedSources,
00043                                                                std::string component)
00044     : mPreserveGeneratedSources(preserveGeneratedSources),
00045       mComponentName(component)
00046 {
00047 }
00048 
00049 DynamicCellModelLoader* CellMLToSharedLibraryConverter::Convert(const FileFinder& rFilePath,
00050                                                                 bool isCollective)
00051 {
00052     DynamicCellModelLoader* p_loader;
00053     std::string absolute_path = rFilePath.GetAbsolutePath();
00054     // Check the file exists
00055     if (!rFilePath.Exists())
00056     {
00057         EXCEPTION("Dynamically loadable cell model '" + absolute_path + "' does not exist.");
00058     }
00059     // Find out whether rFilePath is a .cellml or .so
00060     size_t dot_position = absolute_path.find_last_of(".");
00061     if (dot_position == std::string::npos)
00062     {
00063         EXCEPTION("File does not have an extension: " + absolute_path);
00064     }
00065     std::string extension = absolute_path.substr(dot_position+1);
00066     if (extension == "cellml")
00067     {
00068         // Split the path into folder and leaf
00069         size_t slash_position = absolute_path.find_last_of("/\\");
00070         assert(slash_position != std::string::npos);
00071         std::string folder = absolute_path.substr(0, slash_position+1); // Include trailing slash
00072         std::string leaf = absolute_path.substr(slash_position+1, dot_position-slash_position); // Include dot
00073         std::string so_path = folder + "lib" + leaf + "so";
00074         // Does the .so file already exist (and was it modified after the .cellml?)
00075         FileFinder so_file(so_path, RelativeTo::Absolute);
00076         if (!so_file.Exists() || rFilePath.IsNewerThan(so_file))
00077         {
00078             if (!isCollective)
00079             {
00080                 EXCEPTION("Unable to convert .cellml to .so unless called collectively, due to possible race conditions.");
00081             }
00082             ConvertCellmlToSo(absolute_path, folder, leaf);
00083         }
00084         // Load the .so
00085         p_loader = DynamicModelLoaderRegistry::Instance()->GetLoader(so_file);
00086     }
00087     else if (extension == "so")
00088     {
00089         // Just load the .so
00090         p_loader = DynamicModelLoaderRegistry::Instance()->GetLoader(rFilePath);
00091     }
00092     else
00093     {
00094         EXCEPTION("Unsupported extension '." + extension + "' of file '" + absolute_path + "'; must be .so or .cellml");
00095     }
00096 
00097     return p_loader;
00098 }
00099 
00100 void CellMLToSharedLibraryConverter::ConvertCellmlToSo(const std::string& rCellmlFullPath,
00101                                                        const std::string& rCellmlFolder,
00102                                                        const std::string& rModelLeafName)
00103 {
00104     std::string tmp_folder, build_folder;
00105     std::string old_cwd = GetCurrentWorkingDirectory();
00106     try
00107     {
00108         // Need to create a .so file from the CellML...
00109         if (PetscTools::AmMaster())
00110         {
00111             // Create a temporary folder within heart/dynamic
00112             std::stringstream folder_name;
00113             folder_name << "dynamic/tmp_" << getpid() << "_" << time(NULL);
00114             tmp_folder = std::string(ChasteBuildRootDir()) + mComponentName + "/" + folder_name.str();
00115             build_folder = std::string(ChasteBuildRootDir()) + mComponentName + "/build/" + ChasteBuildDirName() + "/" + folder_name.str();
00116             int ret = mkdir(tmp_folder.c_str(), 0700);
00117             EXCEPT_IF_NOT(ret == 0);
00118             // Copy the .cellml file (and any relevant others) into the temporary folder
00119             size_t dot_pos = rCellmlFullPath.rfind('.');
00120             std::string cellml_base = rCellmlFullPath.substr(0, dot_pos);
00121             EXPECT0(system, "cp " + cellml_base + "* " + tmp_folder);
00122             // If there's a config file, copy that too
00123             std::string config_path = rCellmlFullPath.substr(0, rCellmlFullPath.length() - 7) + "-conf.xml";
00124             if (FileFinder(config_path, RelativeTo::Absolute).Exists())
00125             {
00126                 EXPECT0(system, "cp " + config_path + " " + tmp_folder);
00127             }
00128             // Change to Chaste source folder
00129             EXPECT0(chdir, ChasteBuildRootDir());
00130             // Run scons to generate C++ code and compile it to a .so
00131             EXPECT0(system, "scons --warn=no-all dyn_libs_only=1 build=" + ChasteBuildType() + " " + tmp_folder);
00132             EXCEPT_IF_NOT(FileFinder(tmp_folder + "/lib" + rModelLeafName + "so", RelativeTo::Absolute).Exists());
00133             // CD back
00134             EXPECT0(chdir, old_cwd);
00135             // Copy the .so to the same folder as the original .cellml file
00136             EXPECT0(system, "cp " + tmp_folder + "/lib" + rModelLeafName + "so " + rCellmlFolder);
00137             if (mPreserveGeneratedSources)
00138             {
00139                 // Copy generated source code as well
00140                 EXPECT0(system, "cp " + build_folder + "/*.?pp " + rCellmlFolder);
00141             }
00142             // Delete the temporary folders
00143             EXPECT0(system, "rm -r " + build_folder);
00144             EXPECT0(system, "rm -r " + tmp_folder);
00145         }
00146     }
00147     catch (Exception& e)
00148     {
00149         PetscTools::ReplicateException(true);
00150         // Delete the temporary folders
00151         EXPECT0(system, "rm -rf " + build_folder); // -f because folder might not exist
00152         EXPECT0(system, "rm -r " + tmp_folder);
00153         EXPECT0(chdir, old_cwd);
00154         EXCEPTION("Conversion of CellML to Chaste shared object failed. Error was: " + e.GetMessage());
00155     }
00156     // This also has the effect of a barrier, ensuring all processes wait for the
00157     // shared library to be created.
00158     PetscTools::ReplicateException(false);
00159 }
00160 
00161 void CellMLToSharedLibraryConverter::CreateOptionsFile(const OutputFileHandler& rHandler,
00162                                                        const std::string& rModelName,
00163                                                        const std::vector<std::string>& rArgs,
00164                                                        const std::string& rExtraXml)
00165 {
00166     if (PetscTools::AmMaster())
00167     {
00168         out_stream p_optfile = rHandler.OpenOutputFile(rModelName + "-conf.xml");
00169         (*p_optfile) << "<?xml version='1.0'?>" << std::endl
00170                      << "<pycml_config>" << std::endl;
00171         if (!rArgs.empty())
00172         {
00173             (*p_optfile) << "<command_line_args>" << std::endl;
00174             for (unsigned i=0; i<rArgs.size(); i++)
00175             {
00176                 (*p_optfile) << "<arg>" << rArgs[i] << "</arg>" << std::endl;
00177             }
00178             (*p_optfile) << "</command_line_args>" << std::endl;
00179         }
00180         (*p_optfile) << rExtraXml << "</pycml_config>" << std::endl;
00181         p_optfile->close();
00182     }
00183     PetscTools::Barrier("CellMLToSharedLibraryConverter::CreateOptionsFile");
00184 }

Generated on Tue May 31 14:31:41 2011 for Chaste by  doxygen 1.5.5