Commit 24e12c12 by Peter Eastman

Added UI for adding missing residues. Added option to delete chains.

parent 892470c1
...@@ -69,7 +69,7 @@ def _overlayPoints(points1, points2): ...@@ -69,7 +69,7 @@ def _overlayPoints(points1, points2):
if len(points1) == 0: if len(points1) == 0:
return (Vec3(0, 0, 0), np.identity(3), Vec3(0, 0, 0)) return (Vec3(0, 0, 0), np.identity(3), Vec3(0, 0, 0))
if len(points1) == 1: if len(points1) == 1:
return (points1[0], np.identity(3), -points2[0]) return (points1[0], np.identity(3), -1*points2[0])
# Compute centroids. # Compute centroids.
...@@ -98,6 +98,7 @@ class PDBFixer(object): ...@@ -98,6 +98,7 @@ class PDBFixer(object):
self.topology = self.pdb.topology self.topology = self.pdb.topology
self.positions = self.pdb.positions self.positions = self.pdb.positions
self.centroid = unit.sum(self.positions)/len(self.positions) self.centroid = unit.sum(self.positions)/len(self.positions)
self._structureChains = list(self.structure.iter_chains())
# Load the templates. # Load the templates.
...@@ -126,8 +127,8 @@ class PDBFixer(object): ...@@ -126,8 +127,8 @@ class PDBFixer(object):
# Insert missing residues here. # Insert missing residues here.
insertHere = [r[2] for r in self.missingResidues if r[0] == chain.index and r[1] == indexInChain] if (chain.index, indexInChain) in self.missingResidues:
if len(insertHere) > 0: insertHere = self.missingResidues[(chain.index, indexInChain)]
endPosition = self._computeResidueCenter(residue) endPosition = self._computeResidueCenter(residue)
if indexInChain > 0: if indexInChain > 0:
startPosition = self._computeResidueCenter(chainResidues[indexInChain-1]) startPosition = self._computeResidueCenter(chainResidues[indexInChain-1])
...@@ -180,8 +181,8 @@ class PDBFixer(object): ...@@ -180,8 +181,8 @@ class PDBFixer(object):
# If this is the end of the chain, add any missing residues that come after it. # If this is the end of the chain, add any missing residues that come after it.
if residue == chainResidues[-1]: if residue == chainResidues[-1] and (chain.index, indexInChain+1) in self.missingResidues:
insertHere = [r[2] for r in self.missingResidues if r[0] == chain.index and r[1] > indexInChain] insertHere = self.missingResidues[(chain.index, indexInChain+1)]
if len(insertHere) > 0: if len(insertHere) > 0:
startPosition = self._computeResidueCenter(residue) startPosition = self._computeResidueCenter(residue)
outward = startPosition-self.centroid outward = startPosition-self.centroid
...@@ -241,6 +242,14 @@ class PDBFixer(object): ...@@ -241,6 +242,14 @@ class PDBFixer(object):
templatePosition = template.positions[atom.index].value_in_unit(unit.nanometer) templatePosition = template.positions[atom.index].value_in_unit(unit.nanometer)
newPositions.append(mm.Vec3(*np.dot(rotate, templatePosition))*unit.nanometer+translate) newPositions.append(mm.Vec3(*np.dot(rotate, templatePosition))*unit.nanometer+translate)
def removeChains(self, chainIndices):
modeller = app.Modeller(self.topology, self.positions)
allChains = list(self.topology.chains())
modeller.delete(allChains[i] for i in chainIndices)
self.topology = modeller.topology
self.positions = modeller.positions
self._structureChains = [self._structureChains[i] for i in range(len(self._structureChains)) if i not in chainIndices]
def findNonstandardResidues(self): def findNonstandardResidues(self):
self.nonstandardResidues = [r for r in self.topology.residues() if r.name in substitutions] self.nonstandardResidues = [r for r in self.topology.residues() if r.name in substitutions]
...@@ -266,7 +275,7 @@ class PDBFixer(object): ...@@ -266,7 +275,7 @@ class PDBFixer(object):
self.positions = modeller.positions self.positions = modeller.positions
def findMissingResidues(self): def findMissingResidues(self):
chains = [c for c in self.structure.iter_chains() if any(atom.record_name == 'ATOM' for atom in c.iter_atoms())] chains = [c for c in self._structureChains if any(atom.record_name == 'ATOM' for atom in c.iter_atoms())]
chainWithGaps = {} chainWithGaps = {}
# Find the sequence of each chain, with gaps for missing residues. # Find the sequence of each chain, with gaps for missing residues.
...@@ -299,8 +308,8 @@ class PDBFixer(object): ...@@ -299,8 +308,8 @@ class PDBFixer(object):
# Now build the list of residues to add. # Now build the list of residues to add.
self.missingResidues = [] self.missingResidues = {}
for structChain, topChain in zip(self.structure.iter_chains(), self.pdb.topology.chains()): for structChain, topChain in zip(self._structureChains, self.pdb.topology.chains()):
if structChain in chainSequence: if structChain in chainSequence:
offset = chainOffset[structChain] offset = chainOffset[structChain]
sequence = chainSequence[structChain].residues sequence = chainSequence[structChain].residues
...@@ -308,7 +317,10 @@ class PDBFixer(object): ...@@ -308,7 +317,10 @@ class PDBFixer(object):
index = 0 index = 0
for i in range(len(sequence)): for i in range(len(sequence)):
if i < offset or i >= len(gappedSequence)+offset or gappedSequence[i-offset] is None: if i < offset or i >= len(gappedSequence)+offset or gappedSequence[i-offset] is None:
self.missingResidues.append((topChain.index, index, sequence[i])) key = (topChain.index, index)
if key not in self.missingResidues:
self.missingResidues[key] = []
self.missingResidues[key].append(sequence[i])
else: else:
index += 1 index += 1
...@@ -337,7 +349,7 @@ class PDBFixer(object): ...@@ -337,7 +349,7 @@ class PDBFixer(object):
# Add missing terminal atoms. # Add missing terminal atoms.
terminals = [] terminals = []
if residue == chainResidues[-1] and not any(r[0] == chain.index and r[1] >= len(chainResidues) for r in self.missingResidues): if residue == chainResidues[-1] and (chain.index, len(chainResidues)) not in self.missingResidues:
templateNames = set(atom.name for atom in template.topology.atoms()) templateNames = set(atom.name for atom in template.topology.atoms())
if 'OXT' not in atomNames and all(name in templateNames for name in ['C', 'O', 'CA']): if 'OXT' not in atomNames and all(name in templateNames for name in ['C', 'O', 'CA']):
terminals.append('OXT') terminals.append('OXT')
......
...@@ -10,7 +10,20 @@ def startPageCallback(parameters, handler): ...@@ -10,7 +10,20 @@ def startPageCallback(parameters, handler):
global fixer global fixer
pdb = PdbStructure(parameters['pdbfile'].value.splitlines()) pdb = PdbStructure(parameters['pdbfile'].value.splitlines())
fixer = PDBFixer(pdb) fixer = PDBFixer(pdb)
displayConvertResiduesPage() displayDeleteChainsPage()
def deleteChainsPageCallback(parameters, handler):
numChains = len(list(fixer.topology.chains()))
deleteIndices = [i for i in range(numChains) if 'include'+str(i) not in parameters]
fixer.removeChains(deleteIndices)
displayAddResiduesPage()
def addResiduesPageCallback(parameters, handler):
keys = [key for key in sorted(fixer.missingResidues)]
for i, key in enumerate(keys):
if 'add'+str(i) not in parameters:
del fixer.missingResidues[key]
displayMissingAtomsPage()
def convertResiduesPageCallback(parameters, handler): def convertResiduesPageCallback(parameters, handler):
fixer.nonstandardResidues = [residue for i, residue in enumerate(fixer.nonstandardResidues) if 'convert'+str(i) in parameters] fixer.nonstandardResidues = [residue for i, residue in enumerate(fixer.nonstandardResidues) if 'convert'+str(i) in parameters]
...@@ -47,9 +60,75 @@ PDB File: <input type="file" name="pdbfile"/> ...@@ -47,9 +60,75 @@ PDB File: <input type="file" name="pdbfile"/>
</html> </html>
""") """)
def displayDeleteChainsPage():
uiserver.setCallback(deleteChainsPageCallback)
numChains = len(list(fixer.topology.chains()))
if numChains < 2:
displayAddResiduesPage()
return
table = ""
proteinResidues = ['ALA', 'ASN', 'CYS', 'GLU', 'HIS', 'LEU', 'MET', 'PRO', 'THR', 'TYR.pdb ARG', 'ASP', 'GLN', 'GLY', 'ILE', 'LYS', 'PHE', 'SER', 'TRP', 'VAL']
rnaResidues = ['A', 'G', 'C', 'U']
dnaResidues = ['DA', 'DG', 'DC', 'DT']
for i, chain in enumerate(fixer.topology.chains()):
residues = list(r.name for r in chain.residues())
if any(r in proteinResidues for r in residues):
content = "Protein"
elif any(r in rnaResidues for r in residues):
content = "RNA"
elif any(r in dnaResidues for r in residues):
content = "DNA"
else:
content = ', '.join(set(residues))
table += ' <tr><td>%d</td><td>%d</td><td>%s</td><td><input type="checkbox" name="include%d" checked></td></tr>\n' % (chain.index+1, len(residues), content, i)
uiserver.setContent("""
<html>
<head><title>PDB Fixer</title></head>
<body>
This PDB file contains %d chains. Select which ones to include.
<p>
<form method="post" action="/">
<table border="1">
<tr><th>Chain</th><th># Residues</th><th>Content</th><th>Include?</th></tr>
%s
</table>
<p>
<input type="submit" value="Continue"/>
</form>
</body>
<html>
""" % (numChains, table))
def displayAddResiduesPage():
uiserver.setCallback(addResiduesPageCallback)
fixer.findMissingResidues()
if len(fixer.missingResidues) == 0:
displayConvertResiduesPage()
return
table = ""
for i, key in enumerate(sorted(fixer.missingResidues)):
residues = fixer.missingResidues[key]
table += ' <tr><td>%d</td><td>%d to %d</td><td>%s</td><td><input type="checkbox" name="add%d" checked></td></tr>\n' % (key[0]+1, key[1]+1, key[1]+len(residues), ', '.join(residues), i)
uiserver.setContent("""
<html>
<head><title>PDB Fixer</title></head>
<body>
The SEQRES records in this PDB file include residues that are missing from the atom data section. Do you want to add the missing residues?
<p>
<form method="post" action="/">
<table border="1">
<tr><th>Chain</th><th>Residue Positions</th><th>Sequence</th><th>Add?</th></tr>
%s
</table>
<p>
<input type="submit" value="Continue"/>
</form>
</body>
<html>
""" % table)
def displayConvertResiduesPage(): def displayConvertResiduesPage():
uiserver.setCallback(convertResiduesPageCallback) uiserver.setCallback(convertResiduesPageCallback)
fixer.findMissingResidues()
fixer.findNonstandardResidues() fixer.findNonstandardResidues()
if len(fixer.nonstandardResidues) == 0: if len(fixer.nonstandardResidues) == 0:
displayMissingAtomsPage() displayMissingAtomsPage()
...@@ -105,7 +184,7 @@ def displayMissingAtomsPage(): ...@@ -105,7 +184,7 @@ def displayMissingAtomsPage():
<body> <body>
The following residues are missing heavy atoms, which will be added. The following residues are missing heavy atoms, which will be added.
<p> <p>
<form method="get" action="/"> <form method="post" action="/">
<table border="1"> <table border="1">
<tr><th>Chain</th><th>Residue</th><th>Missing Atoms</th></tr> <tr><th>Chain</th><th>Residue</th><th>Missing Atoms</th></tr>
%s %s
...@@ -125,7 +204,7 @@ def displayDownloadPage(): ...@@ -125,7 +204,7 @@ def displayDownloadPage():
<body> <body>
The fixed PDB file is ready to download. The fixed PDB file is ready to download.
<p> <p>
<form method="get" action="/"> <form method="post" action="/">
<input type="submit" name="download" value="Download"/> <input type="submit" name="download" value="Download"/>
<input type="submit" name="newfile" value="Process Another File"/> <input type="submit" name="newfile" value="Process Another File"/>
</form> </form>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment