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

Last change on this file since 5885 was 5885, checked in by gah, 9 years ago

fixes from martin for uq results

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