#!/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)]

#INPUT FILES: /home/helios/oagData/controlFiles/Linac/conditioning/Linac.stdTo0
#             /home/helios/oagData/controlFiles/LTP/LTP.stdTo0
#             /home/helios/oagData/controlFiles/PTB/PTB.stdTo0
#             /home/helios/oagData/controlFiles/LEUTL/LEUTL.std
#             /home/helios/oagData/controlFiles/LTP/LTP_degauss.sdds
#             /home/helios/oagData/controlFiles/PTB/PTB_degauss.sdds
#             /home/helios/oagData/controlFiles/LEUTL/LEUTL_degauss.sdds
#             /home/helios/oagData/controlFiles/PAR/*.std
#             /home/helios/OAG/oagData/controlFiles/Linac/conditioning/linacConditioning.snap
#             /home/helios/oagData/linac/magnets/*.excitation
#             /home/helios/oagData/linac/magnets/*.prop
#             /home/helios/oagData/linac/magnets/crossReference.sdds
#             /home/helios/oagData/linac/magnets/PSCal.sdds
#             /home/helios/oagData/linac/magnets/L3:BMT.calibration
#             /home/helios/oagData/deviceConfig/linac/PSOps.pvTable
#             /home/helios/oagData/deviceConfig/linac/LTPToEndPSOps.pvTable
#             $snapDir/$latticeSetup(ShortFilename)
#             $latticeDirectory($sectionDir)/$rootname/$runRootname($sectionDir).param
#             $latticeDirectory($sectionDir)/$rootname/$runRootname($sectionDir).twi
#             $latticeDirectory($sectionDir)/$rootname/$runRootname($sectionDir).cen
#             $outDir/$latticeDir/$latticeSetupFiles/und.matrix
#             $outDir/$latticeDir/latticeSetupFiles/adjustp.ele
#             $outDir/$latticeDir/latticeSetupFiles/$runRootname($sectionDir)Starting.param
#             $outDir/$eleFile
#             $latticeDirectory($sectionDir)/$latticeName($sectionDir)/$runRootname($sectionDir).twi 





APSDebugPath
set CVSRevisionAuthor "\$Author: borland $"
set PTB 0
set verbose 0
set args $argv
APSParseArguments {PTB verbose}

APSApplication . -name LinacLatticeSetup \
  -overview "Converts elegant lattice data to current setpoints for LINAC, LTP, PAR, PTB, and LEA magnets.  Also sets the position of the chicane magnets."

set status ""
APSScrolledStatus .status -parent .userFrame -textVariable status -height 10 -width 85

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 apsParMagnetsDir /home/helios/oagData/par/magnetFiles
set mainDir $OAGGlobal(LinacLatticesDirectory)

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 PAR PB PTB BB LU LA LS LEA}
    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
        set fileToUse(LEA) /home/helios/oagData/controlFiles/LEUTL/LEUTL.std
        set fileToUse(PAR) /home/helios/oagData/controlFiles/PAR/P375MeV.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)  /home/helios/oagData/controlFiles/LEUTL/LEUTL_degauss.sdds
        set fileToUse(LU)  /home/helios/oagData/controlFiles/LEUTL/LEUTL_degauss.sdds
        set fileToUse(LS)  /home/helios/oagData/controlFiles/LEUTL/LEUTL_degauss.sdds
        set fileToUse(LEA) /home/helios/oagData/controlFiles/LEUTL/LEUTL_degauss.sdds
        set fileToUse(PAR) /home/helios/oagData/controlFiles/PAR/PAR_degauss.std
    }
    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]
    }
}

proc PlotMultipleLattices {args} {
    set sectionDir ""
    if [APSStrictParseArguments {sectionDir}] {
        return -code error "invalid arguments (PlotMultipleLattices)"
    }
    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 choices [APSChooseItemFromList -name "Lattice choice" -multiItem 1\
                                    -itemList $validList -returnList $validList ]
    if ![string length $choices] {
        APSSetVarAndUpdate status "No lattice chosen"
        cd $oldDir 
        return
    }
    set files ""
    foreach choice $choices {
        lappend files $choice/$runRootname($sectionDir).twi
    }
    eval exec sddsplot -layout=1,3 -grap=line,vary -legend=file,edit=%/\/$runRootname($sectionDir).twi// -col=s,etax -unsup=y $files -endp \
      -col=s,betax -unsup=y $files -endp -col=s,betay -unsup=y $files &
    
}

# 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..."
        puts "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"
    } 
    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 CompareWithSCR {args} {
    set sectionDir ""
    APSParseArguments {sectionDir}
    
    global latticeDirectory latticeName runRootname setpointsOutputFile SCRchoice  quadFudgeFactor changeMomentum
    global momentumBreakPointValue
    
    set latticeDir [file dir $latticeDirectory($sectionDir)]
   
    set lattice 0
    if {[file exist $latticeDir/latticeSetupFiles] && [file exists $latticeDir/latticeSetupFiles/$runRootname($sectionDir).ele]} {
        set lattice 1
    }
    set output  $setpointsOutputFile($sectionDir)
    if {![string length $output] || ![file exist $output] } {
        setStatus "setpoints file was not generated yet, quit."
        return
    }

   set SCRsystem LPL   
    set snapDir  /home/helios/oagData/SCR/snapshots/$SCRsystem
    global dialogBoxResponse latticeSetup
    set dialogBoxResponse -1
    set latticeSetup(ShortFilename) ""
    APSDialogBox .scr  -cancelCommand "set dialogBoxResponse cancel" \
      -okCommand "set dialogBoxResponse ok"  -name "Select SCR"
    APSAddSCRDialog .file -parent .scr.userFrame -system LPL \
      -label "Choose SCR file for comparison" \
      -arrayName  latticeSetup \
      -defaultFile $latticeSetup(ShortFilename)
    tkwait window .scr
    if {$dialogBoxResponse=="cancel"} {
        setStatus "compare with SCR  was cancelled."
        return
    }
    if ![string length $latticeSetup(ShortFilename)] {
        setStatus "No SCR file chosen."
        return
    }
    set tmpRoot /tmp/[APSTmpString]
    APSAddToTmpFileList -ID btslattice -fileList $tmpRoot
    if [catch {exec sddsprocess $output -pipe=out -scan=col,LatticeValue,ValueString,%lf \
                 | sddsconvert -pipe -del=col,ValueString \
                 | sddsxref -pipe $snapDir/$latticeSetup(ShortFilename) -nowarnings -match=ControlName -take=ValueString \
                 | sddsprocess -pipe -scan=col,SCRValue,ValueString,%lf \
                 | sddsprocess -pipe=in $tmpRoot "-define=col,SCR-Lattice,SCRValue LatticeValue -" } result] {
        return -code error "Error comparing with SCR1: $result"
    }
    #compute K1 values
    
    if [catch {ComputeK1Values -rootname $runRootname($sectionDir) -sectionDir $sectionDir -SCRValueFile $tmpRoot } result] {
        return -code error "Error computing k1 values for SCR: $result"
    }
   
    if [catch {exec sddsprintout $tmpRoot $tmpRoot.print \
                 "-title=compare with $latticeSetup(ShortFilename) SCR"  \
                 -col=ControlName,format=%22s \
                 -col=LatticeValue,format=%6.2f \
                 -col=SCRValue,format=%6.2f \
                 -col=SCR-Lattice,format=%6.2f \
                 -col=EffLatticeK1,format=%6.2f -col=EffSCRK1,format=%6.2f } result] {
        return -code error  "Error comparing with SCR2: $result"
    }
        
    APSFileDisplayWindow [APSUniqueName .] -fileName $tmpRoot.print -deleteOnClose 1 -width 130 \
      -printCommand "enscript -r" -height 30
    APSAddToTmpFileList -ID btslattice -fileList "$tmpRoot.1 $tmpRoot.print"
    if !$lattice {
        return
    }
    
    global outDir
    
    set magnetList [join [exec sdds2stream -col=ElementName $tmpRoot]]
    eval global $magnetList
    
    set SCRchoice($sectionDir) $latticeSetup(ShortFilename)
    set rootname $latticeName($sectionDir)-$runRootname($sectionDir)
    set eleFile $outDir/$rootname.ele
    set eleTemplate $latticeDir/latticeSetupFiles/$runRootname($sectionDir).ele
    set refDir $latticeDirectory($sectionDir)/$latticeName($sectionDir)
    set origList ""
    set replList ""
    foreach magnet $magnetList {
        lappend origList <${magnet}>
        lappend replList [set ${magnet}]
    }
    lappend origList <refDir>
    lappend replList $refDir
    lappend origList <latticeDir>
    lappend replList $latticeDir/latticeSetupFile
    lappend origList <latticeDirOrig>
    lappend replList $latticeDirectory($sectionDir)
    lappend origList <rootname>
    lappend replList $rootname
    lappend origList <latticeName>
    lappend replList $latticeName($sectionDir)
    if {$sectionDir=="PAR_BIS"} {
        lappend origList <p_central>
        lappend replList [exec rpnl "$momentumBreakPointValue($sectionDir,begin) mev /"]
    }
    if [catch {exec replaceText $eleTemplate $eleFile \
                 -orig=[join $origList ,] -repl=[join $replList ,] } result] {
        return -code error "Error creating ele file: $result"
    }
   
    cd $outDir
    if [file exist $latticeDir/latticeSetupFiles/und.matrix] {
        set specDir $latticeDir/$latticeSetupFiles
    } elseif [file exist $latticeDirectory($sectionDir)/$latticeName($sectionDir)/und.matrix] {
        set specDir $latticeDirectory($sectionDir)/$latticeName($sectionDir)
    } else {
        set specDir ""
    }
    if [string length $specDir] {
        exec cp $specDir/und.matrix .
        catch { exec cp $specDir/twiss.input . }
        catch {exec cp $specDir/knsl45.liwake.sdds . }
    }
    if {$changeMomentum($sectionDir) && [file exist $latticeDir/latticeSetupFiles/adjustp.ele]} {
        global momentumBreakPointValue
      
        set p0 [expr $momentumBreakPointValue($sectionDir,begin) / 0.51099906]
        
        if [catch {exec replaceText $latticeDir/latticeSetupFiles/adjustp.ele ${rootname}.ajustp.ele \
                     -orig=<rootname>,<beginMomentum>,<postL2Momentum>,<postL4Momentum>,<postL5Momentum>,<p0> \
                     -repl=$rootname,$momentumBreakPointValue($sectionDir,begin),$momentumBreakPointValue($sectionDir,L2),$momentumBreakPointValue($sectionDir,L4),$momentumBreakPointValue($sectionDir,L5),$p0  } result] {
            return -code error "Error generating runAdjustp: $result"
        }
        if [catch {exec elegant ${rootname}.ajustp.ele > $rootname.adjustp.log } result] {
            return -code error "Error running adjustp elegant:$result"
        }
    } else {
        catch {exec cp $latticeDir/latticeSetupFiles/[set runRootname($sectionDir)]Starting.param $rootname.paramOpt}
    }
    
    if [catch {exec elegant $eleFile > $rootname.log } result] {
        return -code error "elegant error: $result"
    }
    
    set refLattice $refDir/$runRootname($sectionDir).twi 
    exec cp $refLattice $rootname.ref.twi
    exec sddsplot -pspace=0.10,0.8,0.25,0.95 -title=  \
      -grap=line,vary -layout=1,3 -split=page -group=nameindex  -sep=nameindex \
      -col=s,betax -col=s,betay -col=s,etax $rootname.ref.twi -legend=spec=$latticeName($sectionDir) \
      -col=s,betax -col=s,betay -col=s,etax   $rootname.twi -leg=spec=$SCRchoice($sectionDir),edit=%/.gz//  \
      -col=s,Profile $rootname.mag -overlay=xmode=normal,yfactor=0.075 \
      -omnipresent &
        
}

