Source code for ihm.multi_state_scheme

# coding=utf-8

import ihm
from ihm.model import _text_choice_property

"""Classes for handling connected/ordered schemes formed by multiple state
    together with information on kinetic schemes"""


[docs] class MultiStateScheme(object): """MultiStateScheme collects information about a collection of multiple states, that can form a connected/ordered scheme. A special case is a kinetic scheme, for which kinetic rates and relaxation times are available. :param str name: The name of the multi-state scheme. :param str details: Details on the scheme. :param connectivities: A list of connectivities that belong to the scheme. :type connectivities: List of :class:`Connectivity` :param relaxation_times: A list of relaxation times not assigned to specific connectivities, but to the scheme :type relaxation_times: List of :class:`RelaxationTime` """ def __init__(self, name, details=None, connectivities=None, relaxation_times=None): self.name = name self.details = details self._connectivity_list = [] self._relaxation_time_list = [] # states is filled automatically based on connectivity_list self._states = [] if connectivities is not None: for c in connectivities: if c not in self._connectivity_list: self.add_connectivity(c) if relaxation_times is not None: for r in relaxation_times: if r not in self._relaxation_time_list: self.add_relaxation_time(r)
[docs] def add_connectivity(self, connectivity): """Add a connectivity to the scheme. :param connectivity: The connectivity to add to the scheme :type connectivity: :class:`Connectivity` """ if connectivity is None: return if connectivity not in self._connectivity_list: # Make sure that the connectivity has not been assigned to # another scheme if not connectivity._assigned_to_scheme: connectivity.set_assigned_to_scheme() self._connectivity_list.append(connectivity) # If the connectivity has been assigned to another scheme, # create a copy of the connectivity and use that else: old_connectivity = connectivity connectivity = \ ihm.multi_state_scheme.Connectivity( begin_state=old_connectivity.begin_state, end_state=old_connectivity.end_state, details=old_connectivity.details, dataset_group=old_connectivity.dataset_group, kinetic_rate=old_connectivity.kinetic_rate, relaxation_time=old_connectivity.relaxation_time ) connectivity.set_assigned_to_scheme() self._connectivity_list.append(connectivity) # Add the states that belong to the connectivity self._add_state(connectivity.begin_state) self._add_state(connectivity.end_state)
def _add_state(self, state): """Add a state to the self._states list if it is not present yet. This function checks whether the state has optional properties, such as a name. If this is the case, the name is compared to the names already in the list. If the state does not have a name, it might only be a list of elements. Then only the contents of the list are checked This is important for empty states, i.e. those that do not have models associated. :param state: The state to add. :type state: :class:`ihm.model.State` """ if state is None: return for tmp_state in self._states: # Check whether both states have the name attributes if hasattr(state, 'name') and hasattr(tmp_state, 'name'): # compare the properties of the two states and the elements of # the lists if state.__dict__ == tmp_state.__dict__ \ and state == tmp_state: # state found return # If neither of the two states has the name attribute, only compare # the elements of the lists if not hasattr(state, 'name') and not hasattr(tmp_state, 'name'): # If the two states have the same elements if state == tmp_state: # state found return # If the state was not found in the list yet, add it self._states.append(state)
[docs] def add_relaxation_time(self, relaxation_time): """Add a relaxation time to the scheme. This relaxation time is not assigned to a connectivity. :param relaxation_time: The relaxation time to add to the scheme. :type relaxation_time: :class:`RelaxationTime` """ if relaxation_time is not None: self._relaxation_time_list.append(relaxation_time)
[docs] def get_connectivities(self): """Return the connectivities assigned to a scheme""" return self._connectivity_list
[docs] def get_relaxation_times(self): """Return the relaxation times assigned to a scheme""" return self._relaxation_time_list
[docs] def get_states(self): """Return the states involved in a scheme""" return self._states
def __eq__(self, other): return ((self.__dict__ == other.__dict__) and (self._connectivity_list == other._connectivity_list) and (self._relaxation_time_list == other._relaxation_time_list))
[docs] class Connectivity(object): """A connectivity between states. Used to describe the directed edge of graph. If no end_state is given, the state is not connected to another state. This could be the case for states where no connection to other states could be resolved. :param begin_state: The start state of the connectivity. :type begin_state: :class:`ihm.model.State` :param end_state: The end state of the connectivity. Can be None in case of states that are not connected to others. :type end_state: :class:`ihm.model.State` :param details: Details to the connectivity. :param dataset_group: The DatasetGroup that was used to obtain information on the connectivity. :type dataset_group: :class:`ihm.dataset.DatasetGroup` :param kinetic_rate: A kinetic rate assigned to the connectivity. :type kinetic_rate: :class:`KineticRate` :param relaxation_time: A relaxation time assigned to the connectivity. :type relaxation_time: :class:`RelaxationTime` """ def __init__(self, begin_state, end_state=None, details=None, dataset_group=None, kinetic_rate=None, relaxation_time=None): self.begin_state = begin_state self.end_state = end_state self.details = details self.dataset_group = dataset_group self.kinetic_rate = kinetic_rate self.relaxation_time = relaxation_time # The _assigned_to_scheme variable tracks whether the connectivity # has been assigned to a scheme. This is to ensure that each # connectivity is only assigned to a single scheme. self._assigned_to_scheme = False def set_assigned_to_scheme(self): self._assigned_to_scheme = True def __eq__(self, other): return self.__dict__ == other.__dict__
[docs] class KineticRate(object): """A base class for a kinetic rate that can be assigned to a connectivity. The kinetic rate could be a transition_rate_constant or an equilibrium_constant. Alternatively, both could be provided. :param float transition_rate_constant: A transition rate constant describing the exchange between two states. Unit: per second. :param equilibrium_constant: An equilibrium constant describing the exchange between two states :type equilibrium_constant: :class:`EquilibriumConstant` or :class:`PopulationEquilibriumConstant` or :class:`KineticRateEquilibriumConstant` :param str details: Details on the kinetic rate. :param dataset_group: The DatasetGroup used to determine the kinetic rate. :type dataset_group: :class:`ihm.dataset.DatasetGroup` :param file: External file containing measurement data for the kinetic rate. :type file: :class:`ihm.location.OutputFileLocation` """ def __init__(self, transition_rate_constant=None, equilibrium_constant=None, details=None, dataset_group=None, file=None): self.transition_rate_constant = transition_rate_constant self.equilibrium_constant = equilibrium_constant self.details = details self.dataset_group = dataset_group self.external_file = file def __eq__(self, other): return self.__dict__ == other.__dict__
[docs] class EquilibriumConstant(object): """Base class for an equilibrium constant. This class handles the case that none of the derived classes is applicable. :param float value: The value of the equilibrium constant :param str unit: Unit of the equilibrium constant. Depending on what the process describes, a unit might be applicable or not""" def __init__(self, value, unit=None): self.method = 'equilibrium constant is determined from another ' \ 'method not listed' self.value = value self.unit = unit def __eq__(self, other): if other is None: return False return self.__dict__ == other.__dict__
[docs] class PopulationEquilibriumConstant(EquilibriumConstant): """An equilibrium constant determined from population""" def __init__(self, value, unit=None): super(PopulationEquilibriumConstant, self).__init__(value, unit) self.method = 'equilibrium constant is determined from population'
[docs] class KineticRateEquilibriumConstant(EquilibriumConstant): """An equilibrium constant determined from kinetic rates as kAB/kBA""" def __init__(self, value, unit=None): super(KineticRateEquilibriumConstant, self).__init__(value, unit) self.method = 'equilibrium constant is determined from kinetic ' \ 'rates, kAB/kBA'
[docs] class RelaxationTime(object): """A relaxation time determined for a scheme. The relaxation time can either be connected to a specific connectivity in the scheme or to the scheme in general if no assignment is possible. :param float value: The relaxation time. :param str unit: The unit of the relaxation time. Options are ['seconds','milliseconds', microseconds'] :param float amplitude: The amplitude of the relaxation time if determined. :param str details: Details on the relaxation time. :param dataset_group: DatasetGroup used to determine the relaxation time. :type dataset_group: :class:`ihm.dataset.DatasetGroup` :param file: An external file containing measurement data for the relaxation time. :type file: :class:`ihm.location.OutputFileLocation` """ def __init__(self, value, unit, amplitude=None, details=None, dataset_group=None, file=None): self.value = value self.unit = unit self.amplitude = amplitude self.details = details self.dataset_group = dataset_group self.external_file = file def __eq__(self, other): return self.__dict__ == other.__dict__ # Check whether the given unit is within the allowed options allowed_relaxation_time_units = ['seconds', 'milliseconds', 'microseconds'] unit = _text_choice_property( "unit", allowed_relaxation_time_units, doc="The unit of the relaxation time.")