vdw_lambda=vdw_lambda, annihilate_coulomb=True, annihilate_vdw=True)) # Create alchemical states where we turn on charges with full Lennard-Jones. for coulomb_lambda in coulomb_lambdas: alchemical_states.append( AlchemicalState(coulomb_lambda=coulomb_lambda, vdw_lambda=1.0, annihilate_coulomb=True, annihilate_vdw=True)) alchemical_factory = AbsoluteAlchemicalFactory( reference_system, alchemical_atoms=alchemical_atoms) systems = alchemical_factory.createPerturbedSystems( alchemical_states ) # systems[istate] will be the System object corresponding to alchemical intermediate state index 'istate' nstates = len(systems) #============================================================================== # Run simulation. #============================================================================== # Initialize NetCDF file to store data. import netCDF4 as netcdf ncfile = netcdf.Dataset(filename, 'w', version='NETCDF4') ncfile.createDimension('iteration', 0) # unlimited number of iterations ncfile.createDimension('state', nstates) # number of replicas ncfile.createDimension( 'atom', reference_system.getNumParticles()) # number of atoms in system ncfile.createDimension('spatial', 3) # number of spatial dimensions
def _create_phase(self, phase, reference_system, positions, atom_indices, thermodynamic_state, protocols=None, options=None, mpicomm=None): """ Create a repex object for a specified phase. Parameters ---------- phase : str The phase being initialized (one of ['complex', 'solvent', 'vacuum']) reference_system : simtk.openmm.System The reference system object from which alchemical intermediates are to be construcfted. positions : list of simtk.unit.Qunatity objects containing (natoms x 3) positions (as np or lists) The list of positions to be used to seed replicas in a round-robin way. atom_indices : dict atom_indices[phase][component] is the set of atom indices associated with component, where component is ['ligand', 'receptor'] thermodynamic_state : ThermodynamicState Thermodynamic state from which reference temperature and pressure are to be taken. protocols : dict of list of AlchemicalState, optional, default=None If specified, the alchemical protocol protocols[phase] will be used for phase 'phase' instead of the default. options : dict of str, optional, default=None If specified, these options will override default repex simulation options. """ # Make sure positions argument is a list of coordinate snapshots. if hasattr(positions, 'unit'): # Wrap in list. positions = [positions] # Check the dimensions of positions. for index in range(len(positions)): # Make sure it is recast as a np array. positions[index] = unit.Quantity(np.array(positions[index] / positions[index].unit), positions[index].unit) [natoms, ndim] = (positions[index] / positions[index].unit).shape if natoms != reference_system.getNumParticles(): raise Exception("positions argument must be a list of simtk.unit.Quantity of (natoms,3) lists or np array with units compatible with nanometers.") # Create metadata storage. metadata = dict() # Make a deep copy of the reference system so we don't accidentally modify it. reference_system = copy.deepcopy(reference_system) # TODO: Use more general approach to determine whether system is periodic. is_periodic = self._is_periodic(reference_system) # Make sure pressure is None if not periodic. if not is_periodic: thermodynamic_state.pressure = None # Compute standard state corrections for complex phase. metadata['standard_state_correction'] = 0.0 # TODO: Do we need to include a standard state correction for other phases in periodic boxes? if phase == 'complex-implicit': # Impose restraints for complex system in implicit solvent to keep ligand from drifting too far away from receptor. if self.verbose: print "Creating receptor-ligand restraints..." reference_positions = positions[0] if self.restraint_type == 'harmonic': restraints = HarmonicReceptorLigandRestraint(thermodynamic_state, reference_system, reference_positions, atom_indices['receptor'], atom_indices['ligand']) elif self.restraint_type == 'flat-bottom': restraints = FlatBottomReceptorLigandRestraint(thermodynamic_state, reference_system, reference_positions, atom_indices['receptor'], atom_indices['ligand']) else: raise Exception("restraint_type of '%s' is not supported." % self.restraint_type) force = restraints.getRestraintForce() # Get Force object incorporating restraints reference_system.addForce(force) metadata['standard_state_correction'] = restraints.getStandardStateCorrection() # standard state correction in kT elif phase == 'complex-explicit': # For periodic systems, we do not use a restraint, but must add a standard state correction for the box volume. # TODO: What if the box volume fluctuates during the simulation? box_vectors = reference_system.getDefaultPeriodicBoxVectors() box_volume = thermodynamic_state._volume(box_vectors) STANDARD_STATE_VOLUME = 1660.53928 * unit.angstrom**3 metadata['standard_state_correction'] = np.log(STANDARD_STATE_VOLUME / box_volume) # TODO: Check sign. # Use default alchemical protocols if not specified. if not protocols: protocols = self.default_protocols # Create alchemically-modified states using alchemical factory. if self.verbose: print "Creating alchemically-modified states..." factory = AbsoluteAlchemicalFactory(reference_system, ligand_atoms=atom_indices['ligand']) systems = factory.createPerturbedSystems(protocols[phase]) # Randomize ligand position if requested, but only for implicit solvent systems. if self.randomize_ligand and (phase == 'complex-implicit'): if self.verbose: print "Randomizing ligand positions and excluding overlapping configurations..." randomized_positions = list() nstates = len(systems) for state_index in range(nstates): positions_index = np.random.randint(0, len(positions)) current_positions = positions[positions_index] new_positions = ModifiedHamiltonianExchange.randomize_ligand_position(current_positions, atom_indices['receptor'], atom_indices['ligand'], self.randomize_ligand_sigma_multiplier * restraints.getReceptorRadiusOfGyration(), self.randomize_ligand_close_cutoff) randomized_positions.append(new_positions) positions = randomized_positions if self.randomize_ligand and (phase == 'complex-explicit'): print "WARNING: Ligand randomization requested, but will not be performed for explicit solvent simulations." # Identify whether any atoms will be displaced via MC. mc_atoms = list() if 'ligand' in atom_indices: mc_atoms = atom_indices['ligand'] # Combine simulation options with defaults. options = dict(self.default_options.items() + options.items()) # Set up simulation. # TODO: Support MPI initialization? if self.verbose: print "Creating replica exchange object..." store_filename = os.path.join(self._store_directory, phase + '.nc') self._store_filenames[phase] = store_filename simulation = ModifiedHamiltonianExchange(store_filename, mpicomm=mpicomm) simulation.create(thermodynamic_state, systems, positions, displacement_sigma=self.mc_displacement_sigma, mc_atoms=mc_atoms, options=options, metadata=metadata) simulation.verbose = self.verbose # Initialize simulation. # TODO: Use the right scheme for initializing the simulation without running. #if self.verbose: print "Initializing simulation..." #simulation.run(0) # TODO: Process user-supplied options. # Clean up simulation. del simulation return
def _create_phase(self, phase, reference_system, positions, atom_indices, thermodynamic_state, protocols=None, options=None, mpicomm=None): """ Create a repex object for a specified phase. Parameters ---------- phase : str The phase being initialized (one of ['complex', 'solvent', 'vacuum']) reference_system : simtk.openmm.System The reference system object from which alchemical intermediates are to be construcfted. positions : list of simtk.unit.Qunatity objects containing (natoms x 3) positions (as np or lists) The list of positions to be used to seed replicas in a round-robin way. atom_indices : dict atom_indices[phase][component] is the set of atom indices associated with component, where component is ['ligand', 'receptor'] thermodynamic_state : ThermodynamicState Thermodynamic state from which reference temperature and pressure are to be taken. protocols : dict of list of AlchemicalState, optional, default=None If specified, the alchemical protocol protocols[phase] will be used for phase 'phase' instead of the default. options : dict of str, optional, default=None If specified, these options will override default repex simulation options. """ # Make sure positions argument is a list of coordinate snapshots. if hasattr(positions, 'unit'): # Wrap in list. positions = [positions] # Check the dimensions of positions. for index in range(len(positions)): # Make sure it is recast as a np array. positions[index] = unit.Quantity( np.array(positions[index] / positions[index].unit), positions[index].unit) [natoms, ndim] = (positions[index] / positions[index].unit).shape if natoms != reference_system.getNumParticles(): raise Exception( "positions argument must be a list of simtk.unit.Quantity of (natoms,3) lists or np array with units compatible with nanometers." ) # Create metadata storage. metadata = dict() # Make a deep copy of the reference system so we don't accidentally modify it. reference_system = copy.deepcopy(reference_system) # TODO: Use more general approach to determine whether system is periodic. is_periodic = self._is_periodic(reference_system) # Make sure pressure is None if not periodic. if not is_periodic: thermodynamic_state.pressure = None # Compute standard state corrections for complex phase. metadata['standard_state_correction'] = 0.0 # TODO: Do we need to include a standard state correction for other phases in periodic boxes? if phase == 'complex-implicit': # Impose restraints for complex system in implicit solvent to keep ligand from drifting too far away from receptor. if self.verbose: print "Creating receptor-ligand restraints..." reference_positions = positions[0] if self.restraint_type == 'harmonic': restraints = HarmonicReceptorLigandRestraint( thermodynamic_state, reference_system, reference_positions, atom_indices['receptor'], atom_indices['ligand']) elif self.restraint_type == 'flat-bottom': restraints = FlatBottomReceptorLigandRestraint( thermodynamic_state, reference_system, reference_positions, atom_indices['receptor'], atom_indices['ligand']) else: raise Exception("restraint_type of '%s' is not supported." % self.restraint_type) force = restraints.getRestraintForce( ) # Get Force object incorporating restraints reference_system.addForce(force) metadata[ 'standard_state_correction'] = restraints.getStandardStateCorrection( ) # standard state correction in kT elif phase == 'complex-explicit': # For periodic systems, we do not use a restraint, but must add a standard state correction for the box volume. # TODO: What if the box volume fluctuates during the simulation? box_vectors = reference_system.getDefaultPeriodicBoxVectors() box_volume = thermodynamic_state._volume(box_vectors) STANDARD_STATE_VOLUME = 1660.53928 * unit.angstrom**3 metadata['standard_state_correction'] = np.log( STANDARD_STATE_VOLUME / box_volume) # TODO: Check sign. # Use default alchemical protocols if not specified. if not protocols: protocols = self.default_protocols # Create alchemically-modified states using alchemical factory. if self.verbose: print "Creating alchemically-modified states..." factory = AbsoluteAlchemicalFactory( reference_system, ligand_atoms=atom_indices['ligand']) systems = factory.createPerturbedSystems(protocols[phase]) # Randomize ligand position if requested, but only for implicit solvent systems. if self.randomize_ligand and (phase == 'complex-implicit'): if self.verbose: print "Randomizing ligand positions and excluding overlapping configurations..." randomized_positions = list() nstates = len(systems) for state_index in range(nstates): positions_index = np.random.randint(0, len(positions)) current_positions = positions[positions_index] new_positions = ModifiedHamiltonianExchange.randomize_ligand_position( current_positions, atom_indices['receptor'], atom_indices['ligand'], self.randomize_ligand_sigma_multiplier * restraints.getReceptorRadiusOfGyration(), self.randomize_ligand_close_cutoff) randomized_positions.append(new_positions) positions = randomized_positions # Identify whether any atoms will be displaced via MC. mc_atoms = list() if 'ligand' in atom_indices: mc_atoms = atom_indices['ligand'] # Combine simulation options with defaults. options = dict(self.default_options.items() + options.items()) # Set up simulation. # TODO: Support MPI initialization? if self.verbose: print "Creating replica exchange object..." store_filename = os.path.join(self._store_directory, phase + '.nc') self._store_filenames[phase] = store_filename simulation = ModifiedHamiltonianExchange(store_filename, mpicomm=mpicomm) simulation.create(thermodynamic_state, systems, positions, displacement_sigma=self.mc_displacement_sigma, mc_atoms=mc_atoms, options=options, metadata=metadata) simulation.verbose = self.verbose # Initialize simulation. # TODO: Use the right scheme for initializing the simulation without running. #if self.verbose: print "Initializing simulation..." #simulation.run(0) # TODO: Process user-supplied options. # Clean up simulation. del simulation return
# # Create alchemical intermediates. # print "Creating alchemical intermediates..." # Create a factory to produce alchemical intermediates. ligand_atoms = range(0, 2) # NaCl from alchemy import AbsoluteAlchemicalFactory factory = AbsoluteAlchemicalFactory(reference_system, ligand_atoms=ligand_atoms) # Get the default protocol for 'denihilating' in complex in explicit solvent. protocol = factory.defaultComplexProtocolImplicit() # Create the perturbed systems using this protocol. systems = factory.createPerturbedSystems(protocol, verbose=True) # # Set up replica exchange simulation. # print "Setting up replica-exchange simulation..." # Create reference state. from thermodynamics import ThermodynamicState reference_state = ThermodynamicState(reference_system, temperature=temperature, pressure=pressure) # Create simulation. from repex import HamiltonianExchange simulation = HamiltonianExchange(reference_state, systems, positions,
print "Creating alchemical intermediates..." alchemical_atoms = range(nfixed) # atoms to be alchemically modified alchemical_states = list() # alchemical_states[istate] is the alchemical state lambda specification for alchemical state 'istate' # Create alchemical states where we turn on Lennard-Jones (via softcore) with zero charge. for vdw_lambda in vdw_lambdas: alchemical_states.append( AlchemicalState(coulomb_lambda=0.0, vdw_lambda=vdw_lambda, annihilate_coulomb=True, annihilate_vdw=True) ) # Create alchemical states where we turn on charges with full Lennard-Jones. for coulomb_lambda in coulomb_lambdas: alchemical_states.append( AlchemicalState(coulomb_lambda=coulomb_lambda, vdw_lambda=1.0, annihilate_coulomb=True, annihilate_vdw=True) ) alchemical_factory = AbsoluteAlchemicalFactory(reference_system, alchemical_atoms=alchemical_atoms) systems = alchemical_factory.createPerturbedSystems(alchemical_states) # systems[istate] will be the System object corresponding to alchemical intermediate state index 'istate' nstates = len(systems) #============================================================================== # Run simulation. #============================================================================== # Initialize NetCDF file to store data. import netCDF4 as netcdf ncfile = netcdf.Dataset(filename, 'w', version='NETCDF4') ncfile.createDimension('iteration', 0) # unlimited number of iterations ncfile.createDimension('state', nstates) # number of replicas ncfile.createDimension('atom', reference_system.getNumParticles()) # number of atoms in system ncfile.createDimension('spatial', 3) # number of spatial dimensions ncfile.createVariable('positions', 'f', ('iteration','state','atom','spatial')) # positions (in A) ncfile.createVariable('box_vectors', 'f', ('iteration','state','spatial','spatial')) # box vectors (in A)
#!/usr/bin/env python """ Create alchemical intermediates for default alchemical protocol for p-xylene in T4 lysozyme L99A in GBSA. """ from alchemy import AbsoluteAlchemicalFactory from openmmtools import testsystems # Create a reference system. print "Creating a reference T4 lysozyme L99A system..." complex = testsystems.LysozymeImplicit() [reference_system, positions] = [complex.system, complex.positions] # Create a factory to produce alchemical intermediates. print "Creating an alchemical factory..." receptor_atoms = range(0,2603) # T4 lysozyme L99A ligand_atoms = range(2603,2621) # p-xylene factory = AbsoluteAlchemicalFactory(reference_system, ligand_atoms=ligand_atoms) # Get the default protocol for 'denihilating' in complex in explicit solvent. protocol = factory.defaultComplexProtocolImplicit() # Create the perturbed systems using this protocol. print "Creating a perturbed system..." systems = factory.createPerturbedSystems(protocol) print "Done."