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

#
# $Log: not supported by cvs2svn $
# Revision 1.8  2008/09/30 18:57:37  shang
# added beep after optimization is done.
#
# Revision 1.7  2008/09/19 21:19:45  shang
# added PauseAfterChange to wait for new setpiont tranfer to data pool, orbit convengence and intensity stablize.
#
# Revision 1.6  2008/05/06 20:45:15  shang
# modifed the GetIDStream proc to select ID strem (ds, us or both) for dual gap ID energy scan to select the closed
# gap or the smaller gap if both are closed or both gaps (move together) if they are the same; and changed the energy
# scan range to be +-0.5Kev of current energy.
#
# Revision 1.5  2008/04/15 21:07:23  shang
# test position scan with Karen and added radio button for selecting the energy gap scan.
#
# Revision 1.4  2007/03/14 22:38:34  shang
# fixed a problem in plotting when energy column does not exist.
#
# Revision 1.3  2006/10/02 17:34:58  shang
# added GetIDStream proc to get the stream name for each ID sector and added stream to the ID gap (or energy) PV names due to the ID device and PV name changes.
#
# Revision 1.2  2006/02/09 22:54:00  emery
# Added more plots to the plot button, including a png file.
#
# Revision 1.1  2006/01/31 19:32:37  shang
# first version.
#
# originally devepoled by Michael Borland

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
APSRenameExecToAPSBGExec

set args $argv
set allowAllSectors 0
set ignoreLock 1
APSStrictParseArguments {allowAllSectors ignoreLock}
set CVSRevisionAuthor "\$Revision: 1.9 $ \$Author: emery $"


set APSExecIDList ""
set optimizeRunControlPV S:IDoptimizationRC
proc KillAPSExecLogs {} {
    global APSExecIDList steeringRunControlPV optimizeRunControlPV
    forech id $APSExecIDList {
        APSExecLogAbort -id $id -destroy 1
    }
    #abort ID steering and optimization
    if [catch {APSAbortControllaw -runControlPV $optimizeRunControlPV} result] {
        return -code error $result
    }
}

APSApplication . -name SRIDIntensityOptimization \
  -overview "SRIDIntensityOptimization allows optimizing the intensity seen on a beamline diagnostic by adjusting the electron beam angle."
dp_atexit append KillAPSExecLogs

set tcl_precision 6

set IDOptimizationStatus Ready.
APSScrolledStatus .status -parent .userFrame -width 60\
        -textVariable IDOptimizationStatus 

proc SetIDOptimizationStatus {text} {
    global IDOptimizationStatus
    set IDOptimizationStatus "[clock format [clock seconds] -format %H:%M:%S]: $text"
    update
    bell
}

proc PrepareFFFiles {args} {
    global FFWaveformFile
    set tmpRoot /tmp/[APSTmpString]
    set waveformDir /home/helios/oagData/sr/orbitControllaw/waveforms
    foreach plane {h v} coord {x y} {
        if [catch {exec sddsprocess $waveformDir/RTFB[string toupper $coord]bpmInfo.sdds \
            -edit=col,ControlName,DeviceName,ei/:${coord}:SelectedMI/ -pipe=out \
            | sddscasr -save -pipe \
            | sddsconvert -pipe=in $tmpRoot.$plane -rename=col,ValueString=BPMName } result] {
            return -code error $result
        }
        set FFWaveformFile($plane) $tmpRoot.$plane
        APSAddToTmpFileList -ID steering -fileList $tmpRoot.$plane
    }
    
}

proc MakeSectorsWidget {widget args} {
    global allowAllSectors IDSectorList

    set parent ""
    APSParseArguments {parent}

    set w $parent$widget
    APSFrame $widget -parent $parent \
      -label "Storage Ring ID selection for steering." \
      -contextHelp {ID selection frame} 

    if !$allowAllSectors {
        set sectorList $IDSectorList 
    }
    
    for {set quad 1} {$quad<5} {incr quad} {
        set start [expr ($quad-1)*10+1]
        set end   [expr $start+9]
        set buttonList {}
        set valueList {}
        APSFrame .sector$quad -parent $w.frame 
        $w.frame.sector$quad.frame configure -relief flat
        for {set sector $start} {$sector<=$end} {incr sector} {
            set cbLabel $sector
            if {$sector<10} {set cbLabel "0$sector"}
            APSButton .sector$sector -parent $w.frame.sector$quad.frame \
              -text "$cbLabel" \
              -command "IDOptimizationDialog -sector $sector" \
              -contextHelp "Brings up dialog box for ID$cbLabel steering."
            if !$allowAllSectors {
                if [expr -1 == [lsearch $sectorList $sector]] {
                    APSDisableButton $w.frame.sector$quad.frame.sector$sector.button
                }
            }
        }
    }
}

