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



set CVSRevisionAuthor "\$Revision: 1.4 $ \$Author: lemery $"

APSApplication . -name "CPUMeasureResponse for CPU Dipole Modes" -version $CVSRevisionAuthor \
  -overview "CPUMeasureResponseModes measures the DC response of the orbit to the CPU correctors operated together in different symmetries."

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

proc SetSROrbitStatus {text} {
    global SROrbitStatus
    set SROrbitStatus $text
    update
    bell
}

set root(v) vResponse
set corrList(v) "ID04b:US_VertCorrSetpt ID04b:DS_VertCorrSetpt"
set amplitudeSymm(v) 4.0
set amplitudeAnti(v) 8.0
set coord(v) y

set root(h) hResponse
set corrList(h) "ID04b:US_HorCorrSetpt ID04b:DS_HorCorrSetpt"
set amplitudeSymm(h) 2.5
set amplitudeAnti(h) 5.0
set coord(h) x

proc MakeInputFrame {widget args} {
    APSStrictParseArguments {parent}
    set w $parent$widget.frame
    APSFrame $widget -parent $parent -label "Input parameters"
    
    # select corrector (plane) and amplitude
    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 "-side top" \
      -text "daily" -size small \
      -command {set outputDir [APSGoToDailyDirectory -subdirectory CPU]}
    APSLabeledEntry .rooth -parent $w -label "Root name of horizontal file: " \
      -textVariable root(h) \
      -contextHelp "Enter the root of the horizontal raw data files and processed output <root><index>."
    APSLabeledEntry .rootv -parent $w -label "Root name of vertical file: " \
      -textVariable root(v) \
      -contextHelp "Enter the root of the vertical raw data files and processed output <root><index>."
#    APSLabeledEntry .deltah -parent $w -label "Amplitude for h-plane (A): " \
#      -textVariable amplitude(h) -width 6 \
#      -contextHelp "Enter the desired value for corrector amplitude."
#    APSLabeledEntry .deltav -parent $w -label "Amplitude for v-plane (A): " \
#      -textVariable amplitude(v) -width 6 \
#      -contextHelp "Enter the desired value for corrector amplitude."
    APSLabeledEntry .bpmPause -parent $w -label "BPM average time (s): " \
      -textVariable bpmPause -width 6 \
      -contextHelp "Enter the time for the averaging of bpms."
    APSLabeledEntry .correctorPause -parent $w -label "Corrector pause time (s): " \
      -textVariable correctorPause -width 6 \
      -contextHelp "Enter the time for the correctors to settle."
    
    APSLabeledEntry .comment -parent $w -label "Comment: " \
      -textVariable comment \
      -width 55 \
      -contextHelp "Enter a comment to be written as a parameter to the output file."
    APSButton .setup -parent $parent \
      -text "Setup"  \
      -packOption "-side left" \
      -command Setup \
      -contextHelp "Sets up data collection,i.e. creates a monitor file of bpms and sets up bpm averaging."

    # collect orbit before and after
    APSButton .collect -parent $parent \
      -text "Collect Data"  \
      -packOption "-side left" \
      -command {CollectData \
                  -outputDir $outputDir \
                  -bpmPause $bpmPause \
                  -correctorPause $correctorPause \
                  -comment $comment \
                  -abortVariable abortRun } \
      -contextHelp "Collects orbit data for two values of the CPU dipole correctors. Horizontal plane is run first, then vertical plane."
    APSButton .abort -parent $parent \
      -text "Abort"  \
      -packOption "-side left" \
      -command {set abortRun 1; \
                  APSSetVarAndUpdate SROrbitStatus "Abort pending..." } \
      -contextHelp "Aborts scan at next appropriate moment."
    APSButton .plot -parent $parent \
      -text "Plot Response"  \
      -packOption "-side left" \
      -command {PlotResponses -outputDir $outputDir} \
      -contextHelp "Plot responses."
    APSButton .calcInv -parent $parent \
      -text "Calculate Inverse"  \
      -packOption "-side left" \
      -command {CalculateInverse  -outputDir $outputDir}\
      -contextHelp "Calculates inverse using only the good bpms as determined by the bpm status management database. This function is already included in the \"Collect Data\" button."
    return
}

