def add_default_flux_bounds(doc, lower=0.0, upper=100.0, unit='mole_per_s'): """ Adds default flux bounds to SBMLDocument. :param doc: :type doc: :param lower: :type lower: :param upper: :type upper: """ # FIXME: overwrites lower/upper parameter (check if existing) # TODO: the units are very specific (more generic) warnings.warn('Adding default flux bounds', UserWarning) model = doc.getModel() parameters = [ factory.Parameter(sid='upper', value=upper, unit=unit), factory.Parameter(sid='lower', value=lower, unit=unit), ] factory.create_objects(model, parameters) for r in model.reactions: rfbc = r.getPlugin("fbc") if not rfbc.isSetLowerFluxBound(): rfbc.setLowerFluxBound('lower') if not rfbc.isSetUpperFluxBound(): rfbc.setUpperFluxBound('upper')
def create_dummy_reactions(model, model_fba, unit_flux=None): """ Creates the dummy reactions. This also creates the corresponding flux parameters and flux assignments. :param model: :param model_fba: :param unit_flux: :return: """ ex_rids = utils.find_exchange_reactions(model_fba) objects = [] for ex_rid, sid in ex_rids.items(): pid_flux = FLUX_PARAMETER_PREFIX + sid rid_flux = DUMMY_REACTION_PREFIX + sid objects.append( # flux parameter: fluxe from fba (rate of reaction) fac.Parameter(sid=pid_flux, value=1.0, constant=True, unit=unit_flux, sboTerm=FLUX_PARAMETER_SBO), ) # dummy reaction (pseudoreaction) fac.create_reaction(model, rid=rid_flux, reversible=False, products={DUMMY_SPECIES_ID: 1}, sboTerm=DUMMY_REACTION_SBO, formula='0 {}'.format(unit_flux)) # flux assignment rule objects.append( fac.AssignmentRule(pid_flux, value=rid_flux, sboTerm=FLUX_ASSIGNMENTRULE_SBO), ) fac.create_objects(model, objects)
def set_units(model, units): """ Set units information on model. :param model: Model :param units: units info """ factory.create_objects(model, units)
def template_doc_bounds(model_id, create_min_max=True): """ Create template bounds model. Adds min and max functions :param create_min_max: :param model_id: model identifier :return: SBMLDocument """ sbmlns = libsbml.SBMLNamespaces(SBML_LEVEL, SBML_VERSION, 'comp', SBML_COMP_VERSION) doc = libsbml.SBMLDocument(sbmlns) doc.setPackageRequired(SBML_COMP_NAME, True) model = doc.createModel() model.setId("{}_bounds".format(model_id)) model.setName("{} (BOUNDS)".format(model_id)) model.setSBOTerm(comp.SBO_CONTINOUS_FRAMEWORK) if create_min_max: objects = [ # definition of min and max Function('max', 'lambda(x,y, piecewise(x,gt(x,y),y) )', name='min'), Function('min', 'lambda(x,y, piecewise(x,lt(x,y),y) )', name='max'), ] factory.create_objects(model, objects) return doc
def template_doc_bounds(model_id, create_min_max=True): """ Create template bounds model. Adds min and max functions :param create_min_max: :param model_id: model identifier :return: SBMLDocument """ sbmlns = libsbml.SBMLNamespaces(SBML_LEVEL, SBML_VERSION, 'comp', SBML_COMP_VERSION) doc = libsbml.SBMLDocument(sbmlns) doc.setPackageRequired(SBML_COMP_NAME, True) model = doc.createModel() model.setId("{}_bounds".format(model_id)) model.setName("{} (BOUNDS)".format(model_id)) model.setSBOTerm(comp.SBO_CONTINOUS_FRAMEWORK) if create_min_max: objects = [ # definition of min and max fac.Function('max', 'lambda(x,y, piecewise(x,gt(x,y),y) )', name='min'), fac.Function('min', 'lambda(x,y, piecewise(x,lt(x,y),y) )', name='max'), ] fac.create_objects(model, objects) return doc
def create_dfba_species(model, model_fba, compartment_id, hasOnlySubstanceUnits=False, unit_amount=None, create_port=True, exclude_sids=[]): """ Add DFBA species and compartments from fba model to model. Creates the dynamic species and respetive compartments with the necessary ports. This is used in the bounds submodel, update submodel and the and top model. :param model: :param model_fba: :return: """ objects = [] port_sids = [] ex_rids = utils.find_exchange_reactions(model_fba) for ex_rid in ex_rids: r = model_fba.getReaction(ex_rid) sid = r.getReactant(0).getSpecies() if sid in exclude_sids: continue s = model_fba.getSpecies(sid) # exchange species to create objects.append( fac.Species(sid=sid, name=s.getName(), initialConcentration=1.0, substanceUnit=unit_amount, hasOnlySubstanceUnits=hasOnlySubstanceUnits, compartment=compartment_id) ) # port of exchange species port_sids.append(sid) fac.create_objects(model, objects) if create_port: comp.create_ports(model, idRefs=port_sids)
def create_dynamic_bounds(model_bounds, model_fba, unit_flux=None): """ Creates the dynamic bounds for the model. It is necessary to create copies of the fixed bounds from the fba model which are subsequently used in the dynamic bounds calculation. :return: """ fba_suffix = "_fba" objects = [] ex_rids = utils.find_exchange_reactions(model_fba) for ex_rid, sid in ex_rids.items(): r = model_fba.getReaction(ex_rid) r_fbc = r.getPlugin(SBML_FBC_NAME) # get compartment from species s = model_bounds.getSpecies(sid) cid = s.getCompartment() # upper bound parameter (export from FBA, i.e increase concentration) ub_id = r_fbc.getUpperFluxBound() fba_ub_id = ub_id + fba_suffix ub_value = model_fba.getParameter(ub_id).getValue() ub_formula = "{}".format(fba_ub_id) objects.extend([ Parameter(sid=fba_ub_id, value=ub_value, unit=unit_flux, constant=True, sboTerm=FLUX_BOUND_SBO), AssignmentRule(sid=ub_id, value=ub_formula, name="fba export bound ({})".format(sid)), ]) # lower bound parameter (import to FBA, i.e decrease concentration) lb_id = r_fbc.getLowerFluxBound() fba_lb_id = lb_id + fba_suffix lb_value = model_fba.getParameter(lb_id).getValue() # concentration/amount formula for import depending on available species if s.getHasOnlySubstanceUnits(): lb_formula = "max({}, -{}/dt)".format(fba_lb_id, sid) else: lb_formula = "max({}, -{}*{}/dt)".format(fba_lb_id, cid, sid) objects.extend([ # default bounds from fba Parameter(sid=fba_lb_id, value=lb_value, unit=unit_flux, constant=False, sboTerm=FLUX_BOUND_SBO), # uptake bounds (lower bound) AssignmentRule(sid=lb_id, value=lb_formula, name="dfba import bound ({})".format(sid)), ]) factory.create_objects(model_bounds, objects)
def create_exchange_reaction(model, species_id, exchange_type=EXCHANGE, flux_unit=None): """ Factory method to create exchange reactions for species in the FBA model. Creates the exchange reaction, the upper and lower bounds, and the ports. :param model: :param species_id: :param exchange_type: :param flux_unit: :return: """ if exchange_type not in [EXCHANGE, EXCHANGE_IMPORT, EXCHANGE_EXPORT]: raise ValueError("Wrong exchange_type: {}".format(exchange_type)) # id (e.g. EX_A) ex_rid = EXCHANGE_REACTION_PREFIX + species_id lb_id = LOWER_BOUND_PREFIX + ex_rid ub_id = UPPER_BOUND_PREFIX + ex_rid lb_value = LOWER_BOUND_DEFAULT ub_value = UPPER_BOUND_DEFAULT if exchange_type == EXCHANGE_IMPORT: # negative flux through exchange reaction ub_value = ZERO_BOUND if exchange_type == EXCHANGE_EXPORT: lb_value = ZERO_BOUND parameters = [ Parameter(sid=lb_id, value=lb_value, unit=flux_unit, constant=True, sboTerm=FLUX_BOUND_SBO, port=True), Parameter(sid=ub_id, value=ub_value, unit=flux_unit, constant=True, sboTerm=FLUX_BOUND_SBO, port=True), ] factory.create_objects(model, parameters) reactions = [ ExchangeReaction(species_id, reversible=True, lowerFluxBound=lb_id, upperFluxBound=ub_id, port=True) ] ex_reactions = factory.create_objects(model, reactions) # only one element in dictionary, get first value return next(iter(ex_reactions.values()))
def bounds_model(sbml_file, directory, doc_fba=None): """" Submodel for dynamically calculating the flux bounds. The dynamically changing flux bounds are the input to the FBA model. """ doc = builder.template_doc_bounds(settings.MODEL_ID) model = doc.getModel() bounds_notes = notes.format(""" <h2>BOUNDS submodel</h2> <p>Submodel for dynamically calculating the flux bounds. The dynamically changing flux bounds are the input to the FBA model.</p> """) utils.set_model_info(model, notes=bounds_notes, creators=creators, units=units, main_units=main_units) # dt compartment_id = "blood" builder.create_dfba_dt(model, time_unit=UNIT_TIME, create_port=True) # compartment builder.create_dfba_compartment(model, compartment_id=compartment_id, unit_volume=UNIT_VOLUME, create_port=True) # dynamic species model_fba = doc_fba.getModel() builder.create_dfba_species(model, model_fba, compartment_id=compartment_id, unit_amount=UNIT_AMOUNT, create_port=True) # bounds builder.create_exchange_bounds(model, model_fba=model_fba, unit_flux=UNIT_FLUX, create_ports=True) # bounds fba_prefix = "fba" model_fba = doc_fba.getModel() objects = [] ex_rids = utils.find_exchange_reactions(model_fba) for ex_rid, sid in ex_rids.items(): r = model_fba.getReaction(ex_rid) # lower & upper bound parameters r_fbc = r.getPlugin(builder.SBML_FBC_NAME) lb_id = r_fbc.getLowerFluxBound() fba_lb_id = fba_prefix + lb_id lb_value = model_fba.getParameter(lb_id).getValue() objects.extend([ # default bounds from fba mc.Parameter(sid=fba_lb_id, value=lb_value, unit=UNIT_FLUX, constant=False), # uptake bounds (lower bound) mc.AssignmentRule(sid=lb_id, value="max({}, -{}*{}/dt)".format(fba_lb_id, compartment_id, sid)), ]) mc.create_objects(model, objects) sbmlio.write_sbml(doc, filepath=pjoin(directory, sbml_file), validate=True)
def bounds_model(sbml_file, directory, doc_fba, annotations=None): """" Bounds model. """ bounds_notes = notes.format(""" <h2>BOUNDS submodel</h2> <p>Submodel for dynamically calculating the flux bounds. The dynamically changing flux bounds are the input to the FBA model.</p> """) doc = builder.template_doc_bounds(settings.MODEL_ID) model = doc.getModel() utils.set_model_info(model, notes=bounds_notes, creators=creators, units=units, main_units=main_units) builder.create_dfba_dt(model, step_size=DT_SIM, time_unit=UNIT_TIME, create_port=True) # compartment compartment_id = 'extern' builder.create_dfba_compartment(model, compartment_id=compartment_id, unit_volume=UNIT_VOLUME, create_port=True) # species model_fba = doc_fba.getModel() builder.create_dfba_species(model, model_fba, compartment_id=compartment_id, unit_amount=UNIT_AMOUNT, hasOnlySubstanceUnits=True, create_port=True) # exchange bounds builder.create_exchange_bounds(model, model_fba=model_fba, unit_flux=UNIT_FLUX, create_ports=True) objects = [ # exchange bounds # FIXME: readout the FBA network bounds mc.Parameter(sid="lb_default", value=builder.LOWER_BOUND_DEFAULT, unit=UNIT_FLUX, constant=True), # kinetic bound parameter & calculation mc.Parameter(sid='ub_R1', value=1.0, unit=UNIT_FLUX, constant=False, sboTerm="SBO:0000625"), mc.Parameter(sid='k1', value=-0.2, unit="per_s", name="k1", constant=False), mc.RateRule(sid="ub_R1", value="k1*ub_R1"), # bound assignment rules mc.AssignmentRule(sid="lb_EX_A", value='max(lb_default, -A/dt)'), mc.AssignmentRule(sid="lb_EX_C", value='max(lb_default, -C/dt)'), ] mc.create_objects(model, objects) # ports comp.create_ports(model, portType=comp.PORT_TYPE_PORT, idRefs=["ub_R1"]) if annotations: annotation.annotate_sbml_doc(doc, annotations) sbmlio.write_sbml(doc, filepath=os.path.join(directory, sbml_file), validate=True)
def bounds_model(sbml_file, directory, doc_fba, annotations=None): """" Bounds model. """ bounds_notes = notes.format(""" <h2>BOUNDS submodel</h2> <p>Submodel for dynamically calculating the flux bounds. The dynamically changing flux bounds are the input to the FBA model.</p> """) doc = builder.template_doc_bounds(settings.MODEL_ID) model = doc.getModel() utils.set_model_info(model, notes=bounds_notes, creators=creators, units=units, main_units=main_units) builder.create_dfba_dt(model, step_size=DT_SIM, time_unit=UNIT_TIME, create_port=True) # compartment compartment_id = 'extern' builder.create_dfba_compartment(model, compartment_id=compartment_id, unit_volume=UNIT_VOLUME, create_port=True) # species model_fba = doc_fba.getModel() builder.create_dfba_species(model, model_fba, compartment_id=compartment_id, unit_amount=UNIT_AMOUNT, hasOnlySubstanceUnits=True, create_port=True) # exchange bounds builder.create_exchange_bounds(model, model_fba=model_fba, unit_flux=UNIT_FLUX, create_ports=True) objects = [ # exchange bounds # FIXME: readout the FBA network bounds mc.Parameter(sid="lb_default", value=builder.LOWER_BOUND_DEFAULT, unit=UNIT_FLUX, constant=True), # kinetic bound parameter & calculation mc.Parameter(sid='ub_R1', value=1.0, unit=UNIT_FLUX, constant=False, sboTerm="SBO:0000625"), mc.Parameter(sid='k1', value=-0.2, unit="per_s", name="k1", constant=False), mc.RateRule(sid="ub_R1", value="k1*ub_R1"), # bound assignment rules mc.AssignmentRule(sid="lb_EX_A", value='max(lb_default, -A/dt)'), mc.AssignmentRule(sid="lb_EX_C", value='max(lb_default, -C/dt)'), ] mc.create_objects(model, objects) # ports comp.create_ports(model, portType=comp.PORT_TYPE_PORT, idRefs=["ub_R1"]) if annotations: annotator.annotate_sbml_doc(doc, annotations) sbmlio.write_sbml(doc, filepath=os.path.join(directory, sbml_file), validate=True)
def create_exchange_reaction(model, species_id, exchange_type=EXCHANGE, flux_unit=None): """ Factory method to create exchange reactions for species in the FBA model. Creates the exchange reaction, the upper and lower bounds, and the ports. :param model: :param species_id: :param exchange_type: :param flux_unit: :return: """ if exchange_type not in [EXCHANGE, EXCHANGE_IMPORT, EXCHANGE_EXPORT]: raise ValueError("Wrong exchange_type: {}".format(exchange_type)) # id (e.g. EX_A) ex_rid = EXCHANGE_REACTION_PREFIX + species_id lb_id = LOWER_BOUND_PREFIX + ex_rid ub_id = UPPER_BOUND_PREFIX + ex_rid lb_value = LOWER_BOUND_DEFAULT ub_value = UPPER_BOUND_DEFAULT if exchange_type == EXCHANGE_IMPORT: # negative flux through exchange reaction ub_value = ZERO_BOUND if exchange_type == EXCHANGE_EXPORT: lb_value = ZERO_BOUND parameters = [ fac.Parameter(sid=lb_id, value=lb_value, unit=flux_unit, constant=True, sboTerm=FLUX_BOUND_SBO), fac.Parameter(sid=ub_id, value=ub_value, unit=flux_unit, constant=True, sboTerm=FLUX_BOUND_SBO), ] fac.create_objects(model, parameters) # exchange reactions are all reversible (it depends on the bounds in which direction they operate) ex_r = fac.create_reaction(model, rid=ex_rid, reversible=True, reactants={species_id: 1}, sboTerm=EXCHANGE_REACTION_SBO) # exchange bounds fbc.set_flux_bounds(ex_r, lb=lb_id, ub=ub_id) # create ports comp.create_ports(model, portType=comp.PORT_TYPE_PORT, idRefs=[ex_rid, lb_id, ub_id]) return ex_r
def create_dfba_dt(model, step_size=DT_SIM, time_unit=None, create_port=True): """ Creates the dt parameter in the model. :param model: :param create_port: :param step_size: :param time_unit: :return: """ objects = [ fac.Parameter(sid=DT_ID, value=step_size, unit=time_unit, constant=True, sboTerm=DT_SBO) ] fac.create_objects(model, objects) if create_port: comp.create_ports(model, idRefs=[DT_ID])
def bounds_model(sbml_file, directory, doc_fba=None): """" Submodel for dynamically calculating the flux bounds. The dynamically changing flux bounds are the input to the FBA model. The units of the exchange fluxes must fit to the transported species. """ doc = builder.template_doc_bounds("ecoli") model = doc.getModel() bounds_notes = notes.format(""" <h2>BOUNDS submodel</h2> <p>Submodel for dynamically calculating the flux bounds. The dynamically changing flux bounds are the input to the FBA model.</p> """) utils.set_model_info(model, notes=bounds_notes, creators=creators, units=units, main_units=main_units) # dt compartment_id = "bioreactor" builder.create_dfba_dt(model, time_unit=UNIT_TIME, create_port=True) # compartment builder.create_dfba_compartment(model, compartment_id=compartment_id, unit_volume=UNIT_VOLUME, create_port=True) # dynamic species model_fba = doc_fba.getModel() builder.create_dfba_species(model, model_fba, compartment_id=compartment_id, unit_amount=UNIT_AMOUNT, create_port=True, exclude_sids=['X']) # FIXME: define biomass separately, also port needed for biomass mc.create_objects(model, [ mc.Parameter(sid='cf_X', value=1.0, unit="g_per_mmol", name="biomass conversion factor", constant=True), mc.Species(sid='X', initialAmount=0.001, compartment=compartment_id, name='biomass', substanceUnit='g', hasOnlySubstanceUnits=True, conversionFactor='cf_X') ]) # exchange & dynamic bounds if not biomass_weighting: builder.create_exchange_bounds(model, model_fba=model_fba, unit_flux=UNIT_FLUX, create_ports=True) builder.create_dynamic_bounds(model, model_fba, unit_flux=UNIT_FLUX) else: builder.create_exchange_bounds(model, model_fba=model_fba, unit_flux=UNIT_FLUX_PER_G, create_ports=True) builder.create_dynamic_bounds(model, model_fba, unit_flux=UNIT_FLUX_PER_G) sbmlio.write_sbml(doc, filepath=pjoin(directory, sbml_file), validate=True)
def create_sbml(self, model): from sbmlutils.factory import create_objects # parameters and rules create_objects(model, self.pars, key='parameters') create_objects(model, self.rules, key='rules') # reaction r = model.createReaction() # type: libsbml.Reaction r.setId(self.rid) if self.name: r.setName(self.name) else: r.setName(self.rid) if self.compartment: r.setCompartment(self.compartment) if self.sboTerm: r.setSBOTerm(self.sboTerm) r.setReversible(self.equation.reversible) r.setFast(self.fast) # equation for reactant in self.equation.reactants: # type: libsbml.SpeciesReference sref = r.createReactant() sref.setSpecies(reactant.sid) sref.setStoichiometry(reactant.stoichiometry) sref.setConstant(True) for product in self.equation.products: # type: libsbml.SpeciesReference sref = r.createProduct() sref.setSpecies(product.sid) sref.setStoichiometry(product.stoichiometry) sref.setConstant(True) for modifier in self.equation.modifiers: sref = r.createModifier() sref.setSpecies(modifier) # kinetics if self.formula: ReactionTemplate.set_kinetic_law(model, r, self.formula.value) # add fbc bounds if self.upperFluxBound or self.lowerFluxBound: r_fbc = r.getPlugin("fbc") # type: libsbml.FbcReactionPlugin if self.upperFluxBound: r_fbc.setUpperFluxBound(self.upperFluxBound) if self.lowerFluxBound: r_fbc.setLowerFluxBound(self.lowerFluxBound) return r
def create_dummy_species(model, compartment_id, unit_amount=None, hasOnlySubstanceUnits=False): """ Creates the dummy species in the top model. Adds a deletion in the top model which removes the object again. :param model: SBML model :param compartment_id: compartment :param unit_amount: unit :param hasOnlySubstanceUnits: switch if amount or concentration :return: """ # dummy species for dummy reactions (empty set) fac.create_objects(model, [fac.Species(sid=DUMMY_SPECIES_ID, name=DUMMY_SPECIES_ID, initialConcentration=0, substanceUnit=unit_amount, hasOnlySubstanceUnits=hasOnlySubstanceUnits, compartment=compartment_id, sboTerm=DUMMY_SPECIES_SBO), ])
def create_dynamic_bounds(model_bounds, model_fba, unit_flux=None): """ Creates the dynamic bounds for the model. It is necessary to create copies of the fixed bounds from the fba model which are subsequently used in the dynamic bounds calculation. :return: """ fba_suffix = "_fba" objects = [] ex_rids = utils.find_exchange_reactions(model_fba) for ex_rid, sid in ex_rids.items(): r = model_fba.getReaction(ex_rid) r_fbc = r.getPlugin(SBML_FBC_NAME) # get compartment from species s = model_bounds.getSpecies(sid) cid = s.getCompartment() # upper bound parameter (export from FBA, i.e increase concentration) ub_id = r_fbc.getUpperFluxBound() fba_ub_id = ub_id + fba_suffix ub_value = model_fba.getParameter(ub_id).getValue() ub_formula = "{}".format(fba_ub_id) objects.extend([ fac.Parameter(sid=fba_ub_id, value=ub_value, unit=unit_flux, constant=True, sboTerm=FLUX_BOUND_SBO), fac.AssignmentRule(sid=ub_id, value=ub_formula, name="fba export bound ({})".format(sid)), ]) # lower bound parameter (import to FBA, i.e decrease concentration) lb_id = r_fbc.getLowerFluxBound() fba_lb_id = lb_id + fba_suffix lb_value = model_fba.getParameter(lb_id).getValue() # concentration/amount formula for import depending on available species if s.getHasOnlySubstanceUnits(): lb_formula = "max({}, -{}/dt)".format(fba_lb_id, sid) else: lb_formula = "max({}, -{}*{}/dt)".format(fba_lb_id, cid, sid) objects.extend([ # default bounds from fba fac.Parameter(sid=fba_lb_id, value=lb_value, unit=unit_flux, constant=False, sboTerm=FLUX_BOUND_SBO), # uptake bounds (lower bound) fac.AssignmentRule(sid=lb_id, value=lb_formula, name="dfba import bound ({})".format(sid)), ]) fac.create_objects(model_bounds, objects)
def create_exchange_bounds(model_bounds, model_fba, unit_flux=None, create_ports=True): """ Creates the exchange reaction flux bounds in the bounds model. :param model_bounds: the bounds model submodel :param model_fba: the fba submodel :param unit_flux: unit of fluxes :param create_ports: should ports be created. :return: """ ex_rids = utils.find_exchange_reactions(model_fba) objects = [] port_sids = [] for ex_rid, sid in ex_rids.items(): r = model_fba.getReaction(ex_rid) # lower & upper bound parameters r_fbc = r.getPlugin(SBML_FBC_NAME) lb_id = r_fbc.getLowerFluxBound() lb_value = model_fba.getParameter(lb_id).getValue() ub_id = r_fbc.getUpperFluxBound() ub_value = model_fba.getParameter(ub_id).getValue() # This creates the dynamical flux bound variables which are initialized with the # constant fba bounds objects.extend([ # for assignments Parameter(sid=lb_id, value=lb_value, unit=unit_flux, constant=False, sboTerm=FLUX_BOUND_SBO), Parameter(sid=ub_id, value=ub_value, unit=unit_flux, constant=False, sboTerm=FLUX_BOUND_SBO), ]) port_sids.extend([lb_id, ub_id]) # create bounds factory.create_objects(model_bounds, objects) # create ports if create_ports: comp.create_ports(model_bounds, idRefs=port_sids)
def test_event() -> None: objects = [ Parameter(sid="p1", value=0.0, constant=False), Event(sid="e1", trigger="time >= 10", assignments={"p1": 10.0}), ] doc = libsbml.SBMLDocument(3, 1) model = doc.createModel() factory.create_objects(model, obj_iter=objects) events = model.getListOfEvents() assert len(events) == 1 e = model.getEvent("e1") assert e is not None assert e.getId() == "e1" assignments = e.getListOfEventAssignments() assert len(assignments) == 1
def test_event(): objects = [ fac.Parameter(sid="p1", value=0.0, constant=False), fac.Event(sid="e1", trigger='time >= 10', assignments={'p1': 10.0}) ] doc = libsbml.SBMLDocument(3, 1) model = doc.createModel() fac.create_objects(model, obj_iter=objects) events = model.getListOfEvents() assert len(events) == 1 e = model.getEvent("e1") assert e is not None assert e.getId() == "e1" assignments = e.getListOfEventAssignments() assert len(assignments) == 1
def create_biomass_species(model, sid, unit, cf_unit, compartment_id, create_port=True): """ Creates the biomass species. :param model: :return: """ # FIXME: implement raise NotImplementedError pass fac.create_objects(model, [ fac.Parameter(sid='cf_X', value=1.0, unit="g_per_mmol", name="biomass conversion factor", constant=True), fac.Species(sid='X', value=0.001, compartment='c', name='biomass', substanceUnit='g', hasOnlySubstanceUnits=True, conversionFactor='cf_biomass') ]) if create_port: comp.create_ports(model, idRefs=['X'])
def create_port_doc(): sbmlns = libsbml.SBMLNamespaces(3, 1, 'comp', 1) doc = libsbml.SBMLDocument(sbmlns) doc.setPackageRequired("comp", True) model = doc.createModel() model.setId("toy_update") model.setName("toy (UPDATE submodel)") model.setSBOTerm(comp.SBO_CONTINOUS_FRAMEWORK) objects = [ fac.Compartment(sid='extern', value=1.0, unit="m3", constant=True, name='external compartment'), fac.Species(sid='A', name="A", initialConcentration=10.0, hasOnlySubstanceUnits=True, compartment="extern"), fac.Species(sid='C', name="C", initialConcentration=0, hasOnlySubstanceUnits=True, compartment="extern"), fac.Parameter(sid="EX_A", value=1.0, constant=False, sboTerm="SBO:0000613"), fac.Parameter(sid="EX_C", value=1.0, constant=False, sboTerm="SBO:0000613"), ] fac.create_objects(model, obj_iter=objects) return doc
def create_dfba_dt(model, step_size=DT_SIM, time_unit=None, create_port=True): """ Creates the dt parameter in the model. :param model: :param create_port: :param step_size: :param time_unit: :return: """ objects = [ Parameter(sid=DT_ID, value=step_size, unit=time_unit, constant=True, sboTerm=DT_SBO, port=create_port) ] factory.create_objects(model, objects)
def create_port_doc(): sbmlns = libsbml.SBMLNamespaces(3, 1, "comp", 1) doc = libsbml.SBMLDocument(sbmlns) doc.setPackageRequired("comp", True) model = doc.createModel() model.setId("toy_update") model.setName("toy (UPDATE submodel)") model.setSBOTerm(SBO_CONTINOUS_FRAMEWORK) objects = [ fac.Compartment( sid="extern", value=1.0, unit="m3", constant=True, name="external compartment", ), fac.Species( sid="A", name="A", initialConcentration=10.0, hasOnlySubstanceUnits=True, compartment="extern", ), fac.Species( sid="C", name="C", initialConcentration=0, hasOnlySubstanceUnits=True, compartment="extern", ), fac.Parameter(sid="EX_A", value=1.0, constant=False, sboTerm="SBO:0000613"), fac.Parameter(sid="EX_C", value=1.0, constant=False, sboTerm="SBO:0000613"), ] fac.create_objects(model, obj_iter=objects) return doc
def create_fba_doc(): sbmlns = libsbml.SBMLNamespaces(3, 1) sbmlns.addPackageNamespace("fbc", 2) sbmlns.addPackageNamespace("comp", 1) doc = libsbml.SBMLDocument(sbmlns) doc.setPackageRequired("comp", True) doc.setPackageRequired("fbc", False) model = doc.createModel() mplugin = model.getPlugin("fbc") mplugin.setStrict(True) objects = [ fac.Compartment(sid='cell', value=1.0), fac.Species(sid='A', initialConcentration=0, compartment="cell"), fac.Species(sid='B', initialConcentration=0, compartment="cell"), ] fac.create_objects(model, objects) return doc
def test_event2(): objects = [ fac.Compartment('c', value=1.0), fac.Species('S1', initialAmount=1.0, compartment='c'), fac.Parameter(sid="p1", value=0.0, constant=False), fac.Event(sid="e1", trigger='time >= 100', assignments={'p1': 10.0, 'S1': "p1 + 10"}) ] doc = libsbml.SBMLDocument(3, 1) model = doc.createModel() fac.create_objects(model, obj_iter=objects) events = model.getListOfEvents() assert len(events) == 1 e = model.getEvent("e1") assert e is not None assert e.getId() == "e1" assignments = e.getListOfEventAssignments() assert len(assignments) == 2
def create_update_parameter(model, sid, unit_flux): """ Creates the update parameter. The update parameter correspond to the flux parameters in the top model. :param model: :type model: :param sid: :type sid: :param unit_flux: :type unit_flux: :return: :rtype: """ pid = FLUX_PARAMETER_PREFIX + sid parameter = fac.Parameter(sid=pid, value=1.0, constant=True, unit=unit_flux, sboTerm=UPDATE_PARAMETER_SBO) fac.create_objects(model, [parameter]) # create port comp.create_ports(model, portType=comp.PORT_TYPE_PORT, idRefs=[pid]) return pid
def test_event2() -> None: objects = [ Compartment("c", value=1.0), Species("S1", initialAmount=1.0, compartment="c"), Parameter(sid="p1", value=0.0, constant=False), Event( sid="e1", trigger="time >= 100", assignments={"p1": 10.0, "S1": "p1 + 10"} ), ] doc = libsbml.SBMLDocument(3, 1) model = doc.createModel() factory.create_objects(model, obj_iter=objects) events = model.getListOfEvents() assert len(events) == 1 e = model.getEvent("e1") assert e is not None assert e.getId() == "e1" assignments = e.getListOfEventAssignments() assert len(assignments) == 2
def update_model(sbml_file, directory, doc_fba=None): """ Submodel for dynamically updating the metabolite count/concentration. This updates the ode model based on the FBA fluxes. """ doc = builder.template_doc_update("ecoli") model = doc.getModel() update_notes = notes.format(""" <h2>UPDATE submodel</h2> <p>Submodel for dynamically updating the metabolite count. This updates the ode model based on the FBA fluxes.</p> """) utils.set_model_info(model, notes=update_notes, creators=creators, units=units, main_units=main_units) # compartment compartment_id = "bioreactor" builder.create_dfba_compartment(model, compartment_id=compartment_id, unit_volume=UNIT_VOLUME, create_port=True) # dynamic species model_fba = doc_fba.getModel() # creates all the exchange reactions, biomass must be handeled separately builder.create_dfba_species(model, model_fba, compartment_id=compartment_id, unit_amount=UNIT_AMOUNT, create_port=True) # FIXME: biomass via function mc.create_objects(model, [ mc.Parameter(sid='cf_biomass', value=1.0, unit="g_per_mmol", name="biomass conversion factor", constant=True), mc.Species(sid='X', initialAmount=0.001, compartment='c', name='biomass', substanceUnit='g', hasOnlySubstanceUnits=True, conversionFactor='cf_biomass') ]) # update reactions # FIXME: weight with X (biomass) builder.create_update_reactions(model, model_fba=model_fba, formula="-{}", unit_flux=UNIT_FLUX, modifiers=[]) # write SBML file sbmlio.write_sbml(doc, filepath=pjoin(directory, sbml_file), validate=True)
def create_dfba_species(model, model_fba, compartment_id, hasOnlySubstanceUnits=False, unit_amount=None, create_port=True, exclude_sids=[]): """ Add DFBA species and compartments from fba model to model. Creates the dynamic species and respetive compartments with the necessary ports. This is used in the bounds submodel, update submodel and the and top model. :param model: :param model_fba: :return: """ objects = [] ex_rids = utils.find_exchange_reactions(model_fba) for ex_rid in ex_rids: r = model_fba.getReaction(ex_rid) sid = r.getReactant(0).getSpecies() if sid in exclude_sids: continue # exchange species s = model_fba.getSpecies(sid) objects.append( Species(sid=sid, name=s.getName(), initialConcentration=1.0, substanceUnit=unit_amount, hasOnlySubstanceUnits=hasOnlySubstanceUnits, compartment=compartment_id, port=create_port)) factory.create_objects(model, objects)
def create_dummy_reactions(model, model_fba, unit_flux=None): """ Creates the dummy reactions. This also creates the corresponding flux parameters and flux assignments. :param model: :param model_fba: :param unit_flux: :return: """ ex_rids = utils.find_exchange_reactions(model_fba) objects = [] for ex_rid, sid in ex_rids.items(): pid_flux = FLUX_PARAMETER_PREFIX + sid rid_flux = DUMMY_REACTION_PREFIX + sid objects = [ # flux parameter: flux from fba (rate of reaction) Parameter(sid=pid_flux, value=1.0, constant=True, unit=unit_flux, sboTerm=FLUX_PARAMETER_SBO), # dummy reaction (pseudoreaction) Reaction(sid=rid_flux, reversible=False, equation=" -> {}".format(DUMMY_SPECIES_ID), sboTerm=DUMMY_REACTION_SBO, formula=('0 {}'.format(unit_flux), unit_flux)), # flux assignment rule AssignmentRule(pid_flux, value=rid_flux, sboTerm=FLUX_ASSIGNMENTRULE_SBO), ] factory.create_objects(model, objects)
def create_exchange_bounds(model_bounds, model_fba, unit_flux=None, create_ports=True): """ Creates the exchange reaction flux bounds in the bounds model. :param model_bounds: the bounds model submodel :param model_fba: the fba submodel :param unit_flux: unit of fluxes :param create_ports: should ports be created. :return: """ ex_rids = utils.find_exchange_reactions(model_fba) objects = [] port_sids = [] for ex_rid, sid in ex_rids.items(): r = model_fba.getReaction(ex_rid) # lower & upper bound parameters r_fbc = r.getPlugin(SBML_FBC_NAME) lb_id = r_fbc.getLowerFluxBound() lb_value = model_fba.getParameter(lb_id).getValue() ub_id = r_fbc.getUpperFluxBound() ub_value = model_fba.getParameter(ub_id).getValue() # This creates the dynamical flux bound variables which are initialized with the # constant fba bounds objects.extend([ # for assignments fac.Parameter(sid=lb_id, value=lb_value, unit=unit_flux, constant=False, sboTerm=FLUX_BOUND_SBO), fac.Parameter(sid=ub_id, value=ub_value, unit=unit_flux, constant=False, sboTerm=FLUX_BOUND_SBO), ]) port_sids.extend([lb_id, ub_id]) # create bounds fac.create_objects(model_bounds, objects) # create ports if create_ports: comp.create_ports(model_bounds, idRefs=port_sids)
def create_update_reaction(model, sid, modifiers=None, formula="-{}"): """ Creates the update reaction for a given species. Creates the update parameter in the process. :param model: :param sid: :param modifiers: :param formula: :return: :rtype: """ if modifiers is None: modifiers = [] rid_update = UPDATE_REACTION_PREFIX + sid # format the formula formula = formula.format(FLUX_PARAMETER_PREFIX + sid) factory.create_objects(model, [ Reaction(sid=rid_update, sboTerm=UPDATE_REACTION_SBO, equation="{} -> {}".format(sid, modifiers), formula=(formula, None)) ])
def create_dummy_species(model, compartment_id, unit_amount=None, hasOnlySubstanceUnits=False): """ Creates the dummy species in the top model. Adds a deletion in the top model which removes the object again. :param model: SBML model :param compartment_id: compartment :param unit_amount: unit :param hasOnlySubstanceUnits: switch if amount or concentration :return: """ # dummy species for dummy reactions (empty set) objects = [ Species(sid=DUMMY_SPECIES_ID, name=DUMMY_SPECIES_ID, initialConcentration=0, substanceUnit=unit_amount, hasOnlySubstanceUnits=hasOnlySubstanceUnits, compartment=compartment_id, sboTerm=DUMMY_SPECIES_SBO), ] factory.create_objects(model, objects)
def create_update_parameter(model, sid, unit_flux): """ Creates the update parameter. The update parameter correspond to the flux parameters in the top model. :param model: :type model: :param sid: :type sid: :param unit_flux: :type unit_flux: :return: id of parameter :rtype: """ pid = FLUX_PARAMETER_PREFIX + sid factory.create_objects(model, [ Parameter(sid=pid, value=1.0, constant=True, unit=unit_flux, sboTerm=UPDATE_PARAMETER_SBO, port=True) ]) return pid
def create_dfba_compartment(model, compartment_id, unit_volume=None, create_port=True): """ Creates the main compartment for the dynamic species. :param model: :param compartment_id: id :param unit_volume: unit :param create_port: flag to create port :return: created libsbml.Compartment """ objects = [ fac.Compartment(sid=compartment_id, value=1.0, unit=unit_volume, constant=True, name=compartment_id, spatialDimensions=3), ] c = fac.create_objects(model, objects) if create_port: comp.create_ports(model, idRefs=[compartment_id]) return c
def create_dfba_compartment(model, compartment_id, unit_volume=None, create_port=True): """ Creates the main compartment for the dynamic species. :param model: :param compartment_id: id :param unit_volume: unit :param create_port: flag to create port :return: created libsbml.Compartment """ objects = [ Compartment(sid=compartment_id, value=1.0, unit=unit_volume, constant=True, name=compartment_id, spatialDimensions=3, port=create_port), ] sbml_objects = factory.create_objects(model, objects) return next(iter(sbml_objects.values()))
def update_exchange_reactions(model, flux_unit): """ Updates existing exchange reaction in FBA model. Sets all the necessary information and checks that correct. This is mainly used to prepare the exchange reactions of metabolites. :param flux_unit: :param model: :return: """ # mapping of bounds to reactions bounds_dict = dict() ex_rids = utils.find_exchange_reactions(model) for ex_rid in ex_rids: r = model.getReaction(ex_rid) # make reversible if not r.getReversible(): r.setReversible(True) logging.info("Exchange reaction set reversible: {}".format(r.getId())) # fix ids for exchange reactions sref = r.getReactant(0) sid = sref.getSpecies() rid = r.getId() if rid != EXCHANGE_REACTION_PREFIX + sid: r.setId(EXCHANGE_REACTION_PREFIX + sid) logging.warning("Exchange reaction fixd id: {} -> {}".format(rid, EXCHANGE_REACTION_PREFIX + sid)) # new lookup necessary, due to possible changed ids ex_rids = utils.find_exchange_reactions(model) for ex_rid in ex_rids: r = model.getReaction(ex_rid) fbc_r = r.getPlugin(SBML_FBC_NAME) # store bounds in dictionary for value lookup for f_bound in ["getLowerFluxBound", "getUpperFluxBound"]: bound_id = getattr(fbc_r, f_bound).__call__() bound = model.getParameter(bound_id) bounds_dict[bound_id] = bound.getValue() # create unique bounds for exchange reactions for ex_rid in ex_rids: r = model.getReaction(ex_rid) fbc_r = r.getPlugin(SBML_FBC_NAME) lb_value = model.getParameter(fbc_r.getLowerFluxBound()).getValue() ub_value = model.getParameter(fbc_r.getUpperFluxBound()).getValue() lb_id = LOWER_BOUND_PREFIX + ex_rid ub_id = UPPER_BOUND_PREFIX + ex_rid parameters = [ fac.Parameter(sid=lb_id, value=lb_value, unit=flux_unit, constant=True, sboTerm=FLUX_BOUND_SBO), fac.Parameter(sid=ub_id, value=ub_value, unit=flux_unit, constant=True, sboTerm=FLUX_BOUND_SBO), ] fac.create_objects(model, parameters) # set bounds fbc.set_flux_bounds(r, lb=lb_id, ub=ub_id) # create ports for bounds and reaction comp.create_ports(model, portType=comp.PORT_TYPE_PORT, idRefs=[ex_rid, lb_id, ub_id]) # check all the exchange reactions for ex_rid in ex_rids: check_exchange_reaction(model, ex_rid)
def fba_model(sbml_file, directory, annotations=None): """ FBA model :param sbml_file: output file name :param directory: output directory :return: SBMLDocument """ fba_notes = notes.format(""" <h2>FBA submodel</h2> <p>DFBA fba submodel. Unbalanced metabolites are encoded via exchange fluxes.</p> """) doc = builder.template_doc_fba(settings.MODEL_ID) model = doc.getModel() utils.set_model_info(model, notes=fba_notes, creators=creators, units=units, main_units=main_units) objects = [ # compartments mc.Compartment(sid='cell', value=1.0, unit=UNIT_VOLUME, constant=True, name='cell', spatialDimensions=3), # exchange species mc.Species(sid='atp', name="ATP", initialConcentration=0, substanceUnit=UNIT_AMOUNT, hasOnlySubstanceUnits=False, compartment="cell"), mc.Species(sid='adp', name="ADP", initialConcentration=0, substanceUnit=UNIT_AMOUNT, hasOnlySubstanceUnits=False, compartment="cell"), mc.Species(sid='glc', name="Glucose", initialConcentration=0, substanceUnit=UNIT_AMOUNT, hasOnlySubstanceUnits=False, compartment="cell"), mc.Species(sid='pyr', name='Pyruvate', initialConcentration=0, substanceUnit=UNIT_AMOUNT, hasOnlySubstanceUnits=False, compartment="cell"), # internal species mc.Species(sid='fru16bp', name='Fructose 1,6-bisphospate', initialConcentration=0, substanceUnit=UNIT_AMOUNT, hasOnlySubstanceUnits=False, compartment="cell"), mc.Species(sid='pg2', name='2-Phosphoglycerate', initialConcentration=0, substanceUnit=UNIT_AMOUNT, hasOnlySubstanceUnits=False, compartment="cell"), # bounds mc.Parameter(sid="ub_R3", value=1.0, unit=UNIT_FLUX, constant=True, sboTerm=builder.FLUX_BOUND_SBO), mc.Parameter(sid="zero", value=0.0, unit=UNIT_FLUX, constant=True, sboTerm=builder.FLUX_BOUND_SBO), mc.Parameter(sid="ub_default", value=builder.UPPER_BOUND_DEFAULT, unit=UNIT_FLUX, constant=True, sboTerm=builder.FLUX_BOUND_SBO), ] mc.create_objects(model, objects) # reactions r1 = mc.create_reaction(model, rid="R1", name="glu + 2 atp -> fru16bp + 2 adp", fast=False, reversible=False, reactants={ "glc": 1, "atp": 2 }, products={ "fru16bp": 1, 'adp': 2 }, compartment='cell') r2 = mc.create_reaction(model, rid="R2", name="fru16bp -> 2 pg2", fast=False, reversible=False, reactants={"fru16bp": 1}, products={"pg2": 2}, compartment='cell') r3 = mc.create_reaction(model, rid="R3", name="pg2 + adp -> pyr + atp", fast=False, reversible=False, reactants={ "pg2": 1, "adp": 2 }, products={ "pyr": 1, "atp": 2 }, compartment='cell') # flux bounds fbc.set_flux_bounds(r1, lb="zero", ub="ub_default") fbc.set_flux_bounds(r2, lb="zero", ub="ub_default") fbc.set_flux_bounds(r3, lb="zero", ub="ub_R3") # fbc.set_flux_bounds(ratp, lb="zero", ub="ub_RATP") # exchange reactions for sid in ['atp', 'adp', 'glc', 'pyr']: builder.create_exchange_reaction(model, species_id=sid, flux_unit=UNIT_FLUX) # objective function model_fbc = model.getPlugin("fbc") fbc.create_objective(model_fbc, oid="RATP_maximize", otype="maximize", fluxObjectives={"R3": 1.0}, active=True) if annotations: annotator.annotate_sbml_doc(doc, annotations) # write SBML sbmlio.write_sbml(doc, filepath=os.path.join(directory, sbml_file), validate=True) return doc
def top_model(sbml_file, directory, emds, doc_fba, annotations=None): """ Create top comp model. Creates full comp model by combining fba, update and bounds model with additional kinetics in the top model. """ top_notes = notes.format(""" <h2>TOP model</h2> <p>Main comp DFBA model by combining fba, update and bounds model with additional kinetics in the top model.</p> """) working_dir = os.getcwd() os.chdir(directory) doc = builder.template_doc_top(settings.MODEL_ID, emds) model = doc.getModel() utils.set_model_info(model, notes=top_notes, creators=creators, units=units, main_units=main_units) # dt builder.create_dfba_dt(model, step_size=DT_SIM, time_unit=UNIT_TIME, create_port=False) # compartment compartment_id = "extern" builder.create_dfba_compartment(model, compartment_id=compartment_id, unit_volume=UNIT_VOLUME, create_port=False) # dynamic species model_fba = doc_fba.getModel() builder.create_dfba_species(model, model_fba, compartment_id=compartment_id, hasOnlySubstanceUnits=True, unit_amount=UNIT_AMOUNT, create_port=False) # dummy species builder.create_dummy_species(model, compartment_id=compartment_id, hasOnlySubstanceUnits=True, unit_amount=UNIT_AMOUNT) # exchange flux bounds builder.create_exchange_bounds(model, model_fba=model_fba, unit_flux=UNIT_FLUX, create_ports=False) # dummy reactions & flux assignments builder.create_dummy_reactions(model, model_fba=model_fba, unit_flux=UNIT_FLUX) # replacedBy (fba reactions) builder.create_top_replacedBy(model, model_fba=model_fba) # replaced builder.create_top_replacements(model, model_fba, compartment_id=compartment_id) # initial concentrations for fba exchange species initial_c = { 'A': 10.0, 'C': 0.0, } for sid, value in initial_c.items(): species = model.getSpecies(sid) species.setInitialConcentration(value) # kinetic model mc.create_objects(model, [ # kinetic species mc.Species(sid='D', initialConcentration=0, substanceUnit=UNIT_AMOUNT, hasOnlySubstanceUnits=True, compartment="extern"), # kinetic mc.Parameter(sid="k_R4", value=0.1, constant=True, unit="per_s", sboTerm="SBO:0000009"), # bounds parameter mc.Parameter(sid='ub_R1', value=1.0, unit=UNIT_FLUX, constant=False, sboTerm="SBO:0000625"), ]) # kinetic reaction (MMK) mc.create_reaction(model, rid="R4", name="R4: C -> D", fast=False, reversible=False, reactants={"C": 1}, products={"D": 1}, formula="k_R4*C", compartment="extern") # kinetic flux bounds comp.replace_elements(model, 'ub_R1', ref_type=comp.SBASE_REF_TYPE_PORT, replaced_elements={'bounds': ['ub_R1_port'], 'fba': ['ub_R1_port']}) # write SBML file if annotations: annotation.annotate_sbml_doc(doc, annotations) sbmlio.write_sbml(doc, filepath=os.path.join(directory, sbml_file), validate=True) # change back the working dir os.chdir(working_dir)
def bounds_model(sbml_file, directory, doc_fba=None, annotations=None): """" Submodel for dynamically calculating the flux bounds. The dynamically changing flux bounds are the input to the FBA model. """ # TODO: the bounds model should be created based on the FBA model (i.e. use the exchange reactions # to create the bounds info. bounds_notes = notes.format(""" <h2>BOUNDS submodel</h2> <p>Submodel for dynamically calculating the flux bounds. The dynamically changing flux bounds are the input to the FBA model.</p> """) doc = builder.template_doc_bounds(settings.MODEL_ID) model = doc.getModel() utils.set_model_info(model, notes=bounds_notes, creators=creators, units=units, main_units=main_units) # dt compartment_id = "bioreactor" builder.create_dfba_dt(model, time_unit=UNIT_TIME, create_port=True) # compartment builder.create_dfba_compartment(model, compartment_id=compartment_id, unit_volume=UNIT_VOLUME, create_port=True) # dynamic species model_fba = doc_fba.getModel() builder.create_dfba_species(model, model_fba, compartment_id=compartment_id, unit_amount=UNIT_AMOUNT, create_port=True) # bounds builder.create_exchange_bounds(model, model_fba=model_fba, unit_flux=UNIT_FLUX, create_ports=True) # bounds fba_infix = "fba_" model_fba = doc_fba.getModel() objects = [] ex_rids = utils.find_exchange_reactions(model_fba) for ex_rid, sid in ex_rids.items(): r = model_fba.getReaction(ex_rid) # lower & upper bound parameters r_fbc = r.getPlugin(builder.SBML_FBC_NAME) lb_id = r_fbc.getLowerFluxBound() fba_lb_id = builder.LOWER_BOUND_PREFIX + fba_infix + ex_rid lb_value = model_fba.getParameter(lb_id).getValue() objects.extend([ # default bounds from fba mc.Parameter(sid=fba_lb_id, value=lb_value, unit=UNIT_FLUX, constant=False), ]) mc.create_objects(model, objects) objects = [ # kinetic lower bounds mc.Parameter(sid="lb_kin_EX_Glcxt", value=builder.LOWER_BOUND_DEFAULT, unit=UNIT_FLUX, constant=False, sboTerm="SBO:0000612"), mc.Parameter(sid="lb_kin_EX_O2", value=builder.LOWER_BOUND_DEFAULT, unit=UNIT_FLUX, constant=False, sboTerm="SBO:0000612"), # parameters for kinetic bounds mc.Parameter(sid='Vmax_EX_O2', value=15, unit=UNIT_FLUX, constant=True), mc.Parameter(sid='Vmax_EX_Glcxt', value=10, unit=UNIT_FLUX, constant=True), mc.Parameter(sid='Km_EX_Glcxt', value=0.015, unit=UNIT_CONCENTRATION, name="Km_vGlcxt", constant=True), # kinetic bounds (unintuitive direction due to the identical concentrations in bioreactor and model) mc.AssignmentRule(sid="lb_kin_EX_Glcxt", value="-Vmax_EX_Glcxt * Glcxt/(Km_EX_Glcxt + Glcxt)"), mc.AssignmentRule(sid="lb_kin_EX_O2", value="-Vmax_EX_O2"), # exchange reaction bounds # uptake bounds (lower bound) # TODO: FIXME the X hack # the bounds for the fba model have to be in mmol/h/gdw mc.AssignmentRule(sid="lb_EX_Ac", value="max(lb_fba_EX_Ac, -Ac/X/1 l_per_mmol*bioreactor/dt)"), mc.AssignmentRule(sid="lb_EX_X", value="max(lb_fba_EX_X, -X/X/1 l_per_mmol*bioreactor/dt)"), mc.AssignmentRule(sid="lb_EX_Glcxt", value="max(lb_kin_EX_Glcxt, -Glcxt/X/1 l_per_mmol*bioreactor/dt)"), mc.AssignmentRule(sid="lb_EX_O2", value="max(lb_kin_EX_O2, -O2/X/1 l_per_mmol*bioreactor/dt)"), ] mc.create_objects(model, objects) if annotations: annotation.annotate_sbml_doc(doc, annotations) sbmlio.write_sbml(doc, filepath=pjoin(directory, sbml_file), validate=True)
def fba_model(sbml_file, directory, annotations=None): """ FBA model :param sbml_file: output file name :param directory: output directory :return: SBMLDocument """ fba_notes = notes.format(""" <h2>FBA submodel</h2> <p>DFBA fba submodel. Unbalanced metabolites are encoded via exchange fluxes.</p> """) doc = builder.template_doc_fba(settings.MODEL_ID) model = doc.getModel() utils.set_model_info(model, notes=fba_notes, creators=creators, units=units, main_units=main_units) objects = [ # compartments mc.Compartment(sid='extern', value=1.0, unit=UNIT_VOLUME, constant=True, name='external compartment', spatialDimensions=3), mc.Compartment(sid='cell', value=1.0, unit=UNIT_VOLUME, constant=True, name='cell', spatialDimensions=3), mc.Compartment(sid='membrane', value=1.0, unit=UNIT_AREA, constant=True, name='membrane', spatialDimensions=2), # exchange species mc.Species(sid='A', name="A", initialConcentration=0, substanceUnit=UNIT_AMOUNT, hasOnlySubstanceUnits=True, compartment="extern"), mc.Species(sid='C', name="C", initialConcentration=0, substanceUnit=UNIT_AMOUNT, hasOnlySubstanceUnits=True, compartment="extern"), # internal species mc.Species(sid='B1', name="B1", initialConcentration=0, substanceUnit=UNIT_AMOUNT, hasOnlySubstanceUnits=True, compartment="cell"), mc.Species(sid='B2', name="B2", initialConcentration=0, substanceUnit=UNIT_AMOUNT, hasOnlySubstanceUnits=True, compartment="cell"), # bounds mc.Parameter(sid="ub_R1", value=1.0, unit=UNIT_FLUX, constant=True, sboTerm=builder.FLUX_BOUND_SBO), mc.Parameter(sid="zero", value=0.0, unit=UNIT_FLUX, constant=True, sboTerm=builder.FLUX_BOUND_SBO), mc.Parameter(sid="ub_default", value=builder.UPPER_BOUND_DEFAULT, unit=UNIT_FLUX, constant=True, sboTerm=builder.FLUX_BOUND_SBO), ] mc.create_objects(model, objects) # reactions r1 = mc.create_reaction(model, rid="R1", name="A import (R1)", fast=False, reversible=True, reactants={"A": 1}, products={"B1": 1}, compartment='membrane') r2 = mc.create_reaction(model, rid="R2", name="B1 <-> B2 (R2)", fast=False, reversible=True, reactants={"B1": 1}, products={"B2": 1}, compartment='cell') r3 = mc.create_reaction(model, rid="R3", name="B2 export (R3)", fast=False, reversible=True, reactants={"B2": 1}, products={"C": 1}, compartment='membrane') # flux bounds fbc.set_flux_bounds(r1, lb="zero", ub="ub_R1") fbc.set_flux_bounds(r2, lb="zero", ub="ub_default") fbc.set_flux_bounds(r3, lb="zero", ub="ub_default") # exchange reactions builder.create_exchange_reaction(model, species_id="A", flux_unit=UNIT_FLUX) builder.create_exchange_reaction(model, species_id="C", flux_unit=UNIT_FLUX) # objective function model_fbc = model.getPlugin("fbc") fbc.create_objective(model_fbc, oid="R3_maximize", otype="maximize", fluxObjectives={"R3": 1.0}, active=True) # create ports for kinetic bounds comp.create_ports(model, portType=comp.PORT_TYPE_PORT, idRefs=["ub_R1"]) # write SBML if annotations: annotator.annotate_sbml_doc(doc, annotations) sbml.write_sbml(doc, filepath=os.path.join(directory, sbml_file), validate=True) return doc
def update_exchange_reactions(model, flux_unit): """ Updates existing exchange reaction in FBA model. Sets all the necessary information and checks that correct. This is mainly used to prepare the exchange reactions of metabolites. :param flux_unit: :param model: :return: """ # mapping of bounds to reactions bounds_dict = dict() ex_rids = utils.find_exchange_reactions(model) for ex_rid in ex_rids: r = model.getReaction(ex_rid) # make reversible if not r.getReversible(): r.setReversible(True) logging.info("Exchange reaction set reversible: {}".format( r.getId())) # fix ids for exchange reactions sref = r.getReactant(0) sid = sref.getSpecies() rid = r.getId() if rid != EXCHANGE_REACTION_PREFIX + sid: r.setId(EXCHANGE_REACTION_PREFIX + sid) logging.warning("Exchange reaction fixd id: {} -> {}".format( rid, EXCHANGE_REACTION_PREFIX + sid)) # new lookup necessary, due to possible changed ids ex_rids = utils.find_exchange_reactions(model) for ex_rid in ex_rids: r = model.getReaction(ex_rid) fbc_r = r.getPlugin(SBML_FBC_NAME) # store bounds in dictionary for value lookup for f_bound in ["getLowerFluxBound", "getUpperFluxBound"]: bound_id = getattr(fbc_r, f_bound).__call__() bound = model.getParameter(bound_id) bounds_dict[bound_id] = bound.getValue() # create unique bounds for exchange reactions for ex_rid in ex_rids: r = model.getReaction(ex_rid) fbc_r = r.getPlugin(SBML_FBC_NAME) lb_value = model.getParameter(fbc_r.getLowerFluxBound()).getValue() ub_value = model.getParameter(fbc_r.getUpperFluxBound()).getValue() lb_id = LOWER_BOUND_PREFIX + ex_rid ub_id = UPPER_BOUND_PREFIX + ex_rid parameters = [ Parameter(sid=lb_id, value=lb_value, unit=flux_unit, constant=True, sboTerm=FLUX_BOUND_SBO), Parameter(sid=ub_id, value=ub_value, unit=flux_unit, constant=True, sboTerm=FLUX_BOUND_SBO), ] factory.create_objects(model, parameters) # set bounds fbc.set_flux_bounds(r, lb=lb_id, ub=ub_id) # create ports for bounds and reaction comp.create_ports(model, portType=comp.PORT_TYPE_PORT, idRefs=[ex_rid, lb_id, ub_id]) # check all the exchange reactions for ex_rid in ex_rids: check_exchange_reaction(model, ex_rid)
def top_model(sbml_file, directory, emds, doc_fba=None, annotations=None): """ Create diauxic comp model. Test script for working with the comp extension in SBML. One model composition combines all the kinetic models, in addition the higher level comp model is created which combines everything (i.e. the FBA & ODE models). For the simulation of the full combined model the tools have to figure out the subparts which are simulated with which simulation environment. Creates the full comp model as combination of FBA and comp models. The submodels must already exist in the given directory """ top_notes = notes.format(""" <h2>TOP model</h2> <p>Main comp DFBA model by combining fba, update and bounds model with additional kinetics in the top model.</p> """) # Necessary to change into directory with submodel files working_dir = os.getcwd() os.chdir(directory) doc = builder.template_doc_top(settings.MODEL_ID, emds) model = doc.getModel() utils.set_model_info(model, notes=top_notes, creators=creators, units=units, main_units=main_units) # dt builder.create_dfba_dt(model, time_unit=UNIT_TIME, create_port=False) # compartment compartment_id = "bioreactor" builder.create_dfba_compartment(model, compartment_id=compartment_id, unit_volume=UNIT_VOLUME, create_port=False) # dynamic species model_fba = doc_fba.getModel() builder.create_dfba_species(model, model_fba, compartment_id=compartment_id, unit_amount=UNIT_AMOUNT, create_port=False) # dummy species builder.create_dummy_species(model, compartment_id=compartment_id, unit_amount=UNIT_AMOUNT) # exchange flux bounds builder.create_exchange_bounds(model, model_fba=model_fba, unit_flux=UNIT_FLUX, create_ports=False) # dummy reactions & flux assignments builder.create_dummy_reactions(model, model_fba=model_fba, unit_flux=UNIT_FLUX) # replacedBy (fba reactions) builder.create_top_replacedBy(model, model_fba=model_fba) # replaced builder.create_top_replacements(model, model_fba, compartment_id=compartment_id) # initial kinetic concentrations initial_c = { 'Glcxt': 10.8, 'Ac': 0.4, 'O2': 0.21, 'X': 0.001, } for sid, value in initial_c.items(): species = model.getSpecies(sid) species.setInitialConcentration(value) objects = [ # biomass conversion factor # mc.Parameter(sid="Y", name="biomass [g_per_l]", value=1.0, unit="g_per_l"), # oxygen exchange parameters mc.Parameter(sid="O2_ref", name="O2 reference", value=0.21, unit=UNIT_CONCENTRATION), mc.Parameter(sid="kLa", name="O2 mass transfer", value=7.5, unit='per_h'), ] mc.create_objects(model, objects) # oxygen transfer reaction mc.create_reaction(model, rid="vO2_transfer", name="oxygen transfer", reversible=True, reactants={}, products={"O2": 1}, formula="kLa * (O2_ref-O2) * bioreactor", compartment="bioreactor") # write SBML file if annotations: annotation.annotate_sbml_doc(doc, annotations) sbmlio.write_sbml(doc, filepath=os.path.join(directory, sbml_file), validate=True) # change back into working dir os.chdir(working_dir)
def fba_model(sbml_file, directory, annotations=None): """ FBA model :param sbml_file: output file name :param directory: output directory :return: SBMLDocument """ fba_notes = notes.format(""" <h2>FBA submodel</h2> <p>DFBA fba submodel. Unbalanced metabolites are encoded via exchange fluxes.</p> """) doc = builder.template_doc_fba(settings.MODEL_ID) model = doc.getModel() utils.set_model_info(model, notes=fba_notes, creators=creators, units=units, main_units=main_units) objects = [ # compartments mc.Compartment(sid='extern', value=1.0, unit=UNIT_VOLUME, constant=True, name='external compartment', spatialDimensions=3), mc.Compartment(sid='cell', value=1.0, unit=UNIT_VOLUME, constant=True, name='cell', spatialDimensions=3), mc.Compartment(sid='membrane', value=1.0, unit=UNIT_AREA, constant=True, name='membrane', spatialDimensions=2), # exchange species mc.Species(sid='A', name="A", initialConcentration=0, substanceUnit=UNIT_AMOUNT, hasOnlySubstanceUnits=True, compartment="extern"), mc.Species(sid='C', name="C", initialConcentration=0, substanceUnit=UNIT_AMOUNT, hasOnlySubstanceUnits=True, compartment="extern"), # internal species mc.Species(sid='B1', name="B1", initialConcentration=0, substanceUnit=UNIT_AMOUNT, hasOnlySubstanceUnits=True, compartment="cell"), mc.Species(sid='B2', name="B2", initialConcentration=0, substanceUnit=UNIT_AMOUNT, hasOnlySubstanceUnits=True, compartment="cell"), # bounds mc.Parameter(sid="ub_R1", value=1.0, unit=UNIT_FLUX, constant=True, sboTerm=builder.FLUX_BOUND_SBO), mc.Parameter(sid="zero", value=0.0, unit=UNIT_FLUX, constant=True, sboTerm=builder.FLUX_BOUND_SBO), mc.Parameter(sid="ub_default", value=builder.UPPER_BOUND_DEFAULT, unit=UNIT_FLUX, constant=True, sboTerm=builder.FLUX_BOUND_SBO), ] mc.create_objects(model, objects) # reactions r1 = mc.create_reaction(model, rid="R1", name="A import (R1)", fast=False, reversible=True, reactants={"A": 1}, products={"B1": 1}, compartment='membrane') r2 = mc.create_reaction(model, rid="R2", name="B1 <-> B2 (R2)", fast=False, reversible=True, reactants={"B1": 1}, products={"B2": 1}, compartment='cell') r3 = mc.create_reaction(model, rid="R3", name="B2 export (R3)", fast=False, reversible=True, reactants={"B2": 1}, products={"C": 1}, compartment='membrane') # flux bounds fbc.set_flux_bounds(r1, lb="zero", ub="ub_R1") fbc.set_flux_bounds(r2, lb="zero", ub="ub_default") fbc.set_flux_bounds(r3, lb="zero", ub="ub_default") # exchange reactions builder.create_exchange_reaction(model, species_id="A", flux_unit=UNIT_FLUX) builder.create_exchange_reaction(model, species_id="C", flux_unit=UNIT_FLUX) # objective function model_fbc = model.getPlugin("fbc") fbc.create_objective(model_fbc, oid="R3_maximize", otype="maximize", fluxObjectives={"R3": 1.0}, active=True) # create ports for kinetic bounds comp.create_ports(model, portType=comp.PORT_TYPE_PORT, idRefs=["ub_R1"]) # write SBML if annotations: annotation.annotate_sbml_doc(doc, annotations) sbmlio.write_sbml(doc, filepath=os.path.join(directory, sbml_file), validate=True) return doc
def fba_model(sbml_file, directory): """ Create FBA submodel. """ # Read the model fba_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'data/ecoli_fba.xml') doc_fba = sbmlio.read_sbml(fba_path) # add comp doc_fba.enablePackage("http://www.sbml.org/sbml/level3/version1/comp/version1", "comp", True) doc_fba.setPackageRequired("comp", True) # add notes model = doc_fba.getModel() fba_notes = notes.format("""DFBA FBA submodel.""") utils.set_model_info(model, notes=fba_notes, creators=None, units=units, main_units=main_units) # clip R_ reaction and M_ metabolite prefixes utils.clip_prefixes_in_model(model) # set id & framework model.setId('ecoli_fba') model.setName('ecoli (FBA)') model.setSBOTerm(comp.SBO_FLUX_BALANCE_FRAMEWORK) # add units and information for species in model.getListOfSpecies(): species.setInitialConcentration(0.0) species.setHasOnlySubstanceUnits(False) species.setUnits(UNIT_AMOUNT) for compartment in model.getListOfCompartments(): compartment.setUnits(UNIT_VOLUME) # The ATPM (atp maintainance reactions creates many problems in the DFBA) # mainly resulting in infeasible solutions when some metabolites run out. # ATP -> ADP is part of the biomass, so we set the lower bound to zero r_ATPM = model.getReaction('ATPM') r_ATPM_fbc = r_ATPM.getPlugin(builder.SBML_FBC_NAME) lb_id = r_ATPM_fbc.getLowerFluxBound() model.getParameter(lb_id).setValue(0.0) # 8.39 before # make unique upper and lower bounds for exchange reaction if not biomass_weighting: builder.update_exchange_reactions(model=model, flux_unit=UNIT_FLUX) else: builder.update_exchange_reactions(model=model, flux_unit=UNIT_FLUX_PER_G) # add exchange reaction for biomass (X) # we are adding the biomass component to the biomass function and create an # exchange reaction for it r_biomass = model.getReaction('BIOMASS_Ecoli_core_w_GAM') # FIXME: refactor in function # FIXME: annotate biomass species (SBO for biomass missing) mc.create_objects(model, [ mc.Parameter(sid='cf_X', value=1.0, unit="g_per_mmol", name="biomass conversion factor", constant=True), mc.Species(sid='X', initialAmount=0.001, compartment='c', name='biomass', substanceUnit='g', hasOnlySubstanceUnits=True, conversionFactor='cf_X') ]) pr_biomass = r_biomass.createProduct() pr_biomass.setSpecies('X') pr_biomass.setStoichiometry(1.0) pr_biomass.setConstant(True) # FIXME: the flux units must fit to the species units. if not biomass_weighting: builder.create_exchange_reaction(model, species_id='X', flux_unit=UNIT_FLUX, exchange_type=builder.EXCHANGE_EXPORT) else: builder.create_exchange_reaction(model, species_id='X', flux_unit=UNIT_FLUX_PER_G, exchange_type=builder.EXCHANGE_EXPORT) # write SBML file sbmlio.write_sbml(doc_fba, filepath=pjoin(directory, sbml_file), validate=True) # Set kinetic laws to zero for kinetic simulation ''' for reaction in model.getListOfReactions(): ast_node = mc.ast_node_from_formula(model=model, formula='0 {}'.format(UNIT_FLUX)) law = reaction.createKineticLaw() law.setMath(ast_node) ''' return doc_fba
def top_model(sbml_file, directory, emds, doc_fba=None, annotations=None): """ Create diauxic comp model. Test script for working with the comp extension in SBML. One model composition combines all the kinetic models, in addition the higher level comp model is created which combines everything (i.e. the FBA & ODE models). For the simulation of the full combined model the tools have to figure out the subparts which are simulated with which simulation environment. Creates the full comp model as combination of FBA and comp models. The submodels must already exist in the given directory """ top_notes = notes.format(""" <h2>TOP model</h2> <p>Main comp DFBA model by combining fba, update and bounds model with additional kinetics in the top model.</p> """) # Necessary to change into directory with submodel files working_dir = os.getcwd() os.chdir(directory) doc = builder.template_doc_top(settings.MODEL_ID, emds) model = doc.getModel() utils.set_model_info(model, notes=top_notes, creators=creators, units=units, main_units=main_units) # dt builder.create_dfba_dt(model, time_unit=UNIT_TIME, create_port=False) # compartment compartment_id = "bioreactor" builder.create_dfba_compartment(model, compartment_id=compartment_id, unit_volume=UNIT_VOLUME, create_port=False) # dynamic species model_fba = doc_fba.getModel() builder.create_dfba_species(model, model_fba, compartment_id=compartment_id, unit_amount=UNIT_AMOUNT, create_port=False) # dummy species builder.create_dummy_species(model, compartment_id=compartment_id, unit_amount=UNIT_AMOUNT) # exchange flux bounds builder.create_exchange_bounds(model, model_fba=model_fba, unit_flux=UNIT_FLUX, create_ports=False) # dummy reactions & flux assignments builder.create_dummy_reactions(model, model_fba=model_fba, unit_flux=UNIT_FLUX) # replacedBy (fba reactions) builder.create_top_replacedBy(model, model_fba=model_fba) # replaced builder.create_top_replacements(model, model_fba, compartment_id=compartment_id) # initial kinetic concentrations initial_c = { 'Glcxt': 10.8, 'Ac': 0.4, 'O2': 0.21, 'X': 0.001, } for sid, value in initial_c.items(): species = model.getSpecies(sid) species.setInitialConcentration(value) objects = [ # biomass conversion factor # Parameter(sid="Y", name="biomass [g_per_l]", value=1.0, unit="g_per_l"), # oxygen exchange parameters Parameter(sid="O2_ref", name="O2 reference", value=0.21, unit=UNIT_CONCENTRATION), Parameter(sid="kLa", name="O2 mass transfer", value=7.5, unit='per_h'), ] factory.create_objects(model, objects) # oxygen transfer reaction create_reaction(model, rid="vO2_transfer", name="oxygen transfer", reversible=True, reactants={}, products={"O2": 1}, formula="kLa * (O2_ref-O2) * bioreactor", compartment="bioreactor") # write SBML file if annotations: annotator.annotate_sbml_doc(doc, annotations) sbmlio.write_sbml(doc, filepath=os.path.join(directory, sbml_file), validate=True) # change back into working dir os.chdir(working_dir)
def xpp2sbml( xpp_file: Path, sbml_file: Path, force_lower: bool = False, validate: bool = True, debug: bool = False, ): """Reads given xpp_file and converts to SBML file. :param xpp_file: xpp input ode file :param sbml_file: sbml output file :param force_lower: force lower case for all lines :param validate: perform validation on the generated SBML file :return: """ print("-" * 80) print("xpp2sbml: ", xpp_file, "->", sbml_file) print("-" * 80) doc = libsbml.SBMLDocument(3, 1) model = doc.createModel() parameters = [] initial_assignments = [] rate_rules = [] assignment_rules = [] functions = [ # definition of min and max fac.Function("max", "lambda(x,y, piecewise(x,gt(x,y),y) )", name="minimum"), fac.Function("min", "lambda(x,y, piecewise(x,lt(x,y),y) )", name="maximum"), # heav (heavyside) fac.Function( "heav", "lambda(x, piecewise(0,lt(x,0), 0.5, eq(x, 0), 1,gt(x,0), 0))", name="heavyside", ), # mod (modulo) fac.Function("mod", "lambda(x,y, x % y)", name="modulo"), ] function_definitions = [] events = [] def replace_fdef(): """ Replace all arguments within the formula definitions.""" changes = False for k, fdata in enumerate(function_definitions): for i in range(len(function_definitions)): if i != k: # replace i with k formula = function_definitions[i]["formula"] new_formula = xpp_helpers.replace_formula( formula, fid=function_definitions[k]["fid"], old_args=function_definitions[k]["old_args"], new_args=function_definitions[k]["new_args"], ) if new_formula != formula: function_definitions[i]["formula"] = new_formula function_definitions[i]["new_args"] = list( sorted( set(function_definitions[i]["new_args"] + function_definitions[k]["new_args"]))) changes = True return changes def create_initial_assignment(sid, value): """ Helper for creating initial assignments """ # check if valid identifier if "(" in sid: warnings.warn( "sid is not valid: {}. Initial assignment is not generated". format(sid)) return try: f_value = float(value) parameters.append( fac.Parameter( sid=sid, value=f_value, name="{} = {}".format(sid, value), constant=False, )) except ValueError: """ Initial data are optional, XPP sets them to zero by default (many xpp model don't write the p(0)=0. """ parameters.append( fac.Parameter(sid=sid, value=0.0, name=sid, constant=False)) initial_assignments.append( fac.InitialAssignment(sid=sid, value=value, name="{} = {}".format(sid, value))) ########################################################################### # First iteration to parse relevant lines and get the replacement patterns ########################################################################### parsed_lines = [] # with open(xpp_file, encoding="utf-8") as f: with open(xpp_file) as f: lines = f.readlines() # add info to sbml text = escape_string("".join(lines)) fac.set_notes(model, NOTES.format(text)) old_line = None for line in lines: if force_lower: line = line.lower() # clean up the ends line = line.rstrip("\n").strip() # handle douple continuation characters in some models line = line.replace("\\\\", "\\") # handle semicolons line = line.rstrip(";") # join continuation if old_line: line = old_line + line old_line = None # empty line if len(line) == 0: continue # comment line if line[0] in XPP_COMMENT_CHARS: continue # xpp setting if line.startswith(XPP_SETTING_CHAR): continue # end word if line == XPP_END_WORD: continue # line continuation if line.endswith(XPP_CONTINUATION_CHAR): old_line = line.rstrip(XPP_CONTINUATION_CHAR) continue # handle the power function line = line.replace("**", "^") # handle if(...)then(...)else() pattern_ite = re.compile( r"if\s*\((.*)\)\s*then\s*\((.*)\)\s*else\s*\((.*)\)") pattern_ite_sub = re.compile( r"if\s*\(.*\)\s*then\s*\(.*\)\s*else\s*\(.*\)") groups = re.findall(pattern_ite, line) for group in groups: condition = group[0] assignment = group[1] otherwise = group[2] f_piecewise = "piecewise({}, {}, {})".format( assignment, condition, otherwise) line = re.sub(pattern_ite_sub, f_piecewise, line) ################################ # Function definitions ################################ """ Functions are defined in xpp via fid(arguments) = formula f(x,y) = x^2/(x^2+y^2) They can have up to 9 arguments. The difference to SBML functions is that xpp functions have access to the global parameter values """ f_pattern = re.compile(r"(.*)\s*\((.*)\)\s*=\s*(.*)") groups = re.findall(f_pattern, line) if groups: # function definitions found fid, args, formula = groups[0] # handles the initial assignments which look like function definitions if args == "0": parsed_lines.append(line) continue # necessary to find the additional arguments from the ast_node ast = libsbml.parseL3Formula(formula) names = set(xpp_helpers.find_names_in_ast(ast)) old_args = [t.strip() for t in args.split(",")] new_args = [a for a in names if a not in old_args] # handle special functions if fid == "power": warnings.warn( "power function cannot be added to model, rename function." ) else: # store functions with additional arguments function_definitions.append({ "fid": fid, "old_args": old_args, "new_args": new_args, "formula": formula, }) # don't append line, function definition has been handeled continue parsed_lines.append(line) if debug: print("\n\nFUNCTION_DEFINITIONS") pprint(function_definitions) # functions can use functions so this also must be replaced changes = True while changes: changes = replace_fdef() # clean the new arguments for fdata in function_definitions: fdata["new_args"] = list(sorted(set(fdata["new_args"]))) if debug: print("\nREPLACED FUNCTION_DEFINITIONS") pprint(function_definitions) # Create function definitions for k, fdata in enumerate(function_definitions): fid = fdata["fid"] formula = fdata["formula"] arguments = ",".join(fdata["old_args"] + fdata["new_args"]) functions.append( fac.Function(fid, "lambda({}, {})".format(arguments, formula)), ) ########################################################################### # Second iteration ########################################################################### if debug: print("\nPARSED LINES") pprint(parsed_lines) print("\n\n") for line in parsed_lines: # replace function definitions in lines new_line = line for fdata in function_definitions: new_line = xpp_helpers.replace_formula(new_line, fdata["fid"], fdata["old_args"], fdata["new_args"]) if new_line != line: if False: print("\nReplaced FD", fdata["fid"], ":", new_line) print("->", new_line, "\n") line = new_line if debug: # line after function replacements print("*" * 3, line, "*" * 3) ################################ # Start parsing the given line ################################ # check for the equal sign tokens = line.split("=") tokens = [t.strip() for t in tokens] ####################### # Line without '=' sign ####################### # wiener if len(tokens) == 1: items = [t.strip() for t in tokens[0].split(" ") if len(t) > 0] # keyword, value if len(items) == 2: xid, sid = items[0], items[1] xpp_type = parse_keyword(xid) # wiener if xpp_type == XPP_WIE: """Wiener parameters are normally distributed numbers with zero mean and unit standard deviation. They are useful in stochastic simulations since they automatically scale with change in the integration time step. Their names are listed separated by commas or spaces.""" # FIXME: this should be encoded using dist parameters.append(fac.Parameter(sid=sid, value=0.0)) continue # line finished else: warnings.warn("XPP line not parsed: '{}'".format(line)) ##################### # Line with '=' sign ##################### # parameter, aux, ode, initial assignments elif len(tokens) >= 2: left = tokens[0] items = [t.strip() for t in left.split(" ") if len(t) > 0] # keyword based information, i.e 2 items are on the left of the first '=' sign if len(items) == 2: xid = items[0] # xpp keyword xpp_type = parse_keyword(xid) expression = (" ".join(items[1:]) + "=" + "=".join(tokens[1:]) ) # full expression after keyword parts = parts_from_expression(expression) if False: print("xid:", xid) print("expression:", expression) print("parts:", parts) # parameter & numbers if xpp_type in [XPP_PAR, XPP_NUM]: """Parameter values are optional; if not they are set to zero. Number declarations are like parameter declarations, except that they cannot be changed within the program and do not appear in the parameter window.""" for part in parts: sid, value = sid_value_from_part(part) create_initial_assignment(sid, value) # aux elif xpp_type == XPP_AUX: """Auxiliary quantities are expressions that depend on all of your dynamic variables which you want to keep track of. Energy is one such example. They are declared like fixed quantities, but are prefaced by aux .""" for part in parts: sid, value = sid_value_from_part(part) if sid == value: # avoid circular dependencies (no information in statement) pass else: assignment_rules.append( fac.AssignmentRule(sid=sid, value=value)) # init elif xpp_type == XPP_INIT: for part in parts: sid, value = sid_value_from_part(part) create_initial_assignment(sid, value) # table elif xpp_type == XPP_TAB: """The Table declaration allows the user to specify a function of 1 variable in terms of a lookup table which uses linear interpolation. The name of the function follows the declaration and this is followed by (i) a filename (ii) or a function of "t".""" warnings.warn( "XPP_TAB not supported: XPP line not parsed: '{}'". format(line)) else: warnings.warn("XPP line not parsed: '{}'".format(line)) elif len(items) >= 2: xid = items[0] xpp_type = parse_keyword(xid) # global if xpp_type == XPP_GLO: """Global flags are expressions that signal events when they change sign, from less than to greater than zero if sign=1 , greater than to less than if sign=-1 or either way if sign=0. The condition should be delimited by braces {} The events are of the form variable=expression, are delimited by braces, and separated by semicolons. When the condition occurs all the variables in the event set are changed possibly discontinuously. """ # global sign {condition} {name1 = form1; ...} pattern_global = re.compile( r"([+,-]{0,1}\d{1})\s+\{{0,1}(.*)\{{0,1}\s+\{(.*)\}") groups = re.findall(pattern_global, line) if groups: g = groups[0] sign = int(g[0]) trigger = g[1] # FIXME: handle sign=-1, sign=0, sign=+1 if sign == -1: trigger = g[1] + ">= 0" elif sign == 1: trigger = g[1] + ">= 0" elif sign == 0: trigger = g[1] + ">= 0" assignment_parts = [t.strip() for t in g[2].split(";")] assignments = {} for p in assignment_parts: key, value = p.split("=") assignments[key] = value events.append( fac.Event( sid="e{}".format(len(events)), trigger=trigger, assignments=assignments, )) else: warnings.warn( "global expression could not be parsed: {}".format( line)) else: warnings.warn("XPP line not parsed: '{}'".format(line)) # direct assignments elif len(items) == 1: right = tokens[1] # init if left.endswith("(0)"): sid, value = left[0:-3], right create_initial_assignment(sid, value) # difference equations elif left.endswith("(t+1)"): warnings.warn( "Difference Equations not supported: XPP line not parsed: '{}'" .format(line)) # ode elif left.endswith("'"): sid = left[0:-1] rate_rules.append(fac.RateRule(sid=sid, value=right)) elif left.endswith("/dt"): sid = left[1:-3] rate_rules.append(fac.RateRule(sid=sid, value=right)) # assignment rules else: assignment_rules.append( fac.AssignmentRule(sid=left, value=right)) else: warnings.warn("XPP line not parsed: '{}'".format(line)) # add time assignment_rules.append( fac.AssignmentRule(sid="t", value="time", name="model time")) # create SBML objects objects = (parameters + initial_assignments + functions + rate_rules + assignment_rules + events) fac.create_objects(model, obj_iter=objects, debug=False) """ Parameter values are optional; if not they are set to zero in xpp. Many models do not encode the initial zeros. """ for p in doc.getModel().getListOfParameters(): if not p.isSetValue(): p.setValue(0.0) sbml.write_sbml( doc, sbml_file, validate=validate, program_name="sbmlutils", program_version=__version__, units_consistency=False, )
def create_sbml(self, sbml_level=SBML_LEVEL, sbml_version=SBML_VERSION): """ Create the SBML model :return: :rtype: """ from sbmlutils.validation import check logging.info('*'*40) logging.info(self.model_id) logging.info('*' * 40) # create core model sbmlns = libsbml.SBMLNamespaces(sbml_level, sbml_version) # add all the packages # FIXME: only add packages which are required for the model sbmlns.addPackageNamespace("fbc", 2) sbmlns.addPackageNamespace("comp", 1) # sbmlns.addPackageNamespace("distrib", 1) self.doc = libsbml.SBMLDocument(sbmlns) self.doc.setPackageRequired("comp", True) self.doc.setPackageRequired("fbc", False) # self.doc.setPackageRequired("distrib", True) self.model = self.doc.createModel() fbc_plugin = self.model.getPlugin("fbc") fbc_plugin.setStrict(False) # name & id check(self.model.setId(self.model_id), 'set id') check(self.model.setName(self.model_id), 'set name') # notes if hasattr(self, 'notes') and self.notes is not None: factory.set_notes(self.model, self.notes) # history if hasattr(self, 'creators'): history.set_model_history(self.model, self.creators) # model units if hasattr(self, 'model_units'): factory.set_model_units(self.model, self.model_units) # lists ofs for attr in [ 'externalModelDefinitions', 'submodels', 'units', 'functions', 'parameters', 'compartments', 'species', 'assignments', 'rules', 'rate_rules', 'reactions', 'events', 'constraints', 'ports', 'replacedElements', 'deletions', 'objectives', 'layouts' ]: # create the respective objects if hasattr(self, attr): objects = getattr(self, attr) if objects: factory.create_objects(self.model, obj_iter=objects, key=attr) else: logging.warning("Not defined: <{}> ".format(attr))
def top_model(sbml_file, directory, emds, doc_fba, annotations=None): """ Create top comp model. Creates full comp model by combining fba, update and bounds model with additional kinetics in the top model. """ top_notes = notes.format(""" <h2>TOP model</h2> <p>Main comp DFBA model by combining fba, update and bounds model with additional kinetics in the top model.</p> """) working_dir = os.getcwd() os.chdir(directory) doc = builder.template_doc_top(settings.MODEL_ID, emds) model = doc.getModel() utils.set_model_info(model, notes=top_notes, creators=creators, units=units, main_units=main_units) # dt builder.create_dfba_dt(model, step_size=DT_SIM, time_unit=UNIT_TIME, create_port=False) # compartment compartment_id = "extern" builder.create_dfba_compartment(model, compartment_id=compartment_id, unit_volume=UNIT_VOLUME, create_port=False) # dynamic species model_fba = doc_fba.getModel() builder.create_dfba_species(model, model_fba, compartment_id=compartment_id, hasOnlySubstanceUnits=True, unit_amount=UNIT_AMOUNT, create_port=False) # dummy species builder.create_dummy_species(model, compartment_id=compartment_id, hasOnlySubstanceUnits=True, unit_amount=UNIT_AMOUNT) # exchange flux bounds builder.create_exchange_bounds(model, model_fba=model_fba, unit_flux=UNIT_FLUX, create_ports=False) # dummy reactions & flux assignments builder.create_dummy_reactions(model, model_fba=model_fba, unit_flux=UNIT_FLUX) # replacedBy (fba reactions) builder.create_top_replacedBy(model, model_fba=model_fba) # replaced builder.create_top_replacements(model, model_fba, compartment_id=compartment_id) # initial concentrations for fba exchange species initial_c = { 'A': 10.0, 'C': 0.0, } for sid, value in initial_c.items(): species = model.getSpecies(sid) species.setInitialConcentration(value) # kinetic model mc.create_objects( model, [ # kinetic species mc.Species(sid='D', initialConcentration=0, substanceUnit=UNIT_AMOUNT, hasOnlySubstanceUnits=True, compartment="extern"), # kinetic mc.Parameter(sid="k_R4", value=0.1, constant=True, unit="per_s", sboTerm="SBO:0000009"), # bounds parameter mc.Parameter(sid='ub_R1', value=1.0, unit=UNIT_FLUX, constant=False, sboTerm="SBO:0000625"), ]) # kinetic reaction (MMK) mc.create_reaction(model, rid="R4", name="R4: C -> D", fast=False, reversible=False, reactants={"C": 1}, products={"D": 1}, formula="k_R4*C", compartment="extern") # kinetic flux bounds comp.replace_elements(model, 'ub_R1', ref_type=comp.SBASE_REF_TYPE_PORT, replaced_elements={ 'bounds': ['ub_R1_port'], 'fba': ['ub_R1_port'] }) # write SBML file if annotations: annotator.annotate_sbml_doc(doc, annotations) sbml.write_sbml(doc, filepath=os.path.join(directory, sbml_file), validate=True) # change back the working dir os.chdir(working_dir)
def top_model(sbml_file, directory, emds, doc_fba, annotations=None): """ Create top comp model. Creates full comp model by combining fba, update and bounds model with additional kinetics in the top model. """ top_notes = notes.format(""" <h2>TOP model</h2> <p>Main comp DFBA model by combining fba, update and bounds model with additional kinetics in the top model.</p> """) working_dir = os.getcwd() os.chdir(directory) doc = builder.template_doc_top(settings.MODEL_ID, emds) model = doc.getModel() utils.set_model_info(model, notes=top_notes, creators=creators, units=units, main_units=main_units) # dt builder.create_dfba_dt(model, step_size=DT_SIM, time_unit=UNIT_TIME, create_port=False) # compartment compartment_id = "cell" builder.create_dfba_compartment(model, compartment_id=compartment_id, unit_volume=UNIT_VOLUME, create_port=False) # dynamic species model_fba = doc_fba.getModel() builder.create_dfba_species(model, model_fba, compartment_id=compartment_id, hasOnlySubstanceUnits=False, unit_amount=UNIT_AMOUNT, create_port=False) # dummy species builder.create_dummy_species(model, compartment_id=compartment_id, hasOnlySubstanceUnits=False, unit_amount=UNIT_AMOUNT) # exchange flux bounds builder.create_exchange_bounds(model, model_fba=model_fba, unit_flux=UNIT_FLUX, create_ports=False) # dummy reactions & flux assignments builder.create_dummy_reactions(model, model_fba=model_fba, unit_flux=UNIT_FLUX) # replacedBy (fba reactions) builder.create_top_replacedBy(model, model_fba=model_fba) # replaced builder.create_top_replacements(model, model_fba, compartment_id=compartment_id) objects = [ # kinetic parameters mc.Parameter(sid="Vmax_RATP", value=1, unit=UNIT_FLUX, constant=True), mc.Parameter(sid='k_RATP', value=0.1, unit=UNIT_CONCENTRATION, constant=True), # balancing rules mc.AssignmentRule(sid="atp_tot", value="atp + adp", unit=UNIT_CONCENTRATION), mc.AssignmentRule(sid="c3_tot", value="2 dimensionless * glc + pyr", unit="mM") ] mc.create_objects(model, objects) ratp = mc.create_reaction(model, rid="RATP", name="atp -> adp", fast=False, reversible=False, reactants={"atp": 1}, products={"adp": 1}, compartment=compartment_id, formula='Vmax_RATP * atp/(k_RATP + atp)') # initial concentrations for fba exchange species initial_c = {'atp': 2.0, 'adp': 1.0, 'glc': 5.0, 'pyr': 0.0} for sid, value in initial_c.items(): species = model.getSpecies(sid) species.setInitialConcentration(value) # write SBML file if annotations: annotator.annotate_sbml_doc(doc, annotations) sbmlio.write_sbml(doc, filepath=os.path.join(directory, sbml_file), validate=True) # change back the working dir os.chdir(working_dir)
def bounds_model(sbml_file, directory, doc_fba=None, annotations=None): """" Submodel for dynamically calculating the flux bounds. The dynamically changing flux bounds are the input to the FBA model. """ # TODO: the bounds model should be created based on the FBA model (i.e. use the exchange reactions # to create the bounds info. bounds_notes = notes.format(""" <h2>BOUNDS submodel</h2> <p>Submodel for dynamically calculating the flux bounds. The dynamically changing flux bounds are the input to the FBA model.</p> """) doc = builder.template_doc_bounds(settings.MODEL_ID) model = doc.getModel() utils.set_model_info(model, notes=bounds_notes, creators=creators, units=units, main_units=main_units) # dt compartment_id = "bioreactor" builder.create_dfba_dt(model, time_unit=UNIT_TIME, create_port=True) # compartment builder.create_dfba_compartment(model, compartment_id=compartment_id, unit_volume=UNIT_VOLUME, create_port=True) # dynamic species model_fba = doc_fba.getModel() builder.create_dfba_species(model, model_fba, compartment_id=compartment_id, unit_amount=UNIT_AMOUNT, create_port=True) # bounds builder.create_exchange_bounds(model, model_fba=model_fba, unit_flux=UNIT_FLUX, create_ports=True) # bounds fba_infix = "fba_" model_fba = doc_fba.getModel() objects = [] ex_rids = utils.find_exchange_reactions(model_fba) for ex_rid, sid in ex_rids.items(): r = model_fba.getReaction(ex_rid) # lower & upper bound parameters r_fbc = r.getPlugin(builder.SBML_FBC_NAME) lb_id = r_fbc.getLowerFluxBound() fba_lb_id = builder.LOWER_BOUND_PREFIX + fba_infix + ex_rid lb_value = model_fba.getParameter(lb_id).getValue() objects.extend([ # default bounds from fba Parameter(sid=fba_lb_id, value=lb_value, unit=UNIT_FLUX, constant=False), ]) factory.create_objects(model, objects) objects = [ # kinetic lower bounds Parameter(sid="lb_kin_EX_Glcxt", value=builder.LOWER_BOUND_DEFAULT, unit=UNIT_FLUX, constant=False, sboTerm="SBO:0000612"), Parameter(sid="lb_kin_EX_O2", value=builder.LOWER_BOUND_DEFAULT, unit=UNIT_FLUX, constant=False, sboTerm="SBO:0000612"), # parameters for kinetic bounds Parameter(sid='Vmax_EX_O2', value=15, unit=UNIT_FLUX, constant=True), Parameter(sid='Vmax_EX_Glcxt', value=10, unit=UNIT_FLUX, constant=True), Parameter(sid='Km_EX_Glcxt', value=0.015, unit=UNIT_CONCENTRATION, name="Km_vGlcxt", constant=True), # kinetic bounds (unintuitive direction due to the identical concentrations in bioreactor and model) AssignmentRule(sid="lb_kin_EX_Glcxt", value="-Vmax_EX_Glcxt * Glcxt/(Km_EX_Glcxt + Glcxt)"), AssignmentRule(sid="lb_kin_EX_O2", value="-Vmax_EX_O2"), # exchange reaction bounds # uptake bounds (lower bound) # TODO: FIXME the X hack # the bounds for the fba model have to be in mmol/h/gdw AssignmentRule( sid="lb_EX_Ac", value="max(lb_fba_EX_Ac, -Ac/X/1 l_per_mmol*bioreactor/dt)"), AssignmentRule( sid="lb_EX_X", value="max(lb_fba_EX_X, -X/X/1 l_per_mmol*bioreactor/dt)"), AssignmentRule( sid="lb_EX_Glcxt", value="max(lb_kin_EX_Glcxt, -Glcxt/X/1 l_per_mmol*bioreactor/dt)"), AssignmentRule( sid="lb_EX_O2", value="max(lb_kin_EX_O2, -O2/X/1 l_per_mmol*bioreactor/dt)"), ] factory.create_objects(model, objects) if annotations: annotator.annotate_sbml_doc(doc, annotations) sbmlio.write_sbml(doc, filepath=pjoin(directory, sbml_file), validate=True)
def fba_model(sbml_file, directory, annotations=None): """ Create FBA submodel. FBA submodel in sbml:fbc-version 2. """ fba_notes = notes.format(""" <h2>FBA submodel</h2> <p>DFBA fba submodel. Unbalanced metabolites are encoded via exchange fluxes.</p> """) doc = builder.template_doc_fba(settings.MODEL_ID) model = doc.getModel() utils.set_model_info(model, notes=fba_notes, creators=creators, units=units, main_units=main_units) objects = [ # compartments mc.Compartment(sid='bioreactor', value=1.0, unit=UNIT_VOLUME, constant=True, name='bioreactor', spatialDimensions=3), # species mc.Species(sid='Glcxt', name="glucose", initialConcentration=0.0, substanceUnit=UNIT_AMOUNT, hasOnlySubstanceUnits=False, compartment="bioreactor"), mc.Species(sid='Ac', name="acetate", initialConcentration=0.0, substanceUnit=UNIT_AMOUNT, hasOnlySubstanceUnits=False, compartment="bioreactor"), mc.Species(sid='O2', name="oxygen", initialConcentration=0.0, substanceUnit=UNIT_AMOUNT, hasOnlySubstanceUnits=False, compartment="bioreactor"), mc.Species(sid='X', name="biomass", initialConcentration=0.0, substanceUnit=UNIT_AMOUNT, hasOnlySubstanceUnits=False, compartment="bioreactor"), # bounds mc.Parameter(sid="zero", name="zero bound", value=0.0, unit=UNIT_FLUX_PER_G, constant=True, sboTerm="SBO:0000612"), mc.Parameter(sid="ub_default", name="default upper bound", value=builder.UPPER_BOUND_DEFAULT, unit=UNIT_FLUX_PER_G, constant=True, sboTerm="SBO:0000612"), ] mc.create_objects(model, objects) # reactions r_v1 = mc.create_reaction(model, rid="v1", name="v1 (39.43 Ac + 35 O2 -> X)", reversible=False, reactants={"Ac": 39.43, "O2": 35}, products={"X": 1}, compartment='bioreactor') r_v2 = mc.create_reaction(model, rid="v2", name="v2 (9.46 Glcxt + 12.92 O2 -> X)", reversible=False, reactants={"Glcxt": 9.46, "O2": 12.92}, products={"X": 1}, compartment='bioreactor') r_v3 = mc.create_reaction(model, rid="v3", name="v3 (9.84 Glcxt + 12.73 O2 -> 1.24 Ac + X)", reversible=False, reactants={"Glcxt": 9.84, "O2": 12.73}, products={"Ac": 1.24, "X": 1}, compartment='bioreactor') r_v4 = mc.create_reaction(model, rid="v4", name="v4 (19.23 Glcxt -> 12.12 Ac + X)", reversible=False, reactants={"Glcxt": 19.23}, products={"Ac": 12.12, "X": 1}, compartment='bioreactor') # flux bounds: internal fluxes fbc.set_flux_bounds(r_v1, lb="zero", ub="ub_default") fbc.set_flux_bounds(r_v2, lb="zero", ub="ub_default") fbc.set_flux_bounds(r_v3, lb="zero", ub="ub_default") fbc.set_flux_bounds(r_v4, lb="zero", ub="ub_default") # reactions: exchange reactions (this species can be changed by the FBA) for sid in ['Ac', 'Glcxt', 'O2', 'X']: builder.create_exchange_reaction(model, species_id=sid, flux_unit=UNIT_FLUX_PER_G, exchange_type=builder.EXCHANGE) # set bounds for the exchange reactions p_lb_O2 = model.getParameter("lb_EX_O2") p_lb_O2.setValue(-15.0) # FIXME: this is in mmol/gdw/h (biomass weighting of FBA) p_lb_Glcxt = model.getParameter("lb_EX_Glcxt") p_lb_Glcxt.setValue(-10.0) # FIXME: this is in mmol/gdw/h # objective function model_fba = model.getPlugin(builder.SBML_FBC_NAME) fbc.create_objective(model_fba, oid="biomass_max", otype="maximize", fluxObjectives={"v1": 1.0, "v2": 1.0, "v3": 1.0, "v4": 1.0}) # write SBML file if annotations: annotation.annotate_sbml_doc(doc, annotations) sbmlio.write_sbml(doc, filepath=pjoin(directory, sbml_file), validate=True) return doc
def fba_model(sbml_file, directory): """ Create FBA submodel. """ # Read the model fba_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'data/ecoli_fba.xml') doc_fba = sbml.read_sbml(fba_path) # add comp doc_fba.enablePackage( "http://www.sbml.org/sbml/level3/version1/comp/version1", "comp", True) doc_fba.setPackageRequired("comp", True) # add notes model = doc_fba.getModel() fba_notes = notes.format("""DFBA FBA submodel.""") utils.set_model_info(model, notes=fba_notes, creators=None, units=units, main_units=main_units) # clip R_ reaction and M_ metabolite prefixes utils.clip_prefixes_in_model(model) # set id & framework model.setId('ecoli_fba') model.setName('ecoli (FBA)') model.setSBOTerm(comp.SBO_FLUX_BALANCE_FRAMEWORK) # add units and information for species in model.getListOfSpecies(): species.setInitialConcentration(0.0) species.setHasOnlySubstanceUnits(False) species.setUnits(UNIT_AMOUNT) for compartment in model.getListOfCompartments(): compartment.setUnits(UNIT_VOLUME) # The ATPM (atp maintainance reactions creates many problems in the DFBA) # mainly resulting in infeasible solutions when some metabolites run out. # ATP -> ADP is part of the biomass, so we set the lower bound to zero r_ATPM = model.getReaction('ATPM') r_ATPM_fbc = r_ATPM.getPlugin(builder.SBML_FBC_NAME) lb_id = r_ATPM_fbc.getLowerFluxBound() model.getParameter(lb_id).setValue(0.0) # 8.39 before # make unique upper and lower bounds for exchange reaction if not biomass_weighting: builder.update_exchange_reactions(model=model, flux_unit=UNIT_FLUX) else: builder.update_exchange_reactions(model=model, flux_unit=UNIT_FLUX_PER_G) # add exchange reaction for biomass (X) # we are adding the biomass component to the biomass function and create an # exchange reaction for it r_biomass = model.getReaction('BIOMASS_Ecoli_core_w_GAM') # FIXME: refactor in function # FIXME: annotate biomass species (SBO for biomass missing) mc.create_objects(model, [ mc.Parameter(sid='cf_X', value=1.0, unit="g_per_mmol", name="biomass conversion factor", constant=True), mc.Species(sid='X', initialAmount=0.001, compartment='c', name='biomass', substanceUnit='g', hasOnlySubstanceUnits=True, conversionFactor='cf_X') ]) pr_biomass = r_biomass.createProduct() pr_biomass.setSpecies('X') pr_biomass.setStoichiometry(1.0) pr_biomass.setConstant(True) # FIXME: the flux units must fit to the species units. if not biomass_weighting: builder.create_exchange_reaction(model, species_id='X', flux_unit=UNIT_FLUX, exchange_type=builder.EXCHANGE_EXPORT) else: builder.create_exchange_reaction(model, species_id='X', flux_unit=UNIT_FLUX_PER_G, exchange_type=builder.EXCHANGE_EXPORT) # write SBML file sbml.write_sbml(doc_fba, filepath=pjoin(directory, sbml_file), validate=True) # Set kinetic laws to zero for kinetic simulation ''' for reaction in model.getListOfReactions(): ast_node = mc.ast_node_from_formula(model=model, formula='0 {}'.format(UNIT_FLUX)) law = reaction.createKineticLaw() law.setMath(ast_node) ''' return doc_fba