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

Last change on this file since 4045 was 3647, checked in by gah, 11 years ago

add string trim to inputs

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