Exemple #1
0
def initialze_cc(pH=7.0, pMg=3.0, temperature=298.15, ionic_strength=0.25):
    cc = ComponentContribution()
    cc.p_h = Q_(pH)
    cc.p_mg = Q_(pMg)
    cc.ionic_strength = Q_(str(ionic_strength) + "M")
    cc.temperature = Q_(str(temperature) + "K")
    return cc
    def __init__(
        self,
        eq_uri=None,
        dg_max=0,
        p_h=7,
        ionic_strength=0,
        p_mg=3,
        physiological=False,
        generation_list=[],
        last_generation_only=False,
    ) -> None:
        self._filter_name = "Thermodynamic Filter"
        self.dg_max = Q_(f"{dg_max}kJ/mol")
        self.p_h = Q_(f"{p_h}")
        self.ionic_strength = Q_(f"{ionic_strength}M")
        self.p_mg = Q_(f"{p_mg}")
        self.physiological = physiological
        self.generation_list = generation_list
        self.last_generation_only = last_generation_only

        self.thermo = Thermodynamics()
        if not eq_uri:
            eq_uri = ""
        if "post" in eq_uri:
            self.thermo.load_thermo_from_postgres(eq_uri)
        elif "sql" in eq_uri:
            self.thermo.load_thermo_from_sqlite(eq_uri)
        else:
            self.thermo.load_thermo_from_sqlite()
    def _choose_items_to_filter(self,
                                pickaxe: Pickaxe,
                                processes: int = 1) -> Set[str]:
        """
        Check the compounds against the MW constraints and return
        compounds to filter.
        """
        cpds_remove_set = set()
        rxns_remove_set = set()

        # TODO put these statements together
        # No reactions to filter for
        if len(pickaxe.reactions) == 0:
            print("No reactions to calculate ∆Gr for.")
            return cpds_remove_set, rxns_remove_set

        if self.last_generation_only and pickaxe.generation != self.generation:
            print("Not filtering for this generation using thermodynamics.")
            return cpds_remove_set, rxns_remove_set

        if self.generation_list and (self.generation -
                                     1) not in self.generation_list:
            print("Not filtering for this generation using thermodynamics.")
            return cpds_remove_set, rxns_remove_set

        print(f"Filtering Generation {pickaxe.generation} "
              f"with ∆G <= {self.dg_max} at pH={self.p_h}, "
              f"I={self.ionic_strength}, pMg={self.p_mg}")

        reactions_to_check = []
        for cpd in pickaxe.compounds.values():
            # Compounds are in generation and correct type
            if cpd["Generation"] == pickaxe.generation and cpd["Type"] not in [
                    "Coreactant",
                    "Target Compound",
            ]:
                reactions_to_check.extend(cpd["Product_of"])

        reactions_to_check = set(reactions_to_check)

        for rxn_id in reactions_to_check:
            if self.physiological:
                rxn_dg = self.thermo.physiological_dg_prime_from_rid(
                    r_id=rxn_id, pickaxe=pickaxe)
            else:
                rxn_dg = self.thermo.dg_prime_from_rid(
                    r_id=rxn_id,
                    pickaxe=pickaxe,
                    p_h=Q_(f"{self.p_h}"),
                    ionic_strength=Q_(f"{self.ionic_strength}"),
                    p_mg=Q_(f"{self.p_mg}"),
                )
            if rxn_dg >= self.dg_max:
                rxns_remove_set.add(rxn_id)

        return cpds_remove_set, rxns_remove_set
Exemple #4
0
 def major_ms(self, p_mg=14):
     try:
         return self._major_ms
     except AttributeError:
         self._major_ms = self.abundant_ms(
             pH=Q_(self.model.compartment_info["pH"][self.compartment]),
             I=Q_(
                 str(self.model.compartment_info["I"][self.compartment]) +
                 " M"),
             temperature=Q_(str(default_T) + " K"),
             pMg=Q_(self.model.compartment_info["pMg"][self.compartment]),
         )
         return self._major_ms
