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

set auto_path [linsert $auto_path 0  /usr/local/oag/apps/lib/$env(HOST_ARCH)]
set auto_path [linsert $auto_path 0 /usr/local/oag/lib_patch/$env(HOST_ARCH)]

APSStandardSetup
set CVSRevisionAuthor "\$Revision: 1.11 $ \$Author: sajaev $"

APSApplication . -name "SRInjectionTools" -version $CVSRevisionAuthor \
  -overview "This is a collection of useful tools to study injection."

#---------------------------------------------------------------------------------------

proc MakeActionWidget1 {widget args} {
    set parent ""
    APSParseArguments {parent}
    
    APSFrame $widget -parent $parent -label "Closed bump optimization" \
	-contextHelp "Control widgets"
    set w $parent$widget.frame
    
    APSLabeledEntry .ik1 -parent $w \
	-label "IK1 fixed setpoint:" -textVariable IK1Closed \
	-contextHelp "Enter a setpoint for IK1. IK1 is the reference amplitude for the other kickers to match to."
    APSLabeledEntry .ik34 -parent $w \
	-label "IK3-4 setpoints (optional):" -textVariable IK34Closed \
	-contextHelp "Enter setpoints for IK3-4 (space separated). If non-empty, they will be used as starting points for optimziation if X plane is chosen."
    APSLabeledEntry .aver -parent $w \
	-label "Number of averagings:" -textVariable averageClosed \
	-contextHelp "Number of waveforms to average for each measurement during optimization."
    APSLabeledEntry .saveFile -parent $w \
	-label "Save snap file:" -textVariable saveFileClosed \
	-contextHelp "Enter a snapshot file name for the pulsed power supply setpoints to be written in the directory above"
    APSRadioButtonFrame .plane -parent $w -label "Plane: " -valueList {X Y XY} \
	-buttonList {X Y "Y using Skew Quads"} -variable planeClosed -orientation horizontal \
	-commandList {{} {} {}} \
	-contextHelp "If X, IK3-IK4 kickers will be used as variables.\nIf Y, S39B:P5, S39B:P1, S40A:P1, and S40B:P5 setpoints will be used as variables. In this case, user needs to start orbit correction in appropriate configuration. Recommended configuration: A:P1, B:P5, and B:P1 plus A:V2, B:V4, and B:V2 in sector 39 and 40. The rest of configuration is default." 
    
    APSButton .minimize  -parent $w -text "Optimize closed bump" \
	-command {
       set cavputString -list=S:IK1:VoltageSetSendAO=$IK1Closed
       #--- Turn off septum feedforward because septum discharge will be disabled:
       set rtfbString [exec cavget -cavput -list=SRFB:GBL:Hor:CloseLoopBO,SRFB:GBL:Vert:CloseLoopBO -pend=10]
       exec cavput -list=SRFB:GBL:Hor:CloseLoopBO=0,SRFB:GBL:Vert:CloseLoopBO=0 -pend=10
       if {[string compare $planeClosed X] != -1} {
           if [string length $IK34Closed] {
               append cavputString ",S:IK3:VoltageSetSendAO=[lindex $IK34Closed 0]"
               append cavputString ",S:IK4:VoltageSetSendAO=[lindex $IK34Closed 1]"
           }
       }
       if [catch {eval exec cavput $cavputString -pend=5} result] {
           set status "Error setting IK3-IK4: $result"
       } else {
           runOptimize -logDir $logDir -average $averageClosed -mode closedBump$planeClosed -method 1
       }
       #--- Restore rtfb state:
       eval exec cavput -list=$rtfbString -pend=10
   } -contextHelp "Starts sddsoptimize for a closed kicker bump. You need to have single bunch already injected. The optimization is slow, so good initial conditions are helpful."
    APSButton .plotProg  -parent $w -text "Plot Progress" \
	-command {plotProgress -logDir $logDir -mode closedBump$planeClosed} \
	-contextHelp "Plots the knob values and emittance."
    APSButton .equal  -parent $w -text "Equalize Kickers" \
	-command EqualizeIK23 \
	-contextHelp "Equalize the kickers after one minimization run."
    APSButton .save  -parent $w -text "Save Pulsed PS" \
	-command {SavePulsed -logDir $logDir -saveFile $saveFileClosed} \
	-contextHelp "Saves pulsed magnets setpoints to file above."

    APSFrame .frame1 -parent $parent -label "IK1 kicker scan"
    set w $parent.frame1.frame
    APSLabeledEntry .ik10 -parent $w \
	-label "IK1 start:" -textVariable ik1StartClosed \
	-contextHelp "Starting IK1 setpoint for scan."
    APSLabeledEntry .ik11 -parent $w \
	-label "IK1 end:  " -textVariable ik1EndClosed \
	-contextHelp "Last IK1 setpoint for scan."
    APSLabeledEntry .ik1steps -parent $w \
	-label "Number of steps:" -textVariable ik1StepsClosed \
	-contextHelp "Number of steps in the scan."
    APSLabeledEntry .ik1file -parent $w \
	-label "File name:" -textVariable ik1filenameClosed \
	-contextHelp "Number of steps in the scan."
    APSButton .scan  -parent $w -text "Scan IK1" \
	-command {
	    set restoreKickersString [exec cavget -cavput -list=S:IK -list=1,2,3,4 \
					  -list=:VoltageSetSendAO -pend=5]
	    if [catch {ScanIK1 -start $ik1StartClosed -stop $ik1EndClosed -steps $ik1StepsClosed \
			   -filename $ik1filenameClosed} result] {
		set status "Error: ScanIK1: $result"
	    }
	    if $simulRun {
		set status "exec cavput -list=$restoreKickersString -pend=5"
	    } else {
		exec cavput -list=$restoreKickersString -pend=5
	    }
	    set status "Kickers restored."
	} -contextHelp "Scans IK1 kicker and records remaining current."
    APSButton .plot  -parent $w -text "Plot scan results" \
	-command {
	    exec sddsplot $ik1filenameClosed -col=IK1,Fraction -graph=sym,conn,sca=3,fil &
	} -contextHelp "Plots results of the scan."
}

#---------------------------------------------------------------------------------------

proc MakeActionWidget2 {widget args} {
    set parent ""
    APSParseArguments {parent}
    
    APSFrame $widget -parent $parent -label "On-axis injection optimization" \
	-contextHelp "Control widgets"
    set w $parent$widget.frame
    
    APSLabeledEntry .ik1 -parent $w \
	-label "IK1 fixed setpoint:" -textVariable IK1Onaxis \
	-contextHelp "Enter a setpoint for IK1. 12kV kills the stored beam so the bpms see only the injected beam."
    APSLabeledEntry .ik34 -parent $w \
	-label "IK3-4 setpoints (optional):" -textVariable IK34Onaxis \
	-contextHelp "Enter setpoints for IK3-4 (space separated). If non-empty, they will be used as starting points for optimziation if X plane is chosen."
    APSLabeledEntry .aver -parent $w \
	-label "Number of averagings:" -textVariable averageOnaxis \
	-contextHelp "Number of waveforms to average for each measurement during optimization."
    APSLabeledEntry .fraction -parent $w \
	-label "Correction fraction:" -textVariable fractionOnaxis \
	-contextHelp "Correction fraction for optimization."
    APSLabeledEntry .iter -parent $w \
	-label "Iterations for smart optimization:" -textVariable iterationsOnaxis \
	-contextHelp "Number of iterations for smart optimization."
    APSLabeledEntry .saveFile -parent $w \
	-label "Save snap file:" -textVariable saveFileOnaxis \
	-contextHelp "Enter a snapshot file name for the pulsed power supply setpoints to be written in the directory above"
    APSRadioButtonFrame .plane -parent $w -label "Plane:  " -valueList {X Y XY} \
	-buttonList {X Y XY} -variable planeOnaxis -orientation horizontal \
	-commandList {{} {} {}} \
	-contextHelp "If X, IK3-IK4 kickers will be used as variables. If Y, BTS correctors B:V1 and C:V1 will be used as variables. If XY, optimization will be done at the same time." 
    APSRadioButtonFrame .method -parent $w -label "Method: " -valueList {1 2 3} \
	-buttonList {"Brainless simplex (traj)" "Scientific guess" "Brainless simplex (effic)"} -variable methodOnaxis -orientation horizontal \
	-commandList {{} {} {}} \
	-contextHelp "Brainless simplex (traj): usual simplex that minimizes turn-by-turn oscillations on a S38A bpm; Scientific guess: calculates incoming coordinates using 1st turn trajectory and corrects them. These two can be affected by charge dependent BPM offsets if the beam losses are large. In this case, use Brainless simplex (effic), which maximizes efficiensy instead of minimizing oscillations." 

    APSButton .minimize  -parent $w -text "Optimize on-axis conditions" \
	-command {
	    set cavputString -list=S:IK1:VoltageSetSendAO=$IK1Onaxis
	    if {[string compare $planeOnaxis X] != -1} {
		if [string length $IK34Onaxis] {
		    append cavputString ",S:IK3:VoltageSetSendAO=[lindex $IK34Onaxis 0]"
		    append cavputString ",S:IK4:VoltageSetSendAO=[lindex $IK34Onaxis 1]"
		}
	    }
	    if [catch {eval exec cavput $cavputString -pend=5} result] {
		set status "cavput $cavputString -pend=5"
		set status "Error setting IK3-IK4: $result"
	    } else {
		if {$methodOnaxis != 2} {
		    runOptimize -logDir $logDir -average $averageOnaxis -mode onAxis$planeOnaxis -method $methodOnaxis
		} else {
		    if [catch {OptimizeKickersSmartly -logDir $logDir -average $averageOnaxis -mode onAxis$planeOnaxis \
				   -fraction $fractionOnaxis -iterations $iterationsOnaxis} result] {
			return -code error "OptimizeKickersSmartly: $result"
		    }
		}
	    }
	} -contextHelp "Starts sddsoptimize for a closed kicker bump. It is better to have single bunch already injected. It is also advised to increase injected charge as this will decrease the bpm noise. The optimization is slow, so good initial conditions are helpful."
    APSButton .plotProg  -parent $w -text "Plot Progress" \
	-command {plotProgress -logDir $logDir -mode onAxis$planeOnaxis} \
	-contextHelp "Plots the knob values and emittance."
    APSButton .save  -parent $w -text "Save PulsedPS" \
	-command {SavePulsed -logDir $logDir -saveFile $saveFileOnaxis} \
	-contextHelp "Saves pulsed magnets setpoints to file above."
}

#---------------------------------------------------------------------------------------

