source: branches/1.4/gui/scripts/analyzer.tcl @ 5874

Last change on this file since 5874 was 5833, checked in by mmh, 9 years ago

remove debugging puts

File size: 56.3 KB
Line 
1# -*- mode: tcl; indent-tabs-mode: nil -*-
2# ----------------------------------------------------------------------
3#  COMPONENT: analyzer - output area for Rappture
4#
5#  This widget acts as the output side of a Rappture application.
6#  When the input has changed, it displays a Simulate button that
7#  launches the simulation.  When a simulation is running, this
8#  area shows status.  When it is finished, the results appear
9#  in place of the button, according to the specs in the <analyze>
10#  XML data.
11# ======================================================================
12#  AUTHOR:  Michael McLennan, Purdue University
13#  Copyright (c) 2004-2012  HUBzero Foundation, LLC
14#
15#  See the file "license.terms" for information on usage and
16#  redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES.
17# ======================================================================
18package require Itk
19
20option add *Analyzer.width 3.5i widgetDefault
21option add *Analyzer.height 4i widgetDefault
22option add *Analyzer.simControl "auto" widgetDefault
23option add *Analyzer.simControlBackground "" widgetDefault
24option add *Analyzer.simControlOutline gray widgetDefault
25option add *Analyzer.simControlActiveBackground #ffffcc widgetDefault
26option add *Analyzer.simControlActiveOutline black widgetDefault
27option add *Analyzer.notebookpage "about" widgetDefault
28
29option add *Analyzer.font \
30    -*-helvetica-medium-r-normal-*-12-* widgetDefault
31option add *Analyzer.codeFont \
32    -*-courier-medium-r-normal-*-12-* widgetDefault
33option add *Analyzer.textFont \
34    -*-helvetica-medium-r-normal-*-12-* widgetDefault
35option add *Analyzer.boldTextFont \
36    -*-helvetica-bold-r-normal-*-12-* widgetDefault
37
38itcl::class Rappture::Analyzer {
39    inherit itk::Widget
40
41    itk_option define -codefont codeFont Font ""
42    itk_option define -textfont textFont Font ""
43    itk_option define -boldtextfont boldTextFont Font ""
44    itk_option define -simcontrol simControl SimControl ""
45    itk_option define -simcontroloutline simControlOutline Background ""
46    itk_option define -simcontrolbackground simControlBackground Background ""
47    itk_option define -simcontrolactiveoutline simControlActiveOutline Background ""
48    itk_option define -simcontrolactivebackground simControlActiveBackground Background ""
49    itk_option define -holdwindow holdWindow HoldWindow ""
50    itk_option define -notebookpage notebookPage NotebookPage ""
51
52    constructor {tool args} {
53        # defined below
54    }
55    destructor {
56        # defined below
57    }
58
59    public method simulate {args}
60    public method reset {{when -eventually}}
61    public method load {xmlobj}
62    public method clear {{xmlobj "all"}}
63    public method download {option args}
64
65    protected method _plot {args}
66    protected method _reorder {comps}
67    protected method _autoLabel {xmlobj path title cntVar}
68    protected method _fixResult {}
69    protected method _fixResultSet {args}
70    protected method _fixSize {}
71    protected method _fixSimControl {}
72    protected method _fixNotebook {}
73    protected method _simState {state args}
74    protected method _simOutput {message}
75    protected method _resultTooltip {}
76    protected method _isPdbTrajectory {data}
77    protected method _isLammpsTrajectory {data}
78    protected method _pdbToSequence {xmlobj path id child data}
79    protected method _lammpsToSequence {xmlobj path id child data}
80    protected method _trajToSequence {xmlobj {path ""}}
81    protected method _pop_uq_dialog {win}
82    protected method _setWaitVariable {state}
83    protected method _adjust_level {win}
84
85    private variable _tool ""          ;# belongs to this tool
86    private variable _appName ""       ;# Name of application
87    private variable _control "manual" ;# start mode
88    private variable _resultset ""     ;# ResultSet object with all results
89    private variable _pages 0          ;# number of pages for result sets
90    private variable _label2page       ;# maps output label => result set
91    private variable _label2desc       ;# maps output label => description
92    private variable _label2item       ;# maps output label => output.xxx item
93    private variable _lastlabel ""     ;# label of last example loaded
94    private variable _plotlist ""      ;# items currently being plotted
95    private variable _lastPlot
96    private common job                 ;# array var used for blt::bgexec jobs
97    private variable _wait_uq 0
98}
99
100itk::usual Analyzer {
101    keep -background -cursor foreground -font
102}
103
104# ----------------------------------------------------------------------
105# CONSTRUCTOR
106# ----------------------------------------------------------------------
107itcl::body Rappture::Analyzer::constructor {tool args} {
108    set _tool $tool
109
110    # use this to store all simulation results
111    set _resultset [Rappture::ResultSet ::\#auto]
112    $_resultset notify add $this [itcl::code $this _fixResultSet]
113
114    # widget settings...
115    itk_option add hull.width hull.height
116    pack propagate $itk_component(hull) no
117
118    frame $itk_interior.simol -borderwidth 1 -relief flat
119    pack $itk_interior.simol -fill x
120
121    itk_component add simbg {
122        frame $itk_interior.simol.simbg -borderwidth 0
123    } {
124        usual
125        rename -background -simcontrolcolor simControlColor Color
126    }
127    pack $itk_component(simbg) -expand yes -fill both
128
129    set simtxt [string trim [$tool xml get tool.action.label]]
130    if {"" == $simtxt} {
131        set simtxt "Simulate"
132    }
133    itk_component add simulate {
134        button $itk_component(simbg).simulate -text $simtxt \
135            -command [itcl::code $this simulate]
136    } {
137        usual
138        rename -highlightbackground -simcontrolcolor simControlColor Color
139    }
140    pack $itk_component(simulate) -side left -padx 4 -pady 4
141
142    # BE CAREFUL: Shift focus when we click on "Simulate".
143    #   This shifts focus away from input widgets and causes them to
144    #   finalize and log any pending changes.  A better way would be
145    #   to have the "sync" operation finalize/sync, but this works
146    #   for now.
147    bind $itk_component(simulate) <ButtonPress> {focus %W}
148
149    # if there's a hub url, then add "About" and "Questions" links
150    set _appName [$_tool xml get tool.id]
151    set url [Rappture::Tool::resources -huburl]
152    if {"" != $url && "" != $_appName} {
153        itk_component add hubcntls {
154            frame $itk_component(simbg).hubcntls
155        } {
156            usual
157            rename -background -simcontrolcolor simControlColor Color
158        }
159        pack $itk_component(hubcntls) -side right -padx 4
160
161        itk_component add icon {
162            label $itk_component(hubcntls).icon -image [Rappture::icon ask] \
163                -highlightthickness 0
164        } {
165            usual
166            ignore -highlightthickness
167            rename -background -simcontrolcolor simControlColor Color
168        }
169        pack $itk_component(icon) -side left
170
171        itk_component add about {
172            button $itk_component(hubcntls).about -text "About this tool" \
173                -command [list Rappture::filexfer::webpage \
174                              "$url/tools/$_appName"]
175        } {
176            usual
177            ignore -font
178            rename -background -simcontrolcolor simControlColor Color
179            rename -highlightbackground -simcontrolcolor simControlColor Color
180        }
181        pack $itk_component(about) -side top -anchor w
182
183        itk_component add questions {
184            button $itk_component(hubcntls).questions -text Questions? \
185                -command [list Rappture::filexfer::webpage \
186                              "$url/resources/$_appName/questions"]
187        } {
188            usual
189            ignore -font
190            rename -background -simcontrolcolor simControlColor Color
191            rename -highlightbackground -simcontrolcolor simControlColor Color
192        }
193        pack $itk_component(questions) -side top -anchor w
194    }
195
196    itk_component add simstatus {
197        text $itk_component(simbg).simstatus -borderwidth 0 \
198            -highlightthickness 0 -height 1 -width 1 -wrap none \
199            -state disabled
200    } {
201        usual
202        ignore -highlightthickness
203        rename -background -simcontrolcolor simControlColor Color
204        rename -font -textfont textFont Font
205    }
206    pack $itk_component(simstatus) -side left -expand yes -fill x
207
208    $itk_component(simstatus) tag configure popup \
209        -underline 1 -foreground blue
210
211    $itk_component(simstatus) tag bind popup \
212        <Enter> {%W configure -cursor center_ptr}
213    $itk_component(simstatus) tag bind popup \
214        <Leave> {%W configure -cursor ""}
215    $itk_component(simstatus) tag bind popup \
216        <ButtonPress> {after idle {Rappture::Tooltip::tooltip show %W}}
217
218
219    itk_component add notebook {
220        Rappture::Notebook $itk_interior.nb
221    }
222    pack $itk_interior.nb -expand yes -fill both
223
224    # ------------------------------------------------------------------
225    # ABOUT PAGE
226    # ------------------------------------------------------------------
227    set w [$itk_component(notebook) insert end about]
228
229    Rappture::Scroller $w.info -xscrollmode off -yscrollmode auto
230    pack $w.info -expand yes -fill both -padx 4 -pady 20
231    itk_component add toolinfo {
232        text $w.info.text -width 1 -height 1 -wrap word \
233            -borderwidth 0 -highlightthickness 0
234    } {
235        usual
236        ignore -borderwidth -relief
237        rename -font -textfont textFont Font
238    }
239    $w.info contents $w.info.text
240
241    # ------------------------------------------------------------------
242    # SIMULATION PAGE
243    # ------------------------------------------------------------------
244    set w [$itk_component(notebook) insert end simulate]
245    frame $w.cntls
246    pack $w.cntls -side bottom -fill x -pady 12
247    frame $w.cntls.sep -background black -height 1
248    pack $w.cntls.sep -side top -fill x
249
250    itk_component add abort {
251        button $w.cntls.abort -text "Abort" \
252            -command [itcl::code $_tool abort]
253    }
254    pack $itk_component(abort) -side left -expand yes -padx 4 -pady 4
255
256    Rappture::Scroller $w.info -xscrollmode auto -yscrollmode auto
257    pack $w.info -expand yes -fill both -padx 4 -pady 4
258    itk_component add runinfo {
259        text $w.info.text -width 1 -height 1 -wrap none \
260            -borderwidth 0 -highlightthickness 0 \
261            -state disabled
262    } {
263        usual
264        ignore -borderwidth -relief
265        rename -font -codefont codeFont Font
266    }
267    $w.info contents $w.info.text
268
269    itk_component add progress {
270        Rappture::Progress $w.progress
271    }
272
273    # ------------------------------------------------------------------
274    # ANALYZE PAGE
275    # ------------------------------------------------------------------
276    set w [$itk_component(notebook) insert end analyze]
277
278    frame $w.top
279    pack $w.top -side top -fill x -pady 8
280    label $w.top.l -text "Result:" -font $itk_option(-font)
281    pack $w.top.l -side left
282
283    itk_component add viewselector {
284        Rappture::Combobox $w.top.sel -width 10 -editable no
285    } {
286        usual
287        rename -font -textfont textFont Font
288    }
289    pack $itk_component(viewselector) -side left -expand yes -fill x
290    bind $itk_component(viewselector) <<Value>> [itcl::code $this _fixResult]
291    bind $itk_component(viewselector) <Enter> \
292        [itcl::code $this download coming]
293
294    Rappture::Tooltip::for $itk_component(viewselector) \
295        "@[itcl::code $this _resultTooltip]"
296
297    $itk_component(viewselector) choices insert end \
298        --- "---"
299
300    itk_component add download {
301        button $w.top.dl -image [Rappture::icon download] -anchor e \
302            -borderwidth 1 -relief flat -overrelief raised \
303            -command [itcl::code $this download start $w.top.dl]
304    }
305    pack $itk_component(download) -side right -padx {4 0}
306    bind $itk_component(download) <Enter> \
307        [itcl::code $this download coming]
308
309    $itk_component(viewselector) choices insert end \
310        @download [Rappture::filexfer::label download]
311
312    if {[Rappture::filexfer::enabled]} {
313        Rappture::Tooltip::for $itk_component(download) "Downloads the current result to a new web browser window on your desktop.  From there, you can easily print or save results.
314
315NOTE:  Your web browser must allow pop-ups from this site.  If your output does not appear, look for a 'pop-up blocked' message and enable pop-ups."
316    } else {
317        Rappture::Tooltip::for $itk_component(download) "Saves the current result to a file on your desktop."
318    }
319
320    itk_component add results {
321        Rappture::Panes $w.pane \
322            -sashwidth 2 -sashrelief solid -sashpadding {2 0}
323    } {
324        usual
325        ignore -sashwidth -sashrelief -sashpadding
326    }
327    pack $itk_component(results) -expand yes -fill both
328    set f [$itk_component(results) pane 0]
329
330    itk_component add resultpages {
331        Rappture::Notebook $f.nb
332    }
333    pack $itk_component(resultpages) -expand yes -fill both
334   set f [$itk_component(results) insert end -fraction 0.1]
335    itk_component add resultselector {
336        Rappture::ResultSelector $f.rsel -resultset $_resultset \
337            -settingscommand [itcl::code $this _plot]
338    }
339    pack $itk_component(resultselector) -expand yes -fill both
340    bind $itk_component(resultselector) <<Layout>> [itcl::code $this _fixSize]
341    bind $itk_component(results) <Configure> [itcl::code $this _fixSize]
342
343    eval itk_initialize $args
344
345    $itk_component(runinfo) tag configure ERROR -foreground red
346    $itk_component(runinfo) tag configure text -font $itk_option(-textfont)
347
348    #
349    # Load up tool info on the first page.
350    #
351    $itk_component(toolinfo) tag configure title \
352        -font $itk_option(-boldtextfont)
353
354    set mesg [string trim [$tool xml get tool.title]]
355    if {"" != $mesg} {
356        $itk_component(toolinfo) insert end $mesg title
357        $itk_component(toolinfo) insert end "\n\n"
358    }
359
360    set mesg [string trim [$tool xml get tool.about]]
361    if {"" != $mesg} {
362        $itk_component(toolinfo) insert end $mesg
363    }
364    $itk_component(toolinfo) configure -state disabled
365    $itk_component(notebook) current about
366
367    # tool can run on "manual" (default) or "auto"
368    set cntl [string trim [$tool xml get tool.control]]
369    if {"" == $cntl} {
370        set cntl [string trim [$tool xml get tool.control.type]]
371    }
372    if {"" != $cntl} {
373        set _control $cntl
374    }
375
376    # reset everything to a clean state
377    reset
378}
379
380# ----------------------------------------------------------------------
381# DESTRUCTOR
382# ----------------------------------------------------------------------
383itcl::body Rappture::Analyzer::destructor {} {
384    after cancel [itcl::code $this simulate]
385    $_resultset notify remove $this
386    itcl::delete object $_resultset
387}
388
389# ----------------------------------------------------------------------
390# USAGE: simulate ?-ifneeded?
391# USAGE: simulate ?<path1> <value1> <path2> <value2> ...?
392#
393# Kicks off the simulator by executing the tool.command associated
394# with the tool.  If any arguments are specified, they are used to
395# set parameters for the simulation.  While the simulation is running,
396# it shows status.  When the simulation is finished, it switches
397# automatically to "analyze" mode and shows the results.
398# ----------------------------------------------------------------------
399itcl::body Rappture::Analyzer::simulate {args} {
400    #puts "simulate args='$args'"
401
402    set uq [$_tool get_uq -uq_type smolyak -uq_args 2]
403
404    # pop up UQ window
405    if {[$uq num_runs] > 1} {
406        set status [$uq run_dialog $itk_component(simulate)]
407        if {$status == 0} {
408            # cancelled
409            return
410        }
411        lappend args -uq_type [$uq type]
412        lappend args -uq_args [$uq args]
413        # Need to put these UQ values into the driver file
414        # so the call to resultset::contains will be correct.
415        set _xml [$_tool xml object]
416        $_xml put uq.type.current [$uq type]
417        $_xml put uq.args.current [$uq args]
418        $_xml put uq.args.about.label "level"
419        $_xml put uq.args.about.description "Polynomial Degree of Smolyak GPC method."
420    }
421    #puts "simulate args=$args"
422
423    if {[lindex $args 0] == "-ifneeded"} {
424        # check to see if simulation is really needed
425        $_tool sync
426        if {[$_resultset contains [$_tool xml object]]
427              && ![string equal $_control "manual-resim"]} {
428            # not needed -- show results and return
429            $itk_component(notebook) current analyze
430            return
431        }
432        set args [lreplace $args 0 0]
433    }
434
435    # simulation is needed -- go to simulation page
436    $itk_component(notebook) current simulate
437
438    # no progress messages yet
439    pack forget $itk_component(progress)
440    lappend args -output [itcl::code $this _simOutput]
441
442    _simState off
443    $itk_component(runinfo) configure -state normal
444    $itk_component(runinfo) delete 1.0 end
445    $itk_component(runinfo) insert end "Running simulation...\n\n" text
446    $itk_component(runinfo) configure -state disabled
447
448    # if the hold window is set, then put up a busy cursor
449    if {$itk_option(-holdwindow) != ""} {
450        blt::busy hold $itk_option(-holdwindow)
451        raise $itk_component(hull)
452    }
453
454    # execute the job
455    #puts "$_tool run $args"
456
457    foreach {status result} [eval $_tool run $args] break
458
459    # if job was aborted, then allow simulation again
460    if {$result == "ABORT"} {
461        _simState on "Aborted"
462    }
463
464    # load results from run.xml into analyzer
465    if {$status == 0 && $result != "ABORT"} {
466        set status [catch {load $result} result]
467    }
468
469    # back to normal
470    if {$itk_option(-holdwindow) != ""} {
471        blt::busy release $itk_option(-holdwindow)
472    }
473    $itk_component(abort) configure -state disabled
474
475    if {$status != 0} {
476        $itk_component(runinfo) configure -state normal
477        # Don't erase program error messages.
478        # $itk_component(runinfo) delete 1.0 end
479        $itk_component(runinfo) insert end "\n\nProblem launching job:\n\n" text
480        _simOutput $result
481        $itk_component(runinfo) configure -state disabled
482        $itk_component(runinfo) see 1.0
483
484        # Try to create a support ticket for this error.
485        # It may be a real problem.
486        if {[Rappture::bugreport::shouldReport for jobs]} {
487            set ::errorInfo "\n\n== RAPPTURE INPUT ==\n[$_tool xml xml]"
488            Rappture::bugreport::register "Problem launching job:\n$result"
489            Rappture::bugreport::attachment [$_tool xml xml]
490            Rappture::bugreport::send
491        }
492    } else {
493        $itk_component(notebook) current analyze
494    }
495
496    # do this last -- after _simOutput above
497    pack forget $itk_component(progress)
498}
499
500
501# ----------------------------------------------------------------------
502# USAGE: reset ?-eventually|-now?
503#
504# Used to reset the analyzer whenever the input to a simulation has
505# changed.  Sets the mode back to "simulate", so the user has to
506# simulate again to see the output.  If the <start> option is set
507# to "auto", the simulation is invoked immediately.
508# ----------------------------------------------------------------------
509itcl::body Rappture::Analyzer::reset {{when -eventually}} {
510    if {$when == "-eventually"} {
511        after cancel [list catch [itcl::code $this reset -now]]
512        after idle [list catch [itcl::code $this reset -now]]
513        return
514    }
515
516    # check to see if simulation is really needed
517    $_tool sync
518    if {![$_resultset contains [$_tool xml object]]
519          || [string equal $_control "manual-resim"]} {
520        # if control mode is "auto", then simulate right away
521        if {[string match auto* $_control]} {
522            # auto control -- don't need button
523            pack forget $itk_interior.simol
524
525            after cancel [itcl::code $this simulate]
526            after idle [itcl::code $this simulate]
527        } else {
528            _simState on "new input parameters"
529        }
530    } else {
531        _simState off
532    }
533}
534
535# ----------------------------------------------------------------------
536# USAGE: load <xmlobj>
537#
538# Loads the data from the given <xmlobj> into the appropriate results
539# sets.  If necessary, new results sets are created to store the data.
540# ----------------------------------------------------------------------
541itcl::body Rappture::Analyzer::load {xmlobj} {
542    # only show the last result? then clear first
543    if {[string trim [$_tool xml get tool.analyzer]] == "last"} {
544        clear
545    }
546    #puts "Analyzer::load"
547    $_resultset add $xmlobj
548
549    # NOTE: Adding will trigger a !change event on the ResultSet
550    # object, which will trigger calls to _fixResultSet to add
551    # the results to display.
552}
553
554# ----------------------------------------------------------------------
555# USAGE: clear ?<xmlobj>?
556#
557# Discards one or more results previously loaded into the analyzer.
558# If an <xmlobj> is specified, then that one result is cleared.
559# Otherwise, all results are cleared.
560# ----------------------------------------------------------------------
561itcl::body Rappture::Analyzer::clear {{xmlobj "all"}} {
562    if {$xmlobj eq "" || $xmlobj eq "all"} {
563        $_resultset clear
564    } else {
565        $_resultset clear $xmlobj
566    }
567
568    # NOTE: Clearing will trigger a !change event on the ResultSet
569    # object, which will trigger calls to _fixResultSet to clean up
570    # the results being displayed.
571}
572
573# ----------------------------------------------------------------------
574# USAGE: download coming
575# USAGE: download controls <downloadCommand>
576# USAGE: download start ?widget?
577# USAGE: download now ?widget?
578#
579# Spools the current result so the user can download it.
580# ----------------------------------------------------------------------
581itcl::body Rappture::Analyzer::download {option args} {
582    set title [$itk_component(viewselector) value]
583    set page [$itk_component(viewselector) translate $title]
584
585    switch -- $option {
586        coming {
587            #
588            # Warn result that a download is coming, in case
589            # it needs to take a screen snap.
590            #
591            if {![regexp {^(|@download|---)$} $page]} {
592                set f [$itk_component(resultpages) page $page]
593                $f.rviewer download coming
594            }
595        }
596        controls {
597            # no controls for this download yet
598            return ""
599        }
600        start {
601            set widget $itk_component(download)
602            if {[llength $args] > 0} {
603                set widget [lindex $args 0]
604                if {[catch {winfo class $widget}]} {
605                    set widget $itk_component(download)
606                }
607            }
608            #
609            # See if this download has any controls.  If so, then
610            # post them now and let the user continue the download
611            # after selecting a file format.
612            #
613            if {$page != ""} {
614                set ext ""
615                set f [$itk_component(resultpages) page $page]
616                set arg [itcl::code $this download now $widget]
617                set popup [$f.rviewer download controls $arg]
618                if {"" != $popup} {
619                    $popup activate $widget below
620                } else {
621                    download now $widget
622                }
623            } else {
624                # this shouldn't happen
625                set file error.html
626                set data "<h1>Not Found</h1>There is no result selected."
627            }
628        }
629        now {
630            set widget $itk_component(download)
631            if {[llength $args] > 0} {
632                set widget [lindex $args 0]
633                if {[catch {winfo class $widget}]} {
634                    set widget $itk_component(download)
635                }
636            }
637            #
638            # Perform the actual download.
639            #
640            if {$page != ""} {
641                set ext ""
642                set f [$itk_component(resultpages) page $page]
643                set item [$itk_component(viewselector) value]
644                set result [$f.rviewer download now $widget $_appName $item]
645                if { $result == "" } {
646                    return;                # User cancelled the download.
647                }
648                foreach {ext data} $result break
649                if {"" == $ext} {
650                    if {"" != $widget} {
651                        Rappture::Tooltip::cue $widget \
652                            "Can't download this result."
653                    }
654                    return
655                }
656                regsub -all {[\ -\/\:-\@\{-\~]} $title {} title
657                set file "$title$ext"
658            } else {
659                # this shouldn't happen
660                set file error.html
661                set data "<h1>Not Found</h1>There is no result selected."
662            }
663
664            Rappture::Logger::log download [$itk_component(viewselector) value]
665            set mesg [Rappture::filexfer::download $data $file]
666            if {[string length $mesg] > 0} {
667                Rappture::Tooltip::cue $widget $mesg
668            }
669        }
670        default {
671            error "bad option \"$option\": should be coming, controls, now, start"
672        }
673    }
674}
675
676# ----------------------------------------------------------------------
677# USAGE: _plot ?<index> <options> <index> <options>...?
678#
679# Used internally to update the plot shown in the current result
680# viewer whenever the resultselector settings have changed.  Causes the
681# desired results to show up on screen.
682# ----------------------------------------------------------------------
683itcl::body Rappture::Analyzer::_plot {args} {
684    #puts "analyzer::_plot"
685    set _plotlist $args
686
687    set page [$itk_component(viewselector) value]
688    set page [$itk_component(viewselector) translate $page]
689    if {"" != $page} {
690        set f [$itk_component(resultpages) page $page]
691        $f.rviewer plot clear
692        foreach {index opts} $_plotlist {
693            $f.rviewer plot add $index $opts
694        }
695    }
696}
697
698# ----------------------------------------------------------------------
699# USAGE: _reorder <compList>
700#
701# Used internally to change the order of a series of output components
702# found in the <output> section.  Moves the <log> elements to the end
703# and returns the updated list.
704# ----------------------------------------------------------------------
705itcl::body Rappture::Analyzer::_reorder {comps} {
706    set i 0
707    set max [llength $comps]
708    while {$i < $max} {
709        set c [lindex $comps $i]
710        if {[string match log* $c]} {
711            set comps [lreplace $comps $i $i]
712            lappend comps $c
713            incr max -1
714        } else {
715            incr i
716        }
717    }
718    return $comps
719}
720
721# ----------------------------------------------------------------------
722# USAGE: _autoLabel <xmlobj> <path> <title> <cntVar>
723#
724# Used internally to check for an about.label property at the <path>
725# in <xmlobj>.  If this object doesn't have a label, then one is
726# supplied using the given <title>.  The <cntVar> is an array of
727# counters in the calling scopes for titles that have been used
728# in the past.  This is used to create titles like "Plot #2" the
729# second time it is encountered.
730#
731# The <xmlobj> is updated so that the label is inserted directly in
732# the tree.
733# ----------------------------------------------------------------------
734itcl::body Rappture::Analyzer::_autoLabel {xmlobj path title cntVar} {
735    upvar $cntVar counters
736
737    set group [$xmlobj get $path.about.group]
738    set label [$xmlobj get $path.about.label]
739    if {"" == $label} {
740        # no label -- make one up using the title specified
741        if {![info exists counters($group-$title)]} {
742            set counters($group-$title) 1
743            set label $title
744        } else {
745            set label "$title (#[incr counters($group-$title)])"
746        }
747        $xmlobj put $path.about.label $label
748    } else {
749        # handle the case of two identical labels in <output>
750        if {![info exists counters($group-$label)]} {
751            set counters($group-$label) 1
752        } else {
753            set label "$label (#[incr counters($group-$label)])"
754            $xmlobj put $path.about.label $label
755        }
756    }
757    return $label
758}
759
760# ----------------------------------------------------------------------
761# USAGE: _fixResult
762#
763# Used internally to change the result page being displayed whenever
764# the user selects a page from the results combobox.
765# ----------------------------------------------------------------------
766itcl::body Rappture::Analyzer::_fixResult {} {
767    set name [$itk_component(viewselector) value]
768    set page ""
769    if {"" != $name} {
770        set page [$itk_component(viewselector) translate $name]
771    }
772    if {$page == "@download"} {
773        # put the combobox back to its last value
774        $itk_component(viewselector) component entry configure -state normal
775        $itk_component(viewselector) component entry delete 0 end
776        $itk_component(viewselector) component entry insert end $_lastlabel
777        $itk_component(viewselector) component entry configure -state disabled
778        # perform the actual download
779        download start $itk_component(download)
780    } elseif {$page == "---"} {
781        # put the combobox back to its last value
782        $itk_component(viewselector) component entry configure -state normal
783        $itk_component(viewselector) component entry delete 0 end
784        $itk_component(viewselector) component entry insert end $_lastlabel
785        $itk_component(viewselector) component entry configure -state disabled
786    } elseif {$page != ""} {
787        set _lastlabel $name
788        $itk_component(resultpages) current $page
789        set f [$itk_component(resultpages) page $page]
790        # We don't want to replot if we're using an existing viewer with the
791        # the same list of objects to plot.  So track the viewer and the list.
792        if { ![info exists _lastPlot($f)] || $_plotlist != $_lastPlot($f) } {
793            set _lastPlot($f) $_plotlist
794            set win [winfo toplevel $itk_component(hull)]
795            blt::busy hold $win
796            #puts "rviewer = $f.rviewer"
797            #puts "_plotlist = $_plotlist"
798            $f.rviewer plot clear
799            eval $f.rviewer plot add $_plotlist
800            blt::busy release $win
801        }
802        Rappture::Logger::log output $_label2item($name)
803        Rappture::Tooltip::for $itk_component(viewselector) \
804            "@[itcl::code $this _resultTooltip]" -log $_label2item($name)
805    }
806}
807
808# ----------------------------------------------------------------------
809# USAGE: _fixResultSet ?<eventData>...?
810#
811# Used internally to react to changes within the ResultSet.  When a
812# result is added, a new result viewer is created for the object.
813# When all results are cleared, the viewers are deleted.
814# ----------------------------------------------------------------------
815itcl::body Rappture::Analyzer::_fixResultSet {args} {
816    #puts "Analyzer::_fixResultSet $args"
817    array set eventData $args
818    switch -- $eventData(op) {
819        add {
820            set xmlobj $eventData(what)
821
822            # Detect molecule elements that contain trajectory data
823            # and convert to sequences.
824            _trajToSequence $xmlobj output
825
826            # Go through the analysis and find all result sets.
827            set haveresults 0
828            foreach item [_reorder [$xmlobj children output]] {
829                if {[$xmlobj get output.$item.about.uqtype] == ""} {
830                    switch -glob -- $item {
831                        log* {
832                            _autoLabel $xmlobj output.$item "Output Log" counters
833                        }
834                        number* {
835                            _autoLabel $xmlobj output.$item "Number" counters
836                        }
837                        integer* {
838                            _autoLabel $xmlobj output.$item "Integer" counters
839                        }
840                        mesh* {
841                            _autoLabel $xmlobj output.$item "Mesh" counters
842                        }
843                        string* {
844                            _autoLabel $xmlobj output.$item "String" counters
845                        }
846                        histogram* - curve* - field* {
847                            _autoLabel $xmlobj output.$item "Plot" counters
848                        }
849                        drawing* {
850                            _autoLabel $xmlobj output.$item "Drawing" counters
851                        }
852                        structure* {
853                            _autoLabel $xmlobj output.$item "Structure" counters
854                        }
855                        table* {
856                            _autoLabel $xmlobj output.$item "Energy Levels" counters
857                        }
858                        sequence* {
859                            _autoLabel $xmlobj output.$item "Sequence" counters
860                        }
861                    }
862                }
863                set label [$xmlobj get output.$item.about.group]
864                if {"" == $label} {
865                    set label [$xmlobj get output.$item.about.label]
866                }
867
868                set hidden [$xmlobj get output.$item.hide]
869                set hidden [expr {"" != $hidden && $hidden}]
870
871                if {"" != $label && !$hidden} {
872                    set haveresults 1
873                }
874            }
875
876            # if there are any valid results, add them to the resultset
877            if {$haveresults} {
878                set index [$_resultset get simnum $xmlobj]
879
880                # add each result to a result viewer
881                foreach item [_reorder [$xmlobj children output]] {
882                    set label [$xmlobj get output.$item.about.group]
883                    if {"" == $label} {
884                        set label [$xmlobj get output.$item.about.label]
885                    }
886                    set hidden [$xmlobj get output.$item.hide]
887                    if {$hidden == ""} {
888                        set hidden 0
889                    }
890                    if {"" != $label && !$hidden} {
891                        set uq_part [$xmlobj get output.$item.about.uqtype]
892
893                        #puts "label=$label uq_part=$uq_part"
894
895                        if {![info exists _label2page($label)]} {
896                            #puts "Adding label: '$label'"
897                            set name "page[incr _pages]"
898                            #puts "Inserting $name into resultpages"
899                            set page [$itk_component(resultpages) \
900                                insert end $name]
901                            set _label2page($label) $page
902                            set _label2item($label) output.$item
903                            set _label2desc($label) \
904                                [$xmlobj get output.$item.about.description]
905                            Rappture::ResultViewer $page.rviewer
906                            pack $page.rviewer -expand yes -fill both -pady 4
907
908                            set end [$itk_component(viewselector) \
909                                choices index -value ---]
910                            if {$end < 0} {
911                                set end "end"
912                            }
913                            $itk_component(viewselector) choices insert $end \
914                                $name $label
915                        }
916
917                        # add/replace the latest result into this viewer
918                        set page $_label2page($label)
919
920                        if {![info exists reset($page)]} {
921                            $page.rviewer clear $index
922                            set reset($page) 1
923                        }
924                        $page.rviewer add $index $xmlobj output.$item $label $uq_part
925                    }
926                }
927            }
928
929            # show the first page by default
930            set max [$itk_component(viewselector) choices size]
931            for {set i 0} {$i < $max} {incr i} {
932                set first [$itk_component(viewselector) choices get -label $i]
933                if {$first != ""} {
934                    set page [$itk_component(viewselector) choices get -value $i]
935                    set char [string index $page 0]
936                    if {$char != "@" && $char != "-"} {
937                        $itk_component(resultpages) current $page
938                        $itk_component(viewselector) value $first
939                        set _lastlabel $first
940                        break
941                    }
942                }
943            }
944        }
945        clear {
946            if {$eventData(what) ne "all"} {
947                # delete this result from all viewers
948                array set params $eventData(what)
949                foreach label [array names _label2page] {
950                    set page $_label2page($label)
951                    $page.rviewer clear $params(simnum)
952                }
953            }
954
955            if {[$_resultset size] == 0} {
956                # reset the size of the controls area
957                set ht [winfo height $itk_component(results)]
958                set cntlht [$itk_component(resultselector) size -controlarea]
959                set frac [expr {double($cntlht)/$ht}]
960                $itk_component(results) fraction end $frac
961
962                foreach label [array names _label2page] {
963                    set page $_label2page($label)
964                    destroy $page.rviewer
965                }
966                $itk_component(resultpages) delete -all
967                set _pages 0
968
969                $itk_component(viewselector) value ""
970                $itk_component(viewselector) choices delete 0 end
971                catch {unset _label2page}
972                catch {unset _label2item}
973                catch {unset _label2desc}
974                set _plotlist ""
975
976                $itk_component(viewselector) choices insert end --- "---"
977                $itk_component(viewselector) choices insert end \
978                    @download [Rappture::filexfer::label download]
979                set _lastlabel ""
980            }
981
982            # fix Simulate button state
983            reset
984        }
985        default {
986            error "don't know how to handle op \"$eventData(op)\""
987        }
988    }
989}
990
991# ----------------------------------------------------------------------
992# USAGE: _fixSize
993#
994# Used internally to change the size of the result set area whenever
995# a new control appears.  Adjusts the size available for the result
996# set up to some maximum.
997# ----------------------------------------------------------------------
998itcl::body Rappture::Analyzer::_fixSize {} {
999    set ht [winfo height $itk_component(results)]
1000    if {$ht <= 1} { set ht [winfo reqheight $itk_component(results)] }
1001    set cntlht [$itk_component(resultselector) size -controlarea]
1002    set frac [expr {double($cntlht)/$ht}]
1003
1004    if {$frac < 0.4} {
1005        $itk_component(results) fraction end $frac
1006    }
1007    _fixSimControl
1008}
1009
1010# ----------------------------------------------------------------------
1011# USAGE: _simState <boolean> ?<message>? ?<settings>?
1012#
1013# Used internally to change the "Simulation" button on or off.
1014# If the <boolean> is on, then any <message> and <settings> are
1015# displayed as well.  If the <boolean> is off, then only display
1016# the message. The <message> is a note to the user about
1017# what will be simulated, and the <settings> are a list of
1018# tool parameter settings of the form {path1 val1 path2 val2 ...}.
1019# When these are in place, the next Simulate operation will use
1020# these settings.  This helps fill in missing data values.
1021# ----------------------------------------------------------------------
1022itcl::body Rappture::Analyzer::_simState {state args} {
1023    if {$state} {
1024        $itk_interior.simol configure \
1025            -background $itk_option(-simcontrolactiveoutline)
1026        configure -simcontrolcolor $itk_option(-simcontrolactivebackground)
1027
1028        $itk_component(abort) configure -state disabled
1029        $itk_component(simulate) configure -state normal \
1030            -command [itcl::code $this simulate]
1031
1032        #
1033        # If there's a special message, then put it up next to the button.
1034        #
1035        set mesg [lindex $args 0]
1036        if {"" != $mesg} {
1037            $itk_component(simstatus) configure -state normal
1038            $itk_component(simstatus) delete 1.0 end
1039            $itk_component(simstatus) insert end $mesg
1040
1041            #
1042            # If there are any settings, then install them in the
1043            # "Simulate" button.  Also, pop them up as a tooltip
1044            # for the message.
1045            #
1046            set settings [lindex $args 1]
1047            if {[llength $settings] > 0} {
1048                $itk_component(simulate) configure \
1049                    -command [eval itcl::code $this simulate $settings]
1050
1051                set details ""
1052                foreach {path val} $settings {
1053                    set str [string trim [$_tool xml get $path.about.label]]
1054                    if {"" == $str} {
1055                        set str [$_tool xml element -as id $path]
1056                    }
1057                    append details "$str = $val\n"
1058                }
1059                set details [string trim $details]
1060
1061                Rappture::Tooltip::for $itk_component(simstatus) $details
1062                $itk_component(simstatus) insert end " "
1063                $itk_component(simstatus) insert end "(details...)" popup
1064            }
1065            $itk_component(simstatus) configure -state disabled
1066        }
1067    } else {
1068        if {"" != $itk_option(-simcontrolbackground)} {
1069            set simcbg $itk_option(-simcontrolbackground)
1070        } else {
1071            set simcbg $itk_option(-background)
1072        }
1073        $itk_interior.simol configure \
1074            -background $itk_option(-simcontroloutline)
1075        configure -simcontrolcolor $simcbg
1076
1077        #$itk_component(simulate) configure -state disabled
1078        $itk_component(abort) configure -state normal
1079
1080        $itk_component(simstatus) configure -state normal
1081        $itk_component(simstatus) delete 1.0 end
1082        set mesg [lindex $args 0]
1083        if {"" != $mesg} {
1084            $itk_component(simstatus) insert end $mesg
1085        }
1086        $itk_component(simstatus) configure -state disabled
1087    }
1088}
1089
1090# ----------------------------------------------------------------------
1091# USAGE: _simOutput <message>
1092#
1093# Invoked automatically whenever output comes in while running the
1094# tool.  Extracts any =RAPPTURE-???=> messages from the output and
1095# sends the output to the display.  For example, any
1096# =RAPPTURE-PROGRESS=> message pops up the progress meter and updates
1097# it to show the latest progress message.  This is useful for
1098# long-running tools, to let the user know how much longer the
1099# simulation will take.
1100# ----------------------------------------------------------------------
1101itcl::body Rappture::Analyzer::_simOutput {message} {
1102    #
1103    # Scan through and pick out any =RAPPTURE-PROGRESS=> messages first.
1104    #
1105
1106    while {[regexp -indices \
1107               {=RAPPTURE-PROGRESS=> *([-+]?[0-9]+) +([^\n]*)(\n|$)} $message \
1108                match percent mesg]} {
1109
1110        foreach {i0 i1} $percent break
1111        set percent [string range $message $i0 $i1]
1112
1113        foreach {i0 i1} $mesg break
1114        set mesg [string range $message $i0 $i1]
1115
1116        pack $itk_component(progress) -fill x -padx 10 -pady 10
1117        $itk_component(progress) settings -percent $percent -message $mesg
1118
1119        foreach {i0 i1} $match break
1120        set message [string replace $message $i0 $i1]
1121    }
1122
1123    #
1124    # Now handle SUBMIT-PROGRESS
1125    #
1126    while {[regexp -indices {=SUBMIT-PROGRESS=> aborted=([0-9]+) finished=([0-9]+) failed=([0-9]+) executing=([0-9]+)\
1127        waiting=([0-9]+) setting_up=([0-9]+) setup=([0-9]+) %done=([0-9.]+) timestamp=([0-9.]+)(\n|$)} $message \
1128        match aborted finished failed executing waiting setting_up setup percent ts mesg]} {
1129
1130        set mesg ""
1131        foreach {i0 i1} $percent break
1132        set percent [string range $message $i0 $i1]
1133        foreach {i0 i1} $failed break
1134        set failed [string range $message $i0 $i1]
1135        foreach {i0 i1} $match break
1136        set message [string replace $message $i0 $i1]
1137
1138        if {$failed != 0} {set mesg "$failed jobs failed!"}
1139        if {$percent >= 100} { set mesg "Jobs finished.  Analyzing results..."}
1140
1141        pack $itk_component(progress) -fill x -padx 10 -pady 10
1142        $itk_component(progress) settings -percent $percent -message $mesg
1143    }
1144
1145    #
1146    # Break up the remaining lines according to =RAPPTURE-ERROR=> messages.
1147    # Show errors in a special color.
1148    #
1149    $itk_component(runinfo) configure -state normal
1150
1151    while {[regexp -indices \
1152               {=RAPPTURE-([a-zA-Z]+)=>([^\n]*)(\n|$)} $message \
1153                match type mesg]} {
1154
1155        foreach {i0 i1} $match break
1156        set first [string range $message 0 [expr {$i0-1}]]
1157        if {[string length $first] > 0} {
1158            $itk_component(runinfo) insert end $first
1159            $itk_component(runinfo) insert end \n
1160        }
1161
1162        foreach {t0 t1} $type break
1163        set type [string range $message $t0 $t1]
1164        foreach {m0 m1} $mesg break
1165        set mesg [string range $message $m0 $m1]
1166        if {[string length $mesg] > 0 && $type != "RUN"} {
1167            $itk_component(runinfo) insert end $mesg $type
1168            $itk_component(runinfo) insert end \n $type
1169        }
1170
1171        set message [string range $message [expr {$i1+1}] end]
1172    }
1173
1174    if {[string length $message] > 0} {
1175        $itk_component(runinfo) insert end $message
1176        if {[$itk_component(runinfo) get end-2char] != "\n"} {
1177            $itk_component(runinfo) insert end "\n"
1178        }
1179        $itk_component(runinfo) see end
1180    }
1181    $itk_component(runinfo) configure -state disabled
1182}
1183
1184# ----------------------------------------------------------------------
1185# USAGE: _resultTooltip
1186#
1187# Used internally to build the tooltip string displayed for the
1188# result selector.  If the current page has an associated description,
1189# then it is displayed beneath the result.
1190#
1191# Returns the string for the tooltip.
1192# ----------------------------------------------------------------------
1193itcl::body Rappture::Analyzer::_resultTooltip {} {
1194    set tip ""
1195    set name [$itk_component(viewselector) value]
1196    if {[info exists _label2desc($name)] &&
1197         [string length $_label2desc($name)] > 0} {
1198        append tip "$_label2desc($name)\n\n"
1199    }
1200    if {[array size _label2page] > 1} {
1201        append tip "Use this control to display other output results."
1202    }
1203    return $tip
1204}
1205
1206# ----------------------------------------------------------------------
1207# USAGE: _fixSimControl
1208#
1209# Used internally to add or remove the simulation control at the
1210# top of the analysis area.  This is controlled by the -simcontrol
1211# option.
1212# ----------------------------------------------------------------------
1213itcl::body Rappture::Analyzer::_fixSimControl {} {
1214    switch -- $itk_option(-simcontrol) {
1215        on {
1216            pack $itk_interior.simol -fill x -before $itk_interior.nb
1217        }
1218        off {
1219            pack forget $itk_interior.simol
1220        }
1221        auto {
1222            #
1223            # If we have two or more radiodials, then there is a
1224            # chance of encountering a combination of parameters
1225            # with no data, requiring simulation.
1226            #
1227            if {[$itk_component(resultselector) size -controls] >= 2} {
1228                pack $itk_interior.simol -fill x -before $itk_interior.nb
1229            } else {
1230                pack forget $itk_interior.simol
1231            }
1232        }
1233        default {
1234            error "bad value \"$itk_option(-simcontrol)\": should be on, off, auto"
1235        }
1236    }
1237}
1238
1239# ----------------------------------------------------------------------
1240# USAGE: _fixNotebook
1241#
1242# Used internally to switch the active notebook page
1243# ----------------------------------------------------------------------
1244itcl::body Rappture::Analyzer::_fixNotebook {} {
1245    switch -- $itk_option(-notebookpage) {
1246        about {
1247            $itk_component(notebook) current about
1248        }
1249        simulate {
1250            $itk_component(notebook) current simulate
1251        }
1252        analyze {
1253            $itk_component(notebook) current analyze
1254        }
1255        default {
1256            error "bad value \"$itk_option(-notebookpage)\": should be about, simulate, analyze"
1257        }
1258    }
1259}
1260
1261# ----------------------------------------------------------------------
1262# USAGE: _isPdbTrajectory <data>
1263#
1264# Used internally to determine whether pdb or lammps data represents a
1265# trajectory rather than a single frame
1266# ----------------------------------------------------------------------
1267itcl::body Rappture::Analyzer::_isPdbTrajectory {data} {
1268    if { [llength $data] == 0 } {
1269        return 0
1270    }
1271    set nModels 0
1272    foreach line $data {
1273        if { [string match "MODEL*" $line] }  {
1274            incr nModels
1275            if { $nModels > 1 } {
1276                # Stop if more than one model found.  No need to count them
1277                # all.
1278                return 1
1279            }
1280        }
1281    }
1282    return 0
1283}
1284
1285# ----------------------------------------------------------------------
1286# USAGE: _isLammpsTrajectory <data>
1287#
1288# Used internally to determine whether pdb or lammps data represents a
1289# trajectory rather than a single frame
1290# ----------------------------------------------------------------------
1291itcl::body Rappture::Analyzer::_isLammpsTrajectory { data } {
1292    if { [llength $data] == 0 } {
1293        return 0
1294    }
1295    set nModels 0
1296    foreach line $data {
1297        if { [regexp {^[\t ]*ITEM:[ \t]+TIMESTEP} $line] } {
1298            incr nModels
1299            if { $nModels > 1 } {
1300                # Stop if more than one model found.  No need to count them
1301                # all.
1302                return 1
1303            }
1304        }
1305    }
1306    return 0
1307}
1308
1309# ----------------------------------------------------------------------
1310# USAGE: _pdbToSequence <xmlobj> ?<path>?
1311#
1312# If the molecule element is a trajectory, delete the original
1313# and create a sequence of individual molecules.
1314# Used internally to detect any molecule output elements that contain
1315# trajectory data.  Trajectories will be converted into sequences of
1316# individual molecules.  All other elements will be unaffected. Scans
1317# the entire xml tree if a starting path is not specified.
1318# ----------------------------------------------------------------------
1319itcl::body Rappture::Analyzer::_pdbToSequence {xmlobj path id child data} {
1320
1321    set seqLabel [$xmlobj get ${child}.about.label]
1322    set descr    [$xmlobj get ${child}.about.description]
1323    set formula  [$xmlobj get ${child}.components.molecule.formula]
1324    $xmlobj remove $child
1325
1326    set sequence  $path.sequence($id)
1327    $xmlobj put ${sequence}.about.label $seqLabel
1328    $xmlobj put ${sequence}.about.description $descr
1329    $xmlobj put ${sequence}.index.label "Frame"
1330
1331    set frameNum 0
1332    set numLines [llength $data]
1333    for { set i 0 } { $i < $numLines } { incr i } {
1334        set line [lindex $data $i]
1335        set line [string trim $line]
1336        set contents {}
1337        if { [string match "MODEL*" $line] } {
1338            # Save the contents until we get an ENDMDL record.
1339            for {} { $i < $numLines } { incr i } {
1340                set line [lindex $data $i]
1341                set line [string trim $line]
1342                if { $line == "" } {
1343                    continue;           # Skip blank lines.
1344                }
1345                if { [string match "ENDMDL*" $line] } {
1346                    break;
1347                }
1348                append contents $line\n
1349            }
1350            set frame ${sequence}.element($frameNum)
1351            $xmlobj put ${frame}.index $frameNum
1352
1353            set molecule ${frame}.structure.components.molecule
1354            $xmlobj put ${molecule}.pdb $contents
1355            $xmlobj put ${molecule}.formula $formula
1356            incr frameNum
1357        }
1358    }
1359}
1360
1361# ----------------------------------------------------------------------
1362# USAGE: _lammpsToSequence <xmlobj> ?<path>?
1363#
1364# If the molecule element is a trajectory, delete the original
1365# and create a sequence of individual molecules.
1366# Used internally to detect any molecule output elements that contain
1367# trajectory data.  Trajectories will be converted into sequences of
1368# individual molecules.  All other elements will be unaffected. Scans
1369# the entire xml tree if a starting path is not specified.
1370# ----------------------------------------------------------------------
1371itcl::body Rappture::Analyzer::_lammpsToSequence {xmlobj path id child data} {
1372
1373    set seqLabel [$xmlobj get ${child}.about.label]
1374    set descr    [$xmlobj get ${child}.about.description]
1375    set typemap  [$xmlobj get ${child}.components.molecule.lammpstypemap]
1376    $xmlobj remove $child
1377
1378    set sequence ${path}.sequence($id)
1379    $xmlobj put ${sequence}.about.label $seqLabel
1380    $xmlobj put ${sequence}.about.description $descr
1381    $xmlobj put ${sequence}.index.label "Frame"
1382
1383    set frameNum 0
1384    set frameContents ""
1385    set inModel 0
1386    foreach line $data {
1387        set line [string trim $line]
1388        if { $line == "" } {
1389            continue;                   # Skip blank lines
1390        }
1391        if {[regexp {^[\t ]*ITEM:[ \t]+ATOMS} $line] } {
1392            if { $inModel && $frameContents != "" } {
1393                set frame ${sequence}.element($frameNum)
1394                $xmlobj put ${frame}.index $frameNum
1395
1396                set molecule ${frame}.structure.components.molecule
1397                $xmlobj put ${molecule}.lammps $frameContents
1398                $xmlobj put ${molecule}.lammpstypemap $typemap
1399
1400                incr frameNum
1401                set frameContents ""
1402            }
1403            set inModel 1
1404        } elseif { [scan $line "%d %d %f %f %f" a b c d e] == 5 } {
1405            if { !$inModel } {
1406                puts stderr "found \"$line\" without previous \"ITEM: ATOMS\""
1407                set inModel 1
1408            }
1409            append frameContents $line\n
1410        }
1411    }
1412    if { $frameContents != "" } {
1413        set frame ${sequence}.element($frameNum)
1414        $xmlobj put ${frame}.index $frameNum
1415
1416        set molecule ${frame}.structure.components.molecule
1417        $xmlobj put ${molecule}.lammps $frameContents
1418        $xmlobj put ${molecule}.lammpstypemap $typemap
1419    }
1420}
1421
1422# ----------------------------------------------------------------------
1423# USAGE: _trajToSequence <xmlobj> ?<path>?
1424#
1425#       Check for PDB and LAMMPS trajectories in molecule data and rewrite
1426#       the individual models as a sequence of molecules.  Used internally
1427#       to detect any molecule output elements that contain trajectory data.
1428#       Trajectories will be converted into sequences of individual molecules.
1429#       All other elements will be unaffected. Scans the entire xml tree if a
1430#       starting path is not specified.
1431#
1432# ----------------------------------------------------------------------
1433itcl::body Rappture::Analyzer::_trajToSequence {xmlobj {path ""}} {
1434    # Remove leading dot from path, if present.
1435    if { [string index $path 0] == "." } {
1436        set path [string range $path 1 end]
1437    }
1438    # Otherwise check each child.
1439    foreach child [$xmlobj children $path] {
1440        set current ${path}.${child}
1441        if { [string match "structure*" $child] } {
1442            set isTraj [$xmlobj get ${current}.components.molecule.trajectory]
1443            if { $isTraj == "" || !$isTraj } {
1444                continue;               # Not a trajectory.
1445            }
1446            # Look for trajectory if molecule element found.  Check both pdb
1447            # data and lammps data.
1448            set type [$xmlobj element -as type $current]
1449            set id   [$xmlobj element -as id $current]
1450            set pdbdata    [$xmlobj get ${current}.components.molecule.pdb]
1451            set lammpsdata [$xmlobj get ${current}.components.molecule.lammps]
1452            if { $pdbdata != "" && $lammpsdata != "" } {
1453                puts stderr \
1454                    "found both <pdb> and <lammps> elements: picking pdb"
1455            }
1456            set pdbdata [split $pdbdata \n]
1457            set lammpsdata [split $lammpsdata \n]
1458            if { [_isPdbTrajectory $pdbdata] } {
1459                _pdbToSequence $xmlobj $path $id $current $pdbdata
1460            } elseif { [_isLammpsTrajectory $lammpsdata] } {
1461                _lammpsToSequence $xmlobj $path $id $current $lammpsdata
1462            }
1463            continue
1464        }
1465        if 0 {
1466        # Recurse over all child nodes.
1467        _trajToSequence $xmlobj $current
1468        }
1469    }
1470}
1471
1472# ----------------------------------------------------------------------
1473# CONFIGURATION OPTION: -simcontrol
1474#
1475# Controls whether or not the Simulate button is showing.  In some
1476# cases, it is not needed.
1477# ----------------------------------------------------------------------
1478itcl::configbody Rappture::Analyzer::simcontrol {
1479    _fixSimControl
1480}
1481
1482# ----------------------------------------------------------------------
1483# CONFIGURATION OPTION: -notebookpage
1484#
1485# Controls which page of the analyzer notebook is shown. It is
1486# particularly needed when using rerun, when you don't want to
1487# "simulate -ifneeded" because an actual simulation might be
1488# kicked off due to differences between tool.xml and run.xml
1489# ----------------------------------------------------------------------
1490itcl::configbody Rappture::Analyzer::notebookpage {
1491    _fixNotebook
1492}
Note: See TracBrowser for help on using the repository browser.