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

# $Log: CPUtuneCorrectionDCmode,v $
# Revision 1.12  2011/05/27 10:17:58  lemery
# Fixed a contextHelp.
#
# Revision 1.11  2011/05/27 09:26:22  lemery
# Added Mode parameter to *.peaks file.
# Added more instructions for the Generate button.
#
# Revision 1.10  2011/05/27 09:08:50  lemery
# Added catch statements to post-processing immediately after tune collection.
# Removes "set pause 15" statement. Changed default tune reference and range.
#
# Revision 1.9  2011/05/27 08:33:35  lemery
# Untabified and re-indented.
#
# Revision 1.8  2011/05/27 08:29:55  lemery
# Corrected more context help.
#
# Revision 1.7  2011/05/19 20:12:02  xiaoam
# Fixed small bugs
#
# Revision 1.6  2011/05/19 19:34:28  xiaoam
# Add auto switch between mode; Add NASA tune measurement.
#
# Revision 1.5  2010/09/21 01:11:35  xiaoam
# Always use CPU=0 as reference point.
#
# Revision 1.4  2010/02/12 20:10:24  xiaoam
# Modify maximum current of CPU, fix a problem due to pv changes.
#
# Revision 1.3  2009/10/05 21:40:27  xiaoam
# Add read calibration co-efficient from old file
#
# Revision 1.2  2009/02/05 21:16:49  xiaoam
# Add quad calibration procession part. Make changes on post file processing. Now output file can be installed as default immediately.
#
# Revision 1.1  2008/06/06 17:28:35  emery
# Simplified version of CPUtuneCorrection for DC modes only.
#

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.12 $ \$Author: lemery $"

APSApplication . -name "CPUtuneCorrection - DC mode" -version \
  $CVSRevisionAuthor -overview "Collects tune readbacks at various ID4 CPU settings in DC mode. Then a quad correction is generated and DC modes file is updated. The results files must be combined manually from four runs."

proc MakeInputFrame {widget args} {
    set parent ""

    APSStrictParseArguments {parent}

    set outputDir .
    APSFrame $widget -parent $parent -label "Input parameters"
    set w $parent$widget.frame
    APSLabeledEntry .outputDir -parent $w \
      -label "Output directory:" -textVariable outputDir \
      -contextHelp "Enter a name for the output file directory." -width 50
    APSButton .daily -parent $w.outputDir -packOption "-anchor e" \
      -text "daily" -size small \
      -command {set outputDir [APSGoToDailyDirectory -subdirectory CPU]}
    APSLabeledEntry .comment -parent $w -label "Comment: " -textVariable comment \
      -width 55 \
      -contextHelp "Enter a comment to be written as a parameter to the output file."
    APSLabeledEntry .fileindex -parent $w -label "Output File Index: " -textVariable index \
      -contextHelp "Output file index. Increased by 1 after each measurement."

    APSRadioButtonFrame .mode -parent $w -orientation horizontal \
      -label "CPU mode for measuring: " -variable mode \
      -limitPerRow 4 \
      -buttonList {CW CCW H V} \
      -valueList {CW CCW H V} \
      -contextHelp \
      "Choose CPU mode for taking or processing the files."
    APSRadioButtonFrame .instrument -parent $w -orientation horizontal \
      -label "Instrument for measuring tune: " -variable Instrument \
      -limitPerRow 2 \
      -buttonList {NASA VSA} \
      -valueList {NASA VSA} \
      -contextHelp \
      "Choose Instrument for measuring tune."

    APSFrame .tunewindow -parent $w -label "" -width 55
    set w0 $w.tunewindow.frame
    APSFrameGrid .fg -parent $w0 -xList {x y}
    set wx $w0.fg.x
    APSLabeledEntry .xtune -parent $wx -label "xTune: " -textVariable xTune \
      -contextHelp "Reference horizontal tune in tune measurement."
    APSLabeledEntry .xtune0 -parent $wx -label "xTune0: " -textVariable xTune0 \
      -contextHelp "Lower limit of xtune search window"

    set wy $w0.fg.y
    APSLabeledEntry .ytune -parent $wy -label "yTune: " -textVariable yTune \
      -contextHelp "Reference vertical tune in tune measurement."
    APSLabeledEntry .xtune1 -parent $wy -label "xTune1: " -textVariable xTune1 \
      -contextHelp "Upper limit of xtune search window"

    APSLabeledEntry .oldfile -parent $w -label "Current Quad File: " -textVariable DCmodeFile \
      -width 55 \
      -contextHelp "Current quad correction file."
    APSLabeledEntry .newfile -parent $w -label "New Quad File: " \
      -textVariable newFile \
      -width 55 \
      -contextHelp "New quad correction file calculated from measurement"
    APSLabeledEntry .calibration -parent $w -label "Calibration coefficient: " \
      -textVariable caliCoef \
      -width 55 \
      -contextHelp "Quad calibration coefficient"
}

