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

#
# $Log: not supported by cvs2svn $
# Revision 1.10  2006/09/21 20:26:51  soliday
# Updated because of PV name changes.
#
# Revision 1.9  2006/03/14 20:18:48  shang
# removed Get lattice button.
#
# Revision 1.8  2006/03/14 20:11:53  shang
# added offset to the injection time and extraction time, so that the first and last point
# in the time table are no longer right at the injection or extraction.
#
# Revision 1.7  2003/02/26 17:00:43  shang
# tested and added more ploting features
#
# Revision 1.6  2002/12/14 02:59:27  sereno
# Added arbitrary ramp points file input as well as calculated orbit from
# corrector changes plots.
#
# Revision 1.5  2002/11/18 16:40:26  shang
# made more changes
#
# Revision 1.4  2002/10/11 20:55:09  shang
# fixed a bug in ZeroOffsetAndSetpoint proc
#
# Revision 1.3  2002/10/11 19:11:00  shang
# removed "bell" from SetMainStatus
#
# Revision 1.2  2002/10/07 17:03:42  soliday
# Restored the auto_path to the correct value.
#
# Revision 1.1  2002/10/04 22:58:05  shang
# first version of booster orbit correction
#
# first version, shang

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

set CVSRevisionAuthor "\$Revision: 1.11 $ \$Author: soliday $"

APSApplication . -name "BoosterOrbitCorrection" -version $CVSRevisionAuthor \
  -overview "BoosterOrbitCorrection provides convenience controls for correcting booster orbit."

set SROrbitStatus "Initializing ..."
APSScrolledStatus .status -parent .userFrame -width 60 \
  -textVariable SROrbitStatus 

proc SetMainStatus {text} {
    global SROrbitStatus
    set SROrbitStatus $text
    update
}

set NinjectionOffset 256
proc MakeOptionFrame {widget args} {
    global steps gain interval averages averageInterval PVSuffix lattice
    global Ninjection Nextraction Einjection Eextraction M AutoLoad PlotData  NPoints
    APSParseArguments {parent}

    APSFrame $widget -parent $parent -label "BoosterOrbitCorrection options" \
      -contextHelp "Frame to specify arguments for booster orbit correction."
    set w0 $parent$widget.frame
    APSFrameGrid .fg -parent $w0 -xList {x1 x2}
    set w1 $w0.fg.x1
    set w2 $w0.fg.x2
    APSLabeledEntry .steps -parent $w1 -label "steps" \
      -textVariable steps -width 10 \
      -contextHelp "Enter the number of steps to perform."
    APSLabeledEntry .gain -parent $w1 -label "gain" \
      -textVariable gain -width 10 \
      -contextHelp "Enter the gain (i.e. fraction of correction at each interval)"
    APSLabeledEntry .interval -parent $w1 -label "interval (s)" \
      -textVariable interval -width 10 \
      -contextHelp "Enter the interval between correction steps."
    # APSLabeledEntry .offset -parent $w1 -label "Injection turns offset (N)" \
    #  -textVariable NinjectionOffset -width 10 \
   #   -contextHelp "Enter offset in ms for injection time."
   # APSLabeledOutput .nInjection -parent $w1 -label "injection turns(N)" \
   #   -textVariable Ninjection -width 10 \
   #   -contextHelp "Enter the turns of injection."
   # APSLabeledOutput .nExtraction -parent $w1 -label "extraction turns(N)" \
   #   -textVariable Nextraction -width 10 \
   #   -contextHelp "Enter the turns of extraction"
    
  #  APSLabeledEntry .nlist -label "Ramp time points: " -width 10 -parent $w1 -textVariable NPoints \
  #    -contextHelp "Please enter the number of ramp time points \n\
#(including the injection and extraction, which is 2 for default \n\
#   The ramp time will be evenly distributed between the injection and extraction"
    
    
    APSLabeledEntry .averages -parent $w2 -label "averages" \
      -textVariable averages -width 10 \
      -contextHelp "Enter the number of averages of bpms at each iteration."
    APSLabeledEntry .averageInterval -parent $w2 -label "interval in averaging" \
      -textVariable averageInterval -width 10 \
      -contextHelp "Enter the interval between readbacks for the bpm averaging."
    #APSLabeledEntry .m -parent $w2 -label "M:" \
    #  -textVariable M -width 10 \
    #  -contextHelp "Enter the value for M."
    #APSLabeledEntry .eInjection -parent $w2 -label "injection energy(Mev)" \
    #  -textVariable Einjection -width 10 \
    #  -contextHelp "Enter the injection energy(Mev)."
    #APSLabeledEntry .eExtraction -parent $w2 -label "extraction energy(Mev)" \
    #  -textVariable Eextraction -width 10 \
    #  -contextHelp "Enter the extraction energy(Mev)"

    # APSFrame .check -parent $w0
    # set w2 $w0.check.frame
    global lattice
   # APSRadioButtonFrame .pvSuffix -parent $w1 -label "bpm processing" \
   #   -variable PVSuffix -valueList {ms scdu} \
   #   -buttonList {ms scdu} -orientation horizontal -contextHelp \
   #   "Select the memory/scanner PV type (i.e. bpm data type)."
    APSLabeledOutput .lattice -parent $w2 -label "lattice"  \
	-textVariable lattice -width 20 -contextHelp "display the linked lattice"
    APSRadioButtonFrame .plot -parent $w2 -label "Plot data:" \
	-variable PlotData -valueList {1 0} \
	-buttonList {Yes No} -orientation horizontal -contextHelp \
	"choose to plot the corrector values or not"
   # APSRadioButtonFrame .load -parent $w2 -label "Auto loading:" \
#	-variable AutoLoad -valueList {1 0} \
#	-buttonList {Yes No} -orientation horizontal -contextHelp \
#	"Auto loading: Yes--automatically load the ramp table created at each step. No- do not load"
    
   # APSButton .get -parent $w2.lattice -text "Get" -command "GetLattice" \
#	-contextHelp "Press to obtain the lattice linked by default"
}

