#!/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 CVSRevisionAuthor "\$Revision: 1.79 $ \$Author: emery $"

APSApplication . -name "SR Beta Function Measurement" \
  -overview "SR beta function measurement procedure interface." -version $CVSRevisionAuthor

# Use the /tmp directory for upgrade/debugging purposes.  Set the
# magnet data mainDir variable.

set mainDir /home/helios/oagData/sr/betaFunctionData

# This procedure sets the status variable used by the status widget.

set quadList {A:Q1 A:Q2 A:Q3 A:Q4 A:Q5 B:Q5 B:Q4 B:Q3 B:Q2 B:Q1}

set quadConfigStatus "Ready."

# Make application and status window widgets.  Returns 1 when completed.

proc MakeBetaMeasurementStatusWidget {widget args} {
    global quadConfigStatus
    set parent ""
    APSParseArguments {parent}
    
    set w $parent$widget
    APSScrolledStatus .status -parent $w -textVariable quadConfigStatus -width 95 -packOption {-side top}
    return 1
}

#Make sector selection widgets.  Returns 1 when completed

APSSRSectorButtons .sextButtons -parent .userFrame -rootname quad \
  -orientation horizontal \
  -label "Quadrupole selections" -description "Quadrupole selections" \
  -itemList $quadList -packOption "-side top" \
  -itemLabelList $quadList -sectorControl 1

# Makes labelled entry widgets for the memory scanner boxcar average,
# BPM gain mode, number of BPM Self Tests, and self test data file.
# The data file is automatically generated based on the most recent
# version.

proc MakeLabelledEntryWidgets {widget args} {
    global mainDir HTuneFreq VTuneFreq NumOfPoints quadRange Description WavefrmNumber
    global HTune VTune Lattice hpvsaSelection
    global expectedYtune expectedXtune

    set parent ""
    APSParseArguments {parent}

    set year ""
    set month ""
    set day ""

    APSFrame $widget -parent $parent \
      -height 30 \
      -packOption {-side top -expand 1}
    
    set w $parent$widget.frame

    APSFrame .labelledEntryFrame -parent $w \
      -height 30 \
      -packOption {-side left -expand 1}

    set w1 ${w}.labelledEntryFrame.frame 
    
    APSLabeledEntry .xtuneFrame -parent $w1 -width 9 \
      -textVariable expectedXtune \
      -packOption {-side top -fill x} \
      -label "Expected Horizontal Tune" \
      -contextHelp "Expected fractional horizontal tune in order to search for the actual tune."

    APSLabeledOutput .htuneFrame -parent $w1 -width 9 \
      -textVariable HTune \
      -packOption {-side top -fill x} \
      -label "Fractional Horizontal Tune" \
      -contextHelp "Fractional horizontal tune determined from a tune measurement."

    APSLabeledOutput .htuneFrequencyFrame -parent $w1 -width 9 \
      -textVariable HTuneFreq \
      -packOption {-side top -fill x} \
      -label "Horizontal Tune Frequency (Hz)" \
      -contextHelp "Frequency of the horizontal tune peak."

    APSLabeledEntry .hrangeFrame -parent $w1 -width 9 \
      -textVariable HRange \
      -packOption {-side top -fill x} \
      -label "VSA Range value for Horizontal Tune (dBm)" \
      -contextHelp "VSA Range horizontal tune determined from a tune measurement."
    
    APSLabeledEntry .ytuneFrame -parent $w1 -width 9 \
      -textVariable expectedYtune \
      -packOption {-side top -fill x} \
      -label "Expected Vertical Tune" \
      -contextHelp "Expected fractional vertical tune in order to search for the actual tune."

    APSLabeledOutput .vtuneFrame -parent $w1 -width 9 \
      -textVariable VTune \
      -packOption {-side top -fill x} \
      -label "Fractional Vertical Tune." \
      -contextHelp "Fractional vertical tune determined from the vertical tune frequency."

    APSLabeledEntry .vtuneFrequencyFrame -parent $w1 -width 9 \
      -textVariable VTuneFreq \
      -packOption {-side top -fill x} \
      -label "Vertical Tune Frequency (Hz)" \
      -contextHelp "Frequency of the vertical tune peak."
# no longer useful. Good to keep as example of a bind command.
#    bind $w1.vtuneFrequencyFrame.entry <Return> {
#        set VTune [ComputeTuneFromFrequency -tuneFreq $VTuneFreq]
#    }


    APSLabeledEntry .vrangeFrame -parent $w1 -width 9 \
      -textVariable VRange \
      -packOption {-side top -fill x} \
      -label "VSA Range value for Vertical Tune (dBm)" \
      -contextHelp "VSA Range vertical tune determined from the vertical tune frequency."
    
    APSLabeledEntry .quadPointsFrame -parent $w1 -width 5 \
      -textVariable NumOfPoints \
      -packOption {-side top -fill x} \
      -label "Number of Data Points (Quadrupole Currents)" \
      -contextHelp "Number of quadrupole current points the tunes are measured at."

    APSLabeledEntry .quadRangeFrame -parent $w1 -width 5 \
      -textVariable quadRange \
      -packOption {-side top -fill x} \
      -label "Quadrupole current range" \
      -contextHelp "Quadrupole current range I_init -> I_init + quadRange."
    APSLabeledEntry .aveLevel1 -parent $w1 -width 5 \
      -textVariable aveLevel1 \
      -packOption {-side top -fill x} \
      -label "Quick \# to average: " -contextHelp \
      "Number of waveforms to average for quick tune-finding."
    APSLabeledEntry .aveLevel2 -parent $w1 -width 5 \
      -textVariable aveLevel2 \
      -packOption {-side top -fill x} \
      -label "Meas. \# to average: " -contextHelp \
      "Number of waveforms to average for tune measurement."

    APSLabeledEntry .descriptionFrame -parent $w1 -width 45 \
      -textVariable Description \
      -packOption {-side top -fill x} \
      -label "Data Description" \
      -contextHelp "Description for sdds data file (lattice characteristics, beam current etc.)"
    APSRadioButtonFrame .process -parent $w1 -orientation Horizontal \
      -buttonList {center-of-mass peak} -valueList {center-of-mass peak} \
      -variable processMethod -label "Processing method:" \
      -contextHelp "center-of-mass method is to get the spectrum (Tune Frequency) at the center-of-mass, peak method gets the spectrum at the peak of waveform."
    APSLabeledEntry .maxIterations -parent $w1 -width 5 \
      -textVariable maxIterations \
      -packOption {-side top -fill x} \
      -label "Iterations for tune feedback" \
      -contextHelp "Number of iterations for restoring the nominal tunes with a reverse bias of the quad. A good guess is applied first, then a measurement of the tune of a particular plane is made. Corrections are done on the tune difference."
    
    APSFrame .tuneMeasurementAndLatticeButtonFrame -parent $w \
      -height 30 \
      -packOption {-side bottom -expand 1}

    set w2 ${w}.tuneMeasurementAndLatticeButtonFrame.frame 

    APSFrame .buttons -parent $w2 -packOption {-side top -expand 1} -relief flat
    set w2b $w2.buttons.frame
    APSFrameGrid .fg -parent $w2b -yList {y1 y2 y3}  -packOption {-side left}
# remove widget with y1
    APSButton .setupVplane -parent $w2b.fg.y2 \
      -text "Setup VSA and Striplines" \
      -command {SetupHPVSAAndDrvStriplines -statusCallback SetStatus} \
      -packOption {-side top -fill x} \
      -contextHelp "This button recalls a state of the HP VSA. The tunes are not measured."
    APSCheckButtonFrame .loadState -parent $w2b.fg.y2 \
      -buttonList [list "Skip loading state"] -orientation horizontal \
      -label "" -variableList skipLoadingState \
      -packOption {-side left -fill x} \
      -contextHelp "Select to skip loading state for faster setup."
    APSButton .measureInitialTunesButtonFrame -parent $w2b.fg.y3 \
      -text "Measure Tunes" \
      -command {MeasureInitialTunes -statusCallback SetStatus} \
      -packOption {-side left -fill x} \
      -contextHelp "Measures the horizontal and vertical tune."

    APSRadioButtonFrame .hpvsaChoiceFrame -parent $w2b \
      -orientation vertical \
      -packOption {-side right -fill x} \
      -label "HPVSA Selection" \
      -variable hpvsaSelection \
      -buttonList {"SR" "Booster"} \
      -valueList {hpvecsr hpvecboo} \
      -contextHelp "This radio button is used to select the HPVSA used to measure the tunes."

    set latticeList [APSSRFindLattices]
    APSFrame .lattice -parent $w2 -packOption {-side top -expand 1}
    set w2b $w2.lattice.frame
    APSRadioButtonFrame .latticeChoiceFrame -parent $w2b \
      -orientation  vertical -limitPerRow 7 \
      -packOption {-side top -fill x} \
      -label "Lattice Choice" \
      -variable Lattice \
      -buttonList $latticeList \
      -valueList $latticeList \
      -contextHelp "This radio button is used to select a lattice used in data analysis and plotting of beta functions."

}

proc MakeButtonActionWidgets {widget args} {
    global mainDir BeamEnergy HTuneFreq VTuneFreq NumOfPoints Description 
    global BetaFunctionDatafileLabel BetaFunctionDatafileName AbortFlag

    set parent ""
    APSParseArguments {parent}
    
    APSFrame $widget -parent $parent \
      -height 30 \
      -packOption {-side top -expand 1}
    
    set w $parent$widget.frame

    APSButton .betaMeasurementButton -parent $w \
      -text "Measure" \
      -command {PerformSRBetaMeasurement -statusCallback SetStatus} \
      -packOption {-side left -fill x} \
      -contextHelp "This button invokes a procedure that performs a SR beta function measurement on selected quads."

    APSButton .abortBetaMeasurementButton -parent $w \
      -text "Abort" \
      -command {set AbortFlag 1} \
      -packOption {-side left -fill x} \
      -contextHelp "This button aborts the SR beta function measurement procedure when it is running."

    APSButton .plotBetaFrame -parent $w \
      -text "Plot Beta Functions" \
      -command {PlotSelectedData -statusCallback SetStatus} \
      -packOption {-side left -fill x} \
      -contextHelp "This button pops up a dialog box to plot the selected beta function measurement data file."

    APSButton .plotRawAndFittedDataFrame -parent $w \
      -text "Plot Raw and Fitted Data" \
      -command {PlotRawAndFittedData -statusCallback SetStatus} \
      -packOption {-side left -fill x} \
      -contextHelp "This button pops up a dialog box to plot the raw and fitted tune/beta function measurement data."

    APSButton .reProcessDataFrame -parent $w \
      -text "Re-Process Data" \
      -command {ReProcessData -statusCallback SetStatus} \
      -packOption {-side left -fill x} \
      -contextHelp "This button pops up a dialog box to select data from a given beta function measurement and reprocess the data for the lattice selected under \"Lattice Choice\"."
}

proc SetStatus {text} {
    global quadConfigStatus
    set quadConfigStatus $text
    update
}

# Disable buttons once one is pressed.

proc DisableButtons {} {
    APSDisableButton .userFrame.buttons.frame.betaMeasurementButton.button
}

# Enable buttons once one is pressed and its associated procedure finishes.

proc EnableButtons {} {
    APSEnableButton .userFrame.buttons.frame.betaMeasurementButton.button
}

# Make a list of quads selected via the checkbuttons.  Procedure returns the list.

proc MakeSelectedQuadList {} {
    global quadList

    set selectedList ""
    for {set sector 1} {$sector<=40} {incr sector} {
        foreach quad $quadList {
            set flagName quadS${sector}$quad
            global $flagName
            if {[set $flagName]} {
                lappend selectedList S${sector}${quad}
            }
        }
    }
    return $selectedList
}

# Procedure computes the tune from the specified tune frequency and returns the tune.

proc ComputeTuneFromFrequency {args} {
    global rfFrequency

    set tuneFreq ""
    APSStrictParseArguments {tuneFreq}
    
    if {$rfFrequency < 300e6} {
        SetStatus "RF frequency readback is < 300 MHz. there could be a problem. No tune calculation possible."
        return
    }
    set revFrequency [expr $rfFrequency / 1296.0]

    return [format %.5f [expr int($tuneFreq / $revFrequency) + 1.0 - ($tuneFreq / $revFrequency)]]
}

# Procedure computes the tune from the specified tune frequency and returns the tune.

proc ComputeFrequencyFromTune {args} {
    global measHarmonic sideband revFrequency

    set tune ""
    APSStrictParseArguments {tune}
    
    set frequency [expr $revFrequency * ($measHarmonic + $tune * $sideband)]

    return [format %.5f $frequency]
}

# Procedure determines the SR quadrupole serial number name from the
# standard Device Name.  Returns the quadrupole serial number name.
# Requires the file ${mainDir}/SQ_xref.sdds.

proc DetermineQuadSerialNumberName {args} {
    global mainDir
    APSParseArguments {quad}
    catch {set quadSerialNumberName \
             [exec sddsprocess -pipe=out ${mainDir}/SQ_xref.sdds -match=col,DeviceName=${quad} \
                | sdds2stream -pipe -col=MagnetName]}
    return $quadSerialNumberName
}

# Procedure sets the driver striplines to drive horizontally and
# restores the saved HPVSA state (HTWCHP) that should show the
# horizontal tune.  The vertical tune HPVSA state is VTWCHP.  The
# important parameters of these states are Span = 10 kHz, RBW = 25 Hz,
# NumberOfPoints = 401, Averages = 100 (rms video), and Marker Peak
# Tracking is ON.

proc SetupHPVSAAndDrvStriplines {args} {
    global hpvsaSelection skipLoadingState

    set statusCallback ""
    APSParseArguments {statusCallback}
    if {$statusCallback!=""} {
        $statusCallback "Setting up Driver striplines for measurement..."
    }
    exec cavput -list=SR:TUNE:sig5bo=0,SR:TUNE:sig6bo=0,SR:TUNE:sig7bo=0,SR:TUNE:sig8bo=0

    if [catch {exec cavput -list=SR:TUNE:HP_1366A_P0_MBBO=ON -pend=10} result] {
            return -code error "SetupHPVSAAndDrvStriplines: Unable to set HP_1366A switch: $result"
        }
    if [catch {exec cavput -list=SR:TUNE:Mux4MO=DTO-BI} result] { 
        return -code error "SetupHPVSAAndDrvStriplines: Unable to set Mux4 switch: $result"
    }
    if [catch {exec cavput -list=SR:TUNE:Mux4Sw2BO=VSA} result] { 
        return -code error "SetupHPVSAAndDrvStriplines: Unable to set Mux4Sw switch: $result"
    }

    if !$skipLoadingState {
        set streamID [APSOpenTelnetStream -IPaddress $hpvsaSelection -GreetingLines 0]
        APSWriteToTelnetStream -command "MMEM:LOAD:STAT 1,'INT:TUNES.STA'" -streamID $streamID
        
        update
        
        set operationCondition 256
        while {$operationCondition & 256} {
            after 1000
            set operationCondition [APSWriteToTelnetStream -command "STAT:OPER:COND?" -streamID $streamID]
        }
        APSCloseTelnetStream -streamID $streamID
    }
    if {$statusCallback!=""} {
        $statusCallback "Done."
    }
    return 1
}

# This procedure sets the HPVSA center frequency to either one of the tune
# frequencies and the span to 5 kHz.  Returns 1 when completed.
# Returns 0 if $plane != Horizontal || Vertical.
# Doesn't actually return a tune value.
# Should leave the instrument with a waveform can be downloaded.
# with procedure DetermineTuneFromWaveform
# Note the source is left on and the auto-tracking of the peak is left on.

proc SetHPVSAHVRange {args} {
    global HTuneFreq newHTuneFreq VTuneFreq newVTuneFreq 
    global hpvsaSelection 
    global HRange VRange aveLevel1 aveLevel2
    APSParseArguments {plane index}

    if {$index==0} {
        set newHTuneFreq $HTuneFreq
        set newVTuneFreq $VTuneFreq
    }

    set streamID [APSOpenTelnetStream -IPaddress $hpvsaSelection]
    # turn on source
    if [catch {APSWriteToTelnetStream -command "OUTP ON" -streamID $streamID \
             } result ] {
        puts stderr $result
        exit 1
    }
    # Ensure that averaging is normal, i.e. not repeating.
    if [catch {APSWriteToTelnetStream -command "AVER:TCON NORM" -streamID $streamID \
             } result ] {
        puts stderr $result
        exit 1
    }
 
# need to turn on peak tracker
    APSWriteToTelnetStream -command "CALC1:MARK:MAX:TRAC ON" -streamID $streamID

    switch $plane {
        Horizontal {
            if [catch {exec cavput -list=SR:TUNE:stripSELmbbo=X \
                     } result ] {
                return -code error "SetHPVSAHVRange: $result"
            }
            APSWriteToTelnetStream -command "PAUSE" -streamID $streamID
            APSWriteToTelnetStream -command "VOLT:RANGE $HRange" -streamID $streamID
            APSWriteToTelnetStream -command "FREQ:CENT ${newHTuneFreq} Hz" -streamID $streamID
            # we're relying on a large resolution bandwidth to
            # remove the spikes.
            APSWriteToTelnetStream -command "SWE:POIN 101" -streamID $streamID
            # Don't need all that averaging.
            APSWriteToTelnetStream -command "AVER:COUN [expr int($aveLevel1)]" -streamID $streamID
            APSWriteToTelnetStream -command "ABOR;*WAI" -streamID $streamID
            update
            after 2000
            APSWriteToTelnetStream -command "DISP:WIND1:TRAC:Y:AUTO ONCE" -streamID $streamID
            # wait for averaging to finish
            set operationCondition 256
            while {$operationCondition & 256} {
                after 1000
                set operationCondition [APSWriteToTelnetStream -command "STAT:OPER:COND?" -streamID $streamID]
            }
            APSWriteToTelnetStream -command "PAUSE" -streamID $streamID
            set newHTuneFreq [APSWriteToTelnetStream -command "CALC:MARK:X?" -streamID $streamID]
            APSWriteToTelnetStream -command "SWE:POIN 1601" -streamID $streamID
            # Need some averaging.
            APSWriteToTelnetStream -command "AVER:COUN [expr int($aveLevel2)]" -streamID $streamID
            APSWriteToTelnetStream -command "FREQ:CENT $newHTuneFreq Hz" -streamID $streamID
            APSWriteToTelnetStream -command "PAUSE" -streamID $streamID
            APSWriteToTelnetStream -command "ABOR;*WAI" -streamID $streamID
            update
            after 2000
            APSWriteToTelnetStream -command "DISP:WIND1:TRAC:Y:AUTO ONCE" -streamID $streamID
            # wait for averaging to finish
            set operationCondition 256
            while {$operationCondition & 256} {
                after 1000
                set operationCondition [APSWriteToTelnetStream -command "STAT:OPER:COND?" -streamID $streamID]
            }
            APSCloseTelnetStream -streamID $streamID
            return 1
        }
        Vertical {
            if [catch {exec cavput -list=SR:TUNE:stripSELmbbo=Y \
                     } result ] {
                return -code error "SetHPVSAHVRange: $result"
            }
            APSWriteToTelnetStream -command "PAUSE" -streamID $streamID
            APSWriteToTelnetStream -command "VOLT:RANGE $VRange" -streamID $streamID
            APSWriteToTelnetStream -command "FREQ:CENT ${newVTuneFreq} Hz" -streamID $streamID
            APSWriteToTelnetStream -command "SWE:POIN 101" -streamID $streamID
            # Don't need all that averaging.
            APSWriteToTelnetStream -command "AVER:COUN [expr int($aveLevel1)]" -streamID $streamID
            APSWriteToTelnetStream -command "ABOR;*WAI" -streamID $streamID
            update
            after 2000
            APSWriteToTelnetStream -command "DISP:WIND1:TRAC:Y:AUTO ONCE" -streamID $streamID
            # wait for averaging to finish
            set operationCondition 256
            while {$operationCondition & 256} {
                after 1000
                set operationCondition [APSWriteToTelnetStream -command "STAT:OPER:COND?" -streamID $streamID]
            }
            APSWriteToTelnetStream -command "PAUSE" -streamID $streamID
            set newVTuneFreq [APSWriteToTelnetStream -command "CALC:MARK:X?" -streamID $streamID]
            APSWriteToTelnetStream -command "SWE:POIN 1601" -streamID $streamID
            # Need some averaging.
            APSWriteToTelnetStream -command "AVER:COUN [expr int($aveLevel2)]" -streamID $streamID
            APSWriteToTelnetStream -command "FREQ:CENT $newVTuneFreq Hz" -streamID $streamID
            APSWriteToTelnetStream -command "PAUSE" -streamID $streamID
            APSWriteToTelnetStream -command "ABOR;*WAI" -streamID $streamID
            update
            after 2000
            APSWriteToTelnetStream -command "DISP:WIND1:TRAC:Y:AUTO ONCE" -streamID $streamID
            # wait for averaging to finish
            set operationCondition 256
            while {$operationCondition & 256} {
                after 1000
                set operationCondition [APSWriteToTelnetStream -command "STAT:OPER:COND?" -streamID $streamID]
            }
            APSCloseTelnetStream -streamID $streamID
            return 1
        }
        default {
            return 0
        }
    }
}

# Procedure to perform the beta function measurement by looping over
# selected quadrupoles.  Returns 0 if no sectors or quads are selected
# or if the measurement is aborted.  Returns 1 when the measurement of
# all the selected quadrupoles is completed.

proc PerformSRBetaMeasurement {args} {
    global SectorSelection Description HTuneFreq VTuneFreq QuadSelection NumOfPoints quad AbortFlag
    global IniQuadISetpoint hpvsaSelection mainDir

    DisableButtons
    update

    if {[catch {exec cavget -pend=5 -list=S:DesiredMode -numerical} mode] || \
          $mode==1 || $mode==2} {
        SetStatus "The machine is in user operations or beamline studies mode---can't go to test mode."
        EnableButtons
        update
        return
    }

    APSParseArguments {statusCallback}
    MeasureInitialTunes -statusCallback SetStatus
    SetupHPVSAAndDrvStriplines
    update

    # Create sector and quadrupole selection lists.  Determine if
    # anything has been selected.  Return 0 if no sectors, quads, or
    # both are selected.

    set selectedQuadList [MakeSelectedQuadList]

    if ![string length $selectedQuadList] {
        EnableButtons
        update
        $statusCallback "No Quads Selected."
        return 0
    }
    
    # Setup sector and quadrupole measurement loops.  
    # Set abort flag to zero initially.  Return 0
    # if it is set to 1
    
    set dataSet [clock format [clock seconds] -format "%Y-%j-%m%d/%H%M%S"]
    # Until we figure out how to pass the mask properly to a new
    # directory with the tcl file command we have to use the unix command.
    #    file mkdir $mainDir/$dataSet
    exec mkdir -p $mainDir/$dataSet

    set AbortFlag 0

    set firstQuadDone 0
    foreach quad $selectedQuadList {
        # Compute quadrupole current and tune ranges.
        set IniQuadISetpoint [exec cavget -list=${quad}:CurrentAO -pendIoTime=25]
        update
        if {![AcquireWaveformData -quad $quad -dataSet $dataSet \
                -statusCallback SetStatus]} {
            EnableButtons
            update
            if {$AbortFlag==1} {
                if {$statusCallback!=""} {
                    $statusCallback "Restoring $quad current to [format %0.3f $IniQuadISetpoint]."
                }
                exec cavput -list=${quad}:CurrentAO=${IniQuadISetpoint} -pendIoTime=25
                if {$statusCallback!=""} {
                    $statusCallback "$quad current restored to [format %0.3f $IniQuadISetpoint].  Measurement aborted."
                    $statusCallback "Note: $quad current restored to [format %0.3f $IniQuadISetpoint] amperes but not reverse biased to return the tunes to nominal."
                }
                return 0
            }
        }
        update
        if !$firstQuadDone {
            # If at least one quad is measured, then
            # update the description file.
            # it is important that the file is
            # stored in ascii mode and with no_row_counts=1 in its header.
            if [file exists $mainDir/descriptions.sdds] {
                set fid [open $mainDir/descriptions.sdds a]
                puts $fid "$dataSet \"$dataSet -> $Description\""
                close $fid
            }
            set firstQuadDone 1
        }
    }
    
    if {$statusCallback!=""} {
        $statusCallback "Beta function measurement completed."
    }
    EnableButtons
    update
    return 1
}

# Procedure performs tune waveform data acquisition for a given
# quadruopole.  Returns 1 when completed.  Returns 0 if the quadrupole
# current increment is undefined (number of quadrupole current points
# is <= 1 or if abort is pressed.

proc AcquireWaveformData {args} {
    global IniQuadISetpoint NumOfPoints quadIInc FnlQuadISetpoint
    global HTuneFreq VTuneFreq AbortFlag mainDir hpvsaSelection

    APSParseArguments {dataSet quad statusCallback}

    set quadIInc [DetermineQuadIInc -points $NumOfPoints -statusCallback SetStatus]
    if {$quadIInc==-1} {
        return 0
    }

    # Setup quadrupole current and waveform measurement loops.
    set quadISetpoint $IniQuadISetpoint

    for {set setpoint 0} {$setpoint < $NumOfPoints} {incr setpoint} {
        if $setpoint!=0 {
            # Compute the quadrupole current setpoint and apply it
            set quadISetpoint [expr $quadISetpoint + $quadIInc]
        }
        exec cavput -list=${quad}:CurrentAO=${quadISetpoint} -pendIoTime=25
        # wait for the quad to settle.
        update
        after 2000
        if {$statusCallback!=""} {
            $statusCallback "Setting quad $quad to [format %0.3f $quadISetpoint] amps."
            $statusCallback "This is quadrupole $quad data point [expr $setpoint + 1.0]."
        }
        update

        foreach plane {Horizontal Vertical} {
            if {$statusCallback!=""} {
                $statusCallback "Taking HPVSA waveform for the $plane plane..."
            }                        
            set waveformFile [CreateTuneWaveformFile -quad ${quad} -dataSet ${dataSet} -index $setpoint -plane $plane -dataType BetaData]
            SetHPVSAHVRange -plane $plane -index $setpoint
            update
            exec hpVecTrace -${hpvsaSelection} a $waveformFile
            update
            AddScalarPVsToWaveformFile -file $waveformFile -quad ${quad}
            AddSDDSDescription -file $waveformFile -quad $quad
            update
            after 1000

            # If Abort is pressed return 0 and print an abort message

            if {$AbortFlag==1} {
                if {$statusCallback!=""} {
                    $statusCallback "Tune Waveform data acquisition for quadrupole $quad aborted."
                }
                set FnlQuadISetpoint $quadISetpoint
                exec cavput -list=${quad}:CurrentAO=${IniQuadISetpoint} -pendIoTime=25
                set tmpHFileList [glob -nocomplain ${quad}_${dataSet}_Horizontal_??.sdds]
                set tmpVFileList [glob -nocomplain ${quad}_${dataSet}_Vertical_??.sdds]
                file delete $tmpHFileList $tmpVFileList
                update
                return 0
            }
        }
        
    }
    set FnlQuadISetpoint $quadISetpoint
    
    if {$statusCallback!=""} {
        $statusCallback "Waveform data acquisition for quadrupole $quad completed."
    }

    if {$statusCallback!=""} {
        $statusCallback "Done with beta function measurement for quadrupole ${quad}.  Collecting data into files..."
    }
    CollectDataAndCleanupFiles -dataSet $dataSet -quad $quad -dataType BetaData
    if {$statusCallback!=""} {
        $statusCallback "Done Collecting data into files.  Plotting raw data."
    }
    PlotRawData -dataSet $dataSet -quad $quad -statusCallback SetStatus
    update
    AnalyzeRawTuneData -dataSet $dataSet -quad $quad -statusCallback SetStatus
    update
    PlotFittedData -dataSet $dataSet -quad $quad -statusCallback SetStatus
    update
    RestoreNominalTune -dataSet $dataSet -quad $quad -statusCallback SetStatus
    update
    return 1
}

# Procedure to add the description and contents field to the beta
# function measurement data file.  Returns 1 when completed.

proc AddSDDSDescription {args} {
    global Description 
    APSParseArguments {file quad}
    exec sddsprocess $file "-print=param,Description,[APSMakeSafeQualifierString $Description]" \
      "-print=param,Contents,Beta Function Measurement Data" \
      -print=param,QuadVaried,$quad \
      "-print=param,CurrentString,${quad}:Current = %.1f Amperes,${quad}:Setpoint" -nowarnings 
    file delete ${file}~
    return 1
}

# Procedure to determine the quadrupole current increment based on the
# initial and final values of the quadrupole current.  Returns the
# increment.  Returns 0 and sets the current increment to -1 if the
# number of points is <=1.

proc DetermineQuadIInc {args} {
    global quadRange

    APSParseArguments {points statusCallback}

    # Make sure the number of quadrupole current points are greater
    # than 1.  Otherwise Return 0 and an error message.  The variable
    # quadIInc must be positive and defined.  Quadrupole current range
    # set to 10 amperes.

    if {$points > 1} {
        set quadIInc [expr abs($quadRange / ($points - 1.0))]
        return $quadIInc
    } else {
        if ![string length $statusCallback] {
            $statusCallback "Error:  Number of quadrupole current points must be an integer > 1."
        }   
        set quadIInc -1
        return $quadIInc
    }
}

# Procedure creates and returns the temporary scalars input file for a given quadrupole.

proc CreateTuneWaveformFile {args} {
    global mainDir
    APSParseArguments {quad dataSet index plane dataType}
    set fileRoot ${dataSet}/${quad}
    switch $dataType {
        BetaData {
            set waveformFile ${mainDir}/${fileRoot}_${plane}_[format %.2d ${index}].sdds
        }
        RestoreData {
            set waveformFile ${mainDir}/${fileRoot}_${plane}_Restore_[format %.2d ${index}].sdds
        }
    }
    return $waveformFile
}

# This procedure adds useful scalar PVs to the waveform data files and deletes the original waveform file.
# Returns 1 when completed.

proc AddScalarPVsToWaveformFile {args} {
    APSParseArguments {file quad}
    set scalarPVList [exec cavget -list=S-DCCT:CurrentM.VAL,S-INJ:MPS:LifetimeMinutesM,${quad}:CurrentAO -pendIoTime=25]
    set currentPV [lindex $scalarPVList 0]
    set lifeTimePV [lindex $scalarPVList 1]
    set quadCurrentPV [lindex $scalarPVList 2]

    exec sddsprocess ${file} \
      -define=param,SRCurrent,${currentPV},units=mA \
      -define=param,SRlifeTime,${lifeTimePV},units=minutes \
      -define=param,${quad}:Setpoint,${quadCurrentPV},units=Amperes \
      -nowarnings
    file delete ${file}~
    return 1
}

# Procedure computes the tune frequency (Hz) by first acquiring the waveform then 
# computing the tune via the integral method.

proc DetermineTuneFromWaveform {} {
    global hpvsaSelection processMethod

    set waveformFile /tmp/waveform.sdds
    exec hpVecTrace -${hpvsaSelection} a $waveformFile
    switch $processMethod {
        center-of-mass {
            set selectedTune [expr [exec sddssmooth -pipe=out $waveformFile \
                                      -col=Waveform -pass=0 \
                                      -despike=neighbors=5,average=5,passes=5 \
                                      | sddsprocess -pipe \
                                      -process=Waveform,minimum,WvfMin \
                                      "-redefine=col,Waveform,Waveform WvfMin -" \
                                      | sddsinteg -pipe -integrate=Waveform -versus=Frequency \
                                      | sddsprocess -pipe -process=WaveformInteg,maximum,WvfMax \
                                      "-redefine=col,WaveformInteg,WaveformInteg WvfMax / 0.5 -" \
                                      -process=WaveformInteg,zerocrossing,TuneFreq,functionOf=Frequency \
                                      | sdds2stream -pipe=in -param=TuneFreq -ignore] * 1.0e6]
        }
        peak {
            set selectedTune [expr [exec sddssmooth -pipe=out $waveformFile \
                                      -col=Waveform -pass=0 \
                                      -despike=neighbors=5,average=5,passes=5 \
                                      | sddsprocess -pipe \
                                      -process=Waveform,maximum,TuneFreq,position,functionOf=Frequency \
                                      | sdds2stream -pipe=in -param=TuneFreq -ignore] * 1.0e6]
            
        }
    }
    file delete $waveformFile
    set selectedTune [format %0.1f $selectedTune]
    return ${selectedTune}
}

# Procedure iteratively finds the quadrupole current to restore the
# nominal 7 GeV tune after the beta function measurement to within 50
# Hz. Returns 1 when completed. 0 if AbortFlag is set or feedback
# requests 4 changes smaller than the quadrupole dac bit resolution of
# 6 mA.

proc RestoreNominalTune {args} {
    global FnlQuadISetpoint IniQuadISetpoint HTuneFreq VTuneFreq quadRange
    global mainDir AbortFlag
    global maxIterations

    APSParseArguments {dataSet quad statusCallback}
    set root ${mainDir}/${dataSet}/${quad}
    
    # these reverse bais current are applicable to the 10 A scan (default quadRange value).
    set quadRevBiasCurrentList {-1.3 -1.6 -1.2 -1.8 -1.8}
    
    # feedback on plane which has the most sensitivity or the least
    # noise in case both planes are equal in sensitivity.
    set tuneFeedbackPlaneList {h h v v v}
    regexp {Q(.)} $quad {} quadNumber
    set quadNumberListIndex [expr int(${quadNumber} - 1.0)]
    set quadRevBiasCurrent [lindex ${quadRevBiasCurrentList} ${quadNumberListIndex}]

    # adjust for the quad range actually used.
    set quadRevBiasCurrent [expr $quadRevBiasCurrent * $quadRange / 10.0]
    set tuneFeedbackPlane [lindex ${tuneFeedbackPlaneList} ${quadNumberListIndex}]
    set rfFrequency [exec sdds2stream ${root}_HTuneData.sdds -page=1 -param=rfFreq]

    update
    if {$statusCallback!=""} {
        $statusCallback "Ramping quad $quad to [format %0.3f $IniQuadISetpoint] A."
    }
    exec cavput -list=${quad}:CurrentAO=$IniQuadISetpoint -ramp=step=5,pause=1
    update

    if {$statusCallback!=""} {
        $statusCallback "Reverse biasing quad $quad by [format %0.3f $quadRevBiasCurrent] A."
    }
    exec cavput -list=${quad}:CurrentAO=${quadRevBiasCurrent} -deltaMode -pendIoTime=25
    update

    switch $tuneFeedbackPlane {
        h {
            SetHPVSAHVRange -plane Horizontal -index 0
            set presentTuneFreq [DetermineTuneFromWaveform]
            set difference [expr (${HTuneFreq} - ${presentTuneFreq}) / (${rfFrequency} / 1296.0)]
            set quadSlope [exec sdds2stream -param=Slope ${root}_HTuneData_IFit.sdds]
        }
        v {
            SetHPVSAHVRange -plane Vertical -index 0
            set presentTuneFreq [DetermineTuneFromWaveform]
            set difference [expr (${VTuneFreq} - ${presentTuneFreq}) / (${rfFrequency} / 1296.0)]
            set quadSlope [exec sdds2stream -param=Slope ${root}_VTuneData_IFit.sdds]
        }
    }

    set tolerance [expr 50.0 / (${rfFrequency} / 1296.0)]

    if {$statusCallback!=""} {
        $statusCallback "Starting difference of tune from nominal is [format %0.4f ${difference}]."
        $statusCallback "Using $tuneFeedbackPlane plane for feedback."
    }

    # While-loop to do feedback.  Exits if the absolute tune
    # difference (from nominal) is < tolerance or if quad current
    # changes are less than the bit level of 6 mA or at least 3
    # iterations of the loop.  Variable iterations is used for this
    # test.  AbortFlag allows manual aborting of the feedback if
    # AbortFlag is set to 1.
    # Exit if S35DCCT reads zero.

    set iterations 0
    set S35DCCT [exec cavget -list=S-DCCT:CurrentM]
    while {[expr abs($difference) > $tolerance] && !$AbortFlag && $iterations<$maxIterations && [expr $S35DCCT > 0.1]} {
        # feedback gain is 0.75
        set newQuadCurrent [expr (${difference} / ${quadSlope}) * -0.75]
        if {$statusCallback!=""} {
            $statusCallback "Applying correction to quadrupole ${quad} current of [format %0.3f ${newQuadCurrent}] A."
        }
        exec cavput -list=${quad}:CurrentAO=${newQuadCurrent} -deltaMode -pendIoTime=25
        incr iterations
        if {[expr abs($newQuadCurrent)]<0.006} {
            if {$statusCallback!=""} {
                $statusCallback "Last quad change was smaller than bit resolution. Exiting feedback after $iterations iterations."
            }
            break
        }
        update
        if {$statusCallback!=""} {
            $statusCallback "Measuring tune in $tuneFeedbackPlane plane again."
        }

        switch $tuneFeedbackPlane {
            h {
                SetHPVSAHVRange -plane Horizontal -index 0
                set presentTuneFreq [DetermineTuneFromWaveform]
                set difference [expr ($HTuneFreq - $presentTuneFreq) / ($rfFrequency / 1296.0)]
            }
            v {
                SetHPVSAHVRange -plane Vertical -index 0
                set presentTuneFreq [DetermineTuneFromWaveform]
                set difference [expr ($VTuneFreq - $presentTuneFreq) / ($rfFrequency / 1296.0)]
            }
        }
        set S35DCCT [exec cavget -list=S-DCCT:CurrentM]
        update
    }

    if $AbortFlag {
        if {$statusCallback!=""} {
            $statusCallback "Warning:  Reverse bias feedback was aborted.  Setting of final tunes and reverse bias current was not finished."
        }
        update
    }
    if {$S35DCCT < 0.1} {
        if [string length $statusCallback] {
            $statusCallback "Warning: No stored beam. Reverse bias feedback stopped."
        }
        update
    }
    if {$iterations==$maxIterations} {
        if {$statusCallback!=""} {
            $statusCallback "Warning:  Reverse bias feedback stopped after $maxIterations iterations."
        }
        update
    } 
    if {[expr abs($difference) < ${tolerance}] } {
        if {$statusCallback!=""} {
            $statusCallback "Warning:  Reverse bias feedback converged."
        }
        update
    } 



    SetHPVSAHVRange -plane Horizontal -index 0
    set presentTuneFreq [DetermineTuneFromWaveform]
    set presentHTune [ComputeTuneFromFrequency -tuneFreq $presentTuneFreq]
    set finalQuadCurrent [exec cavget -list=${quad}:CurrentAO -pendIoTime=25]

    SetHPVSAHVRange -plane Vertical -index 0
    set presentTuneFreq [DetermineTuneFromWaveform]
    set presentVTune [ComputeTuneFromFrequency -tuneFreq $presentTuneFreq]

    if {$statusCallback!=""} {
        $statusCallback "Final tunes: H [format %0.4f ${presentHTune}], V [format %0.4f ${presentVTune}]."
        $statusCallback "Final quad current is [format %0.4f ${finalQuadCurrent}]."
        $statusCallback "Finished with feedback biasing of quadrupole ${quad}."
    }

    exec sddsprocess ${root}_HTuneData.sdds \
      "-define=param,revBiasDifferenceCurrent,$IniQuadISetpoint ${finalQuadCurrent} -,units=Amperes" \
      -define=param,RestoredHTune,${presentHTune} \
      -nowarnings

    exec sddsprocess ${root}_VTuneData.sdds \
      "-define=param,revBiasDifferenceCurrent,$IniQuadISetpoint ${finalQuadCurrent} -,units=Amperes" \
      -define=param,RestoredVTune,${presentVTune} \
      -nowarnings
    
    file delete ${root}_HTuneData.sdds~ ${root}_VTuneData.sdds~
    update
    return 1
}

# This procedure collects and combines all the tune waveform data
# files for a given quad into one file.  Returns 1 when completed.

proc CollectDataAndCleanupFiles {args} {
    global mainDir rfFrequency

    APSParseArguments {dataSet quad dataType}

    if {[string match $dataType BetaData]} {
        set dataFileHList [lsort [glob -nocomplain ${mainDir}/${dataSet}/${quad}_Horizontal_??.sdds]]
        set dataFileVList [lsort [glob -nocomplain ${mainDir}/${dataSet}/${quad}_Vertical_??.sdds]]
        eval exec sddscombine $dataFileHList ${mainDir}/${dataSet}/${quad}_HTuneData.sdds
        eval exec sddscombine $dataFileVList ${mainDir}/${dataSet}/${quad}_VTuneData.sdds

        exec sddsprocess ${mainDir}/${dataSet}/${quad}_HTuneData.sdds \
          -define=param,rfFreq,${rfFrequency},units=Hz \
          -nowarnings
        exec sddsprocess ${mainDir}/${dataSet}/${quad}_VTuneData.sdds \
          -define=param,rfFreq,${rfFrequency},units=Hz \
          -nowarnings
        eval file delete ${dataFileHList} ${dataFileVList} ${mainDir}/${dataSet}/${quad}_HTuneData.sdds~ ${mainDir}/${dataSet}/${quad}_VTuneData.sdds~
    }
    return 1
}

# This procedure plots the raw data for a given filelabel.  Returns 1 when finished.

proc PlotRawData {args} {
    global mainDir
    APSParseArguments {dataSet quad statusCallback}
    set root ${mainDir}/${dataSet}/${quad}
    set HFileName ${root}_HTuneData.sdds
    set VFileName ${root}_VTuneData.sdds

    if {$statusCallback!=""} {
        $statusCallback "Plotting beta function measurement data in file ${root}_H,VTuneData.sdds..."
    }

    catch {exec sddsplot -title= -labelsize=0.03 \
             -split=pages -sep=pages \
             -col=Frequency,Waveform -same \
             "-topline=Horizontal Tune Waveforms data" \
             -ticks=yfactor=1e6 \
             -string=@Description,p=0.05,q=0.95,scale=1.25 \
             -string=@Contents,p=0.05,q=0.90,scale=1.25 \
             -string=@CurrentString,p=0.05,q=0.85,scale=1.25 \
             $HFileName -filenamesOnTopline -end \
             -col=Frequency,Waveform -same \
             "-topline=Vertical Tune Waveforms data" \
             -ticks=yfactor=1e6 \
             -string=@Description,p=0.05,q=0.95,scale=1.25 \
             -string=@Contents,p=0.05,q=0.90,scale=1.25 \
             -string=@CurrentString,p=0.05,q=0.85,scale=1.25 \
             $VFileName  -filenamesOnTopLine \
             & \
         } 
    
    if {$statusCallback!=""} {
        $statusCallback "Done."
    }
    return 1
}

# Procedure plots the fitted tune vs quadrupole current data.  Returns
# 1 when completed.

proc PlotFittedData {args} {
    global mainDir
    APSParseArguments {dataSet quad statusCallback}

    set root ${mainDir}/${dataSet}/${quad}
    if {$statusCallback!=""} {
        $statusCallback "Plotting beta function tune vs quad current and fitted data in file ${root}_H,VTuneData_BnLFit.sdds..."
    }

    set HFileName ${root}_HTuneData_BnLFit.sdds
    set VFileName ${root}_VTuneData_BnLFit.sdds
    
    catch {exec sddsplot -title= -labelsize=0.03 \
             -col=BnL,HTune -graph=symbol,scale=3,subtype=1 $HFileName \
             -col=BnL,HTuneFit -graph=line,type=1 $HFileName \
             -legend=specified=HTune \
             "-topline=Nominal Horizontal Tune vs Quad Integrated Field Data" \
             -string=@BetaXString,p=0.4,q=0.9,scale=1.25 \
             -string=@QuadNameString,p=0.05,q=0.9,scale=1.25 \
             -end \
             -col=BnL,VTune -graph=symbol,scale=3,subtype=2 $VFileName \
             -col=BnL,VTuneFit -graph=line,type=2 $VFileName \
             -legend=specified=VTune \
             "-topline=Nominal Vertical Tune vs Quad Integrated Field Data" \
             -string=@BetaYString,p=0.4,q=0.9,scale=1.25 \
             -string=@QuadNameString,p=0.05,q=0.9,scale=1.25 \
             & }
    after 1000
    set tmpfile /tmp/[APSTmpString]
    set energy 7.0
    set rigidity [expr $energy / 0.299792458 ]
    foreach plane {H V} {
        if {![APSYesNoPopUp "Would like to delete points for ${plane}Tune?"]} {
            continue
        }
        global cancel
        APSDialogBox .points -name "Delete points from ${plane}Tune"  \
          -okCommand {set cancel 0} -cancelCommand {set cancel 1}
        APSLabel .info -parent .points.userFrame \
          -text "Please provide the index of point you want to delete from ${plane}Tune (separate by space)"
        global deletePoints
        APSLabeledEntry .point -parent .points.userFrame \
          -label "deleting point index:" -textVariable deletePoints \
          -width 30
        tkwait window .points
        if $cancel {
            $statusCallback "deleting data from ${plane}Tune was cancelled."
            continue
        }
        if [llength $deletePoints] {
            set point1 [lindex $deletePoints 0]
            if [catch {set a [expr $point1/2] } result] {
                return -code error "Non-integer value given!"
            }
            set filterOption -filter=col,Index,$point1,$point1,!
            set leftPoints [lreplace $deletePoints 0 0]
            foreach index $leftPoints {
                if [catch {set a [expr $index/2] } result] {
                    return -code error "Non-integer value given!"
                }
                append filterOption ,Index,$index,$index,!,&
            }
            set filename [set ${plane}FileName]
            if [catch {exec sddsprocess $filename -pipe=out \
                         "-define=col,Index,i_row 1 +,type=long" \
                         $filterOption \
                         | sddspfit -pipe -terms=2 -generate -col=BnL,HTune \
                         | sddsprocess -pipe=in $tmpfile.$plane \
                         "-redefine=param,BetaX,4.0 pi * Slope * $rigidity * abs,units=m" \
                         "-redefine=param,BetaXSigma,4.0 pi * SlopeSigma * $rigidity *,units=m" \
                         "-reprint=param,BetaXString,\$gb\$r\$bx\$n = %.2f \$sa\$e %.2f %s,BetaX,BetaXSigma,BetaX.units" \
                         "-reprint=param,QuadNameString,${quad}" \
                         -process=HTune,first,InitialHTune1
            } result] {
                return -code error $result
            }
            exec sddsplot "-title=${plane}Tune after deleting point $deletePoints" -labelsize=0.03 \
              -col=BnL,HTune -graph=symbol,scale=3,subtype=1 $tmpfile.$plane \
              -col=BnL,HTuneFit -graph=line,type=1 $tmpfile.H \
              -legend=specified=HTune \
              "-topline=Nominal Horizontal Tune vs Quad Integrated Field Data" \
              -string=@BetaXString,p=0.4,q=0.9,scale=1.25 \
              -string=@QuadNameString,p=0.05,q=0.9,scale=1.25 &
            $statusCallback "Points [join $deletePoints ,] are deleted from ${plane}Tune"
        }
    }
    return 1
}

# Procedure is used to reprocess the data based an the selected
# lattice given by the value of the global variable "Lattice".
# Returns 1 when completed.  Returns 0 if no dataSet is selected and
# prints a status message.

proc ReProcessData {args} {

    global mainDir Lattice

    APSParseArguments {statusCallback}
    
    set dataSetList ""
    set selectionList [FindDataSetsAndDescriptions]
    set completeDataSetList [lindex $selectionList 0]
    set completeDescriptionList [lindex $selectionList 1]
    set dataSetList [APSChooseItemFromList \
                     -name "Data Set Selection" \
                     -itemList $completeDescriptionList \
                     -returnList $completeDataSetList \
                     -returnIndices 0 \
                     -multiItem 1 \
                     -contextHelp "Select a beta function measurement data set for data reprocessing."]

    if {$dataSetList==""} {
        if {$statusCallback!=""} {
            $statusCallback "Please select a valid data set for reprocessing."
        }
        return 0
    }

    if {$statusCallback==""} {
        $statusCallback "Reprocessing data for data sets $dataSetList..."
    }

    foreach dataSet $dataSetList {
        set dataFileList [glob -nocomplain $mainDir/$dataSet/*_HTuneData.sdds]
        foreach dataFile $dataFileList {
            regexp "$mainDir/$dataSet/(.*)_HTuneData.sdds" $dataFile {} quad
            AnalyzeRawTuneData -dataSet $dataSet -quad $quad \
              -statusCallback SetStatus
        }
    }

    if {$statusCallback!=""} {
        $statusCallback "Done reprocessing data for data set(s) $dataSetList"
    }

    return 1
}

# Procedure computes the beta function from the raw tune data.  Uses an
# integration method to find the tune from the center of the distribution.

proc AnalyzeRawTuneData {args} {
    global mainDir IniQuadISetpoint HTuneFreq Lattice processMethod OAGGlobal

    APSParseArguments {dataSet quad statusCallback}

    set latticeDir $OAGGlobal(SRLatticesDirectory)
    set energy 7.0
    set rigidity [expr $energy / 0.299792458 ]
    set magnetDir /home/helios/SR/controlFiles/magnets/quad
    set quadLengthList {0.5 0.8 0.5 0.5 0.6}
    regexp {Q(.)} $quad {} quadNumber
    set quadNumberListIndex [expr $quadNumber - 1.0]
    set quadLength [lindex $quadLengthList [expr int($quadNumberListIndex)]]
    
    set root ${mainDir}/${dataSet}/${quad}
    exec sddsprocess $latticeDir/$Lattice/aps.twiAve ${root}_aps.twi \
      -match=col,ElementName=${quad} \
      -process=sAverage,first,s \
      -process=psixAverage,first,Psix \
      -process=psiyAverage,first,Psiy
    update
    
    set excitationFile ${magnetDir}/[DetermineQuadSerialNumberName -quad $quad]_excit.sdds
    
    if {$statusCallback!=""} {
        $statusCallback "Processing beta function measurement data for ${quad}..."
    }   

    set HFileName ${root}_HTuneData.sdds
    set HBnLFileName ${root}_HTuneData_BnLFit.sdds
    set HIFileName ${root}_HTuneData_IFit.sdds
    set VFileName ${root}_VTuneData.sdds
    set VBnLFileName ${root}_VTuneData_BnLFit.sdds
    set VIFileName ${root}_VTuneData_IFit.sdds
    set rfFrequency [expr [exec sdds2stream $HFileName \
                                     -page=1 -param=rfFreq] / 1.0e6]

# one should offer the option of processing with convolution.
# This wil help when there are mutliple peaks, and when
# the noise baseline changes.
    switch $processMethod {
        center-of-mass {
            exec sddssmooth -pipe=out $HFileName \
              -col=Waveform -pass=0 \
              -despike=neighbors=5,average=5,passes=5 \
              | sddsprocess -pipe -process=Waveform,minimum,WvfMin \
              "-redefine=col,Waveform,Waveform WvfMin -" \
              | sddsinteg -pipe -integrate=Waveform -versus=Frequency \
              | sddsprocess -pipe -process=WaveformInteg,maximum,WvfMax \
              "-redefine=col,WaveformInteg,WaveformInteg WvfMax / 0.5 -" \
              -process=WaveformInteg,zerocrossing,HFreq,functionOf=Frequency \
              "-define=param,HTune,${rfFrequency} 1296 / sto revf HFreq revf / int 1 + revf * HFreq - revf /" \
              | sddsxref -pipe $HFileName \
              -transfer=parameter,s,${quad}:Setpoint,SRCurrent,SRlifeTime,Description,Contents,QuadVaried,CurrentString,FileName \
              "-leave=*" \
              | sddscollapse -pipe \
              | sddssort -pipe -col=${quad}:Setpoint,increasing \
              | sddspfit -pipe \
              -terms=2 -generate \
              -col=${quad}:Setpoint,HTune \
              | sddsprocess -pipe=in $HIFileName \
              "-print=param,QuadNameString,${quad}"
        }
        peak {
            exec sddssmooth -pipe=out $HFileName \
              -col=Waveform -pass=0 \
              -despike=neighbors=5,average=5,passes=5 \
              | sddsprocess -pipe \
              -process=Waveform,Maximum,HFreq,position,functionOf=Frequency \
              "-define=param,HTune,${rfFrequency} 1296 / sto revf HFreq revf / int 1 + revf * HFreq - revf /" \
              | sddsxref -pipe $HFileName \
              -transfer=parameter,s,${quad}:Setpoint,SRCurrent,SRlifeTime,Description,Contents,QuadVaried,CurrentString,FileName \
              "-leave=*" \
              | sddscollapse -pipe \
              | sddssort -pipe -col=${quad}:Setpoint,increasing \
              | sddspfit -pipe \
              -terms=2 -generate \
              -col=${quad}:Setpoint,HTune \
              | sddsprocess -pipe=in $HIFileName \
              "-print=param,QuadNameString,${quad}" "-print=par,Method,Peak"
        }
    }
    update

    exec sddsinterp -pipe=out ${excitationFile} \
      -columns=I,BnL \
      -aboveRange=extrapolate \
      -fileValues=$HIFileName,col=${quad}:Setpoint \
      | sddsconvert -pipe -rename=col,I=${quad}:Setpoint \
      | sddsxref -pipe $HIFileName -take=HTune \
      | sddspfit -pipe -terms=2 -generate \
      -col=BnL,HTune \
      | sddsprocess -pipe=in $HBnLFileName \
      "-define=param,BetaX,4.0 pi * Slope * $rigidity * abs,units=m" \
      "-define=param,BetaXSigma,4.0 pi * SlopeSigma * $rigidity *,units=m" \
      "-print=param,BetaXString,\$gb\$r\$bx\$n = %.2f \$sa\$e %.2f %s,BetaX,BetaXSigma,BetaX.units" \
      "-print=param,QuadNameString,${quad}" \
      -process=HTune,first,InitialHTune
    
    catch {exec sddsxref $HBnLFileName $HFileName \
             -transfer=param,revBiasDifferenceCurrent,RestoredHTune \
             "-leave=*"}

    catch {sddsxref $HFileName $HBnLFileName \
             -transfer=parameter,InitialHTune}

    catch {exec sddsxref $HFileName ${root}_aps.twi \
             "-leave=*" \
             -transfer=parameter,s,Psix
    }
    catch {exec sddsxref $HBnLFileName ${root}_aps.twi \
             "-leave=*" \
             -transfer=parameter,s,Psix
    }
    catch {exec sddsxref $HIFileName ${root}_aps.twi \
             "-leave=*" \
             -transfer=parameter,s,Psix
    }
    update
    switch $processMethod {
        center-of-mass {
            exec sddssmooth -pipe=out $VFileName  \
              -col=Waveform -pass=0 \
              -despike=neighbors=5,average=5,passes=5 \
              | sddsprocess -pipe -process=Waveform,minimum,WvfMin \
              "-redefine=col,Waveform,Waveform WvfMin -" \
              | sddsinteg -pipe -integrate=Waveform -versus=Frequency \
              | sddsprocess -pipe -process=WaveformInteg,maximum,WvfMax \
              "-redefine=col,WaveformInteg,WaveformInteg WvfMax / 0.5 -" \
              -process=WaveformInteg,zerocrossing,VFreq,functionOf=Frequency \
              "-define=param,VTune,${rfFrequency} 1296 / sto revf VFreq revf / int 1 + revf * VFreq - revf /" \
              | sddsxref -pipe $VFileName \
              -transfer=parameter,s,${quad}:Setpoint,SRCurrent,SRlifeTime,Description,Contents,QuadVaried,CurrentString,FileName \
              "-leave=*" \
              | sddscollapse -pipe \
              | sddssort -pipe -col=${quad}:Setpoint,increasing \
              | sddspfit -pipe \
              -terms=2 -generate \
              -col=${quad}:Setpoint,VTune \
              | sddsprocess -pipe=in $VIFileName \
              "-print=param,QuadNameString,${quad}"
        }
        peak {
            exec sddssmooth -pipe=out $VFileName  \
              -col=Waveform -pass=0 \
              -despike=neighbors=5,average=5,passes=5 \
              | sddsprocess -pipe \
              -process=Waveform,maximum,VFreq,position,functionOf=Frequency \
              "-define=param,VTune,${rfFrequency} 1296 / sto revf VFreq revf / int 1 + revf * VFreq - revf /" \
              | sddsxref -pipe $VFileName \
              -transfer=parameter,s,${quad}:Setpoint,SRCurrent,SRlifeTime,Description,Contents,QuadVaried,CurrentString,FileName \
              "-leave=*" \
              | sddscollapse -pipe \
              | sddssort -pipe -col=${quad}:Setpoint,increasing \
              | sddspfit -pipe \
              -terms=2 -generate \
              -col=${quad}:Setpoint,VTune \
              | sddsprocess -pipe=in $VIFileName \
              -print=par,Method,Peak  "-print=param,QuadNameString,${quad}"
        }
    }
    update

    exec sddsinterp -pipe=out ${excitationFile} \
      -columns=I,BnL \
      -aboveRange=extrapolate \
      -fileValues=$VIFileName,col=${quad}:Setpoint \
      | sddsconvert -pipe -rename=col,I=${quad}:Setpoint \
      | sddsxref -pipe $VIFileName -take=VTune \
      | sddspfit -pipe -terms=2 -generate \
      -col=BnL,VTune \
      | sddsprocess -pipe=in $VBnLFileName \
      "-define=param,BetaY,4.0 pi * Slope * $rigidity * abs,units=m" \
      "-define=param,BetaYSigma,4.0 pi * SlopeSigma * $rigidity * ,units=m" \
      "-print=param,BetaYString,\$gb\$r\$by\$n = %.2f \$sa\$e %.2f %s,BetaY,BetaYSigma,BetaY.units" \
      "-print=param,QuadNameString,${quad}" \
      -process=VTune,first,InitialVTune

    catch {exec sddsxref $VBnLFileName $VFileName \
             -transfer=param,revBiasDifferenceCurrent,RestoredVTune \
             "-leave=*"}

    catch {sddsxref $VFileName $VBnLFileName \
             -transfer=parameter,InitialVTune}

    catch {exec sddsxref $VFileName ${root}_aps.twi \
             "-leave=*" \
             -transfer=parameter,s,Psiy}
    catch {exec sddsxref $VBnLFileName ${root}_aps.twi \
             "-leave=*" \
             -transfer=parameter,s,Psiy}
    catch {exec sddsxref $VIFileName ${root}_aps.twi \
             "-leave=*" \
             -transfer=parameter,s,Psiy}
    
    if {$statusCallback!=""} {
        $statusCallback "Done."
    }

    catch {eval file delete [glob *~]}
    catch {eval file delete ${root}_aps.twi}
    update
    return 1
}

# Procedure measures and sets the initial tune values.  Returns 1 when completed.

proc MeasureInitialTunes {args} {
    global mainDir HTuneFreq VTuneFreq HTune VTune hpvsaSelection
    
    APSParseArguments {statusCallback}
    
    if {$statusCallback!=""} {
        $statusCallback "Measuring and setting the horizontal tune..."
    }

    SetHPVSAHVRange -plane Horizontal -index 0
    
    set HTuneFreq [DetermineTuneFromWaveform]
    set HTune [ComputeTuneFromFrequency -tuneFreq ${HTuneFreq}]

    if {$statusCallback!=""} {
        $statusCallback "Measuring and setting the vertical tune..."
    }

    SetHPVSAHVRange -plane Vertical -index 0
    update

    set VTuneFreq [DetermineTuneFromWaveform]
    set VTune [ComputeTuneFromFrequency -tuneFreq ${VTuneFreq}]

    if {$statusCallback!=""} {
        $statusCallback "Finished setting the tunes."
    }
    return 1
}

# Returns a sorted list of data sets and descriptions in the current
# mainDir.

proc FindDataSetsAndDescriptions {} {
    global mainDir env

    if {![file exists $mainDir/descriptions.sdds]} {
        set dirOld [pwd]
        cd $mainDir
        # create file of data sets and descriptions
        set fid [open descriptions.sdds w]
        puts $fid "SDDS1"
        puts $fid "&column name=DataSet type=string &end"
        puts $fid "&column name=Description type=string &end"
        puts $fid "&data mode=ascii no_row_counts=1 &end"
        set subDirList [lsort -decreasing [glob -nocomplain ????-*-????/??????]]
        foreach subDir $subDirList {
            cd $mainDir/$subDir
            set sampleFile [lindex [glob -nocomplain *_HTuneData.sdds] 0]
            if ![llength $sampleFile] {
                continue
            }
            set description [exec sdds2stream -page=1 -para=Description $sampleFile]
            regexp {^"(.*)"$} $description {} description
            puts $fid "$subDir \"$subDir -> $description\""
        }
        close $fid
#        if [regexp {Linux} $env(HOST_ARCH)] {
#            catch {exec setfacl -M $mainDir/betaFiles.acl $mainDir/descriptions.sdds}
#        } else {
#            catch {exec setfacl -f $mainDir/betaFiles.acl $mainDir/descriptions.sdds}
#        }
        cd $dirOld
    }
    sdds load $mainDir/descriptions.sdds descriptions
    set dataSetList [lindex $descriptions(Column.DataSet) 0]
    set descriptionList [lindex $descriptions(Column.Description) 0]
    return [list $dataSetList $descriptionList]
}

# Plots beta function data for a given data set defined by a
# dataSet.  Returns 1 when completed.  Returns 0 if no dataSet is
# selected and prints a status message.

proc PlotSelectedData {args} {
    global mainDir Lattice OAGGlobal

    APSParseArguments {statusCallback}
    
    set latticeDir $OAGGlobal(SRLatticesDirectory)
    set dataSetList ""
    set selectionList [FindDataSetsAndDescriptions]
    set completeDataSetList [lindex $selectionList 0]
    set completeDescriptionList [lindex $selectionList 1]
    set dataSetList [APSChooseItemFromList \
                     -name "Data Set Selection" \
                     -itemList $completeDescriptionList \
                     -returnList $completeDataSetList \
                     -returnIndices 0 \
                     -multiItem 1 \
                     -contextHelp "Select a beta function measurement data set for plotting."]

    if ![string length $dataSetList] {
        if {$statusCallback!=""} {
            $statusCallback "Please select a beta function data data set for plotting."
        }
        return 0
    }

    set HFileList ""
    set VFileList ""
    foreach dataSet $dataSetList {
        set root ${mainDir}/${dataSet}
        eval lappend HFileList [glob -nocomplain ${root}/S*_HTuneData_BnLFit.sdds]
        eval lappend VFileList [glob -nocomplain ${root}/S*_VTuneData_BnLFit.sdds]
    }

    set tmpPlot_HTuneData_BnLFit /tmp/[APSTmpString].Plot_HTuneData_BnLFit
    set tmpPlot_VTuneData_BnLFit /tmp/[APSTmpString].Plot_VTuneData_BnLFit
    set tmpPlot_Xref /tmp/[APSTmpString].Plot_Xref
    set tmpTwiss /tmp/[APSTmpString].Twiss
    set tmpPlot_HTuneData_Diff /tmp/[APSTmpString].Plot_HTuneData_Diff
    set tmpPlot_VTuneData_Diff /tmp/[APSTmpString].Plot_VTuneData_Diff

    eval exec sddscombine ${HFileList} -pipe=out -overWrite -collapse \
      | sddssort -pipe=in $tmpPlot_HTuneData_BnLFit \
      -col=s,increasing \
      -nowarnings

    set firstQuad [exec sddsprocess $tmpPlot_HTuneData_BnLFit -pipe=out \
                     -process=QuadNameString,first,StartQuad \
                     | sdds2stream -pipe=in -param=StartQuad]

    set lastQuad [exec sddsprocess $tmpPlot_HTuneData_BnLFit -pipe=out \
                    -process=QuadNameString,last,LastQuad \
                    | sdds2stream -pipe=in -param=LastQuad]

    set firstQuads [expr [exec sddsprocess $latticeDir/$Lattice/aps.twiAve -pipe=out \
                            -match=col,ElementName=${firstQuad} \
                            | sdds2stream -pipe=in -col=sAverage] - 1.5]
    
    set lastQuads [expr [exec sddsprocess $latticeDir/$Lattice/aps.twiAve -pipe=out \
                           -match=col,ElementName=${lastQuad} \
                           | sdds2stream -pipe=in -col=sAverage] + 1.5]

    # file $tmpTiss is used to plot the model twiss function as a
    # background to the data

    eval exec sddsprocess $latticeDir/$Lattice/aps.twiAve ${tmpTwiss}.1 \
      -filter=col,sAverage,[expr ${firstQuads} - 3.0],[expr ${lastQuads} + 3]
    eval exec sddsprocess $latticeDir/$Lattice/aps.twiAve -pipe=out \
      -filter=col,sAverage,[expr ${firstQuads} - 3.0],[expr ${lastQuads} + 3] \
      | sddsconvert -pipe -delete=col,s,betax,betay \
      | sddsconvert -pipe=in ${tmpTwiss}.2 \
      -rename=col,sAverage=s,betaxAverage=betax,betayAverage=betay
    exec sddscombine ${tmpTwiss}.1 ${tmpTwiss}.2 -pipe=out -merge \
      | sddssort -pipe=in ${tmpTwiss} -col=s
    
    exec sddsselect $latticeDir/$Lattice/aps.twiAve $tmpPlot_HTuneData_BnLFit \
      $tmpPlot_Xref \
      -match=ElementName=QuadNameString

    exec sddsxref $tmpPlot_HTuneData_BnLFit $tmpPlot_Xref -pipe=out \
      -take=betax,betaxAverage \
      | sddsprocess -pipe=in $tmpPlot_HTuneData_Diff           \
      "-define=col,BetaXDifference,BetaX betaxAverage -,units=m,symbol=\$gDb\$r\$bx\$n" \
      "-define=col,BetaXDifferenceSigma,BetaXSigma,units=m" \
      "-define=col,RelBetaXDifference,BetaX betaxAverage - betaxAverage /,symbol=\$gDb\$r\$bx\$a\$n/\$gb\$r\$bx\$n" \
      "-define=col,RelBetaXDifferenceSigma,BetaXSigma betaxAverage /"

    eval exec sddscombine ${VFileList} -pipe=out -overWrite -collapse \
      | sddssort -pipe=in $tmpPlot_VTuneData_BnLFit \
      -col=s,increasing \
      -nowarnings

    exec sddsxref -pipe=out $tmpPlot_VTuneData_BnLFit $tmpPlot_Xref \
      -take=betay,betayAverage \
      | sddsprocess -pipe=in $tmpPlot_VTuneData_Diff           \
      "-define=col,BetaYDifference,BetaY betayAverage -,units=m,symbol=\$gDb\$r\$by\$n" \
      "-define=col,BetaYDifferenceSigma,BetaYSigma,units=m"    \
      "-define=col,RelBetaYDifference,BetaY betayAverage - betayAverage /,symbol=\$gDb\$r\$by\$a\$n/\$gb\$r\$by\$n" \
      "-define=col,RelBetaYDifferenceSigma,BetaYSigma betayAverage /"

    if {$statusCallback!=""} {
        $statusCallback "Plotting beta functions for data in ${dataSet}..."
    }

    catch {exec sddsplot -labelsize=0.03 -title= \
             -col=s,BetaX -graph=symbol,scale=2,subtype=1 "-legend=specified=Horiz Data" \
             $tmpPlot_HTuneData_BnLFit \
             -col=s,BetaX,BetaXSigma -graph=errorbar,subtype=1 \
             $tmpPlot_HTuneData_BnLFit \
             -col=s,betax -graph=line,type=1 \
             $tmpTwiss "-legend=specified=Horiz Design" \
             -col=s,BetaY -graph=symbol,scale=2,subtype=2 "-legend=specified=Vert Data" \
             $tmpPlot_VTuneData_BnLFit \
             -col=s,BetaY,BetaYSigma -graph=errorbar,subtype=2 \
             $tmpPlot_VTuneData_BnLFit \
             -col=s,betay -graph=line,type=2 \
             $tmpTwiss "-legend=specified=Vert Design" \
             "-topline=Horizontal and Vertical Measured and Design Beta Functions vs Distance" -end \
             \
             -col=QuadNameString,BetaX -graph=symbol,scale=2,subtype=1 "-legend=specified=Horiz Data" \
             $tmpPlot_HTuneData_BnLFit \
             -col=QuadNameString,BetaX,BetaXSigma -graph=errorbar,subtype=1 \
             $tmpPlot_HTuneData_BnLFit \
             -col=QuadNameString,betaxAverage -graph=line,type=1 \
             $tmpPlot_HTuneData_Diff "-legend=specified=Horiz Design" \
             -col=QuadNameString,BetaY -graph=symbol,scale=2,subtype=2 "-legend=specified=Vert Data" \
             $tmpPlot_VTuneData_BnLFit \
             -col=QuadNameString,BetaY,BetaYSigma -graph=errorbar,subtype=2 \
             $tmpPlot_VTuneData_BnLFit \
             -col=QuadNameString,betayAverage -graph=line,type=2 \
             $tmpPlot_VTuneData_Diff "-legend=specified=Vert Design" \
             "-topline=Horizontal and Vertical Measured and Design Beta Functions vs Quadrupole Name" \&}
    
    catch {exec sddsplot -labelsize=0.03 -title= \
             -col=s,BetaXDifference -graph=symbol,scale=2,subtype=1 "-legend=specified=Horizontal" \
             $tmpPlot_HTuneData_Diff \
             -col=s,BetaXDifference,BetaXDifferenceSigma -graph=errorbar,subtype=1 \
             $tmpPlot_HTuneData_Diff \
             -col=s,BetaXDifference -graph=line,type=1 \
             $tmpPlot_HTuneData_Diff \
             -col=s,BetaYDifference -graph=symbol,scale=2,subtype=2 "-legend=specified=Vertical" \
             $tmpPlot_VTuneData_Diff \
             -col=s,BetaYDifference,BetaYDifferenceSigma -graph=errorbar,subtype=2 \
             $tmpPlot_VTuneData_Diff \
             -col=s,BetaYDifference -graph=line,type=2 \
             $tmpPlot_VTuneData_Diff \
             "-topline=Difference Between Measured and Design Beta Functions vs Distance" -end \
             -col=QuadNameString,BetaXDifference -graph=symbol,scale=2,subtype=1 "-legend=specified=Horizontal" \
             $tmpPlot_HTuneData_Diff \
             -col=QuadNameString,BetaXDifference,BetaXDifferenceSigma -graph=errorbar,subtype=1 \
             $tmpPlot_HTuneData_Diff \
             -col=QuadNameString,BetaXDifference -graph=line,type=1 \
             $tmpPlot_HTuneData_Diff \
             -col=QuadNameString,BetaYDifference -graph=symbol,scale=2,subtype=2 "-legend=specified=Vertical" \
             $tmpPlot_VTuneData_Diff \
             -col=QuadNameString,BetaYDifference,BetaYDifferenceSigma -graph=errorbar,subtype=2 \
             $tmpPlot_VTuneData_Diff \
             -col=QuadNameString,BetaYDifference -graph=line,type=2 \
             $tmpPlot_VTuneData_Diff \
             "-topline=Difference Between Measured and Design Beta Functions vs Quadrupole Name" \&}

    catch {exec sddsplot -labelsize=0.03 -title= \
             -col=Psix,RelBetaXDifference -graph=symbol,scale=2,subtype=1 "-legend=specified=Horizontal" \
             $tmpPlot_HTuneData_Diff \
             -col=Psix,RelBetaXDifference,RelBetaXDifferenceSigma -graph=errorbar,subtype=1 \
             $tmpPlot_HTuneData_Diff \
             -col=Psix,RelBetaXDifference -graph=line,type=2 \
             $tmpPlot_HTuneData_Diff \
             "-topline=Relative Difference Between Measured and Design Horizontal Beta Functions vs Phase Advance" -end \
             -col=Psiy,RelBetaYDifference -graph=symbol,scale=2,subtype=1 "-legend=specified=Vertical" \
             $tmpPlot_VTuneData_Diff \
             -col=Psiy,RelBetaYDifference,RelBetaYDifferenceSigma -graph=errorbar,subtype=1 \
             $tmpPlot_VTuneData_Diff \
             -col=Psiy,RelBetaYDifference -graph=line,type=2 \
             $tmpPlot_VTuneData_Diff \
             "-topline=Relative Difference Between Measured and Design Vertical Beta Functions vs Phase Advance" \&}

    catch {exec sddsplot -labelsize=0.03 -title= \
             -col=QuadNameString,revBiasDifferenceCurrent \
             -graph=sym,sca=2,conn=sub,subtype=1 "-legend=specified=Rev Current" \
             $tmpPlot_HTuneData_BnLFit \
             "-topline=Reverse Bias Current From the Nominal 7 GeV Value vs QuadName" \
             -end \
             -col=QuadNameString,InitialHTune -graph=sym,sca=2,conn=sub,subtype=1 \
             $tmpPlot_HTuneData_BnLFit -legend=specified=IniHTune \
             -col=QuadNameString,RestoredHTune -graph=sym,sca=2,conn=sub,subtype=2 \
             $tmpPlot_HTuneData_BnLFit -legend=specified=RestHTune \
             "-topline=Initial and Restored Horizontal Tune vs QuadName" -end \
             -col=QuadNameString,InitialVTune -graph=sym,sca=2,conn=sub,subtype=1 \
             $tmpPlot_VTuneData_BnLFit -legend=specified=IniVTune \
             -col=QuadNameString,RestoredVTune -graph=sym,sca=2,conn=sub,subtype=2\
             $tmpPlot_VTuneData_BnLFit -legend=specified=RestVTune \
             "-topline=Initial and Restored Vertical Tune vs QuadName" \&}
    
    if {$statusCallback!=""} {
        $statusCallback "Done."
    }
    return 1
}

# Procedure plots raw and fitted data for nominal and restored data.
# Returns 1 when complete.  Returns 0 if no file is selected.

proc PlotRawAndFittedData {args} {
    global mainDir
    
    APSParseArguments {statusCallback}
    
    set dataSetList ""
    set selectionList [FindDataSetsAndDescriptions]
    set completeDataSetList [lindex $selectionList 0]
    set completeDescriptionList [lindex $selectionList 1]
    set dataSetList [APSChooseItemFromList \
                       -name "Data Set Selection" \
                       -itemList $completeDescriptionList \
                       -returnList $completeDataSetList \
                       -returnIndices 0 \
                       -multiItem 0 \
                       -contextHelp "Select a beta function measurement data set for raw data plotting."]
    set dataSet [lindex $dataSetList 0]
    if {[llength $dataSetList] > 1} {
        if {$statusCallback!=""} {
            $statusCallback "First data set $dataSet is selected by default."
        }
    }
    set fileList [glob -nocomplain ${mainDir}/${dataSet}/S*_HTuneData.sdds]
    set itemList ""
    foreach file $fileList {
        regexp {S[1-9][0-9]?[AB]:Q.} $file item
        lappend itemList $item
    }
    set rawDataFile [APSChooseItemFromList \
                       -name "Raw Data Selection" \
                       -itemList $itemList \
                       -returnList $fileList \
                       -returnIndices 0 \
                       -multiItem 0 \
                       -contextHelp "Select a quadrupole beta function measurement for raw data plotting."]

    if ![string length $rawDataFile] {
        if {$statusCallback!=""} {
            $statusCallback "Please select a valid data file to plot."
        }
        return 0
    }
    regexp {S[1-9][0-9]?[AB]:Q.} $rawDataFile quad

    if {$statusCallback!=""} {
        $statusCallback "Plotting raw and fitted beta function data for ${quad}..."
    }
    
    PlotRawData -dataSet $dataSet -quad $quad -statusCallback SetStatus
    PlotFittedData -dataSet $dataSet -quad $quad -statusCallback SetStatus
    if {$statusCallback!=""} {
        $statusCallback "Done."
    }
    return 1
}

set rfFrequency [exec cavget -list=A014-IETS:BTC:SRSetFreqM -floatFormat=%.1f -pendIoTime=5]
set harmonic 1296
set revFrequency [expr $rfFrequency / $harmonic]
set measHarmonic 1315
set sideband -1

set expectedXtune 0.12
set HTune $expectedXtune
set HTuneFreq [format %.0f [ComputeFrequencyFromTune -tune $HTune]]
set HRange -25

set processMethod center-of-mass

set expectedYtune 0.20
set VTune $expectedYtune
set VTuneFreq [format %.0f [ComputeFrequencyFromTune -tune $VTune]]
set VRange -25

set NumOfPoints 5
set quadRange 10

set aveLevel1 10
set aveLevel2 50

set Lattice [file readlink $OAGGlobal(SRLatticesDirectory)/default]
set hpvsaSelection hpvecsr

MakeBetaMeasurementStatusWidget .userFrame .
MakeLabelledEntryWidgets .labelledEntries -parent .userFrame
MakeButtonActionWidgets .buttons -parent .userFrame
set skipLoadingState 1
set maxIterations 1

