from __future__ import division, print_function
from __future__ import absolute_import
from __future__ import unicode_literals
import pickle as pickle
from sympy.matrices import Matrix
from sympy import sympify
import sys
from .ccobjects import CCBase
from ...utils.misc import extract_model
from ...utils.misc import get_filename_from_caller
from ...modeltools import make_path, get_file_path
from ...latextools import LatexExpr
from .symca_toolbox import SymcaToolBox as SMCAtools
from numpy import savetxt, array
from ...utils import ConfigReader
import warnings
all = ['Symca']
[docs]class Symca(object):
"""
A class that performs Symbolic Metabolic Control Analysis.
This class takes pysces model as an input and performs symbolic inversion
of the ``E matrix`` using ``Sympy`` by calculating the determinant and
adjoint matrices of this ``E matrix``.
Parameters
----------
mod : PysMod
The pysces model on which to perform symbolic control analysis.
auto_load : boolean
If true
Returns
------
"""
def __init__(self, mod, auto_load=False, internal_fixed=False, ignore_steady_state=False, keep_zero_elasticities=True):
super(Symca, self).__init__()
ConfigReader.get_config()
self._ignore_steady_state = ignore_steady_state
self._keep_zero_ecs = keep_zero_elasticities
self.mod, obj_type = extract_model(mod)
if not self._ignore_steady_state:
self.mod.doMca()
else:
warnings.warn_explicit("\nIgnoring steady-state solution: Steady-state variables set to 1. Note that parameter scan functionality is unavailable.",
Warning,
filename=get_filename_from_caller(),
lineno=42)
SMCAtools.populate_with_fake_elasticities(mod)
SMCAtools.populate_with_fake_fluxes(mod)
SMCAtools.populate_with_fake_ss_concentrations(mod)
self._analysis_method = 'symca'
self._internal_filename = 'object_data'
self._working_dir = make_path(self.mod, self._analysis_method)
self._ltxe = LatexExpr(self.mod)
self.cc_results = None
self._nmatrix = None
self._species = None
self._num_ind_species = None
self._species_independent = None
self._species_dependent = None
self._fluxes = None
self._num_ind_fluxes = None
self._fluxes_independent = None
self._fluxes_dependent = None
self._kmatrix = None
self._lmatrix = None
self._subs_fluxes = None
self._scaled_k = None
self._scaled_l = None
self._scaled_k0 = None
self._scaled_l0 = None
self._es_matrix = None
self._esL = None
self._ematrix = None
self.internal_fixed = internal_fixed
if obj_type == 'RateCharData':
self.internal_fixed = True
if auto_load:
try:
self.load_session()
except:
print('Nothing to load_session: Run `do_symca` first')
@property
def nmatrix(self):
if not self._nmatrix:
self._nmatrix = SMCAtools.get_nmatrix(self.mod)
return self._nmatrix
@property
def num_ind_species(self):
if not self._num_ind_species:
self._num_ind_species = SMCAtools.get_num_ind_species(self.mod)
return self._num_ind_species
@property
def species(self):
if not self._species:
self._species = SMCAtools.get_species_vector(self.mod)
return self._species
@property
def species_independent(self):
if not self._species_independent:
self._species_independent = Matrix(
self.species[:self.num_ind_species]
)
return self._species_independent
@property
def species_dependent(self):
if not self._species_dependent:
self._species_dependent = Matrix(
self.species[self.num_ind_species:]
)
return self._species_dependent
@property
def num_ind_fluxes(self):
if not self._num_ind_fluxes:
self._num_ind_fluxes = SMCAtools.get_num_ind_fluxes(self.mod)
return self._num_ind_fluxes
@property
def fluxes(self):
if not self._fluxes:
self._fluxes = SMCAtools.get_fluxes_vector(self.mod)
return self._fluxes
@property
def fluxes_independent(self):
if not self._fluxes_independent:
self._fluxes_independent = Matrix(
self.fluxes[:self.num_ind_fluxes]
)
return self._fluxes_independent
@property
def fluxes_dependent(self):
if not self._fluxes_dependent:
self._fluxes_dependent = Matrix(
self.fluxes[self.num_ind_fluxes:]
)
return self._fluxes_dependent
@property
def kmatrix(self):
if not self._kmatrix:
self._kmatrix = Matrix(self.mod.kmatrix)
return self._kmatrix
@property
def lmatrix(self):
if not self._lmatrix:
self._lmatrix = Matrix(self.mod.lmatrix)
return self._lmatrix
@property
def subs_fluxes(self):
if not self._subs_fluxes:
self._subs_fluxes = SMCAtools.substitute_fluxes(
self.fluxes,
self.kmatrix
)
return self._subs_fluxes
@property
def scaled_l(self):
if not self._scaled_l:
self._scaled_l = SMCAtools.scale_matrix(
self.species,
self.lmatrix,
self.species_independent
)
return self._scaled_l
@property
def scaled_k(self):
if not self._scaled_k:
self._scaled_k = SMCAtools.scale_matrix(
self.subs_fluxes,
self.kmatrix,
self.fluxes_independent
)
return self._scaled_k
@property
def scaled_l0(self):
if not self._scaled_l0:
self._scaled_l0 = self.scaled_l[self.num_ind_species:, :]
return self._scaled_l0
@property
def scaled_k0(self):
if not self._scaled_k0:
self._scaled_k0 = self.scaled_k[self.num_ind_fluxes:, :]
return self._scaled_k0
@property
def es_matrix(self):
if not self._es_matrix:
if self._ignore_steady_state or self._keep_zero_ecs:
es_method = SMCAtools.get_es_matrix_no_mca
else:
es_method = SMCAtools.get_es_matrix
self._es_matrix = es_method(
self.mod,
self.nmatrix,
self.fluxes,
self.species
)
return self._es_matrix
@property
def esL(self):
if not self._esL:
self._esL = self.es_matrix * self.scaled_l
return self._esL
@property
def ematrix(self):
if not self._ematrix:
self._ematrix = SMCAtools.simplify_matrix(
self.scaled_k.row_join(
-self.esL
)
)
return self._ematrix
[docs] def path_to(self, path):
full_path = make_path(self.mod, self._analysis_method, [path])
return full_path
[docs] def save_session(self, file_name=None):
file_name = get_file_path(working_dir=self._working_dir,
internal_filename=self._internal_filename,
fmt='pickle',
file_name=file_name,
write_suffix=False)
assert self.cc_results, 'Nothing to save_session, run ``do_symca`` method first'
main_cc_dict = SMCAtools.make_inner_dict(self.cc_results, 'cc_results')
counter = 0
while True:
cc_container_name = 'cc_results_{0}'.format(counter)
try:
cc_container = getattr(self, cc_container_name)
main_cc_dict.update(
SMCAtools.make_inner_dict(cc_container, cc_container_name))
counter += 1
except:
break
to_save = main_cc_dict
with open(file_name, 'wb') as f:
pickle.dump(to_save, f)
[docs] def load_session(self, file_name=None):
file_name = get_file_path(working_dir=self._working_dir,
internal_filename=self._internal_filename,
fmt='pickle',
file_name=file_name,
write_suffix=False)
with open(file_name, 'rb') as f:
main_cc_dict = pickle.load(f)
cc_containers = {}
for key, value in main_cc_dict.items():
common_denom_exp = value.pop('common_denominator')
cc_container = SMCAtools.spawn_cc_objects(self.mod,
list(value.keys()),
[exp for exp in
list(value.values())],
common_denom_exp,
self._ltxe)
cc_containers[key] = SMCAtools.make_CC_dot_dict(cc_container)
for key, value in cc_containers.items():
setattr(self, key, value)
[docs] def save_results(self, file_name=None, separator=',',fmt='%.9f'):
file_name = get_file_path(working_dir=self._working_dir,
internal_filename='cc_summary',
fmt='csv',
file_name=file_name, )
rows = []
cc_counter = 0
cc_dicts = [self.cc_results]
max_len = 0
while True:
try:
next_dict = getattr(self, 'cc_results_%s' % cc_counter)
cc_dicts.append(next_dict)
cc_counter += 1
except:
break
sep = ('######################', 0, '', '')
cc_counter = -1
for cc_dict in cc_dicts:
result_name = '# results from cc_results'
if cc_counter >= 0:
result_name += '_%s' % cc_counter
head = (result_name, 0, '', '')
rows.append(head)
for cc_name in sorted(cc_dict.keys()):
cc_obj = cc_dict[cc_name]
row_1 = (cc_obj.name,
cc_obj.value,
cc_obj.latex_name,
cc_obj.latex_expression)
expr_len = len(cc_obj.latex_expression)
if expr_len > max_len:
max_len = expr_len
rows.append(row_1)
if not cc_obj.name == 'common_denominator':
for cp in cc_obj.control_patterns.values():
cols = (cp.name,
cp.value,
cp.latex_name,
cp.latex_expression)
rows.append(cols)
rows.append(sep)
cc_counter += 1
str_fmt = 'U%s' % max_len
head = ['name', 'value', 'latex_name', 'latex_expression']
X = array(rows,
dtype=[(head[0], str_fmt),
(head[1], 'float'),
(head[2], str_fmt),
(head[3], str_fmt)])
try:
savetxt(fname=file_name,
X=X,
header=separator.join(head),
delimiter=separator,
fmt=['%s', fmt, '%s', '%s'],)
except IOError as e:
print(e.strerror)
[docs] def do_symca(self, internal_fixed=None, auto_save_load=False):
if internal_fixed is None:
internal_fixed = self.internal_fixed
def do_symca_internals(self):
CC_i_num, common_denom_expr = SMCAtools.invert(
self.ematrix,
self.path_to('temp')
)
cc_sol = SMCAtools.solve_dep(
CC_i_num,
self.scaled_k0,
self.scaled_l0,
self.num_ind_fluxes,
self.path_to('temp')
)
cc_sol, common_denom_expr = SMCAtools.fix_expressions(
cc_sol,
common_denom_expr,
self.lmatrix,
self.species_independent,
self.species_dependent
)
common_denom_object = CCBase(self.mod,
'common_denominator',
common_denom_expr,
self._ltxe)
if common_denom_object.value < 0:
common_denom_expr *= -1
cc_sol *= -1
del common_denom_object
cc_names = SMCAtools.build_cc_matrix(
self.fluxes,
self.fluxes_independent,
self.species_independent,
self.fluxes_dependent,
self.species_dependent
)
cc_objects = SMCAtools.spawn_cc_objects(self.mod,
cc_names,
cc_sol,
common_denom_expr,
self._ltxe)
self.cc_results = SMCAtools.make_CC_dot_dict(cc_objects)
if internal_fixed:
simpl_dic = SMCAtools.make_internals_dict(cc_sol,
cc_names,
common_denom_expr,
self.path_to('temp'))
CC_block_counter = 0
for each_common_denom_expr, name_num in simpl_dic.items():
name_num[1], \
each_common_denom_expr = SMCAtools.fix_expressions(
name_num[1],
each_common_denom_expr,
self.lmatrix,
self.species_independent,
self.species_dependent
)
simpl_cc_objects = SMCAtools.spawn_cc_objects(self.mod,
name_num[0],
name_num[1],
each_common_denom_expr,
self._ltxe, )
CC_dot_dict = SMCAtools.make_CC_dot_dict(simpl_cc_objects)
setattr(self, 'cc_results_%s' %
CC_block_counter, CC_dot_dict)
CC_block_counter += 1
self.CC_i_num = CC_i_num
if auto_save_load:
try:
self.load_session()
except:
do_symca_internals(self)
self.save_session()
else:
do_symca_internals(self)