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

#
# $Log: not supported by cvs2svn $
# Revision 1.1  2007/02/14 01:14:09  emery
# First installation of Shang's group of codes to
# do BM steering optimization using a video system.
#

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 adjustOnly 0
set allowTransfer 0
set allowAllSectors 0
set includeSourcePoints 0
APSStrictParseArguments {adjustOnly allowTransfer allowAllSectors includeSourcePoints}
set CVSRevisionAuthor "\$Revision: 1.2 $ \$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
    }
    if [catch {APSAbortControllaw -runControlPV $steeringRunControlPV} result] {
        return -code error $result
    }
}

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

set tcl_precision 6

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

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

proc MakeSectorsWidget {widget args} {
    global sector allowAllSectors BMSectorList

    set parent ""
    APSParseArguments {parent}

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

    if !$allowAllSectors {
        set sectorList $BMSectorList 
    }
    
    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 "BMOptimizationDialog -sector $sector" \
              -contextHelp "Brings up dialog box for BM$cbLabel steering."
            if !$allowAllSectors {
                if [expr -1 == [lsearch $sectorList $sector]] {
                    APSDisableButton $w.frame.sector$quad.frame.sector$sector.button
                }
            }
        }
    }
}

proc MakeOptionWidget {widget args} {
    global sector beamTolerance intTolerance timeLimit statusCallback
    global interval gain 

    set parent ""
    APSParseArguments {parent}

    set w $parent$widget
    APSFrame $widget -parent $parent -label "Options" \
        -contextHelp "Options in BM steering."
    
    APSFrame .parameters -parent $w.frame  -packOption  {-side top}
    set w $parent$widget.frame.parameters
    $w.frame configure -relief flat

    APSFrame .misc -parent $w.frame -packOption  {-side left}
    $w.frame.misc.frame configure -relief flat
    APSLabeledEntry .timeLimit -parent $w.frame.misc.frame -label "Time limit (sec)" \
      -textVariable timeLimit  -width 8 \
      -contextHelp "Time allowed for sddscontrollaw to steer the beam to the desired setpoints."
    APSLabeledEntry .interval -parent $w.frame.misc.frame -label "Interval (sec)" \
      -textVariable interval  -width 8 \
      -contextHelp "Time interval between sddscontrollaw interations."
    APSLabeledEntry .gain -parent $w.frame.misc.frame -label "Gain" \
      -textVariable gain  -width 8 \
      -contextHelp "Fraction of correction to be applied at every iterations. Use a value of 0 for safe debugging."
}

proc MakeTransferWidget {widget args} {
    set parent ""
    APSParseArguments {parent}

    set w $parent$widget
    APSFrame $widget -parent $parent -label "Orbit transfer to setpoints" \
        -contextHelp "Buttons to transfer x, y, or both orbits to setpoint values.  Not part of BM steering per se, but useful for related operations."
    
    APSFrame .parameters -parent $w.frame  -packOption  {-side top}
    set w $parent$widget.frame.parameters
    $w.frame configure -relief flat

    APSFrame .misc -parent $w.frame -packOption  {-side left}
    $w.frame.misc.frame configure -relief flat
    APSButton .xferAdjValues -parent $w.frame.misc.frame -text "Transfer both" \
      -command {DoTransfer -msType mswAve -plane both -includeSourcePoints $includeSourcePoints} \
      -contextHelp "Transfers present adjusted orbit values to steering setpoints, in order to lock in the present orbit.  Not part of BM steering per se, but useful for related operations."
    APSButton .hxferAdjValues -parent $w.frame.misc.frame -text "Transfer x" \
      -command {DoTransfer -msType mswAve -plane x -includeSourcePoints $includeSourcePoints} \
      -contextHelp "Transfers present adjusted x orbit values to steering setpoints, in order to lock in the present horizontal orbit.  Not part of BM steering per se, but useful for related operations."
    APSButton .vxferAdjValues -parent $w.frame.misc.frame -text "Transfer y" \
      -command {DoTransfer -msType mswAve -plane y -includeSourcePoints $includeSourcePoints} \
      -contextHelp "Transfers present adjusted y orbit values to steering setpoints, in order to lock in the present vertical orbit.  Not part of BM steering per se, but useful for related operations."
    global includeSourcePoints
    APSRadioButtonFrame .mode -parent $w.frame.misc.frame -label "Include source points" \
      -variable includeSourcePoints -buttonList "Yes No" -valueList "1 0" -orientation horizontal \
      -contextHelp "Determines whether setpoints for BPMs used by the fine orbit correction are also changed.  These setpoints are important in pinning down the source points for BM and BM lines, and should not normalling be included in the transfer."
}

proc DoTransfer {args} {
    set msType ""
    set plane ""
    set includeSourcePoints 0
    APSStrictParseArguments {msType plane includeSourcePoints} 

    set dataDir /home/helios/oagData/sr/localSteering
    set excludeConfigFile ""
    SetBMOptimizationStatus "Transferring present adjusted orbit to setpoints for $plane plane(s)"
    if !$includeSourcePoints {
        if [string compare $plane both]==0 {
            lappend excludeConfigFile \
              $dataDir/userLightSources.config \
              $dataDir/userLightSources.config
        } else {
            set excludeConfigFile $dataDir/userLightSources.config
        }
        SetBMOptimizationStatus "Setpoints for ID/BM source points are not being changed."
    } else {
        SetBMOptimizationStatus "Setpoints for ID/BM source points *are* being changed."
    }
    
    if [catch {APSSRTransferBPMAdjustedValues  -msType $msType -plane $plane \
                 -statusCallback SetBMOptimizationStatus -excludeConfigFileList $excludeConfigFile} result] {
        SetBMOptimizationStatus "$result"
        return 
    }
    if [catch {APSTransferVectorAdjust -coord $plane} result] {
        SetBMOptimizationStatus "$result"
        return 
    }
    SetBMOptimizationStatus "Transfer done."
}

