#pragma section-numbers 2 = Structural Modelling = <> == Introduction == The class {{{Model}}} has a range of methods, of which some are only useful for kinetic models (which are also structural models, though the opposite is not true). Among the structurally relevant methods we find {{{ConsMoieties()}}} - which prints a list of conserved moieties; {{{DeadReactions()}}} - which returns a list of reactions that cannot carry steady state flux; {{{FindIsoforms()}}} - which identifies reactions from the model that are redundant, i.e. a set of reactions have identical stoichiometry; {{{ElModes()}}} - which returns an elementary modes object; {{{Externals()}}} - which returns a list of external metabolites. These are all described further below. All structural modelling analyses are in fact implemented by actions on the model's stoichiometry matrices, which can be accessed as described in the next section. == The stoichiometry matrix == The fields {{{Model.sm}}} and {{{Model.smexterns}}} are the two stoichiometry matrices assocciated with a model - the former is the internal matrix, the latter the external. The external matrix contains infomation about external metabolites, whereas the internal does not. All instances of {{{ScrumPy}}} matrices (subclasses of {{{DynMatrix}}}) have the fields {{{cnames}}} - column names and {{{rnames}}} - row names. {{{#!python >>> m.sm.cnames ['R_1', 'R_2', 'R_3', 'R_4', 'R_5', 'R_6', 'E_tx', 'A_tx'] >>> m.sm.rnames #but m.smexterns.rnames will be longer ['A', 'B', 'C', 'E', 'D', 'F'] }}} Useful methods of {{{sm}}} (and {{{smexterns}}}) include {{{ReacToStr(reac)}}}, {{{#!python >>> print m.sm.ReacToStr('R_2') R_2: 1/1 B -> 1/1 C ~ }}} and {{{InvolvedWith(name)}}}, {{{#!python >>> m.sm.InvolvedWith('R_2') {'C': mpq(1,1), 'B': mpq(-1,1)} >>> m.sm.InvolvedWith('C') {'R_2': mpq(1,1), 'R_3': mpq(-1,1)} }}} == Reaction reversibility == {{{ScrumPy}}} accepts three reversibility symbols: {{{"->"}}} - left to right irreversible, {{{"<-"}}} - right to left irreversible, and {{{<>}}} - reversible. Reaction reversibility is handled by the stoichiometry matrix. {{{#!python >>> m.sm.GetIrrevs() ['R_1', 'R_2', 'R_3', 'R_4', 'R_5', 'R_6', 'E_tx', 'A_tx'] >>> m.sm.MakeRevers('R_2') >>> m.sm.GetIrrevs() ['R_1', 'R_3', 'R_4', 'R_5', 'R_6', 'E_tx', 'A_tx'] >>> m.Reload() >>> m.sm.GetIrrevs() ['R_1', 'R_2', 'R_3', 'R_4', 'R_5', 'R_6', 'E_tx', 'A_tx'] }}} == Orphan Metabolites == An orphan metabolite is one that cannot be balanced at steady-state because it is involved with only one reaction, and can therefore be only consumed or produced. These are identified by the {{{OrphanMets()}}} method. {{{#!highlight python >>> orphans = m.OrphanMets() >>> len(orphans) 7 >>> print orphans ['x_CO2', 'x_NADPH_ch', 'x_Proton_ch', 'x_NADP_ch', 'x_PGA_cyt', 'x_GAP_cyt', 'x_DHAP_cyt'] >>> }}} Here the model has 7 orphan metabolites, but, as denoted by the x_ prefix, they are all external metabolites, and so this does not indicate a problem with model. In general, when practical , it is desirable to associate external metabolites with exactly one transport reaction, as it can considerably simplify subsequent analysis of results obtained from the model. == Nullspace analysis == The kernel of the stoichiometry matrix can be calculated using the {{{sm.NullSpace()}}} method ({{{smexterns}}} also has the method, but the kernel of the external matrix is only related to the futile cycles of the model, not possible steady-state solutions). {{{#!python >>> k = m.sm.NullSpace() >>> k c_0 c_1 R_1 -1/1 0/1 R_2 -1/1 1/1 R_3 -1/1 1/1 R_4 0/1 -1/1 R_5 0/1 -1/1 R_6 0/1 0/1 E_tx -1/1 0/1 A_tx -1/1 0/1 }}} Even if the signs of some of the coeffients indicate thermodynamically infeasible solutions (e.g. all active reactions in the first column have negative coefficients, even though they are irreversible) a lot of useful information can be obtained form {{{k}}}. For instance, we see that the row associated with {{{R_6}}} is a null-vector, indicating that there is no steady-state solution involving {{{R_6}}}. In fact this is how {{{ScrumPy}}} detects dead reactions, as follows: === Dead Reactions === A dead reaction is one which can carry no flux at steady-state. This is usually, but not always, caused by the presence of internal orphan metabolites. The inability to carry flux applies to ''any'' further analysis of the model - for example, a dead reaction will never be present as part of an LP solution, will never show up in an elementary mode and will always carry zero flux (within machine precision) in any kinetic steady-state determination. They are identified by the {{{DeadReactions()}}} method, e.g.: {{{#!highlight python >>> dead = m.DeadReactions() >>> len(dead) 1 >>> print dead ['GlcTx'] }}} In this case a glucose 6 phosphate transporter was dead, despite the fact that in this case the internal substrate, G6P, was not an orphan metabolite. {{{#!highlight python GlcTx: x_G6P <> G6P ~ }}} The reason was that phosphate (in this model) was a conserved moiety, and the transporter could not carry steady-state flux unless a phosphate could leave the system for each G6P that entered. === Enzyme (reaction) subsets === In the null-space reported above, note that some of the row-vectors are proportional to each other - {{{R_2}}}, {{{R_3}}}; {{{R_4}}}, {{{R_5}}}; and {{{E_tx}}}, {{{A_tx}}}, {{{R_1}}}. This implies that these sets must carry flux in a coordinated fashion, e.g. any flux solution involving {{{R_4}}} must also involve {{{R_5}}}. These sets of coordinated reactions are referred to as ''enzyme subsets'' and can be determined using the {{{Model}}} method {{{EnzSubsets()}}}. This method returns a dictionary object where keys are subset names (or reaction name if a reaction is in a singleton set) and values are nested dictionaries where keys are reaction names and values are the flux ratios of the reactions. The key {{{DeadReacs}}} maps to a list of dead reactions, since all dead reactions satisfy the definition of a subset (if rather trivially). {{{#!python >>> ess=m.EnzSubsets() >>> ess {'Ess_3': {'R_4': mpq(-1,1), 'R_5': mpq(-1,1)}, 'Ess_2': {'R_2': mpq(1,1), 'R_3': mpq(1,1)}, 'Ess_1': {'E_tx': mpq(1,1), 'R_1': mpq(1,1), 'A_tx': mpq(1,1)}, 'DeadReacs': {'R_6': mpq(1,1)}} }}} === Conserved Moieties === == Elementary Modes Analysis == The elementary modes of a model can be analysed using the method {{{Model.ElModes()}}}. The field {{{mo}}} is a matrix similar to {{{k}}}. {{{#!python >>> elmo = m.ElModes() >>> elmo.mo ElMo_0 ElMo_1 R_1 1/1 1/1 R_2 1/1 0/1 R_3 1/1 0/1 R_4 0/1 1/1 R_5 0/1 1/1 R_6 0/1 0/1 E_tx 1/1 1/1 A_tx 1/1 1/1 }}} The relationship between modes and metabolites is stored in the {{{sto}}} matrix. {{{#!python >>> elmo.sto ElMo_0 ElMo_1 x_A -1/1 -1/1 A 0/1 0/1 B 0/1 0/1 C 0/1 0/1 E 0/1 0/1 D 0/1 0/1 F 0/1 0/1 x_E 1/1 1/1 }}} The methods {{{Modes()}}} and {{{Stos()}}} returns a string with with same information as the matrices above. {{{#!python >>> print elmo.Modes() ElMo_0, 1/1 E_tx, 1/1 R_1, 1/1 R_2, 1/1 R_3, 1/1 A_tx ElMo_1, 1/1 E_tx, 1/1 R_1, 1/1 A_tx, 1/1 R_4, 1/1 R_5 >>> print elmo.Stos() ElMo_0: 1/1 x_A -> 1/1 x_E ~ ElMo_1: 1/1 x_A -> 1/1 x_E ~ }}} == The Matrix Class == Fully described in utility section - enough here to understand SMs, datasets and monitors.