proc MakeActionWidget3 {widget args} {
    set parent ""
    APSParseArguments {parent}
    
    APSFrame $widget -parent $parent -label "Kicker Scan" \
      -contextHelp "Control widgets"
    set w $parent$widget.frame

    APSLabeledEntry .steps -parent $w \
      -label "Number of steps:" -textVariable scanSteps \
      -contextHelp "Number of steps for kicker scan."
    APSLabeledEntry .file1 -parent $w \
      -label "Closed bump file:" -textVariable scanClosedFile \
      -contextHelp "Previously saved kicker file for closed bump optimization."
    APSLabeledEntry .file2 -parent $w \
      -label "On-axis kickers file:" -textVariable scanOnaxisFile \
      -contextHelp "Previously saved kicker file for on-axis optimization."
    APSLabeledEntry .aver -parent $w \
	-label "Number of averagings:" -textVariable averageKickerScan \
	-contextHelp "Number of waveforms to average for each step of the scan."
    APSLabeledEntry .file3 -parent $w \
      -label "Output file:" -textVariable scanOutputFile \
      -contextHelp "File name for results."


    APSFrameGrid .grid -parent $w -yList {y1 y2}
    set w1 $w.grid.y1
    set w2 $w.grid.y2
    APSButton .scan1  -parent $w1 -text "Run efficiency scan" \
	-command {
	    set status "Start kicker scan..."
	    if [catch {RunEfficiencyScan -steps $scanSteps -closedBumpFile $scanClosedFile \
			   -onAxisFile $scanOnaxisFile -outputFile $scanOutputFile -average $averageKickerScan} result] {
		SetStatus "RunEfficiencyScan: $result"
	    }
	} -contextHelp "Runs kicker scan in efficiency mode."
    APSButton .scan2  -parent $w1 -text "Run amplitude scan" \
	-command {
	    if [catch {RunAmplitudeScan -steps $scanSteps -closedBumpFile $scanClosedFile \
			   -onAxisFile $scanOnaxisFile -outputFile $scanOutputFile -average $averageKickerScan} result] {
		SetStatus "RunAmplitudeScan: $result"
	    }
	} -contextHelp "Runs kicker scan in amplitude mode."
    APSButton .plot1  -parent $w1 -text "Plot Efficiency scan" \
      -command {
	  exec sddsplot $scanOutputFile -col=IK4,Efficiency -graph=sym,connect,sca=3,fil &
      } -contextHelp "Plots the results of the efficiency scan."
    APSButton .plot2  -parent $w1 -text "Plot Amplitude scan" \
      -command {
	  exec sddsplot $scanOutputFile -col=IK4,Amplitude -graph=sym,connect,sca=3,fil &
      } -contextHelp "Plots the results of the amplitude scan."
    APSButton .knobs  -parent $w2 -text "Make New Kicker Knobs" \
      -command {
	  set knobFile /home/helios/oagData/sr/knobFiles/default/kickers/IK3-4-[exec date +%y%m%d].cokn
	  if [catch {exec /home/helios/SR/bin/createKickerKnobs \
			 -knobFile $knobFile -closedBumpFile $scanClosedFile -onAxisFile $scanOnaxisFile} result] {
	      SetStatus "/home/helios/SR/bin/createKickerKnobs: $result"
	  } else {
	      file delete /home/helios/oagData/sr/knobFiles/default/kickers/IK3-4.cokn
	      exec ln -s $knobFile /home/helios/oagData/sr/knobFiles/default/kickers/IK3-4.cokn
	  }
      } -contextHelp "Plots the results of the amplitude scan."
}

#---------------------------------------------------------------------------------------

proc MakeActionWidget4 {widget args} {
    set parent ""
    APSParseArguments {parent}
    
    APSFrame $widget -parent $parent -label "Injection trajectory" \
      -contextHelp "Control widgets"
    set w $parent$widget.frame

    APSLabeledEntry .ik1 -parent $w \
	-label "IK1 fixed setpoint:" -textVariable IK1Traj \
	-contextHelp "Enter a setpoint for IK1. 12kV kills the stored beam so the bpms see \
        only the injected beam. Empty string to not do anything to IK1."
    APSLabeledEntry .fileRoot -parent $w \
      -label "Output file root:" -textVariable outputFileRoot \
      -contextHelp "File to write data."
    APSLabeledEntry .fileIndex -parent $w \
      -label "File index:" -textVariable fileIndex \
      -contextHelp "Increased right before the measurement."
    APSLabeledEntry .trajAver -parent $w \
      -label "Number of trajectories to average:" -textVariable nTrajAver \
      -contextHelp "This number of trajectories will be collected, then averaged."
    APSLabeledEntry .sextFile -parent $w \
      -label "Sextupole parameter file:" -textVariable sextParamFile \
      -contextHelp "Correct sextupoles are important for injection processing."
    APSLabeledEntry .sectorRange -parent $w \
      -label "Sector range for fitting:" -textVariable sectorRangeTraj \
      -contextHelp "Trajectory fitting will be performed for BPMs in this sector range. Space separated."
    APSLabeledEntry .turnRange -parent $w \
      -label "Turn range for output relative to 2096:" -textVariable turnRangeTraj \
      -contextHelp "Normal injection trigger happens at 2096, but MPS dump happens earlier, so for MPS dump need to change. Space separated."
    APSRadioButtonFrame .plane -parent $w -label "Plane (sets up BPMs, takes some time):" -valueList {X Y XY} \
	-buttonList {X Y Both} -variable planeTraj -orientation horizontal \
	-contextHelp "Data will be collected in this plane. BPMs will be set up here too, \
        so no need to press \"Set up FPGA bpms\" after changing planes. XY means: P2s and P5s will be set to X, \
        P3s and P4s will be set to Y." \
	-commandList {"set status \"Switching to X plane and loading FPGA waveforms...\"; LoadRAM -plane X -mode measurement" \
			  "set status \"Switching to Y plane and loading FPGA waveforms...\"; LoadRAM -plane Y -mode measurement" \
			  "set status \"Switching to XY plane and loading FPGA waveforms...\"; LoadRAM -plane XY -mode measurement"}

    APSFrameGrid .grid -parent $w -yList {y1 y2 y3}
    set w1 $w.grid.y1
    set w2 $w.grid.y2
    set w3 $w.grid.y3
    APSButton .setupBpms  -parent $w1 -text "Set up FPGA bpms" \
      -command {
          set status "Loading RAM settings (single bunch, $planeTraj, no commutation)..."
          set status "Don't forget to restore bpm settings after the program is stopped."
          if [catch {LoadRAM -plane $planeTraj -mode measurement} result] {
              SetStatus "LoadRAM: $result"
          }
      } -contextHelp "Loads FPGA bpm RAM settings from \
          /home/helios/oagData/SCR/snapshots/SBPMWaveform/SBPMWaveform-singleXY.gz into all FPGA bpms."
    APSButton .collect  -parent $w1 -text "Collect injected motion" \
      -command {
          if {!$simulRun && [string length $IK1Traj]} {exec cavput -list=S:IK1:VoltageSetSendAO=$IK1Traj -pend=10}
          SetStatus "Arming triggers and injecting..."
          update
          set wmonFile $logDir/fpga.wmon
          set smonFile $logDir/fpga.mon
          if {![file exists $wmonFile] || ![file exists $smonFile]} {
              set status "Loading RAM settings (single bunch, $planeTraj, no commutation)..."
              set status "Don't forget to restore bpm settings after the program is stopped."
              if [catch {LoadRAM -plane $planeTraj -mode measurement} result] {
                  SetStatus "LoadRAM: $result"
              }
          }
          incr fileIndex
          set outputFile $logDir/$outputFileRoot[format %02d $fileIndex]
          if [catch {CollectInjectedMotion -simulRun $simulRun -wmonFile $wmonFile -smonFile $smonFile \
                       -outputFile $outputFile -nTrajAver $nTrajAver -plane $planeTraj} result] {
              SetStatus "CollectInjectedMotion: $result"
          } else {
              SetStatus "Done."
          }
      } -contextHelp "Collects injected beam motion in the chosen plane."
    APSButton .setupBpms1  -parent $w2 -text "Restore FPGA bpms for single bunch" \
      -command {
          set status "Loading RAM settings (single bunch, with commutation)..."
          if [catch {LoadRAM -plane $planeTraj -mode singleBunch} result] {
              SetStatus "LoadRAM: $result"
          }
      } -contextHelp "Loads FPGA bpm RAM settings from \
          /home/helios/oagData/SCR/snapshots/SBPMWaveform/SBPMWaveform-singleBunch.gz into all FPGA bpms."
    APSButton .setupBpms2  -parent $w2 -text "Restore FPGA bpms for 24 singlets" \
      -command {
          set status "Loading RAM settings (24 singlets)..."
          if [catch {LoadRAM -plane $planeTraj -mode 24singlets} result] {
              SetStatus "LoadRAM: $result"
          }
      } -contextHelp "Loads FPGA bpm RAM settings from \
          /home/helios/oagData/SCR/snapshots/SBPMWaveform/SBPMWaveform-24singlets.gz into all FPGA bpms."
    APSButton .plotTraj  -parent $w3 -text "Plot injection\ntrajectory" \
      -command {
          if {$fileIndex < 10} {set fileIndexString 0$fileIndex} else {set fileIndexString $fileIndex}
          SetStatus "Plotting trajectories $logDir/$outputFileRoot$fileIndexString..."
          update
          if [catch {PlotTrajectory -dataFile $logDir/$outputFileRoot$fileIndexString} result] {
              SetStatus "PlotTrajectory: $result"
          }
      } -contextHelp "Plots the injected beam trajectory."
    APSButton .plotMotion  -parent $w3 -text "Plot injection\noscillations" \
      -command {
          if {$fileIndex < 10} {set fileIndexString 0$fileIndex} else {set fileIndexString $fileIndex}
          SetStatus "Plotting oscillations $logDir/$outputFileRoot$fileIndexString..."
          update
          if [catch {PlotOscillations -dataFile $logDir/$outputFileRoot$fileIndexString} result] {
              SetStatus "PlotOscillations: $result"
          }
      } -contextHelp "Plots turn-by-turn motion on every bpm separately."
    APSButton .processSynchMotion  -parent $w3 -text "Process synch\nmotion" \
      -command {
          if {$fileIndex < 10} {set fileIndexString 0$fileIndex} else {set fileIndexString $fileIndex}
          set dataFile $logDir/$outputFileRoot$fileIndexString
          if {[string compare Y [exec sdds2stream $dataFile -para=Plane]] == 0} {
              SetStatus "File $dataFile contains Y data only. No synchrotron motion was processed."
          } else {
              SetStatus "Processing synchrotron motion $logDir/$outputFileRoot$fileIndexString..."
              update
              if [catch {ProcessSynchMotion -dataFile $logDir/$outputFileRoot$fileIndexString} result] {
                  SetStatus "ProcessSynchMotion: $result"
              }
          }
      } -contextHelp "Calculates initial dP/P and synch phase using synchrotron oscillations on S38A:P2."
    APSButton .processInjMotion  -parent $w3 -text "Process injected\nmotion" \
      -command {
          if {$fileIndex < 10} {set fileIndexString 0$fileIndex} else {set fileIndexString $fileIndex}
          SetStatus "Processing injected bunch motion $logDir/$outputFileRoot$fileIndexString..."
          update
          if [catch {ProcessInjectedMotion -dataFile $logDir/$outputFileRoot$fileIndexString \
                       -sextParamFile $sextParamFile -sectorRange $sectorRangeTraj} result] {
              SetStatus "ProcessInjMotion: $result"
          }
	} -contextHelp "Calculates initial (X, XP) or (Y, YP). Uses SVD to fit the trajectory."
}

#---------------------------------------------------------------------------------------