proc CollectData {args} {
    APSParseArguments {DCmodeFile xTune yTune comment abortVar}
    global outputDir index mode Instrument
    global $abortVar

    incr index
    if {![string length $outputDir] } {
        APSSetVarAndUpdate status "Output directory or root not given."
        return
    }
    set dir [pwd]
    cd $outputDir

    set DCmodeDir /home/helios/oagData/sr/IDs/CPU/DCmodes
    if {$DCmodeFile == ""} {
        set DCmodeFile default
    }

    # Initialize CPU
    exec cavput -list=ID04b:on_off.VAL=On
    exec cavput -list=ID04b:set_V_coil.VAL=0
    exec cavput -list=ID04b:set_H_coil.VAL=0
    exec cawait -interval=0.5 -waitFor=ID04b:feedback.VAL,sameAs=Ready
    switch $mode {
        CW {
            # Even though Iv are negative in this file, the PV will get
            # converted to positive by IOC.
            exec cavput -list=ID04b:DesiredMode=0
            set col Iv
            set coilSetPV ID04b:set_V_coil.VAL
            set max 400
        }
        CCW {
            exec cavput -list=ID04b:DesiredMode=1
            set col Iv
            set coilSetPV ID04b:set_V_coil.VAL
            set max 400
        }
        H {
            # Even though Iv are negative in this file, the PV will get
            # converted to positive by IOC.
            exec cavput -list=ID04b:DesiredMode=3
            set col Iv
            set coilSetPV ID04b:set_V_coil.VAL
            set max 400
        }
        V {
            # Even though Ih are negative in this file, the PV will get
            # converted to positive by IOC.
            exec cavput -list=ID04b:DesiredMode=2
            set col Ih
            set coilSetPV ID04b:set_H_coil.VAL
            set max 1600
        }
        default {
            return -code error "Can't understand $desiredMode value for PV ID04b:DesiredMode.VAL"
        }
    }

    # In DC mode files, the setpoints always have to start with the highest 
    # in absolute value. But we want to run with 0 A.
    
    set setpointList [exec sddsprocess $DCmodeDir/$DCmodeFile -pipe=out \
                        -match=para,Mode=$mode \
                        "-redef=col,$col,$col abs" \
                        | sddssort -pipe -col=$col,increasing \
                        | sdds2stream -pipe=in -col=$col ]

    # can start index at other 100's
    set indexf ${index}00

    foreach setpoint $setpointList {
        update
        if ([set $abortVar]) {
            exec cavput -list=$coilSetPV=$max
            exec cawait -interval=0.5 -waitFor=ID04b:feedback.VAL,sameAs=Ready
            exec cavput -list=$coilSetPV=0
            exec cawait -interval=0.5 -waitFor=ID04b:feedback.VAL,sameAs=Ready
            set $abortVar 0
            break
        }
        set indexf [format %03ld $indexf]
        APSSetVarAndUpdate status "Doing setpoint [format %.1f $setpoint] A in mode $mode..." 
        exec cavput -list=$coilSetPV=$setpoint
        exec cawait -interval=0.5 -waitFor=ID04b:feedback.VAL,sameAs=Ready

        catch {collectTune -Instrument $Instrument -xTune $xTune -yTune $yTune \
                 -setpoint $setpoint -fileRoot tunes-${indexf}} status 

        if ([set $abortVar]) {
            exec cavput -list=$coilSetPV=$max
            exec cawait -interval=0.5 -waitFor=ID04b:feedback.VAL,sameAs=Ready
            exec cavput -list=$coilSetPV=0
            exec cawait -interval=0.5 -waitFor=ID04b:feedback.VAL,sameAs=Ready
            set $abortVar 0
            break
        }

        incr indexf
    }
    exec cavput -list=$coilSetPV=0
    APSSetVarAndUpdate status "Data collection finished"
    update
    cd $dir
}

