source: trunk/gui/scripts/energyLevels.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: 16.7 KB
Line 
1# ----------------------------------------------------------------------
2#  COMPONENT: EnergyLevels - visualizer for discrete energy levels
3#
4#  This widget is a simple visualizer for a set of quantized energy
5#  levels, as you might find for a molecule or a quantum well.  It
6#  takes the Rappture XML representation for a <table> and extracts
7#  values from the "energy" column, then plots those energies on a
8#  graph.
9# ======================================================================
10#  AUTHOR:  Michael McLennan, Purdue University
11#  Copyright (c) 2004-2005
12#  Purdue Research Foundation, West Lafayette, IN
13# ======================================================================
14package require Itk
15package require BLT
16
17option add *EnergyLevels.width 4i widgetDefault
18option add *EnergyLevels.height 4i widgetDefault
19option add *EnergyLevels.levelColor blue widgetDefault
20option add *EnergyLevels.levelTextForeground blue widgetDefault
21option add *EnergyLevels.levelTextBackground #d9d9d9 widgetDefault
22
23option add *EnergyLevels.font \
24    -*-helvetica-medium-r-normal-*-*-120-* widgetDefault
25
26option add *EnergyLevels.detailFont \
27    -*-helvetica-medium-r-normal-*-*-100-* widgetDefault
28
29itcl::class Rappture::EnergyLevels {
30    inherit itk::Widget
31
32    itk_option define -layout layout Layout ""
33    itk_option define -output output Output ""
34    itk_option define -levelcolor levelColor LevelColor ""
35    itk_option define -leveltextforeground levelTextForeground Foreground ""
36    itk_option define -leveltextbackground levelTextBackground Background ""
37
38    constructor {args} { # defined below }
39    destructor { # defined below }
40
41    protected method _render {}
42    protected method _adjust {what val}
43    protected method _getColumn {name}
44    protected method _getUnits {name}
45    protected method _getMidPt {elist pos}
46}
47
48itk::usual EnergyLevels {
49}
50
51# ----------------------------------------------------------------------
52# CONSTRUCTOR
53# ----------------------------------------------------------------------
54itcl::body Rappture::EnergyLevels::constructor {args} {
55    itk_option add hull.width hull.height
56    pack propagate $itk_component(hull) no
57
58    #
59    # Add label for the title.
60    #
61    itk_component add title {
62        label $itk_interior.title
63    }
64    pack $itk_component(title) -side top
65
66
67    itk_component add cntls {
68        frame $itk_interior.cntls
69    }
70    pack $itk_component(cntls) -side right -fill y
71    grid rowconfigure $itk_component(cntls) 0 -weight 1
72    grid rowconfigure $itk_component(cntls) 1 -minsize 10
73    grid rowconfigure $itk_component(cntls) 2 -weight 1
74
75    #
76    # Add MORE/FEWER levels control for TOP of graph
77    #
78    itk_component add upperE {
79        frame $itk_component(cntls).upperE
80    }
81
82    itk_component add upperEmore {
83        label $itk_component(upperE).morel -text "More"
84    } {
85        usual
86        rename -font -detailfont detailFont Font
87    }
88    pack $itk_component(upperEmore) -side top
89
90    itk_component add upperEfewer {
91        label $itk_component(upperE).fewerl -text "Fewer"
92    } {
93        usual
94        rename -font -detailfont detailFont Font
95    }
96    pack $itk_component(upperEfewer) -side bottom
97
98    itk_component add upperEcntl {
99        scale $itk_component(upperE).cntl -orient vertical -showvalue 0 \
100            -command [itcl::code $this _adjust upper]
101    }
102    pack $itk_component(upperEcntl) -side top -fill y
103
104    #
105    # Add MORE/FEWER levels control for BOTTOM of graph
106    #
107    itk_component add lowerE {
108        frame $itk_component(cntls).lowerE
109    }
110
111    itk_component add lowerEmore {
112        label $itk_component(lowerE).morel -text "More"
113    } {
114        usual
115        rename -font -detailfont detailFont Font
116    }
117    pack $itk_component(lowerEmore) -side bottom
118
119    itk_component add lowerEfewer {
120        label $itk_component(lowerE).fewerl -text "Fewer"
121    } {
122        usual
123        rename -font -detailfont detailFont Font
124    }
125    pack $itk_component(lowerEfewer) -side top
126
127    itk_component add lowerEcntl {
128        scale $itk_component(lowerE).cntl -orient vertical -showvalue 0 \
129            -command [itcl::code $this _adjust lower]
130    }
131    pack $itk_component(lowerEcntl) -side top -fill y
132
133    #
134    # Add graph showing levels
135    #
136    itk_component add graph {
137        blt::graph $itk_interior.graph \
138            -highlightthickness 0 -plotpadx 0 -plotpady 0 \
139            -width 3i -height 3i
140    } {
141        keep -background -foreground -cursor -font
142    }
143    pack $itk_component(graph) -expand yes -fill both
144    $itk_component(graph) legend configure -hide yes
145
146    eval itk_initialize $args
147}
148
149# ----------------------------------------------------------------------
150# DESTRUCTOR
151# ----------------------------------------------------------------------
152itcl::body Rappture::EnergyLevels::destructor {} {
153}
154
155# ----------------------------------------------------------------------
156# USAGE: _render
157#
158# Used internally to load a list of energy levels from a <table> within
159# the -output XML object.  The -layout object indicates how information
160# should be extracted from the table.  The <layout> should have an
161# <energies> tag and perhaps a <labels> tag, which indicates the table
162# and the column within the table containing the energies.
163# ----------------------------------------------------------------------
164itcl::body Rappture::EnergyLevels::_render {} {
165    #
166    # Clear any information shown in the graph.
167    #
168    set graph $itk_component(graph)
169    eval $graph element delete [$graph element names]
170    eval $graph marker delete [$graph marker names]
171
172    #
173    # Plug in the title from the layout
174    #
175    set title ""
176    if {$itk_option(-layout) != ""} {
177        set title [$itk_option(-layout) get label]
178    }
179    if {"" != $title} {
180        pack $itk_component(title) -side top -before $graph
181        $itk_component(title) configure -text $title
182    } else {
183        pack forget $itk_component(title)
184    }
185
186    #
187    # Look through the layout and figure out what to extract
188    # from the table.
189    #
190    set elist [_getColumn energies]
191    if {[llength $elist] == 0} {
192        return
193    }
194    set units [_getUnits energies]
195
196    set llist [_getColumn names]
197    if {[llength $llist] == 0} {
198        # no labels? then invent some
199        set i 0
200        foreach name $elist {
201            lappend llist "E$i"
202            incr i
203        }
204    }
205
206    #
207    # Update the graph to show the current set of levels.
208    #
209    set n 0
210    set nlumo -1
211    set emax ""
212    set emin ""
213    set ehomo ""
214    set elumo ""
215    foreach eval $elist lval $llist {
216        if {$lval == "HOMO"} {
217            set ehomo $eval
218            set lval "HOMO = $eval $units"
219            set nlumo [expr {$n+1}]
220        } elseif {$lval == "LUMO" || $n == $nlumo} {
221            set elumo $eval
222            set lval "LUMO = $eval $units"
223        } else {
224            set lval ""
225        }
226
227        set elem "elem[incr n]"
228        $graph element create $elem \
229            -xdata {0 1} -ydata [list $eval $eval] \
230            -color $itk_option(-levelcolor) -symbol "" -linewidth 1
231
232        if {$lval != ""} {
233            $graph marker create text -coords [list 0.5 $eval] \
234                -text $lval -anchor c \
235                -foreground $itk_option(-leveltextforeground) \
236                -background $itk_option(-leveltextbackground)
237        }
238
239        if {$emax == ""} {
240            set emax $eval
241            set emin $eval
242        } else {
243            if {$eval > $emax} {set emax $eval}
244            if {$eval < $emin} {set emin $eval}
245        }
246    }
247    $graph xaxis configure -min 0 -max 1 -showticks off -linewidth 0
248    if {$units != ""} {
249        $graph yaxis configure -title "Energy ($units)"
250    } else {
251        $graph yaxis configure -title "Energy"
252    }
253
254    # bump the limits so they are big enough to show labels
255    set fnt $itk_option(-font)
256    set h [expr {0.5*([font metrics $fnt -linespace] + 5)}]
257    set emin [expr {$emin-($emax-$emin)*$h/150.0}]
258    set emax [expr {$emax+($emax-$emin)*$h/150.0}]
259    $graph yaxis configure -min $emin -max $emax
260
261    #
262    # If we found HOMO/LUMO levels, then add the band gap at
263    # that point.  Also, fix the controls for energy range.
264    #
265    if {$ehomo != "" && $elumo != ""} {
266        set id [$graph marker create line \
267            -coords [list 0.2 $elumo 0.2 $ehomo]]
268        $graph marker after $id
269
270        set egap [expr {$elumo-$ehomo}]
271        set emid [expr {0.5*($ehomo+$elumo)}]
272        $graph marker create text \
273            -coords [list 0.21 $emid] -background "" \
274            -text "Eg = [format %.2g $egap] $units" -anchor w
275
276        # fix the limits for the lower scale
277        set elim [_getMidPt $elist [expr {$nlumo-1}]]
278        if {"" != $elim} {
279            $itk_component(lowerEcntl) configure -from $elim -to $emin \
280                -resolution [expr {0.02*($elim-$emin)}]
281            grid $itk_component(lowerE) -row 2 -column 0 -sticky ns
282
283            set e0 [_getMidPt $elist [expr {$nlumo-3}]]
284            if {"" != $e0} {
285                $itk_component(lowerEcntl) set $e0
286            } else {
287                $itk_component(lowerEcntl) set $elim
288            }
289        } else {
290            grid forget $itk_component(lowerE)
291        }
292
293        # fix the limits for the upper scale
294        set elim [_getMidPt $elist [expr {$nlumo+1}]]
295        if {"" != $elim} {
296            $itk_component(upperEcntl) configure -from $emax -to $elim \
297                -resolution [expr {0.02*($emax-$elim)}]
298            grid $itk_component(upperE) -row 0 -column 0 -sticky ns
299
300            set e0 [_getMidPt $elist [expr {$nlumo+3}]]
301            if {"" != $e0} {
302                $itk_component(upperEcntl) set $e0
303            } else {
304                $itk_component(upperEcntl) set $elim
305            }
306        } else {
307            grid forget $itk_component(upperE)
308        }
309    } else {
310        grid forget $itk_component(upperE)
311        grid forget $itk_component(lowerE)
312    }
313}
314
315# ----------------------------------------------------------------------
316# USAGE: _adjust <what> <val>
317#
318# Used internally to adjust the upper/lower limits of the graph
319# as the user drags the slider from "More" to "Fewer".  Sets
320# the specified limit to the given value.
321# ----------------------------------------------------------------------
322itcl::body Rappture::EnergyLevels::_adjust {what val} {
323    switch -- $what {
324        upper {
325            $itk_component(graph) yaxis configure -max $val
326        }
327        lower {
328            $itk_component(graph) yaxis configure -min $val
329        }
330        default {
331            error "bad limit \"$what\": should be upper or lower"
332        }
333    }
334}
335
336# ----------------------------------------------------------------------
337# USAGE: _getColumn <name>
338#
339# Used internally to load a list of energy levels from a <table> within
340# the -output XML object.  The -layout object indicates how information
341# should be extracted from the table.  The <layout> should have an
342# <energies> tag and perhaps a <labels> tag, which indicates the table
343# and the column within the table containing the energies.
344# ----------------------------------------------------------------------
345itcl::body Rappture::EnergyLevels::_getColumn {name} {
346puts "_getColumn $name"
347    if {$itk_option(-output) == ""} {
348        return
349    }
350
351    #
352    # Figure out which column in which table contains the data.
353    # Then, find that table and extract the column.  Figure out
354    # the position of the column from the list of all column names.
355    #
356    if {$itk_option(-layout) != ""} {
357        set table [$itk_option(-layout) get $name.table]
358        set col [$itk_option(-layout) get $name.column]
359
360        set clist ""
361        foreach c [$itk_option(-output) children -type column $table] {
362            lappend clist [$itk_option(-output) get $table.$c.label]
363        }
364        set ipos [lsearch $clist $col]
365        if {$ipos < 0} {
366            return  ;# can't find data -- bail out!
367        }
368        set units [$itk_option(-output) get $table.column$ipos.units]
369        set path "$table.data"
370    } else {
371        set clist ""
372        foreach c [$itk_option(-output) children -type column] {
373            lappend clist [$itk_option(-output) get $c.units]
374        }
375        if {$name == "energies"} {
376            set units "eV"
377        } else {
378            set units ""
379        }
380        set ipos [lsearch -exact $clist $units]
381        if {$ipos < 0} {
382            return  ;# can't find data -- bail out!
383        }
384        set path "data"
385    }
386
387    set rlist ""
388    foreach line [split [$itk_option(-output) get $path] "\n"] {
389        if {"" != [string trim $line]} {
390            set val [lindex $line $ipos]
391
392            if {$units != ""} {
393                set val [Rappture::Units::convert $val \
394                    -context $units -to $units -units off]
395            }
396            lappend rlist $val
397        }
398    }
399    return $rlist
400}
401
402# ----------------------------------------------------------------------
403# USAGE: _getUnits <name>
404#
405# Used internally to extract the units from a <table> within the
406# -output XML object.  The -layout object indicates how information
407# should be extracted from the table.  The <layout> should have an
408# <energies> tag and perhaps a <labels> tag, which indicates the table
409# and the column within the table containing the units.
410# ----------------------------------------------------------------------
411itcl::body Rappture::EnergyLevels::_getUnits {name} {
412    if {$itk_option(-output) == ""} {
413        return
414    }
415
416    #
417    # Figure out which column in which table contains the data.
418    # Then, find that table and extract the column.  Figure out
419    # the position of the column from the list of all column names.
420    #
421    if {$itk_option(-layout) != ""} {
422        set table [$itk_option(-layout) get $name.table]
423        set col [$itk_option(-layout) get $name.column]
424
425        set clist ""
426        foreach c [$itk_option(-output) children -type column $table] {
427            lappend clist [$itk_option(-output) get $table.$c.label]
428        }
429        set ipos [lsearch $clist $col]
430        if {$ipos < 0} {
431            return  ;# can't find data -- bail out!
432        }
433        set units [$itk_option(-output) get $table.column$ipos.units]
434    } else {
435        if {$name == "energies"} {
436            set units "eV"
437        } else {
438            set units ""
439        }
440    }
441    return $units
442}
443
444# ----------------------------------------------------------------------
445# USAGE: _getMidPt <elist> <pos>
446#
447# Used internally to compute the midpoint between two energy levels
448# at <pos> and <pos-1> in the <elist>.  Returns a number representing
449# the mid-point (average value) or "" if the levels involved do
450# no exist in <elist>.
451# ----------------------------------------------------------------------
452itcl::body Rappture::EnergyLevels::_getMidPt {elist pos} {
453    if {$pos < [llength $elist] && $pos > 1} {
454        set e1 [lindex $elist $pos]
455        set e0 [lindex $elist [expr {$pos-1}]]
456        return [expr {0.5*($e0+$e1)}]
457    }
458    return ""
459}
460
461# ----------------------------------------------------------------------
462# OPTION: -layout
463# ----------------------------------------------------------------------
464itcl::configbody Rappture::EnergyLevels::layout {
465    if {$itk_option(-layout) != ""
466          && ![Rappture::library isvalid $itk_option(-layout)]} {
467        error "bad value \"$itk_option(-layout)\": should be Rappture::library object"
468    }
469    after idle [itcl::code $this _render]
470}
471
472# ----------------------------------------------------------------------
473# OPTION: -output
474# ----------------------------------------------------------------------
475itcl::configbody Rappture::EnergyLevels::output {
476    if {$itk_option(-output) != ""
477          && ![Rappture::library isvalid $itk_option(-output)]} {
478        error "bad value \"$itk_option(-output)\": should be Rappture::library object"
479    }
480    after cancel [itcl::code $this _render]
481    after idle [itcl::code $this _render]
482}
483
484# ----------------------------------------------------------------------
485# OPTION: -levelColor
486# ----------------------------------------------------------------------
487itcl::configbody Rappture::EnergyLevels::levelcolor {
488    after cancel [itcl::code $this _render]
489    after idle [itcl::code $this _render]
490}
491
492# ----------------------------------------------------------------------
493# OPTION: -leveltextforeground
494# ----------------------------------------------------------------------
495itcl::configbody Rappture::EnergyLevels::leveltextforeground {
496    after cancel [itcl::code $this _render]
497    after idle [itcl::code $this _render]
498}
499
500# ----------------------------------------------------------------------
501# OPTION: -leveltextbackground
502# ----------------------------------------------------------------------
503itcl::configbody Rappture::EnergyLevels::leveltextbackground {
504    after cancel [itcl::code $this _render]
505    after idle [itcl::code $this _render]
506}
Note: See TracBrowser for help on using the repository browser.