def run_step(self, index): """Runs a single step of the job. @param index: the index of the step. @type index: int. @note: the argument index is the index of the loop note the index of the frame. """ # Read the current step in the xdatcar file. config = self._xdatcarFile.read_step(index) conf = Configuration(self._universe,config) conf.convertFromBoxCoordinates() self._universe.setConfiguration(conf) # The real coordinates are foled then into the simulation box (-L/2,L/2). self._universe.foldCoordinatesIntoBox() time = index*self.configuration["time_step"]["value"]*Units.fs # A call to the snapshot generator produces the step corresponding to the current frame. self._snapshot(data = {'time': time}) return index, None
def calc(self, frameIndex, trajectory): """Calculates the contribution for one frame. @param frameIndex: the index of the frame. @type frameIndex: integer. @param trajectory: the trajectory. @type trajectory: MMTK.Trajectory.Trajectory object """ orderedAtoms = sorted(trajectory.universe.atomList(), key = operator.attrgetter('index')) selectedAtoms = Collection([orderedAtoms[ind] for ind in self.subset]) targetAtoms = Collection([orderedAtoms[ind] for ind in self.target]) initialConf = Configuration(trajectory.universe, self.initialConfArray) # First frame, nothing to do because the initialConf already stores the initial transformation. if frameIndex == self.firstFrame: trajectory.universe.setConfiguration(initialConf) else: trajectory.universe.setFromTrajectory(trajectory, frameIndex) # Find and apply the linear transformation that will minimize the RMS with the configuration # resulting from the principal axes transformation. tr, rms = selectedAtoms.findTransformation(initialConf) #selectedAtoms.applyTransformation(tr) trajectory.universe.applyTransformation(tr) globalMotionFilteredFrame = {} for at in targetAtoms: globalMotionFilteredFrame[at.index] = at.position() return frameIndex, globalMotionFilteredFrame
def _prepare_ligand_CD(self): """Prepares the ligand for CD simulations Returns ------- seeds : list of np.array Ligand configurations minimized in milestone D """ if self.data['CD'].protocol == []: params_o = self.system.paramsFromAlpha(1.0, 'CD') self.system.setParams(params_o) if (self.args.params['CD']['pose'] == -1): seeds = self._get_confs_to_rescore(site=True, minimize=True)[0] self.data['CD'].confs['starting_poses'] = seeds else: # For pose BPMF, starting_poses is defined in _set_universe_evaluator seeds = self.data['CD'].confs['starting_poses'] if seeds == []: seeds = None else: # initializes smart darting for CD and sets the universe # to the lowest energy configuration self.iterator.initializeSmartDartingConfigurations( seeds, 'CD', self.log, self.data) if len(seeds) > 0: self.top.universe.setConfiguration(\ Configuration(self.top.universe,np.copy(seeds[-1]))) # Ramp up the temperature using HMC self._ramp_T(self.args.params['BC']['T_TARGET'], normalize=False) seeds = [np.copy(self.top.universe.configuration().array) \ for n in range(self.args.params['CD']['seeds_per_state'])] return seeds
def _initial_sim_state(self, seeds, process, params_k): """ Initializes a state, returning the configurations and potential energy. Attempts simulation up to 12 times, adjusting the time step. """ if not 'delta_t' in params_k.keys(): params_k[ 'delta_t'] = 1. * self.args.params[process]['delta_t'] * MMTK.Units.fs params_k['steps_per_trial'] = self.args.params[process]['steps_per_sweep'] attempts_left = 12 while (attempts_left > 0): # Get initial potential energy Es_o = [] for seed in seeds: self.top.universe.setConfiguration( Configuration(self.top.universe, seed)) Es_o.append(self.top.universe.energy()) Es_o = np.array(Es_o) # Perform simulation results = [] if self.args.cores > 1: # Multiprocessing code import multiprocessing m = multiprocessing.Manager() task_queue = m.Queue() done_queue = m.Queue() for k in range(len(seeds)): task_queue.put((seeds[k], process, params_k, True, k)) processes = [multiprocessing.Process(target=self.iterator.iteration_worker, \ args=(task_queue, done_queue)) for p in range(self.args.cores)] for p in range(self.args.cores): task_queue.put('STOP') for p in processes: p.start() for p in processes: p.join() results = [done_queue.get() for seed in seeds] for p in processes: p.terminate() else: # Single process code results = [self.iterator.iteration(\ seeds[k], process, params_k, True, k) for k in range(len(seeds))] seeds = [result['confs'] for result in results] Es_n = np.array([result['Etot'] for result in results]) deltaEs = Es_n - Es_o attempts_left -= 1 # Get the time step delta_t = np.array([result['delta_t'] for result in results]) if np.std(delta_t) > 1E-3: # If the integrator adapts the time step, take an average delta_t = min(max(np.mean(delta_t), \ self.args.params[process]['delta_t']/5.0*MMTK.Units.fs), \ self.args.params[process]['delta_t']*0.1*MMTK.Units.fs) else: delta_t = delta_t[0] # Adjust the time step if self.args.params[process]['sampler'] == 'HMC': # Adjust the time step for Hamiltonian Monte Carlo acc_rate = float(np.sum([r['acc_Sampler'] for r in results]))/\ np.sum([r['att_Sampler'] for r in results]) if acc_rate > 0.8: delta_t += 0.125 * MMTK.Units.fs elif acc_rate < 0.4: if delta_t < 2.0 * MMTK.Units.fs: params_k['steps_per_trial'] = max( int(params_k['steps_per_trial'] / 2.), 1) delta_t -= 0.25 * MMTK.Units.fs if acc_rate < 0.1: delta_t -= 0.25 * MMTK.Units.fs else: attempts_left = 0 else: # For other integrators, make sure the time step # is small enough to see changes in the energy if (np.std(deltaEs) < 1E-3): delta_t -= 0.25 * MMTK.Units.fs else: attempts_left = 0 if delta_t < 0.1 * MMTK.Units.fs: delta_t = 0.1 * MMTK.Units.fs params_k['delta_t'] = delta_t sampler_metrics = '' for s in ['ExternalMC', 'SmartDarting', 'Sampler']: if np.array(['acc_' + s in r.keys() for r in results]).any(): acc = np.sum([r['acc_' + s] for r in results]) att = np.sum([r['att_' + s] for r in results]) time = np.sum([r['time_' + s] for r in results]) if att > 0: sampler_metrics += '%s %d/%d=%.2f (%.1f s); '%(\ s,acc,att,float(acc)/att,time) return (seeds, Es_n - Es_o, delta_t, sampler_metrics)
def _random_CD(self): """ Randomly places the ligand into the receptor and evaluates energies The first state of CD is sampled by randomly placing configurations from the high temperature ligand simulation into the binding site. """ # Select samples from the high T unbound state E_MM = [] E_OBC = [] confs = [] for k in range(1, len(self.data['BC'].Es[0])): E_MM += list(self.data['BC'].Es[0][k]['MM']) if ('OBC' in self.data['BC'].Es[0][k].keys()): E_OBC += list(self.data['BC'].Es[0][k]['OBC']) confs += list(self.data['BC'].confs['samples'][0][k]) random_CD_inds = np.array(np.linspace(0,len(E_MM), \ self.args.params['CD']['seeds_per_state'],endpoint=False),dtype=int) BC0_Es_MM = [E_MM[ind] for ind in random_CD_inds] BC0_Es_OBC = [] if E_OBC != []: BC0_Es_OBC = [E_OBC[ind] for ind in random_CD_inds] BC0_confs = [confs[ind] for ind in random_CD_inds] # Do the random CD params_o = self.system.paramsFromAlpha(0.0, 'CD') params_o['delta_t'] = 1. * self.data['BC'].protocol[0]['delta_t'] self.data['CD'].protocol = [params_o] # Set up the force field with full interaction grids self.system.setParams(self.system.paramsFromAlpha(1.0, 'CD')) # Either loads or generates the random translations and rotations for the first state of CD if not (hasattr(self, '_random_trans') and hasattr(self, '_random_rotT')): self.data['CD']._max_n_trans = 10000 # Default density of points is 50 per nm**3 self.data['CD']._n_trans = max( min( np.int( np.ceil(self._forceFields['site'].volume * self.args.params['CD']['site_density'])), self.data['CD']._max_n_trans), 5) self.data['CD']._random_trans = np.ndarray( (self.data['CD']._max_n_trans), dtype=Vector) for ind in range(self.data['CD']._max_n_trans): self.data['CD']._random_trans[ind] = Vector( self._forceFields['site'].randomPoint()) self.data['CD']._max_n_rot = 100 self._n_rot = 100 self._random_rotT = np.ndarray((self.data['CD']._max_n_rot, 3, 3)) from AlGDock.Integrators.ExternalMC.ExternalMC import random_rotate for ind in range(self.data['CD']._max_n_rot): self._random_rotT[ind, :, :] = np.transpose(random_rotate()) else: self.data['CD']._max_n_trans = self.data['CD']._random_trans.shape[0] self._n_rot = self._random_rotT.shape[0] # Get interaction energies. # Loop over configurations, random rotations, and random translations E = {} for term in (['MM', 'site'] + scalables): # Large array creation may cause MemoryError E[term] = np.zeros((self.args.params['CD']['seeds_per_state'], \ self.data['CD']._max_n_rot,self.data['CD']._n_trans)) self.log.tee(" allocated memory for interaction energies") from AlGDock.system import term_map converged = False n_trans_o = 0 n_trans_n = self.data['CD']._n_trans while not converged: for c in range(self.args.params['CD']['seeds_per_state']): E['MM'][c, :, :] = BC0_Es_MM[c] if BC0_Es_OBC != []: E['OBC'][c, :, :] = BC0_Es_OBC[c] for i_rot in range(self._n_rot): conf_rot = Configuration(self.top.universe,\ np.dot(BC0_confs[c], self._random_rotT[i_rot,:,:])) for i_trans in range(n_trans_o, n_trans_n): self.top.universe.setConfiguration(conf_rot) self.top.universe.translateTo( self.data['CD']._random_trans[i_trans]) eT = self.top.universe.energyTerms() for (key, value) in eT.iteritems(): if key != 'electrostatic': # For some reason, MMTK double-counts electrostatic energies E[term_map[key]][c, i_rot, i_trans] += value E_c = {} for term in E.keys(): # Large array creation may cause MemoryError E_c[term] = np.ravel(E[term][:, :self._n_rot, :n_trans_n]) self.log.tee(" allocated memory for %d translations" % n_trans_n) (u_kln,N_k) = self._u_kln([E_c],\ [params_o,self._next_CD_state(E=E_c, params_o=params_o, decoupling=False)]) du = u_kln[0, 1, :] - u_kln[0, 0, :] bootstrap_reps = 50 f_grid0 = np.zeros(bootstrap_reps) for b in range(bootstrap_reps): du_b = du[np.random.randint(0, len(du), len(du))] f_grid0[b] = -np.log(np.exp(-du_b + min(du_b)).mean()) + min(du_b) f_grid0_std = f_grid0.std() converged = f_grid0_std < 0.1 if not converged: self.log.tee(" with %s translations "%n_trans_n + \ "the predicted free energy difference is %.5g (%.5g)"%(\ f_grid0.mean(),f_grid0_std)) if n_trans_n == self.data['CD']._max_n_trans: break n_trans_o = n_trans_n n_trans_n = min(n_trans_n + 25, self.data['CD']._max_n_trans) for term in (['MM', 'site'] + scalables): # Large array creation may cause MemoryError E[term] = np.dstack((E[term], \ np.zeros((self.args.params['CD']['seeds_per_state'],\ self.data['CD']._max_n_rot,25)))) if self.data['CD']._n_trans != n_trans_n: self.data['CD']._n_trans = n_trans_n self.log.tee(" %d ligand configurations "%len(BC0_Es_MM) + \ "were randomly docked into the binding site using "+ \ "%d translations and %d rotations "%(n_trans_n,self._n_rot)) self.log.tee(" the predicted free energy difference between the" + \ " first and second CD states is " + \ "%.5g (%.5g)"%(f_grid0.mean(),f_grid0_std)) self.log.recordStart('ravel') for term in E.keys(): E[term] = np.ravel(E[term][:, :self._n_rot, :self.data['CD']._n_trans]) self.log.tee(" raveled energy terms in " + \ HMStime(self.log.timeSince('ravel'))) return (BC0_confs, E)
def __call__(self, **options): # Process the keyword arguments self.setCallOptions(options) # Check if the universe has features not supported by the integrator Features.checkFeatures(self, self.universe) RT = R*self.getOption('T') delta_t = self.getOption('delta_t') if 'steps_per_trial' in self.call_options.keys(): steps_per_trial = self.getOption('steps_per_trial') ntrials = self.getOption('steps')/steps_per_trial else: steps_per_trial = self.getOption('steps') ntrials = 1 if 'normalize' in self.call_options.keys(): normalize = self.getOption('normalize') else: normalize = False # Seed the random number generator if 'random_seed' in self.call_options.keys(): np.random.seed(self.getOption('random_seed')) self.universe.initializeVelocitiesToTemperature(self.getOption('T')) # Get the universe variables needed by the integrator masses = self.universe.masses() fixed = self.universe.getAtomBooleanArray('fixed') nt = self.getOption('threads') comm = self.getOption('mpi_communicator') evaluator = self.universe.energyEvaluator(threads=nt, mpi_communicator=comm) evaluator = evaluator.CEvaluator() late_args = ( masses.array, fixed.array, evaluator, N.zeros((0, 2), N.Int), N.zeros((0, ), N.Float), N.zeros((1,), N.Int), N.zeros((0,), N.Float), N.zeros((2,), N.Float), N.zeros((0,), N.Float), N.zeros((1,), N.Float), delta_t, self.getOption('first_step'), steps_per_trial, self.getActions(), 'Hamiltonian Monte Carlo step') # Variables for velocity assignment m3 = np.repeat(np.expand_dims(masses.array,1),3,axis=1) sigma_MB = np.sqrt((self.getOption('T')*Units.k_B)/m3) natoms = self.universe.numberOfAtoms() xs = [] energies = [] # Store initial configuration and potential energy xo = np.copy(self.universe.configuration().array) self.sampling_universe.configuration().array[-natoms:,:] = xo pe_o = self.sampling_universe.energy() # <- Using sampling Hamiltonian # rather than guidance Hamiltonian acc = 0 for t in range(ntrials): # Initialize the velocity v = self.universe.velocities() v.array = np.multiply(sigma_MB,np.random.randn(natoms,3)) # Store total energy eo = pe_o + 0.5*np.sum(np.multiply(m3,np.square(v.array))) # Run the velocity verlet integrator self.run(MMTK_dynamics.integrateVV, (self.universe, self.universe.configuration().array, self.universe.velocities().array) + late_args) # Decide whether to accept the move self.sampling_universe.configuration().array[-natoms:,:] = \ self.universe.configuration().array pe_n = self.sampling_universe.energy() # <- Using sampling Hamiltonian # rather than guidance Hamiltonian en = pe_n + 0.5*np.sum(np.multiply(m3,np.square(v.array))) # TODO: Confirm acceptance criterion if ((en<eo) or (np.random.random()<N.exp(-(en-eo)/RT))) and \ ((abs(pe_o-pe_n)/RT<250.) or (abs(eo-en)/RT<250.)): xo = np.copy(self.universe.configuration().array) pe_o = pe_n acc += 1 if normalize: self.universe.normalizePosition() else: self.universe.setConfiguration(Configuration(self.universe,xo)) xs.append(np.copy(self.universe.configuration().array)) energies.append(pe_o) return (xs, energies, acc, ntrials, delta_t)
def setParams(self, params): """Sets the universe evaluator to values appropriate for the parameters. Parameters ---------- params : dict The elements in the dictionary params can be: MM - True, to turn on the Generalized AMBER force field site - True, to turn on the binding site sLJr - scaling of the soft Lennard-Jones repulsive grid sLJa - scaling of the soft Lennard-Jones attractive grid sELE - scaling of the soft electrostatic grid LJr - scaling of the Lennard-Jones repulsive grid LJa - scaling of the Lennard-Jones attractive grid ELE - scaling of the electrostatic grid k_angular_int - spring constant of flat-bottom wells for angular internal degrees of freedom (kJ/nm) k_spatial_ext - spring constant of flat-bottom wells for spatial external degrees of freedom (kJ/nm) k_angular_ext - spring constant of flat-bottom wells for angular external degrees of freedom (kJ/nm) T - the temperature in K """ self.T = params['T'] # Reuse evaluators that have been stored evaluator_key = ','.join(['%s:%s'%(k,params[k]) \ for k in sorted(params.keys())]) if evaluator_key in self._evaluators.keys(): self.top.universe._evaluator[(None,None,None)] = \ self._evaluators[evaluator_key] return # Otherwise create a new evaluator fflist = [] if ('MM' in params.keys()) and params['MM']: fflist.append(self._forceFields['gaff']) if ('site' in params.keys()) and params['site']: # Set up the binding site in the force field append_site = True # Whether to append the binding site to the force field if not 'site' in self._forceFields.keys(): if (self.args.params['CD']['site']=='Sphere') and \ (self.args.params['CD']['site_center'] is not None) and \ (self.args.params['CD']['site_max_R'] is not None): from AlGDock.ForceFields.Sphere.Sphere import SphereForceField self._forceFields['site'] = SphereForceField( center=self.args.params['CD']['site_center'], max_R=self.args.params['CD']['site_max_R'], name='site') elif (self.args.params['CD']['site']=='Cylinder') and \ (self.args.params['CD']['site_center'] is not None) and \ (self.args.params['CD']['site_direction'] is not None): from AlGDock.ForceFields.Cylinder.Cylinder import CylinderForceField self._forceFields['site'] = CylinderForceField( origin=self.args.params['CD']['site_center'], direction=self.args.params['CD']['site_direction'], max_Z=self.args.params['CD']['site_max_Z'], max_R=self.args.params['CD']['site_max_R'], name='site') else: # Do not append the site if it is not defined print 'Binding site not defined!' append_site = False if append_site: fflist.append(self._forceFields['site']) # Add scalable terms for scalable in scalables: if (scalable in params.keys()) and params[scalable] > 0: # Load the force field if it has not been loaded if not scalable in self._forceFields.keys(): if scalable == 'OBC': from AlGDock.ForceFields.OBC.OBC import OBCForceField if self.args.params['CD']['solvation']=='Fractional' and \ ('ELE' in params.keys()): self.log.recordStart('grid_loading') self._forceFields['OBC'] = OBCForceField(\ desolvationGridFN=self.args.FNs['grids']['desolv']) self.log.tee(' %s grid loaded from %s in %s'%(scalable, \ os.path.basename(self.args.FNs['grids']['desolv']), \ HMStime(self.log.timeSince('grid_loading')))) else: self._forceFields['OBC'] = OBCForceField() else: # Grids self.log.recordStart('grid_loading') grid_FN = self.args.FNs['grids'][{ 'sLJr': 'LJr', 'sLJa': 'LJa', 'sELE': 'ELE', 'LJr': 'LJr', 'LJa': 'LJa', 'ELE': 'ELE' }[scalable]] grid_scaling_factor = 'scaling_factor_' + \ {'sLJr':'LJr','sLJa':'LJa','sELE':'electrostatic', \ 'LJr':'LJr','LJa':'LJa','ELE':'electrostatic'}[scalable] # Determine the grid threshold if scalable == 'sLJr': grid_thresh = 10.0 elif scalable == 'sELE': # The maximum value is set so that the electrostatic energy # less than or equal to the Lennard-Jones repulsive energy # for every heavy atom at every grid point # TODO: For conversion to OpenMM, get ParticleProperties from the Force object scaling_factors_ELE = np.array([ \ self.top.molecule.getAtomProperty(a, 'scaling_factor_electrostatic') \ for a in self.top.molecule.atomList()],dtype=float) scaling_factors_LJr = np.array([ \ self.top.molecule.getAtomProperty(a, 'scaling_factor_LJr') \ for a in self.top.molecule.atomList()],dtype=float) toKeep = np.logical_and( scaling_factors_LJr > 10., abs(scaling_factors_ELE) > 0.1) scaling_factors_ELE = scaling_factors_ELE[toKeep] scaling_factors_LJr = scaling_factors_LJr[toKeep] grid_thresh = min( abs(scaling_factors_LJr * 10.0 / scaling_factors_ELE)) else: grid_thresh = -1 # There is no threshold for grid points from AlGDock.ForceFields.Grid.Interpolation \ import InterpolationForceField self._forceFields[scalable] = InterpolationForceField(grid_FN, \ name=scalable, interpolation_type='Trilinear', \ strength=params[scalable], scaling_property=grid_scaling_factor, inv_power=4 if scalable=='LJr' else None, \ grid_thresh=grid_thresh) self.log.tee(' %s grid loaded from %s in %s'%(scalable, \ os.path.basename(grid_FN), \ HMStime(self.log.timeSince('grid_loading')))) # Set the force field strength to the desired value self._forceFields[scalable].set_strength(params[scalable]) fflist.append(self._forceFields[scalable]) if ('k_angular_int' in params.keys()) or \ ('k_spatial_ext' in params.keys()) or \ ('k_angular_ext' in params.keys()): # Load the force field if it has not been loaded if not ('ExternalRestraint' in self._forceFields.keys()): Xo = np.copy(self.top.universe.configuration().array) self.top.universe.setConfiguration( Configuration(self.top.universe, self.starting_pose)) import AlGDock.rigid_bodies rb = AlGDock.rigid_bodies.identifier(self.top.universe, self.top.molecule) (TorsionRestraintSpecs, ExternalRestraintSpecs) = rb.poseInp() self.top.universe.setConfiguration( Configuration(self.top.universe, Xo)) # Create force fields from AlGDock.ForceFields.Pose.PoseFF import InternalRestraintForceField self._forceFields['InternalRestraint'] = \ InternalRestraintForceField(TorsionRestraintSpecs) from AlGDock.ForceFields.Pose.PoseFF import ExternalRestraintForceField self._forceFields['ExternalRestraint'] = \ ExternalRestraintForceField(*ExternalRestraintSpecs) # Set parameter values if ('k_angular_int' in params.keys()): self._forceFields['InternalRestraint'].set_k(\ params['k_angular_int']) fflist.append(self._forceFields['InternalRestraint']) if ('k_spatial_ext' in params.keys()): self._forceFields['ExternalRestraint'].set_k_spatial(\ params['k_spatial_ext']) fflist.append(self._forceFields['ExternalRestraint']) if ('k_angular_ext' in params.keys()): self._forceFields['ExternalRestraint'].set_k_angular(\ params['k_angular_ext']) compoundFF = fflist[0] for ff in fflist[1:]: compoundFF += ff self.top.universe.setForceField(compoundFF) if self.top_RL.universe is not None: if 'OBC_RL' in params.keys(): if not 'OBC_RL' in self._forceFields.keys(): from AlGDock.ForceFields.OBC.OBC import OBCForceField self._forceFields['OBC_RL'] = OBCForceField() self._forceFields['OBC_RL'].set_strength(params['OBC_RL']) if (params['OBC_RL'] > 0): self.top_RL.universe.setForceField( self._forceFields['OBC_RL']) eval = ForceField.EnergyEvaluator(\ self.top.universe, self.top.universe._forcefield, None, None, None, None) eval.key = evaluator_key self.top.universe._evaluator[(None, None, None)] = eval self._evaluators[evaluator_key] = eval
def energyTerms(self, confs, E=None, process='CD'): """Calculates energy terms for a series of configurations Units are kJ/mol. Parameters ---------- confs : list of np.array Configurations E : dict of np.array Dictionary to add to process : str Process, either 'BC' or 'CD' Returns ------- E : dict of np.array Dictionary of energy terms """ if E is None: E = {} params_full = self.paramsFromAlpha(alpha=1.0, process=process, site=(process == 'CD')) if process == 'CD': for scalable in scalables: params_full[scalable] = 1 self.setParams(params_full) # Molecular mechanics and grid interaction energies E['MM'] = np.zeros(len(confs), dtype=float) if process == 'BC': if 'OBC' in params_full.keys(): E['OBC'] = np.zeros(len(confs), dtype=float) if process == 'CD': for term in (scalables): E[term] = np.zeros(len(confs), dtype=float) if self.isForce('site'): E['site'] = np.zeros(len(confs), dtype=float) if self.isForce('InternalRestraint'): E['k_angular_int'] = np.zeros(len(confs), dtype=float) if self.isForce('ExternalRestraint'): E['k_angular_ext'] = np.zeros(len(confs), dtype=float) E['k_spatial_ext'] = np.zeros(len(confs), dtype=float) for c in range(len(confs)): self.top.universe.setConfiguration( Configuration(self.top.universe, confs[c])) eT = self.top.universe.energyTerms() for (key, value) in eT.iteritems(): if key == 'electrostatic': pass # For some reason, MMTK double-counts electrostatic energies elif key.startswith('pose'): # For pose restraints, the energy is per spring constant unit E[term_map[key]][c] += value / params_full[term_map[key]] else: try: E[term_map[key]][c] += value except KeyError: print key print 'Keys in eT', eT.keys() print 'Keys in term map', term_map.keys() print 'Keys in E', E.keys() raise Exception('key not found in term map or E') return E
def __call__(self, **options): # Process the keyword arguments self.setCallOptions(options) # Check if the universe has features not supported by the integrator Features.checkFeatures(self, self.universe) RT = R * self.getOption('T') delta_t = self.getOption('delta_t') if 'steps_per_trial' in self.call_options.keys(): steps_per_trial = self.getOption('steps_per_trial') ntrials = self.getOption('steps') / steps_per_trial else: steps_per_trial = self.getOption('steps') ntrials = 1 if 'max_diff' in self.call_options.keys(): max_diff = self.getOption('max_diff') else: max_diff = 1000. if 'normalize' in self.call_options.keys(): normalize = self.getOption('normalize') else: normalize = False # Seed the random number generator if 'random_seed' in self.call_options.keys(): np.random.seed(self.getOption('random_seed')) # Get the universe variables needed by the integrator masses = self.universe.masses() fixed = self.universe.getAtomBooleanArray('fixed') nt = self.getOption('threads') comm = self.getOption('mpi_communicator') evaluator = self.universe.energyEvaluator(threads=nt, mpi_communicator=comm) evaluator = evaluator.CEvaluator() late_args = (masses.array, fixed.array, evaluator, N.zeros((0, 2), N.Int), N.zeros( (0, ), N.Float), N.zeros((1, ), N.Int), N.zeros((0, ), N.Float), N.zeros( (2, ), N.Float), N.zeros( (0, ), N.Float), N.zeros((1, ), N.Float), delta_t, self.getOption('first_step'), steps_per_trial, self.getActions(), 'Velocity Verlet step') xs = [] energies = [] # Store initial configuration and potential energy xo = np.copy(self.universe.configuration().array) pe_o = self.universe.energy() acc = 0 for t in range(ntrials): # Initialize the velocity self.universe.initializeVelocitiesToTemperature( self.getOption('T')) # Store total energy eo = pe_o + self.universe.kineticEnergy() # Run the velocity verlet integrator self.run(MMTK_dynamics.integrateVV, (self.universe, self.universe.configuration().array, self.universe.velocities().array) + late_args) # Decide whether to accept the move pe_n = self.universe.energy() en = pe_n + self.universe.kineticEnergy() diff = np.abs(en - eo) if (not np.isnan(en)) and (diff < max_diff): xo = np.copy(self.universe.configuration().array) pe_o = pe_n acc += 1 if normalize: self.universe.normalizePosition() else: # print diff self.universe.setConfiguration(Configuration( self.universe, xo)) xs.append(np.copy(self.universe.configuration().array)) energies.append(pe_o) return (xs, energies, acc, ntrials, delta_t)
def _prepare_ligand_BC(self): """Prepares the ligand for BC simulations Returns ------- seeds : list of np.array Ligand configurations minimized in milestone B """ if self.data['BC'].protocol == []: # Set up the force field params_o = self.system.paramsFromAlpha(1.0, 'BC', site=False) self.system.setParams(params_o) # Get starting configurations basename = os.path.basename(self.args.FNs['score']) basename = basename[:basename.find('.')] dirname = os.path.dirname(self.args.FNs['score']) minimizedB_FN = os.path.join(dirname, basename + '_minB.nc') if os.path.isfile(minimizedB_FN): from netCDF4 import Dataset dock6_nc = Dataset(minimizedB_FN, 'r') minimizedConfigurations = [ dock6_nc.variables['confs'][n][ self.top.inv_prmtop_atom_order_L, :] for n in range(dock6_nc.variables['confs'].shape[0]) ] Es = dict([(key, dock6_nc.variables[key][:]) for key in dock6_nc.variables.keys() if key != 'confs']) dock6_nc.close() else: (minimizedConfigurations, Es) = self._get_confs_to_rescore(site=False, minimize=True) from netCDF4 import Dataset dock6_nc = Dataset(minimizedB_FN, 'w') dock6_nc.createDimension('n_confs', len(minimizedConfigurations)) dock6_nc.createDimension('n_atoms', minimizedConfigurations[0].shape[0]) dock6_nc.createDimension('n_cartesian', 3) dock6_nc.createDimension('one', 1) dock6_nc.createVariable('confs', 'f8', ('n_confs', 'n_atoms', 'n_cartesian')) for n in range(len(minimizedConfigurations)): dock6_nc.variables['confs'][n] = minimizedConfigurations[ n][self.top.prmtop_atom_order_L, :] for key in Es.keys(): dock6_nc.createVariable(key, 'f8', ('one', 'n_confs')) dock6_nc.variables[key][:] = Es[key] dock6_nc.close() # initializes smart darting for BC # and sets the universe to the lowest energy configuration self.iterator.initializeSmartDartingConfigurations( minimizedConfigurations, 'BC', self.log, self.data) if len(minimizedConfigurations) > 0: self.top.universe.setConfiguration( Configuration(self.top.universe, minimizedConfigurations[-1])) self.data['BC'].confs['starting_poses'] = minimizedConfigurations # Ramp the temperature from 0 to the desired starting temperature using HMC self._ramp_T(params_o['T'], normalize=True) # Run at starting temperature seeds = [np.copy(self.top.universe.configuration().array) \ for n in range(self.args.params['BC']['seeds_per_state'])] else: seeds = None return seeds
def _ramp_T(self, T_START, T_LOW=20., normalize=False): """Ramp the temperature from T_LOW to T_START Parameters ---------- T_START : float The final temperature T_LOW : float The lowest temperature in the ramp normalize : bool If True, the ligand center of mass will be normalized """ self.log.recordStart('T_ramp') # First minimize the energy from MMTK.Minimization import SteepestDescentMinimizer # @UnresolvedImport minimizer = SteepestDescentMinimizer(self.top.universe) original_stderr = sys.stderr sys.stderr = NullDevice() # Suppresses warnings for minimization x_o = np.copy(self.top.universe.configuration().array) e_o = self.top.universe.energy() for rep in range(5000): minimizer(steps=10) x_n = np.copy(self.top.universe.configuration().array) e_n = self.top.universe.energy() diff = abs(e_o - e_n) if np.isnan(e_n) or diff < 0.05 or diff > 1000.: self.top.universe.setConfiguration( Configuration(self.top.universe, x_o)) break else: x_o = x_n e_o = e_n sys.stderr = original_stderr self.log.tee(" minimized to %.3g kcal/mol over %d steps" % (e_o, 10 * (rep + 1))) # Then ramp the energy to the starting temperature from AlGDock.Integrators.HamiltonianMonteCarlo.HamiltonianMonteCarlo \ import HamiltonianMonteCarloIntegrator sampler = HamiltonianMonteCarloIntegrator(self.top.universe) e_o = self.top.universe.energy() T_LOW = 20. T_SERIES = T_LOW * (T_START / T_LOW)**(np.arange(30) / 29.) for T in T_SERIES: delta_t = 2.0 * MMTK.Units.fs steps_per_trial = 10 attempts_left = 10 while attempts_left > 0: random_seed = int(T*10000) + attempts_left + \ int(self.top.universe.configuration().array[0][0]*10000) if self.args.random_seed == 0: random_seed += int(time.time() * 1000) random_seed = random_seed % 32767 (xs, energies, acc, ntrials, delta_t) = \ sampler(steps = 2500, steps_per_trial = 10, T=T,\ delta_t=delta_t, random_seed=random_seed) attempts_left -= 1 acc_rate = float(acc) / ntrials if acc_rate < 0.4: delta_t -= 0.25 * MMTK.Units.fs else: attempts_left = 0 if delta_t < 0.1 * MMTK.Units.fs: delta_t = 0.1 * MMTK.Units.fs steps_per_trial = max(int(steps_per_trial / 2), 1) fmt = " T = %d, delta_t = %.3f fs, steps_per_trial = %d, acc_rate = %.3f" if acc_rate < 0.01: print self.top.universe.energyTerms() self.log.tee(fmt % (T, delta_t * 1000, steps_per_trial, acc_rate)) if normalize: self.top.universe.normalizePosition() e_f = self.top.universe.energy() self.log.tee(" ramped temperature from %d to %d K in %s, "%(\ T_LOW, T_START, HMStime(self.log.timeSince('T_ramp'))) + \ "changing energy to %.3g kcal/mol\n"%(e_f))
def iteration(self, seed, process, params_k, \ initialize=False, reference=0): """Performs an iteration for a single thermodynamic state Parameters ---------- seed : np.array Starting configuration process : str Process, either 'BC' or 'CD' params_k : dict of float Parameters describing a thermodynamic state """ self.top.universe.setConfiguration( Configuration(self.top.universe, seed)) self.system.setParams(params_k) if 'delta_t' in params_k.keys(): delta_t = params_k['delta_t'] else: raise Exception('No time step specified') if 'steps_per_trial' in params_k.keys(): steps_per_trial = params_k['steps_per_trial'] else: steps_per_trial = self.args.params[process]['steps_per_sweep'] if initialize: steps = self.args.params[process]['steps_per_seed'] ndarts = self.args.params[process]['darts_per_seed'] else: steps = self.args.params[process]['steps_per_sweep'] ndarts = self.args.params[process]['darts_per_sweep'] random_seed = reference * reference + int(abs(seed[0][0] * 10000)) if self.args.random_seed > 0: random_seed += self.args.random_seed else: random_seed += int(time.time() * 1000) results = {} # Execute external MCMC moves if (process == 'CD') and (self.args.params['CD']['MCMC_moves']>0) \ and (params_k['alpha'] < 0.1) and (self.args.params['CD']['pose']==-1): time_start_ExternalMC = time.time() dat = self._samplers['ExternalMC'](ntrials=5, T=params_k['T']) results['acc_ExternalMC'] = dat[2] results['att_ExternalMC'] = dat[3] results['time_ExternalMC'] = (time.time() - time_start_ExternalMC) # Execute dynamics sampler time_start_sampler = time.time() dat = self._samplers[process](\ steps=steps, steps_per_trial=steps_per_trial, \ T=params_k['T'], delta_t=delta_t, \ normalize=(process=='BC'), adapt=initialize, random_seed=random_seed) results['acc_Sampler'] = dat[2] results['att_Sampler'] = dat[3] results['delta_t'] = dat[4] results['time_Sampler'] = (time.time() - time_start_sampler) # Execute smart darting if (ndarts > 0) and not ((process == 'CD') and (params_k['alpha'] < 0.1)): time_start_SmartDarting = time.time() dat = self._samplers[process+'_SmartDarting'](\ ntrials=ndarts, T=params_k['T'], random_seed=random_seed+5) results['acc_SmartDarting'] = dat[2] results['att_SmartDarting'] = dat[3] results['time_SmartDarting'] = (time.time() - time_start_SmartDarting) # Store and return results results['confs'] = np.copy(dat[0][-1]) results['Etot'] = dat[1][-1] results['reference'] = reference return results
def do_gMC(nr_attempts, BAT_converter, state_indices_to_swap, torsion_threshold): """ Assume self.top.universe, confs, protocol, state_inds, inv_state_inds exist as global variables when the function is called. If at least one of the torsions in the combination chosen for an crossover attempt changes more than torsion_threshold, the crossover will be attempted. The function will update confs. It returns the number of attempts and the number of accepted moves. """ if nr_attempts < 0: raise Exception('Number of attempts must be nonnegative!') if torsion_threshold < 0.: raise Exception('Torsion threshold must be nonnegative!') # if len(BAT_converter.BAT_to_crossover) == 0: return 0., 0. # from random import randrange # get reduced energies and BAT for all configurations in confs BATs = [] energies = np.zeros(K, dtype=float) for c_ind in range(K): s_ind = state_inds[c_ind] self.top.universe.setConfiguration( Configuration(self.top.universe, confs[c_ind])) BATs.append(np.array(BAT_converter.BAT(extended=True), dtype=float)) self.system.setParams(protocol[s_ind]) reduced_e = self.top.universe.energy() / (R * protocol[s_ind]['T']) energies[c_ind] = reduced_e # nr_sets_of_torsions = len(BAT_converter.BAT_to_crossover) # attempt_count, acc_count = 0, 0 sweep_count = 0 while True: sweep_count += 1 if (sweep_count * K) > (1000 * nr_attempts): self.log.tee( ' GMC Sweep too many times, but few attempted. Consider reducing torsion_threshold.' ) return attempt_count, acc_count # for state_pair in state_indices_to_swap: conf_ind_k0 = inv_state_inds[state_pair[0]] conf_ind_k1 = inv_state_inds[state_pair[1]] # check if it should attempt for this pair of states ran_set_torsions = BAT_converter.BAT_to_crossover[randrange( nr_sets_of_torsions)] do_crossover = np.any( np.abs(BATs[conf_ind_k0][ran_set_torsions] - BATs[conf_ind_k1][ran_set_torsions]) >= torsion_threshold) if do_crossover: attempt_count += 1 # BAT and reduced energies before crossover BAT_k0_be = copy.deepcopy(BATs[conf_ind_k0]) BAT_k1_be = copy.deepcopy(BATs[conf_ind_k1]) e_k0_be = energies[conf_ind_k0] e_k1_be = energies[conf_ind_k1] # BAT after crossover BAT_k0_af = copy.deepcopy(BAT_k0_be) BAT_k1_af = copy.deepcopy(BAT_k1_be) for index in ran_set_torsions: tmp = BAT_k0_af[index] BAT_k0_af[index] = BAT_k1_af[index] BAT_k1_af[index] = tmp # Cartesian coord and reduced energies after crossover. BAT_converter.Cartesian(BAT_k0_af) self.system.setParams(protocol[state_pair[0]]) e_k0_af = self.top.universe.energy() / ( R * protocol[state_pair[0]]['T']) conf_k0_af = copy.deepcopy(self.top.universe.configuration().array) # BAT_converter.Cartesian(BAT_k1_af) self.system.setParams(protocol[state_pair[1]]) e_k1_af = self.top.universe.energy() / ( R * protocol[state_pair[1]]['T']) conf_k1_af = copy.deepcopy(self.top.universe.configuration().array) # de = (e_k0_be - e_k0_af) + (e_k1_be - e_k1_af) # update confs, energies, BATS if (de > 0) or (np.random.uniform() < np.exp(de)): acc_count += 1 confs[conf_ind_k0] = conf_k0_af confs[conf_ind_k1] = conf_k1_af # energies[conf_ind_k0] = e_k0_af energies[conf_ind_k1] = e_k1_af # BATs[conf_ind_k0] = BAT_k0_af BATs[conf_ind_k1] = BAT_k1_af # if attempt_count == nr_attempts: return attempt_count, acc_count
def _set_configuration(self, universe, conf_array): universe.setConfiguration(Configuration(universe, conf_array)) return None