proc MakeFileFrame {widget args} {
    global hResponseDir vResponseDir hRampTable vRampTable rampDir lattice rampDataDir
    global PVSuffix 
    global plane
    global SensitiveWidgetList
    global dataDir hRampDir vRampDir
    APSParseArguments {parent}

    set w $parent$widget.frame
    APSFrame $widget -parent $parent -label "Configuration" \
      -contextHelp "Frame to specify additional options, such as the directory of the response file, the type of bpm data, validity ranges for the sddscontrollaw tests file."

    set widgetList [APSTabFrame .planes -parent $parent$widget.frame -label "" \
                      -labelList "Horizontal Vertical" -width 600 -height 130 \
                      -commandList {{setCorrPlane H} {setCorrPlane V}} ]

    pack $parent$widget.frame.planes -side top
    $parent$widget.frame.planes.frame.tn select 0
    lappend SensitiveWidgetList $parent$widget.frame.planes.frame.tn
    set windex 0

    set configWidth 41
    set loadWidth 43
    # Horizontal Response Directory
    set tabwidget [lindex $widgetList $windex]
    incr windex
    APSFrame .dir -parent $tabwidget -label "" \
      -contextHelp "Frame to specify directories in which files related to horizontal plane correction are found."
    set w $tabwidget.dir.frame
    APSLabeledEntry .responseDir -parent $w -label "Configuration" \
      -textVariable hResponseDir -width $configWidth -contextHelp \
      "Name of the directory for the response file for the HORIZONTAL plane which can be used with sddscontrollaw."
    APSButton .install -parent $w.responseDir \
      -text D -size small -packOption "-side right" \
      -command "InstallFile -link h.default -fileVariable hResponseDir" \
      -contextHelp "make the choosed directory as h.default."
    APSButton .dir -parent $w.responseDir \
      -text P -size small -packOption "-side right" \
      -command "findDir -dirVariable hResponseDir -filter h.*" \
      -contextHelp "Bring up a directory selection dialog box to choose the directory."

    #create load ramp table frame
    APSFrame .ramp -parent $tabwidget -label "" \
      -contextHelp "Frame to choose ramptable and load it."
    set w $tabwidget.ramp.frame
    APSFileSelectWidget .table -parent $w -mode file \
          -label "Ramp Table:" -width $loadWidth \
          -variable hRampTable -filter h* \
          -pathVariableList [list rampDataDir hRampDir] \
          -contextHelp \
          "enter the name of ramptable for h plane."
    APSButton .default -parent $w.table -text L -size small \
          -contextHelp "load the choosed ramp table" \
          -command "LoadBoosterRampTable -plane h -fileVariable hRampTable -rampDirVar hRampTableDir"

    # Vertical Response Directory
    set tabwidget [lindex $widgetList $windex]
    incr windex
    APSFrame .dir -parent $tabwidget -label ""  \
      -contextHelp "Frame to specify directories in which files related to vertical plane correction are found."

    set w $tabwidget.dir.frame
    APSLabeledEntry .responseDir -parent $w -label "Configuration" \
      -textVariable vResponseDir -width $configWidth -contextHelp \
      "Name of the directory for the response file for the VERTICAL plane which can be used with sddscontrollaw."
    APSButton .install -parent $w.responseDir \
      -text D -size small -packOption "-side right" \
      -command "InstallFile -link v.default -fileVariable vResponseDir" \
      -contextHelp "make the choosed directory as v.default."
    APSButton .dir -parent $w.responseDir \
      -text P -size small -packOption "-side right" \
      -command "findDir -dirVariable vResponseDir -filter v.*" \
      -contextHelp "Bring up a directory selection dialog box to choose the directory."
    
    #create load ramp table frame
    APSFrame .ramp -parent $tabwidget -label "" \
      -contextHelp "Frame to choose ramptable and load it."
    set w $tabwidget.ramp.frame
    APSFileSelectWidget .table -parent $w -mode file \
          -label "Ramp Table:" -width $loadWidth \
          -variable vRampTable -filter v* \
          -pathVariableList [list rampDataDir vRampDir] \
          -contextHelp \
          "enter the name of ramptable for v plane."
    APSButton .default -parent $w.table -text L -size small \
          -contextHelp "load the choosed ramp table" \
          -command "LoadBoosterRampTable  -plane v -fileVariable vRampTable -rampDirVar vRampTableDir"
    
    set w $parent$widget.frame
    global NFile NPoints InputRampTable  
    APSLabeledEntry .inputramp -label "Ramp Table for cal. orbit:" -textVariable InputRampTable \
      -contextHelp "Input the ramp table for calculating the predicted orbit." -width 50 -parent $w
    APSButton .select -parent $w.inputramp -text "select" -packOption "-side left" \
      -command "SelectRampTable" \
      -contextHelp "press to select a ramptable for calculating the predicted orbit."
    return 0
}

proc SelectRampTable {} {
    global InputRampTable env    
    set listDir $env(HOME)/daily
    set InputRampTable [APSFileSelectDialog .chooseInputFile -listDir $listDir]
}
proc InstallFile {args} {
    set fileVariable ""
    set link ""
    APSParseArguments {fileVariable link}
    if ![string length $fileVariable] {
        return -code error "InstallFile: No fileVariable supplied."
    }
    if ![string length $link] {
        return -code error "InstallFile: No link supplied."
    }
    global $fileVariable
    set file [set $fileVariable]
    if [catch {APSMakeLink -filename $file -linkname $link} result] {
        SetMainStatus "$result"
        return
    }
    set $fileVariable $link
    
    return
}


proc MakeActionWidget {widget args} {
    global Plane plane coord Coord brief
    
    APSParseArguments {parent}

    APSFrame $widget -parent $parent \
      -contextHelp "Frame for containing action buttons."
    set w $parent$widget.frame
    $w configure -relief flat
    APSFrame .y1 -parent $parent$widget.frame \
      -contextHelp "Frame for containing action buttons."
    APSFrame .y2 -parent $parent$widget.frame \
      -contextHelp "Frame for containing action buttons."
    
    set w $parent$widget.frame.y1.frame
    $w configure -relief flat
    APSButton .compute -parent $w -text "ComputeTimeTable" \
        -command "ComputeTimeAndEnergy"
    APSButton .start -parent $w -text START -command \
	"APSFreezeVars [list Plane plane coord Coord]; DisableTabs; ChangeButtonState 0; CorrectorBoosterOrbit; APSUnfreezeVars [list Plane plane coord Coord]; EnableTabs; ChangeButtonState 1" \
	-contextHelp "Generates new tests files if necessary, send the appropriate averaging parameters to the bpms IOCs if necessary, and starts a sddscontrollaw command with the options specified."   
    APSButton .abort -parent $w -text "ABORT" -command "AbortOrbitCorrection" 
    APSButton .orbit -parent $w -text "GET CALCULATED ORBIT" -command "CalculatePredictOrbit" \
      -contextHelp "Obtain and plot the calculated orbit from the previous calculated ramp table."

    set w $parent$widget.frame.y2.frame
    $w configure -relief flat
    APSButton .offset -parent $w -text "ZERO OFFSET" -command \
	"APSFreezeVars [list Plane plane coord Coord]; DisableTabs;ChangeButtonState 0;  ZeroOffsetAndSetpoint -type OffsetAO; APSUnfreezeVars [list Plane plane coord Coord]; EnableTabs; ChangeButtonState 1" \
	-contextHelp "presse to set the offsets of thebpms in choosed config file to zero."
    APSButton .setpoint -parent $w -text "ZERO SETPOINT" -command \
	"APSFreezeVars [list Plane plane coord Coord]; DisableTabs;ChangeButtonState 0;  ZeroOffsetAndSetpoint -type SetpointAO; APSUnfreezeVars [list Plane plane coord Coord]; EnableTabs; ChangeButtonState 1" \
	-contextHelp "presse to set the setpoints of thebpms in choosed config file to zero."

    APSButton .get -parent $w -text "GET OFFSET AND SETPOINT" -command "GetOffsetAndSetpoint"
}

proc setCorrPlane {value} {
    global Plane plane Coord coord
    if ![string compare [string toupper $value] "H"] {
        set Plane H
        set plane h
        set coord x
        set Coord X
    } else {
        set Plane V
        set plane v
        set coord y
        set Coord Y
    }
    SetMainStatus "$Plane Plane selected."
    return
}

# **************************** findDir ********************************
proc findDir {args} {
    # General purpose directory selection
    # args is passed to APSFileSelectDialog
    set dirVariable ""
    set trim 0
    APSParseArguments {dirVariable trim}
    global $dirVariable

    set dirName [eval dirSelectDialog [APSUniqueName .] $args]
    if [string length $dirName] {
        # Trim the current working directory from the name
        if $trim {
            set dirName [file tail $dirName]
        }
        set $dirVariable $dirName
    }
    update
}

proc dirSelectDialog {widget args} {
    global dirSelection
    set filter ""
    APSParseArguments {filter}
    if [string length $filter] {
        set dirList [lsort -decreasing [glob -nocomplain $filter]]
    } else {
        set dirList [lsort -decreasing [glob -nocomplain *]]
    }
    APSScrolledListWindow $widget \
      -name "Directory selection" \
      -label "Select a directory" \
      -itemList $dirList \
      -selectionVar dirSelection
    tkwait variable dirSelection
    return $dirSelection
}

proc DisableTabs {} {
    global SensitiveWidgetList
    foreach widget $SensitiveWidgetList {
        $widget configure -state disabled
    }
}

proc EnableTabs {} {
    global SensitiveWidgetList
    foreach widget $SensitiveWidgetList {
        $widget configure -state normal
    }
}


