4. ORACLE parameter samplingΒΆ
We here present the first open-source implementation of the ORACLE parametrization method [3-6]. ORACLE makes use of sampling alternative steady states and parameter backcalculation to efficiently sample large sets of locally stable parameters.
The first step in the ORACLE workflow is to integrate physiological data. Here we integrare observed concentrations and we assume that the glucose transporter operates far from equilibrium.
from pytfa.io.json import load_json_model, save_json_model
path_to_tmodel = './../../models/tfa_varma.json'
tmodel = load_json_model(path_to_tmodel)
GLPK= 'optlang-glpk'
CPLEX = 'optlang-cplex'
tmodel.solver = GLPK
tmodel.solver.configuration.tolerances.feasibility = 1e-9
# Define the reactor medium
#Glucose to 10 g/L = 0.056 mol/l 1/2 Reactor concentration
GLUCOSE_CONCENTRATION = 0.056
PHOSPHATE = 10e-3
CARBON_DIOXIDE = 1e-7
OXYGEN = 8e-3*0.062 # 8 mg/L 1g = 0.062 mol
tmodel.log_concentration.get_by_id('glc-D_e').variable.ub = np.log(GLUCOSE_CONCENTRATION*1.2)
tmodel.log_concentration.get_by_id('glc-D_e').variable.lb = np.log(GLUCOSE_CONCENTRATION*0.8)
tmodel.log_concentration.get_by_id('pi_e').variable.lb = np.log(PHOSPHATE*0.8)
tmodel.log_concentration.get_by_id('pi_e').variable.ub = np.log(PHOSPHATE*1.2)
tmodel.log_concentration.get_by_id('co2_e').variable.ub = np.log(CARBON_DIOXIDE*1.2)
tmodel.log_concentration.get_by_id('co2_e').variable.lb = np.log(CARBON_DIOXIDE*0.8)
tmodel.log_concentration.get_by_id('o2_e').variable.ub = np.log(OXYGEN*1.2)
tmodel.log_concentration.get_by_id('o2_e').variable.lb = np.log(OXYGEN*0.8)
# Enforce glucose transporter displacements
tmodel.thermo_displacement.GLCptspp.variable.ub = -2.0
# Test feasiblity
print(tmodel.optimize())
In the next step we sample the flux and concentration space:
from pytfa.analysis.sampling import sample
NUM_TFA_SAMPLES = 10
samples = sample(tmodel, NUM_TFA_SAMPLES, method='achr')
samples.to_csv('./samples_fdp1_1000.csv'.format())
Fluxes sampled in the TFA problem are mass fluxes in units of mmol/gDW/hr we convert these
to reaction rates in units of [concentration]/[time] therefore we require the cell density and
the wet weight to dry weight ratio. It is also useful to choose a different concentration unit than [M] since
most intracellular metabolite concentration are between 1 mM and 1 uM, which can be achived by choosing a different
concentration scaling factor: [C] = [M] x CONCENTRATION_SCALING.
N_PARAMETER_SAMPLES = 10
CONCENTRATION_SCALING = 1e6 # 1 umol
TIME_SCALING = 1 # 1hr
DENSITY = 1200 # g/L
GDW_GWW_RATIO = 0.3 # Assumes 70% Water
Finally we call the parameter sampler for each sampled reference steady-state. The parameter sampler provides then information on the charateristic timescales this information can then later be used to discard parameter samples exhibiting unphysiological characteristics.
The parameter sampler will requires that the Jacobian is compiled kmodel.compile_jacobian() to evaluate the stablity of the samples.
from skimpy.io.yaml import load_yaml_model
from skimpy.analysis.oracle.load_pytfa_solution import load_fluxes, \
load_concentrations, load_equilibrium_constants
from skimpy.core.parameters import ParameterValuePopulation, load_parameter_population
from skimpy.sampling.simple_parameter_sampler import SimpleParameterSampler
from skimpy.utils.general import get_stoichiometry
NCPU = 8
path_to_kmodel = './../../models/kin_varma.yml'
path_for_output = './paramter_pop_{}.h5'
kmodel = load_yaml_model(path_to_kmodel)
# Perp and compile to sample parameters
kmodel.prepare()
kmodel.compile_jacobian(ncpu=NCPU)
sampler_params = SimpleParameterSampler.Parameters(n_samples=N_PARAMETER_SAMPLES)
sampler = SimpleParameterSampler(sampler_params)
lambda_max_all = []
lambda_min_all = []
S = get_stoichiometry(kmodel, kmodel.reactants).todense()
from skimpy.utils.namespace import *
from skimpy.analysis.ode.utils import make_flux_fun
fluxfun= make_flux_fun(kmodel, QSSA)
fluxes = []
for i, sample in samples.iterrows():
# Load fluxes and concentrations and scale them to the desired units
fluxes = load_fluxes(sample, tmodel, kmodel,
density=DENSITY,
ratio_gdw_gww=GDW_GWW_RATIO,
concentration_scaling=CONCENTRATION_SCALING,
time_scaling=TIME_SCALING)
concentrations = load_concentrations(sample, tmodel, kmodel,
concentration_scaling=CONCENTRATION_SCALING)
# Fetch equilibrium constants and scale them to the desired units
load_equilibrium_constants(sample, tmodel, kmodel,
concentration_scaling=CONCENTRATION_SCALING,
in_place=True)
# Generate samples and fetch slowest and fastest eigenvalues
params, lamda_max, lamda_min = sampler.sample(kmodel, fluxes, concentrations,
only_stable=True,
min_max_eigenvalues=True)
lambda_max_all.append(pd.DataFrame(lamda_max))
lambda_min_all.append(pd.DataFrame(lamda_min))
params_population = ParameterValuePopulation(params, kmodel)
params_population.save(path_for_output.format(i))
# Process df and save dataframe
lambda_max_all = pd.concat(lambda_max_all, axis=1)
lambda_min_all = pd.concat(lambda_min_all, axis=1)