#!/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)]
set CVSRevisionAuthor "\$Author: soliday $"

APSApplication . -name ITSLatticeSetup \
  -overview "Converts elegant lattice data to current setpoints for ITS magnets."

set status ""
APSScrolledStatus .status -parent .userFrame -textVariable status -height 10 -width 85 -packOption "-fill x -expand true"

proc setStatus {text} {
    APSSetVarAndUpdate status $text
}

set apsLinacPSDeviceFile /home/helios/oagData/deviceConfig/linac/PSOps.pvTable
set apsLEUTLPSDeviceFile /home/helios/oagData/deviceConfig/linac/LTPToEndPSOps.pvTable
set apsLTSPSDeviceFile /home/helios/oagData/deviceConfig/lts/LTSOps.pvTable

set apsITSMagnetsDir /home/helios/oagData/ITS/magnets
set mainDir $OAGGlobal(ITSLatticesDirectory)

proc APSMakeInjectorConditioningFile {args} {
    set output ""
    set sectorList ""
    set cycles -1
    set degauss 0
    APSStrictParseArguments {output sectorList cycles degauss}
    if ![string length $output] {
        return -code error "APSMakeInjectorConditioningFile: no output file"
    }

    set tmpRoot /tmp/[APSTmpString]

    set knownSectorList {LTS}
    if ![llength $sectorList] {
        set sectorList $knownSectorList
    }

    if !$degauss {
        set fileToUse(LTS) /home/helios/oagData/controlFiles/LTS/LTS_standardize.std
    } else {
        set fileToUse(LTS) /home/helios/oagData/controlFiles/LTS/LTS_degauss.sdds
    }
    set fileList ""
    foreach sector $sectorList {
        set sector [string toupper $sector]
        if [lsearch -exact $knownSectorList $sector]==-1 {
            APSDeleteTmpFileList -ID APSMakeInjectorConditioningFile
            return -code error "APSMakeInjectorConditioningFile: unknown sector $sector given"
        }
        if [string length $fileToUse($sector)]==0 continue
        APSAddToTmpFileList -ID APSMakeInjectorConditioningFile -fileList $tmpRoot.$sector
        if {[catch {exec sddsprocess $fileToUse($sector) $tmpRoot.$sector -nowarning \
                      -match=column,ControlName=$sector*} result]} {
            APSDeleteTmpFileList -ID APSMakeInjectorConditioningFile
            return -code error "APSMakeInjectorConditioningFile: $result ($fileToUse($sector) with $sector)"
        }
        lappend fileList $tmpRoot.$sector
    }
    file delete -force $output
    if [llength $fileList]==0 {
        return 
    }
    if [catch {eval exec sddscombine $fileList $output -merge} result] {
        return -code error "APSMakeInjectorConditioningFile: $result"
    }
}

proc PickLattice {args} {
    set sectionDir ""
    if [APSStrictParseArguments {sectionDir}] {
        return -code error "invalid arguments (PickLattice)"
    }
    
    global latticeDirectory latticeName runRootname

    if {![file exists $latticeDirectory($sectionDir)] \
          || ![file isdirectory $latticeDirectory($sectionDir)]} {
        return -code error "$latticeDirectory not found or not a directory"
    }
    set oldDir [pwd]
    cd $latticeDirectory($sectionDir)
    set rootnameList [lsort [glob -nocomplain *?*]]
    set validList ""
    foreach rootname $rootnameList {
        if ![file isdirectory $rootname] {
            continue
        }
        if {![file exists $rootname/$runRootname($sectionDir).param] || \
              (![file exists $rootname/$runRootname($sectionDir).twi] && \
                 ![file exists $rootname/$runRootname($sectionDir).cen]) } {
            continue
        }
        lappend validList $rootname
    }
    if ![llength $validList] {
        APSSetVarAndUpdate status "No recognized/valid subdirectories found in $latticeDirectory($sectionDir)"
        cd $oldDir
        return
    }
    set latticeName($sectionDir) [APSChooseItemFromList -name "Lattice choice" \
                                    -itemList $validList -returnList $validList ]
    if ![string length $latticeName($sectionDir)] {
        cd $oldDir
        return
    }
    UpdateMomentumProfile -sectionDir $sectionDir
    cd $oldDir
}

proc UpdateMomentumProfile {args} {
    set sectionDir ""
    if [APSStrictParseArguments {sectionDir}] {
        return -code error "invalid arguments (UpdateMomentumProfile)"
    }
    
    global latticeDirectory latticeName runRootname
    global momentumBreakPointNameList changeMomentum setpointsOutputFile
    global momentumBreakPointValue
    
    set rootname $latticeDirectory($sectionDir)/$latticeName($sectionDir)/$runRootname($sectionDir)
    if [file exists $rootname.cen] {
        set profileFile $rootname.cen
        set pCenColumn pCentral
    } else {
        set profileFile $rootname.twi
        set pCenColumn pCentral0
    }
    foreach breakpoint $momentumBreakPointNameList($sectionDir) {
        if [string compare $breakpoint begin]==0 {
            set value [exec sddsprocess $profileFile -pipe=out \
                         -match=col,ElementName=_BEG_ \
                         | sdds2stream -pipe -column=$pCenColumn]
        } else {
            set value [exec sddsprocess $profileFile -pipe=out \
                         -match=col,ElementName=${breakpoint}CELL* \
                         -clip=0,1,invert \
                         | sdds2stream -pipe -column=$pCenColumn]
        }
        set momentumBreakPointValue($sectionDir,$breakpoint) [expr $value*0.51099906]
    }
}

# Allows viewing lattice functions 

