void GenerateCells() throw (Exception)
    {
        // Do the conversions preserving generated sources
        CellMLToSharedLibraryConverter converter(true);
        std::string dirname = "TestGeneralizedRushLarsen";
        std::string model = "LuoRudy1991";
        boost::shared_ptr<AbstractIvpOdeSolver> p_solver;
        boost::shared_ptr<ZeroStimulus> p_stimulus(new ZeroStimulus());

        std::vector<std::string> args;
        args.push_back("--grl1");

        { // No opt
            // Copy CellML file into output dir
            OutputFileHandler handler(dirname + "/normal");
            FileFinder cellml_file("heart/src/odes/cellml/" + model + ".cellml", RelativeTo::ChasteSourceRoot);
            FileFinder copied_file = handler.CopyFileTo(cellml_file);

            // Create options file & convert
            converter.CreateOptionsFile(handler, model, args);
            DynamicCellModelLoaderPtr p_loader = converter.Convert(copied_file);
            mpGeneralizedRushLarsenCell = dynamic_cast<AbstractCardiacCell*>(p_loader->CreateCell(p_solver, p_stimulus));
        }
    }
void CellMLToSharedLibraryConverter::ConvertCellmlToSo(const std::string& rCellmlFullPath,
                                                       const std::string& rCellmlFolder)
{
    FileFinder tmp_folder;
    FileFinder build_folder;

    std::string old_cwd = GetCurrentWorkingDirectory();
    // Check that the Chaste build tree exists
    FileFinder chaste_root("", RelativeTo::ChasteBuildRoot);

    if (!chaste_root.IsDir())
    {
        EXCEPTION("No Chaste build tree found at '" << chaste_root.GetAbsolutePath()
                  << "' - you need the source to use CellML models directly in Chaste.");
    }
    FileFinder component_dir(mComponentName, RelativeTo::ChasteBuildRoot);
    if (!component_dir.IsDir())
    {
        EXCEPTION("Unable to convert CellML model: required Chaste component '" << mComponentName
                  << "' does not exist in '" << chaste_root.GetAbsolutePath() << "'.");
    }
    // Try the conversion
    try
    {
        // Need to create a .so file from the CellML...
        if (PetscTools::AmMaster())
        {
            // Create a temporary folder within heart/dynamic
            std::stringstream folder_name;
            folder_name << "dynamic/tmp_" << getpid() << "_" << time(NULL);

#ifdef CHASTE_CMAKE ///todo: #2656 - ignoring all cmake-specific code, revise after cmake transition
#define COVERAGE_IGNORE
            tmp_folder.SetPath(component_dir.GetAbsolutePath() + "/" + folder_name.str(), RelativeTo::Absolute);
            build_folder.SetPath(component_dir.GetAbsolutePath() + "/" + folder_name.str(), RelativeTo::Absolute);
#undef COVERAGE_IGNORE
#else
            tmp_folder.SetPath(component_dir.GetAbsolutePath() + "/" + folder_name.str(), RelativeTo::Absolute);
            build_folder.SetPath(component_dir.GetAbsolutePath() + "/build/" + ChasteBuildDirName() + "/" + folder_name.str(), RelativeTo::Absolute);
#endif

            int ret = mkdir((tmp_folder.GetAbsolutePath()).c_str(), 0700);
            if (ret != 0)
            {
                EXCEPTION("Failed to create temporary folder '" << tmp_folder.GetAbsolutePath() << "' for CellML conversion: "
                          << strerror(errno));
            }

            // Copy the .cellml file (and any relevant others) into the temporary folder
            FileFinder cellml_file(rCellmlFullPath, RelativeTo::Absolute);
            FileFinder cellml_folder = cellml_file.GetParent();
            std::string cellml_leaf_name = cellml_file.GetLeafNameNoExtension();
            std::vector<FileFinder> cellml_files = cellml_folder.FindMatches(cellml_leaf_name + "*");

            BOOST_FOREACH(const FileFinder& r_cellml_file, cellml_files)
            {
                r_cellml_file.CopyTo(tmp_folder);
            }

#ifdef CHASTE_CMAKE ///todo: #2656 - ignoring all cmake-specific code, revise after cmake transition
#define COVERAGE_IGNORE
            std::string cmake_lists_filename = tmp_folder.GetAbsolutePath() + "/CMakeLists.txt";
            std::ofstream cmake_lists_filestream(cmake_lists_filename.c_str());
            cmake_lists_filestream << "cmake_minimum_required(VERSION 2.8.10)\n" <<
                                      "find_package(Chaste COMPONENTS " << mComponentName << ")\n" <<
                                      "chaste_do_cellml(sources " << cellml_file.GetAbsolutePath() << " " << "ON)\n" <<
                                      "set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})\n" <<
                                      "include_directories(${Chaste_THIRD_PARTY_INCLUDE_DIRS} ${Chaste_INCLUDE_DIRS})\n" <<
                                      "add_library(" << cellml_leaf_name << " SHARED " << "${sources})\n"
                                      //"target_link_libraries(" << cellml_leaf_name << " ${Chaste_LIBRARIES})\n"
                                      ;
            cmake_lists_filestream.close();
            std::string cmake_args = " -DCMAKE_PREFIX_PATH=" + chaste_root.GetAbsolutePath() +
                                     " -DCMAKE_BUILD_TYPE=" + ChasteBuildType() +
                                     " -DBUILD_SHARED_LIBS=ON" +
                                     " -DENABLE_CHASTE_TESTING=OFF" +
                                     " -DChaste_USE_SHARED_LIBS=ON";
            EXPECT0(chdir, tmp_folder.GetAbsolutePath());
            EXPECT0(system, "cmake" + cmake_args + " .");
            EXPECT0(system, "cmake --build . --config " + ChasteBuildType());
#undef COVERAGE_IGNORE
#else
            // Change to Chaste source folder
            EXPECT0(chdir, chaste_root.GetAbsolutePath());
            // Run scons to generate C++ code and compile it to a .so
            EXPECT0(system, "scons --warn=no-all dyn_libs_only=1 build=" + ChasteBuildType() + " " + tmp_folder.GetAbsolutePath());
#endif

            FileFinder so_file(tmp_folder.GetAbsolutePath() + "/lib" + cellml_leaf_name + "." + msSoSuffix, RelativeTo::Absolute);
            EXCEPT_IF_NOT(so_file.Exists());
            // CD back
            EXPECT0(chdir, old_cwd);

            // Copy the .so to the same folder as the original .cellml file
            FileFinder destination_folder(rCellmlFolder, RelativeTo::Absolute);
            so_file.CopyTo(destination_folder);

            if (mPreserveGeneratedSources)
            {
                // Copy generated source code as well
                std::vector<FileFinder> generated_files = build_folder.FindMatches("*.?pp");
                BOOST_FOREACH(const FileFinder& r_generated_file, generated_files)
                {
                    r_generated_file.CopyTo(destination_folder);
                }
            }
            // Delete the temporary folders
            build_folder.DangerousRemove();
            tmp_folder.DangerousRemove();
        }
    void RunTest(const std::string& rOutputDirName,
                 const std::string& rModelName,
                 const std::vector<std::string>& rArgs,
                 bool testLookupTables=false,
                 double tableTestV=-1000)
    {
        // Copy CellML file (and .out if present) into output dir
        OutputFileHandler handler(rOutputDirName, true);
        FileFinder cellml_file("heart/test/data/cellml/" + rModelName + ".cellml", RelativeTo::ChasteSourceRoot);
        handler.CopyFileTo(cellml_file);
        FileFinder out_file("heart/test/data/cellml/" + rModelName + ".out", RelativeTo::ChasteSourceRoot);
        if (out_file.Exists())
        {
            handler.CopyFileTo(out_file);
        }

        // Create options file
        std::vector<std::string> args(rArgs);
//        args.push_back("--profile");
        CellMLToSharedLibraryConverter converter(true);
        if (!args.empty())
        {
            converter.CreateOptionsFile(handler, rModelName, args);
        }

        // Do the conversion
        FileFinder copied_file(rOutputDirName + "/" + rModelName + ".cellml", RelativeTo::ChasteTestOutput);
        DynamicCellModelLoaderPtr p_loader = converter.Convert(copied_file);
        // Apply a stimulus of -40 uA/cm^2 - should work for all models
        boost::shared_ptr<AbstractCardiacCellInterface> p_cell(CreateCellWithStandardStimulus(*p_loader, -40.0));

        // Check that the default stimulus units are correct
        if (p_cell->HasCellMLDefaultStimulus())
        {
            // Record the existing stimulus and re-apply it at the end
            boost::shared_ptr<AbstractStimulusFunction> original_stim = p_cell->GetStimulusFunction();

            // Tell the cell to use the default stimulus and retrieve it
            boost::shared_ptr<RegularStimulus> p_reg_stim = p_cell->UseCellMLDefaultStimulus();

            if (rModelName!="aslanidi_model_2009") // Even before recent changes aslanidi model has stimulus of -400 !
            {
                // Stimulus magnitude should be approximately between -5 and -81 uA/cm^2
                TS_ASSERT_LESS_THAN(p_reg_stim->GetMagnitude(),-5);
                TS_ASSERT_LESS_THAN(-81,p_reg_stim->GetMagnitude());
            }

            // Stimulus duration should be approximately between 0.1 and 5 ms.
            TS_ASSERT_LESS_THAN(p_reg_stim->GetDuration(),6.01);
            TS_ASSERT_LESS_THAN(0.1,p_reg_stim->GetDuration());

            // Stimulus period should be approximately between 70 (for bondarenko - seems fast! - would expect 8-10 beats per second for mouse) and 2000ms.
            TS_ASSERT_LESS_THAN(p_reg_stim->GetPeriod(),2000);
            TS_ASSERT_LESS_THAN(70,p_reg_stim->GetPeriod());

            p_cell->SetIntracellularStimulusFunction(original_stim);
        }

        // Check lookup tables exist if they should
        if (testLookupTables && rModelName != "hodgkin_huxley_squid_axon_model_1952_modified")
        {
            double v = p_cell->GetVoltage();
            p_cell->SetVoltage(tableTestV);
            TS_ASSERT_THROWS_CONTAINS(p_cell->GetIIonic(), "outside lookup table range");
            p_cell->SetVoltage(v);
        }
        Simulate(rOutputDirName, rModelName, p_cell);
    }