#!/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.9 $ \$Author: shang $"

APSApplication . -name SRbetaCorrection -version 1 \
    -overview {This application allows correction of the vertical beta function at quadrupoles using a selection of quadrupoles as correctors.}

set betaCorrConfigStatus ""
APSScrolledStatus .status -parent .userFrame \
  -textVariable betaCorrConfigStatus  \
  -width 90

#quad readback list and quad corrector list
set readList {A:Q1 A:Q2 A:Q3 A:Q4 A:Q5 B:Q5 B:Q4 B:Q3 B:Q2 B:Q1}
set corrList {A:Q1 A:Q2 A:Q3 A:Q4 A:Q5 B:Q5 B:Q4 B:Q3 B:Q2 B:Q1}


set baseDir /home/helios/oagData/sr/latticeFunctionCorrection/beta
set configBaseDir $baseDir/lattices/default
set refMatrixDir $baseDir/lattices/default
set refMatrixFileX default.betax
set refMatrixFileY default.betay
set plane xy
set removeDC 1

proc GenerateCorrectionDir {} {
    global corrMatrixDir baseDir
    set configurationBaseDir $baseDir/lattices/default
    set corrMatrixDir [APSNextGenerationedName -directory $configurationBaseDir \
                         -name [clock format [clock seconds] -format %Y-%m%d].00 -newFile 1 -separator .]
    if [file exists $configurationBaseDir/$corrMatrixDir] {
        APSSetVarAndUpdate betaCorrConfigStatus "Configuration $corrMatrixDir already exists."
    } else {
        if [catch {file mkdir $configurationBaseDir/$corrMatrixDir} result] {
            return -code error "GenerateCorrectionDir: $result"
        }
    }
    return -code ok
}

