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

# $Log: not supported by cvs2svn $
# Revision 1.6  2005/11/03 21:55:25  borland
# Works now with L5 beam-to-rf phase control as well as L5 phase control.
#
# Revision 1.5  2004/12/19 20:25:29  borland
# Added option to change the post-change-pause time.
#
# Revision 1.4  2004/08/20 00:14:29  borland
# Removed recommendation about running orbit correction.
#
# Revision 1.3  2004/08/19 19:51:42  borland
# Added control of the number of samples to average and the step size.
# Also added plotting of the log file.
#
# Revision 1.2  2003/12/18 15:19:39  borland
# Added button to test the test variables.  Added some status information.
#
# Revision 1.1  2002/08/13 19:38:18  borland
# First version.
#

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.7 $ \$Author: sereno $"
APSApplication . -name optimizeParEfficiency -version $CVSRevisionAuthor \
  -overview {Adjust steering setpoints in LTP and rf phase in linac to optimize PAR efficiency.}

set status "Don't use script during top-up!"
APSScrolledStatus .status -parent .userFrame \
  -textVariable status -width 50

proc CheckControllaw {args} {
    global inputConfig GUN

    SetStatus "Check linac traj controllaw, LTP controllaw, and linac phase controllaw..."
    set linacX Linac:ControlLawXRC
    set linacY Linac:ControlLawYRC
    set ltpX LTP:ControlLawXRC
    set ltpY LTP:ControlLawYRC
    set phase L:BPD:RFGUN${GUN}:L1L2L4L5RC
    
    while {1} {
	if [catch {exec cavget -list=$linacX,$linacY,$ltpX,$ltpY,$phase -list=.RUN -pend=10 -numerical \
		       -printErrors } valList] {
	    return -code error "Error reading controllaws: $valList"
	}
	set LinacX [lindex $valList 0]
	set LinacY [lindex $valList 1]
	set LTPX [lindex $valList 2]
	set LTPY [lindex $valList 3]
	set Phase [lindex $valList 4]

	if {!$LinacX || !$LinacY} {
	    set answer [APSMultipleChoice .info -name "Linac horizontal or vertical trajectory controllaw" \
			    -question "Linac trajector controllaw is not running, please choose start them and continue or abort " \
			    -labelList {Check-Again Abort} \
			    -returnList {Check-Again Abort} ]
	    if {$answer=="Abort"} {
		return -code error "Error: linac trajectory controllaw is not running."
	    }
	} else {
	    break
	}
    }
    global resumeList
    set resumeList ""
    if {$inputConfig=="PARCorrector"} {
	set putList ""
	if $LTPX {
	    lappend putList $ltpX.SUSP=1
	    lappend resumeList $ltpX.SUSP=0
	}
	if $LTPY {
	    lappend putList $ltpY.SUSP=1
	    lappend resumeList $ltpY.SUSP=0
	}
	if $Phase {
	    lappend putList $phase.SUSP=1
	    lappend resumeList $phase.SUSP=0
	}
	if [string length $putList] {
	    SetStatus "suspending LTP and Linac phase controllaw..."
	    if [catch {exec cavput -list=[join $putList ,] -pend=10 } result] {
		return -code error "Error suspending LTP and linac phase controllaw: $result"
	    }
	}
	return
    }
    while {1} {
	SetStatus "Check if LTP and phase controllaw are running..."
	if [catch {exec cavget -list=$ltpX,$ltpY,$phase -list=.RUN -pend=10  -numerical \
		       -printErrors } result] {
	    return -code error "Error reading controllaws: $result"
	}
	set LTPX [lindex $result 0]
	set LTPY [lindex $result 1]
	set Phase [lindex $result 2]
	
	set message ""
	if {!$LTPX} {
	    lappend message "horizontal LTP controllaw"
	}
	if {!$LTPY} {
	    lappend message "vertical LTP controllaw"
	}
	if {!$Phase} {
	    lappend message "linac phase controllaw"
	}
	if [llength $message] {
	    set answer [APSMultipleChoice .info -name "LTP/Phase controllaw not running" \
			    -question "[join $message ,] are not running, please choose start them and check again or abort " \
			    -labelList {Check-Again Abort} \
			    -returnList {Check-Again Abort} ]
	    if {$answer=="Abort"} {
		return -code error "Error: [join $message ,] controllaw not running."
	    }
	} else {
	    break
	}
    }
    return
}

