def find_unbalanced_reactions_milp(model, unbalanced_reactions=None): if unbalanced_reactions is None: unbalanced_reactions = [rxn.id for rxn in model.reactions.values() if len(rxn.get_substrates()) == 0 or len(rxn.get_products()) == 0] unbalanced_reactions.append(model.biomass_reaction) reactions = [rxn for rxn in model.reactions.values() if rxn.id not in unbalanced_reactions] solver = solver_instance() for m_id in model.metabolites: solver.add_variable(m_id, lb=0, update_problem=False) solver.add_variable('y_' + m_id, vartype=VarType.BINARY, update_problem=False) solver.update() for rxn in reactions: solver.add_constraint('c_' + rxn.id, rxn.stoichiometry, '=', 0, update_problem=False) for m_id in model.metabolites: solver.add_constraint('b_' + m_id, {m_id: 1, 'y_' + m_id: 1}, '>', 1, update_problem=False) solution = solver.solve(linear={'y_' + m_id: 1 for m_id in model.metabolites}, minimize=True) return solution
def check_mass_conservation(model, unbalanced_reactions=None): if unbalanced_reactions is None: unbalanced_reactions = [rxn.id for rxn in model.reactions.values() if len(rxn.get_substrates()) == 0 or len(rxn.get_products()) == 0] unbalanced_reactions.append(model.biomass_reaction) reactions = [rxn for rxn in model.reactions.values() if rxn.id not in unbalanced_reactions] solver = solver_instance() for m_id in model.metabolites: solver.add_variable(m_id, lb=1, update_problem=False) solver.update() for rxn in reactions: solver.add_constraint('c_' + rxn.id, rxn.stoichiometry, '=', 0, update_problem=False) solver.update() solution = solver.solve(linear={m_id: 1 for m_id in model.metabolites}, minimize=True) result = solution.status == Status.OPTIMAL return result, solution
def simulate_ensemble(ensemble, method='FBA', constraints=None, solver=None, get_fluxes=True): """ Simulate an Ensemble Model Args: ensemble (EnsembleModel): ensemble model method (str): simulation method (default: 'FBA') constraints (dict): additional constraints (optional) solver (Solver): solver instance (optional) get_fluxes (bool): if True returns flux distributions for all models, otherwise only the objective function values are returned (default: True) Returns: ensemble flux distributions or ensemble objective function values """ if method not in ['FBA', 'pFBA']: print('Method not available:', method) return if not solver: solver = solver_instance(ensemble.model) if get_fluxes: flux_sample = OrderedDict([(r_id, [None] * ensemble.size) for r_id in ensemble.model.reactions]) else: objective = [None] * ensemble.size for i in range(ensemble.size): current = ensemble.get_constraints(i) if constraints: current.update(constraints) if method == 'FBA': sol = FBA(ensemble.model, constraints=current, solver=solver, get_values=get_fluxes) if method == 'pFBA': sol = pFBA(ensemble.model, constraints=current, solver=solver) if sol.status == Status.OPTIMAL: if get_fluxes: for r_id in ensemble.model.reactions: flux_sample[r_id][i] = sol.values[r_id] else: objective[i] = sol.fobj if get_fluxes: return flux_sample else: return objective
def find_unbalanced_reactions_lp(model, unbalanced_reactions=None, abstol=1e-6): if unbalanced_reactions is None: unbalanced_reactions = [ rxn.id for rxn in model.reactions.values() if len(rxn.get_substrates()) == 0 or len(rxn.get_products()) == 0 ] unbalanced_reactions.append(model.biomass_reaction) reactions = [ r_id for r_id in model.reactions if r_id not in unbalanced_reactions ] solver = solver_instance() for m_id in model.metabolites: solver.add_variable(m_id, lb=1, update_problem=False) objective = {} for r_id in reactions: solver.add_variable('p_' + r_id, lb=0, update_problem=False) solver.add_variable('n_' + r_id, lb=0, update_problem=False) objective['p_' + r_id] = 1 objective['n_' + r_id] = 1 solver.update() for r_id in reactions: lhs_p = {'p_' + r_id: -1} lhs_n = {'n_' + r_id: 1} lhs_p.update(model.reactions[r_id].stoichiometry) lhs_n.update(model.reactions[r_id].stoichiometry) solver.add_constraint('cp_' + r_id, lhs_p, '<', 0, update_problem=False) solver.add_constraint('cn_' + r_id, lhs_n, '>', 0, update_problem=False) solution = solver.solve(objective, minimize=True) balance = { r_id: -solution.values['n_' + r_id] + solution.values['p_' + r_id] for r_id in reactions if (abs(solution.values['n_' + r_id]) > abstol or abs(solution.values['p_' + r_id]) > abstol) } return balance
def scanCAFBA(model, values, we=8.3e-4, wr=0.169, pmax=0.484): solver = solver_instance(model) solutions = {} for value in values: solutions[value] = CAFBA(model, wc=value, we=we, wr=wr, pmax=pmax, solver=solver) return solutions
def fix_futile_cycles(model, samples): # Initialise environmental conditionsz env = {} # Set lower bound of all ireversible reactions to 0 env.update( {rid: (0, r.ub) for rid, r in model.reactions.items() if r.lb > 0}) # Close exachnge reactions bounds: lower = upper = 0 env.update({ rid: (0, 0) for rid, r in model.reactions.items() if rid.startswith('R_EX_') or rid.startswith('R_sink_') or rid.startswith('R_DM_') }) # Run FVA fva = FVA(model, constraints=env) # Identify reactions in futile cycles futile_cycle_reactions = { rid for rid, (lb, ub) in fva.items() if (lb is None) or (ub is None) or (lb < 0) or (ub > 0) } # Verbose print '[INFO] %d futile cycle reactions found: %s' % ( len(futile_cycle_reactions), '; '.join(futile_cycle_reactions)) # Fix reactions values and minimise futile cycle reactions if len(futile_cycle_reactions) > 0: solver = solver_instance(model) for i in samples.index: env.update({ rid: (samples.ix[i, rid], samples.ix[i, rid]) for rid in samples if rid not in futile_cycle_reactions }) fba = abs_min_fba(model, constraints=env, reactions=futile_cycle_reactions, solver=solver) for rid in futile_cycle_reactions: samples.ix[i, rid] = fba.values[rid] return samples
def get_warmup_points(model, constraints=None): # Calculate warm-up points running FVA solver = solver_instance(model) fva = fva_with_values(model, constraints=constraints, solver=solver) # Get upper and lower bounds reactions, lb, ub = zip(*[(r, fva[r][0].fobj if fva[r][0] else -np.Inf, fva[r][1].fobj if fva[r][1] else np.Inf) for r in fva]) reactions, lb, ub = np.array(reactions), np.array(lb), np.array(ub) # Warm-up points warmup_points = np.array([[fva[r][i].values[r_in] for r_in in reactions] for r in reactions for i in [0, 1] if fva[r][i]]).T return lb, ub, warmup_points, reactions
def ensemble_essentiality(ensemble, constraints, voting_thresholds, min_growth=0.1): solver = solver_instance(ensemble.model) essential_all = [] for i in range(ensemble.size): current = ensemble.get_constraints(i) if constraints: current.update(constraints) essential = essential_genes(ensemble.model, constraints=current, min_growth=min_growth, solver=solver) essential_all.extend(essential) results =[{gene for gene in ensemble.model.genes if essential_all.count(gene)/float(ensemble.size) >= t} for t in voting_thresholds] return results
def find_unbalanced_reactions_lp(model, unbalanced_reactions=None, abstol=1e-6): if unbalanced_reactions is None: unbalanced_reactions = [rxn.id for rxn in model.reactions.values() if len(rxn.get_substrates()) == 0 or len(rxn.get_products()) == 0] unbalanced_reactions.append(model.biomass_reaction) reactions = [r_id for r_id in model.reactions if r_id not in unbalanced_reactions] solver = solver_instance() for m_id in model.metabolites: solver.add_variable(m_id, lb=1, update_problem=False) objective = {} for r_id in reactions: solver.add_variable('p_' + r_id, lb=0, update_problem=False) solver.add_variable('n_' + r_id, lb=0, update_problem=False) objective['p_' + r_id] = 1 objective['n_' + r_id] = 1 solver.update() for r_id in reactions: lhs_p = {'p_' + r_id: -1} lhs_n = {'n_' + r_id: 1} lhs_p.update(model.reactions[r_id].stoichiometry) lhs_n.update(model.reactions[r_id].stoichiometry) solver.add_constraint('cp_' + r_id, lhs_p, '<', 0, update_problem=False) solver.add_constraint('cn_' + r_id, lhs_n, '>', 0, update_problem=False) solution = solver.solve(objective, minimize=True) balance = {r_id: -solution.values['n_' + r_id] + solution.values['p_' + r_id] for r_id in reactions if (abs(solution.values['n_' + r_id]) > abstol or abs(solution.values['p_' + r_id]) > abstol)} return balance
def simulate_biolog(model, medium, source, compounds, main_compounds, max_uptake=10, min_growth=0.1, verbose=False, add_transporters=False, add_sinks=False, ensemble=False, voting_thresholds=None, flavor=None): if ensemble: ensemble = model model = ensemble.model if flavor == 'seed': ex_rxn_format = 'EX_{}_e0' else: ex_rxn_format = 'R_EX_{}_e' env = Environment.from_compounds(medium, max_uptake=max_uptake, exchange_format='"{}"'.format(ex_rxn_format)) constraints = env.apply(model, inplace=False, warning=False) for cmpd in main_compounds[source]: main_compound_rxn = ex_rxn_format.format(cmpd) constraints[main_compound_rxn] = (0, None) no_exchange = [] not_in_model = [] growth_pred = {} if flavor == 'seed': model_mets = {m_id[:-3] for m_id in model.metabolites} else: model_mets = {m_id[2:-2] for m_id in model.metabolites} new_rxns = [] if add_transporters: model = model.copy() for met in compounds: met_e = ('{}_e0' if flavor == 'seed' else 'M_{}_e').format(met) met_c = ('{}_c0' if flavor == 'seed' else 'M_{}_c').format(met) if met_e not in model.metabolites and met_c in model.metabolites: if flavor == 'seed': rxn_str = 'EX_{}: {} <-> [0, 0]'.format(met_e, met_c) else: rxn_str = 'R_EX_{}_e: {} <-> [0, 0]'.format(met, met_c) new_rxns.append(model.add_reaction_from_str(rxn_str)) if add_sinks: model = model.copy() for m_id in model.metabolites: if m_id.endswith('_c'): rxn_str = 'Sink_{}: {} --> '.format(m_id, m_id) model.add_reaction_from_str(rxn_str) solver = solver_instance(model) summary = {} for met in compounds: growth_pred[met] = [None]*len(voting_thresholds) if ensemble else None r_id = ex_rxn_format.format(met) if r_id in model.reactions: tmp = constraints[r_id] if r_id in constraints else (0, 0) constraints[r_id] = (-max_uptake, 0) if ensemble: growth_all = simulate_ensemble(ensemble, constraints=constraints, solver=solver, get_fluxes=False) growth_bool = [rate > min_growth if rate is not None else False for rate in growth_all] growth_pred[met] = [sum(growth_bool)/float(ensemble.size) >= t for t in voting_thresholds] else: sol = FBA(model, constraints=constraints, solver=solver) if sol.status == Status.OPTIMAL: growth_pred[met] = sol.fobj > min_growth else: growth_pred[met] = False constraints[r_id] = tmp else: if met in model_mets: no_exchange.append(met) else: not_in_model.append(met) if verbose and no_exchange: print 'No exchange reactions in model:', ' '.join(sorted(no_exchange)) if verbose and not_in_model: print 'Metabolites not in model:', ' '.join(sorted(not_in_model)) return growth_pred
def abs_min_fba(model, constraints=None, reactions=None, solver=None): if not solver: solver = solver_instance(model) if not reactions: reactions = model.reactions.keys() if not hasattr(solver, 'pFBA_flag'): solver.pFBA_flag = True for r_id in reactions: if model.reactions[r_id].reversible: pos, neg = r_id + '+', r_id + '-' solver.add_variable(pos, 0, None, persistent=False, update_problem=False) solver.add_variable(neg, 0, None, persistent=False, update_problem=False) solver.update() for r_id in reactions: if model.reactions[r_id].reversible: pos, neg = r_id + '+', r_id + '-' solver.add_constraint('c' + pos, { r_id: -1, pos: 1 }, '>', 0, persistent=False, update_problem=False) solver.add_constraint('c' + neg, { r_id: 1, neg: 1 }, '>', 0, persistent=False, update_problem=False) solver.update() objective = dict() for r_id in reactions: if model.reactions[r_id].reversible: pos, neg = r_id + '+', r_id + '-' objective[pos] = 1 objective[neg] = 1 else: objective[r_id] = 1 solution = solver.solve(objective, minimize=True, constraints=constraints) # post process if solution.status == Status.OPTIMAL: for r_id in reactions: if model.reactions[r_id].reversible: pos, neg = r_id + '+', r_id + '-' del solution.values[pos] del solution.values[neg] return solution
def fva_with_values(model, obj_percentage=0, reactions=None, constraints=None, loopless=False, internal=None, solver=None): """ Run Flux Variability Analysis (FVA). Arguments: model (CBModel): a constraint-based model obj_percentage (float): minimum percentage of growth rate (default 0.0, max: 1.0) reactions (list): list of reactions to analyze (default: all) constraints (dict): additional constraints (optional) loopless (bool): run looplessFBA internally (very slow) (default: false) internal (list): list of internal reactions for looplessFBA (optional) solver (Solver): pre-instantiated solver instance (optional) Returns: dict: flux variation ranges """ _constraints = {} if constraints: _constraints.update(constraints) if not solver: solver = solver_instance(model) if obj_percentage > 0: target = model.detect_biomass_reaction() solution = FBA(model, objective={target: 1}, constraints=constraints, solver=solver) _constraints[target] = (obj_percentage * solution.fobj, None) if not reactions: reactions = model.reactions.keys() variability = OrderedDict([(r_id, [None, None]) for r_id in reactions]) for r_id in reactions: if loopless: solution = looplessFBA(model, {r_id: 1}, True, constraints=_constraints, internal=internal, solver=solver, get_values=True) else: solution = FBA(model, {r_id: 1}, True, constraints=_constraints, solver=solver, get_values=True) if solution.status == Status.OPTIMAL: variability[r_id][0] = solution elif solution.status == Status.UNBOUNDED: pass elif solution.status == Status.INF_OR_UNB: pass elif solution.status == Status.INFEASIBLE: warn('Infeasible solution status') else: warn('Unknown solution status') for r_id in reactions: if loopless: solution = looplessFBA(model, {r_id: 1}, False, constraints=_constraints, internal=internal, solver=solver, get_values=True) else: solution = FBA(model, {r_id: 1}, False, constraints=_constraints, solver=solver, get_values=True) if solution.status == Status.OPTIMAL: variability[r_id][1] = solution elif solution.status == Status.UNBOUNDED: pass elif solution.status == Status.INF_OR_UNB: pass elif solution.status == Status.INFEASIBLE: warn('Infeasible solution status') else: warn('Unknown solution status') return variability
def CAFBA(model, wc=0, we=8.3e-4, wr=0.169, pmax=0.484, carbon_source="M_glc__D_e", constraints=None, solver=None): if solver is None: solver = solver_instance(model) if hasattr(solver, 'CAFBA_flag'): uptake = solver.uptake enzymatic = solver.enzymatic else: solver.CAFBA_flag = True solver.uptake = [] solver.enzymatic = [] uptake = solver.uptake enzymatic = solver.enzymatic for r_id in model.reactions: if model.reactions[r_id].reversible: pos, neg = r_id + '+', r_id + '-' solver.add_variable(pos, 0, None, persistent=False, update_problem=False) solver.add_variable(neg, 0, None, persistent=False, update_problem=False) solver.update() for r_id in model.reactions: if model.reactions[r_id].reversible: pos, neg = r_id + '+', r_id + '-' solver.add_constraint('c' + pos, { r_id: -1, pos: 1 }, '>', 0, persistent=False, update_problem=False) solver.add_constraint('c' + neg, { r_id: 1, neg: 1 }, '>', 0, persistent=False, update_problem=False) solver.update() for r_id, rxn in model.reactions.items(): compartments = model.get_reaction_compartments(r_id) if carbon_source in rxn.stoichiometry and len(compartments) == 2: if rxn.reversible: uptake.append(r_id + '+') uptake.append(r_id + '-') else: uptake.append(r_id) if len(compartments) == 1 and rxn.gpr is not None: if rxn.reversible: enzymatic.append(r_id + '+') enzymatic.append(r_id + '-') else: enzymatic.append(r_id) main_constr = {} for r_id in enzymatic: main_constr[r_id] = we for r_id in uptake: main_constr[r_id] = wc main_constr[model.biomass_reaction] = wr solver.add_constraint('alloc', main_constr, '=', pmax, persistent=False, update_problem=True) solution = solver.solve(model.get_objective(), minimize=False, constraints=constraints) if solution is not None: solution.p_enz = sum(we * solution.values[r_id] for r_id in enzymatic) solution.p_upt = sum(wc * solution.values[r_id] for r_id in uptake) solution.p_rib = wr * solution.values[model.biomass_reaction] solution.enzymatic = { r_id: solution.values[r_id] for r_id in enzymatic } solution.uptake = {r_id: solution.values[r_id] for r_id in uptake} solver.remove_constraint('alloc') return solution
def myCFBA(model, w_e=0.001, w_r=0.5, spontaneous='G_s0001', constraints=None, solver=None): if solver is None: solver = solver_instance(model) if hasattr(solver, 'myCFBA_flag'): new_vars = solver.new_vars else: solver.myCFBA_flag = True solver.new_vars = [] new_vars = solver.new_vars tmp = [] for r_id, rxn in model.reactions.items(): if rxn.gpr is not None and spontaneous not in rxn.get_associated_genes( ): if rxn.reversible: pos, neg = r_id + '+', r_id + '-' solver.add_variable(pos, 0, None, persistent=False, update_problem=False) solver.add_variable(neg, 0, None, persistent=False, update_problem=False) new_vars.append(pos) new_vars.append(neg) tmp.append(r_id) else: new_vars.append(r_id) solver.update() for r_id in tmp: pos, neg = r_id + '+', r_id + '-' solver.add_constraint('c' + pos, { r_id: -1, pos: 1 }, '>', 0, persistent=False, update_problem=False) solver.add_constraint('c' + neg, { r_id: 1, neg: 1 }, '>', 0, persistent=False, update_problem=False) solver.update() alloc_constr = {r_id: w_e for r_id in new_vars} alloc_constr[model.biomass_reaction] = w_r solver.add_constraint('alloc', alloc_constr, '<', 1, persistent=False, update_problem=True) solution = solver.solve(model.get_objective(), minimize=False, constraints=constraints) if solution is not None: solution.v_sum = sum(solution.values[r_id] for r_id in new_vars) solver.remove_constraint('alloc') return solution