#!/bin/sh  
# \
exec oagwish "$0" "$@"

#
# $Log: not supported by cvs2svn $
# Revision 1.8  2004/02/25 22:58:27  shang
# added extension .resp to the response matrix filename
#
# Revision 1.7  2004/02/13 17:20:43  shang
# replaced APSMakeSafeQualifierString by APSMakeSafeQualifierStringForEval to fix
# the mixing character , and / problem for comment
#
# Revision 1.6  2004/02/13 16:03:49  shang
# added "save raw data" option to save the raw data into rawData sub-directory
#
# Revision 1.5  2003/11/11 20:37:20  shang
# changed the default directory of loading configuration to be the same as
# reponse file and used file selection dialog for saving configurations.
#
# Revision 1.4  2003/11/06 22:18:54  shang
# changed the symbolic name of readbacks from <pvname> to <pvname>Slope
# in definition file to be consistent with the column names of the inverse
# response matrix
#
# Revision 1.3  2003/10/16 15:03:16  shang
# fixed the mis-spelling "dialy" to "daily"
#
# Revision 1.2  2003/10/15 19:49:12  shangS
# fixed the problem in processing inverse response matrix
#
# Revision 1.1  2003/09/30 22:33:52  shang
# first version for response matrix measurement
#S
# the interface is copied from quickExperiment, SHANG

set auto_path [linsert $auto_path 0  /usr/local/oag/apps/lib/$env(HOST_ARCH)]
set auto_path [linsert $auto_path 0 /usr/local/oag/lib_patch/$env(HOST_ARCH)]
set CVSRevisionAuthor "\$Revision: 1.9 $ \$Author: shang $"

APSApplication . -name boosterResponseMeasurement -version $CVSRevisionAuthor \
  -overview {This is the quickResponseMeasurement utility.  It provides a simple interface to the sddsexperiment program, which allows varying and measuring EPICS data, and logging the results and some statistical analysis to an SDDS file.  The data can be plotted after it is collected. You can also manipulate and display the data offline using the SDDS toolkit programs.}

set Variables 0
set VariableLines 1

set mainStatus "Press ADD to enter more PV names for measurements and variables"

proc SetMainStatus {text} {
    global mainStatus
    set mainStatus "[exec date] $text"
    update
}

proc UpdateRegion {args} {
    global index env configDir responseFile plane varScroll plane region
    set responseFile [APSGoToDailyDirectory -subdirectory BoosterBPMResponse-$plane]/$region.resp
    SetInvResponseFile
}

proc LoadInput {args} {
    global index env configDir responseFile plane varScroll StartBumpList EndBumpList StartBump EndBump measFile plane region
    
    set measFile  /home/helios/oagData/booster/responseMeasFiles/meas${plane}.sdds
    set measFile /home/helios/oagData/booster/responseMeasFiles/measAll.sdds
    set varFile /home/helios/oagData/booster/responseMeasFiles/variables${plane}.sdds
    
    set names  [exec sdds2stream -col=ControlName $varFile ]
    set symbols [exec sdds2stream -col=SymbolicName $varFile]
    set initialValues [exec sdds2stream -col=InitialValue $varFile]
    set finalValues [exec sdds2stream -col=FinalValue $varFile]
    set relativeValues [exec sdds2stream -col=Relative $varFile]
   # ClearVarSettings $varScroll 0
  #  foreach name $names symbol $symbols init $initialValues final $finalValues relative $relativeValues {
  #      MakeNewVariableLine $varScroll -pvName $name  -symbolName $symbol \
  \#        -initVal [format %.3f $init] -finalVal [format %.3f $final] -relative $relative
   # }
    set responseFile [APSGoToDailyDirectory -subdirectory BoosterBPMResponse-$plane]/$region.resp
    SetInvResponseFile
}

set serverStarted 0
proc StartCorrectorLoader {args} {
    global loaderID VariableLines VarPVname VarSymName serverStarted DC startCorrList

    
    set startCorrList [GetSelectedCorrectors]
    set loaderID ""
    
    if ![llength $startCorrList] {
        return -code error "No correctors selected."
    }
    SetMainStatus "starting corrector loader..."
    catch {exec checkAndLoadBoosterBump -corrList $startCorrList -DC $DC &} loaderID
    set serverStarted 1
    SetMainStatus "started."
}
set loaderID ""
proc KillCorrectorLoader {args} {
    global loaderID serverStarted
    if [string length $loaderID] {
        SetMainStatus "Killing corrector loader ..."
        if [catch {exec kill -9 $loaderID} result] {
            SetMainStatus "Error in killing corrector loader: $result"
            return
        }
        set serverStarted 0
        SetMainStatus "done."
    }
}

set iocList [exec sddsprocess /home/helios/oagData/SCR/requestFiles/SBPMWaveform.config -pipe=out \
               -match=par,Location=Accel -match=par,BPMType=Booster | sdds2stream -pipe -par=IOCName]
proc ChangeArmState {args} {
    set state ""
    APSParseArguments {state}
    global iocList
    switch $state {
        disable {
            set value 0
        }
        enable {
            set value 1
        }
        default {
            return -code error "Invalid state - $state provided."
        }
    }
    
    if [catch {exec cavput -list=[join $iocList ,]  -list=:intervalAvg:AutoRestart=$value -pendIO=30
        exec cavput -list=[join $iocList ,]  -list=:turn:gtr:arm=$value -pendIO=30 } result] {
        return -code error "Error $state bpms: $result"
    }
    if $value {
        if [catch {exec cavput -list=[join $iocList ,] -list=:startRamp_er.OUT4=1 -pend=30} result] {
             return -code error "Error $state bpms (:startRamp_er.OUT4): $result"
        }
    }
}