proc MakeActionWidget5 {widget args} {
    set parent ""
    APSParseArguments {parent}
    
    APSFrame $widget -parent $parent -label "RF Phase or Booster Energy scan" \
      -contextHelp "Control widgets"
    set w $parent$widget.frame
    
    #------ Top part
    APSLabeledEntry .ik1 -parent $w \
      -label "IK1 fixed setpoint:" -textVariable IK1PEScan \
      -contextHelp "Enter a setpoint for IK1. 12kV kills the stored beam so the bpms see only the injected beam."
    APSLabeledEntry .steps -parent $w \
      -label "Number of steps:" -textVariable stepNumberPEScan \
      -contextHelp "Number of steps in the phase scan."
    APSLabeledEntry .aver -parent $w \
      -label "Number of averaging:" -textVariable averagePEScan \
      -contextHelp "Number of waveforms to average for each step of the phase scan."
    APSRadioButtonFrame .readEffic -parent $w -label "Read injection efficiency?" \
        -variable readEfficPEScan -valueList {0 1} \
        -buttonList {no yes} \
        -orientation horizontal \
        -commandList {{} {}} \
        -contextHelp "At every step of the scan, readEffic command will be run to read injection efficiency in addition to amplitude measurement."

    APSFrameGrid .grid -parent $w -xList {x1 x2}
    set w1 $w.grid.x1
    set w2 $w.grid.x2

    #------ Phase scan part
    APSFrame .frame1 -parent $w1 -label "RF Phase scan" \
      -contextHelp "Control widgets"
    set w1f $w1.frame1.frame
    APSLabeledEntry .stepSize -parent $w1f \
      -label "Step size (deg):" -textVariable stepSizePhaseScan \
      -contextHelp "Step size in deg for the phase scan."
    APSLabeledEntry .outputFile -parent $w1f \
      -label "Output file:" -textVariable outputFilePhaseScan \
      -contextHelp "Output file name for the results of the phase scan."
    APSFrameGrid .grid -parent $w1f -yList {y1 y2}
    set w1f1 $w1f.grid.y1
    set w1f2 $w1f.grid.y2
    APSButton .scan  -parent $w1f1 -text "Scan rf phase" \
      -command {
          if [file exists $logDir/$outputFilePhaseScan] {
              SetStatus "Error: Output file $logDir/$outputFilePhaseScan exists."
          } else {
              if [catch {exec cavput -list=S:IK1:VoltageSetSendAO=$IK1PEScan -pend=5} result] {
                  set status "Error setting IK1: $result"
              } else {
                  set phase0 [exec cavget -list=BRF:S:PS1:Ch0]
                  if [catch {RunPhaseScan -outputFile $logDir/$outputFilePhaseScan -average $averagePEScan \
                               -steps $stepNumberPEScan -stepSize $stepSizePhaseScan -readEffic $readEfficPEScan} result] {
                      SetStatus "RunPhaseScan: $result"
                  }
                  exec cavput -list=BRF:S:PS1:Ch0=$phase0 -pend=5
              }
          }
      } -contextHelp "Scans rf phase and record synchrotron oscillations of the incoming beam."
    APSButton .plotScan  -parent $w1f2 -text "Plot scan results" \
      -command {
          set plotAver [exec sdds2stream $logDir/$outputFilePhaseScan -para=Average]
          if {$plotAver == 1} {
              exec sddsplot -graph=sym,conn,sca=3,fil -col=Phase,Ampl $logDir/$outputFilePhaseScan -end \
                -col=Phase,Efficiency $outputFilePhaseScan &
          } else {
              exec sddsplot -col=Phase,Ampl -graph=sym,conn,sca=3,fil $logDir/$outputFilePhaseScan \
                -col=Phase,Ampl,Std -graph=error $logDir/$outputFilePhaseScan -end \
                -col=Phase,Efficiency $logDir/$outputFilePhaseScan &
          }
      } -contextHelp "Plots the scan results."
    
    APSButton .plotScan1  -parent $w1f2 -text "Plot injection motion" \
      -command {
          exec sddsplot -col=Index,X $logDir/$outputFilePhaseScan.tbt -split=page -sep &
          exec sddsplot -col=Index,Y $logDir/$outputFilePhaseScan.tbt -split=page -sep &
      }

    #------ Booster Energy scan part
    APSFrame .frame2 -parent $w2 -label "Booster energy scan" \
	-contextHelp "Control widgets"
    set w2f $w2.frame2.frame
    APSLabeledEntry .stepSize -parent $w2f \
	-label "Step size (units of 1%):" -textVariable stepSizeEnergyScan \
	-contextHelp "Step size in deg for the scan."
    APSLabeledEntry .outputFile -parent $w2f \
	-label "Output file:" -textVariable outputFileEnergyScan \
	-contextHelp "Output file name for the results of the scan."
    APSFrameGrid .grid -parent $w2f -yList {y1 y2}
    set w2f1 $w2f.grid.y1
    set w2f2 $w2f.grid.y2
    APSButton .scan  -parent $w2f1 -text "Scan Booster energy" \
	-command {
	    if [file exists $logDir/$outputFileEnergyScan] {
		SetStatus "Error: Output file $outputFileEnergyScan exists."
	    } else {
		if [catch {exec cavput -list=S:IK1:VoltageSetSendAO=$IK1PEScan -pend=5} result] {
		    set status "Error setting IK1: $result"
		} else {
		    if [catch {RunEnergyScan -outputFile $logDir/$outputFileEnergyScan -average $averagePEScan \
				   -steps $stepNumberPEScan -stepSize $stepSizeEnergyScan -readEffic $readEfficPEScan} result] {
			SetStatus "RunEnergyScan: $result"
		    }
		}
	    }
	} -contextHelp "Scans booster energy and record synchrotron oscillations of the incoming beam."
    APSButton .plotScan  -parent $w2f2 -text "Plot scan results" \
	-command {
	    set plotAver [exec sdds2stream $logDir/$outputFileEnergyScan -para=Average]
	    if {$plotAver == 1} {
		exec sddsplot -graph=sym,conn,sca=3,fil -col=Energy,Ampl $logDir/$outputFileEnergyScan -end \
		    -col=Energy,Efficiency $logDir/$outputFileEnergyScan &
	    } else {
		exec sddsplot -col=Energy,Ampl -graph=sym,conn,sca=3,fil $logDir/$outputFileEnergyScan \
		    -col=Energy,Ampl,Std -graph=error $logDir/$outputFileEnergyScan -end \
		    -col=Energy,Efficiency $logDir/$outputFileEnergyScan &
	    }
	} -contextHelp "Plots the scan results."

    APSButton .plotScan1  -parent $w2f2 -text "Plot injection motion" \
	-command {
	    exec sddsplot -col=Index,X $logDir/$outputFileEnergyScan.tbt -split=page -sep &
	    exec sddsplot -col=Index,Y $logDir/$outputFileEnergyScan.tbt -split=page -sep &
	}

    APSFrameGrid .grid1 -parent $w -xList {x1 x2}
    set w1 $w.grid1.x1
    set w2 $w.grid1.x2
    #------ RF freq scan part
    APSFrame .frame1 -parent $w1 -label "RF frequency scan" \
	-contextHelp "Control widgets"
    set w1f $w1.frame1.frame
    APSLabeledEntry .stepSize -parent $w1f \
	-label "Step size (Hz):" -textVariable stepSizeFreqScan \
	-contextHelp "Step size in Hz for the rf frequency scan."
    APSLabeledEntry .outputFile -parent $w1f \
	-label "Output file:" -textVariable outputFileFreqScan \
	-contextHelp "Output file name for the results of the rf frequency scan."
    APSFrameGrid .grid -parent $w1f -yList {y1 y2}
    set w1f1 $w1f.grid.y1
    set w1f2 $w1f.grid.y2
    APSButton .scan  -parent $w1f1 -text "Scan rf freq" \
	-command {
	    if [file exists $logDir/$outputFileFreqScan] {
		SetStatus "Error: Output file $logDir/$outputFileFreqScan exists."
	    } else {
		if [catch {exec cavput -list=S:IK1:VoltageSetSendAO=$IK1PEScan -pend=5} result] {
		    set status "Error setting IK1: $result"
		} else {
		    set freq0 [exec cavget -list=A014-IETS:BTC:SRSetFreqM -floatFormat=%.1f -pendIoTime=5]
		    if [catch {RunFreqScan -outputFile $logDir/$outputFileFreqScan -average $averagePEScan \
				   -steps $stepNumberPEScan -stepSize $stepSizeFreqScan -readEffic $readEfficPEScan} result] {
			SetStatus "RunFreqScan: $result"
		    }
		    exec cavput -list=A014-IETS:BTC:SRSetFreqM=$freq0
		}
	    }
	} -contextHelp "Scans rf frequency and record synchrotron oscillations of the incoming beam."
    APSButton .plotScan  -parent $w1f2 -text "Plot scan results" \
	-command {
	    set plotAver [exec sdds2stream $logDir/$outputFileFreqScan -para=Average]
	    if {$plotAver == 1} {
		exec sddsplot -graph=sym,conn,sca=3,fil -col=Phase,Ampl $logDir/$outputFileFreqScan -end \
		    -col=Phase,Efficiency $outputFileFreqScan &
	    } else {
		exec sddsplot -col=Phase,Ampl -graph=sym,conn,sca=3,fil $logDir/$outputFileFreqScan \
		    -col=Phase,Ampl,Std -graph=error $logDir/$outputFileFreqScan -end \
		    -col=Phase,Efficiency $logDir/$outputFileFreqScan &
	    }
	} -contextHelp "Plots the scan results."

    APSButton .plotScan1  -parent $w1f2 -text "Plot injection motion" \
	-command {
	    exec sddsplot -col=Index,X $logDir/$outputFileFreqScan.tbt -split=page -sep &
	    exec sddsplot -col=Index,Y $logDir/$outputFileFreqScan.tbt -split=page -sep &
	    exec sddsplot -col=Index,Xsum $logDir/$outputFileFreqScan.tbt -split=page -sep &
	}


}

#---------------------------------------------------------------------------------------

proc MakeActionWidget6 {widget args} {
    set parent ""
    APSParseArguments {parent}
    
    APSFrame $widget -parent $parent -label "Septum Scan" \
      -contextHelp "Control widgets"
    set w $parent$widget.frame

    APSLabeledEntry .ik1 -parent $w \
	-label "IK1 fixed setpoint:" -textVariable IK1SepScan \
	-contextHelp "Enter a setpoint for IK1. 12kV kills the stored beam so the bpms see only the injected beam."
    APSLabeledEntry .steps -parent $w \
      -label "Number of steps:" -textVariable sepScanSteps \
      -contextHelp "Number of steps for septum IS1 scan."
    APSLabeledEntry .stepSize -parent $w \
      -label "Step size:" -textVariable stepSizeSepScan \
      -contextHelp "Step size for IS1 scan."
    APSLabeledEntry .aver -parent $w \
	-label "Number of averagings:" -textVariable averageSepScan \
	-contextHelp "Number of shots to average for readEffic."
    APSLabeledEntry .file -parent $w \
      -label "Output file:" -textVariable sepScanOutputFile \
      -contextHelp "File name for results."


    APSButton .scan  -parent $w -text "Run efficiency scan" \
      -command {
          set status "Start septum IS1 scan..."
          update
          if [catch {exec cavput -list=S:IK1:VoltageSetSendAO=$IK1SepScan -pend=5} result] {
              set status "Error setting IK1: $result"
          } else {
              if [catch {RunSeptumScan -steps $sepScanSteps -outputFile $sepScanOutputFile -average $averageSepScan \
                           -stepSize $stepSizeSepScan} result] {
                  SetStatus "RunEfficiencyScan: $result"
              }
          }
      } -contextHelp "Runs IS1 septum scan and measures injection efficiency on each step. Scan is run around the current IS1 setpoint."
    APSButton .plot  -parent $w -text "Plot results" \
      -command {
          exec sddsplot $sepScanOutputFile -col=Septum,Efficiency -graph=sym,connect,sca=3,fil &
      } -contextHelp "Plots the results of the septum scan."
}

