def isomer_init(self): ''' The purpose of this function is to add to the primitives the driving coordinate prims if they dont exist. This is depracated because it's better to build the topology properly before initializing GSM. See main.py ''' #TODO ANGLE, TORSION or OOP between fragments will not work if using TRIC with BLOCK LA changed_top = False #TODO first check if there is any add/break then rebuild topology and makePrimitives for i in self.driving_coords: if "ADD" in i or "BREAK" in i: # order if i[1] < i[2]: bond = Distance(i[1] - 1, i[2] - 1) else: bond = Distance(i[2] - 1, i[1] - 1) self.nodes[0].coord_obj.Prims.add(bond, verbose=True) changed_top = True if "ANGLE" in i: if i[1] < i[3]: angle = Angle(i[1] - 1, i[2] - 1, i[3] - 1) else: angle = Angle(i[3] - 1, i[2] - 1, i[1] - 1) self.nodes[0].coord_obj.Prims.add(angle, verbose=True) if "TORSION" in i: if i[1] < i[4]: torsion = Dihedral(i[1] - 1, i[2] - 1, i[3] - 1, i[4] - 1) else: torsion = Dihedral(i[4] - 1, i[3] - 1, i[2] - 1, i[1] - 1) self.nodes[0].coord_obj.Prims.add(torsion, verbose=True) if "OOP" in i: if i[1] < i[4]: oop = OutOfPlane(i[1] - 1, i[2] - 1, i[3] - 1, i[4] - 1) else: oop = OutOfPlane(i[4] - 1, i[3] - 1, i[2] - 1, i[1] - 1) self.nodes[0].coord_obj.Prims.add(oop, verbose=True) self.nodes[0].coord_obj.Prims.clearCache() if changed_top: self.nodes[0].coord_obj.Prims.rebuild_topology_from_prim_bonds( self.nodes[0].xyz) self.nodes[0].coord_obj.Prims.reorderPrimitives() self.nodes[0].update_coordinate_basis()
def get_driving_coord_prim(dc): prim=None if "ADD" in dc or "BREAK" in dc: if dc[1]<dc[2]: prim = Distance(dc[1]-1,dc[2]-1) else: prim = Distance(dc[2]-1,dc[1]-1) elif "ANGLE" in dc: if dc[1]<dc[3]: prim = Angle(dc[1]-1,dc[2]-1,dc[3]-1) else: prim = Angle(dc[3]-1,dc[2]-1,dc[1]-1) elif "TORSION" in dc: if dc[1]<dc[4]: prim = Dihedral(dc[1]-1,dc[2]-1,dc[3]-1,dc[4]-1) else: prim = Dihedral(dc[4]-1,dc[3]-1,dc[2]-1,dc[1]-1) elif "OOP" in dc: #if dc[1]<dc[4]: prim = OutOfPlane(dc[1]-1,dc[2]-1,dc[3]-1,dc[4]-1) #else: # prim = OutOfPlane(dc[4]-1,dc[3]-1,dc[2]-1,dc[1]-1) return prim
def add_restraints(self, system): # Bond Restraints if self.restrain_bondfile is not None: nifty.printcool(" Adding bonding restraints!") # Harmonic constraint flat_bottom_force = openmm.CustomBondForce( 'step(r-r0) * (k/2) * (r-r0)^2') flat_bottom_force.addPerBondParameter('r0') flat_bottom_force.addPerBondParameter('k') system.addForce(flat_bottom_force) with open(self.restrain_bondfile, 'r') as input_file: for line in input_file: print(line) columns = line.split() atom_index_i = int(columns[0]) atom_index_j = int(columns[1]) r0 = float(columns[2]) k = float(columns[3]) flat_bottom_force.addBond(atom_index_i, atom_index_j, [r0, k]) # Torsion restraint if self.restrain_torfile is not None: nifty.printcool(" Adding torsional restraints!") # Harmonic constraint tforce = openmm.CustomTorsionForce( "0.5*k*min(dtheta, 2*pi-dtheta)^2; dtheta = abs(theta-theta0); pi = 3.1415926535" ) tforce.addPerTorsionParameter("k") tforce.addPerTorsionParameter("theta0") system.addForce(tforce) xyz = manage_xyz.xyz_to_np(self.geom) with open(self.restrain_torfile, 'r') as input_file: for line in input_file: columns = line.split() a = int(columns[0]) b = int(columns[1]) c = int(columns[2]) d = int(columns[3]) k = float(columns[4]) dih = Dihedral(a, b, c, d) theta0 = dih.value(xyz) tforce.addTorsion(a, b, c, d, [k, theta0]) # Translation restraint if self.restrain_tranfile is not None: nifty.printcool(" Adding translational restraints!") trforce = openmm.CustomExternalForce( "k*periodicdistance(x, y, z, x0, y0, z0)^2") trforce.addPerParticleParameter("k") trforce.addPerParticleParameter("x0") trforce.addPerParticleParameter("y0") trforce.addPerParticleParameter("z0") system.addForce(trforce) xyz = manage_xyz.xyz_to_np(self.geom) with open(self.restrain_tranfile, 'r') as input_file: for line in input_file: columns = line.split() a = int(columns[0]) k = float(columns[1]) x0 = xyz[a, 0] * 0.1 # Units are in nm y0 = xyz[a, 1] * 0.1 # Units are in nm z0 = xyz[a, 2] * 0.1 # Units are in nm trforce.addParticle(a, [k, x0, y0, z0])
def get_tangent(node1, node2, print_level=1, **kwargs): ''' Get internal coordinate tangent between two nodes, assumes they have unique IDs ''' if node2 is not None and node1.node_id != node2.node_id: print(" getting tangent from between %i %i pointing towards %i" % (node2.node_id, node1.node_id, node2.node_id)) assert node2 != None, 'node n2 is None' PMDiff = np.zeros(node2.num_primitives) for k, prim in enumerate(node2.primitive_internal_coordinates): if type(prim) is Distance: PMDiff[k] = 2.5 * prim.calcDiff(node2.xyz, node1.xyz) else: PMDiff[k] = prim.calcDiff(node2.xyz, node1.xyz) return np.reshape(PMDiff, (-1, 1)), None else: print(" getting tangent from node ", node1.node_id) driving_coords = kwargs.get('driving_coords', None) assert driving_coords is not None, " Driving coord is None!" c = Counter(elem[0] for elem in driving_coords) nadds = c['ADD'] nbreaks = c['BREAK'] nangles = c['nangles'] ntorsions = c['ntorsions'] ictan = np.zeros((node1.num_primitives, 1), dtype=float) # breakdq = 0.3 bdist = 0.0 atoms = node1.atoms xyz = node1.xyz.copy() for i in driving_coords: if "ADD" in i: # order indices to avoid duplicate bonds if i[1] < i[2]: index = [i[1] - 1, i[2] - 1] else: index = [i[2] - 1, i[1] - 1] bond = Distance(index[0], index[1]) prim_idx = node1.coord_obj.Prims.dof_index( index, 'Distance') if len(i) == 3: # TODO why not just use the covalent radii? d0 = (atoms[index[0]].vdw_radius + atoms[index[1]].vdw_radius) / 2.8 elif len(i) == 4: d0 = i[3] current_d = bond.value(xyz) # TODO don't set tangent if value is too small ictan[prim_idx] = -1 * (d0 - current_d) # if nbreaks>0: # ictan[prim_idx] *= 2 # => calc bdist <= if current_d > d0: bdist += np.dot(ictan[prim_idx], ictan[prim_idx]) if print_level > 0: print( " bond %s target (less than): %4.3f current d: %4.3f diff: %4.3f " % ((i[1], i[2]), d0, current_d, ictan[prim_idx])) elif "BREAK" in i: # order indices to avoid duplicate bonds if i[1] < i[2]: index = [i[1] - 1, i[2] - 1] else: index = [i[2] - 1, i[1] - 1] bond = Distance(index[0], index[1]) prim_idx = node1.coord_obj.Prims.dof_index( index, 'Distance') if len(i) == 3: d0 = (atoms[index[0]].vdw_radius + atoms[index[1]].vdw_radius) elif len(i) == 4: d0 = i[3] current_d = bond.value(xyz) ictan[prim_idx] = -1 * (d0 - current_d) # => calc bdist <= if current_d < d0: bdist += np.dot(ictan[prim_idx], ictan[prim_idx]) if print_level > 0: print( " bond %s target (greater than): %4.3f, current d: %4.3f diff: %4.3f " % ((i[1], i[2]), d0, current_d, ictan[prim_idx])) elif "ANGLE" in i: if i[1] < i[3]: index = [i[1] - 1, i[2] - 1, i[3] - 1] else: index = [i[3] - 1, i[2] - 1, i[1] - 1] angle = Angle(index[0], index[1], index[2]) prim_idx = node1.coord_obj.Prims.dof_index(index, 'Angle') anglet = i[4] ang_value = angle.value(xyz) ang_diff = anglet * np.pi / 180. - ang_value # print(" angle: %s is index %i " %(angle,ang_idx)) if print_level > 0: print( (" anglev: %4.3f align to %4.3f diff(rad): %4.3f" % (ang_value, anglet, ang_diff))) ictan[prim_idx] = -ang_diff # TODO need to come up with an adist # if abs(ang_diff)>0.1: # bdist+=ictan[ICoord1.BObj.nbonds+ang_idx]*ictan[ICoord1.BObj.nbonds+ang_idx] elif "TORSION" in i: if i[1] < i[4]: index = [i[1] - 1, i[2] - 1, i[3] - 1, i[4] - 1] else: index = [i[4] - 1, i[3] - 1, i[2] - 1, i[1] - 1] torsion = Dihedral(index[0], index[1], index[2], index[3]) prim_idx = node1.coord_obj.Prims.dof_index( index, 'Dihedral') tort = i[5] torv = torsion.value(xyz) tor_diff = tort - torv * 180. / np.pi if tor_diff > 180.: tor_diff -= 360. elif tor_diff < -180.: tor_diff += 360. ictan[prim_idx] = -tor_diff * np.pi / 180. if tor_diff * np.pi / 180. > 0.1 or tor_diff * np.pi / 180. < 0.1: bdist += np.dot(ictan[prim_idx], ictan[prim_idx]) if print_level > 0: print(( " current torv: %4.3f align to %4.3f diff(deg): %4.3f" % (torv * 180. / np.pi, tort, tor_diff))) elif "OOP" in i: index = [i[1] - 1, i[2] - 1, i[3] - 1, i[4] - 1] oop = OutOfPlane(index[0], index[1], index[2], index[3]) prim_idx = node1.coord_obj.Prims.dof_index( index, 'OutOfPlane') oopt = i[5] oopv = oop.value(xyz) oop_diff = oopt - oopv * 180. / np.pi if oop_diff > 180.: oop_diff -= 360. elif oop_diff < -180.: oop_diff += 360. ictan[prim_idx] = -oop_diff * np.pi / 180. if oop_diff * np.pi / 180. > 0.1 or oop_diff * np.pi / 180. < 0.1: bdist += np.dot(ictan[prim_idx], ictan[prim_idx]) if print_level > 0: print(( " current oopv: %4.3f align to %4.3f diff(deg): %4.3f" % (oopv * 180. / np.pi, oopt, oop_diff))) bdist = np.sqrt(bdist) if np.all(ictan == 0.0): raise RuntimeError(" All elements are zero") return ictan, bdist
def __init__(self, options): super(OpenMM, self).__init__(options) # get simulation from options if it exists #self.options['job_data']['simulation'] = self.options['job_data'].get('simulation',None) self.simulation = self.options['job_data'].get('simulation', None) if self.lot_inp_file is not None and self.simulation is None: # Now go through the logic of determining which FILE options are activated. self.file_options.set_active('use_crystal', False, bool, "Use crystal unit parameters") self.file_options.set_active( 'use_pme', False, bool, '', "Use particle mesh ewald-- requires periodic boundary conditions" ) self.file_options.set_active('cutoff', 1.0, float, '', depend=(self.file_options.use_pme), msg="Requires PME") self.file_options.set_active('prmtopfile', None, str, "parameter file") self.file_options.set_active('inpcrdfile', None, str, "inpcrd file") self.file_options.set_active('restrain_torfile', None, str, "list of torsions to restrain") self.file_options.set_active('restrain_tranfile', None, str, "list of translations to restrain") for line in self.file_options.record(): print(line) # set all active values to self for easy access for key in self.file_options.ActiveOptions: setattr(self, key, self.file_options.ActiveOptions[key]) nifty.printcool(" Options for OpenMM") for val in [self.prmtopfile, self.inpcrdfile]: assert val != None, "Missing prmtop or inpcrdfile" # Integrator will never be used (Simulation requires one) integrator = openmm.VerletIntegrator(1.0) # create simulation object if self.use_crystal: crystal = load_file(self.prmtopfile, self.inpcrdfile) if self.use_pme: system = crystal.createSystem( nonbondedMethod=openmm_app.PME, nonbondedCutoff=self.cutoff * openmm_units.nanometer, ) else: system = crystal.createSystem( nonbondedMethod=openmm_app.NoCutoff, ) # Torsion restraint if self.restrain_torfile is not None: nifty.printcool(" Adding torsional restraints!") # Harmonic constraint tforce = openmm.CustomTorsionForce( "0.5*k*min(dtheta, 2*pi-dtheta)^2; dtheta = abs(theta-theta0); pi = 3.1415926535" ) tforce.addPerTorsionParameter("k") tforce.addPerTorsionParameter("theta0") system.addForce(tforce) xyz = manage_xyz.xyz_to_np(self.geom) with open(self.restrain_torfile, 'r') as input_file: for line in input_file: columns = line.split() a = int(columns[0]) b = int(columns[1]) c = int(columns[2]) d = int(columns[3]) k = float(columns[4]) dih = Dihedral(a, b, c, d) theta0 = dih.value(xyz) tforce.addTorsion(a, b, c, d, [k, theta0]) # Translation restraint if self.restrain_tranfile is not None: nifty.printcool(" Adding translational restraints!") trforce = openmm.CustomExternalForce( "k*periodicdistance(x, y, z, x0, y0, z0)^2") trforce.addPerParticleParameter("k") trforce.addPerParticleParameter("x0") trforce.addPerParticleParameter("y0") trforce.addPerParticleParameter("z0") system.addForce(trforce) xyz = manage_xyz.xyz_to_np(self.geom) with open(self.restrain_tranfile, 'r') as input_file: for line in input_file: columns = line.split() a = int(columns[0]) k = float(columns[1]) x0 = xyz[a, 0] * 0.1 # Units are in nm y0 = xyz[a, 1] * 0.1 # Units are in nm z0 = xyz[a, 2] * 0.1 # Units are in nm trforce.addParticle(a, [k, x0, y0, z0]) self.simulation = openmm_app.Simulation( crystal.topology, system, integrator) # set the box vectors inpcrd = openmm_app.AmberInpcrdFile(self.inpcrdfile) if inpcrd.boxVectors is not None: print(" setting box vectors") print(inpcrd.boxVectors) self.simulation.context.setPeriodicBoxVectors( *inpcrd.boxVectors) else: # Do not use crystal parameters prmtop = openmm_app.AmberPrmtopFile(self.prmtopfile) if self.use_pme: system = prmtop.createSystem( nonbondedMethod=openmm_app.PME, nonbondedCutoff=self.cutoff * openmm_units.nanometer, ) else: system = prmtop.createSystem( nonbondedMethod=openmm_app.NoCutoff, ) # Torsion restraint if self.restrain_torfile is not None: nifty.printcool(" Adding torsional restraints!") # Harmonic constraint tforce = openmm.CustomTorsionForce( "0.5*k*min(dtheta, 2*pi-dtheta)^2; dtheta = abs(theta-theta0); pi = 3.1415926535" ) tforce.addPerTorsionParameter("k") tforce.addPerTorsionParameter("theta0") system.addForce(tforce) xyz = manage_xyz.xyz_to_np(self.geom) with open(self.restrain_torfile, 'r') as input_file: for line in input_file: columns = line.split() a = int(columns[0]) b = int(columns[1]) c = int(columns[2]) d = int(columns[3]) k = float(columns[4]) dih = Dihedral(a, b, c, d) theta0 = dih.value(xyz) tforce.addTorsion(a, b, c, d, [k, theta0]) # Translation restraint if self.restrain_tranfile is not None: nifty.printcool(" Adding translational restraints!") trforce = openmm.CustomExternalForce( "k*distance(x, y, z, x0, y0, z0)^2") trforce.addPerParticleParameter("k") trforce.addPerParticleParameter("x0") trforce.addPerParticleParameter("y0") trforce.addPerParticleParameter("z0") system.addForce(trforce) xyz = manage_xyz.xyz_to_np(self.geom) with open(self.restrain_tranfile, 'r') as input_file: for line in input_file: columns = line.split() a = int(columns[0]) k = float(columns[1]) x0 = xyz[a, 0] * 0.1 # Units are in nm y0 = xyz[a, 1] * 0.1 # Units are in nm z0 = xyz[a, 2] * 0.1 # Units are in nm trforce.addParticle(a, [k, x0, y0, z0]) self.simulation = openmm_app.Simulation( prmtop.topology, system, integrator, )