Exemple #1
0
    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)
Exemple #2
0
    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)
Exemple #3
0
    def define_instance_variables(self):
        """
        Define instance variables

        :return:
        """

        self.report_material = {}
        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.reactions_swapper = ReactionsChanger(
            self.model,
            self.__type,
            self.__model_database,
            self.__universal_model,
            compounds_converter=self.__compoundsIdConverter)
Exemple #4
0
    def __check_generic_complete_relationship(self,reactants,products,reaction):

        generic_reactants = []
        complete_reactants = []
        generic_products = []
        complete_products = []

        compounds_ontology = CompoundsDBAccessor()

        for reactant in reactants:
            if reactant.generic:
                generic_reactants.append(reactant)
            else:
                complete_reactants.append(reactant)

        for product in products:
            if product.generic:
                generic_products.append(product)
            else:
                complete_products.append(product)

        if len(complete_reactants) == len(generic_products) or len(generic_reactants) == len(complete_products):
            return True

        elif not generic_reactants and not generic_products:
            reactants_components = []
            products_components = []

            reactants_components_dict = {}
            products_components_dict = {}


            for complete_reactant in complete_reactants:
                reactant_components = compounds_ontology.get_predecessors_by_ont_id_rel_type(complete_reactant.id,"component_of")
                reactants_components.append(reactant_components)
                reactants_components_dict[complete_reactant.id] = reactant_components


            for complete_product in complete_products:
                product_components = compounds_ontology.get_predecessors_by_ont_id_rel_type(complete_product.id,"component_of")
                products_components.append(product_components)
                products_components_dict[complete_product.id] = products_components

            reactants_components = sorted(reactants_components)
            products_components = sorted(products_components)

            if reactants_components!=products_components:
                deleted = self.__delete_components_from_reaction(reactants_components,
                                                       products_components,reactants_components_dict,
                                                       products_components_dict,reaction)

                if deleted:
                    return True

                else:
                    return False

        return True
Exemple #5
0
    def get_targets_to_replace_by_type(self, target: int):
        compounds_ontology = CompoundsDBAccessor()

        res = {}
        precursors = compounds_ontology.get_all_predecessors_by_ont_id_rel_type(
            target, "precursor_of")

        for precursor in precursors:
            parent = compounds_ontology.get_successors_by_ont_id_rel_type(
                precursor, "is_a")

            if parent[0] in res:
                res.get(parent[0]).append(precursor)
            else:
                res[parent[0]] = [precursor]
        return res
Exemple #6
0
    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
Exemple #7
0
    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
Exemple #8
0
    def define_instance_variables(self):
        """
        Instance variables definition

        :return:
        """

        self.__compounds_ontology = CompoundsDBAccessor()

        self.__added_reactions_and_respective_target = {}

        self.__reactionsAnnotationConfigs = file_utilities.read_conf_file(
            REACTIONS_ANNOTATION_CONFIGS_PATH)

        self.metabolite_report_material = {}
        self.reaction_report_material = {}
        self.__set_components()
Exemple #9
0
    def __init__(self, model, compoundsAnnotationConfigs,
                 compoundsIdConverter):
        self.model = model
        self.__compoundsAnnotationConfigs = compoundsAnnotationConfigs
        self.__compoundsIdConverter = compoundsIdConverter
        self.__compounds_ontology = CompoundsDBAccessor()

        self.mapped = False

        self.boimmg_db_model_map = {}

        self.boimmg_db_model_map_reverse = {}

        self.compounds_aliases_indexation = {}

        self.compound_inchikey_indexation = {}

        self.__compounds_aliases_indexation_reverse = {}
Exemple #10
0
    def test_components_scraping(self):
        db_acessor = CompoundsDBAccessor()
        components = [200, 437, 436, 129]

        all_new_met = []
        compounds = db_acessor.get_compounds_with_specific_parent_within_set_of_components(
            12, components)
        for compound in compounds:
            precursors = db_acessor.get_all_predecessors_by_ont_id_rel_type(
                compound, "precursor_of")
            all_new_met.extend(precursors)

        # res = []
        # for new_met in all_new_met:
        #     if new_met not in res:
        #         res.append(new_met)

        print(len(all_new_met))
Exemple #11
0
    def define_instance_variables(self):
        """
        Instance variables definition

        :return:
        """

        self.__compounds_ontology = CompoundsDBAccessor()

        self.__added_reactions_and_respective_target = {}

        self.__reactionsAnnotationConfigs = file_utilities.read_conf_file(
            REACTIONS_ANNOTATION_CONFIGS_PATH)

        print("setting components...")
        start = time.time()
        self.__set_components()
        end = time.time()
        print("components set: %d" % (end - start))
def integrate_quinones():
    accessor = CompoundsDBAccessor()
    ele_quinone = accessor.get_predecessors_by_ont_id_rel_type(749300, "is_a")
    ele_quinol = accessor.get_predecessors_by_ont_id_rel_type(749301, "is_a")

    for ele_quinon in ele_quinone:

        ele_quinone_precursors = accessor.get_all_predecessors_by_ont_id_rel_type(
            ele_quinon, "precursor_of")

        for pre in ele_quinone_precursors:
            accessor.add_relationship(pre, 321415, "is_a")

    for ele_quino in ele_quinol:

        ele_quinone_precursors = accessor.get_all_predecessors_by_ont_id_rel_type(
            ele_quino, "precursor_of")

        for pre in ele_quinone_precursors:
            accessor.add_relationship(pre, 321415, "is_a")
Exemple #13
0
    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
Exemple #14
0
    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.report_material = {}
        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()
Exemple #15
0
    def check_compounds_representation_and_balance_reactions(self, reactions:list):

        res = []
        self.__get_hydrogen_from_model()

        compounds_ontology = CompoundsDBAccessor()

        to_remove = []
        for reaction in reactions:

            reaction_ontology_reactants = []
            reaction_ontology_products = []

            for compound in reaction.reactants:
                aliases = AnnotationUtils.get_annotation_from_cobra_annotation(compound)
                found = False
                for key in aliases:
                    for alias in aliases[key]:
                        new_key = self.compoundsAnnotationConfigs.get(key)

                        if key == "BOIMMG":
                            id = self.get_boimmg_id_from_annotation(aliases[key])
                            container = compounds_ontology.get_node_by_ont_id(id)

                            reaction_ontology_reactants.append(container)
                            found = True
                            break

                        elif new_key in self.__mapper.compounds_aliases_indexation.keys():
                            entities = self.__mapper.compounds_aliases_indexation.get(new_key).get(alias)
                            if entities:
                                for entity in entities:
                                    entity_id = entity.id

                                    if entity_id in self.__mapper.boimmg_db_model_map:

                                        ont_id = self.__mapper.boimmg_db_model_map.get(entity_id)
                                        entity_container = compounds_ontology.get_node_by_ont_id(ont_id)
                                        reaction_ontology_reactants.append(entity_container)
                                        found = True
                                        break
                    if found:
                        break


            for compound in reaction.products:

                found = False
                aliases = AnnotationUtils.get_annotation_from_cobra_annotation(compound)
                for key in aliases:
                    new_key = self.compoundsAnnotationConfigs.get(key)
                    for alias in aliases[key]:

                        if key == "BOIMMG":

                            id = self.get_boimmg_id_from_annotation(aliases[key])

                            container = compounds_ontology.get_node_by_ont_id(id)

                            reaction_ontology_products.append(container)
                            found = True
                            break


                        elif new_key in self.__mapper.compounds_aliases_indexation.keys():

                            entities = self.__mapper.compounds_aliases_indexation.get(new_key).get(alias)
                            if entities:
                                for entity in entities:
                                    entity_id = entity.id

                                    if entity_id in self.__mapper.boimmg_db_model_map:

                                        ont_id = self.__mapper.boimmg_db_model_map.get(entity_id)
                                        entity_container = compounds_ontology.get_node_by_ont_id(ont_id)
                                        reaction_ontology_products.append(entity_container)
                                        found = True
                                        break

                    if found:
                        break

            # self.__check_generic_complete_relationship(reaction_ontology_reactants,reaction_ontology_products,reaction)

            # if reaction_ontology_reactants and reaction_ontology_products:
            balanced = self.check_balanced_reaction(reaction)

            if not balanced:
                to_remove.append(reaction)

            else:
                res.append(reaction)

                # if generalization:
                #     self.__check_if_generic_complete_relationship()

        # print("reactions to remove: ")
        # print(to_remove)
        self.__model.remove_reactions(to_remove)
        return res
