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

APSApplication . -name GenerateLinacQuadSetpoints \
  -overview "Converts an elegant lattice to current setpoints for LINAC to LEUTL quadrupoles.  You must supply a parameters file and either a centroid or twiss file."
set status ""
APSScrolledStatus .status -parent .userFrame -textVariable status -height 10 -width 60

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 apsLinacMagnetsDir /home/helios/oagData/linac/magnets/
set mainDir $OAGGlobal(LinacLatticesDirectory)/default/
# set mainDir /home/oxygen/BORLAND/aps/bunchComp/VaryL3/optics7.0

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 {L1 L2 L3 L4 L5 LTP PB PTB BB LU LA LS}
    if ![llength $sectorList] {
        set sectorList $knownSectorList
    }

    if !$degauss {
        set fileToUse(L1) ""
        set fileToUse(L2) /home/helios/oagData/controlFiles/Linac/conditioning/Linac.stdTo0
        set fileToUse(L3) /home/helios/oagData/controlFiles/Linac/conditioning/Linac.stdTo0
        set fileToUse(L4) /home/helios/oagData/controlFiles/Linac/conditioning/Linac.stdTo0
        set fileToUse(L5) /home/helios/oagData/controlFiles/Linac/conditioning/Linac.stdTo0
        set fileToUse(LTP) /home/helios/oagData/controlFiles/LTP/LTP.stdTo0
        set fileToUse(PTB) /home/helios/oagData/controlFiles/PTB/PTB.stdTo0
        set fileToUse(PB)  /home/helios/oagData/controlFiles/LEUTL/LEUTL.std
        set fileToUse(BB)  /home/helios/oagData/controlFiles/LEUTL/LEUTL.std
        set fileToUse(LA)  /home/helios/oagData/controlFiles/LEUTL/LEUTL.std
        set fileToUse(LU)  /home/helios/oagData/controlFiles/LEUTL/LEUTL.std
        set fileToUse(LS)  /home/helios/oagData/controlFiles/LEUTL/LEUTL.std
    } else {
        set fileToUse(L1) ""
        set fileToUse(L2) ""
        set fileToUse(L3) ""
        set fileToUse(L4) ""
        set fileToUse(L5) ""
        set fileToUse(LTP) /home/helios/oagData/controlFiles/LTP/LTP_degauss.sdds
        set fileToUse(PTB) /home/helios/oagData/controlFiles/PTB/PTB_degauss.sdds
        set fileToUse(PB)  /home/helios/oagData/controlFiles/LEUTL/LEUTL_degauss.sdds
        set fileToUse(BB)  /home/helios/oagData/controlFiles/LEUTL/LEUTL_degauss.sdds
        set fileToUse(LA)  ""
        set fileToUse(LU)  ""
        set fileToUse(LS)  /home/helios/oagData/controlFiles/LEUTL/LEUTL_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 \
                      -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"
    }
}

# Sets the momentum profile to a default value for a given beam source

proc SetDefaultMomentumProfile {args} {
    global MomentumL1 MomentumL2 MomentumL4 MomentumL5 latticeDirectory latticeName mainDir
    set source ""
    set target ""
    APSStrictParseArguments {source target}
    set latticeDirectory $mainDir/$source
    set latticeDirectory $latticeDirectory/$target
    set latticeName ""
    switch $source {
        PCGun -
        PB {
            set MomentumL1 42
            set MomentumL2 135
            set MomentumL4 217
            set MomentumL5 217
        }
        RG1 -
        RG2 {
            set MomentumL1 2.8
            set MomentumL2 160
            set MomentumL4 325
            set MomentumL5 325
        }
    }
}

# Allows picking a specific lattice file from those available for a given source

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

# Allows viewing lattice functions

proc ViewLattice {} {
    global latticeDirectory latticeName runRootname
    if {![file exists $latticeDirectory] || ![file isdirectory $latticeDirectory]} {
        return -code error "$latticeDirectory not found or not a directory"
    }
    if ![string length $latticeName] {
        return -code error "No lattice chosen."
    }
    set rootname $latticeDirectory/$latticeName/$runRootname
    if ![file exists $rootname.twi] {
        return -code error "Not found: $rootname.twi"
    }
    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 -yscale=id=2 -column=s,beta* -legend=ysymbol 
    lappend plotOptions -unsup=y -zoom=yfac=0.87,qcent=0.53 $rootname.twi -yscale=id=1 
        if [file exists $rootname.sig] {
        lappend plotOptions -end -column=s,Sx -column=s,Sy -legend=ysymbol -unsup=y 
        lappend plotOptions -zoom=yfac=0.87,qcent=0.53 $rootname.sig -yscale=id=4 -column=s,pCentral0 
        lappend plotOptions -legend=spec=p -unsup=y -factor=yMultiplier=0.511 "-ylabel=p (MeV/c)" -zoom=yfac=0.87,qcent=0.53 
        lappend plotOptions $rootname.twi -yscale=id=3 -end 
    }
    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 and beam sizes..."
    foreach exten {hrm vrm} plane {Horizontal Vertical} {
        set filename $latticeDirectory/$latticeName/$runRootname.$exten
        if ![file exists $filename] {
            setStatus "Not found: [file tail $filename]"
            continue
        }
        setStatus "Plotting $plane response matrices..."
        exec sddsplot $filename -graph=sym,connect -separate \
          "-title=$plane response matrix for $rootname" \
          -column=BPMName,*:* &
    }
    set flagOptionList ""
    foreach exten {LI:FL:FS1 LI:FL:S1C1 LI:FL:S1C2 L3:FS1 L3:FS4 LI:FL:FS4 \
                     LI:FL:FS5 LI:FL:FS6 LI:FL:FS7 LI:FL:FS8 LI:FL:FS9 PB:FL:C1} {
        if [file exists $latticeDirectory/$latticeName/$runRootname.$exten] {
            lappend flagOptionList -column=x,y -title=$exten 
            lappend flagOptionList $latticeDirectory/$latticeName/$runRootname.$exten
        }
    }
    if [llength $flagOptionList] {
        setStatus "Plotting flag images..." 
        eval exec sddsplot -aspect=1 -graph=dot -presparse=10 -separate -same=global $flagOptionList &
    }
}

