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); }