def coarse_grain(self, user_sets): r"""Coarse-grains the flux onto user-defined sets. Parameters ---------- user_sets : list of int-iterables sets of states that shall be distinguished in the coarse-grained flux. Returns ------- (sets, tpt) : (list of int-iterables, tpt-object) sets contains the sets tpt is computed on. The tpt states of the new tpt object correspond to these sets of states in this order. Sets might be identical, if the user has already provided a complete partition that respects the boundary between A, B and the intermediates. If not, Sets will have more members than provided by the user, containing the "remainder" states and reflecting the splitting at the A and B boundaries. tpt contains a new tpt object for the coarse-grained flux. All its quantities (gross_flux, net_flux, A, B, committor, backward_committor) are coarse-grained to sets. Notes ----- All user-specified sets will be split (if necessary) to preserve the boundary between A, B and the intermediate states. """ # coarse-grain sets (tpt_sets, Aindexes, Bindexes) = self._compute_coarse_sets(user_sets) nnew = len(tpt_sets) # coarse-grain fluxHere we should branch between sparse and dense implementations, but currently there is only a F_coarse = tptapi.coarsegrain(self._gross_flux, tpt_sets) Fnet_coarse = tptapi.to_netflux(F_coarse) # coarse-grain stationary probability and committors - this can be done all dense pstat_coarse = np.zeros(nnew) forward_committor_coarse = np.zeros(nnew) backward_committor_coarse = np.zeros(nnew) for i in range(0, nnew): I = list(tpt_sets[i]) muI = self._mu[I] pstat_coarse[i] = np.sum(muI) partialI = muI / pstat_coarse[ i] # normalized stationary probability over I forward_committor_coarse[i] = np.dot(partialI, self._qplus[I]) backward_committor_coarse[i] = np.dot(partialI, self._qminus[I]) res = ReactiveFlux(Aindexes, Bindexes, Fnet_coarse, mu=pstat_coarse, qminus=backward_committor_coarse, qplus=forward_committor_coarse, gross_flux=F_coarse, dt_model=self.dt_model) return tpt_sets, res
def test_with_almost_converged_stat_dist(self): """ test for #106 """ from msmtools.analysis import committor, is_reversible from msmtools.flux import tpt, flux_matrix, to_netflux, ReactiveFlux T = np.array([[ 0.2576419223095193, 0.2254214623509954, 0.248270708174756, 0.2686659071647294 ], [ 0.2233847186210225, 0.2130434781715344, 0.2793477268264001, 0.284224076381043 ], [ 0.2118717275169231, 0.2405661227681972, 0.2943396213976011, 0.2532225283172787 ], [ 0.2328617711043517, 0.2485926610067547, 0.2571819311236834, 0.2613636367652102 ]]) mu = np.array([ 0.2306979668517676, 0.2328013892993006, 0.2703312416016573, 0.2661694022472743 ]) assert is_reversible(T) np.testing.assert_allclose(mu.dot(T), mu) np.testing.assert_equal(mu.dot(T), T.T.dot(mu)) A = [0] B = [1] # forward committor qplus = committor(T, A, B, forward=True, mu=mu) # backward committor if is_reversible(T, mu=mu): qminus = 1.0 - qplus else: qminus = committor(T, A, B, forward=False, mu=mu) tpt_obj = tpt(T, A, B) tpt_obj.major_flux(1.0) # gross flux grossflux = flux_matrix(T, mu, qminus, qplus, netflux=False) # net flux netflux = to_netflux(grossflux) F = ReactiveFlux(A, B, netflux, mu=mu, qminus=qminus, qplus=qplus, gross_flux=grossflux) F.pathways(1.0)