# Searches for a lattice file that matches a given momentum profile and source

proc FindLattice {} {
    global MomentumL1 MomentumL2 MomentumL4 MomentumL5 beamSource beamTarget
    global latticeDirectory latticeName runRootname
    if {![file exists $latticeDirectory] || ![file isdirectory $latticeDirectory]} {
        return -code error "$latticeDirectory not found or not a directory"
    }
    set oldDir [pwd]
    cd $latticeDirectory
    set latticeList [lsort [glob -nocomplain $MomentumL2+$MomentumL4+$MomentumL5*]]
    if ![llength $latticeList] {
        APSSetVarAndUpdate status "No match for that momentum profile. (1)"
        cd $oldDir
        return
    }
    set lattice ""
    foreach lattice0 $latticeList {
        if ![file isdirectory $lattice0] continue
        if {![file exists $lattice0/$runRootname.param] || \
              !([file exists $lattice0/$runRootname.twi] || [file exists $lattice0/$runRootname.cen])} {
            continue
        }
        set lattice $lattice0
        break
    }
    if ![string length $lattice] {
        APSSetVarAndUpdate status "No match for that momentum profile. (2)"
        cd $oldDir
        return
    }
    set latticeName $lattice
    cd $oldDir
}

# Finds main or trim current for L3:BMs

