Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Mrg: Dev #2

Merged
merged 19 commits into from
Jun 6, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion doc/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ def __getattr__(cls, name):
version = '0.9'
# The full version, including alpha/beta/rc tags.

release = '0.9.0-b1'
release = '0.9.0-b2'

# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
Expand Down
8 changes: 4 additions & 4 deletions pytfa/analysis/manipulation.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,10 +67,10 @@ def apply_directionality(tmodel,solution, inplace = True):
backward_use = _tmodel.backward_use_variable.get_by_id(this_reaction.id)
forward_use = _tmodel.forward_use_variable.get_by_id(this_reaction.id)

backward_use.variable.lb = round(solution.x_dict[backward_use.name])
backward_use.variable.ub = round(solution.x_dict[backward_use.name])
backward_use.variable.lb = round(solution.raw[backward_use.name])
backward_use.variable.ub = round(solution.raw[backward_use.name])

forward_use.variable.lb = round(solution.x_dict[forward_use.name])
forward_use.variable.ub = round(solution.x_dict[forward_use.name])
forward_use.variable.lb = round(solution.raw[forward_use.name])
forward_use.variable.ub = round(solution.raw[forward_use.name])

return _tmodel
10 changes: 5 additions & 5 deletions pytfa/analysis/variability.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,21 +75,21 @@ def find_directionality_profiles(tmodel, bidirectional, max_iter = 1e4,
except SolverError:
break

profiles[iter_count] = solution.x_dict
profiles[iter_count] = solution.raw
if iter_count > 0:
sse = sum((profiles[iter_count-1] - profiles[iter_count])**2)
else:
sse =0

tmodel.logger.info(str(iter_count) + ' - ' + str(sse))
tmodel.logger.debug(str(iter_count) + ' - ' + str(sse))

# active_use_variables = get_active_use_variables(this_tmodel,solution)
active_use_variables = get_direction_use_variables(this_tmodel,solution)
bidirectional_use_variables = [x for x in active_use_variables \
if x.reaction in bidirectional_reactions]
bool_id = ''.join('1' if isinstance(x,ForwardUseVariable) else '0' \
for x in bidirectional_use_variables)
Tracer()()

# Make the expression to forbid this expression profile to happen again
# FP_1101: FU_rxn1 + FU_rxn2 + BU_rxn3 + FU_rxn4 <= 4-1 = 3
expr = sum(bidirectional_use_variables)
Expand Down Expand Up @@ -205,10 +205,10 @@ def calculate_dissipation(tmodel,solution=None):
solution = tmodel.solution

reaction_id = [x.id for x in tmodel.reactions]
fluxes = solution.x_dict[reaction_id]
fluxes = solution.fluxes[reaction_id]

deltag_var = tmodel.get_variables_of_type(DeltaG)
deltag = pd.Series({x.id:solution.x_dict[x.name]
deltag = pd.Series({x.id:solution.raw[x.name]
for x in deltag_var})
dissipation = fluxes*deltag

Expand Down
23 changes: 20 additions & 3 deletions pytfa/core/model.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,10 @@

def timeit(method):
"""
Adapted from Andreas Jung's blog:
https://www.zopyx.com/andreas-jung/contents/a-python-decorator-for-measuring-the-execution-time-of-methods
Adapted from Andreas Jung's `blog
<https://www.zopyx.com/andreas-jung/contents/a-python-decorator-for-measuring-the-execution-time-of-methods>`_

:param method:
:param method: The method to time
:return:
"""

Expand Down Expand Up @@ -121,6 +121,7 @@ def add_variable(self, kind, hook, queue=False, **kwargs):
**kwargs)

self._var_dict[var.name] = var
self.logger.debug('Added variable: {}'.format(var.name))
# self.add_cons_vars(var.variable)

return var
Expand Down Expand Up @@ -150,6 +151,7 @@ def add_constraint(self, kind, hook, expr, queue=False,**kwargs):
queue=queue,
**kwargs)
self._cons_dict[cons.name] = cons
self.logger.debug('Added constraint: {}'.format(cons.name))
# self.add_cons_vars(cons.constraint)

return cons
Expand Down Expand Up @@ -321,6 +323,21 @@ def get_solution(self):
"""
Overrides the cobra.thermo.solution method, to also get the supplementary
variables we added to the cobra_model

* :code:`solution.fluxes` in `cobrapy` is a transformed version of the solver
output, as it actually calculates the _net_ flux of each reaction by
substracting the reverse variable value to the forward variable value.
This should be used anytime one needs the actual flux value

* :code:`solution.raw` is a clear copy of the solver output. From there one
can access the value at solution for all the variables of the problem.
However, looking for a reaction ID in there will only give the
_forward_ flux. This should be used for any other variable than fluxes.

* :code:`solution.values` yields variables multiplied by their scaling factor
(1 by default). Useful if you operated scaling on your equations for
numerical reasons. This does _not_ include fluxes

:return:
"""
objective_value = self.solver.objective.value
Expand Down
21 changes: 19 additions & 2 deletions pytfa/io/dict.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

from ..optim.variables import ReactionVariable, MetaboliteVariable, ModelVariable
from ..optim.constraints import ReactionConstraint, MetaboliteConstraint, ModelConstraint
from ..optim.utils import symbol_sum

from optlang.util import expr_to_json, parse_expr

Expand Down Expand Up @@ -155,6 +156,10 @@ def get_solver_string(model):
return SOLVER_DICT[model.solver.__class__.__module__]


def obj_to_dict(model):
return {x.name: v
for x,v in model.objective.expression.as_coefficients_dict().items()}

def model_to_dict(model):
"""

Expand All @@ -167,6 +172,7 @@ def model_to_dict(model):
obj = cbd.model_to_dict(model)

obj['solver'] = get_solver_string(model)
obj['objective'] = obj_to_dict(model)

# Copy variables, constraints
# obj['var_dict'] = archive_variables(model._var_kinds)
Expand Down Expand Up @@ -285,15 +291,17 @@ def model_from_dict(obj, solver=None, custom_hooks = None):
id_=this_id,
ub=ub,
lb=lb,
queue=True)
queue=True,
scaling_factor=scaling_factor)
elif classname in name2class:
hook = name2hook[classname].get_by_id(this_id)
this_class = name2class[classname]
nv = new.add_variable(kind=this_class,
hook=hook,
ub = ub,
lb = lb,
queue=True)
queue=True,
scaling_factor=scaling_factor)
else:
raise TypeError(
'Class {} serialization not handled yet' \
Expand Down Expand Up @@ -343,6 +351,11 @@ def model_from_dict(obj, solver=None, custom_hooks = None):

new.repair()

try:
rebuild_obj_from_dict(new, obj['objective'])
except KeyError:
pass

# Relaxation info
try:
new.relaxation = obj['relaxation']
Expand All @@ -351,6 +364,10 @@ def model_from_dict(obj, solver=None, custom_hooks = None):

return new

def rebuild_obj_from_dict(new, objective_dict):
obj_expr = symbol_sum([v*new.variables.get(x) for x,v in objective_dict.items()])
new.objective = obj_expr

def add_custom_classes(model, custom_hooks):
"""
Allows custom variable serialization
Expand Down
2 changes: 1 addition & 1 deletion pytfa/io/plotting.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ def plot_thermo_displacement_histogram(tmodel,solution = None):
thermo_displacements = tmodel.get_variables_of_type(ThermoDisplacement)
varnames = [x.name for x in thermo_displacements]

values = solution.x_dict[varnames]
values = solution.raw[varnames]

p1 = plot_histogram(values)

Expand Down
13 changes: 11 additions & 2 deletions pytfa/optim/constraints.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,14 @@
"""

from ..utils.str import camel2underscores
from .meta import ABCRequirePrefixMeta

###################################################
### CONSTRAINTS ###
###################################################


class GenericConstraint:
class GenericConstraint(metaclass=ABCRequirePrefixMeta):
"""
Class to represent a generic constraint. The purpose is that the interface
is instantiated on initialization, to follow the type of interface used
Expand All @@ -35,7 +36,7 @@ class GenericConstraint:
:cobra_model: the cobra_model hook.
:constraint: links directly to the cobra_model representation of tbe constraint
"""
prefix = ''
prefix = NotImplemented


@property
Expand Down Expand Up @@ -159,6 +160,8 @@ def __init__(self, model, expr, id_, **kwargs):
hook=model,
**kwargs)

prefix = 'MODC_'


class GeneConstraint(GenericConstraint):
"""
Expand Down Expand Up @@ -186,6 +189,8 @@ def id(self):
def model(self):
return self.gene.model

prefix = 'GC_'

class ReactionConstraint(GenericConstraint):
"""
Class to represent a variable attached to a reaction
Expand Down Expand Up @@ -213,6 +218,8 @@ def id(self):
def model(self):
return self.reaction.model

prefix = 'RC_'

class MetaboliteConstraint(GenericConstraint):
"""
Class to represent a variable attached to a enzyme
Expand All @@ -239,6 +246,8 @@ def id(self):
def model(self):
return self.metabolite.model

prefix = 'MC_'

class NegativeDeltaG(ReactionConstraint):
"""
Class to represent thermodynamics constraints.
Expand Down
28 changes: 28 additions & 0 deletions pytfa/optim/meta.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# -*- coding: utf-8 -*-
"""
.. module:: pytfa
:platform: Unix, Windows
:synopsis: Thermodynamics-based Flux Analysis

.. moduleauthor:: pyTFA team

Metaclass declarations to force the definition of prefixes in GenericVariable
and GeneriConstraint subclasses

"""
from abc import ABCMeta

class RequirePrefixMeta(type):
"""Metaclass that enforces child classes define prefix."""

def __init__(cls, name, bases, attrs):
# Skip the check if there are no parent classes,
# which allows base classes to not define prefix.
if not bases:
return
if attrs.get('prefix', NotImplemented) is NotImplemented:
# Choose your favorite exception.
raise NotImplementedError('You forgot to define a prefix for your class ;)')

ABCRequirePrefixMeta = type('ABCRequirePrefixMeta',
(ABCMeta, RequirePrefixMeta), {})
15 changes: 11 additions & 4 deletions pytfa/optim/variables.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,13 @@
Variable declarations

"""
from abc import ABCMeta

from distutils.version import LooseVersion
from optlang import __version__ as OPTLANG_VER

from ..utils.str import camel2underscores
from .meta import ABCRequirePrefixMeta

from warnings import warn

Expand All @@ -28,8 +31,7 @@
### VARIABLES ###
###################################################


class GenericVariable:
class GenericVariable(metaclass=ABCRequirePrefixMeta):
"""
Class to represent a generic variable. The purpose is that the interface
is instantiated on initialization, to follow the type of interface used
Expand All @@ -46,7 +48,7 @@ class GenericVariable:
:cobra_model: the cobra_model hook.
:variable: links directly to the cobra_model representation of tbe variable
"""
prefix = ''
prefix = NotImplemented

@property
def __attrname__(self):
Expand Down Expand Up @@ -147,7 +149,7 @@ def unscaled(self):
@property
def value(self):
try:
return self.model.solution.x_dict[self.name]
return self.model.solution.raw[self.name]
except AttributeError:
warn('Model need to be optimized to get a value for this variable')

Expand Down Expand Up @@ -345,6 +347,7 @@ def __init__(self, model, id_, **kwargs):
model=model,
hook=model,
**kwargs)
prefix = 'MODV_'

class GeneVariable(GenericVariable):
"""
Expand Down Expand Up @@ -422,6 +425,8 @@ def id(self):
def model(self):
return self.reaction.model

prefix = 'RV_'

class MetaboliteVariable(GenericVariable):
"""
Class to represent a variable attached to a enzyme
Expand All @@ -447,6 +452,8 @@ def id(self):
def model(self):
return self.metabolite.model

prefix = 'MV_'


class ForwardUseVariable(ReactionVariable, BinaryVariable):
"""
Expand Down
Loading