def _compute_eigendecomposition(self, neig): """ Conducts the eigenvalue decomposition and stores k eigenvalues, left and right eigenvectors """ from msmtools.analysis import rdl_decomposition if self.reversible: self._R, self._D, self._L = rdl_decomposition( self.transition_matrix, norm='reversible', k=neig, ncv=self.ncv) # everything must be real-valued self._R = self._R.real self._D = self._D.real self._L = self._L.real else: self._R, self._D, self._L = rdl_decomposition( self.transition_matrix, k=neig, norm='standard', ncv=self.ncv) # if the imaginary parts are zero, discard them. if _np.all(self._R.imag == 0): self._R = _np.real(self._R) if _np.all(self._D.imag == 0): self._D = _np.real(self._D) if _np.all(self._L.imag == 0): self._L = _np.real(self._L) self._eigenvalues = _np.diag(self._D)
def update(self, Tij, Pi=None): r""" Updates the transition matrix and recomputes all derived quantities """ # EMMA imports from msmtools import analysis as msmana # save a copy of the transition matrix self._Tij = np.array(Tij) assert msmana.is_transition_matrix( self._Tij), 'Given transition matrix is not a stochastic matrix' assert self._Tij.shape[ 0] == self._nstates, 'Given transition matrix has unexpected number of states ' # initial / stationary distribution if (Pi is not None): assert np.all( Pi >= 0 ), 'Given initial distribution contains negative elements.' Pi = np.array(Pi) / np.sum( Pi) # ensure normalization and make a copy if (self._stationary): pT = msmana.stationary_distribution(self._Tij) if Pi is None: # stationary and no stationary distribution fixed, so computing it from trans. mat. self._Pi = pT else: # stationary but stationary distribution is fixed, so the transition matrix must be consistent assert np.allclose(Pi, pT), 'Stationary HMM requested, but given distribution is not the ' \ 'stationary distribution of the given transition matrix.' self._Pi = Pi else: if Pi is None: # no initial distribution given, so use stationary distribution anyway self._Pi = msmana.stationary_distribution(self._Tij) else: self._Pi = Pi # reversible if self._reversible: assert msmana.is_reversible( Tij ), 'Reversible HMM requested, but given transition matrix is not reversible.' # try to do eigendecomposition by default, because it's very cheap for hidden transition matrices from scipy.linalg import LinAlgError try: if self._reversible: self._R, self._D, self._L = msmana.rdl_decomposition( self._Tij, norm='reversible') # everything must be real-valued self._R = self._R.real self._D = self._D.real self._L = self._L.real else: self._R, self._D, self._L = msmana.rdl_decomposition( self._Tij, norm='standard') self._eigenvalues = np.diag(self._D) self._spectral_decomp_available = True except LinAlgError: logger().warn('Eigendecomposition failed for transition matrix\n' + str(self._Tij) + '\nspectral properties will not be available') self._spectral_decomp_available = False
def test_rdl_decomposition(self): P = self.bdc.transition_matrix() mu = self.bdc.stationary_distribution() """Non-reversible""" """k=None""" Rn, Dn, Ln = rdl_decomposition(P) Xn = np.dot(Ln, Rn) """Right-eigenvectors""" assert_allclose(np.dot(P, Rn), np.dot(Rn, Dn)) """Left-eigenvectors""" assert_allclose(np.dot(Ln, P), np.dot(Dn, Ln)) """Orthonormality""" assert_allclose(Xn, np.eye(self.dim)) """Probability vector""" assert_allclose(np.sum(Ln[0, :]), 1.0) """k is not None""" Rn, Dn, Ln = rdl_decomposition(P, k=self.k) Xn = np.dot(Ln, Rn) """Right-eigenvectors""" assert_allclose(np.dot(P, Rn), np.dot(Rn, Dn)) """Left-eigenvectors""" assert_allclose(np.dot(Ln, P), np.dot(Dn, Ln)) """Orthonormality""" assert_allclose(Xn, np.eye(self.k)) """Probability vector""" assert_allclose(np.sum(Ln[0, :]), 1.0) """Reversible""" """k=None""" Rn, Dn, Ln = rdl_decomposition(P, norm='reversible') Xn = np.dot(Ln, Rn) """Right-eigenvectors""" assert_allclose(np.dot(P, Rn), np.dot(Rn, Dn)) """Left-eigenvectors""" assert_allclose(np.dot(Ln, P), np.dot(Dn, Ln)) """Orthonormality""" assert_allclose(Xn, np.eye(self.dim)) """Probability vector""" assert_allclose(np.sum(Ln[0, :]), 1.0) """Reversibility""" assert_allclose(Ln.transpose(), mu[:, np.newaxis] * Rn) """k is not None""" Rn, Dn, Ln = rdl_decomposition(P, norm='reversible', k=self.k) Xn = np.dot(Ln, Rn) """Right-eigenvectors""" assert_allclose(np.dot(P, Rn), np.dot(Rn, Dn)) """Left-eigenvectors""" assert_allclose(np.dot(Ln, P), np.dot(Dn, Ln)) """Orthonormality""" assert_allclose(Xn, np.eye(self.k)) """Probability vector""" assert_allclose(np.sum(Ln[0, :]), 1.0) """Reversibility""" assert_allclose(Ln.transpose(), mu[:, np.newaxis] * Rn)
def update(self, Tij, Pi=None): r""" Updates the transition matrix and recomputes all derived quantities """ # EMMA imports from msmtools import analysis as msmana # save a copy of the transition matrix self._Tij = np.array(Tij) assert msmana.is_transition_matrix(self._Tij), 'Given transition matrix is not a stochastic matrix' assert self._Tij.shape[0] == self._nstates, 'Given transition matrix has unexpected number of states ' # initial / stationary distribution if (Pi is not None): assert np.all(Pi >= 0), 'Given initial distribution contains negative elements.' Pi = np.array(Pi) / np.sum(Pi) # ensure normalization and make a copy if (self._stationary): pT = msmana.stationary_distribution(self._Tij) if Pi is None: # stationary and no stationary distribution fixed, so computing it from trans. mat. self._Pi = pT else: # stationary but stationary distribution is fixed, so the transition matrix must be consistent assert np.allclose(Pi, pT), 'Stationary HMM requested, but given distribution is not the ' \ 'stationary distribution of the given transition matrix.' self._Pi = Pi else: if Pi is None: # no initial distribution given, so use stationary distribution anyway self._Pi = msmana.stationary_distribution(self._Tij) else: self._Pi = Pi # reversible if self._reversible: assert msmana.is_reversible(Tij), 'Reversible HMM requested, but given transition matrix is not reversible.' # try to do eigendecomposition by default, because it's very cheap for hidden transition matrices from scipy.linalg import LinAlgError try: if self._reversible: self._R, self._D, self._L = msmana.rdl_decomposition(self._Tij, norm='reversible') # everything must be real-valued self._R = self._R.real self._D = self._D.real self._L = self._L.real else: self._R, self._D, self._L = msmana.rdl_decomposition(self._Tij, norm='standard') self._eigenvalues = np.diag(self._D) self._spectral_decomp_available = True except LinAlgError: logger().warn('Eigendecomposition failed for transition matrix\n'+str(self._Tij)+ '\nspectral properties will not be available') self._spectral_decomp_available = False
def _compute_eigendecomposition(self, neig): """ Conducts the eigenvalue decomposition and stores k eigenvalues, left and right eigenvectors """ from msmtools.analysis import rdl_decomposition if self.reversible: self._R, self._D, self._L = rdl_decomposition(self.transition_matrix, norm='reversible', k=neig, ncv=self.ncv) # everything must be real-valued self._R = self._R.real self._D = self._D.real self._L = self._L.real else: self._R, self._D, self._L = rdl_decomposition(self.transition_matrix, k=neig, norm='standard', ncv=self.ncv) self._eigenvalues = np.diag(self._D)
def setUp(self): self.k = 4 p = np.zeros(10) q = np.zeros(10) p[0:-1] = 0.5 q[1:] = 0.5 p[4] = 0.01 q[6] = 0.1 self.bdc = BirthDeathChain(q, p) self.mu = self.bdc.stationary_distribution() self.T = self.bdc.transition_matrix_sparse() """Test matrix-vector product against spectral decomposition""" R, D, L = rdl_decomposition(self.T, k=self.k) self.L = L self.R = R self.ts = timescales(self.T, k=self.k) self.times = np.array([1, 5, 10, 20, 100]) ev = np.diagonal(D) self.ev_t = ev[np.newaxis, :]**self.times[:, np.newaxis] """Observable""" obs1 = np.zeros(10) obs1[0] = 1 obs1[1] = 1 self.obs = obs1 """Initial distribution""" w0 = np.zeros(10) w0[0:4] = 0.25 self.p0 = w0
def setUp(self): self.k = 4 p = np.zeros(10) q = np.zeros(10) p[0:-1] = 0.5 q[1:] = 0.5 p[4] = 0.01 q[6] = 0.1 self.bdc = BirthDeathChain(q, p) self.mu = self.bdc.stationary_distribution() self.T = self.bdc.transition_matrix_sparse() R, D, L = rdl_decomposition(self.T, k=self.k) self.L = L self.R = R self.ts = timescales(self.T, k=self.k) self.times = np.array([1, 5, 10, 20, 100]) ev = np.diagonal(D) self.ev_t = ev[np.newaxis, :]**self.times[:, np.newaxis] obs1 = np.zeros(10) obs1[0] = 1 obs1[1] = 1 obs2 = np.zeros(10) obs2[8] = 1 obs2[9] = 1 self.obs1 = obs1 self.obs2 = obs2 self.one_vec = np.ones(10)
def rdl_decomposition(P, reversible=True): # TODO: this treatment is probably not meaningful for weakly connected matrices. import msmtools.estimation as msmest import msmtools.analysis as msmana # output matrices n = np.shape(P)[0] if reversible: dtype = np.float64 norm = 'reversible' else: dtype = complex norm = 'standard' R = np.zeros((n, n), dtype=dtype) D = np.zeros((n, n), dtype=dtype) L = np.zeros((n, n), dtype=dtype) # treat each strongly connected set separately S = msmest.connected_sets(P) for s in S: indices = np.ix_(s, s) if len(s) > 1: right_eigvec, eigval_diag, left_eigvec = msmana.rdl_decomposition( P[s, :][:, s], norm=norm) # write to full R[indices] = right_eigvec D[indices] = eigval_diag L[indices] = left_eigvec else: # just one element. Write 1's R[indices] = 1 D[indices] = 1 L[indices] = 1 # done return R, D, L
def rdl_decomposition(P, reversible=True): # TODO: this treatment is probably not meaningful for weakly connected matrices. import msmtools.estimation as msmest import msmtools.analysis as msmana # output matrices n = np.shape(P)[0] if reversible: dtype = np.float64 else: dtype = complex R = np.zeros((n, n), dtype=dtype) D = np.zeros((n, n), dtype=dtype) L = np.zeros((n, n), dtype=dtype) # treat each strongly connected set separately S = msmest.connected_sets(P) for s in S: I = np.ix_(s, s) if len(s) > 1: if reversible: r, d, l = msmana.rdl_decomposition(P[s, :][:, s], norm='reversible') # everything must be real-valued - this should rather be handled by msmtools R[I] = r.real D[I] = d.real L[I] = l.real else: r, d, l = msmana.rdl_decomposition(P[s, :][:, s], norm='standard') # write to full R[I] = r D[I] = d L[I] = l else: # just one element. Write 1's R[I] = 1 D[I] = 1 L[I] = 1 # done return R, D, L
def setUp(self): self.k = 4 p = np.zeros(10) q = np.zeros(10) p[0:-1] = 0.5 q[1:] = 0.5 p[4] = 0.01 q[6] = 0.1 self.bdc = BirthDeathChain(q, p) self.mu = self.bdc.stationary_distribution() self.T = self.bdc.transition_matrix_sparse() R, D, L = rdl_decomposition(self.T, k=self.k) self.L = L self.R = R self.ts = timescales(self.T, k=self.k) self.times = np.array([1, 5, 10, 20]) ev = np.diagonal(D) self.ev_t = ev[np.newaxis, :] ** self.times[:, np.newaxis] self.tau = 7.5 """Observables""" obs1 = np.zeros(10) obs1[0] = 1 obs1[1] = 1 obs2 = np.zeros(10) obs2[8] = 1 obs2[9] = 1 self.obs1 = obs1 self.obs2 = obs2 """Initial vector for relaxation""" w0 = np.zeros(10) w0[0:4] = 0.25 self.p0 = w0
def test_rdl_decomposition_rev(self): P = self.bdc.transition_matrix_sparse() mu = self.bdc.stationary_distribution() """Non-reversible""" """k=None""" with self.assertRaises(ValueError): Rn, Dn, Ln = rdl_decomposition(P, reversible=True) """norm='standard'""" Rn, Dn, Ln = rdl_decomposition(P, k=self.k, reversible=True, norm='standard') Xn = np.dot(Ln, Rn) """Right-eigenvectors""" assert_allclose(P.dot(Rn), np.dot(Rn, Dn)) """Left-eigenvectors""" assert_allclose(P.transpose().dot(Ln.transpose()).transpose(), np.dot(Dn, Ln)) """Orthonormality""" assert_allclose(Xn, np.eye(self.k)) """Probability vector""" assert_allclose(np.sum(Ln[0, :]), 1.0) """Standard l2-normalization of right eigenvectors except dominant one""" Yn = np.dot(Rn.T, Rn) assert_allclose(np.diag(Yn)[1:], 1.0) """ncv is not None""" Rn, Dn, Ln = rdl_decomposition(P, k=self.k, reversible=True, norm='standard', ncv=self.ncv) Xn = np.dot(Ln, Rn) """Right-eigenvectors""" assert_allclose(P.dot(Rn), np.dot(Rn, Dn)) """Left-eigenvectors""" assert_allclose(P.transpose().dot(Ln.transpose()).transpose(), np.dot(Dn, Ln)) """Orthonormality""" assert_allclose(Xn, np.eye(self.k)) """Probability vector""" assert_allclose(np.sum(Ln[0, :]), 1.0) """Standard l2-normalization of right eigenvectors except dominant one""" Yn = np.dot(Rn.T, Rn) assert_allclose(np.diag(Yn)[1:], 1.0) """norm='reversible'""" Rn, Dn, Ln = rdl_decomposition(P, reversible=True, norm='reversible', k=self.k) Xn = np.dot(Ln, Rn) """Right-eigenvectors""" assert_allclose(P.dot(Rn), np.dot(Rn, Dn)) """Left-eigenvectors""" assert_allclose(P.transpose().dot(Ln.transpose()).transpose(), np.dot(Dn, Ln)) """Orthonormality""" assert_allclose(Xn, np.eye(self.k)) """Probability vector""" assert_allclose(np.sum(Ln[0, :]), 1.0) """Reversibility""" assert_allclose(Ln.transpose(), mu[:, np.newaxis] * Rn) Rn, Dn, Ln = rdl_decomposition(P, reversible=True, norm='reversible', k=self.k, ncv=self.ncv) Xn = np.dot(Ln, Rn) """Right-eigenvectors""" assert_allclose(P.dot(Rn), np.dot(Rn, Dn)) """Left-eigenvectors""" assert_allclose(P.transpose().dot(Ln.transpose()).transpose(), np.dot(Dn, Ln)) """Orthonormality""" assert_allclose(Xn, np.eye(self.k)) """Probability vector""" assert_allclose(np.sum(Ln[0, :]), 1.0) """Reversibility""" assert_allclose(Ln.transpose(), mu[:, np.newaxis] * Rn) """mu is not None""" """norm='standard'""" Rn, Dn, Ln = rdl_decomposition(P, k=self.k, reversible=True, norm='standard', mu=mu) Xn = np.dot(Ln, Rn) """Right-eigenvectors""" assert_allclose(P.dot(Rn), np.dot(Rn, Dn)) """Left-eigenvectors""" assert_allclose(P.transpose().dot(Ln.transpose()).transpose(), np.dot(Dn, Ln)) """Orthonormality""" assert_allclose(Xn, np.eye(self.k)) """Probability vector""" assert_allclose(np.sum(Ln[0, :]), 1.0) """Standard l2-normalization of right eigenvectors except dominant one""" Yn = np.dot(Rn.T, Rn) assert_allclose(np.diag(Yn)[1:], 1.0) """ncv is not None""" Rn, Dn, Ln = rdl_decomposition(P, k=self.k, reversible=True, norm='standard', ncv=self.ncv, mu=mu) Xn = np.dot(Ln, Rn) """Right-eigenvectors""" assert_allclose(P.dot(Rn), np.dot(Rn, Dn)) """Left-eigenvectors""" assert_allclose(P.transpose().dot(Ln.transpose()).transpose(), np.dot(Dn, Ln)) """Orthonormality""" assert_allclose(Xn, np.eye(self.k)) """Probability vector""" assert_allclose(np.sum(Ln[0, :]), 1.0) """Standard l2-normalization of right eigenvectors except dominant one""" Yn = np.dot(Rn.T, Rn) assert_allclose(np.diag(Yn)[1:], 1.0) """norm='reversible'""" Rn, Dn, Ln = rdl_decomposition(P, reversible=True, norm='reversible', k=self.k, mu=mu) Xn = np.dot(Ln, Rn) """Right-eigenvectors""" assert_allclose(P.dot(Rn), np.dot(Rn, Dn)) """Left-eigenvectors""" assert_allclose(P.transpose().dot(Ln.transpose()).transpose(), np.dot(Dn, Ln)) """Orthonormality""" assert_allclose(Xn, np.eye(self.k)) """Probability vector""" assert_allclose(np.sum(Ln[0, :]), 1.0) """Reversibility""" assert_allclose(Ln.transpose(), mu[:, np.newaxis] * Rn) Rn, Dn, Ln = rdl_decomposition(P, reversible=True, norm='reversible', k=self.k, ncv=self.ncv, mu=mu) Xn = np.dot(Ln, Rn) """Right-eigenvectors""" assert_allclose(P.dot(Rn), np.dot(Rn, Dn)) """Left-eigenvectors""" assert_allclose(P.transpose().dot(Ln.transpose()).transpose(), np.dot(Dn, Ln)) """Orthonormality""" assert_allclose(Xn, np.eye(self.k)) """Probability vector""" assert_allclose(np.sum(Ln[0, :]), 1.0) """Reversibility""" assert_allclose(Ln.transpose(), mu[:, np.newaxis] * Rn)
def test_rdl_decomposition(self): P = self.bdc.transition_matrix_sparse() mu = self.bdc.stationary_distribution() """Non-reversible""" """k=None""" with self.assertRaises(ValueError): Rn, Dn, Ln = rdl_decomposition(P) """k is not None""" Rn, Dn, Ln = rdl_decomposition(P, k=self.k) Xn = np.dot(Ln, Rn) """Right-eigenvectors""" assert_allclose(P.dot(Rn), np.dot(Rn, Dn)) """Left-eigenvectors""" assert_allclose(P.transpose().dot(Ln.transpose()).transpose(), np.dot(Dn, Ln)) """Orthonormality""" assert_allclose(Xn, np.eye(self.k)) """Probability vector""" assert_allclose(np.sum(Ln[0, :]), 1.0) """k is not None, ncv is not None""" Rn, Dn, Ln = rdl_decomposition(P, k=self.k, ncv=self.ncv) Xn = np.dot(Ln, Rn) """Right-eigenvectors""" assert_allclose(P.dot(Rn), np.dot(Rn, Dn)) """Left-eigenvectors""" assert_allclose(P.transpose().dot(Ln.transpose()).transpose(), np.dot(Dn, Ln)) """Orthonormality""" assert_allclose(Xn, np.eye(self.k)) """Probability vector""" assert_allclose(np.sum(Ln[0, :]), 1.0) """Reversible""" """k=None""" with self.assertRaises(ValueError): Rn, Dn, Ln = rdl_decomposition(P, norm='reversible') """k is not None""" Rn, Dn, Ln = rdl_decomposition(P, k=self.k, norm='reversible') Xn = np.dot(Ln, Rn) """Right-eigenvectors""" assert_allclose(P.dot(Rn), np.dot(Rn, Dn)) """Left-eigenvectors""" assert_allclose(P.transpose().dot(Ln.transpose()).transpose(), np.dot(Dn, Ln)) """Orthonormality""" assert_allclose(Xn, np.eye(self.k)) """Probability vector""" assert_allclose(np.sum(Ln[0, :]), 1.0) """Reversibility""" assert_allclose(Ln.transpose(), mu[:, np.newaxis] * Rn) """k is not None ncv is not None""" Rn, Dn, Ln = rdl_decomposition(P, k=self.k, norm='reversible', ncv=self.ncv) Xn = np.dot(Ln, Rn) """Right-eigenvectors""" assert_allclose(P.dot(Rn), np.dot(Rn, Dn)) """Left-eigenvectors""" assert_allclose(P.transpose().dot(Ln.transpose()).transpose(), np.dot(Dn, Ln)) """Orthonormality""" assert_allclose(Xn, np.eye(self.k)) """Probability vector""" assert_allclose(np.sum(Ln[0, :]), 1.0) """Reversibility""" assert_allclose(Ln.transpose(), mu[:, np.newaxis] * Rn)
def test_rdl_decomposition_rev(self): P = self.bdc.transition_matrix() mu = self.bdc.stationary_distribution() """norm='standard'""" """k=None""" Rn, Dn, Ln = rdl_decomposition(P, reversible=True, norm='standard') Xn = np.dot(Ln, Rn) """Right-eigenvectors""" assert_allclose(np.dot(P, Rn), np.dot(Rn, Dn)) """Left-eigenvectors""" assert_allclose(np.dot(Ln, P), np.dot(Dn, Ln)) """Orthonormality""" assert_allclose(Xn, np.eye(self.dim)) """Probability vector""" assert_allclose(np.sum(Ln[0, :]), 1.0) """Standard l2-normalization of right eigenvectors except dominant one""" Yn = np.dot(Rn.T, Rn) assert_allclose(np.diag(Yn)[1:], 1.0) """k is not None""" Rn, Dn, Ln = rdl_decomposition(P, k=self.k, reversible=True, norm='standard') Xn = np.dot(Ln, Rn) """Right-eigenvectors""" assert_allclose(np.dot(P, Rn), np.dot(Rn, Dn)) """Left-eigenvectors""" assert_allclose(np.dot(Ln, P), np.dot(Dn, Ln)) """Orthonormality""" assert_allclose(Xn, np.eye(self.k)) """Probability vector""" assert_allclose(np.sum(Ln[0, :]), 1.0) """Standard l2-normalization of right eigenvectors except dominant one""" Yn = np.dot(Rn.T, Rn) assert_allclose(np.diag(Yn)[1:], 1.0) """norm='reversible'""" """k=None""" Rn, Dn, Ln = rdl_decomposition(P, reversible=True, norm='reversible') Xn = np.dot(Ln, Rn) """Right-eigenvectors""" assert_allclose(np.dot(P, Rn), np.dot(Rn, Dn)) """Left-eigenvectors""" assert_allclose(np.dot(Ln, P), np.dot(Dn, Ln)) """Orthonormality""" assert_allclose(Xn, np.eye(self.dim)) """Probability vector""" assert_allclose(np.sum(Ln[0, :]), 1.0) """Reversibility""" assert_allclose(Ln.transpose(), mu[:, np.newaxis] * Rn) """k is not None""" Rn, Dn, Ln = rdl_decomposition(P, reversible=True, norm='reversible', k=self.k) Xn = np.dot(Ln, Rn) """Right-eigenvectors""" assert_allclose(np.dot(P, Rn), np.dot(Rn, Dn)) """Left-eigenvectors""" assert_allclose(np.dot(Ln, P), np.dot(Dn, Ln)) """Orthonormality""" assert_allclose(Xn, np.eye(self.k)) """Probability vector""" assert_allclose(np.sum(Ln[0, :]), 1.0) """Reversibility""" assert_allclose(Ln.transpose(), mu[:, np.newaxis] * Rn)
def main(nEigenvectors, nRuns, m, outputFolder, plotEigenvectors, plotGMRQ, plotPMF, clusters, lagtimes, native, save_plots, showPlots, filtered, destFolder, resname, plotTransitions=True): minPos = get_min_Pos(native, resname) if save_plots and outputFolder is None: outputFolder = "plots_MSM" eigenPlots = os.path.join(outputFolder, "eigenvector_plots") GMRQPlots = os.path.join(outputFolder, "GMRQ_plots") PMFPlots = os.path.join(outputFolder, "PMF_plots") TransitionPlots = os.path.join(outputFolder, "transitions") if save_plots and not os.path.exists(outputFolder): os.makedirs(outputFolder) if filtered is not None: filter_str = "_filtered" else: filter_str = "" if plotEigenvectors and save_plots and not os.path.exists(eigenPlots): os.makedirs(eigenPlots) if plotGMRQ and save_plots and not os.path.exists(GMRQPlots): os.makedirs(GMRQPlots) if plotPMF and save_plots and not os.path.exists(PMFPlots): os.makedirs(PMFPlots) if plotTransitions and save_plots and not os.path.exists(TransitionPlots): os.makedirs(TransitionPlots) minPos = np.array(minPos) GMRQValues = {} print("Running from " + destFolder) if plotGMRQ: GMRQValues = [] if not os.path.exists(os.path.join(destFolder, "eigenvectors")): os.makedirs(os.path.join(destFolder, "eigenvectors")) for i in range(nRuns): titleVar = "%s, run %d" % (destFolder, i) if plotGMRQ or plotEigenvectors: msm_object = utilities.readClusteringObject( os.path.join(destFolder, "MSM_object_%d.pkl" % i)) if plotGMRQ: GMRQValues.append(np.sum(msm_object.eigenvalues()[:m])) if plotEigenvectors or plotPMF: clusters = np.loadtxt( os.path.join(destFolder, "clusterCenters_%d.dat" % i)) distance = np.linalg.norm(clusters - minPos, axis=1) volume = np.loadtxt( os.path.join(destFolder, "volumeOfClusters_%d.dat" % i)) print("Total volume for system %s , run %d" % (destFolder, i), volume.sum()) if filtered is not None: volume = volume[filtered] clusters = clusters[filtered] distance = distance[filtered] if plotEigenvectors: if clusters.size != msm_object.stationary_distribution.size: mat = computeDeltaG.reestimate_transition_matrix( msm_object.count_matrix_full) else: mat = msm_object.transition_matrix _, _, L = rdl_decomposition(mat) figures = [] axes = [] for _ in range((nEigenvectors - 1) // 4 + 1): f, axarr = plt.subplots(2, 2, figsize=(12, 12)) f.suptitle(titleVar) figures.append(f) axes.append(axarr) for j, row in enumerate(L[:nEigenvectors]): pdb_filename = os.path.join(destFolder, "eigenvectors", "eigen_%d_run_%d.pdb" % (j + 1, i)) if j: atomnames = utilities.getAtomNames( utilities.sign(row, tol=1e-3)) utilities.write_PDB_clusters(clusters, use_beta=False, elements=atomnames, title=pdb_filename) else: utilities.write_PDB_clusters(np.vstack( (clusters.T, row)).T, use_beta=True, elements=None, title=pdb_filename) if filtered is not None: row = row[filtered] np.savetxt( os.path.join( destFolder, "eigenvectors", "eigen_%d_run_%d%s.dat" % (j + 1, i, filter_str)), row) axes[j // 4][(j // 2) % 2, j % 2].scatter(distance, row) axes[j // 4][(j // 2) % 2, j % 2].set_xlabel("Distance to minimum") axes[j // 4][(j // 2) % 2, j % 2].set_ylabel("Eigenvector %d" % (j + 1)) if save_plots: for j, fg in enumerate(figures): fg.savefig( os.path.join( eigenPlots, "eigenvector_%d_run_%d%s.png" % (j + 1, i, filter_str))) plt.figure() plt.scatter(distance, L[0]) plt.xlabel("Distance to minimum") plt.ylabel("Eigenvector 1") plt.savefig( os.path.join( eigenPlots, "eigenvector_1_alone_run_%d%s.png" % (i, filter_str))) if plotPMF: data = np.loadtxt(os.path.join(destFolder, "pmf_xyzg_%d.dat" % i)) g = data[:, -1] if filtered is not None: g = g[filtered] print("Clusters with less than 2 PMF:") print(" ".join(map(str, np.where(g < 2)[0]))) print("") plt.figure() plt.title("%s" % (destFolder)) plt.scatter(distance, g) plt.xlabel("Distance to minima") plt.ylabel("PMF") if save_plots: plt.savefig( os.path.join(PMFPlots, "pmf_run_%d%s.png" % (i, filter_str))) if plotGMRQ: for t in GMRQValues: plt.figure() plt.title("%s" % (destFolder)) plt.xlabel("Number of states") plt.ylabel("GMRQ") plt.boxplot(GMRQValues) if save_plots: plt.savefig(os.path.join(GMRQPlots, "GMRQ.png" % t)) if plotTransitions: sasas = [] for file in glob.glob("*/repor*"): sasas.extend( pd.read_csv(file, sep=' ', engine='python')["sasaLig"].values) sasas = np.array(sasas) plt.figure() plt.title("%s" % (destFolder)) plt.xlabel("SASA") plt.ylabel("Transition Counts") plt.hist(sasas, 50, alpha=0.75) if save_plots: plt.savefig(os.path.join(TransitionPlots, "transition_hist.png")) if showPlots and (plotEigenvectors or plotGMRQ or plotPMF): plt.show()
def main(nEigenvectors, nRuns, m, outputFolder, plotEigenvectors, plotGMRQ, plotPMF, clusters, lagtimes, minPos, save_plots, showPlots, filtered, destFolder, sasa_col, path_to_report): if save_plots and outputFolder is None: outputFolder = "plots_MSM" if outputFolder is not None: eigenPlots = os.path.join(outputFolder, "eigenvector_plots") GMRQPlots = os.path.join(outputFolder, "GMRQ_plots") PMFPlots = os.path.join(outputFolder, "PMF_plots") if save_plots and not os.path.exists(outputFolder): os.makedirs(outputFolder) if filtered is not None: filter_str = "_filtered" else: filter_str = "" if plotEigenvectors and save_plots and not os.path.exists(eigenPlots): os.makedirs(eigenPlots) if plotGMRQ and save_plots and not os.path.exists(GMRQPlots): os.makedirs(GMRQPlots) if plotPMF and save_plots and not os.path.exists(PMFPlots): os.makedirs(PMFPlots) minPos = np.array(minPos) GMRQValues = {} print("Running from", destFolder) if plotGMRQ: GMRQValues = [] if not os.path.exists(os.path.join(destFolder, "eigenvectors")): os.makedirs(os.path.join(destFolder, "eigenvectors")) for i in range(nRuns): if sasa_col is not None: representatives_files = os.path.join( destFolder, "representative_structures/representative_structures_%d.dat" % i) sasa = getSASAvalues(representatives_files, sasa_col, path_to_report) titleVar = "%s, run %d" % (destFolder, i) if plotGMRQ or plotEigenvectors: msm_object = utilities.readClusteringObject( os.path.join(destFolder, "MSM_object_%d.pkl" % i)) if plotGMRQ: GMRQValues.append(np.sum(msm_object.eigenvalues()[:m])) if plotEigenvectors or plotPMF: clusters = np.loadtxt( os.path.join(destFolder, "clusterCenters_%d.dat" % i)) distance = np.linalg.norm(clusters - minPos, axis=1) volume = np.loadtxt( os.path.join(destFolder, "volumeOfClusters_%d.dat" % i)) print("Total volume for system %s , run %d" % (destFolder, i), volume.sum()) if filtered is not None: volume = volume[filtered] clusters = clusters[filtered] distance = distance[filtered] if sasa_col is not None: sasa = sasa[filtered] if plotEigenvectors: if clusters.size != msm_object.stationary_distribution.size: mat = computeDeltaG.reestimate_transition_matrix( msm_object.count_matrix_full) else: mat = msm_object.transition_matrix _, _, L = rdl_decomposition(mat) figures = [] axes = [] for _ in range((nEigenvectors - 1) // 4 + 1): f, axarr = plt.subplots(2, 2, figsize=(12, 12)) f.suptitle(titleVar) figures.append(f) axes.append(axarr) for j, row in enumerate(L[:nEigenvectors]): pdb_filename = os.path.join(destFolder, "eigenvectors", "eigen_%d_run_%d.pdb" % (j + 1, i)) if j: atomnames = utilities.getAtomNames( utilities.sign(row, tol=1e-3)) utilities.write_PDB_clusters(clusters, use_beta=False, elements=atomnames, title=pdb_filename) else: utilities.write_PDB_clusters(np.vstack( (clusters.T, row)).T, use_beta=True, elements=None, title=pdb_filename) if filtered is not None: row = row[filtered] np.savetxt( os.path.join( destFolder, "eigenvectors", "eigen_%d_run_%d%s.dat" % (j + 1, i, filter_str)), row) axes[j // 4][(j // 2) % 2, j % 2].scatter(distance, row) axes[j // 4][(j // 2) % 2, j % 2].set_xlabel("Distance to minimum") axes[j // 4][(j // 2) % 2, j % 2].set_ylabel("Eigenvector %d" % (j + 1)) Q = msm_object.count_matrix_full.diagonal( ) / msm_object.count_matrix_full.sum() plt.figure() plt.scatter(distance, Q) plt.xlabel("Distance to minimum") plt.ylabel("Metastability") if save_plots: plt.savefig( os.path.join(eigenPlots, "Q_run_%d%s.png" % (i, filter_str))) if save_plots: for j, fg in enumerate(figures): fg.savefig( os.path.join( eigenPlots, "eigenvector_%d_run_%d%s.png" % (j + 1, i, filter_str))) plt.figure() plt.scatter(distance, L[0]) plt.xlabel("Distance to minimum") plt.ylabel("Eigenvector 1") plt.savefig( os.path.join( eigenPlots, "eigenvector_1_alone_run_%d%s.png" % (i, filter_str))) if plotPMF: data = np.loadtxt(os.path.join(destFolder, "pmf_xyzg_%d.dat" % i)) g = data[:, -1] annotations = ["Cluster %d" % i for i in range(g.size)] if filtered is not None: g = g[filtered] annotations = np.array(annotations)[filtered].tolist() print("Clusters with less than 2 PMF:") print(" ".join(map(str, np.where(g < 2)[0]))) print("") fig_pmf, axarr = plt.subplots(2, 2, figsize=(12, 12)) fig_pmf.suptitle(titleVar) sc1 = axarr[1, 0].scatter(distance, g) sc2 = axarr[0, 1].scatter(distance, volume) sc3 = axarr[0, 0].scatter(g, volume) axes = [axarr[0, 1], axarr[1, 0], axarr[0, 0]] scs = [sc2, sc1, sc3] if sasa_col is not None: axarr[1, 1].scatter(sasa, g) axarr[1, 0].set_xlabel("Distance to minima") axarr[1, 0].set_ylabel("PMF") axarr[0, 1].set_xlabel("Distance to minima") axarr[0, 1].set_ylabel("Volume") axarr[0, 0].set_xlabel("PMF") axarr[0, 0].set_ylabel("Volume") annot1 = axarr[1, 0].annotate("", xy=(0, 0), xytext=(20, 20), textcoords="offset points", bbox=dict(boxstyle="round", fc="w"), arrowprops=dict(arrowstyle="->")) annot1.set_visible(False) annot2 = axarr[0, 1].annotate("", xy=(0, 0), xytext=(20, 20), textcoords="offset points", bbox=dict(boxstyle="round", fc="w"), arrowprops=dict(arrowstyle="->")) annot2.set_visible(False) annot3 = axarr[0, 0].annotate("", xy=(0, 0), xytext=(20, 20), textcoords="offset points", bbox=dict(boxstyle="round", fc="w"), arrowprops=dict(arrowstyle="->")) annot3.set_visible(False) annot_list = [annot2, annot1, annot3] if sasa_col is not None: axarr[1, 1].set_xlabel("SASA") axarr[1, 1].set_ylabel("PMF") if save_plots: fig_pmf.savefig( os.path.join(PMFPlots, "pmf_run_%d%s.png" % (i, filter_str))) if plotGMRQ: for t in GMRQValues: plt.figure() plt.title("%s" % (destFolder)) plt.xlabel("Number of states") plt.ylabel("GMRQ") plt.boxplot(GMRQValues) if save_plots: plt.savefig(os.path.join(GMRQPlots, "GMRQ.png" % t)) if showPlots and (plotEigenvectors or plotGMRQ or plotPMF): if plotPMFs: def update_annot(ind, sc, annot): """Update the information box of the selected point""" pos = sc.get_offsets()[ind["ind"][0]] annot.xy = pos annot.set_text(annotations[int(ind["ind"][0])]) # annot.get_bbox_patch().set_facecolor(cmap(norm( z_values[ind["ind"][0]]))) def hover(event): """Action to perform when hovering the mouse on a point""" # vis = any([annot.get_visible() for annot in annot_list]) for i, ax_comp in enumerate(axes): vis = annot_list[i].get_visible() if event.inaxes == ax_comp: for j in range(len(axes)): if j != i: annot_list[j].set_visible(False) cont, ind = scs[i].contains(event) if cont: update_annot(ind, scs[i], annot_list[i]) annot_list[i].set_visible(True) fig_pmf.canvas.draw_idle() else: if vis: annot_list[i].set_visible(False) fig_pmf.canvas.draw_idle() fig_pmf.canvas.mpl_connect("motion_notify_event", hover) plt.show()