proc FindL3BMCurrent {args} {
    set element ""
    set angle 0
    set momentum 0
    set trimForCurrent 0
    APSStrictParseArguments {element angle momentum trimForCurrent}
    global apsLinacMagnetsDir

    # momentum is beta*gamma 
    set BRho [expr $momentum*0.001704509390960]
    set BLNeeded [expr $angle*$BRho]

    #APSSetVarAndUpdate status "FindL3BMCurrent: Element=$element, angle=$angle, momentum=$momentum"
    #APSSetVarAndUpdate status "  BRho = $BRho   BLNeeded=$BLNeeded"

    set data $apsLinacMagnetsDir/${element}.prop
    set excitation $apsLinacMagnetsDir/${element}.excitation

    if $trimForCurrent<=0 {
        # This is a magnet without a trim.
        # Find current for which B(I)*LEffective(I,angle) = BRho*angle

        if ![file exists $data] {
            return -code error "Not found: $data"
        }
        if ![file exists $excitation] {
            return -code error "Not found: $excitation"
        }

        set tmpRoot /tmp/[APSTmpString]
        APSAddToTmpFileList -ID FindL3BMCurrent -fileList "$tmpRoot.1 $tmpRoot.2 $tmpRoot.3"
        
        switch $element {
            L3:BM1 -
            L3:BM2 {
                set PSName L3:BM:US
            }
            L3:BM3 -
            L3:BM4 {
                set PSName L3:BM:DS
            }
            default {
                return -code error "Not found: $element"
            }
        }

        if [catch {exec sddscombine -merge $data -pipe=out \
                     | sddssort -pipe -column=B0 -column=angle \
                     | sddsbreak -pipe -change=B0 \
                     | sddsinterp -pipe -column=angle,B0,LEffective -atValue=$angle \
                     | sddscombine -merge -pipe \
                     | sddssort -column=B0 -pipe=in $tmpRoot.1} result] {
            return -code error "$result"
        }
        if [catch {exec sddsprocess $tmpRoot.1 -process=LEffective,ave,%sAve -pipe=out \
                     | sdds2stream -pipe -parameter=LEffectiveAve} L] {
            return -code error "$L"
        }
        set tries 5
        while {$tries} {
            set B [expr $BLNeeded/$L]
            if [catch {exec sddsinterp $tmpRoot.1 -atValue=$B -column=B0,LEffective -pipe=out \
                         | sdds2stream -column=LEffective -pipe} L] {
                return -code error "$L"
            }
            set dBL [expr $BLNeeded-$B*$L]
            if [expr abs($dBL)<1e-10] {
                break
            }
            incr tries -1
        }
        if $tries==0 {
            set percentError [expr 100.0*$dBL/$BLNeeded]
            APSSetVarAndUpdate status "Warning: convergence error of [format %.3g $percentError] % for $element"
        }
        if [catch {exec sddsinterp $excitation /dev/null -atValue=$B \
                     -column=B,Current -print=bare,stdout} result] {
            return -code error "$result"
        }
        set IMMF [lindex $result 1]
        # Now that I have the MMF current, compute the CurrentAO.
        if [catch {exec sddsprocess $apsLinacMagnetsDir/PSCal.sdds -pipe=out -match=col,PSName=$PSName \
                     | sdds2stream -column=CalSlope,CalIntercept -pipe} result] {
            return -code error "$result"
        }
        APSSetVarsFromList -variableList {Slope Intercept} -valueList $result
        set CurrentAO [expr $IMMF*$Slope+$Intercept]
        # APSSetVarAndUpdate status "CurrentAO = $CurrentAO   IMMF = $IMMF"
        return [list $CurrentAO $IMMF]
    } else {
        # This magnet has a trim, for which I calculate the setpoint here.
        # 1. Find BL for the main current and angle (both passed as argument).
        # 2. Find trim current to get the desired B*L
        if [catch {exec sddsinterp $excitation /dev/null -atValue=$trimForCurrent \
                     -column=Current,B -print=bare,stdout} result] {
            return -code error "$result"
        }
        set BMain [lindex $result 1]
        if [catch {exec sddscombine -merge $data -pipe=out \
                     | sddssort -pipe -column=B0 -column=angle \
                     | sddsbreak -pipe -change=B0 \
                     | sddsinterp -pipe -column=angle,B0,LEffective -atValue=$angle \
                     | sddscombine -merge -pipe \
                     | sddssort -column=B0 -pipe \
                     | sddsinterp -pipe -column=B0,LEffective -atValue=$BMain \
                     | sdds2stream -pipe -column=LEffective} result] {
            return -code error "$result"
        }
        set LEffective $result
        # APSSetVarAndUpdate status "BMain = $BMain   L = $LEffective   BLMain = [expr $BMain*$LEffective]   MainCurrent=$trimForCurrent"
        set dB [expr (abs($BLNeeded)-abs($BMain*$LEffective))/$LEffective]
        # APSSetVarAndUpdate status "dB = $dB"
        if [catch {exec sddsinterp $apsLinacMagnetsDir/L3:BMT.calibration -pipe=out \
                     -column=MainCurrent,Slope -atValue=$trimForCurrent \
                     -above=extrap -below=extrap \
                     | sdds2stream -pipe -column=Slope} slope] {
            return -code error "$slope"
        }
        # APSSetVarAndUpdate status "slope = $slope"
        return [expr $dB/$slope]
    }
}

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

