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

# $Log: not supported by cvs2svn $
# Revision 1.15  2003/07/24 22:14:39  emery
# INcreased the steps for orbit correction to 300000
#
# Revision 1.14  2003/04/07 15:41:14  shang
# increaded the runcontrol pingTimeout to 30 seconds
#
# Revision 1.13  2003/03/25 06:14:22  emery
# Changed version of sddsexperiment from Shang's version to the public version.
#
# Revision 1.12  2003/01/14 23:41:41  emery
# Indented code and removed some commented out statements.
#
# Revision 1.11  2002/12/11 01:31:51  shang
# added pre ramping and post ramping into sddsexperiment and made other changes
#
# Revision 1.10  2002/12/10 20:49:43  shang
# changed the description of ID local bump config
#
# Revision 1.9  2002/11/28 18:02:52  shang
# changed some experiment parameter values
#
# Revision 1.8  2002/11/28 16:25:34  shang
# added setting SRF:AGC:FB_SoftEngage1BO and SRF:AGC:FB_SoftEngage2BO to 1 after dumping the beam
#
# Revision 1.7  2002/11/28 16:00:50  shang
# converted orbit correction to datapool
#
# Revision 1.6  2002/03/05 16:25:21  emery
# Reduced time intervals for orbit correction now that faster
# corrector communications are available. Added separate pv test process.
# Added tab widgets to sddscontrollaw and sddspvtests, and the necessary
# destroy statements upon restarting processes.
#
# Revision 1.5  2002/03/04 21:01:16  emery
# Changed sddscontrollaw interval from 2.5 to 0.5 seconds.
#
# Revision 1.4  2002/03/04 20:51:10  emery
# Fixed problem with number variable in proc Inject.
#
# Revision 1.3  2002/03/04 20:48:03  emery
# Updated RF AGC reseting. Added selection of number of bunches for injection.
#
# Revision 1.2  2001/09/05 16:44:22  emery
# Added dialog box for checking orbit correction status.
# Added some calculation of expected tune shift.
# Fixed some sddsxref arguments. Added
# plot of angle difference in processing.
#
# Revision 1.1  2001/06/08 18:46:21  emery
# First installation
#

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

APSStandardSetup
set CVSRevisionAuthor "\$Revision: 1.16 $ \$Author: emery $"

APSApplication . -name IDmeasureLocalImpedance -version $CVSRevisionAuthor \
  -overview {Local impedance can be measured by scanning closed bumps in a  straight section select by the user.\n\nThe scanning is done by running sddsexperiment with a closed bump using H2 and H3 (or V2 and V3) feedforward PVs. The closed bump is guaranteed by running orbit correction using the H2 or V2. The data of interest is the resulting H2 or V2 for a given H3 or V3. The scan is repeatd for different single bunch current. The results is processed displaying H2 or V3 as independent variable and the change in H2 or V2 as the result.\n\nAn appropriate orbit correction configuration must hgave been prepared in advance for the H and V scans.\n\nThe bunch monitor using the ADC750 has to be working well since the value of the single bunch current is obtained from the ADC750. Also the ring must be in a state that is reprodcible form measurement to measurement.\n\nThe scan can be aborted using the bottom row button in the APSExecLog window. The correctors will return to the original values.}

set status Working
APSScrolledStatus .status -parent .userFrame -textVariable status -width 80 \
  -height 10

set abortRun 0
update

proc setStatus {text} {
    global status
    set status $text
    update
}
for {set i 1} {$i < 41} {incr i} {
    lappend sectorList $i
}

proc MakeOptionWidget {widget args} {
    global sector sensitiveWidgets root
    set parent ""
    APSParseArguments {parent}

    APSFrame $widget -parent $parent \
      -contextHelp "Setup options for Measuring local impedance"
    set w $parent$widget.frame
    for {set i 1} {$i <=40} {incr i} {
        lappend sectorList $i
        lappend formattedSectorList "[format %2ld $i]"
    }
    APSRadioButtonFrame .bframe -parent $w -label "Sector" \
      -buttonList $formattedSectorList -valueList $sectorList \
      -variable sector \
      -orientation horizontal -limitPerRow 10 \
      -contextHelp "Select a sector of the ID straight section for local impedance measurement."
    APSLabeledEntry .root -parent $w -label "Root name of file: " \
      -textVariable root \
      -contextHelp "Root name of file for closed bump scan in x or y. The plane coordinate and the index number will be added to make an output file."
    APSLabeledEntry .totalCharge -parent $w -label "Total current: " \
      -textVariable current \
      -contextHelp "Total current for each fill pattern. A low current of 10 mA is recommended since we don't expect thermal transients."

    APSLabeledEntry .loBunches -parent $w -label "Number of bunches for high-charge pattern: " \
      -textVariable loBunches \
      -contextHelp "Choose a low number of bunches for high charge per bunch.A charge per bunch of ~ 5 mA is recommended, since a local bump may for a laregr charge may be unstable."

    APSLabeledEntry .hiBunches -parent $w -label "Number of bunches for low-charge pattern: " \
      -textVariable hiBunches \
      -contextHelp "Choose a large number of bunches for low charge per bunch.A charge per bunch of ~ 1 mA is recommended, since too low a charge will make the bpm noisy."

    APSLabeledOutput .presentPattern -parent $w -label "Bunch Pattern" \
      -textVariable presentPattern \
      -contextHelp "Bunch pattern currently stored after the last injection performed by this application."
    APSButton .lo -parent $w.presentPattern -packOption "-side right" \
      -text "Low charge" -size small \
      -command "set presentPattern loCharge" \
      -contextHelp "Overwrites the value of present bunch pattern to \"loCharge\". Useful if beam pattern is unknown to the script."
    APSButton .hi -parent $w.presentPattern -packOption "-side right" \
      -text "Hi charge" -size small \
      -command "set presentPattern hiCharge" \
      -contextHelp "Overwrites the value of present bunch pattern to \"hiCharge\". Useful if beam pattern is unknown to the script."


    APSLabeledOutput .singleBunch -parent $w -label "Single bunch current (mA): " \
      -textVariable singleBunch \
      -contextHelp "Readback of current monitor for single bunch at bucket 0 at the end of injection."
    APSButton .read -parent $w.singleBunch -packOption "-side right" \
      -text "Read" -size small \
      -command "ReadSingleBunch" \
      -contextHelp "Reads the single bunch current. Done automatically after an injection."

    APSLabeledEntry .hdefault -parent $w -label "Regular H-correction matrix" \
      -textVariable  hdefault \
      -contextHelp "H-corrector matrix to be used for orbit correction just after the bunch has been injected into the ring. Normally doesn't have Xray bpms since the charge is expected to be low."
    APSLabeledEntry .vdefault -parent $w -label "Regular V-correction matrix" \
      -textVariable  vdefault \
      -contextHelp "V-corrector matrix to be used for orbit correction just after the bunch has been injected into the ring. Normally doesn't have Xray bpms since the charge is expected to be low."
    
    return
}

proc resetRFAGC {} {
    if [catch {exec cavget -list=S-DCCT:CurrentM} S35DCCT] {
        setStatus "resetRFAGC: Problem reading S-DCCT:CurrentM"
        return 0
    }
    if {[expr abs($S35DCCT) > 0.001]} {
        APSSetVarAndUpdate bunchTrainStatus "Skipping reseting of RF AGC. Got stored beam already."
        return 0
    }        
    if [catch {exec cavput -list=SRF:AGC:FB_SoftEngage -list=1,2 -list=BO=1 \
                 -pend=10 \
             } result] {
        APSSetVarAndUpdate status "resetRFAGC: Problem setting AGC on RF systems: $results"
    }
    return
}

proc ReadSingleBunch {args} {
    if [catch {exec cavget -list=BNCHI:BunchCurrentAI.VAL} results] {
        APSSetVarAndUpdate status "Inject: $result"
        return -code error "ReadSingleBunch $result"
    }
    APSSetVarAndUpdate singleBunch $results
}