proc GenerateCorrectionMatrix {args} {
    global readList corrList baseDir
    set configFile ""
    set outputRoot ""
    set referenceBetaxMatrix ""
    set referenceBetayMatrix ""
    set plane ""
    set removeVectors 0
    set generate 0
    set install 0
    set rootname ""
    set singularValues 320
    set removeVectors 0
    APSStrictParseArguments {configFile outputRoot \
                               referenceBetaxMatrix referenceBetayMatrix \
                               generate plane \
                               install rootname singularValues removeVectors}
    if ![file exists $outputRoot] {
        if [catch {file mkdir $outputRoot } result] {
            return -code error "GenerateCorrectionMatrix: $result"
        }
    }
    if ![string length $outputRoot] {
        return -code error "GenerateCorrectionMatrix: supply an output rootname."
    }
    if ![string length $plane] {
        return -code error "GenerateCorrectionMatrix: supply a plane value."
    }
    switch -exact $plane {
        x {
            set origRefBetaxMatrix $referenceBetaxMatrix
            set origRefMatrix $referenceBetaxMatrix
        }
        y {
            set origRefBetayMatrix $referenceBetayMatrix
            set origRefMatrix $referenceBetayMatrix
        }
        xy {
            set origRefBetaxMatrix $referenceBetaxMatrix
            set origRefBetayMatrix $referenceBetayMatrix
        }
    }
    # create two quad config files, one for monitor and one for corrector.
    set monConfigFile $outputRoot/config.monitor
    set corrConfigFile $outputRoot/config.corrector
    file delete -force -- $monConfigFile $corrConfigFile
    APSSetVarAndUpdate betaCorrConfigStatus "Creating file $monConfigFile and $corrConfigFile..."
    APSWriteSRConfig -rootname betaRead -filename $monConfigFile \
      -nameTypeList {Monitor} -interactive 0 \
      -suffixLists [list $readList] \
      -description "beta correction"
    APSWriteSRConfig -rootname betaCorr -filename $corrConfigFile \
      -nameTypeList {Corrector} -interactive 0 \
      -suffixLists [list $corrList] \
      -description "beta correction"

    if [catch {exec sddsprocess $corrConfigFile -pipe=out \
                 -match=parameter,NameType=CorrectorNames \
                 -filter=column,Flag,1,1 \
                 | sddscombine -merge -pipe \
                 | sdds2stream -pipe -column=Name} correctorNames] {
        return -code error "GenerateCorrectionMatrix(1): $correctorNames"
    }
    file delete -force -- $outputRoot/monitors
    if [catch {exec sddsprocess $monConfigFile -pipe=out \
                 -match=parameter,NameType=MonitorNames \
                 -filter=column,Flag,1,1 \
                 | sddscombine -pipe -merge \
                 | tee $outputRoot/monitors \
                 | sdds2stream -pipe -column=Name} monitorNames] {
        return -code error "APSSRGenerateOrbCorrFiles(2): $monitorNames"
    }
    set monitorNameMatchOption ""
    foreach item $monitorNames {
        if [string length $monitorNameMatchOption] {
            set monitorNameMatchOption "$monitorNameMatchOption,ElementName=$item,|"
        } else {
            set monitorNameMatchOption "-match=column,ElementName=$item"
        }
    }
    if $removeVectors {
        set inverseOptions "-largestSingularValues=$singularValues -removeDCVectors"
    } else {
        set inverseOptions "-largestSingularValues=$singularValues"
    }
    if [lsearch -exact [APSGetSDDSNames -fileName $outputRoot/monitors -class column] Weight]!=-1 {
        # can't use weight when both planes are requested (for now).
        if ![string match $plane xy] {
            lappend inverseOptions "-weights=$outputRoot/monitors,name=Name,value=Weight"
        }
    }
    # these are calibration factor not taken into account in the referenceMatrix
    if ![file exists $outputRoot/quad.calib] {
        # it would be better to find the slope of the excitation curve.
        # calibration is    <PS current>/<elegant K1>
        set calib(Q1) [expr 241 / -0.514]
        set calib(Q2) [expr 330 / 0.715]
        set calib(Q3) [expr 261 / -0.586]
        set calib(Q4) [expr 390 / -0.811]
        set calib(Q5) [expr 369 / 0.785]
        if [catch {open $outputRoot/quad.calib w} fid] {
            return -code error "APSSRGenerateOrbCorrFiles(3): $fid"
        }
        puts $fid "SDDS1"
        puts $fid "&column name=QuadType type=string &end"
        puts $fid "&column name=Calibration type=double &end"
        puts $fid "&data mode=ascii no_row_counts=1 &end"
        foreach type [lsort [array names calib]] {
            puts $fid "$type $calib($type)"
        }
        close $fid
    }
    # decide whether to do one plane or both
    switch -exact $plane {
        x {
            set referenceMatrix $referenceBetaxMatrix
        }
        y {
            set referenceMatrix $referenceBetayMatrix
        }
        xy {
        # do nothing here. most of the work to be done next.
        }
    }
    # irmElegant is the set of delta K1's to modifiy elegant elements
    file delete -force -- $outputRoot/irm $outputRoot/irmElegant
    if [string match $plane xy] {
        set tmpfile /tmp/[APSTmpString]
        set referenceMatrix $tmpfile.matrix
        if [catch {eval exec sddsconvert $referenceBetaxMatrix -pipe=out \
                     -retain=column,ElementName,[join $correctorNames ,] \
                     | sddsprocess -pipe=in $tmpfile.rm.x \
                     -print=col,QuadAndPlane,%sx,ElementName \
                     $monitorNameMatchOption \
                 } result] {
            return -code error "APSSRGenerateOrbCorrFiles(4): $result"
        }
        if [catch {eval exec sddsconvert $referenceBetayMatrix -pipe=out \
                     -retain=column,ElementName,[join $correctorNames ,] \
                     | sddsprocess -pipe=in $tmpfile.rm.y \
                     -print=col,QuadAndPlane,%sy,ElementName \
                     $monitorNameMatchOption \
                 } result] {
            return -code error "APSSRGenerateOrbCorrFiles(5): $result"
        }
        if [catch {exec sddscombine $tmpfile.rm.x $tmpfile.rm.y \
                     $referenceMatrix -merge  \
                 } result] {
            return -code error "APSSRGenerateOrbCorrFiles(6): $result"
        }
        if [catch {eval exec sddspseudoinverse $referenceMatrix -pipe=out \
                     $inverseOptions \
                     -newColumnNames=QuadAndPlane \
                     | sddsconvert -pipe -rename=column,OldColumnNames=Quadrupoles \
                     | tee $outputRoot/irmElegant \
                     | sddsprocess -pipe \
                     -edit=col,QuadType,Quadrupoles,Z: \
                     | sddsxref -pipe $outputRoot/quad.calib \
                     -take=Calibration -match=QuadType -reuse \
                     | sddsprocess -pipe \
                     \"-redefine=col,%s,%s Calibration *,select=S*,units=m/A,description=deltaK per unit relative beta error\" \
                     | sddsconvert -pipe \
                     -delete=col,QuadType,Calibration \
                     | sddsprocess -pipe=in $outputRoot/irm \
                     -print=para,Plane,$plane \
                     -print=parameter,MonitorConfigurationFile,$monConfigFile \
                     -print=parameter,CorrectorConfigurationFile,$corrConfigFile \
                     -print=parameter,ReferenceBetaxMatrix,$origRefBetaxMatrix \
                     -print=parameter,ReferenceBetayMatrix,$origRefBetayMatrix \
                 } result] {
            return -code error "APSSRGenerateOrbCorrFiles(7): $result"
        }
    } else {
        if [catch {eval exec sddsconvert $referenceMatrix -pipe=out \
                     -retain=column,ElementName,[join $correctorNames ,] \
                     | sddsprocess -pipe $monitorNameMatchOption \
                     | sddspseudoinverse -pipe $inverseOptions \
                     | sddsconvert -pipe -rename=column,OldColumnNames=Quadrupoles \
                     | tee $outputRoot/irmElegant \
                     | sddsprocess -pipe \
                     -edit=col,QuadType,Quadrupoles,Z: \
                     | sddsxref -pipe $outputRoot/quad.calib \
                     -take=Calibration -match=QuadType -reuse \
                     | sddsprocess -pipe \
                     \"-redefine=col,%s,%s Calibration *,select=S*,units=m/A,description=deltaK per unit relative beta error\" \
                     | sddsconvert -pipe \
                     -delete=col,QuadType,Calibration \
                     | sddsprocess -pipe=in $outputRoot/irm \
                     -print=para,Plane,$plane \
                     -print=parameter,MonitorConfigurationFile,$monConfigFile \
                     -print=parameter,CorrectorConfigurationFile,$corrConfigFile \
                     -print=parameter,ReferenceMatrix,$origRefMatrix} result] {
            return -code error "APSSRGenerateOrbCorrFiles(8): $result"
        }
    }
    if [catch {exec sdds2stream -param=ConditionNumber $outputRoot/irm} condNumber] {
        return -code error "APSSRGenerateOrbCorrFiles: error getting condition number"
    }
    APSSetVarAndUpdate betaCorrConfigStatus "Done.  Condition number is $condNumber ."
    update
}

# corrects beta in SR by creating a file to apply to SR.
# also creates a file to apply to elegant lattice.
proc CorrectBeta {args} {
    set measFile ""
    set betaReferenceFile ""
    set corrMatrixDir ""
    set gain ""
    set removeDC 0
    set burtOutputDir ""
    set burtOutputFile ""
    APSParseArguments {measFile betaReferenceFile removeDC \
                         corrMatrixDir gain burtOutputDir burtOutputFile}
    if {![string length $measFile] || \
          ![string length $betaReferenceFile] || \
          ![string length $corrMatrixDir] || \
          ![string length $gain] || ![string length $burtOutputDir] || \
          ![string length $burtOutputFile] } {
        return -code error "CorrectBeta: Not all argument specified."
    }
    if ![file exists $corrMatrixDir] {
        return -code error "CorrectBeta: Can't find directory $corrMatrixDir"
    }
    if ![file exists $measFile] {
        return -code error "CorrectBeta: Can't find file $measFile"
    }
    if ![file exists $burtOutputDir] {
        return -code error "CorrectBeta: Can't find directory $burtOutputDir"
    }
    if ![file exists $betaReferenceFile] {
        return -code error "CorrectBeta: Can't find file $betaReferenceFile."
    }
# determine whether one plane or two.
    set plane [exec sdds2stream -para=Plane $corrMatrixDir/irm]
    set tmpRoot /tmp/[APSTmpString]
    set betaRelDiff $tmpRoot.betaRelDiff
# filter beta measurement to match correction matrix columns.
    switch -exact $plane {
        x -
        y {
            set Plane [string toupper $plane]
            if [catch {exec sddsxref $measFile \
                         $betaReferenceFile -pipe=out \
                         -take=betax,betay -match=QuadNameString=ElementName \
                         | sddsprocess -pipe \
                         "-def=col,betaRelDiff,Beta$Plane beta$plane - beta$plane /,units=m" \
                         | sddsselect -pipe $corrMatrixDir/monitors -match=QuadNameString=Name \
                         | sddsconvert -pipe=in $betaRelDiff \
                         -retain=col,QuadNameString,betaRelDiff \
                     } result] {
                return -code error "CorrectBeta(1a): $result"
            }
        }
        xy {
            # make file with x data first and then y data in same column
            if [catch {exec sddsxref $measFile \
                         $betaReferenceFile -pipe=out \
                         -take=betax,betay -match=QuadNameString=ElementName \
                         | sddsprocess -pipe \
                         "-def=col,betaRelDiff,BetaX betax - betax /,units=m" \
                         | sddsselect -pipe $corrMatrixDir/monitors -match=QuadNameString=Name \
                         | sddsconvert -pipe=in $tmpRoot.xdiff \
                         -retain=col,QuadNameString,betaRelDiff \
                     } result] {
                return -code error "CorrectBeta(1b): $result"
            }
            if [catch {exec sddsxref $measFile \
                         $betaReferenceFile -pipe=out \
                         -take=betax,betay -match=QuadNameString=ElementName \
                         | sddsprocess -pipe \
                         "-def=col,betaRelDiff,BetaY betay - betay /,units=m" \
                         | sddsselect -pipe $corrMatrixDir/monitors -match=QuadNameString=Name \
                         | sddsconvert -pipe=in $tmpRoot.ydiff \
                         -retain=col,QuadNameString,betaRelDiff \
                     } result] {
                return -code error "CorrectBeta(1c): $result"
            }
            if [catch {exec sddscombine $tmpRoot.xdiff $tmpRoot.ydiff \
                         $betaRelDiff -merge \
                        } result] {
                return -code error "CorrectBeta(1d): $result"
            }  
        }
        default {
            return -code error "CorrectBeta: Plane in file $corrMatrixDir/irm not recognized." 
        }
    }

# file to apply to SR
    if [catch {exec sddsmatrixmult $corrMatrixDir/irm $betaRelDiff -pipe=out \
                 | sddsxref -pipe $corrMatrixDir/irm \
                 -take=Quadrupoles \
                 | sddsprocess -pipe=in $tmpRoot.SRvalues \
                 "-def=col,quadDelta,betaRelDiff chs $gain *,units=A" \
             } result] {
        return -code error "CorrectBeta(2a): $result"
    }
    if $removeDC {
        foreach type {Q1 Q2 Q3 Q4 Q5} {
            if [catch {exec sddsprocess $tmpRoot.SRvalues $tmpRoot.SRvalues.$type \
                         -match=col,Quadrupoles=*${type} -noWarning \
                         -proc=quadDelta,average,quadDeltaAverage \
                         "-redef=col,quadDelta,quadDelta quadDeltaAverage -,units=A" \
                     } result] {
                return -code error "CorrectBeta(2b$type): $result"
            }
            lappend valuesList $tmpRoot.SRvalues.$type
        }
        if [catch {eval exec sddscombine $valuesList $tmpRoot.SRvalues -overWrite  \
                     -merge
                 } result] {
            return -code error "CorrectBeta(2c): $result"
        }
    }
    if [catch {exec sddsprocess $tmpRoot.SRvalues $burtOutputDir/$burtOutputFile \
                 -print=col,ControlName,%s:CurrentAO,Quadrupoles \
                 -print=col,ValueString,%lf,quadDelta \
                 -print=col,ControlType,pv \
                 -print=col,Lineage,- \
                 -define=col,Count,1,type=long \
                 -print=para,SnapType,Relative \
             } result] {
        return -code error "CorrectBeta(2c): $result"
    }
# file to apply to elegant
    if [catch {exec sddsmatrixmult $corrMatrixDir/irmElegant $betaRelDiff -pipe=out \
                 | sddsxref -pipe $corrMatrixDir/irmElegant \
                 -take=Quadrupoles \
                 | sddsprocess -pipe \
                 "-def=col,quadDelta,betaRelDiff $gain *" \
                 -print=col,ElementName,%s,Quadrupoles \
                 -def=col,deltaK1,quadDelta,units=m\$a-2\$n \
                 | sddsconvert -pipe=in $burtOutputDir/$burtOutputFile.deltaK1 \
                 -retain=col,ElementName,deltaK1 \
             } result] {
        return -code error "CorrectBeta(3a): $result"
    }
    if $removeDC {
        set valuesList ""
        foreach type {Q1 Q2 Q3 Q4 Q5} {
            if [catch {exec sddsprocess $burtOutputDir/$burtOutputFile.deltaK1 \
                         $tmpRoot.deltaK1.$type \
                         -match=col,ElementName=*${type} -noWarning \
                         -proc=deltaK1,average,%sAverage \
                         "-redef=col,deltaK1,deltaK1 deltaK1Average -,units=A" \
                     } result] {
                return -code error "CorrectBeta(3b$type): $result"
            }
            lappend valuesList $tmpRoot.SRvalues.$type
        }
        if [catch {eval exec sddscombine $valuesList $burtOutputDir/$burtOutputFile.deltaK1 \
                     -merge -overWrite  \
                 } result] {
            return -code error "CorrectBeta(3c): $result"
        }
    }
    
    if [catch {exec sddsplot -layout=1,2 -sep -axes=x \
                 -col=QuadNameString,betaRelDiff $betaRelDiff \
                 -grap=sym,conn,sca=0.5 \
                 -col=Quadrupoles,quadDelta -grap=sym,conn \
                 $burtOutputDir/$burtOutputFile & \
             } result] {
        return -code error "CorrectBeta(4): $result"
    }
    APSSetVarAndUpdate betaCorrConfigStatus "Done."
}

proc ApplyCorrection {args} {
    APSParseArguments {burtFile}
    if ![file exists $burtFile] {
        return -code error "Can't find file $burtFile"
    }
    if [catch {APSShutterPermitGiven} permit] {
        return -code error "APSSRChangeBeamSwitchState: $result"
    }   
    if $permit {
        APSSetVarAndUpdate betaCorrConfigStatus "Can't apply correction with shutters open."
        return 
    }
    exec burtwb -f $burtFile
    #exec sddscasr -restore $burtFile
    APSSetVarAndUpdate betaCorrConfigStatus "Done."
}
    
proc ApplyCorrectionToModel {args} {
    global betaDataFile OAGGlobal
    APSParseArguments {deltaFile} 
    # add basic aps.lte.sdds file in official area to deltaK1 file.
    set refLattice $OAGGlobal(SRLatticesDirectory)/default/aps.lte.sdds
    set scriptDir /home/helios/oagData/sr/latticeFunctionCorrection/beta/scripts
    set workingDir [file dirname $deltaFile]
    set file [file tail $deltaFile]
    
    # file $workingDir/$file.param is the elegant parameter file.
    set tmpfile /tmp/[APSTmpString]
    if [catch {exec sddsprocess $refLattice -pipe=out \
                 -match=col,ElementType=QUAD,ElementParameter=K1 \
                 | sddsconvert -pipe \
                 -retain=col,ElementName,ElementParameter,Kn \
                 | sddsselect -pipe $workingDir/$file \
                 -match=ElementName \
                 | sddsxref -pipe $workingDir/$file \
                 -match=ElementName -take=deltaK1 \
                 | sddsprocess -pipe=in $tmpfile.param \
                 "-redef=col,ParameterValue,Kn deltaK1 +" \
             } result] {
        return -code error "ApplyCorrectionToModel(1): $result"
    }
    if [catch {exec replaceText $scriptDir/twissTemplate.ele \
                 ${tmpfile}.ele \
                 -orig=<parameterFile>,<twissFile> -repl=$tmpfile.param,$tmpfile.twi \
             } result] {
        return -code error "ApplyCorrectionToModel(2): $result"
    }

    APSSetVarAndUpdate betaCorrConfigStatus "Running elegant..."
    if [catch {exec elegant ${tmpfile}.ele >& ${tmpfile}.ele.log \
             } result] {
        APSSetVarAndUpdate betaCorrConfigStatus "$result"
    }

    if [catch {exec averageOverElements -input ${tmpfile}.twi \
                 -output ${tmpfile}.twi.ave \
                 -itemList "betax betay" \
             } result] {
        return -code error "ApplyCorrectionToModel(3): $result"
        exit
    }
    if [catch {exec sddsconvert ${tmpfile}.twi.ave -pipe=out \
                 -retain=col,ElementName,betaxAverage,betayAverage \
                 -edit=col,*Average,%/Average// \
                 | sddsselect -pipe $betaDataFile \
                 -match=ElementName=QuadNameString \
                 | sddsxref -pipe=in $betaDataFile ${tmpfile}.twi.sel \
                 -take=BetaY,BetaX -match=ElementName=QuadNameString \
             } result] {
        return -code error "ApplyCorrectionToModel(4): $result"
        exit
    }
    # compare the beta functions from elegant with the ones 
    # from the measurement
    if [catch {exec sddsplot ${tmpfile}.twi.sel \
                 "-topline=Measurement and reverse correction effect on model" \
                 -title= \
                 -col=ElementName,BetaY  \
                 "-ylabel=BetaY (m)" \
                 -grap=sym,subtype=1,sca=1 -leg=spec=Measurement \
                 -col=ElementName,betay \
                 -grap=sym,subtype=2,sca=1 "-leg=spec=Effect on Model" \
                 -endpanel \
                 -col=ElementName,BetaX  \
                 "-ylabel=BetaX (m)" \
                 -grap=sym,subtype=1,sca=1 -leg=spec=Measurement \
                 -col=ElementName,betax \
                 -grap=sym,subtype=2,sca=1 "-leg=spec=Effect on Model" \
                 & \
             } result] {
        return -code error "ApplyCorrectionToModel(5): $result"
        exit
    }

    APSSetVarAndUpdate betaCorrConfigStatus "Done."
}
    
set gain 1
set singularValues 12
set betaReferenceFile $OAGGlobal(SRLatticesDirectory)/default/aps.twiAve
set measFile ""
set measDir /home/helios/oagData/sr/betaFunctionData
set burtOutputFile quadDelta01

set widgetList [APSTabFrame .tabs -parent .userFrame -width 1000 -height 280 \
                  -labelList "\"Quad readbacks\" \"Quad correctors\"" -label ""]

APSSRSectorButtons .readButtons -parent [lindex $widgetList 0] -rootname betaRead -orientation horizontal \
  -label "Quad readback selections" -description "Quad readback selections" \
  -itemList $readList -packOption "-side top" \
  -itemLabelList $readList \

APSSRSectorButtons .corrButtons -parent [lindex $widgetList 1] -rootname betaCorr -orientation horizontal \
  -label "Quad corrector selections" -description "Quad corrector selections" \
  -itemList $corrList -packOption "-side top" \
  -itemLabelList $corrList

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

proc FindDataSetsAndDescriptions {} {
    global measDir env

    if {![file exists $measDir/descriptions.sdds]} {
        set dirOld [pwd]
        cd $measDir
        # 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 $measDir/$subDir
            set sampleFile [lindex [glob -nocomplain *_HTuneData.sdds] 0]
            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 $measDir/betaFiles.acl $measDir/descriptions.sdds}
#        } else {
#            catch {exec setfacl -M $measDir/betaFiles.acl $measDir/descriptions.sdds}
#        }
        cd $dirOld
    }
    sdds load $measDir/descriptions.sdds descriptions
    set dataSetList [lindex $descriptions(Column.DataSet) 0]
    set descriptionList [lindex $descriptions(Column.Description) 0]
    return [list $dataSetList $descriptionList]
}

proc SelectedData {args} {
    global readList
    set directory ""
    APSParseArguments {directory}
    if ![string length $directory] {
        return -code error "SelectedData: Null directory string."
    }
    set fileLabel ""

    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."]
    if ![string length $dataSetList] {
        APSSetVarAndUpdate betaCorrConfigStatus "Please select a valid beta function data fileLabel for plotting."
        return 0
    }
    set VFileList ""
    foreach dataSet $dataSetList {
        set root ${directory}/${dataSet}
        eval lappend VFileList [glob -nocomplain ${root}/S*_VTuneData_BnLFit.sdds]
    }
    set HFileList ""
    foreach dataSet $dataSetList {
        set root ${directory}/${dataSet}
        eval lappend HFileList [glob -nocomplain ${root}/S*_HTuneData_BnLFit.sdds]
    }
    set betayDataFile /tmp/[APSTmpString].betay
    set betaxDataFile /tmp/[APSTmpString].betax
    set betaDataFile /tmp/[APSTmpString].beta
    # for now duplicate quadrupole measurements are chopped out but
    # in the future one could have averaging.
    eval exec sddscombine ${VFileList} -pipe=out -overWrite -collapse \
      | sddssort -pipe=in $betayDataFile \
      -col=s,increasing -unique \
      -nowarnings
    eval exec sddscombine ${HFileList} -pipe=out -overWrite -collapse \
      | sddssort -pipe=in $betaxDataFile \
      -col=s,increasing -unique \
      -nowarnings
    exec sddsxref $betayDataFile $betaxDataFile $betaDataFile \
      -match=QuadNameString -take=BetaX
    APSExecLog .printout -unixCommand "sddsprintout -col=(QuadNameString,BetaY,BetaX) $betaDataFile -formatDefaults=double=%6.2f" -width 50
    # set the sector buttons
    APSSetSRSectorButtons -mode all-off -rootname betaRead \
      -itemList $readList
    set quadList [exec sdds2stream -col=QuadNameString $betaDataFile]
    foreach quad $quadList {
        global betaRead${quad}
        set betaRead${quad} 1
    }
    # use the file that conatins both betay and betax
    return $betaDataFile
}

# several tabs are useful
# select beta data
# make configuration
# calculate correction
# apply correction
# save correction
set widgetList [APSTabFrame .actionTabs -parent .userFrame -width 800 -height 220 \
                  -labelList "\"Data...\" \"Setup...\" \"Calculate...\" \"Apply...\" \"Save...\"" -label ""]

set frameWidth 800
set frameHeight 280

set windex 0
set twidget [lindex $widgetList $windex]
APSFrame .data -parent $twidget  -label "Beta Data" \
  -packOption "-side top -anchor w" \
  -width $frameWidth -height $frameHeight -contextHelp \
  "Use this frame to select the beta function data from the Beta Function Measurement application."
set w0 $twidget.data.frame
APSButton .selectBetaData -parent $w0 \
  -packOption "-side top -anchor w" \
  -text "Select Beta data" \
  -command {set betaDataFile [SelectedData -directory $measDir]} \
  -contextHelp "Dialog box to selected beta measurement data files. Button widgets will be updated. Quadrupole measurements may be removed after this step and before creating a configuration file."
APSLabeledEntry .betaReference -parent $w0 \
  -packOption "-side top -anchor w" \
  -label "Beta reference file:" \
  -textVariable betaReferenceFile -width 55

incr windex
set twidget [lindex $widgetList $windex]
APSFrame .config -parent $twidget  -label "Configure Correction" \
  -width $frameWidth -height $frameHeight -contextHelp \
  "Use this frame to configure the readback and correction quads before correction is done."
set w0 $twidget.config.frame
APSLabeledEntry .refMatrixFileX -parent $w0 \
  -packOption "-side top -anchor w" \
  -label "Reference matrix file for betax:" \
  -textVariable refMatrixFileX -width 30
APSLabeledEntry .refMatrixFileY -parent $w0 \
  -packOption "-side top -anchor w" \
  -label "Reference matrix file for betay:" \
  -textVariable refMatrixFileY -width 30

APSFileSelectWidget .corrMatrixDir -parent $w0 \
  -pathVariableList [list configBaseDir] \
  -label "Correction matrix directory:" \
  -noSelect 0 -mode directory -incrementButtons 1 \
  -variable corrMatrixDir -width 30
APSButton .genCorrDir  -parent $w0.corrMatrixDir \
  -packOption "-side top -anchor w" \
  -text "G" -size small \
  -command {GenerateCorrectionDir} \
  -contextHelp "Generate correction directory into which to put beta correction matrix."
APSRadioButtonFrame .plane -parent $w0 -label "Plane" \
  -orientation horizontal \
  -variable plane \
  -buttonList {x y x/y} \
  -valueList {x y xy} \
  -contextHelp "Selected the plane for beta function correction."
APSLabeledEntry .singularValues -parent $w0 \
  -packOption "-side top -anchor w" \
  -label "Number of singular values:" \
  -textVariable singularValues -width 30
APSButton .genCorrMatrix  -parent $w0 \
  -packOption "-side top -anchor w" \
  -text "Generate correction matrix" \
  -command {GenerateCorrectionMatrix -outputRoot $baseDir/lattices/default/$corrMatrixDir \
              -singularValues $singularValues \
              -plane $plane \
              -referenceBetaxMatrix $refMatrixDir/$refMatrixFileX \
              -referenceBetayMatrix $refMatrixDir/$refMatrixFileY} \
  -contextHelp "Uses the selected quads to filter out columns and rows of the reference matrix. The resulting matrix is inverted and written into a subdirectory of /home/helios/oagData/sr/latticeFunctionCorrection/lattices/default."

incr windex
set twidget [lindex $widgetList $windex]
APSFrame .calculate -parent $twidget  -label "Calculate Correction" \
  -width $frameWidth -height $frameHeight -contextHelp \
  "Use this frame to calculate correction quads changes for the correction is done."
set w0 $twidget.calculate.frame
APSButton .resultsDaily  -parent $w0 \
  -packOption "-side top -anchor w" \
  -text "Go to daily directory" \
  -command {set burtOutputDir [APSGoToDailyDirectory -subdirectory betaCorrection]} \
  -contextHelp "Setting daily directory in which to put beta correction."
APSLabeledEntry .burtOutputDir -parent $w0 \
  -packOption "-side top -anchor w" \
  -label "Burt output directory:" \
  -textVariable burtOutputDir -width 55
APSLabeledEntry .burtOutputFile -parent $w0 \
  -packOption "-side top -anchor w" \
  -label "Burt output file:" \
  -textVariable burtOutputFile 
APSLabeledEntry .gain -parent $w0 \
  -packOption "-side top -anchor w" \
  -label "Gain:" \
  -textVariable gain -width 10
APSRadioButtonFrame .removeDC -parent $w0 -label "Remove DC from each family" \
  -orientation horizontal \
  -variable removeDC \
  -buttonList {no yes} \
  -valueList {0 1} \
  -contextHelp "Remvoing DC component of each family will help prevent a tune shift
when applying the correction."
APSButton .genBurtOutput  -parent $w0 \
  -packOption "-side top -anchor w" \
  -text "Calculate beta correction" \
  -command {CorrectBeta -measFile $betaDataFile -gain $gain \
              -corrMatrixDir $configBaseDir/$corrMatrixDir \
              -betaReferenceFile $betaReferenceFile \
              -removeDC $removeDC \
              -burtOutputDir $burtOutputDir -burtOutputFile $burtOutputFile} \
  -contextHelp "Generate a burt output file with quadrupole correction."

incr windex
set twidget [lindex $widgetList $windex]
APSFrame .apply -parent $twidget  -label "Apply Correction" \
  -width $frameWidth -height $frameHeight -contextHelp \
  "Use this frame to apply the correction to quadrupole PVs."
set w0 $twidget.apply.frame
APSButton .applyCorrection -parent $w0 \
  -packOption "-side top -anchor w" \
  -text "Apply beta correction" \
  -command {ApplyCorrection -burtFile $burtOutputDir/$burtOutputFile} \
  -contextHelp "Sends the calculated quadrupole correction to control system."
APSButton .applyCorrectionModel -parent $w0 \
  -packOption "-side top -anchor w" \
  -text "Apply reverse beta correction to model" \
  -command {ApplyCorrectionToModel -deltaFile $burtOutputDir/$burtOutputFile.deltaK1} \
  -contextHelp "Takes the negative of the calculated quadrupole correction and applies it to an elegant model. The resulting twiss functions is plotted. The data is supposed to match the measurement data. It is good to try this first to get an idea of how many singular values to use."

# to add next:
# make save of SR
# make standardization file from save
# option to install standardization file.
proc SaveConfig {args} {
    set description ""
    APSParseArguments {description}
    if ![string length $description] {
        return -code error "MakeStandardizeFile: description has null value."
    }
    set saveConfig [APSSaveMachine -machine SR -description $description]
    APSSetVarAndUpdate etaxCorrConfigStatus "Save to $saveConfig Done."
    return -code ok $saveConfig
}
proc MakeStandardizeFile {args} {
    set root ""
    set directory ""
    APSParseArguments {root directory}
    if ![string length $root] {
        return -code error "MakeStandardizeFile: root has null value."
    }
    if ![string length $directory] {
        return -code error "MakeStandardizeFile: directory has null value."
    }
    exec snap2standardize -snapshot \
      /home/helios/oagData/SCR/snapshots/SR/$root.gz \
      -output $directory/$root.std  \
      -template /home/helios/oagData/sr/magnetConditioning/template.std
    exec standardize -configure $directory/$root.std
    APSSetVarAndUpdate etaxCorrConfigStatus "Configured to $directory/$root.std"
}
    

incr windex
set twidget [lindex $widgetList $windex]
APSFrame .save -parent $twidget  -label "Save SR configuration" \
  -width $frameWidth -height $frameHeight -contextHelp \
  "Use this frame to make a save of the SR and make a standardization file."
set w0 $twidget.save.frame
APSLabeledEntry .saveDescription -parent $w0 \
  -packOption "-side top -anchor w" \
  -label "Save description:" \
  -textVariable saveDescription -width 55
set saveConfig ""
APSButton .saveMachine -parent $w0 \
  -packOption "-side top -anchor w" \
  -text "Save SR configuration" \
  -command {set saveConfig [SaveConfig -description $saveDescription -statusCallback "APSSetVarAndUpdate betaCorrConfigStatus"]} \
  -contextHelp "Saves SR configuration, just like SaveCompareRestore."
APSLabeledEntry .saveConfig -parent $w0 \
  -packOption "-side top -anchor w" \
  -label "Save configuration:" \
  -textVariable saveConfig -width 30 \
  -contextHelp "Name of the SR configuration from which the standardize file is created. This entry box gets a value when the Save SR configuration button button is pressed and the action completes. User may type in a valid file name."
APSButton .makeStandardizeFile -parent $w0 \
  -packOption "-side top -anchor w" \
  -text "Make/Apply standardize file" \
  -command {MakeStandardizeFile -directory $burtOutputDir \
       -root [file root $saveConfig]} \
  -contextHelp "Makes a standardization file from a saved SR configuration and applies the values to the control system. One may proceed to pem stanardization."

APSSetVarAndUpdate betaCorrConfigStatus "Ready."