proc ComputeK1Values {args} {
    set rootname ""
    set SCRValueFile ""
    set sectionDir ""
    APSStrictParseArguments {rootname SCRValueFile sectionDir}
   
    global latticeDirectory latticeName outDir setpointsOutputFile apsLinacMagnetsDir  quadFudgeFactor
    
    set tmpRoot /tmp/[APSTmpString]K1
    cd $outDir
    set magnets [exec sdds2stream -col=ElementName $SCRValueFile]
    set scrValues [exec sdds2stream -col=SCRValue $SCRValueFile]
    set paramFile $latticeDirectory($sectionDir)/$latticeName($sectionDir)/$rootname.param
    set setpointFile $setpointsOutputFile($sectionDir)
    set pCentralList [exec sdds2stream -col=pCentral $SCRValueFile]
    set typeList [exec sdds2stream -col=ElementType $SCRValueFile]
    set latticeK1List [exec sdds2stream -col=K1 $SCRValueFile]
   # set scrValues [exec sdds2stream -col=LatticeValue $SCRValueFile]
    
    foreach magnet $magnets val $scrValues type $typeList pCentral $pCentralList latticeK1 $latticeK1List {
        global $magnet
        set effLatticeK1 $latticeK1
        set fieldStrength 0
        set effL 0
        if [regexp {P:IS} $magnet] {
            set geomStrength [expr 0.2 * $val /  504.16571 * 831.704073976183167 / $pCentral]
            set K1 $geomStrength
            set effK1 $K1
        } elseif [regexp "Pos" $magnet] {
            set K1 0
            set effK1 $K1
        } elseif [regexp {BEN} $type] {
            #bending magnet ANGLE = geometricStrength
            if [catch {exec sddsinterp $apsLinacMagnetsDir/${magnet}.excitation -col=Current,IntegratedStrength -atValues=$val -pipe=out \
                         | sdds2stream -pipe=in -col=IntegratedStrength } fieldStrength] {
                return -code error "Error getting field strength for $magnet: $fieldStrength"
            }
            if [catch {exec sddsprocess $apsLinacMagnetsDir/crossReference.sdds -pipe=out \
                         -match=col,ElementName=$magnet \
                         | sdds2stream -pipe=in -col=Sign } Sign] {
                return -code error "Error getting sign of $magnet: $Sign"
            }
            set integStrength $fieldStrength
            set geomStrength [expr $integStrength / $pCentral / 0.00170450939096 * $Sign]
            set K1 $geomStrength
            set effK1 $K1
        } else {
            if [catch {exec sddsinterp $apsLinacMagnetsDir/${magnet}.excitation -col=Current,IntegratedStrength -atValues=$val -pipe=out \
                         | sdds2stream -pipe=in -col=IntegratedStrength } fieldStrength] {
                return -code error "Error getting field strength for $magnet: $fieldStrength"
            }
            if [catch {exec sddsprocess $apsLinacMagnetsDir/crossReference.sdds -pipe=out -match=col,ElementName=$magnet \
                         | sdds2stream -pipe -col=Sign,BnLMultiplier,EffectiveLength } valList] {
                return -code error "Error getting sign and BnLMultiplier and  EffectiveLength for $magnet: $valList"
            }
            
            set Sign [lindex $valList 0]
            set BnLMultiplier [lindex $valList 1]
            set effL [lindex $valList 2]
            #L2 quads has 5 elements length of L=5 for example L2:QM1
           
            set integStrength [expr $fieldStrength / $Sign * $BnLMultiplier]
          #  puts "$magnet $fieldStrength $Sign $BnLMultiplier  $integStrength"
            set geomStrength [expr $integStrength / $pCentral / 0.00170450939096]
           # puts "$pCentral $geomStrength $Sign $BnLMultiplier"
            if {$type=="ALPH"} {
                set K1 [expr sqrt(3.304453768404287/$geomStrength)]
                set effK1 $K1
            } else {
                if [catch {exec sddsprocess $paramFile -pipe=out -match=col,ElementName=$magnet -match=col,ElementParameter=L \
                         | sdds2stream -pipe -col=ParameterValue } L] {
                    return -code error "Error getting L value for $magnet: $L"
                }
                set len [llength $L]
                set L [lindex $L 0]
                set K1 [expr $geomStrength / $L /  $quadFudgeFactor($sectionDir) / $len ]
                if {$len>1} {
                    set effK1 [expr $K1 * $L * $len / $effL]
                    set effLatticeK1 [expr $latticeK1 * $L * $len / $effL]
                } else {
                    set effK1 $K1
                }
            }
           #"$magnet pcent = $pCentral  IntegSt=$fieldStrength gemo=$geomStrength BnL = $BnLMultiplier L=$L K1=$K1"
        }
        
        set $magnet $K1
        setStatus "$magnet current=$val integStrength=$fieldStrength L=$effL geo=$geomStrength  K1=$K1"
        lappend K1List $K1
        lappend effLatticeK1List $effLatticeK1
        lappend effK1List $effK1
    }
    
    if [catch {exec sddsmakedataset $SCRValueFile.K1 -col=SCRK1,type=double -data=[join $K1List ,] \
                 -col=EffLatticeK1,type=double -data=[join $effLatticeK1List ,] \
                 -col=EffSCRK1,type=double -data=[join $effK1List ,]
        exec sddsxref $SCRValueFile $SCRValueFile.K1 $SCRValueFile.1 -take=SCRK1,EffLatticeK1,EffSCRK1 } result] {
        return -code error "Error computing SCR K1: $result"
    }
    
    exec mv $SCRValueFile.1 $SCRValueFile
}

set newLatticeDir ""
proc SaveSCRLattice {args} {
    set sectionDir ""
    APSParseArguments {sectionDir}

    global outDir latticeDirectory latticeName runRootname newLatticeName newLatticeDir mainDir SCRchoice momentumBreakPointValue

    cd $outDir
    if {![info exist SCRchoice($sectionDir)] || ![string length $SCRchoice($sectionDir)]} {
        setStatus "No SCR selected for $sectionDir. Use Compare Lattice With SCR first to generate SCR lattice."
        return
    }
    set rootname $latticeName($sectionDir)-$runRootname($sectionDir)
    if {![file exist $rootname.lte] || ![file exist $rootname.twi]} {
        setStatus "$rootname.lte or $rootname.twi  lattice file does not exist yet. Use \"Compare Lattice with SCR\" to generate it first."
        return
    }
   # exec cp $rootname.lte $runRootname($sectionDir).lte
   # exec cp $rootname.twi $runRootname($sectionDir).twi
    set newLatticeName $rootname
    if ![string length $newLatticeDir] {
        set newLatticeDir $outDir
    }
    APSDialogBox .newlattice -name "New Lattice Name" -cancelCommand "set newLatticeName \"\""
    APSLabeledEntry .dir -parent .newlattice.userFrame -label "Directory to save SCR lattice:" -width 70 \
        -textVariable newLatticeDir
    APSLabeledEntry .name -parent .newlattice.userFrame -label "name of SCR lattice:" -textVariable newLatticeName \
      -width 70

    tkwait window .newlattice 
    if ![string length $newLatticeName] {
        setStatus "new lattice name is not provided, creating new lattice is cancelled."
        return
    }
    cd $newLatticeDir
    if [file exist $newLatticeName/$runRootname($sectionDir).lte] {
        if ![APSYesNoPopUp "lattice $newLatticeName already exist, do you want to overwrite it?"] {
            setStatus "$newLatticeName already exist!"
            return
        }
    } else {
        if ![file exist $newLatticeName] {
            exec mkdir $newLatticeName
            exec chmod a+rwx $newLatticeName
        }
    }
    cd $newLatticeName
    exec cp $outDir/$rootname.lte $runRootname($sectionDir).lte
    exec cp $outDir/$rootname.twi $runRootname($sectionDir).twi
    exec cp $outDir/$rootname.param $runRootname($sectionDir).param
    set refDir  $latticeDirectory($sectionDir)/$latticeName($sectionDir)
    set pcentralZ [expr $momentumBreakPointValue($sectionDir,begin)/0.511]
    if [catch {exec replaceText \
                 [file dir $latticeDirectory($sectionDir)]/latticeSetupFiles/work/$runRootname($sectionDir).ele \
                 $runRootname($sectionDir).ele \
                 -orig=<refDir>,<p_central> \
                 -repl=$refDir,$pcentralZ } result] {
        return -code error "Error creating ele file: $result"
    }
    foreach file {und.matrix twiss.input knsl45.liwake.sdds} {
        catch {exec cp $latticeDirectory($sectionDir)]/latticeSetupFiles/$file .}
    }
   
    if [catch {exec elegant $runRootname($sectionDir).ele > $runRootname($sectionDir).log } result] {
        return -code error "Error running elegant: $result"
    }
    exec cp $runRootname($sectionDir).twi $outDir/$runRootname($sectionDir)-new.twi 
    cd $outDir
    exec sddsplot -pspace=0.10,0.8,0.25,0.95 -title=  \
      -grap=line,vary -layout=1,3 -split=page -group=nameindex  -sep=nameIndex \
      -col=s,betax -col=s,betay -col=s,etax $runRootname($sectionDir)-new.twi -leg=spec=new_lattice \
      -col=s,betax -col=s,betay -col=s,etax  $rootname.twi -leg=spec=Saved_SCR_Lattice  \
      -col=s,Profile $rootname.mag -overlay=xmode=normal,yfactor=0.075 \
      -omnipresent &
}

# 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]
    }
}

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

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

    GenerateLinacSetpointFile -convertAll $convertAll -sectionDir $sectionDir \
      -rootname $latticeDirectory($sectionDir)/$latticeName($sectionDir)/$runRootname($sectionDir) \
      -output $setpointsOutputFile($sectionDir) \
      -rescale $changeMomentum($sectionDir) \
      -quadStrengthFudgeFactor $quadFudgeFactor($sectionDir) \
      -beginMomentum $momentumBreakPointValue($sectionDir,begin) \
      -postL2Momentum $momentumBreakPointValue($sectionDir,L2) \
      -postL4Momentum $momentumBreakPointValue($sectionDir,L4) \
      -postL5Momentum $momentumBreakPointValue($sectionDir,L5) \
      -includeChicane $includesChicane($sectionDir)
}

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