proc APSRunParEfficiencyOptimizer {args} {
    set plot 0
    set save 0
    set restore 0
    set test 0
    set averages 30
    set postChangePause 6.0
    set statusCallback APSNoOp
    set stepSizeMultiplier 1.0
    APSStrictParseArguments {plot save restore statusCallback test stepSizeMultiplier averages postChangePause}
    
    global tolerance evaluations method simplex1d rcdsNoise rcdsStepSize rcdsDebugger rcdsUseMinimum cycles outDir inputConfig resumeList
    OptimizerParameter -edit 0
    cd $outDir
    if {$inputConfig == "InjTrigger"} {
	#need read the initial values for P1H1 and P2H2
	if ![file exist measureCharge] {
	    exec cp /home/helios/oagData/par/optimizationConfig/parInjEffOptimizer/InjTrigger/measureCharge .
	}
	if ![file exist changeVars] {
	     exec cp /home/helios/oagData/par/optimizationConfig/parInjEffOptimizer/InjTrigger/changeVars .
	}
	if ![file exist bumpConfig.sdds] {
	    exec cp /home/helios/oagData/par/optimizationConfig/parInjEffOptimizer/InjTrigger/bumpConfig.sdds .
	}
	if [catch {exec sddscasr -save bumpConfig.sdds bumpConfig.initValue} result] {
	    return -code error "Error reading inital value of P1H1 and P2H1: $result"
	}
    } else {
	if {$save || $restore} {
	    set snapshotFile /tmp/APSRunParEfficiencyOptimizer.[pid]
	    if $save {
		exec sddscasr $outDir/PAROpt.vars -save $snapshotFile 
		eval $statusCallback {"PAR optimizer settings saved."}
	    } else {
		exec sddscasr -restore $snapshotFile
		eval $statusCallback {"PAR optimizer settings restored."}
	    }
	    return
	} 
    } 
    if $test {
        set tmpFile /tmp/[APSTmpString]
        if [catch {exec sddssnapshot $outDir/PAROpt.tests -pipe=out \
		       | sddsprocess -pipe \
		       "-def=col,InBounds,MinimumValue Value < pop pop ? Value MaximumValue < pop pop ? 1 : 0 $ : 0 $,type=long" \
		       | sddsprocess -pipe=in -nowarnings -filter=col,InBounds,0,0 $tmpFile } result] {
	    return -code error "Error reading tests values: $result"
	}
	set rows [exec sdds2stream -rows=bar $tmpFile]
	if !$rows {
	    SetStatus "Tests passed."
	} else {
          exec  sddsprintout  $tmpFile $tmpFile.print  \
	      "-title=Following PVs failed testing.\n" \
	      -column=ControlName,format=%40s -column=MinimumValue,format=%10.3g \
	      -column=Value,format=%10.3g -column=MaximumValue,format=%10.3g \
	      -column=Description
	    APSFileDisplayWindow [APSUniqueName .] -height 20 \
	      -comment "Tests for PAR efficiency optimizer" \
	      -width 120 -fileName $tmpFile.print -deleteOnClose 1
	}
	APSAddToTmpFileList -ID parinjopt -fileList "$tmpFile $tmpFile.print"
	return
    }

     
    SetStatus "Starting par injection efficiency optimization with $inputConfig ..."
    if [catch {CheckControllaw } result] {
	SetStatus "Error in checking controllaws: $result"
	return
    }
    if $rcdsDebugger {
        set rcdsOpt -rcds=evaluations=$evaluations,cycles=$cycles,noise=$rcdsNoise,step=$rcdsStepSize,verbose
    } else {
        set rcdsOpt -rcds=evaluations=$evaluations,cycles=$cycles,noise=$rcdsNoise,step=$rcdsStepSize
    }
    if $rcdsUseMinimum {
        append rcdsopt ,useMin
    }
    switch $method {
	Simplex {
	    if !$simplex1d {
		set opt -simplex=restart=1,cycles=$cycles,evaluations=$evaluations,rand,no1dscan
            } else {
                set opt -simplex=restart=1,cycles=$cycles,eval=$evaluations,rand 
            }
	}
	RCDS {
	    set opt $rcdsOpt
	}
    }
     
    set optMeasFile $outDir/PAROpt.meas 
    global apsRunParEfficiencyOptimizer
    set apsRunParEfficiencyOptimizer -1
    
    if {$inputConfig=="InjTrigger"} {
	set opt "$opt -measScript=measureCharge -varScript=changeVars"
    } else {
	set opt "$opt -measFile=$optMeasFile"
    }
    set oldDir [pwd]
    cd $outDir

    set logFile ${method}[clock format [clock seconds] -format %Y-%m%d:%H%M%S].$inputConfig.log
    
    set optVarFile $outDir/PAROpt.vars
   
    
    APSExecLog [APSUniqueName .] -closeInput 0 \
      -unixCommand "sddsoptimize \
        -tolerance=$tolerance \
        -varFile=$optVarFile -testValues=file=PAROpt.tests,limit=200 \
        $opt \
        -verbose -logFile=$logFile -maximize \
        -runControlPV=string=PAREfficOptimizerRC,pingtimeout=30 \
        \"-runControlDescription=string=Efficiency Optimizer\"" \
	-callback "set apsRunParEfficiencyOptimizer finished" \
	-abortCallback "set apsRunParEfficiencyOptimizer cancelled" \
	-cancelCallback "set apsRunParEfficiencyOptimizer cancelled" \
      -width 120 -height 20 -lineLimit 1000 \
      -contextHelp "PAR efficiency optimizer"
    cd $oldDir
    eval $statusCallback {"PAR optimizer started."}
    if $plot {
        after 60000 "exec sddsplot -repeat \"-device=motif,-movie true -keep 1\" \
                       -column=EvalIndex,currentValue $logFile -graph=sym -factor=ymult=-1 \
                      -xlabel=IterationNumber -ylabel=ObjectiveValue &"
    }
    
    tkwait variable apsRunParEfficiencyOptimizer
    PAROptCallback -status $apsRunParEfficiencyOptimizer
}