proc CorrectorBoosterOrbit {args} {
    global steps plane coord interval averages averageInterval PVSuffix rampDir rampDataDir Abort
    global hResponseDir vResponseDir dataDir twiss gain  hRampTable vRampTable SetpointDelta PlotData
    global Ninjection Nextraction Einjection Eextraction M lattice NFile corrList SetpointData
    global NValueList RampTimeList EnergyList PSCUSampleTimeList NPoints rampDataDir 
    if ![string length $PVSuffix] {
        SetMainStatus "no bpm PVSuffix electronics scdu | ms."
        cd $dataDir
        return
    }
    if {$averages<2} {
        SetMainStatus "Invalid average number given."
        cd $dataDir
        return
    }
    #make default link to the updated lattice
    set oldDir [pwd]
    set lattice [file readlink $dataDir]
    cd /home/helios/oagData/booster/orbitControllaw/lattices/rampRecord
    if ![file exist $lattice] {
        exec mkdir $lattice
    }
    # APSMakeLink -filename $lattice -linkname $rampDataDir/default
    cd $oldDir
    set rampDir $rampDataDir/default
    switch $coord {
        x {
            # T-m/A
            set calib 0.00136
            set config $hResponseDir
        }
        y {
            # T-m/A
            set calib 0.00113
            set config $vResponseDir
        }
    }
    cd $config
    if {![file exist config] || ![file exist irm]} {
        cd $oldDir
        SetMainStatus "config or irm (matrix) file does not exist!"
        return
    }
    SetMainStatus "working in $config dir"

    if [catch {exec sddsquery irm -sddsOutput -column \
                   | sddsprocess -pipe -match=col,Name=B?C?? \
                   -match=col,Units=m/rad,! -nowarning \
                   | sdds2stream -rows=bare -pipe} result] {
        cd $dataDir
        SetMainStatus "$result"
        return 
    }
    if $result!=0 {
        cd $dataDir
        SetMainStatus "$result"
        return 
    }

    if [catch {ComputeTimeAndEnergy} result] {
        cd $dataDir
        return -code error $result
    }
    set size [llength $NValueList]
    global hRampTableDir vRampTableDir hOrbitDir vOrbitDir
    set firstTime 1
    set rampTableDir [set ${plane}RampTableDir]
    set orbitDir [set ${plane}OrbitDir]
    set orbitFileList ""
    set corrFileList ""
    for {set step 0} {$step < $steps} {incr step} {
        if $Abort {
            set Abort 0
            SetMainStatus "Orbit correction aborted!"
            cd $dataDir
            return
        }
        foreach N $NValueList Energy $EnergyList time $RampTimeList pscu $PSCUSampleTimeList {
            # Get Orbit for a given N
            if $Abort {
                set Abort 0
                SetMainStatus "Orbit correction aborted!"
                cd $dataDir
                return
            }
            setTiming -N $N -M $M -pscu $pscu
            after 2000 
            if $Abort {
                set Abort 0
                SetMainStatus "Orbit correction orbited!"
                cd $dataDir
                return
            } 
            #read current 
            if [catch {GetRampSetpointData -firstTime $firstTime -time $time} result] {
                cd $dataDir
                return -code error $result
            }
            set firstTime 0
            SetMainStatus "Set N=${N}"
            # set lastOrbitFile [lindex [lsort [glob -nocomplain ${orbitDir}/Bbpm_${coord}_N${N}.????]] end]
            # if ![string length $lastOrbitFile] {
            #     set number 0000
            #     set bpm1 ${orbitDir}/Bbpm_${coord}_N${N}.$number
            # } else {
            #     set bpm1 [APSNextGenerationedName -name $lastOrbitFile -newFile 1 -separator .]
            #     regexp {([^.]*).(.+)} [file extension $bpm1] a n number
            # }
            # set bpm2 ${orbitDir}/BbpmD_${coord}_N${N}.$number
            # set corr ${orbitDir}/Corr_${coord}_N${N}.$number
            set tmpRoot /tmp/[APSTmpString]
            set bpm1 $tmpRoot.bpm1
            set bpm2 $tmpRoot.bpm2
            set corr $tmpRoot.corr
            APSAddToTmpFileList -ID CorrectBoosterOrbit -fileList \
                "$bpm1 $bpm2 $corr"
            update
            if [catch {exec sddsprocess config\
                           -match=par,NameType=MonitorNames -pipe=out  \
                           | sddsprocess -pipe \
                           -print=col,ControlName,%s:$PVSuffix:$coord:ErrorCC,Name \
                           | sddssnapshot -pipe \
                           -average=$averages,$averageInterval \
                           -nameOfData=$coord -unitsOfData=mm  \
                           | sddsconvert -pipe -retain=col,ControlName,$coord,Name \
                           | sddsprocess -pipe=in $bpm1 \
                           -match=column,ControlName=*:${PVSuffix}:${coord}* \
                           -print=par,config,$dataDir/$config \
                           "-redefine=param,M,256" \
                           "-redefine=param,N,${N}" \
                           "-redefine=param,RampTime,${time},units=ms" \
                           "-print=param,RampTimeString,%0.3f %s,RampTime,RampTime.units" \
                           "-redefine=column,$coord,$coord 1000 /,units=m" } result] {
                APSDeleteTmpFileList -ID CorrectBoosterOrbit
                cd $oldDir
                SetMainStatus "$result"
                return 
            }
            SetMainStatus "Got data"
            update
            #calculate deltaP for x plane
            if [string compare $coord x]==0 {
                APSAddToTmpFileList -ID BoosterOrbitCorrection -fileList "$bpm1.1"
                if [catch {eval exec sddsxref $bpm1 $twiss $bpm1.1 -nowarning \
                               -take=eta${coord} -match=Name=ElementName} result] {
                    APSDeleteTmpFileList -ID CorrectBoosterOrbit 
                    cd $oldDir
                    SetMainStatus "$result"
                    return 
                }
                set define1 "\"-define=par,deltaP,${coord}Sum eta${coord}Sum /\""
                set define2 "\"-define=col,delta${coord},deltaP eta${coord} *\""
                set define3 "\"-redefine=col,x,x delta${coord} -\""
                if [catch {eval exec sddsprocess $bpm1.1 -pipe=out \
                               -process=eta${coord},sum,eta${coord}Sum \
                               -process=${coord},sum,${coord}Sum \
                               | sddsprocess -pipe $define1 \
                               | sddsprocess -pipe $define2 \
                               | sddsprocess -pipe $define3 \
                               | sddsconvert -pipe=in $bpm2 \
                               -retain=col,Name,ControlName,$coord  \
                           } result] {
                    APSDeleteTmpFileList -ID CorrectBoosterOrbit
                    cd $oldDir
                    SetMainStatus "$result"
                    return 
                }
            } else {
                if [catch {exec sddsconvert $bpm1 $bpm2 -retain=col,Name,ControlName,$coord } result] {
                    APSAddToTmpFileList -ID CorrectBoosterOrbit -fileList $fileList
                    APSDeleteTmpFileList -ID CorrectBoosterOrbit
                    cd $oldDir
                    SetMainStatus "sddsconvert: $result"
                }
            }
            update
            # Multiply the inverse response matrix by the vector of bpm delta values
            if [catch {exec sddsmatrixmult irm $bpm2 -pipe=out \
                           | sddsprocess -pipe \
                           "-define=col,Value,$coord $Energy 299.79 / * $calib / 19 / $gain * -1 *,units=A/19" \
                           | sddsconvert -pipe -delete=col,$coord \
                           | sddsxref -pipe -take=Actuators irm \
                           | sddsprocess -pipe=in $corr \
                           -match=col,Actuators=etax,! \
                           "-redefine=param,M,256" \
                           "-redefine=param,N,${N}" \
                           "-redefine=param,RampTime,${time},units=ms" \
                           "-print=param,RampTimeString,%0.3f %s,RampTime,RampTime.units"} result] {

                cd $oldDir
                SetMainStatus "$result"
                return 
            }
            if $PlotData {
                exec sddsplot "-title=[clock format [clock seconds]]" -legend=param=RampTimeString \
                    -col=Name,*$coord $bpm2 \
                    "-topline=BPM Orbit Data at the RampTime Point" -end \
                    -column=Actuators,Value $corr \
                    "-topline=Normalized Corrector Data at the RampTime Point" &
            }
            set correctors [exec sdds2stream $corr -col=Actuators]
            set values [exec sdds2stream $corr -col=Value]
            foreach corr1 $correctors val $values {
                lappend SetpointDelta($corr1) $val
            }
            lappend corrFileList $corr
            lappend orbitFileList $bpm2
            update
        }
        update
        #save the setpoint data
        set tmpRoot /tmp/[APSTmpString]
        set output(Description.Text) "Corrector ramps"
        set output(Description.Contents) "booster ramp"
        set output(ParameterNames) "ControlName ControlType RampBias CorrName CorrCurrentAO RefMatrix Gain Calibration"
        set output(ParameterInfo.RefMatrix) "type SDDS_STRING"
        set output(ParameterInfo.Gain) "type SDDS_DOUBLE"
        set output(ParameterInfo.Calibration) "type SDDS_DOUBLE"
        set output(ParameterInfo.ControlName) "type SDDS_STRING"
        set output(ParameterInfo.ControlType) "type SDDS_STRING"
        set output(ParameterInfo.RampBias) "type SDDS_DOUBLE"
        set output(ParameterInfo.CorrName) "type SDDS_STRING"
        set output(ParameterInfo.CorrCurrentAO) "type SDDS_STRING"
        set output(ColumnNames) "RampTime OrigRampSetpoint DeltaRampSetpoint Energy"
        set output(ColumnInfo.RampTime) "type SDDS_DOUBLE"
        set output(ColumnInfo.OrigRampSetpoint) "type SDDS_DOUBLE"
        set output(ColumnInfo.DeltaRampSetpoint) "type SDDS_DOUBLE"
        set output(ColumnInfo.Energy) "type SDDS_DOUBLE"

        set ControlNameData ""
        set ControlTypeData ""
        set RampBiasData ""
        set CorrNameData ""
        set CorrCurrentAOData ""
        set RampTimeData ""
        set RampSetpointList ""
        set OrigRampSetpointData ""
        set NData ""
        set RampSetpointDelta ""
        set MatrixData ""
        set EnergyData ""
        set GainData ""
        set CalibrationData ""

        set timeList ""
        set rows [llength $SetpointData(time)]
        set time1 [lindex $SetpointData(time) [expr $rows-2]]
        set time2 [lindex $SetpointData(time) end]
        set timeList $SetpointData(time)
        set timeList [linsert $timeList 0 0]
        set timeList [linsert $timeList end 250]
        set EnergyDataList ""
        set EnergyDataList [linsert $EnergyList 0 325]
        set EnergyDataList [linsert $EnergyDataList end 7000]

        set pages [llength $SetpointData(correctors)]
        if [file exist [pwd]/refMatrix] {
            set ref [pwd]/refMatrix
        } else {
            set ref /home/helios/oagData/booster/orbitControllaw/lattices/$lattice/refMatrices/${plane}.default
        }
        for {set i 0} {$i < $pages} {incr i} {
            set corrName [lindex $SetpointData(correctors) $i]
            lappend ControlNameData ${corrName}:rampRAMPTABLE
            lappend ControlTypeData pv
            lappend RampBiasData 0.0
            lappend CorrNameData $corrName
            lappend CorrCurrentAOData $corrName:CurrentAO
            lappend MatrixData "$ref"
            lappend GainData $gain
            lappend CalibrationData $calib

            set values $SetpointData($corrName)
            set endValue [lindex $values end]
            set values [linsert $values 0 0]
            set values [linsert $values end $endValue]
            lappend RampTimeData $timeList
            lappend EnergyData $EnergyDataList
            lappend OrigRampSetpointData $values

            set deltaValues $SetpointDelta($corrName)
            set value1 [lindex $deltaValues [expr $rows-2]]
            set value2 [lindex $deltaValues end]
            # set endValue [expr ($value2-$value1*1.0)/($time2-$time1)*(236.4396-$time2)+$value2]
            # set deltaValues [linsert $deltaValues end $endValue]
            set deltaValues [linsert $deltaValues 0 0]
            set deltaValues [linsert $deltaValues end $value2]
            lappend RampSetpointDelta $deltaValues
        }
        set output(Parameter.RefMatrix) $MatrixData
        set output(Parameter.Gain) $GainData
        set output(Parameter.Calibration) $CalibrationData
        set output(Parameter.ControlName) $ControlNameData
        set output(Parameter.ControlType) $ControlTypeData
        set output(Parameter.RampBias) $RampBiasData
        set output(Parameter.CorrName) $CorrNameData
        set output(Parameter.CorrCurrentAO) $CorrCurrentAOData
        set output(Column.RampTime) $RampTimeData
        set output(Column.OrigRampSetpoint) $OrigRampSetpointData
        set output(Column.DeltaRampSetpoint) $RampSetpointDelta
        set output(Column.Energy) $EnergyData
        set tmpRamp /tmp/[APSTmpString]
        APSAddToTmpFileList -ID BoosterOrbitCorrection -fileList $tmpRamp
        if [catch {sdds save $tmpRamp output} result] {
            APSDeleteTmpFileList -ID CorrectBoosterOrbit
            cd $oldDir
            SetMainStatus "$result"
            return 
        }
        APSAddToTmpFileList -ID CorrectBoosterOrbit -fileList deltaRamp.$step

        set date [clock format [clock seconds] -format %Y-%m%d]
        set lastRampFile [lindex [lsort [glob -nocomplain $rampTableDir/${plane}-${date}.????]] end]
        if ![string length $lastRampFile] {
            set newFile $rampTableDir/${plane}-$date.0000
        } else {
            set newFile [APSNextGenerationedName -name $lastRampFile -newFile 1 -separator .]
        }
        set matchOpt ""
        if [catch {exec sddssort $tmpRamp -pipe=out -parameter=CorrName \
                       | sddsprocess -pipe=in \
                       "-redefine=col,RampSetpoint,OrigRampSetpoint DeltaRampSetpoint +,symbol=RampSetpoint" \
                       $newFile } result] {
            APSDeleteTmpFileList -ID CorrectBoosterOrbit
            SetMainStatus "$result"
            cd $oldDir
            return
        }
        update
        global InputRampTable 
        set InputRampTable $newFile
        SetMainStatus "Made $newFile"
        set ${plane}RampTable [file tail $newFile]
        global AutoLoad
        if $AutoLoad {
            if {[APSYesNoPopUp "Step $step: Load Ramp Table?"]} {  
                if [catch {LoadBoosterRampTable -plane $plane -fileVariable \
                               ${plane}RampTable -rampDirVar ${plane}RampTableDir} result] {
                    SetMainStatus "Loading error: $result"
                    cd $dataDir
                    return
                }
            }
        }

        #combine the error orbit file
        set orbitFile $orbitDir/Orbit-[set ${plane}RampTable]
        set corrFile $orbitDir/Corr-[set ${plane}RampTable]
        if [catch {eval exec sddscombine $orbitFileList $orbitFile -overwrite} result] {
            cd $dataDir
            return -code error $result
        }
        if [catch {eval exec sddscombine $corrFileList $corrFile -overwrite} result] {
            cd $dataDir
            return -code error $result
        }
        global hCorrDeltaTable vCorrDeltaTable hOriginOrbit vOriginOrbit
        set ${plane}OriginOrbit [file tail $orbitFile]
        set ${plane}CorrDeltaTable [file tail $corrFile]

        # if $PlotData {
        exec sddsplot -same=y -groupby=page -split=page -sep=page -title=@CorrName \
            "-topline=Individual Corrector Ramps Before and After Correction" \
            -col=RampTime,RampSetpoint -graphic=symbol=2,scale=2,sub=1,con=1 \
            -legend=specified=before $newFile \
            -col=RampTime,OrigRampSetpoint -graphic=symbol=4,scale=2,sub=2,con=2  \
            -legend=specified=after $newFile &
        exec sddsplot -same=y -groupby=page -split=page -sep=page -legend=para=RampTimeString -col=Name,$coord \
            "-topline=Orbit Before Correction at Each RampTime Point" -title= $orbitFile &
        exec sddsplot -same=y -groupby=page -split=page -sep=page -legend=para=RampTimeString \
            -col=Actuators,Value "-topline=Normalized Corrector Delta at Each RampTime Point" -title= $corrFile &

        # }
        if {$steps>1 && $step < [expr $steps-1]} {
            set endTime [expr [clock seconds] + $interval]
            while {[clock seconds] < $endTime} {
                if $Abort {
                    set Abort 0
                    SetMainStatus "Orbit correction aborted!"
                    cd $dataDir
                    return
                }
            }
        }
    }
    APSDeleteTmpFileList -ID CorrectBoosterOrbit
    cd $oldDir
    return      
}

