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

# $Log: not supported by cvs2svn $

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 "\$Author: emery $"

APSApplication . -name "SR Light Source Beta Function Interpolator" \
  -overview "SR Light Source Beta Function Interpolator calculated the beta functions for a light source from beta function measurements at nearest quadrupoles." -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 sourceList {AMSext AM BMSext BM ID}

set status "Ready."
APSScrolledStatus .status -parent .userFrame -textVariable status -width 90
proc SetStatus {text} {
    global status
    set status $text
}

#Make sector selection widgets.  Returns 1 when completed
APSSRSectorButtons .sectorButtons -parent .userFrame \
  -rootname source -orientation horizontal \
  -label "Light source selections" -description "Light source selections" \
  -itemList $sourceList -packOption "-side top" \
  -itemLabelList $sourceList

# 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 outputFileDir outputFile lattice 

    set parent ""
    APSParseArguments {parent}

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

    APSFrame $widget -parent $parent \
      -height 30 \
      -packOption {-side top -expand 1}
    $parent$widget.frame configure -relief flat
    APSFrame .entries -parent $parent$widget.frame \
      -height 30 -label "File Entry" \
      -packOption {-side left -expand 1}
    set w $parent$widget.frame.entries.frame

    APSLabeledEntry .outputFileDir -parent $w -label "Directory: " \
      -textVariable outputFileDir -width 70 \
      -contextHelp "Diretcory for output file for beta function interpolation results for all light sources selected."
    APSLabeledEntry .outputFile -parent $w -label "File: " \
      -textVariable outputFile -width 70 \
      -contextHelp "File for beta function interpolation results for all light sources selected."
    APSButton .daily -parent $w.outputFileDir -packOption "-anchor e" \
      -text "daily" -size small \
      -command {set outputFileDir [APSGoToDailyDirectory]}

    APSFrame .lattice -parent $parent$widget.frame \
      -height 30 \
      -packOption {-side right -expand 1}
    $parent$widget.frame.lattice.frame configure -relief flat
    set w $parent$widget.frame.lattice.frame
    
    set latticeList [APSSRFindLattices]
    APSRadioButtonFrame .latticeChoiceFrame -parent $w \
      -orientation vertical \
      -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 .select -parent $w \
      -text "Select Data Set" \
      -command {PlotSelectedData} \
      -packOption {-side left -fill x} \
      -contextHelp "This button pops up a dialog box to select data sets that may contain the quads from which interpolation is required for the light source selected."

}


# Make a list of quads selected via the checkbuttons.  Procedure returns the list.
proc MakeSelectedSourceList {} {
    global sourceList

    set selectedList ""
    for {set sector 1} {$sector<=40} {incr sector} {
        foreach source $sourceList {
            set flagName sourceS${sector}$source
            global $flagName
            if {[set $flagName]} {
                lappend selectedList S${sector}${source}
            }
        }
    }
    return $selectedList
}

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

