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

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)]
APSDebugPath
APSApplication . -name SRSextupoleBeamOffset -version 1 \
    -overview "This application allows measurement of the beam position inside a sextupole using the tune change that occurs when the sextupole current is changed.\n\nIts probably a good idea to know where the tunes are in the first place and enter then in the tune boxes below. The orbit error should be tranfered to setpoint in order for the orbit correction to get a smooth orbit to owkr on when the sextupoles are changed."

set sextConfigStatus ""
APSScrolledStatus .status -parent .userFrame -textVariable sextConfigStatus  \
    -width 90
set sextList {A:S1 A:S2 A:S3 A:S4 B:S3 B:S2 B:S1}
APSSRSectorButtons .sextButtons -parent .userFrame -rootname sext -orientation horizontal \
        -label "Sextupole selections" -description "Sextupole selections" \
        -itemList $sextList -packOption "-side top" \
        -itemLabelList $sextList

APSFrame .controls -parent .userFrame -label "Experiment controls" -packOption "-side top"
set w .userFrame.controls.frame
set setCurrent(1) 0
# with data pool the wait time is very short
set orbitCorrWait 1
set setCurrent(2) 200
# with data pool the wait time is very short
#set orbitCorrWait(2) 1

set outputDir [pwd]
set outputRoot ""
set tunePlane y
set twissFile $OAGGlobal(SRLatticesDirectory)/default/aps.twi
set xTune 0.13
set yTune 0.20
set Nsteps 5

APSFrameGrid .current -parent $w -xList {x1 x2} -yList {y1 y2}
set w2 $w.current

APSLabeledEntry .firstCurrent -parent $w2.x1.y1 -label "First current (A): " \
  -textVariable setCurrent(1) -contextHelp \
  "First value of sextupole current to use."

APSLabeledEntry .currentSteps -parent $w2.x1.y1 -label "Number of steps: " \
  -textVariable Nsteps -contextHelp \
  "Number of steps in current."

APSLabeledEntry .minWait -parent $w2.x1.y2 -label \
  "Wait time for orbit correction (s): " \
  -textVariable orbitCorrWait -contextHelp \
  "Seconds to wait after setting a sextupole. During this time, orbit correction should be on-going.  Allow enough time for the power supply to settle and orbit correction to converge."

APSLabeledEntry .secondCurrent -parent $w2.x2.y1 -label "Second current (A): " \
  -textVariable setCurrent(2) -contextHelp \
  "Second value of sextupole current to use."

APSFrameGrid .tunes -parent $w -xList {x1 x2} -yList {y1 y2}
set w3 $w.tunes

APSRadioButtonFrame .tunePlane -parent $w3.x1.y1 -label "Tune measurement plane: " -orientation horizontal \
    -variable tunePlane -buttonList {x/H y/V} -orientation horizontal -valueList {x y} \
    -contextHelp "Choose the plane for tune measurements.  You must indicate to this script which tune you've set up to measure.  Use x (y) tune when the beta function is expected to be larger in the x (y) plane."


APSLabeledEntry .xTune -parent $w3.x2.y1 -label "x-tune: " \
  -textVariable xTune -contextHelp \
  "Value of x-tune expected during the measurement. This wil be the center frequency of the hpvec."
APSLabeledEntry .yTune -parent $w3.x2.y2 -label "y-tune: " \
  -textVariable yTune -contextHelp \
  "Value of y-tune expected during the measurement. This wil be the center frequency of the hpvec."

APSLabeledEntry .twissfile -parent $w -label \
  "Twiss parameters file: " -textVariable twissFile -width 80 -contextHelp \
  "Enter the name of the directory in which to put files."

APSFrameGrid .output -parent $w -xList {x1 x2} -yList {y1 y2}
set w1 $w.output
APSLabeledEntry .dirname -parent $w1.x1.y1 -label \
  "Output directory: " -textVariable outputDir -width 60 -contextHelp \
  "Enter the name of the directory in which to put files."
APSButton .daily -parent $w1.x1.y1.dirname -packOption "-anchor e" \
  -text "daily" -size small \
  -command {set outputDir [APSGoToDailyDirectory -subdirectory sextupoleOffset]} \
   -contextHelp "Setting daily directory in which to put data files."