proc PlotData {args} {
    set orbitFile ""
    set corrFile ""
    APSParseArguments {orbitFile corrFile}
    if [file exist $orbitFile] {
        

    }
}
proc GetRampSetpointData {args} {
    set time ""
    set firstTime 0
    global SetpointData plane dataDir hResponseDir vResponseDir corrList SetpointDelta
    APSParseArguments {time firstTime}
    
    if $firstTime {
        set corrList ""
        set config $dataDir/[set ${plane}ResponseDir]/config
        if [catch {exec sddsprocess $config -match=par,NameType=CorrectorNames \
                     -edit=col,ControlName,Name,ei/:CurrentAI/ -pipe=out | \
                     sdds2stream -pipe=in -col=ControlName} corrList] {
            return -code error $corrList
        }
	#puts $corrList
        set corrList [lsort $corrList]
        set SetpointData(correctors) [exec sddsprocess $config -match=par,NameType=CorrectorNames \
                                        -pipe=out | sdds2stream -pipe -col=Name]
        set SetpointData(time) ""
        foreach corr $SetpointData(correctors) {
            set SetpointData($corr) ""
            set SetpointDelta($corr) ""
        }
    }
    lappend SetpointData(time) $time
    if [catch {exec cavget -list=[join $corrList ,] -pend=30} current] {
        return -code error $current
    }
    foreach corr $SetpointData(correctors) val $current {
        set val [expr $val / 19.0]
        lappend  SetpointData($corr) $val
    }
    #puts "$time $val"
}

