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

if [info exists env(LOCO_BINDIR)] {
    set locoBinDir $env(LOCO_BINDIR)
} else {
    puts stderr "Error: LOCO_BINDIR environment variable is not defined"
    exit
}
set workDir [exec pwd]
set outputStatusDevice statusScreen

if [info exists env(LOCO_TMPDIR)] {
    set tmpDir $env(LOCO_TMPDIR)
} else {
    set tmpDir $env(HOME)/tmp
}
source $locoBinDir/locoCommonProcedures

set tabFrameWidth 1100
set tabFrameHeight 360

set CVSRevisionAuthor "\$Revision: 1.6 $ \$Author: sajaev $"

set usage "SROpticsCorrection \[-calcMode <beta|coupling>\]"
set args $argv
set calcMode beta
APSParseArguments {calcMode}
if {[string compare $calcMode beta] != 0 && [string compare $calcMode coupling] != 0} {
    puts stdout $usage
    exit
}

set hostname [exec hostname]
set applicationName SROpticsCorrection@$hostname
APSApplication . -name $applicationName -version 1 \
    -overview {This application corrects twiss functions of the storage ring (both beta functions and dispersion) or off-diagonal RM elements \
		   using the results of LOCO fitting. Implemented by V. Sajaev}

set matrixFilePrecalculated /home/helios/oagData/sr/calibratedModels/LOCOMatrices/default/twissCorrectionMatrix.sdds

#----------------------------------------------------------------------------------------------------------------------------

proc DisableWidgets {args} {
    global sensitiveWidgets deviceTabWidgetVAR widgetPage
    APSParseArguments {option}
    if {-1 < [lsearch [array names widgetPage] $option]} {
        foreach page $widgetPage($option) {
            $deviceTabWidgetVAR pageconfigure $page -state disabled
        }
    }
    if {-1 < [lsearch [array names sensitiveWidgets] $option]} {
        foreach widget $sensitiveWidgets($option) {
            $widget configure -state disabled
        }
    }
    return
}
proc EnableWidgets {args} {
    global sensitiveWidgets deviceTabWidgetVAR widgetPage
    APSParseArguments {option}
    if {-1 < [lsearch [array names widgetPage] $option]} {
        foreach page $widgetPage($option) {
            $deviceTabWidgetVAR pageconfigure $page -state normal
        }
    }
    if {-1 < [lsearch [array names sensitiveWidgets] $option]} {
        foreach widget $sensitiveWidgets($option) {
            $widget configure -state normal
        }
    }
    return
}

#---------------------------------------------------------------------------------------------------------------------------

proc ReadMeasuredBPMs {args} {
    global bpmSufList
    APSParseArguments {filename}
    set bpmList [exec sdds2stream $filename -col=Rootname]
    APSSetSRSectorButtons -mode all-off -rootname dBpms -itemList $bpmSufList
    foreach element $bpmList {
	global dBpms${element}
	set dBpms${element} 1
    }
}

#---------------------------------------------------------------------------------------------------------------------------

proc UncheckXYBpms {args} {
    global bpmSufList
    APSSetSRSectorButtons -mode all-off -rootname xBpms -itemList $bpmSufList
    APSSetSRSectorButtons -mode all-off -rootname yBpms -itemList $bpmSufList
}

#---------------------------------------------------------------------------------------------------------------------------

proc GetElementList {args} {
    set sectorCount 40
    set sectorName S
    set nameList ""
    APSParseArguments {sufListName rootname sectorCount}
    global $sufListName
    set suffixList [set $sufListName]
    for {set sector 1} {$sector<=$sectorCount} {incr sector} {
	foreach suffix $suffixList {
	    set nameFlag ${rootname}${sectorName}[format %02d ${sector}]$suffix
	    global $nameFlag
	    if [set $nameFlag] {
		lappend nameList ${sectorName}[format %02d ${sector}]$suffix
	    }
	}
    }
    return $nameList
}

#---------------------------------------------------------------------------------------------------------------------------

proc RemoveQuotations {args} {
    APSParseArguments {string}
    set L [string length $string]
    set outString ""
    for {set I 0} {$I<$L} {incr I} {
	if {[string compare "\"" [string range $string $I $I]] != 0} {
	    append outString [string range $string $I $I]
	}
    }
    return $outString
}

#---------------------------------------------------------------------------------------------------------------------------

proc ChooseLOCOConfig { args } {

    APSParseArguments { configDir }

    set dirList [glob -nocomplain -- $configDir/??? ]

    set commentList ""
    set datasetList ""

    foreach directory $dirList {
        set commentFile $directory/comment
	if [file exists $commentFile] {
	    set comment "[file tail $directory]: "
	    if [catch {open $commentFile r} fid] {
		return -code error "$fid"
	    } else {
		lappend commentList [append comment [gets $fid]]
		close $fid
		lappend datasetList $directory
	    }
	}
    }

    set sortedCommentList [lsort -ascii $commentList]
    set sortedDatasetList ""
    foreach comment $sortedCommentList {
        set i [lsearch -exact $commentList $comment]
        if {$i >= 0} {
            lappend sortedDatasetList [lindex $datasetList $i]
        } else {
            return -code error "Error in the comment lists!"
        }
    }
    
    set chosenList [APSChooseItemFromList \
                        -name "Data Set Selection" \
                        -itemList $sortedCommentList \
                        -returnList $sortedDatasetList \
                        -returnIndices 0 \
                        -multiItem 1 \
                        -contextHelp "Select saveset for data reprocessing."]
    return $chosenList
}

#--------------------------------------------------------------------------------------------------------------------------

proc ReadLOCOConfig {args} {
    global lteMeasured lteMeasuredEmit beamlineMeasured param1Measured param2Measured param3Measured \
	lteDesired lteDesiredEmit beamlineDesired param1Desired param2Desired workDir calcMode
    APSParseArguments {locoConfig}
    if ![string length $locoConfig] {
	APSSetVarAndUpdate status "No LOCO configuration chosen."
	return
    }
    set readList [list rawLteFile beamlineName latticeParamFile latticeParamFile1 latticeParamFile2 resultsFile]
    array set Variables [join [exec sddsmakedataset -pipe=out -col=VariableName,type=string -data=[join $readList ,] \
				   | sddsxref -pipe $locoConfig/variables.sdds -take=VariableValue -match=VariableName \
				   -nowarning \
				   | sdds2stream -pipe=in -col=VariableName,VariableValue] ]

    set lteMeasured ""
    set lteDesired ""
    set beamlineMeasured ""
    set beamlineDesired ""
    set param1Measured ""
    set param1Desired ""
    set param2Measured ""
    set param2Desired ""
    if [info exists Variables(rawLteFile)] {
	set lteMeasured $Variables(rawLteFile)
	set lteDesired  $Variables(rawLteFile)
	set lteMeasuredEmit $Variables(rawLteFile)
	set lteDesiredEmit  $Variables(rawLteFile)
    }
    if [info exists Variables(beamlineName)] {
	set beamlineMeasured $Variables(beamlineName)
	set beamlineDesired  $Variables(beamlineName)
    }
    if [info exists Variables(latticeParamFile)] {
	set param1Measured $Variables(latticeParamFile)
	set param1Desired  $Variables(latticeParamFile)
    }
    if [info exists Variables(latticeParamFile1)] {
	set param2Measured $Variables(latticeParamFile1)
	set param2Desired  $Variables(latticeParamFile1)
    }
    if [info exists Variables(latticeParamFile2)] {
	set param3Measured $Variables(latticeParamFile2)
	APSSetVarAndUpdate status "Error: LOCO configuration contains 3 parameter files. One too many!"
	return -code error "Read LOCO configuration: not completed."
    }
    if [info exists Variables(resultsFile)] {
	set resultsFile $locoConfig/$Variables(resultsFile)
	set quadFile $workDir/loco-quads-skew.param
	exec sddsprocess $resultsFile -pipe=out "-match=para,PageID=Quad*,PageID=Skew,|" -nowarning \
	    | sddscombine -pipe=in $quadFile -overWrite -merge
	#--- Creation of ElementName will be skipped if it exists:
### Somewhere here ElementOccurence is not treated correctly.
###
	if 0 {
	    if [catch {Fit_MakeElementNameFromTagName -input $quadFile -tagNameColumn TagName -elementNameColumn ElementName -addElementOccurence 1} result] {
		return -code error "Fit_MakeElementNameFromTagName: $result"
	    }
	}
	if [string length $param1Measured] {
	    if [string length $param2Measured] {
		set param3Measured $quadFile
	    } else {
		set param2Measured $quadFile
	    }
	} else {
	    set param1Measured $quadFile
	}
    } else {
	APSSetVarAndUpdate status "Error: LOCO configuration does not have results file."
	return -code error "Read LOCO configuration: not completed."
    }

    if {[string compare $calcMode coupling] == 0} {
	#------ Reading element lists and checking corresponding buttons:
	set hcorList [join [exec sddsprocess $locoConfig/listRM.sdds -pipe=out -match=para,ListName=HCorr "-reedit=col,List,%@#1@@" | sdds2stream -pipe=in -col=List] ]
	set vcorList [join [exec sddsprocess $locoConfig/listRM.sdds -pipe=out -match=para,ListName=VCorr "-reedit=col,List,%@#1@@" | sdds2stream -pipe=in -col=List] ]
	set hbpmList [join [exec sddsprocess $locoConfig/listRM.sdds -pipe=out -match=para,ListName=HBPM | sdds2stream -pipe=in -col=List] ]
	set vbpmList [join [exec sddsprocess $locoConfig/listRM.sdds -pipe=out -match=para,ListName=VBPM | sdds2stream -pipe=in -col=List] ]
	set elementListRM [list $hcorList $vcorList $hbpmList $vbpmList]
	if [catch {RestoreElementButtons -elementListRM $elementListRM} result ] {
	    APSSetVarAndUpdate status "RestoreElementButtons: $result"
	}
    }

    APSSetVarAndUpdate status "Read LOCO configuration: Done."
}

#--------------------------------------------------------------------------------------------------------------------------

proc RestoreElementButtons {args} {

    APSParseArguments {elementListRM}
    global sectorList preffixArray hcorrSufList vcorrSufList

    set itemListList [list $hcorrSufList $vcorrSufList]
    set rmRootList  [list hCorrs vCorrs]
    set elementListList [list [lindex $elementListRM 0] [lindex $elementListRM 1]]

    foreach varRoot $rmRootList elementList $elementListList itemList $itemListList {
	set preffixIndex $varRoot
	set localSectorList [GetLocalSectorList -varRoot $varRoot]
	if [catch {GetButtonNamesFromVarNames -sectorList $localSectorList -itemList $itemList \
		       -preffix $preffixArray($preffixIndex)} arrayList] {
	    APSSetVarAndUpdate status "GetButtonNamesFromVarNames: $arrayList"
	} else {
	    array set gridArray $arrayList
	    SetSRSectorButtons -mode all-off -rootname $varRoot -itemList $itemList -sectorCount [llength $localSectorList]
	    foreach element $elementList {
		global ${varRoot}$gridArray($element)
		set ${varRoot}$gridArray($element) 1
	    }
	}
    }

}

#----------------------------------------------------------------------------------------------------------------------------

