diff --git a/source/conservation/ConservedMoietyConverter.cpp b/source/conservation/ConservedMoietyConverter.cpp index e2291ba056..c3467942db 100644 --- a/source/conservation/ConservedMoietyConverter.cpp +++ b/source/conservation/ConservedMoietyConverter.cpp @@ -435,12 +435,27 @@ static void createReorderedSpecies(Model* newModel, Model* oldModel, // remove all the existing independent species ListOfSpecies *species = newModel->getListOfSpecies(); + // indSpecies/depSpecies are about to be (re)inserted fresh below -- + // exclude them here so a species that's both structurally independent + // and constant/boundary (e.g. never a reactant or product, but also + // flagged constant) doesn't end up inserted twice. + std::set reorderedSet(indSpecies.begin(), indSpecies.end()); + reorderedSet.insert(depSpecies.begin(), depSpecies.end()); + unsigned index = 0; while(index < species->size()) { Species *s = species->get(index); - if (!s->getBoundaryCondition()) + // A constant, non-boundary species (e.g. one used only as a fixed + // parameter in kinetic laws) is bookkept as a boundary species + // elsewhere (see LLVMModelDataSymbols::initFloatingSpecies / + // initBoundarySpecies), so it must be kept here too, or symbols that + // reference it (e.g. an assignment rule for an independent species) + // would no longer resolve after conversion. + bool keep = (s->getBoundaryCondition() || s->getConstant()) + && reorderedSet.find(s->getId()) == reorderedSet.end(); + if (!keep) { species->remove(index); delete s; @@ -476,7 +491,8 @@ static void createReorderedSpecies(Model* newModel, Model* oldModel, assert(s && "could not get dependent species from original model"); - newSpecies->insertAndOwn(index++, new ConservedMoietySpecies(*s, true)); + bool hasOwnRule = oldModel->getRule(depSpecies[i]) != NULL; + newSpecies->insertAndOwn(index++, new ConservedMoietySpecies(*s, !hasOwnRule)); } } @@ -495,6 +511,13 @@ static std::vector createConservedMoietyParameters( for (unsigned int i = 0; i < depSpecies.size(); ++i) { + if (newModel->getRule(depSpecies[i]) != NULL) + { + // species already has its own rule; it is not a real + // conserved moiety, so it needs no CSUM parameter. + continue; + } + Poco::UUID uuid = uuidGen.create(); std::string id = "_CSUM" + rr::toStringSize(i); std::replace( id.begin(), id.end(), '-', '_'); @@ -578,6 +601,13 @@ static void createDependentSpeciesRules(Model* newModel, throw std::invalid_argument("model does not contain dependent species " + id); } + if (newModel->getRule(id) != NULL) + { + // species already has its own rule; do not overwrite it with + // a bogus conserved-moiety rule. + continue; + } + bool isAmt = dspecies->getHasOnlySubstanceUnits(); AssignmentRule *rule = newModel->createAssignmentRule(); @@ -747,6 +777,38 @@ static inline void conservedMoietyException(const std::string& what) throw std::invalid_argument(what + help); } +// Non-boundary species can be in rules only if they also do not appear in any reactions. +static bool speciesParticipatesInReactionStoichiometry(const Model* model, + const std::string& speciesId) +{ + const ListOfReactions* reactions = model->getListOfReactions(); + + for (unsigned int i = 0; i < reactions->size(); ++i) + { + const Reaction* reaction = reactions->get(i); + + const ListOfSpeciesReferences* reactants = reaction->getListOfReactants(); + for (unsigned int j = 0; j < reactants->size(); ++j) + { + if (reactants->get(j)->getSpecies() == speciesId) + { + return true; + } + } + + const ListOfSpeciesReferences* products = reaction->getListOfProducts(); + for (unsigned int j = 0; j < products->size(); ++j) + { + if (products->get(j)->getSpecies() == speciesId) + { + return true; + } + } + } + + return false; +} + static void conservedMoietyCheck(const SBMLDocument *doc) { @@ -761,7 +823,17 @@ static void conservedMoietyCheck(const SBMLDocument *doc) const Species *species = model->getSpecies(rule->getVariable()); - if(species && !species->getBoundaryCondition() && model->getNumReactions() > 0) + // Only an AssignmentRule is safe to relax here: its RHS is inlined at + // every point of use, so the species it governs never enters the ODE + // state vector and (per speciesParticipatesInReactionStoichiometry's + // comment above) can never be chosen as a conservation law's + // eliminated species. A RateRule species has real, independently + // integrated dynamics regardless of whether it participates in any + // reaction's stoichiometry, so it must keep throwing unconditionally. + bool relaxable = rule->isAssignment() + && !speciesParticipatesInReactionStoichiometry(model, species ? species->getId() : ""); + if(species && !species->getBoundaryCondition() && model->getNumReactions() > 0 + && !relaxable) { std::string msg = "Cannot perform moiety conversion when floating " "species are defined by rules. The floating species, " diff --git a/source/llvm/LLVMExecutableModel.cpp b/source/llvm/LLVMExecutableModel.cpp index ce0cac5ca5..e3196b49e2 100644 --- a/source/llvm/LLVMExecutableModel.cpp +++ b/source/llvm/LLVMExecutableModel.cpp @@ -2048,7 +2048,8 @@ std::vector LLVMExecutableModel::getRateRuleSymbols() const { int LLVMExecutableModel::getFloatingSpeciesAmounts(size_t len, const int* indx, double* values) { - return getValues(getFloatingSpeciesAmountPtr, len, indx, values); + int result = getValues(getFloatingSpeciesAmountPtr, len, indx, values); + return result; } int LLVMExecutableModel::setFloatingSpeciesAmounts(size_t len, int const* indx, diff --git a/source/llvm/LLVMModelDataSymbols.cpp b/source/llvm/LLVMModelDataSymbols.cpp index 322f192745..da9a5a132a 100644 --- a/source/llvm/LLVMModelDataSymbols.cpp +++ b/source/llvm/LLVMModelDataSymbols.cpp @@ -21,6 +21,7 @@ #pragma warning(default: 4624) #endif +#include #include "rr-libstruct/lsLibStructural.h" #include "rrLogger.h" #include "rrSparse.h" @@ -945,7 +946,7 @@ void LLVMModelDataSymbols::initBoundarySpecies(const libsbml::Model* model) const Species* s = species->get(i); std::vector quantities = ConservationExtension::getConservedQuantities(*s); - if (!s->getBoundaryCondition()) + if (!s->getBoundaryCondition() && !s->getConstant()) { continue; } @@ -1146,8 +1147,14 @@ void LLVMModelDataSymbols::initFloatingSpecies(const libsbml::Model* model, bool const Species *s = species->get(i); std::vector quantities = ConservationExtension::getConservedQuantities(*s); - if (s->getBoundaryCondition()) + if (s->getBoundaryCondition() || s->getConstant()) { + // Constant, non-boundary species (e.g. a species used only as a + // fixed parameter in rate laws) are processed as boundary + // species instead -- they have no ODE and are never touched by + // moiety or state-vector reduction, so treating them as + // floating species here would leave a structurally-zero row in + // the steady-state Jacobian. continue; } @@ -1176,6 +1183,7 @@ void LLVMModelDataSymbols::initFloatingSpecies(const libsbml::Model* model, bool bool conservedMoiety = ConservationExtension::getConservedMoiety(*s); + bool indInit = (!hasInitialAssignmentRule(sid) && (!hasAssignmentRule(sid) || conservedMoiety)); diff --git a/source/llvm/LLVMModelGenerator.cpp b/source/llvm/LLVMModelGenerator.cpp index aaed4bbafa..428ee8779f 100644 --- a/source/llvm/LLVMModelGenerator.cpp +++ b/source/llvm/LLVMModelGenerator.cpp @@ -340,7 +340,8 @@ namespace rrllvm { if (index >= 0) { // new model has this species - if (newModel->symbols->isConservedMoietySpecies(id)) { + bool isCM = newModel->symbols->isConservedMoietySpecies(id); + if (isCM) { deferredConservedMoietySpecies.push_back(i); continue; } diff --git a/source/llvm/LLVMModelSymbols.cpp b/source/llvm/LLVMModelSymbols.cpp index 4a9ef0e40e..f21e538076 100644 --- a/source/llvm/LLVMModelSymbols.cpp +++ b/source/llvm/LLVMModelSymbols.cpp @@ -397,8 +397,11 @@ void LLVMModelSymbols::processSpecies(SymbolForest ¤tSymbols, assert(math); - if (species->getBoundaryCondition()) + if (species->getBoundaryCondition() || species->getConstant()) { + // Keep in sync with LLVMModelDataSymbols::initFloatingSpecies / + // initBoundarySpecies, which route constant non-boundary species + // into the boundary-species bucket as well. currentSymbols.boundarySpecies[species->getId()] = math; } else diff --git a/source/rrRoadRunner.cpp b/source/rrRoadRunner.cpp index 807d42dce4..709192894a 100644 --- a/source/rrRoadRunner.cpp +++ b/source/rrRoadRunner.cpp @@ -1786,8 +1786,8 @@ namespace rr { self.loadOpt.setConservedMoietyConversion(previousValue); throw; } - impl->document.reset(olddoc); - + //impl->document.reset(olddoc); + delete olddoc; // restore original reload value self.loadOpt.modelGeneratorOpt = savedOpt; } diff --git a/test/cxx_api_tests/StructuralAnalysisTests.cpp b/test/cxx_api_tests/StructuralAnalysisTests.cpp index bd984bbc54..ed7e384abb 100644 --- a/test/cxx_api_tests/StructuralAnalysisTests.cpp +++ b/test/cxx_api_tests/StructuralAnalysisTests.cpp @@ -1,10 +1,12 @@ #include #include "gtest/gtest.h" +#include #include "RoadRunnerTest.h" #include "TestModelFactory.h" #include "GillespieIntegrator.h" #include "rrConfig.h" +#include "rrExecutableModel.h" #include "Matrix.h" using namespace rr; @@ -147,6 +149,257 @@ class StructuralAnalysisTests : public RoadRunnerTest { }; +// Regression test for a general RoadRunner bug (not specific to Teusink's +// NAD/NADH or ATP/ADP/AMP structure): after a real conserved-moiety +// conversion, a species governed by its own pre-existing assignment-rule +// chain stopped responding to changes in its dependency, even though it +// has nothing to do with the moiety being eliminated. J1's rate reaches Q +// only through that chain (S2 = ks2*W1, W1 = kw1*Q), so its sensitivity to +// Q must be identical before and after conversion. +TEST_F(StructuralAnalysisTests, AssignmentRuleChainRateSensitivitySurvivesConversion) { + path sbmlPath = modelAnalysisModelsDir / "assignment_rule_chain_moiety.xml"; + + auto measureJ1RateSensitivityToQ = [](RoadRunner& rr) { + ExecutableModel* model = rr.getModel(); + int n = model->getStateVector(0); + std::vector ids; + for (int i = 0; i < n; ++i) { + ids.push_back(model->getStateVectorId(i)); + } + int qIndex = std::distance(ids.begin(), std::find(ids.begin(), ids.end(), "Q")); + EXPECT_LT(qIndex, n); + + std::vector y(n); + model->getStateVector(y.data()); + + int j1Index = model->getReactionIndex("J1"); + double rateBefore = 0; + model->getReactionRates(1, &j1Index, &rateBefore); + + y[qIndex] += 0.1; + model->setStateVector(y.data()); + + double rateAfter = 0; + model->getReactionRates(1, &j1Index, &rateAfter); + + return rateAfter - rateBefore; + }; + + double expectedDelta = 0.1 * 0.5 * 3 * 2; // dQ * k1 * ks2 * kw1 + + RoadRunner rrBefore(sbmlPath.string()); + EXPECT_NEAR(measureJ1RateSensitivityToQ(rrBefore), expectedDelta, 1e-6); + + RoadRunner rrAfter(sbmlPath.string()); + rrAfter.setConservedMoietyAnalysis(true); + EXPECT_NEAR(measureJ1RateSensitivityToQ(rrAfter), expectedDelta, 1e-6); +} + +// A species governed by its own assignment rule but with zero stoichiometric +// coupling to any reaction (W1, S2) is not a real conserved moiety and must +// not be counted as one: only the genuine Q+P2 (via J1) and A+B (via J2) +// cycles should be reported. W1 and S2 must also keep tracking their +// dependency chain dynamically after conversion, not freeze at their +// pre-conversion value. +TEST_F(StructuralAnalysisTests, RuleGovernedSpeciesTrackDependencyAfterConversion) { + RoadRunner rr((modelAnalysisModelsDir / "assignment_rule_chain_moiety.xml").string()); + rr.setConservedMoietyAnalysis(true); + + ExecutableModel* model = rr.getModel(); + EXPECT_EQ(model->getNumConservedMoieties(), 2); + + int n = model->getStateVector(0); + std::vector ids; + for (int i = 0; i < n; ++i) { + ids.push_back(model->getStateVectorId(i)); + } + int qIndex = std::distance(ids.begin(), std::find(ids.begin(), ids.end(), "Q")); + ASSERT_LT(qIndex, n); + + std::vector y(n); + model->getStateVector(y.data()); + y[qIndex] += 0.1; + model->setStateVector(y.data()); + + double qAfter = rr.getValue("Q"); + double w1After = rr.getValue("W1"); + double s2After = rr.getValue("S2"); + + EXPECT_NEAR(w1After, 2.0 * qAfter, 1e-9); + EXPECT_NEAR(s2After, 3.0 * w1After, 1e-9); + + int j1Index = model->getReactionIndex("J1"); + double rate = 0; + model->getReactionRates(1, &j1Index, &rate); + EXPECT_NEAR(rate, 0.5 * s2After, 1e-9); +} + +// BIOMD0000000064 (Teusink et al. 2000, yeast glycolysis) has two species, +// SUM_P and F26BP, declared with constant="true" and boundaryCondition="false" +// -- they're used only as fixed parameters inside kinetic laws (the AK +// equilibrium and the PFK rate law), never as reactants/products. They +// should be classified as boundary species (and excluded from the +// floating-species/Newton state vector), not as ordinary floating species +// with a structurally-zero rate row. +TEST_F(StructuralAnalysisTests, TeusinkConstantSpeciesAreBoundary) { + RoadRunner rr((modelAnalysisModelsDir / "teusink_glycolysis.xml").string()); + + auto boundaryIds = rr.getBoundarySpeciesIds(); + EXPECT_NE(std::find(boundaryIds.begin(), boundaryIds.end(), "SUM_P"), boundaryIds.end()); + EXPECT_NE(std::find(boundaryIds.begin(), boundaryIds.end(), "F26BP"), boundaryIds.end()); + + auto floatingIds = rr.getFloatingSpeciesIds(); + EXPECT_EQ(std::find(floatingIds.begin(), floatingIds.end(), "SUM_P"), floatingIds.end()); + EXPECT_EQ(std::find(floatingIds.begin(), floatingIds.end(), "F26BP"), floatingIds.end()); +} + +// The NAD/NADH pair forms a genuine stoichiometric conservation cycle in +// this model (via the GAPDH/ADH/G3PDH reactions), independent of the +// constant-species fix above. This checks that RoadRunner's structural +// analysis (the same analysis ConservedMoietyConverter::convert() reads +// its independent/dependent species split from) actually finds it: NAD or +// NADH should come back as a dependent species for a conservation law. +TEST_F(StructuralAnalysisTests, TeusinkNADCycleIsFound) { + RoadRunner rr((modelAnalysisModelsDir / "teusink_glycolysis.xml").string()); + + auto dependentIds = rr.getDependentFloatingSpeciesIds(); + bool foundNADCycle = std::find(dependentIds.begin(), dependentIds.end(), "NAD") != dependentIds.end() + || std::find(dependentIds.begin(), dependentIds.end(), "NADH") != dependentIds.end(); + EXPECT_TRUE(foundNADCycle); +} + +// Before the constant-species-as-boundary fix and the conserved-moiety +// rule-duplication fix, steadyState() failed with "Jacobian matrix singular +// in NLEQ" on this model. Expected values are this model's own steady +// state (matches Table 4 of Teusink et al. 2000, and the "this model" +// column in the SBML's own notes). +TEST_F(StructuralAnalysisTests, TeusinkSteadyStateConverges) { + RoadRunner rr((modelAnalysisModelsDir / "teusink_glycolysis.xml").string()); + + ASSERT_NO_THROW(rr.steadyState()); + + EXPECT_NEAR(rr.getValue("[G6P]"), 1.0332, 1e-3); + EXPECT_NEAR(rr.getValue("[F6P]"), 0.1128, 1e-3); + EXPECT_NEAR(rr.getValue("[PYR]"), 8.5232, 1e-3); + EXPECT_NEAR(rr.getValue("[ATP]"), 2.5084, 1e-3); + EXPECT_NEAR(rr.getValue("[ADP]"), 1.2921, 1e-3); + EXPECT_NEAR(rr.getValue("[NADH]"), 0.0444, 1e-3); +} + +// TeusinkNADCycleIsFound confirms LibStructural finds the NAD/NADH cycle from +// the raw stoichiometry, but steadyState()'s auto_moiety_analysis retry +// swallows any exception from setConservedMoietyAnalysis() and silently falls +// back to no conversion. Calling it directly here surfaces that exception (if +// any) instead, and confirms the conversion actually produces the expected +// number of conserved moieties on the compiled model, not just in the +// structural analysis (3 real cycles: NAD/NADH, the adenylate pool, and one +// more -- not the 6 a rule-duplication bug once produced by also counting +// non-reacting, rule-governed species as moieties). +TEST_F(StructuralAnalysisTests, TeusinkConservedMoietyConversionSucceeds) { + RoadRunner rr((modelAnalysisModelsDir / "teusink_glycolysis.xml").string()); + + ASSERT_NO_THROW(rr.setConservedMoietyAnalysis(true)); + EXPECT_TRUE(rr.getConservedMoietyAnalysis()); + EXPECT_EQ(rr.getModel()->getNumConservedMoieties(), 3); +} + +// ATP and ADP are related to P (and SUM_P) through the AK-equilibrium +// assignment rules, never directly through a reaction. Perturbing P must +// still update them dynamically after conversion, not leave them frozen at +// their pre-conversion value the way the rule-duplication bug did. +TEST_F(StructuralAnalysisTests, TeusinkPerturbingPAfterConversionUpdatesATP) { + RoadRunner rr((modelAnalysisModelsDir / "teusink_glycolysis.xml").string()); + rr.setConservedMoietyAnalysis(true); + + ExecutableModel* model = rr.getModel(); + int n = model->getStateVector(0); + std::vector ids; + for (int i = 0; i < n; ++i) { + ids.push_back(model->getStateVectorId(i)); + } + int pIndex = std::distance(ids.begin(), std::find(ids.begin(), ids.end(), "P")); + ASSERT_LT(pIndex, n); + + std::vector y(n); + model->getStateVector(y.data()); + + double atpBefore = rr.getValue("[ATP]"); + double adpBefore = rr.getValue("[ADP]"); + + y[pIndex] += 1.0; + model->setStateVector(y.data()); + + double atpAfter = rr.getValue("[ATP]"); + double adpAfter = rr.getValue("[ADP]"); + + EXPECT_NE(atpAfter, atpBefore); + EXPECT_NE(adpAfter, adpBefore); +} + +// createReorderedSpecies deletes any that's neither +// boundary/constant nor part of indSpecies/depSpecies -- ATP/ADP/AMP satisfy +// none of those (not constant, never a reactant/product). Their +// elements, and their classification as ordinary floating species, must +// survive conversion so their assignment rules (referencing P and SUM_P) +// keep resolving. +TEST_F(StructuralAnalysisTests, TeusinkATPClassificationAfterConversion) { + RoadRunner rr((modelAnalysisModelsDir / "teusink_glycolysis.xml").string()); + rr.setConservedMoietyAnalysis(true); + + auto floatingIds = rr.getFloatingSpeciesIds(); + auto boundaryIds = rr.getBoundarySpeciesIds(); + auto globalParamIds = rr.getGlobalParameterIds(); + + for (const std::string& id : {"ATP", "ADP", "AMP"}) { + EXPECT_NE(std::find(floatingIds.begin(), floatingIds.end(), id), floatingIds.end()) << id; + EXPECT_EQ(std::find(boundaryIds.begin(), boundaryIds.end(), id), boundaryIds.end()) << id; + EXPECT_EQ(std::find(globalParamIds.begin(), globalParamIds.end(), id), globalParamIds.end()) << id; + } + for (const std::string& id : {"SUM_P", "F26BP"}) { + EXPECT_NE(std::find(boundaryIds.begin(), boundaryIds.end(), id), boundaryIds.end()) << id; + } +} + +// P only reaches kinetic laws indirectly, through the inlined ADP/ATP +// assignment rules, so perturbing it must still change at least one +// reaction rate after conversion -- the rule-duplication bug froze those +// rules to a constant, making every reaction rate blind to P. +TEST_F(StructuralAnalysisTests, TeusinkPerturbingPAfterConversionChangesReactionRates) { + RoadRunner rr((modelAnalysisModelsDir / "teusink_glycolysis.xml").string()); + rr.setConservedMoietyAnalysis(true); + + ExecutableModel* model = rr.getModel(); + int n = model->getStateVector(0); + std::vector ids; + for (int i = 0; i < n; ++i) { + ids.push_back(model->getStateVectorId(i)); + } + int pIndex = std::distance(ids.begin(), std::find(ids.begin(), ids.end(), "P")); + ASSERT_LT(pIndex, n); + + std::vector y(n); + model->getStateVector(y.data()); + + int numReactions = model->getNumReactions(); + std::vector ratesBefore(numReactions); + model->getReactionRates(numReactions, 0, ratesBefore.data()); + + y[pIndex] += 1.0; + model->setStateVector(y.data()); + + std::vector ratesAfter(numReactions); + model->getReactionRates(numReactions, 0, ratesAfter.data()); + + bool anyRateChanged = false; + for (int i = 0; i < numReactions; ++i) { + if (std::abs(ratesAfter[i] - ratesBefore[i]) > 1e-9) { + anyRateChanged = true; + break; + } + } + EXPECT_TRUE(anyRateChanged); +} + /************************************************************ * Check structural properties in the BimolecularEnd TestModel */ @@ -479,9 +732,3 @@ J0,J1,J2,J3,J4 0,1,-1,0,-1 */ } - - - - - - diff --git a/test/models/ModelAnalysis/assignment_rule_chain_moiety.xml b/test/models/ModelAnalysis/assignment_rule_chain_moiety.xml new file mode 100644 index 0000000000..d5475a41c1 --- /dev/null +++ b/test/models/ModelAnalysis/assignment_rule_chain_moiety.xml @@ -0,0 +1,75 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + kw1 Q + + + + + ks2 W1 + + + + + + + + + + + + + + k1 S2 + + + + + + + + + + + + + + k2 A + k3 B + + + + + + + diff --git a/test/models/ModelAnalysis/teusink_glycolysis.xml b/test/models/ModelAnalysis/teusink_glycolysis.xml new file mode 100644 index 0000000000..073fcff7ff --- /dev/null +++ b/test/models/ModelAnalysis/teusink_glycolysis.xml @@ -0,0 +1,2733 @@ + + + + + +

+ Can yeast glycolysis be understood in terms of in vitro kinetics of the constituent enzymes? Testing biochemistry. +
+ Teusink,B et al.: Eur J Biochem 2000 Sep;267(17):5313-29. +
+ The model reproduces the steady-state fluxes and metabolite concentrations of the branched model as given in Table 4 of the paper. It is derived from the model on JWS online, but has the ATP consumption in the succinate branch with the same stoichiometrie as in the publication. The model was successfully tested on copasi v.4.4(build 26).
+ For Vmax values, please note that there is a conversion factor of approx. 270 to convert from U/mg-protein as shown in Table 1 of the paper to mmol/(min*L_cytosol). The equilibrium constant for the ADH reaction in the paper is given for the reverse reaction (Keq = 1.45*10 4 + ). The value used in this model is for the forward reaction: 1/Keq = 6.9*10 -5 + .
+ Vmax parameters values used (in [mM/min] except VmGLT): + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ VmGLT + 97.264mmol/min
+ VmGLK + 226.45 +
+ VmPGI + 339.667 +
+ VmPFK + 182.903 +
+ VmALD + 322.258 +
+ VmGAPDH_f + 1184.52 +
+ VmGAPDH_r + 6549.68 +
+ VmPGK + 1306.45 +
+ VmPGM + 2525.81 +
+ VmENO + 365.806 +
+ VmPYK + 1088.71 +
+ VmPDC + 174.194 +
+ VmG3PDH + 70.15 +
+ The result of the G6P steady state concentration (marked in red) differs slightly from the one given in table 4. of the publication
+ Results for steady state: + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ orig. articlethis model
+ Fluxes[mM/min] +   + +
Glucose 88 88 
Ethanol 129 129 
Glycogen 
Trehalose 4.8 4.8 (G6P flux through trehalose branch)
Glycerol 18.2 18.2 
Succinate 3.6 3.6 
+ Conc.[mM] +   + +
G6P 1.07 1.03 
F6P 0.11 0.11 
F1,6P 0.6 0.6 
DHAP 0.74 0.74 
3PGA 0.36 0.36 
2PGA 0.04 0.04 
PEP 0.07 0.07 
PYR 8.52 8.52 
AcAld 0.17 0.17 
ATP 2.51 2.51 
ADP 1.29 1.29 
AMP 0.3 0.3 
NAD 1.55 1.55 
NADH 0.04 0.04 
+ Authors of the publication also mentioned a few misprints in the original article:
+ in the kinetic law for ADH + :

    +
  1. the species a + should denote NAD + and b + Ethanol
  2. +
  3. the last term in the equation should read bpq + /( K ib + K iq + K p + )
  4. +
+ in the kinetic law for PFK + :
    +
  1. R = 1 + λ 1 + + λ 2 + + g r + λ 1 + λ 2
  2. +
  3. equation L should read: L = L0*(..) 2 + *(..) 2 + *(..) 2 + not L = L0*(..) 2 + *(..) 2 + *(..)
  4. +
+ To make the model easier to curate, the species ATP + , ADP + and AMP + were added. These are calculated via assignment rules from the active phosphate species, P + , and the sum of all AXP + , SUM_P + .

+
+

To the extent possible under law, all copyright and related or neighbouring rights to this encoded model have been dedicated to the public domain worldwide. Please refer to CC0 Public Domain Dedication + for more information.

+

In summary, you are entitled to use this encoded model in absolutely any manner you deem suitable, verbatim, or with modification, alone or embedded it in a larger context, redistribute it, commercially or not, in a restricted way or not.

+
+

To cite BioModels Database, please use: Li C, Donizelli M, Rodriguez N, Dharuri H, Endler L, Chelliah V, Li L, He E, Henry A, Stefan MI, Snoep JL, Hucka M, Le Novère N, Laibe C (2010) BioModels Database: An enhanced, curated and annotated resource for published quantitative kinetic models. BMC Syst Biol., 4:92.

+ +
+ + + + + + + + Snoep + Jacky L + + jls@sun.ac.za + + Stellenbosh University + + + + + Endler + Lukas + + lukas@ebi.ac.uk + + EMBL-EBI + + + + + Dharuri + Harish + + hdharuri@cds.caltech.edu + + California Institute of Technology + + + + + + 2008-09-16T14:00:06Z + + + 2012-07-19T18:26:07Z + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + L + + + CiATP + + + KiATP + + + CAMP + + + KAMP + + + CF26BP + + + KF26BP + + + CF16BP + + + KF16BP + + + AT + + + AM + + + F16 + + + F26 + + + + L + + + + + + + 1 + + + CiATP + + + AT + KiATP + + + + + + 1 + + + AT + KiATP + + + + 2 + + + + + + + + 1 + + + CAMP + + + AM + KAMP + + + + + + 1 + + + AM + KAMP + + + + 2 + + + + + + + + 1 + + + + + CF26BP + F26 + + KF26BP + + + + + + CF16BP + F16 + + KF16BP + + + + + 1 + + + F26 + KF26BP + + + + F16 + KF16BP + + + + 2 + + + + + + + + + + KmF6P + + + KmATP + + + g + + + AT + + + F6 + + + + 1 + + + F6 + KmF6P + + + + AT + KmATP + + + + g + + + F6 + KmF6P + + + + AT + KmATP + + + + + + + + + + + CATP + + + KmATP + + + AT + + + + 1 + + + CATP + + + AT + KmATP + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SUM_P + + + + + + + + + P + 2 + + + + 1 + + + 4 + KeqAK + + + + + + 2 + SUM_P + P + + + + + 4 + KeqAK + + 1 + + + + + SUM_P + 2 + + + 0.5 + + + + + 1 + + + 4 + KeqAK + + + + + + + + + + + + P + ADP + + 2 + + + + + + + + + + SUM_P + ATP + + ADP + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + cytosol + VmGLK + + + + KmGLKGLCi + KmGLKATP + + + + + + + GLCi + ATP + + + + + + G6P + ADP + + KeqGLK + + + + + + + + 1 + + + GLCi + KmGLKGLCi + + + + G6P + KmGLKG6P + + + + + 1 + + + ATP + KmGLKATP + + + + ADP + KmGLKADP + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + cytosol + VmPGI_2 + + KmPGIG6P_2 + + + + G6P + + + F6P + KeqPGI_2 + + + + + + 1 + + + G6P + KmPGIG6P_2 + + + + F6P + KmPGIF6P_2 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + cytosol + KGLYCOGEN_3 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + cytosol + KTREHALOSE + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + cytosol + VmPFK + gR + + + F6P + KmPFKF6P + + + + ATP + KmPFKATP + + + R_PFK + KmPFKF6P + KmPFKATP + gR + ATP + F6P + + + + + + + + R_PFK + KmPFKF6P + KmPFKATP + gR + ATP + F6P + + 2 + + + + + L_PFK + Lzero + CiPFKATP + KiPFKATP + CPFKAMP + KPFKAMP + CPFKF26BP + KPFKF26BP + CPFKF16BP + KPFKF16BP + ATP + AMP + F16P + F26BP + + + + + T_PFK + CPFKATP + KmPFKATP + ATP + + 2 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + cytosol + VmALD + + KmALDF16P + + + + F16P + + + + + + + KeqTPI + + + 1 + KeqTPI + + + TRIO + + + 1 + + + 1 + KeqTPI + + + TRIO + + KeqALD + + + + + + 1 + + + F16P + KmALDF16P + + + + + + + + KeqTPI + + + 1 + KeqTPI + + + TRIO + + KmALDGAP + + + + + + + + 1 + + + 1 + KeqTPI + + + TRIO + + KmALDDHAP + + + + + + + + KeqTPI + + + 1 + KeqTPI + + + TRIO + + + 1 + + + 1 + KeqTPI + + + TRIO + + + + KmALDGAP + KmALDDHAP + + + + + + + F16P + + + KeqTPI + + + 1 + KeqTPI + + + TRIO + + + + KmALDGAPi + KmALDF16P + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + cytosol + + + + + + + VmGAPDHf + + + KeqTPI + + + 1 + KeqTPI + + + TRIO + NAD + + + + KmGAPDHGAP + KmGAPDHNAD + + + + + + + VmGAPDHr + BPG + NADH + + + + KmGAPDHBPG + KmGAPDHNADH + + + + + + + + + 1 + + + + + + + KeqTPI + + + 1 + KeqTPI + + + TRIO + + KmGAPDHGAP + + + + BPG + KmGAPDHBPG + + + + + 1 + + + NAD + KmGAPDHNAD + + + + NADH + KmGAPDHNADH + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + cytosol + VmPGK + + + + KmPGKP3G + KmPGKATP + + + + + + + KeqPGK + BPG + ADP + + + + P3G + ATP + + + + + + + + 1 + + + BPG + KmPGKBPG + + + + P3G + KmPGKP3G + + + + + 1 + + + ATP + KmPGKATP + + + + ADP + KmPGKADP + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + cytosol + VmPGM + + KmPGMP3G + + + + P3G + + + P2G + KeqPGM + + + + + + 1 + + + P3G + KmPGMP3G + + + + P2G + KmPGMP2G + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + cytosol + VmENO + + KmENOP2G + + + + P2G + + + PEP + KeqENO + + + + + + 1 + + + P2G + KmENOP2G + + + + PEP + KmENOPEP + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + cytosol + VmPYK + + + + KmPYKPEP + KmPYKADP + + + + + + + PEP + ADP + + + + + + PYR + ATP + + KeqPYK + + + + + + + + 1 + + + PEP + KmPYKPEP + + + + PYR + KmPYKPYR + + + + + 1 + + + ATP + KmPYKATP + + + + ADP + KmPYKADP + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + cytosol + VmPDC + + + + + PYR + nPDC + + + + KmPDCPYR + nPDC + + + + + + 1 + + + + + PYR + nPDC + + + + KmPDCPYR + nPDC + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + cytosol + KSUCC + ACE + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + VmGLT + KmGLTGLCo + + + + GLCo + + + GLCi + KeqGLT + + + + + + 1 + + + GLCo + KmGLTGLCo + + + + GLCi + KmGLTGLCi + + + + + + 0.91 + GLCo + GLCi + + + + KmGLTGLCo + KmGLTGLCi + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + cytosol + + + + + + + + VmADH + + + KiADHNAD + KmADHETOH + + + + + + + NAD + ETOH + + + + + + NADH + ACE + + KeqADH + + + + + + 1 + + + NAD + KiADHNAD + + + + + + KmADHNAD + ETOH + + + + KiADHNAD + KmADHETOH + + + + + + + KmADHNADH + ACE + + + + KiADHNADH + KmADHACE + + + + + NADH + KiADHNADH + + + + + + NAD + ETOH + + + + KiADHNAD + KmADHETOH + + + + + + + KmADHNADH + NAD + ACE + + + + KiADHNAD + KiADHNADH + KmADHACE + + + + + + + KmADHNAD + ETOH + NADH + + + + KiADHNAD + KmADHETOH + KiADHNADH + + + + + + + NADH + ACE + + + + KiADHNADH + KmADHACE + + + + + + + NAD + ETOH + ACE + + + + KiADHNAD + KmADHETOH + KiADHACE + + + + + + + ETOH + NADH + ACE + + + + KiADHETOH + KiADHNADH + KmADHACE + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + cytosol + VmG3PDH + + + + KmG3PDHDHAP + KmG3PDHNADH + + + + + + + + + 1 + + + 1 + KeqTPI + + + TRIO + NADH + + + + + + GLY + NAD + + KeqG3PDH + + + + + + + + 1 + + + + + + + 1 + + + 1 + KeqTPI + + + TRIO + + KmG3PDHDHAP + + + + GLY + KmG3PDHGLY + + + + + 1 + + + NADH + KmG3PDHNADH + + + + NAD + KmG3PDHNAD + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + cytosol + KATPASE + ATP + + + + + + + + +
+