proc SaveSetpointData {args} {
    set file ""
    global SetpointData corrList
    APSParseArguments {file} 
    
    set data(ParameterNames) "CorrCurrentAO"
    set data(ParameterInfo.CorrCurrentAO) "type SDDS_STRING"
    
    set data(ColumnNames) "RampTime RampSetpoint"
    set data(ColumnInfo.RampTime) "type SDDS_DOUBLE"
    set data(ColumnInfo.RampSetpoint) "type SDDS_DOUBLE"
    
    set TimeData ""
    set RampData ""
    set ParameterData ""
    set corrList [lsort $corrList]
    set time1 [lindex $SetpointData(time) 0]
    set time2 [lindex $SetpointData(time) end]
    set timeList [linsert $SetpointData(time) 0 0.0]
    set timeList [linsert $timeList end 236.4396]
    set timeList [linsert $timeList end 250.0]
    foreach corr $corrList {
        set rampList $SetpointData($corr)
        set value1 [lindex $rampList 0]
        set value2 [lindex $rampList end]
        set endValue [expr ($value2-$value1*1.0)/($time2-$time1)*(236.4396-$time2)+$value2]
        set rampList [linsert $rampList 0 0.0]
        set rampList [linsert $rampList end $endValue]
        set rampList [linsert $rampList end $endValue]
        lappend TimeData $timeList
        lappend RampData $rampList
        lappend ParameterData $corr
    }
    set data(Parameter.CorrCurrentAO) $ParameterData
    set data(Column.RampTime) $TimeData
    set data(Column.RampSetpoint) $RampData

    if [catch {sdds save $file data} result] {
        return -code error $result
    }   
}

set firstTime 1
proc ComputeTimeAndEnergy {args} {
   # set NPoints ""
    #M value could be provided or obtained from PVs (need talk with Nick)
    #set M 256
    #set firstTime 0
    #APSStrictParseArguments {NPoints M firstTime}
    global NPoints M firstTime
    
    if ![string length $NPoints] {
        SetMainStatus "Number of N points is not provided!"
        return
    }
    #following graph shows the booster timing diagram
    set diagram \
"
                             Booster Timing Diagram


 RampStart                                     BoosterIP
 |                                               |
 |                            |<-BoosterTrigger->|
 |                            |<--BPMOffset------|->|<------4N------>|<--4M-->|
 |                            |<-----------------|--------PSCU Time------>|
 |                                               |<------deltaT---------->|
 |<-----------RampStartOffset------------------->|                        |
 |                                               |                        |
 |                 DipoleRampStart               |                        |
 |<-RampStartDipoleDelay->|<-DipoleZeroRef->|    |                        |
 |                        |<-----------------------Tbpm-------------------|
 |                        |   CorrectorRampStart |
 |<-RampStartCorrectorDelay---------------->|<---|--------Ramp Time------>
                          |                    Injection                        Extraction End
                          |<----Tinjection------>|                                   |      |
                          |<------------------------Textraction----------------------|
                          |<--------------------------------------Tend----------------------|
 Textraction=236.439589  Eextraction=7.0Gev   Tend=250.0
"
    #constant values
    #set Textraction 236.439589

    global T0 RampStartOffset RampStartDelay Tinjection triggerTime bpmOffsetTime BoosterTurns
    global Einjection Eextraction ExtractionTime BoosterIP Textraction
    global Nextraction NinjectionOffset
    if $firstTime  {
        if [catch {GetTiming} result] {
            return -code error $result
        }
        set firstTime 0
    }
    global NValueList RampTimeList EnergyList PSCUSampleTimeList NFile
    set NValueList ""
    set RampTimeList ""
    set EnergyList ""
    set PSCUSampleTimeList ""
    if {$NPoints <1} {
        return -code error "Number of ramp time points should be greater than 1!"
    }
    SetMainStatus "using $NPoints equidistant points between injection and extraction"
    set delta [expr ($Nextraction-$NinjectionOffset)/($NPoints-1)]
    for {set i 0} {$i < $NPoints} {incr i} {
        lappend NValueList [format %.0f [expr $i* $delta + $NinjectionOffset]]
    }
    foreach N $NValueList {
        #calculate deltaT
       # set deltaT [expr (4.0*$N + 2.0*$M)*$T0 + $bpmOffsetTime - $triggerTime/1000]
        #calculate bpm time at N
       # set RampTime [expr $RampStartOffset - $RampStartDelay + 4.0*$N * $T0]
       # lappend RampTimeList $RampTime
        #calculate energy
       # set En [expr $Einjection + (4.0 * $N * $T0 /$ExtractionTime)*($Eextraction-$Einjection)]
       # lappend EnergyList $En
        #calculate PSCU Time 
       # set PSCUSampleTime [format %.0f [expr (4.0*$N + 2.0*$M)*$T0*1000 + $triggerTime/1000 ]]
       # set PSCUTime [expr $PSCUSampleTime - $BoosterIP + $triggerTime]
        set PSCUTime  [format %.0f [expr 4.0*$N*$T0*1000 + $triggerTime/1000 ]]
        set RampTime [expr $PSCUTime /1000.0 - $triggerTime/1.0e6 + ($RampStartOffset - $RampStartDelay) ]
        
        set deltaT [expr $RampTime - ($RampStartOffset - $RampStartDelay)]
        set En [expr $Einjection + ($deltaT/$ExtractionTime)*($Eextraction-$Einjection)]
        
        lappend EnergyList $En
        lappend RampTimeList $RampTime
        lappend PSCUSampleTimeList $PSCUTime
    }
    set data(ColumnNames) "N RampTime Energy PSCUSampleTime"
    set data(ColumnInfo.N) "type SDDS_LONG"
    set data(ColumnInfo.RampTime) "type SDDS_DOUBLE"
    set data(ColumnInfo.Energy) "type SDDS_DOUBLE"
    set data(ColumnInfo.PSCUSampleTime) "type SDDS_LONG"
    set data(Column.N) [list $NValueList]
    set data(Column.RampTime) [list $RampTimeList] 
    set data(Column.Energy) [list $EnergyList]
    set data(Column.PSCUSampleTime) [list $PSCUSampleTimeList]
    set tmpRoot /tmp/[APSTmpString]
    APSAddToTmpFileList -ID BoosterCorrection -fileList "$tmpRoot.n $tmpRoot.n.print"
    if [catch {sdds save $tmpRoot.n data} result] {
        return -code error $result
    }
    if [catch {exec sddsprintout $tmpRoot.n $tmpRoot.n.print -col} result] {
        return -code error $result
    }
    APSFileDisplayWindow [APSUniqueName .] -fileName $tmpRoot.n.print \
      -deleteOnClose 1 -width 60 -height 30 -printCommand "enscript -r"
}

