def __init__( self, storage, move_scheme=None, sample_set=None, initialize=True ): """ Parameters ---------- storage : :class:`openpathsampling.storage.Storage` the storage where all results should be stored in move_scheme : :class:`openpathsampling.MoveScheme` the move scheme used for the pathsampling cycle sample_set : :class:`openpathsampling.SampleSet` the initial SampleSet for the Simulator initialize : bool if `False` the new PathSimulator will continue at the step and not create a new SampleSet object to cut the connection to previous steps """ super(PathSampling, self).__init__(storage) self.move_scheme = move_scheme if move_scheme is not None: self.root_mover = move_scheme.move_decision_tree() self._mover = paths.PathSimulatorMover(self.root_mover, self) else: self.root_mover = None self._mover = None initialization_logging(init_log, self, ['move_scheme', 'sample_set']) self.live_visualizer = None self.status_update_frequency = 1 if initialize: samples = [] if sample_set is not None: for sample in sample_set: samples.append(sample.copy_reset()) self.sample_set = paths.SampleSet(samples) mcstep = MCStep( simulation=self, mccycle=self.step, active=self.sample_set, change=paths.AcceptedSampleMoveChange(self.sample_set.samples) ) self._current_step = mcstep else: self.sample_set = sample_set self._current_step = None self.root = self.sample_set if self.storage is not None: self.save_current_step()
def save_initial_step(self): """ Save the initial state as an MCStep to the storage """ mcstep = MCStep(simulation=self, mccycle=self.step, active=self.sample_set, change=paths.AcceptedSampleMoveChange( self.sample_set.samples)) if self.storage is not None: self.storage.steps.save(mcstep) self.storage.sync_all()
def _make_fake_steps(self, sample_sets, mover): steps = [] for (mccycle, sample_set) in enumerate(sample_sets): change = paths.AcceptedSampleMoveChange( samples=sample_set.samples, mover=mover, details=None, input_samples=None ) step = paths.MCStep(mccycle=mccycle, active=sample_set, change=change) steps.append(step) return steps
def _make_fake_minus_steps(self, scheme, descriptions): network = scheme.network state_adjustment = { self.state_A: lambda x: x, self.state_B: lambda x: 1.0 - x } minus_ensemble_to_mover = {m.minus_ensemble: m for m in scheme.movers['minus']} assert_equal(set(minus_ensemble_to_mover.keys()), set(network.minus_ensembles)) steps = [] mccycle = 0 for minus_traj in descriptions: for i, minus_ensemble in enumerate(network.minus_ensembles): replica = -1 - i adjustment = state_adjustment[minus_ensemble.state_vol] traj = make_1d_traj([adjustment(s) for s in minus_traj]) assert_equal(minus_ensemble(traj), True) samp = paths.Sample(trajectory=traj, ensemble=minus_ensemble, replica=replica) sample_set = paths.SampleSet([samp]) change = paths.AcceptedSampleMoveChange( samples=[samp], mover=minus_ensemble_to_mover[samp.ensemble], details=paths.Details() ) # NOTE: this makes it so that only one ensemble is # represented in the same set at any time, which isn't quite # how it actually works. However, this is doesn't matter for # the current implementation steps.append(paths.MCStep(mccycle=mccycle, active=sample_set, change=change)) mccycle += 1 assert_equal(len(steps), 4) return steps
def test_with_minus_move_flux(self): network = self.mstis scheme = paths.DefaultScheme(network, engine=RandomMDEngine()) scheme.build_move_decision_tree() # create the minus move steps # `center` is the edge of the state/innermost interface center = {self.state_A: 0.0, self.state_B: 1.0} replica = {self.state_A: -1, self.state_B: -2} minus_ensemble_to_mover = {m.minus_ensemble: m for m in scheme.movers['minus']} state_to_minus_ensemble = {ens.state_vol: ens for ens in network.minus_ensembles} minus_changes = [] # `delta` is the change on either side for in vs. out for (state, delta) in [(self.state_A, 0.1), (self.state_B, -0.1)]: minus_ens = state_to_minus_ensemble[state] minus_mover = minus_ensemble_to_mover[minus_ens] a_in = center[state] - delta a_out = center[state] + delta # note that these trajs are equivalent to minus move # descriptions in TestMinusMoveFlux seq_1 = [a_in] + [a_out]*2 + [a_in]*5 + [a_out]*5 + [a_in] seq_2 = [a_in] + [a_out]*3 + [a_in]*3 + [a_out]*3 + [a_in] for seq in [seq_1, seq_2]: traj = make_1d_traj(seq) assert_equal(minus_ens(traj), True) samp = paths.Sample(trajectory=traj, ensemble=minus_ens, replica=replica[state]) sample_set = paths.SampleSet([samp]) change = paths.AcceptedSampleMoveChange( samples=[samp], mover=minus_mover, details=paths.Details() ) minus_changes.append(change) active = self.mstis_steps[0].active steps = [] cycle = -1 for m_change in minus_changes: cycle += 1 active = active.apply_samples(m_change.samples) step = paths.MCStep(mccycle=cycle, active=active, change=m_change) steps.append(step) for old_step in self.mstis_steps[1:]: cycle += 1 active = active.apply_samples(old_step.change.samples) step = paths.MCStep(mccycle=cycle, active=active, change=old_step.change) steps.append(step) analysis = StandardTISAnalysis( network=self.mstis, scheme=scheme, max_lambda_calcs={t: {'bin_width': 0.1, 'bin_range': (-0.1, 1.1)} for t in network.sampling_transitions}, steps=steps ) # now we actually verify correctness avg_t_in = (5.0 + 3.0) / 2 avg_t_out = (2.0 + 5.0 + 3.0 + 3.0) / 4 expected_flux = 1.0 / (avg_t_in + avg_t_out) # NOTE: Apparently this approach screws up the TCP calculation. I # think this is a problem in the fake data, not the simulation. for flux in analysis.flux_matrix.values(): assert_almost_equal(flux, expected_flux)
def move(self, input_sample, trial_trajectory, shooting_point, accepted, direction=None): """Fake a move. Parameters ---------- input_sample: :class:`paths.Sample` the input sample for this shooting move trial_trajectory: :class:`paths.Trajectory` the trial trajectory generated by this move shooting_point: :class:`paths.Snapshot` the shooting point snapshot for this trial accepted: bool whether the trial was accepted direction: +1, -1, or None direction of the shooting move (positive is forward, negative is backward). If self.pre_joined is True, the trial trajectory is reconstructed from the parts. To use the exact input trial trajectory with self.pre_joined == True, set direction=None """ initial_trajectory = input_sample.trajectory replica = input_sample.replica ensemble = input_sample.ensemble if not self.pre_joined: trial_trajectory = self.join_one_way(initial_trajectory, trial_trajectory, shooting_point, direction) # determine the direction based on trial trajectory shared = trial_trajectory.shared_subtrajectory(initial_trajectory) if len(shared) == 0: raise RuntimeError("No shared frames. " + "Were these shot from each other?") if shared[0] == trial_trajectory[0]: choice = 0 # forward submover elif shared[-1] == trial_trajectory[-1]: choice = 1 # backward submover else: # pragma: no cover raise RuntimeError("Are you sure this is 1-way shooting?") details = paths.Details( initial_trajectory=initial_trajectory, shooting_snapshot=shooting_point ) trial = paths.Sample( replica=replica, trajectory=trial_trajectory, ensemble=ensemble, parent=input_sample, # details=trial_details, mover=self.mimic.movers[choice] ) trials = [trial] # move_details = paths.MoveDetails() if accepted: inner = paths.AcceptedSampleMoveChange( samples=trials, mover=self.mimic.movers[choice], details=details ) else: inner = paths.RejectedSampleMoveChange( samples=trial, mover=self.mimic.movers[choice], details=details ) rc_details = paths.MoveDetails() rc_details.inputs = [] rc_details.choice = choice rc_details.chosen_mover = self.mimic.movers[choice] rc_details.probability = 0.5 rc_details.weights = [1, 1] return paths.RandomChoiceMoveChange( subchange=inner, mover=self.mimic, details=rc_details )