#!/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 apsttk 1
set CVSRevisionAuthor "\$Revision: 1.70 $ \$Author: shang $"

APSApplication . -name mpsDumpReview -version $CVSRevisionAuthor -overview \
  "Provides a way to review data from storage ring MPS dumps.  The data consists of a snapshot file\
 giving values of MPS process variables after the dump, along with automatically collected beam\
 history data from relevant BPMs."

set mainDataDir /home/helios/oagData/mpsDumps
set xrefDir $OAGGlobal(SRLatticesDirectory)/scripts
set HLimitMin 0
set HLimitMax 2047
set fbLimitMin -100
set fbLimitMax -0.6
set FFTLimitMin 0
set FFTLimitMax 67.9
set AveMin 0
set AveMax 512
set fbbpmLimitMin -100
set fbbpmLimitMax 3.0
set oldDir [pwd]

set TopupGlitchBefore 240
set TopupGlitchAfter 240

proc MakeDateTimeFrame {widget args} {
    set parent .
    set label "Date of Interest"
    APSStrictParseArguments {parent label}

    APSFrame $widget -parent $parent -label $label
    set w $parent$widget.frame

    APSDateTimeAdjEntry .startDate -parent $w \
      -yearVariable searchYear \
      -monthVariable searchMonth \
      -dayVariable searchDay 
    
}

proc SearchForDumps {args} {
    global mainDataDir dayDirName
    set year ""
    set day ""
    set month ""
    APSStrictParseArguments {day month year}
    global dumpDay
    set dumpDay [APSFormatDate -year $year -month $month -day $day -dateFormat Y-J-MD]
    set dayDirName $mainDataDir/$dumpDay
    if ![file exists $dayDirName] {
        SetMpsDumpReviewStatus "No data for that date."
        return
    }
    if ![file isdirectory $dayDirName] {
        SetMpsDumpReviewStatus "Error: $dayDirName is not a directory!"
        return
    }
    if [winfo exists .notebook] {
        CheckIfNewInputSaved
    }
    set oldDir [pwd]
    cd $dayDirName
    set matchList [lsort [glob -nocomplain \[0-9\]\[0-9\]\[0-9\]\[0-9\]\[0-9\]\[0-9\]]]
    cd $oldDir
    if ![llength $matchList] {
        SetMpsDumpReviewStatus "No data for that date."
        return
    }
    set HMSList ""
    foreach elem $matchList {
        lappend HMSList [string range $elem 0 1]:[string range $elem 2 3]:[string range $elem 4 5]
    }

    if [winfo exists .userFrame.dumpList] {
        destroy .userFrame.dumpList
    }

    APSScrolledList .dumpList -parent .userFrame \
      -name "MPS Dump Choices for $month/$day/$year" \
      -itemList $HMSList -packOption "-side bottom" \
      -callback MakeDumpPlots \
      -packOption "-fill y -expand yes" \
      -contextHelp "List of MPS dumps for $month/$day/$year.  Double-click to review a dump.  The numbers give the time of the dumps in hours, minutes, and seconds."

}

