def _process_urey_bradley(struct, force): """ Adds Urey-Bradley parameters to the structure """ if not struct.angles: warnings.warn( 'Adding what seems to be Urey-Bradley terms before ' # pragma: no cover 'Angles. This is unexpected, but the parameters will ' 'all be present in one form or another.', OpenMMWarning) typemap = dict() for ii in range(force.getNumBonds()): i, j, req, k = force.getBondParameters(ii) ai, aj = struct.atoms[i], struct.atoms[j] key = (req._value, k._value) if struct.angles and ai not in aj.angle_partners: warnings.warn( 'Adding what seems to be Urey-Bradley terms, but ' # pragma: no cover 'atoms %d and %d do not appear to be angled to each ' 'other. Parameters will all be present, but may not ' 'be in expected places.' % (ai.idx, aj.idx), OpenMMWarning) if key in typemap: urey_type = typemap[key] else: urey_type = BondType(k * 0.5, req) typemap[key] = urey_type struct.urey_bradley_types.append(urey_type) struct.urey_bradleys.append(UreyBradley(ai, aj, type=urey_type)) struct.urey_bradley_types.claim()
def _load_urey_brad_info(self): """ Loads the Urey-Bradley types and array """ del self.urey_bradleys[:] del self.urey_bradley_types[:] for k, req in zip(self.parm_data['CHARMM_UREY_BRADLEY_FORCE_CONSTANT'], self.parm_data['CHARMM_UREY_BRADLEY_EQUIL_VALUE']): self.urey_bradley_types.append( BondType(k, req, self.urey_bradley_types)) it = iter(self.parm_data['CHARMM_UREY_BRADLEY']) for i, j, k in zip(it, it, it): self.urey_bradleys.append( UreyBradley(self.atoms[i - 1], self.atoms[j - 1], self.urey_bradley_types[k - 1]))
def create_random_structure(parametrized, novalence=False): """ Create a random Structure with random attributes Parameters ---------- parametrized : bool If True, add at least two of all kinds of parameters to the generated random structure. If False, just fill in the atoms and residues and some random valence terms, but no "types" novalence : bool, optional If True, no valence terms will be added. Default is False. This is set to False if parametrized is True """ from parmed.topologyobjects import ( Atom, Bond, AtomType, BondType, AngleType, DihedralType, ImproperType, CmapType, OutOfPlaneBendType, StretchBendType, TorsionTorsionType, AmoebaNonbondedExceptionType, Angle, UreyBradley, Dihedral, Improper, Cmap, TrigonalAngle, OutOfPlaneBend, StretchBend, PiTorsion, TorsionTorsion, AcceptorDonor, Group, ChiralFrame, MultipoleFrame, NonbondedException, RBTorsionType) from parmed import structure from copy import copy if parametrized: novalence = False # Generate random atom and parameter types atom_types = [ AtomType(''.join(random.sample(uppercase, 3)), i, random.random() * 16 + 1, random.randint(1, 8)) for i in range(random.randint(8, 20)) ] bond_types = [ BondType(random.random() * 2, random.random() * 100) for i in range(random.randint(10, 20)) ] angle_types = [ AngleType(random.random() * 50, random.random() * 120) for i in range(random.randint(10, 20)) ] dihed_types = [ DihedralType(random.random() * 10, random.randint(1, 6), random.choice([0, 180])) for i in range(random.randint(10, 20)) ] rb_types = [RBTorsionType(*[random.random() * 10 for i in range(6)])] imp_types = [ ImproperType(random.random() * 100, random.choice([0, 180])) for i in range(random.randint(10, 20)) ] cmap_types = [ CmapType(24, [random.random() * 5 for i in range(24 * 24)]) for i in range(random.randint(5, 10)) ] oop_types = [ OutOfPlaneBendType(random.random() * 100) for i in range(random.randint(10, 20)) ] strbnd_types = [ StretchBendType(random.random() * 10, random.random() * 10, random.random() * 2, random.random() * 2, random.random() * 120) for i in range(random.randint(10, 20)) ] ang1, ang2 = list(range(-180, 180, 36)), list(range(-180, 180, 18)) tortor_types = [ TorsionTorsionType((10, 20), ang1[:], ang2[:], [random.random() * 10 for j in range(200)]) for i in range(random.randint(5, 10)) ] for typ in atom_types: typ.set_lj_params(random.random() * 2, random.random() * 2) struct = structure.Structure() # Add atoms in residues for res in range(random.randint(20, 30)): resname = ''.join(random.sample(uppercase, 3)) resid = res + 1 for i in range(random.randint(10, 25)): name = ''.join(random.sample(uppercase, 4)) if parametrized: typ = random.choice(atom_types) type = str(typ) mass = typ.mass atomic_number = typ.atomic_number else: type = ''.join(random.sample(uppercase, 3)) mass = random.random() * 16 + 1 atomic_number = random.randint(1, 8) charge = random.random() * 2 - 1 solvent_radius = random.random() * 2 screen = random.random() * 2 atom = Atom(atomic_number=atomic_number, type=type, charge=charge, mass=mass, solvent_radius=solvent_radius, screen=screen, name=name) if parametrized: atom.atom_type = typ struct.add_atom(atom, resname, resid) if novalence: return struct # Possibly add parameter type lists if parametrized: struct.bond_types.extend([copy(x) for x in bond_types]) struct.bond_types.claim() struct.angle_types.extend([copy(x) for x in angle_types]) struct.angle_types.claim() struct.dihedral_types.extend([copy(x) for x in dihed_types]) struct.dihedral_types.claim() struct.rb_torsion_types.extend([copy(x) for x in rb_types]) struct.rb_torsion_types.claim() struct.urey_bradley_types.extend([copy(x) for x in bond_types]) struct.urey_bradley_types.claim() struct.improper_types.extend([copy(x) for x in imp_types]) struct.improper_types.claim() struct.cmap_types.extend([copy(x) for x in cmap_types]) struct.cmap_types.claim() struct.trigonal_angle_types.extend([copy(x) for x in angle_types]) struct.trigonal_angle_types.claim() struct.out_of_plane_bend_types.extend([copy(x) for x in oop_types]) struct.out_of_plane_bend_types.claim() struct.pi_torsion_types.extend([copy(x) for x in dihed_types]) struct.pi_torsion_types.claim() struct.stretch_bend_types.extend([copy(x) for x in strbnd_types]) struct.stretch_bend_types.claim() struct.torsion_torsion_types.extend([copy(x) for x in tortor_types]) struct.torsion_torsion_types.claim() struct.adjust_types.extend([ AmoebaNonbondedExceptionType(0.5, 0.5, 0.6, 0.6, 0.7) for i in range(random.randint(10, 20)) ]) struct.adjust_types.claim() # Add valence terms with optional for i in range(random.randint(40, 50)): struct.bonds.append(Bond(*random.sample(struct.atoms, 2))) if parametrized: struct.bonds[-1].type = random.choice(struct.bond_types) for i in range(random.randint(35, 45)): struct.angles.append(Angle(*random.sample(struct.atoms, 3))) if parametrized: struct.angles[-1].type = random.choice(struct.angle_types) for i in range(random.randint(35, 45)): struct.urey_bradleys.append( UreyBradley(*random.sample(struct.atoms, 2))) if parametrized: struct.urey_bradleys[-1].type = random.choice( struct.urey_bradley_types) for i in range(random.randint(30, 40)): struct.dihedrals.append( Dihedral(*random.sample(struct.atoms, 4), improper=random.choice([True, False]))) if parametrized: struct.dihedrals[-1].type = random.choice(struct.dihedral_types) for i in range(random.randint(30, 40)): struct.rb_torsions.append(Dihedral(*random.sample(struct.atoms, 4))) if parametrized: struct.rb_torsions[-1].type = random.choice( struct.rb_torsion_types) for i in range(random.randint(10, 20)): struct.impropers.append(Improper(*random.sample(struct.atoms, 4))) if parametrized: struct.impropers[-1].type = random.choice(struct.improper_types) for i in range(random.randint(25, 35)): struct.cmaps.append(Cmap(*random.sample(struct.atoms, 5))) if parametrized: struct.cmaps[-1].type = random.choice(struct.cmap_types) for i in range(random.randint(30, 40)): struct.trigonal_angles.append( TrigonalAngle(*random.sample(struct.atoms, 4))) if parametrized: struct.trigonal_angles[-1].type = random.choice( struct.trigonal_angle_types) for i in range(random.randint(30, 40)): struct.out_of_plane_bends.append( OutOfPlaneBend(*random.sample(struct.atoms, 4))) if parametrized: struct.out_of_plane_bends[-1].type = random.choice( struct.out_of_plane_bend_types) for i in range(random.randint(30, 40)): struct.stretch_bends.append( StretchBend(*random.sample(struct.atoms, 3))) if parametrized: struct.stretch_bends[-1].type = random.choice( struct.stretch_bend_types) for i in range(random.randint(20, 30)): struct.pi_torsions.append(PiTorsion(*random.sample(struct.atoms, 6))) if parametrized: struct.pi_torsions[-1].type = random.choice( struct.pi_torsion_types) for i in range(random.randint(10, 20)): struct.torsion_torsions.append( TorsionTorsion(*random.sample(struct.atoms, 5))) if parametrized: struct.torsion_torsions[-1].type = random.choice( struct.torsion_torsion_types) # Now use some lesser-used features for i in range(random.randint(5, 10)): struct.acceptors.append(AcceptorDonor(*random.sample(struct.atoms, 2))) struct.donors.append(AcceptorDonor(*random.sample(struct.atoms, 2))) struct.groups.append(Group(random.choice(struct.atoms), 2, 0)) struct.chiral_frames.append( ChiralFrame(*random.sample(struct.atoms, 2), chirality=random.choice([-1, 1]))) struct.multipole_frames.append( MultipoleFrame(random.choice(struct.atoms), 0, 1, 2, 3)) for i in range(random.randint(20, 30)): struct.adjusts.append( NonbondedException(*random.sample(struct.atoms, 2))) if parametrized: struct.adjusts[-1].type = random.choice(struct.adjust_types) struct.prune_empty_terms() struct.unchange() struct.update_dihedral_exclusions() return struct
def load_parameters(self, parmset, copy_parameters=True): """ Loads parameters from a parameter set that was loaded via CHARMM RTF, PAR, and STR files. Parameters ---------- parmset : :class:`CharmmParameterSet` List of all parameters copy_parameters : bool, optional, default=True If False, parmset will not be copied. WARNING: ------- Not copying parmset will cause ParameterSet and Structure to share references to types. If you modify the original parameter set, the references in Structure list_types will be silently modified. However, if you change any reference in the parameter set, then that reference will no longer be shared with structure. Example where the reference in ParameterSet is changed. The following will NOT modify the parameters in the psf:: psf.load_parameters(parmset, copy_parameters=False) parmset.angle_types[('a1', 'a2', a3')] = AngleType(1, 2) The following WILL change the parameter in the psf because the reference has not been changed in ``ParameterSet``:: psf.load_parameters(parmset, copy_parameters=False) a = parmset.angle_types[('a1', 'a2', 'a3')] a.k = 10 a.theteq = 100 Extra care should be taken when trying this with dihedral_types. Since dihedral_type is a Fourier sequence, ParameterSet stores DihedralType for every term in DihedralTypeList. Therefore, the example below will STILL modify the type in the :class:`Structure` list_types:: parmset.dihedral_types[('a', 'b', 'c', 'd')][0] = DihedralType(1, 2, 3) This assigns a new instance of DihedralType to an existing DihedralTypeList that ParameterSet and Structure are tracking and the shared reference is NOT changed. Use with caution! Notes ----- - If any dihedral or improper parameters cannot be found, I will try inserting wildcards (at either end for dihedrals and as the two central atoms in impropers) and see if that matches. Wild-cards will apply ONLY if specific parameters cannot be found. - This method will expand the dihedrals attribute by adding a separate Dihedral object for each term for types that have a multi-term expansion Raises ------ ParameterError if any parameters cannot be found """ if copy_parameters: parmset = _copy(parmset) self.combining_rule = parmset.combining_rule # First load the atom types for atom in self.atoms: try: if isinstance(atom.type, int): atype = parmset.atom_types_int[atom.type] else: atype = parmset.atom_types_str[atom.type] except KeyError: raise ParameterError('Could not find atom type for %s' % atom.type) atom.atom_type = atype # Change to string type to look up the rest of the parameters atom.type = str(atom.atom_type) atom.atomic_number = atype.atomic_number # Next load all of the bonds for bond in self.bonds: # Construct the key key = (min(bond.atom1.type, bond.atom2.type), max(bond.atom1.type, bond.atom2.type)) try: bond.type = parmset.bond_types[key] except KeyError: raise ParameterError('Missing bond type for %r' % bond) bond.type.used = False # Build the bond_types list del self.bond_types[:] for bond in self.bonds: if bond.type.used: continue bond.type.used = True self.bond_types.append(bond.type) bond.type.list = self.bond_types # Next load all of the angles. If a Urey-Bradley term is defined for # this angle, also build the urey_bradley and urey_bradley_type lists del self.urey_bradleys[:] for ang in self.angles: # Construct the key key = (min(ang.atom1.type, ang.atom3.type), ang.atom2.type, max(ang.atom1.type, ang.atom3.type)) try: ang.type = parmset.angle_types[key] ang.type.used = False ubt = parmset.urey_bradley_types[key] if ubt is not NoUreyBradley: ub = UreyBradley(ang.atom1, ang.atom3, ubt) self.urey_bradleys.append(ub) ubt.used = False except KeyError: raise ParameterError('Missing angle type for %r' % ang) del self.urey_bradley_types[:] del self.angle_types[:] for ub in self.urey_bradleys: if ub.type.used: continue ub.type.used = True self.urey_bradley_types.append(ub.type) ub.type.list = self.urey_bradley_types for ang in self.angles: if ang.type.used: continue ang.type.used = True self.angle_types.append(ang.type) ang.type.list = self.angle_types # Next load all of the dihedrals. active_dih_list = set() for dih in self.dihedrals: # Store the atoms a1, a2, a3, a4 = dih.atom1, dih.atom2, dih.atom3, dih.atom4 key = (a1.type, a2.type, a3.type, a4.type) # First see if the exact dihedral is specified if not key in parmset.dihedral_types: # Check for wild-cards key = ('X', a2.type, a3.type, 'X') if not key in parmset.dihedral_types: raise ParameterError('No dihedral parameters found for ' '%r' % dih) dih.type = parmset.dihedral_types[key] dih.type.used = False pair = (dih.atom1.idx, dih.atom4.idx) # To determine exclusions if (dih.atom1 in dih.atom4.bond_partners or dih.atom1 in dih.atom4.angle_partners): dih.ignore_end = True elif pair in active_dih_list: dih.ignore_end = True else: active_dih_list.add(pair) active_dih_list.add((dih.atom4.idx, dih.atom1.idx)) del self.dihedral_types[:] for dihedral in self.dihedrals: if dihedral.type.used: continue dihedral.type.used = True self.dihedral_types.append(dihedral.type) dihedral.type.list = self.dihedral_types # Now do the impropers for imp in self.impropers: # Store the atoms a1, a2, a3, a4 = imp.atom1, imp.atom2, imp.atom3, imp.atom4 at1, at2, at3, at4 = a1.type, a2.type, a3.type, a4.type key = tuple(sorted([at1, at2, at3, at4])) altkey1 = a1.type, a2.type, a3.type, a4.type altkey2 = a4.type, a3.type, a2.type, a1.type # Check for exact harmonic or exact periodic if key in parmset.improper_types: imp.type = parmset.improper_types[key] elif key in parmset.improper_periodic_types: imp.type = parmset.improper_periodic_types[key] elif altkey1 in parmset.improper_periodic_types: imp.type = parmset.improper_periodic_types[altkey1] elif altkey2 in parmset.improper_periodic_types: imp.type = parmset.improper_periodic_types[altkey2] else: # Check for wild-card harmonic for anchor in (at2, at3, at4): key = tuple(sorted([at1, anchor, 'X', 'X'])) if key in parmset.improper_types: imp.type = parmset.improper_types[key] break # Check for wild-card periodic if key not in parmset.improper_types: for anchor in (at2, at3, at4): key = tuple(sorted([at1, anchor, 'X', 'X'])) if key in parmset.improper_periodic_types: imp.type = parmset.improper_periodic_types[key] break # Not found anywhere if key not in parmset.improper_periodic_types: raise ParameterError( 'No improper parameters found for ' '%r' % imp) imp.type.used = False # prepare list of harmonic impropers present in system del self.improper_types[:] for improper in self.impropers: if improper.type.used: continue improper.type.used = True if isinstance(improper.type, ImproperType): self.improper_types.append(improper.type) improper.type.list = self.improper_types elif isinstance(improper.type, DihedralType): self.dihedral_types.append(improper.type) improper.type.list = self.dihedral_types else: assert False, 'Should not be here' # Look through the list of impropers -- if there are any periodic # impropers, move them over to the dihedrals list for i in reversed(range(len(self.impropers))): if isinstance(self.impropers[i].type, DihedralType): imp = self.impropers.pop(i) dih = Dihedral(imp.atom1, imp.atom2, imp.atom3, imp.atom4, improper=True, ignore_end=True, type=imp.type) imp.delete() self.dihedrals.append(dih) # Now do the cmaps. These will not have wild-cards for cmap in self.cmaps: key = (cmap.atom1.type, cmap.atom2.type, cmap.atom3.type, cmap.atom4.type, cmap.atom2.type, cmap.atom3.type, cmap.atom4.type, cmap.atom5.type) try: cmap.type = parmset.cmap_types[key] except KeyError: raise ParameterError('No CMAP parameters found for %r' % cmap) cmap.type.used = False del self.cmap_types[:] for cmap in self.cmaps: if cmap.type.used: continue cmap.type.used = True self.cmap_types.append(cmap.type) cmap.type.list = self.cmap_types
def load_parameters(self, parmset): """ Loads parameters from a parameter set that was loaded via CHARMM RTF, PAR, and STR files. Parameters ---------- parmset : :class:`CharmmParameterSet` List of all parameters Notes ----- - If any dihedral or improper parameters cannot be found, I will try inserting wildcards (at either end for dihedrals and as the two central atoms in impropers) and see if that matches. Wild-cards will apply ONLY if specific parameters cannot be found. - This method will expand the dihedrals attribute by adding a separate Dihedral object for each term for types that have a multi-term expansion Raises ------ ParameterError if any parameters cannot be found """ parmset = _copy(parmset) self.combining_rule = parmset.combining_rule # First load the atom types for atom in self.atoms: try: if isinstance(atom.type, int): atype = parmset.atom_types_int[atom.type] else: atype = parmset.atom_types_str[atom.type] except KeyError: raise ParameterError('Could not find atom type for %s' % atom.type) atom.atom_type = atype # Change to string type to look up the rest of the parameters atom.type = str(atom.atom_type) atom.atomic_number = atype.atomic_number # Next load all of the bonds for bond in self.bonds: # Construct the key key = (min(bond.atom1.type, bond.atom2.type), max(bond.atom1.type, bond.atom2.type)) try: bond.type = parmset.bond_types[key] except KeyError: raise ParameterError('Missing bond type for %r' % bond) bond.type.used = False # Build the bond_types list del self.bond_types[:] for bond in self.bonds: if bond.type.used: continue bond.type.used = True self.bond_types.append(bond.type) bond.type.list = self.bond_types # Next load all of the angles. If a Urey-Bradley term is defined for # this angle, also build the urey_bradley and urey_bradley_type lists del self.urey_bradleys[:] for ang in self.angles: # Construct the key key = (min(ang.atom1.type, ang.atom3.type), ang.atom2.type, max(ang.atom1.type, ang.atom3.type)) try: ang.type = parmset.angle_types[key] ang.type.used = False ubt = parmset.urey_bradley_types[key] if ubt is not NoUreyBradley: ub = UreyBradley(ang.atom1, ang.atom3, ubt) self.urey_bradleys.append(ub) ubt.used = False except KeyError: raise ParameterError('Missing angle type for %r' % ang) del self.urey_bradley_types[:] del self.angle_types[:] for ub in self.urey_bradleys: if ub.type.used: continue ub.type.used = True self.urey_bradley_types.append(ub.type) ub.type.list = self.urey_bradley_types for ang in self.angles: if ang.type.used: continue ang.type.used = True self.angle_types.append(ang.type) ang.type.list = self.angle_types # Next load all of the dihedrals. active_dih_list = set() for dih in self.dihedrals: # Store the atoms a1, a2, a3, a4 = dih.atom1, dih.atom2, dih.atom3, dih.atom4 key = (a1.type, a2.type, a3.type, a4.type) # First see if the exact dihedral is specified if not key in parmset.dihedral_types: # Check for wild-cards key = ('X', a2.type, a3.type, 'X') if not key in parmset.dihedral_types: raise ParameterError('No dihedral parameters found for ' '%r' % dih) dih.type = parmset.dihedral_types[key] dih.type.used = False pair = (dih.atom1.idx, dih.atom4.idx) # To determine exclusions if (dih.atom1 in dih.atom4.bond_partners or dih.atom1 in dih.atom4.angle_partners): dih.ignore_end = True elif pair in active_dih_list: dih.ignore_end = True else: active_dih_list.add(pair) active_dih_list.add((dih.atom4.idx, dih.atom1.idx)) del self.dihedral_types[:] for dihedral in self.dihedrals: if dihedral.type.used: continue dihedral.type.used = True self.dihedral_types.append(dihedral.type) dihedral.type.list = self.dihedral_types # Now do the impropers for imp in self.impropers: # Store the atoms a1, a2, a3, a4 = imp.atom1, imp.atom2, imp.atom3, imp.atom4 at1, at2, at3, at4 = a1.type, a2.type, a3.type, a4.type key = tuple(sorted([at1, at2, at3, at4])) # Check for exact harmonic or exact periodic if key in parmset.improper_types: imp.type = parmset.improper_types[key] elif key in parmset.improper_periodic_types: imp.type = parmset.improper_periodic_types[key] else: # Check for wild-card harmonic for anchor in (at2, at3, at4): key = tuple(sorted([at1, anchor, 'X', 'X'])) if key in parmset.improper_types: imp.type = parmset.improper_types[key] break # Check for wild-card periodic if key not in parmset.improper_types: for anchor in (at2, at3, at4): key = tuple(sorted([at1, anchor, 'X', 'X'])) if key in parmset.improper_periodic_types: imp.type = parmset.improper_periodic_types[key] break # Not found anywhere if key not in parmset.improper_periodic_types: raise ParameterError('No improper parameters found for' '%r' % imp) imp.type.used = False # prepare list of harmonic impropers present in system del self.improper_types[:] for improper in self.impropers: if improper.type.used: continue improper.type.used = True if isinstance(improper.type, ImproperType): self.improper_types.append(improper.type) improper.type.list = self.improper_types elif isinstance(improper.type, DihedralType): self.dihedral_types.append(improper.type) improper.type.list = self.dihedral_types else: assert False, 'Should not be here' # Look through the list of impropers -- if there are any periodic # impropers, move them over to the dihedrals list for i in reversed(range(len(self.impropers))): if isinstance(self.impropers[i].type, DihedralType): imp = self.impropers.pop(i) dih = Dihedral(imp.atom1, imp.atom2, imp.atom3, imp.atom4, improper=True, ignore_end=True, type=imp.type) imp.delete() self.dihedrals.append(dih) # Now do the cmaps. These will not have wild-cards for cmap in self.cmaps: key = (cmap.atom1.type, cmap.atom2.type, cmap.atom3.type, cmap.atom4.type, cmap.atom2.type, cmap.atom3.type, cmap.atom4.type, cmap.atom5.type) try: cmap.type = parmset.cmap_types[key] except KeyError: raise ParameterError('No CMAP parameters found for %r' % cmap) cmap.type.used = False del self.cmap_types[:] for cmap in self.cmaps: if cmap.type.used: continue cmap.type.used = True self.cmap_types.append(cmap.type) cmap.type.list = self.cmap_types