One of the researchers here needed a way to see which waters bridged between a protein and a nucleic acid during a trajectory. The specific waters change during the simulation, so the static method used in the graphics form doesn't work. Instead, the vmd_frame variable and a caching method similar to the sscache of the previous section was used for the following solution:
The cache data is stored in the array bridging_waters. Unlike sscache, this array is indexed only by the frame number; you'll have to modify it to analyze multiple changing selections.
When the frame number changes, the cache is checked and, if no data exists, the selection is rebuilt. Since the selection is created in a procedure, it must be given by the global command to make it exist outside that procedure's context.
The global Tcl variable bridging is set to the selection for this frame.
The first text selection in the graphics form is set to @bridging. This is one of the special extensions to the selection language which enable the selections to reference a Tcl variable. Note also that the display updates are temporarily turned off. This is used to keep the display from being drawn an additional time by the call to mol modselect. This is done every time the frame changes since that's the only way to tell VMD the graphics have changed; forcing it to recalculate that representation's display.
# start the trace proc start_bridging {{molid top}} { global vmd_frame bridging_molecule if {![string compare $molid top]} { set molid [molinfo top] } trace variable vmd_frame($molid) w calc_bridging set bridging_molecule $molid } # stop the trace proc stop_bridging {} { global bridging_molecule vmd_frame trace vdelete vmd_frame($bridging_molecule) w calc_bridging } # do the actual calculation proc calc_bridging {args} { global bridging_waters bridging_molecule bridging # get the current frame number set frame [molinfo $bridging_molecule get frame] # has the selection already been made? if {! [info exists bridging_waters($frame)]} { puts "Calculating frame $frame for $bridging_molecule" set bridging_waters($frame) [atomselect $bridging_molecule {(water within 4 of segname DNA) and (water within 4 of segname PRO1)} frame $frame] } # set things up for the graphics form to use the precomputed selection set bridging $bridging_waters($frame) # do this since otherwise the selection is deleted when the proc ends $bridging global # update the 0th element of the graphics molecule # Note: if the display wasn't turned off, there would be an extra # update of the animation ... very bad display update off mol modselect 0 $bridging_molecule {@bridging} display update on }
Since the selections are available in the global scope, you can analyze the results at any time. This simple function prints how many atoms are in each selection of the cache.
proc num_bridging {} { global bridging_waters set nums [lsort -integer [array names bridging_waters]] foreach num $nums { set num_atoms [$bridging_waters($num) num] puts "Frame $num has $num_atoms atoms" } }
It would be nice to change the text selection used, support multiple selections, have the ``@'' variables in more complicated expressions in the graphics selections, and be able to use this script for multiple molecules. These are left to the student as an exercise :).