proc ViewLattice {args} {
    set sectionDir ""
    set details 0
    set plots 1
    if [APSStrictParseArguments {sectionDir details plots}] {
        return -code error "invalid arguments (ViewLattice)"
    }
    
    global latticeDirectory latticeName runRootname
    global momentumBreakPointNameList changeMomentum setpointsOutputFile
    global momentumBreakPointValue

    if {![file exists $latticeDirectory($sectionDir)] || ![file isdirectory $latticeDirectory($sectionDir)]} {
        return -code error "$latticeDirectory($sectionDir) not found or not a directory"
    }
    if ![string length $latticeName($sectionDir)] {
        return -code error "No lattice chosen."
    }
    set rootname $latticeDirectory($sectionDir)/$latticeName($sectionDir)/$runRootname($sectionDir)
    if ![file exists $rootname.twi] {
        return -code error "Not found: $rootname.twi"
    }
    if $plots {
        lappend plotOptions -column=s,etax -legend=ysymbol -unsup=y -zoom=yfac=0.87,qcent=0.53 
        lappend plotOptions $rootname.twi -yscale=id=2 -column=s,etay -legend=ysymbol -unsup=y 
        lappend plotOptions -zoom=yfac=0.87,qcent=0.53 $rootname.twi 
        lappend plotOptions -yscale=id=2 -column=s,beta* -legend=ysymbol 
        lappend plotOptions -unsup=y -zoom=yfac=0.87,qcent=0.53 $rootname.twi -yscale=id=1 
        eval exec sddsplot -graph=line,type=1,vary \
          {"-title=Twiss parameters for $rootname"}   \
          $plotOptions \
          -column=s,Profile $rootname.mag -omni -graph=line,type=0 \
          -overlay=xmode=normal,yfactor=0.05,qoffset=0.43,ycenter,ymode=unit &
        setStatus "Plotting Twiss parameters..."
    } 
    if $details {
        set tmpRoot /tmp/[APSTmpString]
        if [catch {exec sddsprintout -column=ElementName,label=Name,format=%10s \
                     -column=s,format=%13.6f \
                     -column=betax,format=%13.6f -column=alphax,format=%13.6f \
                     -column=etax,format=%13.6f \
                     -column=betay,format=%13.6f -column=alphay,format=%13.6f \
                     -column=etay,format=%13.6f \
                     $rootname.twi $tmpRoot.twiPrint} result] {
            setStatus "Error: $result"
        } else {
            APSFileDisplayWindow [APSUniqueName .] -fileName $tmpRoot.twiPrint \
              -deleteOnClose 1 -width 130 \
              -sddsExportableFile $rootname.twi -comment "Twiss parameters for $rootname"
        }
        if [file exists $rootname.param] {
            if [catch {exec sddsprocess $rootname.param -pipe=out \
                         -match=column,ElementType=*QUAD,ElementType=*BEN* \
                         | sddsprintout -pipe=in $tmpRoot.paramPrint \
                         -column=ElementName,label=Name,format=%10s \
                         -column=ElementParameter,label=Item,format=%10s \
                         -column=ParameterValue,label=Value,format=%13.6g} result] {
                setStatus "Error: $result"
            } else {
                APSFileDisplayWindow [APSUniqueName .] -fileName $tmpRoot.paramPrint \
                  -deleteOnClose 1 -width 130 \
                  -sddsExportableFile $rootname.param \
                  -comment "Lattice parameters for $rootname"
            }
        }
    }
}


proc MakeFilename {args} {
    set sectionDir ""
    if [APSStrictParseArguments {sectionDir}] {
        return -code error "invalid arguments (MakeFilename)"
    }
    
    global latticeDirectory latticeName runRootname setpointsOutputFile
    if [string length $latticeName($sectionDir)]==0 {
        return -code error "Pick a lattice first"
    }
    set dir [APSGoToDailyDirectory]
    set setpointsOutputFile($sectionDir) [file join $dir $latticeName($sectionDir).sdds]
}

proc GenerateITSSetpointFile1 {args} {
    set sectionDir ""
    set convertAll 0
    if [APSStrictParseArguments {sectionDir convertAll}] {
        return -code error "invalid arguments (GenerateITSSetpointFile1)"
    }
    
    global latticeDirectory latticeName runRootname
    global momentumBreakPointNameList changeMomentum setpointsOutputFile
    global momentumBreakPointValue

    GenerateITSSetpointFile -convertAll $convertAll \
      -rootname $latticeDirectory($sectionDir)/$latticeName($sectionDir)/$runRootname($sectionDir) \
      -output $setpointsOutputFile($sectionDir) \
      -rescale $changeMomentum($sectionDir) \
      -beginMomentum $momentumBreakPointValue($sectionDir,begin)
}

# Generates the magnet setpoints (currents) from the chosen lattice file

