diff --git a/src/sbml/conversion/SBMLRateRuleConverter.cpp b/src/sbml/conversion/SBMLRateRuleConverter.cpp index c670dc4603..2fd59f5ab4 100644 --- a/src/sbml/conversion/SBMLRateRuleConverter.cpp +++ b/src/sbml/conversion/SBMLRateRuleConverter.cpp @@ -414,10 +414,15 @@ SBMLRateRuleConverter::isDocumentAppropriate(OperationReturnValues_t& returnValu if (mModel->getNumCompartments() > 1) { - mDocument->getErrorLog()->logError(ModelContainsMultipleCompartments, mDocument->getLevel(), - mDocument->getVersion(), "There are multiple compartments."); - returnValue = LIBSBML_OPERATION_FAILED; - return false; + if (speciesFromMultipleCompartmentsInSameRateRule()) + { + mDocument->getErrorLog()->logError(ModelContainsMultipleCompartments, mDocument->getLevel(), + mDocument->getVersion(), "There are multiple compartments with species in the same rate rule."); + returnValue = LIBSBML_OPERATION_FAILED; + return false; + } + returnValue = LIBSBML_OPERATION_SUCCESS; + return true; } // 3. the document is invalid @@ -434,6 +439,96 @@ SBMLRateRuleConverter::isDocumentAppropriate(OperationReturnValues_t& returnValu /** @cond doxygenIgnored */ +bool +SBMLRateRuleConverter::speciesFromMultipleCompartmentsInSameRateRule() +{ + listPairString compartmentSpeciesPairs = getCompartmentSpeciesPairs(); + listPairString variablesRateRulePairs = getVariablesRateRulePairs(); + for (listPairStringIt it_c = compartmentSpeciesPairs.begin(); + it_c != compartmentSpeciesPairs.end(); ++it_c) + { + for (listPairStringIt it_r = variablesRateRulePairs.begin(); + it_r != variablesRateRulePairs.end(); ++it_r) + { + if (it_c->second == it_r->second) + { + // species from compartment it_c->first is a participant in a rule it_r + std::string ruleVar = it_r->first; + std::string compartmentId = it_c->first; + + // check that the variable for this rule is in a same compartment + for (listPairStringIt it_c1 = compartmentSpeciesPairs.begin(); + it_c1 != compartmentSpeciesPairs.end(); ++it_c1) + { + if (it_c1 == it_c) + { + // skip the pair we have already considered + continue; + } + if (it_c1->second == ruleVar) + { + if (it_c1->first != compartmentId) + { + // variable in different compartment + return true; + } + } + } + } + } + } + return false; +} + +listPairString +SBMLRateRuleConverter::getCompartmentSpeciesPairs() +{ + listPairString compartmentSpeciesPairs; + for (unsigned int n = 0; n < mDocument->getModel()->getNumCompartments(); n++) + { + Compartment* comp = mDocument->getModel()->getCompartment(n); + std::string compId = comp->getId(); + for (unsigned int m = 0; m < mDocument->getModel()->getNumSpecies(); m++) + { + Species* spec = mDocument->getModel()->getSpecies(m); + if (spec->getCompartment() != compId) + { + continue; + } + pairString pair(comp->getId(), spec->getId()); + compartmentSpeciesPairs.push_back(pair); + } + } + + return compartmentSpeciesPairs; +} + +listPairString +SBMLRateRuleConverter::getVariablesRateRulePairs() +{ + listPairString variablesRateRulePairs; + for (unsigned int n = 0; n < mDocument->getModel()->getNumRules(); n++) + { + Rule* rule = mDocument->getModel()->getRule(n); + if (rule->getType() != RULE_TYPE_RATE) + { + continue; + } + std::string varId = rule->getVariable(); + const ASTNode* math = rule->getMath(); + List* variables = math->getListOfNodes(ASTNode_isName); + for (ListIterator it = variables->begin(); it != variables->end(); ++it) + { + ASTNode* m = static_cast(*it); + std::string mId = m->getName(); + pairString pair(varId, mId); + variablesRateRulePairs.push_back(pair); + } + } + return variablesRateRulePairs; +} + + void SBMLRateRuleConverter::addODEPair(std::string id, Model* model) { diff --git a/src/sbml/conversion/SBMLRateRuleConverter.h b/src/sbml/conversion/SBMLRateRuleConverter.h index 379d120d4c..4ff5a3b807 100644 --- a/src/sbml/conversion/SBMLRateRuleConverter.h +++ b/src/sbml/conversion/SBMLRateRuleConverter.h @@ -83,6 +83,8 @@ typedef std::vector setCoeff; typedef std::vector > >::iterator setCoeffIt; typedef std::pair pairString; +typedef std::vector< pairString > listPairString; +typedef std::vector< pairString >::iterator listPairStringIt; typedef std::vector< std::vector > setRnCoeffs; @@ -227,6 +229,12 @@ class LIBSBML_EXTERN SBMLRateRuleConverter : public SBMLConverter bool useStoichiometryFromMath(); + // functions to deal with multiple compartments + bool speciesFromMultipleCompartmentsInSameRateRule(); + + listPairString getCompartmentSpeciesPairs(); + + listPairString getVariablesRateRulePairs(); // functions for populateODEinfo() diff --git a/src/sbml/conversion/test/TestSBMLRateRuleConverter.cpp b/src/sbml/conversion/test/TestSBMLRateRuleConverter.cpp index 5dc7d1a91a..bf66c3364b 100644 --- a/src/sbml/conversion/test/TestSBMLRateRuleConverter.cpp +++ b/src/sbml/conversion/test/TestSBMLRateRuleConverter.cpp @@ -1113,7 +1113,7 @@ START_TEST(test_converter_errors_3) delete d; } END_TEST -START_TEST(test_converter_errors_4) + START_TEST(test_converter_errors_4) { std::string raterule_file(TestDataDirectory); raterule_file += "rn_rr_fail_90104.xml"; @@ -1134,6 +1134,62 @@ START_TEST(test_converter_errors_4) delete d; } END_TEST +START_TEST(test_converter_errors_5) +{ + std::string raterule_file(TestDataDirectory); + raterule_file += "rn_rr_pass_90104.xml"; + + SBMLDocument* d = readSBMLFromFile(raterule_file.c_str()); + + rule_rn_props.addOption("useStoichiometryFromMath", true); + rule_rn_converter->setProperties(&rule_rn_props); + + + rule_rn_converter->setDocument(d); + int ret = rule_rn_converter->convert(); + fail_unless(ret == LIBSBML_OPERATION_SUCCESS); + fail_unless(d->getNumErrors() == 0); + + delete d; +} +END_TEST + +START_TEST(test_converter_errors_6) +{ + std::string raterule_file(TestDataDirectory); + raterule_file += "rn_rr_fail_90104_1.xml"; + + SBMLDocument* d = readSBMLFromFile(raterule_file.c_str()); + + rule_rn_props.addOption("useStoichiometryFromMath", true); + rule_rn_converter->setProperties(&rule_rn_props); + + + rule_rn_converter->setDocument(d); + int ret = rule_rn_converter->convert(); + fail_unless(ret == LIBSBML_OPERATION_FAILED); + fail_unless(d->getNumErrors() == 1); + fail_unless(d->getError(0)->getErrorId() == 90104); + fail_unless(d->getError(0)->getCategory() == LIBSBML_CAT_RATE_RULE_CONVERSION); + + delete d; +} +END_TEST + + +START_TEST(test_rule_reaction_multi_compartment) +{ + std::string raterule_file(TestDataDirectory); + raterule_file += "rr_rn_multi_compartments.xml"; + + std::string reaction_file(TestDataDirectory); + reaction_file += "rr_rn_multi_compartments_reactions.xml"; + + bool result = test_rule_to_reaction(raterule_file, reaction_file); + + fail_unless(result == true); +} +END_TEST Suite * create_suite_TestSBMLRateRuleConverter (void) @@ -1143,10 +1199,10 @@ Suite *suite = suite_create("SBMLRateRuleConverter"); TCase *tcase = tcase_create("SBMLRateRuleConverter"); tcase_add_checked_fixture(tcase, RateRuleConverter_setup, RateRuleConverter_teardown); - + if (testing) { - tcase_add_test(tcase, test_rule_reaction_07); + tcase_add_test(tcase, test_converter_errors_6); } else { @@ -1184,6 +1240,9 @@ Suite *suite = suite_create("SBMLRateRuleConverter"); tcase_add_test(tcase, test_converter_errors_2); tcase_add_test(tcase, test_converter_errors_3); tcase_add_test(tcase, test_converter_errors_4); + tcase_add_test(tcase, test_converter_errors_5); + tcase_add_test(tcase, test_converter_errors_6); + tcase_add_test(tcase, test_rule_reaction_multi_compartment); diff --git a/src/sbml/conversion/test/test-data/rn_rr_fail_90104.xml b/src/sbml/conversion/test/test-data/rn_rr_fail_90104.xml index 41d03fe7e5..c8f83656e5 100644 --- a/src/sbml/conversion/test/test-data/rn_rr_fail_90104.xml +++ b/src/sbml/conversion/test/test-data/rn_rr_fail_90104.xml @@ -6,29 +6,21 @@ - + + + - - - - - - + - - - 2 - t - + y_3 - - - time + + + 22 - - - + + diff --git a/src/sbml/conversion/test/test-data/rn_rr_fail_90104_1.xml b/src/sbml/conversion/test/test-data/rn_rr_fail_90104_1.xml new file mode 100644 index 0000000000..0446be25aa --- /dev/null +++ b/src/sbml/conversion/test/test-data/rn_rr_fail_90104_1.xml @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + y_2 + y_3 + + + + + + diff --git a/src/sbml/conversion/test/test-data/rn_rr_pass_90104.xml b/src/sbml/conversion/test/test-data/rn_rr_pass_90104.xml new file mode 100644 index 0000000000..41d03fe7e5 --- /dev/null +++ b/src/sbml/conversion/test/test-data/rn_rr_pass_90104.xml @@ -0,0 +1,34 @@ + + + + + + + + + + + + + + + + + + + + + 2 + t + + + + + + time + + + + + + diff --git a/src/sbml/conversion/test/test-data/rr_rn_multi_compartments.xml b/src/sbml/conversion/test/test-data/rr_rn_multi_compartments.xml new file mode 100644 index 0000000000..020adef151 --- /dev/null +++ b/src/sbml/conversion/test/test-data/rr_rn_multi_compartments.xml @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + 11 + + + + + 22 + + + + + diff --git a/src/sbml/conversion/test/test-data/rr_rn_multi_compartments_reactions.xml b/src/sbml/conversion/test/test-data/rr_rn_multi_compartments_reactions.xml new file mode 100644 index 0000000000..ccda1a3d79 --- /dev/null +++ b/src/sbml/conversion/test/test-data/rr_rn_multi_compartments_reactions.xml @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + + + + 11 + + + + + + + + + + 22 + + + + + +