Exemple #1
0
 def test_distance2(self):
     """ Tests the distance2 calculation """
     a1, a2 = Atom(), Atom()
     a1.xx = a1.xy = a1.xz = 0
     a2.xx = 3
     a2.xy = 4
     a2.xz = 0
     self.assertEqual(geo.distance2(a1, a2), 25)
     # Make sure it also works for tuples and a mixture of both
     self.assertEqual(geo.distance2((0, 0, 0), (3, 4, 0)), 25)
     self.assertEqual(geo.distance2(a1, (3, 4, 0)), 25)
     self.assertEqual(geo.distance2((0, 0, 0), a2), 25)
 def test_dihedral(self):
     """ Tests calculating a torsion angle between 4 points """
     a1, a2, a3, a4 = Atom(), Atom(), Atom(), Atom()
     a1.xx, a1.xy, a1.xz = 1, 0, 0
     a2.xx, a2.xy, a2.xz = 0, 0, 0
     a3.xx, a3.xy, a3.xz = 0, 0, 1
     a4.xx, a4.xy, a4.xz = 0.1, 0.6, 1
     self.assertAlmostEqual(geo.dihedral(a1, a2, a3, a4), 80.537677791974374)
     self.assertAlmostEqual(
             geo.dihedral([1, 0, 0], [0, 0, 0], [0, 0, 1], [0.1, 0.6, 1]),
             80.537677791974374
     )
Exemple #3
0
 def test_angle(self):
     """ Tests the angle calculation """
     a1, a2, a3 = Atom(), Atom(), Atom()
     a1.xx = a1.xy = a1.xz = 0
     a2.xx, a2.xy, a2.xz = 1, 0, 0
     a3.xx, a3.xy, a3.xz = 1, 1, 0
     self.assertAlmostEqual(geo.angle(a1, a2, a3), 90)
     # Check pathological cases
     a3.xx, a3.xy, a3.xz = 2, 0, 0
     self.assertAlmostEqual(geo.angle(a1, a2, a3), 180)
     a3.xx = a3.xy = a3.xz = 0
     self.assertAlmostEqual(geo.angle(a1, a2, a3), 0)
Exemple #4
0
def pdb4all2parmed(structure: 'PDB') -> 'Structure':
    structure.guess_elements()
    struc_pmd = Structure()
    for a in structure.pdb:
        atom = Atom(atomic_number=Ptable[a['element']]['N'],
                    name=a['name'],
                    number=a['serial'])
        struc_pmd.add_atom(atom=atom,
                           resname=a['resName'],
                           resnum=a['resSeq'],
                           chain=a['chainID'],
                           segid=a['segment'])
    struc_pmd.coordinates = structure.xyz
    struc_pmd.assign_bonds()
    return struc_pmd
Exemple #5
0
 def test_dihedral(self):
     """ Tests calculating a torsion angle between 4 points """
     a1, a2, a3, a4 = Atom(), Atom(), Atom(), Atom()
     a1.xx, a1.xy, a1.xz = 1, 0, 0
     a2.xx, a2.xy, a2.xz = 0, 0, 0
     a3.xx, a3.xy, a3.xz = 0, 0, 1
     a4.xx, a4.xy, a4.xz = 0.1, 0.6, 1
     self.assertAlmostEqual(geo.dihedral(a1, a2, a3, a4), 80.537677791974374)
     self.assertAlmostEqual(
             geo.dihedral([1, 0, 0], [0, 0, 0], [0, 0, 1], [0.1, 0.6, 1]),
             80.537677791974374
     )