proc GenerateITSSetpointFile {args} {
    set rootname ""
    set output ""
    set beginMomentum 0
    set convertAll 0
    set rescale 0
    APSStrictParseArguments {rootname output convertAll beginMomentum \
                               rescale}

    global apsITSMagnetsDir apsLTSPSDeviceFile
#    global apsITSMagnetsDir

    if ![string length $output] {
        return -code error "No output filename given"
    }
    if ![file exist $rootname.param] {
        return -code "not found: $rootname.param"
    }

    if [string compare [set outputDir [file dirname $output]] .]==0 {
        set outputDir [pwd]
    }

    set tmpRoot /tmp/[APSTmpString]
    switch $rescale {
        0 {
            # Find file giving the momentum at each element
            if ![file exists [set paramFile $rootname.param]] {
                return -code error "not found: $rootname.param"
            }
            if ![file exists [set profileFile $rootname.cen]] {
                if ![file exists [set profileFile $rootname.twi]] {
                    return -code error "not found: $rootname.cen or $rootname.twi"
                }
                set pCenColumn pCentral0
            } else {
                set pCenColumn pCentral
            }
        }
        1 {
            # run elegant to get scaled file
            set adjustFile [file join [file dirname [file dirname $rootname]] adjustp.ele]
            if ![file exists $adjustFile] {
                return -code error "not found: $adjustFile"
            }
            global elegantRunDone
            set elegantRunDone 0
            set elegantCmd "elegant $adjustFile \
                         -macro=latticeDir=[file dirname [file dirname $rootname]] \
                         -macro=rootname=$tmpRoot,startingFile=$rootname.param \
                         -macro=p0=[expr $beginMomentum/0.51099906]"
            catch {eval exec $elegantCmd >& $tmpRoot.log} result
            if ![file exists $tmpRoot.done] {
                APSFileDisplayWindow [APSUniqueName .] -fileName $tmpRoot.log \
                  -deleteOnClose 1 -width 130 
                update
                APSDeleteTmpFileList -ID GenerateITSSetpointFile
                return -code error "elegant run failed.  Look on /tmp for files."
            }
            APSAddToTmpFileList -ID GenerateITSSetpointFile -fileList \
              [glob -nocomplain $tmpRoot.*]
            # Find file giving the momentum at each element
            if ![file exists [set paramFile $tmpRoot.param]] {
                APSDeleteTmpFileList -ID GenerateITSSetpointFile
                return -code error "not found: $paramFile"
            }
            if ![file exists [set profileFile $tmpRoot.cen]] {
                APSDeleteTmpFileList -ID GenerateITSSetpointFile
                return -code error "not found: $profileFile"
            }
            set pCenColumn pCentral
        }
    }
    
    # generate setpoint for each element by interpolating excitation curves
    # 1a. Extract quad elements from parameters file (data: K1, L)
    # 1b. Extract bend elements from parameters file (data: ANGLE)
    # 2. Xref in the momentum from the appropriate file
    # 3. Compute the integrated strength (IS), summed over pieces.
    # 4. Multiply IS by BnLMultiplier, which accounts for strength differences between
    #    magnets using the same excitation curve.  If BnLMultiplier<1, then the
    #    magnet is weaker than the excitation curve says.
    # 5. Interpolate the excitation curve to get the current.
    APSAddToTmpFileList -ID GenerateITSSetpointFile -fileList "$tmpRoot.K1 $tmpRoot.ANGLE $tmpRoot.B1L $tmpRoot.beamlines $tmpRoot.dev"
#    APSAddToTmpFileList -ID GenerateITSSetpointFile -fileList "$tmpRoot.K1 $tmpRoot.ANGLE $tmpRoot.B1L $tmpRoot.beamlines"
    APSAddToTmpFileList -ID GenerateITSSetpointFile -fileList "$tmpRoot.K1L $tmpRoot.GS $tmpRoot.alpha"
    APSAddToTmpFileList -ID GenerateITSSetpointFile -fileList "$tmpRoot.res0 $tmpRoot.res1 $tmpRoot.res2"
    APSAddToTmpFileList -ID GenerateITSSetpointFile -fileList "$tmpRoot.flr $tmpRoot.flr1 $tmpRoot.flr2 $tmpRoot.flr3 $tmpRoot.VP "
    if $convertAll {
        set xrefExtraOpt -fillIn
    } else {
        set xrefExtraOpt -nowarning
    }
    if [catch {exec sddscombine $apsLTSPSDeviceFile -merge $tmpRoot.dev -overwrite} result] {
        APSDeleteTmpFileList -ID GenerateITSSetpointFile
        return -code error "GenerateITSSetpointFile: $result"
    }
    if [catch {exec sddsprocess $paramFile -pipe=out -match=col,ElementType=*QUAD* \
                 -match=col,ElementParameter=K1 \
                 | sddsconvert -pipe=in $tmpRoot.K1 \
                 -rename=column,ParameterValue=K1
        exec sddsprocess $paramFile -pipe=out -match=col,ElementType=*BEN* -nowarning \
                 -match=column,ElementParameter=ANGLE \
                 | sddsconvert -pipe=in $tmpRoot.ANGLE \
                 -rename=column,ParameterValue=GeometricIntegratedStrength
        exec sddsprocess $paramFile $tmpRoot.alpha -match=col,ElementType=ALPH -nowarning \
                 -match=column,ElementParameter=XMAX \
                 "-define=column,GeometricIntegratedStrength,ParameterValue sqr rec 3.304453768404287 *"
        exec sddsprocess $paramFile -pipe=out -match=col,ElementType=*QUAD* \
                 -match=col,ElementParameter=L \
                 | sddsconvert -pipe -rename=col,ParameterValue=L \
                 | sddsxref -pipe $tmpRoot.K1 -take=K1 -match=ElementName \
                 | sddsprocess -pipe=in $tmpRoot.K1L \
                 "-define=column,GeometricIntegratedStrength,K1 L *"


        exec sddscombine -merge $tmpRoot.ANGLE $tmpRoot.K1L $tmpRoot.alpha -pipe=out \
                 | tee $tmpRoot.GS \
                 | sddsxref -pipe $profileFile -take=$pCenColumn -match=ElementName \
                 | sddsprocess -pipe \
                 "-define=column,IntegratedStrength,GeometricIntegratedStrength $pCenColumn * 0.001704509390960 *,units=T*m^n" \
                 | sddsbreak -pipe -change=ElementName \
                 | sddsprocess -pipe -process=ElementName,first,%s -process=GeometricIntegratedStrength,sum,%s \
                 -process=IntegratedStrength,sum,%s -process=$pCenColumn,ave,pCentral \
                 | sddscollapse -pipe \
                 | sddsxref -pipe $apsITSMagnetsDir/crossReference.sdds -nowarning \
                 -match=ElementName -take=*  \
                 | sddsxref -pipe $apsITSMagnetsDir/ITS.CN -match=ElementName=DeviceName -take=ControlName \
                    -nowarning $xrefExtraOpt \
                 | sddsprocess -pipe \
                 "-redefine=column,IntegratedStrength,IntegratedStrength BnLMultiplier / Sign *,units=T" \
                 -print=column,ExcitationFile,$apsITSMagnetsDir/%s.excitation,ElementName \
                 | sddsinterpset -pipe \
                 -order=1 -data=fileColumn=ExcitationFile,interpolate=Current,functionOf=IntegratedStrength,column=IntegratedStrength \
                 -belowRange=value=0 -aboveRange=extrapolate \
                 | sddsprocess -pipe \
                 "-print=column,ValueString,%21.15e,Current" \
                 "-define=column,OverLimit,Current abs SupplyLimit > ? 1 : 0 \$ ,type=long" \
                 -edit=column,Beamline,ControlName,S/:/100D \
                 "-define=column,Momentum,pCentral 0.51099906 *,units=MeV/c" \
                 | sddsconvert -pipe=in $tmpRoot.res0 \
                 -retain=column,ElementName,ControlName,Current,ValueString,Beamline,IntegratedStrength,pCentral,Momentum,GeometricIntegratedStrength,SupplyLimit,OverLimit} result] {
        APSDeleteTmpFileList -ID GenerateITSSetpointFile 
        return -code error "GenerateITSSetpointFile: $result"
    }
    set output0 $tmpRoot.res0

    file copy -force $tmpRoot.res0 $output


    set count1 [lindex [split [exec sddssort -col=ElementName -unique $tmpRoot.GS -pipe=out | sdds2stream -rows -pipe]] 0]
    set count2 [lindex [split [exec sdds2stream -rows $output]] 0]


    if $count1!=$count2 {
        set elemNames \
          [exec sddsselect $tmpRoot.GS $output -match=ElementName -pipe=out -invert -reuse=rows \
             | sdds2stream -pipe -column=ElementName]
        set delete [APSMultipleChoice [APSUniqueName .] \
                      -question "$count1 elements are in the lattice, but $count2 setpoints were generated.  Probably one or more magnets are missing from the magnet cross reference or the device configuration file.  The elements in question are: [join $elemNames ,]\nWhat do you want to do?" \
                      -returnList {0 1} -labelList {continue abort}]
        if $delete {
            file delete -force $output
        }
    }
    APSDeleteTmpFileList -ID GenerateITSSetpointFile 
}