proc GetLocalSectorList {args} {
    global sectorList
    APSParseArguments {varRoot}
    set localSectorList $sectorList 
    global sectorList$varRoot
    if [info exists sectorList$varRoot] { 
	set localSectorList [set sectorList$varRoot]
    } 
    return $localSectorList
}

#----------------------------------------------------------------------------------------------------------------------------

proc GetButtonNamesFromVarNames {args} {
    set sectorList ""
    set itemList ""
    set preffix ""
    APSParseArguments {sectorList itemList preffix}
    
    set sectorCount [llength $sectorList]
    if !$sectorCount {
        return -code error "GetButtonNamesFromVarNames: The sectorList is not provided!"
    }
    for {set i 0} {$i<$sectorCount} {incr i} {
        foreach item $itemList {
            set array(${preffix}[lindex $sectorList $i]$item) S[format %02d [expr $i +1]]$item
        }
    }
    return [array get array]
}

#----------------------------------------------------------------------------------------------------------------------------

proc SetSRSectorButtons {args} {
    set mode ""
    set rootname ""
    set sectorCount ""
    set itemList ""
    set missingList ""
    set missingListVar ""
    APSStrictParseArguments {mode rootname sectorCount itemList missingList missingListVar}

    if [string length $missingListVar] {
        global $missingListVar
        set missingList [set $missingListVar]
    }
    switch $mode {
        all-on  {set value 1}
        all-off {set value 0}
        default {return}
    }
    foreach item $itemList {
        set toggleVar ${rootname}S${item}
        global $toggleVar
        set $toggleVar $value
        APSSRSectorTogglePosition -item $item -rootname $rootname \
          -sectorCount $sectorCount -missingList $missingList -toggleVar $toggleVar
    }
}

#----------------------------------------------------------------------------------------------------------------------------

set status "Usage: SROpticsCorrection \[-calcMode <beta|coupling>\]"
APSScrolledStatus .status -parent .userFrame -textVariable status -width 110 -height 10

# APS SR element lists
switch $calcMode {
    beta {
	set deviceWidgetList [APSTabFrame .tabsMain -parent .userFrame -width $tabFrameWidth -height $tabFrameHeight \
				  -labelList "\"Quads\" \"Hor.BPMs\" \"Ver.BPMs\" \"Disp.BPMs\"" -label ""]
	set quadSufList [list A:Q1 A:Q2 A:Q3 A:Q4 A:Q5 A:Q6 A:Q7 A:Q8 B:Q8 B:Q7 B:Q6 B:Q5 B:Q4 B:Q3 B:Q2 B:Q1]
	set quadsMissing ""
    }
    coupling {
	set deviceWidgetList [APSTabFrame .tabsMain -parent .userFrame -width $tabFrameWidth -height $tabFrameHeight \
				  -labelList "\"Quads\" \"H Corrs\" \"V Corrs\" \"Hor. BPMs\" \"Ver. BPMs\" \"Disp.BPMs\"" \
				  -label ""]
	set quadSufList [list A:SQ1 A:SQ2 B:SQ2 B:SQ1]
	set quadsMissing ""
    }
}
set bpmSufList [list A:P0 A:P1 A:P2 A:P3 A:P4 A:P5 A:P6 B:P6 B:P5 B:P4 B:P3 B:P2 B:P1 B:P0]
set sectorList [list S01 S02 S03 S04 S05 S06 S07 S08 S09 S10 S11 S12 S13 S14 S15 S16 S17 S18 S19 S20 S21 S22 S23 S24 \
		    S25 S26 S27 S28 S29 S30 S31 S32 S33 S34 S35 S36 S37 S38 S39 S40]
array set preffixArray [list hCorrs "" vCorrs ""]

#--- APSSRSectorButtons makes buttons that connect to variables $rootname$sector$suffix where
#--- $sector is taken from -sectorList option (S by default like at APS), $suffix is taken from $itemLabelList

set index 0
APSSRSectorButtons .quadButtons -parent [lindex $deviceWidgetList $index] -rootname quads \
    -orientation horizontal -sectorList $sectorList \
    -label "Quads" -description "Quadrupole selections" \
    -itemList $quadSufList -packOption "-side top" -missingList $quadsMissing \
    -itemLabelList $quadSufList -sectorControl 1
incr index
if {[string compare $calcMode coupling] == 0} {
    set hcorrSufList [list A:FH1 A:FH2 B:FH2 B:FH1]
    set vcorrSufList [list A:FV1 A:FV2 B:FV2 B:FV1]
    #------ Button names are $rootname$sector$item - hCorrsS1A:H1
    APSSRSectorButtons .hcorrButtons -parent [lindex $deviceWidgetList $index] -rootname hCorrs \
	-orientation horizontal -sectorList $sectorList \
	-label "H correctors" \
	-description "Selection of H correctors to calculate response matrix." \
	-itemList $hcorrSufList -packOption "-side top" \
	-itemLabelList $hcorrSufList -sectorControl 1
    incr index
    APSSRSectorButtons .vcorrButtons -parent [lindex $deviceWidgetList $index] -rootname vCorrs \
	-orientation horizontal -sectorList $sectorList \
	-label "V correctors" \
	-description "Selection of V correctors to calculate response matrix." \
	-itemList $vcorrSufList -packOption "-side top" \
	-itemLabelList $vcorrSufList -sectorControl 1
    incr index
}
APSSRSectorButtons .hbpmButtons -parent [lindex $deviceWidgetList $index] -rootname xBpms \
    -orientation horizontal -sectorList $sectorList \
    -label "BPMs to correct X beta function" \
    -description "Selection of BPMs where the horizontal beta function correction will be done." \
    -itemList $bpmSufList -packOption "-side top" \
    -itemLabelList $bpmSufList -sectorControl 1
incr index
APSSRSectorButtons .vbpmButtons -parent [lindex $deviceWidgetList $index] -rootname yBpms \
    -orientation horizontal -sectorList $sectorList \
    -label "BPMs to correct Y beta function" \
    -description "Selection of BPMs where the vertical beta function fit correction be done." \
    -itemList $bpmSufList -packOption "-side top" \
    -itemLabelList $bpmSufList -sectorControl 1
incr index
APSSRSectorButtons .dbpmButtons -parent [lindex $deviceWidgetList $index] -rootname dBpms \
    -orientation horizontal -sectorList $sectorList \
    -label "BPMs to correct dispersion" \
    -description "Selection of BPMs where the horizontal dispersion correction will be done." \
    -itemList $bpmSufList -packOption "-side top" \
    -itemLabelList $bpmSufList -sectorControl 1
incr index

#----------------------------------------------------------------------------------------------------------------------
# --- Lower frame -------------------------------------------------------------------------------------------------
#----------------------------------------------------------------------------------------------------------------------

switch $calcMode {
    beta {set commandWidgetList [APSTabFrame .actionTabs -parent .userFrame -width 850 -height 390 \
				     -labelList "\"Files...\" \"Calculate...\" \"Scan SV...\" \"Setpoints...\"" \
				     -label ""]}
    coupling {set  commandWidgetList [APSTabFrame .actionTabs -parent .userFrame -width 850 -height 390 \
					  -labelList "\"Files...\" \"Minimize using RM...\" \"Minimize using envelopes...\" \"Scan SV...\" \"Setpoints...\"" \
					  -label ""]}
}
set w .userFrame 

#----------------------------------------------------------------------------------------------------------------------
# --- Files frame -------------------------------------------------------------------------------------------------
#----------------------------------------------------------------------------------------------------------------------

set fileInputboxLength 62
set windex 0
set twidget [lindex $commandWidgetList $windex]

APSFrame .frameResults -parent $twidget
set w $twidget.frameResults.frame

APSLabeledEntry .locoConfig -parent $w \
    -label "LOCO Config directory: " \
    -textVariable locoConfigDir -width $fileInputboxLength
APSButton .read -parent $w.locoConfig \
    -text "Read Config" -size small \
    -command {set locoConfig [ChooseLOCOConfig -configDir $locoConfigDir]; ReadLOCOConfig -locoConfig $locoConfig} \
    -contextHelp "Display the content of the main LOCO configuration directory and allows to choose a configuration. Then fills in the input boxes below with file names from the chosen LOCO configuration."

APSLabeledEntry .workDir -parent $w \
    -label "Working directory:               " \
    -textVariable workDir -width $fileInputboxLength
APSLabeledEntry .outputFile -parent $w \
    -label "Output file:               " \
    -textVariable outputFile -width $fileInputboxLength


set labelList [list "Measured lattice" "Target lattice" "Emittance calcs"]
set fileTabList [APSTabFrame .fileTabs -parent $twidget -width 800 -height 200 \
			   -labelList $labelList -label ""]

set parentTab [lindex $fileTabList 0]

APSFrame .frameMeasured -parent $parentTab -label "Present (measured) lattice:"
set w $parentTab.frameMeasured.frame
APSRadioButtonFrame .useMeasDisp -parent $w \
    -label "Correct measured dispersion only: " \
    -variable useMeasDisp -valueList {0 1} \
    -buttonList {no yes} \
    -orientation horizontal \
    -commandList {{
	EnableWidgets -option dontUseMeasDisp
	DisableWidgets -option useMeasDisp
    } {
	UncheckXYBpms
	set useTunes 0
	set iterations 1
	set SVratio 40
	set corFraction 1.0
	DisableWidgets -option dontUseMeasDisp
	EnableWidgets -option useMeasDisp
    }} \
    -contextHelp "If chosen, only measured dispersion will be corrected. Beta functions will be free to go bad."

APSLabeledEntry .lteMeasured -parent $w \
    -label "Lattice .lte file: " \
    -textVariable lteMeasured -width $fileInputboxLength
lappend sensitiveWidgets(dontUseMeasDisp) $w.lteMeasured.label $w.lteMeasured.entry
APSLabeledEntry .beamlineMeasured -parent $w \
    -label "Beamline name: " \
    -textVariable beamlineMeasured -width $fileInputboxLength
lappend sensitiveWidgets(dontUseMeasDisp) $w.beamlineMeasured.label $w.beamlineMeasured.entry
APSLabeledEntry .param1Measured -parent $w \
    -label "Parameter file (optional): " \
    -textVariable param1Measured -width $fileInputboxLength
lappend sensitiveWidgets(dontUseMeasDisp) $w.param1Measured.label $w.param1Measured.entry
APSLabeledEntry .param2Measured -parent $w \
    -label "Parameter file (optional): " \
    -textVariable param2Measured -width $fileInputboxLength
lappend sensitiveWidgets(dontUseMeasDisp) $w.param2Measured.label $w.param2Measured.entry
APSLabeledEntry .param3Measured -parent $w \
    -label "Parameter file (optional): " \
    -textVariable param3Measured -width $fileInputboxLength
lappend sensitiveWidgets(dontUseMeasDisp) $w.param3Measured.label $w.param3Measured.entry

APSLabeledEntry .measDispFile -parent $w \
    -label "Measured dispersion: " \
    -textVariable measDispFile -width $fileInputboxLength
APSButton .read -parent $w.measDispFile \
    -text "Read BPMs" -size small \
    -command {ReadMeasuredBPMs -filename $measDispFile} \
    -contextHelp "Reads correctors and bpms from the file and selects corresponding elements in the above tabs."