Exemple #6
0
    def _parse_residue(fileobj, name):
        """
        Parses the residue information out of the OFF file assuming the file
        is pointed at the first line of an atoms table section of the OFF file

        Parameters
        ----------
        fileobj : file-like
            Assumed to be open for read, this file is parsed until the *next*
            atom table is read
        name : str
            The name of the residue being processed right now
        """
        container = ResidueTemplateContainer(name)
        nres = 1
        templ = ResidueTemplate(name)
        line = fileobj.readline()
        while line[0] != '!':
            nam, typ, typx, resx, flags, seq, elmnt, chg = line.split()
            nam = _strip_enveloping_quotes(nam)
            typ = _strip_enveloping_quotes(typ)
            typx = int(typx)
            resx = int(resx)
            flags = int(flags)
            seq = int(seq)
            elmnt = int(elmnt)
            chg = float(chg)
            atom = Atom(atomic_number=elmnt, type=typ, name=nam, charge=chg)
            if resx == nres + 1:
                container.append(templ)
                nres += 1
                templ = ResidueTemplate(name)
            templ.add_atom(atom)
            line = fileobj.readline()
        container.append(templ)
        if nres > 1:
            start_atoms = []
            runsum = 0
            for res in container:
                start_atoms.append(runsum)
                runsum += len(res)
        # Make sure we get the next section
        rematch = AmberOFFLibrary._sec2re.match(line)
        if not rematch:
            raise RuntimeError('Expected pertinfo table not found')
        elif rematch.groups()[0] != name:
            raise RuntimeError('Found residue %s while processing residue %s' %
                               (rematch.groups()[0], name))
        line = fileobj.readline()
        while line[0] != '!':
            if not line:
                raise RuntimeError('Unexpected EOF in Amber OFF library')
            # Not used, just skip
            # TODO sanity check
            line = fileobj.readline()
        rematch = AmberOFFLibrary._sec3re.match(line)
        if not rematch:
            raise RuntimeError('Expected boundbox table not found')
        elif rematch.groups()[0] != name:
            raise RuntimeError('Found residue %s while processing residue %s' %
                               (rematch.groups()[0], name))
        # Only 5 lines
        try:
            hasbox = float(fileobj.readline().strip())
            angle = float(fileobj.readline().strip())
            a = float(fileobj.readline().strip())
            b = float(fileobj.readline().strip())
            c = float(fileobj.readline().strip())
        except ValueError:
            raise RuntimeError('Error processing boundbox table entries')
        else:
            if hasbox > 0:
                angle *= RAD_TO_DEG
                container.box = [a, b, c, angle, angle, angle]
        # Get the child sequence entry
        line = fileobj.readline()
        rematch = AmberOFFLibrary._sec4re.match(line)
        if not rematch:
            raise RuntimeError('Expected childsequence table not found')
        elif rematch.groups()[0] != name:
            raise RuntimeError('Found residue %s while processing residue %s' %
                               (rematch.groups()[0], name))
        n = int(fileobj.readline().strip())
        if nres + 1 != n:
            warnings.warn('Unexpected childsequence (%d); expected %d for '
                          'residue %s' % (n, nres+1, name), AmberWarning)
        elif not isinstance(templ, ResidueTemplate) and n != len(templ) + 1:
            raise RuntimeError('child sequence must be 1 greater than the '
                               'number of residues in the unit')
        # Get the CONNECT array to set head and tail
        line = fileobj.readline()
        rematch = AmberOFFLibrary._sec5re.match(line)
        if not rematch:
            raise RuntimeError('Expected connect array not found')
        elif rematch.groups()[0] != name:
            raise RuntimeError('Found residue %s while processing residue %s' %
                               (rematch.groups()[0], name))
        try:
            head = int(fileobj.readline().strip())
            tail = int(fileobj.readline().strip())
        except ValueError:
            raise RuntimeError('Error processing connect table entries')
        if head > 0 and nres == 1:
            templ.head = templ[head-1]
        elif head > 0 and nres > 1:
            if head < sum([len(r) for r in container]):
                raise RuntimeError('HEAD on multi-residue unit not supported')
        if tail > 0 and nres == 1:
            templ.tail = templ[tail-1]
        elif tail > 0 and nres > 1:
            if tail < sum([len(r) for r in container]):
                warnings.warn('TAIL on multi-residue unit not supported (%s). '
                              'Ignored...' % name, AmberWarning)
        # Get the connectivity array to set bonds
        line = fileobj.readline()
        rematch = AmberOFFLibrary._sec6re.match(line)
        if not rematch:
            raise RuntimeError('Expected connectivity table not found')
        elif rematch.groups()[0] != name:
            raise RuntimeError('Found residue %s while processing residue %s' %
                               (rematch.groups()[0], name))
        line = fileobj.readline()
        while line[0] != '!':
            i, j, flag = line.split()
            line = fileobj.readline()
            if nres > 1:
                # Find which residue we belong in
                i = int(i) - 1
                j = int(j) - 1
                for ii, idx in enumerate(start_atoms):
                    if idx > i:
                        ii -= 1
                        break
                start_idx = start_atoms[ii]
                container[ii].add_bond(i-start_idx, j-start_idx)
            else:
                templ.add_bond(int(i)-1, int(j)-1)
        # Get the hierarchy table
        rematch = AmberOFFLibrary._sec7re.match(line)
        if not rematch:
            raise RuntimeError('Expected hierarchy table not found')
        elif rematch.groups()[0] != name:
            raise RuntimeError('Found residue %s while processing residue %s' %
                               (rematch.groups()[0], name))
        line = fileobj.readline()
        while line[0] != '!':
            # Skip this section... not used
            # TODO turn this into a sanity check
            line = fileobj.readline()
        # Get the unit name
        rematch = AmberOFFLibrary._sec8re.match(line)
        if not rematch:
            raise RuntimeError('Expected unit name string not found')
        elif rematch.groups()[0] != name:
            raise RuntimeError('Found residue %s while processing residue %s' %
                               (rematch.groups()[0], name))
        fileobj.readline() # Skip this... not used
        line = fileobj.readline()
        # Get the atomic positions
        rematch = AmberOFFLibrary._sec9re.match(line)
        if not rematch:
            raise RuntimeError('Expected unit positions table not found')
        elif rematch.groups()[0] != name:
            raise RuntimeError('Found residue %s while processing residue %s' %
                               (rematch.groups()[0], name))
        for res in container:
            for atom in res:
                x, y, z = fileobj.readline().split()
                atom.xx, atom.xy, atom.xz = float(x), float(y), float(z)
        line = fileobj.readline()
        # Get the residueconnect table
        rematch = AmberOFFLibrary._sec10re.match(line)
        if not rematch:
            raise RuntimeError('Expected unit residueconnect table not found')
        elif rematch.groups()[0] != name:
            raise RuntimeError('Found residue %s while processing residue %s' %
                               (rematch.groups()[0], name))
        for i in range(nres):
            c1,c2,c3,c4,c5,c6 = [int(x) for x in fileobj.readline().split()]
            if templ.head is not None and templ.head is not templ[c1-1]:
                warnings.warn('HEAD atom is not connect0')
            if templ.tail is not None and templ.tail is not templ[c2-1]:
                warnings.warn('TAIL atom is not connect1')
            for i in (c3, c4, c5, c6):
                if i == 0: continue
                templ.connections.append(templ[i-1])
        # Get the residues table
        line = fileobj.readline()
        rematch = AmberOFFLibrary._sec11re.match(line)
        if not rematch:
            raise RuntimeError('Expected unit residues table not found')
        elif rematch.groups()[0] != name:
            raise RuntimeError('Found residue %s while processing residue %s' %
                               (rematch.groups()[0], name))
        for i in range(nres):
            resname, id, next, start, typ, img = fileobj.readline().split()
            resname = _strip_enveloping_quotes(resname)
            id = int(id)
            start = int(start)
            next = int(next)
            typ = _strip_enveloping_quotes(typ)
            img = int(img)
            if next - start != len(container[i]):
                warnings.warn('residue table predicted %d, not %d atoms for '
                              'residue %s' % (next-start, len(container[i]),
                              name), AmberWarning)
            if typ == 'p':
                container[i].type = PROTEIN
            elif typ == 'n':
                container[i].type = NUCLEIC
            elif typ == 'w':
                container[i].type = SOLVENT
            elif typ != '?':
                warnings.warn('Unknown residue type "%s"' % typ,
                              AmberWarning)
            if nres > 1:
                container[i].name = resname
        # Get the residues sequence table
        line = fileobj.readline()
        rematch = AmberOFFLibrary._sec12re.match(line)
        if not rematch:
            raise RuntimeError('Expected residue sequence number not found')
        elif rematch.groups()[0] != name:
            raise RuntimeError('Found residue %s while processing residue %s' %
                               (rematch.groups()[0], name))
        for i in range(nres):
            #TODO sanity check
            fileobj.readline()
        line = fileobj.readline()
        # Get the solventcap array
        rematch = AmberOFFLibrary._sec13re.match(line)
        if not rematch:
            raise RuntimeError('Expected unit solventcap array not found')
        elif rematch.groups()[0] != name:
            raise RuntimeError('Found residue %s while processing residue %s' %
                               (rematch.groups()[0], name))
        # Ignore the solvent cap
        fileobj.readline()
        fileobj.readline()
        fileobj.readline()
        fileobj.readline()
        fileobj.readline()
        # Velocities
        line = fileobj.readline()
        rematch = AmberOFFLibrary._sec14re.match(line)
        if not rematch:
            raise RuntimeError('Expected unit solventcap array not found')
        elif rematch.groups()[0] != name:
            raise RuntimeError('Found residue %s while processing residue %s' %
                               (rematch.groups()[0], name))
        for res in container:
            for atom in res:
                vx, vy, vz = [float(x) for x in fileobj.readline().split()]
                atom.vx, atom.vy, atom.vz = vx, vy, vz

        if nres > 1:
            return container
        return templ
