#!/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)]
APSDebugPath



set CVSRevisionAuthor "\$Revision: 1.5 $ \$Author: sereno $"

APSApplication . -name "Set Klystron Power at Saturation" \
  -overview "Sets the desired klystron output power at the tube saturation point." -version $CVSRevisionAuthor

set directory /home/helios/OAG/oagData/linac/linacSectorGain

# This procedure sets the status variable used by the status widget.

set ControlStatus "Ready."

#Make application and status window widgets.  Returns 1 when completed.

proc MakeScanStatusWidget {widget args} {

    global ControlStatus
    set parent ""
    APSParseArguments {parent}
    
    set w $parent$widget
    APSScrolledStatus .status -parent $w -textVariable ControlStatus -width 95 -packOption {-side top}
    return 1
}

# Makes widgets used to perform the alpha magnet and scraper scans.

proc MakeScanWidgets {args} {

    global directory klyPower LinacSector PFNVoltage w
    global uniqueFileLabelList fileLabelList
    set parent ""
    set widget ""
    APSStrictParseArguments {widget parent}

    APSFrame $widget -parent $parent \
      -height 30 -label "" \
      -packOption {-side top -expand 1}
    
    set w $parent$widget.frame

    APSRadioButtonFrame .linacSectorChoiceFrame -parent $w \
      -orientation horizontal \
      -packOption {-side top -fill x} \
      -label "Linac Sector:  " \
      -variable LinacSector \
      -buttonList {L1 L2 L3 L4 L5 L6} \
      -valueList {L1 L2 L3 L4 L5 L6} \
      -commandList {setKlyPowerAndPFN setKlyPowerAndPFN setKlyPowerAndPFN setKlyPowerAndPFN setKlyPowerAndPFN setKlyPowerAndPFN} \
      -contextHelp "Radio button to select the desired linac sector."
    
    APSLabeledEntry .klyPowerFrame -parent $w -width 5 \
      -textVariable klyPower \
      -packOption {-side top -fill x} \
      -label "Desired Klystron Output Power (MW):" \
      -contextHelp "Desired klystron output power at saturation."

    bind ${w}.klyPowerFrame.entry <Return> "getPFNAtSaturation"

    APSLabeledOutput .pfnVoltageOutputFrame -parent $w -width 5 \
      -textVariable PFNVoltage \
      -packOption {-side top -fill x} \
      -label "PFN Voltage Setpoint at Saturation (kV):" \
      -contextHelp "Interpolated PFN voltage at saturation for desired klystron output power."
     
    APSButton .setButtonFrame -parent $w \
      -text "Set Saturated Power" \
      -command {setSaturatedPower -statusCallback SetStatus} \
      -packOption {-side left -fill x} \
      -contextHelp "Set linac sector klystron to deliver desired power at the tube saturation point."

    APSButton .plotButtonFrame -parent $w \
      -text "Plot Sector Gain Data" \
      -command {plotSectorGainData -statusCallback SetStatus} \
      -packOption {-side left -fill x} \
      -contextHelp "Plot most recent sector klystron gain data."

    APSButton .abortUpdateBCDriveFreqFrame -parent $w \
      -text "Abort" \
      -command {set abortFlag 0} \
      -packOption {-side left -fill x} \
      -contextHelp "This button aborts the klystron set saturated power procedure."

    return 1
}

# procedure to set the status display

proc SetStatus {text} {
    global ControlStatus
    set ControlStatus $text
    update
}

# Disable buttons once one is pressed.

proc DisableButtons {} {
    global w
    APSDisableButton ${w}.setButtonFrame.button
    return 1
}

# Enable buttons once one is pressed and its associated procedure finishes.

proc EnableButtons {} {
    global w
    APSEnableButton ${w}.setButtonFrame.button
    return 1
}

# Procedure to get the PFN voltage from the measured gain data.
# Returns 1 when completed.

