Commit 992e0987 by peastman

Merge pull request #115 from jaimergp/master

Specify water box dimensions with JS enhanced padding field
parents 7b94709a c165bad8
...@@ -8,14 +8,21 @@ function validateForm() { ...@@ -8,14 +8,21 @@ function validateForm() {
} }
} }
if (document.getElementById("addWaterCheckbox").checked) { if (document.getElementById("addWaterCheckbox").checked) {
var custombox = document.getElementById("customBoxRadio").checked
var xsize = document.getElementById("boxxfield").value var xsize = document.getElementById("boxxfield").value
var ysize = document.getElementById("boxyfield").value var ysize = document.getElementById("boxyfield").value
var zsize = document.getElementById("boxzfield").value var zsize = document.getElementById("boxzfield").value
var strength = document.getElementById("ionicstrengthfield").value if (custombox && !(xsize > 0 && ysize > 0 && zsize > 0)) {
if (!(xsize > 0 && ysize > 0 && zsize > 0)) {
alert("Box dimensions must be positive numbers.") alert("Box dimensions must be positive numbers.")
return false return false
} }
var geombox = document.getElementById("geometricBoxRadio").checked
var padsize = document.getElementById("geomPadding").value
if (geombox && !(padsize > 0)) {
alert("Box padding must be a positive number.")
return false
}
var strength = document.getElementById("ionicstrengthfield").value
if (!(strength >= 0)) { if (!(strength >= 0)) {
alert("Ionic strength must be a nonnegative number.") alert("Ionic strength must be a nonnegative number.")
return false return false
...@@ -23,7 +30,61 @@ function validateForm() { ...@@ -23,7 +30,61 @@ function validateForm() {
} }
return true return true
} }
function applyPaddingToWaterBox(padding) {
padding = parseFloat(padding);
if(!padding || padding<0) padding = 0;
if (document.getElementById('cubicPaddingCheckBox').checked){
var maxAxis = Math.max.apply(Math, molxyz);
for (var i = pbcxyz.length; i--;) {
pbcxyz[i].value = Math.ceil((padding+maxAxis)*1000) / 1000;
}
}
else {
for (var i = pbcxyz.length; i--;) {
pbcxyz[i].value = Math.ceil((padding+molxyz[i])*1000) / 1000;
}
}
}
</script> </script>
<style>
a.tooltip {
display: inline;
position: relative;
color: #000;
border-bottom: 1px dotted #000;
text-decoration: none;
}
a.tooltip:hover:after {
content: attr(rel);
text-align: center;
font-size: 80%%;
background: #000;
color: #fff;
width: 250px;
bottom: 30px;
left: -125px;
padding: 10px 15px;
position: absolute;
z-index: 100;
/* Effects */
background: rgba(0,0,0,0.75);
border-radius: 5px;
box-shadow: 0 0 25px #333;
}
/* Down arrow */
a.tooltip:hover:before {
border: solid;
border-color: #333 transparent;
border-width: 10px 10px 0 10px;
bottom: 20px;
left: -6px;
content: "";
position: absolute;
z-index: 99;
/* Effects */
border-color: rgba(0,0,0,0.75) transparent;
}
</style>
<form id="mainform" method="post" action="/"> <form id="mainform" method="post" action="/">
<h1>Delete Heterogens</h1> <h1>Delete Heterogens</h1>
A heterogen is any residue other than a standard amino acid or nucleotide. Do you want to delete heterogens? A heterogen is any residue other than a standard amino acid or nucleotide. Do you want to delete heterogens?
...@@ -43,7 +104,30 @@ Add a water box surrounding the model? ...@@ -43,7 +104,30 @@ Add a water box surrounding the model?
<input type="checkbox" id="addWaterCheckbox" name="addwater" onchange="enableControls(document.getElementById('waterInputs'), document.getElementById('addWaterCheckbox').checked)"> Add water <input type="checkbox" id="addWaterCheckbox" name="addwater" onchange="enableControls(document.getElementById('waterInputs'), document.getElementById('addWaterCheckbox').checked)"> Add water
<div id="waterInputs" style="margin-left:50px"> <div id="waterInputs" style="margin-left:50px">
<table style="text-align:right"> <table style="text-align:right">
<tr><td>Box dimensions (in nm):</td><td><input type="text" id="boxxfield" name="boxx" size="8"></td><td><input type="text" id="boxyfield" name="boxy" size="8"></td><td><input type="text" id="boxzfield" name="boxz" size="8"></td></tr> <tr>
<td style="text-align:left"><input id="customBoxRadio" type="radio" name="boxType" value="custom" checked>Custom box dimensions (in nm):</td>
<div id="customBoxDimensions">
<td><input type="text" id="boxxfield" name="boxx" size="8"></td>
<td><input type="text" id="boxyfield" name="boxy" size="8"></td>
<td><input type="text" id="boxzfield" name="boxz" size="8"></td>
</div>
</tr>
<tr>
<td style="text-align:left"><input id="geometricBoxRadio" type="radio" name="boxType" value="geometry">Geometry with padding (in nm):</td>
<div id="geometricBoxDimensions">
<td><input type="text" id="geomPadding" name="geomPadding" size="8">
</td>
<td colspan="2">
<select id="geometryDropdown" name="geometryDropdown">
<option value="cube" selected="selected">Cube</option>
<option value="truncatedOctahedron">Truncated octahedron</option>
<option value="rhombicDodecahedron">Rhombic dodecahedron</option>
</select>
<a href="#" rel="The specified padding will be applied on the largest molecular axis, while maintaining selected geometry." class="tooltip">?</a>
</div>
</td>
</tr>
%s %s
</table> </table>
<p> <p>
...@@ -59,8 +143,14 @@ Add a water box surrounding the model? ...@@ -59,8 +143,14 @@ Add a water box surrounding the model?
<input type="button" value="Continue" onclick="if (validateForm()) submitWithSpinner()"/> <input type="button" value="Continue" onclick="if (validateForm()) submitWithSpinner()"/>
</form> </form>
<script> <script>
setCurrentStep(6) setCurrentStep(6);
enableControls(document.getElementById('waterInputs'), false) enableControls(document.getElementById('waterInputs'), false);
var molxyz = [].slice.call(document.getElementById('boxContainingAllAtoms').getElementsByTagName('td')).splice(1,3).map(function(td){ return parseFloat(td.textContent)});
var hiddenInput = document.createElement("input");
hiddenInput.setAttribute("type", "hidden");
hiddenInput.setAttribute("name", "maxMolecularAxis");
hiddenInput.setAttribute("value", Math.max.apply(Math, molxyz));
document.getElementById("mainform").appendChild(hiddenInput);
</script> </script>
</body> </body>
<html> <html>
...@@ -1021,15 +1021,17 @@ class PDBFixer(object): ...@@ -1021,15 +1021,17 @@ class PDBFixer(object):
self.topology = modeller.topology self.topology = modeller.topology
self.positions = modeller.positions self.positions = modeller.positions
def addSolvent(self, boxSize=None, padding=None, positiveIon='Na+', negativeIon='Cl-', ionicStrength=0*unit.molar): def addSolvent(self, boxSize=None, padding=None, boxVectors=None, positiveIon='Na+', negativeIon='Cl-', ionicStrength=0*unit.molar):
"""Add a solvent box surrounding the structure. """Add a solvent box surrounding the structure.
Parameters Parameters
---------- ----------
boxSize : simtk.openmm.Vec3, optional, default=None boxSize : simtk.openmm.Vec3, optional, default=None
The size of the box to fill with water. If specified, padding must not be specified. The size of the box to fill with water. If specified, padding and boxVectors must not be specified.
padding : simtk.unit.Quantity compatible with nanometers, optional, default=None padding : simtk.unit.Quantity compatible with nanometers, optional, default=None
Padding around macromolecule for filling box with water. If specified, boxSize must not be specified. Padding around macromolecule for filling box with water. If specified, boxSize and boxVectors must not be specified.
boxVectors : 3-tuple of simtk.openmm.Vec3, optional, default=None
Three vectors specifying the geometry of the box. If specified, padding and boxSize must not be specified.
positiveIon : str, optional, default='Na+' positiveIon : str, optional, default='Na+'
The type of positive ion to add. Allowed values are 'Cs+', 'K+', 'Li+', 'Na+', and 'Rb+'. The type of positive ion to add. Allowed values are 'Cs+', 'K+', 'Li+', 'Na+', and 'Rb+'.
negativeIon : str, optional, default='Cl-' negativeIon : str, optional, default='Cl-'
...@@ -1053,7 +1055,7 @@ class PDBFixer(object): ...@@ -1053,7 +1055,7 @@ class PDBFixer(object):
modeller = app.Modeller(self.topology, self.positions) modeller = app.Modeller(self.topology, self.positions)
forcefield = self._createForceField(self.topology, True) forcefield = self._createForceField(self.topology, True)
modeller.addSolvent(forcefield, padding=padding, boxSize=boxSize, positiveIon=positiveIon, negativeIon=negativeIon, ionicStrength=ionicStrength) modeller.addSolvent(forcefield, padding=padding, boxSize=boxSize, boxVectors=boxVectors, positiveIon=positiveIon, negativeIon=negativeIon, ionicStrength=ionicStrength)
chains = list(modeller.topology.chains()) chains = list(modeller.topology.chains())
if len(chains) == 1: if len(chains) == 1:
chains[0].id = 'A' chains[0].id = 'A'
......
...@@ -3,9 +3,11 @@ from __future__ import absolute_import ...@@ -3,9 +3,11 @@ from __future__ import absolute_import
import webbrowser import webbrowser
import os.path import os.path
import time import time
from math import sqrt
import simtk.openmm.app as app import simtk.openmm.app as app
import simtk.unit as unit import simtk.unit as unit
from simtk.openmm.vec3 import Vec3
from .pdbfixer import PDBFixer, proteinResidues, dnaResidues, rnaResidues, _guessFileFormat from .pdbfixer import PDBFixer, proteinResidues, dnaResidues, rnaResidues, _guessFileFormat
from . import uiserver from . import uiserver
...@@ -111,11 +113,25 @@ def addHydrogensPageCallback(parameters, handler): ...@@ -111,11 +113,25 @@ def addHydrogensPageCallback(parameters, handler):
pH = float(parameters.getfirst('ph')) pH = float(parameters.getfirst('ph'))
fixer.addMissingHydrogens(pH) fixer.addMissingHydrogens(pH)
if 'addwater' in parameters: if 'addwater' in parameters:
boxSize = (float(parameters.getfirst('boxx')), float(parameters.getfirst('boxy')), float(parameters.getfirst('boxz')))*unit.nanometer padding, boxSize, boxVectors = None, None, None
if parameters.getfirst('boxType') == 'geometry':
geompadding = float(parameters.getfirst('geomPadding')) * unit.nanometer
geometry = parameters.getfirst('geometryDropdown')
base_size = float(parameters.getfirst('maxMolecularAxis')) * unit.nanometer
if geometry == 'cube':
padding = geompadding
elif geometry == 'truncatedOctahedron':
vectors = Vec3(1,0,0), Vec3(1/3,2*sqrt(2)/3,0), Vec3(-1/3,1/3,sqrt(6)/3)
boxVectors = [(base_size+geompadding)*v for v in vectors]
elif geometry == 'rhombicDodecahedron':
vectors = Vec3(1,0,0), Vec3(0,1,0), Vec3(0.5,0.5,sqrt(2)/2)
boxVectors = [(base_size+geompadding)*v for v in vectors]
else:
boxSize = (float(parameters.getfirst('boxx')), float(parameters.getfirst('boxy')), float(parameters.getfirst('boxz')))*unit.nanometer
ionicStrength = float(parameters.getfirst('ionicstrength'))*unit.molar ionicStrength = float(parameters.getfirst('ionicstrength'))*unit.molar
positiveIon = parameters.getfirst('positiveion')+'+' positiveIon = parameters.getfirst('positiveion')+'+'
negativeIon = parameters.getfirst('negativeion')+'-' negativeIon = parameters.getfirst('negativeion')+'-'
fixer.addSolvent(boxSize, None, positiveIon, negativeIon, ionicStrength) fixer.addSolvent(boxSize, padding, boxVectors, positiveIon, negativeIon, ionicStrength)
displaySaveFilePage() displaySaveFilePage()
def saveFilePageCallback(parameters, handler): def saveFilePageCallback(parameters, handler):
...@@ -123,7 +139,10 @@ def saveFilePageCallback(parameters, handler): ...@@ -123,7 +139,10 @@ def saveFilePageCallback(parameters, handler):
output = StringIO() output = StringIO()
if fixer.source is not None: if fixer.source is not None:
output.write("REMARK 1 PDBFIXER FROM: %s\n" % fixer.source) output.write("REMARK 1 PDBFIXER FROM: %s\n" % fixer.source)
app.PDBFile.writeFile(fixer.topology, fixer.positions, output, True) try:
app.PDBFile.writeFile(fixer.topology, fixer.positions, output, True)
except AssertionError:
print
handler.sendDownload(output.getvalue(), 'output.pdb') handler.sendDownload(output.getvalue(), 'output.pdb')
else: else:
displayStartPage() displayStartPage()
...@@ -219,7 +238,7 @@ def displayAddHydrogensPage(): ...@@ -219,7 +238,7 @@ def displayAddHydrogensPage():
if fixer.topology.getUnitCellDimensions() is not None: if fixer.topology.getUnitCellDimensions() is not None:
dimensions = "<tr><td>Crystallographic unit cell:</td><td>%.3f</td><td>%.3f</td><td>%.3f</td></tr>" % fixer.topology.getUnitCellDimensions().value_in_unit(unit.nanometer) dimensions = "<tr><td>Crystallographic unit cell:</td><td>%.3f</td><td>%.3f</td><td>%.3f</td></tr>" % fixer.topology.getUnitCellDimensions().value_in_unit(unit.nanometer)
sizeRange = tuple(max((pos[i] for pos in fixer.positions))-min((pos[i] for pos in fixer.positions)) for i in range(3)) sizeRange = tuple(max((pos[i] for pos in fixer.positions))-min((pos[i] for pos in fixer.positions)) for i in range(3))
dimensions += "<tr><td>Box containing all atoms:</td><td>%.3f</td><td>%.3f</td><td>%.3f</td></tr>" % tuple(x.value_in_unit(unit.nanometer) for x in sizeRange) dimensions += "<tr id='boxContainingAllAtoms'><td>Box containing all atoms:</td><td>%.3f</td><td>%.3f</td><td>%.3f</td></tr>" % tuple(x.value_in_unit(unit.nanometer) for x in sizeRange)
uiserver.setContent(header+loadHtmlFile("addHydrogens.html") % dimensions) uiserver.setContent(header+loadHtmlFile("addHydrogens.html") % dimensions)
def displaySaveFilePage(): def displaySaveFilePage():
......
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