proc GetTiming {args} {
    global T0 RampStartOffset RampStartDelay Tinjection triggerTime bpmOffsetTime BoosterTurns
    global Einjection Eextraction Textraction BoosterIP ExtractionTime Ninjection Nextraction M N
   
    #calculate rf revolution time
    if [catch {exec cavget -list=Mt:BoosterRampTurnsAO,A014-IETS:BTC:BInjectionCycleM,A014-IETS:BTC:BExtractionCycleM,A014-IETS:BTC:SRSetFreqM -pend=20 -printErrors -floatformat=%lf} results] {
        return -code error "Error reading Mt:BoosterRampTurnsAO,A014-IETS:BTC:BInjectionCycleM,A014-IETS:BTC:BExtractionCycleM,A014-IETS:BTC:SRSetFreqM: $results"
    }
    set srExtractionTurns [lindex $results 0]
    set bInjectionCycle [lindex $results 1]
    set bExtractionCycle [lindex $results 2]
    set srFreq [lindex $results 3]
    set T0 [expr ($bExtractionCycle - $bInjectionCycle) / ($srFreq * 3 * $srExtractionTurns)]
    set T0 [expr 1000 * $T0]

    if [catch {exec cavget -list=It:Bs:LastBunch2BoosterIp -pend=30} BoosterIP] {
        return -code error $BoosterIP
    }
    
    #get RampStartOffset
    if [catch {exec cavget -list=It:Bs:StartRamp2BsIp -pend=30} RampStartOffset] {
        return -code error "$RampStartOffset"
    }
    #get RampStartDelay
    if [catch {exec cavget -list=It:Ddg4chan6.DLY -pend=30} RampStartDelay] {
        return -code error "$RampStartDelay"
    }
    #calculate injection time
    set BRHOCONVERT 3.335640952
    
    #set Tinjection [expr $RampStartOffset - $RampStartDelay]
    set pbrho [exec caget -t P:BRhoCALC]
    set einjection [format "%.3f" [expr ($pbrho/$BRHOCONVERT) * 1000]]
   
    #get trigger time
    if [catch {exec cavget -list=It:Bs:Trig2BsIp -pend=30} triggerTime] {
        return -code error "$triggerTime"
    }
    
    #get bpm offset time
    if [catch {exec cavget -list=It:Ddg3chan6.DLY -pend=30} bpmOffsetTime] {
        return -code error "$bpmOffsetTime"
    }
    
    if [catch {exec cavget -list=Mt:BoosterRampTurnsBsCC.VAL -pend=30} BoosterTurns] {
        return -code error "$BoosterTurns"
    }
    set ExtractionTime [expr $BoosterTurns * $T0]    
    set Tinjection [expr $RampStartOffset - $RampStartDelay]
#    set Nextraction [format %.0f [expr (($Eextraction-$Einjection)/(7000-$Einjection)*$BoosterTurns-$M*2)/4]]
    ###set Textraction [expr $Tinjection + (4*$Nextraction + 2* $M)*$T0]
    if [catch {exec cavget -list=Mt:BoosterRampTurnsAO.VAL -pend=30} srTurns] {
        return -code error $srTurns
    }
    set Nextraction [expr 3 * $srTurns /4 - 2*$M]
    set Textraction [expr $Tinjection + $srTurns * 3 * $T0]
}


proc setTiming {args} {

    set N 0
    set M 256
    set pscu ""
    APSStrictParseArguments {N M pscu}

    if [catch {GetTimingPVs} Timings] {
        SetMainStatus "Error: $Timings!"
        return
    }
    SetMainStatus "Seting N=$N, PSCU sample time=$pscu"
    set putList ""
    foreach timing $Timings {
        lappend putList B:bpmT${timing}:Cycle_count_lo=$M
        lappend putList B:bpmT${timing}:Delay_count_lo=$N
    }
     
    if [catch {exec cavput -list=[join $putList ,] -pend=30} result] {
        SetMainStatus "Error: $result"
        return
    }
    if [catch {exec cavput -list=It:Ddg3chan3.DLY=$pscu -pend=30} result] {
    	return -code error $result
    }

    if {0} {
    if [catch {exec cavput -list=B:bpmT1_8:Delay_count_lo=${N},B:bpmT9_16:Delay_count_lo=${N},B:bpmT17_24:Delay_count_lo=${N},B:bpmT25_32:Delay_count_lo=${N},B:bpmT33_40:Delay_count_lo=${N},B:bpmT41_48:Delay_count_lo=${N},B:bpmT49_56:Delay_count_lo=${N},B:bpmT57_64:Delay_count_lo=${N},B:bpmT65_72:Delay_count_lo=${N},B:bpmT73_77:Delay_count_lo=${N},B:bpmT78_80:Delay_count_lo=${N} -pendIoTime=20} result] {
        return -code error "settiming: $result"
    }

    if [catch {exec cavput -list=B:bpmT1_8:Cycle_count_lo=${M},B:bpmT9_16:Cycle_count_lo=${M},B:bpmT17_24:Cycle_count_lo=${M},B:bpmT25_32:Cycle_count_lo=${M},B:bpmT33_40:Cycle_count_lo=${M},B:bpmT41_48:Cycle_count_lo=${M},B:bpmT49_56:Cycle_count_lo=${M},B:bpmT57_64:Cycle_count_lo=${M},B:bpmT65_72:Cycle_count_lo=${M},B:bpmT73_77:Cycle_count_lo=${M},B:bpmT78_80:Cycle_count_lo=${M} -pendIoTime=20} result] {
        return -code error "settiming: $result"
    }
    }
    return 0
}

proc LoadBoosterRampTable {args} {
    set fileVariable ""
    set plane ""
   
    APSStrictParseArguments {fileVariable plane rampDirVar}
    if ![string length $fileVariable] {
        SetMainStatus "the fileVariable name is not provided."
        return
    }
    global $fileVariable $rampDirVar
    set rampTable [set $rampDirVar]/[set $fileVariable]
     
    SetMainStatus "Loading ramp $rampTable ..."
    SetMainStatus "This procedure will take a few seconds to complete."
    APSExecLog .bCorrRampLoad -unixCommand "loadbramp $rampTable" -callback "SetMainStatus \"Done\""
}