proc GenerateLinacSetpointFile {args} {
    global verbose
    if $verbose {
        setStatus "GenerateLinacSetpointFile $args"
    }
    set rootname ""
    set output ""
    set beginMomentum 0
    set postL2Momentum 0
    set postL4Momentum 0
    set postL5Momentum 0
    set convertAll 0
    set rescale 0
    set includeChicane 0
    set quadStrengthFudgeFactor 1.0
    set sectionDir ""
    APSStrictParseArguments {rootname output convertAll beginMomentum \
                               postL2Momentum postL4Momentum postL5Momentum rescale \
                               includeChicane quadStrengthFudgeFactor sectionDir}

    global apsLinacMagnetsDir apsLinacPSDeviceFile apsLEUTLPSDeviceFile apsParMagnetsDir

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

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

    if $verbose {
        setStatus "GenerateLinacSetpointFile 1"
        set tmpRoot $outputDir/[APSTmpString]
    } else {
        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] \
                         -macro=postL2Momentum=$postL2Momentum \
                         -macro=postL4Momentum=$postL4Momentum \
                         -macro=postL5Momentum=$postL5Momentum"
            catch {eval exec $elegantCmd > $tmpRoot.log} result
            
            if ![file exists $tmpRoot.done] {
                APSFileDisplayWindow [APSUniqueName .] -fileName $tmpRoot.log \
                  -deleteOnClose 1 -width 130 
                update
                APSDeleteTmpFileList -ID GenerateLinacSetpointFile
                return -code error "elegant run failed.  Look on /tmp for files."
            }
            APSAddToTmpFileList -ID GenerateLinacSetpointFile -fileList \
              [glob -nocomplain $tmpRoot.*]
            # Find file giving the momentum at each element
            if ![file exists [set paramFile $tmpRoot.param]] {
                APSDeleteTmpFileList -ID GenerateLinacSetpointFile
                return -code error "not found: $paramFile"
            }
            if ![file exists [set profileFile $tmpRoot.cen]] {
                APSDeleteTmpFileList -ID GenerateLinacSetpointFile
                return -code error "not found: $profileFile"
            }
            set pCenColumn pCentral
        }
    }
    
    if $verbose {
        setStatus "GenerateLinacSetpointFile 2"
    }

    # 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.
    if !$verbose {
        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"
        APSAddToTmpFileList -ID GenerateLinacSetpointFile -fileList "$tmpRoot.flr $tmpRoot.flr1 $tmpRoot.flr2 $tmpRoot.flr3 $tmpRoot.VP "
    }
    if $convertAll {
        set xrefExtraOpt -fillIn
    } else {
        set xrefExtraOpt -nowarning
    }        
    if [catch {exec sddscombine $apsLinacPSDeviceFile $apsLEUTLPSDeviceFile -merge \
                 $tmpRoot.dev -overwrite} result] {
        APSDeleteTmpFileList -ID GenerateLinacSetpointFile
        return -code error "GenerateLinacSetpointFile: $result"
    }
    if $verbose {
        setStatus "GenerateLinacSetpointFile 3"
    }
    if [catch {exec sddsprocess $paramFile -pipe=out -match=col,ElementType=*QUAD* \
                 -match=col,ElementParameter=K1 \
                 "-redefine=column,ParameterValue,ParameterValue $quadStrengthFudgeFactor *" \
                 | sddsconvert -pipe=in $tmpRoot.K1 \
                 -rename=column,ParameterValue=K1} result] {
        APSDeleteTmpFileList -ID GenerateLinacSetpointFile
        return -code error "GenerateLinacSetpointFile: $result"
    }
    if $verbose {
        setStatus "GenerateLinacSetpointFile 3.1"
    }
    if [catch {exec sddsprocess $paramFile -pipe=out -match=col,ElementType=*BEN* -nowarning \
                 -match=column,ElementParameter=ANGLE \
                 "-define=col,K1,ParameterValue" \
                 | sddsconvert -pipe=in $tmpRoot.ANGLE \
                 -rename=column,ParameterValue=GeometricIntegratedStrength} result] {
        APSDeleteTmpFileList -ID GenerateLinacSetpointFile
        return -code error "GenerateLinacSetpointFile: $result"
    }
    if $verbose {
        setStatus "GenerateLinacSetpointFile 3.2"
    }
    if [catch {exec sddsprocess $paramFile $tmpRoot.alpha -match=col,ElementType=ALPH -nowarning \
                 -match=column,ElementParameter=XMAX \
                 "-define=column,GeometricIntegratedStrength,ParameterValue sqr rec 3.304453768404287 *" \
                 "-define=col,K1,ParameterValue"} result] {
        APSDeleteTmpFileList -ID GenerateLinacSetpointFile
        return -code error "GenerateLinacSetpointFile: $result"
    }
    if $verbose {
        setStatus "GenerateLinacSetpointFile 3.3"
    }
    if [catch {exec sddsprocess $tmpRoot.dev $tmpRoot.CN -match=col,Operation=SetCurrent } result] {
        APSDeleteTmpFileList -ID GenerateLinacSetpointFile
        return -code error "GenerateLinacSetpointFile: $result"
    }
    if $verbose {
        setStatus "GenerateLinacSetpointFile 3.4"
    }
    if [catch {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 *"} result] {
        APSDeleteTmpFileList -ID GenerateLinacSetpointFile
        return -code error "GenerateLinacSetpointFile: $result"
    }
    if $verbose {
        setStatus "GenerateLinacSetpointFile 3.5"
    }
    if [string compare $sectionDir "PAR"]==0 {
        set xrefFile $apsParMagnetsDir/P_xref.sdds
        if [catch {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=*Name*,first,%s -process=GeometricIntegratedStrength,sum,%s \
                     -process=IntegratedStrength,sum,%s -process=$pCenColumn,ave,pCentral \
                     | sddscollapse -pipe \
                     | sddsxref -pipe $xrefFile -nowarning -match=ElementName -take=*  \
                     | sddsprocess -pipe -reprint=column,ControlName,%s:CurrentAO,DeviceName \
                     "-redefine=column,IntegratedStrength,IntegratedStrength CalFactor / FamilyCalSign *,units=T" \
                     -reprint=column,ExcitationFile,$apsParMagnetsDir/%s,ExcitationFile \
                     | sddsxref $tmpRoot.GS -pipe -match=ElementName -take=L \
                     | tee $tmpRoot.tmp \
                     | sddsinterpset -pipe \
                     -order=1 -data=fileColumn=ExcitationFile,interpolate=I,functionOf=IntegratedStrength,column=IntegratedStrength \
                     -belowRange=value=0 -aboveRange=extrapolate \
                     | sddsconvert -pipe -rename=col,I=Current \
                     | sddsprocess -pipe \
                     "-print=column,ValueString,%21.15e,Current" \
                     "-define=column,OverLimit,Current abs SupplyLimit > ? 1 : 0 \$ ,type=long" \
                     -print=col,Beamline,P \
                     "-define=column,Momentum,pCentral 0.51099906 *,units=MeV/c" \
                     | sddsxref -pipe $tmpRoot.GS -match=ElementName -take=ElementType,K1 -fillIn -nowarnings \
                     | sddsxref -pipe $rootname.twi -match=ElementName -take=s \
                     | sddsconvert -pipe=in $tmpRoot.res0 \
                     -retain=column,ElementName,ControlName,DeviceName,Current,ValueString,Beamline,IntegratedStrength,pCentral,Momentum,GeometricIntegratedStrength,SupplyLimit,OverLimit,K1,ElementType,s} result] {
            APSDeleteTmpFileList -ID GenerateLinacSetpointFile 
            return -code error "GenerateLinacSetpointFile: $result"
        }
    } else {
        set xrefFile $apsLinacMagnetsDir/crossReference.sdds
        if [catch {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=*Name*,first,%s -process=GeometricIntegratedStrength,sum,%s \
                     -process=IntegratedStrength,sum,%s -process=$pCenColumn,ave,pCentral \
                     | sddscollapse -pipe \
                     | sddsxref -pipe $xrefFile -nowarning -match=ElementName -take=*  \
                     | sddsxref -pipe $tmpRoot.CN -match=DeviceName -take=*Name* -nowarning $xrefExtraOpt \
                     | sddsprocess -pipe -match=col,ControlName=,! \
                     "-redefine=column,IntegratedStrength,IntegratedStrength BnLMultiplier / Sign *,units=T" \
                     -print=column,ExcitationFile,$apsLinacMagnetsDir/%s.excitation,DeviceName \
                     | sddsxref -pipe $tmpRoot.GS -match=ElementName -take=L \
                     | tee $tmpRoot.tmp \
                     | 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,ElementName,S/:/100D \
                     "-define=column,Momentum,pCentral 0.51099906 *,units=MeV/c" \
                     | sddsxref -pipe $tmpRoot.GS -match=ElementName -take=ElementType,K1 -fillIn -nowarnings \
                     | sddsxref -pipe $rootname.twi -match=ElementName -take=s \
                     | sddsconvert -pipe=in $tmpRoot.res0 \
                     -retain=column,ElementName,ControlName,DeviceName,Current,ValueString,Beamline,IntegratedStrength,pCentral,Momentum,GeometricIntegratedStrength,SupplyLimit,OverLimit,K1,ElementType,s} result] {
            APSDeleteTmpFileList -ID GenerateLinacSetpointFile 
            return -code error "GenerateLinacSetpointFile: $result"
        }
    }
    if $verbose {
        setStatus "GenerateLinacSetpointFile 4"
    }

    if [catch {exec sddsprocess $tmpRoot.GS -match=col,ElementName=P:IS -pipe=out -nowarnings \
        | sdds2stream -pipe -col=GeometricIntegratedStrength } PISGeomInteg] {
        return -code error "GenerateLinacSetpointFile (error getting geometricIntegratedStrength for P:IS: $PISGeomInteg"
    }
    if $verbose {
        setStatus "GenerateLinacSetpointFile 5"
    }

    if [string length $PISGeomInteg] {
        set pCentral [lindex [exec sdds2stream $tmpRoot.res0 -col=pCentral] 0]
        set momentum [lindex [exec sdds2stream $tmpRoot.res0 -col=Momentum] 0]
        set PISInteg [expr $PISGeomInteg * $pCentral * 0.001704509390960]
        set current [expr $PISGeomInteg * $pCentral / 0.2 / 831.704073976183167 * 504.1657]
        if {$current>1000} {
            set over 1
        } else {
            set over 0
        }
        if [catch {exec sddsmakedataset $tmpRoot.PIS -col=ElementName,type=string -data=P:IS \
                     -col=GeometricIntegratedStrength,type=double -data=$PISGeomInteg \
                     -col=IntegratedStrength,type=double -data=$PISInteg \
                     -col=pCentral,type=double -data=$pCentral \
                     -col=SupplyLimit,type=double -data=1000 \
                     -col=ControlName,type=string -data=P:ISP:VoltageSetSendAO \
                     -col=Current,type=double -data=$current \
                     -col=ValueString,type=string -data=$current \
                     -col=OverLimit,type=long  -data=$over \
                     -col=Beamline,type=string -data=LTP \
                     -col=Momentum,type=double -data=$momentum } result] {
            return -code error "Error generating current file for P:IS: $result"
        }
        if [catch {exec sddscombine $tmpRoot.res0 $tmpRoot.PIS -merge $tmpRoot.res0a } result] {
            return -code error "Error combining PIS with reso: $result"
        }
        set output0 $tmpRoot.res0a
    } else {
        set output0 $tmpRoot.res0
    }
    if $verbose {
        setStatus "GenerateLinacSetpointFile 6"
    }

    # 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 $output0 -pipe=out -match=col,ElementName=L3:BM* \
          | tee $tmpRoot.res1 | sdds2stream -rows=bare -pipe] {
        if [catch {exec sddsprocess $output0 $tmpRoot.res2 -match=col,ElementName=L3:BM*,!
                sdds load $tmpRoot.res1 L3BMData} result] {
            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 {
                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] {
            return -code error "GenerateLinacSetpointFile: $result"
        }
    } else {
        file copy -force $output0 $output
    }
    if $verbose {
        setStatus "GenerateLinacSetpointFile 7"
    }

    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 $includeChicane {
        if [catch {exec sddsprocess $rootname.flr -pipe=out -match=col,ElementName=L3:BM\[34\]-VP \
                     | sddssort -pipe -col=ElementName \
                     | sddsconvert -pipe=in $tmpRoot.VP -rename=col,X=XVP,Z=ZVP
            exec sddsprocess $rootname.flr -pipe=out -match=col,ElementName=L3:BM\[34\]-C \
                     | sddssort -pipe -col=ElementName \
                     | sddsconvert -pipe -rename=col,X=XC,Z=ZC \
                     | sddsxref -pipe $tmpRoot.VP -take=*VP \
                     | sddsprocess -pipe=in $tmpRoot.flr1 \
                     -process=ZC,first,ZReference -process=XVP,last,XReference \
                     "-define=column,XOffset,XVP XReference - 1e3 *,units=mm" \
                     "-define=column,ZFinal,ZC ZReference - 0.770294 - 1e3 *,units=m" 
            exec sddsprocess $tmpRoot.flr1 -pipe=out -match=col,ElementName=L3:BM3* \
                     "-print=col,ControlName,L3:BC:XOffset:motorSM" \
                     | sddsconvert -pipe=in $tmpRoot.flr2 -rename=col,XOffset=ControlValue 
            exec sddsprocess $tmpRoot.flr1 -pipe=out -match=col,ElementName=L3:BM4* \
                     "-print=col,ControlName,L3:BC:ZFinal:motorSM" \
                     | sddsconvert -pipe=in $tmpRoot.flr3 -rename=col,ZFinal=ControlValue 
            exec sddscombine $tmpRoot.flr2 $tmpRoot.flr3 -pipe=out \
                     | sddsprocess -pipe \
                     "-reedit=column,ElementName,%/-C//%/-VP//ei/Pos/" \
                     "-print=column,Beamline,L3:Movers" \
                     "-print=column,ValueString,%21.15le,ControlValue" \
                     "-print=column,ProfileFile,$profileFile" \
                     | sddsinterpset -pipe=in $tmpRoot.flr -order=1  \
                     -data=file=ProfileFile,interp=$pCenColumn,func=s,col=s \
                     -belowRange=value=0 -aboveRange=extrapolate 
            exec sddscombine $output $tmpRoot.flr $tmpRoot.res0b -merge -overwrite
            file rename -force $tmpRoot.res0b $output} result] {
            APSDeleteTmpFileList -ID GenerateLinacSetpointFile 
            return -code error "GenerateLinacSetpointFile: $result"
        }
    }
    if $verbose {
        setStatus "GenerateLinacSetpointFile 8"
    }

    if [catch {exec sddssort $output $output.1 -col=s } result] {
        return -code error "Error sorting by s: $result"
    }
    if $verbose {
        setStatus "GenerateLinacSetpointFile 9"
    }

    exec mv $output.1 $output
    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
        }
    }
    if $verbose {
        setStatus "GenerateLinacSetpointFile 10"
    }

   # APSDeleteTmpFileList -ID GenerateLinacSetpointFile 
}