proc Inject {args} {
    global singleBunch loBunches hiBunches
    set current 10
    set mode ""
    APSParseArguments {mode current}
    set gap 200
    switch $mode {
        loCharge {
            set number $hiBunches
            set interval [expr int((1296.0 - $gap)/ $number)]
        }
        hiCharge {
            set number $loBunches
            set interval [expr int((1296.0 - $gap)/ $number)]
        }
        default {
            APSSetVarAndUpdate status "Invalid mode value"
            return
        }
    }
    set options "-start 0 -interval $interval -number $number -multiplet 1 -stopAt $current -cycles 100"
    #dump beam and reset
    APSSetVarAndUpdate status "Dumping..."
    set useRFPhase 0
    if $useRFPhase {
        if [catch {exec cavput -delta=factor=-1 \
                     -list=S1=90,S4=90,S2=-90,S3=-90 \
                     -list=:K:phaseShifter1Ch0 
            after 500 \
                     exec cavput -delta=factor=1 \
                     -list=S1=90,S4=90,S2=-90,S3=-90 \
                     -list=:K:phaseShifter1Ch0
        } results] {
            APSSetVarAndUpdate status "Inject: Problem with setting klystron phase shifters: $results"
            APSSetVarAndUpdate presentPattern unknown
            return -code error "Inject: Problem with klystron phase shifters: $results"
        }
    } else {
        if [catch {exec cavput -list=S:MPS:dumpBeamSQ=1 -pend=10 \
                 } results] {
            APSSetVarAndUpdate status "Inject: Problem with setting S:MPS:dumpBeamSQ: $results"
            APSSetVarAndUpdate presentPattern unknown
            return -code error "Inject: Problem with setting S:MPS:dumpBeamSQ: $results"
        }
    }
    after 1000
    #set SRF:AGC:FB_SoftEngage2BO to 1
    if [catch {exec cavput -list=SRF:AGC:FB_SoftEngage -list=1,2 -list=BO=1 -pend=30} result] {
        APSSetVarAndUpdate status "Inject: Problem with setting SRF:AGC:FB_SoftEngage1,2BO: $results"
        APSSetVarAndUpdate presentPattern unknown
        return -code error "Inject: Problem with setting  SRF:AGC:FB_SoftEngage1,2BO: $results"
    }
    if [catch {exec resetMPS\
             } results] {
        APSSetVarAndUpdate status "Inject: $results"
        APSSetVarAndUpdate presentPattern unknown
        return -code error
    }
    after 1000
    APSSetVarAndUpdate status "Reseting RF ACG..."
    if [catch {resetRFAGC \
             } results] {
        APSSetVarAndUpdate status "Inject: $results"
        APSSetVarAndUpdate presentPattern unknown
        return -code error
    }
    after 1000
    if [catch {exec cavput -list=Mt:P0:resync_counters_bo=1} result] {
        return 0
    }
    APSSetVarAndUpdate status "Injecting..."
    if [catch {eval DoIOCBunchTrainInjection $options} results] {
        APSSetVarAndUpdate status "Inject: $result"
        APSSetVarAndUpdate presentPattern unknown
        return -code error "Inject: $result"
    }
    APSSetVarAndUpdate status "Injection done."
    set presentPattern $mode
    APSSetVarAndUpdate presentPattern $mode
    if [catch {ReadSingleBunch} results] {
        return -code error "Inject:  $result"
    }
    if [catch {exec cavget -list=BNCHI:BunchCurrentAI.VAL} results] {
        APSSetVarAndUpdate status "Inject: $result"
        return -code error "Inject:  $result"
    }
    APSSetVarAndUpdate singleBunch $results
    if [catch {exec cavput -list=S25,S27 -list=BpmLoadDefPatternsBO.VAL=1} results] {
        APSSetVarAndUpdate status "Inject: $result"
        return -code error
    }
    # start orbit correction
    StartControllaw -type default
    if [catch {exec cavput -list=S25,S27 -list=BpmLoadDefPatternsBO.VAL=1} results] {
        APSSetVarAndUpdate status "Inject: $result"
        return -code error
    }
    return
}

proc TransferOrbit {args} {
    set statusDir /home/helios/oagData/sr/BPMStatus

    APSSetVarAndUpdate status "Transfering rf bpms..."
    if [catch {APSSRTransferBPMAdjustedValues -saveSnapshot 0 \
                 -msType msAve -plane both} result] {
        return -code error "TransferOrbit: $result"
    }

    set BMBPMList [exec sddsprocess $statusDir/config.sdds -pipe=out \
                     -match=col,DeviceName=*BM:P? -noWarning \
                     -filter=col,NonexistentV,0,0 \
                     | sdds2stream -pipe -col=DeviceName] 

    if [llength $BMBPMList] {
        APSSetVarAndUpdate status "Transfering BM xray bpms..."
        if [catch {APSSRTransferBPMList -list $BMBPMList \
                     -msType msAve -plane y \
                 } result] {
            return -code error "TransferOrbit: $result"
        }
    }

    set IDBPMList [exec sddsprocess $statusDir/config.sdds -pipe=out \
                     -match=col,DeviceName=*ID:P? -noWarning \
                     -filter=col,NonexistentH,0,0,NonexistentV,0,0,& \
                     | sdds2stream -pipe -col=DeviceName] 
    
    if [llength $IDBPMList] {
        APSSetVarAndUpdate status "Transfering ID xray bpms..."
        if [catch {APSSRTransferBPMList -list $IDBPMList \
                     -msType msAve -plane both} result] {
            return -code error "TransferOrbit: $result"
        }
    }
    APSSetVarAndUpdate status "Transfer done."
}

proc ApplyBPMAverage {args} {
    global num2Ave
    if [catch {APSSRSetIOCAveraging -num2Ave $num2Ave \
                 -BPMList {A:P0 A:P1 A:P2 A:P3 A:P4 B:P5 B:P4 B:P3 \
                             B:P2 B:P1 B:P0 BM:P1 BM:P2 ID:P1 ID:P2} \
                 -enable 0 \
             } result] {
        return -code error "ApplyBPMAverage: $result"
    }
    APSSetVarAndUpdate status "Done."
    return
}
proc clearRCRecord {args} {
    set PV ""
    if {[APSStrictParseArguments {PV}] || ![string length $PV]} {
        return -code error "clearRCRecord: bad arguments"
    }
    if [exec cavget -list=$PV.RUN] {
        exec cavput -list=$PV.ABRT=1
        APSSetVarAndUpdate status "Waiting for $PV to clear..."
        exec cawait -waitfor=$PV.RUN,equal=0
    }
    catch {exec cavput -list=$PV.CLR=1}
}

