def __init__(self, topology=None, system=None, pbc=False, platform='CUDA'): from .md import MD from .quench import Quench from .move import Move from .distance import Distance from .acceptance import Acceptance if topology is None: raise ValueError('topology is needed') if system is None: raise ValueError('system is needed') integrator = LangevinIntegrator(0 * u.kelvin, 1.0 / u.picoseconds, 2.0 * u.femtoseconds) #integrator.setConstraintTolerance(0.00001) if platform == 'CUDA': platform = Platform.getPlatformByName('CUDA') properties = {'CudaPrecision': 'mixed'} elif platform == 'CPU': platform = Platform.getPlatformByName('CPU') properties = {} self.topology = topology self.context = Context(system, integrator, platform, properties) self.n_atoms = msm.get(self.context, target='system', n_atoms=True) self.n_dof = 0 for i in range(system.getNumParticles()): if system.getParticleMass(i) > 0 * u.dalton: self.n_dof += 3 for i in range(system.getNumConstraints()): p1, p2, distance = system.getConstraintParameters(i) if system.getParticleMass( p1) > 0 * u.dalton or system.getParticleMass( p2) > 0 * u.dalton: self.n_dof -= 1 if any( type(system.getForce(i)) == CMMotionRemover for i in range(system.getNumForces())): self.n_dof -= 3 self.pbc = pbc if self.pbc: raise NotImplementedError self.md = MD(self) self.quench = Quench(self) self.move = Move(self) self.distance = Distance(self) self.acceptance = Acceptance(self)
def test_xtc_reporter_append(tmpdir, get_fn): pdb = PDBFile(get_fn('native.pdb')) forcefield = ForceField('amber99sbildn.xml', 'amber99_obc.xml') # NO PERIODIC BOUNDARY CONDITIONS system = forcefield.createSystem(pdb.topology, nonbondedMethod=CutoffNonPeriodic, nonbondedCutoff=1.0 * nanometers, constraints=HBonds, rigidWater=True) integrator = LangevinIntegrator(300 * kelvin, 1.0 / picoseconds, 2.0 * femtoseconds) integrator.setConstraintTolerance(0.00001) platform = Platform.getPlatformByName('Reference') simulation = Simulation(pdb.topology, system, integrator, platform) simulation.context.setPositions(pdb.positions) simulation.context.setVelocitiesToTemperature(300 * kelvin) tmpdir = str(tmpdir) xtcfile = os.path.join(tmpdir, 'traj.xtc') xtcfile_cp = os.path.join(tmpdir, 'traj_cp.xtc') checkpoint = os.path.join(tmpdir, 'checkpoint.chk') reporter = XTCReporter(xtcfile, 2) simulation.reporters.append(reporter) simulation.reporters.append(CheckpointReporter(checkpoint, 10)) simulation.step(10) reporter.close() shutil.copyfile(xtcfile, xtcfile_cp) system = forcefield.createSystem(pdb.topology, nonbondedMethod=CutoffNonPeriodic, nonbondedCutoff=1.0 * nanometers, constraints=HBonds, rigidWater=True) integrator = LangevinIntegrator(300 * kelvin, 1.0 / picoseconds, 2.0 * femtoseconds) integrator.setConstraintTolerance(0.00001) platform = Platform.getPlatformByName('Reference') simulation = Simulation(pdb.topology, system, integrator, platform) simulation.loadCheckpoint(checkpoint) reporter = XTCReporter(xtcfile, 2, append=True) simulation.reporters.append(reporter) simulation.step(10) reporter.close() xtc_traj = md.load(xtcfile, top=get_fn('native.pdb')) xtc_traj_cp = md.load(xtcfile_cp, top=get_fn('native.pdb')) eq(xtc_traj.xyz[:5], xtc_traj_cp.xyz) eq(xtc_traj.n_frames, 10) eq(xtc_traj_cp.n_frames, 5) eq(xtc_traj.time[:5], xtc_traj_cp.time)
def setup_platform_with_resources(compute_resources): """Creates an OpenMM `Platform` object which requests a set amount of compute resources (e.g with a certain number of cpus). Parameters ---------- compute_resources: ComputeResources Returns ------- Platform The created platform """ from simtk.openmm import Platform # Setup the requested platform: if compute_resources.number_of_gpus > 0: # A platform which runs on GPUs has been requested. platform_name = 'CUDA' if compute_resources.preferred_gpu_toolkit == 'CUDA' else 'OpenCL' # noinspection PyCallByClass,PyTypeChecker platform = Platform.getPlatformByName(platform_name) if compute_resources.gpu_device_indices is not None: property_platform_name = platform_name if compute_resources.preferred_gpu_toolkit == 'CUDA': property_platform_name = platform_name.lower().capitalize() platform.setPropertyDefaultValue( property_platform_name + 'DeviceIndex', compute_resources.gpu_device_indices) logging.info('Setting up an openmm platform on GPU {}'.format( compute_resources.gpu_device_indices or 0)) else: # noinspection PyCallByClass,PyTypeChecker platform = Platform.getPlatformByName('CPU') platform.setPropertyDefaultValue( 'Threads', str(compute_resources.number_of_threads)) logging.info('Setting up a simulation with {} threads'.format( compute_resources.number_of_threads)) return platform
def get_potential_energy(item, coordinates=None, platform_name='CUDA'): from simtk.openmm import LangevinIntegrator, Platform, Context from simtk import unit import numpy as np integrator = LangevinIntegrator(0.0 * unit.kelvin, 0.0 / unit.picoseconds, 2.0 * unit.femtoseconds) platform = Platform.getPlatformByName(platform_name) context = Context(item.system, integrator, platform) if coordinates is None: context.setPositions(item.coordinates) else: context.setPositions(coordinates) if item.box is not None: context.setPeriodicBoxVectors(item.box[0], item.box[1], item.box[2]) state = context.getState(getEnergy=True) potential_energy = state.getPotentialEnergy() return potential_energy
def energy_minimization(item, platform_name='CUDA', verbose=True): from simtk.openmm import LangevinIntegrator, Platform, Context, LocalEnergyMinimizer_minimize from simtk import unit # Integrator. integrator = LangevinIntegrator(0 * unit.kelvin, 1.0 / unit.picoseconds, 2.0 * unit.femtoseconds) # Platform. platform = Platform.getPlatformByName(platform_name) # Context. context = Context(item.system, integrator, platform) context.setPositions(item.coordinates) # Minimization. if verbose == True: energy = context.getState(getEnergy=True).getPotentialEnergy() print('Potential energy before minimization: {}'.format(energy)) LocalEnergyMinimizer_minimize(context) if verbose == True: energy = context.getState(getEnergy=True).getPotentialEnergy() print('Potential energy after minimization: {}'.format(energy)) item.coordinates = context.getState(getPositions=True).getPositions( asNumpy=True) pass
def _prep_sim(self, coords, external_forces=[]): try: from simtk.openmm import Platform, LangevinIntegrator, Vec3 from simtk.openmm.app import Modeller, ForceField, \ CutoffNonPeriodic, PME, Simulation, HBonds from simtk.unit import angstrom, nanometers, picosecond, \ kelvin, Quantity, molar except ImportError: raise ImportError( 'Please install PDBFixer and OpenMM in order to use ClustENM.') positions = Quantity([Vec3(*xyz) for xyz in coords], angstrom) modeller = Modeller(self._topology, positions) if self._sol == 'imp': forcefield = ForceField(*self._force_field) system = forcefield.createSystem(modeller.topology, nonbondedMethod=CutoffNonPeriodic, nonbondedCutoff=1.0 * nanometers, constraints=HBonds) if self._sol == 'exp': forcefield = ForceField(*self._force_field) modeller.addSolvent(forcefield, padding=self._padding * nanometers, ionicStrength=self._ionicStrength * molar) system = forcefield.createSystem(modeller.topology, nonbondedMethod=PME, nonbondedCutoff=1.0 * nanometers, constraints=HBonds) for force in external_forces: system.addForce(force) integrator = LangevinIntegrator(self._temp * kelvin, 1 / picosecond, 0.002 * picosecond) # precision could be mixed, but single is okay. platform = self._platform if self._platform is None else Platform.getPlatformByName( self._platform) properties = None if self._platform is None: properties = {'Precision': 'single'} elif self._platform in ['CUDA', 'OpenCL']: properties = {'Precision': 'single'} simulation = Simulation(modeller.topology, system, integrator, platform, properties) simulation.context.setPositions(modeller.positions) return simulation
def run(self): """Run the process: set positions and compute energies and forces. Positions and box vectors are received from the task_queue in units of nanometers. Energies and forces are pushed to the result_queue in units of kJ/mole and kJ/mole/nm, respectively. """ from simtk import unit from simtk.openmm import Platform, Context # create the context # it is crucial to do that in the run function and not in the constructor # for some reason, the CPU platform hangs if the context is created in the constructor # see also https://github.com/openmm/openmm/issues/2602 openmm_platform = Platform.getPlatformByName(self._openmm_platform_name) self._openmm_context = Context( self._openmm_system, self._openmm_integrator, openmm_platform, self._openmm_platform_properties ) self._openmm_context.reinitialize(preserveState=True) # get tasks from the task queue for task in iter(self._task_queue.get, None): (index, positions, box_vectors, evaluate_energy, evaluate_force, evaluate_positions, evaluate_path_probability_ratio, err_handling, n_simulation_steps) = task try: # initialize state self._openmm_context.setPositions(positions) if box_vectors is not None: self._openmm_context.setPeriodicBoxVectors(box_vectors) log_path_probability_ratio = self._openmm_integrator.step(n_simulation_steps) # compute energy and forces state = self._openmm_context.getState( getEnergy=evaluate_energy, getForces=evaluate_force, getPositions=evaluate_positions ) energy = state.getPotentialEnergy().value_in_unit(unit.kilojoule_per_mole) if evaluate_energy else None forces = ( state.getForces(asNumpy=True).value_in_unit(unit.kilojoule_per_mole / unit.nanometer) if evaluate_force else None ) new_positions = state.getPositions().value_in_unit(unit.nanometers) if evaluate_positions else None except Exception as e: if err_handling == "warning": warnings.warn("Suppressed exception: {}".format(e)) elif err_handling == "exception": raise e # push energies and forces to the results queue self._result_queue.put( [index, energy, forces, new_positions, log_path_probability_ratio] )
def create_simulation(self, topology, system): self.integrator = self.create_integrator(system) if self.platform is None: simulation = Simulation(topology, system, self.integrator) else: platform = Platform.getPlatformByName(self.platform) simulation = Simulation(topology, system, self.integrator, platform) for reporter in self.reporters: simulation.reporters.append(reporter) return simulation
def _initialize_simulation(self): if self._initialized: self._integrator.setTemperature(self._temperature) if self._options.softcore: print self._sc_lambda_lj self._simulation.context.setParameter('qq_lambda', self._sc_lambda_coulomb) self._simulation.context.setParameter('lj_lambda', self._sc_lambda_lj) self._simulation.context.setParameter('sc_lambda', self._sc_lambda_lj) logger.debug('set sc %d %f %f %f', self._rank, self._sc_lambda_coulomb, self._sc_lambda_lj, self._sc_lambda_lj) meld_rests = _update_always_active_restraints(self._always_on_restraints, self._alpha, self._timestep, self._force_dict) _update_selectively_active_restraints(self._selectable_collections, meld_rests, self._alpha, self._timestep, self._force_dict) for force in self._force_dict.values(): if force: force.updateParametersInContext(self._simulation.context) else: self._initialized = True # we need to set the whole thing from scratch prmtop = _parm_top_from_string(self._parm_string) sys = _create_openmm_system(prmtop, self._options.cutoff, self._options.use_big_timestep, self._options.use_bigger_timestep, self._options.implicit_solvent_model, self._options.remove_com) if self._options.softcore: sys = softcore.add_soft_core(sys) if self._options.use_amap: adder = cmap.CMAPAdder(self._parm_string, self._options.amap_alpha_bias, self._options.amap_beta_bias, self._options.ccap, self._options.ncap) adder.add_to_openmm(sys) meld_rests = _add_always_active_restraints(sys, self._always_on_restraints, self._alpha, self._timestep, self._force_dict) _add_selectively_active_restraints(sys, self._selectable_collections, meld_rests, self._alpha, self._timestep, self._force_dict) self._integrator = _create_integrator(self._temperature, self._options.use_big_timestep,self._options.use_bigger_timestep) platform = Platform.getPlatformByName('CUDA') properties = {'CudaDeviceIndex': str(self._device_id)} self._simulation = _create_openmm_simulation(prmtop.topology, sys, self._integrator, platform, properties) if self._options.softcore: self._simulation.context.setParameter('qq_lambda', self._sc_lambda_coulomb) self._simulation.context.setParameter('lj_lambda', self._sc_lambda_lj) self._simulation.context.setParameter('sc_lambda', self._sc_lambda_lj) logger.debug('set sc %d %f %f %f', self._rank, self._sc_lambda_coulomb, self._sc_lambda_lj, self._sc_lambda_lj)
def __init__(self, system, integrator=None): # if strings are passed in, assume that they are paths to # xml files on disk if isinstance(system, basestring): with open(system) as f: system = XmlSerializer.deserialize(f.read()) if isinstance(integrator, basestring): with open(integrator) as f: integrator = XmlSerializer.deserialize(f.read()) if integrator is None: # this integrator isn't really necessary, but it has to be something # for the openmm API to let us serialize the state integrator = VerletIntegrator(2*femtoseconds) self.context = Context(system, integrator, Platform.getPlatformByName('Reference'))
def get_platform(platform_name): if platform_name == 'fastest': platform = None else: # TODO file access control attempt = 0 retries = 500 while True: try: platform = Platform.getPlatformByName(platform_name) return platform except IndexError as e: if attempt < retries: attempt += 1 time.sleep(5 * random.random()) else: raise e
def __init__(self, system, integrator=None): # if strings are passed in, assume that they are paths to # xml files on disk if isinstance(system, basestring): with open(system) as f: system = XmlSerializer.deserialize(f.read()) if isinstance(integrator, basestring): with open(integrator) as f: integrator = XmlSerializer.deserialize(f.read()) if integrator is None: # this integrator isn't really necessary, but it has to be something # for the openmm API to let us serialize the state integrator = VerletIntegrator(2 * femtoseconds) self.context = Context(system, integrator, Platform.getPlatformByName('Reference'))
def calculate_fragment_energetics(frag_no=1): """ * Create an OpenMM system with a fragment. * Calculate the energy of the system and print. :param frag_no: The number of the fragment being analysed (used to access files). """ os.chdir(f'group2/frag{frag_no}') # Necessary due to size of calculation sys.setrecursionlimit(15000) pdb = PDBFile(f'QUBE_pro_frag{frag_no}.pdb') forcefield = ForceField(f'QUBE_pro_frag{frag_no}_plus.xml') system = forcefield.createSystem( pdb.topology, nonbondedMethod=NoCutoff, ) system = apply_opls_combo(system) with open(f'QUBE_pro_frag{frag_no}_out.xml', 'w') as outfile: serialized_system = XmlSerializer.serialize(system) outfile.write(serialized_system) # Create the integrator to do Langevin dynamics integrator = LangevinIntegrator( 298.15 * unit.kelvin, # Temperature of heat bath 1.0 / unit.picoseconds, # Friction coefficient 2.0 * unit.femtoseconds, # Time step ) platform = Platform.getPlatformByName('CPU') simulation = Simulation(pdb.topology, system, integrator, platform) simulation.context.setPositions(pdb.positions) print('energy from openmm library') print(simulation.context.getState(getEnergy=True).getPotentialEnergy()) structure = parmed.load_file(f'QUBE_pro_frag{frag_no}.pdb') energy_comps = parmed.openmm.energy_decomposition_system(structure, system) total_energy = 0.0 for comp in energy_comps: total_energy += comp[1] print(*comp) print(f'Total energy {total_energy: 6.6f}')
def get_platform(platform_name): attempt = 0 retries = 10 if platform_name == 'fastest': platform = None else: while True: try: platform = Platform.getPlatformByName(platform_name) return platform #except IndexError as e: except Exception as e: if attempt < retries: attempt += 1 time.sleep(5 * random.random()) else: raise e
) system = apply_opls_combo(system, switching_distance=496.0 * unit.angstroms) with open('QUBE_pro_out.xml', 'w') as outfile: serialized_system = XmlSerializer.serialize(system) outfile.write(serialized_system) # Create the integrator to do Langevin dynamics integrator = LangevinIntegrator( 298.15 * unit.kelvin, # Temperature of heat bath 1.0 / unit.picoseconds, # Friction coefficient 2.0 * unit.femtoseconds, # Time step ) platform = Platform.getPlatformByName('CPU') simulation = app.Simulation(pdb.topology, system, integrator, platform) simulation.context.setPositions(pdb.positions) print('energy from openmm library') print(simulation.context.getState(getEnergy=True).getPotentialEnergy()) # platform.setPropertyValue(simulation.context, property='Precision', value='double') # Minimize the energy # print('Minimizing energy') # Minimize(simulation, iters=0) structure = parmed.load_file('QUBE_pro.pdb') energy_comps = parmed.openmm.energy_decomposition_system(structure, system) total_energy = 0.0
membrane_barostat = MonteCarloMembraneBarostat( 1 * bar, 0.0 * bar * nanometer, 308 * kelvin, MonteCarloMembraneBarostat.XYIsotropic, MonteCarloMembraneBarostat.ZFree, 15) system_generator = SystemGenerator( forcefields=['amber/lipid17.xml', 'amber/tip3p_standard.xml'], small_molecule_forcefield='gaff-2.11', barostat=membrane_barostat, forcefield_kwargs=forcefield_kwargs, periodic_forcefield_kwargs=periodic_forcefield_kwargs) system = system_generator.create_system(pdb.topology, molecules=molecule) integrator = LangevinIntegrator(300 * kelvin, 1 / picosecond, 0.002 * picosecond) platform = Platform.getPlatformByName('CUDA') simulation = app.Simulation(pdb.topology, system, integrator, platform) simulation.context.setPositions(pdb.positions) simulation.loadState('parent.xml') simulation.reporters.append( StateDataReporter('seg.nfo', 5000, step=True, potentialEnergy=True, kineticEnergy=True, temperature=True)) simulation.reporters.append(HDF5Reporter('seg.h5', 10000)) simulation.step(50000) simulation.saveState('seg.xml')
def _initialize_simulation(self): if self._initialized: # update temperature and pressure self._integrator.setTemperature(self._temperature) if self._options.enable_pressure_coupling: self._simulation.context.setParameter( self._barostat.Temperature(), self._temperature) # update all of the system transformers self._transformers_update() else: # we need to set the whole thing from scratch self._initialized = True prmtop = _parm_top_from_string(self._parm_string) # create parameter objects pme_params = PMEParams(enable=self._options.enable_pme, tolerance=self._options.pme_tolerance) pcouple_params = PressureCouplingParams( enable=self._options.enable_pressure_coupling, temperature=self._temperature, pressure=self._options.pressure, steps=self._options.pressure_coupling_update_steps) # build the system sys, barostat = _create_openmm_system( prmtop, self._options.solvation, self._options.cutoff, self._options.use_big_timestep, self._options.use_bigger_timestep, self._options.implicit_solvent_model, pme_params, pcouple_params, self._options.remove_com, self._temperature) self._barostat = barostat if self._options.use_amap: adder = cmap.CMAPAdder(self._parm_string, self._options.amap_alpha_bias, self._options.amap_beta_bias, self._options.ccap, self._options.ncap) adder.add_to_openmm(sys) # setup the transformers self._transformers_setup() if len(self._always_on_restraints) > 0: print('Not all always on restraints were handled.') for r in self._always_on_restraints: print('\t', r) raise RuntimeError( 'Not all always on restraints were handled.') if len(self._selectable_collections) > 0: print('Not all selectable restraints were handled.') for r in self._selectable_collections: print('\t', r) raise RuntimeError( 'Not all selectable restraints were handled.') sys = self._transformers_add_interactions(sys, prmtop.topology) self._transformers_finalize(sys, prmtop.topology) # create the integrator self._integrator = _create_integrator( self._temperature, self._options.use_big_timestep, self._options.use_bigger_timestep) # setup the platform platform = Platform.getPlatformByName('CUDA') properties = { 'CudaDeviceIndex': str(self._device_id), 'CudaPrecision': 'mixed' } # create the simulation object self._simulation = _create_openmm_simulation( prmtop.topology, sys, self._integrator, platform, properties) self._transformers_update()
def platform(name): from simtk.openmm import Platform return Platform.getPlatformByName(name)
def calculate_protein_energetics(): """ * Create an OpenMM system using the first fragment. * Add each fragment into the system. * Calculate the energy of the system and print. """ os.chdir('group2') # Necessary due to size of calculation sys.setrecursionlimit(15000) frag1 = PDBFile('frag1/no_QUP_frag1.pdb') forcefield = ForceField( 'frag1/QUBE_pro_frag1.xml', 'frag2/QUBE_pro_frag2_plus.xml', 'frag3/QUBE_pro_frag3_plus.xml', 'frag4/QUBE_pro_frag4_plus.xml', ) modeller = Modeller(frag1.topology, frag1.positions) frag2 = PDBFile('frag2/no_QUP_frag2.pdb') modeller.add(frag2.topology, frag2.positions) frag3 = PDBFile('frag3/no_QUP_frag3.pdb') modeller.add(frag3.topology, frag3.positions) frag4 = PDBFile('frag4/no_QUP_frag4.pdb') modeller.add(frag4.topology, frag4.positions) system = forcefield.createSystem( modeller.topology, nonbondedMethod=NoCutoff, ) system = apply_opls_combo(system) integrator = LangevinIntegrator( 298.15 * unit.kelvin, # Temperature of heat bath 1.0 / unit.picoseconds, # Friction coefficient 2.0 * unit.femtoseconds, # Time step ) platform = Platform.getPlatformByName('CPU') simulation = Simulation(modeller.topology, system, integrator, platform) simulation.context.setPositions(modeller.positions) print('energy from openmm library') print(simulation.context.getState(getEnergy=True).getPotentialEnergy()) positions = simulation.context.getState(getPositions=True).getPositions() with open('output.pdb', 'w') as out_file: PDBFile.writeFile(simulation.topology, positions, out_file) structure = parmed.load_file('output.pdb') energy_comps = parmed.openmm.energy_decomposition_system(structure, system) total_energy = 0.0 for comp in energy_comps: total_energy += comp[1] print(*comp) print(f'Total energy {total_energy: 6.6f}')
def simulate(self, header, content): """Main method that is "executed" by the receipt of the msg_type == 'simulate' message from the server. We run some OpenMM dynamics, and then send back the results. """ self.log.info('Setting up simulation...') state, topology = self.deserialize_input(content) # set the GPU platform platform = Platform.getPlatformByName(str(self.platform)) if self.platform == 'CUDA': properties = {'CudaPrecision': 'mixed', 'CudaDeviceIndex': str(self.device_index) } elif self.platform == 'OpenCL': properties = {'OpenCLPrecision': 'mixed', 'OpenCLDeviceIndex': str(self.device_index) } else: properties = None simulation = Simulation(topology, self.system, self.integrator, platform, properties) # do the setup self.set_state(state, simulation) self.sanity_check(simulation) if self.minimize: self.log.info('minimizing...') simulation.minimizeEnergy() if self.random_initial_velocities: try: temp = simulation.integrator.getTemperature() simulation.context.setVelocitiesToTemperature(temp) except AttributeError: print "I don't know what temperature to use!!" # TODO: look through the system's forces to find an andersen # thermostate? raise pass assert content.output.protocol == 'localfs', "I'm currently only equiped for localfs output" self.log.info('adding reporters...') self.add_reporters(simulation, content.output.path) # run dynamics! self.log.info('Starting dynamics') simulation.step(self.number_of_steps) for reporter in simulation.reporters: # explicitly delete the reporters so that any open file handles # are closed. del reporter # tell the master that I'm done self.send_recv(msg_type='simulation_done', content={ 'status': 'success', 'output': { 'protocol': 'localfs', 'path': content.output.path } })
def __init__(self, n_workers, system, integrator, platform_name, platform_properties={}): """Set up workers and queues.""" from simtk.openmm import Platform, Context assert n_workers == 1 openmm_platform = Platform.getPlatformByName(platform_name) self._openmm_context = Context(system, integrator, openmm_platform, platform_properties)
def langevin_NVT(item, time = None, saving_timestep = None, integration_timestep= 2*unit.femtoseconds, friction=1.0/unit.picoseconds, temperature=300.0*unit.kelvin, initial_coordinates=None, initial_velocities=None, platform_name='CUDA', reporters=None, tqdm=True): """Newtonian classical dynamics of a molecular system with OpenMM. The trajectory of a newtonian classical dynamics of a molecular system is obtained together with the values of potential and kinetic energy. This method is nothing but a short cut to run quick molecular dynamics with the test systems of this library by means of OpenMM. Parameters ---------- system: simtk.openmm.System Molecular system as a system class of OpenMM (see: link) friction: unit.Quantity Damping parameter of the Langevin dynamics (in units of 1/time). initial_coordinates: unit.Quantity Initial coordinates of the system as a numpy array with shape [n_particles, 3] and units of length. Where 'n_particles' is the number of particles of the system. initial_velocities: unit.Quantity Initial velocities of the system as a numpy array with shape [n_particles, 3] and units of length/time. Where 'n_particles' is the number of particles of the system. integration_timestep: unit.Quantity Time step used by the integrator of the equations of motion. The parameter needs to have units of time. saving_timestep: unit.Quantity Time step used to report the output trajectory. The parameter needs to have units of time. total_time: unit.Quantity Total runing time of the simulation. The parameter needs to have units of time. platform_name: str (default: 'CPU') Platform to run the dynamics: 'CPU', 'OPENCL' or 'CUDA' (according to those options to run OpenMM, see documentation), verbose: bool (default: True) Verbose switcher. The method will print out information if the value is True. Returns ------- time: unit.Quantity Time as numpy array of shape [n_frames] with units of picoseconds. position: unit.Quantity Positions of the systems particles in every reported frame as numpy array of shape [n_frames, n_particles, 3] with units of nanometers. velocity: unit.Quantity Velocities of the systems particles in every reported frame as numpy array of shape [n_frames, n_particles, 3] with units of nanometers/picoseconds. kinetic_energy: unit.Quantity Kinetic energy of the system in every reported frame as numpy array of shape [n_frames] with units of kilocalories/mole. potential_energy: unit.Quantity Potential energy of the system in every reported frame as numpy array of shape [n_frames] with units of kilocalories/mole. Examples -------- >>> from uibcdf_test_systems import DoubleWell >>> from uibcdf_test_systems.simulation import newtonian >>> from simtk import unit >>> double_well = DoubleWell(n_particles = 1, mass = 64 * unit.amu, Eo=4.0 * unit.kilocalories_per_mole, a=1.0 * unit.nanometers, b=0.0 * unit.kilocalories_per_mole)) >>> initial_coordinates = np.zeros([1, 3], np.float32) * unit.nanometers >>> initial_velocities = np.zeros([1, 3], np.float32) * unit.nanometers/unit.picoseconds >>> initial_coordinates[0,0] = 1.0 * unit.nanometers >>> time, position, velocity, kinetic_energy, potential_energy = langevin_NVT(double_well, >>> friction = 0.1/unit.picoseconds, >>> initial_coordinates = initial_coordinates, >>> initial_velocities = initial_velocities, >>> integration_timestep = 0.02 * unit.picoseconds, >>> saving_timestep = 0.5 * unit.picoseconds, >>> total_time = 100 * unit.picoseconds) Notes ----- See the `corresponding documentation in the user guide regarding this method <../../simulations/newtonian.html>`_. Some simple examples on how this method is used can be found in the users guide sections corresponding to `the free particle <../../systems/free_particle.html>`_, `the harmonic well potential <../../systems/harmonic_well_potential.html>`_ or `the double well potential <../../systems/double_well_potential.html>`_. """ from simtk.openmm import LangevinIntegrator, Platform, Context from simtk import unit import numpy as np # System parameters. n_particles = item.system.getNumParticles() # Integrator. integrator = LangevinIntegrator(temperature, friction, integration_timestep) # Platform. platform = Platform.getPlatformByName(platform_name) # Simulation. simulation = Simulation(item.topology, item.system, integrator, platform) # Initial Context. if initial_coordinates is None: initial_coordinates = item.coordinates simulation.context.setPositions(initial_coordinates) if initial_velocities=='zeros' or initial_velocities is None: initial_velocities = np.zeros([n_particles, 3], np.float32) * unit.nanometers/unit.picosecond simulation.context.setVelocities(initial_velocities) elif initial_velocities=='boltzmann': simulation.context.setVelocitiesToTemperature(temperature) else: simulation.context.setVelocities(initial_velocities) # Reporters. default_reporter = False tqdm_reporter = False if reporters is None: reporters = [] if saving_timestep is not None and len(reporters)==0: saving_steps_interval = int(saving_timestep/integration_timestep) default_reporter = MolSysMTTrajectoryDictReporter(saving_steps_interval, time=True, coordinates=True, potentialEnergy=True, kineticEnergy=True, box=True) reporters.append(default_reporter) for reporter in reporters: simulation.reporters.append(reporter) # Initial report initial_state = simulation.context.getState(getEnergy=True, getPositions=True, getVelocities=True) for reporter in reporters: reporter.report(simulation, initial_state) n_steps = int(time/integration_timestep) if tqdm: tqdm_reporter = TQDMReporter(100, n_steps) simulation.reporters.append(tqdm_reporter) simulation.step(n_steps) if tqdm_reporter: tqdm_reporter.finalize() if default_reporter: return default_reporter.finalize() else: pass
def main(argdict): """ Main function for entry point checking. Expects a dictionary of command line arguments. """ # load configuration from logfile: with open(argdict["log"], 'r') as f: argdict = json.load(f) # load system initial configuration: pdb = pdb_file_nonstandard_bonds(argdict["pdb"]) print("--> input topology: ", end="") print(pdb.topology) # physical parameters of simulation: sim_temperature = argdict["temperature"] * kelvin sim_andersen_coupling = 1 / picosecond sim_pressure = ( (argdict["pressure"], argdict["pressure"], argdict["pressure"]) * bar) sim_scale_x = True sim_scale_y = True sim_scale_z = True # simulation control parameters: sim_timestep = argdict["timestep"] * femtoseconds # restraints parameters: sim_restr_fc = argdict["restr_fc"] * kilojoule_per_mole / nanometer**2 # create force field object: ff = ForceField(*argdict["ff"]) # build a simulation system from topology and force field: # (note that AMOEBA is intended to be run without constraints) # (note that mutualInducedtargetEpsilon defaults to 0.01 unlike what is # specified in the documentation which claims 0.00001) system = ff.createSystem( pdb.topology, nonbondedMethod=PME, nonbondedCutoff=argdict["nonbonded_cutoff"] * nanometer, vdwCutoff=argdict["vdw_cutoff"] * nanometer, ewaldErrorTolerance=argdict["ewald_error_tolerance"], polarisation=argdict["polarisation"], mutualInducedTargetEpsilon=argdict["mutual_induced_target_epsilon"], constraints=None, rigidWater=False, removeCMMotion=True # removes centre of mass motion ) # overwrite the polarisation method set at system creation; this is # necessary as openMM always sets polarisation method to "mutual" of the # target epsilon is specified at system creation; this way, target epsilon # is ignored for all but the mutual method multipole_force = [ f for f in system.getForces() if isinstance(f, AmoebaMultipoleForce) ][0] print("--> using polarisation method " + str(argdict["polarisation"])) if argdict["polarisation"] == "mutual": multipole_force.setPolarizationType(multipole_force.Mutual) if argdict["polarisation"] == "extrapolated": multipole_force.setPolarizationType(multipole_force.Extrapolated) if argdict["polarisation"] == "direct": multipole_force.setPolarizationType(multipole_force.Direct) # will use Andersen thermostat here: # (Inhibits particle dynamics somewhat, but little or no ergodicity # issues (from Gromacs documenation). However, only alternative is full # Langevin dynamics, which is even worse wrt dynamics. Bussi/v-rescale is # not available at the moment, it seems (it is available in tinker, but # without GPU acceleration)) system.addForce(AndersenThermostat(sim_temperature, sim_andersen_coupling)) # use anisotropic barostat: # (note that this corresponds to semiisotropic pressure coupling in Gromacs # if the pressure is identical for the x- and y/axes) # (note that by default this attempts an update every 25 steps) system.addForce( MonteCarloAnisotropicBarostat(sim_pressure, sim_temperature, sim_scale_x, sim_scale_y, sim_scale_z)) # prepare harmonic restraining potential: # (note that periodic distance is absolutely necessary here to prevent # system from blowing up, as otherwise periodic image position may be used # resulting in arbitrarily large forces) force = CustomExternalForce("k*periodicdistance(x, y, z, x0, y0, z0)^2") force.addGlobalParameter("k", sim_restr_fc) force.addPerParticleParameter("x0") force.addPerParticleParameter("y0") force.addPerParticleParameter("z0") # apply harmonic restraints to C-alphas: if argdict["restr"] == "capr": print("--> applying harmonic positional restraints to CA atoms") for atm in pdb.topology.atoms(): if atm.name == "CA": force.addParticle(atm.index, pdb.positions[atm.index]) elif argdict["restr"] == "hapr": sys.exit("Restraints mode " + str(argdict["restr"]) + "is not implemented.") elif argdict["restr"] == "none": print("--> applying no harmonic positional restraints to any atom") else: sys.exit("Restraints mode " + str(argdict["restr"]) + "is not implemented.") # add restraining force to system: system.addForce(force) # make special group for nonbonded forces: for f in system.getForces(): if (isinstance(f, AmoebaMultipoleForce) or isinstance(f, AmoebaVdwForce) or isinstance(f, AmoebaGeneralizedKirkwoodForce) or isinstance(f, AmoebaWcaDispersionForce)): f.setForceGroup(1) # select integrator: if argdict["integrator"] == "mts": # use multiple timestep RESPA integrator: print("--> using RESPA/MTS integrator") integrator = MTSIntegrator(sim_timestep, [(0, argdict["inner_ts_frac"]), (1, 1)]) if argdict["integrator"] == "verlet": # use Leapfrog Verlet integrator here: print("--> using Verlet integrator") integrator = VerletIntegrator(sim_timestep) # select a platform (should be CUDA, otherwise VERY slow): platform = Platform.getPlatformByName(argdict["platform"]) properties = { "CudaPrecision": argdict["precision"], "CudaDeviceIndex": "0" } # create simulation system: sim = Simulation(pdb.topology, system, integrator, platform, properties) # unit conversion factors: ang2nm = 0.1 # create MDA universe: u = mda.Universe(args.s, args.f) # selection for overall system will be needed to set OpenMM positions # accordingt to trajectory: allsystem = u.select_atoms("all") # get parameters to define cylinder around protein center of geometry: # (the cylinder spans the entire box in the z-direction) protein = u.select_atoms("protein") radius = str(args.r) z_margin = args.z_margin z_min = str(protein.bbox()[0, 2] - protein.center_of_geometry()[2] - z_margin) z_max = str(protein.bbox()[1, 2] - protein.center_of_geometry()[2] + z_margin) # select all solvent atoms, note that AMOEBA residue name is HOH: # (these must be updating, as water may move in and out of pore!) solvent = u.select_atoms("byres (resname HOH SOL) and cyzone " + radius + " " + z_max + " " + z_min + " protein", updating=True) solvent_ow = solvent.select_atoms("name O OW", updating=True) # lambda function for converting atomic dipoles to molecular dipoles: # (this only works on 1D arrays, hence use apply_along_axis if quantity is # vector-valued, e.g. positions and dipoles) def atomic2molecular_sum(arr): return np.bincount(allsystem.resindices, arr) def atomic2molecular_avg(arr): return np.bincount(allsystem.resindices, arr) / np.bincount( allsystem.resindices) # create lambda function for obtaining charges in vectorisable way: # (units are elementary_charge) get_atomic_charges = np.vectorize( lambda index: multipole_force.getMultipoleParameters(int(index))[ 0].value_in_unit(elementary_charge)) # obtain atomic charges: # (charges are static, so need this only once; units are elementary charge) atomic_charges = get_atomic_charges(allsystem.ix) # obtain start and end time as will as time step: dt = float(args.dt) t_start = float(args.b) t_end = float(args.e) # prepare results dictionary: res = { "t": [], "x": [], "y": [], "z": [], "indu_rho": [], "indu_costheta": [], "indu_cosphi": [], "perm_rho": [], "perm_costheta": [], "perm_cosphi": [], "mono_rho": [], "mono_costheta": [], "mono_cosphi": [], "total_rho": [], "total_costheta": [], "total_cosphi": [] } # loop over trajectory: for ts in u.trajectory: # skip all frames before starting frame: if ts.time < t_start: continue # only analyse relevant time frames: if round(ts.time, 4) % dt == 0: # inform user: print("analysing frame: " + str(ts.frame) + " at time: " + str(ts.time)) print("number of selected solvent molecules in this frame: " + str(solvent.n_residues)) # convert mda positions to OpenMM positions and set context: omm_positions = Quantity( [tuple(pos) for pos in list(allsystem.positions)], unit=angstrom) sim.context.setPositions(omm_positions) # calculate molecular positions (or molecular centre of geometry) by # averaging over all atomic positions within a residue: # (units are Angstrom in MDAnalysis!) molecular_positions = np.apply_along_axis( atomic2molecular_avg, 0, allsystem.positions) * ang2nm # calculate charge-weighted positions by multiplying the relative # atomic positions with the atomic charges (relative positions are # necessary to account for charged residues/molecules, where the # dipole moment is calculated relative to the center of geometry of # the residue): # (units are elementary charge * nanometer) atomic_charge_weighted_positions = ( allsystem.positions - molecular_positions[allsystem.resindices]) atomic_charge_weighted_positions *= (atomic_charges[np.newaxis].T * ang2nm) # obtain induced and permanent atomic dipoles from OpenMM: # (units are elementary charge * nm) atomic_dipoles_indu = np.array( multipole_force.getInducedDipoles(sim.context)) atomic_dipoles_perm = np.array( multipole_force.getLabFramePermanentDipoles(sim.context)) # convert atomic to molecular quantities and calculate total dipole: molecular_dipoles_indu = np.apply_along_axis( atomic2molecular_sum, 0, atomic_dipoles_indu) molecular_dipoles_perm = np.apply_along_axis( atomic2molecular_sum, 0, atomic_dipoles_perm) molecular_dipoles_mono = np.apply_along_axis( atomic2molecular_sum, 0, atomic_charge_weighted_positions) molecular_dipoles_total = (molecular_dipoles_indu + molecular_dipoles_perm + molecular_dipoles_mono) # convert to spherical coordinates: molecular_dipoles_indu = cartesian2spherical( molecular_dipoles_indu) molecular_dipoles_perm = cartesian2spherical( molecular_dipoles_perm) molecular_dipoles_mono = cartesian2spherical( molecular_dipoles_mono) molecular_dipoles_total = cartesian2spherical( molecular_dipoles_total) # insert into results dictionary: res["t"].append(np.repeat(ts.time, solvent.n_residues)) res["x"].append(molecular_positions[solvent_ow.resindices, 0]) res["y"].append(molecular_positions[solvent_ow.resindices, 1]) res["z"].append(molecular_positions[solvent_ow.resindices, 2]) res["indu_rho"].append( molecular_dipoles_indu[solvent_ow.resindices, 0]) res["indu_costheta"].append( molecular_dipoles_indu[solvent_ow.resindices, 1]) res["indu_cosphi"].append( molecular_dipoles_indu[solvent_ow.resindices, 2]) res["perm_rho"].append( molecular_dipoles_perm[solvent_ow.resindices, 0]) res["perm_costheta"].append( molecular_dipoles_perm[solvent_ow.resindices, 1]) res["perm_cosphi"].append( molecular_dipoles_perm[solvent_ow.resindices, 2]) res["mono_rho"].append( molecular_dipoles_mono[solvent_ow.resindices, 0]) res["mono_costheta"].append( molecular_dipoles_mono[solvent_ow.resindices, 1]) res["mono_cosphi"].append( molecular_dipoles_mono[solvent_ow.resindices, 2]) res["total_rho"].append( molecular_dipoles_total[solvent_ow.resindices, 0]) res["total_costheta"].append( molecular_dipoles_total[solvent_ow.resindices, 1]) res["total_cosphi"].append( molecular_dipoles_total[solvent_ow.resindices, 2]) # stop iterating through trajectory after end time: if ts.time > t_end: break # convert lists of arrays to arrays: for k in res.keys(): res[k] = np.concatenate(res[k]) # convert units of dipole magnitude to Debye: eNm2debye = 48.03205 res["indu_rho"] = eNm2debye * res["indu_rho"] res["perm_rho"] = eNm2debye * res["perm_rho"] res["mono_rho"] = eNm2debye * res["mono_rho"] res["total_rho"] = eNm2debye * res["total_rho"] # load spline curve data: with open(args.j, "r") as f: chap_data = json.load(f) # create spline curve from CHAP data: spline_curve = BSplineCurve(chap_data) # calculate s-coordinate from z-coordinate: res["s"] = spline_curve.z2s(res["z"]) # convert results to data frame: df_res = pd.DataFrame(res) # loop over various numbers of bins: df = [] for nbins in args.nbins: # create a temporary data frame: tmp = df_res # drop positional coordinates: tmp = tmp.drop(["x", "y", "z", "t"], axis=1) # bin by value of s-coordinate: tmp = tmp.groupby(pd.cut(tmp.s, nbins)) # aggregate variables: tmp = tmp.agg([np.mean, np.std, sem, np.size, np.median, qlo, qhi]).reset_index() # rename columns (combines variable name with aggregation method): tmp.columns = ["_".join(x) for x in tmp.columns.ravel()] # remove grouping key: tmp = tmp.drop("s_", axis=1) # add column wit number of bins: tmp["nbins"] = nbins # append to list of data frames: df.append(tmp) # combine list of data frames into single data frame: df = pd.concat(df) # write to JSON file: df.to_json(args.o, orient="records") # need to add newline for POSIX compliance: with open(args.o, "a") as f: f.write("\n")
def test_reporter(tmpdir, get_fn): pdb = PDBFile(get_fn('native.pdb')) forcefield = ForceField('amber99sbildn.xml', 'amber99_obc.xml') # NO PERIODIC BOUNDARY CONDITIONS system = forcefield.createSystem(pdb.topology, nonbondedMethod=CutoffNonPeriodic, nonbondedCutoff=1.0 * nanometers, constraints=HBonds, rigidWater=True) integrator = LangevinIntegrator(300 * kelvin, 1.0 / picoseconds, 2.0 * femtoseconds) integrator.setConstraintTolerance(0.00001) platform = Platform.getPlatformByName('Reference') simulation = Simulation(pdb.topology, system, integrator, platform) simulation.context.setPositions(pdb.positions) simulation.context.setVelocitiesToTemperature(300 * kelvin) tmpdir = str(tmpdir) hdf5file = os.path.join(tmpdir, 'traj.h5') ncfile = os.path.join(tmpdir, 'traj.nc') dcdfile = os.path.join(tmpdir, 'traj.dcd') reporter = HDF5Reporter(hdf5file, 2, coordinates=True, time=True, cell=True, potentialEnergy=True, kineticEnergy=True, temperature=True, velocities=True) reporter2 = NetCDFReporter(ncfile, 2, coordinates=True, time=True, cell=True) reporter3 = DCDReporter(dcdfile, 2) simulation.reporters.append(reporter) simulation.reporters.append(reporter2) simulation.reporters.append(reporter3) simulation.step(100) reporter.close() reporter2.close() reporter3.close() with HDF5TrajectoryFile(hdf5file) as f: got = f.read() eq(got.temperature.shape, (50, )) eq(got.potentialEnergy.shape, (50, )) eq(got.kineticEnergy.shape, (50, )) eq(got.coordinates.shape, (50, 22, 3)) eq(got.velocities.shape, (50, 22, 3)) eq(got.cell_lengths, None) eq(got.cell_angles, None) eq(got.time, 0.002 * 2 * (1 + np.arange(50))) assert f.topology == md.load(get_fn('native.pdb')).top with NetCDFTrajectoryFile(ncfile) as f: xyz, time, cell_lengths, cell_angles = f.read() eq(cell_lengths, None) eq(cell_angles, None) eq(time, 0.002 * 2 * (1 + np.arange(50))) hdf5_traj = md.load(hdf5file) dcd_traj = md.load(dcdfile, top=get_fn('native.pdb')) netcdf_traj = md.load(ncfile, top=get_fn('native.pdb')) # we don't have to convert units here, because md.load already # handles that assert hdf5_traj.unitcell_vectors is None eq(hdf5_traj.xyz, netcdf_traj.xyz) eq(hdf5_traj.unitcell_vectors, netcdf_traj.unitcell_vectors) eq(hdf5_traj.time, netcdf_traj.time) eq(dcd_traj.xyz, hdf5_traj.xyz)
def simulate(self, header, content): """Main method that is "executed" by the receipt of the msg_type == 'simulate' message from the server. We run some OpenMM dynamics, and then send back the results. """ self.log.info('Setting up simulation...') state, topology = self.deserialize_input(content) starting_state_path = content.starting_state.path # set the GPU platform platform = Platform.getPlatformByName(str(self.platform)) if self.platform == 'CUDA': properties = { 'CudaPrecision': 'mixed', 'CudaDeviceIndex': str(self.device_index) } elif self.platform == 'OpenCL': properties = { 'OpenCLPrecision': 'mixed', 'OpenCLDeviceIndex': str(self.device_index) } else: properties = None simulation = Simulation(topology, self.system, self.integrator, platform, properties) # do the setup self.set_state(state, simulation) self.sanity_check(simulation) if self.minimize: self.log.info('minimizing...') simulation.minimizeEnergy() if self.random_initial_velocities: try: temp = simulation.integrator.getTemperature() simulation.context.setVelocitiesToTemperature(temp) except AttributeError: print "I don't know what temperature to use!!" # TODO: look through the system's forces to find an andersen # thermostate? raise pass assert content.output.protocol == 'localfs', "I'm currently only equiped for localfs output" self.log.info('adding reporters...') self.add_reporters(simulation, content.output.path) # run dynamics! self.log.info('Starting dynamics') simulation.step(self.number_of_steps) for reporter in simulation.reporters: # explicitly delete the reporters so that any open file handles # are closed. del reporter # tell the master that I'm done self.send_recv(msg_type='simulation_done', content={ 'status': 'success', 'starting_state': { 'protocol': 'localfs', 'path': starting_state_path }, 'output': { 'protocol': 'localfs', 'path': content.output.path } })
def setup_platform_with_resources(compute_resources, high_precision=False): """Creates an OpenMM `Platform` object which requests a set amount of compute resources (e.g with a certain number of cpus). Parameters ---------- compute_resources: ComputeResources The compute resources which describe which platform is most appropriate. high_precision: bool If true, a platform with the highest possible precision (double for CUDA and OpenCL, Reference for CPU only) will be returned. Returns ------- Platform The created platform """ from simtk.openmm import Platform # Setup the requested platform: if compute_resources.number_of_gpus > 0: # TODO: Make sure use mixing precision - CUDA, OpenCL. # TODO: Deterministic forces = True from openff.evaluator.backends import ComputeResources toolkit_enum = ComputeResources.GPUToolkit( compute_resources.preferred_gpu_toolkit) # A platform which runs on GPUs has been requested. platform_name = ("CUDA" if toolkit_enum == ComputeResources.GPUToolkit.CUDA else ComputeResources.GPUToolkit.OpenCL) # noinspection PyCallByClass,PyTypeChecker platform = Platform.getPlatformByName(platform_name) if compute_resources.gpu_device_indices is not None: property_platform_name = platform_name if toolkit_enum == ComputeResources.GPUToolkit.CUDA: property_platform_name = platform_name.lower().capitalize() platform.setPropertyDefaultValue( property_platform_name + "DeviceIndex", compute_resources.gpu_device_indices, ) if high_precision: platform.setPropertyDefaultValue("Precision", "double") logger.info("Setting up an openmm platform on GPU {}".format( compute_resources.gpu_device_indices or 0)) else: if not high_precision: # noinspection PyCallByClass,PyTypeChecker platform = Platform.getPlatformByName("CPU") platform.setPropertyDefaultValue( "Threads", str(compute_resources.number_of_threads)) else: # noinspection PyCallByClass,PyTypeChecker platform = Platform.getPlatformByName("Reference") logger.info("Setting up a simulation with {} threads".format( compute_resources.number_of_threads)) return platform
if args.platform in platform_properties: properties = {} props = platform_properties[args.platform] for v in props: p_name = args.platform + '_' + v value = os.environ.get(p_name.upper(), None) if hasattr(args, p_name.lower()): value = getattr(args, v.lower()) if value: properties[args.platform + '_' + v.replace('_', '')] = value if args.platform == 'fastest': platform = None else: platform = Platform.getPlatformByName(args.platform) print 'Reading PDB' pdb = PDBFile(args.topology_pdb) print 'Done' with open(args.system_xml) as f: system_xml = f.read() system = XmlSerializer.deserialize(system_xml) with open(args.integrator_xml) as f: integrator_xml = f.read() integrator = XmlSerializer.deserialize(integrator_xml)
def test_reporter_subset(tmpdir, get_fn): pdb = PDBFile(get_fn('native2.pdb')) pdb.topology.setUnitCellDimensions([2, 2, 2]) forcefield = ForceField('amber99sbildn.xml', 'amber99_obc.xml') system = forcefield.createSystem(pdb.topology, nonbondedMethod=CutoffPeriodic, nonbondedCutoff=1 * nanometers, constraints=HBonds, rigidWater=True) integrator = LangevinIntegrator(300 * kelvin, 1.0 / picoseconds, 2.0 * femtoseconds) integrator.setConstraintTolerance(0.00001) platform = Platform.getPlatformByName('Reference') simulation = Simulation(pdb.topology, system, integrator, platform) simulation.context.setPositions(pdb.positions) simulation.context.setVelocitiesToTemperature(300 * kelvin) tmpdir = str(tmpdir) hdf5file = os.path.join(tmpdir, 'traj.h5') ncfile = os.path.join(tmpdir, 'traj.nc') dcdfile = os.path.join(tmpdir, 'traj.dcd') xtcfile = os.path.join(tmpdir, 'traj.xtc') atomSubset = [0, 1, 2, 4, 5] reporter = HDF5Reporter(hdf5file, 2, coordinates=True, time=True, cell=True, potentialEnergy=True, kineticEnergy=True, temperature=True, velocities=True, atomSubset=atomSubset) reporter2 = NetCDFReporter(ncfile, 2, coordinates=True, time=True, cell=True, atomSubset=atomSubset) reporter3 = DCDReporter(dcdfile, 2, atomSubset=atomSubset) reporter4 = XTCReporter(xtcfile, 2, atomSubset=atomSubset) simulation.reporters.append(reporter) simulation.reporters.append(reporter2) simulation.reporters.append(reporter3) simulation.reporters.append(reporter4) simulation.step(100) reporter.close() reporter2.close() reporter3.close() reporter4.close() t = md.load(get_fn('native.pdb')) t.restrict_atoms(atomSubset) with HDF5TrajectoryFile(hdf5file) as f: got = f.read() eq(got.temperature.shape, (50, )) eq(got.potentialEnergy.shape, (50, )) eq(got.kineticEnergy.shape, (50, )) eq(got.coordinates.shape, (50, len(atomSubset), 3)) eq(got.velocities.shape, (50, len(atomSubset), 3)) eq(got.cell_lengths, 2 * np.ones((50, 3))) eq(got.cell_angles, 90 * np.ones((50, 3))) eq(got.time, 0.002 * 2 * (1 + np.arange(50))) assert f.topology == md.load(get_fn('native.pdb'), atom_indices=atomSubset).topology with NetCDFTrajectoryFile(ncfile) as f: xyz, time, cell_lengths, cell_angles = f.read() eq(cell_lengths, 20 * np.ones((50, 3))) eq(cell_angles, 90 * np.ones((50, 3))) eq(time, 0.002 * 2 * (1 + np.arange(50))) eq(xyz.shape, (50, len(atomSubset), 3)) hdf5_traj = md.load(hdf5file) dcd_traj = md.load(dcdfile, top=hdf5_traj) netcdf_traj = md.load(ncfile, top=hdf5_traj) xtc_traj = md.load(xtcfile, top=hdf5_traj) # we don't have to convert units here, because md.load already handles that eq(hdf5_traj.xyz, netcdf_traj.xyz) eq(hdf5_traj.unitcell_vectors, netcdf_traj.unitcell_vectors) eq(hdf5_traj.time, netcdf_traj.time) eq(xtc_traj.time, netcdf_traj.time) eq(dcd_traj.xyz, hdf5_traj.xyz) eq(xtc_traj.xyz, hdf5_traj.xyz) eq(dcd_traj.unitcell_vectors, hdf5_traj.unitcell_vectors)
def subtest_mcmc_expectation(testsystem, move_set): if debug: print(testsystem.__class__.__name__) print(str(move_set)) # Test settings. temperature = 298.0 * units.kelvin nequil = 10 # number of equilibration iterations niterations = 40 # number of production iterations # Retrieve system and positions. [system, positions] = [testsystem.system, testsystem.positions] platform_name = 'Reference' from simtk.openmm import Platform platform = Platform.getPlatformByName(platform_name) # Compute properties. kB = units.BOLTZMANN_CONSTANT_kB * units.AVOGADRO_CONSTANT_NA kT = kB * temperature ndof = 3 * system.getNumParticles() - system.getNumConstraints() # Create thermodynamic state from openmmmcmc.thermodynamics import ThermodynamicState thermodynamic_state = ThermodynamicState(system=testsystem.system, temperature=temperature) # Create MCMC sampler. from openmmmcmc.mcmc import MCMCSampler sampler = MCMCSampler(thermodynamic_state, move_set=move_set, platform=platform) # Create sampler state. from openmmmcmc.mcmc import SamplerState sampler_state = SamplerState(system=testsystem.system, positions=testsystem.positions, platform=platform) # Equilibrate for iteration in range(nequil): #print("equilibration iteration %d / %d" % (iteration, nequil)) # Update sampler state. sampler_state = sampler.run(sampler_state, 1) # Accumulate statistics. x_n = np.zeros( [niterations], np.float64 ) # x_n[i] is the x position of atom 1 after iteration i, in angstroms potential_n = np.zeros( [niterations], np.float64 ) # potential_n[i] is the potential energy after iteration i, in kT kinetic_n = np.zeros( [niterations], np.float64 ) # kinetic_n[i] is the kinetic energy after iteration i, in kT temperature_n = np.zeros( [niterations], np.float64 ) # temperature_n[i] is the instantaneous kinetic temperature from iteration i, in K volume_n = np.zeros( [niterations], np.float64) # volume_n[i] is the volume from iteration i, in K for iteration in range(niterations): if debug: print("iteration %d / %d" % (iteration, niterations)) # Update sampler state. sampler_state = sampler.run(sampler_state, 1) # Get statistics. potential_energy = sampler_state.potential_energy kinetic_energy = sampler_state.kinetic_energy total_energy = sampler_state.total_energy instantaneous_temperature = kinetic_energy * 2.0 / ndof / ( units.BOLTZMANN_CONSTANT_kB * units.AVOGADRO_CONSTANT_NA) volume = sampler_state.volume #print "potential %8.1f kT | kinetic %8.1f kT | total %8.1f kT | volume %8.3f nm^3 | instantaneous temperature: %8.1f K" % (potential_energy/kT, kinetic_energy/kT, total_energy/kT, volume/(units.nanometers**3), instantaneous_temperature/units.kelvin) # Accumulate statistics. x_n[iteration] = sampler_state.positions[0, 0] / units.angstroms potential_n[iteration] = potential_energy / kT kinetic_n[iteration] = kinetic_energy / kT temperature_n[iteration] = instantaneous_temperature / units.kelvin volume_n[iteration] = volume / (units.nanometers**3) # Compute expected statistics. if ('get_potential_expectation' in dir(testsystem)): # Skip this check if the std dev is zero. skip_test = False if (potential_n.std() == 0.0): skip_test = True if debug: print("Skipping potential test since variance is zero.") if not skip_test: potential_expectation = testsystem.get_potential_expectation( thermodynamic_state) / kT potential_mean = potential_n.mean() g = timeseries.statisticalInefficiency(potential_n, fast=True) dpotential_mean = potential_n.std() / np.sqrt(niterations / g) potential_error = potential_mean - potential_expectation nsigma = abs(potential_error) / dpotential_mean test_passed = True if (nsigma > NSIGMA_CUTOFF): test_passed = False if debug or (test_passed is False): print("Potential energy expectation") print( "observed %10.5f +- %10.5f kT | expected %10.5f | error %10.5f +- %10.5f (%.1f sigma)" % (potential_mean, dpotential_mean, potential_expectation, potential_error, dpotential_mean, nsigma)) if test_passed: print("TEST PASSED") else: print("TEST FAILED") print( "----------------------------------------------------------------------------" ) if ('get_volume_expectation' in dir(testsystem)): # Skip this check if the std dev is zero. skip_test = False if (volume_n.std() == 0.0): skip_test = True if debug: print("Skipping volume test.") if not skip_test: volume_expectation = testsystem.get_volume_expectation( thermodynamic_state) / (units.nanometers**3) volume_mean = volume_n.mean() g = timeseries.statisticalInefficiency(volume_n, fast=True) dvolume_mean = volume_n.std() / np.sqrt(niterations / g) volume_error = volume_mean - volume_expectation nsigma = abs(volume_error) / dvolume_mean test_passed = True if (nsigma > NSIGMA_CUTOFF): test_passed = False if debug or (test_passed is False): print("Volume expectation") print( "observed %10.5f +- %10.5f kT | expected %10.5f | error %10.5f +- %10.5f (%.1f sigma)" % (volume_mean, dvolume_mean, volume_expectation, volume_error, dvolume_mean, nsigma)) if test_passed: print("TEST PASSED") else: print("TEST FAILED") print( "----------------------------------------------------------------------------" )
def _initialize_simulation(self): if self._initialized: # update temperature and pressure self._integrator.setTemperature(self._temperature) if self._options.enable_pressure_coupling: self._simulation.context.setParameter( self._barostat.Temperature(), self._temperature ) # update all of the system transformers self._transformers_update() else: # we need to set the whole thing from scratch self._initialized = True prmtop = _parm_top_from_string(self._parm_string) # create parameter objects pme_params = PMEParams( enable=self._options.enable_pme, tolerance=self._options.pme_tolerance ) pcouple_params = PressureCouplingParams( enable=self._options.enable_pressure_coupling, temperature=self._temperature, pressure=self._options.pressure, steps=self._options.pressure_coupling_update_steps, ) # build the system sys, barostat = _create_openmm_system( prmtop, self._options.solvation, self._options.cutoff, self._options.use_big_timestep, self._options.use_bigger_timestep, self._options.implicit_solvent_model, pme_params, pcouple_params, self._options.remove_com, self._temperature, self._extra_bonds, self._extra_restricted_angles, self._extra_torsions, self._options.implicitSolventSaltConc, self._options.soluteDielectric, self._options.solventDielectric, ) self._barostat = barostat if self._options.use_amap: adder = cmap.CMAPAdder( self._parm_string, self._options.amap_alpha_bias, self._options.amap_beta_bias, self._options.ccap, self._options.ncap, ) adder.add_to_openmm(sys) # setup the transformers self._transformers_setup() if len(self._always_on_restraints) > 0: print("Not all always on restraints were handled.") for r in self._always_on_restraints: print("\t", r) raise RuntimeError("Not all always on restraints were handled.") if len(self._selectable_collections) > 0: print("Not all selectable restraints were handled.") for r in self._selectable_collections: print("\t", r) raise RuntimeError("Not all selectable restraints were handled.") sys = self._transformers_add_interactions(sys, prmtop.topology) self._transformers_finalize(sys, prmtop.topology) # create the integrator self._integrator = _create_integrator( self._temperature, self._options.use_big_timestep, self._options.use_bigger_timestep, ) # setup the platform, CUDA by default and Reference for testing if self.platform == "Reference": logger.info("Using Reference platform.") platform = Platform.getPlatformByName("Reference") properties = {} elif self.platform == "CPU": logger.info("Using CPU platform.") platform = Platform.getPlatformByName("CPU") properties = {} elif self.platform == "CUDA": logger.info("Using CUDA platform.") platform = Platform.getPlatformByName("CUDA") # The plugin currently requires that we use nvcc, as # nvrtc is not able to compile code that uses the cub # library, which we use in the plugin. # We can force the use of nvcc by setting CudaCompiler. # We set it to the default value, which will reflect the # OPENMM_CUDA_COMPILER environmnet variable if set. compiler = platform.getPropertyDefaultValue("CudaCompiler") logger.debug(f"Using CUDA compiler {compiler}.") properties = { "CudaDeviceIndex": str(self._device_id), "CudaPrecision": "mixed", "CudaCompiler": compiler, } else: raise RuntimeError(f"Unknown platform {self.platform}.") # create the simulation object self._simulation = _create_openmm_simulation( prmtop.topology, sys, self._integrator, platform, properties ) self._transformers_update()
def test_reporter_subset(tmpdir, get_fn): pdb = PDBFile(get_fn('native2.pdb')) pdb.topology.setUnitCellDimensions([2, 2, 2]) forcefield = ForceField('amber99sbildn.xml', 'amber99_obc.xml') system = forcefield.createSystem(pdb.topology, nonbondedMethod=CutoffPeriodic, nonbondedCutoff=1 * nanometers, constraints=HBonds, rigidWater=True) integrator = LangevinIntegrator(300 * kelvin, 1.0 / picoseconds, 2.0 * femtoseconds) integrator.setConstraintTolerance(0.00001) platform = Platform.getPlatformByName('Reference') simulation = Simulation(pdb.topology, system, integrator, platform) simulation.context.setPositions(pdb.positions) simulation.context.setVelocitiesToTemperature(300 * kelvin) tmpdir = str(tmpdir) hdf5file = os.path.join(tmpdir, 'traj.h5') ncfile = os.path.join(tmpdir, 'traj.nc') dcdfile = os.path.join(tmpdir, 'traj.dcd') xtcfile = os.path.join(tmpdir, 'traj.xtc') atomSubset = [0, 1, 2, 4, 5] reporter = HDF5Reporter(hdf5file, 2, coordinates=True, time=True, cell=True, potentialEnergy=True, kineticEnergy=True, temperature=True, velocities=True, atomSubset=atomSubset) reporter2 = NetCDFReporter(ncfile, 2, coordinates=True, time=True, cell=True, atomSubset=atomSubset) reporter3 = DCDReporter(dcdfile, 2, atomSubset=atomSubset) reporter4 = XTCReporter(xtcfile, 2, atomSubset=atomSubset) simulation.reporters.append(reporter) simulation.reporters.append(reporter2) simulation.reporters.append(reporter3) simulation.reporters.append(reporter4) simulation.step(100) reporter.close() reporter2.close() reporter3.close() reporter4.close() t = md.load(get_fn('native.pdb')) t.restrict_atoms(atomSubset) with HDF5TrajectoryFile(hdf5file) as f: got = f.read() eq(got.temperature.shape, (50,)) eq(got.potentialEnergy.shape, (50,)) eq(got.kineticEnergy.shape, (50,)) eq(got.coordinates.shape, (50, len(atomSubset), 3)) eq(got.velocities.shape, (50, len(atomSubset), 3)) eq(got.cell_lengths, 2 * np.ones((50, 3))) eq(got.cell_angles, 90 * np.ones((50, 3))) eq(got.time, 0.002 * 2 * (1 + np.arange(50))) assert f.topology == md.load(get_fn('native.pdb'), atom_indices=atomSubset).topology with NetCDFTrajectoryFile(ncfile) as f: xyz, time, cell_lengths, cell_angles = f.read() eq(cell_lengths, 20 * np.ones((50, 3))) eq(cell_angles, 90 * np.ones((50, 3))) eq(time, 0.002 * 2 * (1 + np.arange(50))) eq(xyz.shape, (50, len(atomSubset), 3)) hdf5_traj = md.load(hdf5file) dcd_traj = md.load(dcdfile, top=hdf5_traj) netcdf_traj = md.load(ncfile, top=hdf5_traj) xtc_traj = md.load(xtcfile, top=hdf5_traj) # we don't have to convert units here, because md.load already handles that eq(hdf5_traj.xyz, netcdf_traj.xyz) eq(hdf5_traj.unitcell_vectors, netcdf_traj.unitcell_vectors) eq(hdf5_traj.time, netcdf_traj.time) eq(xtc_traj.time, netcdf_traj.time) eq(dcd_traj.xyz, hdf5_traj.xyz) eq(xtc_traj.xyz, hdf5_traj.xyz) eq(dcd_traj.unitcell_vectors, hdf5_traj.unitcell_vectors)
DATA_PATH = "mixtures/amber/" RESULT_PATH = "density_simulation/" #md_platform = 'Reference' # e.g. Reference or CUDA or OpenCL md_platform = 'OpenCL' # Some file names prmtop_filename = DATA_PATH + identifier + '.prmtop' inpcrd_filename = DATA_PATH + identifier + '.inpcrd' xml_filename = RESULT_PATH + identifier + '.xml' # For serialized system #--------------MINIMIZATION---------------- MIN_TIME_STEP = 0.5 * femtoseconds MIN_STEPS = 0 # 0=Until convergence is reached MIN_TOLERANCE = 10.0 * kilojoule_per_mole MIN_PLATFORM = Platform.getPlatformByName('Reference') MIN_FRICTION = 1.0 / picoseconds #-------------------NVT-------------------- NVT_TIME_STEP = 1.0 * femtoseconds NVT_STEPS = 50000 NVT_FRICTION = 1.0 / picoseconds NVT_PLATFORM = Platform.getPlatformByName(md_platform) NVT_PROPERTIES = {'DeviceIndex': 1} # TEST if md_platform == 'CUDA': NVT_PROPERTIES = {'CudaPrecision': 'mixed'} else: NVT_PROPERTIES = {} NVT_OUTPUT_FREQ = 10000 NVT_DATA_FREQ = 10000
def test_reporter(tmpdir, get_fn): pdb = PDBFile(get_fn('native.pdb')) forcefield = ForceField('amber99sbildn.xml', 'amber99_obc.xml') # NO PERIODIC BOUNDARY CONDITIONS system = forcefield.createSystem(pdb.topology, nonbondedMethod=CutoffNonPeriodic, nonbondedCutoff=1.0 * nanometers, constraints=HBonds, rigidWater=True) integrator = LangevinIntegrator(300 * kelvin, 1.0 / picoseconds, 2.0 * femtoseconds) integrator.setConstraintTolerance(0.00001) platform = Platform.getPlatformByName('Reference') simulation = Simulation(pdb.topology, system, integrator, platform) simulation.context.setPositions(pdb.positions) simulation.context.setVelocitiesToTemperature(300 * kelvin) tmpdir = str(tmpdir) hdf5file = os.path.join(tmpdir, 'traj.h5') ncfile = os.path.join(tmpdir, 'traj.nc') dcdfile = os.path.join(tmpdir, 'traj.dcd') xtcfile = os.path.join(tmpdir, 'traj.xtc') reporter = HDF5Reporter(hdf5file, 2, coordinates=True, time=True, cell=True, potentialEnergy=True, kineticEnergy=True, temperature=True, velocities=True) reporter2 = NetCDFReporter(ncfile, 2, coordinates=True, time=True, cell=True) reporter3 = DCDReporter(dcdfile, 2) reporter4 = XTCReporter(xtcfile, 2) simulation.reporters.append(reporter) simulation.reporters.append(reporter2) simulation.reporters.append(reporter3) simulation.reporters.append(reporter4) simulation.step(100) reporter.close() reporter2.close() reporter3.close() reporter4.close() with HDF5TrajectoryFile(hdf5file) as f: got = f.read() eq(got.temperature.shape, (50,)) eq(got.potentialEnergy.shape, (50,)) eq(got.kineticEnergy.shape, (50,)) eq(got.coordinates.shape, (50, 22, 3)) eq(got.velocities.shape, (50, 22, 3)) eq(got.cell_lengths, None) eq(got.cell_angles, None) eq(got.time, 0.002 * 2 * (1 + np.arange(50))) assert f.topology == md.load(get_fn('native.pdb')).top with NetCDFTrajectoryFile(ncfile) as f: xyz, time, cell_lengths, cell_angles = f.read() eq(cell_lengths, None) eq(cell_angles, None) eq(time, 0.002 * 2 * (1 + np.arange(50))) hdf5_traj = md.load(hdf5file) dcd_traj = md.load(dcdfile, top=get_fn('native.pdb')) netcdf_traj = md.load(ncfile, top=get_fn('native.pdb')) xtc_traj = md.load(xtcfile, top=get_fn('native.pdb')) # we don't have to convert units here, because md.load already # handles that assert hdf5_traj.unitcell_vectors is None eq(hdf5_traj.xyz, netcdf_traj.xyz) eq(hdf5_traj.unitcell_vectors, netcdf_traj.unitcell_vectors) eq(hdf5_traj.time, netcdf_traj.time) eq(xtc_traj.time, netcdf_traj.time) eq(dcd_traj.xyz, hdf5_traj.xyz) eq(xtc_traj.xyz, dcd_traj.xyz, decimal=3)
def _initialize_simulation(self): if self._initialized: # update temperature and pressure self._integrator.setTemperature(self._temperature) if self._options.enable_pressure_coupling: self._simulation.context.setParameter( self._barostat.Temperature(), self._temperature ) # update all of the system transformers self._transformers_update() else: # we need to set the whole thing from scratch self._initialized = True prmtop = _parm_top_from_string(self._parm_string) # create parameter objects pme_params = PMEParams( enable=self._options.enable_pme, tolerance=self._options.pme_tolerance ) pcouple_params = PressureCouplingParams( enable=self._options.enable_pressure_coupling, temperature=self._temperature, pressure=self._options.pressure, steps=self._options.pressure_coupling_update_steps, ) # build the system sys, barostat = _create_openmm_system( prmtop, self._options.solvation, self._options.cutoff, self._options.use_big_timestep, self._options.use_bigger_timestep, self._options.implicit_solvent_model, pme_params, pcouple_params, self._options.remove_com, self._temperature, self._extra_bonds, self._extra_restricted_angles, self._extra_torsions, self._options.implicitSolventSaltConc, self._options.soluteDielectric, self._options.solventDielectric, ) self._barostat = barostat if self._options.use_amap: adder = cmap.CMAPAdder( self._parm_string, self._options.amap_alpha_bias, self._options.amap_beta_bias, self._options.ccap, self._options.ncap, ) adder.add_to_openmm(sys) # setup the transformers self._transformers_setup() if len(self._always_on_restraints) > 0: print("Not all always on restraints were handled.") for r in self._always_on_restraints: print("\t", r) raise RuntimeError("Not all always on restraints were handled.") if len(self._selectable_collections) > 0: print("Not all selectable restraints were handled.") for r in self._selectable_collections: print("\t", r) raise RuntimeError("Not all selectable restraints were handled.") sys = self._transformers_add_interactions(sys, prmtop.topology) self._transformers_finalize(sys, prmtop.topology) # create the integrator self._integrator = _create_integrator( self._temperature, self._options.use_big_timestep, self._options.use_bigger_timestep, ) # setup the platform, CUDA by default and Reference for testing if self._test: platform = Platform.getPlatformByName("Reference") properties = {} else: platform = Platform.getPlatformByName("CUDA") properties = { "CudaDeviceIndex": str(self._device_id), "CudaPrecision": "mixed", } # create the simulation object self._simulation = _create_openmm_simulation( prmtop.topology, sys, self._integrator, platform, properties ) self._transformers_update()
def subtest_mcmc_expectation(testsystem, move_set): if debug: print testsystem.__class__.__name__ print str(move_set) # Test settings. temperature = 298.0 * units.kelvin pressure = 1.0 * units.atmospheres nequil = 10 # number of equilibration iterations niterations = 20 # number of production iterations # Retrieve system and positions. [system, positions] = [testsystem.system, testsystem.positions] platform_name = 'Reference' from simtk.openmm import Platform platform = Platform.getPlatformByName(platform_name) # Compute properties. kB = units.BOLTZMANN_CONSTANT_kB * units.AVOGADRO_CONSTANT_NA kT = kB * temperature ndof = 3*system.getNumParticles() - system.getNumConstraints() # Create thermodynamic state from repex.thermodynamics import ThermodynamicState thermodynamic_state = ThermodynamicState(system=testsystem.system, temperature=temperature, pressure=pressure) # Create MCMC sampler. from repex.mcmc import MCMCSampler sampler = MCMCSampler(thermodynamic_state, move_set=move_set, platform=platform) # Create sampler state. from repex.mcmc import SamplerState sampler_state = SamplerState(system=testsystem.system, positions=testsystem.positions, platform=platform) # Equilibrate for iteration in range(nequil): #print "equilibration iteration %d / %d" % (iteration, nequil) # Update sampler state. sampler_state = sampler.run(sampler_state, 1) # Accumulate statistics. x_n = np.zeros([niterations], np.float64) # x_n[i] is the x position of atom 1 after iteration i, in angstroms potential_n = np.zeros([niterations], np.float64) # potential_n[i] is the potential energy after iteration i, in kT kinetic_n = np.zeros([niterations], np.float64) # kinetic_n[i] is the kinetic energy after iteration i, in kT temperature_n = np.zeros([niterations], np.float64) # temperature_n[i] is the instantaneous kinetic temperature from iteration i, in K volume_n = np.zeros([niterations], np.float64) # volume_n[i] is the volume from iteration i, in K for iteration in range(niterations): if debug: print "iteration %d / %d" % (iteration, niterations) # Update sampler state. sampler_state = sampler.run(sampler_state, 1) # Get statistics. potential_energy = sampler_state.potential_energy kinetic_energy = sampler_state.kinetic_energy total_energy = sampler_state.total_energy instantaneous_temperature = kinetic_energy * 2.0 / ndof / (units.BOLTZMANN_CONSTANT_kB * units.AVOGADRO_CONSTANT_NA) volume = sampler_state.volume #print "potential %8.1f kT | kinetic %8.1f kT | total %8.1f kT | volume %8.3f nm^3 | instantaneous temperature: %8.1f K" % (potential_energy/kT, kinetic_energy/kT, total_energy/kT, volume/(units.nanometers**3), instantaneous_temperature/units.kelvin) # Accumulate statistics. x_n[iteration] = sampler_state.positions[0,0] / units.angstroms potential_n[iteration] = potential_energy / kT kinetic_n[iteration] = kinetic_energy / kT temperature_n[iteration] = instantaneous_temperature / units.kelvin volume_n[iteration] = volume / (units.nanometers**3) # Compute expected statistics. if ('get_potential_expectation' in dir(testsystem)): # Skip this check if the std dev is zero. skip_test = False if (potential_n.std() == 0.0): skip_test = True if debug: print "Skipping potential test since variance is zero." if not skip_test: potential_expectation = testsystem.get_potential_expectation(thermodynamic_state) / kT potential_mean = potential_n.mean() g = timeseries.statisticalInefficiency(potential_n, fast=True) dpotential_mean = potential_n.std() / np.sqrt(niterations / g) potential_error = potential_mean - potential_expectation nsigma = abs(potential_error) / dpotential_mean test_passed = True if (nsigma > NSIGMA_CUTOFF): test_passed = False if debug or (test_passed is False): print "Potential energy expectation" print "observed %10.5f +- %10.5f kT | expected %10.5f | error %10.5f +- %10.5f (%.1f sigma)" % (potential_mean, dpotential_mean, potential_expectation, potential_error, dpotential_mean, nsigma) if test_passed: print "TEST PASSED" else: print "TEST FAILED" print "----------------------------------------------------------------------------" if ('get_volume_expectation' in dir(testsystem)): # Skip this check if the std dev is zero. skip_test = False if (volume_n.std() == 0.0): skip_test = True if debug: print "Skipping volume test." if not skip_test: volume_expectation = testsystem.get_volume_expectation(thermodynamic_state) / (units.nanometers**3) volume_mean = volume_n.mean() g = timeseries.statisticalInefficiency(volume_n, fast=True) dvolume_mean = volume_n.std() / np.sqrt(niterations / g) volume_error = volume_mean - volume_expectation nsigma = abs(volume_error) / dvolume_mean test_passed = True if (nsigma > NSIGMA_CUTOFF): test_passed = False if debug or (test_passed is False): print "Volume expectation" print "observed %10.5f +- %10.5f kT | expected %10.5f | error %10.5f +- %10.5f (%.1f sigma)" % (volume_mean, dvolume_mean, volume_expectation, volume_error, dvolume_mean, nsigma) if test_passed: print "TEST PASSED" else: print "TEST FAILED" print "----------------------------------------------------------------------------"
def main(argdict): """ Main function for entry point checking. Expects a dictionary of command line arguments. """ # are we continuing from logfile or starting from fresh PDB? if argdict["log"] is None: # keep track of restart number: argdict["restart_number"] = int(0) # write arguments to a file to keep a record: with open(argdict["outname"] + "_parameters.log", 'w') as f: print(json.dumps(argdict, sort_keys=True, indent=4), file=f) else: # load configuration from logfile: logfile = argdict["log"] with open(argdict["log"], 'r') as f: argdict = json.load(f) # make sure log file has appropriate entry: argdict["log"] = logfile # increment restart number: argdict["restart_number"] += 1 # write unnumbered parameters file (for easy restarts): with open(argdict["outname"] + "_parameters.log", 'w') as f: print(json.dumps(argdict, sort_keys=True, indent=4), file=f) # write numbered parameters file (for record keeping): with open( argdict["outname"] + "_" + str(argdict["restart_number"]) + "_parameters.log", 'w') as f: print(json.dumps(argdict, sort_keys=True, indent=4), file=f) # load system initial configuration: pdb = pdb_file_nonstandard_bonds(argdict["pdb"]) print("--> input topology: ", end="") print(pdb.topology) # get XML file from absolute path: xmlfile = os.path.abspath(argdict["xml"]) # set box size in topology to values from XML file: box_vectors = periodic_box_vectors_from_xml(xmlfile) pdb.topology.setPeriodicBoxVectors(box_vectors) # physical parameters of simulation: sim_temperature = argdict["temperature"] * kelvin sim_andersen_coupling = 1 / picosecond sim_pressure = ( (argdict["pressure"], argdict["pressure"], argdict["pressure"]) * bar) sim_scale_x = True sim_scale_y = True sim_scale_z = True # simulation control parameters: sim_timestep = argdict["timestep"] * femtoseconds sim_num_steps = argdict["num_steps"] sim_traj_rep_steps = argdict["report_freq"] sim_state_rep_steps = argdict["report_freq"] sim_checkpoint_steps = argdict["report_freq"] # restraints parameters: sim_restr_fc = argdict["restr_fc"] * kilojoule_per_mole / nanometer**2 # create force field object: ff = ForceField(*argdict["ff"]) # build a simulation system from topology and force field: # (note that AMOEBA is intended to be run without constraints) # (note that mutualInducedtargetEpsilon defaults to 0.01 unlike what is # specified in the documentation which claims 0.00001) sys = ff.createSystem( pdb.topology, nonbondedMethod=PME, nonbondedCutoff=argdict["nonbonded_cutoff"] * nanometer, vdwCutoff=argdict["vdw_cutoff"] * nanometer, ewaldErrorTolerance=argdict["ewald_error_tolerance"], polarisation=argdict["polarisation"], mutualInducedTargetEpsilon=argdict["mutual_induced_target_epsilon"], constraints=None, rigidWater=False, removeCMMotion=True # removes centre of mass motion ) # overwrite the polarisation method set at system creation; this is # necessary as openMM always sets polarisation method to "mutual" of the # target epsilon is specified at system creation; this way, target epsilon # is ignored for all but the mutual method multipole_force = sys.getForce(9) print("--> using polarisation method " + str(argdict["polarisation"])) if argdict["polarisation"] == "mutual": multipole_force.setPolarizationType(multipole_force.Mutual) elif argdict["polarisation"] == "extrapolated": multipole_force.setPolarizationType(multipole_force.Extrapolated) elif argdict["polarisation"] == "direct": multipole_force.setPolarizationType(multipole_force.Direct) else: raise Exception("Polarisation method " + str(argdict["polarisation"]) + " not supported!") # will use Andersen thermostat here: # (Inhibits particle dynamics somewhat, but little or no ergodicity # issues (from Gromacs documenation). However, only alternative is full # Langevin dynamics, which is even worse wrt dynamics. Bussi/v-rescale is # not available at the moment, it seems (it is available in tinker, but # without GPU acceleration)) sys.addForce(AndersenThermostat(sim_temperature, sim_andersen_coupling)) # use anisotropic barostat: # (note that this corresponds to semiisotropic pressure coupling in Gromacs # if the pressure is identical for the x- and y/axes) # (note that by default this attempts an update every 25 steps) sys.addForce( MonteCarloAnisotropicBarostat(sim_pressure, sim_temperature, sim_scale_x, sim_scale_y, sim_scale_z)) # prepare harmonic restraining potential: # (note that periodic distance is absolutely necessary here to prevent # system from blowing up, as otherwise periodic image position may be used # resulting in arbitrarily large forces) force = CustomExternalForce("k*periodicdistance(x, y, z, x0, y0, z0)^2") force.addGlobalParameter("k", sim_restr_fc) force.addPerParticleParameter("x0") force.addPerParticleParameter("y0") force.addPerParticleParameter("z0") # apply harmonic restraints to C-alphas: if argdict["restr"] == "capr": print("--> applying harmonic positional restraints to CA atoms") for atm in pdb.topology.atoms(): if atm.name == "CA": force.addParticle(atm.index, pdb.positions[atm.index]) elif argdict["restr"] == "hapr": sys.exit("Restraints mode " + str(argdict["restr"]) + "is not implemented.") elif argdict["restr"] == "none": print("--> applying no harmonic positional restraints to any atom") else: sys.exit("Restraints mode " + str(argdict["restr"]) + "is not implemented.") # add restraining force to system: sys.addForce(force) # make special group for nonbonded forces: for f in sys.getForces(): if (isinstance(f, AmoebaMultipoleForce) or isinstance(f, AmoebaVdwForce) or isinstance(f, AmoebaGeneralizedKirkwoodForce) or isinstance(f, AmoebaWcaDispersionForce)): f.setForceGroup(1) # read umbrella parameters from file: with open(argdict["umbrella_target"], "r") as f: umbrella_target = json.load(f) # obtain index from atom to be restrained: umbrella_index = umbrella_target["target_particle"]["index"] umbrella_fc = (umbrella_target["umbrella_params"]["fc"] * kilojoule_per_mole / nanometer**2) umbrella_cv = umbrella_target["umbrella_params"]["cv"] * nanometer # inform user: print("--> applying umbrella potential to " + str(list(pdb.topology.atoms())[umbrella_index]) + " at position " + str(pdb.positions[umbrella_index])) # additional restraining force applied to ion under umbrella restraints: umbrella_force = CustomExternalForce( "k*periodicdistance(0.0, 0.0, z, 0.0, 0.0, z0)^2") umbrella_force.addGlobalParameter("k", umbrella_fc) # z0 is set to value in JSON file rather than initial particle coordinate to # allow for a few steps of energy minimisation to avoid clashes between the # restrained umbrella target and surrounding atoms: umbrella_force.addGlobalParameter("z0", umbrella_cv) # select integrator: if argdict["integrator"] == "mts": # use multiple timestep RESPA integrator: print("--> using RESPA/MTS integrator") integrator = MTSIntegrator(sim_timestep, [(0, argdict["inner_ts_frac"]), (1, 1)]) elif argdict["integrator"] == "verlet": # use Leapfrog Verlet integrator here: print("--> using Verlet integrator") integrator = VerletIntegrator(sim_timestep) else: # no other integrators supported: raise Exception("Integrator " + str(argdict["integrator"]) + " is not supported.") # select a platform: platform = Platform.getPlatformByName(argdict["platform"]) properties = { "CudaPrecision": argdict["precision"], "CudaDeviceIndex": "0" } # prepare a simulation from topology, system, and integrator and set initial # positions as in PDB file: sim = Simulation(pdb.topology, sys, integrator, platform, properties) # is this initial simulation or restart from checkpoint? if argdict["log"] is None: # load positions and velocities from XML file: print("--> loading simulation state from XML file...") sim.loadState(xmlfile) # find all particles bonded to ion (i.e. Drude particles): idx_bonded = atom_idx_from_bonds(sim.topology, umbrella_index) idx_shift = idx_bonded + [umbrella_index] # shift target particle into position: pos = (sim.context.getState(getPositions=True).getPositions( asNumpy=True)) pos[idx_shift, :] = (umbrella_target["target_particle"]["init_pos"] * nanometer) print("--> target particle now placed at " + str(pos[idx_shift, :])) # set new particle positions in context: sim.context.setPositions(pos) e_pot = sim.context.getState(getEnergy=True).getPotentialEnergy() print("--> potential energy after target placement is: " + str(e_pot)) # minimise energy to remove clashes: # (too many steps might ruin everythin!) print("--> running energy minimisation...") sim.minimizeEnergy(maxIterations=argdict["minimisation_steps"]) e_pot = sim.context.getState(getEnergy=True).getPotentialEnergy() print( "--> " + str(argdict["minimisation_steps"]) + " steps of energy minimisation reduced the potential energy to " + str(e_pot)) # reduce time step for equilibration period: print("--> running equilibration at reduced time step...") sim.integrator.setStepSize(0.1 * sim.integrator.getStepSize()) sim.context.setTime(0.0 * picosecond) # will write report about equilibration phase: sim.reporters.append( StateDataReporter(stdout, int(argdict["equilibration_steps"] / 10), step=True, time=True, speed=True, progress=True, remainingTime=True, totalSteps=argdict["equilibration_steps"], separator="\t")) # run equilibration steps: sim.step(argdict["equilibration_steps"]) # reset step size to proper value: sim.integrator.setStepSize(10.0 * sim.integrator.getStepSize()) sim.context.setTime(0.0 * picosecond) sim.reporters.clear() else: # load checkpoint file: checkpoint_file = (str(argdict["outname"]) + "_" + str(argdict["restart_number"] - 1) + ".chk") print("--> loading checkpoint file " + checkpoint_file) sim.loadCheckpoint(checkpoint_file) # write collective variable value to file: sample_outname = (argdict["outname"] + "_" + str(argdict["restart_number"]) + str(".dat")) sim.reporters.append( CollectiveVariableReporter(sample_outname, argdict["umbrella_freq"], umbrella_index)) # write simulation trajectory to DCD file: dcd_outname = (argdict["outname"] + "_" + str(argdict["restart_number"]) + str(".dcd")) sim.reporters.append(DCDReporter(dcd_outname, sim_traj_rep_steps)) # write state data to tab-separated CSV file: state_outname = (argdict["outname"] + "_" + str(argdict["restart_number"]) + str(".csv")) sim.reporters.append( StateDataReporter(state_outname, sim_state_rep_steps, step=True, time=True, progress=False, remainingTime=True, potentialEnergy=True, kineticEnergy=True, totalEnergy=True, temperature=True, volume=True, density=False, speed=True, totalSteps=sim_num_steps, separator="\t")) # write limited state information to standard out: sim.reporters.append( StateDataReporter(stdout, sim_state_rep_steps, step=True, time=True, speed=True, progress=True, remainingTime=True, totalSteps=sim_num_steps, separator="\t")) # write checkpoint files regularly: checkpoint_outname = (argdict["outname"] + "_" + str(argdict["restart_number"]) + ".chk") sim.reporters.append( CheckpointReporter(checkpoint_outname, sim_checkpoint_steps)) # run simulation: sim.step(argdict["num_steps"]) # save final simulation state: sim.saveState(argdict["outname"] + "_" + str(argdict["restart_number"]) + ".xml") positions = sim.context.getState(getPositions=True).getPositions() PDBFile.writeFile( sim.topology, positions, open( argdict["outname"] + "_" + str(argdict["restart_number"]) + ".pdb", "w"))