proc BMOptimizationDialog {args} {
    global BMSectorList GoodBPMList

    set sector ""
    APSParseArguments {sector}
    if ![string length $sector] {
        APSAlertBox [APSUniqueName .] -errorMessage \
          "No sector variable specified in BMOptimizationDialog"
        return 1
    }
    if [catch {APSCheckAndUpdateLocalSteeringConfigs -steeringType BM -sector $sector -statusCallback SetBMOptimizationStatus} result] {
	SetBMOptimizationStatus "$result"
        APSAlertBox [APSUniqueName .] -errorMessage "Error in updating local steering configs for sector $sector"
        return 1
    }
    
    if {-1 == [lsearch $GoodBPMList S${sector}B:P4] ||
        -1 == [lsearch $GoodBPMList S${sector}B:P3] } {
        APSInfoWindow .warning  -packOption "-side left" \
            -infoMessage "** Steering is disabled for ${sector}BM.**\n\nAt last one of S${sector}B:P4 or S${sector}B:P3 is considered bad for steering. \n\nContact experts if steering is really required. Press OK to remove this window." \
            -modal 1
        SetBMOptimizationStatus "Disabled ${sector}BM steering not attempted."
        return
    }
    
    
    global BP3x BP3y BP3y BP4y
    global statusCallback adjustOnly allowTransfer errorCode logFile

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

    global intensityPVConnected intensityPVName logFile logDir beamTolerance intTolerance
    set beamTolerance($sector) 3.0
    set intTolerance($sector) 500
    set intensityPVConnected($sector) 0
    set intensityPVName($sector) BM${sector}:SteeringGoodness
    set logFile($sector) [APSNextGenerationedName -directory $logDir -name S${sector}BMOptLog-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 "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"
    APSButton .refresh -parent $dialogFrame.intensity.frame.logfile \
      -size small -text New \
      -command "set logFile($sector) [APSNextGenerationedName -directory $logDir -name S${sector}BMOptLog-0000 -newFile 1 -separator -]" -contextHelp "press to generate a new file name that does not exist."
   
    
    set Sn $sector
    set useHighLevelPV($sector) 0
    if !$useHighLevelPV($sector) {
        if {[pv linkw \
                 [list BP4x($sector) BP4y($sector) BP3x($sector) BP3y($sector)] \
                 [list S${Sn}B:P4:ms:x:SetpointAO S${Sn}B:P4:ms:y:SetpointAO \
                      S${Sn}B:P3:ms:x:SetpointAO S${Sn}B:P3:ms:y:SetpointAO ]] != 0} {
            APSAlertBox .alert -errorMessage "$errorCode (1)"
            exit
        } 
    } else {
        # set high level PV to msAve
        if [catch {exec cavput -list=S${sector}B:P -list=3,4 -list=:y:ErrorCC:ModeMO=0 \
                   } result ] {
            APSAlertBox .alert -errorMessage "$result\nSomething wrong with a cavput command."
            return
        }
        if {[pv linkw \
                 [list BP4x($sector) BP4y($sector) BP3x($sector) BP3y($sector)] \
                 [list S${Sn}B:P4:ms:x:SetpointAO S${Sn}B:P4:ms:y:SetpointAO \
                      S${Sn}B:P3:ms:x:SetpointAO S${Sn}B:P3:ms:y:SetpointAO ]] != 0} {
            APSAlertBox .alert -errorMessage "$errorCode"
            exit
        }
    }
    if {[pv umon BP4x($sector)] != 0} {
        APSAlertBox .alert -errorMessage "$errorCode (2)"
        exit
    }
    if {[pv umon BP4y($sector)] != 0} {
        APSAlertBox .alert -errorMessage "$errorCode (3)"
        exit
    }
    if {[pv umon BP3x($sector)] != 0} {
        APSAlertBox .alert -errorMessage "$errorCode (4)"
        exit
    }
    if {[pv umon BP3y($sector)] != 0} {
        APSAlertBox .alert -errorMessage "$errorCode (5)"
        exit
    }

    global video ROI_XCenter ROI_YCenter ROI_XSize1 ROI_YSize1 ROI_XSize2 ROI_YSize2 videoList minIntensity feedbackGain
    
    set video($sector) S:VID1
    set ROI_XCenter($sector) 255
    set ROI_YCenter($sector) 241
    set ROI_XSize1($sector) 310
    set ROI_YSize1($sector) 400
    set ROI_XSize2($sector) 150
    set ROI_YSize2($sector) 100
    set minIntensity($sector) 500
    set feedbackGain($sector) 0.75

    global beamPos beamAngle intPos intAngle peakOpt
    # these are the feeback flags
    # If they are both zero, then no feedback is done,
    # and we go straight to optimization
    set beamPos($sector) 1
    set beamAngle($sector) 0
    # these are the feedback flags
    set intPos($sector) 0
    set intAngle($sector) 1
    set peakOpt($sector) opt
    
    APSFrame .opt -parent $dialogFrame -label "Optimization options and parameters" -packOption "-side top"  
    set w1 $dialogFrame.opt.frame  
   # APSFrame .x1 -parent $w1 -relief flat -label ""
    APSRadioButtonFrame .viedo -parent $w1  -label "Image System:  " -orientation horizontal \
        -buttonList $videoList -valueList $videoList \
        -variable video($sector)  
    
    APSRadioButtonFrame .radio -parent $w1 -orientation horizontal \
        -label "Find beam with?" -buttonList {"Optimization" "Feedback"} \
        -valueList {opt feedback} -variable peakOpt($sector)   \
        -contextHelp "choose option of finding beam: optimization of x and y or feedback of x and y"
    APSFrame .min -parent $w1 -relief flat -label ""
    APSLabeledEntry .min -parent $w1.min.frame -label "Minimum intensity level for optimization:" \
        -textVariable minIntensity($sector) -width 11 -packOption "-side left" \
        -contextHelp "The optimization will not be done if the beam intensity (S:VID1:x:fit:peakM, S:VID1:y:fit:peakM) is less than this value."
    APSLabeledEntry .gain -parent $w1.min.frame -label "  Feedback gain:" \
        -textVariable feedbackGain($sector) -width 11 -packOption "-side left" \
        -contextHelp "The gain value for beam finding feedback."
    
    set width 8
    APSFrame .opt1 -parent $w1 -relief flat -label ""
    set w2 $w1.opt1.frame
    APSFrame .xcenter -parent $w2 -relief flat -label "X center" \
        -width $width -packOption "-side left" \
        -contextHelp "Enter image X center position in pixels." 
    APSLabeledEntry .beam -parent $w2.xcenter.frame -label "Beam finding" \
        -textVariable ROI_XCenter($sector) -width $width
    APSLabeledEntry .int -parent $w2.xcenter.frame -label "Intensity Opt." \
        -textVariable ROI_XCenter($sector) -width $width
    
    APSFrame .ycenter -parent $w2 -relief flat -label "Y center" \
        -width $width -packOption "-side left" \
        -contextHelp "Enter image Y center position in pixels." 
    APSLabeledEntry .beam -parent $w2.ycenter.frame -label "" \
        -textVariable ROI_YCenter($sector) -width $width
    APSLabeledEntry .int -parent $w2.ycenter.frame -label "" \
        -textVariable ROI_YCenter($sector) -width $width
    
    APSFrame .xsize -parent $w2 -relief flat -label "X size" \
        -width $width -packOption "-side left" \
        -contextHelp "Enter image X size in pixels." 
    APSLabeledEntry .beam -parent $w2.xsize.frame -label "" \
        -textVariable ROI_XSize1($sector) -width $width
    APSLabeledEntry .int -parent $w2.xsize.frame -label "" \
        -textVariable ROI_XSize2($sector) -width $width
    
    APSFrame .ysize -parent $w2 -relief flat -label "Y size" \
        -width $width -packOption "-side left" \
        -contextHelp "Enter image Y size in pixels." 
    APSLabeledEntry .beam -parent $w2.ysize.frame -label "" \
        -textVariable ROI_YSize1($sector) -width $width
    APSLabeledEntry .int -parent $w2.ysize.frame -label "" \
        -textVariable ROI_YSize2($sector) -width $width
    
    APSFrame .tolerance -parent $w2 -relief flat -label "Tolerance" \
        -width $width -packOption "-side left" \
        -contextHelp "Enter image Y size in pixels." 
    APSLabeledEntry .beam -parent $w2.tolerance.frame -label "" \
        -textVariable beamTolerance($sector) -width $width
    APSLabeledEntry .int -parent $w2.tolerance.frame -label "" \
        -textVariable intTolerance($sector) -width $width
    
    APSFrame .pos -parent $w2 -relief flat -label "Actuators" \
        -width $width -packOption "-side left" \
        -contextHelp "Enter image Y size in pixels." 
    APSCheckButtonFrame .beam -parent $w2.pos.frame -buttonList {"x,y" "x',y'"} -orientation horizontal \
        -variableList [list beamPos($sector) beamAngle($sector)] -label ""
    APSCheckButtonFrame .int -parent $w2.pos.frame -label "" -orientation horizontal \
        -buttonList {"x,y" "x',y'"} -variableList [list intPos($sector) intAngle($sector)] 

    
    global xpLowerLimit xpUpperLimit xpStep xLowerLimit xUpperLimit xStep
    global ypLowerLimit ypUpperLimit ypStep yLowerLimit yUpperLimit yStep
 

    APSFrame .angles -parent $dialogFrame -packOption "-side top" -label "Optimization variable parameters"
    
    set xLowerLimit($sector) -500
    set xUpperLimit($sector) 500
    set xStep($sector) 20
    set xpLowerLimit($sector) -60
    set xpUpperLimit($sector)  60
    set xpStep($sector)        10
    set ypLowerLimit($sector) -30
    set ypUpperLimit($sector)  30
    set ypStep($sector)         10
    set yLowerLimit($sector) -100
    set yUpperLimit($sector) 100
    set yStep($sector) 10

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

    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 .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
    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
    
    APSFrame .step -parent $dialogFrame.angles.frame -relief flat \
        -label "Initial step" -width 10 -packOption "-side left" \
        -contextHelp "Enter upper limit for angle variation" 
    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
    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
    
   
    
    #checkbutton $dialogFrame.angles.frame.choice.frame.cbx -variable optPos($sector) 
    #pack $dialogFrame.angles.frame.choice.frame.cbx
    #checkbutton $dialogFrame.angles.frame.choice.frame.cby -variable optPos($sector) 
    #pack $dialogFrame.angles.frame.choice.frame.cby
    #checkbutton $dialogFrame.angles.frame.choice.frame.cbx1 -variable optAngle($sector) 
    #pack $dialogFrame.angles.frame.choice.frame.cbx1
    #checkbutton $dialogFrame.angles.frame.choice.frame.cby1 -variable optAngle($sector) 
    #pack $dialogFrame.angles.frame.choice.frame.cby1

    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 BM$sector"
    APSLabeledOutput .bp4x \
        -parent $wframe.parameters.frame.setpoints.frame \
        -label "S${Sn}B:P4:x (mm)"  -width 10 \
        -textVariable BP4x($sector) \
        -contextHelp "View value for S${Sn}B:P4:ms:x:SetpointAO."
    APSLabeledOutput .bp4y \
        -parent $wframe.parameters.frame.setpoints.frame \
        -label "S${Sn}B:P4:y (mm)"  -width 10 \
      -textVariable BP4y($sector) \
      -contextHelp "View value for S${Sn}B:P4:ms:y:SetpointAO."
    APSLabeledOutput .bp3x \
        -parent $wframe.parameters.frame.setpoints.frame \
        -label "S${Sn}B:P3:x (mm)"  -width 10 \
        -textVariable BP3x($sector) \
        -contextHelp "View value for S${Sn}B:P3:ms:x:SetpointAO."
    APSLabeledOutput .bp3y \
        -parent $wframe.parameters.frame.setpoints.frame \
        -label "S${Sn}B:P3:y (mm)"  -width 10 \
        -textVariable BP3y($sector) \
        -contextHelp "View value for S${Sn}B:P3:ms:y:SetpointAO."
    
    if {[pv linkw \
             [list BP4xSetpoint($sector) BP4ySetpoint($sector) BP3xSetpoint($sector) BP3ySetpoint($sector)] \
             [list S${Sn}B:P4:ms:x:SetpointAO S${Sn}B:P4:ms:y:SetpointAO \
                  S${Sn}B:P3:ms:x:SetpointAO S${Sn}B:P3:ms:y:SetpointAO ]] != 0} {
        APSAlertBox .alert -errorMessage "$errorCode (6)"
        exit
    }
    if {[pv linkw \
             [list BP4xOffset($sector) BP4yOffset($sector) BP3xOffset($sector) BP3yOffset($sector)] \
             [list S${Sn}B:P4:ms:x:OffsetAO S${Sn}B:P4:ms:y:OffsetAO \
                  S${Sn}B:P3:ms:x:OffsetAO S${Sn}B:P3:ms:y:OffsetAO ]] != 0} {
        APSAlertBox .alert -errorMessage "$errorCode (7)"
        exit
    }
    if {[pv linkw \
             [list BP4xAdjusted($sector) BP4yAdjusted($sector) BP3xAdjusted($sector) BP3yAdjusted($sector)] \
             [list S${Sn}B:P4:ms:x:AdjustedCC S${Sn}B:P4:ms:y:AdjustedCC \
                  S${Sn}B:P3:ms:x:AdjustedCC S${Sn}B:P3:ms:y:AdjustedCC ]] != 0} {
        APSAlertBox .alert -errorMessage "$errorCode (8)"
        exit
    }
    
    if {[pv linkw \
             [list BP4xError($sector) BP4yError($sector) BP3xError($sector) BP3yError($sector)] \
             [list S${Sn}B:P4:ms:x:ErrorCC S${Sn}B:P4:ms:y:ErrorCC \
                  S${Sn}B:P3:ms:x:ErrorCC S${Sn}B:P3:ms:y:ErrorCC ]] != 0} {
        APSAlertBox .alert -errorMessage "$errorCode (9)"
        exit
    }
    if {[pv umon BP3xOffset($sector)]!=0} {
        APSAlertBox .alert -errorMessage "$errorCode BP3xOffset($sector)"
        exit
    }
    if {[pv umon BP3yOffset($sector)]!=0} {
        APSAlertBox .alert -errorMessage "$errorCode BP3yOffset($sector)"
        exit
    }
    if {[pv umon BP4xOffset($sector)]!=0} {
        APSAlertBox .alert -errorMessage "$errorCode BP4xOffset($sector)"
        exit
    }
    if {[pv umon BP4yOffset($sector)]!=0} {
        APSAlertBox .alert -errorMessage "$errorCode BP4yOffset($sector)]"
        exit
    }
    
    if {[pv umon BP4xAdjusted($sector)]!=0} {
        APSAlertBox .alert -errorMessage "$errorCode BP4xAdjusted($sector)"
        exit
    }
    if {[pv umon BP4yAdjusted($sector)]!=0} {
        APSAlertBox .alert -errorMessage "$errorCode BP4yAdjusted($sector)"
        exit
    }
    if {[pv umon BP3xAdjusted($sector)]!=0} {
        APSAlertBox .alert -errorMessage "$errorCode BP3xAdjusted($sector)"
        exit
    }
    if {[pv umon BP3yAdjusted($sector)]!=0} {
        APSAlertBox .alert -errorMessage "$errorCode BP3yAdjusted($sector)"
        exit
    }
    
    if {[pv umon BP4xError($sector)]!=0} {
        APSAlertBox .alert -errorMessage "$errorCode BP4xError($sector)"
        exit
    }
    if {[pv umon BP4yError($sector)]!=0} {
        APSAlertBox .alert -errorMessage "$errorCode BP4yError($sector)"
        exit
    }
    if {[pv umon BP3xError($sector)]!=0} {
        APSAlertBox .alert -errorMessage "$errorCode BP3xError($sector)"
        exit
    }
    if {[pv umon BP3yError($sector)]!=0} {
        APSAlertBox .alert -errorMessage "$errorCode BP3yError($sector)"
        exit
    }
    
    APSFrame .moreParameters -parent $wframe -packOption "-side left" -relief flat
    APSLabeledOutputFrame .offset -parent $wframe.moreParameters.frame \
        -label Offsets -packOption "-side left" \
        -variableList "BP4xOffset($sector) BP4yOffset($sector) BP3xOffset($sector) BP3yOffset($sector)"\
        -orientation vertical -width 10 \
        -contextHelp "Electrical offset of BM$sector bpms."
    $wframe.moreParameters.frame.offset.frame configure -relief flat

    APSLabeledOutputFrame .adjusted -parent $wframe.moreParameters.frame \
        -label "Adjusted" -packOption "-side left" \
        -variableList "BP4xAdjusted($sector) BP4yAdjusted($sector) BP3xAdjusted($sector) BP3yAdjusted($sector)"\
        -orientation vertical -width 10 \
        -contextHelp "Adjusted readbacks of BM$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 "BP4xError($sector) BP4yError($sector) BP3xError($sector) BP3yError($sector)"\
        -orientation vertical -width 10 \
        -contextHelp "Error readbacks of BM$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 .dialogBM$sector.buttonRow.ok.button
    
    APSButton .optimize -parent .dialogBM$sector.buttonRow -text Optimize \
        -command "OptimizeIntensity -sector $sector -parent .dialogBM$sector.buttonRow"
    
    if $allowTransfer {
        APSButton .transfer -parent .dialogBM$sector.buttonRow -text Transfer \
            -command "TransferValues -sector $sector" -contextHelp  "Transfers present adjusted bpm values to the setpoint values for BM $sector."
    }
    
    update
    if {$statusCallback!=""} {
        $statusCallback "Enabling averaging for S${Sn}B:P4 and S${Sn}B:P3."
    }
    
    if [catch {exec cavput -list=S${Sn}B:P4,S${Sn}B:P3 \
                   -list=:msAve:AveEnbBO=Enable \
                   -pendIoTime=10 \
               } result ] {
        APSAlertBox .alert -errorMessage "$result\nSomething wrong with a cavput command. Averaging may not be enabled."
        return
    }
}

proc OptimizeIntensity {args} {
    set sector 0
    set parent ""
    APSStrictParseArguments {sector parent}
    if {$sector<1 || $sector>40} {
        APSAlertBox .alert -errorMessage "Sector invalid ($sector) in OptimizeIntensity"
    }
    global optimizeRunControlPV
    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] {
        SetBMOptimizationStatus "Can not read optimization runcontrol pv: $optRunning"
        APSAlertBox [APSUniqueName .] -errorMessage "Can not read optimization runcontrol pv: $optRunning"
        return
    }
    if {$optRunning} {
        SetBMOptimizationStatus "Another BM optimization is running."
        APSAlertBox [APSUniqueName .] -errorMessage "Can not start BM optimization since another one is running"
        return
    }
    # start steering   
    if [catch {StartControllaw -sector $sector} result] {
        SetBMOptimizationStatus "Can't optimize because steering didn't start - $result."
        APSAlertBox [APSUniqueName .] -errorMessage "Unable to start BM steering: $result"
        return
    }
    global logFile logDir video steeringRunControlPV
    if [catch {CreateOptimizationFiles -sector $sector} result] {
        SetBMOptimizationStatus "Can't optimize - $result."
        APSAlertBox [APSUniqueName .] -errorMessage "Unable to create optimization files: $result"
        return
    }

    global beamTolerance intTolerance  
    global beamPos beamAngle intPos intAngle peakOpt
    global feedbackGain optimization1 optimization2
    set optimization1 0
    set optimziation2 0

# there are two while loops, one for centering the beam in the ROI (there are
# two methods for this one),
# the second for optimizing the intensity.

    while {1} {
        if [APSYesNoPopUp "Start or continue optimizing?\nPress no to get to the second step"] {
            if {$peakOpt($sector)=="opt"} {
                # search for zeroes of x and y using optimizer
                if {!$beamPos($sector) && !$beamAngle($sector)} {
                    SetBMOptimizationStatus "No variables selected for finding beam!"
                    APSAlertBox [APSUniqueName .] -errorMessage "No variables selected for beam finding!"
                    return
                }
                # Prepare sddsoptimize command
                SetBMOptimizationStatus "Finding Beam with optimization..."
                file delete -force $logDir/$logFile($sector).ref
                if {$beamPos($sector) && $beamAngle($sector)} {
                    set varInput $logDir/$logFile($sector).all.optIn
                } elseif $beamPos($sector) {
                    set varInput $logDir/$logFile($sector).pos.optIn
                } elseif $beamAngle($sector) {
                    set varInput $logDir/$logFile($sector).angle.optIn 
                }
                if [catch {SetROI -sector $sector -type 1} result] {
                    return -code error $result
                }
                set varScript "setBMSteering -position $beamPos($sector) -angle $beamAngle($sector) -sector $sector  -reference $logDir/$logFile($sector).ref" 
                set measScript "measureBMIntensity -video $video($sector) -findBeam 1" 
                # sddsoptimize to minimize the output of above script
                set command "sddsoptimize -target=0 -varFile=$varInput \"-measScript=$measScript\" -testValues=file=$logDir/$logFile($sector).test,limit=1000 -verbose -simplex=restart=2,cycles=3,evaluations=100 \"-varScript=$varScript\"  -tolerance=$beamTolerance($sector) -logFile=$logDir/$logFile($sector).peakpos -runControlPV=string=$optimizeRunControlPV,pingTimeout=100 \"-runControlDesc=string=BM$sector beam finding with opt\""
             
                set optimization1 0
                APSExecLog .optimize -width 100 -unixCommand $command \
                    -callback "set optimization1 1" \
                    -cancelCallback "set optimization1 2" \
                    -abortCallback "set optimization1 2"
                tkwait variable optimization1
            } else {
                # search for zeroes of x and y using feedback
                SetBMOptimizationStatus "Finding Beam with feedback..."
                set optimization1 0
                if [catch {SetROI -sector $sector -type 1} result] {
                    return -code error $result
                }
                APSExecLog .optimize -width 100 -unixCommand "sddscontrollaw $logDir/$logFile($sector).irm -runControlPV=string=$optimizeRunControlPV,pingTimeout=100 \"-runControlDesc=string=BM$sector beam finding with feedback\" -integral -interval=10 -step=1000 -deltaLimit=value=0.1 -test=$logDir/$logFile($sector).test -gain=$feedbackGain($sector)" \
                    -callback "set optimization1 1" \
                    -cancelCallback "set optimization1 2" \
                    -abortCallback "set optimization1 2"
                tkwait variable optimization1
            }
        } else {
            break
        }
    }
    
    while {1} {
        if [APSYesNoPopUp "Start or continue to maximize BM$sector beam intensity?"] {
            global intPos intAngle intTolerance
            if {!$intPos($sector) && !$intAngle($sector)} {
                SetBMOptimizationStatus "No variables selected for optimizing BM$sector intensity!"
                APSAlertBox [APSUniqueName .] -errorMessage "No variables selected for optimizing BM$sector intensity!"
                return
            }
            file delete -force $logDir/$logFile($sector).ref
            if {$intPos($sector) && $intAngle($sector)} {
                set varInput $logDir/$logFile($sector).all.optIn
            } elseif $intPos($sector) {
                set varInput $logDir/$logFile($sector).pos.optIn
            } elseif $intAngle($sector) {
                set varInput $logDir/$logFile($sector).angle.optIn
            }
            set varScript "setBMSteering -angle $intAngle($sector) -position $intPos($sector) -sector $sector  -reference  $logDir/$logFile($sector).ref" 
            set measScript "measureBMIntensity -video $video($sector) -findBeam 0"
            if [catch {SetROI -sector $sector -type 2} result] {
                return -code error $result
            }
            # turn off baseline substraction
            if [catch {exec cavput -list=$video($sector):autoBaselineShiftC=0} result] {
                return -code error $result
            }
            SetBMOptimizationStatus "Maximizing Beam intensity..."
            set command "sddsoptimize -varFile=$varInput \"-measScript=$measScript\" -testValues=file=$logDir/$logFile($sector).test,limit=1000 -verbose -simplex=restart=2,cycles=3,evaluations=100 \"-varScript=$varScript\" -maximize -tolerance=$beamTolerance($sector) -logFile=$logDir/$logFile($sector) -runControlPV=string=$optimizeRunControlPV,pingTimeout=100 \"-runControlDesc=string=BM$sector intensity optimization\""
            set optimization2 0
            APSExecLog .optimize -width 100 -unixCommand $command \
                -callback "set optimization2 1" \
                -cancelCallback "set optimization2 2" \
                -abortCallback "set optimization2 2"
            tkwait variable optimization2
           
        } else {
            break
        }
    }
    if {$optimization1 || $optimization2} {
        #abort BM steering
        if [catch {APSAbortControllaw -runControlPV $steeringRunControlPV} result] {
            return -code error $result
        }
    }
    RestoreROI -video $video($sector)
    # restore baseline substraction
    if [catch {exec cavput -list=$video($sector):autoBaselineShiftC=1 } result] {
        return -code error $result
    }
}
 
