source: trunk/gui/apps/simsim.in @ 1210

Last change on this file since 1210 was 1210, checked in by dkearney, 16 years ago

minor parsing errors and comments for future version

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