proc GenerateLinacSetpointFile {args} {
    set latticeDirectory ""
    set latticeName ""
    set runRootname full
    set output ""
    set MomentumL1 0
    set MomentumL2 0
    set MomentumL4 0
    set MomentumL5 0
    set convertAll 0
    APSStrictParseArguments {latticeDirectory latticeName runRootname \
                               output convertAll MomentumL1 \
                               MomentumL2 MomentumL4 MomentumL5}

    global apsLinacMagnetsDir apsLinacPSDeviceFile apsLEUTLPSDeviceFile

    if ![string length $output] {
        return -code error "No output filename given"
    }
    if {[string length [set dirname [file dirname $output]]] && ![file exists $dirname]} {
        return -code error "Directory $dirname does not exist"
    }
    
    # Decide whether the lattice needs to be rescaled to the specified momentum profile
    # and ask user whether to do this.
    set tmpRoot /tmp/[APSTmpString]
    set rescale [APSMultipleChoice [APSUniqueName .] \
                   -question "Rescale $latticeName to match above profile, or use as-is?  Rescaling without acceleration will rescale all settings to the post-L5 level given above.  Rescaling with acceleration assumes your configuration extends from the alpha-magnet area to after L5." \
                   -labelList {"Rescale w/acceleration" "Rescale w/o acceleration" "Use As-Is" Abort} -returnList {rwa rwoa uai abort} \
                   -contextHelp "To rescale the lattice to match the acceleration profile you've given, press Rescale.  Otherwise, press As-Is."]
    if [string compare $rescale "abort"]==0 {
        return
    }

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

    set logParams \
      "generate $latticeDirectory/$latticeName/$runRootname->[file join $outputDir $output] $rescale" 
    APSLogScriptAction -procedure GenerateLinacSetpointFile \
      -parameters $logParams -action Start -state Ok

    switch $rescale {
        uai {
            # Find file giving the momentum at each element
            if [file exists $latticeDirectory/$latticeName/$runRootname.cen] {
                set EProfileFile $latticeDirectory/$latticeName/$runRootname.cen
                set pCentralColumn pCentral 
            } elseif [file exists $latticeDirectory/$latticeName/$runRootname.twi] {
                set EProfileFile $latticeDirectory/$latticeName/$runRootname.twi
                set pCentralColumn pCentral0
            } else {
                APSLogScriptAction -procedure GenerateLinacSetpointFile \
                  -parameters "$logParams" \
                  -state "Didn't find .twi or .cen file for $latticeDirectory/$latticeName/$runRootname" \
                  -action RescalingUAI
                return -code error "Didn't find .twi or .cen file for $latticeDirectory/$latticeName/$runRootname"
            }
            set paramFile $latticeDirectory/$latticeName/$runRootname.param
        }
        rwoa {
            # Find file giving the momentum at each element
            if [file exists $latticeDirectory/$latticeName/$runRootname.cen] {
                set EProfileFile $latticeDirectory/$latticeName/$runRootname.cen
                set pCentralColumn pCentral 
            } elseif [file exists $latticeDirectory/$latticeName/$runRootname.twi] {
                set EProfileFile $latticeDirectory/$latticeName/$runRootname.twi
                set pCentralColumn pCentral0
            } else {
                APSLogScriptAction -procedure GenerateLinacSetpointFile \
                  -parameters "$logParams" \
                  -state "Didn't find .twi or .cen file for $latticeDirectory/$latticeName/$runRootname" \
                  -action RescalingRWOA
                return -code error "Didn't find .twi or .cen file for $latticeDirectory/$latticeName/$runRootname"
            }
            set paramFile $latticeDirectory/$latticeName/$runRootname.param
            APSAddToTmpFileList -ID GenerateLinacSetpointFile -fileList $tmpRoot.pcenmod
            exec sddsprocess $EProfileFile $tmpRoot.pcenmod \
              -redefine=column,$pCentralColumn,[expr $MomentumL5/0.51099906]
            set EProfileFile $tmpRoot.pcenmod
        }
        rwa {
            # Run elegant in order to get the momentum at each element, given
            # the momentum after each linac.
            if {![file exists $latticeDirectory/EProfileTemplate.ele] || \
                  ![file exist $latticeDirectory/EProfile.lte]} {
                APSLogScriptAction -procedure GenerateLinacSetpointFile \
                  -parameters "$logParams" \
                  -state "EProfileTemplate files missing from $latticeDirectory" \
                  -action RescalingRWA
                return -code error "GenerateLinacSetpointFile: EProfileTemplate files missing from $latticeDirectory"
            }
            APSAddToTmpFileList -ID GenerateLinacSetpointFile -fileList "$tmpRoot.ele $tmpRoot.cen $tmpRoot.log $tmpRoot.lte"
            set pCentral [expr $MomentumL1/0.51099906]
            set L2V [expr ($MomentumL2-$MomentumL1)*1e6/4.0]
            set L4V [expr ($MomentumL4-$MomentumL2)*1e6/4.0]
            set L5V [expr ($MomentumL5-$MomentumL4)*1e6/4.0]
            set oldDir [pwd]
            cd /tmp
            if [catch {exec replaceText $latticeDirectory/EProfileTemplate.ele \
                         $tmpRoot.ele \
                         -original=<lattice>,<pCentral>,<L2V>,<L4V>,<L5V> \
                         -replace=$tmpRoot.lte,$pCentral,$L2V,$L4V,$L5V 
                file copy $latticeDirectory/EProfile.lte $tmpRoot.lte 
                exec elegant $tmpRoot.ele > $tmpRoot.log} result] {
                APSDeleteTmpFileList -ID GenerateLinacSetpointFile 
                APSLogScriptAction -procedure GenerateLinacSetpointFile \
                  -parameters "$logParams" \
                  -state "$result" \
                  -action Rescaling
                return -code error "GenerateLinacSetpointFile: $result"
            }
            cd $oldDir
            set runRootname [file tail $tmpRoot]
            set paramFile $tmpRoot.param
            set pCentralColumn pCentral
            set EProfileFile $tmpRoot.cen
        }
    }
    
    APSLogScriptAction -procedure GenerateLinacSetpointFile -parameters $logParams \
      -action Rescaling$rescale -state Ok

    # 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 GenerateLinacSetpointFile \
       -fileList "$tmpRoot.K1 $tmpRoot.ANGLE $tmpRoot.B1L $tmpRoot.beamlines $tmpRoot.CN $tmpRoot.dev"
    APSAddToTmpFileList -ID GenerateLinacSetpointFile -fileList "$tmpRoot.K1L $tmpRoot.GS $tmpRoot.alpha"
    APSAddToTmpFileList -ID GenerateLinacSetpointFile -fileList "$tmpRoot.res0 $tmpRoot.res1 $tmpRoot.res2"
    if $convertAll {
        set xrefExtraOpt -fillIn
    } else {
        set xrefExtraOpt -nowarning
    }        
    if [catch {exec sddscombine $apsLinacPSDeviceFile $apsLEUTLPSDeviceFile -merge \
                 $tmpRoot.dev -overwrite} result] {
        APSDeleteTmpFileList -ID GenerateLinacSetpointFile
        APSLogScriptAction -procedure GenerateLinacSetpointFile \
          -parameters "$logParams" \
          -state "$result" -action Combining
        return -code error "GenerateLinacSetpointFile: $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 $tmpRoot.dev $tmpRoot.CN -match=col,Operation=SetCurrent 
        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 $EProfileFile -take=$pCentralColumn -match=ElementName \
                 | sddsprocess -pipe \
                 "-define=column,IntegratedStrength,GeometricIntegratedStrength $pCentralColumn * 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=$pCentralColumn,ave,pCentral \
                 | sddscollapse -pipe \
                 | sddsxref -pipe $apsLinacMagnetsDir/crossReference.sdds -nowarning \
                 -match=ElementName -take=*  \
                 | sddsxref -pipe $tmpRoot.CN -match=ElementName=DeviceName -take=ControlName \
                    -nowarning $xrefExtraOpt \
                 | sddsprocess -pipe \
                 "-redefine=column,IntegratedStrength,IntegratedStrength BnLMultiplier * Sign *,units=T" \
                 -print=column,ExcitationFile,$apsLinacMagnetsDir/%s.excitation,ElementName \
                 "-print=column,InterpCommand,sddsinterp -at=%21.15e %s /dev/null -column=IntegratedStrength\\\,Current -print=bare\\\,stdout -aboveRange=extrapolate -belowRange=value=0 | token -last,IntegratedStrength,ExcitationFile" \
                 -system=column,ValueString,InterpCommand \
                 -scan=column,Current,ValueString,%lf,type=double,units=A \
                 "-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 GenerateLinacSetpointFile 
        APSLogScriptAction -procedure GenerateLinacSetpointFile -parameters $logParams \
          -action Calibrating -state "$result"
        return -code error "GenerateLinacSetpointFile: $result"
    }
    set output0 $tmpRoot.res0
    # See if L3:BM* magnets are there.  If so, need to refine the calculation for these magnets.
    # Also, compute trim strengths.
    if [exec sddsprocess -nowarning $tmpRoot.res0 -pipe=out -match=col,ElementName=L3:BM* \
          | tee $tmpRoot.res1 | sdds2stream -rows=bare -pipe] {
        if [catch {exec sddsprocess $tmpRoot.res0 $tmpRoot.res2 -match=col,ElementName=L3:BM*,!
                sdds load $tmpRoot.res1 L3BMData} result] {
            APSLogScriptAction -procedure GenerateLinacSetpointFile \
              -parameters "$logParams" -state $result \
              -action CalibratingL3:BMs 
            return -code error "GenerateLinacSetpointFile: $result"
        }
        foreach element {L3:BM1 L3:BM2 L3:BM3 L3:BM4} {
            set index [lsearch [lindex $L3BMData(Column.ElementName) 0] $element]
            if $index==-1 {
                APSLogScriptAction -procedure GenerateLinacSetpointFile \
                  -parameters "$logParams" -state "Missing one or more L3:BM* elements." \
                  -action Calibrating$element
                return -code error "GenerateLinacSetpointFile: Missing one or more L3:BM* elements."
            }
            set strength [lindex [lindex $L3BMData(Column.GeometricIntegratedStrength) 0] $index]
            set pCentral [lindex [lindex $L3BMData(Column.pCentral) 0] $index]
            switch $element {
                L3:BM1 {
                    set dataList [FindL3BMCurrent -element $element -angle $strength \
                                             -momentum $pCentral]
                    set current(L3:BM:US) [lindex $dataList 0]
                    set current(L3:BM:USForTrim) [lindex $dataList 1]
                }
                L3:BM3 {
                    set dataList [FindL3BMCurrent -element $element -angle $strength \
                                    -momentum $pCentral]
                    set current(L3:BM:DS) [lindex $dataList 0]
                    set current(L3:BM:DSForTrim) [lindex $dataList 1]
                }
                L3:BM2 {
                    set current(L3:BM2T) [FindL3BMCurrent -element $element -angle $strength \
                                            -momentum $pCentral -trimForCurrent $current(L3:BM:USForTrim)]
                }
                L3:BM4 {
                    set current(L3:BM4T) [FindL3BMCurrent -element $element -angle $strength \
                                            -momentum $pCentral -trimForCurrent $current(L3:BM:DSForTrim)]
                }
            }
        }
        set L3BMOut(ColumnNames) $L3BMData(ColumnNames)
        foreach item $L3BMOut(ColumnNames) {
            set L3BMOut(ColumnInfo.$item) $L3BMData(ColumnInfo.$item)
            switch $item {
                Current -
                ValueString {
                    set L3BMOut(Column.$item) [list [list $current(L3:BM:US) $current(L3:BM2T) $current(L3:BM:DS) \
                                                         $current(L3:BM4T)] ]
                }
                ControlName {
                    set L3BMOut(Column.ControlName) [list {L3:BM:US:CurrentAO L3:BM2T:CurrentAO \
                                                              L3:BM:DS:CurrentAO L3:BM4T:CurrentAO}]
                }
                default {
                    set L3BMOut(Column.$item) $L3BMData(Column.$item)
                }
            }
        }
        if [catch {sdds save $tmpRoot.res1 L3BMOut
            exec sddscombine $tmpRoot.res2 $tmpRoot.res1 -merge -pipe=out \
                     | sddsprocess -pipe=in $output \
                     "-redefine=column,OverLimit,Current abs SupplyLimit > ? 1 : 0 \$ ,type=long" } result] {
            APSLogScriptAction -procedure GenerateLinacSetpointFile -parameters "$logParams" \
              -state $result" -action Combining(2)
            return -code error "GenerateLinacSetpointFile: $result"
        }
    } else {
        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 GenerateLinacSetpointFile 
    APSLogScriptAction -procedure GenerateLinacSetpointFile -parameters $logParams \
      -action Finish -state Ok
}

# Reviews data in a previously generated setpoint file

proc ViewLinacSetpointFile {args} {
    set fileName ""
    APSStrictParseArguments {fileName}
    
    if {![string length $fileName] || ![file exists $fileName]} {
        return -code error "ViewLinacSetpointFile: Give a valid filename"
    }
    set tmpFile /tmp/[APSTmpString].printout
    if [catch {exec sddsprintout $fileName $tmpFile -column=ControlName,format=%26s \
                -column=ElementName,format=%8s \
                 -column=Beamline,format=%8s -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 "ViewLinacSetpointFile: $result"
    }
    APSFileDisplayWindow [APSUniqueName .] -fileName $tmpFile -deleteOnClose 1 -width 120 \
      -printCommand "enscript -r"
}

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

set conditioningCycles 0
proc RestoreLinacSetpointFile {args} {
    global apsLinacMagnetsDir apsLinacPSDeviceFile apsLEUTLPSDeviceFile
    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 "RestoreLinacSetpointFile: Give a valid filename"
    }
    # Present a dialog to allow choosing which beamlines to restore.
    set tmpRoot /tmp/[APSTmpString]
    # APSAddToTmpFileList -ID RestoreLinacSetpointFile -fileList "$tmpRoot.snap $tmpRoot.snap0 $tmpRoot.snap1 $tmpRoot.snap2 $tmpRoot.dev $tmpRoot.std $tmpRoot.deg $tmpRoot.L3BMT"
    if [catch {exec sddscombine $apsLinacPSDeviceFile $apsLEUTLPSDeviceFile -merge \
                 $tmpRoot.dev -overwrite} result] {
        APSDeleteTmpFileList -ID RestoreLinacSetpointFile
       return -code error "RestoreLinacSetpointFile: $result"
    }
    if [catch {exec sddssort $fileName -pipe=out -column=Beamline -unique \
                 | sdds2stream -pipe -column=Beamline} beamlineList] {
        return -code error "RestoreLinacSetpointFile: $beamlineList"
    }
    set w [APSUniqueName .]
    APSDialogBox $w -name "$action Dialog" \
      -okCommand "set apsRestoreLinacSetpointFile 1" \
      -cancelCommand "set apsRestoreLinacSetpointFile 0" 

    global apsRestoreLinacSetpointFile 
    set apsRestoreLinacSetpointFile -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 "RestoreLinacSetpointFile: $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 (0=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 apsRestoreLinacSetpointFile
    if $apsRestoreLinacSetpointFile {
        # 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 RestoreLinacSetpointFile
            return
        }
        set logParams "$action: [join $outDir $fileName] [join $elementList ,]"
        APSLogScriptAction -procedure RestoreLinacSetpointFile -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 RestoreLinacSetpointFile
                APSLogScriptAction -procedure RestoreLinacSetpointFile -parameters $logParams \
                  -action "Making device list" -state $result
                return -code error "1: $result"
            }
            if [catch {exec sddsprocess $tmpRoot.dev $matchOptDN -nowarning} result] {
                APSDeleteTmpFileList -ID RestoreLinacSetpointFile
                APSLogScriptAction -procedure RestoreLinacSetpointFile -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 RestoreLinacSetpointFile -parameters $logParams \
                  -action "Halting conditioning" -state $result
                APSDeleteTmpFileList -ID RestoreLinacSetpointFile
                return -code error "2: $result"
            }
            if {[lsearch -exact $totalElemList L3:BM2]!=-1 || \
                  [lsearch -exact $totalElemList L3:BM4]!=-1} {
                ## set the dipole trims
                if [catch {exec sddsprocess $fileName $tmpRoot.L3BMT \
                             $matchOptEN \
                             -print=param,SnapType,Absolute \
                             -print=col,ControlType,pv \
                             -print=col,Lineage,- -define=col,Count,1,type=long \
                             -match=col,ControlName=L3:BM?T* -nowarning} result] {
                    APSLogScriptAction -procedure RestoreLinacSetpointFile -parameters $logParams \
                      -action "Setting dipole trims" -state $result
                    APSDeleteTmpFileList -ID RestoreLinacSetpointFile
                    return -code error "3: $result"
                }
                if {[exec sdds2stream -rows=bare $tmpRoot.L3BMT]!=0 && \
                      [catch {exec sddscasr -restore $tmpRoot.L3BMT} result]} {
                    APSDeleteTmpFileList -ID RestoreLinacSetpointFile
                    APSLogScriptAction -procedure RestoreLinacSetpointFile -parameters $logParams \
                      -action "Setting dipole trims" -state $result
                    return -code error "4: $result"
                }
            }

            ## Configure
            # Make standardize and degauss files for Linac->LEUTL.  This is for
            # the supplies with standard record names.
            APSMakeInjectorConditioningFile -output $tmpRoot.std -cycles $conditioningCycles \
              -sectorList {L1 L2 L3 L4 L5 LTP PB PTB BB LU LA LS}
            if [catch {exec sddsprocess $tmpRoot.std $matchOptCN -nowarning} result] {
                return -code error "4.1: $result"
            }
            APSMakeInjectorConditioningFile -degauss 1 -output $tmpRoot.deg -cycles $conditioningCycles \
              -sectorList {L1 L2 L3 L4 L5 LTP PB PTB BB LU LA LS}
            if [catch {exec sddsprocess $tmpRoot.deg $matchOptCN -nowarning} result] {
                return -code error "4.2: $result"
            }

            if [catch {exec standardize -configure $tmpRoot.std} result] {
                APSDeleteTmpFileList -ID RestoreLinacSetpointFile
                return -code error "5: $result"
            }
            # Send back conditioning defaults all linac devices with aberrant conditioning
            # record names
            set conditioningDir /home/helios/OAG/oagData/controlFiles/Linac/conditioning
            if {[catch {exec sddscasr -restore $conditioningDir/linacConditioning.snap} result]} {
                APSDeleteTmpFileList -ID RestoreLinacSetpointFile
                return -code error "6: $result"
            }
            # Set the number of conditioning cycles for all devices
            if {$conditioningCycles && \
                  [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 RestoreLinacSetpointFile
                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 RestoreLinacSetpointFile
                return -code error "8: $result"
            }

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

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

            set deviceList [exec sdds2stream -column=ElementName $tmpRoot.snap]
            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 LinacPS} 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 RestoreLinacSetpointFile -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 RestoreLinacSetpointFile
            return -code error "11: $result"
        }
        eval $statusCallback {"Restore completed."}
        APSLogScriptAction -action RestoreLinacSetpointFile -parameters $logParams \
          -state done
    } else {
        eval $statusCallback {"$action cancelled."}
    }
    APSDeleteTmpFileList -ID RestoreLinacSetpointFile
}