proc TransferValues {args} {
    global timeLimit tolerance statusCallback P0Sector

    set sector ""
    APSParseArguments {sector}
    if ![string length $sector] {
        APSAlertBox [APSUniqueName .] -errorMessage \
          "No sector variable specified in BMOptimizationDialog"
        return 1
    }
    if $P0Sector($sector) {
        set digit 0
    } else {
        set digit 1
    }
    global BPxAdjusted BPyAdjusted APxAdjusted APyAdjusted
    if ![APSYesNoPopUp "You are asking to transfer adjusted bpm values to setpoint values.  Are you sure?"] {
            SetBMOptimizationStatus "Transfer cancelled."
            return 1
        }
    set Sn $sector
    set Sn1 [exec rpnl "$Sn 1 + 40 > pop ? 40 - : \$"]
    set cavputList S${Sn}B:P${digit}:ms:x:SetpointAO=$BPxAdjusted($sector),
    append cavputList S${Sn}B:P${digit}:ms:y:SetpointAO=$BPyAdjusted($sector),
    append cavputList S${Sn1}A:P${digit}:ms:x:SetpointAO=$APxAdjusted($sector),
    append cavputList S${Sn1}A:P${digit}:ms:y:SetpointAO=$APyAdjusted($sector)
    if [catch {exec cavput -list=$cavputList -pendIoTime=10 \
               } result ] {
        APSAlertBox .alert -errorMessage "$result\nSomething wrong with a cavput command. Setpoints may not be asserted."
        return 1
    }
    if {$statusCallback!=""} {
        $statusCallback "Refreshing datapool vector of bpm adjust PVs..."
    }
    
    set pvList [list S${Sn}B:P4 S${Sn}B:P3]
    if [catch {APSRefreshVectorAdjust -pvList $pvList \
                   -waveformFile rfBpmInfo.sdds -plane both} result] {
        APSAlertBox .alert -errorMessage "$result\nSomething wrong with resetting vector adjust values."
        return 1
    }
    if {$statusCallback!=""} {
        $statusCallback "Done."
    }
    return 0
}

set steeringMode none
proc StartControllaw {args} {
    global timeLimit tolerance statusCallback steeringRunControlPV
    global gain interval 
    global steeringMode 
    set steeringMode none

    set sector ""
    APSParseArguments {sector}

    if ![string length $sector] {
        rerturn -code error "No sector variable specified in BMSteeringDialog" 
    }
    if [catch {APSSRCheckCorrectorMode -plane h} hCorrMode] {
        return -code error "$hCorrMode" 
    }
    if [catch {APSSRCheckCorrectorMode -plane v} vCorrMode] {
        return -code error "$vCorrMode" 
    }
    if [string compare $hCorrMode $vCorrMode]!=0 {
        return -code error "The corrector modes in x and y plane are not consistent!" 
    }
    if [string compare $hCorrMode vector]==0 {
        set steeringRunControlPV DP:S:SteeringSDDS
    } else {
        set steeringRunControlPV S:SteeringSDDS
    }
    if [catch {exec cavget -list=$steeringRunControlPV.RUN -pend=30} running] {
        return -code error $running
    }
    if $running {
        if [APSYesNoPopUp "Another steering is running, would you like to abort it and continue?"] {
            if [catch {exec cavput -list=$steeringRunControlPV.ABRT=1 -pend=30} result] {
                return -code error $result
            }
            after 2000
            if [catch {exec cavput -list=$steeringRunControlPV.CLR=1 \
                           -pend=30} result] {
                return -code error "Unable to abort steering: $result"
            }
        } else {
            return -code error "SRBMSteering: another steering is running!"
        }
    }
    set Sn $sector
    
    if {$statusCallback!=""} {
        $statusCallback "Refreshing datapool vector of bpm adjust PVs..."
    }
    set pvList [list S${Sn}B:P4 S${Sn}B:P3]
    if [catch {APSRefreshVectorAdjust -pvList $pvList -waveformFile rfBpmInfo.sdds -plane both} result] {
        return -code error "$result\nSomething wrong with resetting vector adjust values." 
    }
    if {$statusCallback!=""} {
        $statusCallback "Done."
    }
    set controllawDir /home/helios/oagData/sr/localSteering/lattices/default/BMs/[format %02ld ${sector}]BM
    if {![file exist $controllawDir]} {
        return -code error "SRBMSteering: $controllawDir does not exist!" 
    }
    
    if {![file exist $controllawDir/irm] || ![file exist $controllawDir/tests] || \
          ![file exist $controllawDir/plain.defs] || ![file exist $controllawDir/dynamic.defs]} {
        return -code error "SRBMSteering: some controllaw files in $controllawDir do not exist!" 
    }
    if [catch {exec sdds2stream -par=ConditionNumber $controllawDir/irm} ConditionNumber] {
        return -code error "SRBMSteering: Problem with getting ConditionNumber from $controllawDir/irm!" 
    }
    if {$ConditionNumber>1.0e3} {
        return -code error "SRBMSteering: The ConditionNumber of $controllawDir/irm is greater than 1.0e3!" 
    }
    # determine what mode the correctors are in to pick the correct 
    # definitions file to use.
    if [catch {exec sdds2stream -col=ControlName $controllawDir/irm} correctors] {
        return -code error "SRBMSteering: Problem with getting correctors from $controllawDir/irm"
    }
    if [catch {exec cavget -pend=15 -list=[join $correctors ,] \
                 -list=:ControlSrcBO -label -embrace} tagValuePairs] {
        return -code error "SRBMSteering: Problem with getting source for correctors: $tagValuePairs"
    }
    # Take first one corrector as giving the reference mode
    set mode [lindex [lindex $tagValuePairs 0] 1]
    set incorrectMode 0
    foreach tagValue $tagValuePairs {
        if {[string compare [lindex $tagValue 1] $mode]} {
            incr incorrectMode
        }
    }
    if $incorrectMode {
        return -code error "Found $incorrectMode correctors not in mode $mode. Correction can't proceed." 
    }
    switch $mode {
        Maintenance {
            set defs plain.defs
        }
        Operation {
            set defs dynamic.defs
        }
    }
    if [catch {exec logMessage  -sourceId=steeringAudit\
                  -tag=Instance BM${sector} -tag=Action Start \
              } result ] {
        return -code error "error with logMessage: $result"
    }

    if [string length $statusCallback]  {
        $statusCallback "Starting sddscontrollaw on BM$sector."
    }
    set oldDir [pwd]
    cd $controllawDir
    
    if [string compare $hCorrMode vector]==0 {
        exec medm -attach -x -macro SDDSPV=$steeringRunControlPV \
	    /usr/local/iocapps/adlsys/srbpm/datapool/sddsEpicsLauncher.adl &
        if [catch {APSSRStartLocalSteeringInIOC -interval $interval -gain $gain \
                     -definition $defs -controllawDir $controllawDir -timeLimit $timeLimit } result] {
            return -code error "Unable to start steering in IOC: $result!" 
        }
        set steeringMode ioc
    } else {
        exec medm -attach -x -macro RCPV=$steeringRunControlPV \
            /usr/local/iocapps/adlsys/sr/psApp/APSRunControlSingle.adl &
        APSExecLog .controllaw -width 100 \
            -lineLimit 1024 \
            -name "$controllawDir local correction" \
            -unixCommand "sddscontrollaw irm \
         -test=tests \
         -runControlPV=string=$steeringRunControlPV,pingTimeout=30 \
         \"-runControlDescription=string=BM steering\" \
         -controlQuantityDefinition=$defs \
         -gain=$gain -interval=$interval -deltaLimit=value=2 \
         -verbose=1 -steps=[expr int($timeLimit/$interval)]" \
            -callback "controllawCallback -sector $sector" \
            -abortCallback "abortControllawCallback  -sector $sector" \
            -cancelCallback "abortControllawCallback  -sector $sector"
        set steeringMode ws
    }
    cd $oldDir
    return 1
}