proc Setup {args} {
    global bpmPause monitorDir
    set interval $bpmPause

    if [catch {APSSRSetIOCAveraging -num2Ave [expr $interval * 10] \
                 -filterCoeff 1.0 -enable 1 \
             } result] {
        APSSetVarAndUpdate SROrbitStatus "Setup: $result"        
        return -code error "Setup: $result"
    }
    if [catch {exec sddsprocess $monitorDir/SROrbit-msAve.vmon \
                 SROrbit-msAve.vmon \
                 -match=col,Suffix=:scdu:ave_sum.VAL,! \
             } result] {
        APSSetVarAndUpdate SROrbitStatus "Setup: $result"        
        return -code error "Setup: $result"
    }
    APSSetVarAndUpdate SROrbitStatus "Created file SROrbit-msAve.vmon in [pwd]"        
    return
}

proc CollectData {args} {
    global corrList amplitudeSymm amplitudeAnti coord monitorDir root
    APSParseArguments {outputDir bpmPause correctorPause comment abortVariable}
    if {$comment == ""} {
        return -code error "CollectData: No values given to comment"
    }
    global $abortVariable
    set interval [expr 1 + $bpmPause + $correctorPause]
    foreach plane {h v} {
        set corrFileList ""
        set output [file join $outputDir $root($plane)]
        set corr1 [lindex $corrList($plane) 0]
        set corr2 [lindex $corrList($plane) 1]
        foreach mode {symm anti} amplitudeVar {amplitudeSymm amplitudeAnti} sign {1 -1} {
            exec sddsmakedataset corr.mon \
              -column=ControlName,type=string -data=$corr1,$corr2
            set delta [set [set amplitudeVar]($plane)]

            #################################
            # +delta tweek
            #################################
            APSSetVarAndUpdate SROrbitStatus "cavput -delta=factor=1 -list=${corr1}=$delta,${corr2}=[expr $sign*$delta]"
            exec cavput -delta=factor=1 -list=${corr1}=$delta,${corr2}=[expr $sign * $delta] -pend=5 -ramp=step=4,pause=0.5
            # wait for some time for corrector and bpms to settle
            APSSetVarAndUpdate SROrbitStatus "wait for $correctorPause for correctors and $bpmPause seconds for bpms"
            APSWaitWithUpdate -waitSeconds $interval -updateInterval 1
            set monID [open "|sddsvmonitor -erase \
                -rootname=$monitorDir/SROrbit-Rootnames.vmon \
                -suffixes=SROrbit-msAve.vmon \
                ${output}.${mode}.raw \
                -scalars=corr.mon \
                -singleShot=noprompt -steps=2" w]
            puts $monID "y"
            if [catch {flush $monID} result] {
                return -code error "CollectData: Problem with flush $monID command (0)"
            }
            APSWaitWithUpdate -waitSeconds 3 -updateInterval 1
            #################################
            # -delta tweek
            #################################
            APSSetVarAndUpdate SROrbitStatus "cavput -delta=factor=-2 -list=${corr1}=$delta,${corr2}=[expr $sign*-$delta]"
            exec cavput -delta=factor=-2 -list=${corr1}=$delta,${corr2}=[expr $sign * $delta] -pend=5 -ramp=step=8,pause=0.5

            # wait for some time for corrector and bpms to settle
            APSSetVarAndUpdate SROrbitStatus "wait for $correctorPause for correctors and $bpmPause seconds for bpms"
            APSWaitWithUpdate -waitSeconds $interval -updateInterval 1
            puts $monID "y"
            if [catch {flush $monID} result] {
                return -code error "CollectData: Problem with flush $monID command (1)"
            }
            APSWaitWithUpdate -waitSeconds 3 -updateInterval 1
            catch {close $monID}
            #################################
            # restore corrector
            #################################
            APSSetVarAndUpdate SROrbitStatus "cavput -delta=factor=1 -list=${corr1}=$delta"
            exec cavput -delta=factor=1 -list=${corr1}=$delta,${corr2}=[expr $sign * $delta] -pend=5 -ramp=step=4,pause=0.5

            # Do some processing for each corrector during loop
            exec sddschanges ${output}.${mode}.raw -pipe=out \
              -change=:msAve:? -cop=Index,Rootname \
              | sddsprocess -pipe \
              "-redef=col,%s,ChangeIn%s $delta / -2.0 /,select=ChangeIn:msAve:?,edit=%/ChangeIn//" \
              |  sddsconvert -pipe \
              -retain=col,Rootname,:msAve:$coord($plane) \
              -rename=col,:msAve:$coord($plane)=$coord($plane) \
              | sddstranspose -pipe -newcolumnnames=Rootname \
              | sddsconvert -pipe -dele=col,OldColumnNames \
              | sddsprocess -pipe=in ${output}.${mode}.proc \
              -print=col,CorrectorMode,${mode} \
              -print=para,Comment,[APSMakeSafeQualifierString $comment]
            lappend corrFileList ${output}.${mode}.proc
        }

        eval exec sddscombine $corrFileList -pipe=out \
          -merge -overWrite \
          | sddsconvert -pipe \
          -retain=col,Corrector,[join [FindGoodBpms -plane $plane] ,] \
          | sddstranspose -pipe=in ${output} \
          -oldColumnNames=BPMNames

    }
    CalculateInverse -outputDir $outputDir
    APSSetVarAndUpdate SROrbitStatus "Done."
}

