Ignore:
Timestamp:
Feb 18, 2016, 4:13:14 PM (9 years ago)
Author:
ldelgass
Message:

Merge UQ and fixes from 1.4 branch

Location:
trunk
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk

  • trunk/lang/tcl/scripts/units.tcl

    r3362 r6021  
     1# -*- mode: tcl; indent-tabs-mode: nil -*-
    12# ----------------------------------------------------------------------
    23#  COMPONENT: units - mechanism for converting numbers with units
     
    6061}
    6162
     63
     64# ----------------------------------------------------------------------
     65# USAGE: mcheck_range value {min ""} {max ""}
     66#
     67# Checks a value or PDF to determine if is is in a required range.
     68# Automatically does unit conversion if necessary.
     69# Returns value if OK.  Error if out-of-range
     70# Examples:
     71#    [mcheck_range "gaussian 0C 1C" 200K 500K] returns 1
     72#    [mcheck_range "uniform 100 200" 150 250] returns 0
     73#    [mcheck_range 100 0 200] returns 1
     74# ----------------------------------------------------------------------
     75
     76proc Rappture::Units::_check_range {value min max units} {
     77    # puts "_check_range $value min=$min max=$max units=$units"
     78    # make sure the value has units
     79    if {$units != ""} {
     80        set value [Rappture::Units::convert $value -context $units]
     81        # for comparisons, remove units
     82        set nv [Rappture::Units::convert $value -context $units -units off]
     83        # get the units for the value
     84        set newunits [Rappture::Units::Search::for $value]
     85    } else {
     86        set nv $value
     87    }
     88
     89    if {"" != $min} {
     90        if {"" != $units} {
     91            # compute the minimum in the new units
     92            set minv [Rappture::Units::convert $min -to $newunits -context $units  -units off]
     93            # same, but include units for printing
     94            set convMinVal [Rappture::Units::convert $min -to $newunits -context $units]
     95        } else {
     96            set minv $min
     97            set convMinVal $min
     98        }
     99        if {$nv < $minv} {
     100            error "Minimum value allowed here is $convMinVal"
     101        }
     102    }
     103    if {"" != $max} {
     104        if {"" != $units} {
     105            # compute the maximum in the new units
     106            set maxv [Rappture::Units::convert $max -to $newunits -context $units -units off]
     107            # same, but include units for printing
     108            set convMaxVal [Rappture::Units::convert $max -to $newunits -context $units ]
     109        } else {
     110            set maxv $max
     111            set convMaxVal $max
     112        }
     113        if {$nv > $maxv} {
     114            error "Maximum value allowed here is $convMaxVal"
     115        }
     116    }
     117    return $value
     118}
     119
     120proc Rappture::Units::mcheck_range {value {min ""} {max ""} {units ""}} {
     121    # puts "mcheck_range $value min=$min max=$max units=$units"
     122
     123    switch -- [lindex $value 0] {
     124        normal - gaussian {
     125            # get the mean
     126            set mean [_check_range [lindex $value 1] $min $max $units]
     127            if {$units == ""} {
     128                set dev [lindex $value 2]
     129                set ndev $dev
     130            } else {
     131                set dev [Rappture::Units::convert [lindex $value 2] -context $units]
     132                set ndev [Rappture::Units::convert $dev -units off]
     133            }
     134            if {$ndev <= 0} {
     135                error "Deviation must be positive."
     136            }
     137            return [list gaussian $mean $dev]
     138        }
     139        uniform {
     140            set min [_check_range [lindex $value 1] $min $max $units]
     141            set max [_check_range [lindex $value 2] $min $max $units]
     142            return [list uniform $min $max]
     143        }
     144        exact  {
     145            return [_check_range [lindex $value 1] $min $max $units]
     146        }
     147        default {
     148            return [_check_range [lindex $value 0] $min $max $units]
     149        }
     150    }
     151}
     152
     153# ----------------------------------------------------------------------
     154# USAGE: mconvert value ?-context units? ?-to units? ?-units on/off?
     155#
     156# This version of convert() converts multiple values.  Used when the
     157# value could be a range or probability density function (PDF).
     158# Examples:
     159#    gaussian 100k 1k
     160#    uniform 0eV 10eV
     161#    42
     162#    exact 42
     163# ----------------------------------------------------------------------
     164
     165proc Rappture::Units::mconvert {value args} {
     166    # puts "mconvert $value : $args"
     167    array set opts {
     168        -context ""
     169        -to ""
     170        -units "on"
     171    }
     172
     173    set value [split $value]
     174
     175    switch -- [lindex $value 0] {
     176        normal - gaussian {
     177            set valtype gaussian
     178            set vals [lrange $value 1 2]
     179            set convtype {0 1}
     180        }
     181        uniform {
     182            set valtype uniform
     183            set vals [lrange $value 1 2]
     184            set convtype {0 0}
     185        }
     186        exact  {
     187            set valtype ""
     188            set vals [lindex $value 1]
     189            set convtype {0}
     190        }
     191        default {
     192            set valtype ""
     193            set vals $value
     194            set convtype {0}
     195        }
     196    }
     197
     198    foreach {key val} $args {
     199        if {![info exists opts($key)]} {
     200            error "bad option \"$key\": should be [join [lsort [array names opts]] {, }]"
     201        }
     202        set opts($key) $val
     203    }
     204
     205    set newval $valtype
     206    foreach val $vals ctype $convtype {
     207        if {$ctype == 1} {
     208            # This code handles unit conversion for deltas (changes).
     209            # For example, if we want a standard deviation of 10C converted
     210            # to Kelvin, that is 10K, NOT a standard deviation of 283.15K.
     211            set units [Rappture::Units::Search::for $val]
     212            set base [eval Rappture::Units::convert 0$units $args -units off]
     213            set new [eval Rappture::Units::convert $val $args -units off]
     214            set delta [expr $new - $base]
     215            set val $delta$opts(-to)
     216        }
     217        # tcl 8.5 allows us to do this:
     218        # lappend newval [Rappture::Units::convert $val {*}$args]
     219        # but we are using tcl8.4 so we use eval :^(
     220        lappend newval [eval Rappture::Units::convert $val $args]
     221    }
     222    return $newval
     223}
     224
    62225# ----------------------------------------------------------------------
    63226# USAGE: convert value ?-context units? ?-to units? ?-units on/off?
     
    69232# current system.
    70233# ----------------------------------------------------------------------
    71 proc Rappture::Units::convert {value args} {
    72     array set opts {
    73         -context ""
    74         -to ""
    75         -units "on"
    76     }
    77     foreach {key val} $args {
    78         if {![info exists opts($key)]} {
    79             error "bad option \"$key\": should be [join [lsort [array names opts]] {, }]"
    80         }
    81         set opts($key) $val
    82     }
    83 
    84     #
    85     # Parse the value into the number part and the units part.
    86     #
    87     set value [string trim $value]
    88     if {![regexp {^([-+]?[0-9]+\.?([0-9]+)?([eEdD][-+]?[0-9]+)?) *(/?[a-zA-Z]+[0-9]*)?$} $value match number dummy1 dummy2 units]} {
    89         set mesg "bad value \"$value\": should be real number with units"
    90         if {$opts(-context) != ""} {
    91             append mesg " of [Rappture::Units::description $opts(-context)]"
    92         }
    93         error $mesg
    94     }
    95     if {$units == ""} {
    96         set units $opts(-context)
    97     }
    98 
    99     #
    100     # Try to find the object representing the current system of units.
    101     #
    102     set units [Rappture::Units::System::regularize $units]
    103     set oldsys [Rappture::Units::System::for $units]
    104     if {$oldsys == ""} {
    105         set mesg "value \"$value\" has unrecognized units"
    106         if {$opts(-context) != ""} {
    107             append mesg ".\nShould be units of [Rappture::Units::description $opts(-context)]"
    108         }
    109         error $mesg
    110     }
    111 
    112     #
    113     # Convert the number to the new system of units.
    114     #
    115     if {$opts(-to) == ""} {
    116         # no units -- return the number as is
    117         return "$number$units"
    118     }
    119     return [$oldsys convert "$number$units" $opts(-to) $opts(-units)]
    120 }
     234# proc Rappture::Units::convert {value args} {}
     235# Actual implementation is in rappture/lang/tcl/src/RpUnitsTclInterface.cc.
     236
    121237
    122238# ----------------------------------------------------------------------
     
    127243# along with a list of all compatible systems.
    128244# ----------------------------------------------------------------------
    129 proc Rappture::Units::description {units} {
    130     set sys [Rappture::Units::System::for $units]
    131     if {$sys == ""} {
    132         return ""
    133     }
    134     set mesg [$sys cget -type]
    135     set ulist [Rappture::Units::System::all $units]
    136     if {"" != $ulist} {
    137         append mesg " ([join $ulist {, }])"
    138     }
    139     return $mesg
    140 }
     245# proc Rappture::Units::description {units} {}
     246# Actual implementation is in rappture/lang/tcl/src/RpUnitsTclInterface.cc.
     247
    141248
    142249# ----------------------------------------------------------------------
     
    153260    private variable _system ""  ;# this system of units
    154261
    155     public proc for {units}
    156     public proc all {units}
     262    # These are in rappture/lang/tcl/src/RpUnitsTclInterface.cc.
     263    # public proc for {units}
     264    # public proc all {units}
     265
    157266    public proc regularize {units}
    158267
     
    360469# if there is no system that matches the units string.
    361470# ----------------------------------------------------------------------
    362 itcl::body Rappture::Units::System::for {units} {
    363     #
    364     # See if the units are a recognized system.  If not, then try to
    365     # extract any metric prefix and see if what's left is a recognized
    366     # system.  If all else fails, see if we can find a system without
    367     # the exact capitalization.  The user might say "25c" instead of
    368     # "25C".  Try to allow that.
    369     #
    370     if {[info exists _base($units)]} {
    371         return $_base($units)
    372     } else {
    373         set orig $units
    374         if {[regexp {^(/?)[cCmMuUnNpPfFaAkKgGtT](.+)$} $units match slash tail]} {
    375             set base "$slash$tail"
    376             if {[info exists _base($base)]} {
    377                 set sys $_base($base)
    378                 if {[$sys cget -metric]} {
    379                     return $sys
    380                 }
    381             }
    382 
    383             # check the base part for improper capitalization below...
    384             set units $base
    385         }
    386 
    387         set matching ""
    388         foreach u [array names _base] {
    389             if {[string equal -nocase $u $units]} {
    390                 lappend matching $_base($u)
    391             }
    392         }
    393         if {[llength $matching] == 1} {
    394             set sys [lindex $matching 0]
    395             #
    396             # If we got rid of a metric prefix above, make sure
    397             # that the system is metric.  If not, then we don't
    398             # have a match.
    399             #
    400             if {[string equal $units $orig] || [$sys cget -metric]} {
    401                 return $sys
    402             }
    403         }
    404     }
    405     return ""
    406 }
     471# itcl::body Rappture::Units::System::for {units} {}
     472# Actual implementation is in rappture/lang/tcl/src/RpUnitsTclInterface.cc.
     473
    407474
    408475# ----------------------------------------------------------------------
     
    413480# relationships that lead to the same base system.
    414481# ----------------------------------------------------------------------
    415 itcl::body Rappture::Units::System::all {units} {
    416     set sys [Rappture::Units::System::for $units]
    417     if {$sys == ""} {
    418         return ""
    419     }
    420 
    421     if {"" != [$sys cget -basis]} {
    422         set basis [lindex [$sys cget -basis] 0]
    423     } else {
    424         set basis $units
    425     }
    426 
    427     set ulist $basis
    428     foreach u [array names _base] {
    429         set obj $_base($u)
    430         set b [lindex [$obj cget -basis] 0]
    431         if {$b == $basis} {
    432             lappend ulist $u
    433         }
    434     }
    435     return $ulist
    436 }
     482# itcl::body Rappture::Units::System::all {units} {}
     483# Actual implementation is in rappture/lang/tcl/src/RpUnitsTclInterface.cc.
     484
    437485
    438486# ----------------------------------------------------------------------
Note: See TracChangeset for help on using the changeset viewer.