APSLabeledEntry .rootname -parent $w1.x1.y2 -label \
  "Output rootname: " -textVariable outputRoot -width 60 -contextHelp \
  "Enter the rootname for the output files.  The sextupole name will be appended to the rootname to make filenames."

set forceReprocessing 0
APSRadioButtonFrame .rb1 -parent $w -variable forceReprocessing \
    -label "Force reprocessing: " -buttonList {Yes No} -valueList {1 0} \
    -orientation horizontal -contextHelp \
    "Choose whether to force reprocessing of measurements that have already been processed."
APSButton .run -parent $w -text Run -contextHelp \
  "Runs the measurements starting at the lowest numbered sectors and proceeding to higher numbered sectors." \
  -command "RunMeasurements $w"
APSButton .process -parent $w -text Process -contextHelp \
  "Processes the measurements for the selected sextupoles for files with the given rootname." \
  -command "ProcessMeasurements $w -reprocess \$forceReprocessing"
APSButton .pause -parent $w -text Pause -contextHelp \
  "Pauses the present measurement." -command "PauseMeasurement $w"
APSButton .resume -parent $w -text Resume -contextHelp \
  "Resumes measurements following a pause." -command "ResumeMeasurement $w"
APSButton .abort -parent $w -text Abort -contextHelp \
  "Aborts the present measurement and all subsequent measurements." \
  -command "AbortMeasurement $w"
APSButton .save -parent $w -text "Save BPM offsets\nto file" -contextHelp \
  "Save calculated BPM offsets for selected sextupoles only for later application." \
  -command "SaveOffsets $w"
APSButton .apply -parent $w -text "Apply BPM\noffsets" -contextHelp \
  "Applies calculated BPM offsets for selected sextupoles only." \
  -command "ApplyOffsets $w"

set pauseRequested 0
set abortRequested 0
set resumeRequested 0
APSDisableButton $w.abort.button
APSDisableButton $w.pause.button
APSDisableButton $w.resume.button
update

set inputFileDir /home/helios/oagData/sr/sextPosition/inputFiles
set xrefDir $OAGGlobal(SRLatticesDirectory)/scripts
set hpSID ""

proc PauseMeasurement {widget} {
    global pauseRequested resumeRequested
    set pauseRequested 1
    set resumeRequested 0
    APSEnableButton $widget.resume.button
    APSDisableButton $widget.pause.button
}

proc ResumeMeasurement {widget} {
    global pauseRequested resumeRequested
    set pauseRequested 0
    set resumeRequested 1
    APSEnableButton $widget.pause.button
    APSDisableButton $widget.resume.button
}

proc AbortMeasurement {widget} {
    global abortRequested
    set abortRequested 1
    APSSetVarAndUpdate sextConfigStatus "Abort requested..."
    APSDisableButton $widget.abort.button
    APSEnableButton $widget.pause.button
    APSEnableButton $widget.resume.button
    APSEnableButton $widget.process.button
    APSEnableButton $widget.run.button
}

proc ApplyOffsets {widget} {
    global abortRequested pauseRequested resumeRequested
    global outputDir outputRoot
    global simulate Nsteps
    set sextFamilyList [list A:S1 A:S2 A:S3 A:S4 B:S3 B:S2 B:S1]
    set nearestBPMList [list A:P2 A:P3 A:P4 B:P5 B:P4 B:P3 B:P2]
    
    
    if ![string length $outputRoot] {
        APSSetVarAndUpdate sextConfigStatus "Output root not given."
        return
    }
    
    set pauseRequested 0
    set abortRequested 0
    set resumeRequested 0
    APSEnableButton $widget.abort.button
    APSEnableButton $widget.pause.button
    APSDisableButton $widget.resume.button
    APSDisableButton $widget.run.button

    set sextList ""
    for {set sector 1} {$sector<=40} {incr sector} {
        foreach sext $sextFamilyList {
            set flagName sextS${sector}$sext
            global $flagName
            set sName S${sector}$sext
            if ![set $flagName] continue
	    lappend sextList S${sector}$sext
	}
    }
    if [llength $sextList] {
	set sextFile sextupoleNames.tmp
	exec sddsmakedataset $sextFile -col=SextName,type=string -data=[join $sextList ,]
	if [catch {join [exec sddsxref $sextFile $outputDir/$outputRoot.results -pipe=out -take=NearestBPM -match=SextName \
			     | sdds2stream -pipe=in -col=NearestBPM] } bpmList] {
	    return -code error $bpmList
	}
	if [catch {join [exec sddsxref $sextFile $outputDir/$outputRoot.results -pipe=out -take=NewBpmOffset -match=SextName \
			     | sddsprintout -pipe=in -col=NewBpmOffset,format=%.4e -nolabel -notitle] } offsetList] {
	    return -code error $offsetList
	}
	set counter 0
	set listString -list
	foreach bpm $bpmList offset $offsetList {
	    if {$counter == 0} {
		append listString =
	    } else {
		append listString ,
	    }
	    set pv $bpm:ms:x:OffsetAO
	    append listString $pv=$offset
	    incr counter
	    if {$counter == 10} {
		if !$simulate {
		    exec cavput $listString
		}
		APSSetVarAndUpdate sextConfigStatus "cavput $listString"
		set counter 0
		set listString -list
	    }
	}
	if {$counter != 10} {
	    if !$simulate {
		exec cavput $listString
	    }
	    APSSetVarAndUpdate sextConfigStatus "cavput $listString"
	}
    }
    APSDisableButton $widget.abort.button
    APSDisableButton $widget.pause.button
    APSDisableButton $widget.resume.button
    APSEnableButton $widget.run.button
}