# Reviews data in a previously generated setpoint file

proc ViewITSSetpointFile {args} {
    set sectionDir ""
    APSStrictParseArguments {sectionDir}
    
    if [APSStrictParseArguments {sectionDir}] {
        return -code error "invalid arguments (PickLattice)"
    }
    
    global latticeDirectory latticeName runRootname setpointsOutputFile
    set fileName $setpointsOutputFile($sectionDir)

    if {![string length $fileName] || ![file exists $fileName]} {
        return -code error "ViewITSSetpointFile: Give a valid filename ($fileName not found in [pwd])"
    }
    set tmpFile /tmp/[APSTmpString].printout
    if [catch {exec sddsprintout $fileName $tmpFile -column=ControlName,format=%22s \
                -column=ElementName,format=%10s \
                 -column=Beamline,format=%10s -column=ValueString,format=%22s \
                 -column=SupplyLimit,label=PSLim,format=%6.2f \
                 -column=OverLimit \
                 -column=GeometricIntegratedStrength,format=%7.4f,label=GeoStrength \
                 -column=IntegratedStrength,format=%8.4f,label=Strength \
                 -column=Momentum,label=p,format=%8.2f} result] {
        file delete -force $tmpFile 
        return -code error "ViewITSSetpointFile: $result"
    }
    APSFileDisplayWindow [APSUniqueName .] -fileName $tmpFile -deleteOnClose 1 -width 130 \
      -printCommand "enscript -r" -height 30
}

# Restore a setpoint file, either by conditioning or simply setting the currents.

proc RestoreITSSetpointFile1 {args} {
    set sectionDir ""
    set statusCallback APSNoOp
    set condition 1
    APSStrictParseArguments {sectionDir statusCallback condition}

    global setpointsOutputFile
    RestoreITSSetpointFile -fileName $setpointsOutputFile($sectionDir) \
      -statusCallback $statusCallback -condition $condition
}