proc IDOptimizationDialog {args} {
    global P0Sector IDSectorList

    set sector ""
    APSParseArguments {sector}
   
    if ![string length $sector] {
        APSAlertBox [APSUniqueName .] -errorMessage \
          "No sector variable specified in IDOptimizationDialog"
        return 1
    }
    if [catch {APSCheckAndUpdateLocalSteeringConfigs -steeringType ID -sector $sector -statusCallback SetIDOptimizationStatus} result] {
        SetIDOptimizationStatus "$result"
        APSAlertBox [APSUniqueName .] -errorMessage "Error in updating local steering configs for sector $sector"
        return 1
    }
    if [catch {GetIDStream -sector $sector} result] {
       # SetIDOptimizationStatus $result
    }
    global waveformFile
    if $P0Sector($sector) {
        set digit 0
        set waveformFile($sector) p0BpmInfo.sdds
    } else {
        set digit 1
        set waveformFile($sector) rfBpmInfo.sdds
    }

    # Check whether ID xray bpms are already in use in global steering.
    # In that case we can't proceed with local steering safely.
    # In most cases local steering runs within a pem, which
    # causes the previous configuration of global correction 
    # to resume immediately after the local steering.
    if {-1<[lsearch $IDSectorList $sector]} {
        SetIDOptimizationStatus "Check and remove sector $sector xbpms if they are in orbit correction..."
        # Here source is expected to be only the BM and ID, no CU side specified.
        if [catch {APSSRRemoveXrayBPMFromOrbitCorrection -sector $sector  -restart 1 -source ID} result] {
            SetIDOptimizationStatus "Error in removing sector $sector xray bpms from orbit correction: $result"
            return
        }
        SetIDOptimizationStatus "$result"
    }
    
    
    global BPx BPy APx APy Stream
    global statusCallback allowTransfer errorCode logFile

    set dialogFrame .dialogID$sector.userFrame
    APSDialogBox .dialogID$sector  \
      -name "ID$sector Dialog" \
      -contextHelp "Dialog box for steering in ID$sector."

    global intensityPVConnected intensityPVName logFile logDir optTolerance pauseAfterChange hRefMatrix vRefMatrix FFWaveformFile
    set intensityPVConnected($sector) 0
   
    set intensityPVName($sector) ID[format %02d ${sector}]:SteeringGoodness

    set logFile($sector) [APSNextGenerationedName -directory $logDir -name S${sector}IDOptLog-0000 -newFile 1 -separator -]
    APSFrame .intensity -parent $dialogFrame -packOption "-side top"
    APSLabeledEntry .pvname -parent $dialogFrame.intensity.frame -label "Intensity PV name: " \
      -textVariable intensityPVName($sector) -width 50 \
      -contextHelp "Enter the name of the beamline PV that gives the intensity."
    APSButton .connect -parent $dialogFrame.intensity.frame.pvname \
      -size small -text "Connect" \
      -command "ConnectToIntensityPV -sector $sector -widget $dialogFrame.intensity.frame.pvname"
    APSLabeledOutput .intensity -parent $dialogFrame.intensity.frame -label "Intensity value: " \
      -textVariable intensityValue($sector) -width 50
    APSLabeledEntry .logdir -parent $dialogFrame.intensity.frame \
      -textVariable logDir -width 60 -label "Log directory: " 
    APSButton .daily -parent $dialogFrame.intensity.frame.logdir -size small -text "daily" \
      -command "global logDir; set logDir [APSGoToDailyDirectory]"
    APSLabeledEntry .logfile -parent $dialogFrame.intensity.frame \
      -textVariable logFile($sector) -width 60 -label "Log file name: " 
    APSButton .plotLog -parent $dialogFrame.intensity.frame.logfile \
      -size small -text Plot \
      -command "PlotLogFile -sector $sector"
# made the command work with " and \$ for logDir variable, which can change because of its entry box. Doesn't work with just {...}.
    APSButton .refresh -parent $dialogFrame.intensity.frame.logfile \
      -size small -text New \
      -command "global logFile; set logFile($sector) \[APSNextGenerationedName -directory \$logDir -name S${sector}IDOptLog-0000 -newFile 1 -separator - \]" -contextHelp "Press to generate a new file name that does not exist."
    APSLabeledEntry .tolerance -parent $dialogFrame.intensity.frame \
	-textVariable optTolerance -width 60 -label "Optimization tolerance: " \
	-contextHelp "The tolerance for optimization convergence."
    APSLabeledEntry .pause -parent $dialogFrame.intensity.frame \
      -textVariable pauseAfterChange -width 60 -label "Pause after change(s): " \
      -contextHelp "The waiting time after changing the correctors for waiting for new values being transferred to datapool and orbit convergence, and intensity settle down."
    if {$Stream($sector.option)} {
        APSRadioButtonFrame .stream -parent $dialogFrame.intensity.frame -label "If scan energy, please select which gap to scan?" \
            -variable Stream($sector) -orientation horizontal -buttonList {ds us both} -valueList {ds us both}
    }
    set Sn $sector
    set Sn1 [exec rpnl "$Sn 1 + 40 > pop ? 40 - : \$"]
    if {[pv linkw \
           [list BPx($sector) BPy($sector) APx($sector) APy($sector)] \
           [list S${Sn}B:P${digit}:ms:x:SetpointAO S${Sn}B:P${digit}:ms:y:SetpointAO \
              S${Sn1}A:P${digit}:ms:x:SetpointAO S${Sn1}A:P${digit}:ms:y:SetpointAO ]] != 0} {
        APSAlertBox .alert -errorMessage "linkw error $errorCode"
        exit
    }
    if {[pv umon BPx($sector)]!=0} {
        APSAlertBox .alert -errorMessage "umon error $errorCode"
        exit
    }
    if {[pv umon BPy($sector)]!=0} {
        APSAlertBox .alert -errorMessage "umon error $errorCode"
        exit
    }
    if {[pv umon APx($sector)]!=0} {
        APSAlertBox .alert -errorMessage "umon error $errorCode"
        exit
    }
    if {[pv umon APy($sector)]!=0} {
        APSAlertBox .alert -errorMessage "umon error $errorCode"
        exit
    }

    global xpLowerLimit xpUpperLimit xpStep 
    global ypLowerLimit ypUpperLimit ypStep 
    global energyLowerLimit energyUpperLimit energyStep includeEnergy otherDisplay
    global xStep yStep xLowerLimit yLowerLimit xUpperLimit yUpperLimit incudeX incudeY includeXp includeYp
   
    APSFrame .angles -parent $dialogFrame -packOption "-side top" -label "Optimization parameters"
    set includeEnergy($sector) 0
    set xpLowerLimit($sector) -60
    set xpUpperLimit($sector)  60
    set xpStep($sector)        10
    set ypLowerLimit($sector) -20
    set ypUpperLimit($sector)  20
    set ypStep($sector)         4
   # set energyLowerLimit($sector)  11.0
   # set energyUpperLimit($sector)  13.0
   # set energyStep($sector)         0.1
    set xStep($sector) 20
    set xLowerLimit($sector) -500
    set xUpperLimit($sector) 500
    set yStep($sector) 10
    set yLowerLimit($sector) -100
    set yUpperLimit($sector) 100
    
    set includeEnergy($sector) 0
    set includeX($sector) 0
    set includeY($sector) 0
    set includeXp($sector) 1
    set includeYp($sector) 1
    
    APSFrame .lowerLimit -parent $dialogFrame.angles.frame -relief flat \
      -label "Lower limit" -width 10 -packOption "-side left" \
      -contextHelp "Enter lower limit for angle and energy variation" 
    APSLabeledEntry .energy -parent $dialogFrame.angles.frame.lowerLimit.frame \
      -label "E (keV):   " -textVariable energyLowerLimit($sector) -width 10 
    APSLabeledEntry .xp -parent $dialogFrame.angles.frame.lowerLimit.frame \
      -label "x' (urad): " -textVariable xpLowerLimit($sector) -width 10
    APSLabeledEntry .yp -parent $dialogFrame.angles.frame.lowerLimit.frame \
      -label "y' (urad): " -textVariable ypLowerLimit($sector) -width 10
     APSLabeledEntry .x -parent $dialogFrame.angles.frame.lowerLimit.frame \
      -label "x (um): " -textVariable xLowerLimit($sector) -width 10
    APSLabeledEntry .y -parent $dialogFrame.angles.frame.lowerLimit.frame \
      -label "y (um): " -textVariable yLowerLimit($sector) -width 10

    APSFrame .upperLimit -parent $dialogFrame.angles.frame -relief flat \
        -label "Upper limit" -width 10 -packOption "-side left" \
        -contextHelp "Enter upper limit for angle and energy variation" 
    APSLabeledEntry .energy -parent $dialogFrame.angles.frame.upperLimit.frame \
        -label "" -textVariable energyUpperLimit($sector) -width 10
    APSLabeledEntry .xp -parent $dialogFrame.angles.frame.upperLimit.frame \
        -label "" -textVariable xpUpperLimit($sector) -width 10
    APSLabeledEntry .yp -parent $dialogFrame.angles.frame.upperLimit.frame \
        -label "" -textVariable ypUpperLimit($sector) -width 10
    APSLabeledEntry .x -parent $dialogFrame.angles.frame.upperLimit.frame \
        -label "" -textVariable xUpperLimit($sector) -width 10
    APSLabeledEntry .y -parent $dialogFrame.angles.frame.upperLimit.frame \
        -label "" -textVariable yUpperLimit($sector) -width 10

    APSFrame .step -parent $dialogFrame.angles.frame -relief flat \
      -label "Initial step" -width 10 -packOption "-side left" \
      -contextHelp "Enter upper limit for angle variation" 
    APSLabeledEntry .energy -parent $dialogFrame.angles.frame.step.frame \
      -label "" -textVariable energyStep($sector) -width 10
    APSLabeledEntry .xp -parent $dialogFrame.angles.frame.step.frame \
      -label "" -textVariable xpStep($sector) -width 10
    APSLabeledEntry .yp -parent $dialogFrame.angles.frame.step.frame \
      -label "" -textVariable ypStep($sector) -width 10
    APSLabeledEntry .x -parent $dialogFrame.angles.frame.step.frame \
      -label "" -textVariable xStep($sector) -width 10
    APSLabeledEntry .y -parent $dialogFrame.angles.frame.step.frame \
      -label "" -textVariable yStep($sector) -width 10
    
    APSFrame .enable -parent $dialogFrame.angles.frame -relief flat \
        -label "Enabled" -width 10 -packOption "-side left -anchor n" 
    
    checkbutton $dialogFrame.angles.frame.enable.frame.energy  \
        -variable includeEnergy($sector) \
        -command "APSEnableDisableWidget $dialogFrame.angles.frame.step.frame.energy -toggle 1; APSEnableDisableWidget $dialogFrame.angles.frame.upperLimit.frame.energy -toggle 1; APSEnableDisableWidget $dialogFrame.angles.frame.lowerLimit.frame.energy -toggle 1"
    pack $dialogFrame.angles.frame.enable.frame.energy 
    APSDisableWidget $dialogFrame.angles.frame.step.frame.energy
    APSDisableWidget $dialogFrame.angles.frame.lowerLimit.frame.energy
    APSDisableWidget $dialogFrame.angles.frame.upperLimit.frame.energy
    
    checkbutton $dialogFrame.angles.frame.enable.frame.xp  \
        -variable includeXp($sector) \
        -command "APSEnableDisableWidget $dialogFrame.angles.frame.step.frame.xp -toggle 1; APSEnableDisableWidget $dialogFrame.angles.frame.upperLimit.frame.xp -toggle 1; APSEnableDisableWidget $dialogFrame.angles.frame.lowerLimit.frame.xp -toggle 1"
    pack $dialogFrame.angles.frame.enable.frame.xp

    checkbutton $dialogFrame.angles.frame.enable.frame.yp \
        -variable includeYp($sector) \
        -command "APSEnableDisableWidget $dialogFrame.angles.frame.step.frame.yp -toggle 1; APSEnableDisableWidget $dialogFrame.angles.frame.upperLimit.frame.yp -toggle 1; APSEnableDisableWidget $dialogFrame.angles.frame.lowerLimit.frame.yp -toggle 1"
    pack $dialogFrame.angles.frame.enable.frame.yp

    checkbutton $dialogFrame.angles.frame.enable.frame.x   \
        -variable includeX($sector) \
        -command "APSEnableDisableWidget $dialogFrame.angles.frame.step.frame.x -toggle 1; APSEnableDisableWidget $dialogFrame.angles.frame.upperLimit.frame.x -toggle 1; APSEnableDisableWidget $dialogFrame.angles.frame.lowerLimit.frame.x -toggle 1"
    pack $dialogFrame.angles.frame.enable.frame.x
    APSDisableWidget $dialogFrame.angles.frame.step.frame.x
    APSDisableWidget $dialogFrame.angles.frame.lowerLimit.frame.x
    APSDisableWidget $dialogFrame.angles.frame.upperLimit.frame.x
    
    checkbutton $dialogFrame.angles.frame.enable.frame.y \
        -variable includeY($sector) \
        -command "APSEnableDisableWidget $dialogFrame.angles.frame.step.frame.y -toggle 1; APSEnableDisableWidget $dialogFrame.angles.frame.upperLimit.frame.y -toggle 1; APSEnableDisableWidget $dialogFrame.angles.frame.lowerLimit.frame.y -toggle 1"
    pack $dialogFrame.angles.frame.enable.frame.y
    APSDisableWidget $dialogFrame.angles.frame.step.frame.y
    APSDisableWidget $dialogFrame.angles.frame.lowerLimit.frame.y
    APSDisableWidget $dialogFrame.angles.frame.upperLimit.frame.y
    

    APSFrame .p1 -parent $dialogFrame -packOption "-side top" 
    set wframe $dialogFrame.p1.frame
    APSFrame .parameters -parent $wframe -packOption "-side left" -relief flat
    APSFrame .setpoints -parent $wframe.parameters.frame \
      -label "Setpoints for bpms"  -width 10 -packOption "-side left" -relief flat \
      -contextHelp "Enter setpoints for the four bpm readbacks of ID$sector"
    APSLabeledOutput .bp1x \
      -parent $wframe.parameters.frame.setpoints.frame \
      -label "S${Sn}B:P${digit}:x (mm)"  -width 10 \
      -textVariable BPx($sector) \
      -contextHelp "View value for S${Sn}B:P${digit}:ms:x:SetpointAO."
    APSLabeledOutput .bpy \
      -parent $wframe.parameters.frame.setpoints.frame \
      -label "S${Sn}B:P${digit}:y (mm)"  -width 10 \
      -textVariable BPy($sector) \
      -contextHelp "View value for S${Sn}B:P${digit}:ms:y:SetpointAO."
    APSLabeledOutput .apx \
      -parent $wframe.parameters.frame.setpoints.frame \
      -label "S${Sn1}A:P${digit}:x (mm)"  -width 10 \
      -textVariable APx($sector) \
      -contextHelp "View value for S${Sn1}A:P${digit}:ms:x:SetpointAO."
    APSLabeledOutput .apy \
      -parent $wframe.parameters.frame.setpoints.frame \
      -label "S${Sn1}A:P${digit}:y (mm)"  -width 10 \
      -textVariable APy($sector) \
      -contextHelp "View value for S${Sn1}A:P${digit}:ms:y:SetpointAO."

    if {[pv linkw \
           [list BPxSetpoint($sector) BPySetpoint($sector) APxSetpoint($sector) APySetpoint($sector)] \
           [list S${Sn}B:P${digit}:ms:x:SetpointAO S${Sn}B:P${digit}:ms:y:SetpointAO \
              S${Sn1}A:P${digit}:ms:x:SetpointAO S${Sn1}A:P${digit}:ms:y:SetpointAO ]] != 0} {
        APSAlertBox .alert -errorMessage "$errorCode"
        exit
    }
    if {[pv linkw \
           [list BPxOffset($sector) BPyOffset($sector) APxOffset($sector) APyOffset($sector)] \
           [list S${Sn}B:P${digit}:ms:x:OffsetAO S${Sn}B:P${digit}:ms:y:OffsetAO \
              S${Sn1}A:P${digit}:ms:x:OffsetAO S${Sn1}A:P${digit}:ms:y:OffsetAO ]] != 0} {
        APSAlertBox .alert -errorMessage "$errorCode"
        exit
    }
    if {[pv linkw \
           [list BPxAdjusted($sector) BPyAdjusted($sector) APxAdjusted($sector) APyAdjusted($sector)] \
           [list S${Sn}B:P${digit}:mswAve:x:AdjustedCC S${Sn}B:P${digit}:mswAve:y:AdjustedCC \
              S${Sn1}A:P${digit}:mswAve:x:AdjustedCC S${Sn1}A:P${digit}:mswAve:y:AdjustedCC ]] != 0} {
        APSAlertBox .alert -errorMessage "$errorCode"
        exit
    }
    if {[pv linkw \
           [list BPxError($sector) BPyError($sector) APxError($sector) APyError($sector)] \
           [list S${Sn}B:P${digit}:mswAve:x:ErrorCC S${Sn}B:P${digit}:mswAve:y:ErrorCC \
              S${Sn1}A:P${digit}:mswAve:x:ErrorCC S${Sn1}A:P${digit}:mswAve:y:ErrorCC ]] != 0} {
        APSAlertBox .alert -errorMessage "$errorCode"
        exit
    }
    if {[pv umon BPxOffset($sector)]!=0} {
        APSAlertBox .alert -errorMessage "$errorCode"
        exit
    }
    if {[pv umon BPyOffset($sector)]!=0} {
        APSAlertBox .alert -errorMessage "$errorCode"
        exit
    }
    if {[pv umon APxOffset($sector)]!=0} {
        APSAlertBox .alert -errorMessage "$errorCode"
        exit
    }
    if {[pv umon APyOffset($sector)]!=0} {
        APSAlertBox .alert -errorMessage "$errorCode"
        exit
    }

    if {[pv umon BPxAdjusted($sector)]!=0} {
        APSAlertBox .alert -errorMessage "$errorCode"
        exit
    }
    if {[pv umon BPyAdjusted($sector)]!=0} {
        APSAlertBox .alert -errorMessage "$errorCode"
        exit
    }
    if {[pv umon APxAdjusted($sector)]!=0} {
        APSAlertBox .alert -errorMessage "$errorCode"
        exit
    }
    if {[pv umon APyAdjusted($sector)]!=0} {
        APSAlertBox .alert -errorMessage "$errorCode"
        exit
    }

    if {[pv umon BPxError($sector)]!=0} {
        APSAlertBox .alert -errorMessage "$errorCode"
        exit
    }
    if {[pv umon BPyError($sector)]!=0} {
        APSAlertBox .alert -errorMessage "$errorCode"
        exit
    }
    if {[pv umon APxError($sector)]!=0} {
        APSAlertBox .alert -errorMessage "$errorCode"
        exit
    }
    if {[pv umon APyError($sector)]!=0} {
        APSAlertBox .alert -errorMessage "$errorCode"
        exit
    }

    APSFrame .moreParameters -parent $wframe -packOption "-side left" -relief flat
    APSLabeledOutputFrame .offset -parent $wframe.moreParameters.frame \
      -label Offsets -packOption "-side left" \
      -variableList "BPxOffset($sector) BPyOffset($sector) APxOffset($sector) APyOffset($sector)"\
      -orientation vertical -width 10 \
      -contextHelp "Electrical offset of ID$sector bpms."
    $wframe.moreParameters.frame.offset.frame configure -relief flat

    APSLabeledOutputFrame .adjusted -parent $wframe.moreParameters.frame \
      -label "Adjusted" -packOption "-side left" \
      -variableList "BPxAdjusted($sector) BPyAdjusted($sector) APxAdjusted($sector) APyAdjusted($sector)"\
      -orientation vertical -width 10 \
      -contextHelp "Adjusted readbacks of ID$sector bpms: raw readback - offsets."
    $wframe.moreParameters.frame.adjusted.frame configure -relief flat

    APSLabeledOutputFrame .error -parent $wframe.moreParameters.frame \
      -label "Error" -packOption "-side left" \
      -variableList "BPxError($sector) BPyError($sector) APxError($sector) APyError($sector)"\
      -orientation vertical -width 10 \
      -contextHelp "Error readbacks of ID$sector bpms: adjusted readback - setpoint."
    $wframe.moreParameters.frame.error.frame configure -relief flat

    set border 3
    foreach outputFrame {offset adjusted error} {
        foreach entry {1 2 3 4} {
            $wframe.moreParameters.frame.${outputFrame}.frame.entry${entry} \
              configure -borderwidth $border
        }
    }

    # AdjustSetpoints -sector $sector -parent $dialogFrame
    APSEnableButton .dialogID$sector.buttonRow.ok.button
    APSButton .info -parent  .dialogID$sector.buttonRow -text info -command "exec medm -x -attach -macro RCPV=S:IDoptimizationRC ./sr/psApp/APSRunControlSingle.adl  &" 
    APSButton .optimize -parent .dialogID$sector.buttonRow -text Optimize \
        -command "OptimizeIntensity -sector $sector"
    APSButton .checkLimits -parent .dialogID$sector.buttonRow -text "Check Limits" \
        -command "OptimizeIntensity  -sector $sector -debug 1 -checkOnly 1"
    APSButton .adt -parent .dialogID$sector.buttonRow -text "SR BPM AdjustedCC ADT (difference mode)" \
      -command "exec adt -geometry +30+0 -f /home/helios/OAG/oagData/ADTFiles/srBpm/sr.bpm.adjusted.pv -d &"
    
    update
    if {$statusCallback!=""} {
        $statusCallback "Enabling averaging for S${Sn}B:P${digit} and S${Sn1}A:P${digit}."
    }
    
    if [catch {exec cavput -list=S${Sn}B:P${digit},S${Sn1}A:P${digit} \
                  -list=:msAve:AveEnbBO=Enable \
                  -pendIoTime=10 \
              } result ] {
        APSAlertBox .alert -errorMessage "$result\nSomething wrong with a cavput command. Averaging may not be enabled."
        return
    }
    
    if [catch {APSSaveMachine -machine SROrbitSetPt -description "Save before sector $sector ID intensity optimization." } result] {
        return -code error "Error doing SR bpm setpoint save: $result"
    }
    if [catch {APSSaveMachine -machine SRCorSetpts -description "Save before sector $sector ID intensity optimization." } result] {
        return -code error "Error doing SR corrector setpoint save: $result"
    }
}

