Esempio n. 1
0
def _process_dihedral(struct, force):
    """ Adds periodic torsions to the structure """
    typemap = dict()
    for ii in range(force.getNumTorsions()):
        i, j, k, l, per, phase, phi_k = force.getTorsionParameters(ii)
        ai, aj = struct.atoms[i], struct.atoms[j]
        ak, al = struct.atoms[k], struct.atoms[l]
        key = (per, phase._value, phi_k._value)
        if key in typemap:
            dihed_type = typemap[key]
        else:
            dihed_type = DihedralType(phi_k, per, phase)
            typemap[key] = dihed_type
            struct.dihedral_types.append(dihed_type)
        improper = (ai in ak.bond_partners and aj in ak.bond_partners
                    and al in ak.bond_partners)
        struct.dihedrals.append(
            Dihedral(ai, aj, ak, al, improper=improper, type=dihed_type))
    struct.dihedral_types.claim()
Esempio n. 2
0
def _process_rbtorsion(struct, force):
    """ Adds Ryckaert-Bellemans torsions to the structure """
    typemap = dict()
    for ii in range(force.getNumTorsions()):
        i, j, k, l, c0, c1, c2, c3, c4, c5 = force.getTorsionParameters(ii)
        ai, aj = struct.atoms[i], struct.atoms[j]
        ak, al = struct.atoms[k], struct.atoms[l]
        # TODO -- Fix this when OpenMM is fixed
        try:
            key = (c0._value, c1._value, c2._value, c3._value, c4._value,
                   c5._value)
            f = 1  # pragma: no cover
        except AttributeError:  # pragma: no cover
            key = (c0, c1, c2, c3, c4, c5)  # pragma: no cover
            f = u.kilojoules_per_mole  # pragma: no cover
        if key in typemap:
            dihed_type = typemap[key]
        else:
            dihed_type = RBTorsionType(c0 * f, c1 * f, c2 * f, c3 * f, c4 * f,
                                       c5 * f)
            typemap[key] = dihed_type
            struct.rb_torsion_types.append(dihed_type)
        struct.rb_torsions.append(Dihedral(ai, aj, ak, al, type=dihed_type))
    struct.rb_torsion_types.claim()
Esempio n. 3
0
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
Esempio n. 4
0
    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
Esempio n. 5
0
 def __init__(self, psf_name=None):
     """
     Opens and parses a PSF file, then instantiates a CharmmPsfFile
     instance from the data.
     """
     global _resre
     Structure.__init__(self)
     # Bail out if we don't have a filename
     if psf_name is None:
         return
     conv = CharmmPsfFile._convert
     # Open the PSF and read the first line. It must start with "PSF"
     with closing(genopen(psf_name, 'r')) as psf:
         self.name = psf_name
         line = psf.readline()
         if not line.startswith('PSF'):
             raise CharmmError('Unrecognized PSF file. First line is %s' %
                               line.strip())
         # Store the flags
         psf_flags = line.split()[1:]
         # Now get all of the sections and store them in a dict
         psf.readline()
         # Now get all of the sections
         psfsections = _ZeroDict()
         while True:
             try:
                 sec, ptr, data = CharmmPsfFile._parse_psf_section(psf)
             except _FileEOF:
                 break
             psfsections[sec] = (ptr, data)
         # store the title
         self.title = psfsections['NTITLE'][1]
         # Next is the number of atoms
         natom = conv(psfsections['NATOM'][0], int, 'natom')
         # Parse all of the atoms
         for i in range(natom):
             words = psfsections['NATOM'][1][i].split()
             atid = int(words[0])
             if atid != i + 1:
                 raise CharmmError('Nonsequential atoms detected!')
             segid = words[1]
             rematch = _resre.match(words[2])
             if not rematch:
                 raise CharmmError('Could not interpret residue number %s'
                                   %  # pragma: no cover
                                   words[2])
             resid, inscode = rematch.groups()
             resid = conv(resid, int, 'residue number')
             resname = words[3]
             name = words[4]
             attype = words[5]
             # Try to convert the atom type to an integer a la CHARMM
             try:
                 attype = int(attype)
             except ValueError:
                 pass
             charge = conv(words[6], float, 'partial charge')
             mass = conv(words[7], float, 'atomic mass')
             props = words[8:]
             atom = Atom(name=name, type=attype, charge=charge, mass=mass)
             atom.props = props
             self.add_atom(atom,
                           resname,
                           resid,
                           chain=segid,
                           inscode=inscode,
                           segid=segid)
         # Now get the number of bonds
         nbond = conv(psfsections['NBOND'][0], int, 'number of bonds')
         if len(psfsections['NBOND'][1]) != nbond * 2:
             raise CharmmError(
                 'Got %d indexes for %d bonds' %  # pragma: no cover
                 (len(psfsections['NBOND'][1]), nbond))
         it = iter(psfsections['NBOND'][1])
         for i, j in zip(it, it):
             self.bonds.append(Bond(self.atoms[i - 1], self.atoms[j - 1]))
         # Now get the number of angles and the angle list
         ntheta = conv(psfsections['NTHETA'][0], int, 'number of angles')
         if len(psfsections['NTHETA'][1]) != ntheta * 3:
             raise CharmmError(
                 'Got %d indexes for %d angles' %  # pragma: no cover
                 (len(psfsections['NTHETA'][1]), ntheta))
         it = iter(psfsections['NTHETA'][1])
         for i, j, k in zip(it, it, it):
             self.angles.append(
                 Angle(self.atoms[i - 1], self.atoms[j - 1],
                       self.atoms[k - 1]))
             self.angles[-1].funct = 5  # urey-bradley
         # Now get the number of torsions and the torsion list
         nphi = conv(psfsections['NPHI'][0], int, 'number of torsions')
         if len(psfsections['NPHI'][1]) != nphi * 4:
             raise CharmmError(
                 'Got %d indexes for %d torsions' %  # pragma: no cover
                 (len(psfsections['NPHI']), nphi))
         it = iter(psfsections['NPHI'][1])
         for i, j, k, l in zip(it, it, it, it):
             self.dihedrals.append(
                 Dihedral(self.atoms[i - 1], self.atoms[j - 1],
                          self.atoms[k - 1], self.atoms[l - 1]))
         self.dihedrals.split = False
         # Now get the number of improper torsions
         nimphi = conv(psfsections['NIMPHI'][0], int, 'number of impropers')
         if len(psfsections['NIMPHI'][1]) != nimphi * 4:
             raise CharmmError(
                 'Got %d indexes for %d impropers' %  # pragma: no cover
                 (len(psfsections['NIMPHI'][1]), nimphi))
         it = iter(psfsections['NIMPHI'][1])
         for i, j, k, l in zip(it, it, it, it):
             self.impropers.append(
                 Improper(self.atoms[i - 1], self.atoms[j - 1],
                          self.atoms[k - 1], self.atoms[l - 1]))
         # Now handle the donors (what is this used for??)
         ndon = conv(psfsections['NDON'][0], int, 'number of donors')
         if len(psfsections['NDON'][1]) != ndon * 2:
             raise CharmmError(
                 'Got %d indexes for %d donors' %  # pragma: no cover
                 (len(psfsections['NDON'][1]), ndon))
         it = iter(psfsections['NDON'][1])
         for i, j in zip(it, it):
             self.donors.append(
                 AcceptorDonor(self.atoms[i - 1], self.atoms[j - 1]))
         # Now handle the acceptors (what is this used for??)
         nacc = conv(psfsections['NACC'][0], int, 'number of acceptors')
         if len(psfsections['NACC'][1]) != nacc * 2:
             raise CharmmError(
                 'Got %d indexes for %d acceptors' %  # pragma: no cover
                 (len(psfsections['NACC'][1]), nacc))
         it = iter(psfsections['NACC'][1])
         for i, j in zip(it, it):
             self.acceptors.append(
                 AcceptorDonor(self.atoms[i - 1], self.atoms[j - 1]))
         # Now get the group sections
         try:
             ngrp, nst2 = psfsections['NGRP NST2'][0]
         except ValueError:  # pragma: no cover
             raise CharmmError(
                 'Could not unpack GROUP pointers')  # pragma: no cover
         tmp = psfsections['NGRP NST2'][1]
         self.groups.nst2 = nst2
         # Now handle the groups
         if len(psfsections['NGRP NST2'][1]) != ngrp * 3:
             raise CharmmError(
                 'Got %d indexes for %d groups' %  # pragma: no cover
                 (len(tmp), ngrp))
         it = iter(psfsections['NGRP NST2'][1])
         for i, j, k in zip(it, it, it):
             self.groups.append(Group(self.atoms[i], j, k))
         # Assign all of the atoms to molecules recursively
         tmp = psfsections['MOLNT'][1]
         set_molecules(self.atoms)
         molecule_list = [a.marked for a in self.atoms]
         if len(tmp) == len(self.atoms):
             if molecule_list != tmp:
                 warnings.warn(
                     'Detected PSF molecule section that is WRONG. '
                     'Resetting molecularity.', CharmmWarning)
             # We have a CHARMM PSF file; now do NUMLP/NUMLPH sections
             numlp, numlph = psfsections['NUMLP NUMLPH'][0]
             if numlp != 0 or numlph != 0:
                 raise NotImplementedError(
                     'Cannot currently handle PSFs with '
                     'lone pairs defined in the NUMLP/'
                     'NUMLPH section.')
         # Now do the CMAPs
         ncrterm = conv(psfsections['NCRTERM'][0], int,
                        'Number of cross-terms')
         if len(psfsections['NCRTERM'][1]) != ncrterm * 8:
             raise CharmmError('Got %d CMAP indexes for %d cmap terms'
                               %  # pragma: no cover
                               (len(psfsections['NCRTERM']), ncrterm))
         it = iter(psfsections['NCRTERM'][1])
         for i, j, k, l, m, n, o, p in zip(it, it, it, it, it, it, it, it):
             self.cmaps.append(
                 Cmap.extended(self.atoms[i - 1], self.atoms[j - 1],
                               self.atoms[k - 1], self.atoms[l - 1],
                               self.atoms[m - 1], self.atoms[n - 1],
                               self.atoms[o - 1], self.atoms[p - 1]))
         self.unchange()
         self.flags = psf_flags
Esempio n. 6
0
    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