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

# 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)]

APSApplication . -name btsResponseMeasurement \
  -overview {This is the btsResponseMeasurement 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 ProcessBPMData {args} {
    global responseFile coeff corrector
    
    set respDir [file dirname $responseFile]
    set rawDir $respDir/rawData
       
    set readbacks [exec sdds2stream /home/helios/oagData/bts/responseMeasurement/BTS.meas -col=SymbolicName]
	   
    set files [glob -nocomplain $rawDir/*.resp]
    if ![llength $files] {
        continue
    }
    SetMainStatus "Process bpm data ..."
    set fileList ""
    set optList ""
    foreach file $files {
        if ![regexp {$responseFile.(.*).resp} $file match corr] {
            return -code error "Problem extracting corrector name from file $file"
        }
        if [catch {exec sddsslopes $file [file root $file].slopes \
                       -independentVariable=$corr -col=[join $readbacks ,] } result] {
            return -code error "Error getting slopes1: $result"
        }
        if ![info exist coeff($corr)] {
            set coeff($corr) 1.0
        }
        if [catch {exec sddsconvert [file root $file].slopes -delete=col,*Intercept -pipe=out \
                       | sddstranspose -pipe \
                       | sddsconvert -pipe -rename=col,OldColumnNames=BPMNames \
                       | sddsprocess -pipe=in -reedit=col,BPMNames,%/Slope// \
                       "-redefine=col,${corr}Normalized,$corr $coeff($corr) /,units=m/rad" \
                       [file root $file].bpm } result] {
            return -code error "Error processing bpm data: $result"
        }
        lappend optList -col=BPMNames,$corr [file root $file].bpm
        lappend fileList [file root $file].bpm
        
        exec sddsplot $file -grap=sym,conn,sub=1,scale=2 -sep -col=${corr}Normalized,BTS*P*   &
    }
    set len [llength $files]
    set n [expr int(($len+2)/3)]
    puts $fileList
    eval exec sddsplot -split=page -sep  -layout=3,$n -gra=sym,conn,scale=2  $optList &
    if [llength $fileList]>1 {
        if [catch {eval exec sddsxref $fileList -pipe=out -match=BPMNames -leave=BPMNames -nowarnings \
                       | sddsprocess -pipe=in -edit=col,BPMName,BPMNames $respDir/HV.resp } result] {
            return -code error "Error combining response file: $result"
        }
    } else {
        if [catch {exec sddsprocess $fileList -edit=col,BPMName,BPMNames $respDir/HV.resp } result] {
            return -code error "Error processing response file: $result"
        }
    }
}

proc ProcessRespData {args} {
    global responseFile plane
    set fileList ""
    set dir [file dir $responseFile]
    cd $dir
    set fileList $responseFile
    if ![llength $fileList] {
        return -code error "No response file found."
    }
    # puts $fileList
    SetMainStatus "Combining response data..."
    if [catch {eval exec sddscombine $fileList -merge -pipe=out \
                 | tee $responseFile.all \
                 | sddsconvert -pipe=in HV.rm -del=col,Mt:BoosterRampTurnsAO } result] {
        return -code error "Error processing response data1: $result"
    }
    #make LOCO resp file
    SetMainStatus "make LOCO resp file..."
    if [catch {exec sddsconvert HV.rm -del=col,*IS*,*BET* LOCO.rm } result] {
        return -code error "Error creating LOCO resp1: $result"
    }
    set cols [exec sddsquery -col $responseFile.all]
    if [lsearch -exact $cols "BExtTurn"]>=0 {
        #process dispersion data
        SetMainStatus "process dispersion data..."
        set extTurns  60685
        set E_inj  425 
        set E_ext  7000
        set E_per_turn [expr ($E_ext - $E_inj) * 1.00 / $extTurns ]
        set deltaPerTurn [expr $E_per_turn  * 1.00  / $E_ext]
        if [catch {exec sddsprocess $responseFile.all xyDisp-BTS \
                       "-redefine=col,dispersion,BExtTurn $deltaPerTurn /,units=mm"  } result] {
            return -code error "Error processing disperson: $result"
        }
    }
    SetMainStatus "resp process done."
}

proc ClearCorrs {args} {
    global plane
    global correctors corrector
    for {set i 0} {$i<$correctors} {incr i} {
        set corrector($i.checked) 0
    }
}

proc LoadCorrector {args} {
    APSParseArguments {}
    
    global correctors corrector
    set varFile /home/helios/oagData/bts/responseMeasurement/BTS.vars
    set names  [exec sdds2stream -col=ControlName $varFile ]
    set symbols [exec sdds2stream -col=SymbolicName $varFile]
    set elegantName [exec sdds2stream -col=ElementName $varFile]
    set initialValues [exec sdds2stream -col=InitialValue $varFile]
    set finalValues [exec sdds2stream -col=FinalValue $varFile]
    set relativeValues [exec sdds2stream -col=Relative $varFile]
    set rows [llength $names]
    set correctors $rows
    for {set i 0} {$i<$rows} {incr i} {
        set corrector($i.PV) [lindex $names $i]
        set corrector($i.symbol) [lindex $symbols $i]
        set corrector($i.elegantName) [lindex $elegantName $i]
        set corrector($i.init) [format %.2f [lindex $initialValues $i]]
        set corrector($i.final) [format %.2f [lindex $finalValues $i]]
        set corrector($i.relative) [lindex $relativeValues $i]
        set corrector($i.checked) 1
    }
    update
}

set correctors 0

proc CreateCorrectorWidget {args} {
    set parent ""
    APSParseArguments {parent}

    global correctors Corrector 
    set varScroll [APSScroll .varScroll -parent $parent]
    set varScrollFrame $parent.varScroll
    $varScroll configure -relief flat -bd 0
    #load input
    LoadCorrector 
    set parent $varScroll
    set rows $correctors
    for {set i 0} {$i<$rows} {incr i} {
        APSFrame .data$i  -parent $parent -height 1
        set w $parent.data$i.frame
        $w configure -relief flat -bd 0
        APSLabeledEntry .x -parent $w -label "PV:" -textVariable \
          corrector($i.PV) -width 30 \
          -contextHelp "Enter the name of a variable process variable (PV) in this field." \
          -packOption "-side left"
        APSLabeledEntry .y -parent $w -label "Symbolic Name:" -textVariable \
          corrector($i.symbol) -width 15 \
          -contextHelp "Enter the name of a variable process variable (PV) in this field." \
          -packOption "-side left"
        APSLabeledEntry .init -parent $w -label "Initial:" -textVariable \
          corrector($i.init) -width 6 \
          -contextHelp "Enter the initial value for the variable process variable (PV) in this field." \
          -packOption "-side left"
        APSLabeledEntry .final -parent $w -label "Final:" -textVariable \
          corrector($i.final) -width 6 \
          -contextHelp "Enter the initial value for the variable process variable (PV) in this field." \
          -packOption "-side left"
        APSCheckButtonFrame .rel -parent $w -label {} -buttonList {Relative} \
          -variableList corrector($i.relative) -orientation horizontal \
          -contextHelp "If checked, then the variation range is defined relative to the PV's original value." \
          -packOption "-side left"
        APSCheckButtonFrame .scan -parent $w -label {} -buttonList {Scan} \
          -variableList corrector($i.checked) -orientation horizontal \
          -contextHelp "If checked, then the variation range is defined relative to the PV's original value." \
          -packOption "-side left"
        tkwait visibility $w.scan
        APSScrollAdjust $varScrollFrame -numVisible 10
    }
}

set outputDir [APSGoToDailyDirectory -subdirectory btsResponse]

proc SelectAll {args} {
    set value 1
    APSParseArguments {value}
    global correctors corrector
    for {set i 0} {$i < $correctors} {incr i} {
        set corrector($i.checked) $value
    }
}

APSScrolledStatus .status -parent .userFrame -textVariable mainStatus -width 80

APSFrame .variable -parent .userFrame  -label Actuators -packOption \
  "-side top -fill x" -contextHelp "Enter data for variable PVs in this frame."

set Steps 5

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"
  

set w1 .userFrame.variable.frame
$w1 configure -relief flat -bd 0
CreateCorrectorWidget -parent $w1
APSButton .all -parent $w1 -text "Select All" -command {SelectAll}
APSButton .none -parent $w1 -text "Select None" -command {SelectAll -value 0}

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

set interval 1.0
set PostChangePause 1
set rampSteps 1

set definitionFile ""
set responseFile ""
set invResponseFile ""
set comment ""
set numToAverage 6
set doStd 1
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 .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."
APSLabeledEntry .ramp -parent $w -label "Ramp steps:" -width 10 \
  -textVariable rampSteps

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."

APSCheckButtonFrame .std -parent $w -buttonList {stddev sigma} -label {Choose your statistics} \
    -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   -orientation horizontal \
    -contextHelp "if save raw data is chosen, then raw data will save under sub-directory rawData."

APSCheckButtonFrame .dry -parent $w -buttonList {yes!} -label {Shall we dry run?} \
    -variableList "dryrun" -orientation horizontal -allNone 0 \
    -contextHelp "Dry run for debugging. Experiments run but with no change in actuators. Pulsed magnets are not touched."

APSLabeledEntry .execution.frame.dir -parent .userFrame -label "Output dir:" \
  -textVariable outputDir -width 80
APSButton .daily -parent .userFrame.execution.frame.dir -size small -text "daily" \
  -command "set outputDir [APSGoToDailyDirectory -subdirectory btsResponse]" -packOption "-side right"
APSLabeledEntry .execution.frame.output -parent .userFrame -label "Response file root: " \
  -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.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."

APSFrame .ops -parent .userFrame \
  -contextHelp "Actions are started in this frame."

set abort 0
APSButton .ops.frame.run -parent .userFrame -text RUN -command "RunExperiment" \
  -contextHelp "Launches a sddsexperiment subprocess to collect the data."

APSButton .ops.frame.process -parent .userFrame -text ProcessRespData -command ProcessRespData \
  -contextHelp "Process the response data."

APSButton .ops.frame.process1 -parent .userFrame -text ProcessBPMData -command ProcessBPMData \
  -contextHelp "Process the bpm reponse data."



APSButton .ops.frame.inv -parent .userFrame -text "InvRespMatrix" \
  -command RecalculateInv \
  -contextHelp "recompute the inverse matrix with different combinations of actuators/measurements and minimum singular value ratio."

APSFrame .ops1 -parent .userFrame

APSButton .ops1.frame.adt -parent .userFrame -text "bts ADT" -command "exec adt -f /home/helios/oagData/ADTFiles/bts/bts.bpm.positions.pv -a /home/helios/oagData/ADTFiles/bts &"

proc RecalculateInv {args} {
    global responseFile invResponseFile
    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 plane Hcorrectors Hcorrector Vcorrectors Vcorrector
    set filename ""
    APSParseArguments {filename}
    set pvList ""
    set symbolList ""
    set initList ""
    set finalList ""
    set relativeList ""
    set corrs  $correctors
    for {set i 1} {$i<$corrs} {incr i} {
        if  [set corrector($i.checked)] {
            set pvName [set corrector($i.PV)
	    if [catch {SearchPVName -pvName $pvName} result] {
		SetMainStatus "$result"
		continue
	    } else {
		lappend pvList $pvName
                lappend initList [set corrector($i.init)
		lappend finalList [set corrector($i.final)
                lappend relativeList [set corrector($i.relative)
                set symbol [set corrector($i.symbol)
                if [string length $symbol] {
                    lappend symbolList $symbol
                } else {lappend symbolList $pvName }
            }
        }
    }
    if ![llength $pvList] {
        SetMainStatus "No correctors 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 "makedataset(2): $result"
    }
    SetMainStatus "Save completed to file $filename."
}

proc ProcessNewData {args} {
    set symbol ""
    set rootname ""
    APSParseArguments {symbol rootname}
    
    set combineFiles ""
    for {set step 0} {$step<=100} {incr step} {
	set files [glob -nocomplain ${rootname}.${symbol}_*.$step.ave]
	if ![llength $files] {
	    break
	}
	if [catch {eval exec sddscombine $files -pipe=out -merge \
		       | sddsprocess -pipe -process=$symbol,ave,$symbol \
		       -process=*S*P*,ave,%s \
		       | sddscollapse -pipe=in ${rootname}.$symbol.$step } result] {
	    return -code error "Error averaging data for $symbol at step $step: $result"
	}
	lappend combineFiles ${rootname}.${symbol}.$step
    }
    if ![llength $combineFiles] {
	return
    }
    if [catch {eval exec sddscombine $combineFiles -merge ${rootname}.${symbol}.resp } result] {
	return -code error "Error creating response file for $symbol: $result"
    }
}

set outputListLength 0
proc RunExperiment {} {
    global dryrun
    global doStd doSigma Average comment startCorrList InitValue FinalValue Relative plane
    global responseFile inputFile experimentDone minimum invResponseFile
    global PostChangePause interval Steps  
    global numToAverage doStd doSigma VarSymName saveRawData rampSteps VarPVname 

    #search for controlname
    
    if [catch {SaveDefinitionFile} result] {
        SetMainStatus "$result"
        return
    }
    SetMainStatus "Checking and creating files ...."
   
    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
        }
    }
    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
            }
        }
    }

    if !$dryrun {
        SetMainStatus "Suspending BTS controllaw..."
        if [catch {exec cavput -list=BTS:ControlLaw -list=X,Y -list=RC.SUSP=1 -pend=10} result] {
            return -code error "Error suppending BTS controllaw: $result"
        }
    }
    
    SetMainStatus "Starting experiment..."
    #for each plane, need do measurement at different conditions with the same correctors
    #1, meas bts bpms
    #2, meas H plane SR bpms
    #3, meas V plane SR bpms
    
    set respFileList ""
    
    set inputDir  /home/helios/oagData/bts/responseMeasurement
    if !$dryrun {
        if [catch {TogglePulsedMagnetEnables -location GunToBoosterExt} result] {
            return -code error "Error enabling booster beam to extraction: $result"
        }
    }
    set expFile $inputDir/btsResponseMeasTemplate.exp
    set measFile $inputDir/BTS.mon
    
    if $saveRawData {
        set tmpRoot ${outDir}/${rootname}
    } else {
        set tmpRoot /tmp/[APSTmpString]
    }
    set respFile $responseFile
    if [catch {doExperiment -tmpRoot $tmpRoot  \
                   -inputFile $expFile -measFile $measFile -responseFile $respFile} result] {
        SetMainStatus "Error meas reponse: $result"
        return
    }
    
    if [catch {ProcessRespData } result] {
        SetMainStatus "erorr processing response data: $result"
        return
    }
    if !$dryrun {
        SetMainStatus "Resuming BTS controllaw..."
        if [catch {exec cavput -list=BTS:ControlLaw -list=X,Y -list=RC.SUSP=0 -pend=10} result] {
            return -code error "Error resuming BTS controllaw: $result"
        }
    }
    
    SetMainStatus "Done."
}

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
    APSParseArguments {}
    
    global outputDir X
    global correctors corrector
    set definitionFile $outputDir/def
    SetMainStatus "save definition file..."
    set referenceNameFile /home/helios/oagData/ADTFiles/bts/bts.bpm.positions.pv
    set measFile /home/helios/oagData/bts/responseMeasurement/BTS.mon
    if ![file exists $measFile] {
        if [catch {exec sddscombine $referenceNameFile -pipe=out -merge \
                       | sddsconvert -pipe -retain=col,ControlName \
                       | sddsprocess -pipe=in $measFile \
                       -edit=col,SymbolicName,ControlName,%/:PositionM// \
                       -print=col,ReadbackName,%s,SymbolicName } result] {
            return -code error "SaveDefinitionFile(0): $result"
        }
    }
    set controlNameList [join [exec sdds2stream -col=ControlName $measFile]]
    set symbolNameList [join [exec sdds2stream -col=SymbolicName $measFile]]
    
    
    for {set i 0} {$i< $correctors} {incr i} {
        lappend controlNameList [string trim [set corrector($i.PV)]]
        lappend symbolNameList  [string trim [set corrector($i.symbol)]]
    }
    if [catch {exec sddsmakedataset -defaultType=string -col=ControlName \
                 -data=[join $controlNameList ,] \
                 -col=SymbolicName -data=[join $symbolNameList ,] \
                 $definitionFile } result] {
        return -code error "SaveDefinitionFile(1): $result"
    }
    SetMainStatus "Definitions are save to $definitionFile!"
   
}

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 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 &
    }
}

proc doExperiment {args} {
    set tmpRoot ""
    set measFile ""
    set responseFile ""
    set inputFile ""
    APSParseArguments {tmpRoot measFile responseFile inputFile }

    global dryrun
    global experimentDone numToAverage doStd doSigma Steps comment
    global PostChangePause interval rampSteps coeff saveRawData
    global plane correctors corrector abort 
    
    set corrs $correctors
    set fileList ""
    set processList ""
    set readbacks [exec sddsprocess $measFile -pipe=out "-match=col,SymbolicName=*sum,!" \
       | sdds2stream -pipe=in -col=SymbolicName -page=1]
    set bpmFileList ""

    set optList ""
    for {set i 0} {$i<$corrs} {incr i} {
        set checked [set corrector($i.checked)]
        if !$checked {
            continue
        }
        set pv [set corrector($i.PV)]
        set symbol [set corrector($i.symbol)]
        set relative  [set corrector($i.relative)]
        set init [set corrector($i.init)]
        set final [set corrector($i.final)]
        if ![string length $pv] {
            #in case the pv name is not provided
            continue
        }
        SetMainStatus "Scanning $pv ..."
        
        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
       
        set macro -macro=monitorFile=$measFile,numToAve=$numToAverage,stddev=$doStd,sigma=$doSigma,actuatorName=$pv,columnName=$symbol,nPoints=$Steps,initialValue=$init,finalValue=$final,relative=$relative,postChangePause=$PostChangePause,interval=$interval,rampSteps=$rampSteps
	
        SetMainStatus "Starting booster extraction..."
        if !$dryrun {
            if [catch {TogglePulsedMagnetEnables -location GunToBoosterExt} result] {
                return -code error "Error enable booster beam: $result"
            }
        }
	SetMainStatus "Scanning $pv ..."
	set experimentDone 0
	if !$dryrun {
            APSExecLog .runExp -width 80 -unixCommand \
                "sddsexperiment $inputFile ${tmpRoot}.${symbol}.sdds $macro \"-comment=[APSMakeSafeQualifierStringForEval $comment]\" -verbose" \
                -cancelCallback "set experimentDone cancelled" \
                -abortCallback "set experimentDone aborted" \
                -callback "set experimentDone done"
        } else {
            APSExecLog .runExp -width 80 -unixCommand \
                "sddsexperiment -dryrun $inputFile ${tmpRoot}.${symbol}.sdds $macro \"-comment=[APSMakeSafeQualifierStringForEval $comment]\" -verbose" \
                -cancelCallback "set experimentDone cancelled" \
                -abortCallback "set experimentDone aborted" \
                -callback "set experimentDone done"
        }
	tkwait variable experimentDone
	if [catch {exec sddsenvelope ${tmpRoot}.${symbol}.sdds -pipe=out -mean=* \
		       | sddsconvert -pipe=in ${tmpRoot}.${symbol}.resp -edit=col,*,%/Mean// } result] {
	    return -code error "Error processing response data1: $result"
	}
        if !$dryrun {
            SetMainStatus "Stop injection..."
            if [catch {SetPulsedMagnetEnables -location GunToBoosterExt -state 0} result] {
                return -code error "Error enable booster beam: $result"
            }
        }

        #average the monitor data
	

        #process data
        if $saveRawData {
            APSAddToTmpFileList -ID response -fileList ${tmpRoot}.$symbol.slopes
        }
        if [catch {exec sddsslopes ${tmpRoot}.$symbol.resp ${tmpRoot}.$symbol.slopes \
                     -independentVariable=$symbol -col=[join $readbacks ,] \
                     -exclude= } result] {
            return -code error "Error in getting slopes: $result; Inverse response matrix is not created"
        }
       
        set col ""
        set color 0
        foreach meas $readbacks {
            append col " -col=$symbol,$meas -graph=sym,scale=2,connected,type=$color,sub=$color"
            incr color
        }
       # eval exec sddsplot ${tmpRoot}.$symbol.resp -legend $col &
        lappend fileList ${tmpRoot}.$symbol.slope
        if ![info exist coeff($symbol)] {
            set coeff($symbol) 1.0
        }
        if [catch {exec sddsconvert ${tmpRoot}.$symbol.slopes -delete=col,*Intercept -pipe=out \
                     | sddstranspose -pipe \
                     | sddsconvert -pipe -rename=col,OldColumnNames=BPMNames \
                     | sddsprocess -pipe=in -reedit=col,BPMNames,%/Slope// \
                     "-redefine=col,$symbol,$symbol $coeff($symbol) /,units=m/rad" \
                     ${tmpRoot}.$symbol.bpm } result] {
            return -code error $result
        }
        lappend bpmFileList ${tmpRoot}.$symbol.bpm
        lappend optList -col=BPMNames,$symbol  ${tmpRoot}.$symbol.bpm
    }
    #puts $optList
    set len [llength $bpmFileList]
    set n [expr int(($len+2)/3)]
    eval exec  sddsplot -split=page -sep -layout=3,$n -gra=sym,connect,scale=2  $optList &
    foreach meas $readbacks {
        lappend renames ${meas}Slope=${meas}
    }
    if ![llength $bpmFileList] {
        return -code error "No reponse file generated!"
    }
    #puts $bpmFileList
    if [llength $bpmFileList]>1 {
        if [catch {eval exec sddsxref $bpmFileList -leave=BPMNames $responseFile  } result] {
            return -code error "Error combining response file: $result"
        }
    } else {
        if [catch {exec sddsprocess [lindex $bpmFileList 0] $responseFile } result] {
            return -code error "Error defining SR inj mode parameter for response file: $result"
        }
    }
    return 
}

set calibrationFile /home/helios/oagData/bts/responseMeasurement/BTS.vars
set corrName [exec sdds2stream -col=SymbolicName $calibrationFile]
set transferFunction [exec sdds2stream -col=TransferFunction $calibrationFile]
set Brho 20.0138
foreach corr $corrName  val $transferFunction {
    set coeff($corr) [expr $val / $Brho ]
}

set dryrun 0
set responseFile HV.resp
set comment test

# **************************** Emacs Editing Sequences *****************
# Local Variables:
# mode: tcl
# End:
