class RedundantCaseSolver(RepresentationProblemSolver): def __init__(self, model, database_format): """ Class constructor :param Model model: cobrapy model :param str database_format: ModelSEED, BiGG or KEGG """ self.model = model self.objective = linear_reaction_coefficients(self.model) if self.objective: self.objective = list(self.objective.keys())[0] else: raise Exception("No objective found") self.__compounds_ontology = CompoundsDBAccessor() self.model = model self.__database_format = database_format self.__configs = file_utilities.read_conf_file(TOOL_CONFIG_PATH) self.__home_path__ = ROOT_DIR self.__modelseedCompoundsDb = ModelSeedCompoundsDB() self.__define_instance_variables() self.write_in_progress_bar("mapping model... ", 1) self.mapper.map_model(database_format) self.write_in_progress_bar("model mapped ", 10) @property def model(self): return self.__model @model.setter def model(self, value): self.__model = value @property def mapper(self): return self.__mapper @mapper.setter def mapper(self, value): self.__mapper = value def write_in_progress_bar(self, message, value): with open(PROGRESS_BAR, "w") as file: file.write(message + ":" + str(value)) def __define_instance_variables(self): """ Define instance variables :return: """ self.__universal_model = Model("universal_model") self.__swapped = [] self.__compounds_ontology = CompoundsDBAccessor() self.__compoundsAnnotationConfigs = file_utilities.read_conf_file( COMPOUNDS_ANNOTATION_CONFIGS_PATH) self.__reactionsAnnotationConfigs = file_utilities.read_conf_file( REACTIONS_ANNOTATION_CONFIGS_PATH) self.__compoundsIdConverter = CompoundsIDConverter() self.__compounds_revisor = CompoundsRevisor(self.model, self.__universal_model) biocyc.set_organism("meta") self.mapper = ModelMapper(self.model, self.__compoundsAnnotationConfigs, self.__compoundsIdConverter) self.__compounds_revisor.set_model_mapper(self.mapper) self.granulator = Granulator(self.model, self.mapper, self.__database_format, self.__compoundsIdConverter, self.__compoundsAnnotationConfigs) def __add_hydrogen_to_virtual_model(self): """ This method set searches for the hydrogen in each compartment of the model. The hydrogens are used to balance reactions. """ compartments = self.__model.compartments metabolites_in_model = self.__model.metabolites res = [] i = 0 while i < len(metabolites_in_model): metabolite = metabolites_in_model[i] if metabolite.formula == "H" and metabolite.compartment in compartments: res.append(metabolite) i += 1 self.__virtual_model.add_metabolites(res) def swap_and_gap_fill(self, target_ontology_id): pass def generalize_model(self, target_ontology_id): pass def gap_fill_model_by_target(self, target_ontology_id: int, components_ont_ids: list): pass def write_reports(self, file_path): metabolites_report_material = self.granulator.metabolite_report_material reactions_report_material = self.granulator.reaction_report_material with open(file_path, "w") as f: f.write("--Metabolites--\n") f.write("metabolite in model,replacer metabolite\n") for metabolite in metabolites_report_material: f.write(metabolite + ",") f.write(metabolites_report_material[metabolite] + "\n") f.write("--Reactions--\n") f.write("reaction in model,replacer reaction\n") for reaction in reactions_report_material: f.write(reaction + ",") f.write(reactions_report_material[reaction] + "\n") def swap_from_generic(self, targets: list, components: list, same_components=False, progress_bar_processes_left=1): """ Swap compounds from a generic target and components. The algorithm acts as follows: 1st: Starts for identifying the reactions present in the requested biosynthetic pathway; 2nd: Creates a virtual model; 3rd: Calls the granulator to granulate the biosynthetic pathway; :param list<str> targets: list of lipid targets :param list<str> components: list of components :param bool same_components: boolean for same or mix of components :param int progress_bar_processes_left: :return: """ targets_generic_ontology_id, components_ont_ids = \ self.transform_targets_and_components_into_boimmg_ids(targets,components) self.__virtual_model = Model("virtual_model") self.__add_hydrogen_to_virtual_model() self.__virtual_model_mapper = ModelMapper( self.__virtual_model, self.__compoundsAnnotationConfigs, self.__compoundsIdConverter) self.__virtual_compounds_revisor = CompoundsRevisor( self.__virtual_model, self.__universal_model, self.__compoundsAnnotationConfigs) self.__virtual_compounds_revisor.set_model_mapper( self.__virtual_model_mapper) self.granulator.set_virtual_model(self.__virtual_model, self.__virtual_model_mapper, self.__virtual_compounds_revisor) for target_generic_ontology_id in targets_generic_ontology_id: biosynthesis_reactions = self.granulator.identify_biosynthesis_pathway( target_generic_ontology_id) self.__biosynthesis_reactions = deepcopy(biosynthesis_reactions) self.__add_new_reactions_to_virtual_model( self.__biosynthesis_reactions) self.__model.remove_reactions(biosynthesis_reactions) self.granulator.granulate(target_generic_ontology_id, components_ont_ids, same_components, progress_bar_processes_left) self.generateISAreactions() def __subtract_reactions_in_list(self, reactions, reactions_to_subtract): res = [] for reaction in reactions: if reaction.id not in reactions_to_subtract: res.append(reaction) return res # def solve_components_reactions(self,same_components=False): # # self.__virtual_model = Model("virtual_model") # self.__universal_model = Model("universal_model") # # self.__virtual_model_mapper = ModelMapper(self.__virtual_model, self.__compoundsAnnotationConfigs, # self.__compoundsIdConverter) # # self.__virtual_compounds_revisor = CompoundsRevisor(self.__virtual_model, self.__universal_model, # self.__compoundsAnnotationConfigs) # # self.__virtual_compounds_revisor.set_model_mapper(self.__virtual_model_mapper) # # granulator = Granulator(self.model, self.mapper, self.__database_format, self.__modelseedCompoundsDb, # self.__compoundsIdConverter, self.__compoundsAnnotationConfigs) # # granulator.set_virtual_model(self.__virtual_model, self.__virtual_model_mapper, # self.__virtual_compounds_revisor) # # granulator.solve_components_reactions(same_components) def __add_new_reactions_to_virtual_model(self, new_reactions): self.__virtual_model_mapper.add_new_reactions_to_model(new_reactions) self.__virtual_model.add_reactions(new_reactions) def __add_new_reactions_to_model(self, new_reactions): self.mapper.add_new_reactions_to_model(new_reactions) self.model.add_reactions(new_reactions) def generateISAreactions(self): parents_and_children = self.get_parent_and_children_in_model() objective_reactants = [ reactant.id for reactant in self.objective.reactants ] reactions = [] for parent in parents_and_children: if parent in objective_reactants: for child in parents_and_children[parent]: name = "ISA_reaction_" + child id = "ISA_reaction_" + child newISAreaction = Reaction(id=id, name=name) child_cobra_container = self.model.metabolites.get_by_id( child) parent_cobra_container = self.model.metabolites.get_by_id( parent) stoichiometry = { child_cobra_container: -1, parent_cobra_container: 1 } newISAreaction.add_metabolites(stoichiometry) reactions.append(newISAreaction) self.model.add_reactions(reactions) def get_parent_and_children_in_model(self): res = {} for model_compound_id in self.mapper.boimmg_db_model_map.keys(): boimmg_id = self.mapper.boimmg_db_model_map[model_compound_id] node = self.__compounds_ontology.get_node_by_ont_id(boimmg_id) if not node.generic: parents = self.__compounds_ontology.get_successors_by_ont_id_rel_type( boimmg_id, "is_a") if parents: parent = parents[0] if parent in self.mapper.boimmg_db_model_map_reverse.keys( ): parents_in_model = self.mapper.boimmg_db_model_map_reverse[ parent] if len(parents_in_model) == 1: parent_in_model = parents_in_model[0] if parent_in_model in res: res[parent_in_model].append(model_compound_id) else: res[parent_in_model] = [model_compound_id] return res def transform_targets_and_components_into_boimmg_ids( self, targets, components): """ Conversion of components and lipid targets into BOIMMG's format :param targets: :param components: :return: """ targets_res = [] components_res = [] accessor = CompoundsDBAccessor() boimmg_prefix = self.__compoundsAnnotationConfigs[ "BOIMMG_ID_CONSTRUCTION"] for target in targets: new_target = self._transform_database_ids_into_boimmg_ids( target, accessor, boimmg_prefix) if not new_target: exit(2) targets_res.append(new_target) for component in components: new_component = self._transform_database_ids_into_boimmg_ids( component, accessor, boimmg_prefix) if not new_component: exit(2) components_res.append(new_component) return targets_res, components_res def _transform_database_ids_into_boimmg_ids(self, target: str, accessor: CompoundsDBAccessor, boimmg_prefix: str): """ Convert target lipid identifier into BOIMMG's format :param str target: :param CompoundsDBAccessor accessor: :param str boimmg_prefix: :return: """ targets_res = '' if boimmg_prefix in target: targets_res = int(target.replace(boimmg_prefix, "")) elif re.match("^[0-9]*$", target): targets_res = int(target) elif "cpd" not in target: model_seed_ids = self.__compoundsIdConverter.convert_db_id_to_model_seed_by_db_id( target) else: model_seed_ids = [target] if not targets_res: for model_seed_id in model_seed_ids: node1 = accessor.get_node_from_model_seed_id(model_seed_id) if node1: targets_res = node1.id break return targets_res
class MetaboliteSwapper: def __init__(self, model, metabolite_in_model, new_metabolite, type, modelSeedCompoundsDb, model_database="ModelSEED", compoundsIdConverter=None, universal_model=None, not_to_change_compounds=[]): """ Class constructor :param Model model: COBRApy model :param int metabolite_in_model: ontology id of the metabolite to be replaced :param int new_metabolite: ontology id of the metabolite that will replace :param int type: type of change (0, 1, 2 or 3) :param ModelSeedDB modelSeedCompoundsDb: Model SEED compounds database :param string model_database: database format of metabolites and reactions :param (optional) CompoundsIDConverter compoundsIdConverter: compound id converter :param (optional) Model universal_model: an universal model :param (optional) list not_to_change_compounds: list with compound that are not supposed to be changed """ if not universal_model: self.__universal_model = universal_model else: self.__universal_model = Model("universal_reactions") if not compoundsIdConverter: self.__compoundsIdConverter = CompoundsIDConverter() else: self.__compoundsIdConverter = compoundsIdConverter self.__model_database = model_database self.__compounds_db = modelSeedCompoundsDb self.__type = type self.__metabolite_in_model = metabolite_in_model self.__new_metabolite = new_metabolite self.__model = model self.__metabolites_not_to_change = not_to_change_compounds self.define_instance_variables() @property def model(self): return self.__model @model.setter def model(self, value): self.__model = value @property def mapper(self): return self.__mapper @mapper.setter def mapper(self, value): self.__mapper = value @property def changed_reactions(self): return self._changed_reactions @changed_reactions.setter def changed_reactions(self, value): self._changed_reactions = value def define_instance_variables(self): """ Define instance variables :return: """ self.__compoundsAnnotationConfigs = file_utilities.read_conf_file( COMPOUNDS_ANNOTATION_CONFIGS_PATH) self.__reactionsAnnotationConfigs = file_utilities.read_conf_file( REACTIONS_ANNOTATION_CONFIGS_PATH) self.__compounds_ontology = CompoundsDBAccessor() self.__home_path__ = ROOT_DIR self.__configs = file_utilities.read_conf_file(TOOL_CONFIG_PATH) self.changed_reactions = [] self.__reactionsChanger = ReactionsChanger( self.model, self.__type, self.__model_database, self.__universal_model, compounds_converter=self.__compoundsIdConverter) def set_type(self, new_type): """ Method to change the type of swap. :param int new_type: new type of swap :return: """ self.__type = new_type self.__reactionsChanger.set_type(new_type) def set_new_compound(self, new_compound): """ Method to set the new compound that will replace the other in the model. :param int new_compound: ontology identifier of the new compound. :return: """ self.__new_metabolite = new_compound def set_compound_in_model(self, compound_in_model): """ Method to set the compound to be replaced. :param int compound_in_model: ontology identifier of the compound in the model. :return: """ self.__metabolite_in_model = compound_in_model def get_universal_model(self): """ Get the instance variable __universal_model. :return: Model __universal_model: return the universal model. """ return self.__universal_model def swap_metabolites(self) -> list: """ Algorithm to swap metabolites: 1º Set the game changer: dictionary with the metabolites' intermediates, conjugated acid or/and base. - {Metabolite in model : metabolite replacer} 2º Swap all the metabolite's intermediates, conjugated acid or/and base and the metabolite itself. 3º Swap the reactions associated to the replaced metabolite using the ReactionSwapper class. :return list : changed reactions """ compounds_with_reactions_to_change = [] game_changer = self.__get_game_changer() game_changer_in_model = {} for compound in game_changer.keys(): compound_container = self.__compounds_ontology.get_node_by_ont_id( compound) in_model_compound_inchikey = compound_container.inchikey modelseed_id = compound_container.model_seed_id in_model_aliases = {} if modelseed_id: in_model_aliases = self.__compoundsIdConverter.get_all_aliases_by_modelSeedID( modelseed_id) metabolitesInModel = self.mapper.check_metabolites_in_model( in_model_compound_inchikey, in_model_aliases, boimmg_container=compound_container) if metabolitesInModel: for metabolite in metabolitesInModel: game_changer_in_model[metabolite] = game_changer[compound] for metabolite in game_changer_in_model.keys(): inModel = game_changer_in_model[metabolite][0] if not inModel: new_compound_ontology_id = game_changer_in_model[metabolite][1] if self.__model_database == "ModelSEED": self.__swap_modelseed_compound(metabolite, new_compound_ontology_id) elif self.__model_database == "BiGG": self.__swap_bigg_metabolite(metabolite, new_compound_ontology_id) elif self.__model_database == "KEGG": self.__swap_kegg_metabolite(metabolite, new_compound_ontology_id) compounds_with_reactions_to_change.append(metabolite) else: mets = game_changer_in_model[metabolite][1] for met in mets: if metabolite.compartment == met.compartment: self.change_reaction_by_swapping_existing_metabolites( metabolite, met) compounds_with_reactions_to_change.append(met) changed_reactions = self.__reactionsChanger.swap_reactions_by_compounds( compounds_with_reactions_to_change) return changed_reactions def __swap_conjugates(self, model_metabolite=None, new_metabolite=None): """ Method to swap the conjugated base and acid of the compounds being swapped. If the model_metabolite and the new_metabolite are provided, the method will replace directly the model_metabolite for the new_metabolite. :param (optional) Metabolite model_metabolite: metabolite in the model to be replaced :param (optional) Metabolite new_metabolite: metabolite to replace. :return: """ conjugates_game_changer = self.__get_game_changer_conjugates() if not new_metabolite and not model_metabolite: compounds_with_reactions_to_change = [] game_changer_in_model = {} for compound in conjugates_game_changer.keys(): compound_container = self.__compounds_ontology.get_node_by_ont_id( compound) in_model_compound_inchikey = compound_container.inchikey in_model_aliases = compound_container.aliases metabolitesInModel = self.mapper.check_metabolites_in_model( in_model_compound_inchikey, in_model_aliases) if metabolitesInModel: for metabolite_to_be_changed in metabolitesInModel: game_changer_in_model[ metabolite_to_be_changed] = conjugates_game_changer[ compound] for metabolite_to_be_changed in game_changer_in_model.keys(): inModel = game_changer_in_model[metabolite_to_be_changed][0] if not inModel: new_compound_ontology_id = game_changer_in_model[ metabolite_to_be_changed][1] if self.__model_database == "ModelSEED": self.__swap_modelseed_compound( metabolite_to_be_changed, new_compound_ontology_id) elif self.__model_database == "BiGG": self.__swap_bigg_metabolite(metabolite_to_be_changed, new_compound_ontology_id) elif self.__model_database == "KEGG": self.__swap_kegg_metabolite(metabolite_to_be_changed, new_compound_ontology_id) compounds_with_reactions_to_change.append( metabolite_to_be_changed) self.__reactionsChanger.swap_reactions_by_compounds( compounds_with_reactions_to_change) else: reactions_to_change = [] for compound in conjugates_game_changer.keys(): conjugates = conjugates_game_changer[compound][1] for conjugate in conjugates: if conjugate.compartment == new_metabolite.compartment: compound_container = self.__compounds_ontology.get_node_by_ont_id( compound) in_model_compound_inchikey = compound_container.inchikey in_model_aliases = compound_container.aliases metabolitesInModel = self.mapper.check_metabolites_in_model( in_model_compound_inchikey, in_model_aliases, compound_container) for metabolite_to_be_changed in metabolitesInModel: if metabolite_to_be_changed.compartment == new_metabolite.compartment: reactions_to_change = self.change_reaction_by_swapping_existing_metabolites( metabolite_to_be_changed, conjugate) else: db_type = self.__compoundsAnnotationConfigs.get( self.__model_database) db_id = conjugate.annotation.get(db_type) if type(db_id) == str: modelseed_id = self.__compoundsIdConverter.convert_db_id_to_model_seed_by_db_id( db_id) else: modelseed_id = self.__compoundsIdConverter.convert_db_id_to_model_seed_by_db_id( db_id[0]) cont = self.__compounds_db.get_compound_by_id( modelseed_id[0]) new_compound = self.generate_new_metabolites(cont) compound_ont_container = self.__compounds_ontology.get_node_by_ont_id( compound) compound_to_be_changed = \ self.mapper.check_metabolites_in_model(compound_ont_container.inchikey, compound_ont_container.aliases, compound_ont_container) if compound_to_be_changed: reactions_to_change = self.change_reaction_by_swapping_existing_metabolites( compound_to_be_changed[0], new_compound[0]) if reactions_to_change: self.__reactionsChanger.swap_reactions(reactions_to_change) def swap_only_metabolites_and_conjugates(self, model_metabolite=None, new_metabolite=None): """ Method to swap only the metabolites and their conjugated acid and/or base. This method does not change the metabolite intermediates/precursors. :param (optional) Model.Metabolite model_metabolite: metabolite in the model to be replaced :param (optional) Model.Metabolite new_metabolite: metabolite to replace. :return: """ compounds_with_reactions_to_change = [] if not model_metabolite: self.__swap_conjugates() ontology_container = self.__compounds_ontology.get_node_by_ont_id( self.__metabolite_in_model) inchikey = ontology_container.inchikey aliases = self.__compoundsIdConverter.get_all_aliases_by_modelSeedID( ontology_container.model_seed_id) model_metabolites = self.mapper.check_metabolites_in_model( inchikey, aliases) replacer_metabolites_in_model = \ self.__check_if_compound_exists_in_model_by_ontology_id(self.__new_metabolite) if not replacer_metabolites_in_model: if self.__model_database == "ModelSEED": for model_metabolite in model_metabolites: self.__swap_modelseed_compound(model_metabolite, self.__new_metabolite) elif self.__model_database == "BiGG": for model_metabolite in model_metabolites: self.__swap_bigg_metabolite(model_metabolite, self.__new_metabolite) elif self.__model_database == "KEGG": for model_metabolite in model_metabolites: self.__swap_kegg_metabolite(model_metabolite, self.__new_metabolite) compounds_with_reactions_to_change.append(model_metabolite) self.__reactionsChanger.swap_reactions_by_compounds( compounds_with_reactions_to_change) else: for model_metabolite in model_metabolites: for replacer_metabolite in replacer_metabolites_in_model: if model_metabolite.compartment == replacer_metabolite.compartment: reactions_to_change = self.change_reaction_by_swapping_existing_metabolites( model_metabolite, replacer_metabolite) self.__reactionsChanger.swap_reactions( reactions_to_change) elif new_metabolite: self.__swap_conjugates(model_metabolite, new_metabolite) reactions_to_change = self.change_reaction_by_swapping_existing_metabolites( model_metabolite, new_metabolite) changed_reactions = self.__reactionsChanger.swap_reactions( reactions_to_change) self.changed_reactions.extend(changed_reactions) def change_reaction_by_swapping_existing_metabolites( self, model_metabolite, new_metabolite): """ Method to change a given metabolite and the respective reactions. :param Model.Metabolite model_metabolite: metabolite in the model to be replaced :param Model.Metabolite new_metabolite: metabolite to replace. :return: list<Reaction> reactions_to_change: list with the reactions to be changed (format, id, annotation, etc...) """ reactions_to_change = [] if model_metabolite.id != new_metabolite.id: reactions = model_metabolite.reactions for reaction in reactions: met_to_add = {} met_to_subtract = {} stoichiometry = reaction.metabolites coef = stoichiometry.get(model_metabolite) met_to_add[new_metabolite] = coef met_to_subtract[model_metabolite] = coef reaction.subtract_metabolites(met_to_subtract) reaction.add_metabolites(met_to_add) reactions_to_change.append(reaction) return reactions_to_change def __swap_bigg_metabolite(self, model_metabolite, new_compound_ontology_id): """ Method to swap a metabolite in the BiGG database format. This method tries to find the BiGG format of the new compound. If it does not find, it will change into the Model SEED format. :param Model.Metabolite model_metabolite: metabolite to be replaced. :param int new_compound_ontology_id: ontology identifier of the metabolite that will replace the other :return: """ model_metabolite.annotation = {} compound_container = self.__compounds_ontology.get_node_by_ont_id( new_compound_ontology_id) model_seed_id = compound_container.model_seed_id if model_seed_id: bigg_ids = None aliases = self.__compoundsIdConverter.get_modelSeedIdToDb().get( model_seed_id) if "BiGG" in aliases: bigg_ids = self.__compoundsIdConverter.convert_modelSeedId_into_other_dbID( model_seed_id, "BiGG") elif "BiGG1" in aliases: bigg_ids = self.__compoundsIdConverter.convert_modelSeedId_into_other_dbID( model_seed_id, "BiGG1") if bigg_ids: bigg_metabolite = None bigg_id = None found = False i = 0 while not found and i < len(bigg_ids): try: bigg_id = bigg_ids[i] bigg_metabolite = bigg.get_bigg_metabolite(bigg_id) found = True except: i += 1 if bigg_metabolite: old_inchikey = "" if "inchi_key" in model_metabolite.annotation.keys(): old_inchikey = model_metabolite.annotation["inchi_key"] old_aliases = AnnotationUtils.get_annotation_from_cobra_annotation( model_metabolite) old_id = model_metabolite.id new_aliases = self.__compoundsIdConverter.get_all_aliases_by_modelSeedID( compound_container.model_seed_id) annotation = AnnotationUtils.get_compound_annotation_format_by_aliases( new_aliases) model_metabolite.annotation = annotation new_inchikey = "" if not compound_container.generic: new_inchikey = compound_container.inchikey model_metabolite.annotation[ "inchi_key"] = compound_container.inchikey model_metabolite.annotation[ "smiles"] = compound_container.smiles model_metabolite.formula = bigg_metabolite.get( "formulae")[0] charges = bigg_metabolite.get("charges") if charges: model_metabolite.charge = charges[0] compartment = model_metabolite.compartment if compartment is None: model_metabolite.compartment = "c" model_metabolite.name = bigg_metabolite.get("name") self.__check_if_id_is_used_in_model_and_delete_it( bigg_id + "_" + model_metabolite.compartment) model_metabolite.id = bigg_id + "_" + model_metabolite.compartment self.mapper.update_maps(old_inchikey, new_inchikey, old_id, model_metabolite.id, new_compound_ontology_id, old_aliases, new_aliases) else: self.__change_boimmg_format_metabolite( model_metabolite, compound_container) else: self.__change_boimmg_format_metabolite(model_metabolite, compound_container) else: self.__change_boimmg_format_metabolite(model_metabolite, compound_container) def __swap_kegg_metabolite(self, model_metabolite, new_compound_ontology_id): """ Method to swap a metabolite in the KEGG database format. This method tries to find the KEGG format of the new compound. If it does not find, it will change into the Model SEED format. :param Model.Metabolite model_metabolite: metabolite to be replaced. :param int new_compound_ontology_id: ontology identifier of the metabolite that will replace the other :return: """ old_inchikey = "" if "inchi_key" in model_metabolite.annotation.keys(): old_inchikey = model_metabolite.annotation["inchi_key"] old_aliases = AnnotationUtils.get_annotation_from_cobra_annotation( model_metabolite) old_id = model_metabolite.id model_metabolite.annotation = {} compound_container = self.__compounds_ontology.get_node_by_ont_id( new_compound_ontology_id) model_seed_id = compound_container.model_seed_id new_aliases = self.__compoundsIdConverter.get_all_aliases_by_modelSeedID( model_seed_id) if model_seed_id in self.__compoundsIdConverter.get_modelSeedIdToDb( ).keys(): if "KEGG" in self.__compoundsIdConverter.get_modelSeedIdToDb().get( model_seed_id): kegg_id = self.__compoundsIdConverter.convert_modelSeedId_into_other_dbID( model_seed_id, "KEGG")[0] kegg_metabolite = KeggCompound(kegg_id) annotation = AnnotationUtils.get_compound_annotation_format_by_aliases( new_aliases) model_metabolite.annotation = annotation new_inchikey = "" if not compound_container.generic: model_metabolite.annotation[ "inchi_key"] = compound_container.inchikey new_inchikey = compound_container.inchikey model_metabolite.annotation[ "smiles"] = compound_container.smiles model_metabolite.formula = kegg_metabolite.get_formula() model_metabolite.name = kegg_metabolite.get_name() model_metabolite.charge = 0 compartment = model_metabolite.compartment self.__check_if_id_is_used_in_model_and_delete_it(kegg_id + "_" + compartment) model_metabolite.id = kegg_id + "_" + compartment self.mapper.update_maps(old_inchikey, new_inchikey, old_id, model_metabolite.id, compound_container.id, old_aliases, new_aliases) else: self.__change_boimmg_format_metabolite(model_metabolite, compound_container) else: self.__change_boimmg_format_metabolite(model_metabolite, compound_container) def __change_boimmg_format_metabolite(self, model_metabolite: Metabolite, compound_container): """ This method changes the id of the metabolite arbitrarily. The format of the metabolite is set for the ontology format. It is worth noting that the :param compound_container can be either a ModelSeedCompound or an OntologyCompound :param Model.Metabolite model_metabolite: metabolite to be replaced. :param CompoundContainer compound_container: compound that will replace the other. :return: """ old_inchikey = "" if "inchi_key" in model_metabolite.annotation.keys(): old_inchikey = model_metabolite.annotation["inchi_key"] old_aliases = AnnotationUtils.get_annotation_from_cobra_annotation( model_metabolite) old_id = model_metabolite.id aliases = self.__compoundsIdConverter.get_all_aliases_by_modelSeedID( compound_container.model_seed_id) annotation = {} if aliases: annotation = AnnotationUtils.get_compound_annotation_format_by_aliases( aliases) annotation["boimmg.compound"] = self.__compoundsAnnotationConfigs["BOIMMG_ID_CONSTRUCTION"]+\ str(compound_container.id) new_aliases = {"BOIMMG": [annotation["boimmg.compound"]]} model_metabolite.annotation = annotation new_inchikey = "" if not compound_container.generic: model_metabolite.annotation[ "inchi_key"] = compound_container.inchikey new_inchikey = compound_container.inchikey model_metabolite.annotation["smiles"] = compound_container.smiles model_metabolite.formula = compound_container.formula model_metabolite.charge = compound_container.charge model_metabolite.name = compound_container.name compartment = model_metabolite.compartment id = self.__compoundsAnnotationConfigs["BOIMMG_ID_CONSTRUCTION"] + str( compound_container.id) new_metabolite_id = id + "_" + compartment self.__check_if_id_is_used_in_model_and_delete_it(new_metabolite_id) model_metabolite.id = new_metabolite_id self.mapper.update_maps(old_inchikey, new_inchikey, old_id, model_metabolite.id, compound_container.id, old_aliases, new_aliases) def __swap_modelseed_compound(self, model_metabolite: Metabolite, new_compound_ontology_id: int): """ Method to swap a metabolite in the Model SEED database format. This method tries to find the Model SEED format of the new compound. If it does not find, it will change into an arbitrary id with the Model SEED or the Ontology format. :param Model.Metabolite model_metabolite: metabolite to be replaced. :param int new_compound_ontology_id: ontology identifier of the metabolite that will replace the other :return: """ old_inchikey = "" if "inchi_key" in model_metabolite.annotation.keys(): old_inchikey = model_metabolite.annotation["inchi_key"] old_aliases = AnnotationUtils.get_annotation_from_cobra_annotation( model_metabolite) old_id = model_metabolite.id model_metabolite.annotation = {} compound_container = self.__compounds_ontology.get_node_by_ont_id( new_compound_ontology_id) new_aliases = self.__compoundsIdConverter.get_all_aliases_by_modelSeedID( compound_container.model_seed_id) annotation = AnnotationUtils.get_compound_annotation_format_by_aliases( new_aliases) model_metabolite.annotation = annotation new_inchikey = "" if not compound_container.generic: model_metabolite.annotation[ "inchi_key"] = compound_container.inchikey new_inchikey = compound_container.inchikey model_metabolite.annotation["smiles"] = compound_container.smiles model_metabolite.formula = compound_container.formula model_metabolite.charge = compound_container.charge compartment = model_metabolite.compartment db_id = compound_container.model_seed_id model_metabolite.name = compound_container.name if db_id: self.__check_if_id_is_used_in_model_and_delete_it( compound_container.model_seed_id + "_" + compartment) model_metabolite.id = compound_container.model_seed_id + "_" + compartment self.mapper.update_maps(old_inchikey, new_inchikey, old_id, model_metabolite.id, new_compound_ontology_id, old_aliases, new_aliases) else: self.__change_boimmg_format_metabolite(model_metabolite, compound_container) def __check_if_id_is_used_in_model_and_delete_it(self, id: int): """ This method checks whether a compound ID is used in the model and if so, it is removed :param id: compound identifier :return: """ inModel = self.model.metabolites.has_id(id) if inModel: metabolite = self.model.metabolites.get_by_id(id) self.model.remove_metabolites([metabolite]) def __get_game_changer_conjugates(self): """ This method searches for the conjugates of a given compound in model and assigns their conjugated acid or base; :return dict {ontology id : (metabolite already in model ? (boolean), COBRApy metabolite or ontology id)} """ conjugated_acid_in_model = self.__compounds_ontology.get_predecessors_by_ont_id_rel_type( self.__metabolite_in_model, "conjugated_acid_of") conjugated_base_in_model = self.__compounds_ontology.get_predecessors_by_ont_id_rel_type( self.__metabolite_in_model, "conjugated_base_of") game_changer = {} if conjugated_base_in_model: conjugated_base_to_change = self.__compounds_ontology.get_predecessors_by_ont_id_rel_type( self.__new_metabolite, "conjugated_base_of") game_changer.update( self.__add_conjugate_to_game_changer( "base", conjugated_base_in_model, conjugated_base_to_change)) if conjugated_acid_in_model: conjugated_acid_to_change = self.__compounds_ontology.get_predecessors_by_ont_id_rel_type( self.__new_metabolite, "conjugated_acid_of") game_changer.update( self.__add_conjugate_to_game_changer( "acid", conjugated_acid_in_model, conjugated_acid_to_change)) return game_changer def __get_game_changer(self): """ This method set the game changer. The game changer will be a dictionary with all of the necessary information to swap the compounds. The game changer will have a given compound intermediates, conjugated acid or/and base and the respective metabolites to replace them. :return dict: {ontology id : (metabolite already in model ? (boolean), COBRApy metabolite or ontology id)} """ intermediates_in_model = self.__compounds_ontology.get_all_predecessors_by_ont_id_rel_type( self.__metabolite_in_model, "precursor_of") conjugated_acid_in_model = self.__compounds_ontology.get_predecessors_by_ont_id_rel_type( self.__metabolite_in_model, "conjugated_acid_of") conjugated_base_in_model = self.__compounds_ontology.get_predecessors_by_ont_id_rel_type( self.__metabolite_in_model, "conjugated_base_of") intermediates_to_change = self.__compounds_ontology.get_all_predecessors_by_ont_id_rel_type( self.__new_metabolite, "precursor_of") # values -----> (met in model?, if true: cobraMetabolite else: ontId) game_changer = self.__add_to_game_changer(self.__metabolite_in_model, self.__new_metabolite) game_changer.update( self.__get_intermediates_game_changer(intermediates_in_model, intermediates_to_change)) if conjugated_acid_in_model: conjugated_acid_to_change = self.__compounds_ontology.get_predecessors_by_ont_id_rel_type( self.__new_metabolite, "conjugated_acid_of") game_changer.update( self.__add_conjugate_to_game_changer( "acid", conjugated_acid_in_model, conjugated_acid_to_change)) intermediates_in_model = self.__compounds_ontology.get_all_predecessors_by_ont_id_rel_type( conjugated_acid_in_model[0], "precursor_of") intermediates_to_change = self.__compounds_ontology.get_all_predecessors_by_ont_id_rel_type( conjugated_acid_to_change[0], "precursor_of") game_changer.update( self.__get_intermediates_game_changer(intermediates_in_model, intermediates_to_change)) if conjugated_base_in_model: conjugated_base_to_change = self.__compounds_ontology.get_predecessors_by_ont_id_rel_type( self.__new_metabolite, "conjugated_base_of") game_changer.update( self.__add_conjugate_to_game_changer( "base", conjugated_base_in_model, conjugated_base_to_change)) intermediates_in_model = self.__compounds_ontology.get_all_predecessors_by_ont_id_rel_type( conjugated_base_in_model[0], "precursor_of") intermediates_to_change = self.__compounds_ontology.get_all_predecessors_by_ont_id_rel_type( conjugated_base_to_change[0], "precursor_of") game_changer.update( self.__get_intermediates_game_changer(intermediates_in_model, intermediates_to_change)) return game_changer def __add_conjugate_to_game_changer(self, type: str, conjugated_in_model: list, new_conjugated: list) -> dict: """ This method add a conjugated acid or base to the game changer :param string type: "acid" or "base" :param list conjugated_in_model: ontology id of the conjugate to be replaced :param list new_conjugated: ontology id of the conjugate that will replace :return dict: {ontology id : (metabolite already in model ? (boolean), COBRApy metabolite or ontology id)} """ game_changer = {} if type == "base": metabolite_added = self.__add_to_game_changer( conjugated_in_model[0], new_conjugated[0]) game_changer.update(metabolite_added) elif type == "acid": metabolite_added = self.__add_to_game_changer( conjugated_in_model[0], new_conjugated[0]) game_changer.update(metabolite_added) return game_changer def __add_to_game_changer(self, met_in_model, new_met): """ This method add metabolites to the game changer :param int met_in_model: ontology id of the metabolite to be replaced :param int new_met: ontology id of the metabolite to be replaced :return dict: {ontology id : (metabolite already in model ? (boolean), COBRApy metabolite or ontology id)} """ game_changer = {} metabolite_container = self.__compounds_ontology.get_node_by_ont_id( new_met) inchikey = metabolite_container.inchikey aliases = self.__compoundsIdConverter.get_all_aliases_by_modelSeedID( metabolite_container.model_seed_id) metabolites_check_in_model = self.mapper.check_metabolites_in_model( inchikey, aliases) if met_in_model not in self.__metabolites_not_to_change: if metabolites_check_in_model: game_changer[met_in_model] = (True, []) for metabolite in metabolites_check_in_model: game_changer[met_in_model][1].append( metabolite ) # (met in model?, if true: [cobraMetabolite] else: ontId) else: game_changer[met_in_model] = (False, new_met) return game_changer else: if not metabolites_check_in_model: if metabolite_container.model_seed_id: ms_container = self.__compounds_db.get_compound_by_id( metabolite_container.model_seed_id) metabolites = self.generate_new_metabolites(ms_container) else: metabolites = self.generate_new_boimmg_metabolites( metabolite_container) self.model.add_metabolites(metabolites) return game_changer def _check_if_compound_is_generic(self, compound_id): """ This method check if some compound is generic or not :param int compound_id: ontology id of the metabolite :return boolean: is generic or not """ compound_container = self.__compounds_ontology.get_node_by_ont_id( compound_id) return compound_container.generic def __get_intermediates_game_changer(self, intermediates_in_model, intermediates_to_change): """ This method finds the correspondent substitute of each intermediate in the model :param list intermediates_in_model: list of ontology ids of the intermediates of the metabolite to be changed :param list intermediates_to_change: list of ontology ids of the intermediates of the metabolite that will replace :return dict: {ontology id : (metabolite already in model? (boolean), COBRApy metabolite or ontology id) } """ game_changer = {} if self.__type == 1: intermediates = self.__set_intermediates_in_game_changer_type1( intermediates_in_model, intermediates_to_change) game_changer.update(intermediates) elif self.__type == 2: intermediates = self.__set_intermediates_in_game_changer_type2( intermediates_in_model, intermediates_to_change) game_changer.update(intermediates) return game_changer def __set_intermediates_in_game_changer_type1(self, intermediates_in_model, intermediates_to_change): """ This method finds the correspondent substitute of each intermediate in the model for the type 1 game change :param list intermediates_in_model: list of ontology ids of the intermediates of the metabolite to be changed :param list intermediates_to_change: list of ontology ids of the intermediates of the metabolite that will replace :return dict: {ontology id : (metabolite already in model? (boolean), COBRApy metabolite or ontology id) } """ game_changer = {} for met in intermediates_in_model: parent_met_in_model = self.__compounds_ontology.get_successors_by_ont_id_rel_type( met, "is_a") i = 0 found = False while not found and i < len(intermediates_to_change): parent2 = self.__compounds_ontology.get_successors_by_ont_id_rel_type( intermediates_to_change[i], "is_a") if parent_met_in_model[0] == parent2[0]: found = True metabolite_added = self.__add_to_game_changer( met, intermediates_to_change[i]) game_changer.update(metabolite_added) i += 1 return game_changer def __set_intermediates_in_game_changer_type2(self, intermediates_in_model, intermediates_to_change): """ This method finds the correspondent substitute of each intermediate in the model for the type 2 game change :param list intermediates_in_model: list of ontology ids of the intermediates of the metabolite to be changed :param list intermediates_to_change: list of ontology ids of the intermediates of the metabolite that will replace :return dict: {ontology id : (metabolite already in model? (boolean), COBRApy metabolite or ontology id) } """ game_changer = {} isGenericInModel = self._check_if_compound_is_generic( intermediates_in_model[0]) self.__reactionsChanger.set_type2_is_generic_in_model(isGenericInModel) if isGenericInModel: for met in intermediates_in_model: i = 0 found = False while not found and i < len(intermediates_to_change): parent_met_to_change = self.__compounds_ontology.get_successors_by_ont_id_rel_type( intermediates_to_change[i], "is_a") if met in parent_met_to_change: game_changer.update( self.__add_to_game_changer( met, intermediates_to_change[i])) found = True i += 1 else: for met in intermediates_in_model: i = 0 found = False while not found and i < len(intermediates_to_change): children = self.__compounds_ontology.get_predecessors_by_ont_id_rel_type( intermediates_to_change[i], "is_a") if met in children: game_changer.update( self.__add_to_game_changer( met, intermediates_to_change[i])) found = True i += 1 return game_changer def __get_metabolite_container_by_id(self, id): """ This method searches for a given metabolite in the Model :param string id: id in the Model :return Model.metabolite: if the metabolite is found returns the metabolite, otherwise returns None """ for met in self.model.metabolites: if met.id == id: return met return None def change_reaction_format(self, reaction): """ This method changes a given reaction format. :param Model.Reaction reaction: reaction to be changed :return: """ self.__reactionsChanger.swap_reactions([reaction]) def __check_if_compound_exists_in_model_by_ontology_id(self, ontology_id): """ Method to check whether a compound exists in the model using BOIMMG ID :param int ontology_id: boimmg id :return list<Compound>: list of compounds in model with this ID (list of the same compound in different compartments) """ container = self.__compounds_ontology.get_node_by_ont_id(ontology_id) inchikey = container.inchikey aliases = {} if container.model_seed_id: aliases = self.__compoundsIdConverter.get_all_aliases_by_modelSeedID( container.model_seed_id) aliases.update(container.aliases) return self.mapper.check_metabolites_in_model(inchikey, aliases, container) def generate_new_metabolites(self, compound_container: ModelSeedCompound): """ This method will generate a new set of compounds (same metabolite in different compartments) :param ModelSeedCompound compound_container: internal wrappers of the ModelSEED compounds :return list<Metabolite>: list of newly generated compounds """ model_metabolites = \ model_utilities.generate_model_compounds_by_database_format(self.model, compound_container.getDbId(), self.__compoundsIdConverter, self.__compounds_db, self.__model_database) self.model.add_metabolites(model_metabolites) self.mapper.add_new_metabolites_to_maps(model_metabolites) return model_metabolites def generate_new_boimmg_metabolites(self, metabolite_container: CompoundNode): """ This method will generate a new set of compounds (same metabolite in different compartments) :param CompoundNode metabolite_container: wrapper of BOIMMG compound :return list<Metabolite>: list of newly generated compounds """ metabolites = model_utilities.generate_boimmg_metabolites( self.model, metabolite_container, self.__model_database, self.__compoundsIdConverter, self.__compoundsAnnotationConfigs) self.model.add_metabolites(metabolites) self.mapper.add_new_metabolites_to_maps(metabolites) return metabolites def setType2_isGenericInModel(self, isGeneric): self.__reactionsChanger.set_type2_is_generic_in_model(isGeneric) def set_model_mapper(self, mapper): self.mapper = mapper
class SimpleCaseSolver(): def __init__(self, model: Model, database_format: str, db_accessor=CompoundsDBAccessor()): """ Class constructor :param Model model: model being analysed :param database_format: database format (ModelSEED, BiGG or KEGG) :param modelseed_compoundsdb: """ self.__universal_model = Model("universal_model") self.model = model self.__database_format = database_format self.__configs = file_utilities.read_conf_file(TOOL_CONFIG_PATH) self.__home_path__ = ROOT_DIR self.__compounds_ontology = db_accessor self.__modelseedCompoundsDb = ModelSeedCompoundsDB() self.__define_instance_variables() def dump_maps(self, destination: str): """ It creates a dump of all the model metabolite maps :param str destination: destination folder :return: """ self.__mapper.create_map_dump(destination) def load_maps(self, folder): """ Load all the metabolite maps in a given folder :param str folder: folder path :return: """ self.__mapper.upload_maps(folder) def map_model(self): """ Creates maps for all the metabolites in the model :return: """ start = time.time() self.write_in_progress_bar("mapping the model... ", 10) self.__mapper.map_model(self.__database_format) self.write_in_progress_bar("model mapped ", 31) finished = time.time() logger.info("mapping finished: %d" % (finished - start)) def write_in_progress_bar(self, message: str, value: float): """ Write information related to the progress bar :param str message: message of what is being done :param float value: value to assign in the progress bar :return: """ with open(PROGRESS_BAR, "w") as file: file.write(message + ":" + str(value)) def get_progress_bar_state(self) -> float: """ This method reads the progress bar message and the respective value :return float state: value to assign in the progress bar """ with open(PROGRESS_BAR, "r") as file: line = file.read() line = line.strip() state = line.split(":")[1] return float(state) def calculate_division_for_progress_bar(self, state, total_processes_left): left = 100 - state for_each_part = left / total_processes_left return for_each_part @property def model(self): return self.__model @model.setter def model(self, value): if isinstance(value, Model): self.__model = value else: raise ValueError("introduce a cobrapy model") def __define_instance_variables(self): """ Method to define a set of instance values :return: """ self.__swapped = [] self.lineage = [] # self.__compounds_ontology = CompoundsDBAccessor() self.__compoundsAnnotationConfigs = file_utilities.read_conf_file( COMPOUNDS_ANNOTATION_CONFIGS_PATH) self.__reactionsAnnotationConfigs = file_utilities.read_conf_file( REACTIONS_ANNOTATION_CONFIGS_PATH) self.__compoundsAnnotationConfigs = file_utilities.read_conf_file( COMPOUNDS_ANNOTATION_CONFIGS_PATH) self.__reactionsAnnotationConfigs = file_utilities.read_conf_file( REACTIONS_ANNOTATION_CONFIGS_PATH) self.__compoundsIdConverter = CompoundsIDConverter() # self.__ptw_handler_quinones = PathwayHandler(self.__modelseedCompoundsDb, self.__compoundsIdConverter) # self.__ptw_handler_quinones.load_from_file(self.__home_path__ + self.__configs["quinones_pathways"]) self.__not_to_change_classes = ["cpd03476"] self.__set_not_to_change_compounds() self.__compounds_revisor = CompoundsRevisor(self.model, self.__universal_model) biocyc.set_organism("meta") self.__swapper = MetaboliteSwapper( self.model, None, None, 0, self.__modelseedCompoundsDb, model_database=self.__database_format, compoundsIdConverter=self.__compoundsIdConverter, universal_model=self.__universal_model, not_to_change_compounds=self.__not_to_change_compounds) self.__mapper = ModelMapper(self.model, self.__compoundsAnnotationConfigs, self.__compoundsIdConverter) self.__swapper.set_model_mapper(self.__mapper) self.__compounds_revisor.set_model_mapper(self.__mapper) def __set_not_to_change_compounds(self): """ One would want to protect few compounds of being changed. :return: """ self.__not_to_change_compounds = [] for compound_class in self.__not_to_change_classes: parent_id = self.__compounds_ontology.get_node_id_from_model_seed_id( compound_class) children = self.__compounds_ontology.get_predecessors_by_ont_id_rel_type( parent_id, "is_a") self.__not_to_change_compounds.extend(children) def swap_compound(self, compound_in_model: str, compound_to_change: str, compounds_left=1): """ This method aims at swapping all the biosynthetic precursors, and the conjugated acid and base of a given target. It accepts all types of changes. :param str compound_in_model: compound in model :param str compound_to_change: compound to replace the one in the model :param str compounds_left: compounds left in the swapping operation :return: """ if not self.__mapper.mapped: self.map_model() compound_in_model = self.transform_input_into_boimmg_ids( compound_in_model) if not compound_to_change: exit(2) compound_to_change = self.transform_input_into_boimmg_ids( compound_to_change) if not compound_to_change: exit(2) compound_in_model_node = self.__compounds_ontology.get_node_by_ont_id( compound_in_model) compound_to_change_node = self.__compounds_ontology.get_node_by_ont_id( compound_to_change) state = self.get_progress_bar_state() per_iteration = self.calculate_division_for_progress_bar( state, compounds_left) self.write_in_progress_bar( "Swapping " + compound_in_model_node.name + " to " + compound_to_change_node.name, state) logger.info( "Swapping " + compound_in_model_node.name + " to " + compound_to_change_node.name, state) type = 0 if compound_in_model_node.generic and not compound_to_change_node.generic: parents = self.__compounds_ontology.get_successors_by_ont_id_rel_type( compound_to_change, "is_a") if compound_in_model in parents: type = 2 else: type = 3 elif compound_to_change_node.generic and not compound_in_model_node.generic: parents = self.__compounds_ontology.get_successors_by_ont_id_rel_type( compound_in_model, "is_a") if compound_to_change in parents: type = 2 else: type = 3 elif not compound_to_change_node.generic and not compound_in_model_node.generic: parents1 = self.__compounds_ontology.get_successors_by_ont_id_rel_type( compound_in_model, "is_a") parents2 = self.__compounds_ontology.get_successors_by_ont_id_rel_type( compound_to_change, "is_a") if parents1 and parents2: if parents1[0] == parents2[0]: type = 1 else: type = 2 if type != 0: self.__swapper.set_type(type) self.__swapper.set_compound_in_model(compound_in_model) self.__swapper.set_new_compound(compound_to_change) self.__swapper.swap_metabolites() else: self.__swapper.set_type(type) self.__swapper.set_compound_in_model(compound_in_model) self.__swapper.set_new_compound(compound_to_change) self.__swapper.swap_only_metabolites_and_conjugates() self.write_in_progress_bar("Swap performed", per_iteration) logger.info("Swap performed") def __check_if_compound_exists_in_model_by_ontology_id( self, ontology_id: int) -> list: """ This method will check whether a BOIMMG compound exists in the model. :param int ontology_id: BOIMMG id :return list: compounds in model """ res = [] for model_id, boimmg_id in self.__mapper.boimmg_db_model_map.items(): if boimmg_id == ontology_id: model_compound_container = self.model.metabolites.get_by_id( model_id) res.append(model_compound_container) return res def __replace_electron_donors_and_acceptors(self): """ This method will swap all the generic electron donors and acceptors eventually added when introducing MetaCyc reactions. :return: """ donor_model_seed_id = "cpd26978" electron_transfer_quinol = 749301 ontology_id = self.__compounds_ontology.get_node_id_from_model_seed_id( donor_model_seed_id) container = self.__compounds_ontology.get_node_by_ont_id(ontology_id) inchikey = container.inchikey aliases = self.__compoundsIdConverter.get_all_aliases_by_modelSeedID( donor_model_seed_id) metabolites_in_model = self.__mapper.check_metabolites_in_model( inchikey, aliases) self.__swapper.set_compound_in_model(ontology_id) self.__swapper.set_type(0) if metabolites_in_model: leaves = self.__compounds_ontology.get_leaves_from_ont_id( ontology_id) for metabolite in metabolites_in_model: compartment = metabolite.compartment found_leaf = False i = 0 while not found_leaf and i < len(leaves): parents = self.__compounds_ontology.get_all_parents( leaves[i]) if electron_transfer_quinol not in parents: leaf_container = self.__compounds_ontology.get_node_by_ont_id( leaves[i]) modelseedid = leaf_container.model_seed_id inchikey = leaf_container.inchikey aliases = self.__compoundsIdConverter.get_all_aliases_by_modelSeedID( modelseedid) metabolites_in_model_to_change = \ self.__mapper.check_metabolites_in_model(inchikey, aliases, leaf_container) found_compartment_leaf = False j = 0 while not found_compartment_leaf and j < len( metabolites_in_model_to_change): if metabolites_in_model_to_change[ j].compartment == compartment: found_compartment_leaf = True found_leaf = True self.__swapper.set_new_compound(leaves[i]) self.__swapper.swap_only_metabolites_and_conjugates( metabolite, metabolites_in_model_to_change[j]) else: j += 1 i += 1 def __swap_metabolites(self, metabolite_in_model: int, new_metabolite: int, type: int, target=False) -> list: """ This method aims at calling the MetaboliteSwapper to swap a given metabolite, their biosynthetic precursors and their conjugated base and acid, eventually. :param int metabolite_in_model: BOIMMG id of the metabolite in model :param int new_metabolite: BOIMMG id of the new metabolite :param int type: type of swap :param boolean target: whether the new metabolite is the target metabolite or not :return: """ self.__swapper.set_compound_in_model(metabolite_in_model) self.__swapper.set_new_compound(new_metabolite) self.__swapper.set_type(type) if type == 2: self.__type_2_isGeneric_setter(metabolite_in_model) if not target: changed_reactions = self.__swapper.swap_only_metabolites_and_conjugates( ) self.__swapped.append(new_metabolite) else: changed_reactions = self.__swapper.swap_metabolites() self.__universal_model = self.__swapper.get_universal_model() return changed_reactions def __type_2_isGeneric_setter(self, metabolite_in_model): container = self.__compounds_ontology.get_node_by_ont_id( metabolite_in_model) if container.generic: self.__swapper.setType2_isGenericInModel(True) else: self.__swapper.setType2_isGenericInModel(False) def __check_and_change_all_children(self, parent: int, new_metabolite: int, target=False) -> list: """ This method absorbs all the compounds of a specific chemical type and swap them into the :param new_metabolite :param int parent: BOIMMG id of the structural parent :param int new_metabolite: BOIMMG id of the metabolite that will prevail :param boolean target: whether the new metabolite is the target or not :return list: changed reactions """ children = self.__compounds_ontology.get_predecessors_by_ont_id_rel_type( parent, "is_a") changed_reactions = [] for child in children: if child != new_metabolite: child_container = self.__compounds_ontology.get_node_by_ont_id( child) aliases = AliasesTransformer.transform_boimmg_aliases_into_model_seed( child_container.aliases) model_seed_id = child_container.model_seed_id if model_seed_id: converted_aliases = self.__compoundsIdConverter.get_all_aliases_by_modelSeedID( model_seed_id) merged_aliases = self.merge_dictionaries( converted_aliases, aliases) child_in_model = self.__mapper.check_metabolites_in_model( child_container.inchikey, merged_aliases) else: child_in_model = self.__mapper.check_metabolites_in_model( child_container.inchikey, child_container.aliases, child_container) if child_in_model: changed_reactions = self.__swap_metabolites( child, new_metabolite, 1, target) return changed_reactions def convert_aliases_into_mapper_format(self, aliases): """ Such method can convert the aliases from retrieved from ModelSEED into the mapper format :param dict aliases: aliases from ModelSEED :return dict new_aliases: the converted dictionary """ new_aliases = {} for alias in aliases: if alias in self.__compoundsAnnotationConfigs.keys(): new_key = self.__compoundsAnnotationConfigs[alias] new_aliases[new_key] = aliases[alias] return new_aliases @staticmethod def merge_dictionaries(dict1, dict2): for key in dict1: if key in dict2: dict1[key].extend(dict2[key]) return dict1 def generate_new_metabolite(self, compound_container): """ Such method generates a whole new metabolite using a ModelSEED compound wrapper or a CompoundNode :param compound_container: ModelSEED compound wrapper :return list: list of newly generated metabolites """ if isinstance(compound_container, ModelSeedCompound): model_metabolites = \ model_utilities.generate_model_compounds_by_database_format(self.model, compound_container.getDbId(), self.__compoundsIdConverter, self.__modelseedCompoundsDb, self.__database_format) elif isinstance(compound_container, CompoundNode): model_metabolites = model_utilities.generate_model_compounds_by_database_format( self.model, compound_container.model_seed_id, self.__compoundsIdConverter, self.__modelseedCompoundsDb, self.__database_format) else: raise ValueError("Not expected type") self.__model.add_metabolites(model_metabolites) self.__mapper.add_new_metabolites_to_maps(model_metabolites) return model_metabolites def generate_new_boimmg_metabolite(self, boimmg_container: CompoundNode) -> list: """ Such method generates new BOIMMG compounds and adds them to the model (same compound in different compartments) :param CompoundNode boimmg_container: BOIMMG container for model addition :return list<Metabolite>: list of model metabolites in different compartments """ model_metabolites = model_utilities.generate_boimmg_metabolites( self.model, boimmg_container, self.__database_format, self.__compoundsIdConverter, self.__compoundsAnnotationConfigs, ) self.__model.add_metabolites(model_metabolites) self.__mapper.add_new_metabolites_to_maps(model_metabolites) return model_metabolites def add_metabolites_to_model(self, metabolites): for metabolite in metabolites: container = self.__compounds_ontology.get_node_by_ont_id( metabolite) metabolites_in_model = self.__mapper.check_metabolites_in_model( container.inchikey, container.aliases, container) if not metabolites_in_model: if container.model_seed_id: ms_container = self.__modelseedCompoundsDb.get_compound_by_id( container.model_seed_id) self.generate_new_metabolite(ms_container) else: self.generate_new_boimmg_metabolite(container) def transform_input_into_boimmg_ids(self, target: str) -> str: """ Method that converts a target ID from an external database into BOIMMG's :param str target: target identifier of an external database :return str: boimmg identifier """ accessor = CompoundsDBAccessor() boimmg_prefix = self.__compoundsAnnotationConfigs[ "BOIMMG_ID_CONSTRUCTION"] target_res = self._transform_database_ids_into_boimmg_ids( target, accessor, boimmg_prefix) return target_res def _transform_database_ids_into_boimmg_ids(self, target: str, accessor: CompoundsDBAccessor, boimmg_prefix: str) -> str: """ Such method transforms a target ID from an external database into BOIMMG's :param str target: target identifier from an external database :param CompoundsDBAccessor accessor: :param str boimmg_prefix: BOIMMG prefix :return: """ targets_res = '' if boimmg_prefix in target: targets_res = int(target.replace(boimmg_prefix, "")) elif re.match("^[0-9]*$", target): targets_res = int(target) elif "cpd" not in target: model_seed_ids = self.__compoundsIdConverter.convert_db_id_to_model_seed_by_db_id( target) else: model_seed_ids = [target] if not targets_res: for model_seed_id in model_seed_ids: node1 = accessor.get_node_from_model_seed_id(model_seed_id) if node1: targets_res = node1.id break return targets_res