# Procedures in this file
# APSSRConfigOrbitCorrection---essentially creates an entire application for
#   handling SR orbit correction configuration.
# APSSRConfigPlaneOrbitCorrection---creates a frame for SR orbit correction
#   config for the h or v plane.
# APSSRInstallOrbCorrFiles---changes the default orbit correction files, which
#   are the ones used by the brief and expert OC screens.
# APSFileSelectWidget---A customized file selection widget that supports path
#   components in a list.  Used for selection of configurations.
# APSPickFileFromDir---Another customized file selection widget.  Lists filenames
#   along with the Description data (SDDS files only).
# APSSRGenerateOrbCorrFiles---Generates and/or installs the inverse matrices for
#   orbit correction.
# APSIncrementConfigFilename---Increments the generation index on a configuration
#   name.
# APSSRWriteOrbitCorrectionConfig---Writes corrector and monitor selection data 
#   to disk.
# APSSRWritePlaneOrbitCorrectionConfig---Writes corrector and monitor selection data
#   for h or v plane to disk.  Used with APSSRConfigPlaneOrbitCorrection.
# APSCountSRConfig---Counts the number of items of a specified type that are
#   enabled by the configuration checkbuttons.
# APSWriteSRConfig---Writes to disk a general configuration grid based on the
#   configuration checkbuttons.  Used by APSSRWriteOrbitCorrectionConfig, for
#   example.
# APSReadOrbitCorrectionConfig---Reads an orbit correction configuration from
#   disk and sets checkbuttons accordingly.
# APSReadSRConfig---Reads a generation configuration grid from disk and
#   sets checkbuttons accordingly.  Used by APSReadOrbitCorrectionConfig,
#   for example.
# APSSRMonitorCheckButtons---Makes check-button grid for SR BPMs.
# APSSRCorrectorCheckButtons---Makes checkbutton grid for one plane of
#   SR correctors.
# APSSRSectorUnsetMissing---Unsets the checkbuttons for missing components.
# APSSRSectorButtons---Makes a general checkbutton grid for 40 sectors and
#   a specified number of items per sector.  Used by APSSRCorrectorCheckButtons
#   and APSSRMonitorCheckButtons.
# APSSRSectorGlobalButtons---Makes +All, -All, and Count buttons for a
#   checkbutton grid made by APSSRSectorButtons.
# APSSetSRSectorButtons---Sets or unsets all checkbuttons in an grid.
# APSSRSectorPositionButtons---Makes buttons for each "position" in a
#   checkbutton grid.  E.g., all A:P1's.
# APSSRSectorTogglePosition---Used by APSSRSectorPositionButtons to
#   toggle a "position" in a checkbutton grid.
# APSGetMissingBPMList---Figures out which BPMs are missing (i.e.,
#   which P0's) and returns a list of them.
# APSSRGetBadOrbitDevices---Gets lists of bad bpms or correctors 
#   from the new configuration files. 
# APSSRFreqGenerateOrbCorrFiles---Copied from BP5 correction configuration
#   application for use here in integrated application

# This procedure is obsolete as it is 
# superceded by APSSRConfigPlaneOrbitCorrection

set SRBPMSuffixList [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 C:P0]
set SRBPMSuffixLabelList [list A0 A1 A2 A3 A4 A5 A6 B6 B5 B4 B3 B2 B1 B0 C0]
set SRHCorrSuffixList [list A:FH1 A:H1 A:FH2 A:H7 B:H7 B:FH2 B:H1 B:FH1 A:Q4T B:Q4T A:Q5T B:Q5T A:M3T B:M3T A:Q8T B:Q8T A:M4T]
set SRVCorrSuffixList [list A:FV1 A:V1 A:FV2 A:V7 A:V8 B:V8 B:V7 B:FV2 B:V1 B:FV1]

set SRHCorrMissingList [list A:H2 A:H3 A:H8 B:H8 B:H3 B:H2]
set SRVCorrMissingList [list A:V2 A:V3 A:V8 B:V3 B:V2]
#set SRHCorrList [list A:H1 A:H7 A:H8 ]
#set SRVCorrList [list A:FV1 A:V1 A:FV2 A:V7 B:V8 B:V7 B:FV2 B:V1 B:FV1]
set SRHCorrLabelList [regsub -all "\:" $SRHCorrSuffixList ""]
set SRVCorrLabelList [regsub -all "\:" $SRVCorrSuffixList ""]

proc APSSRConfigOrbitCorrection {widget args} {
    set parent ""
    set rootname sconfig
    set fileFrame 1
    set buttonOrientation vertical
    set includeP0s 0
    set includeIDs 0
    set includeBMs 0
    APSStrictParseArguments {parent rootname fileFrame buttonOrientation includeP0s includeIDs includeBMs}

    global SRBPMSuffixList SRHCorrSuffixList SRVCorrSuffixList
    set BPMSuffixList [list A:P1 A:P2 A:P3 A:P4 A:P5 A:P6 B:P6 B:P5 B:P4 B:P3 B:P2 B:P1]
    if $includeP0s {
        set BPMSuffixList [concat A:P0 $BPMSuffixList B:P0 C:P0]
    }
    if $includeIDs {
        set BPMSuffixList [concat $BPMSuffixList IDFE-XBPM:P1us  IDFE-XBPM:P1ds  IDFE-XBPM:P2us IDFE-XBPM:P2ds]
    }
    if $includeBMs {
        set BPMSuffixList [concat $BPMSuffixList BMFE-XBPM:P1 BMFE-XBPM:P2]
    }
    switch -regexp $rootname {
        rf -
        h {
            set BPMMissingList [APSGetMissingBPMList -plane h]
        }
        v {
            set BPMMissingList [APSGetMissingBPMList -plane v]
        }
        default {
            set BPMMissingList [APSGetMissingBPMList -plane h]
        }
    }
    # Make a frame grid with three vertical areas.  "top" will contain the
    # checkbutton grids, and bot will contain the controls (read, write, etc.)
    APSFrameGrid $widget -parent $parent -yList {status top bot}

    # Make a dedicated scrolled status area for this configuration.
    global ${rootname}ConfigStatus
    set ${rootname}ConfigStatus ""
    APSScrolledStatus .scrolled -parent $parent$widget.status \
      -textVariable ${rootname}ConfigStatus \
      -width 110 -height 3 -lineLimit 1000 -label ""
    APSFrame .but -parent $parent$widget.top

    # Make the checkbutton grids
    set w $parent$widget.top.but.frame
    if [string compare $buttonOrientation vertical]==0 {
        set pOption "-side left"
    } else {
        set pOption "-side top"
    }
    APSSRMonitorCheckButtons .smbut -parent $w -rootname $rootname \
      -orientation $buttonOrientation \
      -packOption $pOption -includeP0s $includeP0s \
      -includeIDs $includeIDs -includeBMs $includeBMs
    APSSRCorrectorCheckButtons .shbut -parent $w -rootname ${rootname} \
      -plane H -orientation $buttonOrientation \
      -packOption $pOption 
    APSSRCorrectorCheckButtons .svbut -parent $w -rootname ${rootname} \
      -plane V -orientation $buttonOrientation \
      -packOption $pOption 

    if $fileFrame {
        # Make frames for read, write, etc. controls.  Will go into a 
        # widget swap frame.
        set frameHeight 150
        set frameWidth 900
        set w $parent$widget.bot.fileops.frame
        APSWidgetSwapFrame .fileops -parent $parent$widget.bot -label "" \
          -contextHelp "File operations frame for orbit correction configuration" \
          -widgetList "$w.lattice $w.read $w.good $w.write $w.refmat $w.matrix"  \
          -labelList [list Lattice... Read... Good... Write... {Reference matrices...} {Generate controllaw files...}] \
          -commandList [list {} {} {} "APSSetVarAndUpdate ${rootname}WriteDir \"\"" {} {}] \
          -height $frameHeight -width $frameWidth \
          -buttonSize small -buttonPosition 0
        pack propagate $parent$widget.bot.fileops.frame 0
        pack $parent$widget.bot.fileops -side top

        # Make lattice selection frame.
        global ${rootname}Lattice ${rootname}MainDir ${rootname}LatSubDir
        set ${rootname}Lattice default
        set ${rootname}MainDir /home/helios/oagData/sr/orbitControllaw
        set ${rootname}LatSubDir lattices
        APSFrame .lattice -parent $w -label "Lattice" -noPack 1 \
          -width $frameWidth -height $frameHeight -contextHelp \
          "Use this frame to specify the lattice directory name and main directory area.  You may also change the default lattice from here."
        set w0 $w.lattice.frame
        APSLabeledEntry .maindir -parent $w0 -label "Main directory: " \
          -textVariable ${rootname}MainDir -width 80 -contextHelp \
          "Enter the name of the main directory for the orbit correction system."
        APSFileSelectWidget .lattice -parent $w0 -label "Lattice: " \
          -pathVariableList [list ${rootname}MainDir ${rootname}LatSubDir] -mode directory -width 76 \
          -variable ${rootname}Lattice -incrementButtons 0 -contextHelp \
          "Enter the name of the lattice with which to work."
       #comment out this default button because it is dangerous to change the default lattice and it is not needed in this application, since we have another software for SR managers to change the default lattice. We had an occasion that it was pressed by a non-familiar person which caused the orbit correction failure and almost dumped the beam.
       # APSButton .default -parent $w0.lattice -text D -size small \
       #   -contextHelp "Makes the named file into the default lattice." \
        #  -command "APSMakeLink -confirm 1 -confirmMessage {Change default lattice? Are you sure?} -local 1 -log 1 -permissions 00775 -filename \[subst \$${rootname}MainDir/\$${rootname}LatSubDir/\$${rootname}Lattice\] -linkname \[subst \$${rootname}MainDir/\$${rootname}LatSubDir/default\]; set ${rootname}Lattice default"

        # Make configuration-read frame.
        global ${rootname}ReadFile ${rootname}ReadDescription ${rootname}Plane
        global ${rootname}FilterEnd1
        set ${rootname}Plane h
        set ${rootname}ReadFile h.default
        set ${rootname}ReadDescription ""
        set ${rootname}FilterEnd1 .*
        APSFrame .read -parent $w -label "Read configuration" -noPack 1 \
          -width $frameWidth -height $frameHeight -contextHelp \
          "Use this frame to read combined monitor and corrector configurations."
        set w0 $w.read.frame
        APSLabeledOutput .lattice -parent $w0 -label "Lattice: " -width 60 \
          -textVariable ${rootname}Lattice -contextHelp \
          "Shows the lattice of the configuration for which this read widget applies."
        APSFileSelectWidget .file -parent $w0 -variable ${rootname}ReadFile -label "Config: " \
          -pathVariableList [list ${rootname}MainDir ${rootname}LatSubDir ${rootname}Lattice] \
          -mode directory -filterVariableList \
          [list ${rootname}Plane ${rootname}FilterEnd1] -width 76 \
          -incrementButtons 1 -contextHelp \
          "Enter the name of the configuration file to read."
        APSLabeledOutput .descrip -parent $w0 -label "Description: " -width 76 \
          -textVariable ${rootname}ReadDescription -contextHelp \
          "Shows the description of the last-read configuration file."
        APSRadioButtonFrame .rb1 -parent $w0 -packOption "-side left" -label "Plane: " \
          -variable ${rootname}Plane -buttonList {H V} -valueList {h v} \
          -orientation horizontal -contextHelp \
          "Choose plane with which you are dealing.  Determines what configurations are viewable and what configuration names are generated."
        APSButton .io0 -parent $w0 -text Read(replace) -size small -command \
          "APSReadOrbitCorrectionConfig -rootname $rootname -filename \$${rootname}MainDir/\$${rootname}LatSubDir/\$${rootname}Lattice/\$${rootname}ReadFile/config -logic replace -includeP0s $includeP0s -includeIDs $includeIDs -includeBMs $includeBMs" \
          -contextHelp "Press to read data to replace the existing configuration, using the named configuration file."
        APSButton .io1 -parent $w0 -text Read(or) -size small -command \
          "APSReadOrbitCorrectionConfig -rootname $rootname -filename \$${rootname}MainDir/\$${rootname}LatSubDir/\$${rootname}Lattice/\$${rootname}ReadFile/config -logic or -includeP0s $includeP0s -includeIDs $includeIDs -includeBMs $includeBMs" \
          -contextHelp "Press to read data to or with the existing configuration, using the named configuration file."
        APSButton .io2 -parent $w0 -text Read(and) -size small -command \
          "APSReadOrbitCorrectionConfig -rootname $rootname -filename \$${rootname}MainDir/\$${rootname}LatSubDir/\$${rootname}Lattice/\$${rootname}ReadFile/config -logic and -includeP0s $includeP0s -includeIDs $includeIDs -includeBMs $includeBMs" \
          -contextHelp "Press to read data to and with the existing configuration, using the named configuration file."
        APSButton .io3 -parent $w0 -text Read(not) -size small -command \
          "APSReadOrbitCorrectionConfig -rootname $rootname -filename \$${rootname}MainDir/\$${rootname}LatSubDir/\$${rootname}Lattice/\$${rootname}ReadFile/config -logic not -includeP0s $includeP0s -includeIDs $includeIDs -includeBMs $includeBMs" \
          -contextHelp "Press to read data specifying elements to turn off, using the named configuration file."

        # Make the write-configuration frame
        global ${rootname}WriteDir 
        APSFrame .write -parent $w -label "Write configuration" -noPack 1 \
          -width $frameWidth -height $frameHeight -contextHelp \
          "Use this frame to write combined monitor and corrector configurations."
        set w0 $w.write.frame
        APSLabeledOutput .lattice -parent $w0 -label "Lattice: " -width 60 \
          -textVariable ${rootname}Lattice -contextHelp \
          "Shows the lattice of the configuration for which this write widget applies."
        #set ${rootname}WriteDir h.[clock format [clock seconds] -format %Y-%m%d].00
	set ${rootname}WriteDir ""
        APSFileSelectWidget .file -parent $w0 -variable ${rootname}WriteDir \
          -pathVariableList [list ${rootname}MainDir ${rootname}LatSubDir ${rootname}Lattice] \
          -label "Config: " -noSelect 0 -mode directory -incrementButtons 1 -width 76 -contextHelp \
          "Enter the name of the configuration to write." \
          -filterVariableList [list ${rootname}Plane ${rootname}FilterEnd1]
        APSButton .genname -parent $w0.file -text G -size small -command \
          "set ${rootname}WriteDir \[APSNextGenerationedName -directory \$${rootname}MainDir/\$${rootname}LatSubDir/\$${rootname}Lattice -name \$${rootname}Plane.\[clock format \[clock seconds\] -format %Y-%m%d\].00 -newFile 1 -separator .\]"
        APSLabeledEntry .descrip -parent $w0 -label "Description: " -width 76 \
          -textVariable ${rootname}WriteDescription -contextHelp \
          "Use to enter a description for the configuration to be written."
        APSRadioButtonFrame .rb1 -parent $w0 -packOption "-side left" -label "Plane: " \
          -variable ${rootname}Plane -buttonList {H V} -valueList {h v} \
          -orientation horizontal -contextHelp \
          "Choose plane with which you are dealing.  Determines what configurations are viewable and what configuration names are generated."
        APSButton .io -parent $w0 -text Write -size small -command \
          "APSSRWriteOrbitCorrectionConfig -interactive 1 -rootname $rootname -filename \$${rootname}MainDir/\$${rootname}LatSubDir/\$${rootname}Lattice/\$${rootname}WriteDir/config -description \$${rootname}WriteDescription -includeP0s $includeP0s -includeIDs $includeIDs -includeBMs $includeBMs -configName \$${rootname}WriteDir" \
          -contextHelp "Press to write data, using the named configuration file."

        # Make frame for read/write/apply of "good" component files
        global ${rootname}GoodHMonFile ${rootname}GoodVMonFile ${rootname}GoodHCorrFile ${rootname}GoodVCorrFile ${rootname}GoodDir
        APSFrame .good -parent $w -label "Good component files" -noPack 1 \
          -width $frameWidth -height $frameHeight -contextHelp \
          "Use this frame to mask the configuration using files that give lists of good monitors, horizontal correctors, and vertical correctors.  These files can be created using the read and write operations of this screen."
        set w0 $w.good.frame 
        set ${rootname}GoodDir goodComponents
        set ${rootname}GoodHMonFile hmon.default
        set ${rootname}GoodVMonFile vmon.default
        set ${rootname}GoodHCorrFile hc.default
        set ${rootname}GoodVCorrFile vc.default
        foreach Plane {H V} plane {h v} {
            APSFileSelectWidget .${plane}mon -parent $w0 -variable ${rootname}Good${Plane}MonFile \
              -pathVariableList [list ${rootname}MainDir ${rootname}GoodDir] \
              -label "${Plane}. Mon.:" -mode file -width 72 -incrementButtons 1 \
              -filter "${plane}mon.*" 
            APSButton .apply -parent $w0.${plane}mon -text A -size small \
              -contextHelp "Applies the file to the present configuration.  Beware of applying a file in the wrong slot---e.g., a monitor file in a corrector slot or vice-versa." \
              -command "APSReadSRConfig -rootname $rootname -filename \[subst \$${rootname}MainDir/\$${rootname}GoodDir/\$${rootname}Good${Plane}MonFile\] -logic and -nameTypeList Monitor -knownSuffixes \{$BPMSuffixList\} -missingList \{$BPMMissingList\}"
            APSButton .write -parent $w0.${plane}mon -text W -size small \
              -contextHelp "Writes the present $Plane monitor configuration to the named file." \
              -command "APSWriteSRConfig -interactive 1 -rootname $rootname -filename \[subst \$${rootname}MainDir/\$${rootname}GoodDir/\$${rootname}Good${Plane}MonFile\] -nameTypeList Monitor -suffixLists \{\{$BPMSuffixList\}\}"
            APSButton .default -parent $w0.${plane}mon -text D -size small \
              -contextHelp "Makes the named file into the default good ${Plane} monitor list." \
              -command "APSMakeLink -confirm 1 -confirmMessage {Change default good ${Plane} monitor list? Are you sure?} -local 1 -log 1 -permissions 00664 -filename \[subst \$${rootname}MainDir/\$${rootname}GoodDir/\$${rootname}Good${Plane}MonFile\] -linkname \[subst \$${rootname}MainDir/\$${rootname}GoodDir/${plane}mon.default\]; set ${rootname}Good${Plane}MonFile ${plane}mon.default"
            APSButton .genname -parent $w0.${plane}mon -text G -size small -command \
              "set ${rootname}Good${Plane}MonFile \[APSNextGenerationedName -directory \$${rootname}MainDir/\$${rootname}GoodDir -name ${plane}mon.\[clock format \[clock seconds\] -format %Y-%m%d\].00 -newFile 1 -separator .\]" \
              -contextHelp "Generates a unique, unused name for the good ${Plane} monitor list."
        }

        APSFileSelectWidget .hcorr -parent $w0 -variable ${rootname}GoodHCorrFile \
          -pathVariableList [list ${rootname}MainDir ${rootname}GoodDir] \
          -label "H. Corr:" -mode file -width 72 -incrementButtons 1 \
          -filter "hc.*"
        APSButton .apply -parent $w0.hcorr -text A -size small \
          -contextHelp "Applies the file to the present configuration.  Beware of applying a file in the wrong slot---e.g., a monitor file in a corrector slot or vice-versa." \
          -command "APSReadSRConfig -rootname $rootname -filename \[subst \$${rootname}MainDir/\$${rootname}GoodDir/\$${rootname}GoodHCorrFile\] -logic and -nameTypeList Corrector -knownSuffixes $SRHCorrSuffixList"
        APSButton .write -parent $w0.hcorr -text W -size small \
          -contextHelp "Writes the present horizontal corrector configuration to the named file." \
          -command "APSWriteSRConfig -interactive 1 -rootname $rootname -filename \[subst \$${rootname}MainDir/\$${rootname}GoodDir/\$${rootname}GoodHCorrFile\] -nameTypeList Corrector -suffixLists $SRHCorrSuffixList"
        APSButton .default -parent $w0.hcorr -text D -size small \
          -contextHelp "Makes the named file into the default good horizontal corrector list." \
          -command "APSMakeLink -confirm 1 -confirmMessage {Change default good horizontal corrector list? Are you sure?} -local 1 -log 1 -permissions 00664 -filename \[subst \$${rootname}MainDir/\$${rootname}GoodDir/\$${rootname}GoodHCorrFile\] -linkname \[subst \$${rootname}MainDir/\$${rootname}GoodDir/hc.default\]; set ${rootname}GoodHCorrFile hc.default"
        APSButton .genname -parent $w0.hcorr -text G -size small -command \
          "set ${rootname}GoodHCorrFile \[APSNextGenerationedName -directory \$${rootname}MainDir/\$${rootname}GoodDir -name hc.\[clock format \[clock seconds\] -format %Y-%m%d\].00 -newFile 1 -separator .\]" \
          -contextHelp "Generates a unique, unused name for the good horizontal corrector list."

        APSFileSelectWidget .vcorr -parent $w0 -variable ${rootname}GoodVCorrFile \
          -pathVariableList [list ${rootname}MainDir ${rootname}GoodDir] \
          -label "V. Corr:" -mode file -width 72 -incrementButtons 1 \
          -filter "vc.*"
        APSButton .apply -parent $w0.vcorr -text A -size small \
          -contextHelp "Applies the file to the present configuration.  Beware of applying a file in the wrong slot---e.g., a monitor file in a corrector slot or vice-versa." \
          -command "APSReadSRConfig -rootname $rootname -filename \[subst \$${rootname}MainDir/\$${rootname}GoodDir/\$${rootname}GoodVCorrFile\] -logic and -nameTypeList Corrector -knownSuffixes $SRVCorrSuffixList"
        APSButton .write -parent $w0.vcorr -text W -size small \
          -contextHelp "Writes the present vertical corrector configuration to the named file." \
          -command "APSWriteSRConfig -interactive 1 -rootname $rootname -filename \[subst \$${rootname}MainDir/\$${rootname}GoodDir/\$${rootname}GoodVCorrFile\] -nameTypeList Corrector -suffixLists $SRVCorrSuffixList"
        APSButton .default -parent $w0.vcorr -text D -size small \
          -contextHelp "Makes the named file into the default good vertical corrector list." \
          -command "APSMakeLink -confirm 1 -confirmMessage {Change default good vertical corrector list? Are you sure?} -local 1 -log 1 -permissions 00664 -filename \[subst \$${rootname}MainDir/\$${rootname}GoodDir/\$${rootname}GoodVCorrFile\] -linkname \[subst \$${rootname}MainDir/\$${rootname}GoodDir/vc.default\]; set ${rootname}GoodVCorrFile vc.default"
        APSButton .genname -parent $w0.vcorr -text G -size small -command \
          "set ${rootname}GoodVCorrFile \[APSNextGenerationedName -directory \$${rootname}MainDir/\$${rootname}GoodDir -name vc.\[clock format \[clock seconds\] -format %Y-%m%d\].00 -newFile 1 -separator .\]" \
          -contextHelp "Generates a unique, unused name for the good vertical corrector list."

        # Make the reference matrix selection frame
        global ${rootname}RefMatrix 
        set ${rootname}RefMatrix(h) h.default
        set ${rootname}RefMatrix(v) v.default
        APSFrame .refmat -parent $w -label "Reference matrices" -noPack 1 \
          -width $frameWidth -height $frameHeight -contextHelp \
          "Use this frame to select the names of the reference matrix files.  These are used together with configuration files to generate the inverse matrices for orbit correction."
        set w0 $w.refmat.frame
        global ${rootname}refMatrices
        set ${rootname}refMatrices refMatrices
        foreach plane {h v} {
            APSFileSelectWidget .${plane}ref -parent $w0 -mode file \
              -label "[string toupper $plane] plane: " -width 76 \
              -variable ${rootname}RefMatrix($plane) \
              -pathVariableList [list ${rootname}MainDir ${rootname}LatSubDir ${rootname}Lattice ${rootname}refMatrices] \
              -contextHelp \
              "Enter the name of the reference response matrix file for the $plane plane."
            APSButton .default -parent $w0.${plane}ref -text D -size small \
              -contextHelp "Makes the named file into the default $plane-plane reference matrix." \
              -command "APSMakeLink -confirm 1 -confirmMessage {Change reference matrix? Are you sure?} -local 1 -log 1 -permissions 00664 -filename \[subst \$${rootname}MainDir/\$${rootname}LatSubDir/\$${rootname}Lattice/\$${rootname}refMatrices/\$${rootname}RefMatrix($plane)\] -linkname \[subst \$${rootname}MainDir/\$${rootname}LatSubDir/\$${rootname}Lattice/\$${rootname}refMatrices/$plane.default\]; set ${rootname}RefMatrix($plane) $plane.default"
        }

        # Make the frame for computing the matrix and installing it.
        global ${rootname}Plane ${rootname}SingValues ${rootname}SVDanalysis ${rootname}SetupOutputDir 
        global ${rootname}DeleteModes 
	global ${rootname}TikhonovFilter ${rootname}TikhonovSVN ${rootname}TikhonovBeta ${rootname}TikhonovType
        APSFrame .matrix -parent $w -label "Compute matrix" -noPack 1 \
          -width $frameWidth -height $frameHeight -contextHelp \
          "Use this frame to generate the matrix for orbit correction from an existing configuration."
        set w0 $w.matrix.frame
        set ${rootname}SingValues 320
        set ${rootname}SVDanalysis 0
        set ${rootname}DeleteModes ""
	set ${rootname}TikhonovFilter 0
	set ${rootname}TikhonovSVN 0
	set ${rootname}TikhonovBeta 0
	set ${rootname}TikhonovType SVN
        APSFileSelectWidget .file -parent $w0 -variable ${rootname}WriteDir \
          -pathVariableList [list ${rootname}MainDir ${rootname}LatSubDir ${rootname}Lattice] \
          -filter "h.* v.*" \
          -filterVariableList [list ${rootname}Plane ${rootname}FilterEnd1] \
          -label "Config: " -noSelect 0 -mode directory \
          -incrementButtons 1 -width 76 -contextHelp \
          "Enter the name of the configuration to use." 
        APSButton .genname -parent $w0.file -text G -size small -command \
          "set ${rootname}WriteDir \[APSNextGenerationedName -directory \$${rootname}MainDir/\$${rootname}LatSubDir/\$${rootname}Lattice -name \$${rootname}Plane.\[clock format \[clock seconds\] -format %Y-%m%d\].00 -newFile 1 -separator .\]"

        frame $w0.f1 
        pack $w0.f1 -fill x
        APSLabeledEntry .le1 -parent $w0.f1 -packOption "-side left" -textVariable ${rootname}SingValues \
          -label "Number of singular values: " -width 8 -contextHelp \
          "Enter the number of singular values to keep."
        APSRadioButtonFrame .rb1 -parent $w0.f1 -packOption "-side left" -label "Plane: " \
            -variable ${rootname}Plane -buttonList {H V} -valueList {h v} \
            -orientation horizontal -contextHelp \
            "Choose plane for which to compute the matrix."
        APSButton .svd -parent $w0.f1 -packOption "-side left" -text "SVD Analysis" -size  small \
            -command "APSSRGenerateOrbCorrFiles -rootname $rootname -generate 1 -configFile \$${rootname}MainDir/\$${rootname}LatSubDir/\$${rootname}Lattice/\$${rootname}WriteDir/config -plane \$${rootname}Plane -referenceMatrix \$${rootname}MainDir/\$${rootname}LatSubDir/\$${rootname}Lattice/refMatrices/\$${rootname}RefMatrix(\$${rootname}Plane) -outputRoot \$${rootname}MainDir/\$${rootname}LatSubDir/\$${rootname}Lattice/\$${rootname}WriteDir/ -singularValues \$${rootname}SingValues -SVDanalysis 1" \
            -contextHelp \
            "Removes DC vectors from singular values decomposition. May help in horizontal plane convergence. Not recommended for vertical plane." 
        APSButton .gen -parent $w0.f1 -text Compute -size small -packOption "-side left" -command \
	    "APSSRGenerateOrbCorrFiles -rootname $rootname -generate 1 -configFile \$${rootname}MainDir/\$${rootname}LatSubDir/\$${rootname}Lattice/\$${rootname}WriteDir/config -plane \$${rootname}Plane -referenceMatrix \$${rootname}MainDir/\$${rootname}LatSubDir/\$${rootname}Lattice/refMatrices/\$${rootname}RefMatrix(\$${rootname}Plane) -outputRoot \$${rootname}MainDir/\$${rootname}LatSubDir/\$${rootname}Lattice/\$${rootname}WriteDir/ -singularValues \$${rootname}SingValues -SVDanalysis 0 -tikhonovFilter \$${rootname}TikhonovFilter -tikhonovSVN \$${rootname}TikhonovSVN -tikhonovBeta \$${rootname}TikhonovBeta -tikhonovType \$${rootname}TikhonovType"
        APSButton .default -parent $w0.f1 -text "Make Default" -size small -packOption "-side left" \
          -contextHelp "Makes the named configuration into the default corrector configuration for chosen plane." \
          -command "APSSRInstallOrbCorrFiles -rootname $rootname"
        APSLabeledEntry .deletemodes -parent $w0 -textVariable ${rootname}DeleteModes \
          -label "Mode to delete: " \
          -contextHelp "a list of modes to be deleted from SVD analysis" -width 80
	APSRadioButtonFrame .tik -parent $w0 -label "Use tikhonov filter?" -buttonList {Yes No} \
	    -valueList {1 0} -variable ${rootname}TikhonovFilter -orientation horizontal
	APSRadioButtonEntryFrame .par -parent $w0.tik -orientation horizontal \
	    -label "Tikhonov filter type:" -packOption "-side right"  \
	    -variable ${rootname}TikhonovType -buttonList {SVN_Number Beta}  -orientation horizontal \
	    -valueList {SVN Beta} -commandList [list "set ${rootname}TikhonovBeta 0" "set ${rootname}TikhonovSVN 0"] \
	    -entryVariableList [list ${rootname}TikhonovSVN ${rootname}TikhonovBeta] \
	    -entryWidth 10
	if {0} {
	APSLabeledEntryFrame .alpha -parent $w0.tik  -orientation horizontal  \
	    -label "  Tikhonov parameters: SVN/Beta:" -variableList [list ${rootname}TikhonovSVN ${rootname}TikhonovBeta] -width 15 \
	    -contextHelp "provide the SVN number or beta (fractional alpha) of the tikhonov filter, the singular value of the provided SVN number will be used as alpha of the tikhonov filter."
	}
    }
    APSSwapInWidget $widget.bot.fileops -parent $parent -swapIn $w.read
}