proc StartControllaw {args} {
    global DCFBbase tabFrameWidgetListForLog
    set type default
    APSParseArguments {type}
    
    ApplyBPMAverage
    foreach plane {h v} Plane {H V} Coord {X Y} coord {x y} {
        set RCPV S:RC:OrbitControlLaw${Coord}C
        set controlTest DP${Plane}tests
        set testpv DP:${Plane}OCtestStatus
        set testcontrolpv DP:${Plane}OCtestRC

        clearRCRecord -PV $testcontrolpv
        APSSetVarAndUpdate status "Aborting $Plane runcontrols..."
        catch {exec cavput -list=$RCPV,$testcontrolpv -list=.ABRT=1}
        global ${plane}${type}
        if ![info exists ${plane}${type}] {
            return -code error "StartControllaw: problem with variable ${plane}${type}."
        }
        set dir $DCFBbase/[set ${plane}${type}]
        if ![file exists $dir] {
            return -code error "StartControllaw: problem with directory $dir."
        }
        if [string compare $type special]==0 {
            if [catch {CreateLocalBumpCorrectionConfig -IncludeBMs 1 -regenerate 0} result] {
                return -code error $result
            }
        }
        set configFile $dir/config
        set mode [exec sdds2stream $configFile -par=PVType]
        switch $plane {
            h {
                set control_parent [lindex $tabFrameWidgetListForLog 0]
                set pvtest_parent [lindex $tabFrameWidgetListForLog 2]
            }
            v {
                set control_parent [lindex $tabFrameWidgetListForLog 1]
                set pvtest_parent [lindex $tabFrameWidgetListForLog 3]
            }
        }
        # wait some time for runcontrol to time out.
        after 2000
        set steps 300000
        set RCTimeout 6
        set interval 0.5
        set time [expr ($interval+3) * $steps ]
        set testInterval [expr $interval/2]
        set pvOptions "-time=$time -interval=$testInterval -runControlPV=string=$testcontrolpv,pingTime=$RCTimeout -runControlDesc=string=runpvtest"

        APSSetVarAndUpdate status "Starting $Plane pvtests..."
        if [winfo exist ${pvtest_parent}.sr${plane}PVtest ] {
            destroy ${pvtest_parent}.sr${plane}PVtest
        }
        APSExecLog .sr${plane}PVtest -parent $pvtest_parent \
          -width 85 -height 30 \
          -unixCommand "sddspvtest $dir/tests -pvOutput=$testpv \
                   $pvOptions -pend=30 -verbose"
        after 2000
        
        APSSetVarAndUpdate status "Starting $Plane correction..."
        if {[string compare DP [lindex $mode 0]]==0} {
            StartDPControllaw -dataDir $DCFBbase -directory [set ${plane}${type}] \
              -steps $steps -type $type \
              -interval $interval -gain 0.4 -deltaLimit 4
            if {$plane=="v"} {
                return
            } else {
                continue
            }
        }
        if [winfo exist ${control_parent}.sddscontrollaw${plane} ] {
            destroy ${control_parent}.sddscontrollaw${plane}
        }
        APSExecLog .sddscontrollaw${plane} -parent $control_parent \
          -width 120 -height 30 \
          -name "SR ${plane}-orbit Correction" \
          -unixCommand "sddscontrollaw $dir/irm \
              -controlQuantityDefinitions=$dir/definitions.msAve  \
              -testValues=$dir/$controlTest \
              -actuator=ControlName \
              -steps=$steps -gain=0.4 \
              -interval=$interval  \
              -deltaLimit=value=4 -verbose \
              -runControlPV=string=$RCPV,pingTimeout=30 \
              -runControlDescription=string=${type}Correction"
    }
    APSSetVarAndUpdate status "Done."
}

proc MakeActionWidget  {widget args} {
    global sector root current loCharge hiCharge
    global sensitiveWidgets loFile hiFile

    set parent ""
    APSParseArguments {parent}

    APSFrame $widget -parent $parent \
      -contextHelp "Action buttons for measuring local impedance."
    set w $parent$widget.frame

    set widgetList [APSTabFrame .tabs -parent $w -label "" \
                      -labelList "Inject Orbit Scan Compare" \
                      -width 570 -height 190]
    set w [lindex $widgetList 0]
    $parent$widget.frame.tabs.frame.tn select 0
    update
    APSFrame .injection -parent $w 
    APSButton .injectLo -parent $w.injection.frame \
      -text "Dump and Inject Low Charge" \
      -command "Inject -mode loCharge -current $current" \
      -contextHelp "Inject the bunch pattern for low charge per bunch. The value of \"Bunch Pattern\" is updated. Standard orbit correction is started after injection."
    lappend sensitiveWidgets $w.injection.frame.injectLo.button
    APSButton .injectHi -parent $w.injection.frame \
      -text "Dump and Inject High Charge" \
      -command "Inject -mode hiCharge -current $current" \
      -contextHelp "Inject the bunch pattern for high charge per bunch. The value of \"Bunch Pattern\" is updated. Standard orbit correction is started after injection."
    lappend sensitiveWidgets $w.injection.frame.injectHi.button
    
    set w [lindex $widgetList 1]
    APSFrame .controllaw -parent $w 
    APSFrame .action -parent $w.controllaw.frame \
      -packOption "-side top"
    APSFrame .averaging -parent $w.controllaw.frame \
      -packOption "-side top"
    $w.controllaw.frame.action.frame configure -relief flat
    $w.controllaw.frame.averaging.frame configure -relief flat
    APSFrame .f1 -parent $w.controllaw.frame.action.frame
    APSFrame .f2 -parent $w.controllaw.frame.action.frame
    set w1 $w.controllaw.frame.action.frame.f1.frame
    set w2 $w.controllaw.frame.action.frame.f2.frame
    $w1 configure -relief flat
    $w2 configure -relief flat
    APSButton .runDefault -parent $w1 \
      -packOption "-side left" \
      -text "Start regular correction" \
      -command "StartControllaw -type default" \
      -contextHelp "Regular controllaw is normally started automatically. One can re-start orbit controllaw with this button."
    APSButton .gen -parent $w1 \
      -packOption "-side left" \
      -text "Generate" \
      -command "CreateLocalBumpCorrectionConfig -IncludeBMs 1 -regenerate 1" \
      -contextHelp "generate controllaw files for ID bump."
    
    APSButton .transfer -parent $w2 -packOption "-side left" \
      -text "Transfer Orbit" \
      -command "TransferOrbit" \
      -contextHelp "Transfer orbit only after orbit has converged."
    APSButton .runSpecial -parent $w2 \
      -text "Start local correction" \
      -command "StartControllaw -type special" \
      -contextHelp "Starts special controllaw which controls the global orbit with only the two local correctors of the straight section, transfer orbit button has to be run before running local correction for correct measurement."
    APSLabeledEntry .num2Ave -parent $w.controllaw.frame.averaging.frame \
      -packOption "-side top" \
      -label "BPM ioc averaging" \
      -textVariable  num2Ave \
      -contextHelp "IOC averaging to be used for BPM orbit readback."
    APSButton .applyAve -parent $w.controllaw.frame.averaging.frame \
      -packOption "-side top -anchor w" \
      -text "Apply Averaging" \
      -command "ApplyBPMAverage" \
      -contextHelp "Applies bpm averaging."
    
    set w [lindex $widgetList 2]
    APSFrame .parallel -parent $w 
    APSFrame .angle -parent $w 
    APSButton .runx -parent $w.parallel.frame \
      -text "Scan H local bump" \
      -command {runScan -sector $sector -plane h -bump parallel -root $root} \
      -contextHelp "Run the scan of local correctors for h bump."
    lappend sensitiveWidgets $w.parallel.frame.runx.button
    APSButton .runy -parent $w.parallel.frame \
      -packOption "-side top" \
      -text "Scan V local bump" \
      -command {runScan -sector $sector -plane v -bump parallel -root $root} \
      -contextHelp "Run the scan of local correctors for vh bump."
    lappend sensitiveWidgets $w.parallel.frame.runy.button
    APSButton .runxa -parent $w.angle.frame \
      -packOption "-side left" \
      -text "Scan H local angle bump" \
      -command {runScan -sector $sector -plane h -bump angle -root $root} \
      -contextHelp "Run the scan of local correctors for h angle bump."
    lappend sensitiveWidgets $w.angle.frame.runxa.button
    APSButton .runya -parent $w.angle.frame \
      -packOption "-side top" \
      -text "Scan V local angle bump" \
      -command {runScan -sector $sector -plane v -bump angle -root $root} \
      -contextHelp "Run the scan of local correctors for v angle bump."
    lappend sensitiveWidgets $w.angle.frame.runya.button

    set w [lindex $widgetList 3]
    APSLabeledEntry .loChargeFile -parent $w -label "Low charge file: " \
      -textVariable loFile -width 40 \
      -contextHelp "Output file scan with low charge."
    APSButton .file -parent $w.loChargeFile -packOption "-side top" \
      -text "F" -size small \
      -command {set loFile [APSFileSelectDialog .openDialog -pattern {*ID*} \
                              -listDir . \
                              -contextHelp "Select a results file for the low bunch charge experiments." \
                              -title "Select low-charge file:"]
          update idletasks}

    APSLabeledEntry .hiChargeFile -parent $w -label "High charge file: " \
      -textVariable hiFile -width 40 \
      -contextHelp "Output file scan with hi charge."
    APSButton .file -parent $w.hiChargeFile -packOption "-side top" \
      -text "F" -size small \
      -command {set hiFile [APSFileSelectDialog .openDialog -pattern {*ID*} \
                              -listDir . \
                              -contextHelp "Select a results file for the high bunch charge experiments." \
                              -title "Select high-charge file:"]
          update idletasks}

    # compare file name is based on hi charge file since
    # the lo charge file should be used as a baseline.
    APSButton .compare -parent $w \
      -packOption "-side top" \
      -text "Compare scans" \
      -command {compareScan -file1 $loFile -file2 $hiFile -output $hiFile.compare} \
      -contextHelp "Compare the results of each scan." 
}

