Skip to content

Commit b523118

Browse files
committed
Prevents conversion with multi-compartment rate rules
Adds a check to prevent rate rule conversion when species from different compartments appear in the same rate rule. This change ensures that the converter correctly handles models with multiple compartments and avoids generating invalid or unexpected results. Also, adds example models for testing.
1 parent 7597cd3 commit b523118

File tree

5 files changed

+180
-6
lines changed

5 files changed

+180
-6
lines changed

src/sbml/conversion/SBMLRateRuleConverter.cpp

Lines changed: 96 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -414,10 +414,15 @@ SBMLRateRuleConverter::isDocumentAppropriate(OperationReturnValues_t& returnValu
414414

415415
if (mModel->getNumCompartments() > 1)
416416
{
417-
mDocument->getErrorLog()->logError(ModelContainsMultipleCompartments, mDocument->getLevel(),
418-
mDocument->getVersion(), "There are multiple compartments.");
419-
returnValue = LIBSBML_OPERATION_FAILED;
420-
return false;
417+
if (speciesFromMultipleCompartmentsInSameRateRule())
418+
{
419+
mDocument->getErrorLog()->logError(ModelContainsMultipleCompartments, mDocument->getLevel(),
420+
mDocument->getVersion(), "There are multiple compartments with species in the same rate rule.");
421+
returnValue = LIBSBML_OPERATION_FAILED;
422+
return false;
423+
}
424+
returnValue = LIBSBML_OPERATION_SUCCESS;
425+
return true;
421426
}
422427

423428
// 3. the document is invalid
@@ -434,6 +439,93 @@ SBMLRateRuleConverter::isDocumentAppropriate(OperationReturnValues_t& returnValu
434439

435440
/** @cond doxygenIgnored */
436441

442+
bool
443+
SBMLRateRuleConverter::speciesFromMultipleCompartmentsInSameRateRule()
444+
{
445+
listPairString compartmentSpeciesPairs = getCompartmentSpeciesPairs();
446+
listPairString VariablesRateRulePairs = getVariablesRateRulePairs();
447+
for (listPairStringIt it1 = compartmentSpeciesPairs.begin();
448+
it1 != compartmentSpeciesPairs.end(); ++it1)
449+
{
450+
for (listPairStringIt it2 = VariablesRateRulePairs.begin();
451+
it2 != VariablesRateRulePairs.end(); ++it2)
452+
{
453+
if (it1->second == it2->first)
454+
{
455+
// species as variable in rate rule found
456+
for (listPairStringIt it3 = compartmentSpeciesPairs.begin(); it3 != compartmentSpeciesPairs.end(); ++it3)
457+
{
458+
if (it3->second == it2->first && it3 != it1)
459+
{
460+
// species from different compartment in same rate rule found
461+
if (it3->first != it1->first)
462+
{
463+
return true;
464+
}
465+
}
466+
}
467+
}
468+
}
469+
}
470+
return false;
471+
}
472+
473+
listPairString
474+
SBMLRateRuleConverter::getCompartmentSpeciesPairs()
475+
{
476+
listPairString compartmentSpeciesPairs;
477+
for (unsigned int n = 0; n < mDocument->getModel()->getNumCompartments(); n++)
478+
{
479+
Compartment* comp = mDocument->getModel()->getCompartment(n);
480+
std::string compId = comp->getId();
481+
for (unsigned int m = 0; m < mDocument->getModel()->getNumSpecies(); m++)
482+
{
483+
Species* spec = mDocument->getModel()->getSpecies(m);
484+
if (spec->getCompartment() != compId)
485+
{
486+
continue;
487+
}
488+
pairString pair(comp->getId(), spec->getId());
489+
compartmentSpeciesPairs.push_back(pair);
490+
}
491+
}
492+
493+
return compartmentSpeciesPairs;
494+
}
495+
496+
listPairString
497+
SBMLRateRuleConverter::getVariablesRateRulePairs()
498+
{
499+
listPairString VariablesRateRulePairs;
500+
for (unsigned int n = 0; n < mDocument->getModel()->getNumRules(); n++)
501+
{
502+
Rule* rule = mDocument->getModel()->getRule(n);
503+
if (rule->getType() != RULE_TYPE_RATE)
504+
{
505+
continue;
506+
}
507+
std::string varId = rule->getVariable();
508+
const ASTNode* math = rule->getMath();
509+
List* variables = math->getListOfNodes(ASTNode_isName);
510+
for (ListIterator it = variables->begin(); it != variables->end(); ++it)
511+
{
512+
ASTNode* m = static_cast<ASTNode*>(*it);
513+
std::string mId = m->getName();
514+
if (mId != varId)
515+
{
516+
continue;
517+
}
518+
else
519+
{
520+
pairString pair(varId, mId);
521+
VariablesRateRulePairs.push_back(pair);
522+
}
523+
}
524+
}
525+
return VariablesRateRulePairs;
526+
}
527+
528+
437529
void
438530
SBMLRateRuleConverter::addODEPair(std::string id, Model* model)
439531
{

src/sbml/conversion/SBMLRateRuleConverter.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,8 @@ typedef std::vector<pairCoeff > setCoeff;
8383
typedef std::vector<std::pair<ASTNode*, std::vector<double> > >::iterator setCoeffIt;
8484

8585
typedef std::pair<std::string, std::string > pairString;
86+
typedef std::list< pairString > listPairString;
87+
typedef std::list< pairString >::iterator listPairStringIt;
8688
typedef std::vector< std::vector<double> > setRnCoeffs;
8789

8890

@@ -227,6 +229,12 @@ class LIBSBML_EXTERN SBMLRateRuleConverter : public SBMLConverter
227229

228230
bool useStoichiometryFromMath();
229231

232+
// functions to deal with multiple compartments
233+
bool speciesFromMultipleCompartmentsInSameRateRule();
234+
235+
listPairString getCompartmentSpeciesPairs();
236+
237+
listPairString getVariablesRateRulePairs();
230238

231239
// functions for populateODEinfo()
232240

src/sbml/conversion/test/TestSBMLRateRuleConverter.cpp

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1135,18 +1135,32 @@ START_TEST(test_converter_errors_4)
11351135
}
11361136
END_TEST
11371137

1138+
START_TEST(test_rule_reaction_multi_compartment)
1139+
{
1140+
std::string raterule_file(TestDataDirectory);
1141+
raterule_file += "rr_rn_multi_compartments.xml";
1142+
1143+
std::string reaction_file(TestDataDirectory);
1144+
reaction_file += "rr_rn_multi_compartments_reactions.xml";
1145+
1146+
bool result = test_rule_to_reaction(raterule_file, reaction_file);
1147+
1148+
fail_unless(result == true);
1149+
}
1150+
END_TEST
1151+
11381152
Suite *
11391153
create_suite_TestSBMLRateRuleConverter (void)
11401154
{
1141-
bool testing = false;
1155+
bool testing = true;
11421156
Suite *suite = suite_create("SBMLRateRuleConverter");
11431157
TCase *tcase = tcase_create("SBMLRateRuleConverter");
11441158
tcase_add_checked_fixture(tcase, RateRuleConverter_setup,
11451159
RateRuleConverter_teardown);
11461160

11471161
if (testing)
11481162
{
1149-
tcase_add_test(tcase, test_rule_reaction_07);
1163+
tcase_add_test(tcase, test_rule_reaction_multi_compartment);
11501164
}
11511165
else
11521166
{
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<sbml xmlns="http://www.sbml.org/sbml/level3/version1/core" level="3" version="1">
3+
<model>
4+
<listOfCompartments>
5+
<compartment id="compartmentOne" spatialDimensions="3" size="1" constant="true"/>
6+
<compartment id="compartmentTwo" spatialDimensions="3" size="1" constant="true"/>
7+
</listOfCompartments>
8+
<listOfSpecies>
9+
<species id="y_1" name="y_1" compartment="compartmentOne" initialConcentration="0" hasOnlySubstanceUnits="false" boundaryCondition="false" constant="false"/>
10+
<species id="y_2" name="y_2" compartment="compartmentTwo" initialConcentration="0" hasOnlySubstanceUnits="false" boundaryCondition="false" constant="false"/>
11+
</listOfSpecies>
12+
<listOfRules>
13+
<rateRule variable="y_1">
14+
<math xmlns="http://www.w3.org/1998/Math/MathML">
15+
<cn> 11 </cn>
16+
</math>
17+
</rateRule>
18+
<rateRule variable="y_2">
19+
<math xmlns="http://www.w3.org/1998/Math/MathML">
20+
<cn> 22 </cn>
21+
</math>
22+
</rateRule>
23+
</listOfRules>
24+
</model>
25+
</sbml>
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<sbml xmlns="http://www.sbml.org/sbml/level3/version1/core" level="3" version="1">
3+
<model>
4+
<listOfCompartments>
5+
<compartment id="compartmentOne" spatialDimensions="3" size="1" constant="true"/>
6+
<compartment id="compartmentTwo" spatialDimensions="3" size="1" constant="true"/>
7+
</listOfCompartments>
8+
<listOfSpecies>
9+
<species id="y_1" name="y_1" compartment="compartmentOne" initialConcentration="0" hasOnlySubstanceUnits="false" boundaryCondition="false" constant="false"/>
10+
<species id="y_2" name="y_2" compartment="compartmentTwo" initialConcentration="0" hasOnlySubstanceUnits="false" boundaryCondition="false" constant="false"/>
11+
</listOfSpecies>
12+
<listOfReactions>
13+
<reaction id="J1" reversible="false" fast="false">
14+
<listOfProducts>
15+
<speciesReference species="y_1" stoichiometry="1" constant="true"/>
16+
</listOfProducts>
17+
<kineticLaw>
18+
<math xmlns="http://www.w3.org/1998/Math/MathML">
19+
<cn> 11 </cn>
20+
</math>
21+
</kineticLaw>
22+
</reaction>
23+
<reaction id="J2" reversible="false" fast="false">
24+
<listOfProducts>
25+
<speciesReference species="y_2" stoichiometry="1" constant="true"/>
26+
</listOfProducts>
27+
<kineticLaw>
28+
<math xmlns="http://www.w3.org/1998/Math/MathML">
29+
<cn> 22 </cn>
30+
</math>
31+
</kineticLaw>
32+
</reaction>
33+
</listOfReactions>
34+
</model>
35+
</sbml>

0 commit comments

Comments
 (0)