set conditioningCycles -1
proc RestoreITSSetpointFile {args} {
    global apsITSMagnetsDir apsLTSPSDeviceFile
    set fileName ""
    set statusCallback APSNoOp
    set condition 1
    APSStrictParseArguments {fileName statusCallback condition}

    set action Restore
    if $condition {
        set action Condition
    }
    if [string compare [set outDir [file dirname $fileName]] .]==0 {
        set outDir [pwd]
    }

    eval $statusCallback "Working..."
    if {![string length $fileName] || ![file exists $fileName]} {
        return -code error "RestoreITSSetpointFile: Give a valid filename"
    }
    set tmpRoot /tmp/[APSTmpString]
#    if $condition {
#        APSAddToTmpFileList -ID RestoreITSSetpointFile -fileList $tmpRoot.data
#        if [catch {exec sddsprocess $fileName $tmpRoot.data \
#                     -match=col,ElementName=*Pos,!} result] {
#            return -code error "RestoreITSSetpointFile: $result"
#        }
#        set fileName $tmpRoot.data
#    }

    # Present a dialog to allow choosing which beamlines to restore.
    APSAddToTmpFileList -ID RestoreITSSetpointFile -fileList "$tmpRoot.snap $tmpRoot.snap0 $tmpRoot.snap1 $tmpRoot.snap2 $tmpRoot.dev $tmpRoot.std $tmpRoot.deg"
#    APSAddToTmpFileList -ID RestoreITSSetpointFile -fileList "$tmpRoot.snap $tmpRoot.snap0 $tmpRoot.snap1 $tmpRoot.snap2 $tmpRoot.std $tmpRoot.deg"
    if [catch {exec sddscombine $apsLTSPSDeviceFile -merge $tmpRoot.dev -overwrite} result] {
        APSDeleteTmpFileList -ID RestoreITSSetpointFile
       return -code error "RestoreITSSetpointFile: $result"
    }
    if [catch {exec sddssort $fileName -pipe=out -column=Beamline -unique \
                 | sdds2stream -pipe -column=Beamline} beamlineList] {
        return -code error "RestoreITSSetpointFile: $beamlineList"
    }
    set w [APSUniqueName .]
    APSDialogBox $w -name "$action Dialog" \
      -okCommand "set apsRestoreITSSetpointFile 1" \
      -cancelCommand "set apsRestoreITSSetpointFile 0" 

    global apsRestoreITSSetpointFile 
    set apsRestoreITSSetpointFile -1
    set totalElemList ""
    foreach beamline $beamlineList {
        if [catch {exec sddsprocess $fileName -pipe=out -match=column,Beamline=$beamline \
                     | sddssort -pipe -column=ElementName \
                     | sdds2stream -pipe -column=ElementName} elementList] {
            return -code error "RestoreITSSetpointFile: $elementList"
        }
        set varList ""
        foreach element $elementList {
            global selectedForRestore$element
            set selectedForRestore$element 1
            lappend varList selectedForRestore$element
            lappend totalElemList $element
        }
        APSCheckButtonFrame .cb$beamline -parent $w.userFrame -label "Beamline $beamline: " \
          -orientation horizontal -allNone 1 \
          -variableList $varList -buttonList $elementList
    }

    if $condition {
        # Also, allow choosing the number of conditioning cycles
        global conditioningCycles
        APSLabeledEntry .cycles -parent $w.userFrame -label "Conditioning Cycles (-1=use default)" \
          -textVariable conditioningCycles -width 10 \
          -contextHelp "Enter the number of conditioning cycles.  If 0, then the number of cycles is left at the present value for each supply."
    }
    update
    tkwait variable apsRestoreITSSetpointFile
    if $apsRestoreITSSetpointFile {
        # filter the file to get just the elements of interest
        set restoreList ""
        set matchOptCN ""
        set matchOptEN ""
        set matchOptDN ""
        foreach element $totalElemList {
            if ![set selectedForRestore${element}] continue
            lappend restoreList $element
            if ![string length $matchOptCN] {
                set matchOptCN -match=column,ControlName=${element}*
                set matchOptEN -match=column,ElementName=$element
                set matchOptDN -match=column,DeviceName=$element
            } else {
                set matchOptCN $matchOptCN,ControlName=${element}*,|
                set matchOptEN $matchOptEN,ElementName=$element,|
                set matchOptDN $matchOptDN,DeviceName=$element,|
            }
        }
        if ![string length $matchOptCN] {
            eval $statusCallback {"Choose one or more elements."}
            APSDeleteTmpFileList -ID RestoreITSSetpointFile
            return
        }
        set logParams "$action: [join $outDir $fileName] [join $elementList ,]"
        APSLogScriptAction -procedure RestoreITSSetpointFile -parameters $logParams \
          -action SettingUp -state Ok

        if $condition {
            if [catch {exec sddsprocess $fileName $tmpRoot.snap -delete=column,ControlName \
                         $matchOptEN -nowarning \
                         -print=param,SnapType,Absolute \
                         -print=col,ControlType,pv \
                         -print=col,Lineage,- -define=col,Count,1,type=long} result] {
                APSDeleteTmpFileList -ID RestoreITSSetpointFile
                APSLogScriptAction -procedure RestoreITSSetpointFile -parameters $logParams \
                  -action "Making device list" -state $result
                return -code error "1: $result"
            }
            if [catch {exec sddsprocess $tmpRoot.dev $matchOptDN -nowarning} result] {
                APSDeleteTmpFileList -ID RestoreITSSetpointFile
                APSLogScriptAction -procedure RestoreITSSetpointFile -parameters $logParams \
                  -action "Making device list" -state $result
                return -code error "1.1: $result"
            }

            ## Stop conditioning in case it is running 
            if [catch {exec sddsprocess $tmpRoot.dev -pipe=out \
                         -match=column,Operation=StopConditioning \
                         | sddsxref -pipe=in $tmpRoot.snap $tmpRoot.snap0 -nowarning \
                         -match=DeviceName=ElementName -take=* -transfer=param,*
                exec sddscasr -restore $tmpRoot.snap0} result] {
                APSLogScriptAction -procedure RestoreITSSetpointFile -parameters $logParams \
                  -action "Halting conditioning" -state $result
                APSDeleteTmpFileList -ID RestoreITSSetpointFile
                return -code error "2: $result"
            }
            
            ## Configure
            # Make standardize and degauss files for ITS.  This is for
            # the supplies with standard record names.
            APSMakeInjectorConditioningFile -output $tmpRoot.std -cycles $conditioningCycles \
              -sectorList {LTS}
            if [catch {exec sddsprocess $tmpRoot.std $matchOptCN -nowarning} result] {
                return -code error "4.1: $result"
            }
            APSMakeInjectorConditioningFile -degauss 1 -output $tmpRoot.deg -cycles $conditioningCycles \
              -sectorList {LTS}
            if [catch {exec sddsprocess $tmpRoot.deg $matchOptCN -nowarning} result] {
                return -code error "4.2: $result"
            }

            if [catch {exec sdds2stream -rows=bare $tmpRoot.std} result] {
                APSDeleteTmpFileList -ID RestoreITSSetpointFile
                return -code error "4.3: $result"
            }
exec cp -f $tmpRoot.std /tmp/bob.std
            if {$result!=0 && [catch {exec standardize -configure $tmpRoot.std} result]} {
                APSDeleteTmpFileList -ID RestoreITSSetpointFile
                return -code error "5: $result"
            }
            if [catch {exec sdds2stream -rows=bare $tmpRoot.deg} result] {
                APSDeleteTmpFileList -ID RestoreITSSetpointFile
                return -code error "5.1: $result"
            }
            if {$result!=0 && [catch {exec degauss -configure $tmpRoot.deg} result]} {
                APSDeleteTmpFileList -ID RestoreITSSetpointFile
                return -code error "5.2: $result"
            }
            # Send back conditioning defaults all ITS devices with aberrant conditioning
            # record names
            set conditioningDir /home/helios/OAG/oagData/controlFiles/Linac/conditioning
            if {0} {
                if {[catch {exec sddscasr -restore $conditioningDir/linacConditioning.snap} result]} {
                    APSDeleteTmpFileList -ID RestoreITSSetpointFile
                    return -code error "6: $result"
                }
            }

            # Set the number of conditioning cycles for all devices
            if {$conditioningCycles>=0 && \
                  [catch {exec sddsprocess $tmpRoot.dev -pipe=out \
                            -match=column,Operation=SetConditioningCycles \
                            | sddsxref -pipe $tmpRoot.snap -nowarning \
                            -match=DeviceName=ElementName -take=* -transfer=param,* \
                            | sddsconvert -pipe -dele=col,ValueString \
                            | sddsprocess -pipe=in $tmpRoot.snap0 \
                            -print=col,ValueString,$conditioningCycles
                      exec sddscasr -restore $tmpRoot.snap0} result]} {
                APSDeleteTmpFileList -ID RestoreITSSetpointFile
                return -code error "7: $result"
            }

            ## send new endpoints 
            if [catch {exec sddsprocess $tmpRoot.dev -pipe=out \
                         -dele=col,ValueString \
                         -match=column,Operation=SetConditioningEndpoint \
                         | sddsxref -pipe=in $tmpRoot.snap $tmpRoot.snap1 -nowarning \
                         -match=DeviceName=ElementName -take=* -transfer=param,*
                exec sddscasr -restore $tmpRoot.snap1} result] {
                APSDeleteTmpFileList -ID RestoreITSSetpointFile
                return -code error "8: $result"
            }

            ## start conditioning
            if [catch {exec sddsprocess $tmpRoot.dev -pipe=out \
                         -match=column,Operation=StartConditioning \
                         | sddsxref -pipe=in $tmpRoot.snap $tmpRoot.snap2 -nowarning \
                         -match=DeviceName=ElementName -take=* -transfer=param,*
                exec sddscasr -restore $tmpRoot.snap2} result] {
                APSDeleteTmpFileList -ID RestoreITSSetpointFile
                return -code error "9: $result"
            }

            eval $statusCallback {"Conditioning initiated."}
            APSLogScriptAction -action RestoreITSSetpointFile -parameters $logParams \
              -state conditioning

            set deviceList [exec sdds2stream $tmpRoot.snap -column=ElementName ]
            set conditioning 1
            # wait for conditioning to complete
            set timeStarted [clock format [clock seconds] -format %H:%M:%S]
            while {$conditioning} {
                APSWaitWithUpdate -waitSeconds 15 -updateInterval 1
                eval $statusCallback {"Conditioning (since $timeStarted)..."}
                if [catch {APSDevSend -deviceList $deviceList -operation QueryConditioning \
                             -group PSOps} result] {
                    eval $statusCallback {"Problem checking conditioning status."}
                    return -code error "10: $result"
                }
                set conditioning 0
                foreach item $result {
                    if $item {
                        set conditioning 1
                    }
                }
            }
        }
        APSLogScriptAction -action RestoreITSSetpointFile -parameters $logParams \
          -state restoring
        # restore setpoints (necessary for degaussed supplies, prudent for
        # others).
        eval $statusCallback {"Restoring values."}

        if [catch {exec sddsprocess $fileName $tmpRoot.snap \
                     $matchOptEN \
                     -print=param,SnapType,Absolute \
                     -print=col,ControlType,pv \
                     -print=col,Lineage,- -define=col,Count,1,type=long
            exec sddscasr -restore $tmpRoot.snap} result] {
            APSDeleteTmpFileList -ID RestoreITSSetpointFile
            return -code error "11: $result"
        }
        
        eval $statusCallback {"Restore completed."}
        APSLogScriptAction -action RestoreITSSetpointFile -parameters $logParams \
          -state done
    } else {
        eval $statusCallback {"$action cancelled."}
    }
    APSDeleteTmpFileList -ID RestoreITSSetpointFile
}