set outDir ""
proc OptimizerParameter {args} {
    set edit 1
    set update 0
    APSParseArguments {edit update}
    
    global mainDir inputConfig outDir gun
    
    if ![string length $outDir] {
	set outDir [APSGoToDailyDirectory -subdirectory parInjEffOpt]
    }
    cd $outDir
    foreach type {vars meas} {
	if {$update || ![file exist $outDir/PAROpt.$inputConfig.$type]} {
	    exec cp $mainDir/$inputConfig/PAROpt.$type PAROpt.$inputConfig.$type
	}
	catch {exec rm PAROpt.$type}
	exec ln -s PAROpt.$inputConfig.$type PAROpt.$type
    }
    if {$update} {
	catch {exec rm PAROpt.$inputConfig.tests}
	exec cp $mainDir/$inputConfig/PAROpt.tests.$gun  PAROpt.$inputConfig.tests
    }
    catch {exec rm PAROpt.tests}
    exec ln -s PAROpt.$inputConfig.tests PAROpt.tests
    if $edit {
	exec sddsedit $outDir/PAROpt.$inputConfig.vars &
	exec sddsedit $outDir/PAROpt.$inputConfig.meas &
	exec sddsedit $outDir/PAROpt.$inputConfig.tests &
    }
}

set resumeList ""
proc PAROptCallback {args} {
    set status done
    APSParseArguments {status}
    global inputConfig resumeList
    SetStatus "PAR optimizer $status."
    exec cavput -list=PAREfficOptimizerRC.ABRT=1
    after 1000
    exec cavput -list=PAREfficOptimizerRC.CLR=1
    
    if {$inputConfig=="PARCorrector"} {
	if [APSYesNoPopUp "Do you want to transfer LTP setpoints after optimization?"] {
	    exec  LinacLTPSetpointTransfer -includeLTP 1 &
	    APSInfoWindow [APSUniqueName .] -name Message -width 30 -infoMessage "Press ok when you are done with LTP setpoint transfer" -modal 1
	}
	if [llength $resumeList] {
	    SetStatus "Resuming LTP and phase controllaw"
	    if [catch {exec cavput -list=[join $resumeList ,] -pend=10 } result] {
		return -code error "Error resuming LTP and phase controllaw: $result"
	    }
	}
    }
}

proc BringupStripTool {args} {
    global mainDir inputConfig
    set file $mainDir/$inputConfig/PAROpt.stp
    puts $file
    exec StripTool $file &
}

proc SetStatus {message} {
    APSSetVarAndUpdate status "$message"
}

if [catch {exec cavget -list=L1:RFG:RF:SW2:positionMI -printErrors -pend=10} gun] {
    puts stderr "Error reading RF gun selection."
    exit 1
}
set GUN [scan $gun RG%ld]

