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

Last change on this file was 3959, checked in by gah, 11 years ago

sync with trunk

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