proc SaveOffsets {widget} {
    global abortRequested pauseRequested resumeRequested
    global outputDir outputRoot
    global simulate Nsteps
    set sextFamilyList [list A:S1 A:S2 A:S3 A:S4 B:S3 B:S2 B:S1]
    set nearestBPMList [list A:P2 A:P3 A:P4 B:P5 B:P4 B:P3 B:P2]
    
    if ![string length $outputRoot] {
        APSSetVarAndUpdate sextConfigStatus "Output root not given."
        return
    }
    
    set pauseRequested 0
    set abortRequested 0
    set resumeRequested 0
    APSEnableButton $widget.abort.button
    APSEnableButton $widget.pause.button
    APSDisableButton $widget.resume.button
    APSDisableButton $widget.run.button

    set sextList ""
    for {set sector 1} {$sector<=40} {incr sector} {
        foreach sext $sextFamilyList {
            set flagName sextS${sector}$sext
            global $flagName
            set sName S${sector}$sext
            if ![set $flagName] continue
	    lappend sextList S${sector}$sext
	}
    }
    if [llength $sextList] {
	if [catch {exec sddsmakedataset -pipe=out -col=SextName,type=string -data=[join $sextList ,] \
		       | sddsxref -pipe $outputDir/$outputRoot.results -take=NearestBPM,NewBpmOffset -match=SextName \
		       | sddsconvert -pipe -rename=col,NearestBPM=ControlName -rename=col,NewBpmOffset=Value \
		       | sddsprocess -pipe=in $outputRoot.offsets "-reedit=col,ControlName,e i :ms:x:OffsetAO" \
		       "-print=col,ValueString,%lf,Value"} result] {
	    APSDisableButton $widget.abort.button
	    APSDisableButton $widget.pause.button
	    APSDisableButton $widget.resume.button
	    APSEnableButton $widget.run.button
	    return -code error $result
	}
    }
    APSDisableButton $widget.abort.button
    APSDisableButton $widget.pause.button
    APSDisableButton $widget.resume.button
    APSEnableButton $widget.run.button
}