proc getPFNAtSaturation {} {
 
    global directory klyPower LinacSector PFNVoltage

    set IntPFNVoltage [exec sddsbreak -pipe=out ${directory}/${LinacSector}Gain/${LinacSector}Gain.sdds \
                         -increaseOf=${LinacSector}PFNset \
                         | sddsprocess -pipe \
                         -process=${LinacSector}PFNset,average,${LinacSector}PFNset \
                         -convertunits=col,${LinacSector}KlyFpwr,MW,Watts,1e-6 \
                         -process=${LinacSector}KlyFpwr,maximum,${LinacSector}KlySatFpwr \
                         | sddscollapse -pipe -noWarnings \
                         | sddsinterp -pipe -col=${LinacSector}KlySatFpwr,${LinacSector}PFNset \
                         -atValues=$klyPower -aboveRange=extrapolate -belowRange=extrapolate \
                         | sdds2stream -pipe=in -col=${LinacSector}PFNset]

    set PFNVoltage [format %0.1f [expr $IntPFNVoltage * 1.0075]]

    if {![string compare $LinacSector "L6"]} {
        set maxPFNVoltage [format %0.1f [exec cavget -list=${LinacSector}:MO:PFNVoltageAO.DRVH -pendIoTime=20]]
    } else {
        set maxPFNVoltage [format %0.1f [exec cavget -list=${LinacSector}:MO:PFNvAO.DRVH -pendIoTime=20]]
    }

    set maxIntSatFpwr [exec sddsbreak -pipe=out ${directory}/${LinacSector}Gain/${LinacSector}Gain.sdds \
                         -increaseOf=${LinacSector}PFNset \
                         | sddsprocess -pipe \
                         -process=${LinacSector}PFNset,average,${LinacSector}PFNset \
                         -convertunits=col,${LinacSector}KlyFpwr,MW,Watts,1e-6 \
                         -process=${LinacSector}KlyFpwr,maximum,${LinacSector}KlySatFpwr \
                         | sddscollapse -pipe -noWarnings \
                         | sddsinterp -pipe -col=${LinacSector}PFNset,${LinacSector}KlySatFpwr \
                         -atValues=$maxPFNVoltage -aboveRange=extrapolate -belowRange=extrapolate \
                         | sdds2stream -pipe=in -col=${LinacSector}KlySatFpwr]

    if {${PFNVoltage}>${maxPFNVoltage}} {
        set PFNVoltage ${maxPFNVoltage}
        set klyPower [format %0.1f $maxIntSatFpwr]
    }
    return $PFNVoltage
}

