From: Axel Kohlmeyer (akohlmey_at_gmail.com)
Date: Sat Sep 28 2013 - 04:27:12 CDT

hi stephanie,

please see my comments below

On Sat, Sep 28, 2013 at 2:42 AM, Stephanie Teich-McGoldrick
<stephanietm_at_gmail.com> wrote:
> Hello all,
>
> I am trying to write a user defined script to make a movie with vmd 1.9.1 on
> a Mac. However, my commands do not seem to be executing in sequence, and
> some seem to be skipped entirely. I am using a 'mywait' script John posted
> to the mailing list, as the 'wait' command does not appear to work for me.

"wait" is a shell builtin. the equivalent to sleep in Tcl is the
"after" command. unlike sleep it takes milliseconds as an argument and
also includes additional features.

> These are my actions:
>
> proc xrotate {} {
> rotate x by 90 20
> }
> proc yrotate {} {
> rotate y by 180 20
> }
> proc mywait { waittime } {
> set starttime [clock seconds]
> while {[expr [clock seconds] - $starttime < $waittime]} {
> }
> }
>
> When I run anyone of these commands individually they work. However, if I
> execute the following:
>
> proc MakeMovie { } {
> xrotate
> mywait 10
> yrotate
> puts "I am done with MakeMovie"
> }
>
> the program waits, then writes "I am done with MakeMovie", then rotates
> around the y-axis. The rotation about the x-axis never happens. I have tried

it does happen, you just don't notice.

> various combinations, but I can't get the program to execute in order. Any
> suggestions of things I might be overlooking?

this is a bit tricky to explain, since this relates to some internals
of how GUI programs work. i am trying to simplify it, so it may not be
100% technically correct, but it should be sufficiently close, so that
you can see where the issue lies and how to deal with it.

in a nutshell, applications are initialized and then enter what is
called an "event loop" from which they never return. the event loop
does "multiplexing" by processing a queue of pending events, i.e. it
tries to act as if it can do many things at the same time, but it
actually just monitors the queue of events and then jumps to a
subroutine designated to react to that event. if this subroutine does
not do much or just does a bit of work and then stops and creates a
new event designated to continue the work where it stopped, you don't
notice that there is actually just a single thread working.
executing a Tcl script is such an event. thus everything else in VMD
is suspended until it completes. because of that, the GUI does not
respond, if you do complex long running script computations or VMD
commands like measure.

now the rotate command is a very old one and uses the event queue in a
way, that you would not do nowadays exactly because of the behavior
you are observing. it creates multiple events and adds them to the
queue. if you type the rotate command at the commend prompt, this
works fine, because you drop back into the event loop after the first
event is executed and then process the rest. however, inside a Tcl
script, this does not happen. so all rotate events are queued up and
then executed as one big swoop after your script ends. not exactly
what you intend to do, right?

this has been recognized, and to alleviate the issue, there is the
"display update" command. this allows you to deliberately suspend and
enable the event queue processing (e.g. if you want to do a lot of
incremental changes, but only want to see the final result) and it
also allows you to process the event queue with "display update". at
this point, the issue of how the smooth rotate is implemented rears
its ugly head, since running the even queue once, is not enough. so
you have to emulate this behavior.
what you end up with is something that could look like this:

# smooth rotation with display updates for scripts
# dir: rotation direction {x, y, or z}
# val: total rotation in degrees
# inc: rotation increments in degrees
# del: delay between increment updates in milliseconds
proc srotate {{dir x} {val 0} {inc 1} {del 0}} {
  set n [expr {int(abs($val) / $inc)}]
  for {set i 0} {$i < $n} {incr i} {
    rotate $dir by $inc
    display update
    after $del
  }
  rotate $dir by [expr {$val - $n*$inc}]
  display update
  after $del
}

proc MakeMovie { } {
    srotate x 90 20 100
    puts "wait"
    after 10000
    srotate y 180 20 100
    puts "done"
}

please give it a try and let us know, if that solves your problem.

ciao,
    axel.

> Cheers,
> Stephanie

-- 
Dr. Axel Kohlmeyer  akohlmey_at_gmail.com  http://goo.gl/1wk0
International Centre for Theoretical Physics, Trieste. Italy.