proc collectTune {args} {
    APSParseArguments {Instrument xTune yTune setpoint fileRoot}
    global xTune0 xTune1 mode
    set xPower 6.0
    set yPower 0.0
    set span 40000
    set rfFrequency [exec cavget -list=A014-IETS:BTC:SRSetFreqM -floatFormat=%.1f -pendIoTime=5]
    set revFrequency [expr $rfFrequency / 1296]
    set measHarmonic 1390
    set sideband -1
    set xFreq [format %.1f [expr $revFrequency * ($measHarmonic + $xTune * $sideband)]]
    set yFreq [format %.1f [expr $revFrequency * ($measHarmonic + $yTune * $sideband)]]
    set dividingLine [format %.3f [expr ($xTune + $yTune)/2.0]]

    APSSetVarAndUpdate status "Getting tunes from $Instrument ..."
    if [catch {APSSetTuneMultiplexer -mode $Instrument} result] {
        SetStatus $result
        return
    }

    switch $Instrument {
        VSA {
            if [catch {exec getxytunes -root $fileRoot -only x -plotTunes 0 \
                         -description "Setpoint $setpoint" -xTune $xTune -yTune $yTune  \
                     } results] {
                APSSetVarAndUpdate status "$results"
                return 
            }
            if [catch {exec sddsprocess ${fileRoot}-x.sdds -pipe=out -noWarning \
                         -def=para,MainCurrent,$setpoint -print=para,Mode,$mode \
                         | sddsprocess -pipe -fil=col,Tune,$xTune0,$xTune1 \
                         | sddssmooth -pipe -col=Waveform -points=3 -pass=6 \
                         | sddsprocess -pipe=in ${fileRoot} \
                         -proc=Waveform,largest,xTune,position,functionOf=Tune \
                     } results] {
                APSSetVarAndUpdate status "sddsprocess ${fileRoot}-x.sdds ...: $results"
            }
            file delete ${fileRoot}-x.sdds
        }
        NASA { 
            APSMpMeasureTunes -ring SR -averagingSeconds -1
            APSMpMeasureTunes -ring SR -useExistingData 1 -averagingSeconds -1 -measureXYtuneTogether 0 \
              -plotData 0 -dividingLine $dividingLine -xPower $xPower -yPower $yPower -span $span \
              -xFreq $xFreq -yFreq $yFreq -outputFile $fileRoot
            if [catch {exec sddsprocess ${fileRoot} -noWarning -match=para,plane=x \
                         -def=para,MainCurrent,$setpoint -print=para,Mode,$mode \
                     } results] {
                APSSetVarAndUpdate status "sddsprocess ${fileRoot} ...: $results"
            }
            
            file delete ${fileRoot}~
        }
    }    
    update
    return
}

proc ProcessData {args} {
    APSParseArguments {xTune0 xTune1}
    #
    #Expects files tunes-<index>??-x.sdds created by scanCPUtunes.\n
    #Creates files $<index>.peaks ."
    #
    global outputDir index

    set dir [pwd]
    cd $outputDir

    eval exec sddscombine [lsort [glob tunes-${index}??]] -pipe=out \
      | sddscollapse -pipe \
      | sddsprocess -pipe=in ${index}.peaks \
      -proc=Mode,first,Mode

    APSSetVarAndUpdate status "Process done."
    cd $dir
    return
} 