proc RunMeasurements {widget} {
    global abortRequested pauseRequested resumeRequested sextList
    global hpSID outputDir outputRoot
    global setCurrent orbitCorrWait tunePlane
    global simulate Nsteps
    set sextFamilyList [list A:S1 A:S2 A:S3 A:S4 B:S3 B:S2 B:S1]
    set sextPolarityList [list 1 -1 -1 1 -1 -1 1]
    set nearestBPMList [list A:P2 A:P3 A:P4 B:P5 B:P4 B:P3 B:P2]
    
    
    if ![string length $outputRoot] {
        APSSetVarAndUpdate sextConfigStatus "Output root not given."
        return
    }
    
    set pauseRequested 0
    set abortRequested 0
    set resumeRequested 0
    APSEnableButton $widget.abort.button
    APSEnableButton $widget.pause.button
    APSDisableButton $widget.resume.button
    APSDisableButton $widget.run.button

    set alreadyThere ""
    for {set sector 1} {$sector<=40} {incr sector} {
        foreach sext $sextList {
            set flagName sextS${sector}$sext
            global $flagName
            if ![set $flagName] continue
            set sName S${sector}$sext
            set fileRoot $outputDir/$outputRoot-$sName
            set filesFound [glob -nocomplain $fileRoot.\[12\].*]
            if [llength $filesFound] {
                lappend alreadyThere $filesFound
            }
        }
    }
    if [llength $alreadyThere] {
        switch \
          [APSMultipleChoice [APSUniqueName .] -question \
             "[llength $alreadyThere] $outputDir/$outputRoot.* files exist for sextpoles you've chosen." \
             -labelList {"Remove old files" "Skip those sextupoles" "Abort"} \
             -returnList {remove skip abort}] {
                 remove {
                     if [catch {eval file delete $alreadyThere} result] {
                         APSSetVarAndUpdate sextConfigStatus "$result"
                         return
                     }
                 }
                 abort {
                     APSSetVarAndUpdate sextConfigStatus "Measurement aborted."
                     return
                 }
             }
    }

    set currentStep [expr ($setCurrent(2) - $setCurrent(1)) / ($Nsteps - 1)]
    set currentList ""
    for {set I 0} {$I < $Nsteps} {incr I} {
	lappend currentList [expr $setCurrent(1) + $I * $currentStep]
    }
    for {set sector 1} {$sector<=40} {incr sector} {
        foreach sext $sextList {
            set index [lsearch $sextFamilyList $sext]
            set polarity [lindex $sextPolarityList $index]
            set nearestBPM [lindex $nearestBPMList $index]
            set flagName sextS${sector}$sext
            if ![set $flagName] continue
            set sName S${sector}$sext
            set fileRoot $outputDir/$outputRoot-$sName
            set filesFound [glob -nocomplain $fileRoot.\[12\].*]
            if [llength $filesFound] {
                APSSetVarAndUpdate sextConfigStatus "Skipping $sName---data already exists"
                continue
            }
            if [catch {exec cavget -list=$sName -list=:CurrentAO} origValue] {
                APSSetVarAndUpdate sextConfigStatus "Skipping $sName due to error: $origValue"
                continue
            }
            if [string compare $origValue ?]==0 {
                APSSetVarAndUpdate sextConfigStatus "Skipping $sName: no connection."
                continue
            }
	    if [catch {ReorderList -list $currentList -value $origValue} localCurrentList] {
		return -code error "ReorderList: $localCurrentList"
	    }
	    
            APSSetVarAndUpdate sextConfigStatus "Doing $sName"
	    set level 0
	    foreach current $localCurrentList {
		incr level
                if [catch {SetSextAndTakeData -value $current -origValue $origValue \
			       -polarity $polarity -tunePlane $tunePlane \
			       -nearestBPM S${sector}$nearestBPM \
			       -sext $sName -rootname $outputDir/$outputRoot-$sName.$level \
			       -orbCorrWait $orbitCorrWait \
			       -abortVariable abortRequested} result] {
                    APSSetVarAndUpdate sextConfigStatus "Error for $sName: $result"
                    break
                }
                if $pauseRequested {
                    APSDisableButton $widget.pause.button
                    APSEnableButton $widget.resume.button
                    set resumeRequested 0
                    set pauseRequested 0
                    APSSetVarAndUpdate sextConfigStatus "Measurement paused. [exec date]"
                    while 1 {
                        after 1000
                        update
                        if $abortRequested {
                            break
                        }
                        if $resumeRequested {
                            break
                        }
                    }
                }
                if $abortRequested {
                    break
                }
            }
	    if !$simulate {
		if [catch {exec cavput -list=$sName:CurrentAO=$origValue -pend=15} result] {
		    APSSetVarAndUpdate sextConfigStatus "Problem restoring sextupole: $result"
		    set abortRequested 1
		}
	    }
            if $abortRequested {
                set sector 41
                break
            }
            APSSetVarAndUpdate sextConfigStatus "Done with $sName"
        }
        if $abortRequested {
            break
        }
    }
    if $abortRequested {
        APSSetVarAndUpdate sextConfigStatus "Aborted."
    }
    APSSetVarAndUpdate sextConfigStatus "Done with series."

    APSDisableButton $widget.abort.button
    APSDisableButton $widget.pause.button
    APSDisableButton $widget.resume.button
    APSEnableButton $widget.run.button
}