proc controllawCallback {args} {
    global statusCallback  

    APSParseArguments {sector}
     
    if {$statusCallback!=""} {
        $statusCallback "sddscontrollaw on BP4 and BP3 bpms for BM$sector completed."
    }
    if [catch {exec logMessage  -sourceId=steeringAudit \
                   -tag=Instance BM${sector} -tag=Action Exit \
               } result ] {
        APSAlertBox .alert -errorMessage "error with logMessage: $result"
        return
    }
    return
}

proc abortControllawCallback {args} {
    global statusCallback 

    APSParseArguments {sector}
    
    if {$statusCallback!=""} {
        $statusCallback "sddscontrollaw on BP4 and BP3 bpms for BM$sector aborted."
    }
    if [catch {exec logMessage  -sourceId=steeringAudit \
                   -tag=Instance BM${sector} -tag=Action Abort \
              } result ] {
        APSAlertBox .alert -errorMessage "error with logMessage: $result"
        return
    }
    return
}

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)] {
        SetBMOptimizationStatus "not found: $logFile($sector)"
    }
#    exec sddsplot -column=EvalIndex,currentValue $logDir/$logFile($sector) -graph=sym &
    exec sddsplot $logDir/$logFile($sector) -layout=1,2 -tick=xtime \
      "-topline=BM$sector Steering Optimization" \
      -leg,firstFileOnly \
      -col=Time,?Slope -gra=line,vary,fixforname -yscale=id=slopes \
      "-ylabel=Slopes (\$gm\$rrad)" \
      -end \
      -col=Time,currentValue -grap=line,type=3,thick=2 \
      -ylabel=Intensity -factor=ymult=-1 -yscale=id=Intensity &
    exec sddsplot $logDir/$logFile($sector) \
      "-topline=BM35 Steering Optimization" \
      -col=xSlope,ySlope -grap=sym,vary=sub,sca=3 \
      -split=col=currentValue,width=1000 -order=spect &
    
    exec sddsplot $logDir/$logFile($sector) -layout=1,2 -tick=xtime \
      "-topline=BM$sector Steering Optimization" \
      -leg,firstFileOnly \
      -col=Time,?Slope -gra=line,vary,fixforname -yscale=id=slopes \
      "-ylabel=Slopes (\$gm\$rrad)" \
      -end \
      -col=Time,currentValue -grap=line,type=3,thick=2 \
      -ylabel=Intensity -factor=ymult=-1 -yscale=id=Intensity \
      -device=lpng -output=$logDir/$logFile($sector).png
    exec sddsplot $logDir/$logFile($sector) \
      "-topline=BM35 Steering Optimization" \
      -col=xSlope,ySlope -grap=sym,vary=sub,sca=3 \
      -split=col=currentValue,width=1000 -order=spect \
      -device=lpng -output=$logDir/$logFile($sector).contour.png

}

