def _write_omm_cmaps(self, xml_root, skip_types): if not self.cmap_types: return xml_force = etree.SubElement(xml_root, 'CMAPTorsionForce') maps = dict() counter = 0 econv = u.kilocalorie.conversion_factor_to(u.kilojoule) for _, cmap in iteritems(self.cmap_types): if id(cmap) in maps: continue maps[id(cmap)] = counter counter += 1 xml_map = etree.SubElement(xml_force, 'Map') grid = cmap.grid.switch_range().T map_string = '' for i in range(cmap.resolution): base = i * cmap.resolution for j in range(cmap.resolution): map_string += ' %s' % (grid[base+j]*econv) map_string += '\n' xml_map.text = map_string used_torsions = set() for (a1, a2, a3, a4, _, _, _, a5), cmap in iteritems(self.cmap_types): if any((a in skip_types for a in (a1, a2, a3, a4, a5))): continue if (a1, a2, a3, a4, a5) in used_torsions: continue used_torsions.add((a1, a2, a3, a4, a5)) used_torsions.add((a5, a4, a3, a2, a1)) etree.SubElement(xml_force, 'Torsion', map=str(maps[id(cmap)]), type1=a1, type2=a2, type3=a3, type4=a4, type5=a5)
def _write_omm_cmaps(self, dest, skip_types): if not self.cmap_types: return dest.write(' <CmapTorsionForce>\n') maps = dict() counter = 0 econv = u.kilocalorie.conversion_factor_to(u.kilojoule) for _, cmap in iteritems(self.cmap_types): if id(cmap) in maps: continue maps[id(cmap)] = counter counter += 1 dest.write(' <Map>\n') grid = cmap.grid.switch_range().T for i in range(cmap.resolution): dest.write(' ') base = i * cmap.resolution for j in range(cmap.resolution): dest.write(' %s' % (grid[base + j] * econv)) dest.write('\n') dest.write(' </Map>\n') used_torsions = set() for (a1, a2, a3, a4, _, _, _, a5), cmap in iteritems(self.cmap_types): if any((a in skip_types for a in (a1, a2, a3, a4, a5))): continue if (a1, a2, a3, a4, a5) in used_torsions: continue used_torsions.add((a1, a2, a3, a4, a5)) used_torsions.add((a5, a4, a3, a2, a1)) dest.write(' <Torsion map="%d" type1="%s" type2="%s" ' 'type3="%s" type4="%s" type5="%s"/>\n' % (maps[id(cmap)], a1, a2, a3, a4, a5)) dest.write(' </CmapTorsionForce>\n')
def _write_omm_cmaps(self, dest, skip_types): if not self.cmap_types: return dest.write(" <CmapTorsionForce>\n") maps = dict() counter = 0 econv = u.kilocalorie.conversion_factor_to(u.kilojoule) for _, cmap in iteritems(self.cmap_types): if id(cmap) in maps: continue maps[id(cmap)] = counter counter += 1 dest.write(" <Map>\n") grid = cmap.grid.switch_range().T for i in range(cmap.resolution): dest.write(" ") base = i * cmap.resolution for j in range(cmap.resolution): dest.write(" %s" % (grid[base + j] * econv)) dest.write("\n") dest.write(" </Map>\n") used_torsions = set() for (a1, a2, a3, a4, _, _, _, a5), cmap in iteritems(self.cmap_types): if any((a in skip_types for a in (a1, a2, a3, a4, a5))): continue if (a1, a2, a3, a4, a5) in used_torsions: continue used_torsions.add((a1, a2, a3, a4, a5)) used_torsions.add((a5, a4, a3, a2, a1)) dest.write( ' <Torsion map="%d" type1="%s" type2="%s" ' 'type3="%s" type4="%s" type5="%s"/>\n' % (maps[id(cmap)], a1, a2, a3, a4, a5) ) dest.write(" </CmapTorsionForce>\n")
def get_typeset(set1, set2): ids1 = set() ids2 = set() for _, item in iteritems(set1): ids1.add(id(item)) for _, item in iteritems(set2): ids2.add(id(item)) return ids1, ids2
def _write_omm_LennardJonesForce(self, dest, skip_types, separate_ljforce): if not self.nbfix_types and not separate_ljforce: return # Convert Conversion factors for writing in natural OpenMM units length_conv = u.angstrom.conversion_factor_to(u.nanometer) ene_conv = u.kilocalories.conversion_factor_to(u.kilojoules) scnb = set() for key in self.dihedral_types: dt = self.dihedral_types[key] for t in dt: if t.scnb: scnb.add(t.scnb) if len(scnb) > 1: raise NotImplementedError( 'Cannot currently handle mixed 1-4 ' 'scaling: L-J Scaling factors %s detected' % (', '.join([str(x) for x in scnb]))) if len(scnb) > 0: lj14scale = 1.0 / scnb.pop() else: lj14scale = 1.0 / self.default_scnb # write L-J records dest.write(' <LennardJonesForce lj14scale="%s">\n' % lj14scale) for name, atom_type in iteritems(self.atom_types): if name in skip_types: continue if (atom_type.rmin is not None) and (atom_type.epsilon is not None): sigma = atom_type.sigma * length_conv # in md_unit_system epsilon = atom_type.epsilon * ene_conv # in md_unit_system else: # Dummy atom sigma = 1.0 epsilon = 0.0 # Ensure we don't have sigma = 0 if (sigma == 0.0): if (epsilon == 0.0): sigma = 1.0 # reset sigma = 1 else: raise ValueError("For atom type '%s', sigma = 0 but " "epsilon != 0." % name) dest.write(' <Atom type="%s" sigma="%s" epsilon="%s"/>\n' % (name, sigma, abs(epsilon))) # write NBFIX records for (atom_types, value) in iteritems(self.nbfix_types): emin = value[0] * ene_conv rmin = value[1] * length_conv # convert to sigma sigma = 2 * rmin / (2**(1.0 / 6)) dest.write( ' <NBFixPair type1="%s" type2="%s" sigma="%s" epsilon="%s"/>\n' % (atom_types[0], atom_types[1], sigma, emin)) dest.write(' </LennardJonesForce>\n')
def _write_omm_dihedrals(self, dest, skip_types, improper_dihedrals_ordering): if not self.dihedral_types and not self.improper_periodic_types: return # In ParameterSet, dihedral_types is *always* of type DihedralTypeList. # The from_structure method ensures that, even if the containing # Structure has separate dihedral entries for each torsion if improper_dihedrals_ordering == 'default': dest.write(' <PeriodicTorsionForce>\n') else: dest.write(' <PeriodicTorsionForce ordering="%s">\n' % improper_dihedrals_ordering) diheds_done = set() pconv = u.degree.conversion_factor_to(u.radians) kconv = u.kilocalorie.conversion_factor_to(u.kilojoule) def nowild(name): return name if name != 'X' else '' for (a1, a2, a3, a4), dihed in iteritems(self.dihedral_types): if any((a in skip_types for a in (a1, a2, a3, a4))): continue if (a1, a2, a3, a4) in diheds_done: continue diheds_done.add((a1, a2, a3, a4)) diheds_done.add((a4, a3, a2, a1)) dest.write(' <Proper type1="%s" type2="%s" type3="%s" ' 'type4="%s"' % (nowild(a1), a2, a3, nowild(a4))) for i, term in enumerate(dihed): i += 1 dest.write(' periodicity%d="%d" phase%d="%s" k%d="%s"' % (i, term.per, i, term.phase * pconv, i, term.phi_k * kconv)) dest.write('/>\n') # Now do the periodic impropers. OpenMM expects the central atom to be # listed first. ParameterSet goes out of its way to list it third # (consistent with Amber) except in instances where order is random (as # in CHARMM parameter files). But CHARMM parameter files don't have # periodic impropers, so we don't have to worry about that here. for (a2, a3, a1, a4), improp in iteritems(self.improper_periodic_types): if any((a in skip_types for a in (a1, a2, a3, a4))): continue # Try to make the wild-cards in the middle if a4 == 'X': if a2 != 'X': a2, a4 = a4, a2 elif a3 != 'X': a3, a4 = a4, a3 if a2 != 'X' and a3 == 'X': # Single wild-card entries put the wild-card in position 2 a2, a3 = a3, a2 dest.write(' <Improper type1="%s" type2="%s" type3="%s" ' 'type4="%s" periodicity1="%d" phase1="%s" k1="%s"/>\n' % (a1, nowild(a2), nowild(a3), nowild(a4), improp.per, improp.phase * pconv, improp.phi_k * kconv)) dest.write(' </PeriodicTorsionForce>\n')
def from_parameterset(cls, params, copy=False): """ Instantiates a CharmmParameterSet from another ParameterSet (or subclass). The main thing this feature is responsible for is converting lower-case atom type names into all upper-case and decorating the name to ensure each atom type name is unique. Parameters ---------- params : :class:`parmed.parameters.ParameterSet` ParameterSet containing the list of parameters to be converted to a CHARMM-compatible set copy : bool, optional If True, the returned parameter set is a deep copy of ``params``. If False, the returned parameter set is a shallow copy. Default False. Returns ------- new_params : OpenMMParameterSet OpenMMParameterSet with the same parameters as that defined in the input parameter set """ new_params = cls() if copy: # Make a copy so we don't modify the original params = _copy(params) new_params.atom_types = new_params.atom_types_str = params.atom_types new_params.atom_types_int = params.atom_types_int new_params.atom_types_tuple = params.atom_types_tuple new_params.bond_types = params.bond_types new_params.angle_types = params.angle_types new_params.urey_bradley_types = params.urey_bradley_types new_params.dihedral_types = params.dihedral_types new_params.improper_types = params.improper_types new_params.improper_periodic_types = params.improper_periodic_types new_params.rb_torsion_types = params.rb_torsion_types new_params.cmap_types = params.cmap_types new_params.nbfix_types = params.nbfix_types new_params.pair_types = params.pair_types new_params.parametersets = params.parametersets new_params._combining_rule = params.combining_rule new_params.default_scee = params.default_scee new_params.default_scnb = params.default_scnb # add only ResidueTemplate instances (no ResidueTemplateContainers) for name, residue in iteritems(params.residues): if isinstance(residue, ResidueTemplate): new_params.residues[name] = residue for name, patch in iteritems(params.patches): if isinstance(patch, PatchTemplate): new_params.patches[name] = patch return new_params
def _write_omm_dihedrals(self, dest, skip_types): if not self.dihedral_types and not self.improper_periodic_types: return # In ParameterSet, dihedral_types is *always* of type DihedralTypeList. # The from_structure method ensures that, even if the containing # Structure has separate dihedral entries for each torsion dest.write(" <PeriodicTorsionForce>\n") diheds_done = set() pconv = u.degree.conversion_factor_to(u.radians) kconv = u.kilocalorie.conversion_factor_to(u.kilojoule) def nowild(name): return name if name != "X" else "" for (a1, a2, a3, a4), dihed in iteritems(self.dihedral_types): if any((a in skip_types for a in (a1, a2, a3, a4))): continue if (a1, a2, a3, a4) in diheds_done: continue diheds_done.add((a1, a2, a3, a4)) diheds_done.add((a4, a3, a2, a1)) dest.write(' <Proper type1="%s" type2="%s" type3="%s" ' 'type4="%s"' % (nowild(a1), a2, a3, nowild(a4))) for i, term in enumerate(dihed): i += 1 dest.write( ' periodicity%d="%d" phase%d="%s" k%d="%s"' % (i, term.per, i, term.phase * pconv, i, term.phi_k * kconv) ) dest.write("/>\n") # Now do the periodic impropers. OpenMM expects the central atom to be # listed first. ParameterSet goes out of its way to list it third # (consistent with Amber) except in instances where order is random (as # in CHARMM parameter files). But CHARMM parameter files don't have # periodic impropers, so we don't have to worry about that here. for (a2, a3, a1, a4), improp in iteritems(self.improper_periodic_types): if any((a in skip_types for a in (a1, a2, a3, a4))): continue # Try to make the wild-cards in the middle if a4 == "X": if a2 != "X": a2, a4 = a4, a2 elif a3 != "X": a3, a4 = a4, a3 if a2 != "X" and a3 == "X": # Single wild-card entries put the wild-card in position 2 a2, a3 = a3, a2 dest.write( ' <Improper type1="%s" type2="%s" type3="%s" ' 'type4="%s" periodicity1="%d" phase1="%s" k1="%s"/>\n' % (a1, nowild(a2), nowild(a3), nowild(a4), improp.per, improp.phase * pconv, improp.phi_k * kconv) ) dest.write(" </PeriodicTorsionForce>\n")
def _write_omm_LennardJonesForce(self, xml_root, skip_types, separate_ljforce): if not self.nbfix_types and not separate_ljforce: return # Convert Conversion factors for writing in natural OpenMM units length_conv = u.angstrom.conversion_factor_to(u.nanometer) ene_conv = u.kilocalories.conversion_factor_to(u.kilojoules) scnb = set() for key in self.dihedral_types: dt = self.dihedral_types[key] for t in dt: if t.scnb: scnb.add(t.scnb) if len(scnb) > 1: raise NotImplementedError('Cannot currently handle mixed 1-4 ' 'scaling: L-J Scaling factors %s detected' % (', '.join([str(x) for x in scnb]))) if len(scnb) > 0: lj14scale = 1.0 / scnb.pop() else: lj14scale = 1.0 / self.default_scnb # write L-J records xml_force = etree.SubElement(xml_root, 'LennardJonesForce', lj14scale=str(lj14scale)) for name, atom_type in iteritems(self.atom_types): if name in skip_types: continue if (atom_type.rmin is not None) and (atom_type.epsilon is not None): sigma = atom_type.sigma * length_conv # in md_unit_system epsilon = atom_type.epsilon * ene_conv # in md_unit_system else: # Dummy atom sigma = 1.0 epsilon = 0.0 # Ensure we don't have sigma = 0 if (sigma == 0.0): if (epsilon == 0.0): sigma = 1.0 # reset sigma = 1 else: raise ValueError("For atom type '%s', sigma = 0 but " "epsilon != 0." % name) etree.SubElement(xml_force, 'Atom', type=name, sigma=str(sigma), epsilon=str(abs(epsilon))) # write NBFIX records for (atom_types, value) in iteritems(self.nbfix_types): emin = value[0] * ene_conv rmin = value[1] * length_conv # convert to sigma; note that NBFIX types are not rmin/2 but rmin sigma = rmin/(2**(1.0/6)) etree.SubElement(xml_force, 'NBFixPair', type1=atom_types[0], type2=atom_types[1], sigma=str(sigma), epsilon=str(emin))
def _find_unused_residues(self): skip_residues = set() for name, residue in iteritems(self.residues): if any( (atom.type not in self.atom_types for atom in residue.atoms)): skip_residues.add(name) return skip_residues
def _write_omm_provenance(self, root, provenance): info = etree.SubElement(root, 'Info') date_generated = etree.SubElement(info, "DateGenerated") date_generated.text = '%02d-%02d-%02d' % datetime.datetime.now().timetuple()[:3] provenance = provenance or dict() for tag, content in iteritems(provenance): if tag == 'DateGenerated': continue if not isinstance(content, list): content = [content] for sub_content in content: if isinstance(sub_content, string_types): item = etree.Element(tag) item.text = sub_content info.append(item) elif isinstance(sub_content, dict): if tag not in sub_content: raise KeyError('Content of an attribute-containing element ' 'specified incorrectly.') attributes = [key for key in sub_content if key != tag] element_content = sub_content[tag] attributes = { k : str(v) for (k,v) in sub_content.items() } item = etree.SubElement(info, tag, **attributes) item.text = str(element_content) else: raise TypeError('Incorrect type of the %s element content' % tag)
def _find_unused_types(self, skip_residues): keep_types = set() for name, residue in iteritems(self.residues): if name not in skip_residues: for atom in residue.atoms: keep_types.add(atom.type) return {typ for typ in self.atom_types if typ not in keep_types}
def _write_omm_residues(self, dest, skip_residues): if not self.residues: return written_residues = set() dest.write(" <Residues>\n") for name, residue in iteritems(self.residues): if name in skip_residues: continue templhash = OpenMMParameterSet._templhasher(residue) if templhash in written_residues: continue written_residues.add(templhash) if residue.overload_level == 0: dest.write(' <Residue name="%s">\n' % residue.name) else: dest.write(' <Residue name="%s" overload="%d">\n' % (residue.name, residue.overload_level)) for atom in residue.atoms: dest.write(' <Atom name="%s" type="%s" charge="%s"/>\n' % (atom.name, atom.type, atom.charge)) for bond in residue.bonds: dest.write(' <Bond atomName1="%s" atomName2="%s"/>\n' % (bond.atom1.name, bond.atom2.name)) if residue.head is not None: dest.write(' <ExternalBond atomName="%s"/>\n' % residue.head.name) if residue.tail is not None and residue.tail is not residue.head: dest.write(' <ExternalBond atomName="%s"/>\n' % residue.tail.name) dest.write(" </Residue>\n") dest.write(" </Residues>\n")
def _compress_impropers(self): """ OpenMM's ForceField cannot handle impropers that match the same four atoms in more than one order, so Peter Eastman wants us to compress duplicates and increment the spring constant accordingly. """ if not self.improper_types: return unique_keys = OrderedDict() # unique_keys[key] is the key to retrieve the improper from improper_types improper_types = OrderedDict() # replacement for self.improper_types with compressed impropers for atoms, improper in iteritems(self.improper_types): # Compute a unique key unique_key = tuple(sorted(atoms)) if unique_key in unique_keys: # Accumulate spring constant, discarding this contribution # TODO: Do we need to check if `psi_eq` is the same? atoms2 = unique_keys[unique_key] improper_types[atoms2].psi_k += improper.psi_k else: # Store this improper unique_keys[unique_key] = atoms improper_types[atoms] = improper self.improper_types = improper_types
def _compareInputOutputPDBs(self, pdbfile, pdbfile2, reordered=False, altloc_option='all'): # Now go through all atoms and compare their attributes for a1, a2 in zip(pdbfile.atoms, pdbfile2.atoms): if altloc_option in ('first', 'all'): self.assertEqual(a1.occupancy, a2.occupancy) a1idx = a1.idx elif altloc_option == 'occupancy': a, occ = a1, a1.occupancy for key, oa in iteritems(a1.other_locations): if oa.occupancy > occ: occ = oa.occupancy a = oa a1idx = a1.idx a1 = a # This is the atom we want to compare with self.assertEqual(a1.atomic_number, a2.atomic_number) self.assertEqual(a1.name, a2.name) self.assertEqual(a1.type, a2.type) self.assertEqual(a1.mass, a2.mass) self.assertEqual(a1.charge, a2.charge) self.assertEqual(a1.bfactor, a2.bfactor) self.assertEqual(a1.altloc, a2.altloc) self.assertEqual(a1idx, a2.idx) if altloc_option == 'all': self.assertEqual(set(a1.other_locations.keys()), set(a2.other_locations.keys())) self.assertEqual(a1.xx, a2.xx) self.assertEqual(a1.xy, a2.xy) self.assertEqual(a1.xz, a2.xz) if altloc_option != 'all': # There should be no alternate locations unless we keep them all self.assertEqual(len(a2.other_locations), 0) if not reordered: self.assertEqual(a1.number, a2.number) # Search all alternate locations as well for k1, k2 in zip(sorted(a1.other_locations.keys()), sorted(a2.other_locations.keys())): self.assertEqual(k1, k2) oa1 = a1.other_locations[k1] oa2 = a2.other_locations[k2] self.assertEqual(oa1.atomic_number, oa2.atomic_number) self.assertEqual(oa1.name, oa2.name) self.assertEqual(oa1.type, oa2.type) self.assertEqual(oa1.mass, oa2.mass) self.assertEqual(oa1.charge, oa2.charge) self.assertEqual(oa1.occupancy, oa2.occupancy) self.assertEqual(oa1.bfactor, oa2.bfactor) self.assertEqual(oa1.altloc, oa2.altloc) self.assertEqual(oa1.idx, oa2.idx) if not reordered: self.assertEqual(oa1.number, oa2.number) # Now compare all residues for r1, r2 in zip(pdbfile.residues, pdbfile2.residues): self.assertEqual(r1.name, r2.name) self.assertEqual(r1.idx, r2.idx) self.assertEqual(r1.ter, r2.ter) self.assertEqual(len(r1), len(r2)) self.assertEqual(r1.insertion_code, r2.insertion_code) if not reordered: self.assertEqual(r1.number, r2.number)
def _write_omm_provenance(self, dest, provenance): dest.write(' <Info>\n') dest.write(' <DateGenerated>%02d-%02d-%02d</DateGenerated>\n' % datetime.datetime.now().timetuple()[:3]) provenance = provenance if provenance is not None else {} for tag, content in iteritems(provenance): if tag == 'DateGenerated': continue if not isinstance(content, list): content = [content] for sub_content in content: if isinstance(sub_content, string_types): dest.write(' <%s>%s</%s>\n' % (tag, sub_content, tag)) elif isinstance(sub_content, dict): if tag not in sub_content: raise KeyError( 'Content of an attribute-containing element ' 'specified incorrectly.') attributes = [key for key in sub_content if key != tag] element_content = sub_content[tag] dest.write(' <%s' % tag) for attribute in attributes: dest.write(' %s="%s"' % (attribute, sub_content[attribute])) dest.write('>%s</%s>\n' % (element_content, tag)) else: raise TypeError( 'Incorrect type of the %s element content' % tag) dest.write(' </Info>\n')
def __init__(self, fname, defines=None, includes=None, notfound_fatal=True): if isinstance(fname, string_types): self._fileobj = genopen(fname, 'r') self._ownhandle = True curpath = path.abspath(path.split(fname)[0]) self.filename = fname else: self._fileobj = fname self._ownhandle = False curpath = path.abspath(path.curdir) self.filename = None if includes is None: self._includes = [curpath] else: self._includes = [curpath] + list(includes) if defines is None: self.defines = OrderedDict() else: # Convert every define to a string self.defines = OrderedDict() for define, value in iteritems(defines): self.defines[define] = str(value) self._notfound_fatal = notfound_fatal # Now to keep track of other basic logic stuff self.included_files = [] self._ifstack = [] self._elsestack = [] self._satisfiedstack = [] self._num_ignoring_if = 0 self._includefile = None
def _write_omm_residues(self, dest, skip_residues): if not self.residues: return written_residues = set() dest.write(' <Residues>\n') for name, residue in iteritems(self.residues): if name in skip_residues: continue templhash = OpenMMParameterSet._templhasher(residue) if templhash in written_residues: continue written_residues.add(templhash) if residue.override_level == 0: dest.write(' <Residue name="%s">\n' % residue.name) else: dest.write(' <Residue name="%s" override="%d">\n' % (residue.name, residue.override_level)) for atom in residue.atoms: dest.write(' <Atom name="%s" type="%s" charge="%s"/>\n' % (atom.name, atom.type, atom.charge)) for bond in residue.bonds: dest.write(' <Bond atomName1="%s" atomName2="%s"/>\n' % (bond.atom1.name, bond.atom2.name)) if residue.head is not None: dest.write(' <ExternalBond atomName="%s"/>\n' % residue.head.name) if residue.tail is not None and residue.tail is not residue.head: dest.write(' <ExternalBond atomName="%s"/>\n' % residue.tail.name) dest.write(' </Residue>\n') dest.write(' </Residues>\n')
def _write_omm_residues(self, xml_root, skip_residues, valid_patches_for_residue=None): if not self.residues: return if valid_patches_for_residue is None: valid_patches_for_residue = dict() written_residues = set() xml_section = etree.SubElement(xml_root, 'Residues') for name, residue in iteritems(self.residues): if name in skip_residues: continue templhash = OpenMMParameterSet._templhasher(residue) if templhash in written_residues: continue written_residues.add(templhash) # Write residue if residue.override_level == 0: xml_residue = etree.SubElement(xml_section, 'Residue', name=residue.name) else: xml_residue = etree.SubElement(xml_section, 'Residue', name=residue.name, override=str(residue.override_level)) # Write residue contents for atom in residue.atoms: etree.SubElement(xml_residue, 'Atom', name=atom.name, type=atom.type, charge=str(atom.charge)) for bond in residue.bonds: etree.SubElement(xml_residue, 'Bond', atomName1=bond.atom1.name, atomName2=bond.atom2.name) if residue.head is not None: etree.SubElement(xml_residue, 'ExternalBond', atomName=residue.head.name) if residue.tail is not None and residue.tail is not residue.head: etree.SubElement(xml_residue, 'ExternalBond', atomName=residue.tail.name) if residue.name in valid_patches_for_residue: for patch_name in valid_patches_for_residue[residue.name]: etree.SubElement(xml_residue, 'AllowPatch', name=patch_name)
def _write_omm_nonbonded(self, dest, skip_types, separate_ljforce): if not self.atom_types: return # Compute conversion factors for writing in natrual OpenMM units. length_conv = u.angstrom.conversion_factor_to(u.nanometer) ene_conv = u.kilocalories.conversion_factor_to(u.kilojoules) # Get the 1-4 scaling factors from the torsion list scee, scnb = set(), set() for key in self.dihedral_types: dt = self.dihedral_types[key] for t in dt: if t.scee: scee.add(t.scee) if t.scnb: scnb.add(t.scnb) if len(scee) > 1: raise NotImplementedError('Cannot currently handle mixed 1-4 ' 'scaling: Elec. Scaling factors %s detected' % (', '.join([str(x) for x in scee]))) if len(scnb) > 1: raise NotImplementedError('Cannot currently handle mixed 1-4 ' 'scaling: L-J Scaling factors %s detected' % (', '.join([str(x) for x in scnb]))) if len(scee) > 0: coulomb14scale = 1.0 / scee.pop() else: coulomb14scale = 1.0 / self.default_scee if len(scnb) > 0: lj14scale = 1.0 / scnb.pop() else: lj14scale = 1.0 / self.default_scnb # Write NonbondedForce records. dest.write(' <NonbondedForce coulomb14scale="%s" lj14scale="%s">\n' % (coulomb14scale, lj14scale)) dest.write(' <UseAttributeFromResidue name="charge"/>\n') for name, atom_type in iteritems(self.atom_types): if name in skip_types: continue if (atom_type.rmin is not None) and (atom_type.epsilon is not None): sigma = atom_type.sigma * length_conv # in md_unit_system epsilon = atom_type.epsilon * ene_conv # in md_unit_system else: # Dummy atom sigma = 1.0 epsilon = 0.0 if self.nbfix_types or separate_ljforce: # turn off L-J. Will use LennardJonesForce to use CostumNonbondedForce to compute L-J interactions sigma = 1.0 epsilon = 0.0 # Ensure we don't have sigma = 0 if (sigma == 0.0): if (epsilon == 0.0): sigma = 1.0 # reset sigma = 1 else: raise ValueError("For atom type '%s', sigma = 0 but " "epsilon != 0." % name) dest.write(' <Atom type="%s" sigma="%s" epsilon="%s"/>\n' % (name, sigma, abs(epsilon))) dest.write(' </NonbondedForce>\n')
def _num_unique_dtypes(dct): used_types = set() num = 0 for _, x in iteritems(dct): if id(x) in used_types: continue used_types.add(id(x)) num += len(x) return num
def _write_omm_nonbonded(self, dest, skip_types): if not self.atom_types: return # Compute conversion factors for writing in natrual OpenMM units. length_conv = u.angstrom.conversion_factor_to(u.nanometer) ene_conv = u.kilocalories.conversion_factor_to(u.kilojoules) # Get the 1-4 scaling factors from the torsion list scee, scnb = set(), set() for key in self.dihedral_types: dt = self.dihedral_types[key] for t in dt: if t.scee: scee.add(t.scee) if t.scnb: scnb.add(t.scnb) if len(scee) > 1: raise NotImplementedError( "Cannot currently handle mixed 1-4 " "scaling: Elec. Scaling factors %s detected" % (", ".join([str(x) for x in scee])) ) if len(scnb) > 1: raise NotImplementedError( "Cannot currently handle mixed 1-4 " "scaling: L-J Scaling factors %s detected" % (", ".join([str(x) for x in scnb])) ) if len(scee) > 0: coulomb14scale = 1.0 / scee.pop() else: coulomb14scale = 1.0 / self.default_scee if len(scnb) > 0: lj14scale = 1.0 / scnb.pop() else: lj14scale = 1.0 / self.default_scnb # Write NonbondedForce records. dest.write(' <NonbondedForce coulomb14scale="%s" lj14scale="%s">\n' % (coulomb14scale, lj14scale)) dest.write(' <UseAttributeFromResidue name="charge"/>\n') for name, atom_type in iteritems(self.atom_types): if name in skip_types: continue if (atom_type.rmin is not None) and (atom_type.epsilon is not None): sigma = atom_type.sigma * length_conv # in md_unit_system epsilon = atom_type.epsilon * ene_conv # in md_unit_system else: # Dummy atom sigma = 1.0 epsilon = 0.0 # Ensure we don't have sigma = 0 if sigma == 0.0: if epsilon == 0.0: sigma = 1.0 # reset sigma = 1 else: raise ValueError("For atom type '%s', sigma = 0 but " "epsilon != 0." % name) dest.write(' <Atom type="%s" sigma="%s" epsilon="%s"/>\n' % (name, sigma, abs(epsilon))) dest.write(" </NonbondedForce>\n")
def testThreeSimpleIndex(self): """ Tests simple indexing with chain, residue, and atom ID """ chains = defaultdict(pmd.TrackedList) for res in pdb2.residues: chains[res.chain].append(res) for chain_name, chain in iteritems(chains): for i, res in enumerate(chain): for j, atom in enumerate(res): self.assertIs(atom, pdb2[chain_name, i, j])
def test_three_simple_index(self): """ Tests simple indexing with chain, residue, and atom ID (view) """ chains = defaultdict(pmd.TrackedList) for res in pdb2.residues: chains[res.chain].append(res) for chain_name, chain in iteritems(chains): for i, res in enumerate(chain): for j, atom in enumerate(res): self.assertIs(atom, pdb2.view[chain_name, i, j])
def _write_omm_dihedrals(self, xml_root, skip_types, improper_dihedrals_ordering): if not self.dihedral_types and not self.improper_periodic_types: return # In ParameterSet, dihedral_types is *always* of type DihedralTypeList. # The from_structure method ensures that, even if the containing # Structure has separate dihedral entries for each torsion if improper_dihedrals_ordering == 'default': xml_force = etree.SubElement(xml_root, 'PeriodicTorsionForce') else: xml_force = etree.SubElement(xml_root, 'PeriodicTorsionForce', ordering=improper_dihedrals_ordering) diheds_done = set() pconv = u.degree.conversion_factor_to(u.radians) kconv = u.kilocalorie.conversion_factor_to(u.kilojoule) def nowild(name): return name if name != 'X' else '' for (a1, a2, a3, a4), dihed in iteritems(self.dihedral_types): if any((a in skip_types for a in (a1, a2, a3, a4))): continue if (a1, a2, a3, a4) in diheds_done: continue diheds_done.add((a1, a2, a3, a4)) diheds_done.add((a4, a3, a2, a1)) terms = dict() for i, term in enumerate(dihed): i += 1 terms['periodicity%d' % i] = str(term.per) terms['phase%d' % i] = str(term.phase*pconv) terms['k%d' % i] = str(term.phi_k*kconv) etree.SubElement(xml_force, 'Proper', type1=nowild(a1), type2=a2, type3=a3, type4=nowild(a4), **terms) # Now do the periodic impropers. OpenMM expects the central atom to be # listed first. ParameterSet goes out of its way to list it third # (consistent with Amber) except in instances where order is random (as # in CHARMM parameter files). But CHARMM parameter files don't have # periodic impropers, so we don't have to worry about that here. for (a2, a3, a1, a4), improp in iteritems(self.improper_periodic_types): if any((a in skip_types for a in (a1, a2, a3, a4))): continue # Try to make the wild-cards in the middle if a4 == 'X': if a2 != 'X': a2, a4 = a4, a2 elif a3 != 'X': a3, a4 = a4, a3 if a2 != 'X' and a3 == 'X': # Single wild-card entries put the wild-card in position 2 a2, a3 = a3, a2 etree.SubElement(xml_force, 'Improper', type1=a1, type2=nowild(a2), type3=nowild(a3), type4=nowild(a4), periodicity1=str(improp.per), phase1=str(improp.phase*pconv), k1=str(improp.phi_k*kconv))
def _write_omm_nonbonded(self, xml_root, skip_types, separate_ljforce): if not self.atom_types: return # Compute conversion factors for writing in natrual OpenMM units. length_conv = u.angstrom.conversion_factor_to(u.nanometer) ene_conv = u.kilocalories.conversion_factor_to(u.kilojoules) # Get the 1-4 scaling factors from the torsion list scee, scnb = set(), set() for key in self.dihedral_types: dt = self.dihedral_types[key] for t in dt: if t.scee: scee.add(t.scee) if t.scnb: scnb.add(t.scnb) if len(scee) > 1: raise NotImplementedError('Cannot currently handle mixed 1-4 ' 'scaling: Elec. Scaling factors %s detected' % (', '.join([str(x) for x in scee]))) if len(scnb) > 1: raise NotImplementedError('Cannot currently handle mixed 1-4 ' 'scaling: L-J Scaling factors %s detected' % (', '.join([str(x) for x in scnb]))) if len(scee) > 0: coulomb14scale = 1.0 / scee.pop() else: coulomb14scale = 1.0 / self.default_scee if len(scnb) > 0: lj14scale = 1.0 / scnb.pop() else: lj14scale = 1.0 / self.default_scnb # Write NonbondedForce records. xml_force = etree.SubElement(xml_root, 'NonbondedForce', coulomb14scale=str(coulomb14scale), lj14scale=str(lj14scale)) etree.SubElement(xml_force, 'UseAttributeFromResidue', name="charge") for name, atom_type in iteritems(self.atom_types): if name in skip_types: continue if (atom_type.rmin is not None) and (atom_type.epsilon is not None): sigma = atom_type.sigma * length_conv # in md_unit_system epsilon = atom_type.epsilon * ene_conv # in md_unit_system else: # Dummy atom sigma = 1.0 epsilon = 0.0 if self.nbfix_types or separate_ljforce: # turn off L-J. Will use LennardJonesForce to use CostumNonbondedForce to compute L-J interactions sigma = 1.0 epsilon = 0.0 # Ensure we don't have sigma = 0 if (sigma == 0.0): if (epsilon == 0.0): sigma = 1.0 # reset sigma = 1 else: raise ValueError("For atom type '%s', sigma = 0 but " "epsilon != 0." % name) etree.SubElement(xml_force, 'Atom', type=name, sigma=str(sigma), epsilon=str(abs(epsilon)))
def test_three_simple_index(self): """ Tests simple indexing with chain, residue, and atom ID """ chains = defaultdict(pmd.TrackedList) for res in pdb2.residues: chains[res.chain].append(res) for chain_name, chain in iteritems(chains): for i, res in enumerate(chain): for j, atom in enumerate(res): self.assertIs(atom, pdb2[chain_name, i, j]) self.assertRaises(IndexError, lambda: pdb2['Z', 0, 0])
def _write_omm_scripts(self, dest, skip_types): # Not currently implemented, so throw an exception if any unsupported # options are specified if self.combining_rule == "geometric": raise NotImplementedError("Geometric combining rule not currently " "supported.") if len(self.nbfix_types) > 0: for (a1, a2), nbfix in iteritems(self.nbfix_types): if any((a in skip_types for a in (a1, a2))): continue else: raise NotImplementedError("NBFIX not currently supported")
def _write_omm_angles(self, xml_root, skip_types): if not self.angle_types: return xml_force = etree.SubElement(xml_root, 'HarmonicAngleForce') angles_done = set() tconv = u.degree.conversion_factor_to(u.radians) kconv = u.kilocalorie.conversion_factor_to(u.kilojoule) * 2 for (a1, a2, a3), angle in iteritems(self.angle_types): if any((a in skip_types for a in (a1, a2, a3))): continue if (a1, a2, a3) in angles_done: continue angles_done.add((a1, a2, a3)) angles_done.add((a3, a2, a1)) etree.SubElement(xml_force, 'Angle', type1=a1, type2=a2, type3=a3, angle=str(angle.theteq*tconv), k=str(angle.k*kconv))
def _write_omm_atom_types(self, xml_root, skip_types): if not self.atom_types: return xml_section = etree.SubElement(xml_root, "AtomTypes") for name, atom_type in iteritems(self.atom_types): if name in skip_types: continue assert atom_type.atomic_number >= 0, 'Atomic number not set!' properties = { 'name' : name, 'class' : name, 'mass' : str(atom_type.mass) } if atom_type.atomic_number == 0: etree.SubElement(xml_section, 'Type', **properties) else: element = Element[atom_type.atomic_number] etree.SubElement(xml_section, 'Type', element=str(element), **properties)
def _write_omm_bonds(self, xml_root, skip_types): if not self.bond_types: return xml_force = etree.SubElement(xml_root, 'HarmonicBondForce') bonds_done = set() lconv = u.angstroms.conversion_factor_to(u.nanometers) kconv = u.kilocalorie.conversion_factor_to(u.kilojoule) / lconv**2 * 2 for (a1, a2), bond in iteritems(self.bond_types): if any((a in skip_types for a in (a1, a2))): continue if (a1, a2) in bonds_done: continue bonds_done.add((a1, a2)) bonds_done.add((a2, a1)) etree.SubElement(xml_force, 'Bond', type1=a1, type2=a2, length=str(bond.req*lconv), k=str(bond.k*kconv))
def typeify_templates(self): """ Assign atom types to atom names in templates """ from parmed.modeller import ResidueTemplateContainer, ResidueTemplate for name, residue in iteritems(self.residues): if isinstance(residue, ResidueTemplateContainer): for res in residue: for atom in res: atom.atom_type = self.atom_types[atom.type] else: assert isinstance(residue, ResidueTemplate), 'Wrong type!' for atom in residue: atom.atom_type = self.atom_types[atom.type]
def _write_omm_scripts(self, dest, skip_types): # Not currently implemented, so throw an exception if any unsupported # options are specified if self.combining_rule == 'geometric': raise NotImplementedError('Geometric combining rule not currently ' 'supported.') if len(self.nbfix_types) > 0: for (a1, a2), nbfix in iteritems(self.nbfix_types): if any((a in skip_types for a in (a1, a2))): continue else: raise NotImplementedError('NBFIX not currently supported')
def populate_actions(cls): """ This will create all of the do_Command methods to trigger command auto-complete. This eliminates the need to modify the ParmedCmd class when a new command is added """ for _cmd, cmdclass in iteritems(COMMANDMAP): if _cmd in ('source', 'go', 'EOF', 'quit', 'help', 'parmout'): continue cmdname = cmdclass.__name__ exec('cls.do_%s = lambda self, line: ' 'self._normaldo(COMMANDMAP["%s"], line)' % (cmdname, _cmd)) cls._populated = True
def _write_omm_impropers(self, xml_root, skip_types): if not self.improper_types: return xml_force = etree.SubElement(xml_root, 'CustomTorsionForce', energy="k*(theta-theta0)^2") etree.SubElement(xml_force, 'PerTorsionParameter', name="k") etree.SubElement(xml_force, 'PerTorsionParameter', name="theta0") kconv = u.kilocalorie.conversion_factor_to(u.kilojoule) tconv = u.degree.conversion_factor_to(u.radian) def nowild(name): return name if name != 'X' else '' for (a1, a2, a3, a4), improp in iteritems(self.improper_types): if any((a in skip_types for a in (a1, a2, a3, a4))): continue etree.SubElement(xml_force, 'Improper', type1=nowild(a1), type2=nowild(a2), type3=nowild(a3), type4=nowild(a4), k=str(improp.psi_k*kconv), theta0=str(improp.psi_eq*tconv))
def test_urey_bradley_type(self): """ Tests handling getting urey-bradley types from Structure """ warnings.filterwarnings('error', category=pmd.exceptions.ParameterWarning) struct = pmd.Structure() struct.add_atom(pmd.Atom('CA', type='CX'), 'ALA', 1) struct.add_atom(pmd.Atom('CB', type='CY'), 'ALA', 1) struct.add_atom(pmd.Atom('CC', type='CZ'), 'ALA', 1) struct.add_atom(pmd.Atom('CD', type='CX'), 'GLY', 2) struct.add_atom(pmd.Atom('CE', type='CY'), 'GLY', 2) struct.add_atom(pmd.Atom('CF', type='CZ'), 'GLY', 2) struct.bond_types.append(pmd.BondType(100.0, 1.0)) struct.bond_types.claim() struct.bonds.extend([ pmd.Bond(struct[0], struct[1], type=struct.bond_types[0]), pmd.Bond(struct[1], struct[2], type=struct.bond_types[0]), pmd.Bond(struct[3], struct[4], type=struct.bond_types[0]), pmd.Bond(struct[4], struct[5], type=struct.bond_types[0]), ]) struct.angle_types.append(pmd.AngleType(10.0, 120.0)) struct.angle_types.append(pmd.AngleType(11.0, 109.0)) struct.angle_types.claim() struct.angles.append( pmd.Angle(struct[0], struct[1], struct[2], type=struct.angle_types[0])) struct.angles.append( pmd.Angle(struct[3], struct[4], struct[5], type=struct.angle_types[0])) struct.urey_bradley_types.append(pmd.BondType(150.0, 2.0)) struct.urey_bradley_types.claim() struct.urey_bradleys.extend([ pmd.UreyBradley(struct[0], struct[2], type=struct.urey_bradley_types[0]), pmd.UreyBradley(struct[3], struct[5], type=struct.urey_bradley_types[0]), ]) params = pmd.ParameterSet.from_structure(struct) self.assertEqual(len(params.urey_bradley_types), 2) for key, ubt in iteritems(params.urey_bradley_types): self.assertEqual(len(key), 3) self.assertEqual(ubt.req, 2.0) self.assertEqual(ubt.k, 150.0) warnings.filterwarnings('default', category=pmd.exceptions.ParameterWarning)
def _write_omm_residues(self, xml_root, skip_residues, valid_patches_for_residue=None): if not self.residues: return if valid_patches_for_residue is None: valid_patches_for_residue = dict() written_residues = set() xml_section = etree.SubElement(xml_root, 'Residues') for name, residue in iteritems(self.residues): if name in skip_residues: continue templhash = OpenMMParameterSet._templhasher(residue) if templhash in written_residues: continue written_residues.add(templhash) # Write residue if residue.override_level == 0: xml_residue = etree.SubElement(xml_section, 'Residue', name=residue.name) else: xml_residue = etree.SubElement(xml_section, 'Residue', name=residue.name, override=str( residue.override_level)) # Write residue contents for atom in residue.atoms: etree.SubElement(xml_residue, 'Atom', name=atom.name, type=atom.type, charge=str(atom.charge)) for bond in residue.bonds: etree.SubElement(xml_residue, 'Bond', atomName1=bond.atom1.name, atomName2=bond.atom2.name) if residue.head is not None: etree.SubElement(xml_residue, 'ExternalBond', atomName=residue.head.name) if residue.tail is not None and residue.tail is not residue.head: etree.SubElement(xml_residue, 'ExternalBond', atomName=residue.tail.name) if residue.name in valid_patches_for_residue: for patch_name in valid_patches_for_residue[residue.name]: etree.SubElement(xml_residue, 'AllowPatch', name=patch_name)
def _write_omm_urey_bradley(self, xml_root, skip_types): if not self.urey_bradley_types: return None xml_root.append( etree.Comment("Urey-Bradley terms") ) xml_force = etree.SubElement(xml_root, 'AmoebaUreyBradleyForce') length_conv = u.angstroms.conversion_factor_to(u.nanometers) _ambfrc = u.kilocalorie_per_mole/u.angstrom**2 _ommfrc = u.kilojoule_per_mole/u.nanometer**2 frc_conv = _ambfrc.conversion_factor_to(_ommfrc) ureys_done = set() for (a1, a2, a3), urey in iteritems(self.urey_bradley_types): if any((a in skip_types for a in (a1, a2, a3))): continue if (a1, a2, a3) in ureys_done: continue if urey == NoUreyBradley: continue etree.SubElement(xml_force, 'UreyBradley', type1=a1, type2=a2, type3=a3, d=str(urey.req*length_conv), k=str(urey.k*frc_conv))
def _write_omm_atom_types(self, dest, skip_types): if not self.atom_types: return dest.write(' <AtomTypes>\n') for name, atom_type in iteritems(self.atom_types): if name in skip_types: continue assert atom_type.atomic_number >= 0, 'Atomic number not set!' if atom_type.atomic_number == 0: element = "" else: element = Element[atom_type.atomic_number] dest.write( ' <Type name="%s" class="%s" element="%s" mass="%s"/>\n' % (name, name, element, atom_type.mass)) dest.write(' </AtomTypes>\n')
def _write_omm_bonds(self, dest, skip_types): if not self.bond_types: return dest.write(' <HarmonicBondForce>\n') bonds_done = set() lconv = u.angstroms.conversion_factor_to(u.nanometers) kconv = u.kilocalorie.conversion_factor_to(u.kilojoule) / lconv**2 * 2 for (a1, a2), bond in iteritems(self.bond_types): if any((a in skip_types for a in (a1, a2))): continue if (a1, a2) in bonds_done: continue bonds_done.add((a1, a2)) bonds_done.add((a2, a1)) dest.write(' <Bond type1="%s" type2="%s" length="%s" k="%s"/>\n' % (a1, a2, bond.req * lconv, bond.k * kconv)) dest.write(' </HarmonicBondForce>\n')
def from_parameterset(cls, params, copy=False): """ Instantiates a CharmmParameterSet from another ParameterSet (or subclass). The main thing this feature is responsible for is converting lower-case atom type names into all upper-case and decorating the name to ensure each atom type name is unique. Parameters ---------- params : :class:`parmed.parameters.ParameterSet` ParameterSet containing the list of parameters to be converted to a CHARMM-compatible set copy : bool, optional If True, the returned parameter set is a deep copy of ``params``. If False, the returned parameter set is a shallow copy. Default False. Returns ------- new_params : OpenMMParameterSet OpenMMParameterSet with the same parameters as that defined in the input parameter set """ new_params = cls() if copy: # Make a copy so we don't modify the original params = _copy(params) new_params.atom_types = new_params.atom_types_str = params.atom_types new_params.atom_types_int = params.atom_types_int new_params.atom_types_tuple = params.atom_types_tuple new_params.bond_types = params.bond_types new_params.angle_types = params.angle_types new_params.urey_bradley_types = params.urey_bradley_types new_params.dihedral_types = params.dihedral_types new_params.improper_types = params.improper_types new_params.improper_periodic_types = params.improper_periodic_types new_params.rb_torsion_types = params.rb_torsion_types new_params.cmap_types = params.cmap_types new_params.nbfix_types = params.nbfix_types new_params.pair_types = params.pair_types new_params.parametersets = params.parametersets new_params._combining_rule = params.combining_rule new_params.default_scee = params.default_scee new_params.default_scnb = params.default_scnb # add only ResidueTemplate instances (no ResidueTemplateContainers) for name, residue in iteritems(params.residues): if isinstance(residue, ResidueTemplate): new_params.residues[name] = residue return new_params
def _write_omm_residues(self, xml_root, skip_residues, valid_patches_for_residue=None): if not self.residues: return if valid_patches_for_residue is None: valid_patches_for_residue = dict() written_residues = set() xml_section = etree.SubElement(xml_root, 'Residues') for name, residue in iteritems(self.residues): if name in skip_residues: continue templhash = OpenMMParameterSet._templhasher(residue) if templhash in written_residues: continue written_residues.add(templhash) # Write residue if residue.override_level == 0: xml_residue = etree.SubElement(xml_section, 'Residue', name=residue.name) else: xml_residue = etree.SubElement(xml_section, 'Residue', name=residue.name, override=str(residue.override_level)) # Write residue contents for atom in residue.atoms: etree.SubElement(xml_residue, 'Atom', name=atom.name, type=atom.type, charge=str(atom.charge)) for bond in residue.bonds: etree.SubElement(xml_residue, 'Bond', atomName1=bond.atom1.name, atomName2=bond.atom2.name) for (index, lonepair) in enumerate(residue.lonepairs): (lptype, a1, a2, a3, a4, r, theta, phi) = lonepair if lptype == 'relative': xweights = [-1.0, 0.0, 1.0] elif lptype == 'bisector': xweights = [-1.0, 0.5, 0.5] else: raise ValueError('Unknown lonepair type: '+lptype) r /= 10.0 # convert to nanometers theta *= math.pi / 180.0 # convert to radians phi = (180 - phi) * math.pi / 180.0 # convert to radians p = [r*math.cos(theta), r*math.sin(theta)*math.cos(phi), r*math.sin(theta)*math.sin(phi)] p = [x if abs(x) > 1e-10 else 0 for x in p] # Avoid tiny numbers caused by roundoff error etree.SubElement(xml_residue, 'VirtualSite', type="localCoords", index=str(index), siteName=a1, atomName1=a2, atomName2=a3, atomName3=a4, wo1="1", wo2="0", wo3="0", wx1=str(xweights[0]), wx2=str(xweights[1]), wx3=str(xweights[2]), wy1="0", wy2="-1", wy3="1", p1=str(p[0]), p2=str(p[1]), p3=str(p[2])) for atom in residue.connections: etree.SubElement(xml_residue, 'ExternalBond', atomName=atom.name) if residue.head is not None: etree.SubElement(xml_residue, 'ExternalBond', atomName=residue.head.name) if residue.tail is not None and residue.tail is not residue.head: etree.SubElement(xml_residue, 'ExternalBond', atomName=residue.tail.name) if residue.name in valid_patches_for_residue: for patch_name in valid_patches_for_residue[residue.name]: etree.SubElement(xml_residue, 'AllowPatch', name=patch_name)
def _write_omm_angles(self, dest, skip_types): if not self.angle_types: return dest.write(' <HarmonicAngleForce>\n') angles_done = set() tconv = u.degree.conversion_factor_to(u.radians) kconv = u.kilocalorie.conversion_factor_to(u.kilojoule) * 2 for (a1, a2, a3), angle in iteritems(self.angle_types): if any((a in skip_types for a in (a1, a2, a3))): continue if (a1, a2, a3) in angles_done: continue angles_done.add((a1, a2, a3)) angles_done.add((a3, a2, a1)) dest.write(' <Angle type1="%s" type2="%s" type3="%s" ' 'angle="%s" k="%s"/>\n' % (a1, a2, a3, angle.theteq * tconv, angle.k * kconv)) dest.write(' </HarmonicAngleForce>\n')
def _write_omm_atom_types(self, dest, skip_types): if not self.atom_types: return dest.write(" <AtomTypes>\n") for name, atom_type in iteritems(self.atom_types): if name in skip_types: continue assert atom_type.atomic_number >= 0, "Atomic number not set!" if atom_type.atomic_number == 0: dest.write(' <Type name="%s" class="%s" mass="%s"/>\n' % (name, name, atom_type.mass)) else: element = Element[atom_type.atomic_number] dest.write( ' <Type name="%s" class="%s" element="%s" mass="%s"/>\n' % (name, name, element, atom_type.mass) ) dest.write(" </AtomTypes>\n")
def _check_uppercase_types(self, params): for aname, atom_type in iteritems(params.atom_types): self.assertEqual(aname, aname.upper()) self.assertEqual(atom_type.name, atom_type.name.upper()) for key in params.bond_types: for k in key: self.assertEqual(k.upper(), k) for key in params.angle_types: for k in key: self.assertEqual(k.upper(), k) for key in params.dihedral_types: for k in key: self.assertEqual(k.upper(), k) for key in params.cmap_types: for k in key: self.assertEqual(k.upper(), k)
def _write_omm_residues(self, xml_root, skip_residues, valid_patches_for_residue=None): if not self.residues: return if valid_patches_for_residue is None: valid_patches_for_residue = dict() written_residues = set() xml_section = etree.SubElement(xml_root, 'Residues') for name, residue in iteritems(self.residues): if name in skip_residues: continue templhash = OpenMMParameterSet._templhasher(residue) if templhash in written_residues: continue written_residues.add(templhash) # Write residue if residue.override_level == 0: xml_residue = etree.SubElement(xml_section, 'Residue', name=residue.name) else: xml_residue = etree.SubElement(xml_section, 'Residue', name=residue.name, override=str(residue.override_level)) # Write residue contents for atom in residue.atoms: etree.SubElement(xml_residue, 'Atom', name=atom.name, type=atom.type, charge=str(atom.charge)) for bond in residue.bonds: etree.SubElement(xml_residue, 'Bond', atomName1=bond.atom1.name, atomName2=bond.atom2.name) for (index, lonepair) in enumerate(residue.lonepairs): (lptype, a1, a2, a3, a4, r, theta, phi) = lonepair if lptype == 'relative': xweights = [-1.0, 0.0, 1.0] elif lptype == 'bisector': xweights = [-1.0, 0.5, 0.5] else: raise ValueError('Unknown lonepair type: '+lptype) r /= 10.0 # convert to nanometers theta *= math.pi / 180.0 # convert to radians phi = (180 - phi) * math.pi / 180.0 # convert to radians p = [r*math.cos(theta), r*math.sin(theta)*math.cos(phi), r*math.sin(theta)*math.sin(phi)] p = [x if abs(x) > 1e-10 else 0 for x in p] # Avoid tiny numbers caused by roundoff error etree.SubElement(xml_residue, 'VirtualSite', type="localCoords", index=str(index), siteName=a1, atomName1=a2, atomName2=a3, atomName3=a4, wo1="1", wo2="0", wo3="0", wx1=str(xweights[0]), wx2=str(xweights[1]), wx3=str(xweights[2]), wy1="0", wy2="-1", wy3="1", p1=str(p[0]), p2=str(p[1]), p3=str(p[2])) if residue.head is not None: etree.SubElement(xml_residue, 'ExternalBond', atomName=residue.head.name) if residue.tail is not None and residue.tail is not residue.head: etree.SubElement(xml_residue, 'ExternalBond', atomName=residue.tail.name) if residue.name in valid_patches_for_residue: for patch_name in valid_patches_for_residue[residue.name]: etree.SubElement(xml_residue, 'AllowPatch', name=patch_name)
def _write_omm_urey_bradley(self, dest, skip_types): if not self.urey_bradley_types: return None dest.write(' <!-- Urey-Bradley terms -->\n') dest.write(' <AmoebaUreyBradleyForce>\n') length_conv = u.angstroms.conversion_factor_to(u.nanometers) _ambfrc = u.kilocalorie_per_mole/u.angstrom**2 _ommfrc = u.kilojoule_per_mole/u.nanometer**2 frc_conv = _ambfrc.conversion_factor_to(_ommfrc) ureys_done = set() for (a1, a2, a3), urey in iteritems(self.urey_bradley_types): if any((a in skip_types for a in (a1, a2, a3))): continue if (a1, a2, a3) in ureys_done: continue if urey == NoUreyBradley: continue dest.write(' <UreyBradley type1="%s" type2="%s" type3="%s" d="%s" k="%s"/>\n' % (a1, a2, a3, urey.req*length_conv, urey.k*frc_conv)) dest.write(' </AmoebaUreyBradleyForce>\n')