Exemple #5
0
def getFreeEnergyData(GEM,
                      work_directory='',
                      pH_i=None,
                      Ionic_strength=None,
                      dG0_uncertainty_threshold=None):

    # Load equilibrator data
    eq_api = ComponentContribution(p_h=Q_(str(pH_i)),
                                   ionic_strength=Q_(Ionic_strength))

    # Get iJO1366/iML1515 reactions as KEGG reaction strings
    GEM2KEGG = pd.read_csv(work_directory + '/iJO1366_reactions.csv',
                           index_col=0)

    # Prepare dictionary with dG0
    def originallyIrreversible(reaction_id):
        return 'forward' not in reaction_id and 'backward' not in reaction_id

    dG0_data = {}
    GEM_rxns = np.array([rxn.id for rxn in GEM.reactions])

    for rxn_id in GEM_rxns:
        try:
            if originallyIrreversible(rxn_id):
                id, direction = rxn_id, ''
            else:
                id, direction = re.split('_(forward|backward)', rxn_id)[:2]

            rxn = parse_reaction_formula(GEM2KEGG.loc[id.lower()]['formula'])

            dG0_prime = eq_api.standard_dg_prime(
                rxn).value.magnitude  # kJ/mmol
            dG0_uncertainty = eq_api.standard_dg_prime(
                rxn).error.magnitude  # kJ/mol
            if dG0_uncertainty < abs(dG0_uncertainty_threshold * dG0_prime):
                # remove uncertain dG0 data
                if 'backward' in direction:
                    dG0_data[rxn_id] = {
                        'dG0': -dG0_prime,
                        'error': dG0_uncertainty
                    }
                else:
                    dG0_data[rxn_id] = {
                        'dG0': dG0_prime,
                        'error': dG0_uncertainty
                    }
        except Exception:
            pass

    return dG0_data
Exemple #6
0
def build_thermo_from_equilibrator(model, T=TEMPERATURE_0):
    """Build `thermo_data` structure from a cobra Model.

    The structure of the returned dictionary is specified in the pyTFA
    [documentation](https://pytfa.readthedocs.io/en/latest/thermoDB.html).

    :param model: cobra.Model
    :return thermo_data: dict
        to be passed as argument to initialize a `ThermoModel`.

    """
    global ccache
    if ccache is None:
        ccache = create_compound_cache_from_quilt()
        logger.debug("eQuilibrator compound cache is loaded.")

    cc = ComponentContribution()
    cc.temperature = Q_(str(T) + "K")

    thermo_data = {"name": "eQuilibrator", "units": "kJ/mol", "cues": {}}
    met_to_comps = compat.map_cobra_metabolites(ccache, model.metabolites)
    thermo_data["metabolites"] = [
        compound_to_entry(met, cc) for met in met_to_comps
    ]
    return thermo_data
def test_dgr_prime(pk_transformed):
    low_p_h = Q_(5)
    high_p_h = Q_(9)
    low_ph_dgp = thermo.dg_prime_from_rid(
        "R6036f02cd619e4515f5180a4d650c27b7a8b40b59dc130a6c8de526d5adaeb0e",
        pk_transformed,
        p_h=low_p_h,
    )
    high_ph_dgp = thermo.dg_prime_from_rid(
        "R6036f02cd619e4515f5180a4d650c27b7a8b40b59dc130a6c8de526d5adaeb0e",
        pk_transformed,
        p_h=high_p_h,
    )

    assert abs(high_ph_dgp.value.magnitude) == pytest.approx(4, 7)
    assert abs(high_ph_dgp.value.magnitude) == pytest.approx(21, 23)
Exemple #8
0
    def calculate_delG_f(self):
        """Calculates the standard transformed Gibbs formation energy of compound using component contribution method. pH, Ionic strength values are taken from model's compartment_info attribute

        Returns:
            float -- Transformed Gibbs energy of formation adjusted to pH, ionic strength of metabolite
        """

        std_dG_f = self.compound_vector @ mu
        if self.compound_vector.any():
            transform = self.equilibrator_accession.transform(
                p_h=Q_(self.model.compartment_info["pH"][self.compartment]),
                ionic_strength=Q_(
                    str(self.model.compartment_info["I"][self.compartment]) +
                    " M"),
                temperature=Q_(str(default_T) + " K"),
            )
            return std_dG_f[0] + transform.to_base_units().magnitude * 1e-3
        else:
            return std_dG_f[0]
