diff --git a/copasi/sedml/SEDMLImporter.cpp b/copasi/sedml/SEDMLImporter.cpp index 24e9947c68..21d5b453b0 100644 --- a/copasi/sedml/SEDMLImporter.cpp +++ b/copasi/sedml/SEDMLImporter.cpp @@ -1005,7 +1005,7 @@ SEDMLImporter::parseSEDML(const std::string & sedmlDocumentText, case LIBSEDML_SEV_FATAL: - // treat unknown as fatal + // treat unknown as fatal default: if (pSEDMLError->getErrorId() == 10804) @@ -1064,15 +1064,22 @@ SEDMLImporter::parseSEDML(const std::string & sedmlDocumentText, // initialize data: initializeContent(); + setSEDMLDocument(pSEDMLDocument); + // merge subtasks if needed mergeNestedSubtasks(); - setSEDMLDocument(pSEDMLDocument); - - if (pOptions != NULL && !pOptions->getModelId().empty()) - importModel(pOptions->getModelId()); + if (pOptions == NULL || pOptions->skipModelImport() == false) + { + if (pOptions != NULL && !pOptions->getModelId().empty()) + importModel(pOptions->getModelId()); + else + importFirstSBMLModel(); + } else - importFirstSBMLModel(); + { + mpCopasiModel = pDataModel->getModel(); + } if (pOptions != NULL && !pOptions->getTaskId().empty()) importTask(mpSEDMLDocument->getTask(pOptions->getTaskId()), false); @@ -1083,7 +1090,6 @@ SEDMLImporter::parseSEDML(const std::string & sedmlDocumentText, assignReportDefinitions(); - if (mpProcessReport != NULL) mpProcessReport->finishItem(mhImportStep); @@ -1145,10 +1151,8 @@ void SEDMLImporter::importTasks(CDataVectorN< CCopasiTask > * pTaskList) importTask(task, pTaskList); } - } - void SEDMLImporter::assignReportDefinitions(CDataVectorN< CCopasiTask > * pTaskList) { @@ -1292,7 +1296,7 @@ void SEDMLImporter::importTask( std::stringstream str; std::vector< double > vals = vrange->getValues(); -for (double val : vals) + for (double val : vals) str << val << " "; group->setValue< std::string >("Values", str.str()); @@ -1428,7 +1432,7 @@ SEDMLImporter::convertSimpleFunctionalRange(SedFunctionalRange * frange, SedRepe knownValues[p->getId()] = p->getValue(); } -for (auto value : oldValues) + for (auto value : oldValues) { knownValues[insideVRange->getId()] = value; newValues.push_back(SBMLTransforms::evaluateASTNode(frange->getMath(), knownValues)); diff --git a/copasi/sedml/SEDMLUtils.cpp b/copasi/sedml/SEDMLUtils.cpp index b4d0b1222b..ea4a6b54d9 100644 --- a/copasi/sedml/SEDMLUtils.cpp +++ b/copasi/sedml/SEDMLUtils.cpp @@ -681,6 +681,9 @@ void SEDMLUtils::setLibCombineTempDir() const CDataObject * SEDMLUtils::getObjectForSbmlId(const CModel * pModel, const std::string & id, const std::string & SBMLType, bool initial /* = false*/) { + if (!pModel) + return NULL; + if (SBMLType == "Time") return static_cast< const CDataObject * >(pModel->getObject(CCommonName("Reference=Time"))); @@ -959,25 +962,7 @@ SedmlInfo::SedmlInfo(SedDocument * pDocument, bool ownDocument) if (!pDocument) return; - std::map< int, int > taskCount; - - for (unsigned int i = 0; i < pDocument->getNumTasks(); ++i) - { - auto * current = pDocument->getTask(i); - mTaskMap[current->getId()] = getModelForTask(current); - taskCount[current->getTypeCode()] = taskCount[current->getTypeCode()] + 1; - mReports[current->getId()] = std::vector< std::pair< std::string, std::string > >(); - mPlots[current->getId()] = std::vector< std::pair< std::string, std::string > >(); - std::stringstream str; - - if (current->isSetName()) - str << current->getName() << " - "; - - str << current->getId(); - - mTaskNames.push_back(std::make_pair(current->getId(), str.str())); - mComplex |= taskCount[current->getTypeCode()] > 1 || mTaskMap[current->getId()].size() > 1; - } + std::map< std::pair< int, int>, int > taskCount; for (unsigned int i = 0; i < pDocument->getNumOutputs(); ++i) { @@ -1000,6 +985,57 @@ SedmlInfo::SedmlInfo(SedDocument * pDocument, bool ownDocument) mPlots[taskId].push_back(std::make_pair(current->getId(), str.str())); } } + + for (unsigned int i = 0; i < pDocument->getNumTasks(); ++i) + { + auto * current = pDocument->getTask(i); + + if (isRecursiveWithoutOutputs(current)) + continue; + + mTaskMap[current->getId()] = getModelForTask(current); + + int simType = SEDML_SIMULATION; + + if (current->getTypeCode() == SEDML_TASK) + { + auto * simulation = pDocument->getSimulation(dynamic_cast< SedTask * >(current)->getSimulationReference()); + + if (simulation != NULL) + simType = simulation->getTypeCode(); + } + + auto currentKey = std::make_pair(current->getTypeCode(), simType); + + taskCount[currentKey] = taskCount[currentKey] + 1; + std::stringstream str; + + if (current->isSetName()) + str << current->getName() << " - "; + + str << current->getId(); + + mTaskNames.push_back(std::make_pair(current->getId(), str.str())); + mComplex |= taskCount[currentKey] > 1 || mTaskMap[current->getId()].size() > 1; + } +} + +bool SedmlInfo::hasOutputs(const std::string & taskId) +{ + return !(mReports[taskId].empty() && mPlots[taskId].empty()); +} + +bool SedmlInfo::isRecursiveWithoutOutputs(SedAbstractTask * task) +{ + auto * repeat = dynamic_cast< SedRepeatedTask * >(task); + + if (repeat == NULL) + return false; + + if (hasOutputs(task->getId())) + return false; + + return true; } SedmlInfo::~SedmlInfo() @@ -1283,6 +1319,7 @@ SedmlImportOptions::SedmlImportOptions( , mPlots(plots) , mReportId(reportId) , mReportFile(reportFilename) + , mSkipModelImport(false) { } @@ -1295,11 +1332,22 @@ SedmlImportOptions & SedmlImportOptions::operator=(const SedmlImportOptions & rh mPlots = rhs.mPlots; mReportId = rhs.mReportId; mReportFile = rhs.mReportFile; + mSkipModelImport = rhs.mSkipModelImport; } return *this; } +void SedmlImportOptions::setSkipModelImport(bool skipModelLoading) +{ + mSkipModelImport = skipModelLoading; +} + +bool SedmlImportOptions::skipModelImport() const +{ + return mSkipModelImport; +} + const std::string & SedmlImportOptions::getTaskId() const { return mTaskId; diff --git a/copasi/sedml/SEDMLUtils.h b/copasi/sedml/SEDMLUtils.h index 30ce00f4ca..86d11ec41b 100644 --- a/copasi/sedml/SEDMLUtils.h +++ b/copasi/sedml/SEDMLUtils.h @@ -116,7 +116,7 @@ class SedmlInfo bool isSupported(); /** - * @return true, if the document is complex ( > 1 model, multiple + * @return true, if the document is complex (> 1 model, multiple tasks of the same type ) requiring the user to choose which one to import. */ @@ -136,6 +136,9 @@ class SedmlInfo std::vector< std::pair< std::string, std::string > > getReportsForTask(const std::string & taskId); std::vector< std::pair< std::string, std::string > > getPlotsForTask(const std::string & taskId); + bool hasOutputs(const std::string & taskId); + bool isRecursiveWithoutOutputs(SedAbstractTask * task); + std::string getReportFileName(const std::string & reportId); void setReportFileName(const std::string & reportId, const std::string & fileName); @@ -146,7 +149,6 @@ class SedmlInfo static SedmlInfo forFile(const std::string & fileName); }; - /** * Utility methods for SED-ML Import / Export */ @@ -236,7 +238,6 @@ class SEDMLUtils static int getAlphaFromArgb(const std::string & argb); static int getAlphaFromRgba(const std::string & rgba); - /** * updates the libcombine temp directory to the COPASI temp path */ diff --git a/copasi/sedml/SedmlImportOptions.h b/copasi/sedml/SedmlImportOptions.h index 2c688cc69a..e8ef2fcfd3 100644 --- a/copasi/sedml/SedmlImportOptions.h +++ b/copasi/sedml/SedmlImportOptions.h @@ -16,6 +16,7 @@ class SedmlImportOptions std::vector< std::string > mPlots; std::string mReportId; std::string mReportFile; + bool mSkipModelImport; public: SedmlImportOptions( @@ -27,6 +28,9 @@ class SedmlImportOptions SedmlImportOptions & operator=(const SedmlImportOptions & rhs); + void setSkipModelImport(bool skipModelLoading); + bool skipModelImport() const; + const std::string & getTaskId() const; const std::string & getModelId() const; const std::string & getReportId() const; @@ -36,8 +40,4 @@ class SedmlImportOptions bool isValid() const; }; - #endif // SEDML_IMPORT_OPTIONS_H - - - diff --git a/tests/test_sedml.cpp b/tests/test_sedml.cpp index 659de3e794..ca43a0b6e4 100644 --- a/tests/test_sedml.cpp +++ b/tests/test_sedml.cpp @@ -140,7 +140,7 @@ TEST_CASE("importing variables with terms", "[copasi,sedml]") CRootContainer::removeDatamodel(dm); } -TEST_CASE("export nested scan", "[copasi,sedml]") +TEST_CASE("export / import nested scan", "[copasi,sedml]") { auto * dm = CRootContainer::addDatamodel(); REQUIRE(dm != nullptr); @@ -156,8 +156,25 @@ TEST_CASE("export nested scan", "[copasi,sedml]") REQUIRE(doc->getDataGenerator("Rtot_1_task3") == NULL); REQUIRE(doc->getDataGenerator("Rtot_1_task5") != NULL); + // the model has a timecourse, and a steady state scan with 3 variables, as such it should not be complex + REQUIRE(SedmlInfo(doc).isComplex() == false); + + // if we had another time course then it should be complex + { + auto * task = doc->getTask(0)->clone(); + task->setId("anotherTaks"); + doc->getListOfTasks()->appendAndOwn(task); + REQUIRE(SedmlInfo(doc).isComplex() == true); + } + delete doc; + // now import + SedmlImportOptions opts; + opts.setSkipModelImport(true); + dm->importSEDMLFromString(sedml, "", NULL, true, &opts); + REQUIRE(dynamic_cast< CScanProblem * >(dm->getTaskList()->operator[]("Scan").getProblem())->getNumberOfScanItems() == 3); + CRootContainer::removeDatamodel(dm); }