proc LaunchADT {args} {
    set type ""
    APSParseArguments {type}
    if ![string length $type] {
        SetMainStatus "The type for launching ADT is not given"
        return
    }
    switch $type {
        bpm {
            set file bpm.error.pv
        }
        corrector {
            set file bpmerrcor.pv
        }
        default {
            SetMainStatus "Unknown type given!"
            return
        }
    }
    set adtDir /home/helios/oagData/ADTFiles/booster
    exec adt -f $adtDir/$file &
}

proc ZeroOffsetAndSetpoint {args} {
    global plane PVSuffix
    global hResponseDir vResponseDir dataDir 
    set type ""
    APSParseArguments {type}
    if ![string length $type] {
	return -code error "type is not given for setting it to zero!"
    }
    if {[string compare $type OffsetAO] && [string compare $type SetpointAO]} {
	return -code error "type has to be OffsetAO or SetpointAO"
    }
    switch $plane {
        h {
            set config $dataDir/$hResponseDir/config
            set coord x
        }
        v {
            set config $dataDir/$vResponseDir/config
            set coord y
        }
    }
    set tmpfile /tmp/[APSTmpString]
    SetMainStatus "Set $type to zero ..."
    if [catch {exec sddsprocess $config $tmpfile \
		   -match=par,NameType=MonitorNames \
		   -edit=col,ControlName,Name,ei/:${PVSuffix}:$coord:$type \
		   -print=col,ValueString,0 \
		   -print=col,ControlType,pv \
		   -print=col,Lineage,- \
		   -define=col,Count,1,type=long \
		   -print=para,SnapType,Absolute } result] {
	return -code error $result
    }
    APSAddToTmpFileList -ID AdjustOfset -fileList $tmpfile
    if [catch {exec sddscasr -restore $tmpfile} result] {
        return -code error $result
    }
    SetMainStatus "Done."
}

proc GetOffsetAndSetpoint {args} {
    global plane coord
    
    if [catch {exec cavget -list=B -range=begin=1,end=4 -list=C -range=begin=0,end=9 -list=P \
		   -range=begin=1,end=2 -dryRun} correctors] {
	return -code error $correctors
    }
    if [catch {exec cavget -list=B -range=begin=1,end=4 -list=C -range=begin=0,end=9 -list=P \
		   -range=begin=1,end=2 -list=:ms:${coord}:OffsetAO -pend=30} offsets] {
	SetMainStatus "$offsets"
	return
    }
    if [catch {exec cavget -list=B -range=begin=1,end=4 -list=C -range=begin=0,end=9 -list=P \
		   -range=begin=1,end=2 -list=:ms:${coord}:SetpointAO -pend=30 } setpoints] {
	SetMainStatus "$offsets"
	return
    }
    lappend display "bpm           Offset        Setpoint"
    foreach corr $correctors offset $offsets setpoint $setpoints {
	lappend display "$corr [format "%12.2f" $offset] [format "%12.2f" $setpoint]"
    }
    APSScrolledList [APSUniqueName .] -name "Offset and Setpoint in $coord plane" \
	-height 30 -width 50 \
	-itemList $display 
}

proc ChangeButtonState {state} {
    if $state {
        #enable buttons
        APSEnableButton .userFrame.actions.frame.y1.frame.start.button
    } else {
        #disable buttons
        APSEnableButton .userFrame.actions.frame.y1.frame.start.button
    }
}

proc GetTimingPVs {args} {
    global plane hResponseDir vResponseDir dataDir
    
    set configfile /home/helios/oagData/booster/orbitControllaw/lattices/config.sdds
    switch $plane {
        h {
            set dir $hResponseDir
        }
        v {
            set dir $vResponseDir
        }
    }
    set tmpfile /tmp/[APSTmpString]
    APSAddToTmpFileList -ID GetTimingPVs -fileList $tmpfile.config
    if [catch {exec sddsprocess $configfile -match=par,NameType=MonitorNames $tmpfile.config
        exec sddsprocess $dataDir/$dir/config -pipe=out -match=par,NameType=MonitorNames | \
                 sddsxref -pipe $tmpfile.config -match=Name -take=Timing | \
                 sddssort -pipe -column=Timing -unique | \
                 sdds2stream -pipe=in -col=Timing } result] {
        return -code error $result
    }
    return $result
}

proc AbortOrbitCorrection {} {
    global Abort
    set Abort 1
}

proc GetLattice {} {
    global lattice dataDir
    
    set lattice [file tail [file readlink $dataDir]]
}

proc CreateBoosterDir {args} {
    global dailyDir 
    set type ""
    set plane ""
    APSParseArguments {type plane}
    if ![string length plane] {
        return -code error "plane is not given!"
    }
    #here type can be orbit or rampTable
    set rampDir $dailyDir/orbitCorrection/$type
    if ![file exist $rampDir] {
        if [catch {file mkdir $rampDir} result] {
            return -code error $result
        }
    }
    switch $plane {
        h {
            set planDir $rampDir/Horizontal
        }
        v {
            set planDir $rampDir/Vertical
        }
    }
    if ![file exist $planDir] {
        if [catch {file mkdir $planDir} result] {
            return -code error $result
        }
    }
    return $planDir
}