proc compareScan {args} {
    global scriptDir
    set file1 ""
    set file2 ""
    APSParseArguments {file1 file2 output}
    if {![string length $file1] || ![string length $file2]} {
        APSSetVarAndUpdate status "compareScan: problem with one of the file names."
        return
    }
    # file1 is supposed to have the low charge, and 
    # take the role of a baseline.
    if ![file exists $file1] {
        APSSetVarAndUpdate status "compareScan: Can't find file $file1."
        return
    }
    if ![file exists $file2] {
        APSSetVarAndUpdate status "compareScan: Can't find file $file2."
        return
    }
    set filetail1 [file tail $file1]
    set filetail2 [file tail $file2]
    set plane ""
    if ![regexp {ID([0-9]+)\.([hv])} $filetail1 {} sectorFile1 plane] {
        APSSetVarAndUpdate status "compareScan: unable to determine sector or plane from filename $file1."
        return
    }
    if ![string length $plane] {
        APSSetVarAndUpdate status "compareScan: unable to determine plane from filename $file1."
        return
    }
    set Plane [string toupper $plane]
    if ![regexp {ID([0-9]+)} $filetail2 {} sectorFile2] {
        APSSetVarAndUpdate status "compareScan: unable to determine sector from filename $file1."
        return
    }
    if {![expr $sectorFile1 == $sectorFile2]} {
        APSSetVarAndUpdate status "compareScan: can't compare files from different IDs."
        return
    }
    set sector $sectorFile1
    
    if { $sector < 1 || $sector > 40} {
        return -code error "Bad sector syntax"
    }
    set sector1 [expr $sector + 1]
    if {$sector1 == 41 } {
        set sector 40 
    }
    set review 0
    if !$review {
        set tmpfile /tmp/[APSTmpString]
        exec sddsprocess $file2 -pipe=out \
          -process=BunchCurrent,average,BunchCurrent \
          | sddsconvert -pipe=in $tmpfile.1 \
          -edit=col,S*CurrentAO,ei/File2/ \
          -edit=para,BunchCurrent,ei/File2/
        # File2 has higher charge than File1, so
        # take file1 as baseline and subtract quantities from
        # it from file2.
        exec sddsxref $file1 $tmpfile.1 -pipe=out  \
          -take=*File2 -transfer=para,BunchCurrentFile2 \
          | sddsprocess -pipe \
          -process=BunchCurrent,average,BunchCurrent \
          "-def=col,%s,%s:CurrentAO,select=S${sector}B:*:CurrentAO,edit=%/:CurrentAO//,units=A" \
          "-def=col,%s,%s:CurrentAO,select=S${sector1}A:*:CurrentAO,edit=%/:CurrentAO//,units=A" \
          "-def=col,%sDiff,%sFile2 %s -,select=S${sector}B:*:CurrentAO,units=A" \
          "-def=col,%sDiff,%sFile2 %s -,select=S${sector1}A:*:CurrentAO,units=A" \
          "-def=col,%sDiff,%s sqr %sFile2 sqr + sqrt,select=SigmaS*:CurrentAO,units=A" \
          "-def=para,BunchCurrentDiff,BunchCurrentFile2 BunchCurrent -,units=mA" \
          | sddsprocess -pipe \
          -process=*Diff,maximum,%sMax \
          | sddsprocess -pipe=in $tmpfile.2 \
          "-redef=col,%s,%s %sMax -,select=S${sector}B*Diff" \
          "-redef=col,%s,%s %sMax -,select=S${sector1}A*Diff"

        # take B[HV]3 column as independent variable
        # Fit a line to the difference in H2/V2 current values,
        # using the sigmas computed for the difference.
        exec sddspfit $tmpfile.2 $tmpfile.slope.1 \
          -col=S${sector}B:${Plane}3,S${sector}B:${Plane}2:CurrentAODiff,xSigma=SigmaS${sector}B:${Plane}3:CurrentAO,ySigma=SigmaS${sector}B:${Plane}2:CurrentAODiff
        
        exec sddspfit $tmpfile.2 $tmpfile.slope.2 \
          -col=S${sector1}A:${Plane}3,S${sector1}A:${Plane}2:CurrentAODiff,xSigma=SigmaS${sector1}A:${Plane}3:CurrentAO,ySigma=SigmaS${sector1}A:${Plane}2:CurrentAODiff

        exec sddsconvert $tmpfile.slope.1 -noWarning \
          -edit=para,Slope,i/B${Plane}2/
        exec sddsconvert $tmpfile.slope.2 -noWarning \
          -edit=para,Slope,i/A${Plane}2/
        exec sddsxref $tmpfile.slope.1 $tmpfile.slope.2 -pipe=out \
          -transfer=para,A${Plane}2Slope \
          | sddsxref -pipe $tmpfile.2 \
          -leave=* -transfer=para,BunchCurrent* \
          | sddsprocess -pipe \
          "-print=para,DiffLabelString,Difference between %3.1f mA and %3.1f mA,BunchCurrent,BunchCurrentFile2" \
          "-def=col,AngleDiff,S${sector}B:${Plane}2:CurrentAODiff S${sector1}A:${Plane}2:CurrentAODiff -,units=A" \
          "-def=col,AngleSum,S${sector}B:${Plane}2:CurrentAODiff S${sector1}A:${Plane}2:CurrentAODiff +,units=A" \
          "-def=col,SigmaAngleDiff,SigmaS${sector}B:${Plane}2:CurrentAODiff sqr SigmaS${sector1}A:${Plane}2:CurrentAODiff sqr + sqrt,units=A" \
          "-def=col,SigmaAngleSum,SigmaS${sector}B:${Plane}2:CurrentAODiff sqr SigmaS${sector1}A:${Plane}2:CurrentAODiff sqr + sqrt,units=A" \
          | sddsconvert -pipe=in $output \
          -edit=col,*${Plane}2:CurrentAO*,%/:CurrentAO//

        exec sddspfit $output $tmpfile.slope.3 \
          -col=S${sector}B:${Plane}3,AngleDiff,ySigma=SigmaAngleDiff
        exec sddsconvert $tmpfile.slope.3 -noWarning \
          -edit=para,Slope*,i/AngleDiff/

        exec sddspfit $output $tmpfile.slope.4 \
          -col=S${sector}B:${Plane}3,AngleSum,ySigma=SigmaAngleSum 
        exec sddsconvert $tmpfile.slope.4 -noWarning \
          -edit=para,Slope*,i/AngleSum/

        exec sddsxref $output $tmpfile.slope.3 -noWarning \
          -take=*Fit \
          -transfer=para,*Slope*
        exec sddsxref $output $tmpfile.slope.4 -noWarning \
          -take=*Fit \
          -transfer=para,*Slope*
        file delete $tmpfile.slope.3~ $tmpfile.slope.4~ $output~
    }
    # effect of current on value of ${Plane}2.
    exec sddsplot  -sep=nameindex -group=nameindex -axes=y \
      -leg=file -grap=error,conn=sub,vary=sub,sca=2,eachFile \
      -title= -file \
      -col=S${sector}B:${Plane}3,(S${sector}B:${Plane}2:CurrentAO,S${sector1}A:${Plane}2:CurrentAO),(Sigma%s,Sigma%s) \
      $file1 $file2 \
      &

    exec sddsplot \
      $output -file \
      "-ylabel=Relative corrector change (A)" \
      -col=S${sector}B:${Plane}3,S${sector}B:${Plane}2Diff,Sigma%s  \
      -grap=sym,type=0,conn=sub,sub=0,sca=3  -leg \
      -col=S${sector}B:${Plane}3,S${sector1}A:${Plane}2Diff,Sigma%s  \
      -grap=sym,type=4,conn=sub,sub=1,sca=3 -leg \
      -col=S${sector}B:${Plane}3,AngleSum,Sigma%s \
      -grap=sym,type=2,conn=sub,sub=2,sca=2.5  -leg=spec=Sum \
      -col=S${sector}B:${Plane}3,AngleSumFit \
      -grap=line,thickness=2,type=2 "-leg=spec=Sum fit" \
      -topline=@DiffLabelString \
      -end \
      -col=S${sector}B:${Plane}3,S${sector}B:${Plane}2Diff,Sigma%s  \
      -grap=sym,type=0,conn=sub,sub=0,sca=3  -leg \
      -col=S${sector}B:${Plane}3,S${sector1}A:${Plane}2Diff,Sigma%s  \
      -grap=sym,type=4,conn=sub,sub=1,sca=3 -leg \
      -col=S${sector}B:${Plane}3,AngleDiff,Sigma%s \
      -grap=sym,type=2,conn=sub,sub=2,sca=2.5  -leg=spec=Diff \
      -col=S${sector}B:${Plane}3,AngleDiffFit \
      -grap=line,thickness=2,type=2 "-leg=spec=Diff fit" \
      -topline=@DiffLabelString \
      &

    exec sddsplot \
      $output -file \
      "-ylabel=Relative corrector change (A)" \
      -col=S${sector}B:${Plane}3,S${sector}B:${Plane}2Diff,Sigma%s  \
      -grap=sym,type=0,conn=sub,sub=0,sca=3  -leg \
      -col=S${sector}B:${Plane}3,S${sector1}A:${Plane}2Diff,Sigma%s  \
      -grap=sym,type=4,conn=sub,sub=1,sca=3 -leg \
      -col=S${sector}B:${Plane}3,AngleSum,Sigma%s \
      -grap=sym,type=2,conn=sub,sub=2,sca=2.5  -leg=spec=Sum \
      -col=S${sector}B:${Plane}3,AngleSumFit \
      -grap=line,thickness=2,type=2 "-leg=spec=Sum fit" \
      -topline=@DiffLabelString \
      -device=gif -output=$output.gif \
      &

    set pi 3.141592653589793
    set BunchCurrentDiff [exec sdds2stream -para=BunchCurrentDiff $output]

    # Calculate effective KnL 
    # if distributed along drift space or
    # if located at the ID chamber tapers.
    # Assume that the slope in the corrector change is due
    # to a kick somewhere in the straight section of opposite
    # sign.
    set MeasSlope [exec sdds2stream -para=AngleSumSlope $output]
    set bumpAmplitudeCoeff [exec sdds2stream -para=Slope \
                              $scriptDir/amplitude]  
    # bumpAmplitudeCoeff is y divided by corrector1 kick.
    set deltaKL [expr -1.0 * $MeasSlope / $bumpAmplitudeCoeff]
    set beta 6
    set tuneShift [expr $deltaKL * $beta / ( 4 * $pi )  / \
                     $BunchCurrentDiff]
    APSSetVarAndUpdate status "Measured focusing strength: deltaKL = [format %10.3g $deltaKL] 1/m"
    APSSetVarAndUpdate status "Tune shift per current with beta of 6 m: [format %10.3g $tuneShift] 1/mA"
    
    # compare that to resistive wall
    # A. Chao p. 146 in cgs units
    set L 500
    set frev 271.55e3
    set e_mks 1.60217733e-19
    set c_cgs 2.99792458e+10
    set N [expr ($BunchCurrentDiff * 1e-3) / $frev / $e_mks]
    # an approximate sigmaz for all currents < 5 mA: 30 ps
    set sigmaz  [expr 30e-12 * $c_cgs]
    set r0 2.8e-13
    set gamma 1.36986e4
    set b 0.25
    set ALconductivity 3.2e17
    set Gamma1over4 3.63560
    # factor 100 to convert the cgs KL units of 1/cm to mks KL units of 1/m.
    set ResKL [expr 100 * ($N * $L * $r0) / ( 2 * $pi * $gamma * pow($b ,3) ) * \
                 sqrt( $c_cgs / ($pi * $ALconductivity * $sigmaz) ) * \
                 $Gamma1over4 ]
    APSSetVarAndUpdate status "Resistive Wall (A. Chao p.146) for b = $b cm: deltaKL = [format %10.3g $ResKL] 1/m,"
    set ResTuneShift [expr $ResKL * $beta / ( 4 * $pi )  / \
                        $BunchCurrentDiff]
    APSSetVarAndUpdate status "with calculated tune shift per current with beta of 6 m: [format %10.3g $ResTuneShift] 1/mA"
    return
}