lappend sensitiveWidgets(useMeasDisp) $w.measDispFile.read.button
lappend sensitiveWidgets(useMeasDisp) $w.measDispFile.label $w.measDispFile.entry

set parentTab [lindex $fileTabList 1]

APSFrame .frameDesired -parent $parentTab -label "Desired (correction target) lattice:"
set w $parentTab.frameDesired.frame
APSLabeledEntry .lteDesired -parent $w \
    -label "Lattice .lte file: " \
    -textVariable lteDesired -width $fileInputboxLength
APSLabeledEntry .beamlineDesired -parent $w \
    -label "Beamline name: " \
    -textVariable beamlineDesired -width $fileInputboxLength
APSLabeledEntry .param1Desired -parent $w \
    -label "Parameter file (optional): " \
    -textVariable param1Desired -width $fileInputboxLength
APSLabeledEntry .param2Desired -parent $w \
    -label "Parameter file (optional): " \
    -textVariable param2Desired -width $fileInputboxLength
APSLabeledEntry .betaTargetFile -parent $w \
    -label "Beta target file (optional): " \
    -textVariable betaTargetFile -width $fileInputboxLength \
    -contextHelp "You can change beta functions on some BPMs by providing this file. The file has to have 4 pages with parameter Plane equal tp X, Y, D, and Q. Also must have 2 columns: Rootname and TargetBeta. Pages can have zero length."

set parentTab [lindex $fileTabList 2]

APSFrame .frameEmit -parent $parentTab -label "Lattice for emittance calculations:"
set w $parentTab.frameEmit.frame

APSLabeledEntry .lteMeasured1 -parent $w \
    -label "Measured kick .lte file: " \
    -textVariable lteMeasuredEmit -width $fileInputboxLength
APSLabeledEntry .beamlineMeasured1 -parent $w \
    -label "Measured RF beamline name: " \
    -textVariable beamlineMeasuredEmit -width $fileInputboxLength
APSLabeledEntry .lteMeasured2 -parent $w \
    -label "Target kick .lte file: " \
    -textVariable lteDesiredEmit -width $fileInputboxLength
APSLabeledEntry .beamlineMeasured2 -parent $w \
    -label "Target RF beamline name: " \
    -textVariable beamlineDesiredEmit -width $fileInputboxLength
APSLabeledEntry .volt -parent $w \
    -label "RF voltage (MV): " \
    -textVariable rfVoltage -width $fileInputboxLength
APSLabeledEntry .h -parent $w \
    -label "RF harmonic: " \
    -textVariable rfH -width $fileInputboxLength
APSLabeledEntry .e -parent $w \
    -label "Beam energy (GeV): " \
    -textVariable beamEnergyEmit -width $fileInputboxLength
APSButton .calcEmit -parent $w -text "Calculate emittances" -command {
    APSSetVarAndUpdate status "Calculating emittances using beam envelopes..."
    if [catch {CalculateEmittances} result ] {
	APSSetVarAndUpdate status "CalculateEmittances: $result"
    }
    update idletasks
} -contextHelp "Calculates emittances using beam envelopes."

#----------------------------------------------------------------------------------------------------------------------
# --- Calculate frame -------------------------------------------------------------------------------------------------
#----------------------------------------------------------------------------------------------------------------------

set inputboxWidth 10
incr windex 
set twidget [lindex $commandWidgetList $windex]

APSRadioButtonFrame .useInverseSolution -parent $twidget \
    -label "Use inverse LOCO solution (use it if LOCO solution for quadrupoles was good):    " \
    -variable useInvSolution -valueList {0 1} \
    -buttonList {no yes} \
    -orientation horizontal \
    -commandList {
	{} 
	{if [catch {InvertLOCOSolution -outputStatusDevice statusScreen} locoResultFile] {
	    APSSetVarAndUpdate status $locoResultFile
	    set useInvSolution 0
	    set locoResultFile dummy
	}
	}
    } -contextHelp "Use inverse (negative) LOCO solution instead of SVD calculations. Not recommended presently."

APSFrame .frameIterations -parent $twidget -label "Iteration parameters"
set wFrame $twidget.frameIterations.frame
APSFrameGrid .grid -parent $wFrame -xList {x1 x2 x3 x4}
set w $wFrame.grid.x1
switch $calcMode {
    beta {
	APSLabeledEntry .betaxWeight -parent $w \
	    -label "Beta X weight:         " \
	    -textVariable betaxWeight -width $inputboxWidth \
	    -contextHelp "Beta X error is multiplied with this weight during the solving."
	lappend sensitiveWidgets(dontUseMeasDisp) $w.betaxWeight.label $w.betaxWeight.entry
	APSLabeledEntry .betayWeight -parent $w \
	    -label "Beta Y weight:         " \
	    -textVariable betayWeight -width $inputboxWidth \
	    -contextHelp "Beta Y error is multiplied with this weight during the solving."
	lappend sensitiveWidgets(dontUseMeasDisp) $w.betayWeight.label $w.betayWeight.entry
	APSLabeledEntry .etaxWeight -parent $w \
	    -label "Eta  X weight:         " \
	    -textVariable etaxWeight -width $inputboxWidth \
	    -contextHelp "Eta X error is multiplied with this weight during the solving."
	lappend sensitiveWidgets(dontUseMeasDisp) $w.etaxWeight.label $w.etaxWeight.entry
	APSLabeledEntry .tunesWeight -parent $w \
	    -label "Tunes  weight:         " \
	    -textVariable tunesWeight -width $inputboxWidth \
	    -contextHelp "Tune errors is multiplied with this weight during the solving."
	lappend sensitiveWidgets(dontUseMeasDisp) $w.tunesWeight.label $w.tunesWeight.entry
    }
    coupling {
	APSLabeledEntry .offdiagWeight -parent $w \
	    -label "Off-diag RM weight:         " \
	    -textVariable offdiagWeight -width $inputboxWidth \
	    -contextHelp "Off diag RM error is multiplied with this weight during the solving."
	lappend sensitiveWidgets(dontUseMeasDisp) $w.offdiagWeight.label $w.offdiagWeight.entry
	APSLabeledEntry .etayWeight -parent $w \
	    -label "Eta Y weight:         " \
	    -textVariable etayWeight -width $inputboxWidth \
	    -contextHelp "Eta Y error is multiplied with this weight during the solving."
	lappend sensitiveWidgets(dontUseMeasDisp) $w.etayWeight.label $w.etayWeight.entry
    }
}
set w $wFrame.grid.x2
APSLabeledEntry .iterations -parent $w \
    -label "Number of iterations:" \
    -textVariable iterations -width $inputboxWidth \
    -contextHelp "Number of iterations."
lappend sensitiveWidgets(dontUseMeasDisp) $w.iterations.label $w.iterations.entry
APSLabeledEntry .fraction -parent $w \
    -label "Correction fraction:" \
    -textVariable corFraction -width $inputboxWidth \
    -contextHelp "Fraction with which the corrections will be applied."
APSRadioButtonFrame .useRelative -parent $w \
    -label "Use relative errors?  \n(except dispersion)" \
    -variable useRelative -valueList {0 1} \
    -buttonList {no yes} \
    -orientation horizontal \
    -commandList {{} {}} \
    -contextHelp "Use relative or absolute differences of beta functions when calculate corrections."

set w $wFrame.grid.x3
if ![string compare $calcMode beta] {
    APSRadioButtonFrame .useTunes -parent $w \
	-label "Use tunes:    " \
	-variable useTunes -valueList {0 1} \
	-buttonList {no yes} \
	-orientation horizontal \
	-commandList {{} {}} \
	-contextHelp "Use tune errors when during iteration."
}

APSFrame .frameMatrix -parent $twidget -label "Matrix calculation parameters"
set wFrame $twidget.frameMatrix.frame
APSFrameGrid .grid1 -parent $wFrame -xList {x1 x2}
set w $wFrame.grid1.x1
APSRadioButtonFrame .derivativeFileChoice -parent $w \
    -label "Derivative matrix file: " \
    -variable matrixFileChoice -valueList {0 1} \
    -buttonList "\"Use entry field below\" $matrixFilePrecalculated" \
    -orientation vertical \
    -commandList {{EnableWidgets -option derivativeFile; EnableWidgets -option calculateMatrix} \
		      {set calculateMatrix 0; set calculateInverse 1; DisableWidgets -option derivativeFile; DisableWidgets -option calculateMatrix}} \
    -contextHelp "If the lattice and all other parameters are the same, one can save time by not recalculating the matrix."
APSLabeledEntry .derivativeFile -parent $w \
    -label "Derivative matrix file: " \
    -textVariable matrixFileWorkdir -width 70 \
    -contextHelp "File name for the derivative of the twiss functions."
lappend sensitiveWidgets(derivativeFile) $w.derivativeFile.entry
APSFrameGrid .grid -parent $wFrame -xList {x1 x2 x3 x4}
set w $wFrame.grid.x1
APSRadioButtonFrame .calculateMatrix -parent $w \
    -label "Calculate  the  twiss \nresponse matrix?      " \
    -variable calculateMatrix -valueList {0 1} \
    -buttonList {no yes} \
    -orientation horizontal \
    -commandList {{} {set calculateInverse 1}} \
    -contextHelp "If the lattice and all other parameters are the same, one can save time by not recalculating the matrix."
lappend sensitiveWidgets(calculateMatrix) $w.calculateMatrix.frame.button1 $w.calculateMatrix.frame.button2
APSRadioButtonFrame .calculateInverse -parent $w \
    -label "Calculate the inverse \nof the matrix?        " \
    -variable calculateInverse -valueList {0 1} \
    -buttonList {no yes} \
    -orientation horizontal \
    -commandList {{} {}} \
    -contextHelp "If you changed the weights, you need to recalculate the inverse too."

set w $wFrame.grid.x2
APSRadioButtonFrame .useDQS -parent $w \
    -label "Use parallel computation?  " \
    -variable useDQS -valueList {0 1} \
    -buttonList {no yes} \
    -orientation horizontal \
    -commandList {{} {}} \
    -contextHelp "Derivative matrix calculations will use parallel computation."
APSLabeledEntry .splitTasks -parent $w \
    -label "Number of tasks for DQS:  " \
    -textVariable splitTasks -width $inputboxWidth \
    -contextHelp "When calculating derivative matrix, splits the task into this number of subtasks for DQS."
APSLabeledEntry .singValues -parent $w \
    -label "Number of singular values:  " \
    -textVariable SVratio -width $inputboxWidth \
    -contextHelp "Keeps singular values within the ratio specified."