proc StopLinacConditioning {args} {
    global apsLinacMagnetsDir apsLinacPSDeviceFile apsLEUTLPSDeviceFile
    set fileName ""
    set statusCallback APSNoOp
    APSStrictParseArguments {fileName statusCallback}
    
    eval $statusCallback {"Working..."}
    if {![string length $fileName] || ![file exists $fileName]} {
        return -code error "StopLinacConditioning: Give a valid filename"
    }
    # Present a dialog to allow choosing which beamlines to restore.
    set tmpRoot /tmp/[APSTmpString]
    APSAddToTmpFileList -ID StopLinacConditioning \
       -fileList "$tmpRoot.snap $tmpRoot.snap0"
    if [catch {exec sddscombine $apsLinacPSDeviceFile $apsLEUTLPSDeviceFile -merge \
                 $tmpRoot.dev -overwrite} result] {
        APSDeleteTmpFileList -ID StopLinacConditioning
        return -code error "StopLinacConditioning: $result"
    }
    if [catch {exec sddssort $fileName -pipe=out -column=Beamline -unique \
                 | sdds2stream -pipe -column=Beamline} beamlineList] {
        APSDeleteTmpFileList -ID StopLinacConditioning
        return -code error "StopLinacConditioning: $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 StopLinacConditioning
        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 StopLinacConditioning
        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 StopLinacConditioning
        return -code error "$result"
    }
    APSDeleteTmpFileList -ID StopLinacConditioning
    eval $statusCallback {"Conditioning stopped."}
}