#---------------------------------------------------------------------------------------

proc MakeActionWidget7 {widget args} {
    global kickerWaveformRootname kickerWaveformIndex
    set parent ""
    APSParseArguments {parent}
     
    APSFrame $widget -parent $parent -label "Single-shot kicker waveform measurement" \
      -contextHelp "Control widgets"
    set w $parent$widget.frame
    APSLabeledEntry .rootname -parent $w \
      -label "Measurement rootname:" -textVariable kickerWaveformRootname \
      -contextHelp "Measurement rootname."
    APSLabeledEntry .index -parent $w \
      -label "Measurement index:" -textVariable kickerWaveformIndex \
      -contextHelp "Measurement index. Increased right before measurements."
    
    APSButton .plot  -parent $w -text "Measure" \
      -command {
          incr kickerWaveformIndex
          set localRoot $kickerWaveformRootname-[format %02d $kickerWaveformIndex]
          APSExecLog .kickerWaveform \
            -lineLimit 2048 -width 90 \
            -name "Single-shot kicker waveform" \
            -unixCommand "/home/helios/SR/bin/singleShotKickerWaveform -rootname $localRoot"
      }
}

#---------------------------------------------------------------------------------------

proc MakeActionWidget8 {widget args} {
    set parent ""
    APSParseArguments {parent}
    
    APSFrame $widget -parent $parent -label "MPS dump trajectory" \
      -contextHelp "Control widgets"
    set w $parent$widget.frame

    APSLabeledEntry .fileRoot -parent $w \
      -label "Output file root:" -textVariable outputFileRootDump \
      -contextHelp "File to write data."
    APSLabeledEntry .fileIndex -parent $w \
      -label "File index:" -textVariable fileIndexDump \
      -contextHelp "Increased right before the measurement."
    APSLabeledEntry .turn0 -parent $w \
      -label "Turn 0:" -textVariable turn0Dump \
      -contextHelp "Turn at which the event of interest happens. Used for processing only."
    APSLabeledEntry .turns -parent $w \
      -label "Turn range for output (space separated):" -textVariable turnRangeDump \
      -contextHelp "For plotting: turns in this range around turn0 will be plotted."
    APSRadioButtonFrame .plane -parent $w -label "Plane (sets up BPMs, takes some time):" -valueList {X Y XY} \
	-buttonList {X Y Both} -variable planeDump -orientation horizontal \
	-contextHelp "Data will be collected in this plane. BPMs will be set up here too, \
        so no need to press \"Set up FPGA bpms\" after changing planes. XY means: P2s and P5s will be set to X, \
        P3s and P4s will be set to Y." \
	-commandList {"set status \"Switching to X plane and loading FPGA waveforms...\"; LoadRAM -plane X -mode measurement" \
			  "set status \"Switching to Y plane and loading FPGA waveforms...\"; LoadRAM -plane Y -mode measurement" \
			  "set status \"Switching to XY plane and loading FPGA waveforms...\"; LoadRAM -plane XY -mode measurement"}

    APSFrameGrid .grid -parent $w -yList {y1 y2 y3}
    set w1 $w.grid.y1
    set w2 $w.grid.y2
    set w3 $w.grid.y3
    APSButton .setupBpms  -parent $w1 -text "Set up FPGA bpms" \
      -command {
          set status "Loading RAM settings (single bunch, $planeTraj, no commutation)..."
          set status "Don't forget to restore bpm settings after the program is stopped."
          if [catch {LoadRAM -plane $planeDump -mode measurement} result] {
              SetStatus "LoadRAM: $result"
          }
      } -contextHelp "Loads FPGA bpm RAM settings from \
          /home/helios/oagData/SCR/snapshots/SBPMWaveform/SBPMWaveform-singleXY.gz into all FPGA bpms."
    APSButton .setupTriggers  -parent $w1 -text "Arm triggers" \
      -command {
          set status "Arming triggers..."
          if [catch {SetupTrigger -mode dump} result] {
              SetStatus "SetupTrigger: $result"
          } else {
              SetStatus "Done."
          }
      } -contextHelp "Arms triggers and sets additional pvs. This button is pressed \
          as part of \"Collect injected motion\", so don't really need to press it."
    APSButton .collect  -parent $w1 -text "Collect MPS dump motion" \
      -command {
          SetStatus "Arming triggers and dumping..."
          update
          set wmonFile $logDir/fpga.wmon
          set smonFile $logDir/fpga.mon
          if {![file exists $wmonFile] || ![file exists $smonFile]} {
              set status "Loading RAM settings (single bunch, $planeTraj, no commutation)..."
              set status "Don't forget to restore bpm settings after the program is stopped."
              if [catch {LoadRAM -plane $planeTraj -mode measurement} result] {
                  SetStatus "LoadRAM: $result"
              }
          }
          incr fileIndexDump
          set outputFile $logDir/$outputFileRootDump[format %02d $fileIndexDump]
          if [catch {CollectInjectedMotion -simulRun $simulRun -wmonFile $wmonFile -smonFile $smonFile \
                       -outputFile $outputFile -plane $planeDump -mode dump} result] {
              SetStatus "CollectInjectedMotion: $result"
          } else {
              SetStatus "Done."
          }
      } -contextHelp "Collects MPS dump beam motion in the chosen plane. User needs to reinject manually."
    APSButton .setupBpms1  -parent $w2 -text "Restore FPGA bpms for single bunch" \
      -command {
          set status "Loading RAM settings (single bunch, with commutation)..."
          if [catch {LoadRAM -plane $planeDump -mode singleBunch} result] {
              SetStatus "LoadRAM: $result"
          }
      } -contextHelp "Loads FPGA bpm RAM settings from \
          /home/helios/oagData/SCR/snapshots/SBPMWaveform/SBPMWaveform-singleBunch.gz into all FPGA bpms."
    APSButton .setupBpms2  -parent $w2 -text "Restore FPGA bpms for 24 singlets" \
      -command {
          set status "Loading RAM settings (24 singlets)..."
          if [catch {LoadRAM -plane $planeDump -mode 24singlets} result] {
              SetStatus "LoadRAM: $result"
          }
      } -contextHelp "Loads FPGA bpm RAM settings from \
          /home/helios/oagData/SCR/snapshots/SBPMWaveform/SBPMWaveform-24singlets.gz into all FPGA bpms."
    APSButton .plotTraj  -parent $w3 -text "Plot\ntrajectory" \
      -command {
          set dataFile $logDir/$outputFileRootDump[format %02d $fileIndexDump]
          SetStatus "Plotting trajectories $dataFile..."
          update
          if [catch {PlotTrajectory -dataFile $dataFile -turnRange $turnRangeDump} result] {
              SetStatus "PlotTrajectory: $result"
          }
      } -contextHelp "Plots the injected beam trajectory."
    APSButton .plotMotion  -parent $w3 -text "Plot\noscillations" \
      -command {
          set dataFile $logDir/$outputFileRootDump[format %02d $fileIndexDump]
          SetStatus "Plotting oscillations $dataFile..."
          update
          if [catch {PlotOscillations -dataFile $dataFile} result] {
              SetStatus "PlotOscillations: $result"
          }
      } -contextHelp "Plots turn-by-turn motion on every bpm separately."
}

#---------------------------------------------------------------------------------------

proc MakeActionWidgetLow {widget args} {
    set parent ""
    APSParseArguments {parent}
    APSButton .motion1  -parent $parent -text "Record/show\ninjected motion" \
      -command {
          set tmpRoot $logDir/[APSTmpString]-inj
          if [catch {exec /home/helios/SR/bin/kickRecordBeam_fpga -rootname $tmpRoot -injection 1 -average 1 -sector both} result] {
              return -code error "/home/helios/SR/bin/kickRecordBeam_fpga: $result"
          }
          exec sddsplot $tmpRoot.wvfrm -col=Index,\[XY\]* -sep -title=@PlotTitle &
      }
    APSButton .motion2  -parent $parent -text "Record/show\nstored motion" \
      -command {
          set tmpRoot $logDir/[APSTmpString]-stored
          if [catch {exec /home/helios/SR/bin/kickRecordBeam_fpga -rootname $tmpRoot -injection 0 -average 1 -sector both} result] {
              return -code error "/home/helios/SR/bin/kickRecordBeam_fpga: $result"
          }
          exec sddsplot $tmpRoot.wvfrm -col=Index,\[XY\]* -sep &
      }
}

#---------------------------------------------------------------------------------------

proc ScanIK1 {args} {
    global status
    APSParseArguments {start stop steps filename}
    set minimumCurrent 0.5
    set stepSize [expr ($stop - $start) / ($steps - 1.0)]
    set kickerSetpoints [exec cavget -list=S:IK -list=1,2,3,4 -list=:VoltageSetSendAO -pend=5]
    for {set i 0} {$i < $steps} {incr i} {
        update
        set targetIK1 [expr $start + $stepSize * $i]
        set currentBefore [exec cavget -list=S-DCCT:CurrentM -pend=5]
        if [catch {ApplyKickers -targetIK1 $targetIK1 -kickerSetpoints0 $kickerSetpoints} result] {
            return -code error "ApplyKickers: $result"
        }
        after 1000
        if [catch {PulseKickersOnce} result] {
            return -code error "PulseKickersOnce: $result"
        }
        #--- Wait for current measurement to settle
        after 5000
        set currentAfter [exec cavget -list=S-DCCT:CurrentM -pend=5]
        lappend fractionList [expr $currentAfter / $currentBefore]
        lappend ik1List $targetIK1
        set status "IK1: $targetIK1 -- fraction: [expr $currentAfter / $currentBefore]"
        if {$currentAfter < $minimumCurrent} {set status "Current is below limit, interrupting..."; break}
        
    }
    exec sddsmakedataset $filename -col=IK1,type=double -data=[join $ik1List ,] \
      -col=Fraction,type=double -data=[join $fractionList ,]
    set status "IK1 scan completed."
}

#---------------------------------------------------------------------------------------
proc PulseKickersOnce {args} {
    exec cavput -list=Mt:Ddg3chan4.GATE=1
    after 500
    exec cavput -list=Mt:Ddg3chan4.GATE=0
}
#---------------------------------------------------------------------------------------
proc ApplyKickers {args} {
    global simulRun status
    APSParseArguments {targetIK1 kickerSetpoints0}
    set tol 0.01
    set ik10 [lindex $kickerSetpoints0 0]
    set ik20 [lindex $kickerSetpoints0 1]
    set ik30 [lindex $kickerSetpoints0 2]
    set ik40 [lindex $kickerSetpoints0 3]
    set fraction [expr $targetIK1 / $ik10]
    set ik1 [format %.4f $targetIK1]
    set ik2 [format %.4f [expr $ik20 * $fraction]]
    set ik3 [format %.4f [expr $ik30 * $fraction]]
    set ik4 [format %.4f [expr $ik40 * $fraction]]
    set status "Setting kickers to $ik1, $ik2, $ik3, $ik4"
    for {set i 0} {$i < 4} {incr i} {
        if $simulRun {
            # IK2 and IK3 should be updating separately because they are processed by the same ioc. Sometimes they setpoints are not processed when the values are updated in the same instance.
            set status "cavput -list=S:IK1:VoltageSetSendAO=$ik1,S:IK3:VoltageSetSendAO=$ik3,S:IK4:VoltageSetSendAO=$ik4 -pend=5"
            set status "cavput -list=S:IK2:VoltageSetSendAO=$ik2 -pend=5"
        } else {
            # Ik2 and IK3 should be updating separately because they are processed by the same ioc. Sometimes they setpoints are nto processed when the values are updated in the same instance.
            exec cavput -list=S:IK1:VoltageSetSendAO=$ik1,S:IK3:VoltageSetSendAO=$ik3,S:IK4:VoltageSetSendAO=$ik4 -pend=5
            exec cavput -list=S:IK2:VoltageSetSendAO=$ik2 -pend=5
        }
        after 1000
        set kickerSetpoints [exec cavget -list=S:IK -list=1,2,3,4 -list=:VoltageSetSendAO -pend=5]
        if {[expr abs([lindex $kickerSetpoints 0] - $ik1)] > $tol \
              || [expr abs([lindex $kickerSetpoints 1] - $ik2)] > $tol \
              || [expr abs([lindex $kickerSetpoints 2] - $ik3)] > $tol \
              || [expr abs([lindex $kickerSetpoints 3] - $ik4)] > $tol} {
        } else {
            return
        }
    }
    return -code error "Error setting kickers: timed out."
}
#---------------------------------------------------------------------------------------