proc CreateOptimizationFiles {args} {
    set sector ""
    APSParseArguments {sector}
    global logDir logFile steeringRunControlPV video minIntensity
    global xpLowerLimit xpUpperLimit xpStep xLowerLimit xUpperLimit xStep
    global ypLowerLimit ypUpperLimit ypStep yLowerLimit yUpperLimit yStep
    
    if ![string length $sector] {
        return -code error "sector is not provided."
    }
    if ![string length $logFile($sector)] {
        set logFile($sector) /tmp/[APSTmpString]S${sector}.log
    }
    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" 
    }
    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"
    }
    
    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" 
    }
    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"
    }
    if [catch {exec sddsmakedataset $logDir/$logFile($sector).all.optIn \
                   -parameter=PauseBetweenReadings,type=double -data=0 \
                   -column=ControlName,type=string -data=xPos,yPos,xSlope,ySlope \
                   -column=LowerLimit,type=double -data=$xLowerLimit($sector),$yLowerLimit($sector),$xpLowerLimit($sector),$ypLowerLimit($sector) \
                   -column=UpperLimit,type=double -data=$xUpperLimit($sector),$yUpperLimit($sector),$xpUpperLimit($sector),$ypUpperLimit($sector) \
                   -column=InitialChange,type=double -data=$xStep($sector),$yStep($sector),$xpStep($sector),$ypStep($sector) \
                   -column=InitialValue,type=double -data=0,0,0,0 } result] {
        return -code error $result
    }
    
    if [catch {exec sddsmakedataset $logDir/$logFile($sector).pos.optIn \
                   -parameter=PauseBetweenReadings,type=double -data=0 \
                   -column=ControlName,type=string -data=xPos,yPos \
                   -column=LowerLimit,type=double -data=$xLowerLimit($sector),$yLowerLimit($sector) \
                   -column=UpperLimit,type=double -data=$xUpperLimit($sector),$yUpperLimit($sector) \
                   -column=InitialChange,type=double -data=$xStep($sector),$yStep($sector) \
                   -column=InitialValue,type=double -data=0,0 } result] {
        return -code error $result
    }
    
    if [catch {exec sddsmakedataset $logDir/$logFile($sector).angle.optIn \
                   -parameter=PauseBetweenReadings,type=double -data=0 \
                   -column=ControlName,type=string -data=xSlope,ySlope \
                   -column=LowerLimit,type=double -data=$xpLowerLimit($sector),$ypLowerLimit($sector) \
                   -column=UpperLimit,type=double -data=$xpUpperLimit($sector),$ypUpperLimit($sector) \
                   -column=InitialChange,type=double -data=$xpStep($sector),$ypStep($sector) \
                   -column=InitialValue,type=double -data=0,0 } result] {
        return -code error $result
    }
    
    if [catch {exec sddsmakedataset $logDir/$logFile($sector).test \
                   -column=ControlName,type=string \
                   -data=S-DCCT:CurrentM,${steeringRunControlPV}.RUN,$video($sector):x:raw:peakM,$video($sector):y:raw:peakM,S${sector}B:P4:ms:x:SetpointAO,S${sector}B:P3:ms:x:SetpointAO,S${sector}B:P4:ms:y:SetpointAO,S${sector}B:P3:ms:y:SetpointAO \
                   -column=MinimumValue,type=double   \
                   -data=40,0.5,$minIntensity($sector),$minIntensity($sector),-3,-3,-3,-3  \
                   -column=MaximumValue,type=double  \
                   -data=305,1.5,1.0e6,1.0e6,3,3,3,3   } result] {
        return -code error $result
        
    }
    #create feedback controllaw files
    #irm  - inverse response matrix including the um/mm conversion
    # and the flip in the x direction from mirror optics
    # and the flip in the y direction from the video processing
    if [catch {exec sddsmakedataset $logDir/$logFile($sector).irm \
                   -col=ControlName,type=string \
                   -data=S${sector}B:P4:ms:x:SetpointAO,S${sector}B:P3:ms:x:SetpointAO,S${sector}B:P4:ms:y:SetpointAO,S${sector}B:P3:ms:y:SetpointAO \
                   -col=S:VID1:x:fit:cal:centrdAvgM,type=double \
                   -data=-1e-3,-1e-3,0,0 \
                   -col=S:VID1:y:fit:cal:centrdAvgM,type=double \
                   -data=0,0,-1e-3,-1e-3 } result] {
        return -code error $result
    }
}