set latticeDirectory ""
set latticeName ""
set runRootname full
set beamSource RG2
set beamTarget LEUTL
SetDefaultMomentumProfile -source $beamSource -target $beamTarget

set beamSourceList [list PCGun PB RG2 RG1]
set commandList [list \
    "SetDefaultMomentumProfile -source PCGun -target LEUTL; set beamTarget LEUTL" \
    "SetDefaultMomentumProfile -source PB -target LEUTL; set beamTarget LEUTL" \
    "SetDefaultMomentumProfile -source RG2 -target LEUTL; set beamTarget LEUTL" \
    "SetDefaultMomentumProfile -source RG1 -target PAR; set beamTarget PAR" \
]
APSRadioButtonFrame .bs -parent .userFrame -label "Beam source" \
        -variable beamSource -buttonList $beamSourceList \
        -valueList $beamSourceList -orientation horizontal \
        -commandList $commandList \
        -contextHelp "Choose the gun from which the beam originates, or the point where your lattice starts."

set beamTargetList [list LEUTL PAR LTP-EA Booster]
set commandList [list \
    "SetDefaultMomentumProfile -source RG2 -target LEUTL; set beamTarget LEUTL" \
    "SetDefaultMomentumProfile -source RG2 -target PAR; set beamTarget PAR" \
    "SetDefaultMomentumProfile -source PCGun -target LTP-EA; set beamTarget LTP-EA" \
    "SetDefaultMomentumProfile -source PB -target Booster; set beamTarget Booster" \
]
APSRadioButtonFrame .bt -parent .userFrame -label "Beam target" \
        -variable beamTarget -buttonList $beamTargetList \
        -valueList $beamTargetList -orientation horizontal \
        -commandList $commandList \
        -contextHelp "Choose the target for the beam." 