proc CalculatePredictOrbit {args} {
    global InputRampTable latticeSelection
    SetMainStatus "Calculating orbit through choosed rampTable ...."

    if ![string length $InputRampTable] {
        SetMainStatus "Please provide the ramp table first."
        return
    }
    if ![file isfile $InputRampTable] {
        SetMainStatus "The given ramp table is not a file."
        return
    }
    set tmpfile [file tail $InputRampTable]
    if ![regexp {[hv]} $tmpfile plane] {
        SetMainStatus "Invalid ramp table name, the ramp table should have h or v (plane indication)"
        return
    }
    switch $plane {
        h  {
            set coord x
        }
        v {
            set coord y
        }
    }
    if [catch {sdds load $InputRampTable rampData} result] {
        return -code error $result
    }
    if [lsearch $rampData(ParameterNames) RefMatrix]>=0 {
        set refMatrix [exec sdds2stream $InputRampTable -par=RefMatrix -page=1]
    } else {
        APSDialogBox .lattice -name "lattice selection"
        APSRadioButtonFrame .inputlattice -parent .lattice.userFrame \
          -label "Choose Lattice for predicting orbit:" -variable latticeSelection \
          -buttonList {92nm 109nm 132nm} \
          -valueList {x13.75-y5.80 x12.75-y9.80 x11.75-y9.80} -orientation horizontal \
          -contextHelp "Choose the corresponding lattice for the choosed ramp table for predicting orbit"
        tkwait window .lattice
        while {![string length $latticeSelection]} {
            APSDialogBox .lattice -name "lattice selection"
            APSRadioButtonFrame .inputlattice -parent .lattice.userFrame \
              -label "Choose Lattice for predicting orbit:" -variable latticeSelection \
              -buttonList {x11.75-y9.80 x12.75-y9.80 x13.75-y5.80} \
              -valueList {x11.75-y9.80 x12.75-y9.80 x13.75-y5.80} -orientation horizontal \
              -contextHelp "Choose the corresponding lattice for the choosed ramp table for predicting orbit"
            tkwait window .lattice
        }
        
        set refMatrix /home/helios/oagData/booster/orbitControllaw/lattices/$latticeSelection/refMatrices/${plane}.default
        SetMainStatus "Lattice $latticeSelection was choosed for calculating orbit."
    }
    #create tmpfile which contains the information of correctors with the delta-setpoint values
    set tmpRoot /tmp/[APSTmpString]
    APSAddToTmpFileList -ID 1 -fileList "$tmpRoot.1 $tmpRoot.2 $tmpRoot.3 $tmpRoot.bpm $tmpRoot.final"
    set energyExist 0
    switch $plane {
        h {
            set Calib 0.00136
        }
        v {
            set Calib 0.00113
        }
    }
    set gain 1
    if [lsearch $rampData(ColumnNames) Energy]>=0 {
        set energyExist 1
        set energyList [lindex $rampData(Column.Energy) 0]
    }
    if [lsearch $rampData(ParameterNames) Calibration]>=0 {
        set Calib [lindex $rampData(Parameter.Calibration) 0]
    }
    if [lsearch $rampData(ParameterNames) Gain]>=0 {
        set gain [lindex $rampData(Parameter.Gain) 0]
    } 
    set pages [llength $rampData(Parameter.CorrName)]
    set rampTime [lindex $rampData(Column.RampTime) 0]
    set points [llength $rampTime]
    set tmpData(ColumnNames) "Corrector DeltaSetpoint"
    set tmpData(ParameterNames) "Energy Gain Calibration RampTime"
    set tmpData(ParameterInfo.Energy) "type SDDS_DOUBLE"
    set tmpData(ParameterInfo.Gain) "type SDDS_DOUBLE"
    set tmpData(ParameterInfo.Calibration) "type SDDS_DOUBLE"
    set tmpData(ColumnInfo.Corrector) "type SDDS_STRING"
    set tmpData(ColumnInfo.DeltaSetpoint) "type SDDS_DOUBLE"
    set tmpData(ColumnInfo.RampTime) "type SDDS_DOUBLE"
    
    set corrList $rampData(Parameter.CorrName)
    set deltaData ""
    set corrData ""
    set energyData ""
    set calibData ""
    set gainData ""
    set timeData ""
    for {set j 0} {$j < $points} {incr j} {
        set deltaList ""
        set time [lindex $rampTime $j]
        if {$time==0 || $time==250.0} {
            continue
        }
        if $energyExist {
            set energy [lindex $energyList $j]
        } else {
            set energy [expr (7000-325)/225*(10.67+$time)]
        }
        for {set i 0} {$i<$pages} {incr i} {
            lappend deltaList [lindex [lindex $rampData(Column.DeltaRampSetpoint) $i] $j]
        }
       
        lappend deltaData $deltaList
        lappend corrData $corrList
        lappend energyData $energy
        lappend calibData $Calib
        lappend gainData $gain
        lappend timeData $time
    }
    set tmpData(Column.Corrector) $corrData
    set tmpData(Column.DeltaSetpoint) $deltaData
    set tmpData(Parameter.Energy) $energyData
    set tmpData(Parameter.Calibration) $calibData
    set tmpData(Parameter.Gain) $gainData
    set tmpData(Parameter.RampTime) $timeData
    if [catch {sdds save $tmpRoot.1 tmpData} result] {
        return -code error $result
    }
    if [catch {exec sddsprocess $tmpRoot.1 $tmpRoot.2 \
                 "-redefine=col,DeltaSetpoint,DeltaSetpoint 299.79 Energy / * Calibration * 19 * Gain / -1 *" } \
          result] {
        return -code error $result
    }
    set BPMNames [exec sdds2stream $refMatrix -col=BPMName]
    if [catch {exec sddsconvert $refMatrix -retain=col,BPMName,[join $corrList ,] -pipe=out \
		   | sddsmatrixmult -pipe=in $tmpRoot.2 $tmpRoot.3 -reuse } result] {
        
        return -code error $result
    }
    set pages [llength $tmpData(Parameter.Energy)]
    if [catch {sdds load $tmpRoot.3 tmpData1} result] {
        return -code error $result
    }
    set tmpData1(ParameterNames) "Energy Gain Calibration RampTime"
    set tmpData1(ParameterInfo.Energy) "type SDDS_DOUBLE"
    set tmpData1(ParameterInfo.Gain) "type SDDS_DOUBLE"
    set tmpData1(ParameterInfo.Calibration) "type SDDS_DOUBLE"
    set tmpData1(ParameterInfo.RampTime) "type SDDS_DOUBLE"
    lappend tmpData1(ColumnNames) "BPMName"
    set tmpData1(ColumnInfo.BPMName) "type SDDS_STRING"
    set tmpData1(Parameter.Energy) $energyData
    set tmpData1(Parameter.Gain) $gainData
    set tmpData1(Parameter.Calibration) $calibData
    set tmpData1(Parameter.RampTime) $timeData
    set bpmList ""
    for {set i 0} {$i<$pages } {incr i} {
        lappend bpmList $BPMNames
    }
    set tmpData1(Column.BPMName) $bpmList
    if [catch {sdds save $tmpRoot.bpm tmpData1} result] {
        return -code error $result
    }
    
    if [catch {exec sddsconvert $tmpRoot.bpm -rename=col,DeltaSetpoint=$coord -pipe=out \
		   | sddsprocess -pipe=in $tmpRoot.final \
		   "-print=par,EnergyString,%.1f MeV,Energy" \
		   "-print=par,RampTimeString,%.3f ms,RampTime" \
		   "-redefine=col,$coord,$coord 1.0e3 *,units=mm" } result] {
        return -code error $result
    }
    SetMainStatus "done, plotting orbit"
    #sddsplot
    exec sddsplot $tmpRoot.final "-yLabel=$coord (mm)" "-topLine=Orbit change calculated from corrector change" \
	-col=BPMName,$coord -sep -split=pages -legend=par=EnergyString -title=@RampTimeString &    
}

set latticeSelection ""
set inputRampTable ""
set hOriginOrbit ""
set vOriginOrbit ""
set dailyDir [APSGoToDailyDirectory]
set NFile ${dailyDir}nfile
set NPoints 5
set lattice ""
set Abort 0
set AutoLoad 0
set PlotData 0
set hRampTable ""
set vRampTable ""
set hRampTableDir [CreateBoosterDir -type rampTable -plane h]
set vRampTableDir [CreateBoosterDir -type rampTable -plane v]
#puts "$hRampTableDir $vRampTableDir"
set hOrbitDir [CreateBoosterDir -type orbitData -plane h]
set vOrbitDir [CreateBoosterDir -type orbitData -plane v]
set hCorrDeltaTable ""
set vCorrDeltaTable ""
set M 256
set Ninjection 0
set Nextraction ""
set Einjection 325
set Eextraction 7000
set steps 1
set gain 0.5
set plane h
set coord x
set interval 5
set averages 30
set averageInterval 0.5
set PVSuffix ms
set hResponseDir h.default
set vResponseDir v.default
set dataDir /home/helios/oagData/booster/orbitControllaw/lattices/default
#set rampDataDir /home/helios/oagData/booster/orbitControllaw/lattices/rampRecord
set twiss /home/helios/oagData/booster/orbitControllaw/lattices/default/refMatrices/booster.twi
set lattice [file readlink $dataDir]

if ![file exist /home/helios/oagData/booster/orbitControllaw/lattices/rampRecord/$lattice] {
    exec mkdir /home/helios/oagData/booster/orbitControllaw/lattices/rampRecord/$lattice
}
set rampDataDir ${dailyDir}/orbitCorrection/rampTable
set hRampDir Horizontal
set vRampDir Vertical

#APSMakeLink -filename $rampDataDir/$lattice -linkname $rampDataDir/rampRecord/default
GetLattice
cd $dataDir
GetTiming

MakeOptionFrame .options -parent .userFrame
MakeFileFrame .files -parent .userFrame
MakeActionWidget .actions -parent .userFrame

.menu.file.menu insert 1 separator
.menu.file.menu  insert 1 command -label "bpm ADT..." -underline 0 \
      -command "LaunchADT -type bpm"
.menu.file.menu insert 1 command -label "corrector ramp control" -underline 0 \
      -command "exec medm -x -local /net/helios/usr/local-sun4u/iocapps/adlsys/booster/psApp/BoosterRampControl.adl &"
