diff --git a/src/sbml/SBMLDocument.cpp b/src/sbml/SBMLDocument.cpp index 7c60a1fffc..0469e1eb5b 100644 --- a/src/sbml/SBMLDocument.cpp +++ b/src/sbml/SBMLDocument.cpp @@ -235,7 +235,11 @@ SBMLDocument::~SBMLDocument () if (mInternalValidator != NULL) delete mInternalValidator; if (mModel != NULL) + { + // remove from static map, since this object is being deleted + SBMLTransforms::clearComponentValues(mModel); delete mModel; + } clearValidators(); } diff --git a/src/sbml/SBMLTransforms.cpp b/src/sbml/SBMLTransforms.cpp index 7c40f85f0a..2dc6138568 100644 --- a/src/sbml/SBMLTransforms.cpp +++ b/src/sbml/SBMLTransforms.cpp @@ -56,7 +56,7 @@ LIBSBML_CPP_NAMESPACE_BEGIN #ifdef __cplusplus /** @cond doxygenLibsbmlInternal */ -SBMLTransforms::IdValueMap SBMLTransforms::mValues; +SBMLTransforms::ModelValuesMap SBMLTransforms::mModelValues; void SBMLTransforms::replaceFD(ASTNode * node, const ListOfFunctionDefinitions *lofd, const IdList* idsToExclude /*= NULL*/) @@ -289,7 +289,11 @@ SBMLTransforms::nodeContainsNameNotInList(const ASTNode * node, IdList& ids) IdList SBMLTransforms::mapComponentValues(const Model * m) { - return getComponentValuesForModel(m, mValues); + IdValueMap values; + IdList result = getComponentValuesForModel(m, values); + mModelValues.erase(m); + mModelValues.insert(std::make_pair(m, values)); + return result; } /** @@ -564,11 +568,37 @@ SBMLTransforms::getComponentValuesForModel(const Model * m, IdValueMap& values) return ids; } +SBMLTransforms::IdValueMap +SBMLTransforms::getComponentValues(const Model* m) +{ + return mModelValues[m]; +} + +IdList +SBMLTransforms::getComponentIds(const Model* m) +{ + IdList result; + IdValueMap values = mModelValues[m]; + for (IdValueMap::iterator i = values.begin(); i != values.end(); ++i) + { + result.append(i->first); + } + return result; +} + void -SBMLTransforms::clearComponentValues() +SBMLTransforms::clearComponentValues(const Model* m) { - mValues.clear(); + if (!m) + { + // clear all maps if no model specified + mModelValues.clear(); + return; + } + + // otherwise remove only specific set + mModelValues.erase(m); } @@ -576,11 +606,15 @@ SBMLTransforms::clearComponentValues() double SBMLTransforms::evaluateASTNode(const ASTNode *node, const Model *m) { - if (mValues.size() == 0) + if (m) { - mapComponentValues(m); + IdValueMap values = mModelValues[m]; + if (values.size() == 0) + { + mapComponentValues(m); + } } - return evaluateASTNode(node, mValues, m); + return evaluateASTNode(node, mModelValues[m], m); } double @@ -1217,6 +1251,7 @@ SBMLTransforms::expandInitialAssignments(Model * m) { IdList idsNoValues = mapComponentValues(m); IdList idsWithValues; + IdValueMap values = mModelValues[m]; IdValueIter iter; bool needToBail = false; @@ -1230,7 +1265,7 @@ SBMLTransforms::expandInitialAssignments(Model * m) /* list ids that have a calculated/assigned value */ idsWithValues.clear(); - for (iter = mValues.begin(); iter != mValues.end(); ++iter) + for (iter = values.begin(); iter != values.end(); ++iter) { if (((*iter).second).second) { @@ -1270,7 +1305,7 @@ SBMLTransforms::expandInitialAssignments(Model * m) while(count > 0 && needToBail == false); // clear the internal map of values - mValues.clear(); + clearComponentValues(m); return true; } @@ -1280,6 +1315,7 @@ bool SBMLTransforms::expandL3V2InitialAssignments(Model * m) { IdList idsNoValues = mapComponentValues(m); + IdValueMap values = mModelValues[m]; IdList idsWithValues; IdValueIter iter; @@ -1294,7 +1330,7 @@ SBMLTransforms::expandL3V2InitialAssignments(Model * m) /* list ids that have a calculated/assigned value */ idsWithValues.clear(); - for (iter = mValues.begin(); iter != mValues.end(); ++iter) + for (iter = values.begin(); iter != values.end(); ++iter) { if (((*iter).second).second) { @@ -1335,7 +1371,7 @@ SBMLTransforms::expandL3V2InitialAssignments(Model * m) while(count > 0 && needToBail == false); // clear the internal map of values - mValues.clear(); + clearComponentValues(m); return true; } @@ -1350,7 +1386,7 @@ SBMLTransforms::expandInitialAssignment(Compartment * c, if (!util_isNaN(value)) { c->setSize(value); - IdValueIter it = mValues.find(c->getId()); + IdValueIter it = mModelValues[c->getModel()].find(c->getId()); ((*it).second).first = value; ((*it).second).second = true; success = true; @@ -1368,7 +1404,7 @@ SBMLTransforms::expandInitialAssignment(Parameter * p, if (!util_isNaN(value)) { p->setValue(value); - IdValueIter it = mValues.find(p->getId()); + IdValueIter it = mModelValues[p->getModel()].find(p->getId()); ((*it).second).first = value; ((*it).second).second = true; success = true; @@ -1386,7 +1422,7 @@ SBMLTransforms::expandInitialAssignment(SpeciesReference * sr, if (!util_isNaN(value)) { sr->setStoichiometry(value); - IdValueIter it = mValues.find(sr->getId()); + IdValueIter it = mModelValues[sr->getModel()].find(sr->getId()); ((*it).second).first = value; ((*it).second).second = true; success = true; @@ -1412,7 +1448,7 @@ SBMLTransforms::expandInitialAssignment(Species * s, s->setInitialConcentration(value); } - IdValueIter it = mValues.find(s->getId()); + IdValueIter it = mModelValues[s->getModel()].find(s->getId()); ((*it).second).first = value; ((*it).second).second = true; success = true; diff --git a/src/sbml/SBMLTransforms.h b/src/sbml/SBMLTransforms.h index a0b391a3db..6b411705b3 100644 --- a/src/sbml/SBMLTransforms.h +++ b/src/sbml/SBMLTransforms.h @@ -89,6 +89,7 @@ class LIBSBML_EXTERN SBMLTransforms typedef std::pair ValueSet; typedef std::map IdValueMap; typedef IdValueMap::iterator IdValueIter; + typedef std::map ModelValuesMap; #endif /** @@ -136,24 +137,119 @@ class LIBSBML_EXTERN SBMLTransforms const IdList* idsToExclude = NULL); + /** + * Expands the initial assignments in the given model + * + * @param m the model to expand the initial assignments in + * + * @return true if the model was changed, false otherwise + */ static bool expandInitialAssignments(Model * m); - + /** + * Evaluates the given AST node for the specified model + * + * @param node the AST node to evaluate + * @param m the model to evaluate the AST node for (if not NULL, all + * component values will be added to the map of values) + * + * @return the result of the evaluation + */ static double evaluateASTNode(const ASTNode * node, const Model * m = NULL); + /** + * Expands the initial assignments in the given L3V2 model + * + * @param m the model to expand the initial assignments in + * + * @return true if the model was changed, false otherwise + */ static bool expandL3V2InitialAssignments(Model * m); #ifndef SWIG + + /** + * Evaluates the given AST node for the specified model and values + * + * @param node the AST node to evaluate + * @param values the values to use for the evaluation of identifiers + * @param m the model to evaluate the AST node for + * + * @return the result of the evaluation + */ static double evaluateASTNode(const ASTNode * node, const IdValueMap& values, const Model * m = NULL); + + /** + * Evaluates the given AST node for the specified model and values + * + * This overload converts the map of values to an IdValueMap first + * + * @param node the AST node to evaluate + * @param values the values to use for the evaluation of identifiers + * @param m the model to evaluate the AST node for + * + * @return the result of the evaluation + */ static double evaluateASTNode(const ASTNode * node, const std::map& values, const Model * m = NULL); + + /** + * creates a new component value map for the specified model (without adding it to the static map) + * + * @param m the model to create the map for + * @param values the values to fill from the model + * + * @return a list of all ids in the created map + */ static IdList getComponentValuesForModel(const Model * m, IdValueMap& values); + + /** + * Returns the component values for the specified model + * + * @param m the model to get the component values for + * + * @return the component values for the specified model (or empty if not in the static map) + */ + + static IdValueMap getComponentValues(const Model* m); + + /** + * Creates an IdList of the map of component values for the specified model + * + * @param m the model to get the component value ids for + * + * @return the list of ids in the map of component values for the specified model + */ + static IdList getComponentIds(const Model* m); #endif + /** + * Creates a map of all values of the specified model. + * + * This also adds the created map to the static map of all model values. All + * identifiers that cannot be determined are returned. + * + * @param m the model to create the map for + * + * @return a list of all ids of the model that could not be determined + */ static IdList mapComponentValues(const Model * m); - static void clearComponentValues(); + /** + * Clears the component values for the specified model or all models if NULL + * + * @param m the model to clear the component values for or NULL to clear all + */ + static void clearComponentValues(const Model *m = NULL); + /** + * Checks whether the node contains any id in the specified list + * + * @param node the node to check + * @param ids the list of ids to check for + * + * @return true, if the node contains any id in the list, false otherwise + */ static bool nodeContainsId(const ASTNode * node, IdList& ids); @@ -183,7 +279,7 @@ class LIBSBML_EXTERN SBMLTransforms const IdList* idsToExclude); - static IdValueMap mValues; + static ModelValuesMap mModelValues; }; diff --git a/src/sbml/conversion/ExpressionAnalyser.cpp b/src/sbml/conversion/ExpressionAnalyser.cpp index 78bc2b9b27..66cf981944 100644 --- a/src/sbml/conversion/ExpressionAnalyser.cpp +++ b/src/sbml/conversion/ExpressionAnalyser.cpp @@ -106,7 +106,7 @@ ExpressionAnalyser::~ExpressionAnalyser () } } mODEs.clear(); - SBMLTransforms::clearComponentValues(); + SBMLTransforms::clearComponentValues(mModel); } /* @@ -126,6 +126,7 @@ ExpressionAnalyser::setODEPairs(std::vector< std::pair< std::string, ASTNode*> > int ExpressionAnalyser::setModel(Model* model) { + SBMLTransforms::clearComponentValues(mModel); mModel = model; SBMLTransforms::mapComponentValues(model); return LIBSBML_OPERATION_SUCCESS; diff --git a/src/sbml/test/TestSBMLTransforms.cpp b/src/sbml/test/TestSBMLTransforms.cpp index 276d276d31..e26ba341d0 100644 --- a/src/sbml/test/TestSBMLTransforms.cpp +++ b/src/sbml/test/TestSBMLTransforms.cpp @@ -976,6 +976,61 @@ START_TEST(test_SBMLTransforms_evaluateAST_L2SpeciesReference) } END_TEST + +START_TEST(test_SBMLTransforms_multipleMaps) +{ + SBMLDocument d1(3, 1); + Model* m1 = d1.createModel(); + Compartment* c1 = m1->createCompartment(); + c1->setId("c"); + c1->setConstant(true); + c1->setSize(1.0); + + Species* s1 = m1->createSpecies(); + s1->setId("s"); + s1->setCompartment("c"); + s1->setInitialConcentration(1.0); + s1->setHasOnlySubstanceUnits(false); + + // at this point there shouldn't be a map for this model + fail_unless(SBMLTransforms::getComponentValues(m1).size() == 0); + + // create a map for this model + IdList list1 = SBMLTransforms::mapComponentValues(m1); + fail_unless(list1.size() == 0); + + SBMLDocument d2(3, 2); + Model* m2 = d2.createModel(); + c1 = m2->createCompartment(); + c1->setId("c"); + c1->setConstant(true); + c1->setSize(2.0); + + s1 = m2->createSpecies(); + s1->setId("s"); + s1->setCompartment("c"); + s1->setInitialConcentration(2.0); + s1->setHasOnlySubstanceUnits(false); + + fail_unless(SBMLTransforms::getComponentValues(m2).size() == 0); + + IdList list2 = SBMLTransforms::mapComponentValues(m2); + fail_unless(list2.size() == 0); + + SBMLTransforms::IdValueMap values1 = SBMLTransforms::getComponentValues(m1); + SBMLTransforms::IdValueMap values2 = SBMLTransforms::getComponentValues(m2); + + fail_unless(values1["c"].first == 1); + fail_unless(values1["s"].first == 1); + fail_unless(values2["c"].first == 2); + fail_unless(values2["s"].first == 2); + + SBMLTransforms::clearComponentValues(m1); + SBMLTransforms::clearComponentValues(m2); + +} +END_TEST + Suite * create_suite_SBMLTransforms (void) { @@ -994,6 +1049,7 @@ create_suite_SBMLTransforms (void) tcase_add_test(tcase, test_SBMLTransforms_evaluateL3V2ASTWithModel); tcase_add_test(tcase, test_SBMLTransforms_L3V2AssignmentNoMath); tcase_add_test(tcase, test_SBMLTransforms_StoichiometryMath); + tcase_add_test(tcase, test_SBMLTransforms_multipleMaps); suite_add_tcase(suite, tcase);