CellMLToSharedLibraryConverter.cpp

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 #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 
00041 DynamicCellModelLoader* CellMLToSharedLibraryConverter::Convert(const FileFinder& rFilePath,
00042                                                                 bool isCollective)
00043 {
00044     DynamicCellModelLoader* p_loader;
00045     std::string absolute_path = rFilePath.GetAbsolutePath();
00046     // Check the file exists
00047     if (!rFilePath.Exists())
00048     {
00049         EXCEPTION("Dynamically loadable cell model '" + absolute_path + "' does not exist.");
00050     }
00051     // Find out whether rFilePath is a .cellml or .so
00052     size_t dot_position = absolute_path.find_last_of(".");
00053     if (dot_position == std::string::npos)
00054     {
00055         EXCEPTION("File does not have an extension: " + absolute_path);
00056     }
00057     std::string extension = absolute_path.substr(dot_position+1);
00058     if (extension == "cellml")
00059     {
00060         // Split the path into folder and leaf
00061         size_t slash_position = absolute_path.find_last_of("/\\");
00062         assert(slash_position != std::string::npos);
00063         std::string folder = absolute_path.substr(0, slash_position+1); // Include trailing slash
00064         std::string leaf = absolute_path.substr(slash_position+1, dot_position-slash_position); // Include dot
00065         std::string so_path = folder + "lib" + leaf + "so";
00066         // Does the .so file already exist (and was it modified after the .cellml?)
00067         FileFinder so_file(so_path, cp::relative_to_type::absolute);
00068         if (!so_file.Exists() || rFilePath.IsNewerThan(so_file))
00069         {
00070             if (!isCollective)
00071             {
00072                 EXCEPTION("Unable to convert .cellml to .so unless called collectively, due to possible race conditions.");
00073             }
00074             ConvertCellmlToSo(absolute_path, folder, leaf);
00075         }
00076         // Load the .so
00077         p_loader = DynamicModelLoaderRegistry::Instance()->GetLoader(so_file);
00078     }
00079     else if (extension == "so")
00080     {
00081         // Just load the .so
00082         p_loader = DynamicModelLoaderRegistry::Instance()->GetLoader(rFilePath);
00083     }
00084     else
00085     {
00086         EXCEPTION("Unsupported extension '." + extension + "' of file '" + absolute_path + "'; must be .so or .cellml");
00087     }
00088 
00089     return p_loader;
00090 }
00091 
00092 void CellMLToSharedLibraryConverter::ConvertCellmlToSo(const std::string& rCellmlFullPath,
00093                                                        const std::string& rCellmlFolder,
00094                                                        const std::string& rModelLeafName)
00095 {
00096     std::string tmp_folder, build_folder;
00097     try
00098     {
00099         // Need to create a .so file from the CellML...
00100         if (PetscTools::AmMaster())
00101         {
00102             // Create a temporary folder within heart/dynamic
00103             std::stringstream folder_name;
00104             folder_name << "dynamic/tmp_" << getpid() << "_" << time(NULL);
00105             tmp_folder = std::string(ChasteBuildRootDir()) + "heart/" + folder_name.str();
00106             build_folder = std::string(ChasteBuildRootDir()) + "heart/build/" + ChasteBuildDirName() + "/" + folder_name.str();
00107             int ret = mkdir(tmp_folder.c_str(), 0700);
00108             if (ret != 0)
00109             { // Some optimised builds see ret as unused if this line is just assert(ret ==0);
00110                 NEVER_REACHED;
00111             }
00112             // Copy the .cellml file into the temporary folder
00113             EXPECT0(system, "cp " + rCellmlFullPath + " " + tmp_folder);
00114             // Run PyCml to generate C++ code
00115             EXPECT0(system, "./python/ConvertCellModel.py -y --normal " + tmp_folder + "/" + rModelLeafName + "cellml");
00116             // Run scons to compile it to a .so
00117             EXPECT0(system, "scons dyn_libs_only=1 build=" + ChasteBuildType() + " " + tmp_folder);
00118             // Copy the .so to the same folder as the original .cellml file
00119             EXPECT0(system, "cp " + tmp_folder + "/lib" + rModelLeafName + "so " + rCellmlFolder);
00120             // Delete the temporary folders
00121             EXPECT0(system, "rm -r " + build_folder);
00122             EXPECT0(system, "rm -r " + tmp_folder);
00123         }
00124     }
00125     catch (Exception& e)
00126     {
00127         PetscTools::ReplicateException(true);
00128         // Delete the temporary folders
00129         EXPECT0(system, "rm -rf " + build_folder); // -f because folder might not exist
00130         EXPECT0(system, "rm -r " + tmp_folder);
00131         EXCEPTION("Conversion of CellML to Chaste shared object failed. Error was: " + e.GetMessage());
00132     }
00133     // This also has the effect of a barrier, ensuring all processes wait for the
00134     // shared library to be created.
00135     PetscTools::ReplicateException(false);
00136 }

Generated by  doxygen 1.6.2