proc runScan {args} {
    global scriptDir
    set amplitude2(v.parallel) 40
    set amplitude3(v.parallel) 40
    set amplitude2(v.angle) 78.5
    set amplitude3(v.angle) 40
    set amplitude2(h.parallel) 19.8
    set amplitude3(h.parallel) 40
    set amplitude2(h.angle) 35.8
    set amplitude3(h.angle) 40
    set bump parallel
    set pause 3
    set steps 10
    set plane v
    set average 10
    set sector ""
    set root ""
    APSParseArguments {sector bump \
                         root pause steps plane average}
    if ![string length $sector] {
        return -code error "runScan: Invalid syntax: sector not supplied."
    }
    set tmpfile  /tmp/[APSTmpString]
    set monitorFile $tmpfile.mon

    switch $plane {
        h {set Plane H}
        v {set Plane V}
    }
    set sector1 [expr $sector + 1]
    if [catch {exec replace $scriptDir/IDtemplate.mon $monitorFile \
                 -original=<n>,<n1>,<Plane> \
                 -replace=$sector,$sector1,$Plane \
             } result] {
        APSSetVarAndUpdate status $result
        return -code error "runScan: $result"
    }
    if {$sector==11} {
        #remove ID 11 P0s since they no longer exist
        set tmpfile /tmp/[APSTmpString]
        exec sddsprocess $monitorFile $tmpfile "-match=col,ControlName=S11B:P0*,!,ControlName=S12A:P0*,!,&"
        exec mv $tmpfile $monitorFile
    }
    set generation 0
    set outputDir [APSGoToDailyDirectory]IDimpedance
    set output ""
    while 1 {
        set lastFile $output
        set output [format ${root}ID$sector.$plane.%02ld $generation]
        if ![file exists $outputDir/$output] {
            break
        }
        incr generation
    }
    set output $outputDir/$output
    set expFile $tmpfile.exp
    set template $scriptDir/ID.exp
    switch $bump {
        parallel {
            set coefFile $scriptDir/${Plane}bump.coef
        }
        angle {
            set coefFile $scriptDir/${Plane}angle.coef
        }
        default {
            APSSetVarAndUpdate status "runScan: Unkown bump type"
            return -code error "runScan: Unkown bump type"
        }
    }
    if {0} {
        if [catch {exec replace $template $expFile \
                     -original=<measFile>,<average>,<steps>,<sector>,<coefFile>,<pause>,<pre_script>,<post_script> \
                     -replace=$monitorFile,$average,$steps,$sector,$coefFile,$pause,\"runProc RampCorrectors -sector $sector -coefFile $coefFile -plane $plane -rampToCoef 1\",\"runProc RampCorrectors -sector $sector -coefFile $coefFile -plane $plane\" \
                 } result] {
            APSSetVarAndUpdate status $result
            return -code error $result
        }
    }
    # check whether orbit correction is running
    # Todo: also make sure the right one is running too!

    set answer [tk_dialog .dialog "Warning" "Make sure that these three steps were followed:\n\nRun regular orbit controllaw\n\nTransfer the orbit\n\nStop regular orbit correction\n\nStart the appropriate orbit controllaw for the ID straight selected." warning -1 Abort Continue]
    case $answer {
        0 {
            # abort = do nothing 
            return
        }
        1 {
            # continue
        }
    }
    if {0} {
        if [catch {exec cavget -list=S:RC:OrbitControlLawXC,S:RC:OrbitControlLawYC,S:rfFreqControlLawRC -list=.RUN} controllawStatus] {
            APSSetVarAndUpdate status "Problem getting orbit controllaw status: $controllawMode"
            return
        }
        if [lsearch $controllawStatus 0]!=-1 {
            APSSetVarAndUpdate status "One of the orbit controllaw or rf frequency controllaw is not running! Please start them all."
            return
        }
    }
    DisableButtons
    if [catch {exec cavput -list=S${sector}B:${Plane}3,S${sector}B:${Plane}2,S${sector1}A:${Plane}2,S${sector1}A:${Plane}3 \
                 "-list=:DacAI.SCAN=.5 second" \
             } result] {
        APSSetVarAndUpdate status $result
        return -code error
    }
    #ramp correctors to coef before experiment

    APSSetVarAndUpdate status "Ramping correctors before experiment ..."
    if [catch {RampCorrectors -sector $sector -coefFile $coefFile -plane $plane -rampToCoef 1} result] {
        return -code error $result
    }
    set comd "-macro=measFile=$monitorFile,average=$average,steps=$steps,sector=$sector,coefFile=$coefFile,pause=$pause,plane=$plane,scriptDir=$scriptDir"

    APSSetVarAndUpdate status "Ramp done."
    APSExecLog [APSUniqueName .] -name "ID bump scan" -width 100 \
      -unixCommand "sddsexperiment $template $output -verbose $comd \"-comment=testing new features and ID impedance measurement\"" \
      -callback "RestoreButtons -sector $sector -coefFile $coefFile -plane $plane" \
      -abortCallback "RestoreButtons -sector $sector -coefFile $coefFile -plane $plane" \
      -cancelCallback "RestoreButtons -sector $sector -coefFile $coefFile -plane $plane"
}

proc DisableButtons {} {
    global sensitiveWidgets
    foreach widget $sensitiveWidgets {
        APSDisableButton $widget
    }
}
proc RestoreButtons {args} {
    global sensitiveWidgets
    set sector ""
    set coefFile ""
    set plane ""
    APSParseArguments {sector coefFile plane}
    foreach widget $sensitiveWidgets {
        APSEnableButton $widget
    }
    #ramp correctors to zero after experiment
    APSSetVarAndUpdate status "Ramping correctors after experiment ..."
    if [catch {RampCorrectors -sector $sector -coefFile $coefFile -plane $plane} result] {
        return -code error $result
    }
    APSSetVarAndUpdate status "Ramp done."
}

proc CreateLocalBumpCorrectionConfig {args} {
    global sector DCFBbase
    set regenerate 0
    set IncludeBMs 0
    set singularValues 320
    set removeVectors 0
    APSParseArguments {regenerate IncludeBMs singularValues removeVectors}
                         
    global hspecial vspecial
    set hspecial h.ID${sector}Bump
    set vspecial v.ID${sector}Bump
    if {!$regenerate} {
        foreach file {config irm definitions.msAve tests corrWaveform waveformTest bpmWaveform} {
            if {![file exist $DCFBbase/$hspecial/$file] \
                  || ![file exist $DCFBbase/$vspecial/$file]} {
                set regenerate 1
                break
            }
        }
    }
    if !$regenerate {
        return
    }
    
    set BPMList [list A:P1 A:P2 A:P3 A:P4 B:P5 B:P4 B:P3 B:P2 B:P1]
    setStatus "Generating controllaw files for ID $sector bump..."
    set sector1 [expr $sector +1]
    set hcorrList [list S${sector}B:H2 S${sector1}A:H2]
    set vcorrList [list S${sector}B:V2 S${sector1}A:V2]
    set MissingPVList [list S${sector}B:P4 S${sector}B:P3 S${sector}B:P2 S${sector}B:P1 \
                         S${sector1}A:P1 S${sector1}A:P2 S${sector1}A:P3 S${sector1}A:P4]
    foreach dir [list $hspecial $vspecial] plane {h v} {
        set dir $DCFBbase/$dir
        if ![file exist $dir] {
            exec mkdir -p $dir
        }
        set configfile $dir/config
        if [catch {sdds open ${configfile} w} fid] {
            return -code error "APSWriteSRConfig: Unable to open file $configfile: $fid"
        }
        if [catch {sdds defineColumn $fid Name -type SDDS_STRING
            sdds defineColumn $fid Flag -type SDDS_SHORT 
            sdds defineColumn $fid Weight -type SDDS_DOUBLE
            sdds defineColumn $fid Despike -type SDDS_LONG
            sdds defineParameter $fid Description -type SDDS_STRING
            sdds defineParameter $fid NameType -type SDDS_STRING
            sdds defineParameter $fid PVType -type SDDS_STRING
            sdds writeLayout $fid} result] {
            catch {sdds close $fid}
            return -code error "CreateLocalBumpCorrectionConfig: problem defining SDDS elements: $result"
        }
        set BPMMissingList [APSGetMissingBPMList -plane $plane]
        set BPMBadList [APSSRGetBadOrbitDevices -application FastDCOrbitCorrection -device BPM  -plane $plane]
        set BPMMissingList [concat $BPMMissingList $MissingPVList $BPMBadList] 
        
        if {[string compare $plane v]==0 && $IncludeBMs} {
            set BPMList  {BM:P1 BM:P2}
        }
        set bpmList ""
        set flags ""
        set weights ""
        set despikeFlags ""
        set monitorNameMatchOption ""
        set BMBPMList ""
        for {set index 1} {$index < 40} {incr index} {
            foreach suffix $BPMList {
                set name S${index}${suffix}
                if [lsearch -exact $BPMMissingList $name]==-1 {
                    lappend bpmList $name
                    lappend flags 1
                    lappend weights 1.0
                    lappend despikeFlags 1
                    if {$IncludeBMs && [string match *BM* $name] } {
                        lappend BMBPMList $name
                    }
                    if [string length $monitorNameMatchOption] {
                        append monitorNameMatchOption ",BPMName=$name,|"
                    } else {
                        set monitorNameMatchOption "-match=column,BPMName=$name"
                    }
                }
            }
        }
        #write bpm into config file
        if [catch {sdds startPage $fid [expr 360*20] 
            sdds setParameter $fid Description "vector mode of ${plane}.ID${sector}Bump"
            sdds setParameter $fid PVType DP
            sdds setParameter $fid NameType MonitorNames} result] {
            catch {sdds close $fid}
            return -code error "CreateLocalBumpCorrectionConfig: SDDS problem: $result"
        }
        
        if [catch {eval sdds setColumn $fid Name $bpmList
            eval sdds setColumn $fid Flag $flags 
            eval sdds setColumn $fid Weight $weights
            eval sdds setColumn $fid Despike $despikeFlags
            sdds writePage $fid} result] {
            catch {sdds close $fid}
            return -code error "CreateLocalBumpCorrectionConfig: SDDS problem: $result"
        }
        #write correctors into config
        set flags ""
        set weights ""
        set despikeFlags ""
        foreach corr [set ${plane}corrList] {
            lappend flags 1
            lappend weights 1.0
            lappend despikeFlags 1
        }
        if [catch {sdds startPage $fid [expr 360*20] 
            sdds setParameter $fid Description "vector mode of ${plane}.ID${sector}Bump"
            sdds setParameter $fid PVType DP 
            sdds setParameter $fid NameType CorrectorNames} result] {
            catch {sdds close $fid}
            return -code error "CreateLocalBumpCorrectionConfig: SDDS problem: $result"
        }
        
        if [catch {eval sdds setColumn $fid Name [set ${plane}corrList]
            eval sdds setColumn $fid Flag $flags 
            eval sdds setColumn $fid Weight $weights
            eval sdds setColumn $fid Despike $despikeFlags
            sdds writePage $fid} result] {
            catch {sdds close $fid}
            return -code error "CreateLocalBumpCorrectionConfig: SDDS problem: $result"
        }
        #generate response matrix file
        set corrList [set ${plane}corrList]
        set referenceMatrix ${DCFBbase}/refMatrices/${plane}.default
        set origRefMatrix $referenceMatrix
        if {$IncludeBMs && [string compare $plane v]==0} {
            set tmpMatrix /tmp/[APSTmpString]
            set equationCmd ""
            set BMBPMsKnownList [APSGetBMXRayBPMList -plane $plane]
            set BMBPMEqnList    [APSGetBMXRayEqnList -plane $plane]
            if ![string length $equationCmd] {
                lappend equationCmd sddsprocess -pipe
            }
            foreach item $BMBPMList {
                set index [lsearch -exact $BMBPMsKnownList $item]
                if $index==-1 {
                    return -code error "CreateLocalBumpCorrectionConfig: no information on $item"
                }
                set equation [lindex $BMBPMEqnList $index]
                if ![string length $equation] {
                    return -code error "CreateLocalBumpCorrectionConfig: no equation defined for $item."
                }
                lappend equationCmd "-define=column,$item,$equation"
            }
            if [catch {eval exec sddstranspose $referenceMatrix -pipe=out  \
                         | $equationCmd \
                         | sddstranspose -pipe=in $tmpMatrix \
                         -newColumnNames=OldColumnNames -oldColumnNames=BPMName} result] {
                return -code error "CreateLocalBumpCorrectionConfig: $result"
            }
            set referenceMatrix $tmpMatrix
        }
        if $removeVectors {
            set inverseOptions "-largestSingularValues=$singularValues -removeDCVectors"
        } else {
            set inverseOptions "-largestSingularValues=$singularValues"
        }
        if [catch {eval exec sddsconvert $referenceMatrix -pipe=out \
                     -retain=column,BPMName,[join $corrList ,]   \
                     | sddsprocess -pipe $monitorNameMatchOption \
                     | sddspseudoinverse -pipe $inverseOptions \
                     | sddsconvert -pipe -rename=column,OldColumnNames=ControlName \
                     | sddsprocess -pipe=in $dir/irm \
                     -print=parameter,ConfigurationFile,$configfile \
                     -print=parameter,ReferenceMatrix,$origRefMatrix} result] {
            return -code error "CreateLocalBumpCorrectionConfig: Error possibly caused by non-existent inverse. Check your configuration.\nProcessing command returns:\n$result"
        }
        if [catch {exec sdds2stream -param=ConditionNumber $dir/irm} condNumber] {
            return -code error "CreateLocalBumpCorrectionConfig: error getting condition number"
        }
        setStatus "Generating $plane irm done.  Condition number is $condNumber."
        #create other controllaw files by APSGenerateControllawFiles 
        set directory [set ${plane}special]
        if [catch {APSGenerateControllawFiles -dataDir $DCFBbase -directory $directory \
                     -corrLimit 148 -regenerateFiles $regenerate} result] {
            return -code error "CreateLocalBumpCorrectionConfig: $result"
        }

        #keep only the currentCC and InjectingStatus and AVSin tests file
        set tmpfile /tmp/[APSTmpString]
        if [catch {exec sddsprocess $dir/tests \
                     "-match=col,ControlName=*currentCC,ControlName=*Injecting*,|,ControlName=*AVS,|" \
                     $tmpfile} result] {
            return -code error "CreateLocalBumpCorrectionConfig: $result"
        }
        exec mv $tmpfile $dir/tests
    }
    setStatus "Done."
}

proc StartDPControllaw {args} {
    set dataDir ""
    set directory ""
    set interval 0.0
    set gain 0.4
    set deltaLimit 4
    set FFcompensation 0
    set type ""
    APSParseArguments {dataDir directory plane interval gain deltaLimit FFcompensation type}

    if [regexp {h\.} $directory] {
        set plane h
        set coord x
        set Coord X
    } elseif [regexp {v\.} $directory] {
        set plane v
        set coord y
        set Coord Y
    } else {
        return -code error "Wrong directory given!"
    }
    #abort workstation controllaw and dp controllaw if they are running
    if [exec cavget -list=S:RC:OrbitControlLaw${Coord}C.RUN -pend=30] {
        setStatus "Abort S:RC:OrbitControlLaw${Coord}C"
        if [catch {exec cavput -list=S:RC:OrbitControlLaw${Coord}C.ABRT=1 -pend=30} result] {
            return -code error $result
        }
        after 2000
    }
    setStatus "Abort DP:S:OrbitControlLaw${Coord}SDDS"
    if [catch {APSAbortSRControllaw -runControlPV DP:S:OrbitControlLaw${Coord}SDDS} result] {
        return -code error $result
    }
    after 2000
    setStatus "Initializing vectors ..."
    set orbitType $type
    if [catch {InitializeVectors -coord $coord -plane $plane -type $orbitType} result] {
        return -code error $result
    }
    setStatus "set controllaw options ..."
    if [catch {PrepareControllawOptions -dataDir $dataDir -directory $directory -infinite \
                 -interval 0.1 -gain $gain -deltaLimit $deltaLimit} result] {
        return -code error $result
    }
    setStatus "Start DP:S:OrbitControlLaw${Coord}SDDS"
    if [catch {exec cavput -list=DP:S:OrbitControlLaw${Coord}SDDS.CMND=1 -pend=30} result] {
        return -code error "Can not start dp orbit correction: $result"
    }
}

proc InitializeVectors {args} {
    set coord ""
    set plane ""
    set type ""
    set setpointReferenceFile /home/helios/oagData/SCR/snapshots/SR/SR-UserBeamPreferred.gz
    set offsetReferenceFile /home/helios/oagData/SCR/snapshots/SR/SR-BPMOffsetReference.gz
    
    APSParseArguments {coord plane type}
    set Plane [string toupper $plane]
    if [catch {APSSetCorrMode -corrMode scalar -plane $Plane } result] {
        return -code error $result
    }
    if [catch {APSInitializeCorrVector -plane $Plane} result] {
        return -code error "InitializeCorrVector: $result"
    }
    if [catch {APSSetCorrMode -corrMode vector -sourceMode Operation \
                 -plane $plane \
             } result] {
        return -code error "$result"
    }
    if {$type=="special"} {
        APSAlertBox .warning -type warning -errorMessage "Be sure to run transfer orbit first before running local correction" 
        return
    }
    set tmpRoot /tmp/[APSTmpString]
    APSAddToTmpFileList -ID IDmeausreLocalImpedance \
      -fileList "$tmpRoot.ref1 $tmpRoot.ref2 $tmpRoot.snap.$coord"
    if [catch {exec sddsprocess $offsetReferenceFile $tmpRoot.ref1 \
                 -match=col,ControlName=*${coord}*OffsetAO
        exec sddsprocess $setpointReferenceFile $tmpRoot.ref2 \
                 -match=col,ControlName=*SetpointAO,ControlName=*FTSetpointAO,!,&,ControlName=*${coord}*,&
        exec sddscombine $tmpRoot.ref1 $tmpRoot.ref2 \
                 -merge $tmpRoot.snap.$coord -overwrite \
             } result] {
        APSDeleteTmpFileList -ID RestoreDPOffsets
        return -code error "InitializeVectors: $result"
    }
    if [catch {APSTransferVectorAdjust -coord $coord} result] {
        return -code error "InitializeVectors: $result"
    }
    if [catch {exec sddscasr -restore $tmpRoot.snap.$coord } result] {
        return -code error "InitializeVectors: Error in restoring offset and setpoints, $result"
    }
    if [catch {APSTransferVectorGain -coord $coord} result] {
        return -code error "InitializeVectors: $result"
    }
}

proc PrepareControllawOptions {args} {
    set dataDir ""
    set directory ""
    set interval 0.1
    set gain 0.4
    set deltaLimit 4
    set FFcompensation 0
    set averages 1
    APSParseArguments {dataDir directory plane interval gain deltaLimit FFcompensation}
    
    if [regexp {h\.} $directory] {
        set plane h
        set coord x
        set Coord X
        set controlTest DPHtests
    } elseif [regexp {v\.} $directory] {
        set plane v
        set coord y
        set Coord Y
        set controlTest DPVtests
    }
    set dir $dataDir/$directory
    set options "$dir/irm"
    if {![file exist $dir/bpmWaveform] || ![file exist $dir/corrWaveform] || \
          ![file exist $dir/waveformTest] } {
        return -code error "PrepareControllawOptions: Waveform files do not exist, press generate inexpert SROrbitControllaw!"
    }
    append options " -waveform=$dir/corrWaveform,actuator -proportional"
    if  $FFcompensation {
        if {![file exist ffWaveform] } {
            return -code error "PrepareControllawOptions: File ffWaveform does not exist, use Generate to generate it first"
        }
        append options " -waveforms=$dir/ffWaveform,ffSetpoint"
        append options " -auxiliaryOutput=gain=1.0,matrix=$dir/rmFF,controlquantitydefinition=$dir/FFdefs,mode=proportional"
    }
    append options " -waveforms=$dir/bpmWaveform,readback"
    if [catch {exec cavput -list=DP:S:OrbitControlLaw${Coord}SDDS.INTR=$interval -pend=30} result] {
        return -code error "PrepareControllawOptions: $result"
    }
    if [catch {exec cavput -list=DP:S:OrbitControlLaw${Coord}SDDS.AVER=$averages -pend=30} result] {
        return -code error "PrepareControllawOptions: $result"
    }
    if [catch {exec cavput -list=DP:S:OrbitControlLaw${Coord}SDDS.GAIN=$gain -pend=30} result] {
        return -code error "PrepareControllawOptions: $result"
    }
    append options " -waveforms=$dir/waveformTest,test"
    append options " -infinite -gain=PVname=DP:S:OrbitControlLaw${Coord}SDDS.GAIN"
    append options " -interval=PVname=DP:S:OrbitControlLaw${Coord}SDDS.INTR"
    append options " -average=PVname=DP:S:OrbitControlLaw${Coord}SDDS.AVER"
    append options " -launcherpv=DP:S:OrbitControlLaw${Coord}SDDS"
    if {$deltaLimit > 0 } {
        append options " -deltaLimit=value=$deltaLimit"
    } else {
        setStatus "Warning: negative deltaLimit ignored." 
    }
    append options " -testValues=$dir/$controlTest -actuator=ControlName -controlQuantityDefinitions=$dir/definitions.msAve"
    if [catch {APScaputTextToWaveform -pvName DP:S:OrbitControlLaw${Coord}SDDS.OPTN \
                 -text $options} result] {
        return -code error ""PrepareControllawOptions: $result"
    }
}

proc RampCorrectors {args} {
    # global scriptDir
    set sector ""
    set steps 10
    set pause 1
    set coefFile ""
    set rampToCoef 0
    APSParseArguments {sector coefFile plane rampToCoef}
    
    #set ceofFile $scriptDir/$coefFile
    
    set wfDir /home/helios/oagData/sr/orbitControllaw/waveforms
    switch $plane {
        h {
            set vectorFile $wfDir/hcorrInfo.sdds
        }
        v {
            set vectorFile $wfDir/vcorrInfo.sdds
        }
    }
    set tmpRoot /tmp/[APSTmpString]
    set sector1 [expr $sector + 1]
    APSAddToTmpFileList -ID 1 -fileList "$tmpRoot.coef"
    if [catch {exec replace $coefFile $tmpRoot.coef \
                 -orig=<sector>,<sector1> -replace=$sector,$sector1 } result] {
        return -code error $result
    }
    if [catch {sdds load $tmpRoot.coef coefData} result] {
        return -code error $result
    }
    set origValues ""
    if [catch {exec sddsconvert $vectorFile -rename=par,FeedforwardWaveformPV=WaveformPV $tmpRoot} result] {
        return -code error $result
    }
    if [catch {exec sddswget $tmpRoot $tmpRoot.orig} result] {
        return -code error $result
    }
    APSAddToTmpFileList -ID IDmeasureLocalImpedance -fileList "$tmpRoot.orig $tmpRoot.set"
    set corrList [exec sdds2stream $tmpRoot.orig -col=DeviceName]
    set valueList [exec sdds2stream $tmpRoot.orig -col=Waveform]
    set setcorrList [lindex $coefData(Column.Corrector) 0]
    set coefValueList [lindex $coefData(Column.Coefficient) 0]
    set rampToValue ""
    if !$rampToCoef {
        foreach corr setcorrList {
            lappend rampToValue 0
        }
    } else {
        foreach val $coefValueList  {
            lappend rampToValue [expr 0.0 - $val]
        }
    }
    foreach corr $setcorrList {
        set i [lsearch $corrList $corr]
        if {$i<0} {
            return -code error "$corr not found in $vectorFile"
        }
        lappend origValues [lindex $valueList $i]
    }
    set tmpData(ColumnNames) "DeviceName Waveform"
    set tmpData(ColumnInfo.DeviceName) "type SDDS_STRING"
    set tmpData(ColumnInfo.Waveform) "type SDDS_DOUBLE"
    set tmpData(Column.DeviceName) [list $setcorrList]
    for {set i 1} {$i<=$steps} {incr i} {
        set setvalueList ""
        set tmpData(Column.Waveform) ""
        foreach value $origValues val2 $rampToValue {
            set val [expr $value + ($val2-$value) *($i*1.0)/($steps*1.0) ]
            lappend setvalueList $val
        }
        set tmpData(Column.Waveform) [list $setvalueList]
        if [catch {sdds save $tmpRoot.wave tmpData} result] {
            return -code error $result
        }
        APSAddToTmpFileList -ID 1 -fileList "$tmpRoot $tmpRoot.orig $tmpRoot.set $tmpRoot.new"
        APSAddToTmpFileList -ID 1 -fileList "$tmpRoot.other $tmpRoot.wave"
        if [catch {exec sddsxref $tmpRoot $tmpRoot.wave -match=DeviceName \
                     -take=Waveform $tmpRoot.new -nowarnings
            exec sddsselect $tmpRoot.orig $tmpRoot.wave $tmpRoot.other -invert -match=DeviceName 
            exec sddscombine $tmpRoot.new $tmpRoot.other -merge -pipe=out | \
                     sddssort -pipe=in -col=Index $tmpRoot.set
            exec sddswput $tmpRoot.set } result] {
            return -code error $result
        }
        after [expr $pause * 1000]
    }
}

set sector 3
set root "scan"
set current 20
set presentPattern "unknown"
set num2Ave 1
set loBunches 4
set hiBunches 20

set scriptDir /home/helios/oagData/sr/IDimpedance/scripts
set DCFBbase /home/helios/oagData/sr/orbitControllaw/lattices/default
set hdefault h.default
set vdefault v.default
set hdefault h.2002-1119.00
set vdefault v.2002-1119.00
set hspecial h.2000-1212.00
set vspecial v.2000-1212.00
# ID4
set sector 4
set hspecial h.2002-0304.00
set vspecial v.2002-0304.00
#ID4 bump
set hspecial h.ID${sector}Bump
set vspecial v.ID${sector}Bump

MakeOptionWidget .options -parent .userFrame
MakeActionWidget .actions -parent .userFrame

APSFrame .execLog -parent ""
.execLog.frame configure -relief flat -bd 0
set sectionList [list controllaw_x controllaw_y pvtest_x pvtest_y]
set tabFrameWidgetListForLog [APSTabFrame .log -parent .execLog.frame \
                                -label "" \
                                -labelList $sectionList \
                                -width 955 -height 500 \
                                -packOption "-expand true"]

set status Ready.
