Opened 7 years ago

Closed 6 years ago

#1682 closed enhancement (fixed)

Expose mmcif template functions to Python

Reported by: Tristan Croll Owned by: Greg Couch
Priority: major Milestone:
Component: Structure Editing Version:
Keywords: Cc: Eric Pettersen
Blocked By: Blocking:
Notify when closed: Platform: all
Project: ChimeraX

Description

The C++ code in bundles/mmcif/mmcif_cpp covers the job of pulling .cif templates from the CCD and turning them into Residue objects, but this functionality isn't exposed to Python. Would be fantastic if it was - one of the next big things on my wish-list for ISOLDE is a set of tools for building new residues into the density.

Change History (13)

comment:1 by Greg Couch, 7 years ago

Do you just want the templates to be included? In that case, you can experiment with _mmcif.load_mmCIF_templates(filename). If that works, I'll make a public API for it. In the daily build, I'm using load_mmCIF_templates to pre-populate the set of templates so they don't need to be downloaded.

comment:2 by Tristan Croll, 7 years ago

I can see that _mmcif.load_mmCIF_templates(filename) adds the template(s) to a tmpl::Molecule* object living on the heap, but unless I'm missing something that object's inaccessible to everything outside of mmcif.cpp and template.cpp. What I'd like is for it to be made accessible to the wider API so I can mine it for the necessary information if, say, I want to add a residue to the terminus of a chain, or place a new ligand centered on some point in space.

comment:3 by Tristan Croll, 7 years ago

Maintaining a list of templates for all currently-loaded residues somewhere accessible would also be really useful for implementing a "residues with missing atoms" function. I see also that the code for tracking leaving atoms is also #defined out in template.cpp - fair enough when loading existing models from a file, but it would be really useful to have this information (with the result stored as a property of tmpl::Atom?) when considering interactive building.

comment:4 by Greg Couch, 7 years ago

Cc: Eric Pettersen added

Unlike Chimera, ChimeraX does not wrap the template Atom/Bond/Residue classes. Including Eric on this ticket so he may make alternative suggestions.

comment:5 by Eric Pettersen, 7 years ago

Wrapping the atomic template Atom/Bond/Residue classes will be happening "soonish" because implementing rotamers, which need them, is one of our higher priority to-do items. However that will only give you basic information about standard amino and nucleic acids, which doesn't cover the entirety of your wish list -- so somehow wrapping the CCD templates may still be something you need.

comment:6 by Eric Pettersen, 6 years ago

Okay, the basic residue template class that is used by the atomic module is now exposed to Python. chimerax.atomic.TmplResidue.get_template(res_name) gets you a TmplResidue instance that has an 'atoms' attribute returning TmplAtoms. Those atoms in turn have 'neighbors' and 'bonds' attributes returning TmplAtoms and TmplBonds respectively.

The TmplResidue class only knows about the standard amino and nucleic acids, and a few well-known others (e.g. 'HOH').

--Eric

in reply to:  7 ; comment:7 by tic20@…, 6 years ago

That looks fantastic! But I'm afraid that requesting an unavailable 
template currently kills ChimeraX (looks like it's just a missing try... 
catch though):

terminate called after throwing an instance of 'std::runtime_error'
   what():  Cannot construct Python TmplResidue instance from C++
Fatal Python error: Aborted

Next on the wish-list would be to have it try to fetch the matching 
residue from the CCD if it's not in the pre-existing dictionary?


On 2019-06-18 23:10, ChimeraX wrote:

comment:8 by Eric Pettersen, 6 years ago

Fixed the crash. It now raises ValueError for residue types that it has no templates for.

I don't think the CCD fetch/handling should be directly in atomic. The mmCIF bundle could leverage the template API to offer its own set of templates. I would need to expose more of the template API -- I only exposed the "read" part of the API since that's all I need for rotamers. The mmCIF code would need the "write" part of the API.

comment:9 by Greg Couch, 6 years ago

Resolution: fixed
Status: assignedclosed

Extended the mmCIF module with two additional functions:

from chimerax.atomic import mmcif
mmcif.load_mmCIF_templates(filename)
template_residue = mmcif.find_template_residue(component_name)