proc ProcessInjectedMotion {args} {
    global execPath
    set sextParamFile ""
    APSParseArguments {dataFile sextParamFile sectorRange}
    set sectorStart [lindex $sectorRange 0]
    set sectorEnd [lindex $sectorRange 1]
    set deleteFiles ""
    set execFile $execPath/processInjectionTrajectory
    set plane [lindex [exec sdds2stream $dataFile -para=Plane] 0]
    if [string length $sextParamFile] {
        set paramFileString " -sextParamFile $sextParamFile "
    } else {
        set paramFileString ""
    }
    if {[string compare $plane "XY"] == 0} {
        set planeList [list X Y]
    } else {
        set planeList $plane
    }
    foreach plane $planeList {
        set tmpRoot /tmp/[APSTmpString]-injProc
        SetStatus "$execFile -inputFile $dataFile.$plane.trajectory -outputRoot $tmpRoot -plot 1 $paramFileString -sectorStart $sectorStart -sectorEnd $sectorEnd -verbose 0"
        if [catch {exec $execFile -inputFile $dataFile.$plane.trajectory -outputRoot $tmpRoot -plot 1 $paramFileString \
                     -sectorStart $sectorStart -sectorEnd $sectorEnd -verbose 0 &} result] {
            return -code error "$execFile: $result"
        }
        lappend deleteFiles $tmpRoot.results
        set counter 0
        while {[file exists $tmpRoot.results] == 0} {
            after 500; incr counter
            if {$counter > 10} {return -code error "Error: Waiting for $execFile to complete takes too long."}
        }
        set nameList [exec sdds2stream $tmpRoot.results -col=ValueName]
        set valueList [exec sdds2stream $tmpRoot.results -col=Value]
        set unitList [exec sdds2stream $tmpRoot.results -col=Units]
        for {set i 0} {$i < [llength $nameList]} {incr i} {
            set valueArray([lindex $nameList $i]) [lindex $valueList $i] 
            set unitsArray([lindex $nameList $i]) [lindex $unitList $i]
        }
        SetStatus "S1 BEGINING: $plane ($unitsArray(sector1_${plane})): [format %.3e $valueArray(sector1_${plane})]; ${plane}P ($unitsArray(sector1_${plane}P)): [format %.3e $valueArray(sector1_${plane}P)]"
        SetStatus "SEPTUM EXIT: $plane ($unitsArray(septum_${plane})): [format %.3e $valueArray(septum_${plane})]; ${plane}P ($unitsArray(septum_${plane}P)): [format %.3e $valueArray(septum_${plane}P)]"
        if {[lsearch $nameList EnergyError] != -1} {
            SetStatus "Residual error stdev after the fit: [format %.3e $valueArray(ResidErrorStd)] ($unitsArray(ResidErrorStd)); Energy error: [format %.3e $valueArray(EnergyError)] ($unitsArray(EnergyError))"
        }
    }
    catch {eval file delete $deleteFiles}
}

#---------------------------------------------------------------------------------------

proc ProcessSynchMotion {args} {
    global OAGGlobal
    APSParseArguments {dataFile}
    
    set motionColumn S38A:P2:turnHistorySmall:Xposition
    set turn0 [expr 2096 + 1]
    set harmonic 1296
    set twiFile $OAGGlobal(SRLatticesDirectory)/default/aps.twi
    set alphac [exec sdds2stream $twiFile -para=alphac]
    set dispersion0 [exec sddsprocess $twiFile -pipe=out -match=col,ElementName=S38A:P2 \
                       | sdds2stream -pipe=in -col=etax]
    
    if {[lsearch -exact [join [exec sddsquery $dataFile -col] ] $motionColumn] == -1} {
        return -code error "Error: File $dataFile does not have $motionColumn column."
    }
    exec sddsprocess $dataFile -pipe=out -filter=col,Index,$turn0,4096 \
      | sddsconvert -pipe=in $dataFile.clip -retain=col,Index,$motionColumn
    exec sddssmooth $dataFile.clip $dataFile.veryslow -col=$motionColumn -points=101 -passes=7
    exec sddsxref $dataFile.clip $dataFile.veryslow -pipe=out -take=$motionColumn -rename=col,$motionColumn=VerySlowMotion \
      | sddsprocess -pipe "-redef=col,Motion,$motionColumn VerySlowMotion -" \
      | sddssmooth -pipe=in $dataFile.synchMotion -col=Motion -points=11 -passes=3
    file delete $dataFile.veryslow $dataFile.clip

    exec sddsprocess $dataFile.synchMotion -pipe=out -filter=col,Index,$turn0,[expr $turn0 + 512] \
      "-redef=col,Index,Index $turn0 -" \
      | sddsnaff -pipe=in $dataFile.naff -col=Index,Motion

    set naffList [exec sddsprocess $dataFile.naff -pipe=out -clip=1,0,inv \
                    | sdds2stream -pipe=in -col=MotionFrequency,MotionAmplitude,MotionPhase,MotionSignificance]
    set synchTune [lindex $naffList 0]
    set motionAmpl [expr [lindex $naffList 1] * 0.001]
    set motionPhase [lindex $naffList 2]
    set deltaMax [expr $motionAmpl / $dispersion0]
    set phiMax [expr $deltaMax * $harmonic * $alphac / $synchTune]
    set delta0 [expr $deltaMax * cos($motionPhase)]
    set phi0 [expr $phiMax * sin($motionPhase) / 3.14 * 180]
    SetStatus "Synch tune: [format %.3e $synchTune] -- deltaP/P [format %.3e $delta0] -- phi0: [format %.3e $phi0] deg."
    exec sddsprocess $dataFile.synchMotion $dataFile.synchMotion1 \
      -process=Index,first,Index0 "-redef=col,Index,Index Index0 -" \
      "-redef=col,MotionFit,2 pi * $synchTune * Index * $motionPhase + cos $motionAmpl * 1e3 *"
    file copy -force $dataFile.synchMotion1 $dataFile.synchMotion; file delete $dataFile.synchMotion1
    exec sddsplot $dataFile.synchMotion -col=Index,Motion* -graph=line,vary &
}

#---------------------------------------------------------------------------------------

proc RunEnergyScan {args} {
    APSParseArguments {outputFile average steps stepSize readEffic}

    APSExecLog .closedBump \
      -lineLimit 2048 -width 90 \
      -name "Booster Energy Scan" \
      -unixCommand "/home/helios/SR/bin/injectionMotionScan -mode energy -readEffic $readEffic \
                    -outputFile $outputFile -steps $steps -stepSize $stepSize -average $average"
}

#---------------------------------------------------------------------------------------
proc RunSeptumScan {args} {
    APSParseArguments {steps outputFile average stepSize}

    APSExecLog .closedBump \
      -lineLimit 2048 -width 90 \
      -name "Septum IS1 Scan" \
      -unixCommand "/home/helios/SR/bin/injectionMotionScan -mode septum \
                    -outputFile $outputFile -steps $steps -stepSize $stepSize -average $average"
}

#---------------------------------------------------------------------------------------
proc RunPhaseScan {args} {
    APSParseArguments {outputFile average steps stepSize readEffic}

    APSExecLog .closedBump \
      -lineLimit 2048 -width 90 \
      -name "RF Phase Scan" \
      -unixCommand "/home/helios/SR/bin/injectionMotionScan -mode phase -readEffic $readEffic \
                    -outputFile $outputFile -steps $steps -stepSize $stepSize -average $average"
}

#---------------------------------------------------------------------------------------
proc RunFreqScan {args} {
    APSParseArguments {outputFile average steps stepSize readEffic}

    APSExecLog .closedBump \
      -lineLimit 2048 -width 90 \
      -name "RF Frequency Scan" \
      -unixCommand "/home/helios/SR/bin/injectionMotionScan -mode freq -readEffic $readEffic \
                    -outputFile $outputFile -steps $steps -stepSize $stepSize -average $average"
}

#---------------------------------------------------------------------------------------

proc PlotOscillations {args} {
    APSParseArguments {dataFile}
    set plane [exec sdds2stream $dataFile -para=Plane]
    set nTrajAver [exec sdds2stream $dataFile -para=NTrajectories]
    exec sddsplot $dataFile.oscil -col=Index,*position -sep "-topline=Injection motion in $plane: Position" &
    exec sddsplot $dataFile.oscil -col=Index,*sum -sep "-topline=Injection motion in $plane: Sum" &
    if {$nTrajAver > 1} {
	set fileList [glob $dataFile.*.oscil]
	set nn [llength $fileList]
	eval exec sddsplot -graph=sym,connect=subt,vary=subt,fil -sep=$nn -groupby=nameIndex -scale=2050,2250,0,0 \
	    \"-topline=Injection motion in $plane: Position\" \
	    -col=Index,*position $fileList &
	eval exec sddsplot -graph=line,vary -sep=$nn -groupby=nameIndex \
	    \"-topline=Injection motion in $plane: sum\" \
	    -col=Index,*sum $fileList &
    }
}

#---------------------------------------------------------------------------------------

proc PlotTrajectory {args} {
    global fpgaSectorList bpmList timingShiftSector turn0 sector39L sectorL circum OAGGlobal
    set turnRange "-2 10"
    APSParseArguments {dataFile turnRange}
    set plane [exec sdds2stream $dataFile -para=Plane]
    set nTrajAver [exec sdds2stream $dataFile -para=NTrajectories]
    set magFile $OAGGlobal(SRLatticesDirectory)/default/aps.mag

    if {[string compare $plane "XY"] == 0} {
        set planeList [list X Y]
    } else {
        set planeList $plane
    }

    foreach plane $planeList {
        #--- Processing averaged measurement file:
        if ![file exists $dataFile.$plane.trajectory] {
            if [catch {ProcessInjectionTrajectory -dataFile $dataFile -plane $plane -turnRange $turnRange} result] {
                return -code error "ProcessInjectionFile: $result"
            }
        } else {
            #--- If turnRange changed in the GUI, recalculate trajectory files:
            set nPages [exec sdds2stream $dataFile.$plane.trajectory -npages=bare]
            foreach {t0 t1} [exec sddsconvert $dataFile.$plane.trajectory -pipe=out -keep=1,$nPages | sdds2stream -pipe=in -para=TurnAfterInj] {}
            if {$t0 != [lindex $turnRange 0] || $t1 != [lindex $turnRange 1]} {
                if [catch {ProcessInjectionTrajectory -dataFile $dataFile -plane $plane -turnRange $turnRange} result] {
                    return -code error "ProcessInjectionFile: $result"
                }
            }
        }
        #--- Making shifted magnet file:
        if ![file exists $dataFile.mag] {
            exec sddsprocess $magFile $dataFile.mag.tmp1 -filter=col,s,0,$sector39L "-redef=col,s,s $sectorL +"
            exec sddsprocess $magFile $dataFile.mag.tmp2 -filter=col,s,$sector39L,$circum "-redef=col,s,s $sector39L -"
            exec sddscombine $dataFile.mag.tmp2 $dataFile.mag.tmp1 $dataFile.mag -merge -overWrite
            file delete $dataFile.mag.tmp2 $dataFile.mag.tmp1
        }
        #--- Plotting trajectory:
        set firstTurn [lindex $turnRange 0]
        set lastTurn [lindex $turnRange 1]
        set plotCommandPosition1 "sddsplot \"-ylabel=Trajectory $plane\" "
        set plotCommandPosition2 "sddsplot \"-ylabel=Trajectory $plane\" "
        set plotCommandSum1 "sddsplot \"-ylabel=Sum $plane\" "
        set plotCommandSum2 "sddsplot \"-ylabel=Sum $plane\" "
        if {$nTrajAver > 1} {set singleFileList [glob $dataFile.*.$plane.trajectory]}
        for {set i $firstTurn} {$i <= $lastTurn} {incr i} {
            if {$nTrajAver > 1} {
                append plotCommandPosition1 "-col=s,Trajectory -filter=para,TurnAfterInj,$i,$i \"-topline=$plane: Turns after injection: $i\" \
                  -graph=sym,connect=subt,subt=1 $dataFile.$plane.trajectory \
                  -col=s,Trajectory,TrajectoryStDev -filter=para,TurnAfterInj,$i,$i -graph=error $dataFile.$plane.trajectory \
                  -col=s,Profile -graph=line $dataFile.mag -overlay=xmode=normal,yfactor=0.075 -end "
                append plotCommandPosition2 "-col=s,Trajectory -filter=para,TurnAfterInj,$i,$i \"-topline=$plane: Turns after injection: $i\" \
                  -graph=sym,connect=subt,vary=subt $singleFileList \
                  -col=s,Profile -graph=line $dataFile.mag -overlay=xmode=normal,yfactor=0.075 -end "
                append plotCommandSum1 "-col=s,Sum -filter=para,TurnAfterInj,$i,$i \"-topline=$plane: Turns after injection: $i\" \
                  -graph=sym,connect=subt,subt=1 $dataFile.$plane.trajectory \
                  -col=s,Sum,SumStDev -filter=para,TurnAfterInj,$i,$i -graph=error $dataFile.$plane.trajectory \
                  -col=s,Profile -graph=line $dataFile.mag -overlay=xmode=normal,yfactor=0.075 -end "
                append plotCommandSum2 "-col=s,Sum -filter=para,TurnAfterInj,$i,$i \"-topline=$plane: Turns after injection: $i\" \
                  -graph=sym,connect=subt,vary=subt $singleFileList \
                  -col=s,Profile -graph=line $dataFile.mag -overlay=xmode=normal,yfactor=0.075 -end "
            } else {
                append plotCommandPosition1 "-col=s,Trajectory -filter=para,TurnAfterInj,$i,$i \"-topline=$plane: Turns after injection: $i\" \
                  -graph=sym,connect=subt,subt=1 $dataFile.$plane.trajectory \
                  -col=s,Profile -graph=line $dataFile.mag -overlay=xmode=normal,yfactor=0.075 -end "
                append plotCommandSum1 "-col=s,Sum -filter=para,TurnAfterInj,$i,$i \"-topline=$plane: Turns after injection: $i\" \
                  -graph=sym,connect=subt,subt=1 $dataFile.$plane.trajectory \
                  -col=s,Profile -graph=line $dataFile.mag -overlay=xmode=normal,yfactor=0.075 -end "

            }
        }
        eval exec $plotCommandPosition1 &
        eval exec $plotCommandSum1 &
        if {$nTrajAver > 1} {
            eval exec $plotCommandPosition2 &
            eval exec $plotCommandSum2 &
        }
    }
}

#---------------------------------------------------------------------------------------

proc ProcessInjectionTrajectory {args} {
    global fpgaSectorList timingShiftSector turn0 sector39L sectorL OAGGlobal
    set turnRange "-10 100"
    APSParseArguments {dataFile plane turnRange}
    set twiFile $OAGGlobal(SRLatticesDirectory)/default/aps.twi
    
    set t0 [lindex $turnRange 0]
    set t1 [lindex $turnRange 1]
    #--- Subtract DC orbit:
    exec sddsprocess $dataFile $dataFile.oscil -process=S*position,aver,%sAver,functionof=Index,lower=1000,upper=2000 \
      "-redef=col,%s,%s %sAver -,select=S*position"
    if {[string compare $plane "XY"] == 0} {
        set planeList [list X Y]
        set bpmSufListList [list [list A:P2 B:P5 B:P2] [list A:P3 A:P4 B:P4 B:P3]]
    } else {
        set planeList $plane
        set bpmSufListList [list [list A:P2 A:P3 A:P4 B:P5 B:P4 B:P3 B:P2]]
    }
    foreach localPlane $planeList bpmSufList $bpmSufListList {
        #--- Determine if the dataFile has StDev columns and defining suffix lists:
        set inputColumnList [join [exec sddsquery $dataFile -col] ]
        if {[lsearch -regexp $inputColumnList StDev] != -1} {
            set suffixList [list position positionStDev sum sumStDev]
            set pvSuffixList [list :turnHistorySmall:${localPlane}position :turnHistorySmall:${localPlane}positionStDev \
                                :turnHistorySmall:${localPlane}sum :turnHistorySmall:${localPlane}sumStDev]
            set columnList [list Trajectory TrajectoryStDev Sum SumStDev]
        } else {
            set suffixList [list position sum]
            set pvSuffixList [list :turnHistorySmall:${localPlane}position :turnHistorySmall:${localPlane}sum]
            set columnList [list Trajectory Sum]
        }
        #--- Processing file:
        set fileList ""
        foreach suffix0 $suffixList pvSuffix $pvSuffixList columnName $columnList {
            set suffix ${localPlane}$suffix0
            set columnList1 ""
            set columnList2 ""
            foreach sector $fpgaSectorList {
                foreach bpm $bpmSufList {
                    if {$sector < $timingShiftSector || $sector == 40} {
                        lappend columnList1 S${sector}${bpm}:turnHistorySmall:$suffix
                    } else {
                        lappend columnList2 S${sector}${bpm}:turnHistorySmall:$suffix
                    }
                }
            }
            exec sddsconvert $dataFile.oscil -pipe=out -retain=col,Index,[join $columnList1 ,] \
              | sddsprocess -pipe=in $dataFile.oscil.1 "-redef=col,Index0,Index $turn0 -" \
              -filter=col,Index0,$t0,$t1
            exec sddsconvert $dataFile.oscil -pipe=out -retain=col,Index,[join $columnList2 ,] \
              | sddsprocess -pipe=in $dataFile.oscil.2 "-redef=col,Index0,Index $turn0 - 1 -" \
              -filter=col,Index0,$t0,$t1
            exec sddsxref $dataFile.oscil.1 $dataFile.oscil.2 -pipe=out -take=S* \
              | sddsbreak -pipe -rowlimit=1 \
              | sddsprocess -pipe -process=Index0,first,TurnAfterInj \
              | sddsconvert -pipe -del=col,Index,Index0 \
              | sddstranspose -pipe -oldColumn=BPMName -rootname=$columnName \
              | sddsprocess -pipe "-reedit=col,BPMName,%@$pvSuffix@@" -reprint=para,Plane,$localPlane \
              | sddsxref -pipe $twiFile -take=s -match=BPMName=ElementName -nowarning -reuse=page \
              | sddsprocess -pipe "-redef=col,s,s $sector39L > ? s $sector39L - : s $sectorL + \$" \
              | sddssort -pipe=in $dataFile.$suffix0 -col=s
            file delete $dataFile.oscil.1 $dataFile.oscil.2
            lappend fileList $dataFile.$suffix0
        }
        #--- Combining all columns:
        eval exec sddsxref $fileList $dataFile.$localPlane.trajectory -take=* -leave=BPMName,s
        eval file delete $fileList
    }
}

#---------------------------------------------------------------------------------------
proc WaitForTriggers {args} {
    global fpgaSectorList
    set selectedIOCList ""
    foreach sector $fpgaSectorList {lappend selectedIOCList S${sector}A S${sector}B}
    set wait 1
    set counter 0
    while {$wait == 1} {
        set triggerList [join [exec cavget -list=[join $selectedIOCList ,] -list=:TurnHistoryIsArmed] ]
        if {[lsearch -exact $triggerList 1] == -1} {set wait 0}
        after 200
        incr counter
        if {$counter > 50} {return -code error "Waiting for triggers to discharge takes too long... Try enabling \"Booster Extraction\"."}
    }
}
#---------------------------------------------------------------------------------------

proc CollectInjectedMotion {args} {
    set mode injection
    set nTrajAver 1
    APSParseArguments {wmonFile smonFile outputFile nTrajAver plane simulRun mode}
    if !$simulRun {
        if [file exists $outputFile] {
            return -code error "Error: File $outputFile already exists."
        }
    }
    if {[string compare $mode "injection"] == 0} {
        #--- Make sure beam current is below target so the injection will happen:
        set beamList [join [exec cavget -list=S-DCCT:CurrentM,Mt:SRinjectCurrentLimitAO.VAL -pend=5] ]
        if {[lindex $beamList 0] > [lindex $beamList 1]} {return -code error "Error: Beam current exceeds beam limit, no injection possible."}
        #--- Setup injection cycle and bucket:
        if !$simulRun {exec cavput -list=Mt:SRbunch000.VAL=0,Mt:SRinjectNumBunchesAO.VAL=1,Mt:SRinjectMaxCyclesAO.VAL=1 -pend=30}
    }
    #--- Collect nTrajAver measurements:
    set fileList ""
    for {set i 0} {$i < $nTrajAver} {incr i} {
        #--- Setup triggers:
        if $simulRun {
            SetStatus "Setup triggers..."
        } else {
            SetStatus "Setup triggers..."; update
            if [catch {SetupTrigger -mode $mode} result] {
                return -code error "SetupTrigger: $result"
            }
        }
        #--- Press "Inject" or MPS button:
        if {[string compare $mode "injection"] == 0} {
            set button Mt:SRinjectMultiBO.VAL
            SetStatus "Injecting beam..."
        } else {
            set button S:MPS:dumpBeamSQ
            SetStatus "Dumping beam..."
        }
        if $simulRun {
            SetStatus "cavput -list=$button=1"
        } else {
            exec cavput -list=$button=1
        }
        #--- Capture data:
        if !$simulRun {
            SetStatus "Waiting for triggers to discharge..."; update
            if [catch {WaitForTriggers} result] {
                after 1000
                if [catch {WaitForTriggers} result] {
                    return -code error "WaitForTriggers: $result"
                }
            }
            SetStatus "Collecting waveforms..."; update
            if [catch {exec sddswmonitor $wmonFile $outputFile.$i -steps=1 -scalars=$smonFile } result] {
                return -code error "sddswmonitor: $result"
            }
        }
        if [catch {ProcessInjectionTrajectory -dataFile $outputFile.$i -plane $plane -mode $mode} result] {
            SetStatus "ProcessInjectionTrajectory: $result"
            SetStatus "Continue measurements..."
        }
        lappend fileList $outputFile.$i
    }
    #--- Combine files and average:
    if {[llength $fileList] == 1} {
        exec sddsprocess $fileList $outputFile -reprint=para,Plane,$plane -redef=para,NTrajectories,$nTrajAver,type=long
    } else {
        eval exec sddscombine $fileList -pipe=out \
          | sddsenvelope -pipe -copy=Index -mean=*position,*sum -stand=*position,*sum \
          | sddsconvert -pipe -edit=col,*Mean,%@Mean@@ \
          | sddsxref -pipe [lindex $fileList 0] -leave=* -transfer=par,* \
          | sddsprocess -pipe=in $outputFile -reprint=para,Plane,$plane -redef=para,NTrajectories,$nTrajAver,type=long
    }
    #--- Creating trajectory and oscillation files:
    if [catch {ProcessInjectionTrajectory -dataFile $outputFile -plane $plane} result] {
        return -code error "ProcessInjectionFile: $result"
    }
}

