#!/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 twissBinDir /home/oxygen/SAJAEV/APPS/TWISSCOR
set workDir [exec pwd]
set outputStatusDevice statusScreen

if [info exists env(LOCO_TMPDIR)] {
    set tmpDir $env(LOCO_TMPDIR)
} else {
    set tmpDir $env(HOME)/tmp
}
set auto_path [linsert $auto_path 0 $locoBinDir/tclLib]

set tabFrameWidth 1050
set tabFrameHeight 310

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

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

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

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}${sector}$suffix
	    global $nameFlag
	    if [set $nameFlag] {
		lappend nameList ${sectorName}${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
}
#---------------------------------------------------------------------------------------------------------------------------

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

set deviceWidgetList [APSTabFrame .tabsMain -parent .userFrame -width $tabFrameWidth -height $tabFrameHeight \
                  -labelList "\"Quads\" \"Hor.BPMs\" \"Ver.BPMs\" \"Disp.BPMs\"" -label ""]

# APS SR element lists
set quadSufList   {A:Q1 A:Q2 A:Q3 A:Q4 A:Q5 B:Q5 B:Q4 B:Q3 B:Q2 B:Q1}
set bpmSufList    {A:P0 A:P1 A:P2 A:P3 A:P4 B:P5 B:P4 B:P3 B:P2 B:P1 B:P0}

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

APSSRSectorButtons .quadButtons -parent [lindex $deviceWidgetList 0] -rootname quads \
    -orientation horizontal \
    -label "Quads" -description "Quadrupole selections" \
    -itemList $quadSufList -packOption "-side top" \
    -itemLabelList $quadSufList -sectorControl 1

APSSRSectorButtons .hbpmButtons -parent [lindex $deviceWidgetList 1] -rootname xBpms \
    -orientation horizontal \
    -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

APSSRSectorButtons .vbpmButtons -parent [lindex $deviceWidgetList 2] -rootname yBpms \
    -orientation horizontal \
    -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

APSSRSectorButtons .dbpmButtons -parent [lindex $deviceWidgetList 3] -rootname dBpms \
    -orientation horizontal \
    -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


set commandWidgetList [APSTabFrame .actionTabs -parent .userFrame -width 850 -height 380 \
			   -labelList "\"Files...\" \"Calculate...\" \"Scan SV...\" \"Setpoints...\"" -label ""]

set w .userFrame 

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

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

APSFrame .frameMeasured -parent $twidget -label "Present (measured) lattice:"
set w $twidget.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 .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

APSFrame .frameDesired -parent $twidget -label "Desired (correction target) lattice:"
set w $twidget.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

APSFrame .frameResults -parent $twidget
set w $twidget.frameResults.frame
APSLabeledEntry .outputFile -parent $w \
    -label "Output file:               " \
    -textVariable outputFile -width $fileInputboxLength

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

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
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
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" \
    -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
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
APSLabeledEntry .derivativeFile -parent $wFrame \
    -label "Derivative matrix file: " \
    -textVariable matrixFile -width 80 \
    -contextHelp "File name for the derivative of the twiss functions."
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."
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
	set weightList [list $betaxWeight $betayWeight $etaxWeight $tunesWeight]
	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 $param1Desired] {lappend paramFileListDesired $param1Desired}
	if [string length $param2Desired] {lappend paramFileListDesired $param2Desired}
	if [catch {MakeElementListFile -filename $elementListFile} result] {
	    APSSetVarAndUpdate status "MakeElementListFile: $result"
	    return
	}
	set command "/home/oxygen/SAJAEV/APPS/TWISSCOR/calculateTwissCorrection \
                       -mode correct \
                       -workDir $workDir \
		       -lteMeasured $lteMeasured \
		       -beamlineMeasured $beamlineMeasured \
		       -paramFileListMeasured \"$paramFileListMeasured\" \
		       -lteDesired $lteDesired \
		       -beamlineDesired $beamlineDesired \
		       -paramFileListDesired \"$paramFileListDesired\" \
		       -outputFile $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 \
		       -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 .plotVar -parent $twidget -text "Plot quad corrections" -command {
    APSSetVarAndUpdate status "Plotting quadrupoles..."
    if [catch {
	set plotFile $tmpDir/[APSTmpString].plotQuadCorr
	exec sddsxref $outputFile $desiredFiles(outParam) -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 &
    } result] {
	APSSetVarAndUpdate status "$result"
    }
    update idletasks
} -contextHelp "Plots quad corrections."

