Opened 8 years ago

Closed 8 years ago

Last modified 8 years ago

#831 closed enhancement (fixed)

Allow methods to access current changes to a specific Structure

Reported by: Tristan Croll Owned by: Eric Pettersen
Priority: blocker Milestone:
Component: Core Version:
Keywords: Cc: Tom Goddard
Blocked By: Blocking:
Notify when closed: Platform: all
Project: ChimeraX

Description

At the moment in ISOLDE I have four different types of annotations to do with structural quality and/or restraints, which need to update their position/colour/visibility as their associated model changes. These are all illustrated in the attached image:

  • position restraints (the 'pin' on the left);
  • Ramachandran scores (CA colours);
  • cis and twisted peptide bonds (pseudo-trapezoid filling the "cup" from CA to CA);
  • torsion restraints ("calipers" around each axial bond indicating the distance from the target by both colour and angle)

At present I have the position and torsion restraint graphical updates slaved to the atomic "changes" trigger, and I should have the other two doing the same (but for now they only update during live simulations). The problem I face is that unless I'm missing something, the change handler offers no fast way to determine if any of the changes are coming from a specific model - it's faster to just update the drawings every time "display changed" or "coord changed" appears in changes.atom_reasons().

What I think would be nice is to be able to avoid unnecessary recalculations b querying the target Structure directly to see if it has any relevant changes. This could be achieved as simply as adding the line:

self.current_changes = gc

at line 309 of structure.py to provide an outward-visible copy of the current change mask, or a little more complex by splitting the changes out into individual boolean variables (self.coords_changed, self.display_changed etc.). That would allow me to use essentially the same logic pipeline that's used in structure.py itself for these updates.

Attachments (1)

image11.png (101.9 KB ) - added by Tristan Croll 8 years ago.
Annotations used in ISOLDE

Download all attachments as: .zip

Change History (13)

by Tristan Croll, 8 years ago

Attachment: image11.png added

Annotations used in ISOLDE

comment:1 by Tom Goddard, 8 years ago

I looked at combining the Structure._graphics_changed and Structure "changes" trigger (in atomic/changes.py) into one change tracking mechanism since they do nearly the same thing. But there is one key difference that _graphics_changed is per-structure while the "changes" trigger is aggregated for all structures. The graphics updating had to have the per-structure change info for efficient rendering. This is the same issue that Tristan raises in this ticket.

I don't see how the proposed fix of "self.current_changes = self._graphics_changed" is going to work because there is no way to be sure that value will be updated before your custom annotation drawing gets the "graphics update" trigger. This is because there is no way to say that your drawing "graphics update" trigger callback should be called after the "graphics update" trigger callback that is supposed to set "self.current_changes".

Some more thought should be given to whether structure change tracking should be done at the individual structure level in general.

in reply to:  3 comment:2 by tic20@…, 8 years ago

A fair point on the lack of control over trigger timing.

A potential alternative approach: provide a dict within the Structure 
class itself to which custom callbacks (taking the structure object and 
the changes as arguments) can be added (via e.g. 
add_redraw_callback(name, func) and remove_redraw_callback(name)). Then 
have it run all callbacks in the dict at the end of 
_update_graphics_if_needed(). Then you have control at the Structure 
level, you know exactly when they run and what information they get, and 
there's minimal need for adjustment of the existing system.

On 2017-09-14 19:32, ChimeraX wrote:

in reply to:  4 ; comment:3 by tic20@…, 8 years ago

... and I realised about a minute after posting that I'd just described 
the existing TriggerSet functionality...

On 2017-09-14 19:54, ChimeraX wrote:

comment:4 by Eric Pettersen, 8 years ago

Component: UnassignedCore
Status: assignedaccepted

comment:5 by Eric Pettersen, 8 years ago

Cc: Eric Pettersen added; Tom Goddard removed
Owner: changed from Eric Pettersen to Tom Goddard
Status: acceptedassigned

Deciding whether there should be per-structure triggers for this purpose seems like it would be in Tom's purview, so reassigned ticket t him.

comment:6 by Tristan Croll, 8 years ago

Just bumping this since I'm currently working on rotamer validation/annotation (and improving my implementation of validation tasks in general), and running into the same issue.

comment:7 by Tom Goddard, 8 years ago

Eric and I just discussed have per-structure triggers. Basically these would work just like the current triggers that apply to all structures. Instead of using session.triggers.add_handler("changes", ...) you would use structure.triggers.add_handler("changes", ...) for the specific structure you want to monitor. The attractiveness of this approach is that it avoids creating different mechanisms to be notified of changes. In fact potentially this new mechanism could replace the current graphics change code that was written before the trigger changes were available.

I'm concerned though that your problem is simply performance, and the new triggers may also not have the performance you need. So I'm interested to know exactly how you expect to use the triggers. Do you plan on simply getting a per-structure "changes" trigger, seeing that it lists reason "coords changed", then you just update everything? Or are you going to try to see which specific atoms moved and only update the annotations effected? The latter approach is likely to be just as slow as the current global "changes" trigger.

in reply to:  9 comment:8 by tic20@…, 8 years ago

Thanks, that sounds perfect! And yep, I’d plan to use it as per your first suggestion.

A query: would you fire the trigger before or after the Structure has calculated its own drawing? Before would have some advantages, I think - e.g. allowing the triggered methods to change atom/bond colors there rather than on the next redraw.

 
 
Tristan Croll
Research Fellow
Cambridge Institute for Medical Research
University of Cambridge CB2 0XY
 

 

comment:9 by Eric Pettersen, 8 years ago

Cc: Tom Goddard added; Eric Pettersen removed
Owner: changed from Tom Goddard to Eric Pettersen

comment:10 by Tom Goddard, 8 years ago

The per-structure triggers would fire before graphics is drawn so graphics can be changed and appear in the next rendered frame. So any molecular structure changes can update the graphics so they appear in the first rendered frame after the structure change was made.

comment:11 by Eric Pettersen, 8 years ago

Resolution: fixed
Status: assignedclosed

Per-structure change triggers are now implemented.

comment:12 by Eric Pettersen, 8 years ago

For the convenience of my other user (Greg), the data given as the trigger argument is now a 2-tuple of (structure, changes) rather than just changes.

--Eric

Note: See TracTickets for help on using tickets.