예제 #1
0
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
예제 #2
0
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
예제 #3
0
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