proc RestoreRAM {args} {
    global BBPMWaveformSCR dialogBoxResponse

    set dialogBoxResponse 0
    set BBPMWaveformSCR(ShortFilename) ""
    APSDialogBox .diag  -cancelCommand "set dialogBoxResponse cancel" \
      -okCommand "set dialogBoxResponse ok"  -name "Select SCR"
    APSAddSCRDialog .scr -parent .diag.userFrame -system BBPMWaveform \
      -label "Choose SCR file for RAM restore" \
      -arrayName BBPMWaveformSCR \
      -defaultFile $BBPMWaveformSCR(ShortFilename)
    tkwait window .diag
    
    if {$dialogBoxResponse=="cancel"} {
        SetMainStatus "load RAM was cancelled."
        return
    }
    if ![string length $BBPMWaveformSCR(ShortFilename)] {
        SetMainStatus "No SCR file chosen."
        return
    }
    set tmpRoot /tmp/[APSTmpString]
    set scrFile $BBPMWaveformSCR(ShortFilename)
   
    if [catch {exec sddsprocess /home/helios/oagData/SCR/snapshots/BBPMWaveform/$scrFile $tmpRoot.restore \
                 -match=col,IsProtected=n -match=col,IsReadOnly=n  } result] {
        return -code error "Error processing $scrFile : $result"
    }
    if [catch {exec sddscasr -restore $tmpRoot.restore -waveform=directory=/home/helios/oagData/SCR/snapshots/BBPMWaveform,onefile,extension=.waveform.gz,rootname=[file root $scrFile] } result] {
        return -code error "Error restoring RAM from $scrFile: $result"
    }
    SetMainStatus "restored $scrFile."
}

proc LaunchADT {args} {
    global index

    exec adt -geometry +30+0 -f /home/helios/oagData/ADTFiles/booster/booster.bpm.pv-region$index.pv &
}

proc SelectCorrectors {args} {
    set all 1
    APSParseArguments {all}
    global sectorList 
  
    foreach quad {B1 B2 B3 B4} {
	foreach sector $sectorList {
	    set nm ${quad}$sector
	    global $nm
	    set $nm $all
	}
    }
}
proc GetSelectedCorrectors {args} {
    global sectorList plane missingListH missingListV
    
    set corrList ""
    foreach quad {B1 B2 B3 B4} {
	foreach sector $sectorList {
	    set nm ${quad}$sector
	    global $nm
	    if [set $nm] {
		lappend corrList $nm
	    }
	}
    }
    if ![llength $corrList] {
	return -code error "No correctors selected."
    }
    set corrList1 ""
    switch $plane {
        H {
            set missingList $missingListH
        }
        V {
            set missingList $missingListV
        }
    }
    foreach corr $corrList {
        set corrpv ${corr}$plane
        if [lsearch -exact $missingList $corrpv]<0 {
            lappend corrList1 $corrpv
        }
    }
    SetMainStatus "Selected $corrList1"
    return $corrList1
}

proc UpdateProcRegion {args} {
    global index env configDir responseFile plane varScroll plane procRegion
    set responseFile [APSGoToDailyDirectory -subdirectory BoosterBPMResponse-$plane]/$procRegion.resp
    SetInvResponseFile
}

set missingListV {B2C9V}
set missingListH ""

set plane H
APSScrolledStatus .status -parent .userFrame -textVariable mainStatus -width 80
set index all
set region regionall
set regionList {region0 region1 region2 region3 region4 region5 region6 region7 region8 region9 regionall}
APSRadioButtonFrame .index -parent .userFrame -label "Time region:" -variable region \
  -valueList $regionList  \
  -buttonList $regionList  \
  -commandList "[APSReplicateItem -item UpdateRegion -number 11]" \
  -orientation horizontal
APSRadioButtonFrame .plane -parent .userFrame -label "Plane:      " -variable plane \
  -valueList {H V} -buttonList {H V} -orientation horizontal -commandList {LoadInput LoadInput}
set DC 0
APSRadioButtonFrame .dc -parent .userFrame -label "DC ramp?    " -buttonList {Yes No} -valueList {1 0} \
    -variable DC -orientation horizontal 

APSLabeledEntry .measFile -parent .userFrame -label "Measurement File:" -width 80 \
    -textVariable measFile
  
APSFrame .variable -parent .userFrame  -label Actuators -packOption \
  "-side top -fill x" -contextHelp "Enter data for variable PVs in this frame."

set Steps 3
set InitialValue -0.1
set FinalValue 0.1
set Relative 0

APSFrameGrid .grid -parent .userFrame.variable.frame -xList {x1 x2 x3 x4}
APSLabeledEntry .steps -parent .userFrame.variable.frame.grid.x1 -label \
  "Steps:  " -textVariable Steps -width 10 -contextHelp "Enter the number of steps (or samples) in this field." -packOption "-side left"
  
APSLabeledEntry .init -parent .userFrame.variable.frame.grid.x2 -label "Initial:" \
  -textVariable InitialValue -width 25 -packOption "-side left"
APSLabeledEntry .final -parent .userFrame.variable.frame.grid.x3 -label "Final:" \
  -textVariable FinalValue -width 25 -packOption "-side left"
#APSCheckButtonFrame .rel -parent .userFrame.variable.frame.grid.x4 -buttonList "Relative" \
#  -variableList Relative -label "" -orientation horizontal -packOption "-side left"

set w1 .userFrame.variable.frame
set sectorList {C0 C1 C2 C3 C4 C5 C6 C7 C8 C9}
foreach cat {B1 B2 B3 B4} {
    set varList ""
    set buttonList ""
    set buttonNumber 0
    foreach but $sectorList {
	set ${cat}$but 0
	lappend varList ${cat}$but
        incr buttonNumber
        lappend buttonList $buttonNumber
    }
    APSCheckButtonFrame .c$cat -parent $w1 -label "$cat" -buttonList $sectorList -variableList $varList \
      -orientation horizontal -allNone 1
}
APSButton .all -parent $w1  -text "Select All" -command "SelectCorrectors -all 1"
APSButton .clear -parent $w1 -text "Clear All" -command "SelectCorrectors -all 0"