def get_dGs(rxn_list: list,
            file_bigg_kegg_ids: str,
            pH: float = 7.0,
            ionic_strength: float = 0.1,
            digits: int = 2) -> dict:
    """
    Given a plain text file with reactions in the form R_FBA: m_g3p_c + m_dhap_c <-> m_fdp_c and a file with a
    mapping between bigg and kegg ids, returns the standard gibbs energy and respective uncertainty for each reaction.
    It skips exchange reactions, which should start with 'R_EX_'.

    Args:
        file_rxns: path to file with plain text reactions.
        file_bigg_kegg_ids: path to file with mapping between bigg and kegg ids.
        pH: pH value to use to calculate standard Gibbs energies.
        ionic_strength: ionic strength value to use to calculate standard Gibbs energies.
        digits: number of digits to round standard gibbs energies and respective uncertainty.

    Returns:
       Dictionary with bigg reaction ids as keys and (standard Gibbs energy, uncertainty) as values.
    """

    map_bigg_to_kegg_ids = pd.read_csv(file_bigg_kegg_ids, index_col=0)

    rxn_dict = convert_rxns_to_kegg(rxn_list, map_bigg_to_kegg_ids)

    rxn_dG_dict = {}
    eq_api = ComponentContribution(p_h=Q_(pH),
                                   ionic_strength=Q_(ionic_strength, 'M'))

    for rxn_id in rxn_dict.keys():

        rxn = parse_reaction_formula(rxn_dict[rxn_id])
        if not rxn.is_balanced():
            print(f'{rxn_id} is not balanced.')

        res = eq_api.standard_dg_prime(rxn)
        dG0 = res.value.magnitude
        dG0_std = res.error.magnitude

        rxn_dG_dict[rxn_id] = (round(dG0, digits), round(dG0_std, digits))

    return rxn_dG_dict
Exemple #10
0
    def __init__(self, rpsbml=None, ph=7.5, ionic_strength=200, pMg=10.0, temp_k=298.15):
        """Constructor class for rpEquilibrator

        :param rpsbml: rpSBML object (Default: None)
        :param ph: pH of the cell input from the rpSBML model input (Default: 7.5)
        :param ionic_strength: Ionic strength from the rpSBML model input (Default: 200)
        :param pMg: pMg value from the rpSBML model input (Default: 10.0)
        :param temp_k: Temperature from the rpSBML model input in Kelvin (Default: 298.15)

        :type rpsbml: rpSBML
        :type ph: float
        :type ionic_strength: float
        :type pMg: float
        :type temp_k: float

        .. document private functions
        .. automethod:: _makeSpeciesStr
        .. automethod:: _makeReactionStr
        .. automethod:: _speciesCmpQuery
        .. automethod:: _reactionCmpQuery
        .. automethod:: _reactionStrQuery
        """
        self.logger = logging.getLogger(__name__)
        self.logger.debug('Started instance of rpEquilibrator')
        self.cc = ComponentContribution()
        self.cc.p_h = Q_(ph)
        self.cc.ionic_strength = Q_(str(ionic_strength)+' mM')
        self.cc.p_mg = Q_(pMg)
        self.cc.temperature = Q_(str(temp_k)+' K')
        self.ph = ph
        self.ionic_strength = ionic_strength
        self.pMg = pMg
        self.temp_k = temp_k
        #self.mnx_default_conc = json.load(open('data/mnx_default_conc.json', 'r'))
        self.mnx_default_conc = json.load(open(os.path.join(os.path.dirname(os.path.abspath( __file__ )), 'data', 'mnx_default_conc.json'), 'r'))
        self.rpsbml = rpsbml
        self.calc_cmp = {}
Exemple #11
0
def initThermo(
    ph: float=DEFAULT_pH,
    ionic_strength: float=DEFAULT_ionic_strength,
    pMg: float=DEFAULT_pMg,
    logger: Logger=getLogger(__name__)
) -> ComponentContribution:

    print_title(
        txt='Initialising eQuilibrator...',
        logger=logger,
        waiting=True
    )

    cc = ComponentContribution()

    cc.p_h = Q_(ph)
    cc.ionic_strength = Q_(f'{ionic_strength}M')
    cc.p_mg = Q_(pMg)
    # if temp_k is not None:
    #     cc.temperature = Q_(str(temp_k)+' K')

    print_OK(logger)

    return cc
    rxn_cpds_array = reactions_helper.parseStoich(
        reactions_dict[rxn]["stoichiometry"])

    All_Mol = True
    Some_Mol = False
    for rgt in rxn_cpds_array:
        if (rgt['compound'] not in seed_mnx_structural_map):
            All_Mol = False
            Some_Mol = True

    if (All_Mol is True):
        complete_mol_rxns_dict[rxn] = 1
    elif (Some_Mol is True):
        incomplete_mol_rxns_dict[rxn] = 1