Exemple #7
0
    def _parse_residue(fileobj, name):
        """
        Parses the residue information out of the OFF file assuming the file
        is pointed at the first line of an atoms table section of the OFF file

        Parameters
        ----------
        fileobj : file-like
            Assumed to be open for read, this file is parsed until the *next*
            atom table is read
        name : str
            The name of the residue being processed right now
        """
        container = ResidueTemplateContainer(name)
        nres = 1
        templ = ResidueTemplate(name)
        line = fileobj.readline()
        while line[0] != '!':
            nam, typ, typx, resx, flags, seq, elmnt, chg = line.split()
            nam = _strip_enveloping_quotes(nam)
            typ = _strip_enveloping_quotes(typ)
            typx = int(typx)
            resx = int(resx)
            flags = int(flags)
            seq = int(seq)
            elmnt = int(elmnt)
            chg = float(chg)
            atom = Atom(atomic_number=elmnt, type=typ, name=nam, charge=chg)
            if resx == nres + 1:
                container.append(templ)
                nres += 1
                templ = ResidueTemplate(name)
            templ.add_atom(atom)
            line = fileobj.readline()
            # Skip blank lines
            while line and not line.strip():
                line = fileobj.readline()
        container.append(templ)
        if nres > 1:
            start_atoms = []
            runsum = 0
            for res in container:
                start_atoms.append(runsum)
                runsum += len(res)
        # Make sure we get the next section
        rematch = AmberOFFLibrary._sec2re.match(line)
        if not rematch:
            raise RuntimeError('Expected pertinfo table not found')
        elif rematch.groups()[0] != name:
            raise RuntimeError('Found residue %s while processing residue %s' %
                               (rematch.groups()[0], name))
        line = fileobj.readline()
        while line[0] != '!':
            if not line:
                raise RuntimeError('Unexpected EOF in Amber OFF library')
            # Not used, just skip
            # TODO sanity check
            line = fileobj.readline()
        rematch = AmberOFFLibrary._sec3re.match(line)
        if not rematch:
            raise RuntimeError('Expected boundbox table not found')
        elif rematch.groups()[0] != name:
            raise RuntimeError('Found residue %s while processing residue %s' %
                               (rematch.groups()[0], name))
        # Only 5 lines
        try:
            hasbox = float(fileobj.readline().strip())
            angle = float(fileobj.readline().strip())
            a = float(fileobj.readline().strip())
            b = float(fileobj.readline().strip())
            c = float(fileobj.readline().strip())
        except ValueError:
            raise RuntimeError('Error processing boundbox table entries')
        else:
            if hasbox > 0:
                if angle < 3.15:
                    # No box is this acute -- must be in radians
                    angle *= RAD_TO_DEG
                container.box = [a, b, c, angle, angle, angle]
        # Get the child sequence entry
        line = fileobj.readline()
        rematch = AmberOFFLibrary._sec4re.match(line)
        if not rematch:
            raise RuntimeError('Expected childsequence table not found')
        elif rematch.groups()[0] != name:
            raise RuntimeError('Found residue %s while processing residue %s' %
                               (rematch.groups()[0], name))
        n = int(fileobj.readline().strip())
        if nres + 1 != n:
            warnings.warn('Unexpected childsequence (%d); expected %d for '
                          'residue %s' % (n, nres+1, name), AmberWarning)
        elif not isinstance(templ, ResidueTemplate) and n != len(templ) + 1:
            raise RuntimeError('child sequence must be 1 greater than the '
                               'number of residues in the unit')
        # Get the CONNECT array to set head and tail
        line = fileobj.readline()
        rematch = AmberOFFLibrary._sec5re.match(line)
        if not rematch:
            raise RuntimeError('Expected connect array not found')
        elif rematch.groups()[0] != name:
            raise RuntimeError('Found residue %s while processing residue %s' %
                               (rematch.groups()[0], name))
        try:
            head = int(fileobj.readline().strip())
            tail = int(fileobj.readline().strip())
        except ValueError:
            raise RuntimeError('Error processing connect table entries')
        if head > 0 and nres == 1:
            templ.head = templ[head-1]
        elif head > 0 and nres > 1:
            if head < sum((len(r) for r in container)):
                raise RuntimeError('HEAD on multi-residue unit not supported')
        if tail > 0 and nres == 1:
            templ.tail = templ[tail-1]
        elif tail > 0 and nres > 1:
            if tail < sum((len(r) for r in container)):
                warnings.warn('TAIL on multi-residue unit not supported (%s). '
                              'Ignored...' % name, AmberWarning)
        # Get the connectivity array to set bonds
        line = fileobj.readline()
        if len(templ.atoms) > 1:
            rematch = AmberOFFLibrary._sec6re.match(line)
            if not rematch:
                raise RuntimeError('Expected connectivity table not found')
            elif rematch.groups()[0] != name:
                raise RuntimeError('Found residue %s while processing residue %s' %
                                   (rematch.groups()[0], name))
            line = fileobj.readline()
            while line[0] != '!':
                i, j, flag = line.split()
                line = fileobj.readline()
                if nres > 1:
                    # Find which residue we belong in
                    i = int(i) - 1
                    j = int(j) - 1
                    for ii, idx in enumerate(start_atoms):
                        if idx > i:
                            ii -= 1
                            break
                    start_idx = start_atoms[ii]
                    container[ii].add_bond(i-start_idx, j-start_idx)
                else:
                    templ.add_bond(int(i)-1, int(j)-1)
        # Get the hierarchy table
        rematch = AmberOFFLibrary._sec7re.match(line)
        if not rematch:
            raise RuntimeError('Expected hierarchy table not found')
        elif rematch.groups()[0] != name:
            raise RuntimeError('Found residue %s while processing residue %s' %
                               (rematch.groups()[0], name))
        line = fileobj.readline()
        while line[0] != '!':
            # Skip this section... not used
            # TODO turn this into a sanity check
            line = fileobj.readline()
        # Get the unit name
        rematch = AmberOFFLibrary._sec8re.match(line)
        if not rematch:
            raise RuntimeError('Expected unit name string not found')
        elif rematch.groups()[0] != name:
            raise RuntimeError('Found residue %s while processing residue %s' %
                               (rematch.groups()[0], name))
        fileobj.readline() # Skip this... not used
        line = fileobj.readline()
        # Get the atomic positions
        rematch = AmberOFFLibrary._sec9re.match(line)
        if not rematch:
            raise RuntimeError('Expected unit positions table not found')
        elif rematch.groups()[0] != name:
            raise RuntimeError('Found residue %s while processing residue %s' %
                               (rematch.groups()[0], name))
        for res in container:
            for atom in res:
                x, y, z = fileobj.readline().split()
                atom.xx, atom.xy, atom.xz = float(x), float(y), float(z)
        line = fileobj.readline()
        # Get the residueconnect table
        rematch = AmberOFFLibrary._sec10re.match(line)
        if not rematch:
            raise RuntimeError('Expected unit residueconnect table not found')
        elif rematch.groups()[0] != name:
            raise RuntimeError('Found residue %s while processing residue %s' %
                               (rematch.groups()[0], name))
        for i in range(nres):
            c1,c2,c3,c4,c5,c6 = (int(x) for x in fileobj.readline().split())
            if (c1 > 0 and templ.head is not None and
                    templ.head is not templ[c1-1]):
                raise RuntimeError('HEAD atom is not connect0')
            if (c2 > 0 and templ.tail is not None and
                    templ.tail is not templ[c2-1]):
                raise RuntimeError('TAIL atom is not connect1')
            for i in (c3, c4, c5, c6):
                if i == 0: continue
                templ.connections.append(templ[i-1])
        # Get the residues table
        line = fileobj.readline()
        rematch = AmberOFFLibrary._sec11re.match(line)
        if not rematch:
            raise RuntimeError('Expected unit residues table not found')
        elif rematch.groups()[0] != name:
            raise RuntimeError('Found residue %s while processing residue %s' %
                               (rematch.groups()[0], name))
        for i in range(nres):
            resname, id, next, start, typ, img = fileobj.readline().split()
            resname = _strip_enveloping_quotes(resname)
            id = int(id)
            start = int(start)
            next = int(next)
            typ = _strip_enveloping_quotes(typ)
            img = int(img)
            if next - start != len(container[i]):
                warnings.warn('residue table predicted %d, not %d atoms for '
                              'residue %s' % (next-start, len(container[i]),
                              name), AmberWarning)
            if typ == 'p':
                container[i].type = PROTEIN
            elif typ == 'n':
                container[i].type = NUCLEIC
            elif typ == 'w':
                container[i].type = SOLVENT
            elif typ != '?':
                warnings.warn('Unknown residue type "%s"' % typ, AmberWarning)
            if nres > 1:
                container[i].name = resname
        # Get the residues sequence table
        line = fileobj.readline()
        rematch = AmberOFFLibrary._sec12re.match(line)
        if not rematch:
            raise RuntimeError('Expected residue sequence number not found')
        elif rematch.groups()[0] != name:
            raise RuntimeError('Found residue %s while processing residue %s' %
                               (rematch.groups()[0], name))
        for i in range(nres):
            #TODO sanity check
            fileobj.readline()
        line = fileobj.readline()
        # Get the solventcap array
        rematch = AmberOFFLibrary._sec13re.match(line)
        if not rematch:
            raise RuntimeError('Expected unit solventcap array not found')
        elif rematch.groups()[0] != name:
            raise RuntimeError('Found residue %s while processing residue %s' %
                               (rematch.groups()[0], name))
        # Ignore the solvent cap
        fileobj.readline()
        fileobj.readline()
        fileobj.readline()
        fileobj.readline()
        fileobj.readline()
        # Velocities
        line = fileobj.readline()
        rematch = AmberOFFLibrary._sec14re.match(line)
        if not rematch:
            raise RuntimeError('Expected unit solventcap array not found')
        elif rematch.groups()[0] != name:
            raise RuntimeError('Found residue %s while processing residue %s' %
                               (rematch.groups()[0], name))
        for res in container:
            for atom in res:
                vx, vy, vz = (float(x) for x in fileobj.readline().split())
                atom.vx, atom.vy, atom.vz = vx, vy, vz

        if nres > 1:
            return container
        return templ
Exemple #8
0
 def __init__(self, psf_name):
     """
     Opens and parses a PSF file, then instantiates a CharmmPsfFile
     instance from the data.
     """
     global _resre
     Structure.__init__(self)
     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 RuntimeError('Could not interpret residue number %s' %
                                    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.segid = segid
             atom.props = props
             self.add_atom(atom,resname,resid,chain=segid,inscode=inscode)
         # 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' %
                                  (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' %
                                  (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' %
                                  (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' %
                                  (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' %
                                  (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' %
                                  (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:
             raise CharmmError('Could not unpack GROUP pointers')
         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' %
                                  (len(tmp), ngrp))
         it = iter(psfsections['NGRP NST2'][1])
         for i, j, k in zip(it, it, it):
             self.groups.append(Group(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' %
                               (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