proc setSaturatedPower {args} {
 
    global directory klyPower LinacSector PFNVoltage abortFlag

    APSStrictParseArguments {statusCallback}

    set PFNVoltage [getPFNAtSaturation]
    set abortFlag 1

    DisableButtons

    if {$statusCallback!=""} {
        $statusCallback "Waiting for $LinacSector klystron PFN voltage to settle to $PFNVoltage kV..."

        if {![string compare $LinacSector "L6"]} {
            exec cavput -list=${LinacSector}:MO:PFNVoltageAO=$PFNVoltage -pendIoTime=20
            exec cawait -waitFor=${LinacSector}:MO:PFNVoltageAI,lowerLimit=[expr $PFNVoltage * 0.9],upperLimit=[expr $PFNVoltage * 1.1]
        } else {
            exec cavput -list=${LinacSector}:MO:PFNvAO=$PFNVoltage -pendIoTime=20
            exec cawait -waitFor=${LinacSector}:MO:PFNvAI,lowerLimit=[expr $PFNVoltage * 0.9],upperLimit=[expr $PFNVoltage * 1.1]
        }
        after 3000
        $statusCallback "Finished ramping PFN voltage to $PFNVoltage kV..."
    }
    
    if {$LinacSector == "L2"} {
        set presentKlyPower [format %0.2f [expr [exec cavget -list=L-K2:LLRF:KlyFwd_PwrRemoteM  -pendIoTime=20] / 1e6]]
    } elseif {$LinacSector == "L5"} {
        set presentKlyPower [format %0.2f [expr [exec cavget -list=L-K5:LLRF:KlyFwd_PwrRemoteM  -pendIoTime=20] / 1e6]]
    } else {
        set presentKlyPower [format %0.2f [expr [exec cavget -list=${LinacSector}:KY:DC2ARF.VAL  -pendIoTime=20] / 1e6]]
    }
    set error [expr abs(${klyPower} - ${presentKlyPower})]
    
    set fineCount 0
    while {${error}>0.05 && ${abortFlag}} {

        update
        if {${klyPower}>${presentKlyPower}} {
            if {${error}>1} {
                exec cavput -list=${LinacSector}:KY:DC2A:pwmCtlC=1.5
            } else {
                exec cavput -list=${LinacSector}:KY:DC2A:pwmCtlC=0.5
                incr fineCount
            }
            after 1000
        } else {
            if {${error}>1} {
                exec cavput -list=${LinacSector}:KY:DC2A:pwmCtlC=-1.5
            } else {
                exec cavput -list=${LinacSector}:KY:DC2A:pwmCtlC=-0.5
                incr fineCount
            }
            after 1000
        }
        update
        if {$LinacSector == "L2"} {
            set presentKlyPower [format %0.2f [expr [exec cavget -list=L-K2:LLRF:KlyFwd_PwrRemoteM  -pendIoTime=20] / 1.0e6]]
        } elseif {$LinacSector == "L5"} {
            set presentKlyPower [format %0.2f [expr [exec cavget -list=L-K5:LLRF:KlyFwd_PwrRemoteM  -pendIoTime=20] / 1.0e6]]
        } else {
            set presentKlyPower [format %0.2f [expr [exec cavget -list=${LinacSector}:KY:DC2ARF.VAL  -pendIoTime=20] / 1.0e6]]
        }
        set error [expr abs(${klyPower} - ${presentKlyPower})]

        if {$statusCallback!=""} {
            $statusCallback "Target $LinacSector forward power is $klyPower MW.  Present $LinacSector forward power is $presentKlyPower MW."
        }
        if {${fineCount}>20} {
            set error 0.0
            if {$statusCallback!=""} {
                $statusCallback "Too many interations.  Feedback terminated."
            }
        }
        update
    }

    if {$abortFlag} {
        if {$statusCallback!=""} {
            $statusCallback "Klystron forward power and PFN voltage set to $presentKlyPower MW and $PFNVoltage kV.\nKlystron tube is at saturation for this power and PFN voltage."
        }
    } else {
        if {$statusCallback!=""} {
            $statusCallback "Feedback process aborted:  Klystron forward power and PFN voltage set to $presentKlyPower MW and $PFNVoltage kV."
        }
    }
    EnableButtons
    set abortFlag 1
    return $PFNVoltage
}