if {0} {
set varScroll [APSScroll .varScroll -parent .userFrame.variable.frame]
set varScrollFrame .userFrame.variable.frame.varScroll

APSButton .addblank -parent .userFrame.variable.frame -text "ADD" \
  -command "MakeNewVariableLine $varScroll" -contextHelp "Press to add another variable PV name entry line.\n\nDuring the experiment all variables will change together with the same number of steps with step size determined from their respective initial and final values."

APSButton .addcopy -parent .userFrame.variable.frame -text "ADD Copy" \
  -command "MakeNewVariableLine $varScroll -addCopy 1" -contextHelp "Press to add another variable PV name entry line.\n\nDuring the experiment all variables will change together with the same number of steps with step size determined from their respective initial and final values."
#$widget.op.frame.add configure -bd 0
APSButton .load -parent .userFrame.variable.frame -text "LOAD NAMES..." \
  -command LoadVariableData -contextHelp "Press to select a file from which to load variable PV names  and corresponding information -- initial and final value etc."
APSButton .save -parent .userFrame.variable.frame -text "SAVE CONFIG..." \
  -command SaveVariableData -contextHelp "Press to save variable configuration data to a file."

}
APSFrame .execution -parent .userFrame -contextHelp "Enter execution parameters here"

set interval 1
set PostChangePause 2
set rampSteps 1
set inputFile /home/helios/oagData/booster/responseMeasFiles/boosterRespMeasTemplate.exp
set definitionFile ""
set responseFile ""
set invResponseFile ""
set comment ""
set numToAverage 5
set cycles 5
set doStd 0
set doSigma 0
set minimum 0
set saveRawData 1
APSFrameGrid .grid -parent .userFrame.execution.frame -xList {x1 x2}
set w .userFrame.execution.frame.grid.x1
APSLabeledEntry .cycle -parent $w -label "Cycles:" -width 10 -textVariable cycles
APSLabeledEntry .average -parent $w -label "No. to average:" -width 10 -textVariable numToAverage \
  -contextHelp "The number of averages of the readback values."
APSLabeledEntry .interval -parent $w -label "Interval (s): " \
  -textVariable interval -width 10 \
  -contextHelp "Enter the time in seconds between measurements."
APSLabeledEntry .minimum -parent $w -label "Minimum singular value ratio:" -width 10 \
  -textVariable minimum \
  -contextHelp "minimumSingularValueRatio used in sddspseudoinverse:\nReject singular values less than the\nlargest singular value times this ratio."

set w .userFrame.execution.frame.grid.x2
APSLabeledEntry .postChangePause -parent $w -label "Post change pause (s): " \
  -textVariable PostChangePause -width 10 \
  -contextHelp "Enter the time in seconds to wait after a variable change and before measurements are taken."
APSLabeledEntry .rampSteps -parent $w -label "Initial Ramp Steps: " \
  -textVariable rampSteps -width 10 \
  -contextHelp "Enter the steps for ramping pvs from current value to the initial values."

APSCheckButtonFrame .std -parent $w -buttonList {stddev sigma} -label {} \
      -variableList "doStd doSigma" -orientation horizontal -allNone 0 \
      -contextHelp "Press these buttons to enable standard deviation or sigma calculation by sddsexperiment."
APSRadioButtonFrame .saverawdata -parent $w -label "Save raw data:" -buttonList {yes no} \
  -valueList {1 0}  -variable saveRawData  -packOption "-side left" -orientation horizontal \
  -contextHelp "if save raw data is chosen, then raw data will save under sub-directory rawData."

if {0} {
APSLabeledEntry .execution.frame.input -parent .userFrame -label "Input file: " \
  -textVariable inputFile -width 80 \
  -contextHelp "Enter a name for the input file in this field, if you wish to.  Otherwise, a filename is generated for you. \
NOTE: This is the name of an input file to sddsexperiment that quickExperiment generates for you.  If the file you name \
exists already, it will be overwritten.  Use this field if you want quickExperiment to put the sddsexperiment input file \
in a place where you can retrieve it for later commandline use."
bind .userFrame.execution.frame.input.entry <Key> {set tmpInputFile 0}
}
APSLabeledEntry .execution.frame.output -parent .userFrame -label "Response file: " \
  -textVariable responseFile -width 80 \
  -contextHelp "Enter a name for the output file to hold the response matrix."
bind .userFrame.execution.frame.output.entry <Leave> SetInvResponseFile
APSLabeledEntry .execution.frame.inv -parent .userFrame -label "Inverse file: " \
  -textVariable invResponseFile -width 80 \
  -contextHelp "Enter a name for inverse response matrix file"

APSButton .daily -parent .userFrame.execution.frame.output -size small -text "daily" \
  -command "set responseFile [APSGoToDailyDirectory]" -packOption "-side right"

APSLabeledEntry .execution.frame.comment -parent .userFrame -label "Comment: " \
  -textVariable comment -width 80 \
  -contextHelp "Enter the comment what you want to be saved as a parameter in the output file."

set procRegion region0
APSRadioButtonFrame .reg -parent .userFrame -label "BPM region for post-process:" -buttonList {0 1 2 3 4 5 6 7 8 9} \
    -orientation horizontal -valueList {region0 region1 region2 region3 region4 region5 region6 region7 region8 region9} \
    -variable procRegion 

APSFrame .ops -parent .userFrame \
  -contextHelp "Actions are started in this frame."