proc FindDataSetsAndDescriptions {} {
    global mainDir

    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]
            set description [exec sdds2stream -page=1 -para=Description $sampleFile]
            regexp {^"(.*)"$} $description {} description
            puts $fid "$subDir \"$subDir -> $description\""
        }
        close $fid
        catch {file attributes descriptions.sdds -permissions 00664}
        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 {} {
    global mainDir lattice betaxFile betayFile outputFileDir outputFile

    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] {
        SetStatus "Please select a beta function data data set for plotting."
        return 0
    }
    update idletasks
    
    SetStatus "Searching beta measurement data area..."
    update 
    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 tempfile /tmp/[APSTmpString]
    set betaxFile ${tempfile}.betax
    set betayFile $tempfile.betay
    
    # H files
    eval exec sddscombine ${HFileList} -pipe=out -overWrite -collapse \
      | sddssort -pipe=in $betaxFile \
      -col=s,increasing \
      -nowarnings

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

    set betaxFileQuadList [exec sdds2stream $betaxFile -col=QuadNameString]
    set betayFileQuadList [exec sdds2stream $betayFile -col=QuadNameString]
    set selectedSourceList [MakeSelectedSourceList]
    set resultsFile $outputFileDir/$outputFile
    set resultsList ""
    set someLS 0
    set someSext 0
    foreach source $selectedSourceList {
        SetStatus "Doing source $source..."
        update
        if [catch {CheckQuadList -source $source -quadList $betaxFileQuadList
            CheckQuadList -source $source -quadList $betayFileQuadList} result ] {
            SetStatus "Problem with quads for source $source.\n$result\nSkipping $source..."
        } else {
            if [catch {CalculateBeta -source $source -plane x \
                         -file $betaxFile -output $tempfile.$source.betax \
                         -lattice $lattice \
                     } result ] {
                return -code error $result
            }
            if [catch {CalculateBeta -source $source -plane y \
                         -file $betayFile -output $tempfile.$source.betay \
                         -lattice $lattice \
                     } result ] {
                return -code error $result
            }
            if [regexp Sext $source] {
                set someSext 1
                if [catch {exec sddsxref $tempfile.$source.betax -noWarning \
                             $tempfile.$source.betay \
                             $tempfile.$source.beta \
                             -take=BetaS2Y,BetaS2YSigma,BetaS3Y,BetaS3YSigma \
                         } result ] {
                    return -code error $result
                }
            } else {
                set someLS 1
                if [catch {exec sddsxref $tempfile.$source.betax -noWarning \
                             $tempfile.$source.betay \
                             $tempfile.$source.beta \
                             -take=BetaY,BetaYSigma,AlphaY,AlphaYSigma \
                         } result ] {
                    return -code error $result
                }
            }
            lappend resultsList $tempfile.$source.beta
        }
        update idletasks
    }
    
    if {[llength $resultsList] > 0} {
        eval exec sddscombine $resultsList $resultsFile -merge -overwrite
    } else {
        SetStatus "No results obtained."
        return 
    }
    if $someLS {
        exec sddsprocess $resultsFile -noWarning \
          -print=col,BetaXSolution,%5.2f+/-%5.2f,BetaX,BetaXSigma,units=m \
          -print=col,AlphaXSolution,%5.2f+/-%5.2f,AlphaX,AlphaXSigma \
          -print=col,BetaYSolution,%5.2f+/-%5.2f,BetaY,BetaYSigma,units=m \
          -print=col,AlphaYSolution,%5.2f+/-%5.2f,AlphaY,AlphaYSigma 
    } 
    if $someSext {
        exec sddsprocess $resultsFile -noWarning \
          -print=col,BetaS2XSolution,%5.2f+/-%5.2f,BetaS2X,BetaS2XSigma,units=m \
          -print=col,BetaS3XSolution,%5.2f+/-%5.2f,BetaS3X,BetaS3XSigma,units=m \
          -print=col,BetaS2YSolution,%5.2f+/-%5.2f,BetaS2Y,BetaS2YSigma,units=m \
          -print=col,BetaS3YSolution,%5.2f+/-%5.2f,BetaS3Y,BetaS3YSigma,units=m
    }
    if $someLS {
        if [catch {exec sddsprocess $resultsFile -pipe=out \
                     -match=col,Source=*Sext*,! \
                     | sddsprintout -pipe=in $tempfile.LS.printout \
                     -col=(Source,BetaXSolution,AlphaXSolution,BetaYSolution,AlphaYSolution) \
                     -formatDefaults=double=%5.2f,string=%8s -wi=80} result ] {
            return -code error $result
        }
    }
    if $someSext {
        if [catch {exec sddsprocess $resultsFile -pipe=out \
                     -match=col,Source=*Sext* \
                     | sddsprintout -pipe=in $tempfile.Sext.printout \
                     -col=(Source,BetaS2XSolution,BetaS3XSolution,BetaS2YSolution,BetaS3YSolution) \
                     -formatDefaults=double=%5.2f,string=%8s -wi=80} result ] {
            return -code error $result
        }
    }
    if $someLS {
        set displayWidget1 .[APSUniqueName printoutLS]
        APSFileDisplayWindow $displayWidget1 -fileName $tempfile.LS.printout -width 90    
        APSDialogBoxAddButton .install -parent $displayWidget1 \
          -text Install \
          -command "InstallBeta -fileName $resultsFile" \
          -contextHelp "Sends the values of the beta functions to the imaging system."
        APSDisableButton $displayWidget1.buttonRow.install.button
    }
    if $someSext {
        set displayWidget2 .[APSUniqueName printoutSext]
        APSFileDisplayWindow $displayWidget2 -fileName $tempfile.Sext.printout -width 90
    }

    SetStatus "Done."
    return 1
}

proc GetUSQuad {source} {
    switch -regexp -- $source {
        ID {
            set USQuadType B:Q1
        }
        BM {
            set USQuadType B:Q4
        }
        AM {
            set USQuadType A:Q3
        }
        default {
            return -code error "GetUSQuad: Source type not recognized"
        }
    }
    regexp {S([1-9][0-9]?)} $source {} sector
    return S${sector}$USQuadType
}

proc GetDSQuad {source} {
    set DSSectorOffset 0
    switch -regexp -- $source {
        ID {
            set DSQuadType A:Q1
            set DSSectorOffset 1
        }
        BM {
            set DSQuadType B:Q3
        }
        AM {
            set DSQuadType A:Q4
        }
        default {
            return -code error "CheckFile: Source type not recognized"
        }
    }
    regexp {S([1-9][0-9]?)} $source {} sector
    if $DSSectorOffset {
        set sectorp1 [expr $sector + 1]
        if {$sectorp1 > 40} {
            set sectorp1 1
        }
        return S${sectorp1}$DSQuadType
    } else {
        return S${sector}$DSQuadType
    }
}

proc CheckQuadList {args} {
    APSParseArguments {source quadList}
    if ![string length $source] {
        return -code error "CheckFile: No source given."
    }
    if ![llength $quadList] {
        return -code error "CheckFile: No quadList given."
    }
    if [catch {GetUSQuad $source} USQuad] {
        return -code error "CheckQuadList: $USQuad"
    }
    if [catch {GetDSQuad $source} DSQuad] {
        return -code error "CheckQuadList: $DSQuad"
    }
    if {-1==[lsearch -exact $quadList $USQuad] || \
          -1==[lsearch -exact $quadList $DSQuad]} {
        return -code error "CheckQuadList: quad $USQuad or $DSQuad for source $source not present in list."
    }
    return -code ok
}

