Repository navigation
CaviTracer: mmCIF output, a truer lining measurement, and multi-frame fixes - #2278
Conversation
…dges, the graph keeps every Voronoi edge, so the search routes through gates narrower than the probe and the channel is discarded afterwards by the bottleneck filter. That loses corridors: a cheap pinched route wins the exit, is dropped, and the wider route to the same mouth is never reported, since only one path per exit comes back. prune_narrow_edges leaves those edges out of the graph instead, at the floor the filter uses - MOLE filters, CAVER prunes, and the option picks. Off by default as it sometimes changes what channels are reported 4/22 cases gain a few channels and none loses any.
…tA becomes a clearance between surfaces, default 1.5. Unknown elements fall back on a named UNKNOWN entry of 2.0 A and say so, rather than raising KeyError as they would have + residues lying inside the route are reported - likely indicating difference between structure used for channel calc and residues detection.
…nown atoms + dropping the deep-atom report from the cavity path as unreachable
…eCavityResidueNames raised KeyError on an element outside VDW_RADII before reaching the lining that had just been taught to fall back, and calcChannels still did on any structure traced with its hetero atoms kept - only water is dropped, so a metalloprotein handed over whole stopped at the trace rather than the report, which is the wrong end to fail at. getVdwRadii is now case-insensitive, falls back on the table's UNKNOWN entry and names what it substituted; _atomRadii adapts it to an Atomic and covers the one case it cannot, a file with no element column. The announcement lives there alone, passed down rather than restated, so a cavity report that reads the radii twice says it once.
…ata - previously the table mixed scales without recording any of them. Bondi's few transition metals are effectively metallic radii, so ZN 1.39 sat a full Angstrom below every modern determination. Each block now names its source. Bondi family where it agrees with Alvarez, Alvarez for the metals, alkali and alkaline earths, and the f-block. Overall, 42 elements added, so MN and CO no longer fall through to UNKNOWN, and 27 values changed, none of them protein-forming.
…chema), selected by output_format arguemnt - either pqr by defualut or mmcif/cif
…rame functions, via _frameBounds: stop_frame is documented as the last frame to analyse, with -1 meaning all of them, but each multi-frame function spelled that out for itself and they did not agree. Where the sentinel was passed straight into a Python slice, -1 was read as an ordinary negative index and the last frame was silently dropped, and every other value was taken exclusively rather than inclusively. Any negative value now means to the end: treating one negative as a sentinel and another as an index is the ambiguity that caused this. getSurfaceCavityResidueNamesMultipleFrames also gains the stop_frame its docstring has always documented but which was never read, and its trajectory branch no longer runs past the results it was given.
… the multi-frame functions now fetch it with getattr and rewind and restore it only for a file-backed trajectory, the form the residue report already used. An in-memory ensemble - Ensemble, PDBEnsemble or atom group - is therefore accepted as trajectory= alongside a DCD, whose position is saved and restored exactly as before.
…one is still there. saveChannelsToPdb, saveCavitiesToPdb and writeChannelsCIF do not write any file when no results exist. Since an earlier run's file then survives and goes on looking current, so these are warned about.
…operties, and say how much of each lining they cover, so every item of schema carries a value. The properties are averaged over standard residues alone, as the schema defines them. A lining with nothing scorable in it. Since the residues left out are rarely a random sample of the wall, any channel whose lining holds them is named with its covered fraction and what was left out, in the log and as a comment above the properties.
…d colours were chosen in CIE-Lab, where they looked well separated, but visually rank 6 was the same cyan as rank 3; offset and cycle are now tuned in OKLab against lit and shadowed versions of each colour, with the CAVER primaries unchanged. + cleaning of couple docstrings details.
|
@karolamik13 please have a look, these include all we discussed, with several minor fixes. After this is resolved, no code changes are expected, unless bugs are to be fixed :) |
karolamik13
left a comment
There was a problem hiding this comment.
I tested the code on multiple examples (single PDBs, multi-model PDBs, trajectories, etc.) -- looks good. The CIF file saved from channels seems to be fine. I don't have experience with this format. I was not able to check it with some visualization programs, but I have checked the CIF file with gemmi (see below; the number of channels is correct, and the CIF passes validation).
CIF validation: PASS
Number of channels: 9
Number of profile points: 720
channel0 points = 40 length = 5.129
channel1 points = 50 length = 5.282
channel2 points = 70 length = 5.082
channel3 points = 65 length = 5.489
channel4 points = 65 length = 5.646
channel5 points = 110 length = 15.127
channel6 points = 160 length = 24.036
channel7 points = 90 length = 16.683
channel8 points = 70 length = 9.312
|
For those who would like to visualize channels in PyMol: from prody import * and then except channels also "vis_channels.py" is created. Next (after gunzip 1tqn.tar.gz or downloading uncompressed pdb file): |
1. Optional mmCIF output in the sb-ncbr tunnels schema
calcChannelsandcalcPoresFromChannelsgainoutput_format—'pqr'(default, unchanged behaviour) or'mmcif'.The schema is the one MOLEonline and ChannelsDB publish tunnels under (sb-ncbr/tunnels-schema v1.0). It puts the profile, the layers and the lining residues of every channel in one file with
keys joining them, where this module otherwise spreads them over a PQR and two text tables joined only by filename convention.
Seven of the schema's eight categories are written.
sb_ncbr_channel_annotationisomitted: it records ChannelsDB literature annotation, not a property of a de-novo
trace.
Notes on the mapping, since the schema fixes no vocabulary for them:
.typefollows MOLE — a channel is aTunnel, a pore aPore, a chamber link aPath. Links share the channels file, told apart by this column, unlike the PQR output which keeps them separate.bRadius, which needs B-factors.separatehas no meaning for mmCIF (the value of the format is the joins between its categories) and is ignored..cifper frame, as the PQR path already does; the schema describes one structure.Cost: +0–6% over the trace, ~11 ms per channel, scaling with channel count rather than structure size. File size is ~2–3× the PQR, dominated by the
layer_residuejoin. Nothing is computed on the PQR path.Viewer: one
vis_channels.pynow serves both formats, with the same group names and the same colour per rank, so a channel is the same colour whichever way the run was written.2. The lining is measured to the atom surface, not its centre
distAbecomes a clearance between van der Waals surfaces rather than a centre-to-centre distance, and its default moves from 2.5 to 1.5 Å.This changes which residues are reported as lining a channel. Both radii belong in the criterion: without the probe radius a fixed
distAreaches a different depth depending on how wide the channel is, and without the atom radius the reach past an atom's own surface varies by element — widest at hydrogen, negative for the alkali and alkaline-earth ions, which then had to overlap the probe before being reported at all.Residues lying inside the route rather than beside it are now reported separately. They are usually an ion or cofactor the tessellation never saw — a real result — but can also indicate that the structure passed to the report is not the one the channels were traced on.
3.
VDW_RADIIoverhauled and every lookup hardenedThe table mixed scales without recording any of them; Bondi's transition metals are effectively metallic radii, so
ZNsat a full Ångström below every modern determination. Each block now names its source (Bondi family where it agrees withAlvarez, Alvarez for the metals, alkali/alkaline earths and f-block). 42 elements added, 27 values changed, none of them protein-forming.
Lookups are case-insensitive and fall back on a named
UNKNOWNentry, announcing the substitution once rather than raisingKeyError. Previously a metalloprotein handed over whole failed at the report rather than the trace — the wrong end to fail at.4.
prune_narrow_edges, off by defaultCAVER-style pruning of sub-probe Voronoi edges. Without it the search routes through gates narrower than the probe and the channel is discarded afterwards by the bottleneck filter, which loses corridors: a cheap pinched route wins the exit, is
dropped, and the wider route to the same mouth is never reported. MOLE filters, CAVER prunes, and the option picks. Off by default — 4 of 22 test cases gain channels, none loses any.
Bug fixes in the multi-frame path
stop_framewas off by one incalcChannelsMultipleFrames's multi-model branch.The sentinel
-1was passed straight into a Python slice, where it means "one before the end" rather than "all", so the last model was silently dropped; positive values were taken exclusively where the docstring promises inclusively. Thefunction's own trajectory branch and the surface-cavity equivalent were correct, so one function disagreed with itself depending on how frames were supplied. All call sites now go through one
_frameBounds()helper, so the branches cannot drift apart again. Out-of-range values are clamped rather than raising, since callers had writtenstop_frame=numCoordsets()to work around the exclusive behaviour.getSurfaceCavityResidueNamesMultipleFramesgains thestop_frameits docstring had always documented but which was never read.trajectory=rejected every in-memory ensemble. The frame cursor_nfiexists only on a file-backed DCD, and the branch above it converts anAtomicargument into anEnsemble— precisely the type that could not survive the next line.AtomGroup,EnsembleandPDBEnsemblenow work alongsideDCDFileandTrajectory; a DCD's position is still saved and restored.Empty results left an empty file. A run finding nothing now writes no file at all