proc PlotData {} {
    global outputDir index

    set dir [pwd]
    cd $outputDir

    exec sddsplot -col=MainCurrent,xTune ${index}.peaks \
      -gra=sym,sca=3,conn=sub,sub=0 \
      -leg=para=Mode \
      &

    APSSetVarAndUpdate status "Plot done."
    cd $dir
    return
}

proc applyCPUcorrection {args} {
    #set usage "applyCPUcorrection -index <integer> -newfile <string> -help \{0|1\}\n
    #Expects files $<index>.peaks .\n
    #Creates files ."
    APSParseArguments {DCmodeFile newFile}
    global outputDir index caliCoef  

    set dir [pwd]
    cd $outputDir

    if {$newFile==""} {
        APSSetVarAndUpdate status "No newFile given."
        return
    }

    set DCmodeDir /home/helios/oagData/sr/IDs/CPU/DCmodes
    if {$DCmodeFile == ""} {
        set DCmodeFile default
    }
    catch {exec sddsprocess ${index}.peaks -pipe=out \
             -filte=col,MainCurrent,0,0 -proc=xTune,first,Tune0 \
             | sdds2stream -pipe=in -para=Tune0} referenceTune
    exec sddsprocess ${index}.peaks -pipe=out \
      "-def=col,xTuneDiff,xTune $referenceTune -" \
      "-def=col,QuadCorrection,xTuneDiff $caliCoef / chs,units=A" \
      | sddssort -pipe=in ${index}.peaks.correction  -col=MainCurrent,dec

    exec sddsplot -grap=sym,conn=sub,sca=3,vary=sub \
      "-topline=Corrections from file ${index}.peaks" \
      -col=MainCurrent,QuadCorrection ${index}.peaks.correction \
      -leg=para=Mode \
      &

    set mode [exec sdds2stream -para=Mode ${index}.peaks]
    switch -exact $mode {
        CCW {set col Iv}
        CW {set col Iv}
        H {set col Iv}
        V {set col Ih}
    }

    exec sddsprocess $DCmodeDir/$DCmodeFile CCW.correction -match=para,Mode=CCW -redef=para,CaliCoef,$caliCoef
    exec sddsprocess $DCmodeDir/$DCmodeFile CW.correction -match=para,Mode=CW -redef=para,CaliCoef,$caliCoef
    exec sddsprocess $DCmodeDir/$DCmodeFile H.correction -match=para,Mode=H -redef=para,CaliCoef,$caliCoef
    exec sddsprocess $DCmodeDir/$DCmodeFile V.correction -match=para,Mode=V -redef=para,CaliCoef,$caliCoef

    exec cp $mode.correction $mode.correction.old 
    exec sddsprocess $mode.correction.old -pipe=out \
      "-def=col,AbsCurrent,$col abs" \
      | sddsxref -pipe  ${index}.peaks.correction \
       -take=QuadCorrection \
      | sddsprocess -pipe "-redef=col,NormalQuad,NormalQuad QuadCorrection +" \
      | sddsprocess -pipe=in $mode.correction.new \
      -del=col,AbsCurrent,QuadCorrection 
    exec cp $mode.correction.new $mode.correction
    
    eval exec sddscombine CW.correction CCW.correction V.correction H.correction \
      $newFile -overWrite

    APSSetVarAndUpdate status "Please copy $newFile to /home/helios/oagData/sr/IDs/CPU/DCmodes"
    APSSetVarAndUpdate status "Then load this file into the CPU control ioc."
    cd $dir
    return
}