APSButton .plotTwiss -parent $twidget -text "Plot twiss functions" -command {
    APSSetVarAndUpdate status "Plotting beta functions..."
    if [catch { PlotTwissFunctions \
		    -desiredFile  $desiredFiles(twiss) \
		    -measuredFile $measuredFiles(twiss) \
		    -achievedFile $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"

#----------------------------------------------------------------------------------------------------------------------
# --- 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 .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 "Calculate corrections" -command \
    {
	APSSetVarAndUpdate status "Running SV scan..."
	set abortFile $workDir/abort.run
	set elementListFile $workDir/twissCorrElements.sdds
	set weightList [list $betaxWeight $betayWeight $etaxWeight $tunesWeight]
	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 $param1Desired] {lappend paramFileListDesired $param1Desired}
	if [string length $param2Desired] {lappend paramFileListDesired $param2Desired}
	if [catch {MakeElementListFile -filename $elementListFile} result] {
	    APSSetVarAndUpdate status "MakeElementListFile: $result"
	    return
	}
	set command "/home/oxygen/SAJAEV/APPS/TWISSCOR/calculateTwissCorrection \
                       -mode scan \
                       -workDir $workDir \
		       -lteMeasured $lteMeasured \
		       -beamlineMeasured $beamlineMeasured \
		       -paramFileListMeasured \"$paramFileListMeasured\" \
		       -lteDesired $lteDesired \
		       -beamlineDesired $beamlineDesired \
		       -paramFileListDesired \"$paramFileListDesired\" \
		       -outputFile $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..."
    exec sddsplot -graph=symbol,connect=subtype,vary=subtype -leg \
	-col=SV,rmsK1 -yscale=id=1 twissScan.sdds -col=SV,rmsTotal -yscale=id=2 twissScan.sdds -end \
	-col=SV,rms\[XYD\] -yscale=id=1 twissScan.sdds -col=SV,rmsN -yscale=id=2 twissScan.sdds &
} -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 \
	-col=ElementName,ParameterValue $outputFile.scan &
} -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 (for altering):     " \
    -textVariable oldSCRFile -width 40
APSLabeledEntry .burtFile -parent $w \
    -label "Output burt file:                     " \
    -textVariable burtFile -width 40
APSLabeledEntry .alterFile -parent $w \
    -label "Output \"SCR-like\" file (for altering):" \
    -textVariable alterFile -width 40
APSLabeledEntry .setpointsCorrFraction -parent $w \
    -label "Fraction of correction to apply: " \
    -textVariable setpointsCorrFraction -width 20
APSLabeledEntry .energy -parent $w \
    -label "Energy: " \
    -textVariable energy -width 20

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 burt and scr-like file" -command \
    {
	set scrFile /home/helios/oagData/SCR/snapshots/SR/$oldSCRFile
	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 {CalculateBurtFile -oldSCRFile $scrFile -method $setpointsMethod \
		       -burtFile $burtFile -energy $energy \
		       -corrFraction $setpointsCorrFraction} result] {
	    APSSetVarAndUpdate status "CalculateBurtFile: $result"
	    APSEnableButton $runButton1
	    return
	} else {
	    APSSetVarAndUpdate status "Generate burt file: done."
	}
	if [catch {exec sddsxref -nowarning $scrFile $burtFile -pipe=out -take=Value -match=ControlName \
		       | sddsprocess -pipe -scan=col,OrigValue,ValueString,%lf \
		       | sddsprocess -pipe "-redef=col,OrigValue,OrigValue Value +" \
		       | sddsprocess -pipe -reprint=col,ValueString,%lf,OrigValue \
		       | sddsconvert -pipe=in $alterFile -del=col,Value -del=col,OrigValue
	} result] {
	    APSSetVarAndUpdate status "Error: $result"
	} else {
	    APSSetVarAndUpdate status "Generate SCR-like file: done."
	}
	update idletasks
	APSEnableButton $runButton1
    } -contextHelp "Calculates quad corrections and puts them into the burt file."