proc StopITSConditioning1 {args} {
    set sectionDir ""
    set statusCallback APSNoOp
    APSStrictParseArguments {sectionDir statusCallback}

    global setpointsOutputFile
    StopITSConditioning -fileName $setpointsOutputFile($sectionDir) \
      -statusCallback $statusCallback
}

proc StopITSConditioning {args} {
    global apsITSMagnetsDir apsLTSPSDeviceFile
    set fileName ""
    set statusCallback APSNoOp
    APSStrictParseArguments {fileName statusCallback}

    eval $statusCallback {"Working..."}
    if {![string length $fileName] || ![file exists $fileName]} {
        return -code error "StopITSConditioning: Give a valid filename"
    }
    # Present a dialog to allow choosing which beamlines to restore.
    set tmpRoot /tmp/[APSTmpString]
    APSAddToTmpFileList -ID StopITSConditioning \
       -fileList "$tmpRoot.snap $tmpRoot.snap0"
    if [catch {exec sddscombine $apsLTSPSDeviceFile -merge \
                 $tmpRoot.dev -overwrite} result] {
        APSDeleteTmpFileList -ID StopITSConditioning
        return -code error "StopITSConditioning: $result"
    }
    if [catch {exec sddssort $fileName -pipe=out -column=Beamline -unique \
                 | sdds2stream -pipe -column=Beamline} beamlineList] {
        APSDeleteTmpFileList -ID StopITSConditioning
        return -code error "StopITSConditioning: $beamlineList"
    }
    set w [APSUniqueName .]
    global apsStopConditioning 
    set apsStopConditioning -1
    foreach beamline $beamlineList {
        global ${beamline}SelectedForRestore
        lappend varList  ${beamline}SelectedForRestore
        set ${beamline}SelectedForRestore 1
    }
#    APSDialogBox $w -name "Stop Conditioning Dialog" -okCommand "set apsStopConditioning 1" -cancelCommand "set apsStopConditioning 0" 
#    APSCheckButtonFrame .cb -parent $w.userFrame -label "Choose Beamlines for which to stop conditioning." -limitPerRow 5 -orientation vertical -buttonList $beamlineList -variableList $varList -allNone 1

    set matchOpt ""
    foreach var $varList beamline $beamlineList {
        if ![set $var] continue
        if ![string length $matchOpt] {
            set matchOpt -match=column,Beamline=$beamline
        } else {
            set matchOpt $matchOpt,Beamline=$beamline,|
        }
    }
    if ![string length $matchOpt] {
        eval $statusCallback {"Choose one or more beamlines."}
        APSDeleteTmpFileList -ID StopITSConditioning
        return
    }
    if [catch {exec sddsprocess $fileName $tmpRoot.snap -delete=column,ControlName \
                 $matchOpt \
                 -print=param,SnapType,Absolute \
                 -print=col,ControlType,pv \
                 -print=col,Lineage,- -define=col,Count,1,type=long} result] {
        APSDeleteTmpFileList -ID StopITSConditioning
        return -code error "$result"
    }

    if [catch {exec sddsprocess $tmpRoot.dev -pipe=out \
                 -match=column,Operation=StopConditioning \
                 | sddsxref -pipe=in $tmpRoot.snap $tmpRoot.snap0 -nowarning \
                 -match=DeviceName=ElementName -take=* -transfer=param,*
        exec sddscasr -restore $tmpRoot.snap0 } result] {
        APSDeleteTmpFileList -ID StopITSConditioning
        return -code error "$result"
    }
    APSDeleteTmpFileList -ID StopITSConditioning
    eval $statusCallback {"Conditioning stopped."}
}

proc ControlMomentumBreakPointWidgets {args} {
    set sectionDir ""
    set mode 0
    if [APSStrictParseArguments {sectionDir mode}] {
        return -code error "invalid arguments (UpdateMomentumProfile)"
    }

    global momentumBreakPointWidgetList
    if $mode==1 {
        # enable widgets
        set state normal
        set color black
    } else {
        # disable widgets
        set state disabled
        set color grey
    }
    foreach item $momentumBreakPointWidgetList($sectionDir) {
        $item configure -state $state -foreground $color
    }
}

proc FillTabFrame {widget args} {
    set sectionDir ""
    set accelBreakPointList begin
    APSStrictParseArguments {sectionDir}
    global sectionDirList
    if [set sectionIndex [lsearch -exact $sectionDirList $sectionDir]]==-1 {
        return -code error "Unknown section directory: $sectionDir"
    }

    global latticeDirectory latticeName runRootname mainDir env changeMomentumProfile
    global momentumBreakPointNameList changeMomentum setpointsOutputFile
    global momentumBreakPointValue momentumBreakPointWidgetList

   # set latticeDirectory($sectionDir) $mainDir/2009-0923/$sectionDir
    set latticeName($sectionDir) ""
    set runRootname($sectionDir) transverse
    APSFrame .lattice -parent ${widget} -label "Lattice Selection"
    set w ${widget}.lattice.frame
    APSLabeledEntry .dirname -parent $w -label "Lattice directory" \
        -textVariable latticeDirectory($sectionDir) -width 65 \
        -contextHelp "Directory where lattice subdirectories reside for this beam path."

    APSLabeledEntry .config -parent $w -label "Lattice name" \
      -textVariable latticeName($sectionDir) -width 65 \
      -contextHelp "Subdirectory of lattice directory containing runs for specific configurations."
    APSLabeledEntry .run -parent $w -label "Run rootname" \
      -textVariable runRootname($sectionDir) -width 65 \
      -contextHelp "Rootname for files within the lattice subdirectory that contain the information of interest.  There must be a .param file and a .twi file."
    APSButton .pickConfig -parent $w -text "Pick Lattice" \
      -command "PickLattice -sectionDir $sectionDir" -contextHelp \
      "Pick a lattice name from the lattice directory"
    APSButton .viewConfig -parent $w -text "Plot Lattice " \
      -command "ViewLattice -sectionDir $sectionDir" -contextHelp \
      "Displays plots of Twiss parameters and other information."
    APSButton .viewDetails -parent $w -text "View Details" \
      -command "ViewLattice -sectionDir $sectionDir -details 1 -plots 0" -contextHelp \
      "Displays printouts of lattice data."

    APSFrame .gen -parent ${widget} -label "Setpoints File" 
    set w ${widget}.gen.frame
    set setpointsOutputFile($sectionDir) ""
    set changeMomentum($sectionDir) 0
    set momentumBreakPointNameList($sectionDir) $accelBreakPointList
    set index 0
    set changeMomentum($sectionDir) 0
    foreach item {begin} {
        set momentumBreakPointValue($sectionDir,$item) 0
    }
    set momentumBreakPointWidgetList($sectionDir) ""
    foreach item $accelBreakPointList {
        APSLabeledEntry .lebp$index -parent $w \
          -label "Momentum after $item (MeV/c): " \
          -textVariable momentumBreakPointValue($sectionDir,$item) 
        lappend momentumBreakPointWidgetList($sectionDir) $w.lebp$index.entry
        $w.lebp$index.entry configure -state disabled
        incr index
    }
    ControlMomentumBreakPointWidgets -sectionDir $sectionDir -mode 0
    APSRadioButtonFrame .chmorb -parent $w -label "Change momentum profile? " \
      -orientation horizontal -variable changeMomentum($sectionDir) \
      -valueList "1 0" -buttonList "Yes No" \
      -commandList [list "ControlMomentumBreakPointWidgets -sectionDir $sectionDir -mode 1" \
                      "ControlMomentumBreakPointWidgets -sectionDir $sectionDir -mode 0"]
    APSLabeledEntry .spfile -parent $w -label "Filename" \
      -textVariable setpointsOutputFile($sectionDir) -width 75 \
      -contextHelp "Enter the name of the file to which you want the setpoints data written."
    APSFrame .bf1 -parent $w -relief flat
    set w1 $w.bf1.frame
    APSButton .makename -parent $w1 -text "Make filename" \
      -contextHelp "Creates a filename suitable for the lattice chosen.  Also creates the daily directory." \
      -command "MakeFilename -sectionDir $sectionDir"
    APSButton .gen -parent $w1 -text "Generate" \
      -contextHelp "Generate a file with power supply setpoints." \
      -command \
      "APSSetVarAndUpdate status Working...; \
          GenerateITSSetpointFile1 -sectionDir $sectionDir; \
          APSSetVarAndUpdate status Done."
    if [string compare $env(USER) borland]==0 {
        APSButton .gen1 -parent $w1 -text "Generate all" \
          -contextHelp "Generate a file with power supply setpoints, \
even for PS that aren't in the device config file." \
          -command \
          "APSSetVarAndUpdate status Working...;\
              GenerateITSSetpointFile1 -sectionDir $sectionDir -convertAll 1;\
              APSSetVarAndUpdate status Done."
    }
    APSButton .view -parent $w1 -text "View" \
      -contextHelp "View the contents of the power supply setpoints file." \
      -command "ViewITSSetpointFile -sectionDir $sectionDir"
    
    APSFrame .bf2 -parent $w -relief flat
    set w2 $w.bf2.frame
    APSButton .restore -parent $w2 -text "Restore..." \
      -contextHelp "Restore part or all of the power supply setpoints file." \
      -command "RestoreITSSetpointFile1 -sectionDir $sectionDir \
                  -statusCallback setStatus -condition 0"
    APSButton .condition -parent $w2 -text "Condition..." \
      -contextHelp "Condition to part or all of the power supply setpoints file." \
      -command "RestoreITSSetpointFile1 -sectionDir $sectionDir \
                  -statusCallback setStatus -condition 1"
    APSButton .stopCondition -parent $w2 -text "Stop conditioning" \
      -contextHelp "Stop conditioning of the power supplies listed in the setpoints file." \
     -command "StopITSConditioning1 -sectionDir $sectionDir \
                 -statusCallback setStatus"
}