proc QuadCalibrate {args} {
    APSParseArguments {xTune yTune}
    global outputDir caliCoef Instrument

    set dir [pwd]
    cd $outputDir
    set points 5
    set limits 5
    set quad0 [lindex [exec caget ID04b:DS_NormalQuadRdbk] 1]
    for {set i 0} {$i < $points} {incr i} {
        set setpoint [expr -$limits + $i * 2.0 * $limits / ($points - 1)]
        APSSetVarAndUpdate status "Doing setpoint [format %.2f $setpoint] A ..." 
        exec cavput -list=ID04b:DS_NormalQuadSetpt=$setpoint

        after 1000
        set if [format %02ld $i]

        if [catch {collectTune -Instrument $Instrument -xTune $xTune -yTune $yTune \
                     -setpoint $setpoint -fileRoot tunes-quadCalibration-${if}} results] {
            APSSetVarAndUpdate status $results
        }     
    }

    if {[expr abs($quad0)]<0.2} {set quad0 0}
    exec caput ID04b:DS_NormalQuadSetpt $quad0

    eval exec sddscombine [lsort [glob tunes-quadCalibration-??]] -pipe=out \
      | sddscollapse -pipe=in quadCalibration.peaks 

    exec sddspfit quadCalibration.peaks quadCalibration.fit \
      -col=MainCurrent,xTune \
      -range=-3.5,3.5 \
      -evaluate=quadCalibration.eval,begin=-5,end=5.number=100

    exec sddsplot -col=MainCurrent,xTune quadCalibration.peaks \
      -gra=sym,sca=3,conn=sub,sub=0 \
      -leg=spec=Peaks \
      -col=MainCurrent,xTune quadCalibration.eval -grap=line,type=1 -leg=spec=Fit \
      &

    set caliCoef [exec sdds2stream -para=Slope quadCalibration.fit]
    set cavput -list=ID04b:set_ -list=H,V -list=_coil.VAL=0.5
    set cavput -list=ID04b:set_ -list=H,V -list=_coil.VAL=0.0
    APSSetVarAndUpdate status "Calibration coefficient: $caliCoef" 
    APSSetVarAndUpdate status "Calibration done."
    cd $dir
    return
}

set args $argv
set outputDir .
set mode CW
set Instrument NASA
set DCmodeFile default
set xTune 0.20
set xTune0 0.14
set xTune1 0.20
set yTune 0.27
set index 0
set abortRun 0
set caliCoef -2.254590466959267e-03
catch {set caliCoef [lindex [exec sdds2stream -para=CaliCoef /home/helios/oagData/sr/IDs/CPU/DCmodes/default] 0]} result
APSParseArguments {outputDir index DCmodeFile xTune yTune comment newFile}

set status "Working..."
APSScrolledStatus .status -parent .userFrame -textVariable status -width 50
MakeInputFrame .input -parent .userFrame

APSButton .run -parent .userFrame -text Collect -command \
  { \
      catch {set abortRun 0
          CollectData -DCmodeFile  $DCmodeFile \
               -xTune $xTune -yTune $yTune \
               -comment $comment -abortVar abortRun} status
      update idletasks
  } \
  -contextHelp "Collects tunes at various CPU setting points"

APSButton .stop -parent .userFrame -text Stop -command \
  { \
      set abortRun 1
      APSDisableButton .userFrame.stop.button
      APSEnableButton .userFrame.run.button } \
  -contextHelp "Aborts whole run."

APSButton .process -parent .userFrame -text PROCESS -command \
  { \
      catch {ProcessData -xTune0 $xTune0 -xTune1 $xTune1} status
      update idletasks
  } \
  -contextHelp "Selects and processes the data collected today."

APSButton .plot -parent .userFrame -text "PLOT" -command \
  { \
      catch {PlotData} status
      update idletasks
  } \
  -contextHelp "Selects and plots the data collected today."

APSButton .apply -parent .userFrame -text Generate -command \
  { \
      catch {applyCPUcorrection -DCmodeFile $DCmodeFile \
               -newFile $newFile \
           } status
      update idletasks
  } \
  -contextHelp "Generate correction quad file for each output file index. Press after each CPU mode measurement. Alternatively, after all measurements are done, press for each \"output file index\" value that were used for measurements. (Parameter Mode is taken from the *.peaks file.)"

APSButton .calibrate -parent .userFrame -text Calibration -command \
  { \
      catch {QuadCalibrate  -xTune $xTune -yTune $yTune} status
      update idletasks
  } \
  -contextHelp "Calibrate quads settings."

set status Ready.
update


# Local Variables:
# mode: tcl
# indent-tabs-mode: nil
# End:
