source: branches/blt4/gui/apps/simsim.in @ 1897

Last change on this file since 1897 was 1897, checked in by gah, 12 years ago

re-merge with latest trunk changes

  • Property svn:executable set to *
File size: 23.6 KB
Line 
1#!/bin/sh
2# ======================================================================
3#  AUTHOR:  Derrick S. Kearney, Purdue University
4#  Copyright (c) 2004-2008  Purdue Research Foundation
5#
6#  See the file "license.terms" for information on usage and
7#  redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES.
8# ======================================================================
9#\
10. rappture.env \
11exec wish "$0" $*
12
13package require Rappture
14package require RapptureGUI
15
16proc defaultHandler {child} {
17    set childchildList {}
18    set units [$child get "units"]
19    # this is for nanowire
20    if {[string is integer -strict $units]} {
21        set units ""
22    }
23    set defaultVal [$child get "default"]
24    if {"" != $defaultVal} {
25        if {"" != $units} {
26            set defaultVal [Rappture::Units::convert $defaultVal \
27                            -context $units -to $units -units on]
28        }
29        $child put "current" $defaultVal
30    } else {
31        if {"components" != [$child element -as type]} {
32            set childchildList [$child children]
33        } elseif {"parameters" != [$child element -as type]} {
34            set childchildList [$child children]
35        } else {
36            set childchildList [$child children]
37        }
38    }
39    return $childchildList
40}
41
42proc numberHandler {child} {
43    set value ""
44    set units [$child get "units"]
45    set min [$child get "min"]
46    set max [$child get "max"]
47
48    if {"" != $min} {
49        if {"" != $units} {
50            # check to see if the user added units to their min value
51            # apps like mosfet need this check.
52            set min [Rappture::Units::convert $min \
53                        -context $units -to $units -units off]
54            if {[string is double -strict $min]} {
55                # pass
56            }
57        }
58    }
59
60    if {"" != $max} {
61        if {"" != $units} {
62            # check to see if the user added units to their min value
63            # apps like mosfet need this check.
64            set max [Rappture::Units::convert $max \
65                        -context $units -to $units -units off]
66            if {[string is double -strict $max]} {
67                # pass
68            }
69        }
70    }
71
72    if {"yes" == [$child get "simset"]} {
73        $child remove "simset"
74    } else {
75        if { ("" != $min) && ("" != $max) } {
76            set value [random $min $max]
77            $child put current $value$units
78        } else {
79            defaultHandler $child
80        }
81    }
82}
83
84proc integerHandler {child} {
85    set value ""
86    set units [$child get "units"]
87    set min [$child get "min"]
88    set max [$child get "max"]
89
90    # nanowire needs this because they set units == 0 and 1 ???
91    if {[string is integer -strict $units]} {
92        set units ""
93    }
94
95    if {"" != $min} {
96        if {"" != $units} {
97            # check to see if the user added units to their min value
98            # apps like mosfet need this check.
99            set min [Rappture::Units::convert $min \
100                        -context $units -to $units -units off]
101            if {[string is integer -strict $min]} {
102                # pass
103            }
104        }
105    }
106
107    if {"" != $max} {
108        if {"" != $units} {
109            # check to see if the user added units to their min value
110            # apps like mosfet need this check.
111            set max [Rappture::Units::convert $max \
112                        -context $units -to $units -units off]
113            if {[string is integer -strict $max]} {
114                # pass
115            }
116        }
117    }
118
119    if {"yes" == [$child get "simset"]} {
120        $child remove "simset"
121    } else {
122        if { ("" != $min) && ("" != $max) } {
123            set value [randomInt $min $max]
124            $child put current $value$units
125        } else {
126            defaultHandler $child
127        }
128    }
129
130}
131
132proc booleanHandler {child} {
133    if {"yes" == [$child get "simset"]} {
134        $child remove "simset"
135    } else {
136        set value [expr {int(rand()*2)}]
137        if {$value == 1} {
138            set value "yes"
139        } else {
140            set value "no"
141        }
142        $child put "current" $value
143    }
144}
145
146proc loaderHandler {child toolDir} {
147
148    set exDir [file join $toolDir "examples"]
149    if {! [file isdirectory $exDir]} {
150        # in this case we should try to keep processing, not exit
151        puts "could not find examples directory: $exDir"
152        exit 0
153    }
154
155    set exPathExp [$child get example]
156    set fpath [file join $exDir $exPathExp]
157    set exFileList [glob -nocomplain $fpath]
158
159    if {0 == [llength $exFileList]} {
160        puts "while searching examples directory: $exDir"
161        puts "could not open find files matching regex: $exPathExp"
162        set defaultEx [$child get "default"]
163        if {[file exists [file join $exDir $defaultEx]]} {
164            lappend exFileList $defaultEx
165            puts "using default example file"
166        } else {
167            puts "default example file does not exists, exiting"
168            exit 0;
169        }
170    }
171
172    set importExFileIdx [expr {int(rand()*[llength $exFileList])}]
173    set importExFile [lindex $exFileList $importExFileIdx]
174
175    if {! [file exists $importExFile]} {
176        # importExFile does not exist
177    }
178
179    set exlib [Rappture::library $importExFile]
180
181    # get the about.label from the file
182    # if about.label does not exist, use the file name
183    set importExLabel [$exlib get about.label]
184    if {"" != $importExLabel} {
185        set currentVal $importExLabel
186    } else {
187        set currentVal [file tail $importExFile]
188    }
189
190    $child put "current" $currentVal
191
192    set exlibChildList [::Rappture::entities -as object $exlib "input"]
193    return $exlibChildList
194}
195
196proc groupHandler {child} {
197    return [$child children -as object]
198}
199
200proc choiceHandler {valType child} {
201    if {"yes" == [$child get "simset"]} {
202        $child remove "simset"
203    } else {
204        set optList [$child children -as object -type option]
205        set optLib ""
206        set value ""
207        if {[llength $optList] > 0} {
208            if {"random" == $valType} {
209                set optIdx [expr {int(rand()*[llength $optList])}]
210                set optLib [lindex $optList $optIdx]
211                set value [$optLib get value]
212            } elseif {"default" == $valType} {
213                set defaultVal [$child get default]
214                foreach optLib $optList {
215                    set label [$optLib get about.label]
216                    set valTag [$optLib get value]
217                    if {($defaultVal == $label) || ($defaultVal == $valTag)} {
218                        set value $valTag
219                        break
220                    }
221                }
222            }
223
224            if {"" == $value} {
225                set optLib [lindex $optList 0]
226                set value [$optLib get value]
227                if {"" == $value} {
228                    set value [$optLib get about.label]
229                }
230            }
231        }
232        $child put "current" $value
233    }
234}
235
236proc defaultize {xmlobj toolDir} {
237    set childList [$xmlobj children -as object input]
238
239    while {[llength $childList]} {
240        set child [lrange $childList 0 0]
241        set childList [lreplace $childList 0 0]
242
243        switch -- [$child element -as type] {
244            number      { defaultHandler $child }
245            integer     { defaultHandler $child }
246            boolean     { defaultHandler $child }
247            string      { defaultHandler $child }
248            choice      { choiceHandler default $child }
249            loader      { loaderHandler  $child $toolDir }
250            structure   { defaultHandler $child }
251            group       { set cclist [groupHandler $child]
252                          set childList [concat $childList $cclist] }
253            phase       { set cclist [groupHandler $child]
254                          set childList [concat $childList $cclist] }
255            default     { defaultHandler $child }
256        }
257    }
258}
259
260proc randomize {presetArr xmlobj toolDir} {
261    upvar $presetArr presets
262    set childList [$xmlobj children -as object input]
263
264    while {[llength $childList]} {
265
266        set child [lrange $childList 0 0]
267        set childList [lreplace $childList 0 0]
268
269        set cpath [cleanPath [$child element -as path]]
270
271        set ppath [$child parent -as path]
272        set cPresets [array get presets $cpath*]
273
274        foreach {cPresetsPath cPresetsVal} $cPresets {
275            set cutIdx [expr {[string length $cpath] + 1}]
276            set iPath [string range $cPresetsPath $cutIdx end]
277
278            # apply the preset value and remove from preset array
279            $child put $iPath $cPresetsVal
280            unset presets($cPresetsPath)
281
282            # if the value was set on a current node, then set a preset flag
283            if {"current" == $iPath} {
284                $child put simset "yes"
285            }
286        }
287
288        switch -- [$child element -as type] {
289            number    { numberHandler  $child }
290            integer   { integerHandler $child }
291            boolean   { booleanHandler $child }
292            string    { defaultHandler $child }
293            choice    { choiceHandler random  $child }
294            loader    {
295                set cpath [$child element -as path]
296                set ccList [loaderHandler $child $toolDir]
297                foreach cc $ccList {
298                    set ccpath [$cc element -as path]
299                    # even though the loader might have been returned in ccList
300                    # do not add the loader back to the childList or you might
301                    # get an infinite loop
302                    if {$cpath != $ccpath} {
303                        set ccpath [cleanPath $ccpath]
304                        $xmlobj copy $ccpath from $cc ""
305                        lappend childList [$xmlobj element -as object $ccpath]
306                    }
307                }
308            }
309            structure { defaultHandler $child }
310            group     {
311                set ccList [groupHandler $child]
312                set childList [concat $childList $ccList]
313            }
314            phase     {
315                set ccList [groupHandler $child]
316                set childList [concat $childList $ccList]
317            }
318            default   { defaultHandler $child }
319        }
320    }
321}
322
323proc random {m M} {
324    return [expr {$m+(rand()*($M-$m))}]
325}
326
327proc randomInt {m M} {
328    return [expr {int(rand()*($M-$m+1)+$m)}]
329}
330
331proc cleanPath { path } {
332    if {"." == [string index $path 0]} {
333        # this is because tcl's library module (element -as path)
334        # returns a crazy dot in the 0th position
335        set path [string range $path 1 end]
336    }
337    return $path
338}
339
340proc parsePathVal {listVar returnVar} {
341    upvar $listVar params
342    upvar $returnVar presetArr
343    catch {unset presetArr}
344
345    # initialize variables
346    set pathValStr ""
347    set match "junk"
348
349    while {"" != $match} {
350        set match ""
351        set path ""
352        set val ""
353        set val2 ""
354        set val3 ""
355        set val4 ""
356        set pathValStr [string trimleft [join $params " "]]
357
358        # search the params for:
359        # 1) xml path
360        # 2) followed by = sign
361        # 3) followed by a starting " sign
362        # 4) followed by any text (including spaces)
363        # 5) followed by an ending " sign
364        # ex: input.number(temperature).current="400K"
365        # ex: input.number(temperature).current=400K
366        # ex: input.string(blahh).current="hi momma, i love you!"
367        #    \"([^\"]+)\"
368        #    ((\"([^\"]+)\")|(:([^:]+):)|(\'([^\']+)\')|([^\s]+))
369        regexp -expanded {
370            (
371                [a-zA-Z0-9]+(\([a-zA-Z0-9._]+\))?
372                (\.[a-zA-Z0-9]+(\([a-zA-Z0-9._]+\))?)*
373            )
374            =
375            ((\"([^\"]+)\")|(\'([^\']+)\')|([^\s]+))
376        } $pathValStr match path junk junk junk val junk val2 junk val3 val4
377
378
379        if {"" != $match} {
380            # remove the matching element from orphaned params list
381            foreach p [split $match] {
382                set paramsIdx [lsearch -exact $params $p]
383                set params [lreplace $params $paramsIdx $paramsIdx]
384            }
385
386            if {("" != $val2) && ("" == $val3) && ("" == $val4)} {
387                set val $val2
388            } elseif {("" == $val2) && ("" != $val3) && ("" == $val4)} {
389                set val $val3
390            } elseif {("" == $val2) && ("" == $val3) && ("" != $val4)} {
391                set val $val4
392            }
393
394            # add the name and value to our preset array
395            set presetArr($path) $val
396        }
397    }
398}
399
400proc printHelp {} {
401    set help {
402simsim [OPTIONS] [CONST]
403
404simulator simulator - simulate simulation
405
406OPTIONS:
407 -tool <path>        - use the tool.xml file specified at <path>
408 -values <valtype>   - the type of values used to populate driver file.
409                       valid <valtype>'s include:
410                       "default" - replace <current> values with <default>'s,
411                       "current" - use <current> values (ie do nothing),
412                       "random" - generate random values for <current>.
413 -driver <path>      - write a driver file to <path>.
414 -compare <path>     - compare the results with the run.xml
415                       file at <path>.
416 -nosim              - no simulation.
417 -help               - print this help menu.
418
419CONST:
420 when -values is set to random, constant values can be set for
421 specific inputs. the general form for constant values is:
422
423   xmlpath(id)=value
424
425 where xmlpath is the path of the element in the xml tree,
426 id is the id of the xml node and value is the constant value
427 you want to place in the element. the following the constant
428 will set input.number(Ef).current to the value "2eV":
429
430   input.number(Ef)=2eV
431
432EXAMPLES:
433simulate using ./tool.xml, default values, no comparisons or driver
434    simsim
435
436simulate using ./tool.xml, random values, no comparisons or driver
437    simsim -values random
438
439from ./tool.xml, create a driver file named "mydriverfile.xml"
440with default values
441    simsim -nosim -driver mydriverfile.xml
442
443from ./tool.xml, create a driver file named "mydriverfile.xml"
444with random values
445    simsim -values random -nosim -driver mydriverfile.xml
446
447from ./tool.xml, simulate with random values but set
448input.number(Ef) to "2eV"
449    simsim -values random input.number(Ef).current=2eV
450
451run a simulation using the current values from driver.xml,
452"-values current" is only useful if you are asking
453simsim to run the simulation and you provide a driver file.
454    simsim -tool driver.xml -values current
455
456compare two xml file, don't do a simulation, don't print a driver.xml
457    simsim -tool driver.xml -compare previousrun.xml -nosim
458
459run a simulation and compare the result to previousrun.xml
460    simsim -compare previousrun.xml
461
462}
463    puts $help
464    exit 0
465}
466
467proc diffs {xmlobj1 xmlobj2} {
468    set rlist ""
469
470    # query the values for all entities in both objects
471    set thisv [concat [Rappture::entities $xmlobj1 "input"] [Rappture::entities $xmlobj1 "output"]]
472    set otherv [concat [Rappture::entities $xmlobj2 "input"] [Rappture::entities $xmlobj2 "output"]]
473
474    # scan through values for this object and compare against other one
475    foreach path $thisv {
476        set i [lsearch -exact $otherv $path]
477        if {$i < 0} {
478            foreach {raw norm} [value $xmlobj1 $path] break
479            lappend rlist - $path $raw ""
480        } else {
481            foreach {traw tnorm} [value $xmlobj1 $path] break
482            foreach {oraw onorm} [value $xmlobj2 $path] break
483            if {![string equal $tnorm $onorm]} {
484                lappend rlist c $path $traw $oraw
485            }
486            set otherv [lreplace $otherv $i $i]
487        }
488    }
489
490    #add any values left over in the other object
491    foreach path $otherv {
492        foreach {oraw onorm} [Rappture::LibraryObj::value $xmlobj2 $path] break
493        lappend rlist + $path "" $oraw
494    }
495    return $rlist
496}
497
498proc value {libobj path} {
499    switch -- [$libobj element -as type $path] {
500        structure {
501            set raw $path
502            # try to find a label to represent the structure
503            set val [$libobj get $path.about.label]
504            if {"" == $val} {
505                set val [$libobj get $path.current.about.label]
506            }
507            if {"" == $val} {
508                if {[$libobj element $path.current] != ""} {
509                    set comps [$libobj children $path.current.components]
510                    set val "<structure> with [llength $comps] components"
511                } else {
512                    set val "<structure>"
513                }
514            }
515            return [list $raw $val]
516        }
517        number {
518            # get the usual value...
519            set raw ""
520            if {"" != [$libobj element $path.current]} {
521                set raw [$libobj get $path.current]
522            } elseif {"" != [$libobj element $path.default]} {
523                set raw [$libobj get $path.default]
524            }
525            if {"" != $raw} {
526                set val $raw
527                # then normalize to default units
528                set units [$libobj get $path.units]
529                if {"" != $units} {
530                    set val [Rappture::Units::convert $val \
531                        -context $units -to $units -units off]
532                }
533            }
534            return [list $raw $val]
535        }
536        curve {
537            set raw ""
538            if {"" != [$libobj element $path.component.xy]} {
539                set raw [$libobj get $path.component.xy]
540            }
541            return [list $raw $raw]
542        }
543        log {
544            set raw ""
545            if {"" != [$libobj element]} {
546                set raw [$libobj get]
547            }
548            return [list $raw $raw]
549        }
550        cloud {
551            set raw ""
552            if {"" != [$libobj element $path.points]} {
553                set raw [$libobj get $path.points]
554            }
555            return [list $raw $raw]
556        }
557        field {
558            set raw ""
559            if {"" != [$libobj element $path.component.values]} {
560                set raw [$libobj get $path.component.values]
561            }
562            return [list $raw $raw]
563        }
564
565
566    }
567
568    # for all other types, get the value (current, or maybe default)
569    set raw ""
570    if {"" != [$libobj element $path.current]} {
571        set raw [$libobj get $path.current]
572    } elseif {"" != [$libobj element $path.default]} {
573        set raw [$libobj get $path.default]
574    }
575    return [list $raw $raw]
576}
577
578proc compare {orig result} {
579    if {"" == $orig} {
580        return
581    }
582    if {"" == $result} {
583        return
584    }
585
586    if {![Rappture::library isvalid $orig]} {
587        set origObj [Rappture::library $orig]
588        if {![Rappture::library isvalid $origObj]} {
589            puts "cannot create Rappture library from $orig\n"
590            return
591        }
592    } else {
593        set origObj $orig
594    }
595
596    if {![Rappture::library isvalid $result]} {
597        set resultObj [Rappture::library $result]
598        if {![Rappture::library isvalid $resultObj]} {
599            puts "cannot create Rappture library from $result\n"
600            return
601        }
602    } else {
603        set resultObj $result
604    }
605
606    foreach {op vpath oldval newval} [diffs $origObj $resultObj] {
607        puts "$op $vpath $oldval $newval"
608    }
609}
610
611proc parseOptions {listVar returnVar} {
612    upvar $listVar argv
613    upvar $returnVar params
614
615    # parse command line arguments
616    set argc [llength $argv]
617    for {set i 0} {$i < $argc} {incr i} {
618        set opt [lindex $argv $i]
619        if {("-t" == $opt) || ("-tool" == $opt) || ("--tool" == $opt)} {
620            if {[expr {$i + 1}] < $argc} {
621                incr i
622                set params(--tool) [lindex $argv $i]
623                # need to check to see if file exists, if not raise error
624            } else {
625                printHelp
626            }
627        } elseif {  ("-d" == $opt)      ||
628                    ("-driver" == $opt) ||
629                    ("--driver" == $opt)    } {
630            if {[expr {$i + 1}] < $argc} {
631                incr i
632                set params(--driver) [lindex $argv $i]
633                # need to check to see if file exists, if not raise error
634            } else {
635                printHelp
636            }
637        } elseif {  ("-v" == $opt)      ||
638                    ("-values" == $opt) ||
639                    ("--values" == $opt)    } {
640            if {[expr {$i + 1}] < $argc} {
641                incr i
642                set valuesFlag [lindex $argv $i]
643                if {("default" == $valuesFlag) ||
644                    ("current" == $valuesFlag) ||
645                    ("random" == $valuesFlag)  } {
646                    set params(--values) $valuesFlag
647                } else {
648                    printHelp
649                }
650            } else {
651                printHelp
652            }
653        } elseif {  ("-c" == $opt)      ||
654                    ("-compare" == $opt)||
655                    ("--compare" == $opt)   } {
656            if {[expr {$i + 1}] < $argc} {
657                incr i
658                set params(--compare) [lindex $argv $i]
659                # need to check to see if file exists, if not raise error
660            } else {
661                printHelp
662            }
663        } elseif {  ("-n" == $opt)      ||
664                    ("-nosim" == $opt)  ||
665                    ("--nosim" == $opt)     } {
666            set params(--nosim) true
667        } elseif {  ("-h" == $opt)      ||
668                    ("-help" == $opt)   ||
669                    ("--help" == $opt)      } {
670            printHelp
671        } else {
672            # place all extra params in the params array
673            lappend params(oParams) $opt
674        }
675    }
676}
677
678proc main {argv} {
679    # set default values
680    array set presets []
681    set i 0
682
683    array set params {
684        --compare ""
685        --values default
686        --nosim false
687        --driver ""
688        --tool "./tool.xml"
689        oParams {}
690    }
691
692    parseOptions argv params
693
694    # keep the wish window from popping up
695    wm withdraw .
696
697    # parse out path=val combinations from the list of orphaned parameters
698    parsePathVal params(oParams) presets
699    if {0 != [llength $params(oParams)]} {
700        puts "Could not understand the following parameters"
701        puts "params(oParams) = $params(oParams)"
702        puts "length params(oParams) = [llength $params(oParams)]"
703    }
704
705    set err ""
706    if {! [file exists $params(--tool)]} {
707        append err "\ntool file \""
708        append err $params(--tool)
709        append err "\" does not exist, use -t option\n"
710        puts $err
711        printHelp
712    }
713
714    set xmlobj [Rappture::library $params(--tool)]
715    set installdir [file dirname $params(--tool)]
716
717    # need a better way to do this,
718    # maybe just take xmldiff functionality out of simsim
719    if {(!$params(--nosim)) || ("" != $params(--driver))} {
720        switch -- $params(--values) {
721            random      { randomize presets $xmlobj $installdir }
722            current     { }
723            default     { defaultize $xmlobj $installdir }
724        }
725    }
726
727    if {"" != $params(--driver)} {
728        set fid [open $params(--driver) w]
729        puts $fid {<?xml version="1.0"?>}
730        puts $fid [$xmlobj xml]
731        close $fid
732    }
733
734    if {$params(--nosim)} {
735        if {"" != $params(--compare)} {
736            compare $xmlobj $params(--compare)
737        }
738        exit 0
739    }
740
741    set tool [Rappture::Tool ::#auto $xmlobj $installdir]
742
743    # read the run.xml file.
744    # from analyzer.tcl:
745
746    set result ""
747    # execute the job
748    foreach {status result} [eval $tool run] break
749
750    # read back the result from run.xml
751    if {$status == 0 && $result != "ABORT"} {
752        if {[Rappture::library isvalid $result]} {
753            # do comparison if user chose to compare with other results
754            if {"" != $params(--compare)} {
755                compare $params(--compare) $result
756            }
757        } else {
758            set status 1
759            puts "Can't find result file in output.\nDid you call Rappture::result in your simulator?"
760        }
761    } else {
762        puts $result
763    }
764}
765
766main $argv
767exit 0
Note: See TracBrowser for help on using the repository browser.