proc PlotResponses {args} {
    global root
    APSParseArguments {outputDir}

    exec sddsplot -layout=1,2 \
      -axes=x -grap=sym,conn -sep \
      -col=BPMNames,ID04b:US_HorCorrSetpt $outputDir/$root(h) \
      "-ylabel=Upstream hcorr" -enum=int=18 \
      -col=BPMNames,ID04b:DS_HorCorrSetpt $outputDir/$root(h) \
      "-ylabel=Downstream hcorr" -enum=int=18 \
      -col=BPMNames,ID04b:US_HorCorrSetpt $outputDir/$root(h) \
      "-ylabel=Upstream hcorr" -match=col,BPMNames=S\[45]\?:P* \
      -col=BPMNames,ID04b:DS_HorCorrSetpt $outputDir/$root(h) \
      "-ylabel=Downstream hcorr" -match=col,BPMNames=S\[45]\?:P* \
      -col=BPMNames,ID04b:US_VertCorrSetpt $outputDir/$root(v) \
      "-ylabel=Upstream vcorr" -enum=int=18 \
      -col=BPMNames,ID04b:DS_VertCorrSetpt $outputDir/$root(v) \
      "-ylabel=Downstream vcorr" -enum=int=18 \
      -col=BPMNames,ID04b:US_VertCorrSetpt $outputDir/$root(v) \
      "-ylabel=Upstream vcorr" -match=col,BPMNames=S\[45]\?:P* \
      -col=BPMNames,ID04b:DS_VertCorrSetpt $outputDir/$root(v) \
      "-ylabel=Downstream vcorr" -match=col,BPMNames=S\[45]\?:P* \
      &
}

proc FindGoodBpms {args} {
    set plane ""
    APSParseArguments {plane}
    set Plane [string toupper $plane]
    set statusFile /home/helios/oagData/sr/BPMStatus/config.sdds
    if [catch {exec sddsprocess $statusFile -pipe=out \
                 -match=col,DeviceName=S*\[ABC\]:P\[012345\] \
                 -filter=col,Nonexistent$Plane,0,0,OkForDCOrbitCorrection$Plane,1,1,& \
                 | sdds2stream -pipe -col=DeviceName \
             } goodBpms] {
        return -code error $goodBpms
    }
    return $goodBpms
}

proc CalculateInverse {args} {
    global root
    set outputDir ""
    APSParseArguments {outputDir}
    foreach plane {h v} coord {x y} {
        set output $outputDir/$root($plane)
        exec sddspseudoinverse ${output} -pipe=out \
            -oldColumnNames=ActuatorName \
            | sddsconvert -pipe=in ${output}.inv \
            -edit=col,S*,ei/:msAve:${coord}:ErrorCC/
    }
    return
}

set bpmPause 10
set correctorPause 3
set outputDir .
set monitorDir /home/helios/oagData/sr/sddsmonitorFiles
set SROrbitStatus "Ready."

MakeInputFrame .input -parent .userFrame


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