Files
sics/site_ansto/instrument/config/nexus/nxscripts_common_1.tcl
Ferdi Franceschini 0edaa1d5d0 Added code and filetype spec for data file policy
Added  environment controller save and sdsinfo commands.
Dynamically set histogram memory rank and dimensions for data file

r2165 | ffr | 2007-09-26 16:21:23 +1000 (Wed, 26 Sep 2007) | 4 lines
2012-11-15 13:25:00 +11:00

828 lines
29 KiB
Tcl

##
# @file nxscripts_common_1.tcl
# @brief Defines functions to create and save a nexus datafile based on the hdb tree metadata
#
MakeNXScript
sicsdatafactory new nxscript_data
##
# @brief Strips the output of a SICS command leaving only the value\n
# TODO Replace $cmd_output with [$cmd_output] so we can just pass the command name
#
# @param cmd_output The output from a command substitution
# @return The unadorned value returned by the SICS command which produced cmd_output
proc getVal {cmd_output} {
return [string trim [lindex [split $cmd_output =] 1 ] ]
}
##
# @brief Generate a filename from sicsdatanumber and sicsdatapath
#
# @param postfix This is the filename suffix, must be one of: nx.hdf, hdf, h5, nx5, xml
proc newFileName {postfix} {
array set inst_mnem {quokka QKK wombat WBT echidna ECH kowari KWR koala KOL taipan TPN platypus PLP pelican PLN}
set idNum [SplitReply [sicsdatanumber]]
set dataPath [SplitReply [sicsdatapath]]
# set prefix [SplitReply [sicsdataprefix]]
set date_time_arr [split [sicstime] " "]
set isodate [lindex $date_time_arr 0]
set isotime [string map {: -} [lindex $date_time_arr 1]]
return [format "%s/%s%07d.%s" $dataPath $inst_mnem([instname]) $idNum $postfix]
}
namespace eval nexus {
##
# @brief This is the nexus dictionary generated by the gen_nxdict function
variable nxdictionary
##
# @brief Records the current Nexus file state.
variable state
##
# @brief Specifies the save policy with an optional list of data link sources.
#
# NOTE: The ::histogram_memory::horizontal_axis and ::histogram_memory::vertical_axis are aliases which
# must be set by the instrument specific histogram memory configuration.
variable filetype_spec {
BEAM_MONITOR {
link {axis 1 ::data::gumtree_save_par_run_number}
link {data_set ::monitor::count_fb_counts}
save_policy {include @all exclude {hmm hmm_xy hmm_xt hmm_yt hmm_x hmm_y hmm_t}}
}
HISTOGRAM_XYT {
link {axis 1 ::data::gumtree_save_par_run_number}
link {axis 2 ::histogram_memory::horizontal_axis}
link {axis 3 ::histogram_memory::vertical_axis}
link {axis 4 ::histogram_memory::time_channel}
link {data_set hmm}
save_policy {include @all exclude {hmm_xy hmm_xt hmm_yt hmm_x hmm_y hmm_t}}
}
HISTOGRAM_XY {
link {axis 1 ::data::gumtree_save_par_run_number}
link {axis 2 ::histogram_memory::horizontal_axis}
link {axis 3 ::histogram_memory::vertical_axis}
link {data_set hmm_xy}
save_policy {include @all exclude {hmm hmm_xt hmm_yt hmm_x hmm_y hmm_t}}
}
HISTOGRAM_XT {
link {axis 1 ::data::gumtree_save_par_run_number}
link {axis 2 ::histogram_memory::horizontal_axis}
link {axis 3 ::histogram_memory::time_channel}
link {data_set hmm_xt}
save_policy {include @all exclude {hmm_xy hmm hmm_yt hmm_x hmm_y hmm_t}}
}
HISTOGRAM_YT {
link {axis 1 ::data::gumtree_save_par_run_number}
link {axis 2 ::histogram_memory::vertical_axis}
link {axis 3 ::histogram_memory::time_channel}
link {data_set hmm_yt}
save_policy {include @all exclude {hmm_xy hmm_xt hmm hmm_x hmm_y hmm_t}}
}
HISTOGRAM_X {
link {axis 1 ::data::gumtree_save_par_run_number}
link {axis 2 ::histogram_memory::horizontal_axis}
link {data_set hmm_x}
save_policy {include @all exclude {hmm_xy hmm_xt hmm_yt hmm hmm_y hmm_t}}
}
HISTOGRAM_Y {
link {axis 1 ::data::gumtree_save_par_run_number}
link {axis 2 ::histogram_memory::vertical_axis}
link {data_set hmm_y}
save_policy {include @all exclude {hmm_xy hmm_xt hmm_yt hmm_x hmm hmm_t}}
}
HISTOGRAM_T {
link {axis 1 ::data::gumtree_save_par_run_number}
link {axis 2 ::histogram_memory::time_channel}
link {data_set hmm_t}
save_policy {include @all exclude {hmm_xy hmm_xt hmm_yt hmm_x hmm_y hmm}}
}
}
proc ::nexus::process_filetype_policy {filetype filetype_spec} {
upvar $filetype_spec ft_spec
array set ft_spec_arr $ft_spec
if {[info exists ft_spec_arr($filetype)] == 0} {
error "$filetype is invalid, should be one of [array names ft_spec_arr]"
}
set ft_policy $ft_spec_arr($filetype)
::nexus::data clear
foreach {pol_type policy} $ft_policy {
switch $pol_type {
"link" {
::nexus::data $policy
}
"save_policy" {
clientput "save_policy is $policy"
foreach {save_action action_list} $policy {
switch $save_action {
"include" {
if {$action_list == "@all"} {
::hdb::set_save / true
} else {
foreach item $action_list {
if {[getatt $item type] == ""} {
error "ERROR: Unknown $item specified for inclusion in the data file"
}
::hdb::set_save [getatt $item hdb_path] true
}
}
}
"exclude" {
if {$action_list == "@all"} {
::hdb::set_save / false
} else {
foreach item $action_list {
if {[getatt $item type] == ""} {
error "ERROR: Unknown $item specified for exclusion from the data file"
}
::hdb::set_save [getatt $item hdb_path] false
}
}
}
default {
error "ERROR: Unknown save action $save_action specified in the save policy"
}
}
}
}
default {
error "$pol_type is invalid, should be one of 'link' 'save_policy'"
}
}
}
}
set exports [list newfile closefile save data]
eval namespace export $exports
if 0 {datafilename}
##
# @brief Initialise state variables
proc init {} {
variable state
variable nexusdic
array set state {file,new "true" file,open "false" file,namestyle "data"\
file,format "hdf" file,type "@none"}
set nexusdic "nexus.dic"
}
##
# @brief Create a nexus file
# This first generates a nexus dictionary file from the hdb tree and then creates a new
# nexus file based on that dictionary.
proc createfile {} {
global cfPath
variable nexusdic
variable state
if {$state(file,open) == "true"} {
error_msg "Can't create a new file because the current file is still open"
} elseif {$state(file,new) == "false"} {
error_msg "This function should only be called when state(file,new) = true"
}
set file_format [SplitReply [SicsDataPostFix]]
array set nxmode [list nx.hdf create5 hdf create5 h5 create5 nx5 create5 xml createxml]
set nxdict_path [::nexus::gen_nxdict $nexusdic]
if {$state(file,namestyle) == "scratch"} {
dataFileName [format "scratch.%s" $file_format]
} else {
sicsdatanumber incr
dataFileName [newFileName $file_format]
}
hsetprop /data currentfiletype [::utility::hgetplainprop /data datatype]
nxscript $nxmode($file_format) [SplitReply [dataFileName]] $nxdict_path
set state(file,open) false
set state(file,new) false
}
variable filetypes
set filetypes [list BEAM_MONITOR HISTOPERIOD_XYT TOTAL_HISTOGRAM_XY TOTAL_HISTOGRAM_XT TOTAL_HISTOGRAM_YT TOTAL_HISTOGRAM_X TOTAL_HISTOGRAM_Y TOTAL_HISTOGRAM_T ]
##
# @brief Checks if the given file type is defined.
#
# @return 1 on success, 0 on failure
proc isValidFileType {type} {
variable filetypes
if {[lsearch $filetypes $type] == -1} {
return 0
} else {
return 1
}
}
##
# @brief Setup file state info for writing a new file.
#
# @type data file type as defined in config/nexus/datafiletype.tcl or clear
# @param namestyle scratch or data, default=data\n
# If namestyle=data, the save command will create numbered files using the ANSTO
# file naming convention.\n
# If namestyle=scratch, the save command will create scratch files.
#
# postconditions:
# state(file,open) true state(file,new) false
# /data/currentfiletype == UNKNOWN
proc newfile {type {namestyle data}} {
variable filetype_spec
variable state
set state(file,namestyle) $namestyle
set state(file,new) true
hsetprop /data currentfiletype UNKNOWN
if {$type == "clear"} {
::nexus::data clear
::hdb::set_save / false
hsetprop /data currentfiletype UNKNOWN
hsetprop /data datatype UNKNOWN
} else {
::nexus::process_filetype_policy $type filetype_spec
}
}
##
# @brief Save data to the currently open file and then close it.
#
# @param point This is the array index for mutable data elements
#
# This function provides the top level call to the recursive ::nexus::savetree
# function
#
# @see ::nexus::savetree
proc save_data {point} {
debug_msg "save point $point in [dataFileName]"
::nexus::nxreopenfile
foreach child [hlist /] {
if {[::utility::hgetplainprop /$child data] == "true"} {
::nexus::savetree $child $point
}
}
::nexus::nxclosefile
}
##
# @brief save data collected by last data acquisition command.
#
# @param point experimental point number, this is the array index for mutable
# datasets in the nexus file. Optional, default = 0
#
# A new file will be created if the new file state has been set to true, or
# if the current data type doesn't match the current file type.
proc save {{point 0}} {
variable state
if {[string is integer $point] == 0} {
error_msg "save index must be an integer"
} elseif {$point < 0} {
error_msg "save index cannot be negative"
}
::data::gumtree_save -set run_number $point
set isNewFile [expr {$state(file,new) == "true"}]
set currFileType [::utility::hgetplainprop /data currentfiletype]
set currDataType [::utility::hgetplainprop /data datatype]
set dataTypeChanged [expr {$currFileType != $currDataType}]
if {$currDataType == "UNKNOWN"} {
error_msg "You must set the file type, eg 'newfile BEAM_MONITOR' or 'newfile BEAM_MONITOR scratch' "
}
if {$isNewFile || $dataTypeChanged} {
set state(file,new) true
::nexus::createfile
::nexus::save_data $point
::nexus::linkdata
} else {
::nexus::save_data $point
}
return
}
##
# @brief Reopen the current file, close it with nxclosefile
#
# @see nxclosefile
proc nxreopenfile {} {
global cfPath
variable state
variable nexusdic
if {$state(file,open) == "false"} {
nxscript reopen [SplitReply [dataFileName]] $cfPath(nexus)/$nexusdic
set state(file,open) true
}
}
##
# @brief Close the current file. You can reopen it with nxreopenfile
#
# @see nxreopenfile
proc nxclosefile {} {
variable state
if {$state(file,open) == "true"} {
nxscript close
set state(file,open) false
set flist [split [SplitReply [dataFileName]] "/"]
set fname [lindex $flist [expr [llength $flist] - 1] ]
clientput "$fname updated" "event"
}
}
##
# @brief Records that a given data source should be linked to nexus data target.
#
# NOTE: If a link has already been recorded then it does nothing. This allows you to
# override default links set by a command. eg A "count" command may link axis_1 to
# the run number but a "scan" command which uses the count command can link axis_1 to
# a scan variable.
#
# Usage:
# data data_set datsource
# Records that /data/data_set should be linked to datsource and sets a data type identifier
# data axis 1|2|3|4 datsource
# Records that /data/axisn should be linked to datsource
# data clear
# Clears all link targets and sets the data type identifier to unknown
# data alias <name>, remove alias <name>
# data alias <name> <target>, set <name> as an alias for <target> unless it has already been defined.
proc ::nexus::data {args} {
variable state
if {[llength $args] == 1} {
set arguments [lindex $args 0]
} else {
set arguments $args
}
set dpath /data
set opt [lindex $arguments 0]
set arglist [lrange $arguments 1 end]
switch $opt {
"axis" {
debug_msg "'axis' case of switch"
set link_target [lindex $arguments 2]
set axnum [lindex $arguments 1]
if {[string is integer $axnum] == 0} {
error "ERROR: [info level -1]->data, index for data axis should be an integer, not $axnum"
}
if {[getatt $link_target type] == ""} {
error "Unknown link target $link_target"
}
set hp $dpath/axis_$axnum
# if {[::utility::hgetplainprop $hp link] == "@none"} {
hsetprop $hp link [getatt [lindex $arguments 2] id]
hsetprop $hp long_name [getatt [lindex $arguments 2] long_name]
# }
}
"data_set" {
debug_msg "'data_set' case of switch"
set link_target [lindex $arguments 1]
if {[getatt $link_target type] == ""} {
error "Unknown link target $link_target"
}
hsetprop $dpath datatype [lindex [info level -1] 0]
set hp $dpath/data_set
# if {[::utility::hgetplainprop $hp link] == "@none"} {
hsetprop $hp link [getatt $link_target id]
hsetprop $hp long_name [getatt $link_target long_name]
# }
}
"clear" {
debug_msg "'clear' case of switch"
foreach child [hlist $dpath] {
hsetprop $dpath/$child link @none
hsetprop $dpath/$child long_name @none
}
}
"alias" {
debug_msg "'alias' case of switch"
set alias_name [lindex $arglist 0]
set alias_target [lindex $arglist 1]
switch $alias_target {
"" {
if {[info exists state(data,alias,$alias_name)]} {
definealias $alias_name
set state(data,alias,$alias_name) @none
}
}
default {
if {[info exists state(data,alias,$alias_name)]} {
if { $state(data,alias,$alias_name) == "@none" } {
definealias $alias_name $alias_target
}
} else {
definealias $alias_name $alias_target
}
return
}
}
}
default {error "ERROR: [info level -1]->data, Unsupported option $opt"}
}
}
##
# @brief Links data and axis into /data group
proc linkdata {} {
array unset axes
set hpath /data
::nexus::nxreopenfile
foreach child [hlist $hpath] {
array set p_arr [::utility::hlistplainprop $hpath/$child]
if {$p_arr(data) == true && $p_arr(nxsave) == true} {
if {[info exists p_arr(nxalias)]} {
if {[info exists p_arr(type)] && $p_arr(type) == "nxvgroup"} {
if {$p_arr(link) != "@none"} {
nxscript makelink $p_arr(nxalias) $p_arr(link)
switch -glob $child {
"axis_*" {
set n [lindex [split $child _] 1]
set axes($n) [::utility::hgetplainprop $hpath/$child long_name]
nxscript putattribute $p_arr(link) axis $n
}
"data_set" {
nxscript putattribute $p_arr(link) signal 1
set data_set_alias $p_arr(link)
}
default {error "ERROR: [info level -1]->linkdata, Unsupported data path $hpath/$child"}
}
}
}
}
}
}
if {[info exists axes]} {
foreach n [lsort [array names axes]] {
lappend axes_list $axes($n)
}
nxscript putattribute $data_set_alias axes [join $axes_list :]
}
::nexus::nxclosefile
}
##
# @brief Traverse the hdb subtree from the given path and save the data in the currently open file
#
# @param hpath path of subtree to save, must not be "/"
# @param pt Current array index for mutable data (optional default=0)
proc savetree {hpath {pt 0}} {
foreach child [hlist /$hpath] {
array unset p_arr
array set p_arr [::utility::hlistplainprop /$hpath/$child]
if {[info exists p_arr(type)] && $p_arr(type) == "nxvgroup"} {
return
}
set data_type [lindex [split [hinfo /$hpath/$child] , ] 0]
if {$p_arr(data) == true && $p_arr(nxsave) == true } {
if {[info exists p_arr(savecmd)] && [info exists p_arr(nxalias)] } {
if {[info exists p_arr(mutable)] && $p_arr(mutable) == "true" } {
$p_arr(savecmd) $p_arr(sicsdev) $p_arr(nxalias) $data_type point $pt
} else {
$p_arr(savecmd) $p_arr(sicsdev) $p_arr(nxalias) $data_type
}
} elseif {[info exists p_arr(savecmd)] || [info exists p_arr(nxalias)]} {
error_msg "/$hpath/$child must have both 'savecmd' and 'nxalias' properties\nThe actual property list for /$hpath/$child is [array get p_arr]"
}
::nexus::savetree $hpath/$child $pt
}
}
}
##
# @brief Recursive portion of gen_nxdict function
#
# @param hpath hdb subtree path to generate dictionary fragment from, must not be "/"
# @param dictPath parent path for nexus dictionary fragment.
# @param name name for child dictionary path
# @param nxc Nexus class name
#
# If the klass name doesn't begin with NX then construct the SDS name by replacing '/' with '_' in the
# hdb path
#
# @see gen_nxdict
proc _gen_nxdict {hpath dictPath name nxc} {
variable nxdictionary
if {[::utility::hgetplainprop /$hpath data] == "false"} {
debug_msg "$hpath doesn't have a data property"
return
}
foreach child [hlist /$hpath] {
if {[::utility::hgetplainprop /$hpath/$child data] == true} {
set nxclass [::utility::hgetplainprop /$hpath/$child klass]
if {[string range $nxc 0 1] == "NX"} {
::nexus::_gen_nxdict $hpath/$child $dictPath/$name,$nxc $child $nxclass
} else {
::nexus::_gen_nxdict $hpath/$child $dictPath ${name}_$child $nxclass
}
}
}
array set p_arr [::utility::hlistplainprop /$hpath]
set data_type [lindex [split [hinfo /$hpath] , ] 0]
if {$p_arr(data) == "true" && $p_arr(nxsave) == "true" && [info exists p_arr(nxalias)]} {
set alias $p_arr(nxalias)
if {[info exists p_arr(sdsinfo)]} {
if {[info exists p_arr(mutable)] && $p_arr(mutable) == "true"} {
set nxdictionary($alias) "$dictPath/SDS $name [$p_arr(sdsinfo) $p_arr(sicsdev) $data_type mutable true]"
} else {
set nxdictionary($alias) "$dictPath/SDS $name [$p_arr(sdsinfo) $p_arr(sicsdev) $data_type mutable false]"
}
} elseif {[info exists p_arr(type)] && $p_arr(type) == "nxvgroup"} {
set nxdictionary($alias) "$dictPath/NXVGROUP"
}
}
}
##
# @brief Generate a nexus dictionary file from the hdb tree
#
# An entry in the nexus dictionary is generated for each node in the
# hdb tree which has the following properties and values, data=true and nxsave=true
#
# @param nexusdic Name of the nexus dictionary that will be created.
# @return Full path to the nexus dictionary.
proc gen_nxdict {nexusdic} {
global cfPath
variable nxdictionary
set nxdict_path $cfPath(nexus)/$nexusdic
array unset nxdictionary
foreach hp [hlist /] {
if {[::utility::hgetplainprop /$hp data] == true} {
set nxclass [::utility::hgetplainprop /$hp klass]
::nexus::_gen_nxdict $hp /entry1,NXentry $hp $nxclass
}
}
set fh [open $nxdict_path w]
puts $fh "##NXDICT-1.0"
puts $fh padim0=0
puts $fh padim1=0
puts $fh padim2=0
foreach {n v} [array get nxdictionary] {
puts $fh "$n = $v"
}
close $fh
return $nxdict_path
}
##
# @brief Set SICS object attributes which are required for creating nexus data files.
proc set_sobj_attributes {} {
# SICS commands
sicslist setatt nxscript privilege internal
# SICS data objects
sicslist setatt nxscript_data privilege internal
foreach sobj [lrange [sicslist type motor] 1 end] {
sicslist setatt $sobj savecmd ::nexus::motor::save
sicslist setatt $sobj sdsinfo ::nexus::motor::sdsinfo
}
foreach sobj [sicslist type configurablevirtualmotor] {
sicslist setatt $sobj savecmd ::nexus::motor::save
sicslist setatt $sobj sdsinfo ::nexus::motor::sdsinfo
}
foreach sobj [sicslist type histmem] {
sicslist setatt $sobj savecmd ::nexus::histmem::save
sicslist setatt $sobj sdsinfo ::nexus::histmem::sdsinfo
}
foreach sobj [sicslist type sicsvariable] {
sicslist setatt $sobj savecmd ::nexus::sicsvariable::save
sicslist setatt $sobj sdsinfo ::nexus::sicsvariable::sdsinfo
}
foreach sobj [sicslist type singlecounter] {
sicslist setatt $sobj savecmd ::nexus::singlecounter::save
sicslist setatt $sobj sdsinfo ::nexus::singlecounter::sdsinfo
}
foreach sobj [sicslist type environment_controller] {
sicslist setatt $sobj savecmd ::nexus::environment_controller::save
sicslist setatt $sobj sdsinfo ::nexus::environment_controller::sdsinfo
}
foreach sobj [sicslist kind script] {
sicslist setatt $sobj savecmd ::nexus::script::save
sicslist setatt $sobj sdsinfo ::nexus::script::sdsinfo
}
}
}
namespace eval ::nexus::histmem {}
namespace eval ::nexus::motor {}
namespace eval ::nexus::environment_controller {}
namespace eval ::nexus::sicsvariable {}
namespace eval ::nexus::singlecounter {}
namespace eval ::nexus::script {}
namespace import ::nexus::*
foreach expt $::nexus::exports {
publish $expt user
sicslist setatt $expt privilege internal
}
##
# @brief Convert the given hdb type to Nexus data type
#
# @param dtype hdb data type
# @return Nexus data type
proc ::nexus::hdb2nx_type {dtype} {
switch $dtype {
int {return NX_INT32}
intar {return NX_INT32}
intvarar {return NX_INT32}
float {return NX_FLOAT32}
floatar {return NX_FLOAT32}
floatvarar {return NX_FLOAT32}
text {return NX_CHAR}
default {error "ERROR: [info level -1]->hdb2nx_type, Unknown type $dtype"}
}
}
##
# @brief Save command for histogram memory data.
#
# The savecmd attribute of any histogram memory objects should be set to this function
#
# @see set_sobj_attributes
proc ::nexus::histmem::save {hm nxalias data_type args} {
set rank [SplitReply [$hm configure rank]]
set datalen 1
set indStartList [lindex $args 1]
set indLenList [list 1]
for {set i 0} {$i < $rank} {incr i} {
lappend indStartList 0
set dim$i [SplitReply [$hm configure dim$i]]
lappend indLenList [set dim$i]
set datalen [expr $datalen * [set dim$i]]
nxscript updatedictvar padim$i [set dim$i]
}
set data_start 0
set bank 0
nxscript putslab $nxalias $indStartList $indLenList $hm $data_start $datalen $bank
}
# TODO Get rank from /data
proc ::nexus::histmem::sdsinfo {hm data_type args} {
array set param $args
array set hm_prop [attlist $hm]
set rank [SplitReply [$hm configure rank]]
for {set i 0} {$i < $rank} {incr i} {lappend dimstr "\$(padim$i)"}
set dimstr [join $dimstr ,]
if {$param(mutable) == true} {
return " -type NX_INT32 -LZW -rank [expr $rank+1] -dim {-1,$dimstr}"
} else {
return " -type NX_INT32 -LZW -rank $rank -dim {$dimstr}"
}
}
# The save commands are called with the sobj name and nxalias
# The sdsinfo commands provide the SDS description for an nxdic
proc ::nexus::motor::save {motor nxalias data_type args} {
if {[lindex $args 0] == "point"} {
set index [lindex $args 1]
nxscript_data clear
nxscript_data putfloat 0 [getVal [$motor] ]
nxscript putslab $nxalias [list $index] [list 1] nxscript_data
} else {
if {[getatt $motor type] == "motor"} {
nxscript putmot $nxalias $motor
} else {
nxscript putfloat $nxalias [SplitReply [$motor]]
}
}
}
proc ::nexus::motor::sdsinfo {motor data_type args} {
array set param $args
array set mot_prop [attlist $motor]
set dtype [::nexus::hdb2nx_type $data_type]
if {$param(mutable) == true} {
return " -type $dtype -rank 1 -dim {-1} -attr {units,$mot_prop(units)} -attr {long_name,$mot_prop(long_name)}"
} else {
return " -type $dtype -attr {units,$mot_prop(units)} -attr {long_name,$mot_prop(long_name)}"
}
}
proc ::nexus::environment_controller::save {evc nxalias data_type args} {
if {[lindex $args 0] == "point"} {
set index [lindex $args 1]
nxscript_data clear
nxscript_data putfloat 0 [getVal [$evc] ]
nxscript putslab $nxalias [list $index] [list 1] nxscript_data
} else {
nxscript putfloat $nxalias [SplitReply [$evc]]
}
}
proc ::nexus::environment_controller::sdsinfo {evc data_type args} {
array set param $args
array set evc_prop [attlist $evc]
set dtype [::nexus::hdb2nx_type $data_type]
if {$param(mutable) == true} {
return " -type $dtype -rank 1 -dim {-1} -attr {units,$evc_prop(units)} -attr {long_name,$evc_prop(long_name)}"
} else {
return " -type $dtype -attr {units,$evc_prop(units)} -attr {long_name,$evc_prop(long_name)}"
}
}
namespace eval ::nexus {
}
proc ::nexus::sicsvariable::save {svar nxalias data_type args} {
array set attribute [attlist $svar]
set val [SplitReply [$svar]]
if {[lindex $args 0] == "point"} {
set index [lindex $args 1]
nxscript_data clear
switch $data_type {
int {nxscript_data putint 0 $val}
float {nxscript_data putfloat 0 $val}
default {error "ERROR: [info level -1]->::nexus::sicsvariable::save, unknown type $data_type"}
}
nxscript putslab $nxalias [list $index] [list 1] nxscript_data
} else {
switch $data_type {
int {nxscript putint $nxalias $val}
float {nxscript putfloat $nxalias $val}
text {nxscript puttext $nxalias $val}
default {error "ERROR: [info level -1]->::nexus::sicsvariable::save, unknown type $data_type"}
}
}
if {[info exists attribute(units)]} {
nxscript putattribute $nxalias units $attribute(units)
}
}
proc ::nexus::sicsvariable::sdsinfo {svar data_type args} {
array set param $args
set dtype [::nexus::hdb2nx_type $data_type]
if {$param(mutable) == true} {
return " -type $dtype -rank 1 -dim {-1}"
} else {
return " -type $dtype"
}
}
proc ::nexus::singlecounter::save {counter nxalias data_type args} {
todo_msg "Save counter: $counter"
}
proc ::nexus::singlecounter::sdsinfo {counter data_type args} {
todo_msg "Get sdsinfo for counter: $counter"
}
##
# @brief Save command for hdb nodes associated with a tcl macro
#
# The macro must return a 1D associative array when called with -arrayname.
proc ::nexus::script::save {script nxalias data_type args} {
array set attribute [attlist $script]
set darray [$script -arrayname]
set size [array size $darray]
switch $data_type {
"intar" - "intvarar" {
nxscript putintarray $nxalias $darray $size
}
"floatar" - "floatvarar" {
nxscript putarray $nxalias $darray $size
}
}
if {[info exists attribute(units)]} {
nxscript putattribute $nxalias units $attribute(units)
}
}
proc ::nexus::script::sdsinfo {script data_type args} {
set dtype [::nexus::hdb2nx_type $data_type]
set darray [$script -arrayname]
set size [array size $darray]
return " -type $dtype -rank 1 -dim {$size}"
}
# TODO Return filename from nxcreatefile and call nxreopen nxclose etc
# TODO Make an nxscript namespace for all this.
# dictalias is a global hash which records the alias which the value of
# a sics object (eg motors) is written to. The has is indexed by the
# objects name. It is useful for making links to datasets.
# dim0 = vertical axis on detector
# dim1 = horizontal axis on detector
set tmpstr [string map {"$" ""} {$Name: not supported by cvs2svn $}]
set nx_content_release_tag [lindex $tmpstr [expr [llength $tmpstr] - 1]]
set tmpstr [string map {"$" ""} {$Revision: 1.30 $}]
set nx_content_revision_num [lindex $tmpstr [expr [llength $tmpstr] - 1]]
namespace eval data {
##
# @brief Nexus data save command for gumtree control interface
#
# @param run_number This is the run or scan point number, it serves as the array
# index for nexus data sets which correspond to mutable data
command gumtree_save {int: run_number} {
::nexus::save $run_number
}
sicslist setatt ::data::gumtree_save long_name save
array set param [::data::gumtree_save -list param]
::utility::mkData $param(run_number) run_number instrument privilege READ_ONLY mutable true control false
command gumtree_type {text:nx.hdf,xml type} {
SicsDataPostFix $type
}
sicslist set ::data::gumtree_type long_name file_format
::data::gumtree_type -set type [SplitReply [SicsDataPostFix]]
}
::nexus::init