proc ReorderList { args } {
    #--- Reorders currentList to follow standartization curve...
    APSParseArguments { list value }
    set N [llength $list]
    set I0 $N
    set list2 [concat $list $list]
    for {set I 0} {$I < $N} {incr I} {
	if {[lindex $list $I] > $value} {
	    set I0 $I
	    break
	}
    }
    set localList ""
    for {set I 0} {$I < $N} {incr I} {
	lappend localList [lindex $list2 [expr $I0 + $I]]
    }
    return $localList
}

proc ProcessMeasurements {widget args} {
    global abortRequested sextList
    global outputDir outputRoot inputFileDir
    global twissFile
    
    set reprocess 0
    APSStrictParseArguments {reprocess}
    
    if ![string length $outputRoot] {
        APSSetVarAndUpdate sextConfigStatus "Output root not given."
        return
    }
    
    set sextExcitFile /home/helios/oagData/sr/magnets/sext/averageExcitCurves.sdds
    set sextLength 0.2527
    set energy 7.0
    set bRho [exec rpnl "$energy 1e9 * c_mks /"]
    
    set abortRequested 0
    APSEnableButton $widget.abort.button
    APSDisableButton $widget.run.button
    APSDisableButton $widget.process.button
    
    set rootnameList ""
    for {set sector 1} {$sector<=40} {incr sector} {
        foreach sext $sextList {
            set flagName sextS${sector}$sext
            global $flagName
            if ![set $flagName] continue
            set sName S${sector}$sext
            set fileRoot $outputDir/$outputRoot-$sName
            set filesFound [glob -nocomplain $fileRoot.?.*]
            if [llength $filesFound] {
                lappend rootnameList $fileRoot
            }
        }
    }
    if ![llength $rootnameList] {
        APSSetVarAndUpdate sextConfigStatus "No files found to process."
        APSDisableButton $widget.abort.button
        APSEnableButton $widget.run.button
        APSEnableButton $widget.process.button
        return
    }
    
    set tmpRoot /tmp/[APSTmpString]
    set slopeFiles ""
    set scanParam CurrentAO
    set measCol Waveform
    set orbitCol x:Adjusted
    set offsetCol x:Offset
    foreach fileRoot $rootnameList {
        if $abortRequested {
            break
        }
        APSSetVarAndUpdate sextConfigStatus "Working on $fileRoot"
        if {[file exists $fileRoot.pfit] && !$reprocess} {
            APSSetVarAndUpdate sextConfigStatus "Already processed---skipping."
            lappend slopeFiles $fileRoot.pfit
            continue
        }
        
        #--- Getting sextupole family name...
        catch {exec sdds2stream $fileRoot.1.tune -param=SextName} sextName
        if {[string first :S1 $sextName] != -1} {
            set sextFamily S1
        } elseif {[string first :S2 $sextName] != -1} {
            set sextFamily S2
        } elseif {[string first :S3 $sextName] != -1} {
            set sextFamily S3
        } elseif {[string first :S4 $sextName] != -1} {
            set sextFamily S4
        } else {
            return -code error "Wrong sextupole name in sextName $sextName."
        }
        
        #--- Getting orbit at nearest BPM...
        catch {exec sdds2stream $fileRoot.1.tune -param=NearestBPM} nearestBPM
	if [catch {eval exec sddscombine [glob -nocomplain $fileRoot.*.orbit] -pipe=out \
		       | sddssort -pipe -para=$scanParam \
		       | sddsprocess -pipe -match=column,BPMName=$nearestBPM \
		       | sddsprocess -pipe -process=$orbitCol,first,Orbit -process=$offsetCol,first,BpmOffset \
		       | sddscollapse -pipe=in $fileRoot.orbit} result] {
	    return -code error "Error getting nearest orbit: $result"
	}
        
        #--- Getting tune peaks as maximum and taking orbit from the above file...
	if [catch {eval exec sddscombine [glob -nocomplain $fileRoot.*.tune] -pipe=out \
		       | sddssort -pipe -para=$scanParam \
		       | sddssmooth -pipe -col=$measCol -passes=0 -despike=passes=5 \
		       | tee $fileRoot.smoothed \
		       | sddsprocess -pipe -process=$measCol,max,TunePeak,functionOf=Tune,position \
		       | sddscollapse -pipe \
		       | sddsprocess -pipe -print=para,NearestBPM,$nearestBPM \
		       -process=TunePeak,first,Tune1 -process=TunePeak,last,Tune2 \"-redef=para,TuneDelta,Tune1 Tune2 - \" \
		       | sddsxref -pipe=in $fileRoot.orbit $fileRoot.peaks -take=Orbit,BpmOffset} result] {
	    return -code error "Error getting tune peaks: $result"
	}
        file delete $fileRoot.orbit
        
        #--- Getting K2s from excitation file and trasferring them to the .peaks file...
        exec sddsinterp $sextExcitFile -pipe=out -col=I,${sextFamily}-BnL -fileValues=$fileRoot.peaks,col=CurrentAO \
          -belowRange=extrap \
          | sddsprocess -pipe=in $fileRoot.K2 "-redef=col,K2,${sextFamily}-BnL $bRho / $sextLength /"
        exec sddsxref $fileRoot.peaks $fileRoot.K2 -nowarning -take=K2
        file delete $fileRoot.K2 $fileRoot.peaks~
        
        #--- Getting slope...
	set nPoints [exec sdds2stream $fileRoot.peaks -rows=bare]
        if {$nPoints == 2} {
            exec sddsprocess $fileRoot.peaks -pipe=out -process=TunePeak,slope,Slope,functionOf=K2 \
              | sddsxref -pipe $fileRoot.1.tune -leave=* \
              -transfer=para,SextName,TunePlaneSign,TunePlane,NearestBPM,SextPolarity \
              | sddsxref -pipe=in $fileRoot.peaks $fileRoot.pfit -leave=* -transfer=para,TuneDelta
        } elseif {$nPoints == 3} {
            exec sddspfit $fileRoot.peaks -pipe=out -col=K2,TunePeak -orders=0,1 -generate \
		| sddsxref -pipe $fileRoot.1.tune -leave=* \
		-transfer=para,SextName,TunePlaneSign,TunePlane,NearestBPM,SextPolarity \
		| sddsxref -pipe=in $fileRoot.peaks $fileRoot.pfit -take=Orbit,BpmOffset -transfer=para,TuneDelta
	} elseif {$nPoints > 3} {
	    set sigmaMin 1e6
	    set dataList ""
	    for {set I 0} {$I <= $nPoints} {incr I} {
		set localDataList \
		    [join [exec sddsprocess $fileRoot.peaks -pipe=out -def=col,Index,i_row "-filter=col,Index,$I,$I,!" \
			       | sddspfit -pipe -col=K2,TunePeak -orders=0,1 -generate \
			       | sddsprocess -pipe "-def=para,SlopeSigmaRel,SlopeSigma Slope / abs" \
			       | sdds2stream -pipe=in -para=Intercept,Slope,SlopeSigma,SlopeSigmaRel] ]
		lappend dataList $localDataList
		if {[lindex $localDataList 3] < $sigmaMin} {
		    set sigmaMin [lindex $localDataList 3]
		    set bestPoint $I
		}
	    }
	    if {[expr [lindex [lindex $dataList $bestPoint] 3] * 2] < [lindex [lindex $dataList $nPoints] 3]} {
		set intercept [lindex [lindex $dataList $bestPoint] 0]
		set slope [lindex [lindex $dataList $bestPoint] 1]
		set slopeSigma [lindex [lindex $dataList $bestPoint] 2]
		exec sddsconvert $fileRoot.peaks -pipe=out -retain=col,K2,TunePeak \
		    | sddsprocess -pipe "-def=col,TunePeakFit,$intercept K2 $slope * +" -def=para,Intercept,$intercept \
		    -def=para,Slope,$slope -def=para,SlopeSigma,$slopeSigma \
		    | sddsxref -pipe $fileRoot.1.tune -leave=* \
		    -transfer=para,SextName,TunePlaneSign,TunePlane,NearestBPM,SextPolarity \
		    | sddsxref -pipe=in $fileRoot.peaks $fileRoot.pfit -take=Orbit,BpmOffset -transfer=para,TuneDelta
		    
	    } else {
		exec sddspfit $fileRoot.peaks -pipe=out -col=K2,TunePeak -orders=0,1 -generate \
		    | sddsxref -pipe $fileRoot.1.tune -leave=* \
		    -transfer=para,SextName,TunePlaneSign,TunePlane,NearestBPM,SextPolarity \
		    | sddsxref -pipe=in $fileRoot.peaks $fileRoot.pfit -take=Orbit,BpmOffset -transfer=para,TuneDelta
	    }
        } else {
	    return -code error "Less than 2 measurement points."
	}
        lappend slopeFiles $fileRoot.pfit
    }
    
    if $abortRequested {
        APSSetVarAndUpdate sextConfigStatus "Aborted."
    } else {
	if [catch {eval exec sddscombine $slopeFiles -pipe=out \
		       | tee $outputDir/$outputRoot.pfit.results \
		       | sddsprocess -pipe -process=Orbit,average,NearestBPMAdjusted -process=BpmOffset,first,BpmOffset \
		       | sddscollapse -pipe \
		       | sddsxref -pipe $twissFile -match=SextName=ElementName -take=beta?,s \
		       | sddssort -pipe -col=s \
		       | sddsprocess -pipe=in $outputDir/$outputRoot.results \
		       -redef=col,Slope,Slope,units=m3 \
		       {"-define=column,betaTunePlane,TunePlaneSign 1 == ? betax : betay $ "} \
		       {"-define=column,SextOrbit,Slope TunePlaneSign * 4 * pi * betaTunePlane / $sextLength / SextPolarity * 1e3 *,units=mm"} \
		       {"-define=column,SextOrbitOffset,SextOrbit NearestBPMAdjusted -,units=mm"} \
		       {"-redef=col,NewBpmOffset,NearestBPMAdjusted BpmOffset + SextOrbit -,units=mm"} } result] {
	    return -code error $result
	}
        
        
        exec sddsplot -column=SextOrbit,NearestBPMAdjusted -graph=symbol $outputDir/$outputRoot.results \
          -aspect=1 &
        
        set filename $outputDir/$outputRoot.pfit.results
        exec sddsplot -layout=1,2 -sep=page,tag -split=page -groupby=page -topline=@SextName \
          -col=K2,TunePeak -tag=pl1 -graph=symbol,scale=2,subtype=1 $filename \
          -col=K2,TunePeakFit -tag=pl1 -graph=line $filename \
          -col=K2,Orbit -tag=pl2 -graph=symbol,connect,scale=2 $filename &
        
        if {[lsearch -exact [exec sddsquery -col $outputDir/$outputRoot.results] SlopeSigma] == -1} {
            exec sddsprintout $outputDir/$outputRoot.results $tmpRoot.printout \
              -formatDefault=double=%10.6f,float=%10.6f \
              -column=SextName \
              -column=Slope,format=%10.2e \
              -column=TuneDelta \
              -column=SextOrbit \
              -column=NearestBPM,label=BPM,format=%6s \
              -column=NearestBPMAdjusted,label=BPMxAdjCC \
              -column=SextOrbitOffset \
              -col=BpmOffset \
              -col=NewBpmOffset
        } else {
            exec sddsprintout $outputDir/$outputRoot.results $tmpRoot.printout \
              -formatDefault=double=%10.6f,float=%10.6f \
              -column=SextName \
              -column=Slope,format=%10.2e \
              -column=SlopeSigma,format=%10.2e \
              -column=TuneDelta \
              -column=SextOrbit \
              -column=NearestBPM,label=BPM,format=%6s \
              -column=NearestBPMAdjusted,label=BPMxAdjCC \
              -column=SextOrbitOffset \
              -col=BpmOffset \
              -col=NewBpmOffset
        }
        APSFileDisplayWindow [APSUniqueName .] -fileName $tmpRoot.printout -deleteOnClose 1 \
          -width 140 -comment "Sextupole beam offset." \
          -printCommand "enscript -r"
    }
    
    APSDisableButton $widget.abort.button
    APSEnableButton $widget.run.button
    APSEnableButton $widget.process.button
}

proc SetSextAndTakeData {args} {
    global simulate
    set sext ""
    set value 0
    set origValue 0
    set orbCorrWait 60
    set rootname ""
    set abortVariable ""
    set polarity 1
    set nearestBPM ""
    set tunePlane x
    APSStrictParseArguments {value origValue rootname sext \
                               orbCorrWait abortVariable \
                               polarity nearestBPM tunePlane} 
    if [string length $abortVariable] {
        global $abortVariable
    }
    global inputFileDir xrefDir xTune yTune
    
    APSSetVarAndUpdate sextConfigStatus "Setting $sext to $value..."
    if !$simulate {
        if [catch {exec cavput -list=$sext -list=:RateDividerAO=100 -pend=15 \
                 } result] {
            catch {exec cavput -list=$sext -list=:RateDividerAO=300 -pend=15}
            return -code error "$result"
        }   
        if [catch {exec cavput -list=$sext -list=:CurrentAO=$value -pend=15 \
                 } result] {
            catch {exec cavput -list=$sext -list=:CurrentAO=$origValue -pend=15}
            return -code error "$result"
        }
    }
    APSSetVarAndUpdate sextConfigStatus "Waiting for PS to change..."
    if !$simulate {
        # some sextupoles have bad tolerances
        set tolerance 3
        if [catch {exec cawait -waitfor=$sext:CurrentAI,lower=[expr $value-$tolerance],upper=[expr $value+$tolerance] -timeLimit=60} result] {
            |            catch {exec cavput -list=$sext -list=:CurrentAO=$origValue -pend=15 }
            return -code error "$result"
        }
    } else {
        after 1000
    }
    APSSetVarAndUpdate sextConfigStatus "Waiting $orbCorrWait sec for orbit correction...[exec date]"
    APSWaitWithUpdate -waitSeconds $orbCorrWait -updateInterval 1 \
      -abortVariable $abortVariable
    APSSetVarAndUpdate sextConfigStatus "Taking orbit data..."
    if [catch {exec sddsmonitor $inputFileDir/srBPMAve.mon $rootname.tmp -steps=1
        exec sddscollect $rootname.tmp -pipe=out \
		   -collect=suffix=:mswAve:x:ErrorCC,column=x:Error \
		   -collect=suffix=:mswAve:y:ErrorCC,column=y:Error \
		   -collect=suffix=:mswAve:x:AdjustedCC,column=x:Adjusted \
		   -collect=suffix=:mswAve:y:AdjustedCC,column=y:Adjusted \
		   -collect=suffix=:ms:x:SetpointAO,column=x:Setpoint \
		   -collect=suffix=:ms:y:SetpointAO,column=y:Setpoint \
		   -collect=suffix=:ms:x:OffsetAO,column=x:Offset \
		   -collect=suffix=:ms:y:OffsetAO,column=y:Offset \
		   | sddsconvert -pipe -rename=col,Rootname=BPMName \
		   | sddsxref -pipe $xrefDir/SRBPMPosition.xref -noWarning -match=BPMName -take=s \
		   | sddsprocess -pipe=in $rootname.orbit -define=para,CurrentAO,$value
        file delete $rootname.tmp} result] {
        return -code error "$result"
    }

    set root /tmp/[APSTmpString].tunes
    switch $tunePlane {
        x {
            set tunePlaneSign 1
        } 
        y {
            set tunePlaneSign -1
        }
    }
    APSSetVarAndUpdate sextConfigStatus "Taking tune data..."
    if !$simulate {
	if [catch {exec getxytunes \
		       -root $rootname -description "$sext experiment" \
		       -only $tunePlane -plotTunes 0 \
		       -xTune $xTune \
		       -yTune $yTune} result] {
	    return -code error "$result. Command was \"getxytunes -root $root -description \"$sext experiment\" -only $tunePlane -plotTunes 0 -xTune $xTune -yTune $yTune"
	}
	if [catch {exec sddsprocess $rootname-$tunePlane.sdds $rootname.tune \
		       -defi=param,CurrentAO,$value -nowarning \
		       -print=parameter,SextName,$sext \
		       -define=parameter,TunePlaneSign,$tunePlaneSign \
		       -print=parameter,TunePlane,$tunePlane \
		       -print=parameter,NearestBPM,$nearestBPM \
		       -define=parameter,SextPolarity,$polarity 
	} result] {
	    return -code error "$result"
	}
	if [catch {exec cavput -list=$sext -list=:RateDividerAO=300 -pend=15 \
		   } result] {
	    return -code error "$result"
	}   
    }
}

APSSetVarAndUpdate sextConfigStatus "Ready."

set simulate 0