proc plotSectorGainData {args} {

    global directory klyPower LinacSector PFNVoltage

    APSStrictParseArguments {statusCallback}
    
    if {$statusCallback!=""} {
        $statusCallback "Plotting klystron gain data for sector $LinacSector..."
    }

    if {$LinacSector == "L2"} {
        set presentKlyFwdPower [format %0.2f [expr [exec cavget -list=L-K2:LLRF:KlyFwd_PwrRemoteM  -pendIoTime=20] / 1e6]]
        set presentKlyDrvPower [format %0.2f [exec cavget -list=L-K2:LLRF:KlyDrive_PwrRemoteM  -pendIoTime=20]]
    } elseif {$LinacSector == "L5"} {
        set presentKlyFwdPower [format %0.2f [expr [exec cavget -list=L-K5:LLRF:KlyFwd_PwrRemoteM  -pendIoTime=20] / 1e6]]
        set presentKlyDrvPower [format %0.2f [exec cavget -list=L-K5:LLRF:KlyDrive_PwrRemoteM  -pendIoTime=20]]
    } else {
        set presentKlyFwdPower [format %0.2f [expr [exec cavget -list=${LinacSector}:KY:DC2ARF.VAL  -pendIoTime=20] / 1e6]]
        set presentKlyDrvPower [format %0.2f [exec cavget -list=${LinacSector}:KY:DC1RF.VAL  -pendIoTime=20]]
    }


    set presKlyFwdPwrString "-string=\$s5\$e,x=$presentKlyDrvPower,y=$presentKlyFwdPower,scale=1,justify=rc,angle=90,linetype=0"

    catch {exec sddsplot -split=pages -title= \
             -col=${LinacSector}KlyDrv,${LinacSector}KlyFpwr -graph=line,vary ${directory}/${LinacSector}Gain/${LinacSector}Gain_Proc.sdds \
             -legend=parameter=${LinacSector}PFNsetString \
             -col=${LinacSector}KlyDrv,${LinacSector}KlyFpwr -graph=symbol,scale=2,vary=subtype ${directory}/${LinacSector}Gain/${LinacSector}Gain_Proc.sdds \
             -subtick=xdiv=5,ydiv=5 \
             "-xLabel=${LinacSector} Drive Power (Watts)" "-yLabel=${LinacSector} Klystron Forward Power (MW)" \
             $presKlyFwdPwrString \
             "-topline=LinacSector ${LinacSector} Klystron Gain for Various PFN Voltages" -end \
             -param=${LinacSector}PFNset,${LinacSector}KlySatFpwr -graph=symbol,scale=2 ${directory}/${LinacSector}Gain/${LinacSector}Gain_Proc.sdds \
             -param=${LinacSector}PFNset,${LinacSector}KlySatFpwr -graph=line ${directory}/${LinacSector}Gain/${LinacSector}Gain_Proc.sdds \
             "-xLabel=${LinacSector} PFN Voltage (kV)" "-yLabel=${LinacSector} Saturated Klystron Forward Power (MW)" \
         "-topline=LinacSector $LinacSector Saturated Klyston Forward Power vs PFN Voltage" -end \
             -param=${LinacSector}PFNset,${LinacSector}KlySatDrvPwr -graph=symbol,scale=2 ${directory}/${LinacSector}Gain/${LinacSector}Gain_Proc.sdds \
             -param=${LinacSector}PFNset,${LinacSector}KlySatDrvPwr -graph=line ${directory}/${LinacSector}Gain/${LinacSector}Gain_Proc.sdds \
             "-xLabel=${LinacSector} PFN Voltage (kV)" "-yLabel=${LinacSector} Saturated Klystron Drive Power (Watts)" \
             "-topline=LinacSector $LinacSector Saturated Klyston Drive Power vs PFN Voltage" \&}

    if {$statusCallback!=""} {
        $statusCallback "Done plotting klystron gain data for sector $LinacSector."
    }
    return 1
}

proc setKlyPowerAndPFN {} {
 
    global directory klyPower LinacSector PFNVoltage

    if {$LinacSector == "L2"} {
        set klyPower [format %0.2f [expr [exec cavget -list=L-K2:LLRF:KlyFwd_PwrRemoteM  -pendIoTime=20] / 1e6]]
    } elseif {$LinacSector == "L5"} {
        set klyPower [format %0.2f [expr [exec cavget -list=L-K5:LLRF:KlyFwd_PwrRemoteM  -pendIoTime=20] / 1e6]]
    } else {
        set klyPower [format %0.1f [expr [exec cavget -list=${LinacSector}:KY:DC2ARF.VAL -pendIoTime=20] / 1e6]]
    }
    set PFNVoltage [getPFNAtSaturation]

    return 1
}

set LinacSector L1
setKlyPowerAndPFN
set abortFlag 1

MakeScanStatusWidget .userFrame .
MakeScanWidgets -widget .klyPwrEntries -parent .userFrame
