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

#
# $Log: not supported by cvs2svn $
# Revision 1.9  1999/01/22 20:07:39  emery
# Added monitoring of SR DCCT.
#
# Revision 1.8  1998/08/24 17:03:49  borland
# New version that allows changing the update interval for sddsmonitor.
#
# Revision 1.7  1998/06/16 01:30:22  borland
# Won't overwrite existing data file without permission.
#
# Revision 1.6  1998/06/16 01:12:25  borland
# Added option to sddsmonitor so that it doesn't run past the allotted time.
#
# Revision 1.5  1998/06/12 16:00:04  borland
# Added titles to plots vs time and PSD plots.
#
# Revision 1.4  1998/06/08 22:54:37  borland
# Added new button to the list of buttons to disable.
#
# Revision 1.3  1998/06/08 22:51:02  borland
# Added option to not compute PSDs when doing non-archival collection.
#
# Revision 1.2  1998/06/05 20:52:27  borland
# Fixed axes for PSD plots (had -ticks=xtime).
#
# Revision 1.1  1998/06/05 19:56:47  borland
# First version.
#
#

set auto_path [linsert $auto_path 0  /usr/local/oag/apps/lib/$env(HOST_ARCH) ]
set auto_path [linsert $auto_path 0 /usr/local/oag/lib_patch/$env(HOST_ARCH)]
APSDebugPath

set CVSRevisionAuthor "\$Revision: 1.10 $ \$Author: borland $"

APSApplication . -name SRMeasureSlowMotion -version $CVSRevisionAuthor \
  -overview {Collects data from SR BPMs to measure the amount of slow beam motion, where slow means <0.5Hz.  For faster bandwidth measurements, try the slow beam history or feedback orbit motion applications.}

set status Working...
APSScrolledStatus .status -parent .userFrame -textVariable status \
        -width 60 -height 6
update

set archiveDir /home/helios/oagData/sr/slowBeamMotion/dataFiles
set archiveDataCollectionInterval 1
set archiveDataCollectionTime 600

set dataDirectory "."
set dataRootname bpms
set dataIndex 0
set dataCollectionInterval 1
set dataCollectionTime 600
set updateInterval 500
set buttonList ""

proc MakeSaveWidget {widget args} {
    set parent ""
    APSStrictParseArguments {parent}
    global dataDirectory dataRootname
    APSFrame $widget -parent $parent \
      -label "Save Data" -contextHelp \
      "Provides for saving the slow beam spectrum to a file."
    set parent $parent$widget.frame
    APSLabeledEntry .directory -parent $parent -label "Directory: " \
      -textVariable dataDirectory -width 60
    APSLabeledEntry .rootname -parent $parent -label "Rootname: " \
      -textVariable dataRootname -width 60
    APSLabeledEntry .index -parent $parent -label "Index: " \
      -textVariable dataIndex -width 60
    APSLabeledEntry .comment -parent $parent -label "Comment: " \
      -textVariable dataComment -width 60
    APSLabeledEntry .interval -parent $parent -label "Interval (s): " \
      -textVariable dataCollectionInterval -contextHelp \
      "Enter the interval in seconds between data points."
    APSLabeledEntry .time -parent $parent -label "Collection time (s): " \
      -textVariable dataCollectionTime -contextHelp \
      "Enter the total time in seconds over which to collect data."
    APSLabeledEntry .update -parent $parent -label "Updated interval (steps): " \
      -textVariable updateInterval -contextHelp \
      "Enter the update interval for the output file, in steps or samples.  If the update interval is too small, you may get a decrease in the data collection rate."

    APSButton .daily -parent $parent -text "Go to daily directory" \
      -command {set dataDirectory [APSGoToDailyDirectory]}
    APSButton .save -parent $parent -text "Acquire" -command \
      "collectOrbitMotionData -PSD 0" -contextHelp \
      "Saves beam motion data to the directory and file you've chosen."
    APSButton .savePSD -parent $parent -text "Acquire and PSD" -command \
      "collectOrbitMotionData -PSD 1" -contextHelp \
      "Saves beam motion data to the directory and file you've chosen."
    APSButton .view -parent $parent -text "Review" -command \
      reviewOrbitMotionData -contextHelp \
      "Lets you review previously-collected orbit motion data."
    global buttonList
    lappend buttonList $parent.daily.button \
      $parent.save.button $parent.view.button $parent.savePSD.button
}

proc APSSRCollectSlowBeamMotionData {args} {
    set output ""
    set msType msAve
    set interval 1
    set time 300
    set useExecLog 0 
    set psdOutput ""
    set gzipData 0
    set statusCallback APSNoOp
    set updateInterval 500
    APSStrictParseArguments {output msType interval time useExecLog psdOutput gzipData statusCallback updateInterval}
    set inputTemplate /home/helios/oagData/sr/slowBeamMotion/inputFiles/monitorTemplate.sdds
    if {![string length $output] && ![string length $psdOutput]} {
        return -code error "APSSRCollectSlowBeamMotionData: no filename given for straight or PSD output."
    }
    if ![string length $output] {
        set output /tmp/[APSTmpString]
        APSAddToTempFileList $output
    }
    if [lsearch -exact {ms msAve mswAve} $msType]==-1 {
        return -code error "APSSRCollectSlowBeamMotionData: msType >$msType< not recognized."
    }
    if $interval<0 {
        set interval 0
    }
    if $time<$interval {
        return -code error "APSSRCollectSlowBeamMotionData: total time is less than time interval"
    }

    set tmpFile /tmp/[APSTmpString]
    APSAddToTempFileList $tmpFile
    if [catch {exec sddscombine /home/helios/oagData/sr/sddsmonitorFiles/DCCT.mon \
                 $inputTemplate -pipe=out -merge \
                 | sddsprocess -pipe=in $tmpFile \
                 "-reedit=column,ControlName,%/<msType>/$msType/" \
                 "-reedit=column,ReadbackName,%/<msType>/$msType/"} result] {
        return -code error "APSSRCollectSlowBeamMotionData: $result"
    }
    set command "sddsmonitor $tmpFile $output -interval=$interval,s -time=$time,s -erase -updateInterval=$updateInterval -enforceTimeLimit "
    set uniqueName [APSUniqueName x]
    set tmpVar apsSRCollectSlowBeamMotionData$uniqueName
    global $tmpVar
    set $tmpVar ?
    eval $statusCallback {"Collecting slow beam motion data."}
    if $useExecLog {
        set widget .$uniqueName
        APSExecLog $widget \
          -width 80 -unixCommand \
          "$command -verbose" \
          -callback "set $tmpVar ok; destroy $widget" \
          -abortCallback "set $tmpVar error; destroy $widget" \
          -cancelCallback "set $tmpVar error; destroy $widget" 
    } else {
        APSExec -callback "set $tmpVar ok; destroy $widget" \
          unixCommand "$command"
      }
    while 1 {
        after 1000
        if [string compare [set $tmpVar] ?] break
        update
    }
    eval $statusCallback {"Return value: [set $tmpVar]"}
    if [string compare [set $tmpVar] ok]!=0 {
        return -code [set $tmpVar] "APSSRCollectSlowBeamMotionData: error returned from sddsmonitor"
    }
    if {$gzipData} {
        if [catch {exec gzip $output} result] {
            return -code error "APSSRCollectSlowBeamMotionData: $result"
        }
        set output $output.gz
    }
    
    if [string length $psdOutput] {
        eval $statusCallback {"Processing slow beam motion data."}
        if [catch {exec sddsfft $output -pipe=output -psdOutput -suppressaverage \
                     -window -columns=Time,*$msType* -nowarnings \
                     | sddsconvert -pipe -delete=column,FFT* \
                     | sddsprocess -pipe -process=PSD*,sum,%sSum \
                     | sddsrowstats -pipe \
                     -mean=PSD:$msType:xMean,bottomLimit=1e-9,topLimit=1e-2,PSD*$msType*x \
                     -mean=PSD:$msType:yMean,bottomLimit=1e-9,topLimit=1e-2,PSD*$msType*y \
                     | sddsprocess -pipe=in $psdOutput \
                     "-define=parameter,%sRMS,PSD%sSum fftFrequencySpacing * sqrt,select=PSD*Sum,edit=%/PSD//%/Sum//,units=mm" \
                 } result] {
            return -code error "APSSRCollectSlowBeamMotionData: $result"
        }
        if {$gzipData} {
            if [catch {exec gzip $psdOutput} result] {
                return -code error "APSSRCollectSlowBeamMotionData: $result"
            }
        }
    }

    eval $statusCallback Done.
}

proc changeButtonStates {state} {
    global buttonList
    if $state {
        foreach button $buttonList {
            APSEnableButton $button
        }
    } else {
        foreach button $buttonList {
            APSDisableButton $button
        }
    }
}

proc reviewOrbitMotionData {args} {
    set archive 0
    APSStrictParseArguments {archive}

    changeButtonStates 0
    set widget [APSUniqueName .]

    global reviewOrbitMotionDataOk doTimePlot doPSDPlot doSourceAnalysis doQuickSDDSplot doExport
    global doXPlots doYPlots sourcePlots sourceOrbitAverages
    foreach var {doTimePlot doPSDPlot doSourceAnalysis doXPlots doYPlots doQuickSDDSplot doExport} { 
        set $var 0 
    }
    set reviewOrbitMotionDataOk -1
    set sourcePlots 1
    set sourceOrbitAverages 0

    APSDialogBox $widget -cancelCommand "set reviewOrbitMotionDataOk 0" \
      -okCommand "set reviewOrbitMotionDataOk 1" 
    APSDisableButton $widget.buttonRow.ok.button
    APSDisableButton $widget.buttonRow.cancel.button

    set uFrame $widget.userFrame
    APSCheckButtonFrame .cb0 -parent $uFrame \
      -label "Analysis/Plots" -orientation horizontal -limitPerRow 2 \
      -buttonList {"Plot vs Time" "Plot PSDs" "Source Analysis" "quickSDDSplot..." "Export..."} \
      -variableList {doTimePlot doPSDPlot doSourceAnalysis doQuickSDDSplot doExport}
    APSCheckButtonFrame .cb1 -parent $uFrame \
      -label "Planes" -buttonList {x y} -orientation horizontal \
      -variableList {doXPlots doYPlots}
    APSFrame .source -parent $uFrame -label "Source Analysis Controls" 
    set w $uFrame.source.frame
    APSRadioButtonFrame .plots -parent $w -label "Orbit plots: " \
      -variable sourcePlots -buttonList {Yes No} -valueList {1 0} -orientation horizontal \
      -contextHelp "Choose whether to make plots of smoothed and unsmoothed orbits.  Can be time-consuming."
    APSLabeledEntry .ave -parent $w -label "Orbits to average: " \
      -textVariable sourceOrbitAverages -contextHelp \
      "Specify how many orbits to include in running averages.  Using this feature may improve predications by reducing noise in the orbits that are analyzed."
      
    global dataSelection
    set dataSelection ""
    if $archive {
        global archiveDir 
        set fileList [lsort [glob -nocomplain $archiveDir/????-???-????.??????.gz]]
        if ![llength $fileList] {
            APSSetVarAndUpdate status "No data available."
            changeButtonStates 1
            return
        }
        regsub -all $archiveDir/ $fileList {} list1
        regsub -all .gz $list1 {} list2
        APSScrolledListWindow .datalist -parent $uFrame \
          -closeButton 0 -clearButton 1 -acceptButton 0 \
          -autoAccept 1 -selectionVar dataSelection \
          -itemList $list2
    } else {
        global dataRootname dataDirectory 
        APSLabeledEntry .filename -parent $uFrame -width 60 \
            -label "Filename" -textVariable dataSelection
        APSButton .fsel -parent $uFrame.filename \
          -text F -command \
          {set dataSelection [APSFileSelectDialog [APSUniqueName .] \
                                -path $dataDirectory -pattern $dataRootname-???.sdds]}
    }
    
    APSEnableButton $widget.buttonRow.ok.button
    APSEnableButton $widget.buttonRow.cancel.button
    tkwait variable reviewOrbitMotionDataOk
    if {![string length $dataSelection]} {
        APSSetVarAndUpdate status "No data chosen."
        changeButtonStates 1
        return
    }
    if $archive {
        set rootname $archiveDir/$dataSelection
        set extension .gz
    } else {
        set rootname $dataSelection
        set extension ""
    }

    if $doQuickSDDSplot {
        exec quickSDDSplot -dataFileList $rootname$extension \
          -message "Data from SRMeasureSlowMotion" &
    }
    if $doExport {
        exec sddsExportData -dataFileList $rootname$extension \
          -message "Data from SRMeasureSlowMotion" &
    }
    if {!$doXPlots && !$doYPlots} {
        APSSetVarAndUpdate status "No planes chosen."
        changeButtonStates 1
        return
    }
    if $doTimePlot {
        if $doXPlots {
            lappend columnArgs -column=Time,*ms*x
        } 
        if $doYPlots {
            lappend columnArgs -column=Time,*ms*y
        } 
        eval exec sddsplot -groupby=namestring -separate -title=[file tail $rootname] \
          -ticks=xtime $rootname$extension $columnArgs &
        APSSetVarAndUpdate status "Time plots launched."
    }
    if {$doSourceAnalysis} {
        APSSetVarAndUpdate status "Doing source analysis."
        if [catch {APSSRFindOrbitSource -input $rootname$extension \
                     -display 1 -plot $sourcePlots \
                     -orbitsToAverage $sourceOrbitAverages \
                     -findSources 1 -title [file tail $rootname] \
                     -overlapPlots 0 -glitch 0} result] {
            APSSetVarAndUpdate status "Source analysis error: $result"
        }
    }
    if $doPSDPlot {
        set doList ""
        if $doXPlots {
            lappend doList x
        } 
        if $doYPlots {
            lappend doList y
        } 
        lappend columnArgs -column=f,PSD*y
        lappend column2Args -column=f,PSD*yMean
        if ![file exists $rootname.psd$extension] {
            APSSetVarAndUpdate status "PSD data not found---taking PSD."
            if [catch {exec sddsfft $rootname -pipe=output -psdOutput -suppressaverage \
                         -window -columns=Time,*ms* -nowarnings \
                         | sddsconvert -pipe -delete=column,FFT* \
                         | sddsprocess -pipe -process=PSD*,sum,%sSum \
                         | sddsrowstats -pipe \
                         -mean=PSD:msAve:xMean,bottomLimit=1e-9,topLimit=1e-2,PSD*msAve*x \
                         -mean=PSD:msAve:yMean,bottomLimit=1e-9,topLimit=1e-2,PSD*msAve*y \
                         | sddsprocess -pipe=in $rootname.psd \
                         "-define=parameter,%sRMS,PSD%sSum fftFrequencySpacing * sqrt,select=PSD*Sum,edit=%/PSD//%/Sum//,units=mm" \
                     } result] {
                return -code error "reviewOrbitMotionData: $result"
            }
            if [string compare $extension .gz]==0 {
                if [catch {exec gzip $rootname.psd} result] {
                    return -code error "reviewOrbitMotionData: $result"
                }
            }
        }
        foreach plane $doList {
            exec sddsplot -mode=y=log,y=special -separate -title=[file tail $rootname] \
              -column=f,PSD*$plane $rootname.psd$extension "-legend=edit=%/PSD //" \
              -column=f,PSD*${plane}Mean $rootname.psd$extension \
              "-legend=specified=Mean $plane" \
              -omnipresent -graph=line,type=1 &
        }
        APSSetVarAndUpdate status "PSD plots launched."
    }
    changeButtonStates 1
}