equilibrator_calculator = ComponentContribution(p_h=Q_(7.0),
                                                ionic_strength=Q_("0.25M"),
                                                temperature=Q_("298.15K"))
output_name = thermodynamics_root + 'eQuilibrator/MetaNetX_Reaction_Energies.tbl'
output_handle = open(output_name, 'w')
for rxn in reactions_dict:
    if (reactions_dict[rxn]['status'] == "EMPTY"):
        continue

    notes_list = reactions_dict[rxn]['notes']
    if (not isinstance(notes_list, list)):
        notes_list = list()

    if (rxn not in complete_mol_rxns_dict):

        #'EQ' means equilibrator approach to calculating energies
Exemple #13
0
    def _reactionCmpQuery(self, libsbml_reaction, write_results=False, physio_param=1e-3):
        """This method makes a list of structure compounds and uses equilibrator to return the reaction dG

        :param libsbml_reaction: A libsbml reaction object
        :param write_results: Write the results to the rpSBML file (Default: False)
        :param physio_param: The physiological parameter, i.e. the concentration of the compounds to calculate the dG (Default: 1e-3)

        :type libsbml_reaction: libsbml.Reaction
        :type write_results: bool
        :type physio_param: float

        :rtype: tuple
        :return: Tuple of size three with dfG_prime_o, dfG_prime_m, uncertainty values in that order or False if fail
        """
        mus = []
        sigma_vecs = []
        S = []
        dfG_prime_o = None
        dfG_prime_m = None
        uncertainty = None
        for rea in libsbml_reaction.getListOfReactants():
            self.logger.debug('------------------- '+str(rea.getSpecies())+' --------------')
            mu, sigma = self._speciesCmpQuery(self.rpsbml.model.getSpecies(rea.getSpecies()))
            self.logger.debug('mu: '+str(mu))
            if not mu:
                self.logger.warning('Failed to calculate the reaction mu thermodynamics using compound query')
                if write_results:
                    self.rpsbml.addUpdateBRSynth(libsbml_reaction, 'dfG_prime_o', 0.0, 'kj_per_mol')
                    self.rpsbml.addUpdateBRSynth(libsbml_reaction, 'dfG_prime_m', 0.0, 'kj_per_mol')
                    self.rpsbml.addUpdateBRSynth(libsbml_reaction, 'dfG_uncert', 0.0, 'kj_per_mol')
                return False
            elif mu=='h': #skipping the Hydrogen
                continue
            mus.append(mu)
            sigma_vecs.append(sigma)
            S.append([-rea.getStoichiometry()])
        for pro in libsbml_reaction.getListOfProducts():
            mu, sigma = self._speciesCmpQuery(self.rpsbml.model.getSpecies(pro.getSpecies()))
            if not mu:
                self.logger.warning('Failed to calculate the reaction mu thermodynamics using compound query')
                if write_results:
                    self.rpsbml.addUpdateBRSynth(libsbml_reaction, 'dfG_prime_o', 0.0, 'kj_per_mol')
                    self.rpsbml.addUpdateBRSynth(libsbml_reaction, 'dfG_prime_m', 0.0, 'kj_per_mol')
                    self.rpsbml.addUpdateBRSynth(libsbml_reaction, 'dfG_uncert', 0.0, 'kj_per_mol')
                return False
            elif mu=='h': #skipping the Hydrogen
                continue
            mus.append(mu)
            sigma_vecs.append(sigma)
            S.append([pro.getStoichiometry()])
        mus = Q_(mus, 'kJ/mol')
        sigma_vecs = Q_(sigma_vecs, 'kJ/mol')
        np_S = np.array(S)
        dfG_prime_o = np_S.T@mus
        dfG_prime_o = float(dfG_prime_o.m[0])
        ###### adjust fot physio parameters to calculate the dGm'
        #TODO: check with Elad
        dfG_prime_m = float(dfG_prime_o)+float(self.cc.RT.m)*sum([float(sto[0])*float(np.log(co)) for sto, co in zip(S, [physio_param]*len(S))])
        uncertainty = np_S.T@sigma_vecs
        uncertainty = [email protected]
        uncertainty = uncertainty.m[0][0]
        if write_results:
            self.rpsbml.addUpdateBRSynth(libsbml_reaction, 'dfG_prime_o', dfG_prime_o, 'kj_per_mol')
            self.rpsbml.addUpdateBRSynth(libsbml_reaction, 'dfG_prime_m', dfG_prime_m, 'kj_per_mol')
            self.rpsbml.addUpdateBRSynth(libsbml_reaction, 'dfG_uncert', uncertainty, 'kj_per_mol')
        return dfG_prime_o, dfG_prime_m, uncertainty
def create_reaction_id_to_dG0_mapping_json(model: cobra.Model, json_path: str) -> None:
    """Creates a reaction ID<->dG0 mapping using the Equilibrator API.

    This function uses the pregenerated BIGG ID to MetaNetX ID mapping, and
    lets the Equilibrator API calculate the dG0 values for each reaction using
    the MetaNetX IDs for the metabolites.

    This function is specifically written for the E. coli models used in CommModelPy's
    publication as its selection of dG0 values is based on BiGG identifiers and as it
    contains specific dG0 corrections for special reactions as referenced in the
    comments of this function.
    However, the general basis of this function can be easily adapted for other types of models.

    Arguments:
    * model: cobra.Model ~ The cobrapy model instance for which the dG0 mapping shall be created.
    * json_path: str ~ The path to the dG0 JSON that is going to be created.

    Output:
    * No variable but a JSON file with the mapping at json_path
    """
    bigg_id_to_metanetx_id = json_load("./publication_runs/ecoli_models/bigg_id_to_metanetx_mapping_json/bigg_id_to_metanetx_id_mapping_from_iML1515.json")
    reaction_id_dG0_mapping: Dict[str, Dict[str, float]] = {}
    cc = ComponentContribution()
    cc.p_h = Q_(7.0)
    cc.ionic_strength = Q_("0.25M")
    cc.temperature = Q_("298.15K")
    cc.p_mg = Q_(3.0)
    reaction_ids_without_dG0: List[str] = []
    for reaction in model.reactions:
        print("==dG0 GENERATION ATTEMPT FOR REACTION "+reaction.id+"==")
        # Exclude exchange reactions
        if reaction.id.startswith("EX_"):
            print("INFO: Reaction is identified as exchange reaction.")
            print("      No dG0 for this reaction!")
            reaction_ids_without_dG0.append(reaction.id)
            continue
        # Exclude special transport reactions
        if ("tpp_" in reaction.id+"_") or ("t1pp_" in reaction.id+"_") or ("tex_" in reaction.id+"_") or reaction.id.endswith("tex"):
            # tpp: Facilitated transport or (proton) symport
            # t1pp: Facilitated transport or (proton) symport
            # tex: "Via diffusion"
            print("INFO: Reaction is identified as special transport reaction.")
            print("      No dG0 for this reaction!")
            reaction_ids_without_dG0.append(reaction.id)
            continue
        # Exclude demand reactions
        if (reaction.id.startswith("DM_")):
            print("INFO: Reaction is identified as sink (demand) reaction.")
            print("      No dG0 for this reaction!")
            reaction_ids_without_dG0.append(reaction.id)
            continue

        educt_strings: List[str] = []
        product_strings: List[str] = []
        is_metanetx_id_missing = False
        for metabolite in reaction.metabolites.keys():
            base_metabolite_id = "".join(metabolite.id.split("_")[:-1])

            if base_metabolite_id.endswith("BIO"):
                base_metabolite_id = base_metabolite_id[:-len("BIO")]

            if base_metabolite_id not in bigg_id_to_metanetx_id.keys():
                is_metanetx_id_missing = True
                break

            if reaction.metabolites[metabolite] < 0:
                educt_strings.append(str(-reaction.metabolites[metabolite]) + " " + bigg_id_to_metanetx_id[base_metabolite_id])
            else:
                product_strings.append(str(reaction.metabolites[metabolite]) + " " + bigg_id_to_metanetx_id[base_metabolite_id])
        if is_metanetx_id_missing:
            print("INFO: MetanetX ID missing for " + base_metabolite_id)
            print("      No dG0 can be given for this reaction!")
            reaction_ids_without_dG0.append(reaction.id)
            continue
        educt_string = " + ".join(educt_strings)
        product_string = " + ".join(product_strings)
        reaction_string = educt_string + " = " + product_string
        print("Reaction string with MetanetX IDs: " + reaction_string)
        try:
            parsed_reaction = cc.parse_reaction_formula(reaction_string)
        except Exception as e:
            print("INFO: Equilibrator reaction parsing error")
            print(e)
            print("      No dG0 can be given for this reaction!")
            reaction_ids_without_dG0.append(reaction.id)
            continue
        try:
            dG0 = cc.standard_dg_prime(parsed_reaction)
            if dG0.m.s > 10000:
                print("INFO: dG0 standard deviation too high")
                print("      No dG0 can be given for this reaction!")
                reaction_ids_without_dG0.append(reaction.id)
                continue
            else:
                reaction_id_dG0_mapping[reaction.id+"_ecoli1"] = {}
                reaction_id_dG0_mapping[reaction.id+"_ecoli1"]["dG0"] = dG0.m.n
                reaction_id_dG0_mapping[reaction.id+"_ecoli1"]["uncertainty"] = 0
                reaction_id_dG0_mapping[reaction.id+"_ecoli2"] = {}
                reaction_id_dG0_mapping[reaction.id+"_ecoli2"]["dG0"] = dG0.m.n
                reaction_id_dG0_mapping[reaction.id+"_ecoli2"]["uncertainty"] = 0
                reaction_id_dG0_mapping[reaction.id+"_ecoli3"] = {}
                reaction_id_dG0_mapping[reaction.id+"_ecoli3"]["dG0"] = dG0.m.n
                reaction_id_dG0_mapping[reaction.id+"_ecoli3"]["uncertainty"] = 0
            print("dG0 calculation successful \\o/")
            print(f"dG0: {dG0}")
        except Exception as e:
            print("INFO:")
            print(e)
            print("      No dG0 can be given for this reaction!")
            reaction_ids_without_dG0.append(reaction.id)
            continue

        # Membrane-bound reaction corrections according to formula 9 in
        # Hamilton, J. J., Dwivedi, V., & Reed, J. L. (2013).
        # Quantitative assessment of thermodynamic constraints on
        # the solution space of genome-scale metabolic models.
        # Biophysical journal, 105(2), 512-522.
        # Formula is:
        # c_j * F * dPsi - 2.3 * h_j * R * T * dpH
        # c_j = net charge transported from outside to inside
        # h_j = Number of protons transported across membrane
        F = 0.10026  # kJ/mV/mol, or 0.02306; kcal/mV/mol
        dPsi = -130  # mV
        dpH = 0.4  # dimensionless
        R = 8.314e-3  # kJ⋅K⁻1⋅mol⁻1
        T = 298.15  # K
        # c_j and h_j are taken from supplementary table 3
        # of the mentioned publication (Hamilton et al., 2013)
        c_j = 0.0
        h_j = 0.0
        # ATP synthase
        if reaction.id.startswith("ATPS4"):
            c_j = 4.0
            h_j = 4.0
        # NADH dehydrogenases
        elif reaction.id.startswith("NADH16"):
            c_j = -3.5
            h_j = -3.5
        elif reaction.id.startswith("NADH17"):
            c_j = -2.0
            h_j = -2.0
        elif reaction.id.startswith("NADH18"):
            c_j = -2.8
            h_j = -2.8
        # Cytochrome dehydrogenases
        elif reaction.id.startswith("CYTBD"):
            c_j = -2.0
            h_j = -2.0
        elif reaction.id.startswith("CYTBO3"):
            c_j = -2.5
            h_j = -2.5

        if (c_j != 0) and (h_j != 0):
            print("Correcting dG0 for special membrane-bound reaction...")
            dG0_correction = c_j * F * dPsi - 2.3 * h_j * R * T * dpH
            print(f"Correction factor is {dG0_correction}")
            reaction_id_dG0_mapping[reaction.id+"_ecoli1"]["dG0"] += dG0_correction
            reaction_id_dG0_mapping[reaction.id+"_ecoli2"]["dG0"] += dG0_correction
            reaction_id_dG0_mapping[reaction.id+"_ecoli3"]["dG0"] += dG0_correction
            print("New dG0 is " + str(reaction_id_dG0_mapping[reaction.id+"_ecoli1"]["dG0"]))

    num_reactions_without_dG0 = len(reaction_ids_without_dG0)
    print("\n==FINAL STATISTICS==")
    print("No dG0 for the following reactions:")
    print("\n".join(reaction_ids_without_dG0))
    print("Total number: ", str(num_reactions_without_dG0))
    print("Fraction from all reactions: ", num_reactions_without_dG0/len(model.reactions))

    json_write(json_path, reaction_id_dG0_mapping)