#set sectionList [list RG2>L3FS5 PCG>L3FS5 L3FS5>PBC1 FS9>PAR LTPEA PAR>Booster PBC1>Booster PBC1>Und PAR/LEUTL]
#set sectionDirList [list RG2_L3FS5 L1O_L3FS5 L3FS5_PBC1 FS9_PAR LTPEA PAR_BIS PBC1_BIS PBC1_UNDO PAR_LEUTL_IL]
set sectionList [list RTG>FL2 RTG>SLFC PCGUN_FL2 PCGUN_SLFC]
set sectionDirList [list RTG_FL2 RTG_SLFC PCGUN_FL2 PCGUN_SLFC]

foreach item $sectionDirList {
    lappend sectionCommandList "APSSetVarAndUpdate beamlineSection $item"
    if [regexp {PCGUN} $item] {
        set latticeDirectory($item) $mainDir/2013-1002/$item
    } else {
        set latticeDirectory($item) $mainDir/2009-0923/$item
    }
    set latticeName($item) ""
    set runRootname($item) transverse
}

set tabFrameWidgetList [APSTabFrame .main -parent .userFrame -label "" \
    -labelList $sectionList -commandList $sectionCommandList \
    -width 800 -height 400]

foreach tabFrame $tabFrameWidgetList sectionDir $sectionDirList {
    FillTabFrame $tabFrame -sectionDir $sectionDir
}

setStatus "Working..."
update
set devFile /tmp/[APSTmpString]
APSAddToTempFileList $devFile
exec sddscombine $apsLTSPSDeviceFile -merge -overwrite $devFile
APSLinkToDevicePVs -fileList $devFile
setStatus "Ready."
update