APSButton .calcCorrections -parent $twidget -text "Calculate corrections" -command \
    {
	APSSetVarAndUpdate status "Running beta function correction..."
	set abortFile $workDir/abort.run
	set elementListFile $workDir/twissCorrElements.sdds
	if {[string compare $calcMode beta] == 0} {
	    set weightList [list $betaxWeight $betayWeight $etaxWeight $tunesWeight]
	} else {
	    set weightList [list $offdiagWeight $etayWeight]
	}
	if ![string length $measDispFile] {set measDispFile dummy}
	set paramFileListMeasured ""
	set paramFileListDesired ""
	if [string length $param1Measured] {lappend paramFileListMeasured $param1Measured}
	if [string length $param2Measured] {lappend paramFileListMeasured $param2Measured}
	if [string length $param3Measured] {lappend paramFileListMeasured $param3Measured}
	if [string length $param1Desired] {lappend paramFileListDesired $param1Desired}
	if [string length $param2Desired] {lappend paramFileListDesired $param2Desired}
	if [catch {MakeElementListFile -calcMode $calcMode -filename $elementListFile} result] {
	    APSSetVarAndUpdate status "MakeElementListFile: $result"
	    return
	}
	if {$matrixFileChoice == 1} {set matrixFile $matrixFilePrecalculated} else {set matrixFile $matrixFileWorkdir}
	set command "$locoBinDir/calculateTwissCorrection \
                       -calcMode $calcMode \
                       -mode correct \
                       -workDir $workDir \
		       -lteMeasured $lteMeasured \
		       -beamlineMeasured $beamlineMeasured \
		       -paramFileListMeasured \"$paramFileListMeasured\" \
		       -lteDesired $lteDesired \
		       -beamlineDesired $beamlineDesired \
		       -paramFileListDesired \"$paramFileListDesired\" \
		       -outputFile $workDir/$outputFile \
		       -elementListFile $elementListFile \
		       -weightList \"$weightList\" \
		       -calculateMatrix $calculateMatrix \
		       -calculateInverse $calculateInverse \
		       -useRelative $useRelative \
		       -SVratio $SVratio \
		       -matrixFile $matrixFile \
		       -corFraction $corFraction \
		       -useDQS $useDQS \
		       -splitTasks $splitTasks \
		       -iterations $iterations \
		       -useTunes $useTunes \
		       -useInvSolution $useInvSolution \
		       -locoResultFile $locoResultFile \
		       -useMeasDisp $useMeasDisp \
		       -measDispFile $measDispFile \
                       -betaTargetFile $betaTargetFile \
		       -abortFile $abortFile"
	catch {file delete $abortFile}
	if [catch {APSExecLog .calculateTwissCorrection \
		       -lineLimit 2048 -width 120 \
		       -name "Running Twiss Correction..." \
		       -unixCommand $command} pid] {
	    APSSetVarAndUpdate status "Error running calculateTwissCorrection: $pid"
	}
    } -contextHelp "Runs defined fit problem."

APSButton .stop -parent $twidget -text Stop -command {exec touch $abortFile} -contextHelp "Aborts whole run."

APSButton .plotSV -parent $twidget -text "Plot SV" -command {
    APSSetVarAndUpdate status "Plotting singular values..."
    exec sddsplot $workDir/tmp/twissCorrectionMatrixFiltered.sdds.SV -col=Index,SingularValues \
	-mode=y=log,y=spec -graph=symbol,connect &
    update idletasks
} -contextHelp "Plots singular values of the derivative matrix."

APSButton .plotVar -parent $twidget -text "Plot quad corrections" -command {
    APSSetVarAndUpdate status "Plotting quadrupoles..."
    if [catch {
	set plotFile $tmpDir/[APSTmpString].plotQuadCorr
	switch $calcMode {
	    beta {
		exec sddsprocess $workDir/tmp/$desiredFiles(outParam) $plotFile.K1s -match=col,ElementParameter=K1
		exec sddsxref $workDir/$outputFile $plotFile.K1s -pipe=out -match=ElementName \
		    -take=ParameterValue -rename=col,ParameterValue=AbsoluteValue \
		    | sddsprocess -pipe=in $plotFile "-def=col,RelQuadChanges,ParameterValue AbsoluteValue /"
		exec sddsplot $plotFile -col=ElementName,RelQuadChanges -graph=symbol,connect &
		file delete $plotFile.K1s
	    }
	    coupling {
		exec sddsplot $workDir/$outputFile -col=ElementName,ParameterValue -graph=symbol,connect &
	    }
	}
    } result] {
	APSSetVarAndUpdate status "$result"
    }
    update idletasks
} -contextHelp "Plots quad corrections."

switch $calcMode {
    beta {
	APSButton .plotTwiss -parent $twidget -text "Plot twiss functions" -command {
	    APSSetVarAndUpdate status "Plotting beta functions..."
	    if [catch { PlotTwissFunctions \
			    -desiredFile  $workDir/tmp/$desiredFiles(twiss) \
			    -measuredFile $workDir/tmp/$measuredFiles(twiss) \
			    -achievedFile $workDir/tmp/$achievedFiles(twiss) \
			    -workDir $workDir} result ] {
		APSSetVarAndUpdate status "PlotTwissFunctions: $result"
	    }
	    update idletasks
	} -contextHelp "Plots twiss functions from files: tmp/measured.twi, tmp/desired.twi and tmp/achieved.twi"
    }
    coupling {
	APSButton .plotOrbits -parent $twidget -text "Plot RM" -command {
	    APSSetVarAndUpdate status "Plotting response matrix..."
	    if [catch {PlotOrbits} result ] {
		APSSetVarAndUpdate status "PlotOrbits: $result"
	    }
	    update idletasks
	} -contextHelp "Plots response matrix vectors from files: tmp/measured.hyrm(vxrm), tmp/desired.hyrm(vxrm) and tmp/achieved.hyrm(vxrm)"
	APSButton .plotDy -parent $twidget -text "Plot etay" -command {
	    APSSetVarAndUpdate status "Plotting vertical dispersion..."
	    exec sddsplot -graph=line,vary \
		-col=s,etay $workDir/tmp/$measuredFiles(twiss) -leg=spec=Measured \
		-col=s,etay $workDir/tmp/$desiredFiles(twiss) -leg=spec=Ideal \
		-col=s,etay $workDir/tmp/$achievedFiles(twiss) -leg=spec=Achieved &
	    update idletasks
	} -contextHelp "Plots vertical dispersion."
	APSButton .calcEmit -parent $twidget -text "Calculate emittances" -command {
	    APSSetVarAndUpdate status "Calculating emittances using beam envelopes..."
	    if [catch {CalculateEmittances -resultFile $workDir/$outputFile} result ] {
		APSSetVarAndUpdate status "CalculateEmittances: $result"
	    }
	    update idletasks
	} -contextHelp "Calculates emittances using beam envelopes."
    }
}

#----------------------------------------------------------------------------------------------------------------------
# --- Calculate using envelopes frame ---------------------------------------------------------------------------------
#----------------------------------------------------------------------------------------------------------------------
if {[string compare $calcMode coupling] == 0} {
incr windex 
set twidget [lindex $commandWidgetList $windex]
APSLabeledEntry .optimRoot -parent $twidget \
    -label "Rootname:  " \
    -textVariable optimRootname -width 50 \
    -contextHelp "Rootname for various files created during optimziation."
APSLabeledEntry .optimTerm -parent $twidget \
    -label "Optimization term:  " \
    -textVariable optimTerm -width 50 \
    -contextHelp "This term will be minimized by elegant."
APSLabeledEntry .optimTerm1 -parent $twidget \
    -label "Optimization term:  " \
    -textVariable optimTerm1 -width 50 \
    -contextHelp "This term will be minimized by elegant."
APSLabeledEntry .optimIters -parent $twidget \
    -label "Optimization restarts, passes, evaluations (list):  " \
    -textVariable optimIterList -width 50 \
    -contextHelp "Space separated list of restarts, passes, and evaluations as used by simplex minimizer in elegant."

APSButton .minimizeEy -parent $twidget -text "Minimize Ey" -command {
    APSSetVarAndUpdate status "Minimizing vertical emittance..."
    if [catch {MinimizeEy -optimTerm $optimTerm -optimTerm1 $optimTerm1 -rootname $optimRootname} result] {
	APSSetVarAndUpdate status "MinimizeEy: $result"
    }
    update idletasks
} -contextHelp "Minimizes vertical emittance using envelope calculations."

APSButton .plot1 -parent $twidget -text "Plot progress" -command {
    exec sddscollapse $workDir/$optimRootname.fin $workDir/$optimRootname.fin.coll
    exec sddsplot $workDir/$optimRootname.fin.coll -col=PageNumber,*ptimizationFunction \
	-graph=line,vary -mode=y=log,y=spec &
    update idletasks
} -contextHelp "Performs sddscollapse on the .fin file and plots the optimization progress."

APSButton .plot2 -parent $twidget -text "Plot results" -command {
    if [catch {MakeResultsFileOptimEmit -input $workDir/$optimRootname.fin.coll \
		   -output $workDir/$optimRootname.results} results] {
	APSSetVarAndUpdate status "MakeResultsFileOptimEmit: $result"
    }
    APSSetVarAndUpdate status "Calculating emittances using beam envelopes..."
    catch {file delete $workDir/tmp/moments.measured.done $workDir/tmp/moments.achieved.done}
    if [catch {CalculateEmittances -resultFile $workDir/$optimRootname.results} result ] {
	APSSetVarAndUpdate status "CalculateEmittances: $result"
    }

    set counter 0
    while {![file exists $workDir/tmp/moments.measured.done] || ![file exists $workDir/tmp/moments.achieved.done]} {
	update
	after 1000
	incr counter
	if {$counter > 30} {
	    APSSetVarAndUpdate status "Error: Waiting for moments calculation takes too long, exiting..."
	    break
	}
    }
    set ey1 [format %.1e [exec sdds2stream $workDir/tmp/moments.measured.mom -para=e2]]
    set ey2 [format %.1e [exec sdds2stream $workDir/tmp/moments.achieved.mom -para=e2]]
    set title "Ey measured: $ey1; Ey minimized: $ey2"
    exec sddsprocess $workDir/tmp/moments.achieved.mom -nowarning -reprint=para,Title,$title
    catch {file delete $workDir/tmp/moments.achieved.mom~ $workDir/tmp/moments.measured.done \
	       $workDir/tmp/moments.achieved.done}
    exec sddsplot -graph=line,vary \
	-col=s,s3 -leg=spec=Measured $workDir/tmp/moments.measured.mom \
	-col=s,s3 -leg=spec=Minimized $workDir/tmp/moments.achieved.mom "-topline=Y size" -end \
	-col=s,ey -leg=spec=Measured $workDir/tmp/moments.measured.mom \
	-col=s,ey -leg=spec=Minimized $workDir/tmp/moments.achieved.mom "-topline=@Title" -end &
    update idletasks
} -contextHelp "Uses current best result to calculate and plot emittance."

APSButton .postProc -parent $twidget -text "Make results file" -command {
    if [catch {MakeResultsFileOptimEmit -input $workDir/$optimRootname.fin.coll \
		   -output $workDir/$optimRootname.results} results] {
	APSSetVarAndUpdate status "MakeResultsFileOptimEmit: $result"
    }
    APSSetVarAndUpdate status "Make results file: done ($workDir/$optimRootname.results)."
    update idletasks
} -contextHelp "Takes best result from the optimization .fin file and creates parameter file."

APSButton .plot3 -parent $twidget -text "Plot skew quads" -command {
    exec sddsplot $workDir/$optimRootname.results -col=ElementName,ParameterValue \
	-graph=symbol,connect &
    update idletasks
} -contextHelp "Minimizes vertical emittance using envelope calculations."

proc MakeResultsFileOptimEmit {args} {
    APSParseArguments {input output}
    if [catch {exec sddssort $input -pipe=out -col=optimizationFunction \
		   | sddsprocess -pipe -clip=1,0,inv \
		   | sddsconvert -pipe -retain=col,*.K1 \
		   | sddstranspose -pipe -oldColumn=ElementName \
		   | sddsconvert -pipe -rename=col,Column=ParameterValue \
		   | sddsprocess -pipe=in $output -print=col,ElementParameter,K1 \
		   "-reedit=col,ElementName,%/.K1//"} result] {
	return -code error "Error making final results file: $result"
    }
}
}
#----------------------------------------------------------------------------------------------------------------------
# --- Scan frame ------------------------------------------------------------------------------------------------------
#----------------------------------------------------------------------------------------------------------------------

incr windex 
set twidget [lindex $commandWidgetList $windex]

APSFrame .frameScan -parent $twidget -label "SV scan parameters"
set wFrame $twidget.frameScan.frame
APSFrameGrid .grid -parent $wFrame -xList {x1 x2 x3}

set w $wFrame.grid.x1
APSLabeledEntry .scanRoot -parent $w \
    -label "Scan rootname:       " \
    -textVariable scanRoot -width $inputboxWidth \
    -contextHelp "Rootname for saving results fo the scan."
APSLabeledEntry .sv1 -parent $w \
    -label "Starting SV number:  " \
    -textVariable SVstart -width $inputboxWidth \
    -contextHelp "Scan over SV number. This is starting SV number."
APSLabeledEntry .sv2 -parent $w \
    -label "Ending SV number:  " \
    -textVariable SVend -width $inputboxWidth \
    -contextHelp "Scan over SV number. This is starting SV number."
APSLabeledEntry .sv3 -parent $w \
    -label "Number of steps:  " \
    -textVariable SVsteps -width $inputboxWidth \
    -contextHelp "Scan over SV number. This is starting SV number."
set w $wFrame.grid.x2
set w $wFrame.grid.x3

set runButtonScan $wFrame.runScan.button
APSButton .runScan -parent $wFrame -text "Run SV scan" -command \
    {
	APSSetVarAndUpdate status "Running SV scan..."
	set abortFile $workDir/abort.run
	set elementListFile $workDir/twissCorrElements.sdds
	if {[string compare $calcMode beta] == 0} {
	    set weightList [list $betaxWeight $betayWeight $etaxWeight $tunesWeight]
	} else {
	    set weightList [list $offdiagWeight $etayWeight]
	}
	if ![string length $measDispFile] {set measDispFile dummy}
	set paramFileListMeasured ""
	set paramFileListDesired ""
	if [string length $param1Measured] {lappend paramFileListMeasured $param1Measured}
	if [string length $param2Measured] {lappend paramFileListMeasured $param2Measured}
	if [string length $param3Measured] {lappend paramFileListMeasured $param3Measured}
	if [string length $param1Desired] {lappend paramFileListDesired $param1Desired}
	if [string length $param2Desired] {lappend paramFileListDesired $param2Desired}
	if [catch {MakeElementListFile -calcMode $calcMode -filename $elementListFile} result] {
	    APSSetVarAndUpdate status "MakeElementListFile: $result"
	    return
	}
	if {$matrixFileChoice == 1} {set matrixFile $matrixFilePrecalculated} else {set matrixFile $matrixFileWorkdir}
	set command "$locoBinDir/calculateTwissCorrection \
                       -calcMode $calcMode \
                       -mode scan \
		       -scanRoot $scanRoot \
                       -workDir $workDir \
		       -lteMeasured $lteMeasured \
		       -beamlineMeasured $beamlineMeasured \
		       -paramFileListMeasured \"$paramFileListMeasured\" \
		       -lteDesired $lteDesired \
		       -beamlineDesired $beamlineDesired \
		       -paramFileListDesired \"$paramFileListDesired\" \
		       -outputFile $workDir/$outputFile \
		       -elementListFile $elementListFile \
		       -weightList \"$weightList\" \
		       -calculateMatrix $calculateMatrix \
		       -useRelative $useRelative \
		       -SVstart $SVstart \
		       -SVend $SVend \
		       -SVsteps $SVsteps \
		       -matrixFile $matrixFile \
		       -corFraction $corFraction \
		       -useDQS $useDQS \
		       -splitTasks $splitTasks \
		       -iterations $iterations \
		       -useTunes $useTunes \
		       -useMeasDisp $useMeasDisp \
		       -measDispFile $measDispFile \
		       -abortFile $abortFile"
	catch {file delete $abortFile}
	if [catch {APSExecLog .calculateTwissCorrection \
		       -lineLimit 2048 -width 120 \
		       -name "Running Twiss Correction..." \
		       -unixCommand $command} pid] {
	    APSSetVarAndUpdate status "Error running calculateTwissCorrection: $pid"
	}
	update idletasks
    } -contextHelp "Runs scan over SV number using parameters from \"Calculate...\" tab."

APSButton .stop -parent $wFrame -text Stop -command {exec touch $abortFile} -contextHelp "Aborts whole run."

APSButton .plotScan -parent $wFrame -text "Plot scan results" -command {
    APSSetVarAndUpdate status "Plotting scan results..."
    switch $calcMode {
	beta {
	    exec sddsplot -graph=symbol,connect=subtype,vary=subtype -leg \
		-col=SV,rmsK1      -yscale=id=1 $scanRoot.results -col=SV,rmsTotal -yscale=id=2 $scanRoot.results -end \
		-col=SV,rms\[XYD\] -yscale=id=1 $scanRoot.results -col=SV,rmsN     -yscale=id=2 $scanRoot.results &
	}
	coupling {
	    exec sddsplot -graph=symbol,connect=subtype,vary=subtype -leg \
		-col=SV,rmsK1 -yscale=id=1 $scanRoot.results -col=SV,rmsTotal -yscale=id=2 $scanRoot.results -end \
		-col=SV,rms\[XY\] -yscale=id=1 $scanRoot.results -col=SV,rmsD -yscale=id=2 $scanRoot.results &
	}
    }
} -contextHelp "Plots rms values as a sunction of SV number."

APSButton .plotQuads -parent $wFrame -text "Plot quads" -command {
    APSSetVarAndUpdate status "Plotting quadrupoles..."
    exec sddsplot -graph=symbol,connect -split=page -sep -same -topline=@TopLine -title=@BottomLine\
	-col=ElementName,ParameterValue $scanRoot.output.param &
} -contextHelp "Plots quadsrupoles for different SV numbers."

#----------------------------------------------------------------------------------------------------------------------
# --- Setpoints frame -------------------------------------------------------------------------------------------------
#----------------------------------------------------------------------------------------------------------------------

incr windex 
set twidget [lindex $commandWidgetList $windex]

APSFrame .frame1 -parent $twidget
set w $twidget.frame1.frame
APSLabeledEntry .scrFileOld -parent $w \
    -label "Existing SCR file:     " \
    -textVariable oldSCRFile -width 50
if {[string compare $calcMode coupling] == 0} {
    APSLabeledEntry .resultsFile -parent $w \
	-label "Minimization result file: " \
	-textVariable resultsFile -width 50
    APSButton .butt1 -parent $w.resultsFile \
	-text "RM" -size small \
	-command {set resultsFile $workDir/$outputFile} \
	-contextHelp "Sets this field to the result of RM minimization."
    APSButton .butt2 -parent $w.resultsFile \
	-text "Ey" -size small \
	-command {set resultsFile $workDir/$optimRootname.results} \
	-contextHelp "Sets this field to the result of RM minimization."
}
APSLabeledEntry .burtFile -parent $w \
    -label "Output casr file:                     " \
    -textVariable casrFile -width 50
APSLabeledEntry .setpointsCorrFraction -parent $w \
    -label "Fraction of correction to apply: " \
    -textVariable setpointsCorrFraction -width 20
APSLabeledEntry .energy -parent $w \
    -label "Energy (GeV): " \
    -textVariable energy -width 20
if 0 {
    if {[string compare $calcMode beta] == 0} {
	APSRadioButtonFrame .setpointsMethod -parent $w \
	    -label "Use setpoints in calculations:        " \
	    -variable setpointsMethod -valueList {ideal actual} \
	    -buttonList {ideal actual} \
	    -orientation horizontal \
	    -commandList {{} {}} \
	    -contextHelp "Delta currents are calculated from delta K1 based on slopes at \"ideal\" or \"actual\" setpoints."
    }
}
set runButton1 $w.calcBurtFile.button
APSButton .calcBurtFile -parent $w -text "Generate casr file" -command {
    set scrFile /home/helios/oagData/SCR/snapshots/SR/$oldSCRFile
    switch $calcMode {
	beta {
	    if [catch {RemoveQuotations -string [exec sdds2stream $scrFile -para=SnapshotDescription]} descr] {
		APSSetVarAndUpdate status "Error reading SCR file $scrFile: $descr"
		return
	    }
	    APSDisableButton $runButton1
	    set description "Altered: $descr"
	    if [catch {CalculateCasrFile -oldSCRFile $scrFile -casrFile $casrFile -energy $energy -deltaK1File $workDir/$outputFile \
			   -corrFraction $setpointsCorrFraction} result] {
		APSSetVarAndUpdate status "CalculateCasrFile: $result"
		APSEnableButton $runButton1
		return
	    } else {
		APSSetVarAndUpdate status "Generate casr file: done."
	    }
	    if [catch {CalculateCasrFile -oldSCRFile $scrFile -casrFile $casrFile.diff -energy $energy -deltaK1File $workDir/$outputFile \
			   -corrFraction $setpointsCorrFraction -differential 1} result] {
		APSSetVarAndUpdate status "CalculateCasrFile: $result"
		APSEnableButton $runButton1
		return
	    } else {
		APSSetVarAndUpdate status "Generate casr differential file: done."
	    }
	}
	coupling {
	    APSDisableButton $runButton1
	    if [catch {CalculateCasrFile -oldSCRFile $scrFile -casrFile $casrFile -energy $energy \
			   -corrFraction $setpointsCorrFraction -deltaK1File $resultsFile} result] {
		APSSetVarAndUpdate status "CalculateCasrFile_Simple: $result"
		APSEnableButton $runButton1
		return
	    } else {
		APSSetVarAndUpdate status "Generate casr file: done."
	    }
	}
    }
    update idletasks
    APSEnableButton $runButton1
} -contextHelp "Calculates quad corrections and puts them into the casr file."

set plotIButton $w.plotI.button
APSButton .plotI -parent $w -text "Plot delta currents" -command {
    APSDisableButton $plotIButton
    switch $calcMode {
	beta {
	    exec sddsplot $casrFile.diff -col=ElementName,Value -graph=symbol,connect &
	}
	coupling {
	    exec sddsplot -graph=symbol,connect=subt,vary=subt "-ylabel=I (A)" \
		-col=ControlName,Value "-leg=spec=New value" $casrFile \
		-col=ControlName,OldValue "-leg=spec=Old value" $casrFile \
		-col=ControlName,DeltaValue "-leg=spec=Delta" $casrFile &
	}
    }
    update idletasks
    APSEnableButton $plotIButton
} -contextHelp "Plots quad corrections from the calculated casr file"

