Ejemplo n.º 1
0
def get_averaged_bias_matrix(bias_sequences, dtrajs, nstates=None):
    from thermotools.util import logsumexp as _logsumexp
    from thermotools.util import logsumexp_pair as _logsumexp_pair
    from thermotools.util import kahan_summation as _kahan_summation
    nmax = int(_np.max([dtraj.max() for dtraj in dtrajs]))
    if nstates is None:
        nstates = nmax + 1
    elif nstates < nmax + 1:
        raise ValueError(
            "nstates is smaller than the number of observed microstates")
    nthermo = bias_sequences[0].shape[1]
    bias_matrix = -_np.ones(shape=(nthermo, nstates),
                            dtype=_np.float64) * _np.inf
    counts = _np.zeros(shape=(nstates, ), dtype=_np.intc)
    for s in range(len(bias_sequences)):
        for i in range(nstates):
            idx = (dtrajs[s] == i)
            nidx = idx.sum()
            if nidx == 0:
                continue
            counts[i] += nidx
            selected_bias_sequence = bias_sequences[s][idx, :]
            for k in range(nthermo):
                bias_matrix[k, i] = _logsumexp_pair(
                    bias_matrix[k, i],
                    _logsumexp(
                        _np.ascontiguousarray(-selected_bias_sequence[:, k]),
                        inplace=False))
    return _np.log(counts)[_np.newaxis, :] - bias_matrix
Ejemplo n.º 2
0
    def set_model_params(self, pi=None, f=None, normalize_f=None, label=None):
        r"""Call to set all basic model parameters.

        Parameters
        ----------
        pi : ndarray(n)
            Stationary distribution. If not already normalized, pi will be
            scaled to fulfill :math:`\sum_i \pi_i = 1`. The free energies f
            will then be computed from pi via :math:`f_i = - \log(\pi_i)`.
        f : ndarray(n)
            Discrete-state free energies. If normalized_f = True, a constant
            will be added to normalize the stationary distribution. Otherwise
            f is left as given. Then, pi will be computed from f via :math:`\pi_i = \exp(-f_i)`
            and, if necessary, scaled to fulfill :math:`\sum_i \pi_i = 1`. If
            both (pi and f) are given, f takes precedence over pi.
        normalize_energy : bool, default=True
            If parametrized by free energy f, normalize them such that
            :math:`\sum_i \pi_i = 1`, which is achieved by :math:`\log \sum_i \exp(-f_i) = 0`.
        label : str, default=None
            Human-readable description for the thermodynamic state of this
            model. May contain a temperature description, such as '300 K' or
            a description of bias energy such as 'unbiased' or 'Umbrella 1'.
        """
        if f is not None:
            _types.assert_array(f, ndim=1, kind='numeric')
            f = _np.array(f, dtype=float)
            if normalize_f:
                f += _logsumexp(
                    -f
                )  # normalize on the level on energies to achieve sum_i pi_i = 1
            pi = _np.exp(-f)
        elif pi is not None:  # if f is not given, use pi. pi can't be None at this point
            _types.assert_array(pi, ndim=1, kind='numeric')
            pi = _np.array(pi, dtype=float)
            f = -_np.log(pi)
            f += _logsumexp(-f)  # always shift f when set by pi
        else:
            raise ValueError(
                "Trying to initialize model without parameters: both pi (stationary distribution)" \
                " and f (free energy) are None. At least one of them needs to be set.")
        # set parameters (None does not overwrite)
        self.update_model_params(pi=pi,
                                 f=f,
                                 normalize_energy=normalize_f,
                                 label=label)