#---------------------------------------------------------------------------------------

#--- Procedure from FPGABpmTurnHistory by H. Shang, adapted
proc LoadRAM {args} {
    global fpgaSectorList logDir scalarList plane
    APSParseArguments {plane mode}
    set SCRdir /home/helios/oagData/SCR/snapshots/SBPMWaveform
    set logFile /tmp/[APSTmpString]
    switch -exact $mode {
        singleBunch {
            set refFile SBPMWaveform-singleBunch.gz
        }
        24singlets {
            set refFile SBPMWaveform-24singlets.gz
        }
        measurement {
            switch -exact $plane {
                X {set refFile SBPMWaveform-singleX.gz}
                Y {set refFile SBPMWaveform-singleY.gz}
                XY {set refFile SBPMWaveform-singleXYadt.gz}
            }
        }
    }
    #--- Make monitor files if mode=measurement:
    if {[string compare $mode measurement] == 0} {
        #--- Make wmonitor files:
        if {[string compare $plane "XY"] == 0} {
            set bpmPlaneList [list X Y Y X Y Y X]
        } else {
            set bpmPlaneList [list $plane $plane $plane $plane $plane $plane $plane]
        }
        foreach sector $fpgaSectorList {
            foreach bpm [list A:P2 A:P3 A:P4 B:P5 B:P4 B:P3 B:P2] bpmPlane $bpmPlaneList {
                lappend columnList S${sector}${bpm}:turnHistorySmall:${bpmPlane}position
                lappend columnList S${sector}${bpm}:turnHistorySmall:${bpmPlane}sum
            }
        }
        set wmonFile $logDir/fpga.wmon
        set smonFile $logDir/fpga.mon
        exec sddsmakedataset $wmonFile \
          -para=WaveformLength,type=long -data=4096 \
          -col=WaveformName,type=string -data=[join $columnList ,] \
          -col=WaveformPV,type=string -data=[join $columnList ,]
        exec sddsmakedataset $smonFile \
          -col=ControlName,type=string -data=[join $scalarList ,]
    }
    #---
    set filename [file readlink $SCRdir/$refFile]
    set restoreError 0
    if [catch {APSSCRLogAction -file $refFile -action restore-start} result] {
        SetStatus "$result"
    }
    if [catch {exec sddscasr $filename -restore -logFile=$logFile -pendIOTime=100 \
                 -waveform=directory=$SCRdir,onefile,rootname=[file rootname [file tail $filename]],extension=.waveform.gz } result] {
        SetStatus "Error in loading $refFile to iocs: $result"
        set restoreError 1
    }
    set fd [open $logFile "r"]
    while {![eof $fd]} {
        set text [gets $fd]
        if {[string match -nocase "*error*" $text]} {
            set restoreError 1
            break
        }
    }
    close $fd
    if $restoreError {
        APSFileDisplayWindow [APSUniqueName .fileDisp] -fileName $logFile \
          -comment "Error output from burtwb" -deleteOnClose 1 \
          -printCommand "enscript -r"
    } else {
        SetStatus "done."
    }
}

#---------------------------------------------------------------------------------------

proc SetupTrigger {args} {
    global fpgaSectorList
    set mode ""
    APSParseArguments {mode}
    set selectedIOCList ""
    foreach sector $fpgaSectorList {lappend selectedIOCList S${sector}A S${sector}B}
    set postTrigger 260144
    #--- Set postrigger for all IOCs
    if [catch {exec cavput -list=[join $selectedIOCList ,] -list=:turn:gtr:numberPTS=$postTrigger -pend=30} result] {
        return -code error "Error setting up trigger(4): $result" 
    }
    #--- Set trigger to event and arm it
    if [catch {exec cavput -list=[join $selectedIOCList ,] \
                 -list=:turn:gtr:trigger=event,:turn:gtr:arm=1 -pend=30} result] {
        return -code error "Error setting up trigger(1): $result"
    }
    #--- Disable/enable required triggers
    if {[string compare dump $mode] == -1} {
        #--- Injection
        if [catch {exec cavput -list=[join $selectedIOCList ,] \
                     -list=:clientEvent2d.OUT4=Disabled,:clientEvent2d.OUT5=Enabled,:clientEvent33.OUT4=Disabled \
                     -pend=30} result] {
            return -code error "Error setting up trigger(2): $result"
        }
    } else {
        #--- MPS bump
        if [catch {exec cavput -list=[join $selectedIOCList ,] \
                     -list=:clientEvent2d.OUT4=Disabled,:clientEvent2d.OUT5=Disabled,:clientEvent33.OUT4=Enabled \
                     -pend=30} result] {
            return -code error "Error setting up trigger(2): $result"
        }
    }
}

#---------------------------------------------------------------------------------------

proc RunEfficiencyScan {args} {
    APSParseArguments {steps closedBumpFile onAxisFile outputFile average}
    if [file exists $outputFile] {
        return -code error "Error: File $outputFile exists!"
    }
    if {![file exists $closedBumpFile]} {
        return -code error "Error: File $closedBumpFile does not exist."
    }
    if {![file exists $onAxisFile]} {
        return -code error "Error: File $onAxisFile does not exist."
    }
    SetStatus "Kicker Efficiency scan is started."
    set command "/home/helios/SR/bin/kickerScan -output $outputFile -points $steps -scanMode 1D -mode Efficiency -closedBumpFile $closedBumpFile -onAxisFile $onAxisFile"
    if [catch {APSExecLog .locoFitting \
                 -lineLimit 2048 -width 120 \
                 -name "Kicker scan..." \
                 -unixCommand $command} pid] {
        APSSetVarAndUpdate status "Error running locoFitting: $pid"
    }
}

#---------------------------------------------------------------------------------------

proc RunAmplitudeScan {args} {
    APSParseArguments {steps closedBumpFile onAxisFile outputFile average}
    if [file exists $outputFile] {
        return -code error "Error: File $outputFile exists!"
    }
    if {![file exists $closedBumpFile] || ![file exists $onAxisFile]} {
        return -code error "Error: Files $closedBumpFile or $onAxisFile do not exist."
    }
    SetStatus "Kicker Amplitude scan is started."
    set command "/home/helios/SR/bin/kickerScan -scanMode 1D -output $outputFile -points $steps -mode Amplitude \
		   -closedBumpFile $closedBumpFile -onAxisFile $onAxisFile -average $average"
    if [catch {APSExecLog .kickerScan \
                 -lineLimit 2048 -width 120 \
                 -name "Kicker scan..." \
                 -unixCommand $command} pid] {
        APSSetVarAndUpdate status "Error running kciker scan: $pid"
    }
}

#---------------------------------------------------------------------------------------

proc SavePulsed {args} {
    global scriptDir
    set logDir .
    set saveFile ""
    APSParseArguments {logDir saveFile}
    if [file exists $logDir/$saveFile] {
        return -code error "File $logDir/$saveFile already exists!"
    }
    exec burtrb -f $scriptDir/pulsedPS.req -o $logDir/$saveFile
    SetStatus "File $logDir/$saveFile written."
    return
}

#---------------------------------------------------------------------------------------

proc plotProgress {args} {
    set logDir .
    APSParseArguments {logDir mode}
    switch $mode {
        closedBumpX -
        closedBumpXY -
        onAxisX {
            set varList [list S:IK3:VoltageSetSendAO S:IK4:VoltageSetSendAO]
        }
        onAxisY {
            set varList [list BTS:BV1:CurrentAO BTS:CV1:CurrentAO]
        }
        default {
            set varList [list S:IK3:VoltageSetSendAO S:IK4:VoltageSetSendAO]
        }
    }
    exec sddsplot $logDir/$mode.optLog \
        -col=EvalIndex,([join $varList ,]) \
        -ylabel=edit=2%/:VoltageSetSendAO//2%/:CurrentAO// \
        -grap=line,vary -alignzero=yfactor -leg=edit=%/:VoltageSetSendAO//%/:CurrentAO// \
        -col=EvalIndex,currentValue  \
        -grap=line,vary -alignzero=yfactor -leg \
        -yscale=id=eval -uns=y \
        &
    if [catch {exec sddsprocess $logDir/$mode.optLog -pipe=out \
                 -process=currentValue,spread,%sSpread \
                 | sdds2stream -pipe=in -para=currentValueSpread } spread] {
        set status "Error: plotProgress: $spread"
        return
    } 
    exec sddsplot $logDir/$mode.optLog \
      -col=[join [lrange $varList 0 1] ,] \
      -ylabel=edit=%/:VoltageSetSendAO//%/:CurrentAO// \
      -xlabel=edit=%/:VoltageSetSendAO//%/:CurrentAO// \
      -grap=sym,thick=10,vary=subtype \
      -split=column=currentValue,width=[expr $spread / 16.0] \
      -order=spectral \
      &
}

#---------------------------------------------------------------------------------------

proc SetStatus {text} {
    global status
    set status $text
}

#---------------------------------------------------------------------------------------

proc EqualizeIK23 {} {
    if [catch {exec cavget -list=S:IK -list=2,3 \
                 -list=:VoltageSetSendAO  "-delimiter= " -pend=5 \
             } IKvals ] {
        return -code error $IKvals
    }
    set IKave [expr ([lindex $IKvals 0] + [lindex $IKvals 1] ) / 2.0 ]
    if [catch {exec cavput -list=S:IK -list=2 \
                 -list=:VoltageSetSendAO=$IKave \
                 -pen=5
        exec cavput -list=S:IK -list=3 \
                 -list=:VoltageSetSendAO=$IKave \
                 -pen=5 \
             } result ] {
        return -code error $result
    }
    SetStatus "Kickers IK2 IK3 equalized."
    return
}

#---------------------------------------------------------------------------------------

proc OptimizeKickersSmartly {args} {
    APSParseArguments {logDir average fraction mode iterations}
    
    APSExecLog .optimize \
      -lineLimit 2048 -width 90 \
      -name "On axis optimization" \
      -unixCommand "optimizeKickersSmartly -nIterations $iterations \
                      -logDir $logDir -stored 0 -average $average -doSetup 1 -fraction $fraction -mode $mode -verbose 0 -stored 0"
}