if {[string compare $calcMode coupling] == 0} {
    APSButton .apply -parent $w -text "Apply skew quad correction" -command {
	if ![file exists $casrFile] {
	    return -code error "Can't find file $casrFile"
	}
	if [catch {exec sddscasr -restore $casrFile -add} result] {
	    APSSetVarAndUpdate status "Error applying casr file: $result"
	} else {
	    APSSetVarAndUpdate etayCorrConfigStatus "Done."
	}
	update idletasks
    } -contextHelp "Applies the casr file calculated in this tab. Remember, that the PS limit is +-15A."
}


if {[string compare $calcMode beta] == 0} {
    APSFrame .frame3 -parent $twidget
    set w $twidget.frame3.frame
    APSLabeledEntry .description -parent $w \
	-label "New SCR description:     " \
	-textVariable description -width 53
    set runButton2 $w.doAlterFile.button
    APSButton .doAlterFile -parent $w -text "Alter SCR file" -command \
	{
	    APSDisableButton $runButton2
	    if [catch {AlterSnapshotFiles -casrFile $casrFile -scrFile $scrFile -description $description} result] {
		APSSetVarAndUpdate status "AlterSnapshotFiles: $result"
	    } else {
		APSSetVarAndUpdate status "Alter file: done."
	    }
	    update idletasks
	    APSEnableButton $runButton2
	} -contextHelp "Alters above scr file with the above output file."

    APSFrame .frame2 -parent $twidget -label "Results verification"
    set w $twidget.frame2.frame
    APSLabeledEntry .scrFileNew -parent $w \
	-label "Existing SCR file (after altering):   " \
	-textVariable newSCRFile -width 40
    
    set plotResultsButton $w.plotResults.button
    APSButton .plotResults -parent $w -text "Plot \"intended\" results" -command \
	{
	    APSDisableButton $plotResultsButton
	    APSSetVarAndUpdate status "Plotting after-correction beta functions..."
	    APSDisableButton $plotResultsButton
	    if [catch {CalculateTwissFunctionsAfterCorrection -workDir $workDir \
			   -lteMeasured $lteMeasured -beamlineMeasured $beamlineMeasured \
			   -param1Measured $param1Measured -param2Measured $param2Measured \
			   -param3Measured $param3Measured \
			   -lteDesired $lteDesired -beamlineDesired $beamlineDesired \
			   -param1Desired $param1Desired -param2Desired $param2Desired \
			   -outputFile $workDir/$outputFile -weightList $weightList -useRelative $useRelative \
			   -useTunes $useTunes -oldSCRFile $oldSCRFile -newSCRFile $newSCRFile \
			   -energy $energy} result] {
		APSSetVarAndUpdate status "CalculateTwissFunctionsAfterCorrection: $result"
	    }
	    update idletasks
	    APSEnableButton $plotResultsButton
	} -contextHelp "Takes \"old\" and \"new\" scr files from above; calculates applied quadrupole differencies using KnLValues; then outputs rms and plots the \"measured\" results similar to plots from the \"Calculate...\" tab."
}

#-------------------------------------------------------------------------------------------------------------------------
#-------------------------------------------------------------------------------------------------------------------------
#-------------------------------------------------------------------------------------------------------------------------

proc CalculateTwissFunctionsAfterCorrection {args} {
    global locoBinDir tmpDir measuredFiles desiredFiles achievedFiles calcMode
    APSParseArguments {workDir lteMeasured beamlineMeasured param1Measured param2Measured param3Measured \
			   lteDesired beamlineDesired param1Desired param2Desired useTunes useRelative \
			   outputFile weightList useRelative useTunes oldSCRFile newSCRFile energy}

    set tmpRoot $tmpDir/[APSTmpString]-twiAfterCor

    #------ Calculating new parameter file with scr file difference:
    set SCRFileOld /home/helios/oagData/SCR/snapshots/SR/$oldSCRFile
    set SCRFileNew /home/helios/oagData/SCR/snapshots/SR/$newSCRFile
    set xrefFile /home/helios/SR/controlFiles/SQ_xref.sdds

    #------ Creating KnLValues files:
    set BRhoPVName S:BRhoCALC
    set newScrRoot $tmpRoot.newScr
    set oldScrRoot $tmpRoot.oldScr
    foreach scrFile [list $SCRFileOld $SCRFileNew] rootname [list $oldScrRoot $newScrRoot] {
	if [catch {APSMpMagnetKnLValues -SCRFile $scrFile -xrefFileList $xrefFile \
		       -energy $energy  -BRhoPVName $BRhoPVName \
		       -outputFileDir [file dir $rootname] -outputFileRoot [file tail $rootname] \
		       -statusCallback "APSSetVarAndUpdate status" \
		       -abortVariable abortRun} result] {
	    return -code error "APSMpMagnetKnLValues: $result"
	}
    }
    #------ Calculating difference between two KnL files:
    set difParamFile $tmpRoot.diffParam
    exec sddschanges $newScrRoot.KnL -pipe=out -base=$oldScrRoot.KnL -change=Kn -copy=ElementName \
	| sddsconvert -pipe -rename=col,ChangeInKn=ParameterValue \
	| sddsprocess -pipe=in $difParamFile -print=col,ElementParameter,K1 -print=col,ParameterMode,differential

    #------ Calculating beta functions:
    set paramFileListMeasured ""
    set paramFileListDesired ""
    if [string length $param1Measured] {lappend paramFileListMeasured $param1Measured}
    if [string length $param2Measured] {lappend paramFileListMeasured $param2Measured}
    if [string length $param3Measured] {lappend paramFileListMeasured $param3Measured}
    if [string length $param1Desired] {lappend paramFileListDesired $param1Desired}
    if [string length $param2Desired] {lappend paramFileListDesired $param2Desired}
    set paramFileListAchieved [concat $paramFileListMeasured $difParamFile]
    set doneFile $tmpRoot.doneFile
    set elementListFile $workDir/twissCorrElements.sdds
    if [catch {MakeElementListFile -calcMode $calcMode -filename $elementListFile} result] {
	APSSetVarAndUpdate status "MakeElementListFile: $result"
	return
    }
    set command "$locoBinDir/calculateTwissCorrection \
                     -calcMode $calcMode \
                     -mode plot \
                     -workDir $workDir/tmp \
                     -lteMeasured $lteMeasured \
                     -beamlineMeasured $beamlineMeasured \
                     -paramFileListMeasured \"$paramFileListMeasured\" \
                     -twiMeasured $workDir/tmp/$measuredFiles(twiss) \
                     -lteDesired $lteDesired \
                     -beamlineDesired $beamlineDesired \
                     -paramFileListDesired \"$paramFileListDesired\" \
                     -twiDesired $workDir/tmp/$desiredFiles(twiss) \
		     -paramFileListAchieved \"$paramFileListAchieved\" \
                     -twiAchieved $workDir/tmp/$achievedFiles(twiss) \
                     -elementListFile $elementListFile \
                     -weightList \"$weightList\" \
                     -useTunes $useTunes \
                     -useRelative $useRelative \
                     -doneFile $doneFile"

    catch {file delete $doneFile}
    if [catch {APSExecLog .calculateTwissCorrection \
		   -lineLimit 2048 -width 120 \
		   -name "Running Twiss correction..." \
		   -unixCommand $command} pid] {
	APSSetVarAndUpdate status "Error running calculateTwissCorrection: $pid"
    }
    set counter 0
    APSSetVarAndUpdate status "Waiting (20 sec timeout)..."
    while {([file exists $doneFile] == 0) && ($counter < 20)} {
	after 1000
	incr counter
    }
    file delete $doneFile

    APSSetVarAndUpdate status "Plotting..."
    #------ Plotting results
    if [catch {PlotTwissFunctions -desiredFile $workDir/tmp/$desiredFiles(twiss) -measuredFile $workDir/tmp/$measuredFiles(twiss) \
		   -achievedFile $workDir/tmp/$achievedFiles(twiss) -workDir $workDir} result] {
	return -code error "PlotTwissFunctions: $result"
    }
}

#-------------------------------------------------------------------------------------------------------------------------

proc MakeElementListFile {args} {
    APSParseArguments {calcMode filename}
    if {[string compare $calcMode beta] == 0} {
	set sufListNameList [list quadSufList bpmSufList bpmSufList bpmSufList]
	set rootnameList [list quads xBpms yBpms dBpms]
	set listNameList [list quadList xbpmList ybpmList dbpmList]
    } else {
	set sufListNameList [list quadSufList hcorrSufList vcorrSufList bpmSufList bpmSufList bpmSufList]
	set rootnameList [list quads hCorrs vCorrs xBpms yBpms dBpms]
	set listNameList [list quadList hcorrList vcorrList xbpmList ybpmList dbpmList]
    }
    #------ Reading element lists:
    foreach sufListName $sufListNameList rootname $rootnameList listName $listNameList {
	    if [catch {GetElementList -sufListName $sufListName -rootname $rootname} $listName] {
		return -code error "GetElementList: [set $listName]"
	    }
	}
    #------ Writing element lists to file:
    set fileList ""
    if {[string compare $calcMode beta] == 0} {
	set elementListList [list $quadList $xbpmList $ybpmList $dbpmList]
	set extList [list Quad xBpm yBpm dBpm]
    } else {
	set elementListList [list $quadList $hcorrList $vcorrList $xbpmList $ybpmList $dbpmList]
	set extList [list Quad hCorr vCorr xBpm yBpm dBpm]
    }
    foreach elementList $elementListList ext $extList {
	set tmpFile $filename.$ext
	if [catch {exec sddsmakedataset $tmpFile \
		       -col=List,type=string -data=[join $elementList ,] \
		       -para=ListName,type=string -data=$ext} result] {
	    -return -code error "Error making elementlist file: $result"
	}
	lappend fileList $tmpFile
    }
    eval exec sddscombine $fileList $filename -overWrite
    eval file delete $fileList
}

#-------------------------------------------------------------------------------------------------------------------------

proc PlotTwissFunctions { args } {

    global tmpDir
    APSParseArguments {measuredFile desiredFile achievedFile workDir}

    set difFile $tmpDir/[APSTmpString].betaDiff
    set measuredBpms $workDir/tmp/measuredBpms.sdds

    exec sddsxref -nowarning $desiredFile $measuredFile -pipe=out -match=ElementName \
	-take=betax -rename=col,betax=betaxMeasured \
	-take=betay -rename=col,betay=betayMeasured \
	-take=etax  -rename=col,etax=etaxMeasured \
	| sddsxref -pipe $achievedFile -match=ElementName \
	-take=betax -rename=col,betax=betaxAchieved \
	-take=betay -rename=col,betay=betayAchieved \
	-take=etax  -rename=col,etax=etaxAchieved \
	| sddsprocess -pipe=in $difFile \
	"-def=col,dBetaxMeasured,betaxMeasured betax - betax /" \
	"-def=col,dBetaxAchieved,betaxAchieved betax - betax /" \
	"-def=col,dBetayMeasured,betayMeasured betay - betay /" \
	"-def=col,dBetayAchieved,betayAchieved betay - betay /" \
	"-def=col,dEtaxMeasured,etaxMeasured etax - " \
	"-def=col,dEtaxAchieved,etaxAchieved etax - " 

    exec sddsplot \
	-col=s,betax $measuredFile -title=Measured -topTitle -sep \
	-col=s,betax  $desiredFile -title=Desired  -topTitle -sep \
	-col=s,betax $achievedFile -title=Achieved -topTitle -sep -layout=1,3 -end \
	-col=s,betay $measuredFile -title=Measured -topTitle -sep \
	-col=s,betay  $desiredFile -title=Desired  -topTitle -sep \
	-col=s,betay $achievedFile -title=Achieved -topTitle -sep -layout=1,3 -end \
	-col=s,etax  $measuredFile -title=Measured -topTitle -sep \
	-col=s,etax   $desiredFile -title=Desired  -topTitle -sep \
	-col=s,etax  $achievedFile -title=Achieved -topTitle -sep -layout=1,3 -end &
    exec sddsplot \
	-col=s,dBetaxMeasured $difFile -title=Measured -topTitle -sep \
	-col=s,dBetaxAchieved $difFile -title=Achieved -topTitle -sep -layout=1,2 -end \
	-col=s,dBetayMeasured $difFile -title=Measured -topTitle -sep \
	-col=s,dBetayAchieved $difFile -title=Achieved -topTitle -sep -layout=1,2 -end \
	-col=s,dEtaxMeasured  $difFile -title=Measured -topTitle -sep \
	-col=s,dEtaxAchieved  $difFile -title=Achieved -topTitle -sep -layout=1,2 -end &
}