proc SetROI {args} {
    set type ""
    set sector ""
    APSParseArguments {type sector}
    
    if ![string length $type] {
        return -code error "The ROI type (for beam finding or intensity optimization) is not given!"
    }
    if ![string length $sector] {
        return -code error "Sector is not given!"
    }
    global video ROI_XCenter ROI_YCenter ROI_XSize1 ROI_YSize1 ROI_XSize2 ROI_YSize2
    set xsize [set ROI_XSize${type}($sector)]
    set ysize [set ROI_YSize${type}($sector)]
    set xstart [expr $ROI_XCenter($sector) - $xsize/2.0]
    set ystart [expr $ROI_YCenter($sector) - $ysize/2.0]
    SetBMOptimizationStatus "Setting ROI to xstart=$xstart, ystart=$ystart, xsize=$xsize, ysize=$ysize..."
    if [catch {exec cavput -list=$video($sector):roiXStartC=$xstart,$video($sector):roiYStartC=$ystart,$video($sector):roiXSizeC=$xsize,$video($sector):roiYSizeC=$ysize -pend=30} result] {
        return -code error $result
    }
    SetBMOptimizationStatus "Done."
}

set videoList {S:VID1 S:VID2 S:VID3 S:VID4}
proc SaveROI {args} {
    global videoList
    eval global $videoList
    foreach video $videoList {
        if [catch {exec cavget -list=${video}:roi -list=XStartC,YStartC,XSizeC,YSizeC \
                       -pend=30} valList] {
            return -code error $valList
        }
        set ${video}(xStart) [lindex $valList 0]
        set ${video}(yStart) [lindex $valList 1]
        set ${video}(xSize) [lindex $valList 2]
        set ${video}(ySize) [lindex $valList 3]
    }
}