APSFrame .momentumProfile -parent .userFrame -label "Momentum Profile in MeV"
set w .userFrame.momentumProfile.frame
foreach item [list L1 L2 L4 L5] row [list 0 0 1 1] col [list 0 1 0 1] {
    APSLabeledEntry .le$item -parent $w -label "After $item" \
      -textVariable Momentum$item -gridPack "-row $row -column $col" \
      -contextHelp "Enter the momentum in MeV/c following sector $item."
}

APSFrame .lattice -parent .userFrame -label "Lattice Selection"
set w .userFrame.lattice.frame
APSLabeledEntry .dirname -parent $w -label "Lattice directory" \
    -textVariable latticeDirectory -width 60 \
    -contextHelp "Directory where lattice subdirectories reside."
APSLabeledEntry .config -parent $w -label "Lattice name" \
    -textVariable latticeName -width 60 \
    -contextHelp "Subdirectory of lattice directory containing runs for the linac to LEUTL or a subset thereof."
APSLabeledEntry .run -parent $w -label "Run rootname" \
    -textVariable runRootname -width 60 \
    -contextHelp "Rootname for runs within the lattice subdirectory that contain the information of interest.  There must be a .param file, and either a .cen or .twi file."
APSButton .findConfig -parent $w -text "Find Lattice" \
    -command FindLattice -contextHelp \
    "Searches the lattice directory for subdirectories containing elegant runs with the given rootname. Attempts to identify a run that has the desired energy profile.  Probably won't work for private runs. Use Pick Lattice instead."