APSButton .ops.frame.run -parent .userFrame -text RUN -command "APSDisableWidget .userFrame.index;RunExperiment;APSEnableWidget .userFrame.index" \
  -contextHelp "Launches a sddsexperiment subprocess to collect the data."

#APSButton .ops.frame.clear -parent .userFrame -text "CLEAR ALL" \
\#  -command "ClearVarSettings $varScroll; set responseFile \"\"; set logplot 0" \
 \# -contextHelp "Clears all of the settings for quickExperiment, including PV names and filenames."

APSButton .ops.frame.clear -parent .userFrame -text "CLEAR ALL" \
  -command "set responseFile \"\"; set logplot 0" \
  -contextHelp "Clears all of the settings for quickExperiment, including PV names and filenames."

#APSButton .ops.frame.clearMeas -parent .userFrame -text "CLEAR VARS" \
#  -command "ClearVarSettings $varScroll" \
 # -contextHelp "Clears the variable PV settings only."

APSButton .ops.frame.inv -parent .userFrame -text "PostProcess" \
  -command PostProcess \
  -contextHelp "recimpute the inverse matrix with different combinations of actuators/measurements and minimum singular value ratio."
#APSButton .ops.frame.loader -parent .userFrame -text "Start Corrector-Load-Sever" -command "StartCorrectorLoader"
##APSButton .ops.frame.kill  -parent .userFrame -text "Kill Corrector-Load-Sever" -command "KillCorrectorLoader"
#APSButton .ops.frame.plot -parent .userFrame -text "Plot Response Data" \
#  -command PlotResponseData 
  
APSFrame .ops1 -parent .userFrame
APSButton .ops1.frame.clear -parent .userFrame -text "Disable AutoReArm" -command "ChangeArmState -state disable" \
  -contextHelp "disable autoRearm of average process."
APSButton .ops1.frame.enable -parent .userFrame -text "Enable AutoReArm" -command "ChangeArmState -state enable" \
  -contextHelp "enable autoRearm of average process."
APSButton .ops1.frame.restore -parent .userFrame -text "Restore RAM" -command "RestoreRAM" \
  -contextHelp "restore the RAM configuration of selected SCR and start autoReArm of average process."
APSButton .ops1.frame.adt -parent .userFrame -text "Launch ADT" -command "LaunchADT"
APSButton .ops1.frame.clearbump -parent .userFrame -text "Clear Bump" -command "ClearBump" \
  -contextHelp "set all corrector bump amplitude to 0."

proc ClearBump {} {
    if [catch {exec cavput -list=B:B -range=begin=1,end=4 -list=C -range=begin=0,end=9 -list=H,V -list=:CorrectionAI=0 -pend=30 } result] {
        return -code error "Error clear bump: $result"
    }
}
#APSButton .corr -parent .userFrame -text "Get Corrs" -command "GetSelectedCorrectors"