proc CalculateBeta {args} {
    global OAGGlobal
    APSParseArguments {source plane file output lattice}
    if {![string length $source] || ![string length $output] || \
          ![string length $lattice] || \
          ![string length $plane] || ![string length $file] } {
        return -code error "CalculateBeta: Missing argument."
    }
    set doS2S3 0
    if [regexp Sext $source] {
        set doS2S3 1
    } 
    set Plane [string toupper $plane]
    if [catch {GetUSQuad $source} USQuad] {
        return -code error "CalculateBeta: $USQuad"
    }
    if [catch {GetDSQuad $source} DSQuad] {
        return -code error "CalculateBeta: $DSQuad"
    }
    if [catch {exec sddsprocess $file -pipe=out \
                 -match=col,QuadNameString=$USQuad \
                 | sdds2stream -pipe -col=Beta${Plane},Beta${Plane}Sigma \
             } result ] {
        return -code error "CalculateBeta(0): $result"
    }
    set USbeta [lindex $result 0]
    set USbetaSigma [lindex $result 1]
    if [catch {exec sddsprocess $file -pipe=out \
                 -match=col,QuadNameString=$DSQuad \
                 | sdds2stream -pipe -col=Beta${Plane},Beta${Plane}Sigma \
             } result ] {
        return -code error "CalculateBeta(1): $result"
    }
    set DSbeta [lindex $result 0]
    set DSbetaSigma [lindex $result 1]
    set USKnL 0
    set DSKnL 0
    set strengthFile $OAGGlobal(SRLatticesDirectory)/$lattice/aps.lte.sdds
    set KnLUS [expr abs([exec sddsprocess $strengthFile -pipe=out \
                           -match=col,ElementName=$USQuad \
                           | sdds2stream -pipe -col=KnL])]
    set KnLDS [expr abs([exec sddsprocess $strengthFile -pipe=out \
                           -match=col,ElementName=$DSQuad \
                           | sdds2stream -pipe -col=KnL])]
    switch -regexp -- $source {
        ID {
            if [catch {exec betaAtQ1 -plane=$plane \
                         -BQ1=beta=$USbeta,error=$USbetaSigma,KnL=$KnLUS \
                         -AQ1=beta=$DSbeta,error=$DSbetaSigma,KnL=$KnLDS \
                     } result ] {
                return -code error "CalculateBeta(2): $result"
            }
        }
        BM {
            if [catch {exec betaAtDipole -plane=$plane -source=BM \
                         -Q4=beta=$USbeta,error=$USbetaSigma,KnL=$KnLUS \
                         -Q3=beta=$DSbeta,error=$DSbetaSigma,KnL=$KnLDS \
                     } result ] {
                return -code error "CalculateBeta(3): $result"
            }
        }
        AM {
            if [catch {exec betaAtDipole -plane=$plane -source=AM \
                         -Q3=beta=$USbeta,error=$USbetaSigma,KnL=$KnLUS \
                         -Q4=beta=$DSbeta,error=$DSbetaSigma,KnL=$KnLDS \
                     } result ] {
                return -code error "CalculateBeta(4): $result"
            }
        }
        default {
            return -code error "CalculateBeta: Source type not recognized"
        }
    }
    if [catch {open $output w} fid] {
        return -code error "CalculateBeta(5): $fid"
    }
    puts $fid "SDDS1"
    puts $fid "&column name=Source type=string &end"
    if !$doS2S3 {
        set index1 [lsearch $result "beta:"]
        set index2 [lsearch $result "alpha:"]
        puts $fid "&column name=Beta$Plane type=double units=m &end"
        puts $fid "&column name=Beta${Plane}Sigma type=double units=m &end"
        puts $fid "&column name=Alpha$Plane type=double units=m &end"
        puts $fid "&column name=Alpha${Plane}Sigma type=double units=m &end"
    } else {
        set index1 [lsearch $result "betaS2:"]
        set index2 [lsearch $result "betaS3:"]
        puts $fid "&column name=BetaS2$Plane type=double units=m &end"
        puts $fid "&column name=BetaS2${Plane}Sigma type=double units=m &end"
        puts $fid "&column name=BetaS3$Plane type=double units=m &end"
        puts $fid "&column name=BetaS3${Plane}Sigma type=double units=m &end"
    }
    puts $fid "&data mode=ascii no_row_counts=1 &end" 
    set line $source
    append line " [lindex $result [expr $index1 + 1]]"
    append line " [lindex $result [expr $index1 + 2]]"
    append line " [lindex $result [expr $index2 + 1]]"
    append line " [lindex $result [expr $index2 + 2]]"
    puts $fid $line
    close $fid

    return
}

set outputFileDir .
set outputFile test

MakeLabelledEntryWidgets .labelledEntries -parent .userFrame
MakeButtonActionWidgets .buttons -parent .userFrame
set lattice [file readlink $OAGGlobal(SRLatticesDirectory)/default]