proc RestoreROI {args} {
    set video ""
    APSParseArguments {video}
    global videoList
    if [lsearch $videoList $video] {
        return "Video $video is not found in video list - $videoList!"
    }
    global $video
    if [catch {exec cavput -list=${video}:roiXStartC=[set ${video}(xStart)],${video}:roiYStartC=[set ${video}(yStart)],${video}:roiXSizeC=[set ${video}(xSize)],${video}:roiYSizeC=[set ${video}(ySize)] -pend=30} result] {
        return -code error $result
    }
}

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

# make list of  P4 and P3 bpms are OK for BM steering
set GoodBPMList [exec sddsprocess /home/helios/oagData/sr/BPMStatus/config.sdds \
                     -pipe=out \
                     -match=col,DeviceName=*B:P4,DeviceName=*B:P3,| \
                     -filter=col,OkForSteeringH,0,0,OkForSteeringV,0,0,|,! \
                     | sdds2stream -pipe=in -col=DeviceName]

MakeSectorsWidget .sectors -parent .userFrame
MakeOptionWidget .options -parent .userFrame
if $allowTransfer {
    MakeTransferWidget .actions -parent .userFrame
}

set tolerance 0.050
set timeLimit 6000
set statusCallback SetBMOptimizationStatus
set interval 0.5
set gain 0.3
set offsetReferenceFile /home/helios/oagData/SCR/snapshots/SR/SR-BPMOffsetReference.gz

set logDir [APSGoToDailyDirectory]/BMOrbitOptimization
if ![file exist $logDir] {
    exec mkdir -p $logDir
}
SaveROI