load_mmCIF_templates preloads the mmCIF component cache with the components in the file. The file format should match the PDB's component.cif file.

find_template_residue returns a template residue for the given component. If the component is not currently cached in memory, it is loaded from the disk cache. If it is not in the disk cache, then it is fetched via the web from the PDB's ligand database.

in reply to:  10 ; comment:10 by tic20@…, 6 years ago

Just playing with these new functions to make a "residues with 
incorrect/missing atoms" method. Works great for the most part, but I 
just ran across a ChimeraX-killer in the console:

{{{
from chimerax.atomic import mmcif
xxx = mmcif.find_template_residue(session, 'XXX')
xxx.<tab> # Segmentation fault

#0  0x00007ffff74d7207 in raise () at /lib64/libc.so.6
#1  0x00007ffff74d88f8 in abort () at /lib64/libc.so.6
#2  0x00007fffe6bcf7d5 in __gnu_cxx::__verbose_terminate_handler() () at 
/lib64/libstdc++.so.6
#3  0x00007fffe6bcd746 in  () at /lib64/libstdc++.so.6
#4  0x00007fffe6bcd773 in  () at /lib64/libstdc++.so.6
#5  0x00007fffe6bcd993 in  () at /lib64/libstdc++.so.6
#6  0x00007fffb6b8dc90 in 
pyinstance::PythonInstance<tmpl::Atom>::py_instance(bool) const ()
     at 
/opt/UCSF/ChimeraX-daily/lib/python3.7/site-packages/chimerax/atomic/lib/libatomstruct.so
#7  0x00007fffb6057066 in 
__pyx_getprop_8chimerax_6atomic_6cytmpl_11TmplResidue_chief(PyObject*, 
void*) (__pyx_v_self=<optimized out>)
     at cytmpl.cpp:1821
#8  0x00007fffb6057066 in 
__pyx_getprop_8chimerax_6atomic_6cytmpl_11TmplResidue_chief(PyObject*, 
void*) (__pyx_v_self=<optimized out>)
     at cytmpl.cpp:1800
#9  0x00007fffb6057066 in 
__pyx_getprop_8chimerax_6atomic_6cytmpl_11TmplResidue_chief(PyObject*, 
void*) (o=<optimized out>, x=<optimized out>)
     at cytmpl.cpp:3840
#10 0x00007ffff794df3f in _PyObject_GenericGetAttrWithDict 
(obj=0x7fff3e626fa8, name=0x7fffb626fe68, dict=0x0, suppress=0) at 
Objects/object.c:1235
#11 0x00007ffff79ed2ba in builtin_getattr (self=<optimized out>, 
args=<optimized out>, nargs=<optimized out>) at 
Python/bltinmodule.c:1127
#12 0x00007ffff790774c in _PyMethodDef_RawFastCallKeywords 
(method=0x7ffff7d76fa0 <builtin_methods+544>, self=<optimized out>, 
args=0x7fff315c67d0, nargs=2, kwnames=<optimized out>) at 
Objects/call.c:651
#13 0x00007ffff79077f5 in _PyCFunction_FastCallKeywords 
(func=0x7ffff7f58e10, args=<optimized out>, nargs=<optimized out>, 
kwnames=<optimized out>)
     at Objects/call.c:730

}}}

On 2019-06-27 22:53, ChimeraX wrote:

comment:11 by Greg Couch, 6 years ago

Resolution: fixed
Status: closedreopened

getattr(xxx, 'atoms') works, so it a bug that's tickled by the Shell tool.

Eric, this looks a bug with the cython TmplResidue wrapping. Is there an obvious bug or am I going to have to dig deeper?

in reply to:  12 ; comment:12 by tic20@…, 6 years ago

Yes - surprisingly, dir(tmpl) works just fine too.
 

 


comment:13 by Eric Pettersen, 6 years ago

Resolution: fixed
Status: reopenedclosed

The chief/link atom properties weren't being wrapped correctly in that the C++ return value wasn't being checked against nullptr.

Note: See TracTickets for help on using tickets.