#set configDir [file dirname $inputFile]
proc PostProcess {args} {
    set rootname ""
    set corrList ""
    APSParseArguments {rootname corrList}
    
    global responseFile invResponseFile procRegion measFile sectorList plane minimum comment
    set dir [file dir $responseFile]
    
    set dataDir $dir/rawData
    cd $dataDir
    if ![llength $corrList] {
	set corrList ""
	foreach quad {B1 B2 B3 B4} {
	    foreach sector $sectorList {
		lappend corrList ${quad}${sector}$plane
	    }
	}
    }
    set fileList ""
    set bpmFileList ""
    set readbacks [exec sdds2stream $measFile -col=SymbolicName -page=1]
    if ![string length $rootname] {
	set rootname [file tail $responseFile]
    }
    
    foreach corr $corrList {
	if [string length $rootname]>0 {
	    set file ${rootname}_$corr.resp.sdds
	    set rootname0 $rootname
	} else {
	    set file regionAll_${corr}.resp.sdds
	    puts $file
	    set rootname0 regionAll
	    if ![file exist $file] {
		set file ${procRegion}_${corr}.resp.sdds
		if ![file exist $file] {
		    continue
		}
		set rootname0 $procRegion
	    }
	}
	if ![file exist  ${rootname0}_${corr}.resp.sdds] {
	    continue
	}
	if [catch {exec sddsenvelope ${rootname0}_${corr}.resp.sdds -pipe=out -mean=* \
		       | sddsconvert -pipe=in ${rootname0}_$corr.resp -edit=col,*,%/Mean//} result] {
	    SetMainStatus "Error in processing raw data: $result"
	    return
	}
	if [catch {exec sddsslopes ${rootname0}_$corr.resp ${rootname0}_${corr}_${procRegion}.slope \
		       -independentVariable=$corr -col=B*${procRegion}*  \
		       -exclude= } result] {
	    SetMainStatus "Error in getting slopes for $corr: $result"
	    return
	}
	set col ""
	set color 0
	foreach meas $readbacks {
	    if [string match *${procRegion}* $meas] {
		append col " -col=$corr,$meas -graph=sym,scale=2,connected,type=$color,sub=$color"
		incr color
	    }
	}
	eval exec sddsplot -mode=y=offset ${rootname0}_${corr}.resp -legend $col &
	lappend fileList ${rootname0}_${corr}_$procRegion.slope
	if [catch {exec sddsconvert ${rootname0}_${corr}_$procRegion.slope -delete=col,*Intercept -pipe=out \
		       | sddstranspose -pipe \
		       | sddsconvert -pipe=in -rename=col,OldColumnNames=BPMNames ${rootname}_${corr}_$procRegion.bpm } result] {
	    return -code error $result
	}
	lappend bpmFileList ${rootname0}_${corr}_$procRegion.bpm
    }
    if ![llength $bpmFileList] {
	return -code error "No reponse file generated!"
    }
    if [file exist $responseFile] {
	exec rm $responseFile
    }
    if [llength $bpmFileList]>1 {
        if [catch {eval exec sddsxref $bpmFileList $responseFile -leave=BPMNames} result] {
            return -code error $result
        }
    } else {
        file copy [lindex $bpmFileList 0] $responseFile
    }
    
    if [catch {exec sddspseudoinverse $responseFile -pipe=out \
                 -minimumSingularValueRatio=$minimum -oldColumnNames=Actuators \
                 | sddsprocess -pipe=in $invResponseFile "-print=par,comment,$comment" } result] {
        SetMainStatus "Error in processing data: $result; Inverse response matrix is not created"
        return
    }
    set condition [exec sdds2stream $invResponseFile -par=ConditionNumber -page=1]
    SetMainStatus "Inverse Response matrix $invResponseFile created, condition number is $condition." 
    return
    if ![file exist $responseFile] {
        return -code error "The response file does not exist!"
    }
    
    
   # SetMainStatus "InvRespMatrix does not work now, checking it..."
  #  exec InvRespMatrix -inputFile $responseFile -outputFile $invResponseFile &
}

proc LoadVariableData {} {
    global env varScroll configDir responseFile
    if ![info exist configDir] {
	set configDir [file dirname $responseFile]
    }
    set filename [APSFileSelectDialog .chooseInputFile -width 40 -path $configDir]
    if [string length $filename]==0 { 
        return 
    }
    if [string first " " $filename]!=-1 {
        SetMainStatus "Filename may not have spaces in it."
        return
    }
    if {![APSCheckSDDSFile -fileName $filename]} {
        SetMainStatus "$filename is not an SDDS file."
        return
    }
    set configDir [file dirname $filename]
    set colNames [APSGetSDDSNames -fileName $filename -class column]
    if {[llength $colNames]<1} {
        SetMainStatus "$filename doesn't contain any data columns from which to get PV names."
        return 
    }
    if {[lsearch -exact $colNames "ControlName"]!=-1} {
        set columnName ControlName
    } elseif {[lsearch -exact $colNames "Device"]!=-1} {
        set columnName Device
    } else {
        SetMainStatus "$filename doesn't contain any data columns from which to get PV names."
        return
    }
    set names [exec sdds2stream $filename -col=$columnName -page=1]
    if {[llength $names]==0} {
        SetMainStatus "$filename has no process variable names."
        return
    }
    if [lsearch -exact $colNames SymbolicName]>=0 {
        set symbols [exec sdds2stream $filename -col=SymbolicName -page=1]
    } else {
        set symbols $names
    }
    set initialValues ""
    if [lsearch -exact $colNames "InitialValue"]!=-1 {
        set initialValues [exec sdds2stream $filename -column=InitialValue -page=1]
    } else {
        for {set i 0} {$i< [llength $names]} {incr i} {
            lappend initialValues 0
        }
    }
    set finalValues ""
    if [lsearch -exact $colNames "FinalValue"]!=-1 {
        set finalValues [exec sdds2stream $filename -column=FinalValue -page=1]
    } else {
        for {set i 0} {$i< [llength $names]} {incr i} {
            lappend finalValues 0
        }
    }
    set relativeValues ""
    if [lsearch -exact $colNames "Relative"]!=-1 {
        set relativeValues [exec sdds2stream $filename -column=Relative -page=1]
    } else {
        for {set i 0} {$i< [llength $names]} {incr i} {
            lappend relativeValues 0
        }
    }
    
    ClearVarSettings $varScroll 0
    foreach name $names symbol $symbols init $initialValues final $finalValues relative $relativeValues {
        MakeNewVariableLine $varScroll -pvName $name  -symbolName $symbol \
          -initVal [format %.3f $init] -finalVal [format %.3f $final] -relative $relative
    }
    SetMainStatus "Measurement data loaded from $filename."
}

proc SaveVariableData {args} {
    global VariableLines VarPVname configDir InitValue FinalValue Relative VarSymName
    set filename ""
    APSParseArguments {filename}
    set pvList ""
    set symbolList ""
    set initList ""
    set finalList ""
    set relativeList ""
    for {set i 1} {$i<$VariableLines} {incr i} {
        if [string length $VarPVname($i)]!=0 {
            if [catch {SearchPVName -pvName $VarPVname($i)} result] {
                SetMainStatus "$result"
                continue
            } else {
                lappend pvList $VarPVname($i)
                lappend initList $InitValue($i)
                lappend finalList $FinalValue($i)
                lappend relativeList $Relative($i)
                if [string length $VarSymName($i)] {
                    lappend symbolList $VarSymName($i)
                } else {lappend symbolList $VarPVname($i) }
            }
        }
    }
    if ![llength $pvList] {
        SetMainStatus "No measurements specified--can't save."
        return
    }
    if ![string length $filename] {
	global configDir  responseFile
	if ![info exist configDir] {
	    set configDir [file dirname $responseFile]
	}
	set filename [APSFileSelectDialog .choosedirectory -listDir $configDir \
			  -title "output file for saving variable configuration" -checkValidity 0 ] 
    }
    if [string length $filename]==0 {
        SetMainStatus "Filename is provided!"
        return
    }
    set configDir [file dirname $filename]
    if [string first " " $filename]!=-1 {
        SetMainStatus "Filename may not contain spaces--nothing saved."
        return
    }
    if [file exist $filename] {
        if ![APSYesNoPopUp "$filename already exist, overwrite it?"] {
            SetMainStatus "configuration saving is cancelled."
            return
        }
	exec rm $filename
    }
    if [catch {exec sddsmakedataset $filename -defaultType=string -col=ControlName -data=[join $pvList ,] \
                 -col=ReadbackName -data=[join $pvList ,] \
                 -col=SymbolicName -data=[join $symbolList ,] \
                 -col=InitialValue,type=double -data=[join $initList ,] \
                 -col=FinalValue,type=double -data=[join $finalList ,] \
                 -col=Relative,type=short -data=[join $relativeList ,] } result] {
        return -code error $result
    }
    SetMainStatus "Save completed to file $filename."
}


proc ClearVarSettings {widget0 {popUp 1}} {
    global VariableLines VarPVname InitValue FinalValue Relative

    if {$popUp} {
	if {![APSYesNoPopUp "Really? Clear variable settings?"]} { return }
    }
    for {set i $VariableLines} {$i>0} {incr i -1} {
        if {[winfo exists $widget0.m$i]} { destroy $widget0.m$i}
        set VarPVname($i) ""
        set InitValue($i) 0
        set FinalValue($i) 0
        set Relative($i) 0
    }
    set VariableLines 1
    SetMainStatus "Press ADD to enter measurement or variable PV names for sddsexperiment"
}

proc MakeNewVariableLine {widget0 args} {
    global varScrollFrame VarSymName
    global VariableLines VarPVname 
    global InitValue FinalValue Relative

    set addCopy 0
    set pvName ""
    set symbolName ""
    set initVal 0
    set finalVal 0
    set relative 0
    APSParseArguments {addCopy}
    APSFrame .m$VariableLines -parent $widget0 -packOption "-anchor w -fill x"
    set widget $widget0.m$VariableLines.frame
    $widget configure -relief flat -bd 0
    APSFrame .op  -parent $widget -packOption "-side left" 
    $widget.op.frame configure -relief flat -bd 0
    APSFrame .data  -parent $widget -height 1
    $widget.data.frame configure -relief flat -bd 0

    if $addCopy {
        set lastVar [expr $VariableLines - 1]
        set pvName $VarPVname($lastVar)
        set symbolName $VarSymName($lastVar)
        set initVal $InitValue($lastVar)
        set finalVal $FinalValue($lastVar)
        set relative $Relative($lastVar)
    }        
    APSParseArguments {pvName symbolName initVal finalVal relative}

    APSButton .delete -parent $widget.op.frame -text "D" -size small \
      -command "DeleteVariableLine $widget0 $VariableLines" \
      -contextHelp "Press to delete the corresponding PV name entry line." 
    $widget.op.frame.delete configure -bd 0
    $widget.op.frame.delete.button configure -font -adobe-courier-medium-r-normal-*-12-*-*-*-*-*-*-*

    APSButton .clear -parent $widget.op.frame -text "C" -size small \
      -command "ClearVariableLine $VariableLines" \
      -contextHelp "Press to clear the corresponding PV name entry line." 
    $widget.op.frame.clear configure -bd 0
    $widget.op.frame.clear.button configure -font -adobe-courier-medium-r-normal-*-12-*-*-*-*-*-*-*
    
    set VarPVname($VariableLines) $pvName
    APSLabeledEntry .x -parent $widget.data.frame -label "PV:" -textVariable \
      VarPVname($VariableLines) -width 20 \
      -contextHelp "Enter the name of a variable process variable (PV) in this field." \
      -packOption "-side left"
    $widget.data.frame.x configure -bd 0
    set VarSymName($VariableLines) $symbolName
    APSLabeledEntry .y -parent $widget.data.frame -label "Symbolic Name:" -textVariable \
      VarSymName($VariableLines) -width 20 \
      -contextHelp "Enter the symbolic name of a variable process variable (PV) in this field." \
      -packOption "-side left"
    $widget.data.frame.y configure -bd 0
    
    set InitValue($VariableLines) $initVal
    APSLabeledEntry .init -parent $widget.data.frame -label "Initial:" -textVariable \
      InitValue($VariableLines) -width 6 \
      -contextHelp "Enter the initial value for the variable process variable (PV) in this field." \
      -packOption "-side left"
    $widget.data.frame.init configure -bd 0
    set FinalValue($VariableLines) $finalVal
    APSLabeledEntry .final -parent $widget.data.frame -label "Final:" -textVariable \
      FinalValue($VariableLines) -width 6 \
      -contextHelp "Enter the final value for the variable process variable (PV) in this field." \
      -packOption "-side left"
    $widget.data.frame.final configure -bd 0
    set Relative($VariableLines) $relative
    APSCheckButtonFrame .rel -parent $widget.data.frame -label {} -buttonList {Relative} \
      -variableList Relative($VariableLines) -orientation horizontal \
      -contextHelp "If checked, then the variation range is defined relative to the PV's original value." \
      -packOption "-side left"
    $widget.data.frame.rel configure -bd 0
    
    incr VariableLines
    tkwait visibility $widget.data.frame.rel
    APSScrollAdjust $varScrollFrame -numVisible 5
}


proc DeleteVariableLine {widget0 number} {
    global VariableLines VarPVname VarSymName
    if {$number} {
        destroy $widget0.m$number
        set VarPVname($number) ""
        set VarSymName($number) ""
    } else {
        bell
    }
}

proc ClearVariableLine {number} {
    global VariableLines VarPVname 
    global InitValue FinalValue Relative

    set VarPVname($number) ""
    set InitValue($number) 0
    set FinalValue($number) 0
    set Relative($number) 0
}

set outputListLength 0
proc RunExperiment {} {
    global doStd doSigma Average comment startCorrList InitialValue FinalValue Relative plane
    global responseFile inputFile experimentDone minimum invResponseFile
    global PostChangePause interval Steps  
    global numToAverage doStd doSigma VarSymName saveRawData rampSteps
    global index StartBumpList EndBumpList serverStarted measFile region cycles procRegion
    
    catch {ClearBump}
    
  #  if !$serverStarted {
  #      SetMainStatus "please start the corrector-loader-server before taking experiment."
  #      return
  #  }
    set corrList [GetSelectedCorrectors]
   
    switch $plane {
        H {
            set coord x
        }
        V {
            set coord y
        }
    }
    #set StartBump [lindex $StartBumpList $index]
    #set EndBump [lindex $EndBumpList $index]
    #SetMainStatus "Setting region pv ..."
    #if [catch {exec cavput -list=B:CorrBumpStart=$StartBump,B:CorrBumpEnd=$EndBump -pend=30} result] {
    #    return -code error "Error setting start and end ramp pvs: $result"
    #}
    #temporarily use B:CorrBumpStart as region pv
    #SetMainStatus "region $index ..."
   # 
   # if [catch {exec cavput -list=B:CorrBumpStart=$index -pend=30} result] {
   #     return -code error "Error setting region pv: $result"
   # }
    SetMainStatus "Setting booster bpm timing..."
    if [catch {exec setBoosterBPMTimeSeg } result] {
        return -code error "Error1: $result"
    }
    #search for controlname
    if [catch {SaveDefinitionFile} result] {
        SetMainStatus "$result"
        return
    }
    SetMainStatus "Checking and creating files ...."
    if {![file exist $inputFile]} {
        SetMainStatus "$inputFile does not exit!"
        bell
        return
    }
    if {[string length $responseFile]==0 || [file isdirector $responseFile]} {
        SetMainStatus "Supply the response filename."
        bell
        return
    }
    if {[string length $invResponseFile]==0 || [file isdirector $invResponseFile]} {
        SetMainStatus "Supply the inverse response filename."
        bell
        return
    }
    if ![string match "*.resp" $responseFile] {
        set responseFile ${responseFile}.resp
    }
    if {[file exists $responseFile]} {
        set ok [APSYesNoPopUp "$responseFile already exists, overwrite it?"]
        if {!$ok} {
            SetMainStatus "Supply a new response matrix filename"
            return
        } else {
            exec rm $responseFile
           # set files [glob -nocomplain [file dir $responseFile]/rawData/[file root [file tail $responseFile]]*]
           # catch {eval file delete -force $files}
        }
    }
    if {[file exists $invResponseFile]} {
        set ok [APSYesNoPopUp "$invResponseFile already exist, overwrite it?"]
        if {!$ok} {
            SetMainStatus "Supply a new inverse response filename"
            return
        } else {
            exec rm $invResponseFile
        }
    }
    
    #save measurements into a file
    if $saveRawData {
        set outDir [file dirname $responseFile]/rawData
        set rootname [file tail $responseFile]
        if ![file exist $outDir] {
            if [catch {exec mkdir -p $outDir} result] {
                SetMainStatus "Can not make directory $outDir: $result."
                return
            }
        }
    }
    SetMainStatus "saving monitor data..."
    if [catch {exec sddscasr -save /home/helios/oagData/booster/responseMeasFiles/bpmTimeRegion.mon \
                 [file root $responseFile]_bpmTime.sdds } result] {
        SetMainStatus "Error in reading BPM timing: $result"
        return
    }
    
    if $saveRawData {
        set tmpRoot ${outDir}/${rootname}
    } else {
        set tmpRoot /tmp/[APSTmpString]
    }
    #always save data
    set tmpRoot ${outDir}/${rootname}
    set fileList ""
    set processList ""
    set readbacks [exec sdds2stream $measFile -col=SymbolicName -page=1]
    set dir [file dirname $responseFile]
    set bpmFileList ""
    
    SetMainStatus "starting experiment..."
    
    foreach corr $corrList {
        after 2000
        set symbol $corr
        set pv B:${corr}:CorrectionAI
        set experimentDone 0
        if !$saveRawData {
            APSAddToTmpFileList -ID response -fileList ${tmpRoot}_$symbol.resp
        } else {
            set file ${tmpRoot}_$symbol.resp
            if [file exist $file] {
                if ![APSYesNoPopUp "$file already exist, overwrite it?"] {
                    SetMainStatus "$file already exist."
                    return
                } else {
                    file delete -force $file
                }
            }
        }
        lappend processList ${tmpRoot}_$symbol.resp
        if {$region=="regionall"} {
            set start 0
            set end 9
            set index -1
            set indexList {0 1 2 3 4 5 6 7 8 9}
        } else {
            set index [scan $region region%ld]
            set start -1
            set end -1
            set indexList $index
        }
        set macro -macro=monitorFile=$measFile,numToAve=$numToAverage,stddev=$doStd,sigma=$doSigma,actuatorName=$pv,columnName=$symbol,nPoints=$Steps,initialValue=$InitialValue,finalValue=$FinalValue,relative=$Relative,postChangePause=$PostChangePause,interval=$interval,rampSteps=$rampSteps,region=$index,corr=$corr,start=$start,end=$end,cycles=$cycles
        if [catch {exec replaceText $inputFile ${tmpRoot}_$symbol.exp \
		       -orig=<monitorFile>,<numToAve>,<stddev>,<sigma>,<actuatorName>,<columnName>,<nPoints>,<initialValue>,<finalValue>,<relative>,<postChangePause>,<interval>,<rampSteps>,<region>,<corr>,<start>,<end>,<cycles> \
		       -repl=$measFile,$numToAverage,$doStd,$doSigma,$pv,$symbol,$Steps,$InitialValue,$FinalValue,$Relative,$PostChangePause,$interval,$rampSteps,$index,$corr,$start,$end,$cycles } result] {
	    return -code error "Error creating exp file: $result"
	}
	#disable beam and resest counts
	#if [catch {SetPulsedMagnetEnables -state 0 -location BoosterExt } result] {
	#    return -code error "Error disable beam: $result"
	#}
	if [catch {exec /home/helios5/ASDOPS/bin/resetTimeouts } result] {
	    return -code error "Error reset timeouts: $result"
	}
	after 1000
	#enable beam
	if [catch {TogglePulsedMagnetEnables -location BoosterExt } result] {
	    return -code error "Error enable beam: $result"
	}
	
        APSExecLog .runExperiment -width 80 -unixCommand \
          "sddsexperiment ${tmpRoot}_$symbol.exp ${tmpRoot}_$symbol.resp.sdds $macro \"-comment=[APSMakeSafeQualifierStringForEval $comment]\" -verbose" \
          -cancelCallback "set experimentDone cancelled" \
          -abortCallback "set experimentDone aborted" \
          -callback "set experimentDone done"
        if !$experimentDone {
            tkwait variable experimentDone
        }
        
        APSEnableWidget .userFrame.index
	catch {exec ramploadnew /home/helios/oagData/booster/ramps/correctors/lattices/default/HVCorr.ramp}
        if {$experimentDone!="done"} {
            SetMainStatus "Experiment was cancelled!"
            return
        }
    }
    SetMainStatus "killing  booster ramp loader."
    KillCorrectorLoader
    if [catch {PostProcess -rootname $rootname -corrList $corrList} result] {
	return -code error "Error processing data: $result"
    }
}


proc SearchPVName {args} {
    set pvName ""
    APSParseArguments {pvName}
    if ![string length $pvName] {
        return
    }
    if [catch {exec cavget -list=$pvName -pend=10} result] {
       return -code error "$pvName not found: $result"
    }
    if {$result=="?"} {
        return -code error "$pvName not found"
    }
}

proc ProcessVariableFiles {args} {
    set processList ""
    set outputFile ""
    APSParseArguments {processList outputFile}
    
    if ![llength $processList] {return -code error "Input files are not provided!"}
    if ![string length $outputFile] { return -code error "output file is not given!"}
    set firstFile [lindex $processList 0]
    if ![regexp {\.(.*)} $firstFile a variable] {
        return -code error "Invalid filename provided."
    }
    set columnNames [exec sddsquery $firstFile -col]
    set readbacks ""
    
    foreach col $columnNames {
        if {$col=="ElapsedTime" || $col=="Time" || $col=="TimeOfDay"} {continue}
        if [string compare $col $variable]==0 {continue}
        lappend readbacks $col
    }
    set tmpRoot /tmp/[APSTmpString]
    foreach file $processList {
        if ![regexp {\.(.*)} $file a variable] {
            return -code error "Invalid filename provided."
        }
        foreach readback $readbacks {
            if [catch {exec sddspfit $file -col=$variable,$readback -pipe=out \
                         | sddsconvert -pipe -rename=par,Slope=${Readback}_Slop \
                     } result] {
                return -code error $result
            }
            
        }
        
    }
}

proc SetInvResponseFile {} {
    global responseFile invResponseFile definitionFile
    if [regexp {(.*)\.} $responseFile a name] {
        set invResponseFile $name.inv
        set definitionFile $name.def
    } else {
        set invResponseFile $responseFile.inv
        set definitionFile $responseFile.def
    }
}

proc SaveDefinitionFile {args} {
    global definitionFile  MeasPVname MeasSymName VarPVname VarSymName VariableLines
    
    set controlNames ""
    set symbolNames ""
    
    for {set i 1} {$i<$VariableLines} {incr i} {
        set VarPVname($i) [string trim $VarPVname($i)]
        set VarSymName($i) [string trim $VarSymName($i)]
        if {[string length $VarPVname($i)] } {
            lappend controlNames $VarPVname($i)
            if ![string length $VarSymName($i)] {
                lappend symbolNames $VarPVname($i)
            } else {
                lappend symbolNames $VarSymName($i)
            }
        }
    }
    if [llength $controlNames] {
        if [catch {exec sddsmakedataset -defaultType=string -col=ControlName \
                     -data=[join $controlNames ,] \
                     -col=SymbolicName -data=[join $symbolNames ,] \
                     $definitionFile } result] {
            return -code error $result
        }
    }
    SetMainStatus "Definitions are save to $definitionFile!"
}

proc PlotResponseData {args} {
    global responseFile invResponseFile
    set dir [file dir $responseFile]
    if ![file exist $dir/rawData] {
        SetMainStatus "No data found"
        return
    }
    cd $dir/rawData
    set files [glob *.resp]
    set tmpRoot /tmp/[APSTmpString]
    if ![llength $files] {
        SetMainStatus "No data found"
        return
    }
    foreach file $files {
        set cols [exec sddsquery -col $file]
        set corr [lindex $cols 3]
        if [regexp {H} $corr] {
            set coord x
        } else {
            set coord y
        }
        exec sddsplot $file -grap=line,vary -layout=2,5  \
          -col=$corr,*region0*:$coord -topline=region0 -endp \
          -col=$corr,*region1*:$coord -topline=region1 -endp \
          -col=$corr,*region2*:$coord -topline=region2 -endp \
          -col=$corr,*region3*:$coord -topline=region3 -endp \
          -col=$corr,*region4*:$coord -topline=region4 -endp \
          -col=$corr,*region5*:$coord -topline=region5 -endp \
          -col=$corr,*region6*:$coord -topline=region6 -endp \
          -col=$corr,*region7*:$coord -topline=region7 -endp \
          -col=$corr,*region8*:$coord -topline=region8 -endp \
          -col=$corr,*region9*:$coord -topline=region9 -endp &
    }
}

set StartBumpList {0    34.0 56.5 79.0 101.5 124.0 146.5 169.0 191  214.0}
set EndBumpList   {29.0 51.5 74   96.5 119   141.5 164.0 186   209  240.0}

#MakeNewVariableLine $varScroll
# MakeNewMeasurementLine .userFrame.measurement.frame
# MakeNewVariableLine .userFrame.variable.frame
LoadInput 
catch {ClearBump}