set plotIButton $w.plotI.button
APSButton .plotI -parent $w -text "Plot delta currents" -command \
    {
	APSDisableButton $plotIButton
	exec sddsplot $burtFile -col=ControlName,Value -graph=symbol,connect &
	update idletasks
	APSEnableButton $plotIButton
    } -contextHelp "Plots quad corrections from the calculated burt file"


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 -newFile $alterFile -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 \
		       -lteDesired $lteDesired -beamlineDesired $beamlineDesired \
		       -param1Desired $param1Desired -param2Desired $param2Desired \
		       -outputFile $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 tmpDir measuredFiles desiredFiles achievedFiles
    APSParseArguments {workDir lteMeasured beamlineMeasured param1Measured param2Measured \
			   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 $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 -filename $elementListFile} result] {
	APSSetVarAndUpdate status "MakeElementListFile: $result"
	return
    }
    set command "/home/oxygen/SAJAEV/APPS/TWISSCOR/calculateTwissCorrection \
                     -mode plot \
                     -workDir $workDir/tmp \
                     -lteMeasured $lteMeasured \
                     -beamlineMeasured $beamlineMeasured \
                     -paramFileListMeasured \"$paramFileListMeasured\" \
                     -twiMeasured $measuredFiles(twiss) \
                     -lteDesired $lteDesired \
                     -beamlineDesired $beamlineDesired \
                     -paramFileListDesired \"$paramFileListDesired\" \
                     -twiDesired $desiredFiles(twiss) \
		     -paramFileListAchieved \"$paramFileListAchieved\" \
                     -twiAchieved $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 $desiredFiles(twiss) -measuredFile $measuredFiles(twiss) \
		   -achievedFile $achievedFiles(twiss) -workDir $workDir} result] {
	return -code error "PlotTwissFunctions: $result"
    }
}

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

proc MakeElementListFile {args} {
    APSParseArguments {filename}
    #------ Reading element lists:
    foreach sufListName [list quadSufList bpmSufList bpmSufList bpmSufList] \
	rootname [list quads xBpms yBpms dBpms] listName [list quadList xbpmList ybpmList dbpmList] {
	    if [catch {GetElementList -sufListName $sufListName -rootname $rootname} $listName] {
		return -code error "GetElementList: [set $listName]"
	    }
	}
    #------ Writing element lists to file:
    set fileList ""
    foreach elementList [list $quadList $xbpmList $ybpmList $dbpmList] ext [list Quad xBpm yBpm dBpm] {
	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 - etax /" \
	"-def=col,dEtaxAchieved,etaxAchieved etax - 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 CalculateBurtFile { args } {

    APSStrictParseArguments {oldSCRFile method burtFile corrFraction energy}

    global desiredFiles measuredFiles achievedFiles tmpDir

    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 $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 $achievedFiles(outParam) $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 $achievedFiles(outParam) $achievedFiles(outParam).index -def=col,Index,i_row
	    exec sddsprocess $measuredFiles(outParam) $measuredFiles(outParam).index -def=col,Index,i_row
	    if [catch {exec sddschanges $achievedFiles(outParam).index -pipe=out -base=$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 $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 $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 $achievedFiles(outParam).index $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 AlterSnapshotFiles { args } {

    global tmpDir
    APSParseArguments {newFile scrFile description}

    set tmpRoot $tmpDir/[APSTmpString]-alter

    set machineName SR
    set replacementFile $tmpRoot.replacement
    exec sddsconvert $scrFile -pipe=out -del=col,ValueString \
	| sddsxref -pipe=in $newFile $replacementFile -take=ValueString -match=ControlName -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
}

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

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

DisableWidgets -option useMeasDisp
set matrixFile $workDir/twissCorrectionMatrix.sdds
set setpointsMethod actual
set burtFile $workDir/burt.file
set alterFile $workDir/correction.scr
set setpointsCorrFraction 1.0
set calculateMatrix 0
set calculateInverse 0
set useRelative 1
set useInvSolution 0
set SVratio 350
set useDQS 1
set splitTasks 8
set iterations 10
set corFraction 0.5
set betaxWeight 1.0
set betayWeight 1.0
set etaxWeight  1.0
set tunesWeight 300.0
set locoResultFile dummy
set useTunes 1
set useMeasDisp 0
set lteMeasured $OAGGlobal(SRLatticesDirectory)/default/aps.lte
set lteDesired  $OAGGlobal(SRLatticesDirectory)/default/aps.lte
set beamlineMeasured RING
set beamlineDesired  RING
set energy 7.0
set outputFile $workDir/twissCorrection.out

set param1Measured ""
set param2Measured ""
set param1Desired ""

set SVstart 100
set SVend 300
set SVsteps 5

set  desiredFiles(outParam)  $workDir/tmp/desired.param
set  desiredFiles(twiss)     $workDir/tmp/desired.twi
set measuredFiles(outParam)  $workDir/tmp/measured.param
set measuredFiles(twiss)     $workDir/tmp/measured.twi
set achievedFiles(outParam)  $workDir/tmp/achieved.param
set achievedFiles(twiss)     $workDir/tmp/achieved.twi
