Skip to content

Commit

Permalink
Merge pull request #172 from Autodesk/vizfixes
Browse files Browse the repository at this point in the history
Updates and fixes for visualization
  • Loading branch information
avirshup authored Aug 10, 2017
2 parents 45de6fe + bc125d5 commit 4639af1
Show file tree
Hide file tree
Showing 9 changed files with 381 additions and 340 deletions.
26 changes: 13 additions & 13 deletions moldesign/_tests/test_atoms.py
Original file line number Diff line number Diff line change
Expand Up @@ -233,21 +233,21 @@ def assert_not_bonded(mol, a1, a2):
def assert_consistent_bond(mol, a1, a2, order):
assert a1 in a2.bond_graph
assert a2 in a1.bond_graph
for bond in a1.bonds:
if bond.a2 is a2:
assert bond.order == order
break
else:
assert False, "bond not found in atom.bonds"

for bond in a2.bonds:
if bond.a1 is a1:
assert bond.order == order
break
else:
assert False, "bond not found in atom.bonds"
_unique_bond_check(a1, a2, order)
_unique_bond_check(a2, a1, order)

assert a1.bond_graph[a2] == a2.bond_graph[a1] == order
assert mol.bond_graph[a1][a2] == mol.bond_graph[a2][a1] == order


def _unique_bond_check(a1, a2, order):
found = False
for bond in a1.bonds:
if bond.partner(a1) is a2:
assert not found, '%s appeared twice' % bond
assert bond.order == order
found = True

if a1.num_bonds > 0 and not found:
assert False, "bond not found in atom.bonds"

2 changes: 1 addition & 1 deletion moldesign/_tests/test_pdb_processing.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ def pdb_1hpk_roundtrip(pdb_1hpk):
@pytest.mark.parametrize('mol', 'pdb_1hpk pdb_1hpk_roundtrip'.split())
def test_1hpk(request, mol):
mol = request.getfixturevalue(mol)
mol = mdt.interfaces.ambertools._prep_for_tleap(mol)
mol = mdt.interfaces.tleap_interface._prep_for_tleap(mol)
for residx in (0, 21, 49, 61, 73, 78):
residue = mol.residues[residx]
assert residue.resname == 'CYX'
Expand Down
10 changes: 10 additions & 0 deletions moldesign/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,3 +41,13 @@ class QMConvergenceError(Exception):
""" Raised when an iterative QM calculation (typically SCF) fails to converge
"""
pass


class ForcefieldAssignmentError(Exception):
""" Class that define displays for common errors in assigning a forcefield
"""
def __init__(self, msg, errors, mol=None, job=None):
self.args = [msg]
self.errors = errors
self.mol = mol
self.job = job
36 changes: 17 additions & 19 deletions moldesign/forcefields/errors.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,29 +16,23 @@
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

"""
Class that define displays for common errors in assigning a forcefield
"""
import cgi
import html
from .. import utils
from .. import units as u
from ..helpers.widgets import nbmolviz_installed


def show_parameterization_results(errormessages, molin, molout=None):
print('Forcefield assignment: %s' % ('Success' if molout is not None else 'Failure'))
for err in errormessages:
print(utils.html_to_text(err.desc))


class ForcefieldAssignmentError(Exception):
def __init__(self, messages, mol, molout=None):
self.errors = messages

def draw(self):
# TODO: get this working again
raise NotImplementedError()

if not nbmolviz_installed:
for err in errormessages:
print(utils.html_to_text(err.desc))
else:
from nbmolviz.uielements.logwidget import display_log
from nbmolviz.widgets.parameterization import ParameterizationDisplay
report = ParameterizationDisplay(errormessages, molin, molout)
display_log(report, title='ERRORS/WARNINGS', show=True)


class ForceFieldMessage(object):
Expand Down Expand Up @@ -144,8 +138,12 @@ def __init__(self, message, atoms, residues):
self.atoms[1],
self.atoms[0].distance(self.atoms[1]))
else:
self.short = 'WARN: Unusual bond - atoms not shown'
self.desc = 'TLeap message:<br><i>%s</i>' % cgi.escape(self.message)
if self.residues[0] is self.residues[1]:
self.short = 'WARN: Unusual bond length in %s' % self.residues[0]
else:
self.short = 'WARN: unusual bond length between %s and %s' % (self.residues[0],
self.residues[1])
self.desc = 'TLeap message:<br><i>%s</i>' % html.escape(self.message)

def show(self, viewer):
if self._has_atoms:
Expand All @@ -165,4 +163,4 @@ def show(self, viewer):
def unshow(self, viewer):
viewer.ribbon(opacity=0.7, render=False)
if self._shape: viewer.remove(self._shape)
self._shape = None
self._shape = None
23 changes: 13 additions & 10 deletions moldesign/forcefields/forcefieldbase.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,10 @@
# limitations under the License.

import moldesign as mdt
from .errors import ForcefieldAssignmentError, show_parameterization_results
from ..exceptions import ForcefieldAssignmentError
from .errors import show_parameterization_results
from ..utils import exports


class Forcefield(object):
""" Abstract class for biomolecular forcefield definitions such as amber14sb or charm22.
Expand Down Expand Up @@ -122,39 +122,42 @@ def __init__(self, fflines, file_list=None):
def assign(self, mol):
newmol = self.create_prepped_molecule(mol)
if newmol.num_atoms != mol.num_atoms:
# TODO: much better error message here
raise ForcefieldAssignmentError()
raise ForcefieldAssignmentError(
"Can't assign forcefield - this molecule is missing atoms. "
"Use `ForceField.create_prepped_molecule` to add them automatically.",
[])

else:
# TODO: much more rigorous consistency checking
newmol.ff.copy_to(mol)

def create_prepped_molecule(self, mol, display=True):
from ..interfaces import ambertools
from ..interfaces import tleap_interface

clean_molecule = ambertools._prep_for_tleap(mol)
clean_molecule = tleap_interface._prep_for_tleap(mol)

job = ambertools._run_tleap_assignment(clean_molecule, self._fflines, self._file_list)
job = tleap_interface._run_tleap_assignment(clean_molecule, self._fflines, self._file_list)

if 'output.inpcrd' in job.get_output():
prmtop = job.get_output('output.prmtop')
inpcrd = job.get_output('output.inpcrd')
params = ambertools.AmberParameters(prmtop, inpcrd, job)
params = tleap_interface.AmberParameters(prmtop, inpcrd, job)
m = mdt.read_amber(params.prmtop, params.inpcrd)
newmol = mdt.helpers.restore_topology(m, mol)
newmol.ff = mdt.forcefields.ForcefieldParams(newmol, params)
else:
newmol = None

errors = ambertools._parse_tleap_errors(job, clean_molecule)
errors = tleap_interface._parse_tleap_errors(job, clean_molecule)

show_parameterization_results(errors, clean_molecule, molout=newmol)

if newmol is not None:
return newmol
else:
raise ForcefieldAssignmentError(
'TLeap failed to assign force field parameters for %s' % mol, job)
'TLeap failed to assign force field parameters for %s' % mol,
errors, job=job, mol=mol)

def add_ff(self, ff):
self._fflines.extend(ff._fflines)
Expand Down
3 changes: 3 additions & 0 deletions moldesign/interfaces/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,10 @@
from . import pdbfixer_interface
from . import pyscf_interface
from . import symmol_interface
from . import tleap_interface

# These statements only import functions for python object conversion,
# i.e. mol_to_[pkg] and [pkg]_to_mol
from .biopython_interface import *
from .openbabel import *
from .openmm import *
Expand Down
Loading

0 comments on commit 4639af1

Please sign in to comment.