# Reviews data in a previously generated setpoint file

proc ViewLinacSetpointFile {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 "ViewLinacSetpointFile: 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 "ViewLinacSetpointFile: $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 RestoreLinacSetpointFile1 {args} {
    set sectionDir ""
    set statusCallback APSNoOp
    set condition 1
    APSStrictParseArguments {sectionDir statusCallback condition}

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

set conditioningCycles -1
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"
    }
    set tmpRoot /tmp/[APSTmpString]
#    if $condition {
#        APSAddToTmpFileList -ID RestoreLinacSetpointFile -fileList $tmpRoot.data
#        if [catch {exec sddsprocess $fileName $tmpRoot.data \
#                     -match=col,ElementName=*Pos,!} result] {
#            return -code error "RestoreLinacSetpointFile: $result"
#        }
#        set fileName $tmpRoot.data
#    }

    # Present a dialog to allow choosing which beamlines to restore.
    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 (-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 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 $matchOptEN -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=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"
                }
            }
            if {[lsearch -exact $totalElemList L3:BM3Pos]!=-1 || \
                [lsearch -exact $totalElemList L3:BM4Pos]!=-1} {
                ## move the chicane
                if [catch {exec sddsprocess $fileName $tmpRoot.chicane \
                             -match=col,ElementName=L3:BM?Pos \
                             -print=param,SnapType,Absolute \
                             -print=col,ControlType,pv \
                             -print=col,Lineage,- -define=col,Count,1,type=long \
                             -nowarning} result] {
                    APSDeleteTmpFileList -ID RestoreLinacSetpointFile
                    return -code error "4.1: $result"
                }
                if {[exec sdds2stream -rows=bare $tmpRoot.chicane]!=0 && \
                      [catch {exec sddscasr -restore $tmpRoot.chicane} result]} {
                    APSDeleteTmpFileList -ID RestoreLinacSetpointFile
                    return -code error "4.2 $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 LA LEA}
            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 LA LEA}
            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 RestoreLinacSetpointFile
                return -code error "4.3: $result"
            }
            if {$result!=0 && [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>=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 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 sddsprocess $tmpRoot.snap -pipe=out \
                              -match=col,ElementName=L3*Pos,! \
                              | sdds2stream -pipe=in -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 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 for [exec sdds2stream -rows=bare $tmpRoot.snap] values."}
        APSLogScriptAction -action RestoreLinacSetpointFile -parameters $logParams -state done
    } else {
        eval $statusCallback {"$action cancelled."}
    }
    APSDeleteTmpFileList -ID RestoreLinacSetpointFile
}

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

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

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."}
}

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 dateDir 2001-1219
    set accelBreakPointList begin
    set chicane 0
    APSStrictParseArguments {sectionDir accelList chicane accelBreakPointList dateDir}
    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 includesChicane momentumBreakPointWidgetList
    global quadFudgeFactor

    set latticeDirectory($sectionDir) $mainDir/$sectionDir/$dateDir
    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."
    if {$sectionDir=="PAR_BIS"} {
        APSRadioButtonFrame .root -parent $w.run -packOption "-side right" -label "" -variable  runRootname($sectionDir) \
          -buttonList {ptb transverse} -valueList {ptb transverse} -orientation horizontal \
          -commandList [list "ClearLattice -sectionDir $sectionDir" "ClearLattice -sectionDir $sectionDir"]
    }
    if {$sectionDir=="FS9_PAR"} {
        APSRadioButtonFrame .root -parent $w.run -packOption "-side right" -label "" -variable  runRootname($sectionDir) \
          -buttonList {ltp transverse} -valueList {ltp transverse} -orientation horizontal \
          -commandList [list "ClearLattice -sectionDir $sectionDir" "ClearLattice -sectionDir $sectionDir"]
    }
    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."
    APSButton .plot1 -parent $w -text "Plot Multiple Lattice" \
      -command "PlotMultipleLattices -sectionDir $sectionDir" \
      -contextHelp "plot and compare multiple lattices"

    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 L2 L4 L5} {
        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"]
    set quadFudgeFactor($sectionDir) 1.0
    APSLabeledEntry .fudge -parent $w -label "Quad strength fudge factor: " \
      -textVariable quadFudgeFactor($sectionDir) 
    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."
    global SCRchoice
    set SCRchoice($sectionDir) ""
    APSLabeledOutput .scrFile -parent $w -label "SCR file" -width 75 \
      -textVariable SCRchoice($sectionDir) \
      -contextHelp "selected SCR file."
    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 .gen1 -parent $w1 -text "Generate" \
              -contextHelp "Generate a file with power supply setpoints." \
              -command \
              "APSSetVarAndUpdate status Working...;\
              GenerateLinacSetpointFile1 -sectionDir $sectionDir -convertAll 1;\
              APSSetVarAndUpdate status Done."
    APSButton .view -parent $w1 -text "View" \
      -contextHelp "View the contents of the power supply setpoints file." \
      -command "ViewLinacSetpointFile -sectionDir $sectionDir"
    APSButton .compare -parent $w1 -text "Compare With SCR" \
      -contextHelp "compare the generated file with selected SCR file." \
      -command "CompareWithSCR -sectionDir $sectionDir"
   # APSButton .lattice -parent $w1 -text "Compare Lattice With SCR" \
   \#   -contextHelp "compare the generated file with selected SCR file." \
    \#  -command "CompareWithSCR -sectionDir $sectionDir -lattice 1"
    APSButton .savelattice -parent $w1 -text "Save SCR Lattice..." \
      -contextHelp "save lattice from selected SCR file." \
      -command "SaveSCRLattice -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 "RestoreLinacSetpointFile1 -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 "RestoreLinacSetpointFile1 -sectionDir $sectionDir \
                  -statusCallback setStatus -condition 1"
    APSButton .stopCondition -parent $w2 -text "Stop conditioning..." \
      -contextHelp "Stop conditioning part or all of the power supplies listed in the setpoints file." \
     -command "StopLinacConditioning1 -sectionDir $sectionDir \
                 -statusCallback setStatus"
    set includesChicane($sectionDir) $chicane
}