set stepSizeMultiplier 1.0
set readingsToAverage 5
set postChangePause 6.0
set tolerance 0.001
set evaluations 100
set method Simplex
set simplex1d 0
set rcdsNoise 0.003
set rcdsStepSize 0.01
set rcdsDebugger 1
set rcdsUseMinimum 0
set cycles 1
set mainDir /home/helios/oagData/par/optimizationConfig/parInjEffOptimizer
set inputConfig PARCorrector
OptimizerParameter -update 1 -edit 0
#APSLabeledEntry .stepSizeMult -parent .userFrame -label "Initial Step size multiplier: " \
\#  -textVariable stepSizeMultiplier \
 \# -contextHelp "Enter a value by which to multiply the starting step sizes. "
#APSLabeledEntry .averages -parent .userFrame -label "Readings to average: " \
\#  -textVariable readingsToAverage \
 \# -contextHelp "Enter the number of efficiency readings to average in order to determine the efficiency.  A larger number will make the process slower but perhaps more reliable."
#APSLabeledEntry .pause -parent .userFrame -label "Pause after changing (s): " \
\#  -textVariable postChangePause 
#APSLabeledEntry .tol -parent .userFrame -label "Tolerance:" -textVariable tolerance
APSLabeledEntry .dir -parent .userFrame -label "Output directory:" -textVariable outDir -width 60
APSLabeledEntry .eval -parent .userFrame -label "Max. number of evaluations:" -textVariable evaluations
APSLabeledEntry .tol -parent .userFrame -label "Tolerance:" -textVariable tolerance

APSRadioButtonFrame .method -parent .userFrame -label "Optimizer:" -buttonList {Simplex RCDS} \
    -variable method -valueList {Simplex RCDS} -orientation horizontal
APSRadioButtonFrame .1d -parent .userFrame -label "With 1d scan for simplex?" -variable simplex1d -buttonList {Yes No} \
    -valueList {1 0} -orientation horizontal
APSRadioButtonFrame .debug -parent .userFrame -label "RCDS debugger on/off?" -buttonList {On Off} \
    -valueList {1 0} -orientation horizontal -variable rcdsDebugger
APSRadioButtonFrame .min -parent .userFrame -label "RCDS use minimum for bracket scan?" -buttonList {Yes No} \
    -valueList {1 0} -orientation horizontal -variable rcdsUseMinimum
APSLabeledEntry .noise -parent .userFrame -label "RCDS signal noise:" -textVariable rcdsNoise
APSLabeledEntry .step -parent .userFrame -label "RCDS relative step size:" -textVariable rcdsStepSize
APSRadioButtonFrame .sub -parent .userFrame -label "Input and measurement configuration:" \
    -buttonList {LinacPhase LTPCorrector InjTrigger} -valueList {LinacPhase PARCorrector InjTrigger} \
    -variable inputConfig -orientation horizontal -commandList {"OptimizerParameter -edit 0 -update 1" "OptimizerParameter -edit 0 -update 1" "OptimizerParameter -edit 0 -update 1"}


#APSButton .save -parent .userFrame -text Save \
#  -command "APSRunParEfficiencyOptimizer -save 1 -statusCallback SetStatus" \
#  -contextHelp "Save the settings that the optimizer changes, in case you want to go back to where you started."

#APSButton .restore -parent .userFrame -text Restore \
#  -command "APSRunParEfficiencyOptimizer -restore 1 -statusCallback SetStatus" \
 # -contextHelp "Restore the saved settings."

APSButton .run -parent .userFrame -text Run \
  -command \
    {APSRunParEfficiencyOptimizer -plot 1  -statusCallback SetStatus \
       -stepSizeMultiplier $stepSizeMultiplier -averages $readingsToAverage \
       -postChangePause $postChangePause } \
  -contextHelp "Run the optimizer."

APSButton .info -parent .userFrame -text Info -command \
  "exec medm -attach -x -macro \"RCPV=PAREfficOptimizerRC\" \
            ./sr/psApp/APSRunControlSingle.adl &" \
  -contextHelp "Bring up ADL screen showing the run control record for the optimizer."

APSButton .test -parent .userFrame -text Test -command \
  "APSRunParEfficiencyOptimizer -test 1" \
  -contextHelp "Evaluate test values to see why the optimizer has halted or is complaining."

APSButton .par -parent .userFrame -text "Edit Var/Object/Test Params" -command OptimizerParameter \
  -contextHelp "bring up optimize variables and measurement info."

APSButton .strip -parent .userFrame -text "StripTool" -command "BringupStripTool"
OptimizerParameter -edit 0