proc APSSRInstallOrbCorrFiles {args} {
    set rootname ""
    set application ""
    # no more than one below should be equal to 1
    set booster 0
    set bts 0
    APSStrictParseArguments {rootname application booster bts}
    global ${rootname}MainDir ${rootname}LatSubDir ${rootname}Lattice
    global ${rootname}WriteDir ${rootname}Plane ${rootname}ConfigStatus
    
    # verify the agreement between ${rootname}Plane and the correctors
    # present in the lattice configuration file
    set Plane [string toupper [set ${rootname}Plane]]
    set configFile [subst \$${rootname}MainDir/\$${rootname}LatSubDir/\$${rootname}Lattice/\$${rootname}WriteDir]/config
    set irmFile [subst \$${rootname}MainDir/\$${rootname}LatSubDir/\$${rootname}Lattice/\$${rootname}WriteDir]/irm
    if ![file exist $configFile] {
        return -code error "$configFile does not exist, please create it first!"
    }
    if $booster {
        set plane [set ${rootname}Plane]
        set DefaultType ${plane}.default
        if ![APSYesNoPopUp "Are you sure to install [set ${rootname}WriteDir] to $DefaultType?"] {
            return
        }
        APSMakeLink -local 1 -log 1 -permissions 00775 \
          -filename [subst \$${rootname}MainDir/\$${rootname}LatSubDir/\$${rootname}Lattice/\$${rootname}WriteDir] \
          -linkname [subst \$${rootname}MainDir/\$${rootname}LatSubDir/\$${rootname}Lattice/$DefaultType]
        return
    }
    global DefaultType cancel
    set DefaultType [set ${rootname}Plane].default
    if {$application=="RTFeedback"} {
        set choices [list [set ${rootname}Plane].default [set ${rootname}Plane].defaultXR]
    } else {
        if !$bts {
            set choices [list [set ${rootname}Plane].default [set ${rootname}Plane].defaultXR [set ${rootname}Plane].defaultMOFB]
        }
    }
    if !$bts {
        APSDialogBox .default -name "choose default type" -width 50 \
            -okCommand {set cancel 0} -cancelCommand {set cancel 1}
        APSLabel .info -parent .default.userFrame -text "Please choose the default type to make link to"
        APSRadioButtonFrame .choice -parent .default.userFrame -buttonList $choices \
            -valueList $choices -variable DefaultType -orientation horizontal -label ""
        tkwait window .default
        if $cancel {
            return
        }
        set PVType [exec sdds2stream $configFile -par=PVType]
        set bpmType [lindex $PVType 0]
        set corrType [lindex $PVType 1]
        if [string match "*XR*" $DefaultType] {
            if [catch {exec sddsprocess $configFile -pipe=out \
                           -match=par,NameType=MonitorNames \
                           -match=col,Name=*BM*,Name=*ID*,| -nowarnings \
                           | sdds2stream -pipe -rows=bar } rows] {
                return -code error $rows
            }
            if !$rows {
                return -code error "Wrong type chosen -- there are no Xray BPMs in config file.!"
            }
        }
        if [string match "*DP*" $DefaultType] {
            if {$bpmType!="DP" || $corrType != "DP" } {
                return -code error "Cannot make link to DP default: the bpm or corrector type is not DP!"
            }
            if {![APSMultipleChoice [APSUniqueName .] \
                      -question "Change a default DP orbit correction files? Are you sure?" -returnList {1 0} \
                      -labelList {Yes No}]} {
                return
            }
            if [regexp "XRDP" $DefaultType] {
                #check the singular values
                if [file exist $irmFile] {
                    set NSV [exec sdds2stream -par=NumberOfSingularValuesUsed $irmFile]
                    if {$NSV<50 || $NSV>60} {
                        if {![APSMultipleChoice [APSUniqueName .] \
                                  -question "The SV number of chosen config is $NSV (not within 50-60 range), install it as XRDP may cause orbit motion, are you sure to install it as XRDP?" -returnList {1 0} \
                                  -labelList {Yes No}]} {
                            return
                        }
                    }
                }
            }
        } else {
            if {$bpmType=="DP" || $corrType == "DP" } {
                return -code error "Cannot make link to default: the bpm or corrector type is DP type!"
            }
            if {![APSMultipleChoice [APSUniqueName .] \
                      -question "Change default orbit correction files? Are you sure?" -returnList {1 0} \
                      -labelList {Yes No}]} {
                return
            }
        }
    } else {
        # bts
        set $DefaultType default
    }
    APSMakeLink -local 1 -log 1 -permissions 00775 \
        -filename [subst \$${rootname}MainDir/\$${rootname}LatSubDir/\$${rootname}Lattice/\$${rootname}WriteDir] \
        -linkname [subst \$${rootname}MainDir/\$${rootname}LatSubDir/\$${rootname}Lattice/$DefaultType]
    
    APSSetVarAndUpdate ${rootname}ConfigStatus "[subst \$${rootname}WriteDir] installed as $DefaultType."
    set ${rootname}WriteDir $DefaultType
  
    if {$application=="RTFeedback"} {
        set plane [string tolower $Plane]
        global ${rootname}SingValues ${rootname}SVDanalysis 
	global ${rootname}TikhonovFilter ${rootname}TikhonovSVN ${rootname}TikhonovBeta ${rootname}TikhonovType
        global BPMLimit XBPMLimit corrLimit rangeErrorLimit S35DCCTLimitH S35DCCTLimitV 
        global dialogBoxResponse PVSuffix
        set S35DCCTLimitH 15
        set S35DCCTLimitV 15
        set BPMLimit 10
        set XBPMLimit 0.5
        set corrLimit 149.5
        set rangeErrorLimit 10
        set PVSuffix msAve
        set answer [APSMultipleChoice [APSUniqueName .] -question "If you made a change in RTFB BPMs in $plane.default,\nyou must\n\n1) press the \"Load Response Matrix\" button in \"SRFB Orbit Feedback Control\" application, and wait for completion.\n\n2) regenerate the compensation files and the controllaw files for each DC configuration. Press \"Regenerate\" to regenerate all necessary files, or \"Cancel\" to return. \n\nThe regeneration procedure takes about one minute.\n\nIf you did not make any BPM changes, you may press \"Cancel\"."  \
                      -labelList {Regenerate Cancel} -returnList {Regenerate Cancel} ]
        switch $answer {
            Cancel {
                APSSetVarAndUpdate ${rootname}ConfigStatus "The DC configurations did not change."
                return
            }
            Regenerate {
                set mainDir /home/helios/oagData/sr/orbitControllaw/lattices/default
                foreach dir [list $plane.default $plane.defaultDP $plane.defaultXR $plane.defaultXRDP \
                               $plane.defaultXRDP.fullSVs $plane.BPLDVerificationDP] {
                    if {![file exist $mainDir/$dir] || ![file exist $mainDir/$dir/config]} {
                        continue
                    }
                    APSSetVarAndUpdate ${rootname}ConfigStatus "Regenerate compensation files for $dir..."
                    if [catch {APSSRGenerateOrbCorrFiles -rootname $rootname -generate 1 \
                                 -configFile $mainDir/$dir/config -plane $plane \
                                 -referenceMatrix $mainDir/refMatrices/$plane.default \
                                 -outputRoot $mainDir/$dir -singularValues [set ${rootname}SingValues] \
                                 -SVDanalysis [set ${rootname}SVDanalysis] \
				   -tikhonovFilter [set ${rootname}TikhonovFilter] \
				   -tikhonovSVN [set ${rootname}TikhonovSVN] \
				   -tikhonovBeta [set ${rootname}TikhonovBeta] \
				   -tikhonovType [set ${rootname}TikhonovType] \
                                 -compensationConfigFile [subst \$${rootname}MainDir/\$${rootname}LatSubDir/\$${rootname}Lattice]/$DefaultType/config } result] {
                        return -code error $result
                    }
                }
                APSSetVarAndUpdate ${rootname}ConfigStatus "Regenerate controllaw files for DC configuration..."
                set dialogBoxResponse ""
                set win [APSUniqueName .]
                APSDialogBox $win -cancelCommand "set dialogBoxResponse cancel"  \
                  -okCommand "set dialogBoxResponse ok"  -name "Controllaw test file limits" 
                
                set w $win.userFrame
                APSLabeledEntry .le0 -parent $w -label "bpm limit (mm)" \
                  -textVariable BPMLimit -width 10
                APSLabeledEntry .le1 -parent $w -label "Xray bpm limit (mm)" \
                  -textVariable XBPMLimit -width 10
                APSLabeledEntry .le2 -parent $w -label "corrector limit (A)" \
                  -textVariable corrLimit -width 10
                APSLabeledEntry .le3 -parent $w -label "Range Error limit (A)" \
                  -textVariable rangeErrorLimit -width 10
                APSLabeledEntry .currLimitH -parent $w -label "S35DCCT lower limit (mA) for H plane" \
                  -textVariable S35DCCTLimitH -width 10 \
                  -contextHelp "Enter the lower limit of S35DCCT readback below which the sddscontrollaw correction iteration is skipped."
                APSLabeledEntry .currLimitV -parent $w -label "S35DCCT lower limit (mA) for V plane" \
                  -textVariable S35DCCTLimitV -width 10 \
                  -contextHelp "Enter the lower limit of S35DCCT readback below which the sddscontrollaw correction iteration is skipped."
		if {0} {
		APSRadioButtonFrame .pvSuffix -parent $w -label "bpm PV type" \
                  -variable PVSuffix -valueList {ms msAve mswAve} \
                  -buttonList {ms msAve mswAve} -orientation horizontal -contextHelp \
                  "Select the memory/scanner PV type (i.e. bpm data type)."
		}
                tkwait window $win
                update
                foreach dir [list $plane.default $plane.defaultDP $plane.defaultXR $plane.defaultXRDP \
                               $plane.defaultXRDP.fullSVs $plane.BPLDVerificationDP] {
                    if {![file exist $mainDir/$dir] || ![file exist $mainDir/$dir/config]} {
                        continue
                    }
                    if [catch {APSGenerateControllawFiles -regenerateFiles 1 \
                                 -dataDir $mainDir -directory $dir \
                                 -PVSuffix $PVSuffix -BPMLimit $BPMLimit -XBPMLimit $XBPMLimit \
                                 -corrLimit $corrLimit -rangeErrorLimit $rangeErrorLimit \
                                 -S35DCCTLimitH $S35DCCTLimitH -S35DCCTLimitV $S35DCCTLimitV \
                             } result] {
                        return -code error "GenerateFiles: $result"
                    }
                }
                APSSetVarAndUpdate ${rootname}ConfigStatus "Regenerate files done"
            }
        }
    }
}

proc APSUpdateTimeRegion {args} {
    set rootname ""
    APSParseArguments {rootname}
    global ${rootname}RefMatrix ${rootname}TimeRegion
    set refmatrix [set ${rootname}RefMatrix]
    
    if [regexp {region0} $refmatrix] {
        set ${rootname}TimeRegion region0
    } elseif [regexp {region1} $refmatrix] {
        set ${rootname}TimeRegion region1
    }  elseif [regexp {region2} $refmatrix] {
        set ${rootname}TimeRegion region2
    }  elseif [regexp {region3} $refmatrix] {
        set ${rootname}TimeRegion region3
    }  elseif [regexp {region4} $refmatrix] {
        set ${rootname}TimeRegion region4
    }  elseif [regexp {region5} $refmatrix] {
        set ${rootname}TimeRegion region5
    }  elseif [regexp {region6} $refmatrix] {
        set ${rootname}TimeRegion region6
    }  elseif [regexp {region7} $refmatrix] {
        set ${rootname}TimeRegion region7
    }  elseif [regexp {region8} $refmatrix] {
        set ${rootname}TimeRegion region8
    }  elseif [regexp {region9} $refmatrix] {
        set ${rootname}TimeRegion region9
    }  else {
        set ${rootname}TimeRegion ""
    }
}

proc APSFileSelectWidget {widget args} {
    set parent ""
    set variable ""
    set contextHelp ""
    set pathVariableList ""
    set filter *
    set filterVariableList ""
    set mode normal
    set incrementButtons 0
    set noPack 0
    set noSelect 0
    set label "File: "
    set width 20
    APSStrictParseArguments {parent variable contextHelp pathVariableList filter filterVariableList mode incrementButtons noPack noSelect label width}
    APSLabeledEntry $widget -parent $parent -label $label -contextHelp \
      $contextHelp -textVariable $variable -width $width
    if !$noSelect {
        if [string compare $mode normal] {
            APSButton .pick -parent $parent$widget -text P -size small -command \
              "set $variable \[APSPickFileFromDir [APSUniqueName .] -pathVariableList \[ list $pathVariableList \] -filter \"$filter\" -type $mode -default \$$variable -filterVariableList \[ list $filterVariableList \] \]"
        } else {
            APSButton .filesel -parent $parent$widget -size small -text F \
              -command "set $variable \[APSFileSelectDialog [APSUniqueName .] -path \[file dirname \$$variable\]\]" \
          }
    }
    if $incrementButtons {
        APSButton .plus -parent $parent$widget -size small  -text + \
          -command "APSIncrementConfigFilename -variable $variable" 
        APSButton .minus -parent $parent$widget -size small  -text - \
          -command "APSIncrementConfigFilename -variable $variable -amount -1" 
    }
}

proc APSPickFileFromDir {widget args} {
    set pathVariableList ""
    set directory .
    set filter *
    set filterVariableList ""
    set type file
    set default ""
    APSStrictParseArguments {pathVariableList filterVariableList type filter default directory}
    if [llength $filterVariableList] {
        set filter ""
        foreach item $filterVariableList {
            global $item
            set filter "${filter}[subst \$$item]"
        }
    }
    if [llength $pathVariableList] {
        set directory ""
        foreach item $pathVariableList {
            global $item
            set directory $directory/[subst \$$item]
       }
    }
    if {![file exists $directory] || ![file isdirectory $directory]} {
        return -code error "Not a directory : $directory"
    }
    set descDatabase 0

    # allows to match hv.* and h.* v.*
    if [regexp {hv|h|v} $filter plane] {
        if [file exist $directory/${plane}configDesc.sdds] {
            set descDatabase 1
        }
    } 
    if $descDatabase {
        set itemList [split [exec sdds2stream $directory/${plane}configDesc.sdds -col=Description] \n]
        set choiceList [exec sdds2stream $directory/${plane}configDesc.sdds -col=Filename]
    } else {
        set oldDir [pwd]
        cd $directory
        set fileList [lsort -decreasing [eval glob -nocomplain $filter]]
        cd $oldDir
        if [llength $fileList]==0 {
            return -code error "No files in directory: $directory"
        }
        set choiceList ""
        set itemList ""
        if {$type == "directory"} {
            foreach filename $fileList {
                set isDir [file isdirectory [file join $directory $filename]]
                if {$isDir} {
                    lappend choiceList $filename
                    if {[file type [file join $directory $filename]] == "link"} {
                        set link [file readlink [file join $directory $filename]]
                        # check for second level of link of type
                        # public/default -> ../etax10cm
                        if {[file type [file join $directory $link]]  == "link"} {
                            set link [file tail [file readlink [file join $directory $link]]]
                        }
                        lappend itemList "$filename -> $link"
                    } else {
                        if {[catch {
                            set fd [sdds open $directory/$filename/config.collapsed]
                            set description [sdds getColumn $fd Description]
                            sdds close $fd}]} {
                            lappend itemList $filename
                        } else {
                            lappend itemList "$filename -> [lindex $description 0]"
                        }
                    }
                }
            }
        } else {
            foreach filename $fileList {
                set isDir [file isdirectory [file join $directory $filename]]
                if {!$isDir} {
                    lappend choiceList $filename
                    if {[file type [file join $directory $filename]] == "link"} {
                        lappend itemList "$filename -> [file readlink [file join $directory $filename]]"
                    } else {
                        if {[catch {
                            set fd [sdds open $directory/$filename/config.collapsed]
                            set description [sdds getColumn $fd Description]
                            sdds close $fd}]} {
                            lappend itemList $filename
                        } else {
                            lappend itemList "$filename -> [lindex $description 0]"
                        }
                    }
                }
            }
        } 
    }
    if ![llength $choiceList] {
        return -code error "No choices in directory: $directory"
    }
    set value [APSChooseItemFromList -name ChoiceList -height 30 \
                 -itemList $itemList -returnList $choiceList -multiItem 0]
    if ![string length $value] {
        return $default
    }
    return $value
}

proc APSSRGenerateOrbCorrFiles {args} {
    set configFile ""
    set outputRoot ""
    set referenceMatrix ""
    set plane h
    set generate 0
    set install 0
    set rootname ""
    set singularValues 320
    set SVDanalysis 0
    set tikhonovFilter 0
    set tikhonovSVN 0
    set tikhonovBeta 0
    set tikhonovType SVN
    set compensationConfigFile ""
    set deleteVectors ""
    APSStrictParseArguments {configFile plane outputRoot referenceMatrix generate install rootname singularValues SVDanalysis compensationConfigFile deleteVectors tikhonovFilter tikhonovSVN tikhonovBeta tikhonovType}
    
    if {!$generate && !$install} return
    if {$tikhonovFilter} {
	if {$tikhonovType=="SVN" && !$tikhonovSVN} {
	    return -code error "APSSRGenerateOrbCorrFiles(0a): tikhonov SVN number not provided!"
	}
	if {$tikhonovType=="Beta" && !$tikhonovBeta} {
	    return -code error "APSSRGenerateOrbCorrFiles(0b): tikhonov beta value not provided!"
	}
    }
    if ![string length $rootname] {
        return -code error "APSSRGenerateOrbCorrFiles(0): programming error: no variable rootname"
    }

    if {![string length $configFile] || ![file exists $configFile]} {
        return -code error "APSSRGenerateOrbCorrFiles(1): supply a configuration file, or one that exists ($configFile was given)."
    }
    set configFile [APSResolveLink $configFile]

    if {[string length $compensationConfigFile] && ![file exists $compensationConfigFile]} {
        return -code error "APSSRGenerateOrbCorrFiles(1a): supply a configuration file for the compensation matrix, or one that exists ($compensationConfigFile was given)."
    }

    if {![string length $referenceMatrix] || ![file exists $referenceMatrix]} {
        return -code error "APSSRGenerateOrbCorrFiles(2): supply a reference matrix file, or one that exists ($referenceMatrix was given)."
    }
    set referenceMatrix [APSResolveLink $referenceMatrix]
    set origRefMatrix $referenceMatrix

    if ![string length $outputRoot] {
        return -code error "APSSRGenerateOrbCorrFiles(3): supply an output rootname."
    }

    global ${rootname}ConfigStatus
    set ${rootname}ConfigStatus "Working..."
    update
    if [catch {exec sddsprocess $configFile -pipe=out \
                 -match=parameter,NameType=CorrectorNames \
                 -filter=column,Flag,1,1 \
                 | sddscombine -merge -pipe \
                 | sdds2stream -pipe -column=Name} correctorNames] {
        return -code error "APSSRGenerateOrbCorrFiles(4): $correctorNames"
    }
    if [string length $compensationConfigFile] {
        if [catch {exec sddsprocess $compensationConfigFile -pipe=out \
                     -match=parameter,NameType=MonitorNames \
                     -filter=column,Flag,1,1 \
                     | sddscombine -merge -pipe \
                     | sdds2stream -pipe -column=Name} RTmonitorNames] {
            return -code error "APSSRGenerateOrbCorrFiles(4a): $RTmonitorNames"
        }
    }
    set tmpRoot /tmp/[APSTmpString]
    APSAddToTempFileList $tmpRoot.monFlags 
    if [catch {exec sddsprocess $configFile -pipe=out \
                 -match=parameter,NameType=MonitorNames \
                 -filter=column,Flag,1,1 \
                 | sddscombine -pipe -merge \
                 | tee $tmpRoot.monFlags \
                 | sdds2stream -pipe -column=Name} monitorNames] {
        return -code error "APSSRGenerateOrbCorrFiles(5): $monitorNames"
    }
    # row filter for reference matrix.
    set monitorNameMatchOption ""
    set IDBPMList ""
    set BMBPMList ""
    foreach item $monitorNames {
        switch -regexp $item {
            ID {
                lappend IDBPMList $item
            }
            BM {
                lappend BMBPMList $item
            }
        }
        if [string length $monitorNameMatchOption] {
            append monitorNameMatchOption ",BPMName=$item,|"
        } else {
            set monitorNameMatchOption "-match=column,BPMName=$item"
        }
    }
    if [string length $compensationConfigFile] {
        set RTmonitorNameMatchOption ""
        foreach item $RTmonitorNames {
            if [string length $RTmonitorNameMatchOption] {
                append RTmonitorNameMatchOption ",BPMName=$item,|"
            } else {
                set RTmonitorNameMatchOption "-match=column,BPMName=$item"
            }
        }
    }
    # create more monitors, i.e. add rows to response matrix
    set equationCmd ""
    if [llength $IDBPMList] {
        set IDBPMsKnownList [APSGetIDXRayBPMList -plane $plane]
        set IDBPMEqnList    [APSGetIDXRayEqnList -plane $plane]
        lappend equationCmd sddsprocess -pipe
        foreach item $IDBPMList {
            set index [lsearch -exact $IDBPMsKnownList $item]
            if $index==-1 {
                return -code error "APSSRGenerateOrbCorrFiles(7): no information on $item"
            }
            set equation [lindex $IDBPMEqnList $index]
            if ![string length $equation] {
                return -code error "APSSRGenerateOrbCorrFiles(8): no equation defined for $item."
            }
            lappend equationCmd "-define=column,$item,$equation"
        }
    }
    if [llength $BMBPMList] {
        set BMBPMsKnownList [APSGetBMXRayBPMList -plane $plane]
        set BMBPMEqnList    [APSGetBMXRayEqnList -plane $plane]
        if ![string length $equationCmd] {
            lappend equationCmd sddsprocess -pipe
        }
        foreach item $BMBPMList {
            set index [lsearch -exact $BMBPMsKnownList $item]
            if $index==-1 {
                return -code error "APSSRGenerateOrbCorrFiles(9): no information on $item"
            }
            set equation [lindex $BMBPMEqnList $index]
            if ![string length $equation] {
                return -code error "APSSRGenerateOrbCorrFiles(10): no equation defined for $item."
            }
            lappend equationCmd "-define=column,$item,$equation"
        }
    }
    if { [llength $IDBPMList] || [llength $BMBPMList] } {
        set tmpMatrix /tmp/[APSTmpString]
        if [catch {eval exec sddstranspose $referenceMatrix -pipe=out  \
                     | $equationCmd \
                     | sddstranspose -pipe=in $tmpMatrix \
                     -newColumnNames=OldColumnNames -oldColumnNames=BPMName} result] {
            return -code error "APSSRGenerateOrbCorrFiles(11): $result"
        }
        set referenceMatrix $tmpMatrix
    }
    set inverseOptions "-largestSingularValues=$singularValues"
    if $tikhonovFilter {
	if {$tikhonovType=="SVN"} {
	    if $tikhonovSVN {
		lappend inverseOptions "-tikhonov=SVN=[expr abs($tikhonovSVN)]"
	    }
	} elseif $tikhonovBeta {
	    lappend inverseOptions "-tikhonov=beta=[expr abs($tikhonovBeta)]"
	}
    }
    if [lsearch -exact [APSGetSDDSNames -fileName $tmpRoot.monFlags -class column] Weight]!=-1 {
        lappend inverseOptions "-weights=$tmpRoot.monFlags,name=Name,value=Weight"
    }
    if ![string length $compensationConfigFile] {
        if $SVDanalysis {
            set tmpOutput /tmp/[APSTmpString]
            APSAddToTmpFileList -ID APSSRGenerateOrbCorrFiles -fileList $tmpOutput
            if [catch {eval exec sddsconvert $referenceMatrix -pipe=out \
                         -retain=column,BPMName,[join $correctorNames ,] \
                         | sddsprocess -pipe $monitorNameMatchOption \
                         | sddspseudoinverse -pipe=in $tmpOutput $inverseOptions \
                         -umatrix=$outputRoot/u \
                         -vmatrix=$outputRoot/v \
                         -sfile=$outputRoot/s \
                     } result] {
                return -code error "APSSRGenerateOrbCorrFiles(svd): Error possibly caused by non-existent inverse. Check your configuration.\nProcessing command returns:\n$result"
            }
            set convertOption -retain=col,OldColumnNames
            for {set i 0} {$i<$singularValues} {incr i} {
                append convertOption ,SV[format %03d $i]
            }
            if [catch {exec sddsconvert $outputRoot/v $tmpOutput.v $convertOption} result] {
                return -code error "APSSRGenerateOrbCorrFiles(svd): $result:`"
            }
            # execution is blocked until the user makes the choice of
            # vectors in tksddsplot and quits.
            set returnList [exec tksddsplot $tmpOutput.v -col=OldColumnNames,SV* -sep \
                              -enum=interval=20 -selectFrames]
            set deleteVectors ""
            set index 0
            foreach selected $returnList {
                if {!$selected} {
                    lappend deleteVectors $index
                }
                incr index
            }
            global ${rootname}DeleteModes
            set ${rootname}DeleteModes $deleteVectors
            APSSetVarAndUpdate ${rootname}ConfigStatus "SVD analysis done."
            return
        }
        global ${rootname}DeleteModes
        if ![string length $deleteVectors] {
            if {[info exists ${rootname}DeleteModes] && 
                [llength [set ${rootname}DeleteModes]]} {
                set deleteVectors [set ${rootname}DeleteModes]
            }
        }
        # When the procedure is called from pem, say, there may
        # be no request to delete modes, and the variable
        # ${rootname}DeleteModes may not even be defined.
        # This variable is defined and set in the GUI.
        # Perhaps the variable should be in the arguments list
        # instead of a global.
        if [llength $deleteVectors] {
            lappend inverseOptions -deleteVectors=[join $deleteVectors ,]
        }
        if [catch {eval exec sddsconvert $referenceMatrix -pipe=out \
                     -retain=column,BPMName,[join $correctorNames ,] \
                     | sddsprocess -pipe $monitorNameMatchOption \
                     | tee $outputRoot/rm \
                     | sddspseudoinverse -pipe $inverseOptions \
                     | sddsconvert -pipe -rename=column,OldColumnNames=ControlName \
                     | sddsprocess -pipe=in $outputRoot/irm \
                     -print=parameter,ConfigurationFile,$configFile \
                     -print=parameter,ReferenceMatrix,$origRefMatrix} result] {
            return -code error "APSSRGenerateOrbCorrFiles(12): Error possibly caused by non-existent inverse. Check your configuration.\nProcessing command returns:\n$result"
        }
        #catch {exec sdds2headlessdata $outputRoot/rm $outputRoot/rm.dat -col=S* -order=column}
        #catch {exec sdds2headlessdata $outputRoot/irm $outputRoot/irm.dat -col=S* -order=column}
        #catch {file delete -force $outputRoot/irm~}
	catch {exec converttobinary.py -input $outputRoot/irm $outputRoot/irm.32bit}
        if [catch {exec sdds2stream -param=ConditionNumber $outputRoot/irm} condNumber] {
            return -code error "APSSRGenerateOrbCorrFiles(13): error getting condition number"
        }
        set ${rootname}ConfigStatus "[exec date] Done.  Condition number is $condNumber."
    } else {
        # get response matrix use bpms of RT system and 
        # correctors of DC correction.
        if [catch {eval exec sddsconvert $referenceMatrix -pipe=out \
                     -retain=column,BPMName,[join $correctorNames ,] \
                     | sddsprocess -pipe=in $outputRoot/rmFF \
                     $RTmonitorNameMatchOption \
                     -print=parameter,ConfigurationFile,$configFile \
                     -print=parameter,ReferenceMatrix,$origRefMatrix} result] {
            return -code error "APSSRGenerateOrbCorrFiles(14): $result"
        }
        set ${rootname}ConfigStatus "[exec date] Done."
    }
    update
    # make PVoffset request file columns ControlName and Offset
    # sddscasr mus tbe run and then processed to produce an offset file
    # before sddscontrollaw is launched or relaunched when setpoints or offsets are changed)
    switch $plane {
        h {set coord x}
        v {set coord y}
    }
    if [catch {exec sddsprocess $configFile -pipe=out \
                   -match=parameter,NameType=MonitorNames \
                   -filter=column,Flag,1,1 \
                   | sddscombine -pipe -merge  \
                   | sddsprocess -pipe=in  $outputRoot/setpoint.req \
                   -edit=col,ControlName,Name,ei/:${coord}:SetpointC/ \
               } result] {
        return -code error "APSSRGenerateOrbCorrFiles(15): Problem making $outputRoot/setpoint.req: $result"
    }
    if [catch {exec sddsprocess $configFile -pipe=out \
                   -match=parameter,NameType=MonitorNames \
                   -filter=column,Flag,1,1 \
                   | sddscombine -pipe -merge  \
                   | sddsprocess -pipe=in  $outputRoot/offset.req \
                   -edit=col,ControlName,Name,ei/:${coord}:OffsetM/ \
               } result] {
        return -code error "APSSRGenerateOrbCorrFiles(16): Problem making $outputRoot/offset.req: $results"
    }
    update
}

proc APSIncrementConfigFilename {args} {
    set variable ""
    set amount 1
    APSStrictParseArguments {variable amount}
    global $variable
    set filename [subst \$$variable]
    set index [string last . $filename]
    if $index!=-1 {
        set filename0 [string range $filename 0 $index]
        scan [string range $filename [expr $index+1] [expr $index+2]] "%ld" counter
        set filename1 [string range $filename [expr $index+3] end]
        incr counter $amount
        if $counter<0 {
            set counter 0
        }
        set $variable ${filename0}[format %02ld $counter]${filename1}
    }
}

proc APSSRWriteOrbitCorrectionConfig {args} {
    set rootname ""
    set filename ""
    set description ""
    set interactive 0
    set includeP0s 0
    set includeIDs 0
    set includeBMs 0
    set configName ""
    APSStrictParseArguments {rootname filename description interactive includeP0s includeIDs includeBMs configName}

    global SRBPMSuffixList SRHCorrSuffixList SRVCorrSuffixList
    if ![string length [string trim $configName]] {
        return -code error "APSSRWriteOrbitCorrectionConfig: supply a configuration name"
    }

    set path [file dirname $filename]
    set pathPart [file tail $path]

    #APSSRSectorUnsetMissing -rootname $rootname -missingList {S1A:H3 S39B:H1 S40A:H3}
    #APSSRSectorUnsetMissing -rootname $rootname -missingList {S1A:V3 S39B:V1 S40A:V3}
    set BPMList [list A:P1 A:P2 A:P3 A:P4 A:P5 A:P6 B:P6 B:P5 B:P4 B:P3 B:P2 B:P1]
    if $includeP0s {
        set BPMList [concat A:P0 $BPMList B:P0]
    }
    if $includeIDs {
        set BPMList [concat $BPMList IDFE-XBPM:P1us  IDFE-XBPM:P1ds  IDFE-XBPM:P2us IDFE-XBPM:P2ds]
    }
    if $includeBMs {
        set BPMList [concat $BPMList BMFE-XBPM:P1 BMFE-XBPM:P2]
    }
    if {$includeBMs || $includeIDs || $includeP0s} {
        switch -regexp $rootname {
            rf -
            h {
                APSSRSectorUnsetMissing -rootname $rootname \
                  -missingList [APSGetMissingBPMList -plane h]
            }
            v {
                APSSRSectorUnsetMissing -rootname $rootname \
                  -missingList [APSGetMissingBPMList -plane v]
            }
            default {
                APSSRSectorUnsetMissing -rootname $rootname \
                  -missingList [APSGetMissingBPMList -plane h]
            }
        }
    }
    if $interactive {
        set corCount(h) [APSCountSRConfig -rootname $rootname \
                           -itemList $SRHCorrSuffixList]
        set corCount(v) [APSCountSRConfig -rootname $rootname \
                           -itemList $SRVCorrSuffixList]

        set confirm 0
        set confirmQuery ""
        if {!$corCount(h) && !$corCount(v)} {
            set confirm 1
            append confirmQuery "\nNo correctors chosen."
        } else {
            set otherPlane v
            foreach plane {h v} {
                if [string match $plane.* $pathPart] {
                    if !$corCount($plane) {
                        set confirm 1
                        append confirmQuery "\nNo $plane correctors chosen for apparent $plane configuration."
                    }
                    if $corCount($otherPlane) {
                        set confirm 1
                        append confirmQuery "\n$otherPlane correctors chosen for apparent $plane configuration."
                    }
                }
                set otherPlane h
            }
        }
        if [APSCountSRConfig -rootname $rootname -itemList $BPMList]==0 {
            set confirm 1
            append confirmQuery "\nNo monitors chosen."
        }
        if {$confirm &&
            [APSMultipleChoice [APSUniqueName .] -question "Possible problem: $confirmQuery" \
               -labelList {Continue Cancel} -returnList {1 0}]==0} {
            return
        }
    }
    
    if ![file exists $path] {
        exec  mkdir $path
        #catch {exec setfacl -m mask:rwx $path}
    } else {
        if {$interactive && \
              [APSMultipleChoice [APSUniqueName .] -question "That configuration exists.  Overwrite?" \
                 -labelList {Yes No} -returnList {1 0}]==0} {
            return
        }
        set filesToDelete [glob -nocomplain $path/*]
        if [llength $filesToDelete] {
            if [catch {eval file delete -force -- $filesToDelete} result] {
                return -code error "APSSRWriteOrbitCorrectionConfig: $result"
            }
        }
    }
    APSWriteSRConfig -rootname $rootname -filename $filename \
      -nameTypeList {Monitor Corrector} -interactive $interactive \
      -suffixLists [list $BPMList $SRHCorrSuffixList $SRVCorrSuffixList] \
      -description $description
    catch {exec sddscollapse $filename $filename.collapsed}
}

proc APSCountSRConfig {args} {
    set rootname ""
    set sectorCount 40
    set itemList ""
    set missingList ""
    set sectorList ""
    APSStrictParseArguments {rootname sectorCount itemList missingList sectorList}

    if [llength $missingList] {
        APSSRSectorUnsetMissing -rootname $rootname -missingList $missingList
    }

    global ${rootname}ConfigStatus
    set count 0
    set sLen [llength $sectorList]
    for {set sector 1} {$sector<=$sectorCount} {incr sector} {
	if [llength $sectorList] {
	    if {$sector>$sLen} {
		break
	    }
	    set sector1 [lindex $sectorList [expr $sector-1]]
	} else {
	    set sector1 S[format %02d $sector]
	}
        foreach item $itemList {
            set nameFlag ${rootname}${sector1}$item
            global $nameFlag
            if [set $nameFlag] {
                incr count
            }
        }
    }
    return $count
}

proc APSWriteSRConfig {args} {
    set rootname ""
    set sectorCount 40
    set filename ""
    set PVTypeList ""
    set nameTypeList ""
    set suffixLists ""
    set description ""
    set interactive 0
    set booster 0
    set sectorList ""
    set updateDatabase 1
    APSStrictParseArguments {rootname sectorCount filename PVTypeList nameTypeList updateDatabase \
                               suffixLists description interactive booster sectorList}
    global env apsScriptHost
    if ![string length $filename] {
        return -code error "APSWriteSRConfig: No filename specified for orbit configuration"
    }
    set oldDir [pwd]
    if {$interactive && [file exists $filename] && \
          [APSMultipleChoice [APSUniqueName .] -question "$filename exists.  Overwrite?" \
             -labelList {Yes No} -returnList {1 0}]==0} {
        return 
    }
    global keepDays
    set keepDays 180
    if [llength $sectorList] {
	set sectorCount [llength $sectorList]
    }
    
    if $interactive {
        APSDialogBox .default -name "How many days do you want to keep this configuration?" -width 50 \
            -okCommand {set cancel 0} -cancelCommand {set cancel 1} -cancelButton 0
        APSLabeledEntry .info -parent .default.userFrame -label "Enter number of days to keep or -1 for keeping forever" -textVariable keepDays
        tkwait window .default
    }
    set origname $filename
    set filename ${filename}.tmp
    #update config description database
    set newConfig [file dir $origname]
    set rootDir [file dir $newConfig]
    set newConfig [file tail $newConfig]
    APSAddToTmpFileList -ID APSWriteConfig -fileList "$filename $filename.bpm $filename.corr $filename.bpm.type"
    set createTime [clock seconds]
    set createDate [clock format $createTime -format "%a %b %d %H:%M:%S %Y"]
    if [catch {sdds open ${filename} w} fid] {
        return -code error "APSWriteSRConfig: Unable to open file $filename: $fid"
    }
    if [catch {sdds defineColumn $fid Name -type SDDS_STRING
        sdds defineColumn $fid Flag -type SDDS_SHORT 
        sdds defineColumn $fid Weight -type SDDS_DOUBLE
        sdds defineColumn $fid Despike -type SDDS_LONG
        sdds defineParameter $fid Description -type SDDS_STRING
        sdds defineParameter $fid NameType -type SDDS_STRING
        sdds defineParameter $fid PVType -type SDDS_STRING
        sdds defineParameter $fid KeepDays -type SDDS_LONG
        sdds defineParameter $fid CreationTime -type SDDS_LONG -units seconds
        sdds defineParameter $fid CreationDate -type SDDS_STRING
        sdds defineParameter $fid User -type SDDS_STRING
        sdds defineParameter $fid Host -type SDDS_STRING
        sdds defineParameter $fid Time -type SDDS_LONG -units seconds
        sdds defineParameter $fid TimeStamp -type SDDS_STRING
	#if [string length $rampTimeRegion] {
	    #sdds defineParameter $fid RampStartTime -type SDDS_DOUBLE
	    #sdds defineParameter $fid RampEndTime -type SDDS_DOUBLE
	    #sdds defineParameter $fid BpmN -type SDDS_DOUBLE
         #   sdds defineParameter $fid TimeRegion -type SDDS_STRING
	#}
        sdds writeLayout $fid} result] {
        catch {sdds close $fid}
        return -code error "APSWriteSRConfig: problem defining SDDS elements: $result"
    }
    set nameTypeIndex -1
    global ${rootname}ConfigStatus
    if [llength $PVTypeList]!=[llength $nameTypeList] {
        set PVTypeList [APSReplicateItem -item unknown -number [llength $nameTypeList]]
    }
    foreach nameType $nameTypeList PVType $PVTypeList {
        incr nameTypeIndex
        set flags ""
        set names ""
        set weights ""
        set despikeFlags ""
        for {set sector 1} {$sector<=$sectorCount} {incr sector} {
	    if [llength $sectorList] {
		set sector1 [lindex $sectorList [expr $sector -1]]
	    } else {
		set sector1 S[format %02d $sector]
	    }
            foreach suffix [lindex $suffixLists $nameTypeIndex] {
                set nameFlag ${rootname}${sector1}$suffix
                set weightVar ${rootname}${sector1}${suffix}Weight
                set despikeVar ${rootname}${sector1}${suffix}Despike
                global $nameFlag $weightVar $despikeVar
                if [set $nameFlag] {
                    lappend flags 1
                    lappend names ${sector1}$suffix
                    if [info exists $weightVar] {
                        lappend weights [set $weightVar]
                    } else {
                        lappend weights 1.0
                    }
                    if [regexp {(BM)|(ID)} $nameFlag] {
                        lappend despikeFlags 0
                    } else {
                        if [info exists $despikeVar] {
                            lappend despikeFlags [set $despikeVar]
                        } else {
                            lappend despikeFlags 1
                        }
                    }
                }
            }
        }
        if [llength $flags]==0 continue
        APSSetVarAndUpdate ${rootname}ConfigStatus "[exec date] [llength $flags] $nameType"
        if [catch {sdds startPage $fid [expr 360*20] 
            sdds setParameter $fid Description $description
            sdds setParameter $fid PVType $PVType 
            sdds setParameter $fid KeepDays $keepDays
            sdds setParameter $fid CreationTime $createTime
            sdds setParameter $fid CreationDate $createDate
            sdds setParameter $fid NameType ${nameType}Names
            sdds setParameter $fid User $env(USER)
            sdds setParameter $fid Host $apsScriptHost
            sdds setParameter $fid Time $createTime
            sdds setParameter $fid TimeStamp $createDate } result] {
            catch {sdds close $fid}
            return -code error "APSWriteSRConfig: SDDS problem: $result"
        }
	#if [string length $rampTimeRegion] {
	   # sdds setParameter $fid RampStartTime $startRamp
	    #sdds setParameter $fid RampEndTime $endRamp
	   # sdds setParameter $fid BpmN $BPMTime
         #   sdds setParameter $fid TimeRegion $rampTimeRegion
	#}
       # foreach column {names flags weights} {
       #     APSSetVarAndUpdate ${rootname}ConfigStatus [llength $column]
       # }
        if [catch {eval sdds setColumn $fid Name $names
            eval sdds setColumn $fid Flag $flags 
            eval sdds setColumn $fid Weight $weights
            eval sdds setColumn $fid Despike $despikeFlags
            sdds writePage $fid} result] {
            catch {sdds close $fid}
            return -code error "APSWriteSRConfig: SDDS problem: $result"
        }
    }
    if [catch {sdds close $fid} result] {
        return -code error "APSWriteSRConfig: SDDS problem: $result"
    }
    global ${rootname}ConfigStatus
    if !$booster {
        set bpmconfig /home/helios/oagData/sr/BPMStatus/config.sdds
        if [catch {exec sddsprocess $filename -match=par,NameType=MonitorNames $filename.bpm
            exec sddsprocess $filename -match=par,NameType=MonitorNames,! $filename.other \
                     -print=col,ElectronicsType,\"\"
            exec sddsxref $filename.bpm $bpmconfig -match=Name=DeviceName \
                     -take=ElectronicsType $filename.bpm.type
            exec sddscombine $filename.bpm.type $filename.other $origname -overwrite} result] {
            return -code error "APSWriteSRConfig: $result"
        }
    } else {
	exec mv $filename $origname
    }
   
    if $updateDatabase {
	set ${rootname}ConfigStatus "[exec date] Update config description database..."
	if [catch {APSUpdateConfigDescriptionDatabase -newConfig $newConfig \
		       -dataDir $rootDir -booster $booster } result] {
	    return -code error "APSWriteSRConfig: $result"
	}
	set ${rootname}ConfigStatus "[exec date] Update config description database done"
    }
    cd $oldDir
    set ${rootname}ConfigStatus "[exec date] Wrote configuration to $origname"
    update
}

proc APSReadOrbitCorrectionConfig {args} {
    set rootname ""
    set filename ""
    set logic replace
    set includeP0s 0
    set includeIDs 0
    set includeBMs 0
    #booster=1 means for booster
    set booster 0 
    set bts 0
    set sectorCount 40
    set nameTypeList {Corrector Monitor}
    set application DCOrbitCorrection
    APSStrictParseArguments {rootname filename logic includeP0s includeIDs includeBMs \
                               booster sectorCount nameTypeList application}
    global ${rootname}BadBPMList SRBPMSuffixList SRHCorrSuffixList SRVCorrSuffixList
    if {![info exists ${rootname}BadBPMList]} {
        set ${rootname}BadBPMList ""
    }
    if !$booster {
        #SR
        set BPMList $SRBPMSuffixList
        if $includeIDs {
            set BPMList [concat $BPMList IDFE-XBPM:P1us  IDFE-XBPM:P1ds  IDFE-XBPM:P2us IDFE-XBPM:P2ds]
        }
        if $includeBMs {
            set BPMList [concat $BPMList BMFE-XBPM:P1 BMFE-XBPM:P2]
        }
        switch -regexp $rootname {
            rf {
                set BPMMissingList [APSGetMissingBPMList -plane h]
                set missingList "$BPMMissingList"
                set corList ""
            }
            h {
                set BPMMissingList [APSGetMissingBPMList -plane h]
                set missingList "$BPMMissingList [set ${rootname}BadBPMList]"
                set corList $SRHCorrSuffixList
            }
            v {
                set BPMMissingList [APSGetMissingBPMList -plane v]
                set missingList "$BPMMissingList [set ${rootname}BadBPMList]"
                set corList $SRVCorrSuffixList
            }
            default {
                set BPMMissingList [APSGetMissingBPMList -plane h]
                set missingList $BPMMissingList
                set corList [concat $SRHCorrSuffixList $SRVCorrSuffixList]
            }
        }
	set sectorList ""
    } else {
        # booster, unchanged in 2024
        set BPMList {P1 P2 }
        switch -regexp $rootname {
            h {
                set corList H
            }
            v {
                set corList V
            }
            default {
                set corList {H V}
            }
        }
        set missingList B2C9V
	set sectorList ""
	for {set b 1} {$b<5} {incr b} {
	    for {set c 0} {$c<10} {incr c} {
		lappend sectorList B${b}C$c
	    }
	}
    }
    set suffixList [concat $BPMList $corList]
    if [catch {APSReadSRConfig -rootname $rootname -filename $filename -logic $logic \
                 -nameTypeList $nameTypeList -sectorList $sectorList \
                 -knownSuffixes $suffixList -booster $booster \
                 -missingList $missingList -application $application } description] {
        return -code error $description
    }
    global ${rootname}ReadDescription
    set ${rootname}ReadDescription $description
}

proc APSReadSRConfig {args} {
    set rootname ""
    set sectorCount 40
    set filename ""
    set logic replace
    set nameTypeList ""
    set knownSuffixes ""
    set missingList ""
    set booster 0
    set sectorList ""
    set application DCOrbitCorrection
    APSStrictParseArguments {rootname sectorCount filename logic nameTypeList knownSuffixes missingList \
                           booster sectorList application}
    
    if ![string length $nameTypeList] {
        return -code error "APSReadSRConfig: nameTypeList argument not given or invalid"
    }
    if ![string length $filename] {
        return -code error "APSReadSRConfig: No filename specified for orbit configuration"
    }
    if ![file exists $filename] {
        return -code error "APSReadSRConfig: File $filename not found."
    }
    set tmpRoot /tmp/[APSTmpString]
    set selectionFiles ""
    foreach nameType $nameTypeList {
        APSAddToTempFileList $tmpRoot.${nameType}1
        APSAddToTempFileList $tmpRoot.${nameType}2
        APSAddToTempFileList $tmpRoot.${nameType}
        if [catch {exec sddsprocess $filename $tmpRoot.${nameType}1 -nowarning \
                     -match=parameter,NameType=${nameType}Names \
                     "-test=parameter,n_rows 0 >" \
                     -filter=column,Flag,1,1 
            exec sddsprocess $filename $tmpRoot.${nameType}2 -nowarning \
                     -match=parameter,NameType=Not${nameType}Names \
                     "-test=parameter,n_rows 0 >" \
                     -filter=column,Flag,0,0 
            exec sddscombine -merge $tmpRoot.${nameType}1 $tmpRoot.${nameType}2 \
                     $tmpRoot.$nameType} result] {
            return -code error "Problem making list of included $nameType items: $result"
        }
        lappend selectionFiles $tmpRoot.$nameType
        if [catch {exec sdds2stream $tmpRoot.$nameType -parameter=PVType} result] {
            set result plain
        }
        switch $nameType {
            Monitor {
                global ${rootname}BPMPVType 
                set ${rootname}BPMPVType $result
            }
            Corrector {
                global ${rootname}CorrectorPVType 
                set ${rootname}CorrectorPVType $result
            }
        }
    }
    APSAddToTempFileList $tmpRoot.selections
    global ${rootname}Plane 
    APSRescanBadOrbitDevices -rootname $rootname -plane [set ${rootname}Plane] -application $application
    if [catch {eval exec sddscombine $selectionFiles -merge -pipe=out \
		   | tee $tmpRoot.selections \
		   | sdds2stream -pipe=in -column=Name} onNameList] {
	return -code error "Problem getting name list: $onNameList"
    }
    
    if [lsearch -exact [APSGetSDDSNames -class column -fileName $tmpRoot.selections] Weight]!=-1 {
        if [catch {APSGetSDDSColumns -fileName $tmpRoot.selections \
                     -columnList Weight -variableList WeightList} result] {
            return -code error "Problem getting weight data: $result"
        }
    } else {
        set WeightList [APSReplicateItem -number [llength $onNameList] -item 1.0]
    }
    if [lsearch -exact [APSGetSDDSNames -class column -fileName $tmpRoot.selections] Despike]!=-1 {
        if [catch {APSGetSDDSColumns -fileName $tmpRoot.selections \
                     -columnList Despike -variableList DespikeList} result] {
            return -code error "Problem getting despike data: $result"
        }
    } else {
        set DespikeList ""
        foreach item $onNameList {
            if [regexp {(BM)|(ID)} $item] {
                lappend DespikeList 0
            } else {
                lappend DespikeList 1
            }
        }            
    }
    if [catch {eval exec sdds2stream $filename -parameter=Description | tail -1} readDescription] {
        set readDescription ""
    }
    global ${rootname}ConfigStatus ${rootname}CBWidget
    set ${rootname}ConfigStatus "Read configuration from $filename"
    update
    set dir [file dir $filename]
    if ![file exist $dir/irm] {
        set ${rootname}ConfigStatus "Warning: the irm of [file tail $dir] does not exist!"
    } else {
        if [catch {exec sdds2stream -par=ConditionNumber $dir/irm} result] {
            set ${rootname}ConfigStatus "$result!"
        } else {
            set ${rootname}ConfigStatus "The condition number is $result"
        }
        if [catch {exec sdds2stream -par=NumberOfSingularValuesUsed $dir/irm} singular] {
            set ${rootname}ConfigStatus "$singular!"
        } else {
            set ${rootname}ConfigStatus "The number of singular values is $singular."
        }
    }
    update
    switch -exact [lsearch [list replace or and not] $logic] {
        1 {
            # or
            foreach item $onNameList weight $WeightList despike $DespikeList {
                set nameFlag ${rootname}${item}
                set weightVar ${rootname}${item}Weight
                set despikeVar ${rootname}${item}Despike
                global $nameFlag ${rootname}${item}Weight ${rootname}${item}Despike
                #set $nameFlag 1
                if {[set $nameFlag] != 1} {
                    [set ${rootname}CBWidget($item)] invoke
                }
                set ${rootname}${item}Weight $weight
                set ${rootname}${item}Despike $despike
            }
        }
        2 {
            # and
            for {set sector 1} {$sector<=$sectorCount} {incr sector} {
		if [llength $sectorList] {
		    set sector1 [lindex $sectorList [expr $sector -1]]
		} else {
		    set sector1 S[format %02d $sector]
		}
                foreach item $knownSuffixes {
                    set name ${sector1}$item
                    if [lsearch $onNameList $name]==-1 {
                        set nameFlag ${rootname}${name} 
                        global $nameFlag
                        if {[info exists $nameFlag]} {
                            if {[set $nameFlag] != 0} {
                                [set ${rootname}CBWidget($name)] invoke
                            }
                            #set $nameFlag 0
                        }
                    }
                }
            }
        }
        3 {
            # not
            foreach item $onNameList {
                set nameFlag ${rootname}${item}
                global $nameFlag
                #set $nameFlag 0
                if {[set $nameFlag] != 0} {
                    [set ${rootname}CBWidget($item)] invoke
                }
            }
        }
        default {
            # replacement
            APSSetSRSectorButtons -mode all-off -rootname ${rootname} -sectorList $sectorList \
              -sectorCount $sectorCount -itemList $knownSuffixes
            foreach item $onNameList weight $WeightList despike $DespikeList {
                set nameFlag ${rootname}${item} 
                set weightVar ${rootname}${item}Weight
                set despikeVar ${rootname}${item}Despike
                global $nameFlag ${rootname}${item}Weight ${rootname}${item}Despike
                #set $nameFlag 1
                [set ${rootname}CBWidget($item)] invoke
                set ${rootname}${item}Weight $weight
                set ${rootname}${item}Despike $despike
            }
        }
    }
   # APSSRSectorUnsetMissing -rootname $rootname -missingList $missingList
    return $readDescription
}

proc APSSRMonitorCheckButtons {widget args} {
    set rootname ""
    set parent ""
    set orientation vertical
    set packOption "-side left"
    set includeP0s 0
    set includeIDs 0
    set includeBMs 0
    set BP5Only 0
    set sectorControl 0
    set missingList ""
    set missingListVar ""
    set noLabel 0
    set colorDesc 1
    APSStrictParseArguments {rootname parent orientation packOption includeP0s includeIDs includeBMs sectorControl missingList missingListVar noLabel BP5Only colorDesc}
    
    
    if ![llength $missingList] {
        switch -regexp $rootname {
            rf -
            h {
                set missingList [APSGetMissingBPMList -plane h]
            }   
            v {     
                set missingList [APSGetMissingBPMList -plane v]
            }
            default {
                set missingList [APSGetMissingBPMList -plane h]
            }       
        }
    }
    global SRBPMSuffixList SRHCorrSuffixList SRVCorrSuffixList SRBPMSuffixLabelList
    set itemList $SRBPMSuffixList
    set itemLabelList $SRBPMSuffixLabelList
    
    if $BP5Only {        
	# actually, we need to add many bpms for rf frequecny controllaw
        # instead of just B:P5
        #set itemList [list A:P0 A:P1 A:P2 A:P3 A:P4 B:P5 B:P4 B:P3 B:P2 B:P1 B:P0]
        #set itemLabelList [list A0 A1 A2 A3 A4 B5 B4 B3 B2 B1 B0]
    } else {
	#if $includeP0s {
	#    set itemList [concat A:P0 $itemList B:P0 C:P0]
	 #   set itemLabelList [concat A0 $itemLabelList B0 C0]
	#}
        if $includeBMs {
            #set itemList [concat $itemList BM:P1 BM:P2]
	    set itemList [concat $itemList BMFE-XBPM:P1 BMFE-XBPM:P2]
            set itemLabelList [concat $itemLabelList BM1 BM2]
        }
        if $includeIDs {
            #set itemList [concat $itemList ID:P1 ID:P2]
	    set itemList [concat $itemList IDFE-XBPM:P1us IDFE-XBPM:P1ds IDFE-XBPM:P2us IDFE-XBPM:P2ds]
            #set itemLabelList [concat $itemLabelList I1 I2]
	    set itemLabelList [concat  $itemLabelList US1 DS1 US2 DS2]
        }

    }
    if $noLabel {
        set label ""
    } else {
        set label Monitors
    }
    if [string length $missingListVar] {
        APSSRSectorButtons .sbbut -parent $parent -rootname ${rootname} \
          -label $label -description "monitors" -orientation $orientation \
          -itemList $itemList -itemLabelList $itemLabelList \
          -sectorControl $sectorControl -colorDesc $colorDesc \
          -packOption $packOption -missingList $missingList \
          -includeWeights 1 -includeDespike 1 -missingListVar $missingListVar \
          -command "APSSRSectorUnsetMissing -rootname ${rootname} -missingListVar $missingListVar"
    } else {
        APSSRSectorButtons .sbbut -parent $parent -rootname ${rootname} \
          -label $label -description "monitors" -orientation $orientation \
          -itemList $itemList -itemLabelList $itemLabelList \
          -packOption $packOption -missingList $missingList \
          -sectorControl $sectorControl -colorDesc $colorDesc  \
          -includeWeights 1 -includeDespike 1 -missingListVar $missingListVar \
          -command "APSSRSectorUnsetMissing -rootname ${rootname} -missingList [list $missingList]"
    }
}

proc APSSRCorrectorCheckButtons {widget args} {
    set rootname ""
    set plane H
    set parent ""
    set orientation vertical
    set sectorControl 0
    set packOption "-side left"
    set missingListVar ""
    set missingList ""
    set noLabel 0
    set globalButtons 1
    APSStrictParseArguments {rootname plane parent orientation sectorControl packOption missingList noLabel missingListVar globalButtons}
    set plane [string toupper $plane]

    if $noLabel {
        set label ""
    } else {
        set label "$plane Correctors"
    }
    global SRHCorrSuffixList SRVCorrSuffixList SRHCorrLabelList SRVCorrLabelList
    switch $plane {
        H {
	    set itemList $SRHCorrSuffixList
	    set itemLabelList $SRHCorrSuffixList
            # pass in command string either missingList or missingListVar
            if [string length $missingListVar] {
                APSSRSectorButtons $widget -parent $parent -rootname ${rootname} -globalButtons $globalButtons \
                  -label $label -description "horizontal correctors" \
                  -itemList $itemList \
                  -itemLabelList $itemLabelList \
                  -sectorControl $sectorControl \
                  -missingList $missingList -missingListVar $missingListVar \
                  -orientation $orientation -packOption $packOption \
                  -command "APSSRSectorUnsetMissing -rootname ${rootname} -missingListVar $missingListVar"
            } else {
                APSSRSectorButtons $widget -parent $parent -rootname ${rootname} -globalButtons $globalButtons \
                  -label $label -description "horizontal correctors" \
                  -itemList $itemList \
                  -itemLabelList $itemLabelList \
                  -sectorControl $sectorControl \
                  -missingList $missingList -missingListVar $missingListVar \
                  -orientation $orientation -packOption $packOption \
                  -command "APSSRSectorUnsetMissing -rootname ${rootname} -missingList [list $missingList]"
            }
        }
        V {
	    set itemList $SRVCorrSuffixList
	    set itemLabelList $SRVCorrLabelList
            if [string length $missingListVar] {
                APSSRSectorButtons $widget -parent $parent -rootname ${rootname} -globalButtons $globalButtons \
                  -label $label -description "vertical correctors" \
                  -itemList $itemList \
                  -itemLabelList $itemLabelList \
                  -sectorControl $sectorControl \
                  -missingList $missingList -missingListVar $missingListVar \
                  -orientation $orientation  -packOption $packOption \
                  -command "APSSRSectorUnsetMissing -rootname ${rootname}  -missingListVar $missingListVar"
            } else {
                APSSRSectorButtons $widget -parent $parent -rootname ${rootname} -globalButtons $globalButtons \
                  -label $label -description "vertical correctors" \
                  -itemList $itemList \
                  -itemLabelList $itemLabelList \
                  -sectorControl $sectorControl \
                  -missingList $missingList -missingListVar $missingListVar \
                  -orientation $orientation  -packOption $packOption \
                  -command "APSSRSectorUnsetMissing -rootname ${rootname} -missingList [list $missingList]"
            }
        }
    }
}

proc APSSRSectorUnsetMissing {args} {
    set rootname ""
    set missingList ""
    set missingListVar ""
    set sectorList ""
    APSParseArguments {rootname missingList missingListVar sectorList}
    if [string length $missingListVar] {
        global $missingListVar
        set missingList [set $missingListVar]
    }
    global ${rootname}CBWidget
    foreach item $missingList {
        set nameFlag ${rootname}${item}
        global $nameFlag
        if {[info exists $nameFlag] && [set $nameFlag] != 0} {
            [set ${rootname}CBWidget($item)] invoke
        }
        set $nameFlag 0
    }
}

proc APSSRSectorButtonsClicked {args} {
    APSStrictParseArguments {widget var selectcolor}
    global $var
    if {[set $var]} {
        $widget configure -selectcolor $selectcolor
    } else {
        $widget configure -selectcolor \#d9d9d9
    }
}

proc APSSRSectorButtons {widget args} {
    global apsBackground
    set parent "" 
    set rootname ""
    set label "Unknown selections"
    set description "No description"
    set itemList ""
    set command ""
    set sectorCount 40
    set missingList ""
    set missingListVar ""
    set packOption "-side left"
    set orientation vertical
    set itemLabelList ""
    set includeWeights 0
    set includeDespike 0
    set onePerSector 0
    set sectorControl 0
    set sectorList ""
    set color0 ""
    set separateCountButton 0
    set globalButtons 1
    set allButtons 1
    set bts 0
    set colorDesc 1
    APSStrictParseArguments {parent rootname label description itemList globalButtons \
				 command sectorCount onePerSector sectorControl \
				 missingList missingListVar packOption orientation \
				 itemLabelList includeWeights includeDespike sectorList color0 separateCountButton \
				 allButtons bts colorDesc}

    global ${rootname}CBWidget ${rootname}BadBPMList ${rootname}SectorList
    if {![info exists ${rootname}BadBPMList]} {
        set ${rootname}BadBPMList ""
    }
    set monoList [exec sddsprocess /home/helios/oagData/sr/BPMStatus/config.sdds -pipe=out -match=col,ElectronicsType=Monopulse \
                    -nowarnings \
		      | sdds2stream -pipe -col=DeviceName]
    set nbList [exec sddsprocess /home/helios/oagData/sr/BPMStatus/config.sdds -pipe=out -match=col,ElectronicsType=Narrowband \
                  -nowarnings \
                  | sdds2stream -pipe -col=DeviceName]
    set FPGAList [exec sddsprocess /home/helios/oagData/sr/BPMStatus/config.sdds -pipe=out -match=col,ElectronicsType=FPGA \
                    -nowarnings \
                    | sdds2stream -pipe -col=DeviceName]
    set IDList [exec  sddsprocess /home/helios/oagData/sr/BPMStatus/config.sdds -pipe=out -match=col,ElectronicsType=Xray \
                  -match=col,DeviceName=*IDFE* -nowarnings \
                  | sdds2stream -pipe -col=DeviceName]
    set BMList [exec  sddsprocess /home/helios/oagData/sr/BPMStatus/config.sdds -pipe=out -match=col,ElectronicsType=Xray \
                  -match=col,DeviceName=*BMFE* -nowarnings \
                  | sdds2stream -pipe -col=DeviceName]
    set liberaList [exec  sddsprocess /home/helios/oagData/sr/BPMStatus/config.sdds -pipe=out -match=col,ElectronicsType=Libera \
                      -nowarnings \
			| sdds2stream -pipe -col=DeviceName]
    set LBList [exec  sddsprocess /home/helios/oagData/sr/BPMStatus/config.sdds -pipe=out -match=col,ElectronicsType=LB+ \
                      -nowarnings \
			| sdds2stream -pipe -col=DeviceName]
    set SparkERList [exec sddsprocess /home/helios/oagData/sr/BPMStatus/config.sdds -pipe=out -match=col,ElectronicsType=Spark-ERXR \
                      -nowarnings \
			| sdds2stream -pipe -col=DeviceName]
    set SparkELList [exec sddsprocess /home/helios/oagData/sr/BPMStatus/config.sdds -pipe=out -match=col,ElectronicsType=Spark-EL \
                      -nowarnings \
			  | sdds2stream -pipe -col=DeviceName]
    set hFastList [exec sddsprocess /home/helios/oagData/sr/HCorrectorStatus/config.sdds -pipe=out -match=col,DeviceType=Fast \
                      -nowarnings \
			  | sdds2stream -pipe -col=DeviceName]
    set vFastList [exec sddsprocess /home/helios/oagData/sr/VCorrectorStatus/config.sdds -pipe=out -match=col,DeviceType=Fast \
                      -nowarnings \
			  | sdds2stream -pipe -col=DeviceName]
    set hRegularList [exec sddsprocess /home/helios/oagData/sr/HCorrectorStatus/config.sdds -pipe=out -match=col,DeviceType=Std \
                      -nowarnings \
			  | sdds2stream -pipe -col=DeviceName]
    set vRegularList [exec sddsprocess /home/helios/oagData/sr/VCorrectorStatus/config.sdds -pipe=out -match=col,DeviceType=Std \
                      -nowarnings \
			  | sdds2stream -pipe -col=DeviceName]
    set btsSparkERXRList [exec sddsprocess /home/helios/oagData/bts/BPMStatus/config.sdds -nowarn -pipe=out \
			       -match=col,ElectronicsType=Spark-ERXR | sdds2stream -pipe=in -col=DeviceName]
    set btsSparkELList [exec sddsprocess /home/helios/oagData/bts/BPMStatus/config.sdds -pipe=out \
			       -match=col,ElectronicsType=Spark-EL -nowarn | sdds2stream -pipe=in -col=DeviceName]
    set btsSteeringList [exec sddsprocess /home/helios/oagData/bts/CorrectorStatus/config.sdds -pipe=out \
			     -match=col,DeviceType=Steering -nowarn | sdds2stream -pipe=in -col=DeviceName]
    set btsQuadsList [exec sddsprocess /home/helios/oagData/bts/CorrectorStatus/config.sdds -pipe=out \
			     -match=col,DeviceType=Quads -nowarn | sdds2stream -pipe=in -col=DeviceName]
    set btsSkewList [exec sddsprocess /home/helios/oagData/bts/CorrectorStatus/config.sdds -pipe=out \
			     -match=col,DeviceType=Skew -nowarn | sdds2stream -pipe=in -col=DeviceName]
    set btsDipoleList [exec sddsprocess /home/helios/oagData/bts/CorrectorStatus/config.sdds -pipe=out \
			   -match=col,DeviceType=Dipole -nowarn | sdds2stream -pipe=in -col=DeviceName]

    APSFrame $widget -parent $parent -label $label \
      -packOption $packOption

    set f1 $parent$widget.frame.f1
    set command1 ""
    set maxSectorLen 3
    if [llength $sectorList] {
        set sectorCount [llength $sectorList]
	foreach text $sectorList {
	    set len [string length $text]
	    if {$len>$maxSectorLen} {
		set maxSectorLen $len
	    }
	}
    }
    set ${rootname}SectorList $sectorList
    if [string match $orientation vertical] {
        frame $parent$widget.frame.f1
        eval pack $parent$widget.frame.f1 -side top
        # make vertical column for sector labels
        frame $f1.labels
        pack $f1.labels -side left -expand 1 -fill y
        for {set n $sectorCount} {$n>=0} {incr n -1} {
            if $n {
                if [llength $sectorList] {
                    set text "[lindex $sectorList [expr $n-1]] "
                } else {
                    set text [format "%3d " $n]
                }
                label $f1.labels.sector$n -text $text \
                  -borderwidth 1 -padx 0 -pady 0 -highlightthickness 0
                pack $f1.labels.sector$n -side bottom
            } else {
                if [llength $itemLabelList] {
                    label $f1.labels.sector$n -text "    " \
                      -borderwidth 1 -padx 0 -pady 0 -highlightthickness 0
                    pack $f1.labels.sector$n -side bottom
                }
            }
        }

        # make vertical columns for checkbuttons vs item name
        set index -1
        foreach item $itemList {
            incr index
            set f2 $f1.item$index
            frame $f2
            pack $f2 -side left
            for {set n $sectorCount} {$n>0} {incr n -1} {
		if [llength $sectorList] {
		    set name [lindex $sectorList [expr $n-1]]$item
		} else {
		    set name  S[format %02d $n]$item
		}
		#set name S${n}$item
                set nameFlag ${rootname}$name
                global $nameFlag 
                if {![info exists $nameFlag]} {
                    set $nameFlag 1
                }
		
                # add default arguments to whatever command is being passed.
                if [string length $command] {
                    set command1 "$command -sector $n -item $item -nameFlag $nameFlag"
                }
		if ![string length $color0] {
		    if {[lsearch -exact $nbList $name]>=0 || [lsearch -exact $LBList $name]>=0 \
			    || [lsearch -exact $hRegularList $name]>=0 || [lsearch -exact $vRegularList $name]>=0 } {
			#oscillate color for neighor double sector
			set color  red
				#change color by MPS double sector
			set s1 [scan $name S%ld]
			if [expr $s1%2]==0 {
			    if [regexp "A:P\[0-4\]" $name] {
				set sd [expr $s1 -1]
			    } else {
				if {$s1==40} {
				    set sd 1
				} else {
				    set sd [expr $s1+1]
				}
			    }
			} else {
			    set sd $s1
			}
			if [expr $sd%4]==1 {
			    set color cyan
			}
		    } elseif {[lsearch -exact $FPGAList $name]>=0 || [lsearch -exact $SparkERList $name]>=0 \
				  || [lsearch -exact $hFastList $name]>=0 || [lsearch -exact $vFastList $name]>=0  } {
			set color yellow
		    } elseif {[lsearch -exact $monoList $name]>=0 || [lsearch -exact $SparkELList $name]>=0} {
			set color blue
		    } elseif [lsearch -exact $BMList $name]>=0 {
			set color "chartreuse"
		    } elseif [lsearch -exact $IDList $name]>=0 {
			set color "dark orange"
		    } elseif [lsearch -exact $liberaList $name]>=0 {
                        set color "violet"
                    } else {
			set color maroon
		    } 
		} else {
		    set color $color0
		}
		if !$colorDesc {
		    set color red
		}
	
      
                if {[set $nameFlag] == 1} {
                    set c $color
                } else {
                    set c \#d9d9d9
                }

                checkbutton $f2.sector$n -text "" -variable $nameFlag \
                  -borderwidth 1 -padx 0 -pady 0 -highlightthickness 0 -fg $color \
                  -command "APSSRSectorButtonsClicked -widget $f2.sector$n -var $nameFlag -selectcolor \"$color\" ; $command1" -selectcolor $c

                set ${rootname}CBWidget\($name\) $f2.sector$n
		
                if {[llength $missingList] && [lsearch $missingList $name]!=-1} {
                    $f2.sector$n configure -state disabled -indicatoron off -borderwidth 0 -pady 1 -padx 1
                } elseif {[llength [set ${rootname}BadBPMList]] && [lsearch [set ${rootname}BadBPMList] $name]!=-1} {
                    $f2.sector$n configure -state disabled -bg $apsBackground -borderwidth 1 -pady 0 -padx 0
                } else {
                    $f2.sector$n configure -state normal -indicatoron on -bg $apsBackground -borderwidth 1 -pady 0 -padx 0
                }
		#if $displayOnly {
		#    $f2.sector$n configure -state disabled 
		#}
		if {0} {
                if [string compare $n$item 20V]==0 {
		    #disable the check button for B2C9V (which is sector 20) since it does not exist
		    set $nameFlag 0
		    $f2.sector$n configure -state disabled -indicatoron off -borderwidth 0 -pady 1 -padx 1
		}
		}
                pack $f2.sector$n -side bottom
                set apsContextHelp($f2.sector$n) $name
                if {$includeWeights || $includeDespike} {
                    set weightVar ${rootname}${name}Weight
                    set despikeVar ${rootname}${name}Despike
                    global $weightVar $despikeVar
                    if ![info exists $weightVar] {
                        set $weightVar 1
                    }
                    if ![info exists $despikeVar] {
                        if [regexp {(BM)|(ID)} $item] {
                            set $despikeVar 0
                        } else {
                            set $despikeVar 1
                        }
                    }
                    if {![llength $missingList] || [lsearch $missingList $name]==-1} {
                        bind $f2.sector$n <ButtonRelease-2> \
                          "APSSRConfigWeightDialog -weight $weightVar -despike $despikeVar -item $name"
                    }
                }
            }
            # item name label
            if [llength $itemLabelList] {
                set itemLabel [lindex $itemLabelList $index]
                label $f2.label -text [join [split [format %3s $itemLabel] ""] \n] \
                  -borderwidth 0 -padx 0 -pady 0 -highlightthickness 0
                pack $f2.label -side bottom
            }
        }
        if {$sectorControl} {
            set index [llength $itemList]
            set f2 $f1.item$index
            frame $f2
            pack $f2 -side left
            for {set n $sectorCount} {$n>0} {incr n -1} {
		if [llength $sectorList] {
		    set name [lindex $sectorList [expr $n-1]]${widget}
		    set sector1 [lindex $sectorList [expr $n-1]]
		} else {
		    set name S[format %02d $n]${widget}
		    set sector1 S[format %02d ${n}]
		}
                set togVar ${rootname}${name}
                global $togVar
                set $togVar 1
                checkbutton $f2.sector$n -text "" -variable $togVar \
                  -borderwidth 1 -padx 0 -pady 0 -highlightthickness 0 \
                  -command "APSSRItemTogglePosition -rootname $rootname -sector $sector1 -itemList [list $itemList] -missingList [list $missingList] -missingListVar \"$missingListVar\" -toggleVar $togVar"
                pack $f2.sector$n -in $f2 -side bottom
                set apsContextHelp($f2.sector$n) \
                  "Toggles all buttons in this sector on or off."
                
            }
            label $f2.label -text "A\nl\n\l" \
              -borderwidth 1 -padx 0 -pady 0 -highlightthickness 0
            pack $f2.label -side bottom
        }
    } else {
        # orientation horizontal
        frame $parent$widget.frame.f1
        pack $parent$widget.frame.f1 -side left
        if [llength $itemLabelList] {
            # make vertical column for labels using item names
            frame $f1.labels
            pack $f1.labels -side left -fill y -expand 1
            set f2 $f1.labels
            # labels for items
            if {$sectorControl} {
                set index [llength $itemList]
                label $f2.item$index -text All \
                  -borderwidth 1 -padx 0 -pady 0 -highlightthickness 0
                pack $f2.item$index -side bottom
            }
            for {set index [llength $itemLabelList]} {$index>0} {} {
                incr index -1
                label $f2.item$index -text [lindex $itemLabelList $index] \
                  -borderwidth 1 -padx 0 -pady 0 -highlightthickness 0
                pack $f2.item$index -side bottom 
            }
            # make vertical columns for checkbuttons vs sector number
            for {set n 1} {$n<=$sectorCount} {incr n} {
                # column for checkbuttons
                frame $f1.sector$n
                pack $f1.sector$n -side left
                set f2 $f1.sector$n
                # make sector buttons
                if {$sectorControl} {
                    set index [llength $itemList]
		    if [llength $sectorList] {
			set name [lindex $sectorList [expr $n-1]]${widget}
			set sector1 [lindex $sectorList [expr $n-1]]
		    } else {
			set name  S[format %02d $n]${widget}
			set sector1 S[format %02d $n]
		    }
                    set togVar ${rootname}${name}
                    global $togVar
                    set $togVar 1
                    checkbutton $f2.item$index -text "" -variable $togVar \
                      -borderwidth 1 -padx 0 -pady 0 -highlightthickness 0 \
                      -command "APSSRItemTogglePosition -rootname $rootname -sector $sector1 -itemList [list $itemList] -missingList [list $missingList] -missingListVar \"$missingListVar\" -toggleVar $togVar"
                    pack $f2.item$index -in $f2 -side bottom
                    set apsContextHelp($f2.item$index) \
                      "Toggles all buttons in this sector on or off."
                }
                for {set index [llength $itemList]} {$index>0} {} {
                    incr index -1
                    set item [lindex $itemList $index]
		    if [llength $sectorList] {
			set name [lindex $sectorList [expr $n-1]]$item
		    } else {
			set name  S[format %02d $n]$item
		    }
                    #set name S${n}$item
                    set nameFlag ${rootname}$name
                    global $nameFlag
                    if {![info exists $nameFlag]} {
                        set $nameFlag 1
                    }
                    if [string length $command] {
                        set command1 "$command -sector $n -item $item -nameFlag $nameFlag"
                    }
		    if ![string length $color0] {
			if {[lsearch -exact $nbList $name]>=0 || [lsearch -exact $LBList $name]>=0 \
				|| [lsearch -exact $hRegularList $name]>=0 || [lsearch -exact $vRegularList $name]>=0 \
				|| [lsearch -exact $btsSparkERXRList $name]>=0 || [lsearch -exact $btsSteeringList $name]>=0} {
			    set color  red
			     #change color by MPS double sector
			    set s1 [scan $name S%ld]
			    if [expr $s1%2]==0 {
				if [regexp "A:P\[0-4\]" $name] {
				    set sd [expr $s1 -1]
				} else {
				    if {$s1==40} {
					set sd 1
				    } else {
				set sd [expr $s1+1]
				    }
				}
			    } else {
				set sd $s1
			    }
			    if [expr $sd%4]==1 {
				set color "cyan"
			    }
		    
			} elseif {[lsearch -exact $FPGAList $name]>=0 || [lsearch -exact $SparkERList $name]>=0 \
				      || [lsearch -exact $hFastList $name]>=0 || [lsearch -exact $vFastList $name]>=0 || \
				      [lsearch -exact $btsSparkELList $name]>=0 || [lsearch -exact $btsQuadsList $name]>=0} {
			    set color yellow
			} elseif {[lsearch -exact $monoList $name]>=0 || [lsearch -exact $SparkELList $name]>=0 \
				      || [lsearch -exact $btsSkewList $name]>=0} {
			    set color blue
			} elseif {[lsearch -exact $BMList $name]>=0 || [lsearch -exact $btsDipoleList $name]>=0} {
			    set color "chartreuse"
			} elseif [lsearch -exact $IDList $name]>=0 {
			    set color "dark orange"
			} else {
			    set color maroon
			}
		    } else {
			set color $color0
		    }
		    if !$colorDesc {
			set color red
		    }
		   
                    if {[set $nameFlag] == 1} {
                        set c $color
                    } else {
                        set c \#d9d9d9
                    }

                    checkbutton $f2.item$index -text "" -variable $nameFlag \
                      -borderwidth 1 -padx 0 -pady 0 -highlightthickness 0 -fg $color \
                      -command "APSSRSectorButtonsClicked -widget $f2.item$index -var $nameFlag -selectcolor \"$color\" ; $command1" -selectcolor $c
                    set ${rootname}CBWidget\($name\) $f2.item$index
		    
		    if {[llength $missingList] && [lsearch $missingList $name]!=-1} {
			$f2.item$index configure -state disabled -indicatoron off -borderwidth 0 -pady 1 -padx 1
		    } elseif {[llength [set ${rootname}BadBPMList]] && [lsearch [set ${rootname}BadBPMList] $name]!=-1} {
			$f2.item$index configure -state disabled -bg $apsBackground -borderwidth 1 -pady 0 -padx 0
		    } else {
			$f2.item$index configure -state normal -indicatoron on -bg $apsBackground -borderwidth 1 -pady 0 -padx 0
		    }
		    if {0} {
		    if [string compare $n$item 20V]==0 {
			#disable the check button for B2C9V (which is sector 20) since it does not exist
			set $nameFlag 0
			$f2.item$index configure -state disabled -indicatoron off -borderwidth 0 -pady 1 -padx 1
		    }
		    }
                    pack $f2.item$index -side bottom
                    set apsContextHelp($f2.item$index) $name
                    if {$includeWeights || $includeDespike} {
                        set weightVar ${rootname}${name}Weight
                        set despikeVar ${rootname}${name}Despike
                        global $weightVar $despikeVar
                        if ![info exists $weightVar] {
                            set $weightVar 1
                        }
                        if ![info exists $despikeVar] {
                            if [regexp {(BM)|(ID)} $item] {
                                set $despikeVar 0
                            } else {
                                set $despikeVar 1
                            }
                        }
                        if {![llength $missingList] || [lsearch $missingList $name]==-1} {
                            bind $f2.item$index <ButtonRelease-2> \
                              "APSSRConfigWeightDialog -weight $weightVar -despike $despikeVar -item $name"
                        }
                    }
                }
                if [llength $sectorList] {
                    set text [lindex $sectorList [expr $n -1]]
		    set len [string length $text]
		    set n1 [expr $maxSectorLen - $len]
		    set text1 ""
		    for {set x 0} {$x<$n1} {incr x} {
			append text1 "\n"
		    }
		    for {set x 0} {$x<$len} {incr x} {
			append text1 "[format %s [string index $text $x]]"
			if {$x<[expr $len-1]} {
			    append text1 "\n"
			}
		    }
		    set text $text1
                } else {
                    if $n>9 {
                        set text [format "\n%1d\n%1d" [expr int($n/10)] [expr $n-int($n/10)*10]]
                    } else {
                        set text [format "\n\n%1d" $n]  
                    }
                }
                label $f2.label -text $text \
                  -borderwidth 0 -padx 0 -pady 0 -highlightthickness 0
               # if $n>9 {
                #     label $f2.label -text \
               #       [format "\n%1d\n%1d" [expr int($n/10)] [expr $n-int($n/10)*10]] \
                #      -borderwidth 0 -padx 0 -pady 0 -highlightthickness 0
               # } else {
               #     label $f2.label -text \
               #       [format "\n\n%1d" $n] \
                #      -borderwidth 0 -padx 0 -pady 0 -highlightthickness 0
                #}
                pack $f2.label -side bottom
            }
        }
    }
 
    # Position toggle buttons
    if $allButtons {
	APSSRSectorPositionButtons .frametog -parent $parent$widget.frame -sectorWidget $widget \
	    -rootname $rootname -sectorCount $sectorCount -sectorControl $sectorControl -sectorList $sectorList \
	    -description $description -itemList $itemList -missingList $missingList \
	    -missingListVar $missingListVar -orientation $orientation  -maxSectorLen $maxSectorLen
    }
    # Global buttons
    if $globalButtons {
	APSSRSectorGlobalButtons .frameButtonsSB -parent $parent$widget.frame  \
	    -rootname $rootname -sectorCount $sectorCount \
	    -description $description -itemList $itemList -missingList $missingList \
	    -missingListVar $missingListVar -orientation $orientation -sectorList $sectorList -separateCountButton $separateCountButton
    }
    
    APSSRSectorUnsetMissing -rootname $rootname -sectorCount $sectorCount \
      -missingList $missingList -missingListVar $missingListVar -sectorList $sectorList

    if !$colorDesc {
	return
    }
    #description for colors
    
    APSFrame .f0 -parent $parent -packOption "-side top"
    $parent.f0.frame configure -bd 0
    set w $parent.f0.frame
    if [regexp {P} $itemList] {
	#bpm
	if !$bts {
	    APSLabel .t1 -parent $w -text "BPM color description" -packOption "-side left"
	     checkbutton $w.c1a -text "LB+ " -borderwidth 1 -padx 0 -pady 0 -highlightthickness 0 -selectcolor cyan -variable ${rootname}ColorSel(LB+) \
		-command "APSSelectItemByType -type LB+ -ring SR -rootname $rootname -bpmCorr bpm -itemList [list $itemList] -sectorList [list $sectorList]"
	    pack $w.c1a -side left
	    checkbutton $w.c1 -text "LB+ " -borderwidth 1 -padx 0 -pady 0 -highlightthickness 0 -selectcolor red -variable ${rootname}ColorSel(LB+) \
		-command "APSSelectItemByType -type LB+ -ring SR -rootname $rootname -bpmCorr bpm -itemList [list $itemList] -sectorList [list $sectorList]"
	    pack $w.c1 -side left
	    checkbutton $w.c2 -text "Spark-ERXR " -borderwidth 1 -padx 0 -pady 0 -highlightthickness 0 -selectcolor yellow \
		-variable ${rootname}ColorSel(Spark-ERXR)  \
		-command "APSSelectItemByType -type Spark-ERXR -ring SR -rootname $rootname -bpmCorr bpm -itemList [list $itemList] -sectorList [list $sectorList]"
	    pack $w.c2 -side left
	    checkbutton $w.c3 -text "Spark-EL " -borderwidth 1 -padx 0 -pady 0 -highlightthickness 0 -selectcolor blue -variable ${rootname}ColorSel(Spark-EL) \
		-command "APSSelectItemByType -type Spark-EL -ring SR -rootname $rootname -bpmCorr bpm -itemList [list $itemList] -sectorList [list $sectorList]"
	    pack $w.c3 -side left
	    checkbutton $w.c4 -text "ID " -borderwidth 1 -padx 0 -pady 0 -highlightthickness 0 -selectcolor "dark orange" -variable ${rootname}ColorSel(ID) \
		-command "APSSelectItemByType -type ID -ring SR -rootname $rootname -bpmCorr bpm -itemList [list $itemList] -sectorList [list $sectorList]"
	    pack $w.c4 -side left
	    checkbutton $w.c5 -text "BM " -borderwidth 1 -padx 0 -pady 0 -highlightthickness 0 -selectcolor "chartreuse" -variable ${rootname}ColorSel(BM) \
		-command "APSSelectItemByType -type BM -ring SR -rootname $rootname -bpmCorr bpm -itemList [list $itemList] -sectorList [list $sectorList]"
	    pack $w.c5 -side left
	} else {
	    APSLabel .t1 -parent $w -text "BPM color description" -packOption "-side left"
	    checkbutton $w.c2 -text "Spark-ERXR " -borderwidth 1 -padx 0 -pady 0 -highlightthickness 0 -selectcolor red -variable ${rootname}ColorSel(Spark-ERXR) \
		-command "APSSelectItemByType -type Spark-ERXR -ring BTS -rootname $rootname -bpmCorr bpm -itemList $itemList -sectorList $sectorList"
	    pack $w.c2 -side left
	    checkbutton $w.c3 -text "Spark-EL " -borderwidth 1 -padx 0 -pady 0 -highlightthickness 0 -selectcolor yellow -variable ${rootname}ColorSel(Spark-EL) \
		-command "APSSelectItemByType -type Spark-EL -ring BTS -rootname $rootname -bpmCorr bpm -itemList $itemList -sectorList $sectorList"
	    pack $w.c3 -side left
	}
    } else {
	#corr
	if !$bts {
	    #SR correctors
	    if [regexp {H} $itemList] {
		#horizontal correctors
		APSLabel .t1 -parent $w -text "H corrector color description" -packOption "-side left"
		checkbutton $w.c1 -text "Standard " -borderwidth 1 -padx 0 -pady 0 -highlightthickness 0 -selectcolor red -variable ${rootname}ColorSel(Std) \
		    -command "APSSelectItemByType -type Std  -ring SR -rootname $rootname -bpmCorr corr -itemList [list $itemList] -sectorList [list $sectorList] -plane h"
		pack $w.c1 -side left
		checkbutton $w.c2 -text "Fast " -borderwidth 1 -padx 0 -pady 0 -highlightthickness 0 -selectcolor yellow -variable ${rootname}ColorSel(Fast) \
		    -command "APSSelectItemByType -type Fast  -ring SR -rootname $rootname -bpmCorr corr -itemList [list $itemList] -sectorList [list $sectorList] -plane h"
		pack $w.c2 -side left
		checkbutton $w.c3 -text "Trim " -borderwidth 1 -padx 0 -pady 0 -highlightthickness 0 -selectcolor maroon -variable ${rootname}ColorSel(Trim) \
		    -command "APSSelectItemByType -type Trim  -ring SR -rootname $rootname -bpmCorr corr -itemList [list $itemList] -sectorList [list $sectorList] -plane h"
		pack $w.c3 -side left
	    } else {
		#vertical correctors
		APSLabel .t1 -parent $w -text "V corrector color description" -packOption "-side left"
		checkbutton $w.c1 -text "Standard " -borderwidth 1 -padx 0 -pady 0 -highlightthickness 0 -selectcolor red -variable ${rootname}ColorSel(Std) \
		    -command "APSSelectItemByType -type Std  -ring SR -rootname $rootname -bpmCorr corr -itemList [list $itemList] -sectorList [list $sectorList] -plane v" 
		pack $w.c1 -side left
		checkbutton $w.c2 -text "Fast " -borderwidth 1 -padx 0 -pady 0 -highlightthickness 0 -selectcolor yellow -variable ${rootname}ColorSel(Fast) \
		    -command "APSSelectItemByType -type Fast  -ring SR -rootname $rootname -bpmCorr corr -itemList [list $itemList] -sectorList [list $sectorList] -plane v" 
		pack $w.c2 -side left
	    }
	} else {
	    #bts correctors
	    #H and V correctors do not separate
	    APSLabel .t1 -parent $w -text "corrector color description" -packOption "-side left"
	    checkbutton $w.c1 -text "Steering " -borderwidth 1 -padx 0 -pady 0 -highlightthickness 0 -selectcolor red -variable ${rootname}ColorSel(Steering) \
		-command "APSSelectItemByType -type Steering  -ring BTS -rootname $rootname -bpmCorr corr -itemList [list $itemList] -sectorList [list $sectorList]"
	    pack $w.c1 -side left
	    checkbutton $w.c2 -text "Quads " -borderwidth 1 -padx 0 -pady 0 -highlightthickness 0 -selectcolor yellow -variable ${rootname}ColorSel(Quads) \
		-command "APSSelectItemByType -type Quads  -ring BTS -rootname $rootname -bpmCorr corr -itemList [list $itemList] -sectorList [list $sectorList]"
	    pack $w.c2 -side left
	    checkbutton $w.c3 -text "Skew " -borderwidth 1 -padx 0 -pady 0 -highlightthickness 0 -selectcolor blue -variable ${rootname}ColorSel(Skew) \
		-command "APSSelectItemByType -type Skew  -ring BTS -rootname $rootname -bpmCorr corr -itemList [list $itemList] -sectorList [list $sectorList]"
	    pack $w.c3 -side left
	    checkbutton $w.c4 -text "Dipole " -borderwidth 1 -padx 0 -pady 0 -highlightthickness 0 -selectcolor chartreuse -variable ${rootname}ColorSel(Dipole) \
		-command "APSSelectItemByType -type Dipole  -ring BTS -rootname $rootname -bpmCorr corr -itemList [list $itemList] -sectorList [list $sectorList]"
	    pack $w.c4 -side left
	}
    }
}

proc APSSelectItemByType {args} {
    set ring SR
    set bpmCorr bpm
    set type ""
    set rootname ""
    set itemList ""
    set sectorList ""
    set plane ""
    APSStrictParseArguments {ring bpmCorr type rootname sectorList plane itemList}
    
    global ${rootname}CBWidget ${rootname}ColorSel
    switch $bpmCorr {
	bpm {
	    switch $ring {
		SR {
		    set configFile /home/helios/oagData/sr/BPMStatus/config.sdds
		    set col ElectronicsType
		}
		BTS {
		    set configFile /home/helios/oagData/bts/BPMStatus/config.sdds
		    set col ElectronicsType
		}
	    }
	}
	corr {
	    switch $ring {
		SR {
		    set configFile /home/helios/oagData/sr/[string toupper $plane]CorrectorStatus/config.sdds 
		    set col DeviceType
		} 
		BTS {
		    set configFile  /home/helios/oagData/bts/CorrectorStatus/config.sdds
		    set col DeviceType
		}
	    }
	}
    }
    switch $type {
	ID {
	    set itemList0 [exec sddsprocess $configFile -pipe=out  -match=col,ElectronicsType=Xray \
                  -match=col,DeviceName=*ID* -nowarnings \
                  | sdds2stream -pipe -col=DeviceName]
	}
	BM  {
	    set itemList0 [exec sddsprocess $configFile -pipe=out  -match=col,ElectronicsType=Xray \
			       -match=col,DeviceName=*BM* -nowarnings \
			       | sdds2stream -pipe -col=DeviceName]
	}
	default {
	    set itemList0 [exec sddsprocess $configFile -pipe=out  -match=col,$col=$type  -nowarnings \
			       | sdds2stream -pipe -col=DeviceName]
	}
    }
    if ![string length $sectorList] {
	for {set i 1} {$i<=40} {incr i} {
	    lappend sectorList S[format %02d $i]
	}
    }
    foreach sector $sectorList {
	foreach item $itemList {
	    set name ${sector}$item
	    set nameFlag ${rootname}$name
	    global $nameFlag
	    if [lsearch -exact $itemList0 $name]>=0 {
		if [set $nameFlag]!=[set ${rootname}ColorSel($type)] {
		    [set ${rootname}CBWidget($name)] invoke
		}
	    }
	}
    }
}

proc APSSRSectorGlobalButtons {widget args} {
    set parent ""
    set rootname ""
    set sectorCount 40
    set description ""
    set itemList ""
    set missingList ""
    set missingListVar ""
    set orientation vertical
    set sectorList ""
    set separateCountButton 0
    APSStrictParseArguments {parent rootname sectorCount description itemList missingList orientation missingListVar sectorList separateCountButton}

    set f2 $parent$widget
    frame $f2
    if [string compare $orientation vertical]==0 {
        set side1 top
        set side2 left
    } else {
        set side1 left
        set side2 top
    }
    pack $f2 -side $side1
    APSButton .allon -parent $f2 -text "+All" \
	-command "APSSetSRSectorButtons -mode all-on -rootname $rootname -sectorCount $sectorCount -itemList [list $itemList] -missingList [list $missingList] -missingListVar \"$missingListVar\" -sectorList [list $sectorList]" \
      -size small -packOption "-side $side2" -contextHelp \
      "Sets all $description buttons on."
    APSButton .alloff -parent $f2 -text "-All" \
	-command "APSSetSRSectorButtons -mode all-off -rootname $rootname -sectorCount $sectorCount -itemList [list $itemList] -missingList [list $missingList] -missingListVar \"$missingListVar\" -sectorList [list $sectorList]" \
      -size small -packOption "-side $side2" -contextHelp \
      "Sets all $description buttons off."
    if !$separateCountButton {
	APSButton .count -parent $f2 -text "Count" -size small -packOption "-side $side2" -command \
	    "set ${rootname}ConfigStatus \"$description count is \[APSCountSRConfig -rootname $rootname -sectorCount $sectorCount -sectorList [list $sectorList] -itemList [list $itemList] -missingList [list $missingList] \]\"" \
      -contextHelp "Counts the number of $description buttons that are on."
    } else {
	#booster itemlist contains both bpm and correctors
	set bpmList ""
	set corrList ""
	foreach item $itemList {
	    if [regexp {P} $item] {
		lappend bpmList $item
	    } elseif {[regexp {H} $item] || [regexp {V} $item]} {
		lappend corrList $item
	    }
	}
	if {![llength $bpmList] || ![llength $corrList]} {
	    return -code error "No bpm or correctors provided, no need separate count button."
	}
	APSButton .count1 -parent $f2 -text "Count_bpm" -size small -packOption "-side $side2" -command \
	    "set ${rootname}ConfigStatus \"$description BPM count is \[APSCountSRConfig -rootname $rootname -sectorCount $sectorCount -sectorList [list $sectorList] -itemList [list $bpmList] -missingList [list $missingList] \]\"" \
      -contextHelp "Counts the number of bpm buttons that are on."
	APSButton .count2 -parent $f2 -text "Count_corr" -size small -packOption "-side $side2" -command \
	    "set ${rootname}ConfigStatus \"$description corrector count is \[APSCountSRConfig -rootname $rootname -sectorCount $sectorCount -sectorList [list $sectorList] -itemList [list $corrList] -missingList [list $missingList] \]\"" \
	    -contextHelp "Counts the number of corrector buttons that are on."
    }
}

proc APSSetSRSectorButtons {args} {
    set mode ""
    set rootname ""
    set sectorCount 40
    set itemList ""
    set missingList ""
    set missingListVar ""
    set sectorList ""
    APSStrictParseArguments {mode rootname sectorCount itemList missingList missingListVar sectorList}

    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  -sectorList $sectorList \
          -sectorCount $sectorCount -missingList $missingList -toggleVar $toggleVar
    }
}

proc APSSRSectorPositionButtons {widget args} {
    set parent ""
    set description ""
    set itemList ""
    set rootname ""
    set sectorCount 40
    set missingList ""
    set missingListVar ""
    set orientation vertical
    set sectorControl 0
    set sectorWidget ""
    set sectorList ""
    set maxSectorLen ""
    APSStrictParseArguments {parent sectorWidget description itemList rootname sectorCount missingList missingListVar orientation sectorControl sectorList maxSectorLen}

    set f2 $parent$widget
    frame $f2
    if [string match $orientation vertical] {
        set side1 top
        set side2 left
    } else {
        set side1 left
        set side2 top
    }
    pack $f2 -side $side1

    if [string match $orientation vertical] {
        label $f2.label -text "All " \
          -borderwidth 1 -padx 0 -pady 0 -highlightthickness 0
    } else {
	set text ""
	if {$maxSectorLen>3} {
	    for {set i 0} {$i<[expr $maxSectorLen -3]} {incr i} {
		append text "\n"
	    }
	    append text "A\nl\nl"
	} else {
	    set text "A\nl\n\l"
	}
        label $f2.label -text $text \
          -borderwidth 1 -padx 0 -pady 0 -highlightthickness 0
    }
    pack $f2.label -side $side2
    foreach item $itemList {
        set togVar ${rootname}S${item}
        global $togVar
        if {![info exists $togVar]} {
            set $togVar 1
        }
        set w $f2.$togVar
        checkbutton $f2.$togVar -text "" -variable $togVar \
          -command "APSSRSectorTogglePosition -rootname $rootname -sectorCount $sectorCount -item $item -missingList [list $missingList] -missingListVar \"$missingListVar\" -toggleVar $togVar -sectorList \"$sectorList\"" \
          -borderwidth 1 -padx 0 -pady 0 -highlightthickness 0
        pack $f2.$togVar -in $f2 -side $side2
        set apsContextHelp($f2.$togVar) \
          "Toggles all $description in this position for all sectors on or off."
    }
    if {$sectorControl} {
        # if more than one frame of buttons is created, say one for
        # monitors and on for correctors, then this button in the two
        # frames will share the same variable.
        set widgetPartsList [split $parent .]
        set widgetParts [llength $widgetPartsList]
        set suffix [lindex $widgetPartsList [expr $widgetParts - 2]]
        set togVar ${rootname}S${suffix}
        global $togVar
        if {![info exists $togVar]} {
            set $togVar 1
        }
        set w $f2.$togVar
        if [string length $missingListVar] {
            set command "APSSRSectorsToggle -widget $sectorWidget -rootname $rootname -itemList [list $itemList] -missingList [list $missingList] -missingListVar $missingListVar -toggleVar $togVar -sectorList [list $sectorList]"
      
        } else {
            set command "APSSRSectorsToggle -widget $sectorWidget -rootname $rootname -itemList [list $itemList] -missingList [list $missingList] -toggleVar $togVar -sectorList [list $sectorList]"
        }
        checkbutton $f2.$togVar -text "" -variable $togVar \
          -command $command \
          -borderwidth 1 -padx 0 -pady 0 -highlightthickness 0
        pack $f2.$togVar -in $f2 -side $side2
        $f2.$togVar configure -state disable
       # set apsContextHelp($f2.$togVar) "Does nothing."
    }
}
proc APSSRSectorsToggle {args} {
    set rootname ""
    set sectorCount 40
    set itemList ""
    set missingList ""
    set missingListVar ""
    set toggleVar ""
    set widget ""
    set sectorList ""
    APSStrictParseArguments {widget rootname sectorCount itemList missingList toggleVar missingListVar sectorList}
    global $toggleVar
   
    for {set n 1} {$n<=$sectorCount} {incr n} {
	if [llength $sectorList] {
	    set name [lindex $sectorList [expr $n-1]]${widget}
	} else {
	    set name S${n}${widget}
	}
        set togVar ${rootname}${name}
        global $togVar
        set $togVar [set $toggleVar]
        if [string length $missingListVar] {
            global $missingListVar
            set missingList [set $missingListVar]
        }
    #    foreach item $itemList {
     #       set name S${n}${item}
      #      set nameFlag ${rootname}${name}
       #     global $nameFlag
        #    set $nameFlag [set $togVar]
        #}
    }
   # foreach item $itemList {
    #    set togVar ${rootname}S${item}
    #    global $togVar
     #   set $togVar [set $toggleVar]
   # }
   # APSSRSectorUnsetMissing -rootname $rootname -missingList $missingList
}
proc APSSRSectorTogglePosition {args} {
    set item ""
    set rootname ""
    set sectorCount 40
    set missingList ""
    set missingListVar ""
    set toggleVar ""
    set sectorList ""
    APSStrictParseArguments {item rootname sectorCount missingList toggleVar missingListVar sectorList}
    global $toggleVar ${rootname}CBWidget
    if [string length $missingListVar] {
        global $missingListVar
        set missingList [set $missingListVar]
    }
    for {set sector 1} {$sector<=$sectorCount} {incr sector} {
	if [llength $sectorList] {
	    set name [lindex $sectorList [expr $sector-1]]${item}
	} else {
	    set name S[format %02d $sector]${item}
	}
        set nameFlag ${rootname}${name}
        global $nameFlag
#        set $nameFlag [set $toggleVar]
        if {[info exists $nameFlag]} {
            if {[set $nameFlag] != [set $toggleVar]} {
                [set ${rootname}CBWidget($name)] invoke
            }
        }
    }
    APSSRSectorUnsetMissing -rootname $rootname -missingList $missingList -sectorList $sectorList
}

proc APSSRItemTogglePosition {args} {
    # similar to APSSRSectorTogglePosition except the loop is over the
    # list of items rather than the list of sectors.
    set sector ""
    set itemList ""
    set rootname ""
    set missingList ""
    set missingListVar ""
    set toggleVar ""
    APSStrictParseArguments {sector itemList rootname missingList toggleVar missingListVar}
    global $toggleVar ${rootname}CBWidget
    if [string length $missingListVar] {
        global $missingListVar
        set missingList [set $missingListVar]
    }
    #set sector [format %02d $sector]
    foreach item $itemList {
        set name ${sector}${item}
        set nameFlag ${rootname}${name}
        global $nameFlag
        #set $nameFlag [set $toggleVar]
        if {[set $nameFlag] != [set $toggleVar]} {
            [set ${rootname}CBWidget($name)] invoke
        }
    }
    APSSRSectorUnsetMissing -rootname $rootname -missingList $missingList
}

proc APSGetIDXRayBPMList {args} {
    set plane ""
    set sddsOutput ""
    APSStrictParseArguments {plane sddsOutput}
    set plane [string toupper $plane]
    set BPMDir /home/helios/oagData/sr/BPMStatus
    set teeCmd "cat "
    if [string length $sddsOutput] {
        set teeCmd "tee $sddsOutput "
    }
    switch $plane {
        H -
        V {
            if [catch {eval exec sddsprocess $BPMDir/config.sdds -pipe=out \
                         -filter=column,Nonexistent${plane},0,0 \
                         -match=col,DeviceName=*ID:P? -noWarning \
                         | $teeCmd \
                         | sdds2stream -pipe -column=DeviceName} bpmList] {
                return -code error "APSGetIDXRayBPMList: $bpmList"
            }
        }
        default {
            if [catch {eval exec sddsprocess $BPMDir/config.sdds -pipe=out \
                         -filter=column,NonexistentH,0,0 \
                         -filter=column,NonexistentV,0,0 \
                        -match=col,DeviceName=*ID:P? -noWarning \
                         | $teeCmd \
                         | sdds2stream -pipe -column=DeviceName} bpmList] {
                return -code error "APSGetIDXRayBPMList: $bpmList"
            }
        }
    }
    return $bpmList
}

proc APSGetIDXRayEqnList {args} {
    set plane ""
    APSParseArguments {plane}
    if ![string length $plane] {
        return -code error "APSGetIDXRayEqnList: Argument plane not specified."
    }
    set BPMDir /home/helios/oagData/sr/BPMStatus
    if [catch {exec sddsprocess $BPMDir/config.sdds -pipe=out \
                 -filter=column,Nonexistent[string toupper ${plane}],0,0 \
                 -match=col,DeviceName=*ID:P? -noWarning \
                 | sdds2stream -pipe \
                 -column=ResponseEquation[string toupper ${plane}]} bpmList] {
        return -code error "APSGetIDXRayBPMList: $bpmList"
    }
    return $bpmList
}

proc APSGetBMXRayBPMList {args} {
    set plane ""
    set sddsOutput ""
    # option okForDCOrbitCorrection works only when plane is specified.
    set okForDCOrbitCorrection 0
    APSStrictParseArguments {plane sddsOutput okForDCOrbitCorrection}
    set plane [string toupper $plane]
    set BPMDir /home/helios/oagData/sr/BPMStatus
    set teeCmd "cat "
    if [string length $sddsOutput] {
        set teeCmd "tee $sddsOutput "
    }
    set extraOption ""
    if $okForDCOrbitCorrection {
        set extraOption -filter=column,OkForDCOrbitCorrection${plane},1,1
    }
    switch $plane {
        H -
        V {
            if [catch {eval exec sddsprocess $BPMDir/config.sdds -pipe=out \
                         -filter=column,Nonexistent${plane},0,0 \
                         $extraOption \
                         -match=col,DeviceName=*BM:P? -noWarning \
                         | $teeCmd \
                         | sdds2stream -pipe -column=DeviceName} bpmList] {
                return -code error "APSGetBMXRayBPMList: $bpmList"
            }
        }
        default {
            if [catch {eval exec sddsprocess $BPMDir/config.sdds -pipe=out \
                         -filter=column,NonexistentV,0,0 \
                         -match=col,DeviceName=*BM:P? -noWarning \
                         | $teeCmd \
                         | sdds2stream -pipe -column=DeviceName} bpmList] {
                return -code error "APSGetBMXRayBPMList: $bpmList"
            }
        }
    }
    return $bpmList
}

proc APSGetBMXRayEqnList {args} {
    set plane ""
    APSParseArguments {plane}
    if ![string length $plane] {
        return -code error "APSGetBMXRayEqnList: Argument plane not specified."
    }
    set BPMDir /home/helios/oagData/sr/BPMStatus
    if [catch {exec sddsprocess $BPMDir/config.sdds -pipe=out \
                 -filter=column,Nonexistent[string toupper ${plane}],0,0 \
                 -match=col,DeviceName=*BM:P? -noWarning \
                 | sdds2stream -pipe \
                 -column=ResponseEquation[string toupper ${plane}]} bpmList] {
        return -code error "APSGetBMXRayBPMList: $bpmList"
    }
    return $bpmList
}

proc APSGetMissingBPMList {args} {
    set plane ""
    APSParseArguments {plane}
    set plane [string toupper $plane]
    set BPMDir /home/helios/oagData/sr/BPMStatus
    switch $plane {
        H -
        V {
            if [catch {exec sddsprocess $BPMDir/config.sdds -pipe=out \
                         -filter=col,Nonexistent$plane,1,1 -noWarning \
                         | sdds2stream -pipe -column=DeviceName} missingList] {
                return -code error "APSGetMissingBPMList: $missingList"
            }
        }
        default {
            if [catch {exec sddsprocess $BPMDir/config.sdds -pipe=out \
                         -filter=col,NonexistentH,1,1 \
                         -filter=col,NonexistentV,1,1 -noWarning \
                         | sdds2stream -pipe -column=DeviceName} missingList] {
                return -code error "APSGetMissingBPMList: $missingList"
            }
        }
    }
    #if [catch {file delete -force $tmpFile} result] {
    #    return -code error $result
    #}
    return $missingList
}

proc APSSRConfigWeightDialog {args} {
    set weight ""
    set despike ""
    set item ""
    APSStrictParseArguments {weight despike item}
    global $weight $despike
    set w .srConfigWeightDialog
    if [winfo exists $w] {destroy $w}
    APSDialogBox $w -name "Weight Dialog for $item" \
      -cancelCommand "set $weight [set $weight]; set $despike [set $despike]" 
    APSLabeledEntry .le -parent $w.userFrame -label "Weight: " \
      -textVariable $weight -type real -width 26 -contextHelp \
      "Enter the weight for $item.  Should be a positive real number."
    APSRadioButtonFrame .rb -parent $w.userFrame -label "Despike: " \
      -variable $despike -packOption "-side top" \
      -orientation horizontal -buttonList {N Y} -valueList {0 1} \
      -contextHelp \
      "Set despike flag for use in orbit correction. Xray BPMs usually have the despike flag unset (N) while SR RF bpms have despike flag set (Y)."
}


proc APSSRConfigPlaneOrbitCorrection {widget args} {
    set parent ""
    set plane h
    set rootname sconfig
    set fileFrame 1
    set buttonOrientation vertical
    set application DCOrbitCorrection
    set includeP0s 0
    set includeIDs 0
    set includeBMs 0
    APSStrictParseArguments {parent rootname fileFrame buttonOrientation \
                               plane application includeP0s includeIDs includeBMs}
    if [lsearch -exact [list h v rf] [set plane [string tolower $plane]]]==-1 {
        return -code error "APSSRConfigPlaneOrbitCorrection: unknown plane: $plane"
    }
    if [string match $plane rf] {
        set rfMode 1
        set plane h
    } else {
        set rfMode 0
    }
    set allowedApplications [list DCOrbitCorrection FastDCOrbitCorrection RTFeedback Steering]
    if [lsearch -exact $allowedApplications $application]==-1 {
        return -code error "APSSRConfigPlaneOrbitCorrection: unknown application: $application"
    }

    # Make a dedicated scrolled status area for this configuration.
    global ${rootname}ConfigStatus
    set ${rootname}ConfigStatus ""
    APSFrame $widget -parent $parent -label "" -packOption "-expand true -fill both"
    APSScrolledStatus .scrolled -parent $parent$widget.frame \
      -textVariable ${rootname}ConfigStatus \
      -width 85 -height 6 -lineLimit 1000 -label ""

    # Make the checkbutton grids
    if $rfMode {
        set widgetList [APSTabFrame .devtab -parent $parent$widget.frame -label "" \
                          -labelList "Monitors" -width 1050 -height 440 \
                            -packOption "-expand true -fill both" ]
    } else {
        set widgetList [APSTabFrame .devtab -parent $parent$widget.frame -label "" \
                          -labelList "Monitors Correctors" -width 1050 -height 440 \
                           -packOption "-expand true -fill both" ]
    }
    set missingBPMList \
      [APSSRGetBadOrbitDevices -plane $plane -device BPM -application $application]
    global ${rootname}BadBPMList 
    set ${rootname}BadBPMList $missingBPMList
    APSSRMonitorCheckButtons .smbut -parent [lindex $widgetList 0] -rootname $rootname \
      -orientation $buttonOrientation -BP5Only $rfMode \
      -includeP0s $includeP0s -includeIDs $includeIDs -includeBMs $includeBMs \
      -missingListVar ${rootname}BadBPMList \
      -noLabel 1 -packOption "-side top"

    global ${rootname}BadCORRECTORList
    if !$rfMode {
        set missingCorrList \
          [APSSRGetBadOrbitDevices -plane $plane -device corrector -application $application]
        set ${rootname}BadCORRECTORList $missingCorrList
        APSSRCorrectorCheckButtons .shbut -parent [lindex $widgetList 1] \
          -rootname ${rootname} -plane $plane \
          -orientation $buttonOrientation \
          -missingListVar ${rootname}BadCORRECTORList \
          -noLabel 1 -packOption "-side top"
    } else {
        set missingCorrList ""
        set ${rootname}BadCORRECTORList ""
    }

    if $fileFrame {
        # Make frames for read, write, etc. controls.  Will go into a widget swap frame.
        set frameWidth 800
        set frameHeight 450
        switch -regexp $rootname {
            {[hv]config} {
                set labelList [list Config... Read... Write... \
                                 {Generate controllaw files...} \
                                 {Generate compensation files...} ]
                set commandList [list {} {} \
                                   "APSSetVarAndUpdate ${rootname}WriteDir \"\"" \
                                   {} {}]
            }
            default {
                set labelList [list Config... Read... Write... \
                                 {Generate controllaw files...} ]
                set commandList [list {} {} \
                                   "APSSetVarAndUpdate ${rootname}WriteDir \"\"" \
                                   {}]
            }
        }
        
        set widgetList [APSTabFrame .fileops -parent $parent$widget.frame -label "" \
                          -labelList $labelList \
                          -commandList $commandList \
                          -height $frameHeight -width $frameWidth]
        pack $parent$widget.frame.fileops -side top
        # select the "Read..." tab
        #$parent$widget.frame.fileops.frame.tn select Read...
        $parent$widget.frame.fileops.frame.tn select 1
        set windex 0

        # Make lattice selection frame.
        global ${rootname}Lattice ${rootname}MainDir ${rootname}LatSubDir
        set ${rootname}Lattice default
        switch -regexp $rootname {
            rf {
                set ${rootname}MainDir /home/helios/oagData/sr/rfOrbitControllaw
            }
            fb {
                set ${rootname}MainDir /home/helios/oagData/sr/rtfeedback
            }
            fdc {
                # fast DC orbit correction
                set ${rootname}MainDir /home/helios/oagData/sr/fastOrbitControllaw
            }
            default {
                set ${rootname}MainDir /home/helios/oagData/sr/orbitControllaw
            }
        }
        set ${rootname}LatSubDir lattices
        set widget [lindex $widgetList $windex]
        incr windex
        APSFrame .lattice -parent $widget  -label "Lattice" \
          -width $frameWidth -height $frameHeight -contextHelp \
          "Use this frame to specify the lattice directory name and main directory area.  You may also change the default lattice from here."
        set w0 $widget.lattice.frame
        APSLabeledEntry .maindir -parent $w0 -label "Main directory: " \
          -textVariable ${rootname}MainDir -width 60 -contextHelp \
          "Enter the name of the main directory for the orbit correction system."
        APSFileSelectWidget .config -parent $w0 -label "Lattice: " \
          -pathVariableList [list ${rootname}MainDir ${rootname}LatSubDir] -mode directory -width 60 \
          -variable ${rootname}Lattice -incrementButtons 0 -contextHelp \
          "Enter the name of the lattice with which to work."
        #comment out this default button because it is dangerous to change the default lattice and it is not needed in this application, since we have another software for SR managers to change the default lattice. We had an occasion that it was pressed by a non-familiar person which caused the orbit correction failure and hilarity ensured.
       # APSButton .default -parent $w0.config -text D -size small \
        #  -contextHelp "Makes the named file into the default lattice." \
          #  -command "APSMakeLink -confirm 1 -confirmMessage {Change default lattice? Are you sure?} -local 1 -log 1 -permissions 00775 -filename \[subst \$${rootname}MainDir/\$${rootname}LatSubDir/\$${rootname}Lattice\] -linkname \[subst \$${rootname}MainDir/\$${rootname}LatSubDir/default\]; set ${rootname}Lattice default"

        global ${rootname}refMatrices ${rootname}RefMatrix
        set ${rootname}RefMatrix $plane.default
        set ${rootname}refMatrices refMatrices
        APSFileSelectWidget .${plane}ref -parent $w0 -mode file \
          -label "Reference matrix: " -width 60 \
          -variable ${rootname}RefMatrix \
          -pathVariableList [list ${rootname}MainDir ${rootname}LatSubDir ${rootname}Lattice ${rootname}refMatrices] \
          -contextHelp \
          "Enter the name of the reference response matrix file for the $plane plane."

        #APSButton .default -parent $w0.${plane}ref -text D -size small \
         # -contextHelp "Makes the named file into the default $plane-plane reference matrix." \
          #-command "APSMakeLink -confirm 1 -confirmMessage {Change reference matrix? Are you sure?} -local 1 -log 1 -permissions 00664 -filename \[subst \$${rootname}MainDir/\$${rootname}LatSubDir/\$${rootname}Lattice/\$${rootname}refMatrices/\$${rootname}RefMatrix\] -linkname \[subst \$${rootname}MainDir/\$${rootname}LatSubDir/\$${rootname}Lattice/\$${rootname}refMatrices/$plane.default\]; set ${rootname}RefMatrix $plane.default"

        # Make configuration-read frame.
        global ${rootname}ReadFile ${rootname}ReadDescription ${rootname}Plane
        global ${rootname}FilterEnd1
        set ${rootname}Plane $plane
        set ${rootname}ReadFile $plane.default
        set ${rootname}ReadDescription ""
        set ${rootname}FilterEnd1 .*
        set widget [lindex $widgetList $windex]
        incr windex
        APSFrame .read -parent $widget -label "Read configuration" \
          -width $frameWidth -height $frameHeight -contextHelp \
          "Use this frame to read combined monitor and corrector configurations."
        set w0 $widget.read.frame
	APSLabeledOutput .lattice -parent $w0 -label "Lattice: " -width 60 \
          -textVariable ${rootname}Lattice -contextHelp \
          "Shows the lattice of the configuration for which this read widget applies."
        APSFileSelectWidget .file -parent $w0 -variable ${rootname}ReadFile -label "Config: " \
          -pathVariableList [list ${rootname}MainDir ${rootname}LatSubDir ${rootname}Lattice] \
          -mode directory -filterVariableList \
          [list ${rootname}Plane ${rootname}FilterEnd1] -width 60 \
          -incrementButtons 1 -contextHelp \
          "Enter the name of the configuration file to read."
        APSLabeledOutput .descrip -parent $w0 -label "Description: " -width 80 -packOption "-side top -anchor w" \
          -textVariable ${rootname}ReadDescription -contextHelp \
          "Shows the description of the last-read configuration file."

        APSFrame .bf -parent $w0 -relief flat -label "" -packOption "-side top -anchor w"
        set w1 $w0.bf.frame
        APSButton .io0 -parent $w1 -text Read(replace) -packOption "-side left -anchor n" -size small -command \
          "APSReadOrbitCorrectionConfig -rootname $rootname -filename \$${rootname}MainDir/\$${rootname}LatSubDir/\$${rootname}Lattice/\$${rootname}ReadFile/config -logic replace -includeP0s $includeP0s -includeIDs $includeIDs -includeBMs $includeBMs  -application $application" \
          -contextHelp "Press to read data to replace the existing configuration, using the named configuration file."
        APSButton .io1 -parent $w1 -text Read(or) -packOption "-side left -anchor n" -size small -command \
          "APSReadOrbitCorrectionConfig -rootname $rootname -filename \$${rootname}MainDir/\$${rootname}LatSubDir/\$${rootname}Lattice/\$${rootname}ReadFile/config -logic or -includeP0s $includeP0s -includeIDs $includeIDs -includeBMs $includeBMs" \
          -contextHelp "Press to read data to or with the existing configuration, using the named configuration file."
        APSButton .io2 -parent $w1 -text Read(and) -packOption "-side left -anchor n" -size small -command \
          "APSReadOrbitCorrectionConfig -rootname $rootname -filename \$${rootname}MainDir/\$${rootname}LatSubDir/\$${rootname}Lattice/\$${rootname}ReadFile/config -logic and -includeP0s $includeP0s -includeIDs $includeIDs -includeBMs $includeBMs" \
          -contextHelp "Press to read data to and with the existing configuration, using the named configuration file."
        APSButton .io3 -parent $w1 -text Read(not) -packOption "-side left -anchor n" -size small -command \
          "APSReadOrbitCorrectionConfig -rootname $rootname -filename \$${rootname}MainDir/\$${rootname}LatSubDir/\$${rootname}Lattice/\$${rootname}ReadFile/config -logic not -includeP0s $includeP0s -includeIDs $includeIDs -includeBMs $includeBMs" \
          -contextHelp "Press to read data specifying elements to turn off, using the named configuration file."
        APSButton .io4 -parent $w1 -text "Refresh good/bad" -packOption "-side left -anchor n" -size small -command \
            "APSRescanBadOrbitDevices -rootname $rootname -plane $plane -application $application"
        if [string compare DCOrbitCorrection $application]==0 {
            # add check buttons for switching allowable devices for the various modes of DC 
            # correction
            global ${rootname}BPMPVType ${rootname}CorrectorPVType 
            set ${rootname}BPMPVType plain
            set ${rootname}CorrectorPVType plain
            APSFrame .switch -parent $w0 -relief flat -label "" -packOption "-side top -anchor w"
	    if {0} {
            APSRadioButtonFrame .rbsw1 -parent $w0.switch.frame -orientation horizontal \
              -label "BPM PV type" -variable ${rootname}BPMPVType -packOption "-side left" \
              -buttonList "plain DP" -valueList "plain DP" -commandList \
              [list \
                 "APSRescanBadOrbitDevices -rootname $rootname -plane $plane -application $application" \
                 "APSRescanBadOrbitDevices -rootname $rootname -plane $plane -application $application"]
            APSRadioButtonFrame .rbsw2 -parent $w0.switch.frame -orientation horizontal \
              -label "Corrector PV type" -variable ${rootname}CorrectorPVType \
              -buttonList "plain dynamic DP" -valueList "plain dynamic DP" -packOption "-side left" \
              -commandList \
              [list \
                 "APSRescanBadOrbitDevices -rootname $rootname -plane $plane -application $application" \
                 "APSRescanBadOrbitDevices -rootname $rootname -plane $plane -application $application" \
                 "APSRescanBadOrbitDevices -rootname $rootname -plane $plane -application $application"]
	    }
        }

        # Make the write-configuration frame
        global ${rootname}WriteDir 
        set widget [lindex $widgetList $windex]
        incr windex
        APSFrame .write -parent $widget -label "Write configuration" \
          -width $frameWidth -height $frameHeight -contextHelp \
          "Use this frame to write combined monitor and corrector configurations."
        set w0 $widget.write.frame
	APSLabeledOutput .lattice -parent $w0 -label "Lattice: " -width 60 \
          -textVariable ${rootname}Lattice -contextHelp \
          "Shows the lattice of the configuration for which this write widget applies."
        #set ${rootname}WriteDir h.[clock format [clock seconds] -format %Y-%m%d].00
	set ${rootname}WriteDir ""
        APSFileSelectWidget .file -parent $w0 -variable ${rootname}WriteDir \
          -pathVariableList [list ${rootname}MainDir ${rootname}LatSubDir ${rootname}Lattice] \
          -label "Config: " -noSelect 0 -mode directory -incrementButtons 1 -width 60 -contextHelp \
          "Enter the name of the configuration to write." \
          -filterVariableList [list ${rootname}Plane ${rootname}FilterEnd1]
        APSButton .genname -parent $w0.file -text G -size small -command \
          "set ${rootname}WriteDir \[APSNextGenerationedName -directory \$${rootname}MainDir/\$${rootname}LatSubDir/\$${rootname}Lattice -name \$${rootname}Plane.\[clock format \[clock seconds\] -format %Y-%m%d\].00 -newFile 1 -separator .\]"
        APSLabeledEntry .descrip -parent $w0 -label "Description: " -width 60 \
          -textVariable ${rootname}WriteDescription -contextHelp \
          "Use to enter a description for the configuration to be written."
       
        APSButton .io -parent $w0 -text Write -size small -command \
          "APSSRWritePlaneOrbitCorrectionConfig -rootname $rootname -interactive 1 -filename \$${rootname}MainDir/\$${rootname}LatSubDir/\$${rootname}Lattice/\$${rootname}WriteDir/config -description \$${rootname}WriteDescription -includeP0s $includeP0s -includeIDs $includeIDs -includeBMs $includeBMs -BP5Only $rfMode -configName \$${rootname}WriteDir -plane $plane" \
          -contextHelp "Press to write data, using the named configuration file."
        
        # Make the frame for computing the matrix and installing it.
        global ${rootname}Plane ${rootname}SingValues ${rootname}SVDanalysis ${rootname}SetupOutputDir 
        global  ${rootname}DeleteModes ${rootname}TikhonovSVN ${rootname}TikhonovBeta ${rootname}TikhonovFilter ${rootname}TikhonovType
        set widget [lindex $widgetList $windex]
        incr windex
        APSFrame .comp -parent $widget -label "Compute matrix" \
          -width $frameWidth -height $frameHeight -contextHelp \
          "Use this frame to generate the matrix for orbit correction from an existing configuration."
        set w0 $widget.comp.frame
        APSLabeledOutput .lattice -parent $w0 -label "Lattice: " -width 60 \
          -textVariable ${rootname}Lattice -contextHelp \
          "Shows the lattice of the configuration for which this generate widget applies."
        set ${rootname}SingValues 320
        set ${rootname}SVDanalysis 0
        set ${rootname}DeleteModes ""
	set ${rootname}TikhonovFilter 0
	set ${rootname}TikhonovSVN 0
	set ${rootname}TikhonovBeta 0
	set ${rootname}TikhonovType SVN
        APSFileSelectWidget .file -parent $w0 -variable ${rootname}WriteDir \
          -pathVariableList [list ${rootname}MainDir ${rootname}LatSubDir ${rootname}Lattice] -filter "h.* v.*" \
          -label "Config: " -noSelect 0 -mode directory -incrementButtons 1 -width 60 -contextHelp \
          "Enter the name of the configuration to use." \
          -filterVariableList [list ${rootname}Plane ${rootname}FilterEnd1] 
        APSButton .genname -parent $w0.file -text G -size small -command \
          "set ${rootname}WriteDir \[APSNextGenerationedName -directory \$${rootname}MainDir/\$${rootname}LatSubDir/\$${rootname}Lattice -name \$${rootname}Plane.\[clock format \[clock seconds\] -format %Y-%m%d\].00 -newFile 1 -separator .\]"

        if $rfMode {
            global ${rootname}BPMPVSuffix
            set ${rootname}BPMPVSuffix LowPass1sRfErrorM
            
            APSRadioButtonFrame .pvsuffix -parent $w0 -label "bpm PV type:" \
                -variable ${rootname}BPMPVSuffix -valueList {LowPass1sRfErrorM LowPass8sRfErrorM LowPass64sRfErrorM} \
                -buttonList {1s 8s 64s} -orientation horizontal \
              -contextHelp "select the filtering PV type for rf controllaw."
            
        }
        frame $w0.f1 
        pack $w0.f1 -fill x
        APSLabeledEntry .le1 -parent $w0.f1 -packOption "-side left" \
          -textVariable ${rootname}SingValues \
          -label "Number of singular values: " -width 8 -contextHelp \
          "Enter the number of singular values to keep."
        if {0} {
        APSRadioButtonFrame .rb2 -parent $w0.f1 -packOption "-side left" \
          -label "SVD analysis: " \
          -variable ${rootname}SVDanalysis -buttonList {N Y} -valueList {0 1} \
          -orientation horizontal -contextHelp \
          "Select \"No\" for immediate calculation of the inverse response matrix using \
 the list of singular values in the entry box \"Vectors to remove\". If the list \
 in \"Vectors to remove\" is empty, then the inverse response matrix (file irm) \
 is calculated as usual. \n\nSelect \"Yes\" to modify the behavior of the \"Compute\" button.\
 The \"Compute\" button will produce plots of the orthogonal vectors of the response \
 matrix. Once the tksddsplot plot has finished loading all the \
 vectors, browse through the plot frame with the \"n\" or \"p\" keys. \
 Select \"No\" in the bottom of tksddsplot widget for vectors that you want \
 to eliminate. After you close the plot, the list of vectors will be listed in \
 the \"Vectors to remove\" entry box. There is no inverse matrix file for \
 orbit correction produced at this point. The next step is to switch the analysis \
 to \"No\" and press compute again. \n\nSelecting \"No\" after a delete list is created\
 in the \"Vectors to remove\", will create the inverse matrix for orbit correction \
 with the vectors selected removed."
        }
        if !$rfMode {
            APSButton .svd -parent $w0.f1 -packOption "-side left" -text "SVD Analysis" -size small \
            -command "APSSRGenerateOrbCorrFiles -rootname $rootname -generate 1 -configFile \$${rootname}MainDir/\$${rootname}LatSubDir/\$${rootname}Lattice/\$${rootname}WriteDir/config -plane \$${rootname}Plane -referenceMatrix \$${rootname}MainDir/\$${rootname}LatSubDir/\$${rootname}Lattice/refMatrices/\$${rootname}RefMatrix -outputRoot \$${rootname}MainDir/\$${rootname}LatSubDir/\$${rootname}Lattice/\$${rootname}WriteDir/ -singularValues \$${rootname}SingValues -SVDanalysis 1" \
            -contextHelp "produce plots of the orthogonal vectors of the response \
                          matrix. Once the tksddsplot plot has finished loading all the \
                          vectors, browse through the plot frame with the \"n\" or \"p\" keys. \
                          Select \"No\" in the bottom of tksddsplot widget for vectors that you want \
                          to eliminate. After you close the plot, the list of vectors will be listed in \
                          the \"Vectors to remove\" entry box."
            APSButton .gen -parent $w0.f1 -text Compute -size small -packOption "-side left" -command \
              "APSSRGenerateOrbCorrFiles -rootname $rootname -generate 1 -configFile \$${rootname}MainDir/\$${rootname}LatSubDir/\$${rootname}Lattice/\$${rootname}WriteDir/config -plane \$${rootname}Plane -referenceMatrix \$${rootname}MainDir/\$${rootname}LatSubDir/\$${rootname}Lattice/refMatrices/\$${rootname}RefMatrix -outputRoot \$${rootname}MainDir/\$${rootname}LatSubDir/\$${rootname}Lattice/\$${rootname}WriteDir/ -singularValues \$${rootname}SingValues -SVDanalysis 0 -tikhonovFilter \$${rootname}TikhonovFilter -tikhonovSVN \$${rootname}TikhonovSVN -tikhonovBeta \$${rootname}TikhonovBeta -tikhonovType \$${rootname}TikhonovType"
        } else {
            
            APSButton .svd -parent $w0.f1 -packOption "-side left" -text "SVD Analysis"  -size small \
              -command "APSSRFreqGenerateOrbCorrFiles -rootname $rootname -generate 1 -configFile \$${rootname}MainDir/\$${rootname}LatSubDir/\$${rootname}Lattice/\$${rootname}WriteDir/config -plane \$${rootname}Plane -referenceMatrix \$${rootname}MainDir/\$${rootname}LatSubDir/\$${rootname}Lattice/refMatrices/\$${rootname}RefMatrix -outputRoot \$${rootname}MainDir/\$${rootname}LatSubDir/\$${rootname}Lattice/\$${rootname}WriteDir/ -singularValues \$${rootname}SingValues -SVDanalysis 1 -bpmSuffix [set ${rootname}BPMPVSuffix]" \
            -contextHelp "produce plots of the orthogonal vectors of the response \
                          matrix. Once the tksddsplot plot has finished loading all the \
                          vectors, browse through the plot frame with the \"n\" or \"p\" keys. \
                          Select \"No\" in the bottom of tksddsplot widget for vectors that you want \
                          to eliminate. After you close the plot, the list of vectors will be listed in \
                          the \"Vectors to remove\" entry box."
            APSButton .gen -parent $w0.f1 -text Compute -size small -packOption "-side left" -command \
              "APSSRFreqGenerateOrbCorrFiles -rootname $rootname -generate 1 -configFile \$${rootname}MainDir/\$${rootname}LatSubDir/\$${rootname}Lattice/\$${rootname}WriteDir/config -plane \$${rootname}Plane -referenceMatrix \$${rootname}MainDir/\$${rootname}LatSubDir/\$${rootname}Lattice/refMatrices/\$${rootname}RefMatrix -outputRoot \$${rootname}MainDir/\$${rootname}LatSubDir/\$${rootname}Lattice/\$${rootname}WriteDir/ -singularValues \$${rootname}SingValues -SVDanalysis 0  -bpmSuffix [set ${rootname}BPMPVSuffix] -tikhonovFilter \$${rootname}TikhonovFilter -tikhonovSVN \$${rootname}TikhonovSVN -tikhonovBeta \$${rootname}TikhonovBeta -tikhonovType \$${rootname}TikhonovType"
        }
        APSButton .default -parent $w0.f1 -text "Make Default" -size small -packOption "-side left" \
          -contextHelp "Makes the named configuration into the default corrector configuration for chosen plane." \
          -command "APSSRInstallOrbCorrFiles -rootname $rootname -application $application"
        APSLabeledEntry .deletemodes -parent $w0 -textVariable ${rootname}DeleteModes \
          -label "Mode to delete: " \
          -contextHelp "Enter the list of vectors to remove from the matrix. A list is created when an analysis is requested." -width 80
	
	APSRadioButtonFrame .tik -parent $w0 -label "Use tikhonov filter?" -buttonList {Yes No} \
	    -valueList {1 0} -variable ${rootname}TikhonovFilter -orientation horizontal
	APSRadioButtonEntryFrame .par -parent $w0.tik -orientation horizontal -label "Tikhonov filter type:"  \
	    -variable ${rootname}TikhonovType -buttonList {SVN_Number Beta} -orientation horizontal \
	    -valueList {SVN Beta} -commandList [list "set ${rootname}TikhonovBeta 0" "set ${rootname}TikhonovSVN 0"] \
	    -entryVariableList [list ${rootname}TikhonovSVN ${rootname}TikhonovBeta] \
	    -entryWidth 10
	if {0} {
	APSLabeledEntryFrame .alpha -parent $w0.tik   -orientation horizontal \
	    -label "  Tikhonov parameters: SVN/Beta:" -variableList [list ${rootname}TikhonovSVN ${rootname}TikhonovBeta] -width 15 \
	    -contextHelp "provide the SVN number or beta (fractional alpha) of the tikhonov filter, the singular value of the provided SVN number will be used as alpha of the tikhonov filter."
	}
        if {$windex == [llength $widgetList]} return
	
        set widget [lindex $widgetList $windex]
        incr windex
        APSFrame .compensation -parent $widget -label "Compute feedforward matrix" \
          -width $frameWidth -height $frameHeight -contextHelp \
          "Use this frame to generate the feedforward matrix for orbit correction from existing configurations in DC correction and FB correction. The feedforward matrix is composed of the DC reference matrix with DC correctors selected and RT bpms selected. One would get a 160 bpm x 80 corrector matrix typically."
        set w0 $widget.compensation.frame
	
        APSLabeledOutput .lattice -parent $w0 -label "Lattice: " -width 60 \
          -textVariable ${rootname}Lattice -contextHelp \
          "Shows the lattice of the configuration for which this generate widget applies."
# singular values not relevant anymore for feedforward matrix.
#        set ${rootname}SingValues 320
#        set ${rootname}SVDanalysis 0
        APSFileSelectWidget .file1 -parent $w0 -variable ${rootname}WriteDir \
          -pathVariableList [list ${rootname}MainDir ${rootname}LatSubDir ${rootname}Lattice] -filter "h.* v.*" \
          -label "DC Config: " -noSelect 0 -mode directory -incrementButtons 1 \
          -width 60 -contextHelp \
          "Enter the name of the configuration to use." \
          -filterVariableList [list ${rootname}Plane ${rootname}FilterEnd1] 
        APSButton .genname -parent $w0.file1 -text G -size small -command \
          "set ${rootname}WriteDir \[APSNextGenerationedName -directory \$${rootname}MainDir/\$${rootname}LatSubDir/\$${rootname}Lattice -name \$${rootname}Plane.\[clock format \[clock seconds\] -format %Y-%m%d\].00 -newFile 1 -separator .\]"

        # select corresponding compensation rootname as hfbconfig or vfbconfig for the
        # appropriate rootname. Fast DC orbit corrections uses the same compensation
        # as regular DC correction.
        switch $rootname {
            hfdcconfig -
            hconfig {set rootnameComp hfbconfig}
            vfdcconfig -
            vconfig {set rootnameComp vfbconfig}
            default {set rootnameComp $rootname}
        }
        # need to assign the feedback main directory in both DC orbit correction
        # because the variables [hv]fbconfigMainDir are used in the FF compensation.
        global ${rootnameComp}MainDir ${rootnameComp}Plane \
          ${rootnameComp}FilterEnd1 ${rootnameComp}LatSubDir \
          ${rootnameComp}Lattice ${rootnameComp}RTDir
        set ${rootnameComp}MainDir /home/helios/oagData/sr/rtfeedback
        set ${rootnameComp}Plane $plane
        set ${rootnameComp}FilterEnd1 .*
        set ${rootnameComp}LatSubDir lattices
        set ${rootnameComp}Lattice default
        set ${rootnameComp}RTDir $plane.default

        APSFileSelectWidget .file2 -parent $w0 -variable ${rootnameComp}RTDir \
          -pathVariableList [list ${rootnameComp}MainDir ${rootnameComp}LatSubDir ${rootnameComp}Lattice] -filter "h.* v.*" \
          -label "RT Config: " -noSelect 0 -mode directory -incrementButtons 1 \
          -width 60 -contextHelp \
          "Enter the name of the configuration to use. Note that the configuration is taken from the feedback configuration area of the appropriate plane." \
          -filterVariableList [list ${rootnameComp}Plane ${rootnameComp}FilterEnd1] 
        APSButton .genname -parent $w0.file2 -text G -size small -command \
          "set ${rootnameComp}RTDir \[APSNextGenerationedName -directory \$${rootnameComp}MainDir/\$${rootnameComp}LatSubDir/\$${rootnameComp}Lattice -name \$${rootnameComp}Plane.\[clock format \[clock seconds\] -format %Y-%m%d\].00 -newFile 1 -separator .\]"

        frame $w0.f1 
        pack $w0.f1 -fill x
        APSButton .gen -parent $w0.f1 -text Compute -size small -packOption "-side left" -command \
          "APSSRGenerateOrbCorrFiles -rootname $rootname -generate 1 -configFile \$${rootname}MainDir/\$${rootname}LatSubDir/\$${rootname}Lattice/\$${rootname}WriteDir/config -plane \$${rootname}Plane -referenceMatrix \$${rootname}MainDir/\$${rootname}LatSubDir/\$${rootname}Lattice/refMatrices/\$${rootname}RefMatrix -outputRoot \$${rootname}MainDir/\$${rootname}LatSubDir/\$${rootname}Lattice/\$${rootname}WriteDir/ -singularValues \$${rootname}SingValues -SVDanalysis \$${rootname}SVDanalysis -compensationConfigFile \$${rootnameComp}MainDir/\$${rootnameComp}LatSubDir/\$${rootnameComp}Lattice/\$${rootnameComp}RTDir/config -tikhonovFilter \$${rootname}TikhonovFilter -tikhonovSVN \$${rootname}TikhonovSVN -tikhonovBeta \$${rootname}TikhonovBeta -tikhonovType \$${rootname}TikhonovType"
        APSButton .default -parent $w0.f1 -text "Make Default" -size small -packOption "-side left" \
          -contextHelp "Makes the named configuration into the default corrector configuration for chosen plane." \
          -command "APSSRInstallOrbCorrFiles -rootname $rootname -application $application"
	#temporarily disable compensation widget
	APSDisableWidget $widget
	global APSDisableCompensation
	set APSEnableCompensation 0
	checkbutton $widget.enable -text "Enable/Disable" -variable APSEnableCompensation \
	    -command "APSEnableDisableWidget $widget -variable APSEnableCompensation" \
	    -borderwidth 1 -padx 0 -pady 0 -highlightthickness 0
	pack $widget.enable
    }
}


proc APSSRWritePlaneOrbitCorrectionConfig {args} {
    set rootname ""
    set filename ""
    set plane h
    set description ""
    set interactive 0
    set includeP0s 0
    set includeIDs 0
    set includeBMs 0
    set BP5Only 0
    set configName ""
    set booster 0
    set sectorCount 40
    set sectorList ""
    #booster=1 for writing booster configuration
    APSStrictParseArguments {rootname filename description interactive includeP0s \
                               includeIDs includeBMs configName  \
                               plane BP5Only booster sectorCount sectorList}

    if [lsearch -exact [list h v] [set plane [string tolower $plane]]]==-1 {
        return -code error "APSSRWritePlaneOrbitCorrectionConfig: invalid plane: $plane"
    }
    
    if ![string length [string trim $configName]] {
        return -code error "APSSRWritePlaneOrbitCorrectionConfig: supply a configuration name"
    }
    if ![string match $plane.* $configName] {
        if !$interactive {
            return -code error "APSSRWritePlaneOrbitCorrectionConfig: configuration name should be $plane.*"
        }
        if [APSMultipleChoice [APSUniqueName .] \
              -question "Configuration name doesn't match the pattern $plane.*, which may cause problems.  What do you want to do?" \
              -labelList [list "Abort (recommended)" "Continue"] \
              -returnList {1 0}] {
            return 
        }
    }

    set path [file dirname $filename]
    set pathPart [file tail $path]

    global ${rootname}BPMPVType ${rootname}CorrectorPVType
    if ![info exists ${rootname}BPMPVType] {
        set ${rootname}BPMPVType plain
    }
    if ![info exists ${rootname}CorrectorPVType] {
        set ${rootname}CorrectorPVType plain
    }
    if $booster {
        set BPMList [list P1 P2]
        switch $plane {
            h {
                set corrList H
            }
            v {
                set corrList V
            }
            default {
                return -code error "APSSRWritePlaneOrbitCorrectionConfig: no such plane: $plane"
            }
        }
	if ![llength $sectorList] {
	    set sectorList ""
	    for {set b 1} {$b<5} {incr b} {
		for {set c 0} {$c<10} {incr c} {
		    lappend sectorList B${b}C$c
		}
	    }
	}
	set sectorCount [llength $sectorList]
        if $interactive {
            set corCount [APSCountSRConfig -rootname $rootname -itemList $corrList -sectorCount $sectorCount -sectorList $sectorList]
            set confirmQuery ""
            set confirm 0
            if {!$corCount} {
                set confirm 1
                append confirmQuery "\nNo correctors chosen."
            }
            if [APSCountSRConfig -rootname $rootname -itemList $BPMList -sectorCount $sectorCount -sectorList $sectorList]==0 {
                set confirm 1
                append confirmQuery "\nNo monitors chosen."
            }
            if {$confirm &&
                [APSMultipleChoice [APSUniqueName .] -question "Possible problem: $confirmQuery" \
                   -labelList {"Cancel (recommended)" Continue} -returnList {0 1}]==0} {
                return
            }
        }
        
        if ![file exists $path] {
            exec mkdir $path
            #catch {exec setfacl -m mask:rwx $path}
        } else {
            if {$interactive && \
                  [APSMultipleChoice [APSUniqueName .] -question "That configuration exists.  Overwrite?" \
                     -labelList {Yes No} -returnList {1 0}]==0} {
                return
            }
            set filesToDelete [glob -nocomplain $path/*]
            if [llength $filesToDelete] {
                if [catch {eval file delete -force -- $filesToDelete} result] {
                    return -code error "APSSRWritePlaneOrbitCorrectionConfig: $result"
                }
            }
        }
        APSWriteSRConfig -rootname $rootname -filename $filename -sectorList $sectorList \
          -nameTypeList {Monitor Corrector} -interactive $interactive \
          -PVTypeList [list [set ${rootname}BPMPVType]  [set ${rootname}CorrectorPVType]] \
          -suffixLists [list $BPMList $corrList] \
          -description $description -sectorCount $sectorCount -booster $booster
        catch {exec sddscollapse $filename $filename.collapsed}
        return
    }
    global SRBPMSuffixList  SRHCorrSuffixList SRVCorrSuffixList
    set BPMList $SRBPMSuffixList
    if $BP5Only {
        #set BPMList [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]
        if ![file exists $path] {
            exec  mkdir $path
            #catch {exec setfacl -m mask:rwx $path}
        } else {
            if {$interactive && \
                  [APSMultipleChoice [APSUniqueName .] -question "That configuration exists.  Overwrite?" \
                     -labelList {Yes No} -returnList {1 0}]==0} {
                return
            }
            set filesToDelete [glob -nocomplain $path/*]
            if [llength $filesToDelete] {
                if [catch {eval file delete -force -- $filesToDelete} result] {
                    return -code error "APSSRWriteOrbitCorrectionConfig: $result"
                }
            }
        }
        APSWriteSRConfig -rootname $rootname -filename $filename \
          -nameTypeList Monitor -interactive $interactive \
          -PVTypeList [set ${rootname}BPMPVType] \
          -suffixLists [list $BPMList] -description $description
    } else {
       # set BPMList [list A:P1 A:P2 A:P3 A:P4 B:P5 B:P4 B:P3 B:P2 B:P1]
       # if $includeP0s {
       #     set BPMList [concat A:P0 $BPMList B:P0 C:P0]
       # }
        if $includeIDs {
            set BPMList [concat $BPMList IDFE-XBPM:P1us  IDFE-XBPM:P1ds  IDFE-XBPM:P2us IDFE-XBPM:P2ds]
        }
        if $includeBMs {
            set BPMList [concat $BPMList BMFE-XBPM:P1 BMFE-XBPM:P2]
        }
        switch $plane {
            h {
		set corrList $SRHCorrSuffixList
            }
            v {
		set corrList $SRVCorrSuffixList
            }
            default {
                return -code error "APSSRWritePlaneOrbitCorrectionConfig: no such plane: $plane"
            }
        }
        if $interactive {
            set corCount [APSCountSRConfig -rootname $rootname -itemList $corrList]
            set confirmQuery ""
            set confirm 0
            if {!$corCount} {
                set confirm 1
                append confirmQuery "\nNo correctors chosen."
            }
            if [APSCountSRConfig -rootname $rootname -itemList $BPMList]==0 {
                set confirm 1
                append confirmQuery "\nNo monitors chosen."
            }
            if {$confirm &&
                [APSMultipleChoice [APSUniqueName .] -question "Possible problem: $confirmQuery" \
                   -labelList {"Cancel (recommended)" Continue} -returnList {0 1}]==0} {
                return
            }
        }
        
        if ![file exists $path] {
            exec mkdir $path
            #catch {exec setfacl -m mask:rwx $path}
        } else {
            if {$interactive && \
                  [APSMultipleChoice [APSUniqueName .] -question "That configuration exists.  Overwrite?" \
                     -labelList {Yes No} -returnList {1 0}]==0} {
                return
            }
            set filesToDelete [glob -nocomplain $path/*]
            if [llength $filesToDelete] {
                if [catch {eval file delete -force -- $filesToDelete} result] {
                    return -code error "APSSRWriteOrbitCorrectionConfig: $result"
                }
            }
        }
        APSWriteSRConfig -rootname $rootname -filename $filename \
          -nameTypeList {Monitor Corrector} -interactive $interactive \
          -PVTypeList [list [set ${rootname}BPMPVType]  [set ${rootname}CorrectorPVType]] \
          -suffixLists [list $BPMList $corrList] \
          -description $description
    }
    catch {exec sddscollapse $filename $filename.collapsed}
}

proc APSSRGetBadOrbitDevices {args} {
    set plane h 
    set device corrector
    set application DCOrbitCorrection
    APSStrictParseArguments {plane application device}
    set plane [string toupper $plane]
    set device [string toupper $device]

    if [lsearch -exact [list H V] $plane]==-1 {
        return -code error "APSSRGetBadOrbitDevices: bad plane: $plane"
    }
    set allowedApplications [list DCOrbitCorrection FastDCOrbitCorrection RTFeedback Steering]
    if [lsearch -exact $allowedApplications $application]==-1 {
        return -code error "APSSRGetBadOrbitDevices: bad application: $application"
    }
    switch $device {
        CORRECTOR {
            set configFile /home/helios/oagData/sr/${plane}CorrectorStatus/config.sdds
        }
        BPM {
            set configFile /home/helios/oagData/sr/BPMStatus/config.sdds
            set application ${application}$plane
        }
        default {
            return -code error "APSSRGetBadOrbitDevices: bad device: $device"
        }
    }
    if ![file exists $configFile] {
        return -code error "APSSRGetBadOrbitDevices: not found: $configFile"
    }
    if [catch {sdds load $configFile configData} result] {
        return -code error "APSSRGetBadOrbitDevices: $result"
    }
    set deviceName [lindex $configData(Column.DeviceName) 0]
    if [lsearch -exact $configData(ColumnNames) Nonexistent$plane]==-1 {
        set deviceNonexistent [lindex $configData(Column.Nonexistent) 0]
    } else {
        set deviceNonexistent [lindex $configData(Column.Nonexistent$plane) 0]
    }
    set deviceOk [lindex $configData(Column.OkFor${application}) 0]
    set badList ""
    foreach device $deviceName nonexistent $deviceNonexistent ok $deviceOk {
        if {$nonexistent || !$ok} {
            lappend badList $device
        }
    }
    return $badList
}

proc APSRescanBadOrbitDevices {args} {
    set plane h
    set rootname ""
    set application DCOrbitCorrection
    set booster 0
    set bts 0
    APSStrictParseArguments {plane rootname application booster bts}
    global ${rootname}BPMPVType ${rootname}CorrectorPVType apsBackground
    if ![info exists ${rootname}BPMPVType] {
        set ${rootname}BPMPVType plain
    }
    if ![info exists ${rootname}CorrectorPVType] {
        set ${rootname}CorrectorPVType plain
    }
    set plane [string toupper $plane]
    if [lsearch -exact [list H V] $plane]==-1 {
        return -code error "APSRescanBadOrbitDevices: bad plane: $plane"
    }
    set allowedApplications [list DCOrbitCorrection FastDCOrbitCorrection RTFeedback Steering]
    if [lsearch -exact $allowedApplications $application]==-1 {
        return -code error "APSRescanBadOrbitDevices: bad application: $application"
    }

    foreach deviceType {BPM CORRECTOR} {
        switch $deviceType {
            CORRECTOR {
		if $bts {
		    set configFile /home/helios/oagData/bts/CorrectorStatus/config.sdds
		} else {
		    set configFile /home/helios/oagData/sr/${plane}CorrectorStatus/config.sdds
		}
                set application0 ${application}
                if {[string compare $application DCOrbitCorrection]==0 && \
                      [lsearch -exact [list dynamic DP] [set ${rootname}CorrectorPVType]]!=-1} {
                    set application0 Fast$application0
                }
            }
            BPM {
		if $booster {
		    set configFile /home/helios/oagData/booster/BPMStatus/config.sdds
		} elseif $bts {
		    set configFile /home/helios/oagData/bts/BPMStatus/config.sdds
		} else {
		    set configFile /home/helios/oagData/sr/BPMStatus/config.sdds
		}
                set application0 ${application}$plane
                if {[string compare [set ${rootname}BPMPVType] DP]==0 && \
                      [string compare $application DCOrbitCorrection]==0} {
                    set application0 Fast$application0
                }
            }
        }
        if ![file exists $configFile] {
            return -code error "APSRescanBadOrbitDevices: not found: $configFile"
        }
        if [catch {sdds load $configFile configData} result] {
            return -code error "APSRescanBadOrbitDevices: $result"
        }
        set deviceName [lindex $configData(Column.DeviceName) 0]
        if [lsearch -exact $configData(ColumnNames) Nonexistent$plane]==-1 {
            set deviceNonexistent [lindex $configData(Column.Nonexistent) 0]
        } else {
            set deviceNonexistent [lindex $configData(Column.Nonexistent$plane) 0]
        }
        set deviceOk [lindex $configData(Column.OkFor${application0}) 0]
        set badList ""
        global ${rootname}CBWidget
        set knownDevices [array names ${rootname}CBWidget]
        foreach device $deviceName nonexistent $deviceNonexistent ok $deviceOk {
	    if $booster {
		set device [string replace $device 0 0 S]
	    }
            if [lsearch -exact $knownDevices $device]==-1 continue
            set nameFlag ${rootname}${device}
            global $nameFlag
            if {$nonexistent || !$ok} {
                set $nameFlag 0
                if {$nonexistent} {
                    [set ${rootname}CBWidget($device)] configure -state disabled -indicatoron off -borderwidth 0 -pady 1 -padx 1
                } else {
                    [set ${rootname}CBWidget($device)] configure -state disabled -bg $apsBackground -borderwidth 1 -pady 0 -padx 0
                }
                lappend badList $device
            } else {
                set wasDisabled [[set ${rootname}CBWidget($device)] cget -state]
                [set ${rootname}CBWidget($device)] configure -state normal -indicatoron on -bg $apsBackground -borderwidth 1 -pady 0 -padx 0
                if {$wasDisabled == "disabled"} {
                    set $nameFlag 0
                    [set ${rootname}CBWidget($device)] invoke
                }
            }
        }
        global ${rootname}Bad${deviceType}List 
        set ${rootname}Bad${deviceType}List $badList
    }
}

proc APSSRFreqGenerateOrbCorrFiles {args} {
    set configFile ""
    set outputRoot ""
    set referenceMatrix ""
    set plane h
    set generate 0
    set install 0
    set rootname ""
    set singularValues 320
    set SVDanalysis 0
    set tikhonovFilter 0
    set tikhonovSVN 0
    set tikhonovBeta 0
    set tikhonovType SVN
    set deleteVectors ""
    set bpmSuffix LowPass1sAdjustedM
    APSStrictParseArguments {configFile plane outputRoot referenceMatrix generate install rootname singularValues SVDanalysis
        deleteVectors bpmSuffix tikhonovFilter tikhonovSVN tikhonovBeta tikhonovType}
    
   
    if {!$generate && !$install} return
    if {$tikhonovFilter} {
	if {$tikhonovType=="SVN" && !$tikhonovSVN} {
	    return -code error "APSSRFreqGenerateOrbCorrFiles(0a): tikhonov SVN number not provided!"
	}
	if {$tikhonovType=="Beta" && !$tikhonovBeta} {
	    return -code error "APSSRFreqGenerateOrbCorrFiles(0b): tikhonov beta value not provided!"
	}
    }
    if ![string length $rootname] {
        return -code error "APSSRFreqGenerateOrbCorrFiles: programming error: no variable rootname"
    }
    
    if {![string length $configFile] || ![file exists $configFile]} {
        return -code error "APSSRFreqGenerateOrbCorrFiles: supply a configuration file, or one that exists ($configFile was given)."
    }
    set configFile [APSResolveLink $configFile]

    if {![string length $referenceMatrix] || ![file exists $referenceMatrix]} {
        return -code error "APSSRFreqGenerateOrbCorrFiles: supply a reference matrix file, or one that exists ($referenceMatrix was given)."
    }
    set referenceMatrix [APSResolveLink $referenceMatrix]
    set origRefMatrix $referenceMatrix

    if ![string length $outputRoot] {
        return -code error "APSSRFreqGenerateOrbCorrFiles: supply an output rootname."
    }
    
   # puts stderr "$configFile $referenceMatrix"
    global ${rootname}ConfigStatus
    set ${rootname}ConfigStatus "Working..."
    update
    set correctorNames A014-IETS:BTC:SROffsetFreqC
    set tmpRoot /tmp/[APSTmpString]
    APSAddToTempFileList $tmpRoot.monFlags 
    
    if [catch {exec sddsprocess $configFile -pipe=out \
                 -match=parameter,NameType=MonitorNames \
                 -filter=column,Flag,1,1 \
                 | sddscombine -pipe -merge \
                 | tee $tmpRoot.monFlags \
                 | sdds2stream -pipe -column=Name} monitorNames] {
        return -code error "APSSRFreqGenerateOrbCorrFiles: $monitorNames"
    }

    #puts stderr "$monitorNames"
    set monitorNameMatchOption ""
    set IDBPMList ""
    foreach item $monitorNames {
        if [string match *ID* $item]!=0 {
            lappend IDBPMList $item
        }
        if [string length $monitorNameMatchOption] {
            set monitorNameMatchOption "$monitorNameMatchOption,BPMName=$item,|"
        } else {
            set monitorNameMatchOption "-match=column,BPMName=$item"
        }
    }
    #puts stderr $monitorNameMatchOption
    set BMBPMList ""
    foreach item $monitorNames {
        if [string match *BM* $item]!=0 {
            lappend BMBPMList $item
        }
        if [string length $monitorNameMatchOption] {
            set monitorNameMatchOption "$monitorNameMatchOption,BPMName=$item,|"
        } else {
            set monitorNameMatchOption "-match=column,BPMName=$item"
        }
    }
    if [llength $IDBPMList] {
        set IDBPMsKnownList [APSGetIDXRayBPMList -plane h]
        set IDBPMEqnList    [APSGetIDXRayEqnList -plane h]
        lappend equationCmd sddsprocess -pipe
        foreach item $IDBPMList {
            set index [lsearch -exact $IDBPMsKnownList $item]
            if $index==-1 {
                return -code error "APSSRFreqGenerateOrbCorrFiles: no information on $item"
            }
            lappend equationCmd "-define=column,$item,[lindex $IDBPMEqnList $index]"
        }
    }
    if [llength $BMBPMList] {
        set BMBPMsKnownList [APSGetBMXRayBPMList -plane h]
        set BMBPMEqnList    [APSGetBMXRayEqnList -plane h]
        lappend equationCmd sddsprocess -pipe
        foreach item $BMBPMList {
            set index [lsearch -exact $BMBPMsKnownList $item]
            if $index==-1 {
                return -code error "APSSRFreqGenerateOrbCorrFiles: no information on $item"
            }
            lappend equationCmd "-define=column,$item,[lindex $BMBPMEqnList $index]"
        }
    }
    if { [llength $IDBPMList] || [llength $BMBPMList] } {
        set tmpMatrix /tmp/[APSTmpString]
        if [catch {eval exec sddstranspose $referenceMatrix -pipe=out  \
                     | $equationCmd \
                     | sddstranspose -pipe=in $tmpMatrix \
                     -newColumnNames=OldColumnNames -oldColumnNames=BPMName} result] {
            return -code error "APSSRFreqGenerateOrbCorrFiles: $result"
        }
        set referenceMatrix $tmpMatrix
    }
    #puts stderr "BM=$BMBPMList ID=$IDBPMList"
    set inverseOptions "-largestSingularValues=$singularValues"
    if $tikhonovFilter {
	if {$tikhonovType=="SVN"} {
	    if $tikhonovSVN {
		lappend inverseOptions "-tikhonov=SVN=[expr abs($tikhonovSVN)]"
	    }
	} elseif $tikhonovBeta {
	    lappend inverseOptions "-tikhonov=beta=[expr abs($tikhonovBeta)]"
	}
    }
    if [lsearch -exact [APSGetSDDSNames -fileName $tmpRoot.monFlags -class column] Weight]!=-1 {
        lappend inverseOptions "-weights=$tmpRoot.monFlags,name=Name,value=Weight"
    }
    #    puts stderr "corr= $correctorNames"
    if $SVDanalysis {
        set tmpOutput /tmp/[APSTmpString]
        APSAddToTmpFileList -ID APSSRGenerateOrbCorrFiles -fileList $tmpOutput
        if [catch {eval exec sddsconvert $referenceMatrix -pipe=out \
                     -retain=column,BPMName,[join $correctorNames ,] \
                     | sddsprocess -pipe $monitorNameMatchOption \
                     | sddspseudoinverse -pipe=in $tmpOutput $inverseOptions \
                     -umatrix=$outputRoot/u \
                     -vmatrix=$outputRoot/v \
                     -sfile=$outputRoot/s \
                 } result] {
            return -code error "APSSRFreqGenerateOrbCorrFiles(svd): Error possibly caused by non-existent inverse. Check your configuration.\nProcessing command returns:\n$result"
        }
        set convertOption -retain=col,OldColumnNames
        for {set i 0} {$i<$singularValues} {incr i} {
            append convertOption ,SV[format %03d $i]
        }
        if [catch {exec sddsconvert $outputRoot/v $tmpOutput.v $convertOption} result] {
            return -code erorr "APSSRFreqGenerateOrbCorrFiles(svd): $result"
        }
        set returnList [exec tksddsplot $tmpOutput.v -col=OldColumnNames,SV* -sep \
                            -enum=interval=20 -selectFrames]
        set deleteVectors ""
        set index 0
        foreach selected $returnList {
            if {!$selected} {
                lappend deleteVectors $index
            }
            incr index
        }
        global ${rootname}DeleteModes
        set ${rootname}DeleteModes $deleteVectors
        APSSetVarAndUpdate ${rootname}ConfigStatus "SVD analysis done."
        return
    }
    global ${rootname}DeleteModes
    if ![llength $deleteVectors] {
        if {[info exists ${rootname}DeleteModes] && 
            [llength [set ${rootname}DeleteModes]]} {
            set deleteVectors [set ${rootname}DeleteModes]
        }
    }
    if [llength $deleteVectors] {
        lappend inverseOptions -deleteVectors=[join $deleteVectors ,]
    }
    if [catch {eval exec sddsconvert $referenceMatrix -pipe=out \
                 -retain=column,BPMName,[join $correctorNames ,] \
                 | sddsprocess -pipe $monitorNameMatchOption \
                 | sddspseudoinverse -pipe $inverseOptions \
                 | sddsconvert -pipe -rename=column,OldColumnNames=Actuators \
                 | sddsprocess -pipe \
                 -print=parameter,ConfigurationFile,$configFile \
                 -print=parameter,ReferenceMatrix,$origRefMatrix \
                 | sddsconvert -pipe=in $outputRoot/irm \
                 -editnames=column,S*,ei/:x:${bpmSuffix}/ \
             } result] {
        return -code error "APSSRFreqGenerateOrbCorrFiles: Error possibly caused by non-existent inverse. Check your configuration.\nProcessing command returns:\n$result"
    }
    catch {file delete -force $outputRoot/irm~ }
    if [catch {exec sdds2stream -param=ConditionNumber $outputRoot/irm} condNumber] {
        return -code error "APSSRFreqGenerateOrbCorrFiles: error getting condition number"
    }

    # create file for circumference calculation
    set referenceCircumference 1103.608
    package require rpn
    set referenceFrequency  [rpn expr "c_mks $referenceCircumference / 1296 *"]
    # the factor turns out to be about 3 in units of um/Hz
    set factor [rpn expr "$referenceCircumference $referenceFrequency / 1e6 *"]
    if [catch {exec sddsprocess $outputRoot/irm $outputRoot/circumferenceMatrix \
                 -reedit=col,Actuators,100Di/S:circumferenceChange/ \
                 "-redef=col,%s,%s $factor *,select=S*:P*"
             } result] {
        return -code error "APSSRFreqGenerateOrbCorrFiles: $result"
    }
    set testFile(ColumnNames) "ControlName MinimumValue MaximumValue SleepTime"
    set testFile(ColumnInfo.MinimumValue) "type SDDS_DOUBLE"
    set testFile(ColumnInfo.MaximumValue) "type SDDS_DOUBLE"
    set testFile(ColumnInfo.SleepTime) "type SDDS_DOUBLE"
    lappend testFile(Column.ControlName)  S-DCCT:CurrentM A014-IETS:BTC:SRSetFreqM
    if [catch {exec cavget -list=A014-IETS:BTC:SRSetFreqM -float=%21.1f -pend=15} freqNow] {
        return -code error "APSSRFreqGenerateOrbCorrFiles: error getting frequency from source: $freqNow"
    }
    if [catch {exec cavget -list=S-MPS:MPSM2:HwBeamLimitCurentM -float=%21.1f -pend=15} maxCurrent] {
        return -code error "APSSRFreqGenerateOrbCorrFiles: error getting maximum current from MPS system: $maxCurrent"
    }
    lappend testFile(Column.MinimumValue) 1.5 [expr $freqNow-100.0]
    lappend testFile(Column.MaximumValue) $maxCurrent [expr $freqNow+100.0]
    lappend testFile(Column.SleepTime) 3.0 3.0
    foreach item $monitorNames {
        lappend testFile(Column.ControlName) ${item}:x:SampledRfErrorM
        lappend testFile(Column.MinimumValue) -1500
        lappend testFile(Column.MaximumValue) 1500
        lappend testFile(Column.SleepTime) 3.0
    }
    set testFile(Column.ControlName) [list $testFile(Column.ControlName)]
    set testFile(Column.MinimumValue) [list $testFile(Column.MinimumValue)]
    set testFile(Column.MaximumValue) [list $testFile(Column.MaximumValue)]
    set testFile(Column.SleepTime) [list $testFile(Column.SleepTime)]
    if {[catch {sdds save $outputRoot/tests testFile} result]} {
        set ${rootname}ConfigStatus "Error: $result"
        bell
        return
    }
    set ${rootname}ConfigStatus "Done.  Condition number is $condNumber ."
    update
}

proc APSBoosterGenerateOrbCorrFiles {args} {
    set configFile ""
    set outputRoot ""
    set referenceMatrix ""
    set plane h
    set generate 0
    set install 0
    set rootname ""
    set singularValues 320
    set tikhonovFilter 0
    set tikhonovSVN 0
    set tikhonovBeta 0
    set tikhonovType SVN
    set SVDanalysis 0
    set deleteVectors ""
    set bts 0
    APSStrictParseArguments {configFile plane outputRoot referenceMatrix generate install rootname \
				 singularValues SVDanalysis deleteVectors bts \
				 tikhonovFilter tikhonovSVN tikhonovBeta tikhonovType}
    
    if {!$generate && !$install} return
    if $tikhonovFilter {
	if {$tikhonovType=="SVN" && !$tikhonovSVN} {
	    return -code error "APSBoosterGenerateOrbCorrFiles(0a): tikhonov SVN number not provided!"
	}
	if {$tikhonovType=="Beta" && !$tikhonovBeta} {
	    return -code error "APSBoosterGenerateOrbCorrFiles(0b): tikhonov beta not provided!"
	}
    }
    
    if ![string length $rootname] {
        return -code error "APSBoosterGenerateOrbCorrFiles: programming error: no variable rootname"
    }

    if {![string length $configFile] || ![file exists $configFile]} {
        return -code error "APSBoosterGenerateOrbCorrFiles: supply a configuration file, or one that exists ($configFile was given)."
    }
    set configFile [APSResolveLink $configFile]

    if {![string length $referenceMatrix] || ![file exists $referenceMatrix]} {
        return -code error "APSBoosterGenerateOrbCorrFiles: supply a reference matrix file, or one that exists ($referenceMatrix was given)."
    }
   # puts $referenceMatrix
    set referenceMatrix [APSResolveLink $referenceMatrix]
    set origRefMatrix $referenceMatrix
    
    if ![string length $outputRoot] {
        return -code error "APSBoosterGenerateOrbCorrFiles: supply an output rootname."
    }
   # puts stderr "$configFile $referenceMatrix"
    global ${rootname}ConfigStatus
    set ${rootname}ConfigStatus "Working..."
    update
    
    set tmpRoot /tmp/[APSTmpString]
    APSAddToTempFileList $tmpRoot.monFlags 
    if [catch {exec sddsprocess $configFile -pipe=out \
                 -match=parameter,NameType=MonitorNames \
                 -filter=column,Flag,1,1 \
                 | sddscombine -pipe -merge \
                 | tee $tmpRoot.monFlags \
                 | sdds2stream -pipe -column=Name} monitorNames] {
        return -code error "APSBoosterGenerateOrbCorrFiles: $monitorNames"
    }
    #puts $monitorNames
    if [catch {exec sddsprocess $configFile -pipe=out \
                 -match=parameter,NameType=CorrectorNames \
                 -filter=column,Flag,1,1 \
                 | sddscombine -pipe -merge \
                 | sdds2stream -pipe -column=Name} correctorNames] {
        return -code error "APSBoosterGenerateOrbCorrFiles: $correctorNames"
    }
  #  puts $correctorNames
    set monitorNameMatchOption ""
    foreach item $monitorNames {
        if [string match *ID* $item]!=0 {
            lappend IDBPMList $item
        }
        if [string length $monitorNameMatchOption] {
            set monitorNameMatchOption "$monitorNameMatchOption,BPMName=$item,|"
        } else {
            set monitorNameMatchOption "-match=column,BPMName=$item"
        }
    }
    set inverseOptions "-largestSingularValues=$singularValues"
    if $tikhonovFilter {
	if {$tikhonovType=="SVN"} {
	    if $tikhonovSVN {
		lappend inverseOptions "-tikhonov=SVN=[expr abs($tikhonovSVN)]"
	    }
	} elseif $tikhonovBeta {
	    lappend inverseOptions "-tikhonov=beta=[expr abs($tikhonovBeta)]"
	}
    }
    if [lsearch -exact [APSGetSDDSNames -fileName $tmpRoot.monFlags -class column] Weight]!=-1 {
        lappend inverseOptions "-weights=$tmpRoot.monFlags,name=Name,value=Weight"
    }
    set tmpOutput /tmp/[APSTmpString]
    if $bts {
	if [catch {exec sddsprocess  $referenceMatrix $tmpOutput.matrix \
		       "-reedit=col,BPMName,%/P0H/P0:x/%/P0V/P0:y/%/P1H/P1:x/%/P1V/P1:y/%/P2H/P2:x/%/P2V/P2:y/%/P3H/P3:x/%/P3V/P3:y/%/P4H/P4:x/%/P4V/P4:y/%/P5H/P5:x/%/P5V/P5:y/%/P6H/P6:x/%/P6V/P6:y/" } result] {
	    return -code error "Error editing BTS bpm name: $result"
	}
	set referenceMatrix $tmpOutput.matrix
    }
    #puts stderr "corr= $correctorNames"
    if $SVDanalysis {
        APSAddToTmpFileList -ID APSSRGenerateOrbCorrFiles -fileList $tmpOutput
        if [catch {eval exec sddsconvert $referenceMatrix -pipe=out \
                     -retain=column,BPMName,[join $correctorNames ,] \
                     | sddsprocess -pipe $monitorNameMatchOption \
                     | sddspseudoinverse -pipe=in $tmpOutput $inverseOptions \
                     -umatrix=$outputRoot/u \
                     -vmatrix=$outputRoot/v \
                     -sfile=$outputRoot/s \
                 } result] {
            return -code error "APSSRGenerateOrbCorrFiles(svd): Error possibly caused by non-existent inverse. Check your configuration.\nProcessing command returns:\n$result"
        }
        set convertOption -retain=col,OldColumnNames
        for {set i 0} {$i<$singularValues} {incr i} {
            append convertOption ,SV[format %03d $i]
        }
        if [catch {exec sddsconvert $outputRoot/v $tmpOutput.v $convertOption} result] {
            return -code error "APSSRGenerateOrbCorrFiles(svd): $result:`"
        }
        set returnList [exec tksddsplot $tmpOutput.v -col=OldColumnNames,SV* -sep \
                          -enum=interval=20 -selectFrames]
        set deleteVectors ""
        set index 0
        foreach selected $returnList {
            if {!$selected} {
                lappend deleteVectors $index
            }
            incr index
        }
        global ${rootname}DeleteModes
        set ${rootname}DeleteModes $deleteVectors
        APSSetVarAndUpdate ${rootname}ConfigStatus "SVD analysis done."
        return
    }
    global ${rootname}DeleteModes
    if ![string length $deleteVectors] {
        if {[info exists ${rootname}DeleteModes] && 
            [llength [set ${rootname}DeleteModes]]} {
            set deleteVectors [set ${rootname}DeleteModes]
        }
    }
    if [llength $deleteVectors] {
        lappend inverseOptions -deleteVectors=[join $deleteVectors ,]
    } 
    if !$bts {
	if [catch {eval exec sddsconvert $referenceMatrix -pipe=out \
		       -retain=column,BPMName,[join $correctorNames ,] \
		       | sddsprocess -pipe $monitorNameMatchOption \
		       | tee $tmpRoot.pseu.input \
		       | sddspseudoinverse -pipe $inverseOptions \
		       | sddsconvert -pipe -rename=column,OldColumnNames=Actuators \
		       | sddsprocess -pipe \
		       -print=parameter,ConfigurationFile,$configFile \
		       -print=parameter,ReferenceMatrix,$origRefMatrix \
		       | sddsconvert -pipe=in $outputRoot/irm \
		       {-editnames=column,S*,ei\\:mswAve:x:RfErrorM\\}} result] {
	    return -code error "APSBoosterGenerateOrbCorrFiles: Error possibly caused by non-existent inverse. Check your configuration.\nProcessing command returns:\n$result"
	}
    } else {
	if [catch {eval exec sddsconvert $referenceMatrix -pipe=out \
		       -retain=column,BPMName,[join $correctorNames ,] \
		       | sddsprocess -pipe $monitorNameMatchOption \
		       | tee $tmpRoot.pseu.input \
		       | sddspseudoinverse -pipe $inverseOptions \
		       | sddsconvert -pipe -rename=column,OldColumnNames=Actuators \
		       | sddsprocess -pipe=in $outputRoot/irm \
		       -print=parameter,ConfigurationFile,$configFile \
		       -print=parameter,ReferenceMatrix,$origRefMatrix} result] {
	    return -code error "APSBoosterGenerateOrbCorrFiles: Error possibly caused by non-existent inverse. Check your configuration.\nProcessing command returns:\n$result"
	}
    }
    catch {file delete  -force $outputRoot/irm~ } 
    if [catch {exec sdds2stream -param=ConditionNumber $outputRoot/irm} condNumber] {
        return -code error "APSBoosterGenerateOrbCorrFiles: error getting condition number"
    }
    set ${rootname}ConfigStatus "Done.  Condition number is $condNumber ."
    update
}

proc APSBoosterPlaneOrbitConfig {widget args} {    
    set rootname ""
    set bpmCorrTogether 0
    set corrector 1
    set bpm 1
    set plane h
    set bpmItemList ""
    set bpmItemLabelList ""
    set corrItemList ""
    set corrItemLabelList ""
    set parent ""
    set fileFrame 1
    set application BoosterOrbitCorrection
    APSParseArguments {rootname bpm corrector plane bpmItemList bpmItemLabelList \
                               corrItemList corrItemLabelList parent fileFrame application bpmCorrTogether}
    
    global ${rootname}ConfigStatus
    set ${rootname}ConfigStatus ""
    set frameWidth 320
    set frameHeight 320
    
    APSFrame $widget -parent $parent
    APSScrolledStatus .scrolled -parent $parent$widget.frame \
      -textVariable ${rootname}ConfigStatus \
      -width 85 -height 3 -lineLimit 1000 -label ""
    set tabList ""
    if $bpm {
        lappend tabList Monitors
    }
    if $corrector {
        lappend tabList Correctors
    }
    set label1 ""
    set label2 ""
    set sectorList ""
    for {set b 1} {$b<5} {incr b} {
	for {set c 0} {$c<10} {incr c} {
	    lappend sectorList B${b}C$c
	}
    }
    
    set w1 $parent$widget
    set w2 $parent$widget
    set label1 "Choose BPM Monitors"
    set label2 "Choose Correctors"
    if !$bpmCorrTogether {
	if $bpm {
	    if ![string length $bpmItemLabelList] {
		set bpmItemLabelList $bpmItemList
	    }
	    set bpmItemList {P1 P2}
	    APSSRSectorButtons .bpm -parent $w1 -rootname $rootname \
		-label $label1 -sectorList $sectorList -orientation horizontal \
		-itemList $bpmItemList -itemLabelList $bpmItemList -description "booster $plane bpms" \
		-sectorControl 1 -packOption "-side top" 
	} 
	if $corrector {
	    if ![string length $corrItemLabelList] {
		set corrItemLabelList $corrItemList
	    }
	    APSSRSectorButtons .corr -parent $w2 -rootname $rootname \
		-label $label2 -sectorList $sectorList \
		-itemList $corrItemList -itemLabelList $corrItemLabelList -description "boostesr $plane correctors" \
		-orientation horizontal -sectorControl 0 -packOption "-side top"  -missingList {B2C9V}  
	}
    } else {
	#put bpm and corrector together
	APSSRSectorButtons .bpmcorr -parent $w1 -rootname $rootname  \
	    -label "Select $plane BPM/correctors (\"[string toupper $plane]\" represents corrector)" -sectorList $sectorList  \
	    -itemList [list P1 P2 [string toupper $plane]] \
	    -itemLabelList [list P1 P2 [string toupper $plane]] \
	    -description "boostesr $plane" -separateCountButton 1 \
	    -orientation horizontal -sectorControl 1 -packOption "-side top"  -missingList {B2C9V B3C2P1 B3C2P2} 
    }
    if $fileFrame {
        #make frames for read, write, ect. controls
        set frameWidth 800
        set frameHeight 200
        set labelList [list Config... Read... Write... \
                         {Generate controllaw files...} ]
        set commandList [list {} {} \
                           "APSSetVarAndUpdate ${rootname}WriteDir \"\"" \
                           {}]
        set widgetList [APSTabFrame .fileops -parent $parent$widget -label "" \
                          -labelList $labelList \
                          -commandList $commandList \
                          -height $frameHeight -width $frameWidth]
        global ${rootname}Lattice ${rootname}MainDir ${rootname}LatSubDir
        set ${rootname}Lattice default
        set ${rootname}MainDir /home/helios/oagData/booster/orbitControllaw
        set ${rootname}LatSubDir lattices
       
        set wConfig [lindex $widgetList 0]
        set wRead [lindex $widgetList 1]
        set wWrite [lindex $widgetList 2]
        set wGenerate [lindex $widgetList 3]
        
        APSFrame .lattice -parent $wConfig  -label "Lattice" \
          -width $frameWidth -height $frameHeight -contextHelp \
          "Use this frame to specify the lattice directory name and main directory area.You may also change the default lattice from here."
        set w0 $wConfig.lattice.frame
        APSLabeledEntry .maindir -parent $w0 -label "Main directory: " \
          -textVariable ${rootname}MainDir -width 60 -contextHelp \
          "Enter the name of the main directory for the orbit correction system."
        APSFileSelectWidget .config -parent $w0 -label "Lattice: " \
          -pathVariableList [list ${rootname}MainDir ${rootname}LatSubDir] -mode directory -width 60 \
          -variable ${rootname}Lattice -incrementButtons 0 -contextHelp \
          "Enter the name of the lattice with which to work."
        #comment out this default button because it is dangerous to change the default lattice and it is not needed in this application, since we have another software for SR managers to change the default lattice. We had an occasion that it was pressed by a non-familiar person which caused the orbit correction failure and almost dumped the beam.
       # APSButton .default -parent $w0.config -text D -size small \
       #   -contextHelp "Makes the named file into the default lattice." \
        #  -command "APSMakeLink -confirm 1 -confirmMessage {Change default lattice? It is dangerous to change default lattice during operations because it changes the orbit correction configuration, Are you sure to change default lattice?} -local 1 -log 1 -permissions 00775 -filename \[subst \$${rootname}MainDir/\$${rootname}LatSubDir/\$${rootname}Lattice\] -linkname \[subst \$${rootname}MainDir/\$${rootname}LatSubDir/default\]; set ${rootname}Lattice default"
        
        global ${rootname}refMatrices ${rootname}RefMatrix  ${rootname}Plane ${rootname}FilterEnd1
        set ${rootname}RefMatrix $plane.default
        set ${rootname}refMatrices refMatrices
        set ${rootname}Plane $plane
        set ${rootname}FilterEnd1 .*
        APSFileSelectWidget .${plane}ref -parent $w0 -mode file \
          -label "Reference matrix: " -width 60 \
          -variable ${rootname}RefMatrix \
          -pathVariableList [list ${rootname}MainDir ${rootname}LatSubDir ${rootname}Lattice ${rootname}refMatrices] \
          -filterVariableList [list ${rootname}Plane ${rootname}FilterEnd1] \
          -contextHelp \
          "Enter the name of the reference response matrix file for the $plane plane."
       
       # bind $w0.${plane}ref.entry <Return> "APSUpdateTimeRegion -rootname $rootname"
       # trace variable ${rootname}RefMatrix w "APSUpdateTimeRegion -rootname $rootname"
        #update the region when reference matrix changes
        
        #APSButton .default -parent $w0.${plane}ref -text D -size small \
        #  -contextHelp "Makes the named file into the default $plane-plane reference matrix." \
         # -command "APSMakeLink -confirm 1 -confirmMessage {Change reference matrix? Are you sure?} -local 1 -log 1 -permissions 00664 -filename \[subst \$${rootname}MainDir/\$${rootname}LatSubDir/\$${rootname}Lattice/\$${rootname}refMatrices/\$${rootname}RefMatrix\] -linkname \[subst \$${rootname}MainDir/\$${rootname}LatSubDir/\$${rootname}Lattice/\$${rootname}refMatrices/$plane.default\]; set ${rootname}RefMatrix $plane.default"

        # Make configuration-read frame.
        global ${rootname}ReadFile ${rootname}ReadDescription
        set ${rootname}ReadFile $plane.default
        set ${rootname}ReadDescription ""
        APSFrame .read -parent $wRead -label "Read configuration" \
          -width $frameWidth -height $frameHeight -contextHelp \
          "Use this frame to read combined monitor and corrector configurations."
        set w0 $wRead.read.frame
	
        APSFileSelectWidget .file -parent $w0 -variable ${rootname}ReadFile -label "Config: " \
          -pathVariableList [list ${rootname}MainDir ${rootname}LatSubDir ${rootname}Lattice] \
          -mode directory -filterVariableList \
          [list ${rootname}Plane ${rootname}FilterEnd1] -width 60 \
          -incrementButtons 1 -contextHelp \
          "Enter the name of the configuration file to read."
        APSLabeledOutput .descrip -parent $w0 -label "Description: " -width 80 -packOption "-side top -anchor w" \
          -textVariable ${rootname}ReadDescription -contextHelp \
          "Shows the description of the last-read configuration file."
       
        APSFrame .bf -parent $w0 -relief flat -label "" -packOption "-side top -anchor w"
        set w1 $w0.bf.frame
        APSButton .io0 -parent $w1 -text Read(replace) -packOption "-side left -anchor n" -size small -command \
	    "APSReadOrbitCorrectionConfig -booster 1 -sectorCount 40  -rootname $rootname -filename \$${rootname}MainDir/\$${rootname}LatSubDir/\$${rootname}Lattice/\$${rootname}ReadFile/config -logic replace " \
          -contextHelp "Press to read data to replace the existing configuration, using the named configuration file."
        APSButton .io1 -parent $w1 -text Read(or) -packOption "-side left -anchor n" -size small -command \
	    "APSReadOrbitCorrectionConfig -booster 1 -sectorCount 40 -rootname $rootname -filename \$${rootname}MainDir/\$${rootname}LatSubDir/\$${rootname}Lattice/\$${rootname}ReadFile/config -logic or " \
          -contextHelp "Press to read data to or with the existing configuration, using the named configuration file."
        APSButton .io2 -parent $w1 -text Read(and) -packOption "-side left -anchor n" -size small -command \
	    "APSReadOrbitCorrectionConfig -booster 1 -sectorCount 40 -rootname $rootname -filename \$${rootname}MainDir/\$${rootname}LatSubDir/\$${rootname}Lattice/\$${rootname}ReadFile/config -logic and " \
          -contextHelp "Press to read data to and with the existing configuration, using the named configuration file."
        APSButton .io3 -parent $w1 -text Read(not) -packOption "-side left -anchor n" -size small -command \
	    "APSReadOrbitCorrectionConfig -booster 1 -sectorCount 40 -rootname $rootname -filename \$${rootname}MainDir/\$${rootname}LatSubDir/\$${rootname}Lattice/\$${rootname}ReadFile/config -logic not " \
          -contextHelp "Press to read data specifying elements to turn off, using the named configuration file."
        APSButton .io4 -parent $w1 -text "Refresh good/bad" -packOption "-side left -anchor n" -size small -command \
          "APSRescanBadOrbitDevices -rootname $rootname -plane $plane -booster 1 "
       

        # Make the write-configuration frame
        global ${rootname}WriteDir 
        set ${rootname}StartRampTime 160
	set ${rootname}EndRampTime 220
        APSFrame .write -parent $wWrite -label "Write configuration" \
          -width $frameWidth -height $frameHeight -contextHelp \
          "Use this frame to write combined monitor and corrector configurations."
        set w0 $wWrite.write.frame
        set ${rootname}WriteDir h.[clock format [clock seconds] -format %Y-%m%d].00
        APSFileSelectWidget .file -parent $w0 -variable ${rootname}WriteDir \
          -pathVariableList [list ${rootname}MainDir ${rootname}LatSubDir ${rootname}Lattice] \
          -label "Config: " -noSelect 0 -mode directory -incrementButtons 1 -width 60 -contextHelp \
          "Enter the name of the configuration to write." \
          -filterVariableList [list ${rootname}Plane ${rootname}FilterEnd1]
        APSButton .genname -parent $w0.file -text G -size small -command \
          "set ${rootname}WriteDir \[APSNextGenerationedName -directory \$${rootname}MainDir/\$${rootname}LatSubDir/\$${rootname}Lattice -name \$${rootname}Plane.\[clock format \[clock seconds\] -format %Y-%m%d\].00 -newFile 1 -separator .\]"
        APSLabeledEntry .descrip -parent $w0 -label "Description: " -width 60 \
          -textVariable ${rootname}WriteDescription -contextHelp \
          "Use to enter a description for the configuration to be written."
	
#	set rampTimeList [exec sddsconvert  /home/helios/oagData/booster/ramps/correctors/lattices/default/HVCorr.ramp \
#			      -toPage=1 -pipe=out \
#			      | sddsprocess -pipe -clip=1,1 \
#			      | sddsprintout -pipe -col=RampTime,format=%.0f -noTitle -noLabels]
#	set itemList ""
	#for {set i 0} {$i<[expr [llength $rampTimeList] -1]} {incr i 1} {
	#    lappend itemList "[lindex $rampTimeList $i]-[lindex $rampTimeList [expr $i+1]]"
	#}
      #  set itemList {region0 region1 region2 region3 region4 region5 region6 region7 region8 region9}
#	set ${rootname}RampTimeRange [lindex $itemList 1]
#	APSComboboxFrame .ramp -parent $w0 -label "BPM/Corrector Time Region:" -editable 0 \
	#    -width 40 -textVariable ${rootname}RampTimeRange -itemList $itemList
	
        APSButton .io -parent $w0 -text Write -size small -command \
	    "APSSRWritePlaneOrbitCorrectionConfig -sectorCount 40 -booster 1 -interactive 1 -sectorList [list $sectorList] -rootname $rootname -filename \$${rootname}MainDir/\$${rootname}LatSubDir/\$${rootname}Lattice/\$${rootname}WriteDir/config -description \$${rootname}WriteDescription  -configName \$${rootname}WriteDir -plane $plane" \
          -contextHelp "Press to write data, using the named configuration file."
        
        
        # Make the frame for computing the matrix and installing it.
        global ${rootname}Plane ${rootname}SingValues ${rootname}SVDanalysis ${rootname}SetupOutputDir
	global ${rootname}TikhonovFilter ${rootname}TikhonovSVN ${rootname}TikhonovBeta ${rootname}TikhonovType
        global  ${rootname}DeleteModes
        APSFrame .comp -parent $wGenerate -label "Compute matrix" \
          -width $frameWidth -height $frameHeight -contextHelp \
          "Use this frame to generate the matrix for orbit correction from an existing configuration."
        set w0 $wGenerate.comp.frame
        
        set ${rootname}SingValues 20
        set ${rootname}SVDanalysis 0
        set ${rootname}DeleteModes ""
	set ${rootname}TikhonovFilter 0
	set ${rootname}TikhonovSVN 0
	set ${rootname}TikhonovBeta 0
	set ${rootname}TikhonovType SVN
        APSFileSelectWidget .file -parent $w0 -variable ${rootname}WriteDir \
          -pathVariableList [list ${rootname}MainDir ${rootname}LatSubDir ${rootname}Lattice] -filter "h.* v.*" \
          -label "Config: " -noSelect 0 -mode directory -incrementButtons 1 -width 60 -contextHelp \
          "Enter the name of the configuration to use." \
          -filterVariableList [list ${rootname}Plane ${rootname}FilterEnd1] 
        APSButton .genname -parent $w0.file -text G -size small -command \
          "set ${rootname}WriteDir \[APSNextGenerationedName -directory \$${rootname}MainDir/\$${rootname}LatSubDir/\$${rootname}Lattice -name \$${rootname}Plane.\[clock format \[clock seconds\] -format %Y-%m%d\].00 -newFile 1 -separator .\]"
        
        frame $w0.f1 
        pack $w0.f1 -fill x
        APSLabeledEntry .le1 -parent $w0.f1 -packOption "-side left" \
          -textVariable ${rootname}SingValues \
          -label "Number of singular values: " -width 8 -contextHelp \
          "Enter the number of singular values to keep."
        APSButton .svd -parent $w0.f1 -packOption "-side left" -size small \
            -text "SVD Analysis" -contextHelp "Removes DC vectors from singular values decomposition. May help in horizontal plane convergence. Not recommended for vertical plane." \
            -command "APSBoosterGenerateOrbCorrFiles -rootname $rootname -generate 1 -configFile \$${rootname}MainDir/\$${rootname}LatSubDir/\$${rootname}Lattice/\$${rootname}WriteDir/config -plane \$${rootname}Plane -referenceMatrix \$${rootname}MainDir/\$${rootname}LatSubDir/\$${rootname}Lattice/refMatrices/\$${rootname}RefMatrix -outputRoot \$${rootname}MainDir/\$${rootname}LatSubDir/\$${rootname}Lattice/\$${rootname}WriteDir/ -singularValues \$${rootname}SingValues -SVDanalysis 1"
        APSButton .gen -parent $w0.f1 -text Compute -size small -packOption "-side left" -command \
          "APSBoosterGenerateOrbCorrFiles -rootname $rootname -generate 1 -configFile \$${rootname}MainDir/\$${rootname}LatSubDir/\$${rootname}Lattice/\$${rootname}WriteDir/config -plane \$${rootname}Plane -referenceMatrix \$${rootname}MainDir/\$${rootname}LatSubDir/\$${rootname}Lattice/refMatrices/\$${rootname}RefMatrix -outputRoot \$${rootname}MainDir/\$${rootname}LatSubDir/\$${rootname}Lattice/\$${rootname}WriteDir/ -singularValues \$${rootname}SingValues -SVDanalysis 0"
        APSButton .default -parent $w0.f1 -text "Make Default" -size small -packOption "-side left" \
          -contextHelp \
          "Makes the named configuration into the default corrector configuration for chosen plane." \
          -command "APSSRInstallOrbCorrFiles -rootname $rootname -application $application -booster 1"
        APSLabeledEntry .deletemodes -parent $w0 -textVariable ${rootname}DeleteModes \
	    -label "Mode to delete: " \
	    -contextHelp "a list of modes to be deleted from SVD analysis" -width 80
	
	APSRadioButtonFrame .tik -parent $w0 -label "Use tikhonov filter?" -buttonList {Yes No} \
	    -valueList {1 0} -variable ${rootname}TikhonovFilter -orientation horizontal
	APSRadioButtonEntryFrame .par -parent $w0.tik -orientation horizontal -label "Tikhonov filter type:" \
	    -variable ${rootname}TikhonovType -buttonList {SVN_Number Beta} -orientation horizontal \
	    -valueList {SVN Beta} -commandList [list "set ${rootname}TikhonovBeta 0" "set ${rootname}TikhonovSVN 0"] \
	    -entryVariableList [list ${rootname}TikhonovSVN ${rootname}TikhonovBeta] \
	    -entryWidth 10
	if {0} {
	APSLabeledEntryFrame .alpha -parent $w0.tik  -orientation horizontal  \
	    -label "  Tikhonov parameters: SVN/Beta:" -variableList [list ${rootname}TikhonovSVN ${rootname}TikhonovBeta] -width 15 \
	    -contextHelp "provide the SVN number or beta (fractional alpha) of the tikhonov filter, the singular value of the provided SVN number will be used as alpha of the tikhonov filter."
	}
    }
    
}

proc APSGetVariableNameOfSRSectorButtons {args} {
    set arrayName ""
    set sectorList ""
    set itemList ""
    set rootname ""
    APSParseArguments {arrayName sectorList itemList rootname}
    
    set sectorCount [llength $sectorList]
    if !$sectorCount {
        return -code error "APSGetVariableNameOfSRSectorButtons: The sectorList is not provided!"
    }
    global $arrayName
    for {set i 0} {$i<$sectorCount} {incr i} {
        foreach item $itemList {
            set ${arrayName}([lindex $sectorList $i]$item) ${rootname}S[expr $i +1]$item
        }
    }
}

proc APSWriteSelectionArrayConfig {args} {
    set filename ""
    set suffixLists ""
    set sectorCount 40
    set sectorList ""
    set rootname ""
    set NameTypeList ""
    set PVTypeList ""
    APSStrictParseArguments {rootname sectorCount filename NameTypeList PVTypeList suffixLists sectorList}
    
    if [llength $sectorList] {
        set sectorCount [llength $sectorList]
    }
    if ![string length $filename] {
        return -code error "APSWriteSelectionArrayConfig: filename is not given!"
    }
    if ![llength $NameTypeList] {
        return -code error "APSWriteSelectionArrayConfig: NameTypeList is not provided!"
    }
    set nameTypeIndex -1
    set fileList ""
    foreach NameType $NameTypeList PVType $PVTypeList {
        incr nameTypeIndex
        set names ""
        set sectors ""
        set itemList [lindex $suffixLists $nameTypeIndex]
        for {set i 1} {$i<=$sectorCount} {incr i} {
            foreach item $itemList {
                set name ${rootname}S${i}$item
                global $name
                if [set $name] {
                    if [llength $sectorList] {
                        lappend names [lindex $sectorList [expr $i -1]]$item
                    } else {
                        lappend names $name
                    }
                    lappend sectors $i
                }
            }
        }
        if ![llength $names] {
            return -code error "APSWriteSelectionArrayConfig: No $NameType PVs are selected!"
        }
        if [catch {exec sddsmakedataset $filename.$nameTypeIndex -defaultType=string \
                     -par=NameType -data=$NameType \
                     -par=PVType -data=$PVType \
                     -col=Name -data=[join $names ,] \
                     -col=Sector,type=long -data=[join $sectors ,] } result] {
            return -code error "APSWriteSelectionArrayConfig: $result"
        }
        lappend fileList $filename.$nameTypeIndex
    }
    APSAddToTmpFileList -ID APSWriteSelectionArrayConfig -fileList $fileList
    if [catch {eval exec sddscombine $fileList $filename -overwrite} result] {
        return -code error "APSWriteSelectionArrayConfig: $result"
    }
}

proc APSReadSelectionArrayConfig {args} {
    set filename ""
    set suffixList ""
    set sectorList ""
    set rootname ""
    set sectorCount 40
    set mode replace
    #mode: and, or, replace
    APSStrictParseArguments {rootname sectorCount suffixList filename mode sectorList}
    
    if ![file exist $filename] {
        return -code error "APSReadGeneralConfig: config file $filename does not exist!"
    }
    
    if [llength $sectorList] {
        set sectorCount [llength $sectorList]
    }

    if [catch {sdds load $filename configData} result] {
        return -code error "APSReadGeneralConfig: $result"
    }
    set pages [llength $configData(Parameter.NameType)]
   
    set OnNameList ""
    for {set i 0} {$i<$pages} {incr i} {
        set names [lindex $configData(Column.Name) $i]
        set sectors [lindex $configData(Column.Sector) $i]
        foreach name $names sector $sectors {
            if [llength $sectorList] {
                set repl [lindex $sectorList [expr $sector -1]]
                regsub $repl $name "" newName
                set name S${sector}$newName
            }
            lappend OnNameList ${rootname}$name
        }
    }
    switch $mode {
        or {
            foreach name $OnNameList {
                global $name
                set $name 1
            }
        }
        and {
            for {set sector 1} {$sector<=$sectorCount} {incr sector} {
                foreach item $suffixList {
                    set name ${rootname}S${sector}$item
                    if [lsearch $OnNameList $name]==-1 {
                        global $name
                        if {![info exists $name] || [set ${name}]} {
                            set $name 0
                        }
                    }
                } 
            }
        }
        not {
            foreach name $OnNameList {
                global $name
                set $name 0
            }
        }
        default {
            #replace
            foreach name $OnNameList {
                global $name
                set $name 1
            }
            for {set sector 1} {$sector<=$sectorCount} {incr sector} {
                foreach item $suffixList {
                    set name ${rootname}S${sector}$item
                    if [lsearch $OnNameList $name]==-1 {
                        global $name
                        set $name 0
                    }
                } 
            }
        }
    }
}

proc APSUpdateConfigDescriptionDatabase {args} {
    set dataDir ""
    set newConfig ""
    set plane ""
    set linkConfig ""
    set update 0
    set booster 0
    APSStrictParseArguments {dataDir newConfig plane linkConfig update booster}
    if $booster {
	if [catch {APSUpdateBoosterOrbitCorrectionConfig -dataDir $dataDir -newConfig $newConfig} result] {
	    return -code error $result
	}
	return
    }
    if ![file exist $dataDir] {
        return -code error "APSUpdateConfigDescriptionDatabase: $dataDir does not exist!"
    }
    
    set oldDir [pwd]
    cd $dataDir
  
    if {![string length $newConfig] && ![string length $linkConfig]} {
        switch $plane {
            h -
            v {
            }
            default {
                return -code error "APSUpdateConfigDescriptionDatabase: invalid plane given!"
            }
        }
        set configFile ${plane}configDesc.sdds
    } else {
        if [string length $newConfig] {
            set newConfig0 $newConfig
        } elseif [string length $linkConfig] {
            set newConfig0 $linkConfig
        } else {
            return -code error "APSUpdateConfigDescriptionDatabase: either plane or newConfig or linkConfig has to be provided."
        }
        switch -regexp $newConfig0 {
            h {
                set plane h
                set configFile hconfigDesc.sdds
            }
            v {
                set plane v
                set configFile vconfigDesc.sdds
            }
            default {
                #return -code error "APSUpdateConfigDescriptionDatabase3: invalid config - $newConfig provided."
		#do not return error to work for other cases
		return
            }
        }
    }
    set tmpRoot /tmp/[APSTmpString]
    if {![file exist $configFile] || $update} {
        set configList [lsort -decreasing [glob -nocomplain ${plane}.*/config]]
        if ![llength $configList] {
            if [file exist $configFile] {
                exec rm $configFile
            }
            cd $oldDir
            return
        }
        set linkList ""
        set otherList ""
        set linkDescList ""
        set isXrayList ""
        set isLinkList ""
        foreach config $configList  {
            set dir [file dirname $config]
            if [catch {file readlink $dir} result] {
                lappend otherList $config
            } else {
                lappend linkList $dir
                lappend linkDescList "$dir --> $result"
                if [regexp {XR} $dir] {
                    lappend isXrayList 1
                } else {
                    lappend isXrayList 0
                }
                lappend isLinkList 1
            }
        }
        if [catch {eval exec sddscombine $otherList -pipe=out \
                     | sddsprocess -pipe -match=par,NameType=MonitorNames \
                     -nowarnings \"-match=col,Name=*ID*,Name=*BM*,|\" -nowarnings \
                     | sddsprocess -pipe -nowarnings \
                     \"-define=par,IsXray,n_rows 0 == pop pop ? 0 : 1 $,type=short\" \
                     | sddscollapse -pipe \
                     | sddsprocess -pipe \
                     -reedit=col,Filename,%/\/config// \
                     \"-reprint=col,Description,%s --> %s,Filename,Description\" \
                     -define=col,IsLink,0 \
                     | sddsconvert -pipe -retain=col,Filename,Description,IsLink,IsXray,KeepDays,PVType,CreationTime \
                     | sddssort -pipe=in -col=Filename,decreasing $configFile} result] {
            cd $oldDir
            return -code error "APSUpdateConfigDescriptionDatabase1.$plane: $result"
        }
        if [llength $linkList] {
            exec cp $configFile $tmpRoot.1
            if [catch {exec sddsmakedataset $tmpRoot.2 -col=Filename,type=string -data=[join $linkList ,] \
                           -col=Description,type=string "-data=[join $linkDescList ,]" \
                           -col=IsXray,type=short -data=[join $isXrayList ,] \
                           -col=IsLink,type=short -data=[join $isLinkList ,] 
                exec sddscombine $tmpRoot.2 $tmpRoot.1 -merge $configFile -overwrite} result] {
                cd $oldDir
                return -code error "APSUpdateConfigDescriptionDatabase1.$plane: $result"
            }
            catch {file delete -force $tmpRoot.1 $tmpRoot.2}
        }
    } else {
        if [string length $newConfig] {
            if ![file exist $newConfig/config] {
                return -code error "APSUpdateConfigDescriptionDatabase2: $newConfig/config does not exit."
            }
            set tmpfile /tmp/[APSTmpString] 
            if [catch {exec sddsprocess $configFile $tmpfile.config -nowarnings \
                           -match=col,Filename=$newConfig,!} result] {
                return -code error "APSUpdateConfigDescriptionDatabase4: $result"
            }
            APSAddToTmpFileList -ID updateconfigdesc -fileList $tmpfile.config
            if [catch {exec sddsprocess $newConfig/config -pipe=out -match=par,NameType=MonitorNames \
                         | sddsprocess -pipe \
                         "-match=col,Name=*ID*,Name=*BM*" -nowarnings \
                         "-define=par,IsXray,n_rows 0 == ? 0 : 1 $ " \
                         | sddscollapse -pipe \
                         | sddsprocess -pipe=in $tmpfile -reprint=col,Filename,$newConfig \
                         "-reprint=col,Description,%s --> %s,Filename,Description" } result] {
                cd $oldDir
                return -code error "APSUpdateConfigDescriptionDatabase5: $result"
            }
            APSAddToTmpFileList -ID updateconfigdesc -fileList $tmpfile 
            if [catch {exec sddscombine $tmpfile $tmpfile.config -merge -pipe=out \
                         | sddsconvert -pipe  -retain=col,Filename,Description,IsLink,IsXray,KeepDays,PVType,CreationTime \
                           | sddssort -pipe=in -col=Filename,decreasing -unique $configFile} result] {
                cd $oldDir
                return -code error "APSUpdateConfigDescriptionDatabase6: $result"
            }
        } elseif [string length $linkConfig] { 
            if [catch {file readlink $linkConfig} linkedConfig] {
                return -code error "APSUpdateConfigDescriptionDatabase7: $linkedConfig"
            }
	   
            set xray [regexp {XR} $linkConfig]
            if [catch {exec sddsmakedataset $tmpRoot.1 -col=Filename,type=string -data=$linkConfig \
                           -col=IsXray,type=short -data=$xray \
                           -col=Description,type=string "-data=$linkConfig --> $linkedConfig" \
                           -col=IsLink,type=short -data=1 
                exec sddsprocess $configFile $tmpRoot.2 -nowarnings -match=col,Filename=$linkConfig,! 
                exec sddscombine $tmpRoot.1 $tmpRoot.2 -merge -pipe=out \
                         | sddsconvert -pipe  -retain=col,Filename,Description,IsLink,IsXray,KeepDays,PVType,CreationTime \
                         | sddssort -pipe=in -col=Filename,decreasing  $configFile } result] {
                return -code error $result
            }
            catch {file delete -force $tmpRoot.1 $tmpRoot.2}
        }
    }
    set columns [exec sddsquery -col $configFile]
    if [lsearch $columns "KeepDays"]<0 {
        if [catch {exec sddsprocess $configFile -nowarnings \
                       "-redefine=col,KeepDays,-1,type=long" \
                       "-redefine=col,CreationTime,0,type=long" } result] {
            return -code error $result
        }   
    }
    cd $oldDir
}

proc APSUpdateBoosterOrbitCorrectionConfig {args} {
    set dataDir ""
    set newConfig ""
    APSStrictParseArguments {dataDir newConfig}
    if ![file exist $dataDir] {
        return -code error "APSUpdateBoostserConfigDescriptionDatabase: $dataDir does not exist!"
    }
    set plane [string index $newConfig 0]
    if {$plane!="h" && $plane!="v"} {
	return -code error "APSUpdateBoostserConfigDescriptionDatabase: invalid config - $newConfig provided."
    }
    
    set oldDir [pwd]
    cd $dataDir
    set dirs [lsort -decreasing [glob ${plane}.*]]
    set files ""
    set nameList ""
    set descList ""
    foreach dir $dirs {
	if [regexp {default} $dir] {
	    lappend nameList $dir
	    lappend descList "$dir      --> [file readlink $dir]"
	} else {
	    if [file exist $dir/config] {
		lappend files $dir/config
	    } else {
		catch {exec rm -r $dir}
	    }
	}
    }
    if ![llength $files] {
	return -code error "APSUpdateBoostserConfigDescriptionDatabase1: No configs found."
    }
    set tmpRoot /tmp/[APSTmpString]
    if [catch {exec sddsmakedataset $tmpRoot.1 -col=Filename,type=string -data=[join $nameList ,] \
		   -col=Description,type=string "-data=[join $descList ,]" } result] {
	return -code error $result
    }
    if ![llength $files] {
	return -code error "APSUpdateBoostserConfigDescriptionDatabase2: No configs found."
    }
    if [catch {eval exec sddscombine $files -pipe=out \
		   | sddscollapse -pipe \
		   | sddsconvert -pipe -retain=col,Filename,Description \
		   | sddssort -pipe -col=Filename,decreasing -unique \
		   | sddsprocess -reedit=col,Filename,%//config// \
		   -pipe=in $tmpRoot.2 \"-reprint=col,Description,%s --> %s,Filename,Description\" \
	       } result] {
	return -code error "APSUpdateBoostserConfigDescriptionDatabase3: $result"
    }
    if [catch {exec sddscombine $tmpRoot.1 $tmpRoot.2 -merge ${plane}configDesc.sdds -overwrite} result] {
	return -code error "APSUpdateBoostserConfigDescriptionDatabase4: $result"
    }
    catch {file delete -force $tmpRoot.1 $tmpRoot.2}
}

proc ComputeBoosterBPMTiming {args} {
    set startRamp ""
    APSParseArguments {startRamp}

    if [catch {exec cavget -list=Mt:BoosterRampTurnsAO,A014-IETS:BTC:BInjectionCycleM,A014-IETS:BTC:BExtractionCycleM,A014-IETS:BTC:SRSetFreqM -pend=20 -printErrors -floatformat=%lf} results] {
        return -code error "Error reading Mt:BoosterRampTurnsAO,A014-IETS:BTC:BInjectionCycleM,A014-IETS:BTC:BExtractionCycleM,A014-IETS:BTC:SRSetFreqM: $results"
    }
    set srExtractionTurns [lindex $results 0]
    set bInjectionCycle [lindex $results 1]
    set bExtractionCycle [lindex $results 2]
    set srFreq [lindex $results 3]
    set boosterPeriod [expr ($bExtractionCycle - $bInjectionCycle) / ($srFreq * 3 * $srExtractionTurns)]
    set boosterPeriod [expr 1e6 * $boosterPeriod]

    #boosterPeriod in us seconds units
    #startRamp is ms,
    set time [expr 1000 * int($startRamp / (4 * $boosterPeriod)) + 1000]
    return $time
}

set BTSbpmSectorList {BTS:A BTS:B BTS:C BTS:D S40SB-A S40SB-B S01SB-A S01SB-B S02SB-A S02SB-B}
set BTScorrSectorList {BTS:A BTS:B BTS:BS BTS:C BTS:D }
#set BTSbpmList {PH1 PV1 PH2 PV2 PH3 PV3 PH4 PV4 PH5 PV5 PH6 PV6 PH7 PV7 :P1:x :P1:y  :P3:x :P3:y :P5:x :P5:y}
#set BTSbpmLabelList {PH1 PV1 PH2 PV2 PH3 PV3 PH4 PV4 PH5 PV5 PH6 PV6 PH7 PV7 P1x P1y  P3x P3y P5x P5y}
set BTSbpmList {PH1 PH2 PH3 PH4 PH5 PH6 PH7 :P1:x :P3:x :P5:x PV1 PV2 PV3 PV4 PV5 PV6 PV7 :P1:y :P3:y :P5:y}
set BTSbpmLabelList {PH1 PH2 PH3 PH4 PH5 PH6 PH7 P1x P3x P5x PV1 PV2 PV3 PV4 PV5 PV6 PV7 P1y P3y P5y}
#this goes with weed. :( different from helios
set BTScorrList {H1 H2 H3 Q1:H1 Q3:H1 Q5:H1 V1 V2 V3 Q2:V1 Q6:V1 Q1 Q2 Q3 Q4 Q5 Q6 B1 B2}
# this goes with helios
set BTScorrList {H1 H2 H3 Q1H Q3H Q5H V1 V2 V3 Q2V Q6V Q1 Q2 Q3 Q4 Q5 Q6 B1 B2}
proc APSBTSRescanBadorbitDevices {args} {
    set rootname ""
    set application ""
    APSParseArguments {rootname application}
    
    global BTSbpmSectorList BTSbpmList BTScorrSectorList BTScorrList 
    set bpmSectorList $BTSbpmSectorList
    set corrSectorList $BTScorrSectorList
    set bpmItemList $BTSbpmList
    set corrItemList $BTScorrList
    set bpmConfig /home/helios/oagData/bts/BPMStatus/config.sdds
    set corrConfig /home/helios/oagData/bts/CorrectorStatus/config.sdds
    set bpmList [exec sdds2stream -col=DeviceName $bpmConfig]
    set corrList [exec sdds2stream -col=DeviceName $corrConfig]
    set bpmMissingList [join [exec sddsprocess $bpmConfig -pipe=out -nowarnings -filter=col,Nonexistent,0.5,1.5 \
				   | sdds2stream -pipe -col=DeviceName]]
  
    set corrMissingList [join [exec sddsprocess $corrConfig -pipe=out -nowarnings -filter=col,Nonexistent,0.5,1.5 \
				   | sdds2stream -pipe -col=DeviceName]]
    foreach sector $bpmSectorList {
	foreach item $bpmItemList {
	    set name ${sector}$item
	    if [lsearch -exact $bpmList $name]<0 {
		lappend bpmMissingList $name
	    }
	}
    }
    foreach sector $corrSectorList {
	foreach item $corrItemList {
	    set name ${sector}$item
	    if [lsearch -exact $corrList $name]<0 {
		lappend corrMissingList $name
	    }
	}
    }
    
    APSSRSectorUnsetMissing -rootname $rootname -missingList $bpmMissingList 
    APSSRSectorUnsetMissing -rootname $rootname -missingLit $corrMissingList
}

###for BTS configuration
proc APSBTSOrbitConfig {widget args} {    
    set rootname ""
    set parent ""
    set fileFrame 1
    set application BTSOrbitCorrection
    APSParseArguments {rootname  parent fileFrame application}
    
    global ${rootname}ConfigStatus BTSbpmSectorList BTScorrSectorList BTSbpmList BTSbpmLabelList BTScorrList
    set ${rootname}ConfigStatus ""
    set frameWidth 320
    set frameHeight 320
    
    APSFrame $widget -parent $parent
    APSScrolledStatus .scrolled -parent $parent$widget.frame \
      -textVariable ${rootname}ConfigStatus \
      -width 85 -height 3 -lineLimit 1000 -label ""
    
    set tabList "Monitors Correctors"
    set widgetList [APSTabFrame .f0 -parent $parent$widget -label "" \
			-labelList $tabList -height 500]
    set label1 ""
    set label2 ""
    set bpmSectorList $BTSbpmSectorList
    set corrSectorList $BTScorrSectorList
    set bpmLabelList $BTSbpmLabelList
    set bpmItemList $BTSbpmList
    set corrLabelList $BTScorrList
    set corrItemList $corrLabelList
    set bpmConfig /home/helios/oagData/bts/BPMStatus/config.sdds
    set corrConfig /home/helios/oagData/bts/CorrectorStatus/config.sdds
    set bpmList [exec sdds2stream -col=DeviceName $bpmConfig]
    set corrList [exec sdds2stream -col=DeviceName $corrConfig]
    set bpmMissingList [join [exec sddsprocess $bpmConfig -pipe=out -nowarnings -filter=col,Nonexistent,0.5,1.5 \
				   | sdds2stream -pipe -col=DeviceName]]
    
    set corrMissingList [join [exec sddsprocess $corrConfig -pipe=out -nowarnings -filter=col,Nonexistent,0.5,1.5 \
				   | sdds2stream -pipe -col=DeviceName]]
    foreach sector $bpmSectorList {
	foreach item $bpmItemList {
	    set name ${sector}$item
	    if [lsearch -exact $bpmList $name]<0 {
		lappend bpmMissingList $name
	    }
	}
    }
   
    foreach sector $corrSectorList {
	foreach item $corrItemList {
	    set name ${sector}$item
	    if [lsearch -exact $corrList $name]<0 {
		lappend corrMissingList $name
	    }
	}
    }
    set w1 [lindex $widgetList 0]
    set w2 [lindex $widgetList 1]
    set label1 "Choose BPM Monitors"
    set label2 "Choose Correctors"
   
    APSSRSectorButtons .bpm -parent $w1 -rootname $rootname -bts 1 \
	-label $label1 -sectorList $bpmSectorList -orientation horizontal \
	-itemList $bpmItemList -itemLabelList $bpmLabelList -description "BTS bpms" \
	-sectorControl 1 -packOption "-side top" -missingList $bpmMissingList

    APSSRSectorButtons .corr -parent $w2 -rootname $rootname -bts 1\
	-label $label2 -sectorList $corrSectorList \
	-itemList $corrItemList -itemLabelList $corrLabelList -description "BTS correctors" \
	-orientation horizontal  -sectorControl 1 -packOption "-side top"  -missingList $corrMissingList  

    #APSBTSOrbitConfig
    if $fileFrame {
        #make frames for read, write, etc. controls
        set frameWidth 800
        set frameHeight 150
        set labelList [list Config... Read... Write... \
                         {Generate controllaw files...} ]
        set commandList [list {} {} \
                           "APSSetVarAndUpdate ${rootname}WriteDir \"\"" \
                           {}]
        set widgetList [APSTabFrame .fileops -parent $parent$widget -label "" \
                          -labelList $labelList \
                          -commandList $commandList \
                          -height $frameHeight -width $frameWidth]
#	puts $widgetList
	$parent$widget.fileops.frame.tn  select 1
	
        global ${rootname}Lattice ${rootname}MainDir ${rootname}LatSubDir
        set ${rootname}Lattice default
        set ${rootname}MainDir /home/helios/oagData/bts/controllaw
        set ${rootname}LatSubDir lattices
       
        set wConfig [lindex $widgetList 0]
        set wRead [lindex $widgetList 1]
        set wWrite [lindex $widgetList 2]
        set wGenerate [lindex $widgetList 3]
        
        APSFrame .lattice -parent $wConfig  -label "Lattice" \
          -width $frameWidth -height $frameHeight -contextHelp \
          "Use this frame to specify the lattice directory name and main directory area.You may also change the default lattice from here."
        set w0 $wConfig.lattice.frame
        APSLabeledEntry .maindir -parent $w0 -label "Main directory: " \
          -textVariable ${rootname}MainDir -width 60 -contextHelp \
          "Enter the name of the main directory for the orbit correction system."
        APSFileSelectWidget .config -parent $w0 -label "Lattice: " \
          -pathVariableList [list ${rootname}MainDir ${rootname}LatSubDir] -mode directory -width 60 \
          -variable ${rootname}Lattice -incrementButtons 0 -contextHelp \
          "Enter the name of the lattice with which to work."

        # use hv. prefix for reference matrix; they have two planes too.
        global ${rootname}refMatrices ${rootname}RefMatrix ${rootname}FilterEnd1
        set ${rootname}RefMatrix hv.default
        set ${rootname}refMatrices refMatrices
        # for bt sbeamline we use full coupling, i.e., h and v planes together
        set ${rootname}FilterEnd1 .*
        APSFileSelectWidget .ref -parent $w0 -mode file \
          -label "Reference matrix: " -width 60 \
          -variable ${rootname}RefMatrix \
          -pathVariableList [list ${rootname}MainDir ${rootname}LatSubDir ${rootname}Lattice ${rootname}refMatrices] \
          -filterVariableList [list ${rootname}Plane ${rootname}FilterEnd1] \
          -contextHelp \
          "Enter the name of the reference response matrix file."
       
      
        # Make configuration-read frame.
        global ${rootname}ReadFile ${rootname}ReadDescription ${rootname}Plane
        # no plane designation for bts. We are doing both planes at a time.
        set ${rootname}Plane "hv"
        set ${rootname}ReadFile hv.default
        set ${rootname}ReadDescription ""
        APSFrame .read -parent $wRead -label "Read configuration" \
          -width $frameWidth -height $frameHeight -contextHelp \
          "Use this frame to read combined monitor and corrector configurations."
        set w0 $wRead.read.frame
        APSFileSelectWidget .file -parent $w0 -variable ${rootname}ReadFile -label "Config: " \
            -pathVariableList [list ${rootname}MainDir ${rootname}LatSubDir ${rootname}Lattice] \
            -mode directory -filterVariableList [list ${rootname}Plane ${rootname}FilterEnd1] -width 60 \
            -incrementButtons 1 -contextHelp \
            "Enter the name of the configuration file to read."
        APSLabeledOutput .descrip -parent $w0 -label "Description: " -width 80 -packOption "-side top -anchor w" \
          -textVariable ${rootname}ReadDescription -contextHelp \
          "Shows the description of the last-read configuration file."
       
        APSFrame .bf -parent $w0 -relief flat -label "" -packOption "-side top -anchor w"
        set w1 $w0.bf.frame
        APSButton .io0 -parent $w1 -text Read(replace) -packOption "-side left -anchor n" -size small -command \
	    "APSReadBTSConfig -bpmSectorList [list $bpmSectorList] -corrSectorList [list $corrSectorList] -bpmList [list $bpmItemList] -corrList [list $corrItemList]  -rootname $rootname -filename \$${rootname}MainDir/\$${rootname}LatSubDir/\$${rootname}Lattice/\$${rootname}ReadFile/config -logic replace " \
          -contextHelp "Press to read data to replace the existing configuration, using the named configuration file."
        APSButton .io1 -parent $w1 -text Read(or) -packOption "-side left -anchor n" -size small -command \
	    "APSReadBTSConfig -bpmSectorList [list $bpmSectorList] -corrSectorList [list $corrSectorList] -bpmList [list $bpmItemList] -corrList [list $corrItemList] -rootname $rootname -filename \$${rootname}MainDir/\$${rootname}LatSubDir/\$${rootname}Lattice/\$${rootname}ReadFile/config -logic or " \
          -contextHelp "Press to read data to or with the existing configuration, using the named configuration file."
        APSButton .io2 -parent $w1 -text Read(and) -packOption "-side left -anchor n" -size small -command \
	    "APSReadBTSConfig -bpmSectorList [list $bpmSectorList] -corrSectorList [list $corrSectorList] -bpmList [list $bpmItemList] -corrList [list $corrItemList] -rootname $rootname -filename \$${rootname}MainDir/\$${rootname}LatSubDir/\$${rootname}Lattice/\$${rootname}ReadFile/config -logic and " \
          -contextHelp "Press to read data to and with the existing configuration, using the named configuration file."
        APSButton .io3 -parent $w1 -text Read(not) -packOption "-side left -anchor n" -size small -command \
	    "APSReadBTSConfig -bpmSectorList [list $bpmSectorList] -corrSectorList [list $corrSectorList] -bpmList [list $bpmItemList] -corrList [list $corrItemList] -rootname $rootname -filename \$${rootname}MainDir/\$${rootname}LatSubDir/\$${rootname}Lattice/\$${rootname}ReadFile/config -logic not " \
          -contextHelp "Press to read data specifying elements to turn off, using the named configuration file."
        APSButton .io4 -parent $w1 -text "Refresh good/bad" -packOption "-side left -anchor n" -size small -command \
          "APSBTSRescanBadOrbitDevices -rootname $rootname -bts 1 "
       
        # APSBTSOrbitConfig
        # Make the write-configuration frame
        global ${rootname}WriteDir 
        APSFrame .write -parent $wWrite -label "Write configuration" \
          -width $frameWidth -height $frameHeight -contextHelp \
          "Use this frame to write combined monitor and corrector configurations."
        set w0 $wWrite.write.frame
        # use hv because bts uses two planes.
        set ${rootname}WriteDir hv.[clock format [clock seconds] -format %Y-%m%d].00
        APSFileSelectWidget .file -parent $w0 -variable ${rootname}WriteDir \
          -pathVariableList [list ${rootname}MainDir ${rootname}LatSubDir ${rootname}Lattice] \
          -label "Config: " -noSelect 0 -mode directory -incrementButtons 1 -width 60 -contextHelp \
          "Enter the name of the configuration to write." \
            -filterVariableList [list ${rootname}Plane ${rootname}FilterEnd1]
        # Below, \$${rootname}Plane has value hv
        APSButton .genname -parent $w0.file -text G -size small -command \
          "set ${rootname}WriteDir \[APSNextGenerationedName -directory \$${rootname}MainDir/\$${rootname}LatSubDir/\$${rootname}Lattice -name  \$${rootname}Plane.\[clock format \[clock seconds\] -format %Y-%m%d\].00 -newFile 1 -separator .\]"
        APSLabeledEntry .descrip -parent $w0 -label "Description: " -width 60 \
          -textVariable ${rootname}WriteDescription -contextHelp \
          "Use to enter a description for the configuration to be written."
	

        APSButton .io -parent $w0 -text Write -size small -command \
	    "APSBTSWriteConfig -interactive 1 -bpmSectorList [list $bpmSectorList] -corrSectorList [list $corrSectorList] -bpmList [list $bpmItemList] -corrList [list $corrItemList] -rootname $rootname -filename \$${rootname}MainDir/\$${rootname}LatSubDir/\$${rootname}Lattice/\$${rootname}WriteDir/config -description \$${rootname}WriteDescription  -configName \$${rootname}WriteDir " \
          -contextHelp "Press to write data, using the named configuration file."
        
        
        # Make the frame for computing the matrix and installing it.
        global ${rootname}SingValues ${rootname}SVDanalysis ${rootname}SetupOutputDir
	global ${rootname}TikhonovFilter ${rootname}TikhonovSVN ${rootname}TikhonovBeta ${rootname}TikhonovType
        global  ${rootname}DeleteModes
        APSFrame .comp -parent $wGenerate -label "Compute matrix" \
          -width $frameWidth -height $frameHeight -contextHelp \
          "Use this frame to generate the matrix for orbit correction from an existing configuration."
        set w0 $wGenerate.comp.frame
        
        set ${rootname}SingValues 20
        set ${rootname}SVDanalysis 0
        set ${rootname}DeleteModes ""
	set ${rootname}TikhonovFilter 0
	set ${rootname}TikhonovSVN 0
	set ${rootname}TikhonovBeta 0
	set ${rootname}TikhonovType SVN
        APSFileSelectWidget .file -parent $w0 -variable ${rootname}WriteDir \
          -pathVariableList [list ${rootname}MainDir ${rootname}LatSubDir ${rootname}Lattice] -filter "h.* v.*" \
          -label "Config: " -noSelect 0 -mode directory -incrementButtons 1 -width 60 -contextHelp \
          "Enter the name of the configuration to use." \
          -filterVariableList [list ${rootname}Plane ${rootname}FilterEnd1] 
        APSButton .genname -parent $w0.file -text G -size small -command \
          "set ${rootname}WriteDir \[APSNextGenerationedName -directory \$${rootname}MainDir/\$${rootname}LatSubDir/\$${rootname}Lattice -name \$${rootname}Plane.\[clock format \[clock seconds\] -format %Y-%m%d\].00 -newFile 1 -separator .\]"
        
        frame $w0.f1 
        pack $w0.f1 -fill x
        APSLabeledEntry .le1 -parent $w0.f1 -packOption "-side left" \
          -textVariable ${rootname}SingValues \
          -label "Number of singular values: " -width 8 -contextHelp \
          "Enter the number of singular values to keep."
        APSButton .svd -parent $w0.f1 -packOption "-side left" -size small \
            -text "SVD Analysis" -contextHelp "Removes DC vectors from singular values decomposition. May help in horizontal plane convergence. Not recommended for vertical plane." \
            -command "APSBoosterGenerateOrbCorrFiles -rootname $rootname -generate 1 -configFile \$${rootname}MainDir/\$${rootname}LatSubDir/\$${rootname}Lattice/\$${rootname}WriteDir/config  -bts 1 -referenceMatrix \$${rootname}MainDir/\$${rootname}LatSubDir/\$${rootname}Lattice/refMatrices/\$${rootname}RefMatrix -outputRoot \$${rootname}MainDir/\$${rootname}LatSubDir/\$${rootname}Lattice/\$${rootname}WriteDir/ -singularValues \$${rootname}SingValues -SVDanalysis 1"
        APSButton .gen -parent $w0.f1 -text Compute -size small -packOption "-side left" -command \
          "APSBoosterGenerateOrbCorrFiles -rootname $rootname -generate 1 -configFile \$${rootname}MainDir/\$${rootname}LatSubDir/\$${rootname}Lattice/\$${rootname}WriteDir/config -bts 1 -referenceMatrix \$${rootname}MainDir/\$${rootname}LatSubDir/\$${rootname}Lattice/refMatrices/\$${rootname}RefMatrix -outputRoot \$${rootname}MainDir/\$${rootname}LatSubDir/\$${rootname}Lattice/\$${rootname}WriteDir/ -singularValues \$${rootname}SingValues -SVDanalysis 0"
        APSButton .default -parent $w0.f1 -text "Make Default" -size small -packOption "-side left" \
          -contextHelp \
          "Makes the named configuration into the default corrector configuration for chosen plane." \
          -command "APSSRInstallOrbCorrFiles -rootname $rootname -application $application -bts 1"
        APSLabeledEntry .deletemodes -parent $w0 -textVariable ${rootname}DeleteModes \
	    -label "Mode to delete: " \
	    -contextHelp "a list of modes to be deleted from SVD analysis" -width 80
	
	APSRadioButtonFrame .tik -parent $w0 -label "Use tikhonov filter?" -buttonList {Yes No} \
	    -valueList {1 0} -variable ${rootname}TikhonovFilter -orientation horizontal
	APSRadioButtonEntryFrame .par -parent $w0.tik -orientation horizontal -label "Tikhonov filter type:" \
	    -variable ${rootname}TikhonovType -buttonList {SVN_Number Beta} -orientation horizontal \
	    -valueList {SVN Beta} -commandList [list "set ${rootname}TikhonovBeta 0" "set ${rootname}TikhonovSVN 0"] \
	    -entryVariableList [list ${rootname}TikhonovSVN ${rootname}TikhonovBeta] \
	    -entryWidth 10
	if {0} {
	APSLabeledEntryFrame .alpha -parent $w0.tik  -orientation horizontal  \
	    -label "  Tikhonov parameters: SVN/Beta:" -variableList [list ${rootname}TikhonovSVN ${rootname}TikhonovBeta] -width 15 \
	    -contextHelp "provide the SVN number or beta (fractional alpha) of the tikhonov filter, the singular value of the provided SVN number will be used as alpha of the tikhonov filter."
	}
    }
    
}

proc APSBTSWriteConfig {args} {
    set rootname ""
    set filename ""
    set description ""
    set interactive 0
    set configName ""
    set bpmSectorList ""
    set corrSectorList ""
    set bpmList ""
    set corrList ""
    APSStrictParseArguments {rootname filename description interactive  configName  \
                               bpmSectorList corrSectorList bpmList corrList}

    set plane "hv"
   
    if ![string length [string trim $configName]] {
        return -code error "APSBTSWriteConfig: supply a configuration name"
    }
    if ![string match ${plane}.????-????.* $configName] {
        if !$interactive {
            return -code error "APSBTSWriteConfig: configuration name should be ????-????.*"
        }
        if [APSMultipleChoice [APSUniqueName .] \
              -question "Configuration name doesn't match the pattern $plane.*, which may cause problems.  What do you want to do?" \
              -labelList [list "Abort (recommended)" "Continue"] \
              -returnList {1 0}] {
            return 
        }
    }

    set path [file dirname $filename]
    set pathPart [file tail $path]
    
    if $interactive {
	set corCount [APSCountSRConfig -rootname $rootname -itemList $corrList -sectorList $corrSectorList]
	set confirmQuery ""
	set confirm 0
	if {!$corCount} {
	    set confirm 1
	    append confirmQuery "\nNo correctors chosen."
	}
	if [APSCountSRConfig -rootname $rootname -itemList $bpmList -sectorList $bpmSectorList]==0 {
	    set confirm 1
	    append confirmQuery "\nNo monitors chosen."
	}
	if {$confirm &&
	    [APSMultipleChoice [APSUniqueName .] -question "Possible problem: $confirmQuery" \
		 -labelList {"Cancel (recommended)" Continue} -returnList {0 1}]==0} {
	    return
	}
    }
        
    if ![file exists $path] {
	exec mkdir $path
	#catch {exec setfacl -m mask:rwx $path}
    } else {
	if {$interactive && \
		[APSMultipleChoice [APSUniqueName .] -question "That configuration exists.  Overwrite?" \
                     -labelList {Yes No} -returnList {1 0}]==0} {
	    return
	}
	set filesToDelete [glob -nocomplain $path/*]
	if [llength $filesToDelete] {
	    if [catch {eval file delete -force -- $filesToDelete} result] {
		return -code error "APSBTSWriteConfig: $result"
	    }
	}
    }
    global keepDays
    set keepDays 180
   
    if $interactive {
        APSDialogBox .default -name "How many days do you want to keep this configuration?" -width 50 \
            -okCommand {set cancel 0} -cancelCommand {set cancel 1} -cancelButton 0
        APSLabeledEntry .info -parent .default.userFrame -label "Enter number of days to keep or -1 for keeping forever" -textVariable keepDays
        tkwait window .default
    }
    
    set bpmConfig /home/helios/oagData/bts/BPMStatus/config.sdds
    set corrConfig /home/helios/oagData/bts/CorrectorStatus/config.sdds
    set bpmMissingList [join [exec sddsprocess $bpmConfig -pipe=out -nowarnings -filter=col,Nonexistent,0.5,1.5 \
				  | sdds2stream -pipe -col=DeviceName]]
    
    set corrMissingList [join [exec sddsprocess $corrConfig -pipe=out -nowarnings -filter=col,Nonexistent,0.5,1.5 \
				   | sdds2stream -pipe -col=DeviceName]]
    APSSRSectorUnsetMissing -rootname $rootname -missingList $bpmMissingList 
    APSSRSectorUnsetMissing -rootname $rootname -missingLit $corrMissingList
    
    set chosenBPMList ""
    foreach sector $bpmSectorList {
	foreach item $bpmList {
	    set nameFlag ${rootname}${sector}$item
	    global $nameFlag
	    if [set $nameFlag] {
		lappend chosenBPMList ${sector}$item
	    }
	}
    }
   
    set chosenCorrList ""
    foreach sector $corrSectorList {
	foreach item $corrList {
	    set nameFlag ${rootname}${sector}$item
	    global $nameFlag
	    if [set $nameFlag] {
		lappend chosenCorrList ${sector}$item
	    }
	}
    }
    set origname $filename
    set filename ${filename}.tmp
    #update config description database
    set newConfig [file dir $origname]
    set rootDir [file dir $newConfig]
    set newConfig [file tail $newConfig]
    APSAddToTmpFileList -ID APSWriteConfig -fileList "$filename $filename.bpm $filename.corr $filename.bpm.type"
    set createTime [clock seconds]
    set createDate [clock format $createTime -format "%a %b %d %H:%M:%S %Y"]
    
    set bpmList $chosenBPMList
    set corrList $chosenCorrList
    global env apsScriptHost ${rootname}WriteDescription
    foreach type {bpm corr} tag {MonitorNames CorrectorNames} {
	if [catch {exec sddsmakedataset -pipe=out -col=Name,type=string -data=[join [set ${type}List] ,] \
		       -par=NameType,type=string -data=$tag \
		       -par=Description,type=string "-data=[APSMakeSafeQualifierString [set ${rootname}WriteDescription]]" \
		       -par=KeepDays,type=long -data=$keepDays \
		       -par=CreationTime,type=long,units=seconds -data=$createTime \
		       -par=CreationDate,type=string -data=$createDate \
		       -par=User,type=string -data=$env(USER) \
		       -par=Hose,type=string -data=$apsScriptHost \
		       -par=Time,type=long,units=seconds -data=$createTime \
		       -par=TimeStamp,type=string "-data=$createDate" \
		       | sddsprocess -pipe=in $filename.$type \
		       -define=col,Flag,1,type=short \
		       -define=col,Despike,0,type=long \
		       -define=col,Weight,1,type=double } result] {
	    return -code error "Error creating BTS $type config: $result"
	}	       
    }
    if [catch {exec sddscombine $filename.bpm $filename.corr $origname -over } result] {
	return -code error "Error creating BTS config: $result"
    }
    #generate definition file
    #if pv names changed, needs run this script
    #/home/helios/oagData/bts/controllaw/lattices/createSupplementaryFiles
    # written for the bts controllaw only.
    set defFile [file dir $origname]/definitions
    if [file exist $defFile] {
	exec rm $defFile
    }
    exec ln -s /home/helios/oagData/bts/controllaw/lattices/definitions $defFile
    set testsFile [file dir $origname]/tests
    if [file exist $testsFile] {
	exec rm $testsFile
    }
    exec ln -s /home/helios/oagData/bts/controllaw/lattices/tests $testsFile
    return
}



proc APSReadBTSConfig {args} {
    set rootname ""
    set filename ""
    set logic replace
    set bpmSectorList ""
    set corrSectorList ""
    set bpmList ""
    set corrList ""
    set missingList ""
    set application DCOrbitCorrection
    APSStrictParseArguments {rootname filename logic missingList \
                           bpmSectorList corrSectorList bpmList corrList application}
  
    if ![string length $filename] {
        return -code error "APSReadSRConfig: No filename specified for orbit configuration"
    }
    if ![file exists $filename] {
        return -code error "APSReadSRConfig: File $filename not found."
    }
    set tmpRoot /tmp/[APSTmpString]
    
    set cols [exec sddsquery -col $filename]
    foreach type {bpm corr} nameType {Monitor Corrector}  {
        APSAddToTempFileList $tmpRoot.${nameType}
        if [catch {exec sddsprocess $filename $tmpRoot.$type -nowarning \
		       -match=parameter,NameType=${nameType}Names \
		       "-test=parameter,n_rows 0 >" \
		       -filter=column,Flag,1,1 } result] {
            return -code error "Problem making list of included $nameType items: $result"
        }
        set on${type}List [join [exec sdds2stream -col=Name $tmpRoot.$type]]

	set rows [llength [set on${type}List]]
	if [lsearch -exact $cols Weight]>=0 {
	    set weight${type}List [join [exec sdds2stream -col=Weight $tmpRoot.$type]]
	}  else {
	    set weight${type}List [APSReplicateItem -number $rows -item 1.0]
	}
	if [lsearch -exact $cols Despike]>=0 {
	    set Despike${type}List [join [exec sdds2stream -col=Despike $tmpRoot.$type]]
	} else {
	    set Despike${type}List [APSReplicateItem -number $rows -item 1]
	}
    }
    APSBTSRescanBadorbitDevices -rootname $rootname -application $application
    
    if [catch {eval exec sdds2stream $filename -parameter=Description | tail -1} readDescription] {
        set readDescription ""
    }
    global ${rootname}ConfigStatus ${rootname}CBWidget
    set ${rootname}ConfigStatus "Read configuration from $filename"
    update
    set dir [file dir $filename]
    if ![file exist $dir/irm] {
        set ${rootname}ConfigStatus "Warning: the irm of [file tail $dir] does not exist!"
    } else {
        if [catch {exec sdds2stream -par=ConditionNumber $dir/irm} result] {
            set ${rootname}ConfigStatus "$result!"
        } else {
            set ${rootname}ConfigStatus "The condition number is $result"
        }
        if [catch {exec sdds2stream -par=NumberOfSingularValuesUsed $dir/irm} singular] {
            set ${rootname}ConfigStatus "$singular!"
        } else {
            set ${rootname}ConfigStatus "The number of singular values is $singular."
        }
    }
    update
    set onNameList [concat $onbpmList $oncorrList]
   
    set weightList [concat $weightbpmList $weightcorrList]
    set despikeList [concat $DespikebpmList $DespikecorrList]
    switch -exact [lsearch [list replace or and not] $logic] {
        1 {
            # or
            foreach item $onNameList  {
                set nameFlag ${rootname}${item}
                global $nameFlag 
                #set $nameFlag 1
                if {[set $nameFlag] != 1} {
                    [set ${rootname}CBWidget($item)] invoke
                }
		#set $nameFlag 1
            }
        }
        2 {
            # and
            for {set sector 1} {$sector<=$sectorCount} {incr sector} {
		if [llength $sectorList] {
		    set sector1 [lindex $sectorList [expr $sector -1]]
		} else {
		    set sector1 S[format %02d $sector]
		}
                foreach item $knownSuffixes {
                    set name ${sector1}$item
                    if [lsearch $onNameList $name]==-1 {
                        set nameFlag ${rootname}${name} 
                        global $nameFlag
                        if {[info exists $nameFlag]} {
                            if {[set $nameFlag] != 0} {
                                [set ${rootname}CBWidget($name)] invoke
                            }
                            #set $nameFlag 0
                        }
                    }
                }
            }
        }
        3 {
            # not
            foreach item $onNameList {
                set nameFlag ${rootname}${item}
                global $nameFlag
                #set $nameFlag 0
                if {[set $nameFlag] != 0} {
                    [set ${rootname}CBWidget($item)] invoke
                }
            }
        }
        default {
            # replacement
            #APSSetSRSectorButtons -mode all-off -rootname ${rootname} -sectorList $sectorList \
             # -sectorCount $sectorCount -itemList $knownSuffixes
	    APSSetSRSectorButtons -mode all-off -rootname ${rootname} -sectorList  $bpmSectorList -itemList $bpmList
	    APSSetSRSectorButtons -mode all-off -rootname ${rootname} -sectorList  $corrSectorList -itemList $corrList
            foreach item $onNameList weight $weightList despike $despikeList {
                set nameFlag ${rootname}${item} 
                set weightVar ${rootname}${item}Weight
                set despikeVar ${rootname}${item}Despike
                global $nameFlag ${rootname}${item}Weight ${rootname}${item}Despike
                #set $nameFlag 1
                [set ${rootname}CBWidget($item)] invoke
                set ${rootname}${item}Weight $weight
                set ${rootname}${item}Despike $despike
            }
        }
    }
   # APSSRSectorUnsetMissing -rootname $rootname -missingList $missingList
    return $readDescription
}

proc APSSRGenerateControllawFiles {args} {
    set config ""
    set statusCallback ""
    set currLimitH 0.5
    set currLimitV 0.5
    set XBPMLimit 500
    set BPMLimit 10000
    set hcorrLimitMargin 0.5
    set vcorrLimitMargin 0.5
    set regenerateFiles 0
    set timeFilter LowPass1s
    set dataDir /home/helios/oagData/sr/orbitControllaw/lattices/default
    APSParseArguments {dataDir config statusCallback XBPMLimit BPMLimit regenerateFiles \
			   hcorrLimitMargin vcorrLimitMargin currLimitH currLimitV timeFilter}
    set oldDir [pwd]
    set plane [string index $config 0]
    
    if {$plane!="h" && $plane!="v"} {
	return -code error "APSSRGenerateControllawFiles1: invalid config provided, should be \[hv\].*"
    }
    set dir $dataDir/$config
    if ![file exist $dir] {
	return -code error "$dir does not exist!"
    }
    
    set config $dir/config
    if {![file exist $config]} {
	return -code error "$dir/config does not exist, please create the configuration first!"
    }
    if ![file exist $dir/irm] {
	return -code error "$dir/irm does not exist, please use the OC configuration tool to compute the irm first!"
    }
    if [string length $statusCallback] {
	eval $statusCallback { "Generating controllaw files for $plane..."}
    }
    if !$regenerateFiles {
	if {[file exist $dir/definitions] && [file exist $dir/tests]} {
	    return
	}
    }
    set tmpRoot /tmp/[APSTmpString]
    switch $plane {
	h {
	    set coord x
	}
	v {
	    set coord y
	}
    }
    
    #generate definition file
    #Xray BPMs PVs are different, needs update it later when finalized
    #for ID: SxxIDFE-XBPM:P1ds:x:LowPass1sM
    #for BM: SxxBMFE-XBPM:P1:x:LowPass1sM
    if [catch {exec sddsprocess $config -match=par,NameType=MonitorNames $tmpRoot.bpm.rf \
		   "-match=col,Name=*IDFE*,!,Name=*BMFE*,!,&" \
		   -edit=col,ControlName,Name,ei/:$coord:${timeFilter}ErrorM/ \
		   -print=col,SymbolicName,%s,Name -nowarn
	 exec sddsprocess $config -match=par,NameType=MonitorNames $tmpRoot.bpm.ID \
		   "-match=col,Name=*IDFE*" \
		   -edit=col,ControlName,Name,ei/:$coord:${timeFilter}M/ \
		   -print=col,SymbolicName,%s,Name -nowarn
	 exec sddsprocess $config -match=par,NameType=MonitorNames $tmpRoot.bpm.BM \
		   "-match=col,Name=*BMFE*" \
		   -edit=col,ControlName,Name,ei/:$coord:${timeFilter}M/ \
		   -print=col,SymbolicName,%s,Name -nowarn	   				   
	exec sddsprocess $config -match=par,NameType=CorrectorNames $tmpRoot.corr \
		   -edit=col,ControlName,Name,ei/:PS:SetCurrentC/ \
		   -print=col,SymbolicName,%s,Name 
	exec sddscombine $tmpRoot.bpm.rf $tmpRoot.bpm.ID $tmpRoot.bpm.BM -merge $tmpRoot.bpm 
	exec sddscombine $tmpRoot.bpm  $tmpRoot.corr -merge -overwrite $dir/definitions } result] {
	return -code error "APSSRGenerateControllawFiles2: error generating definition file: $result"
    }
    APSAddToTmpFileList -ID oc -fileList "$tmpRoot.bpm $tmpRoot.bpm.rf $tmpRoot.bpm.ID $tmpRoot.bpm.BM $tmpRoot.corr"
    #current test value
    set currentLimit [set currLimit[string toupper $plane]]
    
    if [catch {exec sddsmakedataset $tmpRoot.curr.tests -col=ControlName,type=string -data=S-DCCT:CurrentM \
		   -col=MinimumValue,type=double -data=$currentLimit \
		   -col=MaximumValue,type=double -data=300} result] {
	return -code error "APSSRGenerateControllawFiles2a: error generating current tests: $result"
    }
    
    
    set lowxbpm [expr -1.0*$XBPMLimit]
    set lowbpm [expr -1.0*$BPMLimit]
   
    if [catch {exec sddsprocess $tmpRoot.bpm $tmpRoot.bpm.tests \
		   "-define=col,MinimumValue,Name \"*ID*\" strmatch Name \"*BM\" strmatch || ? $lowxbpm : $lowbpm $ " \
		   "-define=col,MaximumValue,Name \"*ID*\" strmatch Name \"*BM\" strmatch || ? $XBPMLimit : $BPMLimit $ "  } result] {
	return -code error "APSSRGenerateControllawFiles3 Error creating bpm test file: $result"
    }
    
  
    if [catch {exec sddsprocess $tmpRoot.corr -reedit=col,ControlName,ei/.DRVH/ -pipe=out \
		   | sddscasr -save -pipe \
		   | sddsprocess -pipe -scan=col,MaximumValue,ValueString,%lf \
		   -reedit=col,ControlName,%/.DRVH// \
		   | sddsprocess -pipe "-redefine=col,MaximumValue,MaximumValue [set ${plane}corrLimitMargin] -" \
		   | sddsconvert -pipe=in $tmpRoot.corr.hi \
		   -retain=col,Name,Flag,Weight,Despike,ElectronicsType,ControlName,SymbolicName,MinimumValue,MaximumValue
	exec sddsprocess $tmpRoot.corr -reedit=col,ControlName,ei/.DRVL/ -pipe=out \
		   | sddscasr -save -pipe \
		   | sddsprocess -pipe -scan=col,MinimumValue,ValueString,%lf \
		   | sddsprocess -pipe=in $tmpRoot.corr.lo "-redefine=col,MinimumValue,MinimumValue [set ${plane}corrLimitMargin] +" 
	exec sddsxref  $tmpRoot.corr.hi  $tmpRoot.corr.lo \
		   -match=Name -take=MinimumValue $tmpRoot.corr.tests } result] {
	return -code error "APSSRGenerateControllawFiles4a Error creating corr test file from driveHigh and driveLow: $result"
    }
    APSAddToTmpFileList -ID config -fileList "$tmpRoot.corr.hi $tmpRoot.corr.lo $tmpRoot.curr.tests"
    
    #corrector rangeerror
    
    if [catch {exec sddscombine $tmpRoot.curr.tests $tmpRoot.bpm.tests $tmpRoot.corr.tests -merge -over $dir/tests } result] {
	return -code error "APSSRGenerateControllawFiles5 : Error generating tests file: $result"
    }
    exec cp $tmpRoot.bpm $dir/despike
    #exec chmod 777 $dir/despike
    file delete -force $tmpRoot.bpm $tmpRoot.corr $tmpRoot.bpm.tests $tmpRoot.corr.tests
    if [string length $statusCallback] {
	eval $statusCallback {"Generating controllaw files for $plane done."}
    }
    cd $oldDir
    
}

proc APSSRPrepareControllawOptions {args} {
    set config ""
    set dataDir /home/helios/oagData/sr/orbitControllaw/lattices/default
    set runControlDesc ""
    set runControlPV ""
    set RCTimeout 30
    set averages 1
    set averageInterval 1
    set deltaLimit 5
    set dryRun 0
    set verbose 1
    set FFcompensation 0
    set despike 0
    set despikePasses 2
    set despikeNeighbors 36
    set despikeAverage 4 
    set despikeCountLimit 1000
    set despikeThresholdSteps 30
    set despikeThresholdStart 3.0
    set despikeThresholdEnd 0.02
    set logActuators 0
    set logStats 0
    set logGlitch 0
    set steps 300000
    set gain 0.4
    set interval 2
    set DCCTLimit 0.5
    set testValues 1
    if [APSStrictParseArguments {config RCTimeout runControlDesc runControlPV averages averageInterval deltaLimit dryRun verbose \
                                   FFcompensation despike despikePasses despikeNeighbors despikeAverage despikeCountLimit \
                                   despikeThresholdSteps despikeThresholdStart despikeThresholdEnd logActuators logStats logGlitch \
                                   steps gain interval DCCTLimit dataDir testValues}] {
        return -code error "APSSRPrepareControllawOptions: invalid arguments"
    }
    
        
    set plane [string index $config 0]
    if {$plane!="h" && $plane!="v"} {
	return -code error "APSSRPrepareControllawOptions1: invalid config ($config) provided!"
    }
    
    set dir $dataDir/$config
    switch $plane {
	h {
	    set coord x
	    set Coord X
	   
	}
	v {
	    set coord y
	    set Coord Y
	}
    }
    if ![string length $runControlPV] {
	set runControlPV S:RC:OrbitControlLaw${Coord}C
    }
    if ![string length $runControlDesc] {
	set runControlDesc "SR ${coord}-orbit correction"
    }
    
    foreach file {irm tests definitions} {
	if ![file exist $dir/$file] {
	    return -code error "APSSRPrepareControllawOptions2: $dir/$file not found!"
	}
    }
    set options "$dir/irm -runControlPV=string=$runControlPV,pingTimeout=$RCTimeout"
    append options " \"-runControlDescription=string=$runControlDesc\""
    append options " -steps=$steps -gain=$gain -interval=$interval"
    if $averages>1 {
	append options " -average=$averages,interval=$averageInterval"
    }
    if $deltaLimit>0 {
	append options " -deltaLimit=value=$deltaLimit"
    }
    if $dryRun {
	append options " -dryRun"
    }
    if $verbose {
	append options " -verbose"
    }
    if {$FFcompensation && [file exist $dir/rmFF] && [file exist $dir/FFdefs]} {
	append options " -auxiliaryOutput=gain=1.0,matrix=$dir/rmFF,controlquantitydefinition=$dir/FFdefs"
    }
    if $despike {
	append options " -despike=pass=$despikePasses,neighbors=$despikeNeighbors,averageOf=$despikeAverage,countLimit=$despikeCountLimit,threshold=$despikeThresholdEnd,file=$dir/despike"
	if $despikeThresholdSteps>2 {
	    append options ",startThreshold=$despikeThresholdStart,endThreshold=$despikeThresholdEnd,stepsThreshold=$despikeThresholdSteps"
	}
    }
    set logDataDir /home/helios/oagData/controllaw/SRorbit/loggedData
    if $logActuators {
	set logFile $logDataDir/sr.${coord}-[exec date +%Y-%m%d-%H%M%S].log
	append options " -controlLogFile=$logFile"
    }
    if $logStats {
	set statsFile $logDataDir/sr.${coord}-[exec date +%Y-%m%d-%H%M%S].stats
	append options " -statistics=$statsFile,mode=brief"
    }
    if $logGlitch {
	set glitchFile $logDataDir/sr.${coord}-[exec date +%Y-%m%d-%H%M%S].glog
	# these essentially disable rms-based glitching and rely on the tests only
	set readbackRmsThreshold 500
	set controlRmsThreshold  500
	append options " -glitchLogFile=file=$glitchFile,readbackRmsThreshold=$readbackRmsThreshold,controlRmsThreshold=$controlRmsThreshold,rows=10"
    }

    if $testValues {
        append options " -testValues=$dir/tests"
    }
    append options " -actuatorColumn=ControlName -controlQuantityDefinitions=$dir/definitions"
    
    return $options
}
