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

Last change on this file since 2170 was 2170, checked in by gah, 11 years ago
  • Property svn:executable set to *
File size: 24.3 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#\
10dir=`dirname $0` ; \
11. $dir/rappture.env ; \
12exec $dir/tclsh "$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 {valType child} {
202    if {"yes" == [$child get "simset"]} {
203        $child remove "simset"
204    } else {
205        set optList [$child children -as object -type option]
206        set optLib ""
207        set value ""
208        if {[llength $optList] > 0} {
209            if {"random" == $valType} {
210                set optIdx [expr {int(rand()*[llength $optList])}]
211                set optLib [lindex $optList $optIdx]
212                set value [$optLib get value]
213            } elseif {"default" == $valType} {
214                set defaultVal [$child get default]
215                foreach optLib $optList {
216                    set label [$optLib get about.label]
217                    set valTag [$optLib get value]
218                    if {($defaultVal == $label) || ($defaultVal == $valTag)} {
219                        set value $valTag
220                        break
221                    }
222                }
223            }
224
225            if {"" == $value} {
226                set optLib [lindex $optList 0]
227                set value [$optLib get value]
228                if {"" == $value} {
229                    set value [$optLib get about.label]
230                }
231            }
232        }
233        $child put "current" $value
234    }
235}
236
237proc defaultize {xmlobj toolDir} {
238    set childList [$xmlobj children -as object input]
239
240    while {[llength $childList]} {
241        set child [lrange $childList 0 0]
242        set childList [lreplace $childList 0 0]
243
244        switch -- [$child element -as type] {
245            number      { defaultHandler $child }
246            integer     { defaultHandler $child }
247            boolean     { defaultHandler $child }
248            string      { defaultHandler $child }
249            choice      { choiceHandler default $child }
250            loader      { loaderHandler  $child $toolDir }
251            structure   { defaultHandler $child }
252            group       { set cclist [groupHandler $child]
253                          set childList [concat $childList $cclist] }
254            phase       { set cclist [groupHandler $child]
255                          set childList [concat $childList $cclist] }
256            default     { defaultHandler $child }
257        }
258    }
259}
260
261proc randomize {presetArr xmlobj toolDir} {
262    upvar $presetArr presets
263    set childList [$xmlobj children -as object input]
264
265    while {[llength $childList]} {
266
267        set child [lrange $childList 0 0]
268        set childList [lreplace $childList 0 0]
269
270        set cpath [cleanPath [$child element -as path]]
271
272        set ppath [$child parent -as path]
273        set cPresets [array get presets $cpath*]
274
275        foreach {cPresetsPath cPresetsVal} $cPresets {
276            set cutIdx [expr {[string length $cpath] + 1}]
277            set iPath [string range $cPresetsPath $cutIdx end]
278
279            # apply the preset value and remove from preset array
280            $child put $iPath $cPresetsVal
281            unset presets($cPresetsPath)
282
283            # if the value was set on a current node, then set a preset flag
284            if {"current" == $iPath} {
285                $child put simset "yes"
286            }
287        }
288
289        switch -- [$child element -as type] {
290            number    { numberHandler  $child }
291            integer   { integerHandler $child }
292            boolean   { booleanHandler $child }
293            string    { defaultHandler $child }
294            choice    { choiceHandler random  $child }
295            loader    {
296                set cpath [$child element -as path]
297                set ccList [loaderHandler $child $toolDir]
298                foreach cc $ccList {
299                    set ccpath [$cc element -as path]
300                    # even though the loader might have been returned in ccList
301                    # do not add the loader back to the childList or you might
302                    # get an infinite loop
303                    if {$cpath != $ccpath} {
304                        set ccpath [cleanPath $ccpath]
305                        $xmlobj copy $ccpath from $cc ""
306                        lappend childList [$xmlobj element -as object $ccpath]
307                    }
308                }
309            }
310            structure { defaultHandler $child }
311            group     {
312                set ccList [groupHandler $child]
313                set childList [concat $childList $ccList]
314            }
315            phase     {
316                set ccList [groupHandler $child]
317                set childList [concat $childList $ccList]
318            }
319            default   { defaultHandler $child }
320        }
321    }
322}
323
324proc random {m M} {
325    return [expr {$m+(rand()*($M-$m))}]
326}
327
328proc randomInt {m M} {
329    return [expr {int(rand()*($M-$m+1)+$m)}]
330}
331
332proc cleanPath { path } {
333    if {"." == [string index $path 0]} {
334        # this is because tcl's library module (element -as path)
335        # returns a crazy dot in the 0th position
336        set path [string range $path 1 end]
337    }
338    return $path
339}
340
341proc parsePathVal {listVar returnVar} {
342    upvar $listVar params
343    upvar $returnVar presetArr
344    catch {unset presetArr}
345
346    # initialize variables
347    set pathValStr ""
348    set match "junk"
349
350    while {"" != $match} {
351        set match ""
352        set path ""
353        set val ""
354        set val2 ""
355        set val3 ""
356        set val4 ""
357        set pathValStr [string trimleft [join $params " "]]
358
359        # search the params for:
360        # 1) xml path
361        # 2) followed by = sign
362        # 3) followed by a starting " sign
363        # 4) followed by any text (including spaces)
364        # 5) followed by an ending " sign
365        # ex: input.number(temperature).current="400K"
366        # ex: input.number(temperature).current=400K
367        # ex: input.string(blahh).current="hi momma, i love you!"
368        #    \"([^\"]+)\"
369        #    ((\"([^\"]+)\")|(:([^:]+):)|(\'([^\']+)\')|([^\s]+))
370        regexp -expanded {
371            (
372                [a-zA-Z0-9]+(\([a-zA-Z0-9._]+\))?
373                (\.[a-zA-Z0-9]+(\([a-zA-Z0-9._]+\))?)*
374            )
375            =
376            ((\"([^\"]+)\")|(\'([^\']+)\')|([^\s]+))
377        } $pathValStr match path junk junk junk val junk val2 junk val3 val4
378
379
380        if {"" != $match} {
381            # remove the matching element from orphaned params list
382            foreach p [split $match] {
383                set paramsIdx [lsearch -exact $params $p]
384                set params [lreplace $params $paramsIdx $paramsIdx]
385            }
386
387            if {("" != $val2) && ("" == $val3) && ("" == $val4)} {
388                set val $val2
389            } elseif {("" == $val2) && ("" != $val3) && ("" == $val4)} {
390                set val $val3
391            } elseif {("" == $val2) && ("" == $val3) && ("" != $val4)} {
392                set val $val4
393            }
394
395            # add the name and value to our preset array
396            set presetArr($path) $val
397        }
398    }
399}
400
401proc printHelp {} {
402    set help {
403simsim [OPTIONS] [CONST]
404
405simulator simulator - simulate simulation
406
407OPTIONS:
408 -tool <path>        - use the tool.xml file specified at <path>
409 -values <valtype>   - the type of values used to populate driver file.
410                       valid <valtype>'s include:
411                       "default" - replace <current> values with <default>'s,
412                       "current" - use <current> values (ie do nothing),
413                       "random" - generate random values for <current>.
414 -driver <path>      - write a driver file to <path>.
415 -compare <path>     - compare the results with the run.xml
416                       file at <path>.
417 -runfile <path>     - move the run file to <path>
418 -nosim              - no simulation.
419 -help               - print this help menu.
420
421CONST:
422 when -values is set to random, constant values can be set for
423 specific inputs. the general form for constant values is:
424
425   xmlpath(id)=value
426
427 where xmlpath is the path of the element in the xml tree,
428 id is the id of the xml node and value is the constant value
429 you want to place in the element. the following the constant
430 will set input.number(Ef).current to the value "2eV":
431
432   input.number(Ef)=2eV
433
434EXAMPLES:
435simulate using ./tool.xml, default values, no comparisons or driver
436    simsim
437
438simulate using ./tool.xml, random values, no comparisons or driver
439    simsim -values random
440
441from ./tool.xml, create a driver file named "mydriverfile.xml"
442with default values
443    simsim -nosim -driver mydriverfile.xml
444
445from ./tool.xml, create a driver file named "mydriverfile.xml"
446with random values
447    simsim -values random -nosim -driver mydriverfile.xml
448
449from ./tool.xml, simulate with random values but set
450input.number(Ef) to "2eV"
451    simsim -values random input.number(Ef).current=2eV
452
453run a simulation using the current values from driver.xml,
454"-values current" is only useful if you are asking
455simsim to run the simulation and you provide a driver file.
456    simsim -tool driver.xml -values current
457
458compare two xml file, don't do a simulation, don't print a driver.xml
459    simsim -tool driver.xml -compare previousrun.xml -nosim
460
461run a simulation and compare the result to previousrun.xml
462    simsim -compare previousrun.xml
463
464}
465    puts $help
466    exit 0
467}
468
469proc diffs {xmlobj1 xmlobj2} {
470    set rlist ""
471
472    # query the values for all entities in both objects
473    set thisv [concat [Rappture::entities $xmlobj1 "input"] [Rappture::entities $xmlobj1 "output"]]
474    set otherv [concat [Rappture::entities $xmlobj2 "input"] [Rappture::entities $xmlobj2 "output"]]
475
476    # scan through values for this object and compare against other one
477    foreach path $thisv {
478        set i [lsearch -exact $otherv $path]
479        if {$i < 0} {
480            foreach {raw norm} [value $xmlobj1 $path] break
481            lappend rlist - $path $raw ""
482        } else {
483            foreach {traw tnorm} [value $xmlobj1 $path] break
484            foreach {oraw onorm} [value $xmlobj2 $path] break
485            if {![string equal $tnorm $onorm]} {
486                lappend rlist c $path $traw $oraw
487            }
488            set otherv [lreplace $otherv $i $i]
489        }
490    }
491
492    #add any values left over in the other object
493    foreach path $otherv {
494        foreach {oraw onorm} [Rappture::LibraryObj::value $xmlobj2 $path] break
495        lappend rlist + $path "" $oraw
496    }
497    return $rlist
498}
499
500proc value {libobj path} {
501    switch -- [$libobj element -as type $path] {
502        structure {
503            set raw $path
504            # try to find a label to represent the structure
505            set val [$libobj get $path.about.label]
506            if {"" == $val} {
507                set val [$libobj get $path.current.about.label]
508            }
509            if {"" == $val} {
510                if {[$libobj element $path.current] != ""} {
511                    set comps [$libobj children $path.current.components]
512                    set val "<structure> with [llength $comps] components"
513                } else {
514                    set val "<structure>"
515                }
516            }
517            return [list $raw $val]
518        }
519        number {
520            # get the usual value...
521            set raw ""
522            if {"" != [$libobj element $path.current]} {
523                set raw [$libobj get $path.current]
524            } elseif {"" != [$libobj element $path.default]} {
525                set raw [$libobj get $path.default]
526            }
527            if {"" != $raw} {
528                set val $raw
529                # then normalize to default units
530                set units [$libobj get $path.units]
531                if {"" != $units} {
532                    set val [Rappture::Units::convert $val \
533                        -context $units -to $units -units off]
534                }
535            }
536            return [list $raw $val]
537        }
538        curve {
539            set raw ""
540            if {"" != [$libobj element $path.component.xy]} {
541                set raw [$libobj get $path.component.xy]
542            }
543            return [list $raw $raw]
544        }
545        log {
546            set raw ""
547            if {"" != [$libobj element]} {
548                set raw [$libobj get]
549            }
550            return [list $raw $raw]
551        }
552        cloud {
553            set raw ""
554            if {"" != [$libobj element $path.points]} {
555                set raw [$libobj get $path.points]
556            }
557            return [list $raw $raw]
558        }
559        field {
560            set raw ""
561            if {"" != [$libobj element $path.component.values]} {
562                set raw [$libobj get $path.component.values]
563            }
564            return [list $raw $raw]
565        }
566
567
568    }
569
570    # for all other types, get the value (current, or maybe default)
571    set raw ""
572    if {"" != [$libobj element $path.current]} {
573        set raw [$libobj get $path.current]
574    } elseif {"" != [$libobj element $path.default]} {
575        set raw [$libobj get $path.default]
576    }
577    return [list $raw $raw]
578}
579
580proc compare {orig result} {
581    if {"" == $orig} {
582        return
583    }
584    if {"" == $result} {
585        return
586    }
587
588    if {![Rappture::library isvalid $orig]} {
589        set origObj [Rappture::library $orig]
590        if {![Rappture::library isvalid $origObj]} {
591            puts "cannot create Rappture library from $orig\n"
592            return
593        }
594    } else {
595        set origObj $orig
596    }
597
598    if {![Rappture::library isvalid $result]} {
599        set resultObj [Rappture::library $result]
600        if {![Rappture::library isvalid $resultObj]} {
601            puts "cannot create Rappture library from $result\n"
602            return
603        }
604    } else {
605        set resultObj $result
606    }
607
608    foreach {op vpath oldval newval} [diffs $origObj $resultObj] {
609        puts "$op $vpath $oldval $newval"
610    }
611}
612
613proc parseOptions {listVar returnVar} {
614    upvar $listVar argv
615    upvar $returnVar params
616
617    # parse command line arguments
618    set argc [llength $argv]
619    for {set i 0} {$i < $argc} {incr i} {
620        set opt [lindex $argv $i]
621        if {("-t" == $opt) || ("-tool" == $opt) || ("--tool" == $opt)} {
622            if {[expr {$i + 1}] < $argc} {
623                incr i
624                set params(--tool) [lindex $argv $i]
625                # need to check to see if file exists, if not raise error
626            } else {
627                printHelp
628            }
629        } elseif {  ("-d" == $opt)      ||
630                    ("-driver" == $opt) ||
631                    ("--driver" == $opt)    } {
632            if {[expr {$i + 1}] < $argc} {
633                incr i
634                set params(--driver) [lindex $argv $i]
635                # need to check to see if file exists, if not raise error
636            } else {
637                printHelp
638            }
639        } elseif {  ("-r" == $opt)      ||
640                    ("-runfile" == $opt) ||
641                    ("--runfile" == $opt)    } {
642            if {[expr {$i + 1}] < $argc} {
643                incr i
644                set params(--runfile) [lindex $argv $i]
645            } else {
646                printHelp
647            }
648        } elseif {  ("-v" == $opt)      ||
649                    ("-values" == $opt) ||
650                    ("--values" == $opt)    } {
651            if {[expr {$i + 1}] < $argc} {
652                incr i
653                set valuesFlag [lindex $argv $i]
654                if {("default" == $valuesFlag) ||
655                    ("current" == $valuesFlag) ||
656                    ("random" == $valuesFlag)  } {
657                    set params(--values) $valuesFlag
658                } else {
659                    printHelp
660                }
661            } else {
662                printHelp
663            }
664        } elseif {  ("-c" == $opt)      ||
665                    ("-compare" == $opt)||
666                    ("--compare" == $opt)   } {
667            if {[expr {$i + 1}] < $argc} {
668                incr i
669                set params(--compare) [lindex $argv $i]
670                # need to check to see if file exists, if not raise error
671            } else {
672                printHelp
673            }
674        } elseif {  ("-n" == $opt)      ||
675                    ("-nosim" == $opt)  ||
676                    ("--nosim" == $opt)     } {
677            set params(--nosim) true
678        } elseif {  ("-h" == $opt)      ||
679                    ("-help" == $opt)   ||
680                    ("--help" == $opt)      } {
681            printHelp
682        } else {
683            # place all extra params in the params array
684            lappend params(oParams) $opt
685        }
686    }
687}
688
689proc main {argv} {
690    # set default values
691    array set presets []
692    set i 0
693
694    array set params {
695        --compare ""
696        --values default
697        --nosim false
698        --driver ""
699        --runfile ""
700        --tool "./tool.xml"
701        oParams {}
702    }
703
704    parseOptions argv params
705
706    # parse out path=val combinations from the list of orphaned parameters
707    parsePathVal params(oParams) presets
708    if {0 != [llength $params(oParams)]} {
709        puts "Could not understand the following parameters"
710        puts "params(oParams) = $params(oParams)"
711        puts "length params(oParams) = [llength $params(oParams)]"
712    }
713
714    set err ""
715    if {! [file exists $params(--tool)]} {
716        append err "\ntool file \""
717        append err $params(--tool)
718        append err "\" does not exist, use -t option\n"
719        puts $err
720        printHelp
721    }
722
723    set xmlobj [Rappture::library $params(--tool)]
724    set installdir [file dirname $params(--tool)]
725
726    # need a better way to do this,
727    # maybe just take xmldiff functionality out of simsim
728    if {(!$params(--nosim)) || ("" != $params(--driver))} {
729        switch -- $params(--values) {
730            random      { randomize presets $xmlobj $installdir }
731            current     { }
732            default     { defaultize $xmlobj $installdir }
733        }
734    }
735
736    if {"" != $params(--driver)} {
737        set fid [open $params(--driver) w]
738        puts $fid {<?xml version="1.0"?>}
739        puts $fid [$xmlobj xml]
740        close $fid
741    }
742
743    if {$params(--nosim)} {
744        if {"" != $params(--compare)} {
745            compare $xmlobj $params(--compare)
746        }
747        exit 0
748    }
749
750
751
752
753    set tool [Rappture::Tool ::#auto $xmlobj $installdir]
754
755    # read the run.xml file.
756    # from analyzer.tcl:
757
758    set result ""
759    # execute the job
760    foreach {status result} [eval $tool run] break
761
762    if {[string compare "" $params(--runfile)] != 0} {
763        set runfilename [$tool getRunFile]
764        set err [catch {file rename $runfilename $params(--runfile)} out]
765        if {$err} {
766            puts stderr $out
767        }
768    }
769
770    # if run was successful, check to see if we should compare
771    if {$status == 0 && $result != "ABORT"} {
772        if {[Rappture::library isvalid $result]} {
773            # do comparison if user chose to compare with other results
774            if {"" != $params(--compare)} {
775                compare $params(--compare) $result
776            }
777        } else {
778            set status 1
779            puts "Can't find result file in output.\nDid you call Rappture::result in your simulator?"
780        }
781    } else {
782        puts $result
783    }
784}
785
786main $argv
787exit 0
Note: See TracBrowser for help on using the repository browser.