#-------------------------------------------------------------------------------------------------------------------------

proc PlotOrbits { args } {
    global measuredFiles achievedFiles desiredFiles workDir
    exec sddsplot -graph=line,vary -enum=inter=5 -sep=3 -groupby=nameinde "-topline=Y response to H correctors" -same \
	-col=BPMName,S* $workDir/tmp/$measuredFiles(hyrm) -leg=spec=Measured \
	-col=BPMName,S* $workDir/tmp/$desiredFiles(hyrm) -leg=spec=Ideal \
	-col=BPMName,S* $workDir/tmp/$achievedFiles(hyrm) -leg=spec=Achieved &
    exec sddsplot -graph=line,vary -enum=inter=5 -sep=3 -groupby=nameinde "-topline=X response to V correctors" -same \
	-col=BPMName,S* $workDir/tmp/$measuredFiles(vxrm) -leg=spec=Measured \
	-col=BPMName,S* $workDir/tmp/$desiredFiles(vxrm) -leg=spec=Ideal \
	-col=BPMName,S* $workDir/tmp/$achievedFiles(vxrm) -leg=spec=Achieved &
}

#-------------------------------------------------------------------------------------------------------------------------

proc MinimizeEy {args} {
    global locoBinDir calcMode workDir param1Measured param2Measured outputFile param3Measured lteMeasuredEmit beamlineMeasuredEmit \
	rfVoltage rfH beamEnergyEmit
    APSParseArguments {optimTerm optimTerm1 rootname}
    set paramFileListMeasured ""
    if [string length $param1Measured] {lappend paramFileListMeasured $param1Measured}
    if [string length $param2Measured] {lappend paramFileListMeasured $param2Measured}
    if [string length $param3Measured] {lappend paramFileListMeasured $param3Measured}
    if [string length $optimTerm1] {set optimTerm1String " -optimTerm1 \"$optimTerm1\" "} else {set optimTerm1String ""}
    set emitArrayList [list rfVoltage [expr $rfVoltage * 1e6] rfH $rfH energy [expr $beamEnergyEmit * 1e3]]
    set elementListFile $workDir/twissCorrElements.sdds
    if [catch {MakeElementListFile -calcMode $calcMode -filename $elementListFile} result] {
	APSSetVarAndUpdate status "MakeElementListFile: $result"
	return
    }
    set command "$locoBinDir/calculateTwissCorrection \
                     -calcMode $calcMode \
                     -mode minEmit \
                     -rootname $rootname \
                     -workDir $workDir \
                     -elementListFile $elementListFile \
                     -lteMeasured $lteMeasuredEmit \
                     -beamlineMeasured $beamlineMeasuredEmit \
                     -paramFileListMeasured \"$paramFileListMeasured\" \
                     -optimTerm \"$optimTerm\" \
                     $optimTerm1String \
	             -emitArrayList \"$emitArrayList\""
    if [catch {APSExecLog .minimizeEmittance \
		   -lineLimit 2048 -width 120 \
		   -name "Running emittance minimization..." \
		   -unixCommand $command} pid] {
	APSSetVarAndUpdate status "Error running calculateTwissCorrection: $pid"
    }
}

#-------------------------------------------------------------------------------------------------------------------------

proc CalculateEmittances {args} {
    set resultFile ""
    APSParseArguments {resultFile}
    global locoBinDir calcMode workDir lteMeasured beamlineMeasured lteDesired beamlineDesired param1Measured param2Measured \
	param1Desired param2Desired param3Measured \
	lteMeasuredEmit beamlineMeasuredEmit lteDesiredEmit beamlineDesiredEmit rfVoltage rfH beamEnergyEmit
    set paramFileListMeasured ""
    set paramFileListDesired ""
    if [string length $param1Measured] {lappend paramFileListMeasured $param1Measured}
    if [string length $param2Measured] {lappend paramFileListMeasured $param2Measured}
    if [string length $param3Measured] {lappend paramFileListMeasured $param3Measured}
    if [string length $param1Desired] {lappend paramFileListDesired $param1Desired}
    if [string length $param2Desired] {lappend paramFileListDesired $param2Desired}
    if [string length $resultFile] {set paramFileListAchieved [concat $paramFileListMeasured $resultFile]} else {set paramFileListAchieved ""}
    set emitArrayList [list rfVoltage [expr $rfVoltage * 1e6] rfH $rfH energy [expr $beamEnergyEmit * 1e3]]
    set command "$locoBinDir/calculateTwissCorrection \
                     -calcMode $calcMode \
                     -mode calcEmit \
                     -workDir $workDir/tmp \
                     -lteMeasured $lteMeasuredEmit \
                     -beamlineMeasured $beamlineMeasuredEmit \
                     -paramFileListMeasured \"$paramFileListMeasured\" \
                     -lteDesired $lteDesiredEmit \
                     -beamlineDesired $beamlineDesiredEmit \
                     -paramFileListDesired \"$paramFileListDesired\" \
		     -paramFileListAchieved \"$paramFileListAchieved\" \
	             -emitArrayList \"$emitArrayList\""
    if [catch {APSExecLog .calculateTwissCorrection \
		   -lineLimit 2048 -width 120 \
		   -name "Running emittance calculation..." \
		   -unixCommand $command} pid] {
	APSSetVarAndUpdate status "Error running calculateTwissCorrection: $pid"
    }
}

#-------------------------------------------------------------------------------------------------------------------------
proc CalculateCasrFile {args} {
    global calcMode
    set differential 0 
    APSStrictParseArguments {oldSCRFile casrFile corrFraction deltaK1File energy differential}
    if [string match "beta" $calcMode] {
	exec sddsprocess $deltaK1File $deltaK1File.fraction "-redef=col,ParameterValue,ParameterValue $corrFraction *"
	catch {file delete $casrFile}
	if [catch {APSDeltaK1FileToSetpoints -input $deltaK1File.fraction -output $casrFile -snapshotFile $oldSCRFile \
		       -energyGeV $energy -differential $differential} result] {
	    return -code error "APSDeltaK1FileToSetpoints: $result"
	}
	exec sddsprocess $casrFile -nowarning -scan=col,Value,ValueString,%lf -edit=col,ElementName,ControlName,%@:PS:SetCurrentC@@
	file delete $deltaK1File.fraction ${casrFile}~
    } else {
	#------ Based on /home/helios/oagData/sr/magnets/skewTransferFunction.sdds
	#------ Current is KNL / (BeamDynamicsTransferFunctionAve) -- column from the file
	set coeff [expr 1.0 / 2.832501e-03]
	#------ Lacking anything better, will use FDR numbers for calibration
	#------ FRD only gives the requirement for the bending angle for fast correctors as 300urad, but we know that the maximum is 500urad @15A
	#------ FRD also gives integrated skew quad field as 0.25 T (without specifying the current). Assuming it is for 15 A.
	# Current is KNL / (0.25 T / 20.014 Tm) * 15A * (Energy / 6GeV)
	# set coeff [expr 20.014 / 0.25 * 15]
	exec sddsprocess $deltaK1File -pipe=out "-redef=col,DeltaValue,ParameterValue $coeff * $corrFraction * $energy 6 / *,units=A" \
	    -edit=col,ControlName,ElementName,%@FS@SQ@ei@:PS:SetCurrentC -print=col,ValueString,%lf,DeltaValue \
	    | sddsxref -pipe $oldSCRFile -take=ValueString -match=ControlName -nowarning -rename=col,ValueString=OldValueString \
	    | sddsprocess -pipe -scan=col,OldValue,OldValueString,%lf,units=A "-redef=col,Value,OldValue DeltaValue +,units=A" -def=para,CalibCoeff,$coeff \
	    | sddsconvert -pipe=in $casrFile -retain=col,ControlName,ParameterMode,ParameterValue,DeltaValue,ValueString,OldValue,Value
    }
}
#-------------------------------------------------------------------------------------------------------------------------