proc MakeDumpPrintout {args} {
    set snapshot ""
    set searchMonth ""
    set searchDay ""
    set searchYear ""
    set HMSItem ""
    APSStrictParseArguments {snapshot searchMonth searchDay searchYear HMSItem}

    set printoutFile [APSTmpDir]/[APSTmpString]
    APSAddToTmpFileList -ID MPSDumpReview -fileList "$printoutFile $printoutFile.tripped $printoutFile.BPLD $printoutFile.time $printoutFile.current"
    exec sddsprocess $snapshot \
      "-match=col,ControlName=S*:P?:*,ControlName=*TripMPSBI*,|,ControlName=*TripBI*,|" \
      $printoutFile.tripped
    set pvNames [exec sdds2stream $printoutFile.tripped -col=ControlName]
    set values [exec sdds2stream $printoutFile.tripped -col=ValueString]
    set TimeStamp [exec sdds2stream $printoutFile.tripped -par=TimeStamp]
    set fileList ""
    if [llength $pvNames] {
        set BPLDNames ""
        set BPLDValues ""
        foreach pv $pvNames value $values {
            if {[string match *TripBI* $pv]} {
                if {$value=="Trip"} {
                    lappend BPLDNames $pv
                    lappend BPLDValues $value 
                }
            } else {
                lappend BPLDNames $pv
                lappend BPLDValues $value
            }
            if {[string match "*TripMPSBI*" $pv]} {
                if {$value=="Tripped"} {
                    set tmpfile [APSTmpDir]/[APSTmpString]
                    if [catch {exec sddsmakedataset $tmpfile -defaultType=string \
                                 -col=ControlName -data=[join $BPLDNames ,] \
                                 -col=ValueString -data=[join $BPLDValues ,] \
                                 -par=TimeStamp -data=$TimeStamp \
                             } result] {
                        return -code error "sddsmakedataset: $result"
                    }
                    lappend fileList $tmpfile
                }
                set BPLDNames ""
                set BPLDValues ""
            }
        }
    }
    if [llength $fileList] {
        APSAddToTmpFileList -ID MPSDumpReview -fileList $fileList
        if [catch {eval exec sddscombine $fileList -merge -pipe=out | \
                     sddsprintout -pipe=in \"-title=Printout for BPLD\" \
                     -parameter=TimeStamp \
                     -column=ControlName,format=%38s \
                     -column=ValueString,format=%-25s > $printoutFile.BPLD } result] {
            return -code error $result
        }
    } else {
        set fid [open $printoutFile.BPLD w]
        puts $fid "No tripped BPLDs.\n"
        close $fid
    }
    exec sddsprocess $snapshot \
      -match=col,ControlName=*TimeSI,ControlName=S:MPS:lastTripCauseSI,| -pipe=out  \
      | sddssort -pipe -col=ValueString \
      | sddsprintout -pipe=in "-title=\nSorted TimeStamps" \
      -parameter=TimeStamp \
      -column=ControlName,format=%38s -column=ValueString,format=%-25s > $printoutFile.time

    exec sddsprocess $snapshot \
      -match=col,ControlName=*S35DCCT* -pipe=out | \
      sddsprintout -pipe=in "-title=\nPrintout for Current" \
      -parameter=TimeStamp \
      -column=ControlName,format=%38s -column=ValueString,format=%-25s > $printoutFile.current
    #scraper units is cm, times 10 to change the units to mm, as bpm position units
    exec sddsprocess $snapshot "-match=col,ControlName=S37B:P1:ms*,ControlName=S38A:P1:ms*,|,ControlName=S*:calcout,|" -pipe=out \
      | sddsprocess -pipe -scan=col,Value,ValueString,%lf \
      | sddsprocess -pipe "-redefine=col,Value,ControlName \"*:calcout\" strmatch ? Value 10 * : Value $ ,units=mm" \
      | sddsprintout -pipe=in "-title=\nPrintout for BPM and Scraper position" \
      -parameter=TimeStamp \
      -column=ControlName,format=%38s -column=Value,format=%10.5f > $printoutFile.pos

    exec cat $printoutFile.BPLD $printoutFile.time $printoutFile.current $printoutFile.pos > $printoutFile
    
    APSFileDisplayWindow [APSUniqueName .] \
      -fileName $printoutFile -deleteOnClose 1 -height 50 \
      -comment "MPS Dump: $searchMonth/$searchDay/$searchYear at $HMSItem"

    return
}

# Should put these set commands for global variable OUTSIDE of procedure. Otherwise this can
# be confusing looking for how the defaults are set.
set FPGATurnHistory(doPlot) 1
set FPGATurnHistory(planeList) "x y"
set FPGATurnHistory(removeOffset) 1
set FPGATurnHistory(sparse) "-sparse=2"
set FPGATurnHistory(redoFFT) 0
set FPGATurnHistory(plotFFT) 0
set FPGATurnHistory(redoFFTplaneList) "x y"
set FPGATurnHistory(lowerTimeLimit) -1000
set FPGATurnHistory(upperTimeLimit) 1000
set FPGATurnHistory(pngFileRoot) .

set FPGADumpHistory(doPlot) 0
set FPGADumpHistory(planeList) "x y"
set FPGADumpHistory(lowerTimeLimit) -10
set FPGADumpHistory(upperTimeLimit) 0

set FPGASlowHistory(doPlot) 0
set FPGASlowHistory(planeList) "x y"
set FPGASlowHistory(redoFFT) 0
set FPGASlowHistory(plotFFT) 0
set FPGASlowHistory(redoFFTplaneList) "x y"
set FPGASlowHistory(lowerTimeLimit) -10000
set FPGASlowHistory(upperTimeLimit) 10000
set FPGASlowHistory(pngFileRoot) .

set FPGATurnMovie(doPlot) 0
set FPGATurnMovie(planeList) "x y"
set FPGATurnMovie(lowerTimeLimit) -1
set FPGATurnMovie(upperTimeLimit) 0
set FPGATurnMovie(frameInterval) 0.1
set FPGATurnMovie(pngFileRoot) .
# versus s or BPM string
set FPGATurnMovie(versus)  s

set FPGASlowMovie(doPlot) 0
set FPGASlowMovie(planeList) "x y"
set FPGASlowMovie(lowerTimeLimit) -10
set FPGASlowMovie(upperTimeLimit) 0
set FPGASlowMovie(frameInterval) 0.1
set FPGASlowMovie(pngFileRoot) .
# versus s or BPM string
set FPGASlowMovie(versus)  s

# Put these set variable commands before the procedure that might change them.
set turnSumMin 0
set turnSumMax 1
set slowSumMin 0
set slowSumMax 1000
proc SelectFPGABpmsToPlot {args} {
    set dirName ""
    APSParseArguments {dirName}
    
    set sectorList [exec sdds2stream /home/helios/oagData/sr/FPGAbpm/sectors.sdds -col=Sector]
    
    global FPGAbpm FPGAresponse FPGATurnHistory FPGASlowHistory FPGATurnMovie FPGASlowMovie FPGADumpHistory
    set variableList ""
    set itemList {A:P2 A:P3 A:P4 B:P5 B:P4 B:P3 B:P2}
    set FPGAresponse 0
    APSDialogBox .fpga -cancelCommand "set FPGAresponse cancel" -okCommand "set FPGAresponse ok" \
      -name "Select FPGA bpms for plot"
    foreach sector $sectorList {
        foreach item $itemList {
            set flag fpga${sector}$item
            global $flag
            set $flag 0
        }
    }
    APSSRSectorButtons .check -parent .fpga.userFrame -label "Select bpm:" \
      -sectorList $sectorList -itemList {A:P2 A:P3 A:P4 B:P5 B:P4 B:P3 B:P2} -itemLabelList $itemList \
      -sectorControl 1 -orientation horizontal \
      -packOption "-side top" -rootname fpga
# turn history: plane, remove offset, sparse option (keep?), redo FFT, plot FFT, FFT plane, plot all time, plot with range, rootname for png files
# slow history: plane, redo FFT, plot FFT, plot all time, plot with range
# turn movie: plane, time range, versus BPM string or versus s, mpl movie interval
# slow movie: plane, time range
# make four frames for the globals
    frame .fpga.userFrame.f1
    frame .fpga.userFrame.f2
    pack .fpga.userFrame.f1 
    pack .fpga.userFrame.f2 -anchor w
    APSFrame .turn -parent .fpga.userFrame.f1 -label "Turn-by-turn processing and plotting" -packOption "-side left -anchor n"
    APSFrame .slow -parent .fpga.userFrame.f1 -label "100-Hz processing and plotting"  -packOption "-side left -anchor n"
    APSFrame .turnmovie -parent .fpga.userFrame.f1 -label "Turn-by-turn movie plotting"  -packOption "-side left -anchor n"
    APSFrame .slowmovie -parent .fpga.userFrame.f1 -label "100-Hz movie plotting"  -packOption "-side left -anchor n"
    APSFrame .dumphistory -parent .fpga.userFrame.f2 -label "Dump history processing and plotting" -packOption "-side top -anchor w"

    set w .fpga.userFrame.f1.turn.frame
    APSRadioButtonFrame .plot -parent $w -buttonList {Yes No} \
        -label "Plot turn-by-turn?"  -variable FPGATurnHistory(doPlot)  -valueList {1 0} \
      -orientation horizontal
    APSRadioButtonFrame .plane -parent $w -buttonList {x y "both"} \
        -label "Planes"  -variable FPGATurnHistory(planeList)  -valueList {x y "x y"} \
      -orientation horizontal
    APSRadioButtonFrame .removeOffset -parent $w -buttonList {Yes No} \
        -label "Remove Offset?"  -variable FPGATurnHistory(removeOffset)  -valueList {1 0} \
      -orientation horizontal
    APSRadioButtonFrame .sparse -parent $w -buttonList {"2" "4" "none"} \
        -label "Sparse option:" -valueList {"-sparse=2" "-sparse=4" "-sparse=1"} \
        -variable FPGATurnHistory(sparse) -orientation horizontal \
        -contextHelp "Choosing sparse=4 makes the plots cleaner when the x/y and phases commutation were on during the acquisition. Choose \"no sparsing\" when the special bpm with plane switching and phase commutation is off. sparse=2 can be used to get a clean plot if the offset is removed using the option below."
    APSLabeledEntry .lowerLimit -parent $w -label "Lower Time Limit (ms)" -textVariable FPGATurnHistory(lowerTimeLimit) -width 10
    APSLabeledEntry .upperLimit -parent $w -label "Upper Time Limit (ms)" -textVariable FPGATurnHistory(upperTimeLimit) -width 10
    APSRadioButtonFrame .redoFFT -parent $w -buttonList {Yes No} \
      -label "Reprocess FFT data?" -variable FPGATurnHistory(redoFFT) -valueList {1 0} \
      -orientation horizontal
    APSRadioButtonFrame .plotFFT -parent $w -buttonList {Yes No} \
      -label "Plot the FFT data?" -variable FPGATurnHistory(plotFFT) -valueList {1 0} \
      -orientation horizontal
    APSRadioButtonFrame .fftplane -parent $w -buttonList {x y "both"} \
        -label "FFT Planes"  -variable FPGATurnHistory(redoFFTplaneList)  -valueList {x y "x y"} \
      -orientation horizontal
    APSLabeledEntry .pngfile -parent $w -label "png File Root" -textVariable FPGATurnHistory(pngFileRoot) -width 15 \
        -contextHelp "Root for all plots to be done. FFT files will have fft suffixes."

    set w .fpga.userFrame.f1.slow.frame
    APSRadioButtonFrame .plot -parent $w -buttonList {Yes No} \
        -label "Plot 100 Hz?"  -variable FPGASlowHistory(doPlot)  -valueList {1 0} \
      -orientation horizontal
    APSRadioButtonFrame .plane -parent $w -buttonList {x y "both"} \
        -label "Planes"  -variable FPGASlowHistory(planeList)  -valueList {x y "x y"} \
      -orientation horizontal
    APSLabeledEntry .lowerLimit -parent $w -label "Lower Time Limit (ms)" -textVariable FPGASlowHistory(lowerTimeLimit) -width 10 \
        -contextHelp "limits for relative time from trigger"
    APSLabeledEntry .upperLimit -parent $w -label "Upper Time Limit (ms)" -textVariable FPGASlowHistory(upperTimeLimit) -width 10 \
        -contextHelp "limits for relative time from trigger"
    APSRadioButtonFrame .redoFFT -parent $w -buttonList {Yes No} \
      -label "Reprocess FFT data?" -variable FPGASlowHistory(redoFFT) -valueList {1 0} \
      -orientation horizontal
    APSRadioButtonFrame .plotFFT -parent $w -buttonList {Yes No} \
      -label "Plot the FFT data?" -variable FPGASlowHistory(plotFFT) -valueList {1 0} \
      -orientation horizontal
    APSRadioButtonFrame .fftplane -parent $w -buttonList {x y "both"} \
        -label "FFT Planes"  -variable FPGASlowHistory(redoFFTplaneList)  -valueList {x y "x y"} \
      -orientation horizontal
    APSLabeledEntry .pngfile -parent $w -label "png File Root" -textVariable FPGASlowHistory(pngFileRoot) -width 15 \
        -contextHelp "Root for all plots to be done. FFT files will have fft suffixes."


    set w .fpga.userFrame.f1.turnmovie.frame
    APSRadioButtonFrame .plot -parent $w -buttonList {Yes No} \
        -label "Plot turn-by-turn movie?"  -variable FPGATurnMovie(doPlot)  -valueList {1 0} \
      -orientation horizontal
    APSRadioButtonFrame .plane -parent $w -buttonList {x y "both"} \
        -label "Planes"  -variable FPGATurnMovie(planeList)  -valueList {x y "x y"} \
      -orientation horizontal
    APSLabeledEntry .lowerLimit -parent $w -label "Lower Time Limit (ms)" -textVariable FPGATurnMovie(lowerTimeLimit) -width 10
    APSLabeledEntry .upperLimit -parent $w -label "Upper Time Limit (ms)" -textVariable FPGATurnMovie(upperTimeLimit) -width 10
    APSRadioButtonFrame .versus -parent $w -buttonList {s BPM} \
        -label "x-axis"  -variable FPGATurnMovie(versus)  -valueList {s BPM} \
      -orientation horizontal
    APSLabeledEntry .frameInterval -parent $w -label "Frame Interval (s)" -textVariable FPGATurnMovie(upperTimeLimit) -width 10
    APSLabeledEntry .pngfile -parent $w -label "png File Root" -textVariable FPGATurnMovie(pngFileRoot) -width 15 \
        -contextHelp "Root for all plots to be done. "

    set w .fpga.userFrame.f1.slowmovie.frame
    APSRadioButtonFrame .plot -parent $w -buttonList {Yes No} \
        -label "Plot 100-Hz movie?"  -variable FPGASlowMovie(doPlot)  -valueList {1 0} \
      -orientation horizontal
    APSRadioButtonFrame .plane -parent $w -buttonList {x y "both"} \
        -label "Planes"  -variable FPGASlowMovie(planeList)  -valueList {x y "x y"} \
      -orientation horizontal
    APSLabeledEntry .lowerLimit -parent $w -label "Lower Time Limit (ms)" -textVariable FPGASlowMovie(lowerTimeLimit) -width 10
    APSLabeledEntry .upperLimit -parent $w -label "Upper Time Limit (ms)" -textVariable FPGASlowMovie(upperTimeLimit) -width 10
    APSRadioButtonFrame .versus -parent $w -buttonList {s BPM} \
        -label "x-axis"  -variable FPGASlowMovie(versus)  -valueList {s BPM} \
      -orientation horizontal
    APSLabeledEntry .frameInterval -parent $w -label "Frame Interval (s)" -textVariable FPGASlowMovie(upperTimeLimit) -width 10
    APSLabeledEntry .pngfile -parent $w -label "png File Root" -textVariable FPGASlowMovie(pngFileRoot) -width 15 \
        -contextHelp "Root for all plots to be done. "

    set w .fpga.userFrame.f2.dumphistory.frame
    APSRadioButtonFrame .plot -parent $w -buttonList {Yes No} \
        -label "Plot dump history?"  -variable FPGADumpHistory(doPlot)  -valueList {1 0} \
      -orientation horizontal
    APSRadioButtonFrame .plane -parent $w -buttonList {x y "both"} \
        -label "Planes"  -variable FPGADumpHistory(planeList)  -valueList {x y "x y"} \
      -orientation horizontal
    APSLabeledEntry .lowerLimit -parent $w -label "Lower Time Limit (ms)" -textVariable FPGADumpHistory(lowerTimeLimit) -width 10
    APSLabeledEntry .upperLimit -parent $w -label "Upper Time Limit (ms)" -textVariable FPGADumpHistory(upperTimeLimit) -width 10



    tkwait variable FPGAresponse
    set selectedList ""
    foreach sector $sectorList {
        foreach bpm $itemList {
            set flag fpga${sector}$bpm
            if [set $flag] {
                lappend selectedList S${sector}$bpm
            }
        }
    }
    if {(![llength $selectedList]) && ($FPGADumpHistory(doPlot) == 0)} {
        return -code error "No FPGA bpm selected for plot."
    }
    
    if {$FPGATurnHistory(redoFFT) || $FPGASlowHistory(redoFFT)} {
        global reprocessDialog reprocessFPGAplane turnSumMin turnSumMax slowSumMin slowSumMax
        set reprocessDialog 0
        
        APSDialogBox .reprocess -cancelCommand "set reprocessDialog cancel" -okCommand "set reprocessDialog ok" \
          -name "Reprocess FFT data"
        APSRadioButtonFrame .fftplaneTbt -parent  .reprocess.userFrame -buttonList {x y "both"} \
            -label "FFT Planes for turn-by-turn"  -variable FPGATurnHistory(redoFFTplaneList)  -valueList {x y "x y"} \
            -orientation horizontal
        APSLabeledEntryFrame .turn -parent .reprocess.userFrame -label "Turn sum filter: min/max:" \
          -width 15 -variableList {turnSumMin turnSumMax} -orientation horizontal

        APSRadioButtonFrame .fftplane100Hz -parent  .reprocess.userFrame -buttonList {x y "both"} \
            -label "FFT Planes for 100 Hz"  -variable FPGASlowHistory(redoFFTplaneList)  -valueList {x y "x y"} \
            -orientation horizontal
        APSLabeledEntryFrame .slow -parent .reprocess.userFrame -label "Slow sum filter: min/max:" \
          -width 15 -variableList {slowSumMin slowSumMax} -orientation horizontal
        tkwait variable reprocessDialog
        if {$reprocessDialog=="cancel"} {
            SetMpsDumpReviewStatus "FPGA fft reprocess request was cancelled."
            return
        }
        
        foreach bpm $selectedList {
            foreach plane $FPGATurnHistory(redoFFTplaneList) {
                SetMpsDumpReviewStatus "reprocessing $bpm FPGA fft $plane data..."
                if $FPGATurnHistory(redoFFT) {
                    ReprocessTurnFPGAData -bpm $bpm -plane $plane -turnSumMin $turnSumMin -turnSumMax \
                        $turnSumMax -slowSumMin $slowSumMin -slowSumMax $slowSumMax -dirName $dirName -sparse $FPGATurnHistory(sparse)
                }
            } 
            foreach plane $FPGASlowHistory(redoFFTplaneList) {
                if $FPGASlowHistory(redoFFT) {
                    Reprocess100HzFPGAData -bpm $bpm -plane $plane -turnSumMin $turnSumMin -turnSumMax \
                        $turnSumMax -slowSumMin $slowSumMin -slowSumMax $slowSumMax -dirName $dirName -sparse $FPGATurnHistory(sparse)
                }
            }
        }
    }
    return $selectedList
}

proc ReprocessTurnFPGAData {args} {
    set bpm ""
    set dirName ""
    set plane ""
    set turnSumMin 0
    set turnSumMax 1
    set sparse "-sparse=4"
    APSParseArguments {dirName bpm  plane turnSumMin turnSumMax sparse}

    regexp {(S.*[AB]):P.} $bpm match ioc
    set file0 $dirName/FPGA-${ioc}.turnHistory.sdds.xz
    if {![file exists $file0]} {
        set file0 $dirName/FPGA-${ioc}.turnHistory.sdds.gz
    }
    # Removed sddsbreak -pipe -rowlimit=4096 just before sddsfft
    # wasn't sure why it was needed
    if [catch {exec sddsconvert $file0 -pipe=out \
                   -retain=col,Index,Time,${bpm}*${plane}* \
                   | sddsprocess -pipe $sparse -noWarning \
                   -filter=col,Index,0,1.31071e5 \
                   | sddsfft -pipe=in  $dirName/FPGA-${bpm}.turnHistory.$plane.fft.xz -truncate -nowarnings \
                   -suppressAverage -psdOutput=plain,integrated \
                   -col=Time,${bpm}:${plane} } result] {
        return -code error "Error in doing fft for $bpm $plane turn history: $result."
    }
}

proc Reprocess100HzFPGAData {args} {
    set bpm ""
    set dirName ""
    set plane ""
    set slowSumMin 0
    set slowSumMax 1000
    set sparse "-sparse=4"
    APSParseArguments {dirName bpm turnHistory slowHistory plane slowSumMin slowSumMax}

    regexp {(S.*[AB]):P.} $bpm match ioc
    set file0 $dirName/FPGA-${ioc}.slowHistory.sdds.xz
    if {![file exists $file0]} {
        set file0 $dirName/FPGA-${ioc}.slowHistory.sdds.gz
    }
    if [catch {exec sddsconvert $file0 -pipe=out \
                   -retain=col,Time,${bpm}*${plane}* \
                   | sddsprocess -pipe -filter=col,${bpm}:${plane}sum,$slowSumMin,$slowSumMax \
                   -nowarnings \
                   | sddsfft -pipe=in  $dirName/FPGA-${bpm}.slowHistory.$plane.fft.xz -truncate -nowarnings \
                   -suppressAverage -psdOutput=plain,integrated \
                   -col=Time,${bpm}:${plane} } result] {
        return -code error "Error in doing fft for $bpm $plane slow history: $result"
    }
}

package require Thread

proc PlotFPGABPMHistory {args} {
    set dirName ""
    APSParseArguments {dirName}
    global FPGATurnHistory FPGADumpHistory FPGASlowHistory FPGATurnMovie FPGASlowMovie turnSumMin turnSumMax slowSumMin slowSumMax OAGGlobal

    # In this call a dialog box is presented not
    # just to select the bpms but also the plotting mode.
    if [catch {SelectFPGABpmsToPlot -dirName $dirName} bpmList] {
        SetMpsDumpReviewStatus "Error in selecting FPGA bpm for plot: $bpmList"
        return
    }
    set tmpRoot [APSTmpDir]/[APSTmpString]
    if {$FPGADumpHistory(doPlot)} {
        set fileList [concat [lsort [glob $dirName/FPGA-S??.turnHistory.sdds.xz $dirName/FPGA-S??.turnHistory.sdds.gz]] [lsort [glob $dirName/FPGA-S???.turnHistory.sdds.xz $dirName/FPGA-S???.turnHistory.sdds.gz]]]
        foreach plane $FPGADumpHistory(planeList) {
            set resultFileList ""
            set i 1
            foreach file $fileList {
                set sector [lindex [split [lindex [split $file "."] 0] "-"] end]
                
                # remove offsets
                if {[catch {exec sdds2stream -rows=bare $file} rows]} {
                    continue
                }
                if {$rows == 0} {
                    continue
                }
                set thread($i) [thread::create -joinable]
                thread::send -async $thread($i) "
                    exec sddsconvert $file -pipe=out \
                      -retain=col,TimeRelativeToTrip,${sector}:P\\\[2345\\\]:${plane} \
                      | sddsremoveoffsets -pipe \
                      -col=${sector}:P\?:${plane} -commutationMode=ab2 -fhead=0.3 \
                      | sddsprocess -pipe=in $tmpRoot.$sector.$plane \
                      -filter=col,TimeRelativeToTrip,$FPGADumpHistory(lowerTimeLimit),$FPGADumpHistory(upperTimeLimit)
                    " result
                lappend resultFileList $tmpRoot.$sector.$plane
                incr i   
            }
            set ii 1
            while {$ii < $i} {
                thread::release $thread($ii)
                thread::join $thread($ii)
                incr ii
            }
            set tmpOutput [APSTmpDir]/[APSTmpString]
            if {[llength $resultFileList] > 1} {
                eval exec sddsxref $resultFileList -pipe=out | sddssortcolumn -pipe=in  $tmpOutput -bpmOrder
            } else {
                exec sddssortcolumn $resultFileList $tmpOutput -bpmOrder
            }
            eval file delete $resultFileList
            exec sddsprocess $tmpOutput -pipe=out -proc=S*,standarddeviation,%sStdDev,fhead=0.2 \
              | sddscollapse -pipe \
              | sddscollect -pipe -coll=suff=StdDev \
              | sddssort -pipe -numeric -col=Rootname \
              | tee $tmpOutput.head.rms \
              | sddsprocess -pipe=in $tmpOutput.goodBpms.rms -filter=col,StdDev,1e-6,.08
            exec sddsprocess $tmpOutput.head.rms $tmpOutput.badBpms.rms -filter=col,StdDev,1e-6,.08,!
            set badBpms [exec sdds2stream -col=Rootname $tmpOutput.badBpms.rms]
            exec sddsconvert $tmpOutput $tmpOutput.goodBpms -delet=col,[join $badBpms ,]
            exec sddsprocess $tmpOutput.goodBpms -pipe=out -proc=S*,last,%sLast \
              | sddscollapse -pipe \
              | sddscollect -pipe -coll=suff=Last,col=Orbit \
              | sddsprocess -pipe -edit=col,BPMName,Rootname,%/:x//%/:y// \
              | sddsxref -pipe $OAGGlobal(SRLatticesDirectory)/default/aps.twi \
              -take=s -match=BPMName=ElementName \
              | sddssort -pipe=in $tmpOutput.goodOrbit -col=s
            file delete $tmpOutput.goodBpms $tmpOutput $tmpOutput.badBpms.rms $tmpOutput.head.rms $tmpOutput.goodBpms.rms 
            if {$plane == "x"} {
                set latticeFile $OAGGlobal(SRLatticesDirectory)/default/aps.hrm
                set refFile /home/helios/oagData/sr/orbitControllaw/lattices/default/refMatrices/h.default
            } else {
                set latticeFile $OAGGlobal(SRLatticesDirectory)/default/aps.vrm
                set refFile /home/helios/oagData/sr/orbitControllaw/lattices/default/refMatrices/v.default
            }
            exec sddsxref $tmpOutput.goodOrbit $refFile \
              $tmpOutput.xref -match=BPMName -take=S*
            exec sddsplot -col=s,Orbit -grap=sym,fil,subtype=1 $tmpOutput.goodOrbit -omni \
              -col=s,S* -sep $latticeFile \
              -yscale=id=response &
            exec sddsplot -col=Orbit,S* -axes -grap=sym,fil $tmpOutput.xref -same -sep -layout=6,4 &
            APSAddToTempFileList $tmpOutput.goodOrbit $tmpOutput.xref
        }
    }
    if $FPGATurnHistory(doPlot) {
        #new collected data by IOC
        foreach bpm $bpmList {
            regexp {(S.*[AB]):P.} $bpm match ioc
            set file $dirName/FPGA-${ioc}.turnHistory.sdds.xz
            if {![file exists $file]} {
                set file $dirName/FPGA-${ioc}.turnHistory.sdds.gz
                if {![file exist $file]} {
                    SetMpsDumpReviewStatus "$bpm turn history data not collected."
                    continue
                }
            }
            foreach plane $FPGATurnHistory(planeList) {
                # If there are two fft files, then take the one without the .xz 
                set fftfile $dirName/FPGA-${bpm}.turnHistory.${plane}.fft
                if ![file exist $fftfile] {
                    set fftfile $dirName/FPGA-${bpm}.turnHistory.${plane}.fft.xz
                }
                if ![file exist $fftfile] {
                    ReprocessTurnFPGAData -dirName $dirName -bpm $bpm -plane $plane
                }
                if !$FPGATurnHistory(removeOffset) {
                    exec sddsplot -sep -grap=sym -title=@TurnHistoryTrigTime $file \
                        "-topline=$bpm $plane turn history" \
                        -filter=col,TimeRelativeToTrip,$FPGATurnHistory(lowerTimeLimit),$FPGATurnHistory(upperTimeLimit) \
                        -col=TimeRelativeToTrip,${bpm}:${plane} -legend=spec=position  \
                        -col=TimeRelativeToTrip,${bpm}:${plane}sum -legend=spec=sum  &
                } else {
                    exec sddsconvert $file  -pipe=out -major=col \
                        -retain=col,Index,Time,TimeRelativeToTrip,${bpm}:${plane},${bpm}:${plane}sum \
                        | sddsremoveoffsets -pipe=in $tmpRoot.${bpm}:${plane} \
                        -col=${bpm}:${plane} -commutationMode=ab2 -removeCommutationOffset -fhead=0.3
                     exec sddsplot -sep -grap=dots -title=@TurnHistoryTrigTime $tmpRoot.${bpm}:${plane} \
                        "-topline=$bpm $plane turn history" \
                        -filter=col,TimeRelativeToTrip,$FPGATurnHistory(lowerTimeLimit),$FPGATurnHistory(upperTimeLimit) \
                        -col=TimeRelativeToTrip,${bpm}:${plane} -legend=spec=position  \
                        -col=TimeRelativeToTrip,${bpm}:${plane}sum -legend=spec=sum  &
                }
                if $FPGATurnHistory(plotFFT) {
                    exec sddsplot -split=pages -sep=request "-topline=FFT of $bpm $plane turn history"  $fftfile \
                        -col=f,FFT* -clip=1,1 -filter=col,f,0,200  \
                        -col=f,FFT* -clip=1,1 -filter=col,f,0,5000   \
                        -col=f,FFT* -clip=1,1 -filter=col,f,0,67887.7849  \
                        -col=f,FFT* -clip=1,1 -filter=col,f,0,135775.570  &
                }
            }
        }
    }
    # under construction
    if {$FPGATurnMovie(doPlot) && $FPGATurnHistory(removeOffset)} {
        # use data in /tmp area.
        foreach plane $FPGATurnMovie(planeList) {
            set fileList ""
            foreach bpm $bpmList {
                # these files was created aboev 
                exec sddsprocess $tmpRoot.${bpm}:${plane} $tmpRoot.${bpm}:${plane}.short \
                    -filter=col,TimeRelativeToTrip,$FPGATurnMovie(lowerTimeLimit),$FPGATurnMovie(upperTimeLimit)
                lappend fileList $tmpRoot.${bpm}:${plane}.short
            }
            if {[llength $fileList] < 2} {
                return -code error "Too few bpms selected to make a movie"
            }
            eval exec sddsxref $fileList -pipe=out \
                | sddstranspose -pipe=in $tmpRoot.x.movie
        }
    }
    if $FPGASlowHistory(doPlot) {
        foreach bpm $bpmList {
            regexp {(S.*[AB]):P.} $bpm match ioc
            set file  $dirName/FPGA-${ioc}.slowHistory.sdds.xz
            if {![file exists $file]} {
                set file  $dirName/FPGA-${ioc}.slowHistory.sdds.gz
            }
            if ![file exist $file] {
                SetMpsDumpReviewStatus "$bpm slow beam data not collected."
                continue
            }
            foreach plane {x y} {
                set fftfile $dirName/FPGA-${bpm}.slowHistory.${plane}.fft
                if ![file exist $fftfile] {
                    set fftfile $dirName/FPGA-${bpm}.slowHistory.${plane}.fft.xz
                }
                if ![file exist $fftfile] {
                    Reprocess100HzFPGAData -dirName $dirName -bpm $bpm -plane $plane 
                }
                exec sddsplot -sep  -grap=dots -title=@MotionTrigTime $file \
                    "-topline=$bpm $plane slow beam history" \
                    -filter=col,TimeRelativeToTrip,$FPGASlowHistory(lowerTimeLimit),$FPGASlowHistory(upperTimeLimit) \
                    -col=TimeRelativeToTrip,${bpm}:$plane -legend=spec=position \
                    -col=TimeRelativeToTrip,${bpm}:${plane}sum -legend=spec=sum  &
                if $FPGASlowHistory(plotFFT) {
                    exec sddsplot -sep \
                        "-topline=fft of $bpm $plane slow beam history"  \
                        $fftfile \
                        -col=f,FFT* -clip=1,1  &
                }
            }
        }
    }
    return
}

# this procedure doesn't seem to be called from anywhere. perhaps it is for future capabilities
proc PlotFPGASlowBeamHistory {args} {
    set filename ""
    APSParseArguments {filename}
    exec sddsplot -sep=2 -graph=line,vary -legend -group=namestring -layout=1,2 $filename "-col=TimeRelativeToTrip,(*position,*sum)" &
    set fileroot [file root [file root $filename]]
    set f $fileroot.fft.sdds.xz
    if {![file exists $f]} {
        set f $fileroot.fft.sdds.gz
    }
    if [file exist $f] {
        exec sddsplot -sep -layout=1,4 -same -filename -col=f,SqrtIntegPSD* $f \
          "-leg=edit=%/Sqrt //%/Integ//%/sum//%/position//%/:turnHistory//%/ PSD //" "-topline=FPGA Slow Beam History" &
        exec sddsplot -sep -same -layout=1,4  -filename -col=f,FFT* $f \
          "-leg=edit=%/FFT //" "-topline=FPGA Slow Beam History" &
    }
}

proc MakeDumpPlots {HMSItem doubleClick} {
    global dayDirName dumpDay searchYear searchMonth searchDay mainDataDir xrefDir
    global plotFastHistX plotFastHistY plotFastFFTX plotFastFFTY
    global plotFBCorrErrRange plotFBCorrErrMovie plotFBCorrDriveRange plotFBCorrDriveMovie simulateOrbitFromFBDrives
    global HLimitMin HLimitMax fbLimitMin fbLimitMax showDumpPrintout plotOrbitCorChanges showOrbitComparison
    global FFTLimitMin FFTLimitMax AveMin AveMax plotFBbpmSpatial fbbpmLimitMin fbbpmLimitMax
    global plotNbBpmTime plotFBbpmTime plotFBCorrErrTime plotFBCorrDriveTime plotDPCorrDriveTime
    global plotRFScopeData analyzeFBbpmSpatial plotFPGABPMHistory plotTimeStamps
    global plotTopupGlitchLogData
    if !$doubleClick {
        return
    }
    SetMpsDumpReviewStatus "Working on $HMSItem"
    regsub -all : $HMSItem "" HMS

    SetMpsDumpReviewStatus "Checking for notebook file..."
    SearchForNotebookFile $HMS $HMSItem
    SetMpsDumpReviewStatus "Data located in $dayDirName/$HMS"
    
    set snapfile $dayDirName/$HMS/dumpRecord.snap.xz
    if {![file exists $snapfile]} {
        set snapfile $dayDirName/$HMS/dumpRecord.snap.gz
    }
    if $showDumpPrintout {
        SetMpsDumpReviewStatus "Displaying dump printout..."

        if [catch {MakeDumpPrintout -snapshot $snapfile \
                     -searchMonth $searchMonth -searchDay $searchDay -searchYear $searchYear \
                     -HMSItem $HMSItem} result] {
            SetMpsDumpReviewStatus "MakeDumpPrintout: $snapfile contains invalid data.. $result"
        }
        
    }

    set snapfile $dayDirName/$HMS/dumpTimeStamps.snap.xz
    if {![file exists $snapfile]} {
        set snapfile $dayDirName/$HMS/dumpTimeStamps.snap.gz
    }
    if $plotTimeStamps {
 	if [catch {PlotTimeStamps -snapshot $snapfile \
                     -searchMonth $searchMonth -searchDay $searchDay \
                     -searchYear $searchYear -HMS $HMS} result] {
	    SetMpsDumpReviewStatus "PlotTimeStamps: $snapfile contains invalid data. $result"
	}
    }
    if {$plotFPGABPMHistory} {
        SetMpsDumpReviewStatus "Plotting FPGA bpm turn history..."
        PlotFPGABPMHistory -dirName $dayDirName/$HMS
    }
    if {$plotFastHistX ||  $plotFastHistY || $plotFastFFTX || $plotFastFFTY || \
          $plotFBCorrErrRange || $plotFBCorrErrMovie || $plotFBCorrDriveRange || $simulateOrbitFromFBDrives || \
          $plotOrbitCorChanges || $showOrbitComparison || $plotFBCorrDriveMovie } {
        SetMpsDumpReviewStatus "Displaying fast BPM data and FB correctors..."
        if [catch {PlotFastBPMAndFBCorrectors -HMS $HMS -HMSItem $HMSItem} result] {
            return -code error $result
        }
    }
    
    if $plotFBbpmSpatial {
        SetMpsDumpReviewStatus "Displaying FB BPM spatial plots..."
        if [catch {PlotFBbpmSpatial -dir $dayDirName/$HMS -minTime $fbbpmLimitMin \
                     -maxTime $fbbpmLimitMax } result] {
            return -code error $result
        }
    }

    if {[file exists $dayDirName/$HMS/FBbpmHistory.x.xz]} {
        set xInput $dayDirName/$HMS/FBbpmHistory.x.xz
        set yInput $dayDirName/$HMS/FBbpmHistory.y.xz
    } else {
        set xInput $dayDirName/$HMS/FBbpmHistory.x.gz
        set yInput $dayDirName/$HMS/FBbpmHistory.y.gz
    }
    if $analyzeFBbpmSpatial {
        SetMpsDumpReviewStatus "Applying glitch analysis to FB BPM spatial data..."
        SRFBBeamHistoryGlitchAnalysis -xInput $xInput -yInput $yInput \
          -display 1 -statusCallback SetMpsDumpReviewStatus
    }

    if $plotFBbpmTime {
        SetMpsDumpReviewStatus "Displaying FB BPM time plots..."
        if {[file exist $xInput]} {
            exec sddsplot -layout=1,2 -sep -col=TimeRelativeToTrip,S* -legend=yname \
              "-filter=col,TimeRelativeToTrip,$fbbpmLimitMin,$fbbpmLimitMax" \
              $xInput  -grap=sym,conn -mode=y=offset -same \
              "-topline=Horizontal BPM time-domain (y-offset mode) plot" \
              -title=@TimeStamp -endpanel &
        } else {
            SetMpsDumpReviewStatus "FBbpmHistory.x.gz does not exist!"
        }
        if {[file exist $yInput]} {
            exec sddsplot -layout=1,2 -sep -col=TimeRelativeToTrip,S* -legend=yname \
              "-filter=col,TimeRelativeToTrip,$fbbpmLimitMin,$fbbpmLimitMax" \
              $yInput -grap=sym,conn,type=1 -mode=y=offset -same \
              "-topline=Vertical BPM time-domain (y-offset mode) plot" \
              -title=@TimeStamp -endpanel &
        } else {
            SetMpsDumpReviewStatus "FBbpmHistory.y.gz does not exist!"
        }
    }
    if $plotNbBpmTime {
        SetMpsDumpReviewStatus "Displaying FB Nb BPM time plots..."
        set f $dayDirName/$HMS/NbBpmHistory.xz
        if {![file exists $f]} {
            set f $dayDirName/$HMS/NbBpmHistory.gz
        }
        if {[file exist $f]} {
            exec sddsplot -layout=1,2 -sep -col=TimeRelativeToTrip,S*x -legend=yname \
              "-filter=col,TimeRelativeToTrip,$fbbpmLimitMin,$fbbpmLimitMax" \
              $f  -grap=sym,conn -mode=y=offset -same \
              "-topline=Horizontal BPM time-domain (y-offset mode) plot" \
              -title=@TimeStamp -endpanel &
            exec sddsplot -layout=1,2 -sep -col=TimeRelativeToTrip,S*y -legend=yname \
              "-filter=col,TimeRelativeToTrip,$fbbpmLimitMin,$fbbpmLimitMax" \
              $f  -grap=sym,conn -mode=y=offset -same \
              "-topline=Horizontal BPM time-domain (y-offset mode) plot" \
              -title=@TimeStamp -endpanel &
        } else {
            SetMpsDumpReviewStatus "NbBpmHistory.gz does not exist!"
        }
    }
    if {$plotFBCorrErrTime || $plotFBCorrDriveTime || $simulateOrbitFromFBDrives} {
        set tmpfile [APSTmpDir]/[APSTmpString]
        APSAddToTmpFileList -ID 1 -fileList $tmpfile
        SetMpsDumpReviewStatus "Displaying FB corrector errors or drive movies or simulating orbit from drives."
        set f $dayDirName/$HMS/FBCorrHistory.sdds.xz
        if {![file exists $f]} {
            set f $dayDirName/$HMS/FBCorrHistory.sdds.gz
        }
        if [catch \
                {exec sddsprocess $f -pipe=out \
                     "-filter=col,TimeRelativeToTrip,$fbLimitMin,$fbLimitMax" \
                     | sddsconvert -pipe=in $tmpfile \
                     "-edit=col,S*GB*Corr*,azG/%/GB/S/a%/:Horz/A:H3/%/:Vert/A:V3/" } result] {
            SetMpsDumpReviewStatus "$result"
        } else {
            if $plotFBCorrErrTime {
                exec sddsplot -layout=1,2 -col=TimeRelativeToTrip,S*H*:CorrErr \
                  $tmpfile -sep -grap=sym,conn \
                  -mode=y=offset -same -title=@TimeStamp \
                  "-topline=Horizontal Corrector Error relative to first point" &
                exec sddsplot -layout=1,2  \
                  -col=TimeRelativeToTrip,S*V*:CorrErr \
                  $tmpfile -sep -grap=sym,conn \
                  -mode=y=offset -same -title=@TimeStamp \
                  "-topline=Vertical Corrector Error relative to first point" &
            }
            if $plotFBCorrDriveTime {
                exec sddsplot -layout=1,2 -col=TimeRelativeToTrip,S*H*Drive \
                  $tmpfile -sep -grap=sym,conn \
                  -mode=y=offset -same -title=@TimeStamp \
                  "-topline=FB Horizontal Corrector Drive relative to first point" &
                exec sddsplot -layout=1,2 -col=TimeRelativeToTrip,S*V*Drive \
                  $tmpfile -sep -grap=sym,conn \
                  -mode=y=offset -same -title=@TimeStamp \
                  "-topline=FB Vertical Corrector Drive relative to first point" &
            }
            if $simulateOrbitFromFBDrives {
# multiply corrector vector with reponse matrix
                set response /home/helios/oagData/sr/orbitControllaw/lattices/default/refMatrices/h.default
                # make list of correctors
                set corrList [exec sddsquery -col $tmpfile | grep CorrDrive | grep H | sed s/:CorrDrive// ]
                if [catch {exec sddsconvert $response $tmpfile.response \
                               -retain=col,[join $corrList ,]} result] {
                    return -code error "$result"
                }
                set corrList2 [exec sddsquery -col $tmpfile | grep CorrDrive | grep H ]
                if [catch {exec sddsconvert $tmpfile -pipe=out \
                               -retain=col,[join $corrList2 ,] \
                               | sddsprocess -pipe \
                               -proc=S*,average,%sAve,fhead=0.5 \
                               "-redef=col,%s,%s %sAve -,select=S*" \
                               | sddsconvert -pipe=in  $tmpfile.FBdata \
                               -dele=para,* \
                           } result] {
                    return -code error "$result"
                }
                # I have to explicitly remove from the FB data some
                # correctors that are not in the response matrix. These
                # correctors have zero values in the data anyways.
                if [catch {exec sddsconvert $tmpfile.FBdata -noWarning \
                               -delete=col,S1A:?3*,S40A:?3*} result] {
                    return -code error "$result"
                }
                # suppose S38A:H3 tripped
                # if [catch {exec sddsprocess $tmpfile.FBdata -noWarning \
                #                -redef=col,%s,0,sel=S36A:H3*} result] {
                #     return -code error "$result"
                # }
                # are there the same number of correctors in the two files?
                set ncol1 [exec sddsquery -col $tmpfile.response | wc -l]
                set ncol2 [exec sddsquery -col $tmpfile.FBdata | wc -l]
                if {$ncol1 != $ncol2} {
                    return -code error "Problem in simulating orbits: The number of correctors in the response matrix is $ncol1, while the number of correctors in the FB data is $ncol2. ?!?"
                }
                # Here we dangerously assume that the order of correctors in $tmpfile.response is the same as in the FB file $tmpfile
                if [catch {exec sddsmatrixop $tmpfile.response $tmpfile.orbits -push=$tmpfile.FBdata -transpose -mult} result] {
                    return -code error "Problem in simulating orbits: $result"
                }
                # Add back the time, s, BPMName for plottings
                #if [catch {exec sddsquery $tmpfile.orbits > /dev/tty} result] {
                #    return -code error "Problem in simulating orbits: $result"
                #}
                #remove above request by Greg, because It is trying to output to
                # a controlling terminal the usually does not exist (if launched from OAGapps, the gnome menu, or if in the background). 
                if [catch {exec sddsprocess $tmpfile.orbits -pipe=out \
                               | sddsxref -pipe $response \
                               -take=BPMName \
                               | sddstranspose -pipe \
                               -newColumn=BPMName -oldColumn=doubleColumns \
                               | sddsxref -pipe $tmpfile \
                               -take=Index,TimeRelativeToTrip \
                               | sddsconvert -pipe=in $tmpfile.orbits.full \
                               -dele=col,doubleColumns \
                           } result] {
                    return -code error "Problem in simulating orbits: $result"
                } 
                if [catch {exec sddsplot -layout=1,2 -sep -axe=x -same \
                               -grap=sym,conn=sub,vary=sub \
                               -col=TimeRelativeToTrip,S*:P? $tmpfile.orbits.full &} result] {
                    return -code error "Problem in simulating orbits: $result"
                }
                # note that the -group=namestring sorts the bpm
                # alphabetically not in the order they appear in the
                # file. So the B:P? bpm are reversed here.
                if [catch {exec sddsplot -layout=1,2 \
                               -sep=namestring -group=namestring \
                               -axe=x -same \
                               -col=TimeRelativeToTrip,S*:P? FBbpmHistory.x.xz \
                               -mode=y=offset -leg=spec=data \
                               -grap=sym,sub=0,conn=sub \
                               -col=TimeRelativeToTrip,S*:P? $tmpfile.orbits.full -leg=spec=sim \
                               -grap=sym,sub=1,conn=sub \
                               &} result] {
                    return -code error "Problem in simulating orbits: $result"
                } 
            }
        }
    }
    if $plotDPCorrDriveTime {
        SetMpsDumpReviewStatus "Displaying datapool time plots..."
        set f $dayDirName/$HMS/DPCorrHistory.sdds.xz
        if {![file exists $f]} {
            set f $dayDirName/$HMS/DPCorrHistory.sdds.gz
        }
        foreach index {1 2 3 4} {
            exec sddsplot -sep -layout=1,2 -same -mode=y=offset \
              -tick=xtime -axe=x $f \
              "-topline=DP Horizontal Corrector Error relative to first point" \
              -title=@TimeStamp \
              -col=HTimeStamps,S*B:H$index  -col=HTimeStamps,S*A:H$index &
            exec sddsplot -sep -layout=1,2 -same -mode=y=offset \
              -tick=xtime -axe=x $f \
              "-topline=DP Vertical Corrector Error relative to first point" \
              -title=@TimeStamp \
              -col=VTimeStamps,S*B:V$index  -col=HTimeStamps,S*A:V$index &
        }
    }
    if $plotRFScopeData {
        set scopeDataFile $dayDirName/$HMS/tds3054_rf.sdds.xz
        if {![file exists $scopeDataFile]} {
            set scopeDataFile $dayDirName/$HMS/tds3054_rf.sdds.gz
        }
        if [file exists $scopeDataFile] {
            set options ""
            foreach station {1 2 3 4} {
                set scope S${station}:K
                foreach channel {1 2 3 4} {
                    append options " -col=${scope}:scaledTimeAxisWF,${scope}:chan${channel}ScaledWaveWF"
                    append options " \"-xlabel=Time (msec)\" \"-ylabel=Channel $channel (div.)\" \"-topline=Scope $scope,sca=2\""
                }
            }
            eval exec sddsplot $scopeDataFile \
              -layout=1,4 \
              -sep \"-xlabel=Time (msec)\" -factor=xmult=1e-3 \
              "-title=" \
              $options  &
        } else {
            SetMpsDumpReviewStatus "File $scopeDataFile not found."
        }
        set scopeDataFile $dayDirName/$HMS/tds3000_rf.sdds.xz
        if {![file exists $scopeDataFile]} {
            set scopeDataFile $dayDirName/$HMS/tds3000_rf.sdds.gz
        }

        if [file exists $scopeDataFile] {

            set waveformPV "{RF1:HV:scaledTimeAxisWF} {RF1:HV:chan1ScaledWaveWF} {RF1:HV:chan2ScaledWaveWF} {RF1:HV:chan3ScaledWaveWF} {RF1:HV:chan4ScaledWaveWF} {RF1:LL:scaledTimeAxisWF} {RF1:LL:chan1ScaledWaveWF} {RF1:LL:chan2ScaledWaveWF} {RF1:LL:chan3ScaledWaveWF} {RF1:LL:chan4ScaledWaveWF} {RF2:HV:scaledTimeAxisWF} {RF2:HV:chan1ScaledWaveWF} {RF2:HV:chan2ScaledWaveWF} {RF2:HV:chan3ScaledWaveWF} {RF2:HV:chan4ScaledWaveWF} {RF2:LL:scaledTimeAxisWF} {RF2:LL:chan1ScaledWaveWF} {RF2:LL:chan2ScaledWaveWF} {RF2:LL:chan3ScaledWaveWF} {RF2:LL:chan4ScaledWaveWF} {RF3:HV:scaledTimeAxisWF} {RF3:HV:chan1ScaledWaveWF} {RF3:HV:chan2ScaledWaveWF} {RF3:HV:chan3ScaledWaveWF} {RF3:HV:chan4ScaledWaveWF} {RF3:LL:scaledTimeAxisWF} {RF3:LL:chan1ScaledWaveWF} {RF3:LL:chan2ScaledWaveWF} {RF3:LL:chan3ScaledWaveWF} {RF3:LL:chan4ScaledWaveWF} {RF4:HV:scaledTimeAxisWF} {RF4:HV:chan1ScaledWaveWF} {RF4:HV:chan2ScaledWaveWF} {RF4:HV:chan3ScaledWaveWF} {RF4:HV:chan4ScaledWaveWF} {RF4:LL:scaledTimeAxisWF} {RF4:LL:chan1ScaledWaveWF} {RF4:LL:chan2ScaledWaveWF} {RF4:LL:chan3ScaledWaveWF} {RF4:LL:chan4ScaledWaveWF}"

            set waveformLabel "{RF1:HV:time} {RF1:Cathode:V} {RF1:Cathode:I} {RF1:Anode:V} {RF1:Anode:I} {RF1:LL:time} {RF1:LL:Source} {RF1:LL:ModOut} {RF1:LL:Driver} {RF1:LL:CavSum} {RF2:HV:time} {RF2:Cathode:V} {RF2:Cathode:I} {RF2:Anode:V} {RF2:Anode:I} {RF2:LL:time} {RF2:LL:Source} {RF2:LL:ModOut} {RF2:LL:Driver} {RF2:LL:CavSum} {RF3:HV:time} {RF3:Cathode:V} {RF3:Cathode:I} {RF3:Anode:V} {RF3:Anode:I} {RF3:LL:time} {RF3:LL:Source} {RF3:LL:ModOut} {RF3:LL:Driver} {RF3:LL:CavSum} {RF4:HV:time} {RF4:Cathode:V} {RF4:Cathode:I} {RF4:Anode:V} {RF4:Anode:I} {RF4:LL:time} {RF4:LL:Source} {RF4:LL:ModOut} {RF4:LL:Driver} {RF4:LL:CavSum}"

            set options ""
            foreach station {1 2 3 4} {
                set scope RF${station}:LL
                foreach channel {1 2 3 4} color {2 6 14 3} {
                    append options " -col=${scope}:scaledTimeAxisWF,${scope}:chan${channel}ScaledWaveWF"
                    append options " -graph=line,type=$color"
                    set i [lsearch -exact $waveformPV ${scope}:chan${channel}ScaledWaveWF]
                    if {$i == -1} {
                        append options " \"-ylabel=Channel $channel (div.)\""
                    } else {
                        append options " \"-ylabel=[lindex $waveformLabel $i]\" \"-legend=specified=[lindex $waveformLabel $i],scale=2\" \"-title=[lindex $waveformLabel $i],edit=%g/:/ /\""
                    }
                    append options " -end"
                }
            }
            foreach station {1 2 3 4} {
                set scope RF${station}:HV
                foreach channel {1 2 3 4} color {0 1 2 3}  {
                    append options " -col=${scope}:scaledTimeAxisWF,${scope}:chan${channel}ScaledWaveWF"
                    append options " -graph=line,type=$color"
                    set i [lsearch -exact $waveformPV ${scope}:chan${channel}ScaledWaveWF]
                    if {$i == -1} {
                        append options " \"-ylabel=Channel $channel (div.)\""
                    } else {
                        append options " \"-ylabel=[lindex $waveformLabel $i]\" \"-legend=specified=[lindex $waveformLabel $i],scale=2\" \"-title=[lindex $waveformLabel $i],edit=%g/:/ /\""
                    }
                    append options " -end"
                }
            }
            eval exec sddsplot $scopeDataFile \
              -layout=1,4 \
              -sep \"-xlabel=Time (msec)\" -factor=xmult=1e-3 -sameScale=x,global -tickSetting=xgrid,ygrid -topTitle \
              "-title=" \
              $options  &
        } else {
            SetMpsDumpReviewStatus "File $scopeDataFile not found."
        }
    }
    if $plotTopupGlitchLogData {
        # determine if there is a file in the topup glitch log area 
        set glitchLogDir /home/helios/oagData/glitchLogs/TopUp
        # do something with dumpDay dayDirName HMSList
        if [catch {regexp  {(..):(..):(..)} $HMSItem match hour min sec} result] {
             SetMpsDumpReviewStatus "Error: can't determine time from $HMSItem"
        }
        set logFile [lindex [glob $glitchLogDir/TopUp-$dumpDay*] 0]
        if ![file exists $logFile] {
            SetMpsDumpReviewStatus "Error: can't file file $logFile"
        } else {
            SetMpsDumpReviewStatus "Located file $logFile for plotting..."
            set w .widget[APSUniqueNumber]
            APSDialogBox $w -name "Topup glictch plotting parameters" \
              -okCommand "set TopupGlitchPlotStatus 0" \
              -cancelCommand "set TopupGlitchPlotStatus 1" \
              -modal 0
            global TopupGlitchBefore TopupGlitchAfter TopupGlitchPlotStatus
            APSLabeledEntry .before -parent $w.userFrame -label "Seconds before dump: " -width 10 -textVariable TopupGlitchBefore \
              -contextHelp "For time plot range, number of seconds before the trip."
            APSLabeledEntry .after -parent $w.userFrame -label "Seconds after dump: " -width 10 -textVariable TopupGlitchAfter \
              -contextHelp "For time plot range, number of seconds after the trip."
            tkwait variable TopupGlitchPlotStatus
           if $TopupGlitchPlotStatus==1 return
            # get time from snapfile
            set dumpTime [exec sdds2stream -para=Time $snapfile]
            # these after and before times are the time filters. Reversed meaning.
            set afterTime [clock format [expr int($dumpTime - $TopupGlitchBefore)] -format %Y/%m/%d@%H:%M:%S]
            set beforeTime [clock format [expr int($dumpTime + $TopupGlitchAfter)] -format %Y/%m/%d@%H:%M:%S]
            exec sddsplot $logFile \
              -tick=xtime -sev=xgap=10 \
              -time=col,Time,after=$afterTime,before=$beforeTime \
              -layout=2,4 \
              -col=Time,S*:cerenkovCount   -sep -grap=sym,vary=sub,sca=1,fil \
              -col=Time,S35DCCT  -omni -grap=line,type=1 -yscal=id=DCCT &

        }
   }
    SetMpsDumpReviewStatus "Done."
}

proc PlotFBbpmSpatial {args} {
    set dir ""
    set minTime ""
    set maxTime ""
    APSStrictParseArguments {dir minTime maxTime}
    
    global plotFBbpmSpatial plotFBbpmTimeDomain
    set tmpfile [APSTmpDir]/[APSTmpString]
    APSAddToTmpFileList -ID MPSDumpReview -fileList "$tmpfile.x $tmpfile.y"
    
    set fx $dir/FBbpmHistory.x.xz
    set fy $dir/FBbpmHistory.y.xz
    if {![file exists $fx]} {
        set fx $dir/FBbpmHistory.x.gz
        set fy $dir/FBbpmHistory.y.gz
    }
    if {[file exist $fx] && [file exist $fy]} {
        foreach plane {x y} {
            if [catch {exec sddsprocess [set f${plane}] \
                         -filter=col,TimeRelativeToTrip,$minTime,$maxTime -pipe=out \
                         "-process=S*P*,first,%sFirst" \
                         "-redef=col,%s,%s %sFirst -,select=S*P*" \
                         | sddsbreak -pipe -changeof=Index \
                         | sddsprocess -pipe \
                         -process=TimeRelativeToTrip,first,%s \
                         "-print=par,PlotLabel,Time relative to trip: %f ms,TimeRelativeToTrip" \
                         | sddsconvert -pipe -delete=col,Index,TimeRelativeToTrip \
                         | sddstranspose -pipe \
                         | sddsconvert -pipe=in -rename=col,OldColumnNames=BPMName,Column=Orbit \
                         $tmpfile.$plane } result] {
                return -code error $result
            }
            set ylabel "[string toupper $plane]-orbit relative to the first point(mm)"
            exec sddsplot -layout=1,1 -graph=sym,type=1,conn,sub=1 -enumeratedScale=interval=10 \
              -split=page -sep=page -same "-topline=@PlotLabel" -title=@TimeStamp \
              -xlabel=BPMName "-col=BPMName,Orbit" "-ylabel=$ylabel" $tmpfile.$plane &
        }
    } else {
        SetMpsDumpReviewStatus "The bpm history files do not exist!"
        return
    }
}


proc PlotTimeStamps {args} {
    global mpsDumpReviewStatus
    APSParseArguments {snapshot searchMonth searchDay searchYear HMS}

    set tmpRoot [APSTmpDir]/[APSTmpString]-mpsDumpReview
    if {[string length $searchMonth] == 1} {set searchMonth 0$searchMonth}
    if {[string length $searchDay] == 1} {set searchDay 0$searchDay}
    set searchYearAbbr [string range $searchYear 2 3]
    set filterDate $searchMonth/$searchDay/$searchYear
    set filterDateAbbr $searchMonth/$searchDay/$searchYearAbbr
    set filterHour [string range $HMS 0 1]
    # some EPICS time stamp PVs have a  mixture of 4-digit date and 2-digit date
    # in order to pose a challenge
    if [catch {exec sddsprocess $snapshot $tmpRoot -match=col,ValueString=*${filterDate}*,ValueString=*${filterDateAbbr}*,| \
                   -match=col,ValueString=*${filterHour}:* \
                   -match=col,ControlName=*MPS:inp*,ControlName=S:MPS:llrfSrcLossTimeSI,| \
                   "-edit=col,ValueString1,ValueString,%@\"@@ %@\"@@ %@$filterDate @@%@$filterDateAbbr @@ a 6d" \
                   -scan=col,TimeStamp,ValueString1,%lf,units=s } result] {
    	return -code error "PlotTimeStamps(0):$result"
    }
    set fileLength [exec sdds2stream $tmpRoot -row=bare]
    if [catch {exec sddsprocess $snapshot -pipe=out -match=col,ValueString=*${filterDate}*,ValueString=*${filterDateAbbr}*,| \
                 -match=col,ValueString=*${filterHour}:* \
                 -match=col,ControlName=S:MPS:llrfSrcLossTimeSI \
                 "-edit=col,ValueString1,ValueString,%@\"@@ %@\"@@ %@$filterDate @@%@$filterDateAbbr @@ a 6d" \
                 -scan=col,TimeStamp,ValueString1,%lf,units=s \
                 | sdds2stream -pipe=in -col=TimeStamp} rfTripTime] {
	return -code error "Error reading rf trip time: $rfTripTime"
    }
    # pspace to make the string more readable
    exec sddsplot $tmpRoot -col=ControlName,TimeStamp -graph=symbol -title=$filterDate@$HMS \
      -drawLine=p0value=0,p1value=1,y0value=$rfTripTime,y1value=$rfTripTime \
      "-topline=Solid line is rf trip time" -pspace=0.15,0.95,0.45,0.95 &
}

proc PlotFastBPMAndFBCorrectors {args} {
    global dayDirName searchYear searchMonth searchDay mainDataDir xrefDir OAGGlobal
    global plotFastHistX plotFastHistY plotFastFFTX plotFastFFTY
    global plotFBCorrErrRange plotFBCorrErrMovie plotFBCorrDriveRange plotFBCorrDriveMovie
    global HLimitMin HLimitMax fbLimitMin fbLimitMax showDumpPrintout plotOrbitCorChanges showOrbitComparison
    global FFTLimitMin FFTLimitMax AveMin AveMax 
    set HMS ""
    set HMSItem ""
    APSParseArguments {HMS HMSItem}

    set oldDir [pwd]
    cd $dayDirName/$HMS
    set planeList [list x y]

    if $HLimitMin==$HLimitMax {
        set HLimitMin 0
        set HLimitMax 0
    }
    if {$HLimitMin>$HLimitMax} {
        SetMpsDumpReviewStatus "Minimum limit ($HLimitMin) exceeds maximum limit ($HLimitMax)."
        return
    }
    if {$HLimitMin<0} {
        set HLimitMin 0
    }
    if {$HLimitMax>=2048} {
        set HLimitMax 2047
    }
    if {$HLimitMin==0 && $HLimitMax==0} {
        set HLimitMax 2047
    } 

    # create files of normal orbit readback for bpm histories.
    if [file exists bpmSetpoints] {
        set SCRfile bpmSetpoints
    } else {
        set SCRfile /home/helios/oagData/SCR/snapshots/SR/SR-UserBeamPreferred.gz
    }
    set tmproot [APSTmpDir]/[APSTmpString]
    set xAveFile $tmproot-xAve
    set yAveFile $tmproot-yAve
    set dataFiles [glob -nocomplain FPGA-S*.slowHistory.sdds*]
    set fileList ""
    if [llength $dataFiles] {
        foreach file $dataFiles {
            if [catch {exec sdds2stream $file -rows=bare} rows] {
                SetMpsDumpReviewStatus "Problem with file $file: $rows"
            }
            if {$rows == 0} continue
            if [catch {regexp {FPGA-(.*).slowHistory} $file match hSector} result] {
                SetMpsDumpReviewStatus "Problem with regexp on $file: $result"
                return -code error
            }
            if [catch {exec sddsprocess $file -pipe=out \
                           -filter=col,Index,$AveMin,$AveMax \
                           -process=S*:P\[2345\]:?,average,%sAve \
                           | sddscollapse -pipe \
                           | sddscollect -pipe=in $tmproot-$hSector.ave \
                           -coll=suff=:xAve,col=xAverageOrbit -coll=suff=:yAve,col=yAverageOrbit \
                       } result ] {
                SetMpsDumpReviewStatus "Problem with file $file: $result"
            } 
            lappend fileList  $tmproot-$hSector.ave
        }
        foreach plane {x y} {
            eval exec sddscombine $fileList -pipe=out -merge \
                | sddsxref -pipe $OAGGlobal(SRLatticesDirectory)/default/aps.twi -noWarn \
                -take=s -match=Rootname=ElementName \
                | sddssort -pipe \
                -col=s \
                | sddsconvert -pipe \
                -dele=col,ElementName \
                | sddsprocess -pipe \
                -print=col,SetpointName,%s:ms:$plane:SetpointAO,Rootname \
                -print=col,OffsetName,%s:ms:$plane:OffsetAO,Rootname \
                | sddsxref -pipe $SCRfile  -noWarn \
                -take=ValueString -match=SetpointName=ControlName \
                | sddsprocess -pipe \
                -scan=col,${plane}SetpointValue,ValueString,%lf \
                | sddsconvert -pipe=in $tmproot-${plane}Ave \
                -dele=col,ValueString
            # Add the setpoint and offset to recontruct the
            # expected raw readback for the bpms
            exec sddsxref $tmproot-${plane}Ave $SCRfile -pipe=out -noWarn \
              -take=ValueString -match=OffsetName=ControlName \
              | sddsprocess -pipe=in $tmproot-${plane}Ave.1 \
              -scan=col,${plane}OffsetValue,ValueString,%lf \
              "-def=col,${plane}ExpectedReadback,${plane}OffsetValue ${plane}SetpointValue +,units=mm,description=Expected readback value inferred from setpoints and offsets of SR UserBeamPreferred file." \
              "-def=col,${plane}OrbitDifference,${plane}AverageOrbit ${plane}ExpectedReadback -,units=mm,description=Difference between BPM history orbit and standard orbit."
            file rename -force -- $tmproot-${plane}Ave.1 $tmproot-${plane}Ave
        }
        foreach plane $planeList {
            if [file exists $tmproot-${plane}Ave] {
                set bpmList [exec sdds2stream $tmproot-${plane}Ave -col=Rootname]
                set orbitList [exec sdds2stream $tmproot-${plane}Ave -col=${plane}ExpectedReadback]
                set plotRequest ""
                foreach bpm $bpmList orbit $orbitList {
                    regexp {S(.*)([AB]):P.} $bpm match sector half
                    set dataFile FPGA-S${sector}${half}.slowHistory.sdds
                    if {![file exists $dataFile]} {
                        set dataFile ${dataFile}.gz
                    }
                    append plotRequest " -col=Index,${bpm}:${plane} $dataFile -grap=line,type=0,thick=2"
                    append plotRequest " -filter=col,${bpm}:${plane}sum,-1000,200,!"
                    append plotRequest " -col=Index,${bpm}:${plane} $dataFile -grap=dots,type=2"
                    append plotRequest " -filter=col,${bpm}:${plane}sum,-1000,200"
                    append plotRequest " -drawLine=x0value=$HLimitMin,x1value=$HLimitMax,y0value=$orbit,y1value=$orbit,linetype=1,thickness=1 -zoom=yfac=0.75,qcent=0.5 -endpanel"
                }
                eval exec sddsplot -layout=2,4,limit=7 \
                  -scales=$HLimitMin,$HLimitMax,0,0 \
                  \"-topline=MPS Dump: $searchMonth/$searchDay/$searchYear at $HMSItem\" \
                  $plotRequest \
                  -title= \
                  &
                SetMpsDumpReviewStatus "Launched plot of [llength $dataFiles] files for $plane."
            }
        } 
    } else {
        SetMpsDumpReviewStatus "No files matching FPGA-S*.slowHistory.sdds*"
    }
    
    
    if {$plotFastFFTX && $plotFastFFTY} {
        set planeFFTList [list x y]
    } elseif {$plotFastFFTX} {
        set planeFFTList x
    } elseif {$plotFastFFTY} {
        set planeFFTList y
    } else {
        set planeFFTList ""
    }
    if [expr $FFTLimitMin>$FFTLimitMax] {
        set FFTLimitMin 0
        set FFTLimitMax 0
    }
    if [expr $FFTLimitMax>67.9] {
        set FFTLimitMax 67.9
    }
    foreach FFTplane $planeFFTList {
        set dataFiles [glob -nocomplain *-$FFTplane.sdds*]
        set ordDataFiles [lsort $dataFiles]
        set tmpFile [APSTmpDir]/[APSTmpString]
        APSAddToTempFileList $tmpFile.1
        
        if {$HLimitMin==0 && $HLimitMax==0} {
            set HLimitMax 2047
        } 

        if {[llength $dataFiles] != 0} {
            if [catch {eval exec sddscombine $ordDataFiles -pipe=out \
                         | tee $tmpFile.1a \
                         | sddsprocess -pipe \
                         -define=parameter,factor,7.365095e-6 \
                         \"-define=column,t,index factor *,units=s\" \
                         -filter=col,index,$HLimitMin,$HLimitMax \
                         -nowarning \"-test=param,n_rows 10 > \" \
                         | sddsfft -pipe \
                         -column=t,${FFTplane} -truncate -suppressAverage \
                         -window=hanning -noWarnings \
                         | sddsxref -pipe=in $tmpFile.1a $tmpFile.1 -leave=* -transfer=param,* \
                     } results] {
                SetMpsDumpReviewStatus "$results"
            }

            eval exec sddsplot -split=page -sep=page \
              \"-scales=[expr $FFTLimitMin*1e3],[expr $FFTLimitMax*1e3],0,0\" \
              -title=@Filename,edit=%/.gz//%/.xz//%/.sdds//%/-x//%/-y// \
              \"-topline=MPS Dump: $searchMonth/$searchDay/$searchYear at $HMSItem \" \
              -groupby=filestring,namestring -separate \
              -column=f,FFT${FFTplane} $tmpFile.1 -end &

            SetMpsDumpReviewStatus "Launched plot of [llength $dataFiles] files for $FFTplane."
        } else {
            SetMpsDumpReviewStatus "No files for plane $FFTplane---try again later."
        }
    }


    if {$plotFBCorrErrRange || $plotFBCorrErrMovie || $plotFBCorrDriveRange || $plotFBCorrDriveMovie} {
        set tmpFile [APSTmpDir]/[APSTmpString]
        set f FBCorrHistory.sdds.xz
        if {![file exists $f]} {
            set f FBCorrHistory.sdds.gz
        }
        if ![file exists $f] {
            SetMpsDumpReviewStatus "No file found for feedback system corrector history."
            SetMpsDumpReviewStatus "Try again later."
        } else {
            if $plotFBCorrErrRange {
                if [catch \
                      {exec sddsprocess $f -pipe=out \
                         "-filter=col,TimeRelativeToTrip,$fbLimitMin,$fbLimitMax" \
                         "-process=*CorrErr,first,%sFirst" \
                         "-redef=col,%s,%s %sFirst -,select=*CorrErr" \
                         | sddsconvert -pipe "-del=col,*" "-retain=col,*Err" \
                         | sddstranspose -pipe \
                         | sddsprocess -pip=in $tmpFile.1 \
                         "-edit=col,magnet,OldColumnNames,azG/%/GB/S/%/:CorrErr//a%/:Horz/A:H3/%/:Vert/A:V3/"\
                         "-scan=col,Sector,magnet,S%d,type=long" \
                         "-define=column,StaggeredSector,Sector i_row 256 / +,type=float" \
                         "-print=parameter,PlotLabel,TimeStamp of Feedback MPS trip: %s,MPSTripTimeStamp"} result] {
                    SetMpsDumpReviewStatus "$result"
                } else {
                    exec sddsplot $tmpFile.1 -lay=1,2 \
                      "-col=StaggeredSector,Column*" "-match=col,magnet=*H3" \
                      -pspace=0.15,0.9,0.2,0.85 \
                      "-topl=Evolution of Horizontal Corrector Errors,scale=1.2" \
                      -graph=impulse,type=1 \
                      -xlabel=Sector "-ylabel=Corrector Error (A)" "-title=@PlotLabel" \
                      -endp \
                      "-col=StaggeredSector,Column*" "-match=col,magnet=*V3" \
                      -pspace=0.15,0.9,0.25,0.9 \
                      "-topl=Evolution of Vertical Corrector Errors,scale=1.2" \
                      -graph=impulse,type=1 \
                      -xlabel=Sector "-ylabel=Corrector Error (A)" \
                      "-title=@PlotLabel" \
                      -endp &
                }
            }
            if $plotFBCorrDriveRange {
                if [catch \
                      {exec sddsprocess $f -pipe=out \
                         -filter=col,TimeRelativeToTrip,$fbLimitMin,$fbLimitMax \
                         -process=*CorrDrive,first,%sFirst \
                         "-redef=col,%s,%s %sFirst -,select=*CorrDrive" \
                         | sddsconvert -pipe "-del=col,*" "-retain=col,*Drive" \
                         | sddstranspose -pipe \
                         | sddsprocess -pip=in $tmpFile.1 \
                         -edit=col,magnet,OldColumnNames,azG/%/GB/S/%/:CorrDrive//a%/:Horz/A:H3/%/:Vert/A:V3/ \
                         -scan=col,Sector,magnet,S%d,type=long \
                         "-define=column,StaggeredSector,Sector i_row 256 / +,type=float" \
                         "-print=parameter,PlotLabel,TimeStamp of Feedback MPS trip: %s,MPSTripTimeStamp" \
                     } result] {
                    SetMpsDumpReviewStatus "$result"
                } else {
                    exec sddsplot $tmpFile.1 -lay=1,2  \
                      -col=StaggeredSector,Column* -match=col,magnet=*H3 \
                      "-topl=Evolution of Horizontal Corrector Drives" \
                      -graph=impulse,type=1 \
                      -xlabel=Sector "-ylabel=Corrector Drive (A)" "-title=@PlotLabel" \
                      -endp \
                      -col=StaggeredSector,Column* -match=col,magnet=*V3 \
                      "-topl=Evolution of Vertical Corrector Drives" \
                      -graph=impulse,type=1 \
                      -xlabel=Sector "-ylabel=Corrector Drive (A)" \
                      -title=@PlotLabel \
                      -endp &
                }
            }
            if $plotFBCorrErrMovie {
                if [catch {exec sddsprocess $f $tmpFile.2 \
                             "-filter=col,TimeRelativeToTrip,$fbLimitMin,$fbLimitMax" \
                             "-process=*CorrErr,first,%sFirst" \
                             "-print=parameter,PlotLabel,TimeStamp of Feedback MPS trip: %s,MPSTripTimeStamp" \
                             "-redef=col,%s,%s %sFirst -,select=*CorrErr" } result] {
                    SetMpsDumpReviewStatus "$result"
                } else {
                    exec sddsplot \
                      -pspace=0.15,0.9,0.25,0.9 \
                      -groupby=subpage,req -sep=request -layout=1,2 -graph=impulse,type=1 \
                      -same=y  "-title=@PlotLabel" -transpose -xlabel=Sector -offset=xChange=1 \
                      "-col=TimeRelativeToTrip,*Horz*Err*" $tmpFile.2 \
                      "-ylabel=Horizontal Delta Error (A)" \
                      "-col=TimeRelativeToTrip,*Vert*Err*"  $tmpFile.2 \
                      "-ylabel=Vertical Delta Error (A)" \
                      "-title=@PlotLabel" &
                }
            }
            if $plotFBCorrDriveMovie {
                if [catch {exec sddsprocess $f $tmpFile.2 \
                             "-filter=col,TimeRelativeToTrip,$fbLimitMin,$fbLimitMax" \
                             "-process=*CorrDrive,first,%sFirst" \
                             "-print=parameter,PlotLabel,TimeStamp of Feedback MPS trip: %s,MPSTripTimeStamp" \
                             "-redef=col,%s,%s %sFirst -,select=*CorrDrive" } result] {
                    SetMpsDumpReviewStatus "$result"
                } else {
                    exec sddsplot \
                      -pspace=0.15,0.9,0.25,0.9 \
                      -groupby=subpage,req -sep=request -layout=1,2 -graph=impulse,type=1 \
                      -same=y  "-title=@PlotLabel" -transpose -xlabel=Sector -offset=xChange=1 \
                      "-col=TimeRelativeToTrip,*Horz*Drive*" $tmpFile.2 \
                      "-ylabel=Horizontal Delta Drive (A)" \
                      "-col=TimeRelativeToTrip,*Vert*Drive*"  $tmpFile.2 \
                      "-ylabel=Vertical Delta Drive (A)" \
                      "-title=@PlotLabel" &
                }
            }
        }
    }
    
    if $plotOrbitCorChanges {
        set tmpRoot [APSTmpDir]/[APSTmpString]
        APSAddToTempFileList $tmpRoot.x $tmpRoot.y
        set plotOK 1
        foreach plane {x y} {
            if ![file exists ${plane}Steering.log] {
                SetMpsDumpReviewStatus "No steering file found. Probably because WS-based orbit correction was not running at the time of the beam dump."
                set plotOK 0
                break
            }
            if [catch {exec sddsprocess  ${plane}Steering.log -pipe=out \
                         -edit=column,CorrName,ControlName,%/SFB://s/:/S/:/100D \
                         | sddsxref -pipe=in $xrefDir/SRCorrPosition.xref \
                         $tmpRoot.$plane -match=CorrName -take=Sector} result] {
                SetMpsDumpReviewStatus "$result"
                set plotOK 0
                break
            }
        }
        if $plotOK {
            exec sddsplot -layout=1,2 \
              -topline=@TimeStamp \
              -column=Sector,Delta $tmpRoot.x -graph=symbol,subtype=1 "-ylabel=x/H Plane Delta (A)" \
              -column=Sector,Delta $tmpRoot.x -graph=impulse,type=1 -end \
              -column=Sector,Delta $tmpRoot.y -graph=symbol,subtype=1 "-ylabel=y/V Plane Delta (A)" \
              -column=Sector,Delta $tmpRoot.y -graph=impulse,type=1 &
        }
    }
    
    if $showOrbitComparison {
        set printoutFile [APSTmpDir]/[APSTmpString]
        foreach plane {x y} {
            exec sddsprintout [set ${plane}AveFile] \
              -column=Rootname,format=%10s -column=(${plane}AverageOrbit,${plane}ExpectedReadback,${plane}OrbitDifference),format=%6.3f > $printoutFile.${plane}
        }
        exec cat $printoutFile.x $printoutFile.y > $printoutFile
        APSFileDisplayWindow [APSUniqueName .] \
          -fileName $printoutFile -deleteOnClose 1 -height 15 \
          -comment "MPS Dump: $searchMonth/$searchDay/$searchYear at $HMSItem"
    }
    
    cd $oldDir
}

proc SearchForNotebookFile {HMS HMSItem} {
    global mainDataDir dumpDay fileTime notebookFile noNotes
    set notebookFile $mainDataDir/notebookFiles/Note-$dumpDay.$HMS
    set blankFile $mainDataDir/notebookFiles/blankFile
    set fileTime $HMSItem

    if [winfo exists .notebook] {
        CheckIfNewInputSaved
    }

    APSEnableButton .userFrame.buttons.frame.note.button

    if ![file exists $blankFile] {
        exec touch $blankFile
        catch {file attribute $blankFile -permissions 00664}
    }

    if [file exists $notebookFile] {
        set noNotes 0
    } else {
        catch {file copy -force -- $blankFile $notebookFile}
        catch {file attribute $notebookFile -permissions 00664}
        set noNotes 1
    }
}

proc EditNotebookFile {} {
    global dayDirName  fileTime dumpDay noNotes timeStamp
    global notebookFile inputSaved text1 text2 noNotes
    set inputSaved 0

    APSDisableButton .userFrame.buttons.frame.note.button

    if !$noNotes {
        SetMpsDumpReviewStatus "Editing $notebookFile"
    }

    set notebookCmd "CheckIfNewInputSaved; APSEnableButton .userFrame.buttons.frame.note.button"

    APSWindow .notebook -name "Notebook for MPS Dump: $dumpDay/$fileTime" 
    .notebook.buttonRow.close.button configure -command $notebookCmd
    APSScrolledText .file1 -parent .notebook.userFrame -width 80 -height 10
    APSScrolledText .file2 -parent .notebook.userFrame -width 80 -height 10
    
    set text1 .notebook.userFrame.file1.text
    set text2 .notebook.userFrame.file2.text
    bind .notebook.userFrame.file2.text <Key> {set inputSaved 0} 

    if !$noNotes {
        set fileName $notebookFile
        
        if [file exists $fileName] {
            if [catch {open $fileName r} f] {
                SetMpsDumpReviewStatus "EditNotebookFile: $f"
                return
            }
            while {![eof $f]} {
                $text1 insert end [read $f 1000]
            }
            if [catch {close $f} results] {
                SetMpsDumpReviewStatus "EditNotebookFile: $results"
                return
            }
        } else {
            SetMpsDumpReviewStatus "Notebook file $notebookFile not found."
            return
        }
    } else {
        SetMpsDumpReviewStatus "No previous entries in the notebook for                    \
				    $dumpDay/$fileTime."
        bell
    }

    $text1 configure -state disabled
    set timeStamp [eval exec date]

    APSDialogBoxAddButton .print -parent .notebook -text Print  \
      -command {SetCombineText $text1 $text2 print} -contextHelp \
      "Print contents of window using enscript command."
    
    APSDialogBoxAddButton .saveFile -parent .notebook -text "Save"  \
      -command "SaveNotebookFile $text1 $text2"  -contextHelp "Export contents of window to a file."

    APSDialogBoxAddButton .undo -parent .notebook -text "Undo Saving"  \
      -command "UndoSaving"  -contextHelp "Export contents of window to a file."

    APSDialogBoxAddButton .tomail -parent .notebook -text "Email..."  \
      -command {SetCombineText $text1 $text2 mail} \
      -contextHelp "Send the contents of window as an email message."

    APSDisableButton .notebook.buttonRow.undo.button
}

proc SetCombineText {text_1 text_2 printMail} {
    global noNotes timeStamp
    set T3 ""
    set T1 ""
    set T2 ""

    if !$noNotes {
        set T1 [$text_1 get 1.0 insert]
    }
    set T2 [$text_2 get 1.0 insert]
    if [llength $T1] {
        append T3 $T1
    }
    if [llength $T2] {
        append T3 "$timeStamp \n"
        append T3 $T2
    }

    if ![string compare $printMail mail] {
        APSEMailDialog [APSUniqueName .] -width 80 -message $T3 -modal 1
    }
    if ![string compare $printMail print] {
        APSPrint -text $T3
    }
}

proc UndoSaving {} {
    global notebookFile inputSaved

    SetMpsDumpReviewStatus "Undoing saving..."
    
    catch {file delete $notebookFile}
    if [file exists $notebookFile~] {
        catch {file copy -force -- $notebookFile~ $notebookFile}
        catch {file attribute $notebookFile -permissions 00664}
    }

    APSDisableButton .notebook.buttonRow.undo.button
    set inputSaved 0
    SetMpsDumpReviewStatus "Done."
}

proc SaveNotebookFile {textWidget1 textWidget2} {
    global notebookFile inputSaved noNotes timeStamp

    if [catch {CheckUsersList} result] {
        bell
        APSAlertBox .alert1 -errorMessage "$result"
        return
    }

    SetMpsDumpReviewStatus "Saving notes..."

    if !$noNotes {
        if [file exists $notebookFile~] {
            catch {file delete $notebookFile~}
        }
        catch {file copy -force -- $notebookFile $notebookFile~}
        catch {file attribute $notebookFile~ -permissions 00664}
    }

    # Open the notebook file for appending
    if [catch {open $notebookFile a} fid] {
        update
        # no access to the file!
        bell
        APSDialogBox .dialog1 -width 40 -height 3
        pack forget .dialog1.buttonRow.cancel.button
        set t_1 .dialog1.userFrame.t1
        text $t_1 -setgrid true -wrap word -width 40 -height 3
        pack $t_1 -side top -fill both -expand true
        $t_1 insert end "No access to: $notebookFile"
        $t_1 configure -state disabled
        update
    }	 


    # See if it has a lock on it
    if [catch {os lockf $fid F_TLOCK 0} result] {
        # file is locked by another user
        close $fid
        SetMpsDumpReviewStatus "Can't update file now---it is locked.  Try later."
        bell
    } else {
        # file is now locked by this process
        global env
        puts $fid "$timeStamp by $env(USER)"
        puts $fid "[$textWidget2 get 1.0 insert] \n"
        close $fid
        SetMpsDumpReviewStatus "File updated by $env(USER)."
    }

    set inputSaved 1
    set noNotes 0
    APSEnableButton .notebook.buttonRow.undo.button
    SetMpsDumpReviewStatus "Done."
}

proc CheckUsersList {} {
    set usersList [list oag sr asdops borland lemery cyao carwar nassiri decker]

    catch {eval exec whoami} userName
    
    if {[lsearch -exact $usersList $userName] < 0} {
        return -code error "You do not have permission to write into this file. Please, send e-mail to borland to be put on the permission list."
    } else {
        return -code ok
    }
}

proc CheckIfNewInputSaved {} {
    global inputSaved text1 text2

    if !$inputSaved {
        catch {APSMultipleChoice [APSUniqueName .] \
                 -question "Last entry in the notebook is not saved. What do you want to do?" \
                 -labelList {Quit Save} \
                 -returnList  {Quit Save}} choice
        
        if ![string compare $choice Save] {
            SaveNotebookFile $text1 $text2
        }
    }
    
    destroy .notebook    
}

proc SetMpsDumpReviewStatus {args} {
    global mpsDumpReviewStatus 
    set mpsDumpReviewStatus "[exec date +%H:%M:%S]: [join $args ]"
    update
}

set DumpReason ""

proc SearchDumpReason {args} {
    global DumpReason StartYear StartMonth StartDay EndYear EndMonth EndDay Answer plotP1 plotCorrDrive plotCorrErr

    set Answer 0
    APSDialogBox .dump -name "Search Dump Reason"  -width 30 \
      -cancelCommand "set Answer 0" -okCommand "set Answer 1;destroy .dump"
    APSLabeledEntry .reason -parent .dump.userFrame -label "Dump Reason" -textVariable DumpReason -width 50
    APSDateTimeAdjEntry .start -parent .dump.userFrame -label "Starting date (year, month, day)" \
      -yearVariable StartYear -monthVariable StartMonth -dayVariable StartDay 
    APSDateTimeAdjEntry .end -parent .dump.userFrame -label "Ending date (year, month, day)   " \
      -yearVariable EndYear -monthVariable EndMonth -dayVariable EndDay 
    APSCheckButtonFrame .plot -parent .dump.userFrame -label "Plot which data?" \
      -buttonList "P1 CorrDrive CorrErr" -orientation horizontal \
      -variableList {plotP1 plotCorrDrive plotCorrErr}
    APSDialogBoxAddButton .search -parent .dump -text "Search..." -command "SearchDumpData"
    APSDialogBoxAddButton .plot -parent .dump -text "Plot" -command "PlotDumpData"
    update
    
    tkwait variable Answer
    if !$Answer {
        SetMpsDumpReviewStatus "Search dump reason was cancelled."
        return
    }
    if [catch {SearchDumpData} result] {
        SetMpsDumpReviewStatus $result
        return
    }
    PlotDumpData
}
set dumpDataList ""
set plotP1 1
set plotCorrDrive 0
set plotCorrErr 0
proc PlotDumpData {args} {
    global dumpDataList plotP1 plotCorrDrive plotCorrErr
    if ![llength $dumpDataList] {
        if [catch {SearchDumpData} result] {
            SetMpsDumpReviewStatus $result
            return
        }
    }
    set oldDir [pwd]
    cd /home/helios/oagData/mpsDumps/
    set file NbBpmHistory.gz
    set fileList ""
    foreach dump $dumpDataList {
        if {[file exists $dump/NbBpmHistory.xz]} {
            lappend fileList $dump/NbBpmHistory.xz
        } else {
            lappend fileList $dump/$file
        }
    }
    set dataList ""
    if $plotP1 {
        lappend dataList S*P1*x
        lappend dataList S*P1*y
    }
    if $plotCorrDrive {
        lappend dataList *CorrDrive
    }
    if $plotCorrErr {
        lappend dataList *CorrErr
    }
    if ![llength $dataList] {
        SetMpsDumpReviewStatus "No data selected for plot."
        return
    }
    foreach data $dataList {
        eval exec sddsplot $fileList \
          -col=TimeRelativeToTrip,$data \
          -sep=nameindex -group=nameindex \
          -mode=y=offset -same \
          -grap=sym,vary=sub,conn=sub -leg=file &
    }
    cd $oldDir
}

proc SearchDumpData {args} {
    global DumpReason StartYear StartMonth StartDay EndYear EndMonth EndDay Answer dumpDataList
    
    set oldDir [pwd]
    cd /home/helios/oagData/mpsDumps/
    set dumpDataList ""
    set dumpViewList ""
    set startTime [clock scan $StartMonth/$StartDay/$StartYear]
    set endTime [expr [clock scan $EndMonth/$EndDay/$EndYear] + 24*3600 - 1]
    set step [expr 24*3600]
    for {set time $startTime} {$time<$endTime} {incr time $step} {
        set date [clock format $time -format %Y-%j-%m%d]
        if ![file exist $date] {
            continue
        }
        cd $date
        set dumpList [lsort [glob -nocomplain \[0123456\]?????]]
        cd ..
        if {[llength $dumpList] == 0} continue
        foreach dump $dumpList {
            set f $date/$dump/dumpRecord.snap.xz
            if {![file exists $f]} {
                set f $date/$dump/dumpRecord.snap.gz
            }
            if [catch {exec sddsprocess $f -pipe=out \
                         -match=col,ControlName=S:MPS:lastTripCauseSI \
                         | sdds2stream -pipe -col=ValueString} result] {
                puts stderr $result
            }
            lappend dumpViewList "$date/$dump --- $result"
            if {[regexp $DumpReason $result]} {
                lappend dumpDataList $date/$dump 
            }
        }
    }
    set tmpfile [APSTmpDir]/[APSTmpString]
    if ![llength $dumpDataList] {
        if [catch {exec sddsmakedataset -pipe=out -col=DumpTime,type=string -data=[join $dumpViewList ,] \
                     | sddsprintout -pipe=in $tmpfile "-title=Available Dump record found from $StartMonth/$StartDay/$StartYear to $EndMonth/$EndDay/$EndYear." \
                     -col=DumpTime } result] {
            cd $oldDir
            return -code error $result
        }
        APSFileDisplayWindow [APSUniqueName .] -fileName $tmpfile -width 50 -deleteOnClose 1
        cd $oldDir
        return -code error "No dump record found for $DumpReason from $StartMonth/$StartDay/$StartYear to $EndMonth/$EndDay/$EndYear." 
    }
    if [catch {exec sddsmakedataset -pipe=out -col=DumpTime,type=string -data=[join $dumpDataList ,] \
                 | sddsprintout -pipe=in $tmpfile "-title=Dump record found for \"$DumpReason\"  from $StartMonth/$StartDay/$StartYear to $EndMonth/$EndDay/$EndYear." \
                 -col=DumpTime } result] {
        cd $oldDir
        return -code error $result
    }
    APSFileDisplayWindow [APSUniqueName .] -fileName $tmpfile -width 50 -deleteOnClose 1
    cd $oldDir

}


set mpsDumpReviewStatus Ready.
APSScrolledStatus .status -parent .userFrame -textVariable mpsDumpReviewStatus -width 60 -packOption "-fill x"

MakeDateTimeFrame .datetime -parent .userFrame 

set plotFastHistX 0
set plotFastHistY 0
set plotFastFFTX 0
set plotFastFFTY 0
set plotFBCorrErrRange 0
set plotFBCorrErrMovie 0
set plotFBCorrDriveRange 0
set showDumpPrintout 1
set plotFBCorrDriveMovie 0
set showDumpPrintout 0
set plotOrbitCorChanges 0
set showOrbitComparison 0
set plotFBbpmSpatial 0
set plotFBbpmTime 0
set plotFBCorrErrTime 0
set plotFBCorrDriveTime 0
set simulateOrbitFromFBDrives 0
set plotDPCorrDriveTime 0
set plotRFScopeData 0
set plotTopupGlitchLogData 0
set analyzeFBbpmSpatial 0
set plotFPGABPMHistory 0
APSCheckButtonFrame .plane -parent .userFrame \
    -orientation vertical -limitPerRow 7 \
    -label "Output choices" -allNone 1 \
    -variableList {showDumpPrintout \
                       plotTimeStamps \
                       showOrbitComparison \
                       plotNbBpmTime \
                       plotFBbpmTime \
                       plotFBbpmSpatial \
                       analyzeFBbpmSpatial \
                       plotFBCorrErrTime \
                       plotFBCorrErrRange \
                       plotFBCorrErrMovie \
                       plotFBCorrDriveTime \
                       plotFBCorrDriveRange \
                       plotFBCorrDriveMovie \
                       simulateOrbitFromFBDrives \
                       plotDPCorrDriveTime \
                       plotOrbitCorChanges \
                       plotRFScopeData \
                       plotTopupGlitchLogData \
                       plotFPGABPMHistory \
                   } \
    -buttonList {"Dump Data Printout" \
                     "Time Stamp plot" \
                     "Orbit Comparison Printout" \
                     "FB Nb bpm time-domain plots" \
                     "FB bpm time-domain plots" \
                     "FB bpm spatial plots" \
                     "FB bpm glitch analysis" \
                     "FB Corrector Error time-domain plots" \
                     "FB Corrector Error Range Plots" \
                     "FB Corrector Error Movie Plot" \
                     "FB Corrector Drive time-domain plots" \
                     "FB Corrector Drive Range Plots" \
                     "FB Corrector Drive Movie Plot" \
                     "Simulate Orbit from FB Corrector Drive" \
                     "DP Corrector Drive time-domain plots" \
                     "Orbit Correction Last Step Plots" \
                     "RF Scope Data" \
                     "Topup Glitch Log data" \
                     "FPGA bpm turn/slow beam history plot" \
                 } \
    -contextHelp \
  "Choose what items you want to review for each dump, prior to double-clicking on the dump time.\n\nFB corrector error data shows what the realtime orbit feedback system predicts to be the required corrector changes to correct the orbit error it sees; this may point to where the source of motion is.\n\nOrbit correction last step plots show the last change to corrector strengths made by the slow orbit correction program.\n\nDump data printouts show a selection of PV values taken just after the dump.\n\nOrbit comparison converts the BPM history data into unadjusted bpm readbacks and then compares them with the expected unadjusted bpm readbacks inferred from the SR User Beam Preferred file."

set labelWidth -60
# no longer any of the old fast bpm waveforms. Need to use the FPGA option
#APSLabeledEntryFrame .fastlimits -parent .userFrame \
  -label [format %${labelWidth}s "Horizontal limits for fast BPM plots (min, max):"] \
  -variableList {HLimitMin HLimitMax} \
  -orientation horizontal -width 5 -contextHelp \
  "Enter the minimum and maximum limits of the horizontal plot region.  If the two numbers are the same, then the plots are autoscaled."

APSLabeledEntryFrame .averagelimits -parent .userFrame \
  -label [format %${labelWidth}s "Limits for calculating average readbacks (min, max):"] \
  -variableList {AveMin AveMax} -orientation horizontal \
  -width 5 -contextHelp \
  "Enter the minimum and maximum limits of slow history BSP-100 bpms for comparison with the expected orbit. One has to choose limits that that excludes very fast orbit change near the end of the record."

# no longer any of the old fast bpm waveforms. Need to use the FPGA option
#APSLabeledEntryFrame .fastlimits -parent .userFrame \
APSLabeledEntryFrame .fftLimits -parent .userFrame \
  -label [format %${labelWidth}s "Freq range (kHz) for fast BPM FFT plots (min, max):"] \
  -variableList {FFTLimitMin FFTLimitMax} -orientation horizontal -width 5 -contextHelp \
  "Enter the minimum and maximum limits of the frequency range for FFT plots.  If the two numbers are the same, then the plots are autoscaled."

APSLabeledEntryFrame .movielimits -parent .userFrame \
  -label [format %${labelWidth}s "Time limits (mS) for corrector error plots (start, end):"] \
  -variableList {fbLimitMin fbLimitMax} -orientation horizontal -width 5 -contextHelp \
  "Enter the minimum and maximum time limits for the corrector error movie.  If the two numbers are the same, then the plots are autoscaled."

APSLabeledEntryFrame .spatiallimits -parent .userFrame \
  -label [format %${labelWidth}s "Time limits (mS) for FB bpm plots (start, end):"] \
  -variableList {fbbpmLimitMin fbbpmLimitMax} -orientation horizontal -width 5 -contextHelp \
  "Enter the minimum and maximum relative-to-trip time limits for FB bpm time and spatial plots."

APSFrame .buttons -parent .userFrame -relief flat -label ""
APSButton .search1 -parent .userFrame.buttons.frame -width "" -command "SearchDumpReason" \
  -text "Search Dump Reason..." -contextHelp "search mps dump data from dumpRecord.snap.gz\
 (i.e. string value of :MPS:lastTripCauseSI) and returns a list of mps dump directories."
APSButton .search -parent .userFrame.buttons.frame -width "" -command \
  {SearchForDumps -year $searchYear -month $searchMonth -day $searchDay} \
  -text "Search" \
  -contextHelp "Searches for MPS dump data from the day selected."
APSButton .note -parent .userFrame.buttons.frame -width "" -text "Edit Notebook" \
  -command EditNotebookFile
# should be commented out for production
#set searchMonth 2
#set searchDay 11

APSDisableButton .userFrame.buttons.frame.note.button

proc SRFBBeamHistoryGlitchAnalysis {args} {
    global OAGGlobal
    set xInput ""
    set yInput ""
    set output [APSTmpDir]/[APSTmpString]
    set display 0
    set plot 0
    set overlapPlots 1
    set findSources 1
    set title ""
    set statusCallback APSNoOp
    set lattice default
    if {[APSStrictParseArguments {xInput yInput output display title plot \
                                    findSources statusCallback overlapPlots \
                                    lattice}] || \
          ![string length $xInput] || ![string length $yInput]} {
        return -code error "SRFBBeamHistoryGlitchAnalysis: bad arguments"
    }
    
    set input(x) $xInput
    set input(y) $yInput

    set tmpID [APSUniqueName tmpID]
    set tmpRoot [APSTmpDir]/[APSTmpString]

    set SROrbitGlitchDir $OAGGlobal(SRLatticesDirectory)/$lattice
    set xrefDir $OAGGlobal(SRLatticesDirectory)/scripts

    set w .widget[APSUniqueNumber]
    global SRFBBeamHistoryGlitchAnalysisStatus
    global SRFBBeamHistoryGlitchIdealMatrix removeNbBpms useCorrectors svNumber
    global SRFBBeamHistoryGlitchAnalysisBaselineT0 SRFBBeamHistoryGlitchAnalysisBaselineT1 \
	SRFBBeamHistoryGlitchAnalysisOrbitsT0 SRFBBeamHistoryGlitchAnalysisOrbitsT1 SRFBBeamHistoryGlitchPlane
    set SRFBBeamHistoryGlitchAnalysisStatus -1
    set SRFBBeamHistoryGlitchIdealMatrix 1
    set SRFBBeamHistoryGlitchAnalysisBaselineT0 -83
    set SRFBBeamHistoryGlitchAnalysisBaselineT1 -76
    set SRFBBeamHistoryGlitchAnalysisOrbitsT0 -3
    set SRFBBeamHistoryGlitchAnalysisOrbitsT1 0
    set SRFBBeamHistoryGlitchPlane 2
    set removeNbBpms 0
    set useCorrectors fast
    set svNumber 80
    APSDialogBox $w -name "Glitch analysis parameters" \
      -okCommand "set SRFBBeamHistoryGlitchAnalysisStatus 0" \
      -cancelCommand "set SRFBBeamHistoryGlitchAnalysisStatus 1" \
      -modal 0 
    APSLabeledEntry .le1 -parent $w.userFrame -label "T0 to calculate orbit baseline: " -width 10 -textVariable SRFBBeamHistoryGlitchAnalysisBaselineT0 \
      -contextHelp "The baseline orbit will be calculated as average of orbits from time T0 to time T1. Time is entered in units of time-domain plots. For example, to use 5 msec in the beginning, enter T0=-83, T1=-78"
    APSLabeledEntry .le2 -parent $w.userFrame -label "T1 to calculate orbit baseline: " -width 10 -textVariable SRFBBeamHistoryGlitchAnalysisBaselineT1 \
      -contextHelp "The baseline orbit will be calculated as average of orbits from time T0 to time T1. Time is entered in units of time-domain plots. For example, to use 5 msec in the beginning, enter T0=-83, T1=-78"
    APSLabeledEntry .le3 -parent $w.userFrame -label "Analyze orbits from time: " -width 10 -textVariable SRFBBeamHistoryGlitchAnalysisOrbitsT0 \
      -contextHelp "Time is entered in units of time-domain plots. For example, to analyze last 5 msec of orbits, enter T0=-5, T1=0"
    APSLabeledEntry .le4 -parent $w.userFrame -label "Analyze orbits   to time: " -width 10 -textVariable SRFBBeamHistoryGlitchAnalysisOrbitsT1 \
      -contextHelp "Time is entered in units of time-domain plots. For example, to analyze last 5 msec of orbits, enter T0=-5, T1=0"
    APSRadioButtonFrame .rb0 -parent $w.userFrame -label "Plane: " -orientation horizontal \
      -buttonList [list X Y Both] -valueList "0 1 2" -variable SRFBBeamHistoryGlitchPlane
    APSRadioButtonFrame .rb1 -parent $w.userFrame -label "Matrix: " -orientation horizontal \
      -buttonList [list Ideal "Calibrated Model"] -valueList "1 0" -variable SRFBBeamHistoryGlitchIdealMatrix
    APSRadioButtonFrame .rb2 -parent $w.userFrame -label "Remove Nb bpms: " -orientation horizontal \
      -buttonList [list No Yes] -valueList "0 1" -variable removeNbBpms
    APSRadioButtonFrame .rb3 -parent $w.userFrame -label "Use A:\[HV\]3, B:\[HV\]4 or all correctors: " -orientation horizontal \
      -buttonList [list rtfb fast all] -valueList "rtfb fast all" -variable useCorrectors
    APSLabeledEntry .le5 -parent $w.userFrame -label "Singular value number for irm: " -width 10 -textVariable svNumber \
      -contextHelp "-largest option for sddspseudoinverse when inverting calculated response matrix. SV spectrum will be shown, after that one can re-run with the appropriate number."
    tkwait variable SRFBBeamHistoryGlitchAnalysisStatus
    if $SRFBBeamHistoryGlitchAnalysisStatus==1 return

    if !$SRFBBeamHistoryGlitchIdealMatrix {
        eval $statusCallback "Computing calibrated model response matrix"
        global responseMatrixComputationStatus
        set w .widget[APSUniqueNumber]
        set responseMatrixComputationStatus -1
	set calibModelDir /home/helios/oagData/sr/calibratedModels/default
        set parameterFileList0 [APSGetSDDSColumn -fileName $calibModelDir/requiredParamFiles.sdds -column filename]
	set parameterFileList ""
	foreach filename $parameterFileList0 {lappend parameterFileList $calibModelDir/[file tail $filename]}
        eval exec sddscombine $parameterFileList -merge $tmpRoot.param -overwrite
        catch {exec elegant /home/helios/oagData/sr/glitchAnalysisFiles/responseMatrix.ele \
		   -macro=parameters=$tmpRoot.param,rootname=$tmpRoot > $tmpRoot.log} result
        if {![file exists $tmpRoot.hrm]  || ![file exists $tmpRoot.vrm]} {
            return -code error "Response matrix computation failed"
        }
        exec sddsnormalize $tmpRoot.hrm $tmpRoot.hrmn -columns=mode=largest,*H*
        exec sddsnormalize $tmpRoot.vrm $tmpRoot.vrmn -columns=mode=largest,*V*
        eval $statusCallback "Response matrix computation completed"
    } else {
        exec sddsnormalize $SROrbitGlitchDir/sr.h1rm $tmpRoot.hrmn -columns=mode=largest,*H*
        exec sddsnormalize $SROrbitGlitchDir/sr.v1rm $tmpRoot.vrmn -columns=mode=largest,*V*
    }

    switch -exact $SRFBBeamHistoryGlitchPlane {
	0 {set planeList [list x]; set hvList [list h]}
	1 {set planeList [list y]; set hvList [list v]}
	2 {set planeList [list x y]; set hvList [list h v]}
    }
    foreach plane $planeList hv $hvList {
        eval $statusCallback "Analyzing $plane plane for glitch source"
	#------ normalized matrix is for overlap analysis, other one is for corrector errors.
	set matrix0norm $tmpRoot.${hv}rmn
	lappend deleteFiles $matrix0norm
        if $SRFBBeamHistoryGlitchIdealMatrix {
#???            set matrix0 $SROrbitGlitchDir/sr.${hv}1rm
            set matrix0 $SROrbitGlitchDir/aps.${hv}rm
        } else {
	    #------ normalized matrix is for overlap analysis, other one is for corrector errors.
            set matrix0 $tmpRoot.${hv}rm
	    lappend deleteFiles $matrix0
        }

        if ![file exists $input($plane)] {
            return -code error "not found: $input($plane)"
        }

        #------ Filtering out narrow-band bpms:
        set bpmTimeDomainFile $input($plane)
        if $removeNbBpms {
            set bpmTimeDomainFile $tmpRoot.bpmTD
            exec sddsconvert $input($plane) $bpmTimeDomainFile "-del=col,S*:P\[01\]"
	    lappend deleteFiles $bpmTimeDomainFile
        }

        #------ Analyze the orbits in the baseline window to get a baseline, then subtract from orbits in analysis window
	set tBaseline0 $SRFBBeamHistoryGlitchAnalysisBaselineT0
	set tBaseline1 $SRFBBeamHistoryGlitchAnalysisBaselineT1
	set tAnalysis0 $SRFBBeamHistoryGlitchAnalysisOrbitsT0
	set tAnalysis1 $SRFBBeamHistoryGlitchAnalysisOrbitsT1
	if [catch {exec sddsconvert $bpmTimeDomainFile -pipe=out -edit=col,S*:*,ei/:$plane/ \
		       | sddsprocess -pipe -process=S*:*,ave,%sAve,functionof=TimeRelativeToTrip,lower=$tBaseline0,upper=$tBaseline1 \
		       "-define=column,ChangeIn%s,%s %sAve -,units=mm,select=S*:*" \
		       -filter=col,TimeRelativeToTrip,$tAnalysis0,$tAnalysis1 \
		       | sddscollect -pipe -collect=prefix=ChangeIn \
		       | sddsconvert -pipe -rename=column,ChangeIn=ChangeIn${plane} \
		       | sddsprocess -pipe -edit=column,BPMName,Rootname,%/:$plane// \
		       | sddsxref -pipe $xrefDir/SRBPMPosition.xref -match=BPMName -take=s -reuse=page \
		       | sddssort -pipe -column=s \
		       | sddsprocess -pipe=in $tmpRoot.orbits.$plane -filter=col,s,0,1200} result] {
            return -code error "Error calculating orbits: $result"
        }

        #------ Select out the part of the matrix for the BPMs we have in the input file
        if [catch {exec sddsselect $matrix0norm $tmpRoot.orbits.$plane -pipe=out -match=BPMName \
                     | sddsconvert -pipe=in -retain=column,*:*,BPMName $matrix0norm.filtered} result] {
            return -code error "$result"
        }
        if [catch {exec sddsselect $matrix0 $tmpRoot.orbits.$plane -pipe=out -match=BPMName \
		       | sddsconvert -pipe=in -retain=column,*:*,BPMName $tmpRoot.${plane}rm.filtered} result] {
            return -code error "$result"
        }
	lappend deleteFiles $tmpRoot.${plane}rm.filtered $tmpRoot.orbits.$plane

        # Compute overlap with response matrix to find likely source
        if [catch \
              {exec sddsconvert $tmpRoot.orbits.$plane -pipe=out -retain=column,ChangeIn${plane} \
                 | sddstranspose -pipe \
                 | sddsmatrixmult -reuse -pipe $matrix0norm.filtered \
                 | sddstranspose -pipe -oldColumnNames=CorrectorName -root=Overlap \
                 | sddsprocess -pipe "-redefine=column,OverlapAbs,Overlap abs" \
		 | tee $tmpRoot.overlap.$plane.plot \
                 | sddssort -pipe -column=OverlapAbs,decr \
                 | sddsprocess -pipe -clip=1,0,invert \
                 "-define=column,OrbitNumber,i_page,type=long" \
                 | sddscombine -merge -pipe \
                 | sddssort -pipe -column=Overlap,decr -column=OrbitNumber,decr \
                 | tee $tmpRoot.overlap.sdds \
                 | sddsprintout -pipe=in $tmpRoot.overlap \
                 "-title=$title" \
                 -column=CorrectorName,label=Corrector \
                 -column=Overlap -column=OrbitNumber

                  exec sddssort $tmpRoot.overlap.sdds -pipe=out \
                 -column=CorrectorName -column=OverlapAbs,decr \
                 | sddsbreak -pipe -change=CorrectorName \
                 | sddsprocess -pipe \
		 "-redef=col,OverlapSign,Overlap Overlap abs /" \
                 -process=CorrectorName,first,CorrectorName \
                 -process=Overlap,count,NumberOfOccurences \
                 -process=OverlapAbs,max,OverlapMax \
                 -process=OverlapSign,first,OverlapSign \
                 -process=OverlapAbs,median,OverlapMedian \
                 | sddscollapse -pipe \
                 | sddssort -pipe -column=NumberOfOccurences,decr \
		 | tee $tmpRoot.overlap.count.sdds \
                 | sddsprintout -pipe=in $tmpRoot.overlap.count \
                 -column=CorrectorName,label=Corrector \
                 -column=NumberOfOccurences,format=%.0f \
                 "-column=OverlapMax,label=Max. Overlap" \
                 "-column=OverlapMedian,label=Median Overlap" \
                 "-title=$title" 
                  exec cat $tmpRoot.overlap.count $tmpRoot.overlap > $tmpRoot.printout.$plane
              } result] {
            return -code error "SRFBBeamHistoryGlitchAnalysis (error calculating overlap): $result"
        }
	lappend deleteFiles $tmpRoot.overlap.sdds $tmpRoot.overlap.count $tmpRoot.overlap $tmpRoot.printout.$plane $tmpRoot.overlap.count.sdds
        if $display {
            APSFileDisplayWindow [APSUniqueName .] \
              -fileName $tmpRoot.printout.$plane -deleteOnClose 1 \
              -width 80 -comment "Orbit glitch source analysis\nTitle: $title"
        }
	set overlapSign [exec sddsprocess $tmpRoot.overlap.count.sdds -clip=1,0,inv -pipe=out | sdds2stream -pipe=in -col=OverlapSign]
	exec sddsplot $tmpRoot.overlap.$plane.plot -col=CorrectorName,OverlapAbs -graph=sym,con=subt,vary=subt -split=page \
	    "-topline=Abs value of orbit overlap with RM" "-title=Corrector name" &
        exec sddsnormalize $tmpRoot.orbits.$plane $tmpRoot.orbits.$plane.norm -columns=mode=largest,ChangeIn*
	exec sddsxref $matrix0norm.filtered $tmpRoot.orbits.$plane.norm -take=s -nowarning
	lappend deleteFiles $matrix0norm.filtered~
	exec sddsplot -same -enum=inter=2 \
	    "-topline=Measured orbit and RM vectors" \
	    -col=s,S* $matrix0norm.filtered -sep -leg \
	    -col=s,ChangeIn$plane -split=page $tmpRoot.orbits.$plane.norm -omni -graph=line,type=1 -factor=ymult=$overlapSign \
	    "-leg=spec=Meas orbits" &

        #------ Calculating and plotting corrector errors
        set matrixFile $matrix0
        set corrFile $tmpRoot.corr.$hv
        set irm $matrixFile.irm
	lappend deleteFiles $irm
        switch $useCorrectors {
            rtfb {
                set correctorList [join [exec sdds2stream /home/helios/oagData/sr/rtfeedback/lattices/default/$hv.default/irm -col=ControlName] ] }
            fast {
                set correctorList [join [exec sddsconvert $matrixFile -pipe=out -del=col,BPMName,s,etax \
                                             | sddsquery -pipe=in -col -readAll | grep B:\[HV\]4 ] ] }
            all {
                set correctorList [join [exec sddsconvert $matrixFile -pipe=out -del=col,BPMName,s,etax \
                                             | sddsquery -pipe=in -col -readAll] ] }
        }
	if [catch {exec sddsconvert $tmpRoot.${plane}rm.filtered -pipe=out -retain=col,[join $correctorList ,] \
		       | sddspseudoinverse -pipe -sFile=$tmpRoot.$plane.sv -largest=$svNumber \
		       | sddsconvert -pipe=in $irm -rename=col,OldColumnNames=ControlName } result] {
	    return -code error "SRFBBeamHistoryGlitchAnalysisA: $result"
	}
        if [catch {exec sddsmatrixmult $irm $tmpRoot.orbits.$plane -pipe=out -reuse \
		       | sddsxref -pipe $irm -take=ControlName -reuse=page \
		       | sddsxref -pipe $tmpRoot.orbits.$plane -leave=* -transfer=para,TimeRelativeToTrip \
		       | sddsprocess -pipe "-print=para,Title,Time to trip %6.2f ms,TimeRelativeToTrip" \
		       | sddsconvert -pipe=in $corrFile -rename=col,ChangeIn$plane=Error } result] {
	    return -code error "SRFBBeamHistoryGlitchAnalysisB: $result"
	}

        exec sddsplot $corrFile -col=ControlName,Error -split=page -sep -graph=symbol,connect "-ylabel=Corrector Error" \
          -topline=@Title &
	exec sddsplot $tmpRoot.$plane.sv -col=Index,SingularValues -mode=y=log -graph=symbol,connect -topline="SV\ spectrum\ in\ $hv\ plane" &
        eval file delete $deleteFiles
    }
}


# Local Variables:
# mode: tcl
# End:
