def main(): from state.Model import Model from state.Species import Species from state.SpeciesReference import SpeciesReference from state.Reaction import Reaction from state.TimeSeriesAllReactions import TimeSeriesAllReactions app = wx.PySimpleApp() # Define a simple model. model = Model() model.id = 'model' model.speciesIdentifiers.append('s1') model.species['s1'] = Species('C1', 'species 1', '13') model.speciesIdentifiers.append('s2') model.species['s2'] = Species('C1', 'species 2', '17') # s1 -> s2 model.reactions.append( Reaction('r1', 'reaction 1', [SpeciesReference('s1')], [SpeciesReference('s2')], True, '1.5')) # s1 + s2 -> 2 s1 model.reactions.append( Reaction('r2', 'reaction 2', [SpeciesReference('s1'), SpeciesReference('s2')], [SpeciesReference('s1', 2)], True, '2.5')) # Trajectories. initialTime = 0. finalTime = 3. # One species, two reactions. t = TimeSeriesAllReactions([0], [0, 1], initialTime, finalTime) t.appendInitialPopulations([13, 17]) t.appendIndices([0, 1, 0]) t.appendTimes([0, 0.5, 1]) t.appendInitialPopulations([13, 17]) t.appendIndices([0, 1, 1, 0]) t.appendTimes([0, 0.33, 0.67, 1]) TableFrame(model, t, 'PopulationsEnd', 'Populations at the end time.').Show() TableFrame(model, t, 'ReactionsEnd', 'Reaction counts at the end time.').Show() TableFrame(model, t, 'PopulationsAll', 'Populations at the start time and reaction events.').Show() TableFrame( model, t, 'ReactionsAll', 'Reaction counts at the start time and reaction events.').Show() app.MainLoop()
def frames(): from FigureNumber import FigureNumber from state.State import State from state.Model import Model from state.Reaction import Reaction from state.Species import Species from state.SpeciesReference import SpeciesReference from state.Histogram import Histogram from state.HistogramFrames import HistogramFrames # Figure number. figureNumber = FigureNumber() # A histogram. numberOfBins = 4 multiplicity = 2 h = Histogram(numberOfBins, multiplicity) h.setCurrentToMinimum() h.accumulate(0, 1) h.accumulate(1, 2) h.accumulate(2, 2) h.accumulate(3, 1) # Simulation output. frameTimes = [0, 1] recordedSpecies = [0, 1, 2] hf = HistogramFrames(numberOfBins, multiplicity, recordedSpecies) hf.setFrameTimes(frameTimes) for i in range(len(frameTimes)): for j in range(len(recordedSpecies)): hf.histograms[i][j].merge(h) # The model. model = Model() model.speciesIdentifiers = ['s1', 's2', 's3'] # The state. state = State() state.models['model'] = model state.output[('model', 'method')] = hf app = wx.PySimpleApp() TestConfiguration(None, 'Populations.', state, figureNumber).Show() app.MainLoop()
def main(): import sys sys.path.insert(1, '..') from random import uniform from state.Model import Model from state.Histogram import Histogram from state.HistogramFrames import HistogramFrames # A histogram. numberOfBins = 4 multiplicity = 2 # Simulation output. frameTimes = [0, 1] recordedSpecies = [0, 1, 2] hf = HistogramFrames(numberOfBins, multiplicity, recordedSpecies) hf.setFrameTimes(frameTimes) for i in range(len(frameTimes)): for j in range(len(recordedSpecies)): h = Histogram(numberOfBins, multiplicity) h.setCurrentToMinimum() for b in range(numberOfBins): h.accumulate(b, uniform(0., 1.)) hf.histograms[i][j].merge(h) # The model. model = Model() model.speciesIdentifiers = ['s1', 's2', 's3'] # The state. class TestState: pass state = TestState() state.models = {} state.models['model'] = model state.output = {} state.output[('model', 'method')] = hf app = wx.PySimpleApp() PValueMean(state, 'P-value for equal means').Show() app.MainLoop()
def average(): from FigureNumber import FigureNumber from state.State import State from state.Model import Model from state.Reaction import Reaction from state.Species import Species from state.SpeciesReference import SpeciesReference from state.Histogram import Histogram from state.HistogramAverage import HistogramAverage # Figure number. figureNumber = FigureNumber() # A histogram. numberOfBins = 4 multiplicity = 2 h = Histogram(numberOfBins, multiplicity) h.setCurrentToMinimum() h.accumulate(0, 1) h.accumulate(1, 2) h.accumulate(2, 2) h.accumulate(3, 1) # Simulation output. recordedSpecies = [0, 1, 2] output = HistogramAverage(numberOfBins, multiplicity, recordedSpecies) for x in output.histograms: x.merge(h) # The model. model = Model() model.speciesIdentifiers = ['s1', 's2', 's3'] # The state. state = State() state.models['model'] = model state.output[('model', 'method')] = output app = wx.PySimpleApp() TestConfiguration(None, 'Populations.', state, figureNumber).Show() app.MainLoop()
def main(): import math from StringIO import StringIO import sys sys.path.insert(1, '..') from state.HistogramFrames import HistogramFrames from state.Model import Model numberOfBins = 20 multiplicity = 2 recordedSpecies = [0] output = HistogramFrames(numberOfBins, multiplicity, recordedSpecies) output.setFrameTimes([1e20 / 9.]) # Poisson with mean 10. PMF = e^-lambda lambda^n / n! poisson = [math.exp(-10)] for n in range(1, numberOfBins): poisson.append(poisson[-1] * 10. / n) cardinality = numberOfBins sumOfWeights = sum(poisson) mean = 0. for i in range(numberOfBins): mean += poisson[i] * i mean /= sumOfWeights summedSecondCenteredMoment = 0. for i in range(numberOfBins): summedSecondCenteredMoment += poisson[i] * (i - mean)**2 stream = StringIO( repr(cardinality) + '\n' + repr(sumOfWeights) + '\n' + repr(mean) + '\n' + repr(summedSecondCenteredMoment) + '\n' + '0\n1\n' + ''.join([repr(_x) + ' ' for _x in poisson]) + '\n' + '0 ' * len(poisson) + '\n') output.histograms[0][0].read(stream, multiplicity) app = wx.PySimpleApp() model = Model() model.speciesIdentifiers = ['X'] TableErrorFrame(model, output).Show() app.MainLoop()
def main(): import sys sys.path.insert(1, '..') from state.Model import Model from state.HistogramFrames import HistogramFrames model = Model() model.speciesIdentifiers = ['s1', 's2'] hf = HistogramFrames(10, [0, 1]) hf.setFrameTimes([0., 1., 2.]) app = wx.PySimpleApp() frame = SpeciesFrameDialog(None, model, hf) result = frame.ShowModal() if result == wx.ID_OK: print 'OK' print frame.getSpecies() print frame.getFrame() else: print 'Cancel' frame.Destroy() app.MainLoop()
class TableStatisticsAverage(wx.Frame): def __init__(self, model, output, title='Statistics', parent=None): wx.Frame.__init__(self, parent, title=title, size=(300, 600)) display = Panel(self, model, output) display.grid.AutoSize() self.Layout() # # Test Code. # if __name__ == '__main__': from StringIO import StringIO import sys sys.path.insert(1, '..') from state.StatisticsAverage import StatisticsAverage from state.Model import Model recordedSpecies = [0] output = StatisticsAverage(recordedSpecies) output.setStatistics([1., 2.]) app = wx.PySimpleApp() model = Model() model.speciesIdentifiers = ['X'] TableStatisticsAverage(model, output).Show() app.MainLoop()
def startElement(self, name, attributes): self.elements.append(name) # # The top level element. if name == 'cain': if 'version' in attributes.keys(): self.version = float(attributes['version']) else: self.version = 1.6 elif name == 'sbml': # Fatal error. raise Exception( 'This is an SBML file. One may only directly open Cain files. Use File->Import SBML instead.' ) # # Elements for the model. # elif name == 'listOfModels': pass elif name == 'model': # Start a new model. self.model = Model() if 'id' in attributes.keys(): self.model.id = attributes['id'] if 'name' in attributes.keys(): self.model.name = attributes['name'] elif name == 'listOfParameters': # Start the dictionary of parameters. self.model.parameters = {} elif name == 'listOfCompartments': # Start the dictionary of compartments. self.model.compartments = {} elif name == 'listOfSpecies': # Start the dictionary of species and list of species identifiers. self.model.species = {} self.model.speciesIdentifiers = [] elif name == 'listOfReactions': # Start the list of reactions. self.model.reactions = [] elif name == 'listOfTimeEvents': # Start the list of time events. self.model.timeEvents = [] elif name == 'listOfTriggerEvents': # Start the list of trigger events. self.model.triggerEvents = [] elif name == 'parameter': # Append a parameter. if not 'id' in attributes.keys(): self.errors += 'Missing id attribute in parameter.\n' return x = Value('', '') error = x.readXml(attributes) if error: self.errors += error return self.model.parameters[attributes['id']] = x elif name == 'compartment': # Append a compartment. if not 'id' in attributes.keys(): self.errors += 'Missing id attribute in compartment.\n' return if not attributes['id']: self.errors += 'Compartment identifier is empty.\n' return compartment = Value('', '') compartment.readXml(attributes) self.model.compartments[attributes['id']] = compartment elif name == 'species': # Append a species. if not 'id' in attributes.keys(): self.errors += 'Missing id attribute in species.\n' return x = Species(None, None, None) x.readXml(attributes) self.model.species[attributes['id']] = x self.model.speciesIdentifiers.append(attributes['id']) elif name == 'reaction': # Append a reaction. x = Reaction('', '', [], [], True, '') error = x.readXml(attributes) if error: self.errors += error return self.model.reactions.append(x) elif name == 'timeEvent': # Append a time event. x = TimeEvent('', '', '', '') error = x.readXml(attributes) if error: self.errors += error return self.model.timeEvents.append(x) elif name == 'triggerEvent': # Append a trigger event. x = TriggerEvent('', '', '', '', 0., False) error = x.readXml(attributes) if error: self.errors += error return self.model.triggerEvents.append(x) elif name == 'listOfReactants': if not self.model.reactions: self.errors += 'Badly placed listOfReactants tag.\n' return elif name == 'listOfProducts': if not self.model.reactions: self.errors += 'Badly placed listOfProducts tag.\n' return elif name == 'listOfModifiers': if not self.model.reactions: self.errors += 'Badly placed listOfModifiers tag.\n' return elif name == 'speciesReference': # Add the reactant or product to the current reaction. if not self.model.reactions: self.errors += 'Badly placed speciesReference tag.\n' return if not 'species' in attributes.keys(): self.errors +=\ 'Missing species attribute in speciesReference.\n' return if 'stoichiometry' in attributes.keys(): stoichiometry = int(attributes['stoichiometry']) else: stoichiometry = 1 # No need to record if the stoichiometry is zero. if stoichiometry != 0: sr = SpeciesReference(attributes['species'], stoichiometry) if self.elements[-2] == 'listOfReactants': self.model.reactions[-1].reactants.append(sr) elif self.elements[-2] == 'listOfProducts': self.model.reactions[-1].products.append(sr) else: self.errors += 'Badly placed speciesReference tag.\n' return elif name == 'modifierSpeciesReference': # Add to the reactants and products of the current reaction. if not self.model.reactions: self.errors += 'Badly placed modifierSpeciesReference tag.\n' return if not 'species' in attributes.keys(): self.errors +=\ 'Missing species attribute in modifierSpeciesReference.\n' return if self.elements[-2] != 'listOfModifiers': self.errors += 'Badly placed modifierSpeciesReference tag.\n' return sr = SpeciesReference(attributes['species']) self.model.reactions[-1].reactants.append(sr) self.model.reactions[-1].products.append(sr) # # Elements for the simulation parameters. # elif name == 'listOfMethods': pass elif name == 'method': m = Method() error = m.readXml(attributes) if error: self.errors += error return self.methods[m.id] = m # # Elements for the simulation output. # elif name == 'listOfOutput': pass # CONTINUE: trajectoryFrames is deprecated. elif name in ('timeSeriesFrames', 'trajectoryFrames'): if not 'model' in attributes.keys(): self.errors +=\ 'Missing model attribute in timeSeriesFrames.\n' return if not 'method' in attributes.keys(): self.errors += 'Missing method attribute in timeSeriesFrames.\n' return key = (attributes['model'], attributes['method']) # An ensemble of trajectories should not be listed twice. if key in self.output: self.errors += 'Simulation output (' + key[0] + ', ' +\ key[1] + ') listed twice.\n' else: # Start a new ensemble. self.output[key] = TimeSeriesFrames() self.currentOutput = self.output[key] # CONTINUE: trajectoryAllReactions is deprecated. elif name in ('timeSeriesAllReactions', 'trajectoryAllReactions'): if not 'model' in attributes.keys(): self.errors +=\ 'Missing model attribute in timeSeriesAllReactions.\n' return if not 'method' in attributes.keys(): self.errors += 'Missing method attribute in timeSeriesAllReactions.\n' return key = (attributes['model'], attributes['method']) if self.version >= 1: if not 'initialTime' in attributes.keys(): self.errors +=\ 'Missing initialTime attribute in timeSeriesAllReactions.\n' return if not 'finalTime' in attributes.keys(): self.errors +=\ 'Missing finalTime attribute in timeSeriesAllReactions.\n' return else: if not 'endTime' in attributes.keys(): self.errors +=\ 'Missing endTime attribute in timeSeriesAllReactions.\n' return # An ensemble of trajectories should not be listed twice. if key in self.output: self.errors += 'Simulation output (' + key[0] + ', ' +\ key[1] + ') listed twice.\n' return # Check that the model has been defined. if not attributes['model'] in self.models: self.errors += 'timeSeriesAllReactions uses an undefined model.\n' return # Start a new ensemble. By definition all of the species and # reactions are recorded. model = self.models[attributes['model']] if self.version >= 1: self.output[key] =\ TimeSeriesAllReactions(range(len(model.speciesIdentifiers)), range(len(model.reactions)), float(attributes['initialTime']), float(attributes['finalTime'])) else: # CONTINUE: Deprecated. self.output[key] =\ TimeSeriesAllReactions(range(len(model.speciesIdentifiers)), range(len(model.reactions)), 0., float(attributes['endTime'])) self.currentOutput = self.output[key] elif name == 'histogramFrames': for key in ('model', 'method', 'numberOfTrajectories'): if not key in attributes.keys(): self.errors +=\ 'Missing ' + key + ' attribute in histogramFrames.\n' return # CONTINUE: Make multiplicity mandatory. if 'multiplicity' in attributes.keys(): multiplicity = int(attributes['multiplicity']) else: multiplicity = 2 key = (attributes['model'], attributes['method']) # An ensemble of trajectories should not be listed twice. if key in self.output: self.errors += 'Simulation output (' + key[0] + ', ' +\ key[1] + ') listed twice.\n' else: # Check that the method has been defined. if not attributes['method'] in self.methods: self.errors += 'HistogramFrames uses an undefined method.\n' return # Start a new ensemble. method = self.methods[attributes['method']] self.output[key] = HistogramFrames(method.numberOfBins, multiplicity) self.currentOutput = self.output[key] self.currentOutput.numberOfTrajectories =\ float(attributes['numberOfTrajectories']) elif name == 'histogramAverage': for key in ('model', 'method', 'numberOfTrajectories'): if not key in attributes.keys(): self.errors +=\ 'Missing ' + key + ' attribute in histogramAverage.\n' return # CONTINUE: Make multiplicity mandatory. if 'multiplicity' in attributes.keys(): multiplicity = int(attributes['multiplicity']) else: multiplicity = 2 key = (attributes['model'], attributes['method']) # An ensemble of trajectories should not be listed twice. if key in self.output: self.errors += 'Simulation output (' + key[0] + ', ' +\ key[1] + ') listed twice.\n' else: # Check that the method has been defined. if not attributes['method'] in self.methods: self.errors += 'HistogramAverage uses an undefined method.\n' return # Start a new ensemble. method = self.methods[attributes['method']] self.output[key] =\ HistogramAverage(method.numberOfBins, multiplicity) self.currentOutput = self.output[key] self.currentOutput.numberOfTrajectories =\ float(attributes['numberOfTrajectories']) elif name == 'statisticsFrames': for key in ('model', 'method'): if not key in attributes.keys(): self.errors +=\ 'Missing ' + key + ' attribute in statisticsFrames.\n' return key = (attributes['model'], attributes['method']) # An ensemble of trajectories should not be listed twice. if key in self.output: self.errors += 'Simulation output (' + key[0] + ', ' +\ key[1] + ') listed twice.\n' else: # Check that the method has been defined. if not attributes['method'] in self.methods: self.errors += 'StatisticsFrames uses an undefined method.\n' return # Start a new ensemble. method = self.methods[attributes['method']] self.output[key] = StatisticsFrames() self.currentOutput = self.output[key] elif name == 'statisticsAverage': for key in ('model', 'method'): if not key in attributes.keys(): self.errors +=\ 'Missing ' + key + ' attribute in statisticsAverage.\n' return key = (attributes['model'], attributes['method']) # An ensemble of trajectories should not be listed twice. if key in self.output: self.errors += 'Simulation output (' + key[0] + ', ' +\ key[1] + ') listed twice.\n' else: # Check that the method has been defined. if not attributes['method'] in self.methods: self.errors += 'StatisticsAverage uses an undefined method.\n' return # Start a new ensemble. method = self.methods[attributes['method']] self.output[key] = StatisticsAverage() self.currentOutput = self.output[key] elif name == 'frameTimes': self.frameTimes = [] # The content should be empty. if self.content: self.errors += 'Mishandled content in frameTimes tag.\n' elif name == 'recordedSpecies': self.recordedSpecies = [] # The content should be empty. if self.content: self.errors += 'Mishandled content in recordedSpecies tag.\n' elif name == 'recordedReactions': self.recordedReactions = [] # The content should be empty. if self.content: self.errors += 'Mishandled content in recordedReactions tag.\n' elif name == 'populations': self.populations = [] # The content should be empty. if self.content: self.errors += 'Mishandled content in population tag.\n' elif name == 'reactionCounts': self.reactionCounts = [] # The content should be empty. if self.content: self.errors += 'Mishandled content in reactionCounts tag.\n' elif name == 'initialPopulations': self.initialPopulations = [] # The content should be empty. if self.content: self.errors += 'Mishandled content in initialPopulations tag.\n' elif name == 'indices': self.indices = [] # The content should be empty. if self.content: self.errors += 'Mishandled content in indices tag.\n' elif name == 'times': self.times = [] # The content should be empty. if self.content: self.errors += 'Mishandled content in times tag.\n' elif name == 'histogram': # CONTINUE: Add 'cardinality', 'mean', 'summedSecondCenteredMoment', # and 'sumOfWeights' to the required attributes. for key in ('lowerBound', 'width', 'species'): if not key in attributes.keys(): self.errors +=\ 'Missing ' + key + ' attribute in histogram.\n' return species = int(attributes['species']) if self.currentOutput.__class__.__name__ == 'HistogramFrames': if not 'frame' in attributes.keys(): self.errors +=\ 'Missing frame attribute in histogram.\n' return frame = int(attributes['frame']) self.currentHistogram =\ self.currentOutput.histograms[frame][species] elif self.currentOutput.__class__.__name__ == 'HistogramAverage': self.currentHistogram =\ self.currentOutput.histograms[species] else: self.errors += 'Unkown histogram type.\n' return self.currentHistogramIndex = 0 # CONTINUE Make these attributes required. if 'cardinality' in attributes: self.currentHistogram.cardinality =\ float(attributes['cardinality']) if 'mean' in attributes: self.currentHistogram.mean = float(attributes['mean']) if 'summedSecondCenteredMoment' in attributes: self.currentHistogram.summedSecondCenteredMoment =\ float(attributes['summedSecondCenteredMoment']) if 'sumOfWeights' in attributes: self.currentHistogram.sumOfWeights =\ float(attributes['sumOfWeights']) self.currentHistogram.lowerBound = float(attributes['lowerBound']) self.currentHistogram.setWidth(float(attributes['width'])) elif name == 'statistics': self.statistics = [] # The content should be empty. if self.content: self.errors += 'Mishandled content in statistics tag.\n' # CONTINUE: These are deprecated. elif name == 'firstHistogram': # The content should be empty. if self.content: self.errors += 'Mishandled content in firstHistogram tag.\n' elif name == 'secondHistogram': # The content should be empty. if self.content: self.errors += 'Mishandled content in secondHistogram tag.\n' elif name == 'histogramElement': # The content should be empty. if self.content: self.errors += 'Mishandled content in histogramElement tag.\n' # # Elements for the random number generator state. # elif name == 'random': if 'seed' in attributes.keys(): self.seed = int(attributes['seed']) elif name == 'stateMT19937': self.listOfMt19937States.append([]) # The content should be empty. if self.content: self.errors += 'Mishandled content in stateMT19937 tag.\n' # # Unknown tag. # else: self.errors += 'Unknown tag: ' + name + '\n'
def readSbmlFile(fileName): # Create an empty model. model = Model() # Read the SBML file. print "Read the SBML file." print fileName #file = open(fileName) #print file.readlines() #file.close() #document = libsbml.SBMLReader().readSBML(fileName) # The SBML model. print 'The SBML model.' #sbmlModel = document.getModel() sbmlModel = libsbml.SBMLReader().readSBML(fileName).getModel() # Model identifier. model.id = sbmlModel.getId() # Model name. model.name = sbmlModel.getName() # For each species. for n in range(sbmlModel.getNumSpecies()): sbmlSpecies = sbmlModel.getSpecies(n) # Add to the dictionary of species. model.species[sbmlSpecies.getId()] = \ Species(sbmlSpecies.getName(), str(sbmlSpecies.getInitialAmount())) # Add to the list of species identifiers. model.speciesIdentifiers.append(sbmlSpecies.getId()) # For each reaction. for n in range(sbmlModel.getNumReactions()): sbmlReaction = sbmlModel.getReaction(n) reactants = [] products = [] # CONTINUE: reactants, products and modifiers may be listed multiple # times. In this case, accumulate the stoichiometry. for m in range(sbmlReaction.getNumReactants()): ref = sbmlReaction.getReactant(m) # CONTINUE: The stoichiometry may be defined with # StoichiometryMath. reactants.append( SpeciesReference(ref.getSpecies(), int(ref.getStoichiometry()))) for m in range(sbmlReaction.getNumProducts()): ref = sbmlReaction.getProduct(m) products.append( SpeciesReference(ref.getSpecies(), int(ref.getStoichiometry()))) for m in range(sbmlReaction.getNumModifiers()): ref = sbmlReaction.getModifier(m) reactants.append(SpeciesReference(ref.getSpecies(), 1)) products.append(SpeciesReference(ref.getSpecies(), 1)) # Add the reaction. model.reactions.append( Reaction(sbmlReaction.getId(), sbmlReaction.getName(), reactants, products, True, '0')) # Add the reverse reaction if necessary. if sbmlReaction.getReversible(): model.reactions.append( Reaction(sbmlReaction.getId() + 'r', sbmlReaction.getName() + 'reverse', products, reactants, True, '0')) return model
def readModelText(input): """Read a model with the following format: <number of species> <number of reactions> <list of initial amounts> <packed reactions> <list of propensity factors> If successful, return the model. Otherwise return None. Note that the model ID and name will not be set as this information is not in the simple text description. The species identifiers will be set to S1, S2, etc. The reaction identifiers will be set to R1, R2, etc. The names for species and reactions will be empty. """ try: # Start with an empty model. The ID and the name are empty. We will use # the unnamed compartment. model = Model() # Number of species. numberOfSpecies = int(input.readline()) assert numberOfSpecies > 0 # Number of reactions. numberOfReactions = int(input.readline()) assert numberOfReactions > 0 # Initial amounts. Read as strings. initialAmounts = input.readline().rstrip().split() assert len(initialAmounts) == numberOfSpecies # The species identifiers are S1, S2, etc. sid = ['S' + str(n + 1) for n in range(numberOfSpecies)] model.speciesIdentifiers = sid # Add the species. for n in range(numberOfSpecies): model.species[sid[n]] = Species('', '', initialAmounts[n]) # Read the packed reactions into a list of integers. data = map(int, input.readline().rstrip().split()) # The propensity factors. propensityFactors = input.readline().rstrip().split() # Add the reactions. n = 0 for i in range(numberOfReactions): id = 'R' + str(i + 1) # Reactants. numberOfReactants = data[n] n = n + 1 reactants = [] for j in range(numberOfReactants): speciesIndex = data[n] n = n + 1 stoichiometry = data[n] n = n + 1 reactants.append(SpeciesReference(sid[speciesIndex], stoichiometry)) # Products. numberOfProducts = data[n] n = n + 1 products = [] for j in range(numberOfProducts): speciesIndex = data[n] n = n + 1 stoichiometry = data[n] n = n + 1 products.append(SpeciesReference(sid[speciesIndex], stoichiometry)) # Add the reaction. model.reactions.append(Reaction(id, '', reactants, products, True, propensityFactors[i])) # Return the model. return model except Exception, error: print(error) return None