proc collectOrbitMotionData {args} {
    set archive 0
    set PSD 1
    APSStrictParseArguments {archive PSD}

    global dataRootname dataDirectory dataIndex status dataComment
    global dataCollectionInterval dataCollectionTime updateInterval
    changeButtonStates 0
    if !$archive {
        set filename [format $dataDirectory/$dataRootname-%03ld.sdds $dataIndex]
        incr dataIndex
        if {[file exists $filename] && \
              ![APSMultipleChoice [APSUniqueName .] \
                  -question "$filename exists.  Overwrite?" \
                  -returnList {0 1} \
                  -labelList {No Yes} ]} {
            APSSetVarAndUpdate status "File not overwritten."
            changeButtonStates 1
            return
        }
        APSSetVarAndUpdate status "Putting data in file $filename"
        set doGzip 0
    } else {
        if [catch {exec timeconvert -now -scriptOutput=now} tScript] {
            return -code error "$tScript"
        }
        eval $tScript
        global archiveDir archiveDataCollectionInterval archiveDataCollectionTime
        set dataCollectionInterval $archiveDataCollectionInterval
        set dataCollectionTime $archiveDataCollectionTime
        set tag [format %d-%03d-%02d%02d.%02d%02d%02d \
                   $nowYear $nowJulianDay $nowMonth $nowDay \
                   $nowHours $nowMinutes $nowSeconds]
        set filename $archiveDir/$tag
        set doGzip 1
    }

    if $PSD {
        set psdOutput $filename.psd
    } else {
        set psdOutput ""
    }
    if [catch {APSSRCollectSlowBeamMotionData -output $filename \
                 -psdOutput $psdOutput -gzipData $doGzip \
                 -msType msAve -interval $dataCollectionInterval \
                 -time $dataCollectionTime -useExecLog 1 -updateInterval $updateInterval \
                 -statusCallback "bell ; APSSetVarAndUpdate status"} result] {
        APSSetVarAndUpdate status "$result"
        changeButtonStates 1
        return
    }
    changeButtonStates 1

    if $PSD {
        if $doGzip {
            set exten .psd.gz
        } else {
            set exten .psd
        }
        exec sddsplot -column=f,PSD*Mean \
          -column=f,PSD*x -column=f,PSD*y $filename$exten -mode=y=log,y=special -separate &
    }
}

proc MakeArchiveWidget {widget args} {
    set parent ""
    APSStrictParseArguments {parent}
    APSFrame $widget -parent $parent -label "Archive" \
      -contextHelp "Controls archiving and review of archived tune data."

    set w $parent$widget.frame

    APSButton .archive -parent $w -text Archive -command \
      "collectOrbitMotionData -archive 1" -contextHelp \
      "Saves beam motion data to the archive area."
    APSButton .review -parent $w -text Review -command \
      "reviewOrbitMotionData -archive 1" -contextHelp \
      "Reviews beam motion data in the archive area."
    global buttonList
    lappend buttonList $w.archive.button $w.review.button 
}

MakeSaveWidget .save -parent .userFrame
MakeArchiveWidget .review -parent .userFrame

APSSetVarAndUpdate status Ready.