proc OptimizeIntensity {args} {
    set sector 0
    set checkOnly 0
    set debug 0
    APSStrictParseArguments {sector checkOnly debug}
    if {$sector<1 || $sector>40} {
        APSAlertBox .alert -errorMessage "Sector invalid ($sector) in OptimizeIntensity"
    }
    if $checkOnly {
        set debug 1
    }
    if [catch {TestSetpointsChangeLimits -sector $sector -debug $debug} result] {
        set answer [APSMultipleChoice [APSUniqueName .] -name warning  -width 60 \
                      -question "$result\nThe optimization on ID sector $sector will probably trip the BPLD system, go ahead or cancel the steering? " -returnList {Go Cancel} \
                      -labelList {Go-Ahead Cancel} ]
        if {$answer == "Cancel"} {
            SetIDOptimizationStatus "$result"
            SetIDOptimizationStatus "Optimization was cancelled due to the probability of BPLD tripping with ID $sector optimization."
            return 1
        }
        SetIDOptimizationStatus "$result"
    }
    if {$checkOnly} {
        return
    }
    global intensityPVConnected intensityPVName P0Sector R12 R34 Stream  FFWaveformFile
    
    if !$intensityPVConnected($sector) {
        if [ConnectToIntensityPV -sector $sector \
              -widget .dialogID$sector.userFrame.intensity.frame.pvname] {
            #APSAlertBox .alert -errorMessage "Unable to connect to intensity PV."
            return
        }
    }    
    global optimizeRunControlPV  ignoreLock
    exec medm -attach -x -macro RCPV=$optimizeRunControlPV \
      /usr/local/iocapps/adlsys/sr/psApp/APSRunControlSingle.adl &
    if [catch {exec cavget -list=$optimizeRunControlPV.RUN -num -pend=30} optRunning] {
        SetIDOptimizationStatus "Can not read optimization runcontrol pv: $optRunning"
        APSAlertBox [APSUniqueName .] -errorMessage "Can not read optimization runcontrol pv: $optRunning"
        return
    }
    if {$optRunning} {
        SetIDOptimizationStatus "Another ID optimization is running."
        APSAlertBox [APSUniqueName .] -errorMessage "Can not start ID optimization since another one is running"
        return
    }
   set controllawDir  /home/helios/oagData/sr/localSteering/lattices/default/IDs/[format %02d $sector]ID
    global steeringRunControlPV logFile logDir
    if ![string length $logFile($sector)] {
        set logFile($sector) /tmp/[APSTmpString]S${sector}.log
    }
    
    # Prepare sddsoptimize input file
    if [catch {CreateOptimizationFiles -sector $sector} result] {
        APSAlertBox .alert -errorMessage "$result"
        return
    }
    
    # Prepare script command for changing slopes
    set referenceFile $logDir/$logFile($sector).ref
    if [file exist $referenceFile] {
        #make sure the referenceFile is fresh at the start of optimization
        file delete -force $referenceFile
    }
    
    set varScript "setIDSteeringAngles.new -sector $sector -stream $Stream($sector) -reference $referenceFile -intensityPV $intensityPVName($sector) -hFFWaveform $FFWaveformFile(h) -vFFWaveform $FFWaveformFile(v) "
    
    set measScript "measureIDIntensity -PVname $intensityPVName($sector)"
    global optTolerance
    # Prepare sddsoptimize command
    set command "sddsoptimize -varFile=$logDir/$logFile($sector).optIn \"-measScript=$measScript\" -testValues=file=$logDir/$logFile($sector).test,limit=1000 -verbose -simplex=restart=2,cycles=3,evaluations=100 \"-varScript=$varScript\" -maximize -tolerance=$optTolerance -logFile=$logDir/$logFile($sector) -runControlPV=string=$optimizeRunControlPV,pingTimeout=100 \"-runControlDesc=string=ID $sector optimization\""
    if !$ignoreLock {
        SetIDOptimizationStatus "Lock global steering..."
        if [catch {exec cavput -list=SRID:SteeringLockBI.VAL=1 -pend=30} result] {
            return -code error "Error in locking global steering: $result"
        }
    }

    global optimizationDone 
    set optimizationDone 0
    SetIDOptimizationStatus "Change corrector rangeError limits to +-50A..."
    foreach plane {h v} {
        if [catch {exec sddscasr -restore $controllawDir/${plane}.corr.range } result] {
            return -code error "Error changing corrector rangeErrors: $result"
        }
    }
    
    APSExecLog .optimize -width 100 -unixCommand $command \
      -callback "set optimizationDone 1" \
      -cancelCallback "set optimizationDone 2" \
      -abortCallback "set optimizationDone 2"
    tkwait variable optimizationDone
    if !$ignoreLock {
        SetIDOptimizationStatus "Unlock global steering..."
        if [catch {exec cavput -list=SRID:SteeringLockBI.VAL=0 -pend=30} result] {
            return -code error "Error in unlocking global steering: $result"
        }
    }
    
    if $optimizationDone {
        #abort ID steering
	bell
	bell
	bell
        SetIDOptimizationStatus "Restore corrector rangeError limits..."
        foreach plane {h v} {
            set corrList [exec sddsquery -col $controllawDir/${plane}.steering.rm | grep S]
            if [catch {exec sddsmakedataset -pipe=out -col=CorrName,type=string \
                         -data=[join $corrList ,] \
                         | sddsprocess -pipe -edit=col,ControlName,CorrName,ei/:DacAI/ \
                         | sddscasr -pipe -save -pend=30 \
                         | sddsprocess -pipe -reedit=col,ControlName,%/DacAI/RangeErrorCALC.B/ \
                         | sddscasr -pipe=in -restore } result] {
                SetStatus "Error in transfer DacAI: $result"
            }
            if [catch {exec sddscasr -restore $controllawDir/${plane}.corr.range.orig } result] {
                return -code error "Error restoring corrector rangeErrors: $result"
            }
        }
        if [APSYesNoPopUp "Do you want to save the optimziation result and make a new UBOP?"] {
            set tagList [exec sdds2stream -col=Name $referenceFile]
            set valList [exec sdds2stream -col=Value $referenceFile]
            set desc "ID intensity optimizatin save after ID $sector optimization: "
            foreach tag $tagList val $valList {
                append desc "$tag: [format %.3f $val]; "
            }
            SetIDOptimizationStatus "Save and make new UBOP after ID $sector optimization..."
            if [catch {APSSRSaveSteeringToOps -installUBOP 1 \
                         -description "$desc" \
                         -statusCallabck SetIDOptimizationStatus } snapshot] {
                SetIDOptimizationStatus "Error in SCR save: $snapshot"
                return
            }
            SetIDOptimizationStatus "done."
        }
    }
}

proc ConnectToIntensityPV {args} {
    set sector 0
    APSStrictParseArguments {sector widget}
    if {$sector<1 || $sector>40} {
        APSAlertBox .alert -errorMessage "Sector invalid ($sector) in ConnectToIntensityPV"
        return 1
    }
    global intensityValue intensityPVName errorCode
    if {![info exist intensityPVName($sector)] || ![string length $intensityPVName($sector)]} {
        APSAlertBox .alert -errorMessage "Unable to connect to intensity PV: the PV name is not given for sector $sector"
        return 1
    }
    if {[pv linkw intensityValue($sector) $intensityPVName($sector)]!=0} {
        APSAlertBox .alert -errorMessage "Unable to connect to intensity PV: $errorCode"
        return 1
    }
    if {[pv umon intensityValue($sector)]!=0} {
        APSAlertBox .alert -errorMessage "Unable to connect to intensity PV: $errorCode"
        return 1
    }
    global intensityPVConnected
    set intensityPVConnected($sector) 1
    APSDisableWidget $widget
    return 0
}

proc TestSetpointsChangeLimits {args} {
    global BPLDList P0Sector
    global xpLowerLimit xpUpperLimit ypLowerLimit ypUpperLimit xLowerLimit xUpperLimit yLowerLimit yUpperLimit
    global includeX includeY includeXp includeYp
    set sector ""
    set debug 1
    APSParseArguments {sector debug}

    if ![string length $sector] {
        return -code error "No sector variable specified"
    }
    set index [lsearch -exact $BPLDList $sector]
    if {$index<0} {
        #no need to check
        SetIDOptimizationStatus "No need to check BPLD limits for sector $sector."
        return
    }
    set Sn $sector
    set Sn1 [exec rpnl "$Sn 1 + 40 > pop ? 40 - : \$"]
    # only the P1 are the BPLDs now
    if [catch {exec cavget -pend=30 -list=S${Sn}B:P1,S${Sn1}A:P1 \
                 -list=:dbpld: \
                 -list=x,y -list=hi,lo -list=AO.VAL -pend=30} tripLimits] {
        return -code error $tripLimits
    }
    foreach {bxUp bxLow byUp byLow axUp axLow ayUp ayLow} $tripLimits {}
    set badList ""
    set digit 1
     if [catch {exec cavget -list=S${Sn}B:,S${Sn1}A: -list=P${digit}:ms: \
                 -list=x,y -list=:GainAO -pend=30 -printErrors} gainList] {
        return -code error "Error in reading gain value of sector $sector pvs."
    }
    #reason for reading setpoint and offset here is because that when P0 bpms are used for steering BPX (etc)
    # are the setpoints of P0 bpms not P1s -- the P1 bpms setpoint and offset have to read here for P0 steering
    
    if [catch {exec cavget -list=S${Sn}B:,S${Sn1}A: -list=P${digit}:ms: \
                 -list=x,y -list=:SetpointAO -pend=30 -printErrors} setpointList] {
        return -code error "Error in reading setpoint value of sector $sector pvs."
    }
    if [catch {exec cavget -list=S${Sn}B:,S${Sn1}A: -list=P${digit}:ms: \
                 -list=x,y -list=:OffsetAO -pend=30 -printErrors} offsetList] {
        return -code error "Error in reading offset value of sector $sector pvs."
    }
    foreach {bpxGain bpyGain apxGain apyGain} $gainList {}
    foreach {bpx bpy apx apy} $setpointList {}
    foreach {bpxOffset bpyOffset apxOffset apyOffset} $offsetList {}
    
    if $debug {
        puts stderr  "set bxUp $bxUp"
        puts stderr  "set bxLow $bxLow"
        puts stderr  "set byUp $byUp"
        puts stderr  "set byLow $byLow"
        puts stderr  "set axUp $axUp"
        puts stderr  "set axLow $axLow"
        puts stderr  "set ayUp $ayUp"
        puts stderr  "set ayLow $ayLow"
    }
    global R11 R12 R33 R34
    set dxLow 0
    set dxUp 0
    set dyLow 0
    set dyUp 0
    # below is cumulative orbit from various position and angle steering requests
    if $includeX($sector) {
        set dxLow [expr $dxLow + $R11($sector)*$xLowerLimit($sector)/1e3] 
        set dxUp [expr $dxUp + $R11($sector)*$xUpperLimit($sector)/1e3]
    }
    if $includeXp($sector) {
        set dxLow [expr $dxLow + $R12($sector)*$xpLowerLimit($sector)/1e3] 
        set dxUp [expr $dxUp + $R12($sector)*$xpUpperLimit($sector)/1e3]
    }
    if $includeY($sector) {
        set dyLow [expr $dyLow + $R33($sector)*$yLowerLimit($sector)/1e3] 
        set dyUp [expr $dyUp + $R33($sector)*$yUpperLimit($sector)/1e3]
    }
    if $includeYp($sector) {
        set dyLow [expr $dyLow + $R34($sector)*$ypLowerLimit($sector)/1e3]
        set dyUp [expr $dyUp + $R34($sector)*$ypUpperLimit($sector)/1e3]
    }
    if $debug {
        puts stderr "set dyLow \[expr $dyLow + $R34($sector)*$ypLowerLimit($sector)/1e3\]"
        puts stderr "set dyUp \[expr $dyLow + $R34($sector)*$ypUpperLimit($sector)/1e3\]"
    }
    # Add proposed -dx to B:P x and +dx to A:P x
    # Add proposed -dy to B:P y and +dy to A:P y
    set bxLow1 [expr ($bpx + $bpxOffset - $dxLow ) / $bpxGain]
    set bxUp1 [expr ($bpx + $bpxOffset  - $dxUp) / $bpxGain]
    set byLow1 [expr ($bpy + $bpyOffset - $dyLow) /  $bpyGain]
    set byUp1 [expr ($bpy + $bpyOffset - $dyUp) /  $bpyGain]
    
    if $debug {
        puts stderr "set bxLow1 \[expr ($bpx + $bpxOffset - $dxLow ) / $bpxGain\]"
        puts stderr "set bxUp1 \[expr ($bpx + $bpxOffset - $dxUp) / $bpxGain\]"
        puts stderr "set byLow1 \[expr ($bpy + $bpyOffset - $dyLow) /  $bpyGain\]"
        puts stderr "set byUp1 \[expr ($bpy + $bpyOffset - $dyUp) /  $bpyGain]"
    }
    set axLow1 [expr ($apx + $apxOffset  + $dxLow) / $apxGain]
    set axUp1 [expr ($apx + $apxOffset + $dxUp) / $apxGain]
    set ayLow1 [expr ($apy + $apyOffset + $dyLow) / $apyGain]
    set ayUp1 [expr ($apy + $apyOffset + $dyUp) / $apyGain]
    if $debug {
        puts stderr "set axLow1 \[expr ($apx + $apxOffset + $dxLow) / $apxGain\]"
        puts stderr "set axUp1 \[expr ($apx + $apxOffset + $dxUp) / $apxGain\]"
        puts stderr "set ayLow1 \[expr ($apy + $apyOffset + $dyLow) / $apyGain\]"
        puts stderr "set ayUp1 \[expr ($apy + $apyOffset + $dyUp) / $apyGain\]"
    }
    
    #for bx and by, compare the low to up, and up to low since the sign is -
    set adjustxLow 0
    set adjustyLow 0
    set adjustxUp 0
    set adjustyUp 0
    
     if {$bxLow1>$bxUp} {
        set adjustxLow 1
        append badList "The lower limit of S${Sn}B:P${digit}:x setpoint is out of BPLD trip limit.\n"
    }
    if {$bxUp1<$bxLow} {
        set adjustxUp 1
        append badList "The upper limit of S${Sn}B:P${digit}:x setpoint is out of BPLD trip limit.\n"
    }
    if {$byLow1>$byUp} {
        set adjustyLow 1
        append badList "The lower limit of S${Sn}B:P${digit}:y setpoint is out of BPLD trip limit.\n"
    }
    if {$byUp1<$byLow} {
        set adjustyUp 1
        append badList "The upper limit of S${Sn}B:P${digit}:y setpoint is out of BPLD trip limit.\n"
    }

    if {$axLow1<$axLow} {
        set adjustxLow 1
        append badList "The lower limit of S${Sn1}A:P${digit}:x setpoint is out of BPLD trip limit.\n"
    }
    if  {$axUp1>$axUp} {
        set adjustxUp 1
        append badList "The upper limit of S${Sn1}A:P${digit}:x setpoint is out of BPLD trip limit.\n"
    }
    if {$ayLow1<$ayLow} {
        set adjustyLow 1
        append badList "The lower limit of S${Sn1}A:P${digit}:y setpoint is out of BPLD trip limit.\n"
    }
    if {$ayUp1>$ayUp} {
        set adjustyUp 1
        append badList "The upper limit of S${Sn1}A:P${digit}:y setpoint is out of BPLD trip limit.\n"
    }
    if {$adjustxLow || $adjustxUp || $adjustyLow || $adjustyUp} {
        append badList "\nYou probably need adjust: \n "
    }
    if {$adjustxLow} {
        append badList "the lowerlimit of x'.\n "
    }
    if {$adjustxUp} {
        append badList "the upperlimit of x'.\n "  
    }
    if {$adjustyLow} {
        append badList "the lowerlimit of y'.\n "
    }
    if {$adjustyUp} {
        append badList "the upperlimit of y'.\n "  
    }
    if [llength $badList] {
        return -code error $badList
    } else {
        SetIDOptimizationStatus "Steering limits for sector $sector optimization within BPLD limits."
    }
    
}

proc PlotLogFile {args} {
    set sector 0
    APSStrictParseArguments {sector}
    global logFile logDir
    if $sector==0 return
    if ![string length $logFile($sector)] return
    if ![file exists $logDir/$logFile($sector)] {
        SetIDOptimizationStatus "not found: $logFile($sector)"
    }
    exec sddsplot -column=EvalIndex,currentValue $logDir/$logFile($sector) -graph=sym &
    set columns [exec sddsquery -col  $logDir/$logFile($sector)]
    if [lsearch $columns "energy"]>=0 {
        exec sddsplot $logDir/$logFile($sector) -layout=1,2 -tick=xtime \
            "-topline=ID$sector Steering Optimization" \
            -leg,firstFileOnly \
            -col=Time,currentValue -grap=line,type=3,thick=2 \
            -ylabel=Intensity -factor=ymult=-1 -yscale=id=Intensity \
            -col=Time,energy -gra=line,vary,fixforname -yscale=id=Energy \
            "-ylabel=Energy (kV)" &
        exec sddsplot $logDir/$logFile($sector) -layout=1,2 -tick=xtime \
            "-topline=ID$sector Steering Optimization" \
            -leg,firstFileOnly \
            -col=Time,currentValue -grap=line,type=3,thick=2 \
            -ylabel=Intensity -factor=ymult=-1 -yscale=id=Intensity \
            -col=Time,energy -gra=line,vary,fixforname -yscale=id=Energy \
            "-ylabel=Energy (kV)" \
            -device=lpng -output=$logDir/$logFile($sector).energy.png
    }
    if [lsearch -regexp $columns "Slope"]>=0 {
        exec sddsplot $logDir/$logFile($sector) -layout=1,2 -tick=xtime \
            "-topline=ID$sector Steering Optimization" \
            -leg,firstFileOnly \
            -col=Time,?Slope -gra=line,vary,fixforname -yscale=id=slopes \
            "-ylabel=Slopes (\$gm\$rrad)"  &
        exec sddsplot $logDir/$logFile($sector) -layout=1,2 -tick=xtime \
            "-topline=ID$sector Steering Optimization" \
            -leg,firstFileOnly \
            -col=Time,?Slope -gra=line,vary,fixforname -yscale=id=slopes \
            "-ylabel=Slopes (\$gm\$rrad)"  \
            -device=lpng -output=$logDir/$logFile($sector).angle.png
    } 
    if [lsearch -regexp $columns "Pos"]>=0 {
        exec sddsplot $logDir/$logFile($sector) -layout=1,2 -tick=xtime \
            "-topline=ID$sector Steering Optimization" \
            -leg,firstFileOnly \
            -col=Time,?Pos -gra=line,vary,fixforname -yscale=id=slopes \
            "-ylabel=Slopes (\$gm\$rm)"  &
        exec sddsplot $logDir/$logFile($sector) -layout=1,2 -tick=xtime \
            "-topline=ID$sector Steering Optimization" \
            -leg,firstFileOnly \
            -col=Time,?Pos -gra=line,vary,fixforname -yscale=id=slopes \
            "-ylabel=Positions (\$gm\$rm)"  \
            -device=lpng -output=$logDir/$logFile($sector).pos.png
    }
}

proc GetIDStream {args} {
    global Stream
    set deviceList [APSIDGetDeviceList]
    set sector ""
    APSParseArguments {sector}

    set sector1 [format %02ld $sector]
    set ds ID${sector1}ds
    set us ID${sector1}us
    
    if [lsearch $deviceList $ds]>=0 {
        if [catch {exec cavget -list=${ds}:Gap -printErrors} dsGap] {
            return -code error "Unable to read the ds gap of sector $sector!"
        }
    } else {
        set dsGap -1
    }
    if [lsearch $deviceList $us]>=0 {
        if [catch {exec cavget -list=${us}:Gap -printErrors} usGap] {
            return -code error "Unable to read the us gap of sector $sector!"
        }
    } else {
        set usGap -1
    }
    if {$dsGap<0} {
        set Stream($sector) us
        set Stream($sector.option) 0
    } elseif {$usGap<0} {
        set Stream($sector) ds
        set Stream($sector.option) 0
    } else {
        set Stream($sector.option) 1
        if {$dsGap==$usGap} {
            set Stream($sector) both
        } elseif {$dsGap<50 && $usGap<50} {
            if {$dsGap<$usGap} {
                set Stream($sector) ds
            } else {
                set Stream($sector) ds
            }
        } elseif {$dsGap<50} {
            set Stream($sector) ds
        } elseif {$usGap<50} {
            set Stream($sector) us
        } else {
            set Stream($sector) invalid
            return -code error "Both gaps are open, can not scan the gaps."
        }
    }
  
    if {$Stream($sector)=="both"} {
        set pv ${ds}:Energy
    } else {
        set pv ID[format %02ld $sector]$Stream($sector):Energy
    }
    if [catch {exec cavget -list=$pv -printErrors}  eng] {
        return -code error "unable to read $pv: $eng"
    }
    global energyUpperLimit energyLowerLimit energyInitial energyStep
   
    set energyUpperLimit($sector) [expr $eng + 0.5]
    set energyLowerLimit($sector) [expr $eng - 0.5]
    set energyInitial($sector) $eng
    set energyStep($sector) 0.05
    
    return
    foreach device $deviceList {
        set sector [scan $device ID%ld]
        if [regexp {ds} $device] {
            set Stream($sector)  ds
        } elseif [regexp {us} $device] {
            set Stream($sector) us
        } else {
            set Stream($sector) ""
        }
    }
}

 
proc CreateOptimizationFiles {args} {
    set sector ""
    APSParseArguments {sector}
    global logDir logFile includeEnergy includeX includeY includeXp includeYp Stream
    global xpLowerLimit xpUpperLimit xpStep xLowerLimit xUpperLimit xStep energyLowerLimit energyUpperLimit energyStep
    global ypLowerLimit ypUpperLimit ypStep yLowerLimit yUpperLimit yStep pauseAfterChange
    
    if ![string length $sector] {
        return -code error "sector is not provided."
    }
    if ![string length $logFile($sector)] {
        set logFile($sector) S${sector}IDOptLog-0000
    }
    set names ""
    set lowerLimit ""
    set upperLimit ""
    set initial ""
    if $includeEnergy($sector) {
        if {$Stream($sector)=="invalid"} {
            return -code error "Both us and ds $sector gaps are open, can not scan energy!"
        }
        if [expr $energyLowerLimit($sector)>=$energyUpperLimit($sector)] {
            return -code error "energy lower limit >= upper limit"
        }
        if [expr $energyStep($sector)<=0] {
            return -code error "energy step <= 0"
        }
        if {$Stream($sector)!="both"} {
            if [catch {exec cavget -list=ID[format %02d $sector]$Stream($sector):Energy \
                         -pend=10 -printErrors} energyInitial] {
                return -code error "$energyInitial"
            }
        } else {
            if [catch {exec cavget -list=ID[format %02d $sector]ds:Energy \
                         -pend=10 -printErrors} energyInitial] {
                return -code error "$energyInitial"
            }
        }
        if {$energyInitial<$energyLowerLimit($sector)} {
            return -code error "The current ID $sector energy ($energyInitial Kev) is less that energy lower limit, please move ID $sector gap or change the energy lower limit."
        }
        lappend names energy
        lappend lowerLimit $energyLowerLimit($sector)
        lappend upperLimit $energyUpperLimit($sector)
        lappend initial $energyInitial
        lappend stepList $energyStep($sector)
    }
    
    if $includeY($sector) {
        if [expr $yLowerLimit($sector)>=$yUpperLimit($sector)] {
            return -code error "y lower limit >= upper limit"
        }
        if [expr $yStep($sector)<=0] {
            return -code error "y step <= 0"
        }
        lappend names yPos
        lappend lowerLimit $yLowerLimit($sector)
        lappend upperLimit $yUpperLimit($sector)
        lappend initial 0
        lappend stepList $yStep($sector)
    }
    if $includeYp($sector) {
        if [expr $ypLowerLimit($sector)>=$ypUpperLimit($sector)] {
            return -code error "y' lower limit >= upper limit"
        }
        if [expr $ypStep($sector)<=0] {
            return -code error "y' step <= 0"
        }
        lappend names ySlope
        lappend lowerLimit $ypLowerLimit($sector)
        lappend upperLimit $ypUpperLimit($sector)
        lappend initial 0
        lappend stepList $ypStep($sector)
    }
    if $includeX($sector) {
        if [expr $xLowerLimit($sector)>=$xUpperLimit($sector)] {
            return -code error "x' lower limit >= upper limit"
        }
        if [expr $xStep($sector)<=0] {
            return -code error "x step <= 0" 
        }
        lappend names xPos
        lappend lowerLimit $xLowerLimit($sector)
        lappend upperLimit $xUpperLimit($sector)
        lappend initial 0
        lappend stepList $xStep($sector)
    }
    
    if $includeXp($sector) {
        if [expr $xpLowerLimit($sector)>=$xpUpperLimit($sector)] {
            return -code error "x' lower limit >= upper limit"
        }
        if [expr $xpStep($sector)<=0] {
            return -code error "x' step <= 0" 
        }
        lappend names xSlope
        lappend lowerLimit $xpLowerLimit($sector)
        lappend upperLimit $xpUpperLimit($sector)
        lappend initial 0
        lappend stepList $xpStep($sector)
    }
    if ![llength $names] {
        return -code error "No actuators selected."
    }
    set genName [APSNextGenerationedName -directory $logDir -name $logFile($sector) -separator - -newFile 1]
    set $logFile($sector) $genName
    
    if [catch {exec sddsmakedataset $logDir/$logFile($sector).optIn \
                   -parameter=PauseBetweenReadings,type=double -data=0 \
                   -parameter=PauseAfterChange,type=double -data=$pauseAfterChange \
                   -column=ControlName,type=string -data=[join $names ,] \
                   -column=LowerLimit,type=double -data=[join $lowerLimit ,]\
                   -column=UpperLimit,type=double -data=[join $upperLimit ,] \
                   -column=InitialChange,type=double -data=[join $stepList ,] \
                   -column=InitialValue,type=double -data=[join $initial ,] } result] {
        return -code error $result
    }
    
    # Prepare test file to ensure that steering is running, beam is present.
    # Should also check for open shutters (which PVs?)
    set sectorf [format %02d $sector]
    #check topup state, if topup -- need add testing of injection
    if [catch {exec cavget -list=Mt:TopUpAutoEnableC.VAL -num -pend=30} topup] {
        return -code error "Error reading topup state: $topup"
    }
    set pvList [list S-DCCT:CurrentM EPS:${sectorf}:ID:PS1:POSITION EPS:${sectorf}:ID:PS2:POSITION EPS:${sectorf}:ID:SS1:POSITION EPS:${sectorf}:ID:SS2:POSITION]
    set minList {40 1.5 1.5 1.5 1.5}
    set maxList {305 2.5 2.5 2.5 2.5}
    if $topup {
        #avoid injection
        lappend pvList Mt:TopUpTime2Inject.VAL
        lappend minList 1
        lappend maxList 500
    }
    exec sddsmakedataset $logDir/$logFile($sector).test \
        -Column=ControlName,type=string \
      -data=[join $pvList ,] \
      -column=MinimumValue,type=double -data=[join $minList ,] \
      -column=MaximumValue,type=double -data=[join $maxList ,]
}

