source: trunk/gui/scripts/analyzer.tcl @ 11

Last change on this file since 11 was 11, checked in by mmc, 16 years ago

Major reorganization of the entire package. The config.xml file
is now irrelevant. All the action is in the tool.xml file. The
main program now organizes all input into 1) side-by-side pages,
2) input/result (wizard-style) pages, or 3) a series of wizard-
style pages. The <input> can have <phase> parts representing
the various pages.

Added a new ContourResult? widget based on Swaroop's vtk plotting
code.

Also, added easymesh and showmesh to the "tools" directory.
We need these for Eric Polizzi's code.

File size: 25.0 KB
Line 
1# ----------------------------------------------------------------------
2#  COMPONENT: analyzer - output area for Rappture
3#
4#  This widget acts as the output side of a Rappture application.
5#  When the input has changed, it displays a Simulate button that
6#  launches the simulation.  When a simulation is running, this
7#  area shows status.  When it is finished, the results appear
8#  in place of the button, according to the specs in the <analyze>
9#  XML data.
10# ======================================================================
11#  AUTHOR:  Michael McLennan, Purdue University
12#  Copyright (c) 2004-2005
13#  Purdue Research Foundation, West Lafayette, IN
14# ======================================================================
15package require Itk
16
17option add *Analyzer.width 5i widgetDefault
18option add *Analyzer.height 5i widgetDefault
19option add *Analyzer.simControl "auto" widgetDefault
20option add *Analyzer.simControlBackground "" widgetDefault
21option add *Analyzer.simControlOutline gray widgetDefault
22option add *Analyzer.simControlActiveBackground #ffffcc widgetDefault
23option add *Analyzer.simControlActiveOutline black widgetDefault
24
25option add *Analyzer.font \
26    -*-helvetica-medium-r-normal-*-*-120-* widgetDefault
27option add *Analyzer.textFont \
28    -*-helvetica-medium-r-normal-*-*-120-* widgetDefault
29option add *Analyzer.boldTextFont \
30    -*-helvetica-bold-r-normal-*-*-120-* widgetDefault
31
32itcl::class Rappture::Analyzer {
33    inherit itk::Widget
34
35    itk_option define -textfont textFont Font ""
36    itk_option define -boldtextfont boldTextFont Font ""
37    itk_option define -simcontrol simControl SimControl ""
38    itk_option define -simcontroloutline simControlOutline Background ""
39    itk_option define -simcontrolbackground simControlBackground Background ""
40    itk_option define -simcontrolactiveoutline simControlActiveOutline Background ""
41    itk_option define -simcontrolactivebackground simControlActiveBackground Background ""
42    itk_option define -holdwindow holdWindow HoldWindow ""
43
44    constructor {tool args} { # defined below }
45    destructor { # defined below }
46
47    public method simulate {args}
48    public method reset {}
49    public method load {file}
50    public method clear {}
51
52    protected method _plot {args}
53    protected method _reorder {comps}
54    protected method _autoLabel {xmlobj path title cntVar}
55    protected method _fixResult {}
56    protected method _fixSize {}
57    protected method _fixSimControl {}
58    protected method _simState {state args}
59
60    private variable _tool ""          ;# belongs to this tool
61    private variable _control "manual" ;# start mode
62    private variable _runs ""          ;# list of XML objects with results
63    private variable _pages 0          ;# number of pages for result sets
64    private variable _label2page       ;# maps output label => result set
65    private variable _plotlist ""      ;# items currently being plotted
66
67    private common job                 ;# array var used for blt::bgexec jobs
68}
69                                                                               
70itk::usual Analyzer {
71    keep -background -cursor foreground -font
72}
73
74# ----------------------------------------------------------------------
75# CONSTRUCTOR
76# ----------------------------------------------------------------------
77itcl::body Rappture::Analyzer::constructor {tool args} {
78    set _tool $tool
79
80    itk_option add hull.width hull.height
81    pack propagate $itk_component(hull) no
82
83    frame $itk_interior.simol -borderwidth 1 -relief flat
84    pack $itk_interior.simol -fill x
85
86    frame $itk_interior.simol.simbg -borderwidth 0
87    pack $itk_interior.simol.simbg -expand yes -fill both
88
89    itk_component add simulate {
90        button $itk_interior.simol.simbg.simulate -text "Simulate" \
91            -command [itcl::code $this simulate]
92    }
93    pack $itk_component(simulate) -side left -padx 4 -pady 4
94
95    itk_component add simstatus {
96        text $itk_interior.simol.simbg.simstatus -borderwidth 0 \
97            -highlightthickness 0 -height 1 -width 1 -wrap none \
98            -state disabled
99    } {
100        usual
101        ignore -highlightthickness
102        rename -font -textfont textFont Font
103    }
104    pack $itk_component(simstatus) -side left -expand yes -fill x
105
106    $itk_component(simstatus) tag configure popup \
107        -underline 1 -foreground blue
108
109    $itk_component(simstatus) tag bind popup \
110        <Enter> {%W configure -cursor center_ptr}
111    $itk_component(simstatus) tag bind popup \
112        <Leave> {%W configure -cursor ""}
113    $itk_component(simstatus) tag bind popup \
114        <ButtonPress> {after idle {Rappture::Tooltip::tooltip show %W}}
115
116
117    itk_component add notebook {
118        Rappture::Notebook $itk_interior.nb
119    }
120    pack $itk_interior.nb -expand yes -fill both
121
122    # ------------------------------------------------------------------
123    # ABOUT PAGE
124    # ------------------------------------------------------------------
125    set w [$itk_component(notebook) insert end about]
126
127    Rappture::Scroller $w.info -xscrollmode off -yscrollmode auto
128    pack $w.info -expand yes -fill both -padx 4 -pady 20
129    itk_component add toolinfo {
130        text $w.info.text -width 1 -height 1 -wrap word \
131            -borderwidth 0 -highlightthickness 0
132    } {
133        usual
134        ignore -borderwidth -relief
135        rename -font -textfont textFont Font
136    }
137    $w.info contents $w.info.text
138
139    # ------------------------------------------------------------------
140    # SIMULATION PAGE
141    # ------------------------------------------------------------------
142    set w [$itk_component(notebook) insert end simulate]
143    frame $w.cntls
144    pack $w.cntls -side bottom -fill x -pady 12
145    frame $w.cntls.sep -background black -height 1
146    pack $w.cntls.sep -side top -fill x
147
148    itk_component add abort {
149        button $w.cntls.abort -text "Abort" \
150            -command [itcl::code $_tool abort]
151    }
152    pack $itk_component(abort) -side left -expand yes -padx 4 -pady 4
153
154    Rappture::Scroller $w.info -xscrollmode off -yscrollmode auto
155    pack $w.info -expand yes -fill both -padx 4 -pady 4
156    itk_component add runinfo {
157        text $w.info.text -width 1 -height 1 -wrap word \
158            -borderwidth 0 -highlightthickness 0 \
159            -state disabled
160    } {
161        usual
162        ignore -borderwidth -relief
163        rename -font -textfont textFont Font
164    }
165    $w.info contents $w.info.text
166
167    # ------------------------------------------------------------------
168    # ANALYZE PAGE
169    # ------------------------------------------------------------------
170    set w [$itk_component(notebook) insert end analyze]
171
172    frame $w.top
173    pack $w.top -side top -fill x -pady 8
174    label $w.top.l -text "Result:" -font $itk_option(-font)
175    pack $w.top.l -side left
176
177    itk_component add resultselector {
178        Rappture::Combobox $w.top.sel -width 50 -editable no
179    } {
180        usual
181        rename -font -textfont textFont Font
182    }
183    pack $itk_component(resultselector) -side left -expand yes -fill x
184    bind $itk_component(resultselector) <<Value>> [itcl::code $this _fixResult]
185
186    itk_component add results {
187        Rappture::Panes $w.pane
188    }
189    pack $itk_component(results) -expand yes -fill both
190    set f [$itk_component(results) pane 0]
191
192    itk_component add resultpages {
193        Rappture::Notebook $f.nb
194    }
195    pack $itk_component(resultpages) -expand yes -fill both
196
197    set f [$itk_component(results) insert end -fraction 0.1]
198    itk_component add resultset {
199        Rappture::ResultSet $f.rset \
200            -clearcommand [itcl::code $this clear] \
201            -settingscommand [itcl::code $this _plot] \
202            -promptcommand [itcl::code $this _simState]
203    }
204    pack $itk_component(resultset) -expand yes -fill both
205    bind $itk_component(resultset) <<Control>> [itcl::code $this _fixSize]
206
207    eval itk_initialize $args
208
209    #
210    # Load up tool info on the first page.
211    #
212    $itk_component(toolinfo) tag configure title \
213        -font $itk_option(-boldtextfont)
214
215    set mesg [$tool xml get tool.title]
216    if {"" != $mesg} {
217        $itk_component(toolinfo) insert end $mesg title
218        $itk_component(toolinfo) insert end "\n\n"
219    }
220
221    set mesg [$tool xml get tool.about]
222    if {"" != $mesg} {
223        $itk_component(toolinfo) insert end $mesg
224    }
225    $itk_component(toolinfo) configure -state disabled
226    $itk_component(notebook) current about
227
228    # reset everything to a clean state
229    reset
230
231    # tool can run on "manual" (default) or "auto"
232    set cntl [$tool xml get tool.control]
233    if {"" != $cntl} {
234        set _control $cntl
235    }
236}
237
238# ----------------------------------------------------------------------
239# DESTRUCTOR
240# ----------------------------------------------------------------------
241itcl::body Rappture::Analyzer::destructor {} {
242    foreach obj $_runs {
243        itcl::delete object $obj
244    }
245    after cancel [itcl::code $this simulate]
246}
247
248# ----------------------------------------------------------------------
249# USAGE: simulate ?-ifneeded?
250# USAGE: simulate ?<path1> <value1> <path2> <value2> ...?
251#
252# Kicks off the simulator by executing the tool.command associated
253# with the tool.  If any arguments are specified, they are used to
254# set parameters for the simulation.  While the simulation is running,
255# it shows status.  When the simulation is finished, it switches
256# automatically to "analyze" mode and shows the results.
257# ----------------------------------------------------------------------
258itcl::body Rappture::Analyzer::simulate {args} {
259    if {$args == "-ifneeded"} {
260        # check to see if simulation is really needed
261        $_tool sync
262        if {[$itk_component(resultset) contains [$_tool xml object]]} {
263            # not needed -- show results and return
264            $itk_component(notebook) current analyze
265            return
266        }
267        set args ""
268    }
269
270    # simulation is needed -- go to simulation page
271    $itk_component(notebook) current simulate
272
273    _simState off
274    $itk_component(runinfo) configure -state normal
275    $itk_component(runinfo) delete 1.0 end
276    $itk_component(runinfo) insert end "Running simulation..."
277    $itk_component(runinfo) configure -state disabled
278
279    # if the hold window is set, then put up a busy cursor
280    if {$itk_option(-holdwindow) != ""} {
281        blt::busy hold $itk_option(-holdwindow)
282        raise $itk_component(hull)
283        update
284    }
285
286    # execute the job
287    foreach {status result} [eval $_tool run $args] break
288
289    # if job was aborted, then allow simulation again
290    if {$result == "ABORT"} {
291        _simState on "Aborted"
292    }
293
294    # read back the results from run.xml
295    if {$status == 0 && $result != "ABORT"} {
296        if {[regexp {=RAPPTURE-RUN=>([^\n]+)} $result match file]} {
297            set status [catch {load $file} msg]
298            if {$status != 0} {
299                set result $msg
300            }
301        } else {
302            set status 1
303            set result "Can't find result file in output:\n\n$result"
304        }
305    }
306
307    # back to normal
308    if {$itk_option(-holdwindow) != ""} {
309        blt::busy release $itk_option(-holdwindow)
310    }
311    $itk_component(abort) configure -state disabled
312
313    if {$status != 0} {
314        $itk_component(runinfo) configure -state normal
315        $itk_component(runinfo) delete 1.0 end
316        $itk_component(runinfo) insert end "Problem launching job:\n\n"
317        $itk_component(runinfo) insert end $result
318        $itk_component(runinfo) configure -state disabled
319    } else {
320        $itk_component(notebook) current analyze
321    }
322}
323
324# ----------------------------------------------------------------------
325# USAGE: reset
326#
327# Used to reset the analyzer whenever the input to a simulation has
328# changed.  Sets the mode back to "simulate", so the user has to
329# simulate again to see the output.  If the <start> option is set
330# to "auto", the simulation is invoked immediately.
331# ----------------------------------------------------------------------
332itcl::body Rappture::Analyzer::reset {} {
333    # check to see if simulation is really needed
334    $_tool sync
335    if {![$itk_component(resultset) contains [$_tool xml object]]} {
336        # if control mode is "auto", then simulate right away
337        if {[string match auto* $_control]} {
338            # auto control -- don't need button
339            pack forget $itk_interior.simol
340
341            after cancel [itcl::code $this simulate]
342            after idle [itcl::code $this simulate]
343        } else {
344            _simState on "new input parameters"
345        }
346    } else {
347        _simState off
348    }
349}
350
351# ----------------------------------------------------------------------
352# USAGE: load <file>
353#
354# Loads the data from the given <file> into the appropriate results
355# sets.  If necessary, new results sets are created to store the data.
356# ----------------------------------------------------------------------
357itcl::body Rappture::Analyzer::load {file} {
358    # try to load new results from the given file
359    set xmlobj [Rappture::library $file]
360    lappend _runs $xmlobj
361
362    # go through the analysis and find all result sets
363    set haveresults 0
364    foreach item [_reorder [$xmlobj children output]] {
365        switch -glob -- $item {
366            log* {
367                _autoLabel $xmlobj output.$item "Output Log" counters
368            }
369            curve* - field* {
370                _autoLabel $xmlobj output.$item "Plot" counters
371            }
372            table* {
373                _autoLabel $xmlobj output.$item "Energy Levels" counters
374            }
375        }
376        set label [$xmlobj get output.$item.about.label]
377
378        if {"" != $label} {
379            set haveresults 1
380        }
381    }
382
383    # if there are any valid results, add them to the resultset
384    if {$haveresults} {
385        set size [$itk_component(resultset) size]
386        set op [$itk_component(resultset) add $xmlobj]
387
388        # add each result to a result viewer
389        foreach item [_reorder [$xmlobj children output]] {
390            set label [$xmlobj get output.$item.about.label]
391
392            if {"" != $label} {
393                if {![info exists _label2page($label)]} {
394                    set name "page[incr _pages]"
395                    set page [$itk_component(resultpages) insert end $name]
396                    set _label2page($label) $page
397                    Rappture::ResultViewer $page.rviewer
398                    pack $page.rviewer -expand yes -fill both -pady 4
399
400                    $itk_component(resultselector) choices insert end \
401                        $name $label
402
403                    #
404                    # NOTE:
405                    #
406                    # If this result is showing up late in the game, then
407                    # we must fill the resultviewer with a series of blank
408                    # entries, so the latest result will align with (have
409                    # the same index as) results in all other viewers.
410                    #
411                    for {set i 0} {$i < $size} {incr i} {
412                        $page.rviewer add $xmlobj ""
413                    }
414                }
415
416                # add/replace the latest result into this viewer
417                set page $_label2page($label)
418                eval $page.rviewer $op [list $xmlobj output.$item]
419            }
420        }
421    }
422
423    # if there is only one result page, take down the selector
424    set w [$itk_component(notebook) page analyze]
425    if {[$itk_component(resultselector) choices size] <= 1} {
426        pack forget $w.top
427    } else {
428        pack $w.top -before $itk_component(results) -side top -fill x
429    }
430
431    # show the first page by default
432    set first [$itk_component(resultselector) choices get -label 0]
433    if {$first != ""} {
434        $itk_component(resultpages) current page1
435        $itk_component(resultselector) value $first
436    }
437}
438
439# ----------------------------------------------------------------------
440# USAGE: clear
441#
442# Discards all results previously loaded into the analyzer.
443# ----------------------------------------------------------------------
444itcl::body Rappture::Analyzer::clear {} {
445    foreach obj $_runs {
446        itcl::delete object $obj
447    }
448    set _runs ""
449
450    foreach label [array names _label2page] {
451        set page $_label2page($label)
452        $page.rviewer clear
453    }
454
455    $itk_component(resultset) clear
456    $itk_component(results) fraction end 0.1
457
458    _simState on
459    _fixSimControl
460}
461
462# ----------------------------------------------------------------------
463# USAGE: _plot ?<index> <options> <index> <options>...?
464#
465# Used internally to update the plot shown in the current result
466# viewer whenever the resultset settings have changed.  Causes the
467# desired results to show up on screen.
468# ----------------------------------------------------------------------
469itcl::body Rappture::Analyzer::_plot {args} {
470    set _plotlist $args
471
472    set page [$itk_component(resultselector) value]
473    set page [$itk_component(resultselector) translate $page]
474    set f [$itk_component(resultpages) page $page]
475    $f.rviewer plot clear
476    foreach {index opts} $_plotlist {
477        $f.rviewer plot add $index $opts
478    }
479}
480
481# ----------------------------------------------------------------------
482# USAGE: _reorder
483#
484# Used internally to change the order of a series of output components
485# found in the <output> section.  Moves the <log> elements to the end
486# and returns the updated list.
487# ----------------------------------------------------------------------
488itcl::body Rappture::Analyzer::_reorder {comps} {
489    set i 0
490    set max [llength $comps]
491    while {$i < $max} {
492        set c [lindex $comps $i]
493        if {[string match log* $c]} {
494            set comps [lreplace $comps $i $i]
495            lappend comps $c
496            incr max -1
497        } else {
498            incr i
499        }
500    }
501    return $comps
502}
503
504# ----------------------------------------------------------------------
505# USAGE: _autoLabel <xmlobj> <path> <title> <cntVar>
506#
507# Used internally to check for an about.label property at the <path>
508# in <xmlobj>.  If this object doesn't have a label, then one is
509# supplied using the given <title>.  The <cntVar> is an array of
510# counters in the calling scopes for titles that have been used
511# in the past.  This is used to create titles like "Plot #2" the
512# second time it is encountered.
513#
514# The <xmlobj> is updated so that the label is inserted directly in
515# the tree.
516# ----------------------------------------------------------------------
517itcl::body Rappture::Analyzer::_autoLabel {xmlobj path title cntVar} {
518    upvar $cntVar counters
519
520    set label [$xmlobj get $path.about.label]
521    if {"" == $label} {
522        # no label -- make one up using the title specified
523        if {![info exists counters($title)]} {
524            set counters($title) 1
525            set label $title
526        } else {
527            set label "$title #[incr counters($title)]"
528        }
529        $xmlobj put $path.about.label $label
530    } else {
531        # handle the case of two identical labels in <output>
532        if {![info exists counters($label)]} {
533            set counters($label) 1
534        } else {
535            set label "$label #[incr counters($label)]"
536            $xmlobj put $path.about.label $label
537        }
538    }
539    return $label
540}
541
542# ----------------------------------------------------------------------
543# USAGE: _fixResult
544#
545# Used internally to change the result page being displayed whenever
546# the user selects a page from the results combobox.
547# ----------------------------------------------------------------------
548itcl::body Rappture::Analyzer::_fixResult {} {
549    set page [$itk_component(resultselector) value]
550    set page [$itk_component(resultselector) translate $page]
551    $itk_component(resultpages) current $page
552
553    set f [$itk_component(resultpages) page $page]
554    $f.rviewer plot clear
555    eval $f.rviewer plot add $_plotlist
556}
557
558# ----------------------------------------------------------------------
559# USAGE: _fixSize
560#
561# Used internally to change the size of the result set area whenever
562# a new control appears.  Adjusts the size available for the result
563# set up to some maximum.
564# ----------------------------------------------------------------------
565itcl::body Rappture::Analyzer::_fixSize {} {
566    set f [$itk_component(results) fraction end]
567    if {$f < 0.4} {
568        $itk_component(results) fraction end [expr {$f+0.15}]
569    }
570    _fixSimControl
571}
572
573# ----------------------------------------------------------------------
574# USAGE: _simState <boolean> ?<message>? ?<settings>?
575#
576# Used internally to change the "Simulation" button on or off.
577# If the <boolean> is on, then any <message> and <settings> are
578# displayed as well.  The <message> is a note to the user about
579# what will be simulated, and the <settings> are a list of
580# tool parameter settings of the form {path1 val1 path2 val2 ...}.
581# When these are in place, the next Simulate operation will use
582# these settings.  This helps fill in missing data values.
583# ----------------------------------------------------------------------
584itcl::body Rappture::Analyzer::_simState {state args} {
585    if {$state} {
586        $itk_interior.simol configure \
587            -background $itk_option(-simcontrolactiveoutline)
588        $itk_interior.simol.simbg configure \
589            -background $itk_option(-simcontrolactivebackground)
590        $itk_component(simulate) configure \
591            -highlightbackground $itk_option(-simcontrolactivebackground)
592        $itk_component(simstatus) configure \
593            -background $itk_option(-simcontrolactivebackground)
594
595        $itk_component(abort) configure -state disabled
596        $itk_component(simulate) configure -state normal \
597            -command [itcl::code $this simulate]
598
599        #
600        # If there's a special message, then put it up next to the button.
601        #
602        set mesg [lindex $args 0]
603        if {"" != $mesg} {
604            $itk_component(simstatus) configure -state normal
605            $itk_component(simstatus) delete 1.0 end
606            $itk_component(simstatus) insert end $mesg
607
608            #
609            # If there are any settings, then install them in the
610            # "Simulate" button.  Also, pop them up as a tooltip
611            # for the message.
612            #
613            set settings [lindex $args 1]
614            if {[llength $settings] > 0} {
615                $itk_component(simulate) configure \
616                    -command [eval itcl::code $this simulate $settings]
617
618                set details ""
619                foreach {path val} $settings {
620                    set str [$_tool xml get $path.about.label]
621                    if {"" == $str} {
622                        set str [$_tool xml element -as id $path]
623                    }
624                    append details "$str = $val\n"
625                }
626                set details [string trim $details]
627
628                Rappture::Tooltip::for $itk_component(simstatus) $details
629                $itk_component(simstatus) insert end " "
630                $itk_component(simstatus) insert end "(details...)" popup
631            }
632            $itk_component(simstatus) configure -state disabled
633        }
634    } else {
635        if {"" != $itk_option(-simcontrolbackground)} {
636            set simcbg $itk_option(-simcontrolbackground)
637        } else {
638            set simcbg $itk_option(-background)
639        }
640        $itk_interior.simol configure \
641            -background $itk_option(-simcontroloutline)
642        $itk_interior.simol.simbg configure -background $simcbg
643        $itk_component(simulate) configure -highlightbackground $simcbg
644        $itk_component(simstatus) configure -background $simcbg
645
646        $itk_component(simulate) configure -state disabled
647        $itk_component(abort) configure -state normal
648
649        $itk_component(simstatus) configure -state normal
650        $itk_component(simstatus) delete 1.0 end
651        $itk_component(simstatus) configure -state disabled
652        Rappture::Tooltip::for $itk_component(simstatus) ""
653    }
654}
655
656# ----------------------------------------------------------------------
657# USAGE: _fixSimControl
658#
659# Used internally to add or remove the simulation control at the
660# top of the analysis area.  This is controlled by the -simcontrol
661# option.
662# ----------------------------------------------------------------------
663itcl::body Rappture::Analyzer::_fixSimControl {} {
664    switch -- $itk_option(-simcontrol) {
665        on {
666            pack $itk_interior.simol -fill x -before $itk_interior.nb
667        }
668        off {
669            pack forget $itk_interior.simol
670        }
671        auto {
672            #
673            # If we have two or more radiodials, then there is a
674            # chance of encountering a combination of parameters
675            # with no data, requiring simulation.
676            #
677            if {[$itk_component(resultset) size -controls] >= 2} {
678                pack $itk_interior.simol -fill x -before $itk_interior.nb
679            } else {
680                pack forget $itk_interior.simol
681            }
682        }
683        default {
684            error "bad value \"$itk_option(-simcontrol)\": should be on, off, auto"
685        }
686    }
687}
688
689# ----------------------------------------------------------------------
690# CONFIGURATION OPTION: -simcontrol
691#
692# Controls whether or not the Simulate button is showing.  In some
693# cases, it is not needed.
694# ----------------------------------------------------------------------
695itcl::configbody Rappture::Analyzer::simcontrol {
696    _fixSimControl
697}
Note: See TracBrowser for help on using the repository browser.