def setup(self): cv = paths.CoordinateFunctionCV('x', lambda x: x.xyz[0][0]) vol_A = paths.CVDefinedVolume(cv, float("-inf"), 0.0) vol_B = paths.CVDefinedVolume(cv, 1.0, float("inf")) ensembles = [ paths.LengthEnsemble(1).named("len1"), paths.LengthEnsemble(3).named("len3"), paths.SequentialEnsemble([ paths.LengthEnsemble(1) & paths.AllInXEnsemble(vol_A), paths.AllOutXEnsemble(vol_A | vol_B), paths.LengthEnsemble(1) & paths.AllInXEnsemble(vol_A) ]).named('return'), paths.SequentialEnsemble([ paths.LengthEnsemble(1) & paths.AllInXEnsemble(vol_A), paths.AllOutXEnsemble(vol_A | vol_B), paths.LengthEnsemble(1) & paths.AllInXEnsemble(vol_B) ]).named('transition'), ] self.ensembles = {ens.name: ens for ens in ensembles} self.traj_vals = [-0.1, 1.1, 0.5, -0.2, 0.1, -0.3, 0.4, 1.4, -1.0] self.trajectory = make_1d_traj(self.traj_vals) self.engine = CalvinistDynamics(self.traj_vals) self.satisfied_when_traj_len = { "len1": 1, "len3": 3, "return": 6, "transition": 8, } self.conditions = EnsembleSatisfiedContinueConditions(ensembles)
def __init__(self, storage, engine=None, states=None, randomizer=None, initial_snapshots=None, direction=None): all_state_volume = paths.join_volumes(states) no_state_volume = ~all_state_volume # shoot forward until we hit a state forward_ensemble = paths.SequentialEnsemble([ paths.AllOutXEnsemble(all_state_volume), paths.AllInXEnsemble(all_state_volume) & paths.LengthEnsemble(1) ]) # or shoot backward until we hit a state backward_ensemble = paths.SequentialEnsemble([ paths.AllInXEnsemble(all_state_volume) & paths.LengthEnsemble(1), paths.AllOutXEnsemble(all_state_volume) ]) super(CommittorSimulation, self).__init__( storage=storage, engine=engine, starting_volume=no_state_volume, forward_ensemble=forward_ensemble, backward_ensemble=backward_ensemble, randomizer=randomizer, initial_snapshots=initial_snapshots ) self.states = states self.direction = direction # override the default self.mover given by the superclass if self.direction is None: self.mover = paths.RandomChoiceMover([self.forward_mover, self.backward_mover]) elif self.direction > 0: self.mover = self.forward_mover elif self.direction < 0: self.mover = self.backward_mover
def analyze_transition_duration(self, trajectory, stateA, stateB): """Analysis to obtain transition durations for given state. Parameters ---------- trajectory : :class:`.Trajectory` trajectory to analyze stateA : :class:`.Volume` initial state volume for the transition stateB : :class:`.Volume` final state volume for the transition Returns ------- :class:`.TrajectorySegmentContainer` transitions from `stateA` to `stateB` within `trajectory` """ # we define the transitions ensemble just in case the transition is, # e.g., fixed path length TPS. We want flexible path length ensemble transition_ensemble = paths.SequentialEnsemble([ paths.AllInXEnsemble(stateA) & paths.LengthEnsemble(1), paths.OptionalEnsemble( # optional to allow instantaneous hops paths.AllOutXEnsemble(stateA) & paths.AllOutXEnsemble(stateB) ), paths.AllInXEnsemble(stateB) & paths.LengthEnsemble(1) ]) segments = [seg[1:-1] for seg in transition_ensemble.split(trajectory)] return TrajectorySegmentContainer(segments, self.dt)
def get_lifetime_segments(trajectory, from_vol, to_vol, forbidden=None, padding=[0, -1]): """General script to get lifetimes. Lifetimes for a transition between volumes are used in several other calculations: obviously, the state lifetime, but also the flux through an interface. This is a generic function to calculate that. Parameters ---------- trajectory : :class:`.Trajectory` trajectory to analyze from_vol : :class:`.Volume` the volume for which this represents the lifetime: the trajectory segments returned are associated with the lifetime of `from_vol` to_vol : :class:`.Volume` the volume which indicates the end of the lifetime: a frame in this volume means the trajectory is no longer associated with `from_vol` forbidden : :class:`.Volume` if a frame is in `forbidden`, it cannot be part of the lifetime of `from_vol`. This isn't needed in 2-state lifetime calculations; however, it is useful to exclude other states from a flux calculation padding : list adjusts which frames are returned as list indices. That is, the returned segments are `full_segment[padding[0]:padding[1]]`. The `full_segment`s are the segments from (and including) each first frame in `from_vol` (after a visit to `to_vol`) until (and including) the first frame in `to_vol`. To get the full segment as output, use `padding=[None, None]`. The default is to remove the final frame (`padding=[0, -1]`) so that it doesn't include the frame in `to_vol`. Returns ------- list of :class:`.Trajectory` the frames from (and including) each first entry from `to_vol` into `from_vol` until (and including) the next entry into `to_vol`, with no frames in `forbidden`, and with frames removed from the ends according to `padding` """ if forbidden is None: forbidden = paths.EmptyVolume() ensemble_BAB = paths.SequentialEnsemble([ paths.LengthEnsemble(1) & paths.AllInXEnsemble(to_vol), paths.PartInXEnsemble(from_vol) & paths.AllOutXEnsemble(to_vol), paths.LengthEnsemble(1) & paths.AllInXEnsemble(to_vol) ]) & paths.AllOutXEnsemble(forbidden) ensemble_AB = paths.SequentialEnsemble([ paths.LengthEnsemble(1) & paths.AllInXEnsemble(from_vol), paths.OptionalEnsemble(paths.AllOutXEnsemble(to_vol)), paths.LengthEnsemble(1) & paths.AllInXEnsemble(to_vol) ]) BAB_split = ensemble_BAB.split(trajectory) AB_split = [ensemble_AB.split(part)[0] for part in BAB_split] return [subtraj[padding[0]:padding[1]] for subtraj in AB_split]
def __init__(self, storage, engine=None, states=None, randomizer=None, initial_snapshots=None, direction=None): super(CommittorSimulation, self).__init__(storage) self.engine = engine paths.EngineMover.default_engine = engine self.states = states self.randomizer = randomizer try: initial_snapshots = list(initial_snapshots) except TypeError: initial_snapshots = [initial_snapshots] self.initial_snapshots = initial_snapshots self.direction = direction all_state_volume = paths.join_volumes(states) # we should always start from a single frame not in any state self.starting_ensemble = (paths.AllOutXEnsemble(all_state_volume) & paths.LengthEnsemble(1)) # shoot forward until we hit a state self.forward_ensemble = paths.SequentialEnsemble([ paths.AllOutXEnsemble(all_state_volume), paths.AllInXEnsemble(all_state_volume) & paths.LengthEnsemble(1) ]) # or shoot backward until we hit a state self.backward_ensemble = paths.SequentialEnsemble([ paths.AllInXEnsemble(all_state_volume) & paths.LengthEnsemble(1), paths.AllOutXEnsemble(all_state_volume) ]) self.forward_mover = paths.ForwardExtendMover( ensemble=self.starting_ensemble, target_ensemble=self.forward_ensemble) self.backward_mover = paths.BackwardExtendMover( ensemble=self.starting_ensemble, target_ensemble=self.backward_ensemble) if self.direction is None: self.mover = paths.RandomChoiceMover( [self.forward_mover, self.backward_mover]) elif self.direction > 0: self.mover = self.forward_mover elif self.direction < 0: self.mover = self.backward_mover
def A2BEnsemble(volume_a, volume_b, trusted=True): # this is a little replacement for the same name that used to be in # EnsembleFactory. It was only used in tests. return paths.SequentialEnsemble([ paths.AllInXEnsemble(volume_a) & paths.LengthEnsemble(1), paths.AllOutXEnsemble(volume_a | volume_b), paths.AllInXEnsemble(volume_b) & paths.LengthEnsemble(1) ])
def __init__(self, transition, snapshot, storage=None, engine=None, extra_interfaces=None, forbidden_states=None): super(FullBootstrapping, self).__init__(storage, engine) if extra_interfaces is None: extra_interfaces = list() if forbidden_states is None: forbidden_states = list() interface0 = transition.interfaces[0] ensemble0 = transition.ensembles[0] state = transition.stateA self.state = state self.first_traj_ensemble = paths.SequentialEnsemble([ paths.OptionalEnsemble(paths.AllOutXEnsemble(state)), paths.AllInXEnsemble(state), paths.OptionalEnsemble( paths.AllOutXEnsemble(state) & paths.AllInXEnsemble(interface0) ), paths.OptionalEnsemble(paths.AllInXEnsemble(interface0)), paths.AllOutXEnsemble(interface0), paths.OptionalEnsemble(paths.AllOutXEnsemble(state)), paths.SingleFrameEnsemble(paths.AllInXEnsemble(state)) ]) & paths.AllOutXEnsemble(paths.join_volumes(forbidden_states)) self.extra_ensembles = [paths.TISEnsemble(transition.stateA, transition.stateB, iface, transition.orderparameter) for iface in extra_interfaces ] self.transition_shooters = [ paths.OneWayShootingMover(selector=paths.UniformSelector(), ensemble=ens) for ens in transition.ensembles ] self.extra_shooters = [ paths.OneWayShootingMover(selector=paths.UniformSelector(), ensemble=ens) for ens in self.extra_ensembles ] self.snapshot = snapshot.copy() self.ensemble0 = ensemble0 self.all_ensembles = transition.ensembles + self.extra_ensembles self.n_ensembles = len(self.all_ensembles) self.error_max_rounds = True
def add_transition(self, stateA, stateB): new_ens = paths.SequentialEnsemble([ paths.AllInXEnsemble(stateA) & paths.LengthEnsemble(1), paths.AllOutXEnsemble(stateA | stateB), paths.AllInXEnsemble(stateB) & paths.LengthEnsemble(1) ]) try: self.ensembles[0] = self.ensembles[0] | new_ens except AttributeError: self.ensembles = [new_ens]
def _build_sampling_transitions(self, transitions): transitions = list(transitions) # input may be iterator # TODO: I don't think transition pairs are used (see comment below; # I think that was the previous use case -- as input to all_in_pairs # However, existing files store this, so we won't actually remove it # yet. self.transition_pairs = self._build_transition_pairs(transitions) # this seems to no longer be used; I think it was necessary when the # MSOuter interface was done implicitly, instead of explicitly. Then # we turn the outermost to MS if and only if it was paired with the # reverse transition # if len(self.transition_pairs) > 0: # all_in_pairs = reduce(list.__add__, map(lambda x: list(x), # self.transition_pairs)) # else: # all_in_pairs = [] # build sampling transitions all_states = paths.join_volumes(self.initial_states + self.final_states) all_states_set = set(self.initial_states + self.final_states) self.transition_to_sampling = {} for transition in transitions: stateA = transition.stateA stateB = transition.stateB if self.strict_sampling: final_state = stateB other_states = paths.join_volumes(all_states_set - set([stateA, stateB])) ensemble_to_intersect = paths.AllOutXEnsemble(other_states) else: final_state = paths.join_volumes(all_states_set) ensemble_to_intersect = paths.FullEnsemble() sample_trans = paths.TISTransition( stateA=stateA, stateB=final_state, interfaces=transition.interfaces, name=stateA.name + "->" + stateB.name, orderparameter=transition.orderparameter) new_ensembles = [ e & ensemble_to_intersect for e in sample_trans.ensembles ] if self.strict_sampling: for (old, new) in zip(new_ensembles, sample_trans.ensembles): old.name = new.name + " strict" sample_trans.ensembles = new_ensembles sample_trans.named("Sampling " + str(stateA) + "->" + str(stateB)) self.transition_to_sampling[transition] = sample_trans self.x_sampling_transitions = \ list(self.transition_to_sampling.values()) self._build_sampling_minus_ensembles()
def __init__(self, stateA, stateB, name=None): super(TPSTransition, self).__init__(stateA, stateB) if name is not None: self.name = name if not hasattr(self, "ensembles"): self.ensembles = [ paths.SequentialEnsemble([ paths.AllInXEnsemble(stateA) & paths.LengthEnsemble(1), paths.AllOutXEnsemble(stateA | stateB), paths.AllInXEnsemble(stateB) & paths.LengthEnsemble(1) ]) ]
def setup(self): cv = paths.FunctionCV("Id", lambda snap: snap.xyz[0][0]) self.state_A = paths.CVDefinedVolume(cv, -0.1, 0.1) self.state_B = ~paths.CVDefinedVolume(cv, -1.0, 1.0) nml_increasing = paths.CVDefinedVolume(cv, 0.1, 1.0) nml_decreasing = paths.CVDefinedVolume(cv, -1.0, -0.1) increasing = paths.AllInXEnsemble(nml_increasing) decreasing = paths.AllInXEnsemble(nml_decreasing) self.ensemble = paths.SequentialEnsemble([ paths.LengthEnsemble(1) & paths.AllInXEnsemble(self.state_A), paths.AllOutXEnsemble(self.state_A | self.state_B), paths.LengthEnsemble(1) & paths.AllInXEnsemble(self.state_B) ]) self.incr_1 = self._make_active([0.0, 0.5, 1.1]) self.incr_2 = self._make_active([0.05, 0.6, 1.2]) self.decr_1 = self._make_active([0.0, -0.5, -1.1]) self.both_1 = self._make_active([0.0, 0.5, -0.5, 1.1]) self.both_2 = self._make_active([0.0, -0.4, 0.4, -1.1]) self.none_1 = self._make_active([0.0, 1.1]) self.none_2 = self._make_active([0.0, -1.1]) self.channels = {'incr': increasing, 'decr': decreasing} # used in simplest tests of relabeling self.toy_results = { 'a': [(0, 5), (8, 10)], 'b': [(3, 9)], 'c': [(7, 9)] } self.results_with_none = { 'a': [(0, 2), (6, 9)], 'b': [(5, 7), (9, 10)], None: [(2, 5)] } self.set_a = frozenset(['a']) self.set_b = frozenset(['b']) self.set_c = frozenset(['c']) self.toy_expanded_results = [(0, 5, self.set_a), (3, 9, self.set_b), (7, 9, self.set_c), (8, 10, self.set_a)] self.expanded_results_simultaneous_ending = [(0, 5, self.set_a), (3, 9, self.set_b), (7, 10, self.set_c), (8, 10, self.set_a)] self.expanded_oldest_skips_internal = [(0, 5, self.set_a), (3, 9, self.set_b), (7, 8, self.set_c), (8, 10, self.set_a), (10, 11, self.set_b)]
def __init__(self, states, progress='default', timestep=None): self.states = states self.all_states = paths.join_volumes(states) all_states_ens = paths.join_ensembles([paths.AllOutXEnsemble(s) for s in states]) ensemble = paths.SequentialEnsemble([ all_states_ens, paths.AllInXEnsemble(self.all_states) & paths.LengthEnsemble(1) ]) super(VisitAllStatesEnsemble, self).__init__(ensemble) self.timestep = timestep self.report_frequency = 10 self.progress_formatter, self.progress_emitter = \ self._progress_indicator(progress) self.cache = EnsembleCache(direction=+1) self._reset_cache_contents()
def __init__(self, initial_state, known_states, stable_contact_state, excluded_volume=None): super(MultipleBindingEnsemble, self).__init__() self.initial_state = initial_state self.known_states = known_states self.final_state = paths.join_volumes( set(known_states) - set([initial_state])) self.states = paths.join_volumes(set([initial_state] + known_states)) self.stable_contact_state = stable_contact_state if excluded_volume is None: excluded_volume = paths.EmptyVolume() self.excluded_volume = excluded_volume self.excluded_volume_ensemble = \ paths.AllOutXEnsemble(self.excluded_volume) self.cache = self._initialize_cache()
def test_subtrajectory_indices(self): # simplify more complicated expressions stateA = self.stateA stateB = self.stateB pretraj = [ 0.20, 0.30, 0.60, 0.40, 0.65, 2.10, 2.20, 2.60, 2.10, 0.80, 0.55, 0.40, 0.20 ] # 00, 01, 02, 03, 04, 05, 06, 07, 08, 09, 10, 11, 12 # A, A, I, A, I, B, B, X, B, X, I, A, A trajectory = make_1d_traj(coordinates=pretraj, velocities=[1.0] * len(pretraj)) ensemble_A = paths.AllInXEnsemble(stateA) ensemble_B = paths.AllInXEnsemble(stateB) ensemble_ABA = paths.SequentialEnsemble([ paths.AllInXEnsemble(stateA) & paths.LengthEnsemble(1), paths.PartInXEnsemble(stateB) & paths.AllOutXEnsemble(stateA), paths.AllInXEnsemble(stateA) & paths.LengthEnsemble(1) ]) subtrajectoriesA = ensemble_A.split(trajectory, overlap=0) subtrajectoriesB = ensemble_B.split(trajectory, overlap=0) subtrajectoriesABA = ensemble_ABA.split(trajectory) # make sure we have the trajectories we expect assert_equal(len(subtrajectoriesA), 3) assert_equal(len(subtrajectoriesB), 2) assert_equal(len(subtrajectoriesABA), 1) # the following assertions check that the subtrajectories are the # ones that we expect; the numbers here are linked to the indices # we'll test next assert_equal(subtrajectoriesA[0], trajectory[0:2]) assert_equal(subtrajectoriesA[1], trajectory[3:4]) assert_equal(subtrajectoriesA[2], trajectory[11:13]) assert_equal(subtrajectoriesB[0], trajectory[5:7]) assert_equal(subtrajectoriesB[1], trajectory[8:9]) assert_equal(subtrajectoriesABA[0], trajectory[3:12]) # now we run the subtrajectory_indices function and test it indicesA = trajectory.subtrajectory_indices(subtrajectoriesA) indicesB = trajectory.subtrajectory_indices(subtrajectoriesB) indicesABA = trajectory.subtrajectory_indices(subtrajectoriesABA) assert_equal(indicesA, [[0, 1], [3], [11, 12]]) assert_equal(indicesB, [[5, 6], [8]]) assert_equal(indicesABA, [[3, 4, 5, 6, 7, 8, 9, 10, 11]])
def fill_minus(minus_ensemble, innermost_ensemble, forbidden_states, initial_trj, engine): initial_state = minus_ensemble.state_vol print(f"Filling minus ensemble for state {initial_state.name}") forbidden_states_ensemble = paths.AllOutXEnsemble( paths.join_volumes(forbidden_states) ) desired_ensemble = innermost_ensemble & forbidden_states_ensemble # ensure we're A->A, not A->B sample_A_to_A = shoot_until_A_to_A(innermost_ensemble, desired_ensemble, initial_trj, engine) # with an A->A segment, just use this to extend into the minus ensemble sample = minus_ensemble.extend_sample_from_trajectories( sample_A_to_A, engine=engine, replica=-1 ) return sample.trajectory
def make_ensemble(self, transitions, forbidden=None): """ Create the ensemble for this MS outer interface. Parameters ---------- transitions : list of :class:`.TISTransition` possible transitions of relevance forbidden : list of :class:`.Volume` or None (optional) volumes to disallow from the ensemble (e.g., other states that should cause the trajectory to stop) Returns ------- :class:`.Ensemble` the union of the TISEnsembles for each volume of the MS outer interface """ if forbidden is None: ensemble_to_intersect = paths.FullEnsemble() else: try: _ = len(forbidden) except TypeError: forbidden = [forbidden] forbidden_vol = paths.join_volumes(forbidden) ensemble_to_intersect = paths.AllOutXEnsemble(forbidden_vol) # TODO: maybe we should crash if given transitions aren't relevant? relevant_transitions = self.relevant_transitions(transitions) outer_ensembles = [] for trans in relevant_transitions: initial = trans.stateA final = trans.stateB volume = self.volume_for_interface_set(trans.interfaces) # TODO: move following to a logger.debug #print initial.name, final.name,\ #self.lambda_for_interface_set(trans.interfaces) outer_ensembles.append(ensemble_to_intersect & paths.TISEnsemble(initial, final, volume)) return paths.join_ensembles(outer_ensembles)
def strict_can_prepend(self, trajectory, trusted=False): n_frames = self.stable_contact_state.n_frames if len(trajectory) < n_frames: # NOTE: technically we might be able to abort earlier on these # short trajectories, but I'm not going to implement that now # (requires checking the freq of contacts and comparing with # possibility of ever having enough) no_known_state_ens = paths.AllOutXEnsemble(self.states) final_frame_allowed = not self.initial_state(trajectory[-1]) other_frames_allowed = (no_known_state_ens(trajectory[:-1]) or len(trajectory) == 1) logger.debug("final_frame_allowed: %s; other_frames_allowed: %s", final_frame_allowed, other_frames_allowed) return final_frame_allowed and other_frames_allowed known_state = self.final_state(trajectory[-1]) subtraj = trajectory[slice(-n_frames, None)] stable_contacts = (self.stable_contact_state.check_end(trajectory) and self.excluded_volume_ensemble(subtraj)) logger.debug("ends in known state: %s; ends in stable contacts: %s", known_state, stable_contacts) return ((known_state or stable_contacts) and self.can_prepend(trajectory, trusted))
def __init__(self, storage, initial_file, mover, network, options=None, options_rejected=None): # TODO: mke the initial file into an initial trajectory if options is None: options = TPSConverterOptions() if options_rejected is None: options_rejected = options self.options = options self.options_rejected = options_rejected self.initial_file = initial_file # needed for restore traj = self.load_trajectory(initial_file) # assume we're TPS here ensemble = network.sampling_ensembles[0] initial_trajectories = ensemble.split(traj) if len(initial_trajectories) == 0: # pragma: no cover raise RuntimeError("Initial trajectory in " + str(initial_file) + " has no subtrajectory satisfying the " + "TPS ensemble.") elif len(initial_trajectories) > 1: # pragma: no cover raise RuntimeWarning("More than one potential initial " + "subtrajectory. We use the first.") initial_trajectory = initial_trajectories[0] initial_conditions = paths.SampleSet([ paths.Sample(replica=0, trajectory=initial_trajectory, ensemble=ensemble) ]) self.extra_bw_frames = traj.index(initial_trajectory[0]) final_frame_index = traj.index(initial_trajectory[-1]) self.extra_fw_frames = len(traj) - final_frame_index - 1 # extra -1 bc frame index counts from 0; len counts from 1 self.summary_root_dir = None self.report_progress = None super(OneWayTPSConverter, self).__init__(storage=storage, initial_conditions=initial_conditions, mover=mover, network=network) # initial_states = self.network.initial_states # final_states = self.network.final_states # TODO: prefer the above, but the below work until fix for network # storage initial_states = [self.network.sampling_transitions[0].stateA] final_states = [self.network.sampling_transitions[0].stateB] all_states = paths.join_volumes(initial_states + final_states) self.fw_ensemble = paths.SequentialEnsemble([ paths.AllOutXEnsemble(all_states), paths.AllInXEnsemble(all_states) & paths.LengthEnsemble(1) ]) self.bw_ensemble = paths.SequentialEnsemble([ paths.AllInXEnsemble(all_states) & paths.LengthEnsemble(1), paths.AllOutXEnsemble(all_states) ]) self.full_ensemble = paths.SequentialEnsemble([ paths.AllInXEnsemble(all_states) & paths.LengthEnsemble(1), paths.AllOutXEnsemble(all_states), paths.AllInXEnsemble(all_states) & paths.LengthEnsemble(1) ]) self.all_states = all_states
def _tps_ensemble(self, stateA, stateB): return paths.SequentialEnsemble([ paths.AllInXEnsemble(stateA) & paths.LengthEnsemble(1), paths.AllOutXEnsemble(stateA | stateB), paths.AllInXEnsemble(stateB) & paths.LengthEnsemble(1) ])
# The idea here is a little subtle, but it makes nice use of our generalized path ensemble idea. # # We want a path which contains at least one frame in each state. The question is, what ensemble can we use to create such a trajectory? # # The first obvious thought would be `goal_ensemble = PartInXEnsemble(stateA) & PartInXEnsemble(stateB)` (which can, of course, be further generalized to more states). However, while that *is* the ensemble we want to eventually satisfy, we can't use its `can_append` to create it, because its `can_append` always returns `True`: the trajectory will go on forever! # # But we can use a trick: since what we want is the first trajectory that satisfies `goal_ensemble`, we know that every shorter trajectory will not satisfy it. This means that the shorter trajectories must satisfy the *complement* of `goal_ensemble`, and the trajectory we want will be the first trajectory that does *not* satisfy the complement! # # So the trick we'll use is to build the trajectory by using the fact that the shorter trajectories are in the complement of `goal_ensemble`, which is given by `complement = AllOutXEnsemble(stateA) | AllOutXEnsemble(stateB)`. The `generate` function will stop when that is no longer true, giving us the trajectory we want. This can be directly generalized to more states. # # Note that here we're not even using the `can_append` function. That happens to be the same as the ensemble itself for this particular ensemble, but conceptually, we're actually using the test of whether a trajectory is in the ensemble at all. # In[8]: init_traj_ensemble = paths.AllOutXEnsemble(C_7eq) | paths.AllOutXEnsemble(alpha_R) # In[9]: # generate trajectory that includes frame in both states trajectory = hi_T_engine.generate(hi_T_engine.current_snapshot, [init_traj_ensemble]) # In[10]: # create a network so we can use its ensemble to obtain an initial trajectory # use all-to-all because we don't care if initial traj is A->B or B->A: it can be reversed tmp_network = paths.TPSNetwork.from_states_all_to_all([C_7eq, alpha_R])
interfaces = paths.VolumeInterfaceSet(cv, minvals=0.0, maxvals=np.linspace( max_bound, min_unbound - 0.01, ninterfaces)) print('Creating network...') mistis = paths.MISTISNetwork([(bound, interfaces, unbound)]) initial_trajectory_method = 'bootstrap' if initial_trajectory_method == 'high-temperature': # We are starting in the bound state, so # generate high-temperature trajectory that reaches the unbound state print('Generating high-temperature trajectory...') #ensemble = not (paths.ExitsXEnsemble(bound) & paths.EntersXEnsemble(unbound)) unbinding_ensemble = paths.AllOutXEnsemble(unbound) bridging_ensemble = paths.AllOutXEnsemble(bound) & paths.AllOutXEnsemble( unbound) initial_trajectories = list() minus_trajectories = list() tmp_network = paths.TPSNetwork(bound, unbound) attempt = 0 while (len(initial_trajectories) == 0) or (len(minus_trajectories) == 0): print('Attempt %d' % attempt) long_trajectory = engine_hot.generate(initial_snapshot_hot, [unbinding_ensemble]) print('long trajectory:') print(long_trajectory) distances = np.array([cv(snapshot) for snapshot in long_trajectory]) print(distances) # split out the subtrajectory of interest
def build_sampling_transitions(self, transitions): # identify transition pairs transition_pair_set_dict = {} for initial in self.initial_states: for t1 in [t for t in transitions if t.stateA==initial]: t_reverse = [ t for t in transitions if t.stateA == t1.stateB and t.stateB == t1.stateA ] if len(t_reverse) == 1: key = frozenset([t1.stateA, t1.stateB]) new_v = [t1, t_reverse[0]] if key not in transition_pair_set_dict.keys(): transition_pair_set_dict[key] = new_v elif len(t_reverse) > 1: # pragma: no cover raise RuntimeError("More than one reverse transition") # if len(t_reverse) is 0, we just pass self.transition_pairs = transition_pair_set_dict.values() if len(self.transition_pairs) > 0: all_in_pairs = reduce(list.__add__, map(lambda x: list(x), self.transition_pairs)) else: all_in_pairs = [] # build sampling transitions all_states = paths.join_volumes(self.initial_states + self.final_states) all_states_set = set(self.initial_states + self.final_states) self.transition_to_sampling = {} for transition in transitions: stateA = transition.stateA stateB = transition.stateB if self.strict_sampling: final_state = stateB other_states = paths.join_volumes(all_states_set - set([stateA, stateB])) ensemble_to_intersect = paths.AllOutXEnsemble(other_states) else: final_state = all_states ensemble_to_intersect = paths.FullEnsemble() sample_trans = paths.TISTransition( stateA=stateA, stateB=final_state, interfaces=transition.interfaces, orderparameter=transition.orderparameter ) new_ensembles = [e & ensemble_to_intersect for e in sample_trans.ensembles] if self.strict_sampling: for (old, new) in zip(new_ensembles, sample_trans.ensembles): old.name = new.name + " strict" sample_trans.ensembles = new_ensembles sample_trans.named("Sampling " + str(stateA) + "->" + str(stateB)) self.transition_to_sampling[transition] = sample_trans self.x_sampling_transitions = self.transition_to_sampling.values() # combining the minus interfaces for initial in self.initial_states: innermosts = [] trans_from_initial = [ t for t in self.x_sampling_transitions if t.stateA==initial ] for t1 in trans_from_initial: innermosts.append(t1.interfaces[0]) minus = paths.MinusInterfaceEnsemble( state_vol=initial, innermost_vols=innermosts ) try: self.special_ensembles['minus'][minus] = trans_from_initial except KeyError: self.special_ensembles['minus'] = {minus : trans_from_initial}
def __init__(self, storage, engine=None, states=None, randomizer=None, initial_snapshots=None, rc=None): # state definition self.states = states state_A = states[0] state_B = states[1] # get min/max reaction coordinate of initial snapshots self.rc = rc rc_array = np.array(self.rc(initial_snapshots)) rc_min = np.nextafter(rc_array.min(), -np.inf) rc_max = np.nextafter(rc_array.max(), np.inf) # define reaction coordinate region of initial snapshots # = starting_volume self.dividing_surface = paths.CVDefinedVolume(self.rc, rc_min, rc_max) # define volume between state A and the dividing surface (including A) self.volume_towards_A = paths.CVDefinedVolume(self.rc, -np.inf, rc_max) # shoot backward until we hit A but never cross the dividing surface backward_ensemble = paths.SequentialEnsemble([ paths.AllInXEnsemble(state_A) & paths.LengthEnsemble(1), paths.AllInXEnsemble(self.volume_towards_A - state_A) ]) # shoot forward until we hit state B without hitting A first # caution: since the mover will consist of backward and forward # shoot in sequence, the starting ensemble for the forward # shoot is the output of the backward shoot, i.e. a # trajectory that runs from A to the dividing surface and # not just a point there. forward_ensemble = paths.SequentialEnsemble([ paths.AllInXEnsemble(state_A) & paths.LengthEnsemble(1), paths.AllOutXEnsemble(state_A | state_B), paths.AllInXEnsemble(state_B) & paths.LengthEnsemble(1), ]) super(ReactiveFluxSimulation, self).__init__( storage=storage, engine=engine, starting_volume=self.dividing_surface, forward_ensemble=forward_ensemble, backward_ensemble=backward_ensemble, randomizer=randomizer, initial_snapshots=initial_snapshots ) # create backward mover (starting from single point) self.backward_mover = paths.BackwardExtendMover( ensemble=self.starting_ensemble, target_ensemble=self.backward_ensemble ) # create forward mover (starting from the backward ensemble) self.forward_mover = paths.ForwardExtendMover( ensemble=self.backward_ensemble, target_ensemble=self.forward_ensemble ) # create mover combining forward and backward shooting, # abort if backward mover fails self.mover = paths.NonCanonicalConditionalSequentialMover([ self.backward_mover, self.forward_mover ])