set IDSectorList [APSGetSDDSColumn -column Sector \
                    -fileName /home/helios/oagData/sr/IDs/sectors.sdds]

MakeSectorsWidget .sectors -parent .userFrame

set optTolerance 500
set pauseAfterChange 5
set tolerance 0.050
set timeLimit 6000
set statusCallback SetIDOptimizationStatus
set interval 0.5
set gain 0.3
set offsetReferenceFile /home/helios/oagData/SCR/snapshots/SR/SR-BPMOffsetReference.gz

# global variable P0Sector is used to set the label names
# of the bpms whose setpoints are changed.
set linkDir /home/helios/oagData/sr/localSteering/lattices/default/IDs
for {set sector 1} {$sector<41} {incr sector} {
    set id ${linkDir}/[format %02ld $sector]ID
    set idLink [file readlink $id] 
    switch -regexp $idLink  {
        P1 {
        # means that P1 bpms are used for steering
            set P0Sector($sector) 0
            set R11($sector) 1.09
            set R12($sector) 4.29
            set R33($sector) 0.91
            set R34($sector) 3.67
        }
        P0 {
        # means that P0 bpms are used for steering
            set P0Sector($sector) 1
            set R11($sector) 1.0
            set R12($sector) 2.48
            set R33($sector) 1.0
            set R34($sector) 2.48
            if {$sector == 34} {
                set R12($sector) 1.24
                set R34($sector) 1.24
            }
        }
    }
}
set BPLDFile /home/helios/oagData/sr/BPLDs/sectors.sdds
set BPLDList [exec sdds2stream -col=Sector $BPLDFile]

set logDir [APSGoToDailyDirectory]/IDOrbitOptimization
if ![file exist $logDir] {
    exec mkdir -p $logDir
}
#GetIDStream
#PrepareFFFiles
set FFWaveformFile(h) /home/helios/oagData/sr/orbitControllaw/waveforms/FFwaveform.h
set FFWaveformFile(v) /home/helios/oagData/sr/orbitControllaw/waveforms/FFwaveform.v

if [regexp {".0"} $env(DISPLAY)] {
    set otherDisplay :0.1
} else {
    set otherDisplay :0.0
}