proc CalculateBurtFile { args } {

    APSStrictParseArguments {oldSCRFile method burtFile corrFraction energy}

    global measuredFiles achievedFiles tmpDir workDir

    set BRhoPVName S:BRhoCALC
    set xrefFile /home/helios/SR/controlFiles/SQ_xref.sdds
    set templateFile /home/helios/oagData/sr/magnetConditioning/templates/SQ_stand.sdds
    set outputFileDir [file dirname $burtFile]
    set outputFileRoot [file tail $burtFile]

    set tmpRoot $tmpDir/[APSTmpString]-burt
    set orderFile $tmpRoot.order
    exec sddsprocess $workDir/tmp/$achievedFiles(outParam) -pipe=out "-match=col,ElementName=S*:Q\[12345\]" \
	-match=col,ElementParameter=K1 \
	| sddsprocess -pipe=in $orderFile "-edit=col,ControlName,ElementName,e i%:CurrentAO%" -def=col,Index,i_row
    switch -exact $method {
	ideal {
	    foreach localRoot [list achieved measured] paramFile [list $workDir/tmp/$achievedFiles(outParam) $workDir/tmp/$measuredFiles(outParam)] {
		if [catch {APSMpMagnetSetpoints -paramFile $paramFile -xrefFileList $xrefFile \
			       -templateFileList $templateFile \
			       -energy $energy -BRhoPVName $BRhoPVName \
			       -outputFileDir $outputFileDir -outputFileRoot $localRoot \
			       -statusCallback "APSSetVarAndUpdate status" \
			       -abortVariable abortRun} result] {
		    return -code error "APSMpMagnetSetpoints: $result"
		}
		exec sddsprocess $outputFileDir/$localRoot.snp $outputFileDir/$localRoot.vals \
		    -scan=col,Value,ValueString,%lf
		file delete $outputFileDir/$localRoot.snp $outputFileDir/$localRoot.std $outputFileDir/$localRoot.results
	    }
	    #--- Calculating difference between two burt files...
	    exec sddsxref $outputFileDir/achieved.vals $outputFileDir/measured.vals -pipe=out -take=Value \
		-match=ControlName -rename=col,Value=ValueOld \
		| sddsprocess -pipe "-redef=col,Value,Value ValueOld -" \
		| sddsprocess -pipe -reprint=col,ValueString,%lf,Value \
		| sddsconvert -pipe=in $burtFile -del=col,ValueOld
	    file delete $outputFileDir/achieved.vals $outputFileDir/measured.vals 
	}
	actual {
	    if [catch {APSMpMagnetKnLValues -SCRFile $oldSCRFile -xrefFileList $xrefFile \
			   -energy $energy  -BRhoPVName $BRhoPVName \
			   -outputFileDir $outputFileDir \
			   -outputFileRoot $outputFileRoot \
			   -statusCallback "APSSetVarAndUpdate status" \
			   -abortVariable abortRun} result] {
		return -code error "APSMpMagnetKnLValues: $result"
	    }
	    exec sddsprocess $workDir/tmp/$achievedFiles(outParam) $workDir/tmp/$achievedFiles(outParam).index -def=col,Index,i_row
	    exec sddsprocess $workDir/tmp/$measuredFiles(outParam) $workDir/tmp/$measuredFiles(outParam).index -def=col,Index,i_row
	    if [catch {exec sddschanges $workDir/tmp/$achievedFiles(outParam).index -pipe=out -base=$workDir/tmp/$measuredFiles(outParam).index \
			   -change=ParameterValue -copy=ElementName,ElementParameter,Index \
			   | sddsprocess -pipe "-match=col,ElementName=S*:Q\[12345\]" -match=col,ElementParameter=K1 \
			   | sddsxref -pipe $outputFileDir/$outputFileRoot.KnL -take=Kn -match=ElementName \
			   | sddsprocess -pipe "-redef=col,ParameterValue,Kn ChangeInParameterValue +" \
			   | sddsxref -pipe $workDir/tmp/$achievedFiles(outParam).index -nowarning \
			   -take=ElementType,ElementOccurence,ElementGroup -equate=Index \
			   | sddsconvert -pipe=in $outputFileDir/$outputFileRoot.newK1 \
			   -del=col,ChangeInParameterValue,Kn} result] {
		return -code error "Error calculating newK1 file: $result"
	    }
	    if [catch {
		exec sddsselect $workDir/tmp/$achievedFiles(outParam).index $outputFileDir/$outputFileRoot.newK1 \
		    $outputFileDir/$outputFileRoot.noQuads -equate=Index -invert
		exec sddscombine $outputFileDir/$outputFileRoot.noQuads $outputFileDir/$outputFileRoot.newK1 \
		    -pipe=out -merge \
		    | sddssort -pipe -col=Index \
		    | sddsconvert -pipe=in $outputFileDir/$outputFileRoot.newParam -del=col,Index
	    } result] {
		return -code error "Error creating new parameter file: $result"
	    }
	    if [catch {APSMpMagnetSetpoints -paramFile $outputFileDir/$outputFileRoot.newParam \
			   -xrefFileList $xrefFile \
			   -templateFileList $templateFile \
			   -energy $energy -BRhoPVName $BRhoPVName \
			   -outputFileDir $outputFileDir -outputFileRoot $outputFileRoot \
			   -statusCallback "APSSetVarAndUpdate status" \
			   -abortVariable abortRun} result] {
		return -code error "APSMpMagnetSetpoints: $result"
	    }
	    exec sddsxref $outputFileDir/$outputFileRoot.snp $oldSCRFile -pipe=out -nowarning \
		-take=ValueString -match=ControlName -rename=col,ValueString=OldValueString \
		| sddsprocess -pipe -scan=col,Value,ValueString,%lf -scan=col,OldValue,OldValueString,%lf \
		| sddsprocess -pipe "-redef=col,Value,Value OldValue -" \
		| sddsconvert -pipe=in $burtFile -del=col,OldValue,OldValueString
	    file delete $workDir/tmp/$achievedFiles(outParam).index $workDir/tmp/$measuredFiles(outParam).index $outputFileDir/$outputFileRoot.KnL \
		$outputFileDir/$outputFileRoot.newK1 $outputFileDir/$outputFileRoot.noQuads \
		$outputFileDir/$outputFileRoot.newParam $outputFileDir/$outputFileRoot.snp \
		$outputFileDir/$outputFileRoot.std $outputFileDir/$outputFileRoot.results
	}
    }
    if [catch {
	exec sddsxref $burtFile $orderFile -pipe=out -take=Index -match=ControlName \
	    | sddssort -pipe -col=Index \
	    | sddsprocess -pipe "-redef=col,Value,Value $corrFraction *" -reprint=col,ValueString,%lf,Value \
	    | sddsconvert -pipe=in $tmpRoot.sorted -del=col,Index
	file copy -force $tmpRoot.sorted $burtFile
	file delete $tmpRoot.sorted
    } result] {
	return -code error "Error sorting burt file: $result"
    }
}

#-----------------------------------------------------------------------------------------------------------------------

proc CalculateBurtFile_Simple { args } {
    APSStrictParseArguments {oldSCRFile burtFile corrFraction outputFile energy}

    #------ Below are Louis's comments copied from SRvertDispersionCorrection:
    # conversion factor
    # From magnetic measurement directory /usr6/apsmmf/sr_mag/sqskew/sqs002
    # I found *log files with the calibration factor 0.0358508 [T/A].
    # elegant uses magnetic length of 0.127 m
    #                
    # kl [m^-1] =  (Calibration) I / 23.349 T-m              
    #     
    # so 1A gives KL = 0.00153 or K = 0.0121
    # and K=1 m^2  gives I = 82.7 A

    #------ New skew quads that are on 6-pole corrector yoke have different calibration.
    # According to Louis, 150A gives 0.5T integrated strength.
    # That means K=1 m^-2 gives 700A (This is inconsistent and old data, see below)
    #------ Based on AOP-TN-2019-027:
    # K=1 m^2 gives 660 A

    set calibration0 82.7
    set calibration1 660
    set energyScaling [expr $energy / 7.0]
    exec sddsprocess $outputFile $burtFile.1 -match=col,ElementName=*QS "-edit=col,ControlName,ElementName,e i/:CurrentAO/" \
	"-redef=col,DeltaValue,ParameterValue $calibration0 * $corrFraction * $energyScaling *" -nowarning
    exec sddsprocess $outputFile $burtFile.2 -match=col,ElementName=*QS4 "-edit=col,ControlName,ElementName,e i/:CurrentAO/" \
	"-redef=col,DeltaValue,ParameterValue $calibration1 * $corrFraction * $energyScaling *" -nowarning
    exec sddscombine $burtFile.1 $burtFile.2 $burtFile -merge -overWrite
    file delete $burtFile.1 $burtFile.2

    exec sddsselect $oldSCRFile $burtFile -pipe=out -match=ControlName \
	| sddsprocess -pipe=in $burtFile.oldK1 -scan=col,OldValue,ValueString,%lf
    exec sddsxref $burtFile $burtFile.oldK1 -pipe=out -take=OldValue,Lineage,Count -match=ControlName -nowarning \
	| sddsprocess -pipe=in $burtFile.newK1 "-redef=col,NewValue,DeltaValue OldValue +"
    exec sddsprocess $burtFile.newK1 $burtFile -redef=col,Value,NewValue -reprint=col,ValueString,%lf,Value
    file delete $burtFile.oldK1
}

#-----------------------------------------------------------------------------------------------------------------------

proc AlterSnapshotFiles { args } {

    global tmpDir
    APSParseArguments {casrFile scrFile description}

    set tmpRoot $tmpDir/[APSTmpString]-alter

    set machineName SR
    set replacementFile $tmpRoot.replacement
    exec sddsxref $scrFile $casrFile $replacementFile -replace=col,ValueString -match=ControlName -leave=* -nowarning
    if {[string compare [file type $scrFile] link] == 0} {
	set sourceFile [file readlink $scrFile]
    } else {
	set sourceFile $scrFile
    }
    if [catch {APSSCRAlterSnapshot \
		   -sourceSnapshot  $sourceFile \
		   -description $description \
		   -replacementData $replacementFile -machine $machineName} result] {
        return -code error "APSSCRAlterSnapshot: $result" \
    }
    file delete $tmpRoot.replacement
}

#-----------------------------------------------------------------------------------------------------------------------
#-----------------------------------------------------------------------------------------------------------------------
#-----------------------------------------------------------------------------------------------------------------------

foreach option [list useMeasDisp derivativeFile calculateMatrix] {DisableWidgets -option $option}
set locoConfigDir /home/oxygen/SR/LOCO/CONFIG
set matrixFileChoice 1
set matrixFileWorkdir $workDir/twissCorrectionMatrix.sdds
set setpointsMethod actual
set casrFile $workDir/casr.file
set setpointsCorrFraction 1.0
set calculateMatrix 0
set calculateInverse 1
set useInvSolution 0
set useDQS 1
set splitTasks 20
set iterations 10
set locoResultFile dummy
set useMeasDisp 0
set lteMeasured $OAGGlobal(SRLatticesDirectory)/default/aps.lte
set lteDesired  $OAGGlobal(SRLatticesDirectory)/default/aps.lte
set lteMeasuredEmit $OAGGlobal(SRLatticesDirectory)/default/aps.lte
set lteDesiredEmit $OAGGlobal(SRLatticesDirectory)/default/aps.lte
set beamlineMeasured RING
set beamlineDesired  RING
set beamlineMeasuredEmit  RINGORBRF
set beamlineDesiredEmit  RINGORBRF
set energy 6.0
set rfVoltage 5.0
set rfH 1296
set beamEnergyEmit 6.0
set outputFile twissCorrection.out
set optimRootname minimizeEmit
set optimTerm "M1#@.s33m sqrt 6e-6 1e-6 segt"
set optimTerm1 ""
set optimIterList "1 5 500"
set scanRoot svScan

switch $calcMode {
    beta {
	set useRelative 1
	set useTunes 1
	set betaxWeight 1.0
	set betayWeight 1.0
	set etaxWeight  1.0
	set tunesWeight 300.0
	set SVratio 200
	set SVstart 100
	set SVend 300
	set SVsteps 5
	set corFraction 0.5
    }
    coupling {
	set useRelative 0
	set useTunes 0
	set offdiagWeight 1.0
	set etayWeight  1000.0
	set SVratio 50
	set SVstart 5
	set SVend 19
	set SVsteps 2
	set corFraction 1.0
    }
}

set param1Measured ""
set param2Measured ""
set param3Measured ""
set param1Desired ""
set param2Desired ""
set betaTargetFile ""

set  desiredFiles(outParam)  desired.param
set  desiredFiles(twiss)     desired.twi
set  desiredFiles(hyrm)      desired.hyrm
set  desiredFiles(vxrm)      desired.vxrm
set measuredFiles(outParam)  measured.param
set measuredFiles(twiss)     measured.twi
set measuredFiles(hyrm)      measured.hyrm
set measuredFiles(vxrm)      measured.vxrm
set achievedFiles(outParam)  achieved.param
set achievedFiles(twiss)     achieved.twi
set achievedFiles(hyrm)      achieved.hyrm
set achievedFiles(vxrm)      achieved.vxrm
