def extract_dummy_atoms(structure, resname=None, serial=True): """ Extract information about dummy atoms from a parmed structure and returns the information as a dictionary. Parameters ---------- structure : :class:`parmed.Structure` The parmed structure object we want to extract from resname : list List of residue name for the dummy atoms (default: ["DM1", "DM2", "DM3"]) serial : bool get indices in serial (starts from 1) or index (starts from 0) Returns ------- dummy_atoms : dict A dictionary containing positions (``pos``), index (``idx``) and mass (``mass``) of dummy atoms. """ if resname is None: resname = ["DM1", "DM2", "DM3"] dummy_atoms = {name: {} for name in resname} for dummy_atom in resname: residue = f":{dummy_atom}" dummy_atoms[dummy_atom]["pos"] = structure[residue].coordinates[0] dummy_atoms[dummy_atom]["mass"] = [ atom.mass for atom in structure[residue].atoms ][0] dummy_atoms[dummy_atom]["idx"] = utils.index_from_mask( structure, residue, amber_index=serial)[0] dummy_atoms[dummy_atom]["idx_type"] = "serial" if serial else "index" return dummy_atoms
def initialize(self): """ Automatically set remaining force constants and targets. Depending on which values are provided for each phase, a different method will be used to determine the list of force constants and targets (below). For attach and release, a ``target`` value is required and the method is determined if the following values are not ``None``: - Method 1: num_windows, fc_initial, fc_final - Method 1a: num_windows, fc_final - Method 2: fc_increment, fc_initial, fc_final - Method 2a: fc_increment, fc_final - Method 3: fraction_list, fc_final - Method 4: fraction_increment, fc_final - Method 5: fc_list For pull, a ``fc`` value is required and the method is determined if the following values are not ``None``: - Method 1: num_windows, target_initial, target_final - Method 1a: num_windows, target_final - Method 2: target_increment, target_initial, target_final - Method 2a: target_increment, target_final - Method 3: fraction_list, target_final - Method 4: fraction_increment, target_final - Method 5: target_list .. note :: This is unnecessary overengineering. """ self.phase = { "attach": { "force_constants": None, "targets": None }, "pull": { "force_constants": None, "targets": None }, "release": { "force_constants": None, "targets": None }, } # ------------------------------------ ATTACH ------------------------------------ # logger.debug("Calculating attach targets and force constants...") # Temporary variables to improve readability force_constants = None targets = None if (self.attach["num_windows"] is not None and self.attach["fc_final"] is not None): if self.attach["fc_initial"] is not None: logger.debug("Attach, Method #1") force_constants, targets = self._calc_method( "a", self.attach, "1") else: logger.debug("Attach, Method #1a") force_constants, targets = self._calc_method( "a", self.attach, "1a") elif (self.attach["fc_increment"] is not None and self.attach["fc_final"] is not None): if self.attach["fc_initial"] is not None: logger.debug("Attach, Method #2") force_constants, targets = self._calc_method( "a", self.attach, "2") else: logger.debug("Attach, Method #2a") force_constants, targets = self._calc_method( "a", self.attach, "2a") elif (self.attach["fraction_list"] is not None and self.attach["fc_final"] is not None): logger.debug("Attach, Method #3") force_constants, targets = self._calc_method("a", self.attach, "3") elif (self.attach["fraction_increment"] is not None and self.attach["fc_final"] is not None): logger.debug("Attach, Method #4") force_constants, targets = self._calc_method("a", self.attach, "4") elif self.attach["fc_list"] is not None: logger.debug("Attach, Method #5") force_constants, targets = self._calc_method("a", self.attach, "5") elif all(v is None for k, v in self.attach.items()): logger.debug( "No restraint info set for the attach phase! Skipping...") else: logger.error( "Attach restraint input did not match one of the supported methods..." ) for k, v in self.attach.items(): logger.debug("{} = {}".format(k, v)) raise Exception( "Attach restraint input did not match one of the supported methods..." ) if force_constants is not None and targets is not None: self.phase["attach"]["force_constants"] = force_constants self.phase["attach"]["targets"] = targets # ------------------------------------ PULL ------------------------------------ # logger.debug("Calculating pull targets and force constants...") force_constants = None targets = None if self.auto_apr and self.pull["target_final"] is not None: self.pull["fc"] = self.phase["attach"]["force_constants"][-1] self.pull["target_initial"] = self.phase["attach"]["targets"][-1] if (self.pull["num_windows"] is not None and self.pull["target_final"] is not None): if self.pull["target_initial"] is not None: logger.debug("Pull, Method #1") force_constants, targets = self._calc_method( "p", self.pull, "1") else: logger.debug("Pull, Method #1a") force_constants, targets = self._calc_method( "p", self.pull, "1a") elif (self.pull["target_increment"] is not None and self.pull["target_final"] is not None): if self.pull["target_initial"] is not None: logger.debug("Pull, Method #2") force_constants, targets = self._calc_method( "p", self.pull, "2") else: logger.debug("Pull, Method #2a") force_constants, targets = self._calc_method( "p", self.pull, "2a") elif (self.pull["fraction_list"] is not None and self.pull["target_final"] is not None): logger.debug("Pull, Method #3") force_constants, targets = self._calc_method("p", self.pull, "3") elif (self.pull["fraction_increment"] is not None and self.pull["target_final"] is not None): logger.debug("Pull, Method #4") force_constants, targets = self._calc_method("p", self.pull, "4") elif self.pull["target_list"] is not None: logger.debug("Pull, Method #5") force_constants, targets = self._calc_method("p", self.pull, "5") elif all(v is None for k, v in self.pull.items()): logger.debug( "No restraint info set for the pull phase! Skipping...") else: logger.error( "Pull restraint input did not match one of the supported methods..." ) for k, v in self.pull.items(): logger.debug("{} = {}".format(k, v)) raise Exception( "Pull restraint input did not match one of the supported methods..." ) if force_constants is not None and targets is not None: self.phase["pull"]["force_constants"] = force_constants self.phase["pull"]["targets"] = targets # ------------------------------------ RELEASE ------------------------------------ # logger.debug("Calculating release targets and force constants...") force_constants = None targets = None # I don't want auto_apr to make release restraints, unless I'm sure the user wants them. # I'm gonna assume that specifying self.attach['fc_final'] indicates you want it, # although this weakens the whole purpose of auto_apr. if self.auto_apr and self.release["fc_final"] is not None: self.release["target"] = self.phase["pull"]["targets"][-1] for key in [ "fc_final", "fc_initial", "num_windows", "fc_increment", "fraction_increment", "fraction_list", "fc_list", ]: if self.attach[key] is not None and self.release[key] is None: self.release[key] = self.attach[key] if (self.release["num_windows"] is not None and self.release["fc_final"] is not None): if self.release["fc_initial"] is not None: logger.debug("Release, Method #1") force_constants, targets = self._calc_method( "r", self.release, "1") else: logger.debug("Release, Method #1a") force_constants, targets = self._calc_method( "r", self.release, "1a") elif (self.release["fc_increment"] is not None and self.release["fc_final"] is not None): if self.release["fc_initial"] is not None: logger.debug("Release, Method #2") force_constants, targets = self._calc_method( "r", self.release, "2") else: logger.debug("Release, Method #2a") force_constants, targets = self._calc_method( "r", self.release, "2a") elif (self.release["fraction_list"] is not None and self.release["fc_final"] is not None): logger.debug("Release, Method #3") force_constants, targets = self._calc_method( "r", self.release, "3") elif (self.release["fraction_increment"] is not None and self.release["fc_final"] is not None): logger.debug("Release, Method #4") force_constants, targets = self._calc_method( "r", self.release, "4") elif self.release["fc_list"] is not None: logger.debug("Release, Method #5") force_constants, targets = self._calc_method( "r", self.release, "5") elif all(v is None for k, v in self.release.items()): logger.debug( "No restraint info set for the release phase! Skipping...") else: logger.error( "Release restraint input did not match one of the supported methods..." ) for k, v in self.release.items(): logger.debug("{} = {}".format(k, v)) raise Exception( "Release restraint input did not match one of the supported methods..." ) if force_constants is not None and targets is not None: self.phase["release"]["force_constants"] = force_constants self.phase["release"]["targets"] = targets # ----------------------------------- WINDOWS ------------------------------------ # for phase in ["attach", "pull", "release"]: if self.phase[phase]["targets"] is not None: window_count = len(self.phase[phase]["targets"]) logger.debug("Number of {} windows = {}".format( phase, window_count)) else: logger.debug( "This restraint will be skipped in the {} phase".format( phase)) # ---------------------------------- ATOM MASKS ---------------------------------- # logger.debug("Assigning atom indices...") self.index1 = utils.index_from_mask(self.topology, self.mask1, self.amber_index) self.index2 = utils.index_from_mask(self.topology, self.mask2, self.amber_index) if self.mask3: self.index3 = utils.index_from_mask(self.topology, self.mask3, self.amber_index) else: self.index3 = None if self.mask4: self.index4 = utils.index_from_mask(self.topology, self.mask4, self.amber_index) else: self.index4 = None # If any `index` has more than one atom, mark it as a group restraint. if self.mask1 and len(self.index1) > 1: self.group1 = True if self.mask2 and len(self.index2) > 1: self.group2 = True if self.mask3 and len(self.index3) > 1: self.group3 = True if self.mask4 and len(self.index4) > 1: self.group4 = True
def test_openmm_cb6but_sim(num_rests=0, guest_pos='guest_inside'): path = './cb6-but_test/' + guest_pos + '/' topology = 'cb6-but-dum.prmtop' coordinates = 'cb6-but-dum.rst7' if num_rests > 0: md_out = 'cb6_but_openmm_rest_{:02d}.csv'.format(num_rests) traj_out = 'cb6_but_openmm_rest_{:02d}.nc'.format(num_rests) else: md_out = 'cb6_but_openmm.csv' traj_out = 'cb6_but_openmm.nc' structure = pmd.load_file(path + topology, path + coordinates, structure=True) traj = pt.load(path + coordinates, path + topology) host = ":CB6" guest = ":BUT" H = [host + "@C7", host + "@C31", host + "@C19"] G = [guest + "@C", guest + "@C3"] D = [":DM1", ":DM2", ":DM3"] H_i = [0, 0, 0] G_i = [0, 0] D_i = [0, 0, 0] # Get indices for atom masks for i, mask in enumerate(H): H_i[i] = utils.index_from_mask(structure, mask, amber_index=False)[0] for i, mask in enumerate(G): G_i[i] = utils.index_from_mask(structure, mask, amber_index=False)[0] for i, mask in enumerate(D): D_i[i] = utils.index_from_mask(structure, mask, amber_index=False)[0] # Set mass of Dummy atoms to 0 so they are non-interacting for i, atom in enumerate(structure.atoms): if atom.name == 'DUM': atom.mass = 0.0 topology_0m = 'cb6-but-dum-0m.prmtop' coordinates_0m = 'cb6-but-dum-0m.rst7' structure.save(path + topology_0m, overwrite=True) structure.save(path + coordinates_0m, overwrite=True) prmtop = app.AmberPrmtopFile(path + topology_0m) inpcrd = app.AmberInpcrdFile(path + coordinates_0m) settings = { 'nonbonded_method': app.NoCutoff, 'temperature': 298.15 * unit.kelvin, 'friction': 1 / unit.picosecond, 'timestep': 0.002 * unit.picosecond, 'implicit_solvent': app.HCT, 'dist_fc': 5.0, 'angle_fc': 100.0, 'numsteps': 500000, } system = prmtop.createSystem( nonbondedMethod=settings['nonbonded_method'], implicitSolvent=settings['implicit_solvent'], removeCMMotion=False, ) integrator = LangevinIntegrator(settings['temperature'], settings['friction'], settings['timestep']) # Create Positional Restraints for Dummy atoms pos_restraint = mm.CustomExternalForce('k*((x-x0)^2+(y-y0)^2+(z-z0)^2)') pos_restraint.addGlobalParameter( 'k', 50.0 * unit.kilocalories_per_mole / unit.angstroms**2) pos_restraint.addPerParticleParameter('x0') pos_restraint.addPerParticleParameter('y0') pos_restraint.addPerParticleParameter('z0') for i, atom in enumerate(structure.positions): if structure.atoms[i].name == 'DUM': pos_restraint.addParticle(i, atom.value_in_unit(unit.nanometers)) static_restraints = [] # Create Distance Restraint static_distance_rest = [D[0], H[0]] static_init_dist = pt.distance(traj, D[0] + ' ' + H[0])[0] dist_restraint = mm.CustomBondForce('k*(r-r0)^2') dist_restraint.addPerBondParameter('k') dist_restraint.addPerBondParameter('r0') r0 = static_init_dist * unit.angstroms k = settings['dist_fc'] * unit.kilocalories_per_mole / unit.angstroms**2 dist_restraint.addBond(D_i[0], H_i[0], [k, r0]) static_restraints.append(dist_restraint) # Create Angle Restraint 1 static_angle_rest_1 = [D[1], D[0], H[0]] static_init_angle_1 = pt.angle(traj, D[1] + ' ' + D[0] + ' ' + H[0])[0] angle_restraint_1 = mm.CustomAngleForce('0.5*k*(theta-theta0)^2') angle_restraint_1.addPerAngleParameter('k') angle_restraint_1.addPerAngleParameter('theta0') theta0 = static_init_angle_1 * unit.degrees k = settings['angle_fc'] * unit.kilocalories_per_mole / unit.radians**2 angle_restraint_1.addAngle(D_i[1], D_i[0], H_i[0], [k, theta0]) static_restraints.append(angle_restraint_1) # Create Dihedral Restraint 1 static_dihedral_rest_1 = [D[2], D[1], D[0], H[0]] static_init_dihedral_1 = pt.dihedral( traj, D[2] + ' ' + D[1] + ' ' + D[0] + ' ' + H[0])[0] dihedral_restraint_1 = mm.CustomTorsionForce('0.5*k*(theta-theta0)^2') dihedral_restraint_1.addPerTorsionParameter('k') dihedral_restraint_1.addPerTorsionParameter('theta0') theta0 = static_init_dihedral_1 * unit.degrees k = settings['angle_fc'] * unit.kilocalories_per_mole / unit.radians**2 dihedral_restraint_1.addTorsion(D_i[2], D_i[1], D_i[0], H_i[0], [k, theta0]) static_restraints.append(dihedral_restraint_1) # Create Angle Restraint 2 static_angle_rest_2 = [D[0], H[0], H[1]] static_init_angle_2 = pt.angle(traj, D[0] + ' ' + H[0] + ' ' + H[1])[0] angle_restraint_2 = mm.CustomAngleForce('0.5*k*(theta-theta0)^2') angle_restraint_2.addPerAngleParameter('k') angle_restraint_2.addPerAngleParameter('theta0') theta0 = static_init_angle_2 * unit.degrees k = settings['angle_fc'] * unit.kilocalories_per_mole / unit.radians**2 angle_restraint_2.addAngle(D_i[0], H_i[0], H_i[1], [k, theta0]) static_restraints.append(angle_restraint_2) # Create Dihedral Restraint 2 static_dihedral_rest_2 = [D[1], D[0], H[0], H[1]] static_init_dihedral_2 = pt.dihedral( traj, D[1] + ' ' + D[0] + ' ' + H[0] + ' ' + H[1])[0] dihedral_restraint_2 = mm.CustomTorsionForce('0.5*k*(theta-theta0)^2') dihedral_restraint_2.addPerTorsionParameter('k') dihedral_restraint_2.addPerTorsionParameter('theta0') theta0 = static_init_dihedral_2 * unit.degrees k = settings['angle_fc'] * unit.kilocalories_per_mole / unit.radians**2 dihedral_restraint_2.addTorsion(D_i[1], D_i[0], H_i[0], H_i[1], [k, theta0]) static_restraints.append(dihedral_restraint_2) # Create Dihedral Restraint 3 static_dihedral_rest_3 = [D[0], H[0], H[1], H[2]] static_init_dihedral_3 = pt.dihedral( traj, D[0] + ' ' + H[0] + ' ' + H[1] + ' ' + H[2])[0] dihedral_restraint_3 = mm.CustomTorsionForce('0.5*k*(theta-theta0)^2') dihedral_restraint_3.addPerTorsionParameter('k') dihedral_restraint_3.addPerTorsionParameter('theta0') theta0 = static_init_dihedral_3 * unit.degrees k = settings['angle_fc'] * unit.kilocalories_per_mole / unit.radians**2 dihedral_restraint_3.addTorsion(D_i[0], H_i[0], H_i[1], H_i[2], [k, theta0]) static_restraints.append(dihedral_restraint_3) #system.addForce(pos_restraint) if num_rests > 0: for rest in static_restraints[0:num_rests]: system.addForce(rest) simulation = app.Simulation(prmtop.topology, system, integrator, mm.Platform.getPlatformByName('CPU')) simulation.context.setPositions(inpcrd.positions) simulation.reporters.append(NetCDFReporter(path + traj_out, 250)) simulation.reporters.append( app.StateDataReporter(path + md_out, 250, step=True, time=True, potentialEnergy=True, kineticEnergy=True, totalEnergy=True, temperature=True, volume=True, density=True)) simulation.step(settings['numsteps'])
constraints=settings["constraints"], implicitSolvent=settings["implicit_solvent"], ) static_restraints = [] dist_restraint = mm.CustomBondForce("k*(r-r0)^2") dist_restraint.addPerBondParameter("k") dist_restraint.addPerBondParameter("r0") rest = rests[0] # first static restraint static_init_dist = rest.phase[phase]["targets"][window_num] bond_fc = rest.phase[phase]["force_constants"][window_num] r0 = static_init_dist * unit.angstroms k = bond_fc * unit.kilocalories_per_mole / unit.angstroms**2 a1 = utils.index_from_mask(structure, mask=rest.mask1, amber_index=False) a2 = utils.index_from_mask(structure, mask=rest.mask2, amber_index=False) dist_restraint.addBond(a1[0], a2[0], [k, r0]) static_restraints.append(dist_restraint) angle_restraint_1 = mm.CustomAngleForce("0.5*k*(theta-theta0)^2") angle_restraint_1.addPerAngleParameter("k") angle_restraint_1.addPerAngleParameter("theta0") rest = rests[1] # second static restraint static_init_angle_1 = rest.phase[phase]["targets"][window_num] angle_fc = rest.phase[phase]["force_constants"][window_num] theta0 = static_init_angle_1 * unit.degrees k = angle_fc * unit.kilocalories_per_mole / unit.radians**2 a1 = utils.index_from_mask(structure, mask=rest.mask1, amber_index=False)