Files
sics/site_ansto/instrument/config/scan/scan_common_1.tcl
Ferdi Franceschini 9ef0bb8afd Make sure bmon scans can save scratch files when the savetype is set to nosave.
r3624 | ffr | 2012-06-29 16:12:30 +1000 (Fri, 29 Jun 2012) | 2 lines
2012-11-15 17:31:53 +11:00

486 lines
16 KiB
Tcl

##
# @file Scan functionality and common high level commands are defined here.
#
# namespace variables\n
# ::scan::save_filetype data/scratch, controls if data will be saved to a
# scratch file.\n
# ::scan::reset_position true/false (default=true), drive motor back to start
# position at end of scan\n
# ::scan::force_scan true/false, (default=false), Will force a scan if the
# instrument isn't ready, eg shutters closed. Note: The scan will still fail if
# you are scanning against a motor and motion control is disabled.\n
# If force_scan is true it is immediately reset to false after it is checked.
#TODO Get rid of duplication in bmonscan and hmscan code
namespace eval scan {
variable ic_runscanpar
variable ic_hmm_datatype
variable save_filetype
variable reset_position
variable check_thread0
variable check_instrument_ready
variable force_scan
set check_thread0 true
set check_instrument_ready true
set force_scan false
set save_filetype "data"
set reset_position "false"
if {[SplitReply [motor_simulation]] == "true"} {
set check_thread0 false
}
}
##
# @brief This is a convenience command which allows hmscans to be forced.
# Call this before calling hmscan run to force a scan if the instrument isn't ready.
proc force_scan {} {
set ::scan::force_scan "true"
}
publish force_scan user
proc ::scan::bm_scan_collect {sobj uobj point} {
set vlist [split [$sobj getvarpar 0] = ];
set w(NP) $point
set sv [string trim [lindex [split [lindex $vlist 0] . ] 1]]
set header [format "%-4.4s %-9.9s %-14s %-7.7s" NP $sv Counts Time]
set varval [SplitReply [$sv]]
set counts [SplitReply [bm getcounts]]
set time [SplitReply [bm gettime]]
set data [format "%-4d %-9.3f %-14d %-7.2f" $point $varval $counts $time]
clientput $header
clientput $data
for {set chn 0} {$chn < $::counter::isc_numchannels} {incr chn} {
clientput "Channel $chn [SplitReply [bm getmonitor $chn]]"
}
}
proc ::scan::hmm_scan_collect {sobj uobj point} {
set vlist [split [$sobj getvarpar 0] = ];
set w(NP) $point
set sv [string trim [lindex [split [lindex $vlist 0] . ] 1]]
set header [format "%-4.4s %-9.9s %-14s %-7.7s" NP $sv Counts Time]
set varval [SplitReply [$sv]]
set counts [SplitReply [::histogram_memory::total_counts]]
set time [SplitReply [::histogram_memory::time]]
set data [format "%-4d %-9.3f %-14d %-7.2f" $point $varval $counts $time]
clientput $header
clientput $data
for {set bmn 1} {$bmn <= $::counter::isc_numchannels} {incr bmn} {
set bmon bm$bmn
clientput "Monitor $bmn [SplitReply [$bmon getcounts]]"
}
}
proc ::scan::ic_initialize {} {
if [ catch {
variable ic_runscanpar
variable ic_hmm_datatype
set ic_hmm_datatype HISTOGRAM_XYT
MakeScanCommand hmscan bm $::cfPath(scan)/scan_common_1.hdd recover.bin
MakeScanCommand bmonscan bm $::cfPath(scan)/scan_common_1.hdd recover.bin
bmonscan configure script
bmonscan function writeheader ::scan::donothing
bmonscan function writepoint ::scan::bm_writepoint
bmonscan function count ::scan::bm_count
bmonscan function collect ::scan::bm_scan_collect
bmonscan function prepare ::scan::bm_scan_prepare
bmonscan function finish ::scan::bm_scan_finish
hmscan configure script
hmscan function writeheader ::scan::donothing
hmscan function writepoint ::scan::hmm_writepoint
hmscan function count ::scan::hmm_count
hmscan function collect ::scan::hmm_scan_collect
hmscan function prepare ::scan::hmm_scan_prepare
hmscan function finish ::scan::hmm_scan_finish
# TODO Use ic_runscanpar to create the ::scan::runscan command and
# to validate the "runscan" proc parameters.
array set ic_runscanpar [subst {
scanvar text=drivable
start float
stop float
numpoints int=0,inf
mode text=[join [concat [list time unlimited period count frame] $::counter::isc_beam_monitor_list ] , ]
preset float=0,inf
datatype text=[join [array names ::nexus::histmem_filetype_spec] , ]
savetype text=save,nosave
force boolean
}]
} message ] {
if {$::errorCode=="NONE"} {return $message}
return -code error $message
}
}
##
# @brief Returns an error if a scan variable target position exceeds the limits.
proc ::scan::check_limit {scan_variable limit_name target} {
switch $limit_name {
"hardlowerlim" - "softlowerlim" {
set limit [SplitReply [$scan_variable $limit_name]]
if { $target < $limit} {
return -code error "Final position of $target violates $limit_name $limit for $scan_variable"
}
}
"hardupperlim" - "softupperlim" {
set limit [SplitReply [$scan_variable $limit_name]]
if { $target > $limit} {
return -code error "Final position of $target violates $limit_name $limit for $scan_variable"
}
}
default {
return -code error "Invalid limit name $limit_name"
}
}
}
## \brief check final position against scan variable limits
#
# NOTE: The sics scan object alread checks if a variable is drivable
# so we don't have to.
# TODO We can't check limits of virtual motors yet because the
# configurablevirtualmotor doesn't set a checklimits function.
proc ::scan::check_scanvar {sobj uobj} {
variable check_thread0
set vlist [split [$sobj getvarpar 0] = ];
set NP [SplitReply [$sobj np]]
set scan_variable [string trim [lindex [split [lindex $vlist 0] . ] 1]]
set scan_start [lindex $vlist 1];
set scan_increment [lindex $vlist 2];
if {[getatt $scan_variable type] == "motor"} {
if {[SplitReply [$scan_variable fixed]] >= 0} {
return -code error "ERROR: Can't drive scan variable, $scan_variable position is set to 'fixed'"
} elseif {$check_thread0 && [SplitReply [$scan_variable thread0]] == -1} {
return -code error "ERROR: Can't scan ${scan_variable}. Thread zero has stopped running on the motion controller"
}
set scan_final [expr $scan_start + ($NP-1) * $scan_increment]
if [catch {
::scan::check_limit $scan_variable softlowerlim $scan_final
::scan::check_limit $scan_variable softupperlim $scan_final
::scan::check_limit $scan_variable softlowerlim $scan_start
::scan::check_limit $scan_variable softupperlim $scan_start
}] {
return -code error $::errorInfo
}
}
}
##
# @brief Instrument specific scan configurations can override this procedure to perform some setup
# before running a scan, eg setting hmm frame frequency.
#
# NOTES\n
# Returning an error will cause the scan to abort before it starts\n
# eg\n
# return -code error "error message"
proc ::scan::pre_hmm_scan_prepare {} {}
##
# @brief Do some pre-scan checks and prime the DAE
proc ::scan::hmm_scan_prepare {sobj uobj} {
variable save_filetype
variable ic_hmm_datatype
variable check_instrument_ready
variable force_scan
if {$force_scan || $check_instrument_ready && [::plc::inst_ready]} {
set force_scan false
if [catch {
::scan::check_scanvar $sobj $uobj
::scan::pre_hmm_scan_prepare
}] {
return -code error "HMSCAN ABORTED: $::errorInfo"
}
if [catch {
set numpoints [SplitReply [$sobj np]]
set vlist [split [$sobj getvarpar 0] = ]
set scanstart [lindex $vlist 1]
set scanstep [lindex $vlist 2]
::scan::runscan_cmd -set feedback status BUSY
run_mode "hmscan"
set ::histogram_memory::histmem_axes(SVAR) [SplitReply [sicslist [::scan::runscan_cmd -set scan_variable] hdb_path] ]
::nexus::newfile $ic_hmm_datatype $save_filetype
clientput "Scan start: $scanstart, Scan step: $scanstep, Number of points: $numpoints"
clientput "Datatype: $ic_hmm_datatype"
# Prime DAE
hmm pause
}] {
run_mode "normal"
return -code error $::errorInfo
}
} else {
return -code error "HMSCAN ABORTED: Instrument not ready"
}
}
proc ::scan::hmm_count {sobj uobj point mode preset} {
::scan::runscan_cmd -set feedback scanpoint $point
::scan::runscan_cmd -set feedback scan_variable_value [SplitReply [[::scan::runscan_cmd -set scan_variable]]]
# Start histogram and block until count is complete
::histogram_memory::start block
}
#TODO rangescan: drive to original position for rangescans, not the start position.
proc ::scan::hmm_scan_finish {sobj uobj} {
variable save_filetype
variable reset_position
set $save_filetype "data"
::histogram_memory::stop
::scan::runscan_cmd -set feedback status IDLE
run_mode "normal"
set ::histogram_memory::histmem_axes(SVAR) "/instrument/run_number"
# Make sure that the next save command doesn't overwrite our scan data.
# and clear any data links
::nexus::newfile clear data
if {$reset_position == "true"} {
set reset_position "false"
set svar [::scan::runscan_cmd -get scan_variable]
set svtype [getatt $svar type]
if {$svtype == "motor" || $svtype == "configurablevirtualmotor"} {
drive $svar [::scan::runscan_cmd -get scan_start]
}
}
# ::histogram_memory::configure_server Filler_defaults
}
proc ::scan::bm_scan_finish {sobj uobj} {
variable reset_position
::scan::hdb_bmonscan -set feedback status IDLE
run_mode "normal"
set ::histogram_memory::histmem_axes(SVAR) "/instrument/run_number"
# Make sure that the next save command doesn't overwrite our scan data.
# and clear any data links
::nexus::newfile clear data
if {$reset_position == "true"} {
set reset_position "false"
set svar [::scan::hdb_bmonscan -get scan_variable]
set svtype [getatt $svar type]
if {$svtype == "motor" || $svtype == "configurablevirtualmotor"} {
drive $svar [::scan::hdb_bmonscan -get scan_start]
}
}
}
proc ::scan::bm_writepoint {sobj uobj pt} {
::nexus::save $pt
::scan::hdb_bmonscan -set feedback counts [SplitReply [bm getcounts]];
}
#TODO Feedback for Histogram memory scan
proc ::scan::hmm_writepoint {sobj uobj pt} {
variable save_filetype
# Write hdb tree
::nexus::save $pt
}
proc ::scan::donothing {args} {}
proc ::scan::bm_count {sobj uobj point mode preset} {
::scan::hdb_bmonscan -set mode $mode
::scan::hdb_bmonscan -set preset $preset
::scan::hdb_bmonscan -set feedback scanpoint $point;
::scan::hdb_bmonscan -set feedback mode $mode;
::scan::hdb_bmonscan -set feedback preset $preset;
::scan::hdb_bmonscan -set feedback scan_variable_value [SplitReply [[::scan::hdb_bmonscan -set scan_variable]]]
::monitor::count $mode $preset
}
proc ::scan::bm_scan_prepare {sobj uobj} {
variable save_filetype
variable check_instrument_ready
variable force_scan
if {$force_scan || $check_instrument_ready && [::plc::inst_ready]} {
set force_scan false
if [catch {
::scan::check_scanvar $sobj $uobj
::scan::pre_hmm_scan_prepare
}] {
return -code error "BMONSCAN ABORTED: $::errorInfo"
}
if [catch {
#TODO Parameterise varindex in some way
set varindex 0;
set numpoints [SplitReply [$sobj np]]
set vlist [split [$sobj getvarpar $varindex] = ]
set scanstart [lindex $vlist 1]
set scanstep [lindex $vlist 2]
::scan::hdb_bmonscan -set NP $numpoints
::scan::hdb_bmonscan -set scan_variable [string trim [lindex [split [lindex $vlist 0] . ] 1]];
::scan::hdb_bmonscan -set scan_start $scanstart
::scan::hdb_bmonscan -set scan_increment $scanstep
set scanvar_pts [SplitReply [$sobj getvardata $varindex]]
::scan::hdb_bmonscan -set feedback status BUSY
run_mode "bmonscan"
array set bm_fb [::scan::hdb_bmonscan -list feedback]
set ::histogram_memory::histmem_axes(SVAR) [SplitReply [sicslist [::scan::hdb_bmonscan -set scan_variable] hdb_path] ]
::nexus::newfile BEAM_MONITOR $save_filetype
#stdscan prepare $sobj $uobj;
clientput "Scan start: $scanstart, Scan step: $scanstep, Number of points: $numpoints"
clientput "Datatype: BEAM_MONITOR"
}] {
run_mode "normal"
return -code error $::errorInfo
}
} else {
return -code error "BMONSCAN ABORTED: Instrument not ready"
}
}
Publish ::scan::hmm_count user
Publish ::scan::hmm_scan_prepare user
Publish ::scan::hmm_scan_finish user
Publish ::scan::hmm_scan_collect user
Publish ::scan::hmm_writepoint user
Publish ::scan::donothing user
Publish ::scan::bm_scan_prepare user
Publish ::scan::bm_scan_finish user
Publish ::scan::bm_scan_collect user
Publish ::scan::bm_writepoint user
Publish ::scan::bm_count user
namespace eval scan {
namespace export runscan
VarMake ::scan::runscan_reset_position Text internal
::scan::runscan_reset_position false
#TODO Add counter (monitor_1 monitor_2 ... histmem) and filetype BEAM_MONITOR HISTMEM_?
##
# @brief Run a histogram memory scan
# @param filetype one of the histogram filetypes (default=HISTOGRAM_XYT)
# @param savetype save/nosave (default=save)
# @param force true/false (default=false)
proc runscan {scanvar start stop numpoints mode preset args} {
variable ic_hmm_datatype
variable save_filetype
variable reset_position
variable force_scan
if [ catch {
set force_scan false
set hm_ft_names [array names ::nexus::histmem_filetype_spec]
# Default filetype for histogram memory scans
set ic_hmm_datatype "HISTOGRAM_XYT"
# Default save uniquely numbered files
set savetype "save"
set reset_position [SplitReply [::scan::runscan_reset_position]]
if {[is_drivable $scanvar] == 0} {
error "The scan variable <$scanvar> must be drivable"
}
if {[string is integer $numpoints] != 1} {
error "Number of points <$numpoints> must be an integer"
}
if { $numpoints < 1 } {
error "Number of points <$numpoints> must not be less than one"
}
if {$numpoints == 1} {
set step 0
} else {
set step [expr double($stop - $start)/($numpoints - 1.0)]
}
if {$step == 0 && $numpoints > 1} {
clientput "WARNING:Scan step is zero and number of points > 1. Adjusting numpoints to one"
set numpoints 1
}
foreach {arg val} $args {
switch $arg {
"force" {
if [string is boolean $val] {
set force_scan $val
} else {
error "ERROR: force must be true or false"
}
}
"datatype" {
set ic_hmm_datatype $val
}
"savetype" {
switch $val {
"save" {
set save_filetype data
}
"nosave" {
set save_filetype scratch
}
default {
error "ERROR: $arg $val, valid values for $arg are 'save' or 'nosave'"
}
}
}
default {
error "ERROR: $arg should be 'datatype' 'savetype' or 'force'"
}
}
}
set det_type [::scan::runscan_cmd -get detector]
if {$det_type == "histmem"} {
# hmscan ignores mode and preset, we use FAT_COUNT_METHOD and FAT_COUNT_STOP
::histogram_memory::count_method $mode
::histogram_memory::count_size $preset
hmscan clear
hmscan add $scanvar $start $step
} elseif {$det_type == "bmon"} {
set mode [string tolower $mode]
switch -glob $mode {
"time" { set bms_mode "timer" }
"monitor" { set bms_mode "monitor" }
default {return -code error "ERROR: mode should be 'time' or 'monitor' not $mode"}
}
bmonscan clear
bmonscan add $scanvar $start $step
} else {
return -code error "ERROR: detector type should be 'histmem' or 'bmon' not $det_type"
}
::scan::runscan_cmd -set numpoints $numpoints
::scan::runscan_cmd -set scan_variable $scanvar
::scan::runscan_cmd -set scan_start $start
::scan::runscan_cmd -set scan_stop $stop
::scan::runscan_cmd -set feedback scan_step $step
::scan::runscan_cmd -set mode $mode
::scan::runscan_cmd -set preset $preset
if {$det_type == "histmem"} {
hmscan run $numpoints timer 0
} else {
bmonscan run $numpoints $bms_mode $preset
}
} message ] {
set force_scan false
return -code error "ERROR [info level 0]\n$message"
} else {
set force_scan false
return $message
}
}
}
namespace import ::scan::runscan
publish runscan user
sicslist setatt runscan privilege internal