Exemple #16
0
class Granulator:
    def __init__(self, model: Model, mapper: ModelMapper, database_format: str,
                 id_converter: CompoundsIDConverter,
                 compoundsAnnotationConfigs: dict):
        """
        Class constructor

        :param Model model: Cobrapy model
        :param ModelMapper mapper: model mapper
        :param str database_format: ModelSEED, KEGG or BiGG
        :param CompoundsIDConverter id_converter:
        :param dict compoundsAnnotationConfigs: compounds annotation configurations
        """

        self.__compoundsAnnotationConfigs = compoundsAnnotationConfigs
        self.__model = model
        self.__compoundsIdConverter = id_converter
        self.__modelseedCompoundsDb = ModelSeedCompoundsDB()
        self.__database_format = database_format
        self.mapper = mapper

        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 virtual_model_mapper(self):
        return self.__virtual_model_mapper

    @virtual_model_mapper.setter
    def virtual_model_mapper(self, value):
        self.__virtual_model_mapper = value

    def define_instance_variables(self):
        """
        Instance variables definition

        :return:
        """

        self.__compounds_ontology = CompoundsDBAccessor()

        self.__added_reactions_and_respective_target = {}

        self.__reactionsAnnotationConfigs = file_utilities.read_conf_file(
            REACTIONS_ANNOTATION_CONFIGS_PATH)

        self.metabolite_report_material = {}
        self.reaction_report_material = {}
        self.__set_components()

    def set_virtual_model(self, virtual_model, virtual_model_mapper,
                          virtual_compounds_revisor):

        self.__virtual_model = virtual_model
        self.__virtual_compounds_revisor = virtual_compounds_revisor
        self.__virtual_model_mapper = virtual_model_mapper

    def write_in_progress_bar(self, message, value):
        with open(PROGRESS_BAR, "w") as file:
            file.write(message + ":" + str(value))

    def get_progress_bar_state(self):
        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,
                                            total_processes_left):
        left = 100 - state
        for_each_part = left / total_processes_left
        for_each_iteration = for_each_part / total

        return for_each_iteration

    def granulate(self, target_generic_ontology_id, components,
                  same_components, progress_bar_processes_left):
        """
        Operation to granulate a given compound:

            1st: Build up structurally defined compounds using the information on the components list. It builds up
            compounds by mixing :param components if :param same_components is False, otherwise it builds up compounds
            without a mix of :param components.

            2nd: Calls a function to generate the whole biosynthetic pathway of all the built up compounds.

        :param int target_generic_ontology_id: generic compound database identifier
        :param list<int> components: list of BOIMMG identifiers of all the requested components
        :param bool same_components:
        :param int progress_bar_processes_left:
        :return:
        """

        if same_components:
            targets_to_replace = \
                self.__compounds_ontology.get_compounds_with_only_one_component(target_generic_ontology_id, components)

        else:
            targets_to_replace = \
                self.__compounds_ontology.get_compounds_with_specific_parent_within_set_of_components(
                    target_generic_ontology_id,
                    components)

        targets_to_replace = self.filter_targets_to_replace(
            targets_to_replace, target_generic_ontology_id)

        state = self.get_progress_bar_state()
        for_each_iteration = self.calculate_division_for_progress_bar(
            state, len(targets_to_replace), progress_bar_processes_left)

        for target in targets_to_replace:

            self.write_in_progress_bar(
                "generating network for C_BOIMMG_" + str(target), state)
            self.handle_target_in_virtual_model(target,
                                                target_generic_ontology_id)
            state += for_each_iteration

    def handle_target_in_virtual_model(self, target: int, parent: int):
        """
        Method to granulate a given lipid target in the virtual model.

            1st: Processes the target biosynthesis pathway;
            2nd: Balance the granulated reactions in the previously processed biosynthesis pathway;
            3rd: Adds them to the model

        :param int target: lipid target BOIMMG identifier (structurally defined)
        :param int parent: lipid parent BOIMMG identifier (generic lipid)
        :return:
        """

        granulated_reactions = self.__process_biosynthesis_pathway(
            target, parent)

        granulated_reactions = self.__virtual_compounds_revisor.balance_reactions(
            granulated_reactions)

        reactions_to_add = deepcopy(granulated_reactions)

        self.__add_new_reactions_to_model(reactions_to_add)

    def identify_biosynthesis_pathway(self,
                                      target_generic_ontology_id: int) -> list:
        """
        Identifies the biosynthesis pathway of a given generic lipid.

        :param int target_generic_ontology_id:
        :return list<Reaction>: list of reactions
        """

        reactions_to_delete = self.get_target_associated_network(
            target_generic_ontology_id)

        return reactions_to_delete

    def __process_biosynthesis_pathway(self, target: int, parent: int) -> list:
        """
        Granulates the biosynthesis pathway of a given target lipid. It uses a "processing" stack to process each reaction
        and each new structurally defined lipid. When the stack is empty it is assumed the pathway to be fully processed.

        :param int target: lipid target BOIMMG identifier (structurally defined)
        :param int parent: lipid parent BOIMMG identifier (generic lipid)
        :return list<Reaction>: list of granulated reactions
        """

        processed_compounds = []
        new_compounds = [(target, parent)]
        granulated_reactions = []

        while new_compounds:
            new_compound_and_parent = new_compounds.pop()

            if new_compound_and_parent[0] not in processed_compounds:

                new_reactions, added_compounds = self.__process_new_compound(
                    new_compound_and_parent)

                processed_compounds.append(new_compound_and_parent[0])

                self.__add_new_reactions_to_virtual_model(new_reactions)

                granulated_reactions.extend(new_reactions)

                new_compounds.extend(added_compounds)

        return granulated_reactions

    def __process_new_compound(self, new_compound_and_parent: tuple):
        """
        Processes a new compound

        :param tuple new_compound_and_parent: (structurally defined compound, its generic parent)
        :return:
        """

        new_compound = new_compound_and_parent[0]

        parent = new_compound_and_parent[1]
        model_boimmg_parents = self.virtual_model_mapper.check_if_boimmg_metabolite_in_model(
            parent)

        if not model_boimmg_parents:
            exit(2)
            raise Exception("please introduce a mapped biosynthetic target")

        parent_and_precursors = self.get_targets_to_replace_by_type(
            new_compound)

        new_reactions = []

        added_compounds = []

        processed = []
        for model_parent in model_boimmg_parents:

            if model_parent not in processed:
                cobra_model_parent = self.__virtual_model.metabolites.get_by_id(
                    model_parent)
                reactions_to_process = self.get_reactions_by_compound(
                    cobra_model_parent)

                for reaction_to_process in reactions_to_process:

                    if reaction_to_process.id not in self.__added_reactions_and_respective_target.keys() or \
                            new_compound not in self.__added_reactions_and_respective_target[reaction_to_process.id]:

                        go = True
                        compounds_ids = [
                            comp.id for comp in reaction_to_process.products
                        ]

                        if go and model_parent in compounds_ids:
                            new_reaction, added = self._process_reaction(
                                reaction_to_process, new_compound,
                                cobra_model_parent, parent_and_precursors)

                            if reaction_to_process.id in self.reaction_report_material:
                                self.reaction_report_material[
                                    reaction_to_process.id].append(
                                        new_reaction.id)
                            else:
                                self.reaction_report_material[
                                    reaction_to_process.id] = [
                                        new_reaction.id
                                    ]

                            new_reactions.append(new_reaction)

                            for compound in added:
                                if compound not in added_compounds:
                                    added_compounds.append(compound)

                            if reaction_to_process.id not in self.__added_reactions_and_respective_target.keys(
                            ):
                                self.__added_reactions_and_respective_target[
                                    reaction_to_process.id] = [new_compound]

                            else:
                                self.__added_reactions_and_respective_target[
                                    reaction_to_process.id].append(
                                        new_compound)

                processed.append(model_parent)

        return new_reactions, added_compounds

    def get_reactions_by_compound(self, compound):

        res = []
        for reaction in self.__virtual_model.reactions:
            metabolites_ids = [m.id for m in reaction.metabolites]

            if compound.id in metabolites_ids:
                res.append(reaction)

        return res

    def _process_reaction(
        self, reaction_to_process: Reaction, new_compound: int,
        model_parent: Metabolite, parent_and_precursors: dict
    ) -> Tuple[Reaction, List[Tuple[Metabolite, int]]]:
        """
        Granulates the :param reaction_to_process

        :param Reaction reaction_to_process: reaction in model to be granulated
        :param int new_compound: structurally defined lipid BOIMMG identifier
        :param Metabolite model_parent: model generic lipid
        :param dict parent_and_precursors: {parent: [children]} -> children of the generic precursors
        :return tuple: the granulated reaction in the cobrapy Reaction object and list of tuples: (added compound, BOIMMG ID)
        """

        new_reaction = deepcopy(reaction_to_process)

        new_reaction_products = list(new_reaction.products)

        new_reaction, added = self.__process_reaction(new_reaction,
                                                      new_compound,
                                                      model_parent,
                                                      parent_and_precursors,
                                                      new_reaction_products)

        reaction_id = self.change_boimmg_reaction_id(new_reaction)

        new_reaction.id = reaction_id

        return new_reaction, added

    def change_boimmg_reaction_id(self, reaction: Reaction) -> str:
        """
        Changes the reaction ID into a cannonical BOIMMG reaction identifier

        :param Reaction reaction:
        :return str: new identifier
        """

        new_id = self.__reactionsAnnotationConfigs["BOIMMG_ID_CONSTRUCTION"]

        metabolites = reaction.metabolites

        metabolites = sorted([metabolite.id for metabolite in metabolites])
        new_id += "_".join(metabolites)

        if len(new_id) > 250:
            new_id = new_id[:230]

        reaction.id = new_id

        return reaction.id

    def __process_reaction(
        self, new_reaction: Reaction, new_compound: int,
        model_parent: Metabolite, parent_and_precursors: dict,
        new_reaction_metabolites: List[Metabolite]
    ) -> Tuple[Reaction, List[Tuple[Metabolite, int]]]:
        """
        Granulates a given reaction. Replaces the generic metabolite by its structurally defined child and corrects the
        precursors.

        :param Reaction new_reaction: the new reaction
        :param int new_compound: the reaction structurally defined product
        :param Metabolite model_parent: the model parent of the structurally defined product
        :param dict parent_and_precursors: dictionary with lipid parents and their children
        :param List[Metabolite] new_reaction_metabolites: list of possibly new metabolites
        :return Tuple[Reaction, List[Tuple[Metabolite, int]]]: returns a tuple with the granulated model reaction
        and the new added compounds that will be processed further.
        """

        i = 0
        found = False

        while not found and i < len(new_reaction_metabolites):
            if new_reaction_metabolites[i].id == model_parent.id:
                new_model_parent = new_reaction_metabolites[i]
                found = True

            i += 1

        coef = new_reaction.get_coefficient(model_parent.id)

        new_metabolite = self.add_boimmg_metabolites_to_reaction(
            new_compound, coef, new_reaction, model_parent.compartment)

        if model_parent.id in self.metabolite_report_material:
            self.metabolite_report_material[model_parent.id].append(
                new_metabolite.id)
        else:
            self.metabolite_report_material[model_parent.id] = [
                new_metabolite.id
            ]

        met_to_subtract = {}

        met_to_subtract[new_model_parent] = coef
        new_reaction.subtract_metabolites(met_to_subtract)

        added = self._correct_precursors(new_reaction, new_compound,
                                         parent_and_precursors)

        return new_reaction, added


    def _correct_precursors(self, new_reaction: Reaction, new_compound:int, parent_and_precursors:dict) -> \
            List[Tuple[Metabolite, int]]:
        """
        Correct the precursors in the new reaction.

        :param Reaction new_reaction: the new reaction
        :param int new_compound: the new structurally defined lipid species BOIMMG identifier
        :param dict parent_and_precursors: dictionary with lipid parents and their children
        :return List[Tuple[Metabolite, int]]: returns a tuple with the granulated model reaction
        and the new added compounds that will be processed further.
        """

        new_compound_components = self.__compounds_ontology.get_predecessors_by_ont_id_rel_type(
            new_compound, "component_of")

        reactants = list(new_reaction.reactants)
        added = self.__correct_precursors(new_reaction, parent_and_precursors,
                                          reactants, new_compound_components)

        return added


    def __correct_precursors(self, new_reaction: Reaction, parent_and_precursors: dict,
                             metabolites: List[Metabolite], new_compound_components: List[int]) -> \
                            List[Tuple[Metabolite, int]]:
        """
        Correct the precursors in the new reaction.

        :param Reaction new_reaction: the new reaction
        :param dict parent_and_precursors: dictionary with lipid parents and their children
        :param List[Metabolite] metabolites: number of reactants in the new reaction to be granulated
        :param List[int] new_compound_components: components of the new product in the reaction
        :return:
        """

        added = []
        while metabolites:

            reactant = metabolites.pop()

            boimmg_id = self.virtual_model_mapper.get_boimmg_id_from_model_compound_id(
                reactant.id)
            if boimmg_id:

                coef = new_reaction.metabolites[reactant]
                if boimmg_id in parent_and_precursors:

                    precursors = parent_and_precursors[boimmg_id]
                    for precursor in precursors:
                        self.add_boimmg_metabolites_to_reaction(
                            precursor, coef, new_reaction,
                            reactant.compartment)

                        added.append((precursor, boimmg_id))

                    met_to_subtract = {}

                    met_to_subtract[reactant] = coef
                    new_reaction.subtract_metabolites(met_to_subtract)

                else:
                    to_replace = self.__compounds_ontology.get_compounds_with_specific_parent_set_of_components(
                        boimmg_id, new_compound_components)

                    if to_replace:
                        to_replace = self.filter_targets_to_replace(
                            to_replace, boimmg_id)

                        self.add_boimmg_metabolites_to_reaction(
                            to_replace[0], coef, new_reaction,
                            reactant.compartment)

                        met_to_subtract = {}

                        met_to_subtract[reactant] = coef
                        new_reaction.subtract_metabolites(met_to_subtract)

                        added.append((to_replace[0], boimmg_id))
        return added

    def add_boimmg_metabolites_to_reaction(self, boimmg_id: int, coef: int,
                                           reaction: Reaction,
                                           compartment: str):
        """
        Add a metabolite to a given reaction receiving BOIMMG identifier as input.

        :param int boimmg_id: BOIMMG identifier of the metabolite being inserted in the reaction
        :param int coef: stoichimetric coefficient in the reaction
        :param Reaction reaction: model reaction
        :param str compartment: compartment
        :return:
        """

        model_seed_ids = self.__compounds_ontology.get_all_model_seed_ids(
            boimmg_id)
        node = self.__compounds_ontology.get_node_by_ont_id(boimmg_id)

        aliases = node.aliases

        found = False
        i = 0
        while not found and i < len(model_seed_ids):

            aliases2 = self.__compoundsIdConverter.get_all_aliases_by_modelSeedID(
                model_seed_ids[i])

            aliases.update(aliases2)

            model_child = self.mapper.check_if_boimmg_metabolite_in_model(
                boimmg_id, aliases)

            if model_child:
                found = True

            i += 1

        if not model_seed_ids:
            model_child = self.mapper.check_if_boimmg_metabolite_in_model(
                boimmg_id)

        if not model_child:

            new_model_compound = self.__create_boimmg_metabolite(
                boimmg_id, compartment)

            met_to_add = {}

            met_to_add[new_model_compound] = coef
            reaction.add_metabolites(met_to_add)

        else:
            found = False
            i = 0
            while not found and i < len(model_child):
                cobra_child_container = self.model.metabolites.get_by_id(
                    model_child[i])
                if cobra_child_container.compartment == compartment:
                    found = True

                    if self.__virtual_model.metabolites.has_id(model_child[i]):
                        found_model_compound = cobra_child_container

                    else:
                        virtual_compound = deepcopy(cobra_child_container)
                        self.__virtual_model.add_metabolites(
                            [virtual_compound])
                        found_model_compound = virtual_compound

                i += 1

            if not found:
                new_model_compound = self.__create_boimmg_metabolite(
                    boimmg_id, compartment)

                met_to_add = {}

                met_to_add[new_model_compound] = coef
                reaction.add_metabolites(met_to_add)

            else:
                met_to_add = {}

                met_to_add[found_model_compound] = coef
                reaction.add_metabolites(met_to_add)

        return new_model_compound

    def __create_boimmg_metabolite(self, boimmg_id: int,
                                   compartment: str) -> Metabolite:
        """
        Generates a new model compound using the internal database information.

        :param int boimmg_id: BOIMMG identifier
        :param str compartment: compartment
        :return Metabolite: the new metabolite
        """

        new_compound_node = self.__compounds_ontology.get_node_by_ont_id(
            boimmg_id)

        model_seed_ids = self.__compounds_ontology.get_all_model_seed_ids(
            boimmg_id)

        for model_seed_id in model_seed_ids:

            translation = self.__compoundsIdConverter.get_modelSeedIdToDb(
            ).get(model_seed_id)

            definitive_model_seed_id = model_seed_id
            if self.__database_format == "BiGG" and \
                    ("BiGG" in translation.keys() or "BiGG1" in translation.keys()):

                definitive_model_seed_id = model_seed_id
                break


            elif self.__database_format == "KEGG" and \
                    "KEGG" in translation.keys():

                definitive_model_seed_id = model_seed_id
                break

        new_model_compound = model_utilities.generate_boimmg_metabolites_in_compartment(
            new_compound_node, compartment, self.__compoundsIdConverter,
            self.__compoundsAnnotationConfigs)
        self.add_metabolites_to_the_virtual_model([new_model_compound])

        return new_model_compound

    def add_metabolites_to_the_virtual_model(self, metabolites):
        self.__virtual_model.add_metabolites(metabolites)
        self.virtual_model_mapper.add_new_metabolites_to_maps(metabolites)

    @staticmethod
    def merge_dictionaries(dict1, dict2):
        for key in dict1:
            if key in dict2:
                dict1[key].extend(dict2[key])
        return dict1

    def get_target_associated_network(
            self, target_generic_ontology_id: int) -> List[Reaction]:
        """
        Identifies the target's biosynthesis network in the model

        :param int target_generic_ontology_id:
        :return List[Reaction]: list of reactions in the network
        """

        res = []
        res_ids = []

        predecessors = \
            self.__compounds_ontology.get_all_predecessors_by_ont_id_rel_type(target_generic_ontology_id, "precursor_of")

        predecessors_and_target = predecessors.copy()
        predecessors_and_target.append(target_generic_ontology_id)

        network_metabolites_in_model = []

        for token in predecessors_and_target:
            metabolites_in_model = self.__check_if_compound_exists_in_model_by_ontology_id(
                token)
            network_metabolites_in_model.extend(metabolites_in_model)

        network_metabolites_ids = [m.id for m in network_metabolites_in_model]

        for metabolites_in_model in network_metabolites_in_model:
            reactions = metabolites_in_model.reactions
            for reaction in reactions:

                if reaction.id not in res_ids:

                    reactants = reaction.reactants
                    products = reaction.products

                    reactant_found = False
                    product_found = False
                    i = 0
                    while not reactant_found and i < len(reactants):
                        reactant = reactants[i]
                        reactant_id = reactant.id
                        if reactant_id in network_metabolites_ids:
                            reactant_found = True

                        i += 1

                    j = 0
                    while not product_found and j < len(products):
                        product = products[j]
                        product_id = product.id
                        if product_id in network_metabolites_ids:
                            product_found = True
                        j += 1

                    if product_found and reactant_found:
                        res.append(reaction)
                        res_ids.append(reaction.id)

        return res

    def __check_if_compound_exists_in_model_by_ontology_id(
            self, ontology_id: int) -> List[Metabolite]:
        """
        This method will check whether a BOIMMG compound exists in the model.

        :param int ontology_id: BOIMMG id
        :return List[Metabolite]: 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 __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 get_targets_to_replace_by_type(self, target: int) -> dict:
        """
        Identifies targets components, precursors and successors in the biosynthesis network. Returns a dictionary
        with the precursors' generic parent as keys and a list of structurally defined precursors as values.

        :param int target: BOIMMG identifier
        :return dict: dictionary with the precursors' generic parent as keys and a list
        of structurally defined precursors as values
        """

        res = {}
        precursors = self.__compounds_ontology.get_all_predecessors_by_ont_id_rel_type(
            target, "precursor_of")

        successors = self.__compounds_ontology.get_successors_by_ont_id_rel_type(
            target, "precursor_of")

        components = self.__compounds_ontology.get_predecessors_by_ont_id_rel_type(
            target, "component_of")

        for component in components:
            if component in self.fatty_acids:
                if self.generic_fatty_acid in res:
                    res.get(self.generic_fatty_acid).append(component)
                else:
                    res[self.generic_fatty_acid] = [component]

        for precursor in precursors:
            parent = self.__compounds_ontology.get_successors_by_ont_id_rel_type(
                precursor, "is_a")

            if parent[0] in res:
                res.get(parent[0]).append(precursor)
            else:
                res[parent[0]] = [precursor]

        for successor in successors:
            parent = self.__compounds_ontology.get_successors_by_ont_id_rel_type(
                successor, "is_a")

            if parent[0] in res:
                res.get(parent[0]).append(successor)
            else:
                res[parent[0]] = [successor]

        return res

    # def find_components_reactions_and_generalize(self):
    #
    #     candidate_reactions = []
    #
    #     res = {}
    #
    #     generic_compounds = []
    #     pseudo_components = []
    #     components = []
    #     components_boimmg_id = []
    #
    #     for compound in self.mapper.boimmg_db_model_map:
    #
    #         boimmg_id =self.mapper.boimmg_db_model_map[compound]
    #         if boimmg_id in self.__components:
    #             model_compound = self.model.metabolites.get_by_id(compound)
    #             pseudo_components.append(compound)
    #             candidate_reactions.extend(list(model_compound.reactions))
    #
    #             if boimmg_id in self.fatty_acids:
    #                 components.append(compound)
    #
    #         node = self.__compounds_ontology.get_node_by_ont_id(self.mapper.boimmg_db_model_map[compound])
    #
    #         if node.generic:
    #             generic_compounds.append(compound)
    #
    #     for reaction in candidate_reactions:
    #
    #         regex = re.compile("[Bb][Ii][Oo][Mm][Aa][Ss][Ss]")
    #
    #         if reaction.annotation != "SBO:0000629" and not regex.match(reaction.name):
    #
    #             reactants = reaction.reactants
    #             products = reaction.products
    #
    #             reactant_found = False
    #             product_found = False
    #
    #             pseudo_component_in_reactants = False
    #
    #             isComponent = False
    #
    #             for reactant in reactants:
    #                 reactant_id = reactant.id
    #
    #                 if reactant_id in generic_compounds:
    #                     reactant_found = True
    #
    #                 elif reactant_id in pseudo_components:
    #                     pseudo_component_in_reactants = True
    #
    #                     if reactant_id in components:
    #                         isComponent = True
    #
    #             for product in products:
    #                 product_id = product.id
    #                 if product_id in generic_compounds:
    #                     product_found = True
    #
    #                 elif product_id in components:
    #                     isComponent = True
    #
    #             if reactant_found or product_found:
    #
    #                 new_reaction, subtracted = \
    #                     self.remove_components_from_reaction(reaction,pseudo_components,pseudo_component_in_reactants,isComponent)
    #
    #                 for sub in subtracted:
    #                     if sub not in components_boimmg_id:
    #                         components_boimmg_id.append(sub)
    #
    #
    #                 res[reaction.id] = (new_reaction,isComponent,pseudo_component_in_reactants,subtracted)
    #
    #     return res,components_boimmg_id

    # def remove_components_from_reaction(self,reaction,pseudo_components,pseudo_component_in_reactants,isComponent):
    #
    #     new_reaction = deepcopy(reaction)
    #
    #     component_parent = None
    #     if pseudo_component_in_reactants:
    #
    #         reactants = list(new_reaction.reactants)
    #
    #         to_subtract = {}
    #
    #         while reactants:
    #             reactant = reactants.pop()
    #             if reactant.id in self.mapper.boimmg_db_model_map.keys():
    #                 if reactant.id in pseudo_components:
    #
    #                     if not component_parent:
    #                         child = self.mapper.get_boimmg_id_from_model_compound_id(reactant.id)
    #                         parent = self.__compounds_ontology.get_successors_by_ont_id_rel_type(child, "is_a")
    #                         component_parent = parent[0]
    #
    #                     coef = new_reaction.metabolites[reactant]
    #                     to_subtract[reactant] = coef
    #
    #         new_reaction.subtract_metabolites(to_subtract)
    #
    #         components = []
    #         for subtracted in to_subtract:
    #             if isComponent:
    #                 boimmg_id = self.mapper.get_boimmg_id_from_model_compound_id(subtracted.id)
    #                 components.append(boimmg_id)
    #
    #             else:
    #                 boimmg_id = self.mapper.get_boimmg_id_from_model_compound_id(subtracted.id)
    #                 new_components = self.__compounds_ontology.get_predecessors_by_ont_id_rel_type(boimmg_id,
    #                                                                                                "component_of")
    #                 components.extend(new_components)
    #
    #         if isComponent:
    #             self.add_boimmg_metabolites_to_reaction(self.generic_fatty_acid, -1, new_reaction, reactant.compartment)
    #
    #         else:
    #
    #             self.add_boimmg_metabolites_to_reaction(component_parent,-1,new_reaction,reactant.compartment)
    #
    #         return new_reaction, components
    #
    #     else:
    #         products = list(new_reaction.products)
    #
    #         to_subtract = {}
    #
    #         while products:
    #             product = products.pop()
    #
    #             if product.id in self.mapper.boimmg_db_model_map.keys():
    #                 if product.id in pseudo_components:
    #
    #                     if not component_parent:
    #
    #                         child = self.mapper.get_boimmg_id_from_model_compound_id(product.id)
    #                         parent = self.__compounds_ontology.get_successors_by_ont_id_rel_type(child, "is_a")
    #
    #                         component_parent = parent[0]
    #
    #                     coef = new_reaction.metabolites[product]
    #                     to_subtract[product] = coef
    #
    #         if isComponent:
    #             self.add_boimmg_metabolites_to_reaction(self.generic_fatty_acid, 1, new_reaction, product.compartment)
    #
    #         else:
    #
    #             self.add_boimmg_metabolites_to_reaction(component_parent, 1, reaction, new_reaction.compartment)
    #
    #         new_reaction.subtract_metabolites(to_subtract)
    #
    #         components = []
    #         for subtracted in to_subtract:
    #             if isComponent:
    #                 boimmg_id = self.mapper.get_boimmg_id_from_model_compound_id(subtracted.id)
    #                 components.append(boimmg_id)
    #
    #             else:
    #                 boimmg_id = self.mapper.get_boimmg_id_from_model_compound_id(subtracted.id)
    #                 new_components = self.__compounds_ontology.get_predecessors_by_ont_id_rel_type(boimmg_id,
    #                                                                                                "component_of")
    #                 components.extend(new_components)
    #
    #
    #         return new_reaction, components

    # def __get_children_in_model(self,product):
    #
    #     children_in_model = {}
    #
    #     parent_boimmg_id = self.virtual_model_mapper.get_boimmg_id_from_model_compound_id(product.id)
    #
    #     if parent_boimmg_id:
    #         children = self.__compounds_ontology.get_predecessors_by_ont_id_rel_type(parent_boimmg_id,"is_a")
    #
    #         for mapped_compound in self.virtual_model_mapper.boimmg_db_model_map:
    #             eventual_child = self.virtual_model_mapper.boimmg_db_model_map[mapped_compound]
    #
    #             if eventual_child in children:
    #
    #                 children_in_model[eventual_child] = self.virtual_model_mapper.boimmg_db_model_map[mapped_compound]
    #
    #     return children_in_model

    # def check_if_decomposition_reaction(self,reaction:Reaction):
    #
    #     reactants = reaction.reactants
    #     products = reaction.products
    #
    #     inReactants = self.__check_component_in_reaction_side(reactants)
    #
    #     inProducts = self.__check_component_in_reaction_side(products)
    #
    #     if inReactants or inProducts:
    #         return True,inReactants
    #
    #     else:
    #         return False, inReactants

    # def __check_component_in_reaction_side(self,metabolites):
    #     for metabolite in metabolites:
    #
    #         boimmg_id = self.virtual_model_mapper.get_boimmg_id_from_model_compound_id(metabolite.id)
    #
    #         if boimmg_id:
    #             if boimmg_id == self.generic_fatty_acid or boimmg_id == self.__generic_acps or \
    #                     boimmg_id == self.__generic_acyl_coa:
    #                 return True
    #
    #     else:
    #         return False

    def __set_components(self):

        self.fatty_acids = self.__compounds_ontology.get_leaves_from_ont_id(
            527)
        self.generic_fatty_acid = 527

        # self.__acyl_coas = self.__compounds_ontology.get_leaves_from_ont_id(43)
        # self.__generic_acyl_coa = 43
        #
        # self.__acyl_acps = self.__compounds_ontology.get_leaves_from_ont_id(704832)
        # self.__generic_acps = 704832

        # self.__components = self.fatty_acids + self.__acyl_acps + self.__acyl_coas
        # self.__components = self.fatty_acids

    # def solve_components_reactions(self,same_components=False,components_reactions = {}, components = []):
    #
    #     if not components_reactions and not components:
    #         components_reactions,components = self.find_components_reactions_and_generalize()
    #
    #     new_reactions = [components_reactions[reaction][0] for reaction in components_reactions.keys()]
    #
    #     self.__add_new_reactions_to_virtual_model(new_reactions)
    #
    #     self.__solve_components_reactions(components_reactions,components,same_components)

    def __solve_components_reactions(self, components_reactions, components,
                                     same_components):

        for reaction in components_reactions:

            self.__correct_component_reaction(components_reactions[reaction],
                                              components, same_components)

    # def __correct_component_reaction(self,reaction_features,components,same_components):
    #
    #     new_reaction = reaction_features[0]
    #     isReactant = reaction_features[2]
    #     deleted = reaction_features[3]
    #
    #     reactants = new_reaction.reactants
    #     products = new_reaction.products
    #
    #     # r_groups_reactants,r_groups_products = self.get_r_groups_from_reaction_compounds(reactants,products)
    #
    #     if isReactant:
    #
    #         boimmg_compound = self.find_boimmg_compound(products)
    #
    #         if boimmg_compound:
    #
    #             self.granulate(boimmg_compound, components, same_components)
    #
    #     else:
    #         boimmg_compound = self.find_boimmg_compound(reactants)
    #
    #         if boimmg_compound:
    #             self.granulate(boimmg_compound, components, same_components,decomposition=True)

    def find_boimmg_compound(self, compounds):
        """
        It finds only one boimmg compound within a list of model compounds
        :param compounds:
        :return:
        """

        for compound in compounds:

            boimmg_id = self.mapper.get_boimmg_id_from_model_compound_id(
                compound.id)

            if boimmg_id:
                return boimmg_id

        return None

    # def get_r_groups_from_reaction_compounds(self,reactants,products):
    #
    #     r_groups_reactants = 0
    #     r_groups_products = 0
    #
    #     for reactant in reactants:
    #         r_groups_reactants += self.get_r_groups_from_compound(reactant)
    #
    #     for product in products:
    #         r_groups_products += self.get_r_groups_from_compound(product)
    #
    #     return r_groups_reactants,r_groups_products

    # def get_r_groups_from_compound(self,model_compound):
    #
    #     boimmg_id = self.virtual_model_mapper.get_boimmg_id_from_model_compound_id(model_compound.id)
    #     if boimmg_id:
    #         node = self.__compounds_ontology.get_node_by_ont_id(boimmg_id)
    #         smiles = node.smiles
    #
    #         if smiles:
    #             return smiles.count("*")
    #
    #         return 0
    #     return 0

    def filter_targets_to_replace(self, targets: List[int],
                                  parent: int) -> List[int]:
        """
        Filter the predicted precursors by side chains.

        :param List[int] targets:
        :param int parent:
        :return List[int]: filtered list
        """

        res = []

        for target in targets:
            components = self.__compounds_ontology.get_predecessors_by_ont_id_rel_type(
                target, "component_of")

            node = self.__compounds_ontology.get_node_by_ont_id(target)

            child_smiles = node.smiles

            parent_node = self.__compounds_ontology.get_node_by_ont_id(parent)

            parent_smiles = parent_node.smiles

            molecules = chemo_utilities.get_side_chains(
                parent_smiles, child_smiles)

            if molecules:
                new_molecules = []
                new_molecules_n = 0
                for molecule in molecules:

                    if molecule not in new_molecules:
                        new_molecules_n += 1
                        new_molecules.append(molecule)

                if new_molecules_n == len(components):
                    res.append(target)

        return res
Exemple #17
0
    def test_database_access(self):

        accessor = CompoundsDBAccessor()
        accessor.get_successors_by_ont_id_rel_type(3, "is_a")
Exemple #18
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
Exemple #19
0
 def test_precursors(self):
     compounds_ontology = CompoundsDBAccessor()
     all_precursors = compounds_ontology.get_all_predecessors_by_ont_id_rel_type(
         322790, "precursor_of")
     print(all_precursors)
Exemple #20
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
Exemple #21
0
class ModelMapper:
    def __init__(self, model, compoundsAnnotationConfigs,
                 compoundsIdConverter):
        self.model = model
        self.__compoundsAnnotationConfigs = compoundsAnnotationConfigs
        self.__compoundsIdConverter = compoundsIdConverter
        self.__compounds_ontology = CompoundsDBAccessor()

        self.mapped = False

        self.boimmg_db_model_map = {}

        self.boimmg_db_model_map_reverse = {}

        self.compounds_aliases_indexation = {}

        self.compound_inchikey_indexation = {}

        self.__compounds_aliases_indexation_reverse = {}

    @property
    def model(self):
        return self.__model

    @model.setter
    def model(self, value):
        self.__model = value

    @property
    def boimmg_db_model_map(self):
        return self.__boimmg_db_model_map

    @boimmg_db_model_map.setter
    def boimmg_db_model_map(self, value):
        if isinstance(value, dict):
            self.__boimmg_db_model_map = value
        else:
            raise ValueError("introduce a dictionary")

    @property
    def boimmg_db_model_map_reverse(self):
        return self.__boimmg_db_model_map_reverse

    @boimmg_db_model_map_reverse.setter
    def boimmg_db_model_map_reverse(self, value):
        if isinstance(value, dict):
            self.__boimmg_db_model_map_reverse = value
        else:
            raise ValueError("introduce a dictionary")

    @property
    def compounds_aliases_indexation(self):
        return self.__compounds_aliases_indexation

    @compounds_aliases_indexation.setter
    def compounds_aliases_indexation(self, value):
        if isinstance(value, dict):
            self.__compounds_aliases_indexation = value
        else:
            raise ValueError("introduce a dictionary")

    @property
    def compounds_aliases_indexation_reverse(self):
        return self.__compounds_aliases_indexation_reverse

    @compounds_aliases_indexation_reverse.setter
    def compounds_aliases_indexation_reverse(self, value):
        if isinstance(value, dict):
            self.__compounds_aliases_indexation_reverse = value
        else:
            raise ValueError("introduce a dictionary")

    @property
    def compound_inchikey_indexation(self):
        return self.__compound_inchikey_indexation

    @compound_inchikey_indexation.setter
    def compound_inchikey_indexation(self, value):
        if isinstance(value, dict):
            self.__compound_inchikey_indexation = value
        else:
            raise ValueError("introduce a dictionary")

    @property
    def mapped(self):
        return self._mapped

    @mapped.setter
    def mapped(self, value: bool):
        self._mapped = value

    def printProgressBar(self,
                         iteration,
                         total,
                         prefix='',
                         suffix='',
                         decimals=1,
                         length=100,
                         fill='|',
                         printEnd="\r"):
        """
      Call in a loop to create terminal progress bar
      @params:
          iteration   - Required  : current iteration (Int)
          total       - Required  : total iterations (Int)
          prefix      - Optional  : prefix string (Str)
          suffix      - Optional  : suffix string (Str)
          decimals    - Optional  : positive number of decimals in percent complete (Int)
          length      - Optional  : character length of bar (Int)
          fill        - Optional  : bar fill character (Str)
          printEnd    - Optional  : end character (e.g. "\r", "\r\n") (Str)
      """
        percent = ("{0:." + str(decimals) + "f}").format(
            100 * (iteration / float(total)))
        filledLength = int(length * iteration // total)
        bar = fill * filledLength + '-' * (length - filledLength)
        print('\r%s |%s| %s%% %s' % (prefix, bar, percent, suffix),
              end="",
              flush=True)
        # Print New Line on Complete
        if iteration == total:
            print()

    def map_model(self, database):

        if database in self.__compoundsAnnotationConfigs.keys():
            database_annotation_key = self.__compoundsAnnotationConfigs[
                database]
        else:
            raise ValueError("introduce a valid database name")

        j = 0
        model_metabolites = list(self.model.metabolites)
        for compound in self.model.metabolites:

            self.printProgressBar(j, len(model_metabolites))
            j += 1
            compound_annotation = compound.annotation

            boimmg_compound_found = False

            annotation_keys = [
                "seed.compound", database_annotation_key, "boimmg.compound",
                "inchi_key"
            ]

            for key in annotation_keys:
                if key in compound_annotation.keys():

                    if isinstance(compound_annotation[key], str):
                        annotation_values = [compound_annotation[key]]
                    else:
                        annotation_values = compound_annotation[key]

                    for annotation_value in annotation_values:

                        if not boimmg_compound_found:

                            if "cpd" in annotation_value:
                                model_seed_id = [annotation_value]
                            else:
                                model_seed_id = self.__compoundsIdConverter.convert_db_id_to_model_seed_by_db_id(
                                    annotation_value)

                            if model_seed_id:
                                found = False
                                i = 0
                                while not found and i < len(model_seed_id):
                                    node = self.__compounds_ontology.get_node_id_from_model_seed_id(
                                        model_seed_id[i])
                                    i += 1
                                    if node:
                                        found = True

                                        boimmg_compound_found = True
                                        self.boimmg_db_model_map[
                                            compound.id] = node

                                        if node in self.boimmg_db_model_map_reverse.keys(
                                        ):
                                            self.boimmg_db_model_map_reverse[
                                                node].append(compound.id)

                                        else:
                                            self.boimmg_db_model_map_reverse[
                                                node] = [compound.id]

                        if key not in self.compounds_aliases_indexation:
                            self.compounds_aliases_indexation[key] = {}

                        if annotation_value not in self.compounds_aliases_indexation[
                                key]:
                            self.compounds_aliases_indexation[key][
                                annotation_value] = []

                        if compound.id not in self.compounds_aliases_indexation_reverse:
                            self.compounds_aliases_indexation_reverse[
                                compound.id] = {}

                        if key not in self.compounds_aliases_indexation_reverse[
                                compound.id]:
                            self.compounds_aliases_indexation_reverse[
                                compound.id] = {
                                    key: []
                                }

                        if annotation_value not in self.compounds_aliases_indexation_reverse[
                                compound.id][key]:
                            self.compounds_aliases_indexation_reverse[
                                compound.id][key].append(annotation_value)

                        if compound.id not in self.compounds_aliases_indexation_reverse[
                                compound.id][key]:
                            self.compounds_aliases_indexation[key][
                                annotation_value].append(compound.id)

                    if not boimmg_compound_found:

                        if key == "boimmg.compound":
                            construction_sub_string = self.__compoundsAnnotationConfigs[
                                "BOIMMG_ID_CONSTRUCTION"]
                            value = compound_annotation[key]

                            boimmg_id = int(
                                value.replace(construction_sub_string, ""))

                            if boimmg_id not in self.boimmg_db_model_map_reverse.keys(
                            ):
                                self.boimmg_db_model_map_reverse[
                                    boimmg_id] = []

                            self.boimmg_db_model_map_reverse[boimmg_id].append(
                                compound.id)

                            if boimmg_id not in self.boimmg_db_model_map.keys(
                            ):
                                self.boimmg_db_model_map_reverse[
                                    compound.id] = []

                            self.boimmg_db_model_map_reverse[
                                compound.id].append(compound.id)

                        elif key == "inchi_key":
                            value = compound_annotation[key][:-1]
                            if value not in self.compound_inchikey_indexation:
                                self.compound_inchikey_indexation[value] = [
                                    compound.id
                                ]
                            else:
                                self.compound_inchikey_indexation[
                                    value].append(compound.id)

        self.mapped = True

    def create_map_dump(self, destination):

        out_file = open(destination + "boimmg_db_model_map.json", "w")
        json.dump(self.boimmg_db_model_map, out_file)
        out_file.close()

        out_file = open(destination + "boimmg_db_model_map_reverse.json", "w")
        json.dump(self.boimmg_db_model_map_reverse, out_file)
        out_file.close()

        out_file = open(destination + "compounds_aliases_indexation.json", "w")
        json.dump(self.compounds_aliases_indexation, out_file)
        out_file.close()

        out_file = open(
            destination + "compounds_aliases_indexation_reverse.json", "w")
        json.dump(self.compounds_aliases_indexation_reverse, out_file)
        out_file.close()

        out_file = open(destination + "compound_inchikey_indexation.json", "w")
        json.dump(self.compound_inchikey_indexation, out_file)
        out_file.close()

    def upload_maps(self, folder):

        in_file = open(folder + "boimmg_db_model_map.json", "r")
        self.boimmg_db_model_map = json.load(in_file)
        in_file.close()

        in_file = open(folder + "boimmg_db_model_map_reverse.json", "r")
        temp = json.load(in_file)
        in_file.close()
        self.boimmg_db_model_map_reverse = {int(k): v for k, v in temp.items()}

        in_file = open(folder + "compounds_aliases_indexation.json", "r")
        self.compounds_aliases_indexation = json.load(in_file)
        in_file.close()

        in_file = open(folder + "compounds_aliases_indexation_reverse.json",
                       "r")
        self.compounds_aliases_indexation_reverse = json.load(in_file)
        in_file.close()

        in_file = open(folder + "compound_inchikey_indexation.json", "r")
        self.compound_inchikey_indexation = json.load(in_file)
        in_file.close()

        self.mapped = True

    def add_new_reactions_to_model(self, new_reactions):

        for reaction in new_reactions:

            self.add_new_metabolites_to_maps(reaction.metabolites)

    def __add_metabolites_to_boimmg_indexation(self, key, annotation_value,
                                               metabolite):

        if key == self.__compoundsAnnotationConfigs.get("ModelSEED"):
            model_seed_id = [annotation_value]

        else:
            model_seed_id = self.__compoundsIdConverter.convert_db_id_to_model_seed_by_db_id(
                annotation_value)

        if model_seed_id:

            found = False
            i = 0
            while not found and i < len(model_seed_id):
                node = self.__compounds_ontology.get_node_id_from_model_seed_id(
                    model_seed_id[i])
                i += 1
                if node:
                    # found = True

                    self.boimmg_db_model_map[metabolite.id] = node

                    if node in self.boimmg_db_model_map_reverse.keys():
                        self.boimmg_db_model_map_reverse[node].append(
                            metabolite.id)

                    else:
                        self.boimmg_db_model_map_reverse[node] = [
                            metabolite.id
                        ]

                    return True

        return False

    def __add_metabolites_to_aliases_indexation(self, annotation_pair,
                                                annotation_value, metabolite):

        if annotation_pair not in self.compounds_aliases_indexation:
            self.compounds_aliases_indexation[annotation_pair] = {}

        if annotation_value not in self.compounds_aliases_indexation[
                annotation_pair]:
            self.compounds_aliases_indexation[annotation_pair][
                annotation_value] = []

        if metabolite.id not in self.compounds_aliases_indexation_reverse:
            self.compounds_aliases_indexation_reverse[metabolite.id] = {}

        if annotation_pair not in self.compounds_aliases_indexation_reverse[
                metabolite.id]:
            self.compounds_aliases_indexation_reverse[metabolite.id] = {
                annotation_pair: []
            }

        if annotation_value not in self.compounds_aliases_indexation_reverse[
                metabolite.id][annotation_pair]:
            self.compounds_aliases_indexation_reverse[
                metabolite.id][annotation_pair].append(annotation_value)

        if metabolite not in self.compounds_aliases_indexation[
                annotation_pair][annotation_value]:
            self.compounds_aliases_indexation[annotation_pair][
                annotation_value].append(metabolite.id)

    def add_new_metabolites_to_maps(self, new_metabolites):

        for metabolite in new_metabolites:

            compound_annotation = metabolite.annotation

            boimmg_compound_found = False
            for key in compound_annotation.keys():
                if key in self.__compoundsAnnotationConfigs.keys():
                    annotation_pair = self.__compoundsAnnotationConfigs[key]

                    if isinstance(compound_annotation[key], str):
                        annotation_values = [compound_annotation[key]]
                    else:
                        annotation_values = compound_annotation[key]

                    for annotation_value in annotation_values:

                        if not boimmg_compound_found:

                            boimmg_compound_found = self.__add_metabolites_to_boimmg_indexation(
                                key, annotation_value, metabolite)

                        self.__add_metabolites_to_aliases_indexation(
                            annotation_pair, annotation_value, metabolite)

                    if not boimmg_compound_found:

                        if key == "boimmg.compound":
                            construction_sub_string = self.__compoundsAnnotationConfigs[
                                "BOIMMG_ID_CONSTRUCTION"]
                            value = compound_annotation[key]

                            boimmg_id = int(
                                value.replace(construction_sub_string, ""))

                            self.boimmg_db_model_map[metabolite.id] = boimmg_id

                            if boimmg_id not in self.boimmg_db_model_map_reverse.keys(
                            ):
                                self.boimmg_db_model_map_reverse[boimmg_id] = [
                                    metabolite.id
                                ]

                            else:
                                self.boimmg_db_model_map_reverse[
                                    boimmg_id].append(metabolite.id)

                        elif key == "inchi_key":
                            value = compound_annotation[key][:-1]
                            if value not in self.compound_inchikey_indexation:
                                self.compound_inchikey_indexation[value] = [
                                    metabolite.id
                                ]
                            else:
                                self.compound_inchikey_indexation[
                                    value].append(metabolite.id)

    def update_maps(self, old_inchikey, new_inchikey, old_id, new_id,
                    new_ontology_id, old_aliases, new_aliases):

        compound_container = self.model.metabolites.get_by_id(new_id)

        if old_id in self.boimmg_db_model_map:
            del self.boimmg_db_model_map[old_id]
            self.boimmg_db_model_map[new_id] = new_ontology_id

        for key, value in self.boimmg_db_model_map_reverse.items():
            if old_id in value:
                del self.boimmg_db_model_map_reverse[key]
                break

        if new_ontology_id not in self.boimmg_db_model_map_reverse:
            self.boimmg_db_model_map_reverse[new_ontology_id] = [
                compound_container.id
            ]

        elif compound_container.id not in self.boimmg_db_model_map_reverse[
                new_ontology_id]:
            self.boimmg_db_model_map_reverse[new_ontology_id].append(
                compound_container.id)

        if old_inchikey:
            if old_inchikey[:-1] in self.compound_inchikey_indexation:
                del self.compound_inchikey_indexation[old_inchikey[:-1]]

        if new_inchikey:
            if new_inchikey[:-1] in self.compound_inchikey_indexation:
                self.compound_inchikey_indexation[new_inchikey[:-1]].append(
                    compound_container.id)
            else:
                self.compound_inchikey_indexation[new_inchikey[:-1]] = [
                    compound_container.id
                ]

        self.__update_aliases_indexation(old_id, new_aliases,
                                         compound_container)

    def __update_aliases_indexation(self, old_id, new_aliases,
                                    compound_container):

        if old_id in self.compounds_aliases_indexation_reverse:
            old_aliases = self.compounds_aliases_indexation_reverse[old_id]
            for db in self.compounds_aliases_indexation:
                if db in old_aliases:
                    for alias in old_aliases[db]:
                        if alias in self.compounds_aliases_indexation[db]:
                            del self.compounds_aliases_indexation[db][alias]

            del self.compounds_aliases_indexation_reverse[old_id]

        for key in new_aliases:
            if key in self.__compoundsAnnotationConfigs.keys() and \
                    key in self.compounds_aliases_indexation:

                for alias in new_aliases[key]:
                    if alias in self.compounds_aliases_indexation[key]:
                        self.compounds_aliases_indexation[key][alias].append(
                            compound_container.id)
                    else:
                        self.compounds_aliases_indexation[key][alias] = [
                            compound_container.id
                        ]

    def check_metabolites_in_model(self,
                                   inchikey: str,
                                   aliases: dict,
                                   boimmg_container=None,
                                   boimmg_id=None) -> list:
        """
        This method checks whether a given metabolite with the :param inchikey and the :param aliases.
        If a BOIMMG node is available the search starts with it.

        :param str inchikey: InchiKey of the metabolite to be searched.
        :param dict aliases: databases links of the metabolite to be searched.
        :param CompoundNode boimmg_container: BOIMMG node
        :return list: metabolites in model
        """

        if not boimmg_container and not boimmg_id:

            if inchikey:
                inchikey_without_protonation = inchikey[:-1]
                if inchikey_without_protonation in self.compound_inchikey_indexation.keys(
                ):
                    compound_ids = self.compound_inchikey_indexation[
                        inchikey_without_protonation]
                    compounds_in_model = [
                        self.model.metabolites.get_by_id(compound_id)
                        for compound_id in compound_ids
                    ]

                    return compounds_in_model

            for key in aliases:
                new_key = None
                if key in self.__compoundsAnnotationConfigs:
                    new_key = self.__compoundsAnnotationConfigs[key]

                if key in self.compounds_aliases_indexation:
                    for alias in aliases[key]:
                        if alias in self.compounds_aliases_indexation.get(key):

                            compound_ids = self.compounds_aliases_indexation[
                                key].get(alias)
                            compounds_in_model = [
                                self.model.metabolites.get_by_id(compound_id)
                                for compound_id in compound_ids
                            ]

                            return compounds_in_model

                elif new_key and new_key in self.compounds_aliases_indexation:
                    for alias in aliases[key]:
                        if alias in self.compounds_aliases_indexation.get(
                                new_key):

                            compound_ids = self.compounds_aliases_indexation[
                                new_key].get(alias)
                            compounds_in_model = [
                                self.model.metabolites.get_by_id(compound_id)
                                for compound_id in compound_ids
                            ]

                            return compounds_in_model

        elif boimmg_container:
            ont_id = boimmg_container.id
            res = []

            if ont_id in self.__boimmg_db_model_map_reverse.keys():
                for model_id in self.__boimmg_db_model_map_reverse[ont_id]:
                    res.append(self.model.metabolites.get_by_id(model_id))

            return res

        else:
            res = []

            if boimmg_id in self.__boimmg_db_model_map_reverse.keys():
                for model_id in self.__boimmg_db_model_map_reverse[boimmg_id]:
                    res.append(self.model.metabolites.get_by_id(model_id))

            return res

        return []

    def check_if_boimmg_metabolite_in_model(self, boimmg_id, aliases={}):

        if boimmg_id in self.boimmg_db_model_map_reverse.keys():
            return self.boimmg_db_model_map_reverse[boimmg_id]

        elif aliases:
            for db in aliases:
                db_aliases = aliases[db]

                for alias in db_aliases:
                    if db in self.compounds_aliases_indexation.keys():
                        if alias in self.compounds_aliases_indexation[db]:
                            compounds = self.compounds_aliases_indexation[db][
                                alias]
                            return compounds
        else:
            return None

        return None

    def get_boimmg_id_from_model_compound_id(self, model_id):

        if model_id in self.boimmg_db_model_map.keys():
            return self.boimmg_db_model_map[model_id]

        return None