Ejemplo n.º 3
0
def get_averaged_bias_matrix(bias_sequences, dtrajs, nstates=None):
    r"""
    Computes a bias matrix via an exponential average of the observed frame wise bias energies.

    Parameters
    ----------
    bias_sequences : list of numpy.ndarray(T_i, num_therm_states)
        A single reduced bias energy trajectory or a list of reduced bias energy trajectories.
        For every simulation frame seen in trajectory i and time step t, btrajs[i][t, k] is the
        reduced bias energy of that frame evaluated in the k'th thermodynamic state (i.e. at
        the k'th Umbrella/Hamiltonian/temperature)
    dtrajs : list of numpy.ndarray(T_i) of int
        A single discrete trajectory or a list of discrete trajectories. The integers are indexes
        in 0,...,num_conf_states-1 enumerating the num_conf_states Markov states or the bins the
        trajectory is in at any time.
    nstates : int, optional, default=None
        Number of configuration states.

    Returns
    -------
    bias_matrix : numpy.ndarray(shape=(num_therm_states, num_conf_states)) object
        bias_energies_full[j, i] is the bias energy in units of kT for each discrete state i
        at thermodynamic state j.
    """
    from thermotools.util import logsumexp as _logsumexp
    from thermotools.util import logsumexp_pair as _logsumexp_pair
    nmax = int(_np.max([dtraj.max() for dtraj in dtrajs]))
    if nstates is None:
        nstates = nmax + 1
    elif nstates < nmax + 1:
        raise ValueError(
            "nstates is smaller than the number of observed microstates")
    nthermo = bias_sequences[0].shape[1]
    bias_matrix = -_np.ones(shape=(nthermo, nstates),
                            dtype=_np.float64) * _np.inf
    counts = _np.zeros(shape=(nstates, ), dtype=_np.intc)
    for s in range(len(bias_sequences)):
        for i in range(nstates):
            idx = (dtrajs[s] == i)
            nidx = idx.sum()
            if nidx == 0:
                continue
            counts[i] += nidx
            selected_bias_sequence = bias_sequences[s][idx, :]
            for k in range(nthermo):
                bias_matrix[k, i] = _logsumexp_pair(
                    bias_matrix[k, i],
                    _logsumexp(
                        _np.ascontiguousarray(-selected_bias_sequence[:, k]),
                        inplace=False))
    idx = counts.nonzero()
    log_counts = _np.log(counts[idx])
    bias_matrix *= -1.0
    bias_matrix[:, idx] += log_counts[_np.newaxis, :]
    return bias_matrix
Ejemplo n.º 4
0
 def set_model_params(self, pi=None, f=None, normalize_f=True):
     r"""
     Parameters
     ----------
     pi : ndarray(n)
         Stationary distribution. If not already normalized, pi will be
         scaled to fulfill :math:`\sum_i \pi_i = 1`. The free energies f
         will be computed from pi via :math:`f_i = - \log(\pi_i)`. Only
         if normalize_f is True, a constant will be added to ensure
         consistency with :math:`\sum_i \pi_i = 1`.
     f : ndarray(n)
         Discrete-state free energies. If normalized_f = True, a constant
         will be added to normalize the stationary distribution. Otherwise
         f is left as given.
     normalize_f : bool, default=True
         If parametrized by free energy f, normalize them such that
         :math:`\sum_i \pi_i = 1`, which is achieved by :math:`\log \sum_i \exp(-f_i) = 0`.
     label : str, default='ground state'
         Human-readable description for the thermodynamic state of this
         model. May contain a temperature description, such as '300 K' or
         a description of bias energy such as 'unbiased' or 'Umbrella 1'
     """
     # check input
     if pi is None and f is None:
         raise ValueError('Trying to initialize model without parameters:'
                          ' Both pi (stationary distribution)'
                          'and f (free energy) are None.'
                          'At least one of them needs to be set.')
     # use f with preference
     if f is not None:
         _types.assert_array(f, ndim=1, kind='numeric')
         f = _np.array(f, dtype=float)
         if normalize_f:
             f += _logsumexp(
                 -f
             )  # normalize on the level on energies to achieve sum_i pi_i = 1
         pi = _np.exp(-f)
     else:  # if f is not given, use pi. pi can't be None at this point
         _types.assert_array(pi, ndim=1, kind='numeric')
         pi = _np.array(pi, dtype=float)
         f = -_np.log(pi)
     pi /= pi.sum()  # always normalize pi
     # set parameters
     self.update_model_params(pi=pi, f=f, normalize_energy=normalize_f)
     # set derived quantities
     self._nstates = len(pi)