proc UpdateRootname {args} {
    set item ""
    APSParseArguments {item}
    global beamlineSection runRootname PTB
    APSSetVarAndUpdate beamlineSection $item
    set latticeName($item) ""
    set runRootname($item) transverse
   # if {$item=="FS9_PAR"} {
    #    set runRootname($item) ltp
    #}
    if {$item=="PAR_BIS" && $PTB} {
        set  runRootname($item) ptb
    }
}

proc ClearLattice {args} {
    set sectionDir ""
    APSParseArguments {sectionDir}
    global latticeName
    set latticeName($sectionDir) ""
    update
}
if $PTB {
    set sectionList  PAR>Booster
    set sectionDirList  PAR_BIS
    set accelBreakPointList begin
    set dateDirList 2001-1219
    set chicaneFlagList 0
} else {
    set sectionList [list RG2>L3FS5 RG1>L3FS5 PCG>L3FS5 L3FS5>PBC1 FS9>PAR LTPEA PAR \
                       PAR>Booster PBC1>Booster PBC1>LEADUT LEADUT>VDUMP LEADUT>SDUMP]
    set sectionDirList [list RG2_L3FS5 RG1_L3FS5 L1O_L3FS5 L3FS5_PBC1 FS9_PAR LTPEA PAR \
                          PAR_BIS PBC1_BIS PBC1_LEADUT LEA_DUT_VDUMP LEA_DUT_SDUMP]
    set dateDirList [list 2001-1219 2021-0129 2001-1219 2001-1219 2001-1219 2001-1219 2025-0121 \
                       2001-1219 2001-1219 2023-0307 2023-0307 2023-0307]
    set accelBreakPointList [list "begin L2" "begin L2" "begin L2" "begin L4 L5" begin begin begin begin begin begin begin begin]
    set chicaneFlagList [list 1 1 1 0 0 0 0 0 0 0 0 0]
}
foreach item $sectionDirList date $dateDirList {
   # lappend sectionCommandList "APSSetVarAndUpdate beamlineSection $item"
    lappend sectionCommandList "UpdateRootname -item $item"
    set latticeDirectory($item) $mainDir/$item/$date
    set latticeName($item) ""
    set runRootname($item) transverse
}
set beamlineSection [lindex $sectionList 0]

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

foreach tabFrame $tabFrameWidgetList sectionDir $sectionDirList accelBP $accelBreakPointList \
  chicane $chicaneFlagList dateDir $dateDirList {
    FillTabFrame $tabFrame -sectionDir $sectionDir -accelBreakPointList $accelBP \
      -chicane $chicane -dateDir $dateDir
}

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

#proc APSLogScriptAction {args} {
#    setStatus "Pretending to log script action: $args"
#}