APSButton .pickConfig -parent $w -text "Pick Lattice" \
    -command PickLattice -contextHelp \
    "Searches the lattice directory for subdirectories containing elegant runs with the given rootname. Allows you to select one of the subdirectories.  Lattice data will then be taken from the matching run in that subdirectory."
APSButton .viewConfig -parent $w -text "View Lattice" \
    -command ViewLattice -contextHelp \
    "Displays plots of Twiss parameters and other information."


APSFrame .gen -parent .userFrame -label "Setpoints File" 
set w .userFrame.gen.frame
set setpointsOutputFile ""
APSLabeledEntry .spfile -parent $w -label "Filename" \
  -textVariable setpointsOutputFile -width 60 \
  -contextHelp "Enter the name of the file to which you want the setpoints data written.  The file is compatible with burtwb."
APSButton .gen -parent $w -text "Generate" \
  -contextHelp "Generate a file with power supply setpoints." \
  -command \
  { APSSetVarAndUpdate status "Working...";
      GenerateLinacSetpointFile -latticeDirectory $latticeDirectory \
      -latticeName $latticeName -output $setpointsOutputFile \
      -runRootname $runRootname \
      -MomentumL1 $MomentumL1 -MomentumL2 $MomentumL2 -MomentumL4 $MomentumL4 \
      -MomentumL5 $MomentumL5;
      APSSetVarAndUpdate status "Done."}
if [string compare $env(USER) borland]==0 {
    APSButton .gen1 -parent $w -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...";
          GenerateLinacSetpointFile -latticeDirectory $latticeDirectory \
          -latticeName $latticeName -output $setpointsOutputFile \
          -runRootname $runRootname -convertAll 1 \
          -MomentumL1 $MomentumL1 -MomentumL2 $MomentumL2 -MomentumL4 $MomentumL4 \
          -MomentumL5 $MomentumL5;
          APSSetVarAndUpdate status "Done."}
}
APSButton .view -parent $w -text "View" \
  -contextHelp "View the contents of the power supply setpoints file." \
  -command {ViewLinacSetpointFile -fileName $setpointsOutputFile}
APSButton .restore -parent $w -text "Restore..." \
  -contextHelp "Restore part or all of the power supply setpoints file." \
  -command {RestoreLinacSetpointFile -fileName $setpointsOutputFile -statusCallback setStatus -condition 0}
APSButton .condition -parent $w -text "Condition..." \
  -contextHelp "Condition to part or all of the power supply setpoints file." \
  -command {RestoreLinacSetpointFile -fileName $setpointsOutputFile -statusCallback setStatus -condition 1}
APSButton .stopCondition -parent $w -text "Stop conditioning..." \
  -contextHelp "Stop conditioning part or all of the power supplies listed in the setpoints file." \
  -command {StopLinacConditioning -fileName $setpointsOutputFile -statusCallback setStatus}

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