def generate_merged_model(self): def _id_pattern(object_id, organism_id): return "{}_{}".format(object_id, organism_id) def _name_pattern(object_name, organism_name): return "{} ({})".format(object_name, organism_name) def _copy_object(obj, org_id, compartment=None): new_obj = obj.copy() new_obj.id = _id_pattern(obj.id, org_id) new_obj.name = _name_pattern(obj.name, org_id) if compartment: new_obj.compartment = compartment return new_obj models_missing_extracelullar_compartment = [ m.id for m in self._organisms.itervalues() if self._extracellular_compartment not in m.compartments ] if models_missing_extracelullar_compartment: raise RuntimeError( "Extracellular compartment '{}' missing from models: '{}'". format(self._extracellular_compartment, "', '".join(models_missing_extracelullar_compartment))) models_missing_biomass = [ m.id for m in self._organisms.itervalues() if not m.biomass_reaction ] if models_missing_biomass: raise RuntimeError( "Biomass reaction not found in models: {}".format( "', '".join(models_missing_biomass))) merged_model = CBModel(self.id) merged_model.biomass_reaction = None organisms_biomass_metabolites = {} community_metabolite_exchange_lookup = {} for org_id, model in self._organisms.items(): self._organisms_reactions[org_id] = set() self._organisms_exchange_reactions[org_id] = {} self._organisms_biomass_reactions[org_id] = {} exchanged_metabolites = { m_id for r_id in model.get_exchange_reactions() for m_id in model.reactions[r_id].stoichiometry } # # Create additional extracellular compartment # if not self._merge_extracellular_compartments: pool_compartment = Compartment('pool', 'common pool') merged_model.add_compartment(pool_compartment) export_pool_compartment = Compartment( 'pool_blacklist', 'blacklisted metabolite pool') merged_model.add_compartment(export_pool_compartment) for c_id, comp in model.compartments.items(): if c_id != self._extracellular_compartment or not self._merge_extracellular_compartments: new_comp = _copy_object(comp, org_id) merged_model.add_compartment(new_comp) elif c_id not in merged_model.compartments: merged_model.add_compartment(deepcopy(comp)) for m_id, met in model.metabolites.items(): if met.compartment != self._extracellular_compartment or not self._merge_extracellular_compartments: new_met = _copy_object( met, org_id, _id_pattern(met.compartment, org_id)) merged_model.add_metabolite(new_met, clear_tmp=False) elif m_id not in merged_model.metabolites: merged_model.add_metabolite(deepcopy(met), clear_tmp=False) m_blacklisted = met.id in self._exchanged_metabolites_blacklist if met.id in exchanged_metabolites and not self._merge_extracellular_compartments: # # For blacklisted metabolites create a separate pool from which metabolites can not be reuptaken # if m_blacklisted and self._interacting: pool_id = _id_pattern(m_id, "pool_blacklist") if pool_id not in merged_model.metabolites: new_met = _copy_object(met, "pool_blacklist", "pool_blacklist") merged_model.add_metabolite(new_met, clear_tmp=False) exch_id = _id_pattern("R_EX_" + m_id, "pool_blacklist") exch_name = _name_pattern( met.name, "pool (blacklist) exchange") blk_rxn = CBReaction(exch_id, name=exch_name, reversible=False, is_exchange=False, is_sink=True) blk_rxn.stoichiometry[pool_id] = -1.0 community_metabolite_exchange_lookup[ new_met.id] = exch_id merged_model.add_reaction(blk_rxn) pool_id = _id_pattern(m_id, "pool") if pool_id not in merged_model.metabolites: new_met = _copy_object(met, "pool", "pool") merged_model.add_metabolite(new_met, clear_tmp=False) exch_id = _id_pattern("R_EX_" + m_id, "pool") exch_name = _name_pattern(met.name, "pool exchange") new_rxn = CBReaction(exch_id, name=exch_name, reversible=True, is_exchange=True) new_rxn.stoichiometry[pool_id] = -1.0 community_metabolite_exchange_lookup[ new_met.id] = exch_id merged_model.add_reaction(new_rxn) for r_id, rxn in model.reactions.items(): is_exchange = rxn.is_exchange if not is_exchange or not self._merge_extracellular_compartments: new_rxn = _copy_object(rxn, org_id) new_rxn.is_exchange = False for m_id, coeff in rxn.stoichiometry.items(): m_blacklisted = m_id in self._exchanged_metabolites_blacklist if model.metabolites[ m_id].compartment != self._extracellular_compartment or not self._merge_extracellular_compartments: del new_rxn.stoichiometry[m_id] new_id = _id_pattern(m_id, org_id) new_rxn.stoichiometry[new_id] = coeff if is_exchange: if model.metabolites[ m_id].compartment == self._extracellular_compartment and not self._merge_extracellular_compartments: # TODO: if m_id in self._exchanged_metabolites_blacklist: pool_id = _id_pattern(m_id, "pool") new_rxn.stoichiometry[pool_id] = -coeff cnm = CommunityNameMapping( organism_reaction=new_rxn.id, original_reaction=r_id, organism_metabolite=new_id, extracellular_metabolite=pool_id, original_metabolite=m_id, community_exchange_reaction= community_metabolite_exchange_lookup[ pool_id]) self._organisms_exchange_reactions[org_id][ new_rxn.id] = cnm if not self.interacting: sink_rxn = CBReaction( 'Sink_{}'.format(new_id), is_exchange=False, is_sink=True, reversible=False) sink_rxn.stoichiometry = {new_id: -1} sink_rxn.lb = 0.0 merged_model.add_reaction(sink_rxn) elif m_blacklisted: pool_blacklist_id = _id_pattern( m_id, "pool_blacklist") blacklist_export_rxn = CBReaction( 'R_EX_BLACKLIST_{}'.format(new_id), is_exchange=False, is_sink=False, reversible=False) blacklist_export_rxn.stoichiometry = { new_id: -1, pool_blacklist_id: 1 } blacklist_export_rxn.lb = 0.0 merged_model.add_reaction( blacklist_export_rxn) if is_exchange and not self._merge_extracellular_compartments: new_rxn.reversible = True new_rxn.lb = None new_rxn.ub = None if self.interacting and not m_blacklisted else 0.0 if rxn.id == model.biomass_reaction: new_rxn.reversible = False if self._create_biomass and rxn.id == model.biomass_reaction: new_rxn.objective = False # Add biomass metabolite to biomass equation m_id = _id_pattern('Biomass', org_id) name = _name_pattern('Framed biomass', org_id) comp = 'pool' if not self._merge_extracellular_compartments else self._extracellular_compartment biomass_met = Metabolite(m_id, name, comp) merged_model.add_metabolite(biomass_met, clear_tmp=False) new_rxn.stoichiometry[m_id] = 1 organisms_biomass_metabolites[org_id] = m_id self._organisms_reactions[org_id].add(new_rxn.id) merged_model.add_reaction(new_rxn) else: if is_exchange and self._merge_extracellular_compartments: self._organisms_exchange_reactions[org_id][ rxn.id] = CommunityNameMapping( organism_reaction=r_id, original_reaction=r_id, extracellular_metabolite=rxn.stoichiometry. keys()[0], original_metabolite=rxn.stoichiometry.keys() [0], organism_metabolite=None) self._organisms_reactions[org_id].add(rxn.id) if r_id in merged_model.reactions: continue new_rxn = deepcopy(rxn) new_rxn.is_exchange = True if rxn.id == model.biomass_reaction and self._create_biomass: new_rxn.reversible = False new_rxn.objective = False m_id = _id_pattern('Biomass', org_id) name = _name_pattern('Biomass', org_id) comp = 'pool' if not self._merge_extracellular_compartments else self._extracellular_compartment biomass_met = Metabolite(m_id, name, comp) merged_model.add_metabolite(biomass_met, clear_tmp=False) new_rxn.stoichiometry[m_id] = 1 organisms_biomass_metabolites[org_id] = m_id merged_model.add_reaction(new_rxn) if r_id == model.biomass_reaction: self._organisms_biomass_reactions[org_id] = new_rxn.id if self._create_biomass: biomass_rxn = CBReaction('R_Community_Growth', name="Community Growth", reversible=False, is_exchange=False, is_sink=True, objective=1.0) for org_biomass in organisms_biomass_metabolites.itervalues(): biomass_rxn.stoichiometry[org_biomass] = -1 merged_model.add_reaction(biomass_rxn) merged_model.biomass_reaction = biomass_rxn.id return merged_model
def merge_models(self): comm_model = CBModel(self.id) old_ext_comps = [] ext_mets = [] self.reaction_map = {} self.metabolite_map = {} # default IDs ext_comp_id = "ext" biomass_id = "community_biomass" comm_growth = "community_growth" # create external compartment comp = Compartment(ext_comp_id, "extracellular environment", external=True) comm_model.add_compartment(comp) # community biomass met = Metabolite(biomass_id, "Total community biomass", ext_comp_id) comm_model.add_metabolite(met, clear_tmp=False) rxn = CBReaction(comm_growth, name="Community growth rate", reversible=False, stoichiometry={biomass_id: -1}, lb=0, ub=None, objective=1) comm_model.add_reaction(rxn, clear_tmp=False) # add each organism for org_id, model in self.organisms.items(): def rename(old_id): return "{}_{}".format(old_id, org_id) # add internal compartments for c_id, comp in model.compartments.items(): if comp.external: old_ext_comps.append(c_id) else: new_comp = Compartment(rename(c_id), comp.name) comm_model.add_compartment(new_comp) # add metabolites for m_id, met in model.metabolites.items(): if met.compartment not in old_ext_comps: # if is internal new_id = rename(m_id) new_met = Metabolite(new_id, met.name, rename(met.compartment)) new_met.metadata = met.metadata.copy() comm_model.add_metabolite(new_met) self.metabolite_map[(org_id, m_id)] = new_id elif m_id not in comm_model.metabolites: # if is external but was not added yet new_met = Metabolite(m_id, met.name, ext_comp_id) new_met.metadata = met.metadata.copy() comm_model.add_metabolite(new_met, clear_tmp=False) ext_mets.append(new_met.id) # add internal reactions for r_id, rxn in model.reactions.items(): if rxn.reaction_type == ReactionType.EXCHANGE: continue new_id = rename(r_id) new_stoichiometry = { m_id if m_id in ext_mets else rename(m_id): coeff for m_id, coeff in rxn.stoichiometry.items() } if r_id == model.biomass_reaction: new_stoichiometry[biomass_id] = 1 new_rxn = CBReaction( new_id, name=rxn.name, reversible=rxn.reversible, stoichiometry=new_stoichiometry, reaction_type=rxn.reaction_type, lb=rxn.lb, ub=rxn.ub, ) comm_model.add_reaction(new_rxn, clear_tmp=False) new_rxn.metadata = rxn.metadata.copy() self.reaction_map[(org_id, r_id)] = new_id # Add exchange reactions for m_id in ext_mets: rxn = CBReaction("R_EX_{}".format(m_id), reversible=True, stoichiometry={m_id: -1}, reaction_type=ReactionType.EXCHANGE) comm_model.add_reaction(rxn, clear_tmp=False) return comm_model
def generate_merged_model(self): def _id_pattern(object_id, organism_id): return "{}_{}".format(object_id, organism_id) def _name_pattern(object_name, organism_name): return "{} ({})".format(object_name, organism_name) def _copy_object(obj, org_id, compartment=None): new_obj = obj.copy() new_obj.id = _id_pattern(obj.id, org_id) new_obj.name = _name_pattern(obj.name, org_id) if compartment: new_obj.compartment = compartment return new_obj models_missing_extracelullar_compartment = [m.id for m in self._organisms.values() if self._extracellular_compartment not in m.compartments] if models_missing_extracelullar_compartment: raise RuntimeError("Extracellular compartment '{}' missing from models: '{}'".format( self._extracellular_compartment, "', '".join(models_missing_extracelullar_compartment))) models_missing_biomass = [m.id for m in self._organisms.values() if not m.biomass_reaction] if models_missing_biomass: raise RuntimeError("Biomass reaction not found in models: {}".format("', '".join(models_missing_biomass))) merged_model = CBModel(self.id) merged_model.biomass_reaction = None organisms_biomass_metabolites = {} community_metabolite_exchange_lookup = {} for org_id, model in self._organisms.items(): self._organisms_reactions[org_id] = [] self._organisms_exchange_reactions[org_id] = {} self._organisms_biomass_reactions[org_id] = {} exchanged_metabolites = {m_id for r_id in model.get_exchange_reactions() for m_id in model.reactions[r_id].stoichiometry} # # Create additional extracellular compartment # if not self._merge_extracellular_compartments: pool_compartment = Compartment('pool', 'common pool') merged_model.add_compartment(pool_compartment) export_pool_compartment = Compartment('pool_blacklist', 'blacklisted metabolite pool') merged_model.add_compartment(export_pool_compartment) for c_id, comp in model.compartments.items(): if c_id != self._extracellular_compartment or not self._merge_extracellular_compartments: new_comp = _copy_object(comp, org_id) merged_model.add_compartment(new_comp) elif c_id not in merged_model.compartments: merged_model.add_compartment(deepcopy(comp)) for m_id, met in model.metabolites.items(): if met.compartment != self._extracellular_compartment or not self._merge_extracellular_compartments: new_met = _copy_object(met, org_id, _id_pattern(met.compartment, org_id)) merged_model.add_metabolite(new_met, clear_tmp=False) elif m_id not in merged_model.metabolites: merged_model.add_metabolite(deepcopy(met), clear_tmp=False) m_blacklisted = met.id in self._exchanged_metabolites_blacklist if met.id in exchanged_metabolites and not self._merge_extracellular_compartments: # # For blacklisted metabolites create a separate pool from which metabolites can not be reuptaken # if m_blacklisted and self._interacting: pool_id = _id_pattern(m_id, "pool_blacklist") if pool_id not in merged_model.metabolites: new_met = _copy_object(met, "pool_blacklist", "pool_blacklist") merged_model.add_metabolite(new_met, clear_tmp=False) exch_id = _id_pattern("R_EX_" + m_id, "pool_blacklist") exch_name = _name_pattern(met.name, "pool (blacklist) exchange") blk_rxn = CBReaction(exch_id, name=exch_name, reversible=False, is_exchange=False, is_sink=True) blk_rxn.stoichiometry[pool_id] = -1.0 community_metabolite_exchange_lookup[new_met.id] = exch_id merged_model.add_reaction(blk_rxn) pool_id = _id_pattern(m_id, "pool") if pool_id not in merged_model.metabolites: new_met = _copy_object(met, "pool", "pool") merged_model.add_metabolite(new_met, clear_tmp=False) exch_id = _id_pattern("R_EX_" + m_id, "pool") exch_name = _name_pattern(met.name, "pool exchange") new_rxn = CBReaction(exch_id, name=exch_name, reversible=True, is_exchange=True) new_rxn.stoichiometry[pool_id] = -1.0 community_metabolite_exchange_lookup[new_met.id] = exch_id merged_model.add_reaction(new_rxn) for r_id, rxn in model.reactions.items(): is_exchange = rxn.is_exchange if not is_exchange or not self._merge_extracellular_compartments: new_rxn = _copy_object(rxn, org_id) new_rxn.is_exchange = False for m_id, coeff in rxn.stoichiometry.items(): m_blacklisted = m_id in self._exchanged_metabolites_blacklist if model.metabolites[m_id].compartment != self._extracellular_compartment or not self._merge_extracellular_compartments: del new_rxn.stoichiometry[m_id] new_id = _id_pattern(m_id, org_id) new_rxn.stoichiometry[new_id] = coeff if is_exchange: if model.metabolites[m_id].compartment == self._extracellular_compartment and not self._merge_extracellular_compartments: # TODO: if m_id in self._exchanged_metabolites_blacklist: pool_id = _id_pattern(m_id, "pool") new_rxn.stoichiometry[pool_id] = -coeff cnm = CommunityNameMapping( organism_reaction=new_rxn.id, original_reaction=r_id, organism_metabolite=new_id, extracellular_metabolite=pool_id, original_metabolite=m_id, community_exchange_reaction=community_metabolite_exchange_lookup[pool_id]) self._organisms_exchange_reactions[org_id][new_rxn.id] = cnm if not self.interacting: sink_rxn = CBReaction('Sink_{}'.format(new_id), is_exchange=False, is_sink=True, reversible=False) sink_rxn.stoichiometry = {new_id: -1} sink_rxn.lb = 0.0 merged_model.add_reaction(sink_rxn) elif m_blacklisted: pool_blacklist_id = _id_pattern(m_id, "pool_blacklist") blacklist_export_rxn = CBReaction('R_EX_BLACKLIST_{}'.format(new_id), is_exchange=False, is_sink=False, reversible=False) blacklist_export_rxn.stoichiometry = {new_id: -1, pool_blacklist_id: 1} blacklist_export_rxn.lb = 0.0 merged_model.add_reaction(blacklist_export_rxn) if is_exchange and not self._merge_extracellular_compartments: new_rxn.reversible = True new_rxn.lb = None new_rxn.ub = None if self.interacting and not m_blacklisted else 0.0 if rxn.id == model.biomass_reaction: new_rxn.reversible = False if self._create_biomass and rxn.id == model.biomass_reaction: new_rxn.objective = False # Add biomass metabolite to biomass equation m_id = _id_pattern('Biomass', org_id) name = _name_pattern('Framed biomass', org_id) comp = 'pool' if not self._merge_extracellular_compartments else self._extracellular_compartment biomass_met = Metabolite(m_id, name, comp) merged_model.add_metabolite(biomass_met, clear_tmp=False) new_rxn.stoichiometry[m_id] = 1 organisms_biomass_metabolites[org_id] = m_id self._organisms_reactions[org_id].append(new_rxn.id) merged_model.add_reaction(new_rxn) else: if is_exchange and self._merge_extracellular_compartments: self._organisms_exchange_reactions[org_id][rxn.id] = CommunityNameMapping( organism_reaction=r_id, original_reaction=r_id, extracellular_metabolite=list(rxn.stoichiometry.keys())[0], original_metabolite=list(rxn.stoichiometry.keys())[0], organism_metabolite=None) self._organisms_reactions[org_id].append(rxn.id) if r_id in merged_model.reactions: continue new_rxn = deepcopy(rxn) new_rxn.is_exchange = True if rxn.id == model.biomass_reaction and self._create_biomass: new_rxn.reversible = False new_rxn.objective = False m_id = _id_pattern('Biomass', org_id) name = _name_pattern('Biomass', org_id) comp = 'pool' if not self._merge_extracellular_compartments else self._extracellular_compartment biomass_met = Metabolite(m_id, name, comp) merged_model.add_metabolite(biomass_met, clear_tmp=False) new_rxn.stoichiometry[m_id] = 1 organisms_biomass_metabolites[org_id] = m_id merged_model.add_reaction(new_rxn) if r_id == model.biomass_reaction: self._organisms_biomass_reactions[org_id] = new_rxn.id if self._create_biomass: biomass_rxn = CBReaction('R_Community_Growth', name="Community Growth", reversible=False, is_exchange=False, is_sink=True, objective=1.0) for org_biomass in organisms_biomass_metabolites.values(): biomass_rxn.stoichiometry[org_biomass] = -1 merged_model.add_reaction(biomass_rxn) merged_model.biomass_reaction = biomass_rxn.id return merged_model