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() {
}
}
if (document.getElementById("addWaterCheckbox").checked) {
var custombox = document.getElementById("customBoxRadio").checked
var xsize = document.getElementById("boxxfield").value
var ysize = document.getElementById("boxyfield").value
var zsize = document.getElementById("boxzfield").value
var strength = document.getElementById("ionicstrengthfield").value
if (!(xsize > 0 && ysize > 0 && zsize > 0)) {
if (custombox && !(xsize > 0 && ysize > 0 && zsize > 0)) {
alert("Box dimensions must be positive numbers.")
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)) {
alert("Ionic strength must be a nonnegative number.")
return false
......@@ -23,7 +30,61 @@ function validateForm() {
}
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>
<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="/">
<h1>Delete Heterogens</h1>
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?
<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">
<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
</table>
<p>
......@@ -59,8 +143,14 @@ Add a water box surrounding the model?
<input type="button" value="Continue" onclick="if (validateForm()) submitWithSpinner()"/>
</form>
<script>
setCurrentStep(6)
enableControls(document.getElementById('waterInputs'), false)
setCurrentStep(6);
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>
</body>
<html>
......@@ -1021,15 +1021,17 @@ class PDBFixer(object):
self.topology = modeller.topology
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.
Parameters
----------
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 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+'
The type of positive ion to add. Allowed values are 'Cs+', 'K+', 'Li+', 'Na+', and 'Rb+'.
negativeIon : str, optional, default='Cl-'
......@@ -1053,7 +1055,7 @@ class PDBFixer(object):
modeller = app.Modeller(self.topology, self.positions)
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())
if len(chains) == 1:
chains[0].id = 'A'
......
......@@ -3,9 +3,11 @@ from __future__ import absolute_import
import webbrowser
import os.path
import time
from math import sqrt
import simtk.openmm.app as app
import simtk.unit as unit
from simtk.openmm.vec3 import Vec3
from .pdbfixer import PDBFixer, proteinResidues, dnaResidues, rnaResidues, _guessFileFormat
from . import uiserver
......@@ -111,11 +113,25 @@ def addHydrogensPageCallback(parameters, handler):
pH = float(parameters.getfirst('ph'))
fixer.addMissingHydrogens(pH)
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
positiveIon = parameters.getfirst('positiveion')+'+'
negativeIon = parameters.getfirst('negativeion')+'-'
fixer.addSolvent(boxSize, None, positiveIon, negativeIon, ionicStrength)
fixer.addSolvent(boxSize, padding, boxVectors, positiveIon, negativeIon, ionicStrength)
displaySaveFilePage()
def saveFilePageCallback(parameters, handler):
......@@ -123,7 +139,10 @@ def saveFilePageCallback(parameters, handler):
output = StringIO()
if fixer.source is not None:
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')
else:
displayStartPage()
......@@ -219,7 +238,7 @@ def displayAddHydrogensPage():
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)
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)
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