Exemplo n.º 1
0
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()
Exemplo n.º 2
0
 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]))
Exemplo 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
Exemplo 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
Exemplo n.º 5
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