#---------------------------------------------------------------------------------------

proc runOptimize {args} {
    global scriptDir execPath
    set logDir .
    APSParseArguments {logDir average mode method}
    
    set varFile $logDir/var.$mode
    set restarts 1
    set kickerPVList [list S:IK3:VoltageSetSendAO S:IK4:VoltageSetSendAO]
    set kickerLowerList [list 0 0]
    set kickerUpperList [list 11 15]
    set kickerInitialChangeList [list 0.2 0.2]
    #    set bpmPVList [list S39B:P5:ms:y:SetpointAO S39B:P1:ms:y:SetpointAO S40A:P1:ms:y:SetpointAO S40B:P5:ms:y:SetpointAO]
    set bpmPVList [list S39B:P5:ms:y:SetpointAO S39B:P2:ms:y:SetpointAO S40A:P1:ms:y:SetpointAO S40B:P5:ms:y:SetpointAO]
    set bpmInitialChangeList [list 0.1 0.1 0.1 0.1]
    set skewPVList [list S39A:QS:CurrentAO S39A:QS4:CurrentAO S40A:QS4:CurrentAO]
    set skewInitialChangeList [list 0.5 2 2]
    set skewInitialChangeList [list 1.0 4 4]
    set skewLowerLimitList [list -10 -100 -100]
    set skewUpperLimitList [list 10 100 100]
    set pauseBetweenReadings 0
    switch -exact $mode {
        closedBumpX {
            set injection 0
            set plane X
            set actionPVList $kickerPVList
            set lowerLimitList $kickerLowerList
            set upperLimitList $kickerUpperList
            set initialChangeList $kickerInitialChangeList
            set spreadMode std
        }
        closedBumpY {
            set injection 0
            set plane Y
            set actionPVList $bpmPVList
            set setpointList [exec cavget -list=[join $bpmPVList ,] -pend=5]
            set lowerLimitList ""
            set upperLimitList ""
            foreach setpoint $setpointList {
                lappend lowerLimitList [expr $setpoint - 1.0] 
                lappend upperLimitList [expr $setpoint + 1.0] 
            }
            set initialChangeList $bpmInitialChangeList
            set spreadMode max
        }
        closedBumpXY {
            if 0 {
                set injection 0
                set plane XY
                set actionPVList [concat $kickerPVList $bpmPVList]
                set setpointList [exec cavget -list=[join $bpmPVList ,] -pend=5]
                set lowerLimitList $kickerLowerList
                set upperLimitList $kickerUpperList
                foreach setpoint $setpointList {
                    lappend lowerLimitList [expr $setpoint - 1.0] 
                    lappend upperLimitList [expr $setpoint + 1.0] 
                }
                set initialChangeList [concat $kickerInitialChangeList $bpmInitialChangeList]
                set spreadMode std
            }
            set injection 0
            set plane Y
            set actionPVList $skewPVList
            set setpointList [exec cavget -list=[join $skewPVList ,] -pend=5]
            set lowerLimitList $skewLowerLimitList
            set upperLimitList $skewUpperLimitList
            set initialChangeList $skewInitialChangeList
            set spreadMode max
            #--- Skew quads are slooooow
            set pauseBetweenReadings 5
        }
        onAxisX {
            set injection 1
            set plane X
            set actionPVList $kickerPVList
            set lowerLimitList $kickerLowerList
            set upperLimitList $kickerUpperList
            set initialChangeList $kickerInitialChangeList
            set spreadMode std
        }
        onAxisY {
            # Somehow the y-BTS controllaw must be suspended for this to work.
            # For now, suspend manually.
            set injection 1
            set plane Y
            set actionPVList [list BTS:BV1:CurrentAO BTS:CV1:CurrentAO]
            set setpointList [exec cavget -list=[join $actionPVList ,] -pend=5]
            set lowerLimitList ""
            set upperLimitList ""
            foreach setpoint $setpointList {
                lappend lowerLimitList [expr $setpoint - 4.0] 
                lappend upperLimitList [expr $setpoint + 4.0] 
            }
            set initialChangeList [list 0.5 0.5]
            set spreadMode max
        }
    }
    exec sddsmakedataset $varFile \
      -para=pauseBetweenReadings,type=double -data=$pauseBetweenReadings \
      -col=ControlName,type=string -data=[join $actionPVList ,] \
      -col=LowerLimit,type=double -data=[join $lowerLimitList ,] \
      -col=UpperLimit,type=double -data=[join $upperLimitList ,] \
      -col=InitialChange,type=double -data=[join $initialChangeList ,]
    
    #--- Initial setup of kickers and bpms:
    if [catch {exec $execPath/setupKickersAndBpms -kickerList "IK1 IK2 IK3 IK4" \
                 -waveformMode short -injection $injection} result] {
        return -code error "$execPath/setupKickersAndBpms: $result"
    }
    switch -exact $method {
        1 {
            APSExecLog .optimize \
              -lineLimit 2048 -width 90 \
              -name "Injection optimization" \
              -unixCommand "sddsoptimize \
                     \"-measScript=/home/helios/SR/bin/findHistorySpread_fpga -average $average -injection $injection -plane $plane -spreadMode $spreadMode\" \
                     -varFile=$varFile  -tolerance=0.01 \
                     -simplex=restarts=$restarts,cycles=1,evaluations=50,no1dscan \
                     -testValues=file=$scriptDir/tests_fpga,limit=3 \
                     -target=0.0 -verbose \
                     -logFile=$logDir/$mode.optLog"
        }
        3 {
            APSExecLog .optimize \
              -lineLimit 2048 -width 90 \
              -name "Injection optimization" \
              -unixCommand "sddsoptimize \
                     \"-measScript=/home/helios/SR/bin/readEffic -pulses $average -enableInjection 1\" \
                     -varFile=$varFile  -tolerance=0.01 \
                     -simplex=restarts=$restarts,cycles=1,evaluations=50,no1dscan \
                     -testValues=file=$scriptDir/tests_fpga,limit=5 \
                     -target=1.0 -verbose -maximize \
                     -logFile=$logDir/$mode.optLog"
        }
    }
}

#---------------------------------------------------------------------------------------

set scriptDir /home/helios/oagData/sr/optimizeScripts/closedBump
set execPath /home/helios/SR/bin
set logDir .
set sector39L 1076.4
set sectorL 27.6
set circum 1104
set sextParamFile ""

set IK1Closed 8.0
set IK34Closed ""
set averageClosed 1
set saveFileClosed closedBump01.snp
set ik1StartClosed 8.0
set ik1EndClosed 9.0
set ik1StepsClosed 5
set ik1filenameClosed ik1scan01.sdds

set IK1Onaxis 12.0
set IK34Onaxis ""
set averageOnaxis 1
set saveFileOnaxis onAxis01.snp
set methodOnaxis 1
set fractionOnaxis 0.75
set iterationsOnaxis 5

set scanSteps 15
set scanClosedFile closedBump01.snp
set scanOnaxisFile onAxis01.snp
set averageKickerScan 1
set scanOutputFile kickerScan01.sdds

set IK1SepScan 12.0
set sepScanSteps 7
set stepSizeSepScan 1.0
set averageSepScan 10
set sepScanOutputFile septumScan01.sdds

set IK1Traj 12.0
set outputFileRoot injection
set fileIndex -1
set nTrajAver 1
set planeClosed X
set planeOnaxis X
set planeTraj X
set sectorRangeTraj "1 26"

set outputFileRootDump beamDump
set fileIndexDump -1
set turn0Dump 2000
set turnRangeDump "-100 0"
set planeDump X

set kickerWaveformRootname kickerWfrm
set kickerWaveformIndex -1

set fpgaSectorList [list 40 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 \
                      25 26 27 28 29 30 31 32 33 34 35 36 37 38 39]
set bpmList [list A:P2 A:P3 A:P4 B:P5 B:P4 B:P3 B:P2]
set scalarList [list S:IK1:VoltageSetSendAO S:IK2:VoltageSetSendAO \
                  S:IK3:VoltageSetSendAO S:IK4:VoltageSetSendAO S:IS1:VoltageSetSendAO S:IS2:VoltageSetSendAO]
set timingShiftSector 28.5
set turn0 2096

set IK1PEScan 12.0
set stepNumberPEScan 7
set averagePEScan 1
set readEfficPEScan 0
set outputFilePhaseScan phaseScan01
set outputFileEnergyScan energyScan01
set stepSizePhaseScan 3
set stepSizeEnergyScan 0.1
set stepSizeFreqScan 10
set outputFileFreqScan freqScan01

set simulRun 0

set status "Working."
APSScrolledStatus .status -parent .userFrame -textVariable status -width 90

APSFrame .frame0 -parent .userFrame -label "" \
  -contextHelp "Common settings"
set w .userFrame.frame0.frame
APSLabeledEntry .logDir -parent $w -width 60 \
  -textVariable logDir \
  -label "Output directory:" \
  -contextHelp "Directory for all output."
APSButton .daily -parent $w.logDir -packOption "-anchor e" \
  -text "daily" -size small \
  -command {set logDir [APSGoToDailyDirectory -subDirectory .]}

APSButton .rtfb  -parent $w -text "Enable septum FF/rtfb" \
  -command {
      set status "Closing loops..."
      update
      #--- Set X gain to 0 and FB block to override:
      exec cavput -list=SRFB:KpSlAO=0,SRFB:KpAO=0,SRFB:GBL:BlockOverrideBO.VAL=1
      after 1000
      #--- Press "Load" button on medm screen
      exec cavput -list=SRFB:GBL:loadBO=1
      after 1000
      #--- Press "Close Selected Loops" on SRFBControl (values from /home/helios/oagData/sr/rtfeedback/parameterFiles/srfb-default.param):
      if [catch {APSMpRTFBCloseLoops -hpFilterCutoffVert 0.07 \
                   -hpFilterCutoffHoriz 0.5 \
                   -hpFilterInitialVert 10 \
                   -hpFilterInitialHoriz 10 \
                   -hpFilterRampPoints 20 \
                   -hpFilterRampInterval 2 \
                   -statusCallback "set status"} result] {
          set status "APSMpRTFBCloseLoops: $result"
          return
      } else {
          set status "RTFB enabled."
          update
      }
  } -contextHelp "Sets RTFB gains to zero, enables low-current override, loads RTFB parameters, closes loops."

set widgetList [APSTabFrame .tab -parent .userFrame -label ""  \
                  -labelList {"Closed bump" "RF Phase or Booster Energy scan" "Septum scan" "On axis" "Kicker scan" \
                                "Injection trajectory" "Kicker waveforms" "Beam dump"} \
                  -width  950 -height 450]

MakeActionWidget1 .action1 -parent [lindex $widgetList 0]
MakeActionWidget5 .action5 -parent [lindex $widgetList 1]
MakeActionWidget6 .action6 -parent [lindex $widgetList 2]
MakeActionWidget2 .action2 -parent [lindex $widgetList 3]
MakeActionWidget3 .action3 -parent [lindex $widgetList 4]
MakeActionWidget4 .action4 -parent [lindex $widgetList 5]
MakeActionWidget7 .action7 -parent [lindex $widgetList 6]
MakeActionWidget8 .action8 -parent [lindex $widgetList 7]

MakeActionWidgetLow .actionLow -parent .userFrame

set status "Ready."

# Local Variables:
# mode: tcl
# End:
