
#
# These procedures used to be in SCRprocedures.tcl.
# However, they are site-specific and where moved here to allow generalizing
# SCR.

#
# List of procedures:
#
# This one must be defined for all sites:
# APSSCRDefineVariables : defines global variables needed for using SCR procedures
#         executed when this file is loaded.
#
# These are APS-specific:
# APSSCRSRCompareConverters : does custom SR comparisons for converters (power supplies)
# APSSCRSRCompareOrbitSetpoints : does custom SR comparisons for orbit setpoints
# APSSCRSRCompareOrbitOffsets : does custom SR comparisons for orbit offsets
# APSSCRSRCompareBPMQuantities : does custom SR comparisons for BPM quantities.
#  Used by APSSCRSRCompareOrbitSetpoints and APSSCRSRCompareOrbitOffsets.
# APSSetTuneMultiplexer: sets SR:TUNE:Mux4Sw2BO to NASA or VSA and
#   SR:TUNE:Mux4MO in both mode

proc APSSCRDefineVariables {args} {
    set topDirectory ""
    set inhibitLogging 0

    APSStrictParseArguments {topDirectory inhibitLogging}

    if ![string length $topDirectory] {
        set topDirectory /home/helios/oagData/SCR
    }
 
    global apsSCRDefineVariablesCalled
    if {[info exists apsSCRDefineVariablesCalled]  && \
          $apsSCRDefineVariablesCalled} {
        return 
    }
    set apsSCRDefineVariablesCalled 1
    
    global apsSCRRequestDir apsSCRSnapDir apsSCRInhibitActionLogging apsSCRAtticDir
    global apsSCRFilterFileDir apsSCRFilterFileName
    global apsSCRUseCarestore apsSCRUseGPServer apsSCRPVNameFilter apsSCRUseCASRServer
    global apsSCRSystemDescription apsSCRAccelManagerAccount
    global apsSCRSystemList apsSCRSystem apsSCRRefChoiceDir apsSCRCustomCompareList
    global apsSCRCustomCompareDescription apsSCRTopDirectory
    global apsSCRCustomReviewList apsSCRCustomReviewDescription
    global apsSCRGroupMembers apsSCRGroupDescription apsSCRGroup
    global apsSCRGroupMenuOrder apsSCRInvertFilterFile
    global apsSCRSuppressSingleBeamline apsSCRPreSelectedSystem
    global apsSCRFirstSnapshot apsSCRSnapshotLogFile apsSCRPendIOTime

    set apsSCRTopDirectory $topDirectory
    set apsSCRRequestDir $topDirectory/requestFiles
    set apsSCRSnapDir $topDirectory/snapshots
    set apsSCRAtticDir $topDirectory/attic
    set apsSCRFilterFileDir $topDirectory/filterFiles/
    set apsSCRRefChoiceDir $topDirectory/preferredChoices
    set apsSCRFilterFileName ""
    set apsSCRUseCarestore 0
    set apsSCRUseGPServer 0
    set apsSCRUseCASRServer 0
    set apsSCRPVNameFilter *
    set apsSCRInhibitActionLogging $inhibitLogging
    set apsSCRInvertFilterFile 0
    set apsSCRSuppressSingleBeamline 0
    set apsSCRPreSelectedSystem ""
    
    if {[file exists ${topDirectory}/SCR.spec]} {
        if {[catch {sdds load ${topDirectory}/SCR.spec spec} result]} {
            return -code error "Unable to load ${topDirectory}/SCR.spec"
        }
        foreach groupDesc $spec(Parameter.GroupDescription) \
          group $spec(Parameter.Group) \
          systems $spec(Column.System) \
          descs $spec(Column.Description) \
          managers $spec(Column.Manager) {
              set apsSCRGroupDescription($group) $groupDesc
              lappend apsSCRGroupMenuOrder $group
              set apsSCRGroupMembers($group) $systems
              foreach system $systems desc $descs manager $managers {
                  set apsSCRSystemDescription($system) $desc
                  set apsSCRAccelManagerAccount($system) $manager
              }
          }
    } else {
        set apsSCRSystemDescription(PLET) "PAR/LET"
        set apsSCRSystemDescription(SR)  "Storage ring"
	set apsSCRSystemDescription(SRBPLD)  "Storage ring MPS and BPLD system"
	set apsSCRSystemDescription(SRBPLDVerify)  "Storage ring BPLD Limits Verfication"
        set apsSCRSystemDescription(Booster) "Booster"
        set apsSCRSystemDescription(BRF) "Booster RF"
        set apsSCRSystemDescription(LINAC) "LINAC"
        set apsSCRSystemDescription(LEUTL) "LEUTL"
        set apsSCRSystemDescription(SRF) "Storage ring RF"
        set apsSCRSystemDescription(SBPMs) "Storage ring BPM controls"
        set apsSCRSystemDescription(SBPMLibera) "Storage ring Libra BPM controls"
        set apsSCRSystemDescription(SBPMWaveform) "Storage ring BSP-100 BPM timing controls"
        set apsSCRSystemDescription(SBPMLiberaWaveform) "Storage ring Libra BPM timing controls"
        set apsSCRSystemDescription(P0Feedback) "Storage ring P0 feedback system controls"
        set apsSCRSystemDescription(TFeedback) "Storage ring Transverse feedback system controls"
        set apsSCRSystemDescription(XrayTranslation) "Portable Xray BPM Translation System"
        set apsSCRSystemDescription(SRNASA) "SR Network/Spectrum Analyzer"
	set apsSCRSystemDescription(PAR) "PAR"
        set apsSCRSystemDescription(PARNASA) "PAR Network/Spectrum Analyzer"
	set apsSCRSystemDescription(PARBPM) "PAR BPMs"
        set apsSCRSystemDescription(StreakCamera) "Streak Camera"
        set apsSCRSystemDescription(Timing) "Linac Timing"
        set apsSCRSystemDescription(SparkBPMs) "Spark BPMs"
        set apsSCRSystemDescription(SRSCDUBits) "SR BPM SCDU Status Bits"
        set apsSCRSystemDescription(IDBM) "SR ID/BM readbacks"
        set apsSCRSystemDescription(SRXrayBPM) "SR Xray BPM readbacks"
        set apsSCRSystemDescription(SRXrayBPMWaveform) "SR Xray BPM waveforms"
        set apsSCRSystemDescription(BBPMs) "Booster BPM controls"
        set apsSCRSystemDescription(BBPMWaveform) "Booster BSP-100 BPM timing controls"
        set apsSCRSystemDescription(BoosterTune) "Booster Tune measurements"
        set apsSCRSystemDescription(BTS_BESOCM) "BTS BESOCM Chains A and B"
        set apsSCRSystemDescription(IDEncoder) "ID Encoders"
        set apsSCRSystemDescription(SROrbitSetPt) "SR Orbit Setpoints and Offsets\nNB: This system is usually used for recovery of setpoints after an error in steering."
        set apsSCRSystemDescription(SRCorSetpts) "SR Corrector Setpoints\nNB: This system is usually used for recovery of setpoints after an error in steering."
        set apsSCRSystemDescription(LPL) "Linac, PAR, and LET"
        set apsSCRSystemDescription(LEA) "Linac Extension Area"
        set apsSCRSystemDescription(LTS) "RFGun Test Stand"
        set apsSCRSystemDescription(SRVideo) "SR video system for S35BM beamline"
        set apsSCRSystemDescription(LI:VD1) "MV200 LI:VD1 video system for all beamlines."
        set apsSCRSystemDescription(DG535) "DG535"
        set apsSCRSystemDescription(Dimtel) "Dimtel systems"
        set apsSCRSystemDescription(RTFBdaq) "DAQ RTFB"
        set apsSCRSystemDescription(S-DAQTBT) "DAQ TBT"
        set apsSCRSystemDescription(BaselineBoosterInterlock) "Baseline Booster Interlock"
        set apsSCRSystemDescription(BaselineBoosterPS) "Baseline Booster PS"
        set apsSCRSystemDescription(BaselineBoosterPSVacuum) "Baseline Booster PS Vacuum"
        set apsSCRSystemDescription(BaselineBoosterTemperature) "Baseline Booster Temperature"
        set apsSCRSystemDescription(BaselineBoosterVacuum) "Baseline Booster Vacuum"
        set apsSCRSystemDescription(BaselineIETS) "Baseline SR IETS"
        set apsSCRSystemDescription(BaselineSRBPM_ZoneA) "Baseline SR BPM Zone A"
        set apsSCRSystemDescription(BaselineSRBPM_ZoneB) "Baseline SR BPM Zone B"
        set apsSCRSystemDescription(BaselineSRBPM_ZoneC) "Baseline SR BPM Zone C"
        set apsSCRSystemDescription(BaselineSRBPM_ZoneD) "Baseline SR BPM Zone D"
        set apsSCRSystemDescription(BaselineSRBPM_ZoneE) "Baseline SR BPM Zone E"
        set apsSCRSystemDescription(BaselineSRBPM_ZoneF) "Baseline SR BPM Zone F"
        set apsSCRSystemDescription(BaselineSRMotor) "Baseline SR Motor"
        set apsSCRSystemDescription(BaselineSRPSInterlock) "Baseline SR PS Interlock"
        set apsSCRSystemDescription(BaselineSRVacuum) "Baseline SR Vacuum"
        
        set apsSCRGroupDescription(Special) "Special systems"
        set apsSCRGroupDescription(SR) "SR systems"
        set apsSCRGroupDescription(Booster) "Booster systems"
        set apsSCRGroupDescription(LPL) "LINAC/PAR/LET systems"
        set apsSCRGroupDescription(MV200) "MV200 systems"
        set apsSCRGroupDescription(Obsolete) "Obsolete systems"
        set apsSCRGroupMenuOrder {LPL Booster SR Special MV200 Obsolete}
        
        set apsSCRGroupMembers(Special) {DG535 IDEncoder SROrbitSetPt SRCorSetpts BaselineBoosterInterlock BaselineBoosterPS BaselineBoosterPSVacuum BaselineBoosterTemperature BaselineBoosterVacuum BaselineIETS BaselineSRBPM_ZoneA  BaselineSRBPM_ZoneB BaselineSRBPM_ZoneC BaselineSRBPM_ZoneD BaselineSRBPM_ZoneE BaselineSRBPM_ZoneF BaselineSRMotor BaselineSRPSInterlock BaselineSRVacuum}
        set apsSCRGroupMembers(SR) {SR SRBPLD SRF SBPMs SBPMLibera SBPMLiberaWaveform IDBM SRXrayBPM SRXrayBPMWaveform Dimtel RTFBdaq S-DAQTBT}
        set apsSCRGroupMembers(Booster) {Booster BRF BBPMs BBPMWaveform BoosterTune BTS_BESOCM}
        set apsSCRGroupMembers(LPL) {LPL PAR PARNASA PARBPM LEA LTS SparkBPMs StreakCamera Timing}
        set apsSCRGroupMembers(Obsolete) {LINAC LEUTL PLET P0Feedback SBPMWaveform SRVideo TFeedback SRNASA SRSCDUBits XrayTranslation}
        set apsSCRGroupMembers(MV200) {LI:VD1}
        set apsSCRAccelManagerAccount(PLET) "borland"
        set apsSCRAccelManagerAccount(SR)   "sr"
        set apsSCRAccelManagerAccount(Booster) "sereno"
        set apsSCRAccelManagerAccount(BRF) "sereno"
        set apsSCRAccelManagerAccount(LINAC) "borland"
        set apsSCRAccelManagerAccount(LEUTL) "leutl"
        set apsSCRAccelManagerAccount(SRF) "sr"
	set apsSCRAccelManagerAccount(SRBPLD) "sr"
	set apsSCRAccelManagerAccount(SRBPLDVerify) "sr"
        set apsSCRAccelManagerAccount(SBPMs) "sr"
        set apsSCRAccelManagerAccount(SBPMLibera) "sr"
        set apsSCRAccelManagerAccount(SBPMWaveform) "sr"
        set apsSCRAccelManagerAccount(SBPMLiberaWaveform) "sr"
        set apsSCRAccelManagerAccount(XrayTranslation) "sr"
        set apsSCRAccelManagerAccount(SRNASA) "sr"
        set apsSCRAccelManagerAccount(PARNASA) "borland"
	set apsSCRAccelManagerAccount(PARBPM) "par"
	set apsSCRAccelManagerAccount(PAR) "par"
        set apsSCRAccelManagerAccount(StreakCamera) "par"
        set apsSCRAccelManagerAccount(Timing) "linac"
        set apsSCRAccelManagerAccount(SparkBPMs) "par"
        set apsSCRAccelManagerAccount(SRSCDUBits) "sr"
        set apsSCRAccelManagerAccount(IDBM) "sr"
        set apsSCRAccelManagerAccount(SRXrayBPM) "sr"
        set apsSCRAccelManagerAccount(SRXrayBPMWaveform) "sr"
        set apsSCRAccelManagerAccount(P0Feedback) "sr"
        set apsSCRAccelManagerAccount(TFeedback) "sr"
        set apsSCRAccelManagerAccount(BBPMs) "sereno"
        set apsSCRAccelManagerAccount(BBPMs) "cyao"
        set apsSCRAccelManagerAccount(BBPMWaveform) "cyao"
        set apsSCRAccelManagerAccount(IDEncoder) "mls"
        set apsSCRAccelManagerAccount(SROrbitSetPt) "sr"
        set apsSCRAccelManagerAccount(SRCorSetpts) "sr"
        set apsSCRAccelManagerAccount(SRVideo) "sr"
        set apsSCRAccelManagerAccount(LEA) "linac"
        set apsSCRAccelManagerAccount(LTS) "linac"
        set apsSCRAccelManagerAccount(LPL) "linac"
        set apsSCRAccelManagerAccount(LI:VD1) "par"
        set apsSCRAccelManagerAccount(DG535) "jbs"
        set apsSCRAccelManagerAccount(Dimtel) "sr"
        set apsSCRAccelManagerAccount(RTFBdaq) "sr"
        set apsSCRAccelManagerAccount(S-DAQTBT) "sr"

        set apsSCRAccelManagerAccount(BaselineBoosterInterlock) "booster"
        set apsSCRAccelManagerAccount(BaselineBoosterPS) "booster"
        set apsSCRAccelManagerAccount(BaselineBoosterPSVacuum) "booster"
        set apsSCRAccelManagerAccount(BaselineBoosterTemperature) "booster"
        set apsSCRAccelManagerAccount(BaselineBoosterVacuum) "booster"
        set apsSCRAccelManagerAccount(BaselineIETS) "sr"
        set apsSCRAccelManagerAccount(BaselineSRBPM_ZoneA) "sr"
        set apsSCRAccelManagerAccount(BaselineSRBPM_ZoneB) "sr"
        set apsSCRAccelManagerAccount(BaselineSRBPM_ZoneC) "sr"
        set apsSCRAccelManagerAccount(BaselineSRBPM_ZoneD) "sr"
        set apsSCRAccelManagerAccount(BaselineSRBPM_ZoneE) "sr"
        set apsSCRAccelManagerAccount(BaselineSRBPM_ZoneF) "sr"
        set apsSCRAccelManagerAccount(BaselineSRMotor) "sr"
        set apsSCRAccelManagerAccount(BaselineSRPSInterlock) "sr"
        set apsSCRAccelManagerAccount(BaselineSRVacuum) "sr"

    }
        
    set apsSCRSystemList [array names apsSCRSystemDescription]
    set apsSCRSystem [lindex $apsSCRSystemList 0]
    set apsSCRGroup ""

    foreach item $apsSCRSystemList {
        set apsSCRCustomCompareList($item) ""
        set apsSCRCustomCompareDescription($item) ""
        set apsSCRPendIOTime($item) 10
    }
    # HT are horizontal trims of which there are many.
    # SQ is for skew quadrupoles
    # D are the gorups of displaced quadrupoles that make the
    # combined function dipole-quadrupole, but not all of them.
    # Q are pure quadrupoles, but also some displaced quadrupoles
    foreach group {H HT V D Q SQ S} {
        lappend apsSCRCustomCompareList(SR) \
          "APSSCRSRCompareConverters -group $group -readback 1" \
          "APSSCRSRCompareConverters -group $group -readback 0" 
        lappend apsSCRCustomCompareDescription(SR) \
          "$group converter readbacks" \
          "$group converter setpoints" 
    }
    lappend apsSCRCustomCompareList(SR) \
      APSSCRSRCompareOrbitSetpoints "APSSCRSRCompareOrbitSetpoints -mode orbitCorrection" APSSCRSRCompareOrbitOffsets 

    lappend apsSCRCustomCompareDescription(SR) \
      "Orbit setpoints" "Orbit setpoints in orbit correction" "BPM offsets"

    lappend apsSCRCustomCompareList(SROrbitSetPt) \
      APSSCRSRCompareOrbitSetpoints "APSSCRSRCompareOrbitSetpoints -mode orbitCorrection" APSSCRSRCompareOrbitOffsets 

    lappend apsSCRCustomCompareDescription(SROrbitSetPt) \
      "Orbit setpoints" "Orbit setpoints in orbit correction" "BPM offsets"

    lappend apsSCRCustomCompareList(XrayTranslation) \
      "APSSCRXrayTranslationCompare -mode 1only" \
      "APSSCRXrayTranslationCompare -mode 2only" \
      "APSSCRXrayTranslationCompare -mode 1of1w2of2" \
      "APSSCRXrayTranslationCompare -mode 2of1w1of2"
    lappend apsSCRCustomCompareDescription(XrayTranslation) \
      "Controller \#1 only" "Controller \#2 only" \
      "Controller \#1 of filename 1 with Controller \#2 of filename 2" \
      "Controller \#2 of filename 1 with Controller \#1 of filename 2" 
    lappend apsSCRCustomCompareList(SRXrayBPM) \
      "APSSRXrayBPMCustomCompare -bpmType ID -plane x -gapcompare 0" \
      "APSSRXrayBPMCustomCompare -bpmType ID -plane y -gapcompare 0" \
      "APSSRXrayBPMCustomCompare -bpmType BM -plane y" \
      "APSSRXrayBPMCustomCompare -bpmType ID -gapcompare 1" \
      "APSSRXrayBPMCustomCompare -bpmType ID -bladescompare 1 -group a -type Rate" \
      "APSSRXrayBPMCustomCompare -bpmType ID -bladescompare 1 -group a -type Offset" \
      "APSSRXrayBPMCustomCompare -bpmType ID -bladescompare 1 -group b -type Rate" \
      "APSSRXrayBPMCustomCompare -bpmType ID -bladescompare 1 -group b -type Offset" 
    lappend apsSCRCustomCompareDescription(SRXrayBPM) \
      "ID x readbacks" \
      "ID y readbacks" \
      "BM y readbacks" \
      "ID gap readbacks" \
      "ID defaultA blade rates" \
      "ID defaultA blade offsets" \
      "ID defaultB blade rates" \
      "ID defaultB blade offsets"

    lappend apsSCRCustomReviewList(SR) \
      "APSSRPlotSCRBPMData -field SetpointC"  \
      "APSSRPlotSCRBPMData -field BpmZeroOffsetC" 
    lappend apsSCRCustomReviewDescription(SR) \
      "BPM Setpoints" \
      "BPM Bpm-zero Offsets" 

    lappend apsSCRCustomReviewList(SBPMs) \
      "APSSRPlotSCRBPMData -field GainC" 
    lappend apsSCRCustomReviewDescription(SBPMs) \
      "BPM Gains"

    # check "system" subdirectories 
    set notInList ""
    foreach filename [lsort [glob -nocomplain $apsSCRSnapDir/*]] {
        if {[file isdirectory $filename] && \
              [lsearch -exact $apsSCRSystemList [file tail $filename]]==-1} {
            lappend notInList [file tail $filename]
        }
    }
    foreach file $apsSCRSystemList {
        set file0 $apsSCRSnapDir/$file
        if {![file exists $file0] || ![file isdirectory $file0]} {
            return -code error "System directory for $file not found."
        }
    }
    if [llength $notInList] {
        puts stderr "Warning: directories for these systems exist but are not accessed: $notInList"
        return -code ok "Warning: directories for these systems exist but are not accessed: $notInList"
    }
}

if {(![info exists apsSkipSCRDefineVariables]) || ($apsSkipSCRDefineVariables == 0)} {
    if {[catch {APSSCRDefineVariables} apsSCRDefineVariablesResults]} {
        global tk_version
        if {[info exists tk_version]} {
            update
            APSAlertBox .errorMessage -errorMessage "Error (APSSCRDefineVariables): $apsSCRDefineVariablesResults"
            exit
        } else {
            puts stderr "Error (APSSCRDefineVariables): $apsSCRDefineVariablesResults"
            exit
        }
    }
}

proc APSSCRSRCompareConverters {args} {
    set machine ""
    set snapshot1 ""
    set snapshot2 ""
    set readback 0
    set group H
    set plots 1
    set fileDisplay 1
    APSStrictParseArguments {machine snapshot1 snapshot2 readback group plots fileDisplay} 
    global SCRdebug apsSCRTopDirectory
    if $SCRdebug { puts stderr "APSSCRSRCompareConverters: snapshots: $snapshot1 $snapshot2"}

    if {![string length $snapshot1] || ![string length $snapshot2] || \
          ![string length $machine]} {
        return -code error "APSSCRSRCompareConverters: bad arguments\nmachine=$machine  snapshot1=$snapshot1  snapshot2=$snapshot2"
    }

    set groupTagList {H HT V D Q SQ S} 
    set groupNameList {"H corrector"      "H trims"   \
                           "V corrector"   "Dipole"  \
                           "Quadrupole" "Skew Quadrupole" "Sextupole"}
    set groupMatchStringList { {S??[AB]:H[178]: S??[AB]:FH[12]:}  S??[AB]:[QM]?T: \
                                   {S??[AB]:V[178]: S??[AB]:FV[12]:}  {S??[AB]:Q[458]: S??[AB]:M[34]:} \
                                  S??[AB]:Q[12367]: S??[AB]:SQ[12]: S??[AB]:S[123]:}
    set groupPVCountList {320        360    \
                              400          360    \
                              400          160      240}
    set groupIndex [lsearch $groupTagList $group]
    if $groupIndex==-1 {
        return -code error "APSSCRSRCompareConverters: group $group is unknown."
    }
    set groupName [lindex $groupNameList $groupIndex]
    set pvCount [lindex $groupPVCountList $groupIndex]
    set matchString [lindex $groupMatchStringList $groupIndex]
    if $readback {
        set title "$groupName readback changes from [file tail [file rootname $snapshot1]] to [file tail [file rootname $snapshot2]]"
        set currentType DCCT:CurrentM
    } else {
        set title "$groupName setpoint changes from [file tail [file rootname $snapshot1]] to [file tail [file rootname $snapshot2]]"
        set currentType PS:SetCurrentC
    }

    set tmpFile /tmp/[APSTmpString]
    set tmpID [APSUniqueName tmpID]
#    APSAddToTmpFileList -ID $tmpID -fileList [list $tmpFile $tmpFile.print]
    # I don't have miscInputs/ConverterMagnetPositions.xref ready yet
    if {[llength $matchString] == 1} {
        set matchOption "ControlName=$matchString$currentType"
    } else {
        set matchOption "ControlName=[lindex $matchString 0]$currentType,ControlName=[lindex $matchString 1]$currentType,|"
    }
    set crossReferencePositionFile $apsSCRTopDirectory/miscInputs/SRConverterMagnetPositions.xref
    if [catch {exec sddscombine $snapshot1 $snapshot2 -pipe=out \
                   | sddsprocess -pipe -match=column,$matchOption \
                   -scan=column,${currentType},ValueString,%le,units=A \
                   -edit=column,ElementName,ControlName,%/:${currentType}// \
                   | sddsxref $crossReferencePositionFile  \
                   -pipe -match=ElementName -take=s,Sector -reuse=page,row -nowarning \
                   | sddsselect -pipe $snapshot1 -match=ControlName -reuse=page -nowarning \
                   | sddsselect -pipe $snapshot2 -match=ControlName -reuse=page -nowarning \
                   | sddssort -pipe -column=s,incr \
                   | sddschanges -pipe -copy=s,ElementName -changesIn=${currentType} \
                   | sddsprocess -pipe \
                   "-redefine=column,Sector,s 1103.608 40 / / 1 + Sector -,type=double" \
                   | tee $tmpFile.for-plots \
                   | sddsprintout -pipe=in $tmpFile.print \
                   -column=ElementName -column=ChangeIn${currentType} "-title=$title"} result] {
        APSDeleteTmpFileList -ID $tmpID
        return -code error "$result"
    }

    if $fileDisplay {
        APSFileDisplayWindow [APSUniqueName .] \
          -comment "$title" -fileName $tmpFile.print -deleteOnClose 1 -width 80 \
          -contextHelp "$title" -sddsExportableFile $tmpFile 
        update
    }

    if $plots {
        exec sddsplot "-topline=$title" \
          $tmpFile.for-plots -split=page -sep=page -title=  \
          -column=Sector,ChangeIn${currentType} -graph=impulse,type=1 \
          -legend=spec=>15A \
          -column=Sector,ChangeIn${currentType} -graph=impulse,type=2 \
          -filter=column,ChangeIn${currentType},-15,15 -legend=spec=>1.5A \
          -column=Sector,ChangeIn${currentType} -graph=impulse,type=0 \
          -filter=column,ChangeIn${currentType},-1.5,1.5 -legend=spec=<1.5A &
    }
}

proc APSSCRSRCompareOrbitSetpoints {args} {
    return [eval APSSCRSRCompareBPMQuantities -quantity SetpointC $args]
}
proc APSSCRSRCompareOrbitOffsets {args} {
    return [eval APSSCRSRCompareBPMQuantities -quantity BpmZeroOffsetC $args]
}

proc APSSCRSRCompareBPMQuantities {args} {
    set quantity SetpointC
    set machine ""
    set snapshot1 ""
    set snapshot2 ""
    set plots 1
    set fileDisplay 1
    set mode ""
    APSStrictParseArguments {machine snapshot1 snapshot2 plots fileDisplay quantity mode} 
    global SCRdebug apsSCRTopDirectory

    if {![string length $snapshot1] || ![string length $snapshot2] || \
          ![string length $machine]} {
        return -code error "APSSCRSRCompareBPMQuantities: bad arguments"
    }
    set title "$quantity changes from [file tail [file rootname $snapshot1]] to [file tail [file rootname $snapshot2]]"

    set tmpFile /tmp/[APSTmpString]
    set tmpID [APSUniqueName tmpID]
    APSAddToTmpFileList -ID $tmpID -fileList \
      [list $tmpFile $tmpFile.x $tmpFile.y $tmpFile.print \
         $tmpFile.ss2 $tmpFile.ss1]
    APSAddToTmpFileList -ID semi-permanent -fileList $tmpFile.xy.exportable

    if [catch {exec sddsprocess $snapshot1 $tmpFile.ss1 \
                 -edit=col,BPMName,ControlName,%/:x://%/:y://%/${quantity}// \
                 -match=column,ControlName=S*:P?:?:${quantity} \
             } result] {
        APSDeleteTmpFileList -ID $tmpID
        return -code error "APSSCRSRCompareBPMQuantities(0): $result"
    }

    # with orbit correction mode, we have to separate the x and y planes
    # into different files, then do the comparison.
    if [string match $mode orbitCorrection] {
        # create file of selected bpms in x and y planes and join them.
        if [catch {exec sddsprocess /home/helios/oagData/sr/orbitControllaw/lattices/default/h.default/config $tmpFile.xbpms \
                     -match=para,NameType=MonitorNames \
                     -filter=col,Flag,1,1 \
                 } result] {
            APSDeleteTmpFileList -ID $tmpID
            return -code error "APSSCRSRCompareBPMQuantities(1): $result"
        }
        
        if [catch {exec sddsprocess /home/helios/oagData/sr/orbitControllaw/lattices/default/v.default/config $tmpFile.ybpms \
                     -match=para,NameType=MonitorNames \
                     -filter=col,Flag,1,1\
                 } result] {
            APSDeleteTmpFileList -ID $tmpID
            return -code error "APSSCRSRCompareBPMQuantities(2): $result"
        }

        foreach coord {x y} {
            # $tmpFile.ss1.${coord}.oc is a smaller snapshot file.
            if [catch {exec sddsselect $tmpFile.ss1 $tmpFile.${coord}bpms -pipe=out \
                         -match=BPMName=Name -reuse \
                         | sddsprocess -pipe=in $tmpFile.ss1.${coord}.oc \
                         -match=col,ControlName=*${coord}* \
                     } result] {
                APSDeleteTmpFileList -ID $tmpID
                return -code error "APSSCRSRCompareBPMQuantities(3): $result"
            }
            # take intersection of snapshot1 and snapshot2 to make smaller snapshot
            # file $tmpFile.ss2.${coord}.oc.
            if [catch {exec sddsselect $snapshot2 $tmpFile.ss1.${coord}.oc -pipe=out \
                         -match=ControlName -reuse \
                         | sddsprocess -pipe=in $tmpFile.ss2.${coord}.oc \
                         -edit=col,BPMName,ControlName,%/:x://%/:y://%/${quantity}// \
                         -match=col,ControlName=*${coord}* \
                     } result] {
                APSDeleteTmpFileList -ID $tmpID
                return -code error "APSSCRSRCompareBPMQuantities(4): $result"
            }
        }
        foreach coord {x y} {
            if [catch {exec sddscombine $tmpFile.ss1.${coord}.oc $tmpFile.ss2.${coord}.oc -pipe=out \
                         | sddsprocess -pipe \
                         -print=para,Plane,${coord} \
                         -scan=column,${quantity}Value,ValueString,%le,units=mm \
                         | sddssort -pipe -column=ControlName -unique \
                         | sddsxref $apsSCRTopDirectory/miscInputs/BPMPositions.xref \
                         -pipe -match=BPMName -take=s -reuse=page,row -nowarning \
                         | sddssort -pipe -column=s,incr \
                         | sddschanges -pipe \
                         -copy=s,BPMName -changesIn=${quantity}Value \
                         | sddsprocess -pipe=in $tmpFile.${coord} \
                         "-define=column,Sector,s 27.6 / 1 +" \
                     } result] {
                APSDeleteTmpFileList -ID $tmpID
                return -code error "APSSCRSRCompareBPMQuantities(5): $result"
            }
        }
        if [catch {exec sddsconvert $tmpFile.x -pipe=out \
                     -rename=column,ChangeIn${quantity}Value=x${quantity}Delta \
                     | sddsprintout -pipe \
                     -para=Plane -column=BPMName \
                     -column=?${quantity}Delta "-title=$title" > $tmpFile.print 
            exec sddsconvert $tmpFile.y -pipe=out \
                     -rename=column,ChangeIn${quantity}Value=y${quantity}Delta \
                     | sddsprintout -pipe \
                     -para=Plane -column=BPMName \
                     -column=?${quantity}Delta "-title=$title" >> $tmpFile.print \
                 } result] {
            APSDeleteTmpFileList -ID $tmpID
            return -code error "APSSCRSRCompareBPMQuantities(6): $result"
        }

    } else {
        # take intersection of sets from snapshot1 and snapshot2
        if [catch {exec sddsselect $snapshot2 $tmpFile.ss1 -pipe=out -match=ControlName \
                     | sddsprocess -pipe=in $tmpFile.ss2 \
                     -edit=col,BPMName,ControlName,%/:x://%/:y://%/${quantity}// \
                 } result] {
            APSDeleteTmpFileList -ID $tmpID
            return -code error "APSSCRSRCompareBPMQuantities(7): $result"
        }
        if [catch {exec sddscombine $tmpFile.ss1 $tmpFile.ss2 -pipe=out \
                     | sddsprocess -pipe \
                     -scan=column,${quantity}Value,ValueString,%le,units=mm \
                     -edit=column,Plane,ControlName,2Z:1fD \
                     | sddssort -pipe -column=ControlName -unique \
                     | sddsxref $apsSCRTopDirectory/miscInputs/BPMPositions.xref \
                     -pipe -match=BPMName -take=s -reuse=page,row -nowarning \
                     | sddssort -pipe -column=Plane,incr -column=s,incr \
                     | sddschanges -pipe=in $tmpFile \
                     -copy=s,Plane,BPMName -changesIn=${quantity}Value \
                 } result] {
            APSDeleteTmpFileList -ID $tmpID
            return -code error "APSSCRSRCompareBPMQuantities(8): $result"
        }
        
        if [catch {exec sddsprocess $tmpFile $tmpFile.x -match=column,Plane=x  \
                     "-define=column,Sector,s 27.6 / 1 +"\
                 } result] {
            APSDeleteTmpFileList -ID $tmpID
            return -code error "APSSCRSRCompareBPMQuantities(9): $result"
        }
        if [catch {exec sddsprocess $tmpFile $tmpFile.y -match=column,Plane=y  \
                     "-define=column,Sector,s 27.6 / 1 +"\
                 } result] {
            APSDeleteTmpFileList -ID $tmpID
            return -code error "APSSCRSRCompareBPMQuantities(10): $result"
        }
        
        if [catch {exec sddsconvert $tmpFile.x -pipe=out \
                     -rename=column,ChangeIn${quantity}Value=x${quantity}Delta \
                     | sddsxref $tmpFile.y -pipe -take=* \
                     | sddsconvert -pipe -rename=column,ChangeIn${quantity}Value=y${quantity}Delta \
                     | tee $tmpFile.xy.exportable \
                     | sddsprintout -pipe=in $tmpFile.print \
                     -column=BPMName -column=?${quantity}Delta "-title=$title"\
                 } result] {
            APSDeleteTmpFileList -ID $tmpID
            return -code error "APSSCRSRCompareBPMQuantities(11): $result"
        }
    }

    if $fileDisplay {
        APSFileDisplayWindow [APSUniqueName .] \
          -comment "$title" -fileName $tmpFile.print -deleteOnClose 1 -width 80 \
          -contextHelp "$title" -sddsExportableFile $tmpFile.xy.exportable 
        update
    }

    if $plots {
        exec sddsplot -split=page -sep=page -title= -limit=ymax=500,ymin=-500,autoscaling \
          -column=Sector,ChangeIn${quantity}Value "-topline=x $title" \
          -graph=impulse,type=0 $tmpFile.x -legend=spec=Other \
          -column=Sector,ChangeIn${quantity}Value $tmpFile.x \
          -graph=impulse,type=1 -legend=spec=P1 -match=col,BPMName=*P1* \
          -column=Sector,ChangeIn${quantity}Value $tmpFile.x \
          -graph=impulse,type=2 -legend=spec=P3+P4 -match=col,BPMName=*P\[34\]* \
          -end \
          -column=Sector,ChangeIn${quantity}Value "-topline=y $title" \
          -graph=impulse,type=0  $tmpFile.y -legend=spec=Other \
          -column=Sector,ChangeIn${quantity}Value $tmpFile.y \
          -graph=impulse,type=1 -legend=spec=P1 -match=col,BPMName=*P1* \
          -column=Sector,ChangeIn${quantity}Value $tmpFile.y \
          -graph=impulse,type=2 -legend=spec=P3+P4 -match=col,BPMName=*P\[34\]* &
    }
    after 60000 "APSDeleteTmpFileList -ID $tmpID"
}

proc APSSCRXrayTranslationCompare {args} {
    set machine ""
    set snapshot1 ""
    set snapshot2 ""
    set mode ""
    APSStrictParseArguments {machine snapshot1 snapshot2 mode} 
    if {![string length $snapshot1] || ![string length $snapshot2] || \
          ![string length $machine] || ![string length $mode] } {
        return -code error "APSSCRXrayTranslationCompare: bad arguments"
    }
    set tmpfile /tmp/[APSTmpString]
    set tmpID [APSUniqueName tmpID]
    APSAddToTmpFileList -ID $tmpID -fileList \
      [list $tmpfile.snap1 $tmpfile.snap2 $tmpfile.change $tmpfile.print]
    APSAddToTmpFileList -ID semi-permanent -fileList $tmpfile.exportable
    switch $mode {
             1only {
            set controller(snap1) 1
            set controller(snap2) 1
        }
        2only {
            set controller(snap1) 2
            set controller(snap2) 2
        }
        1of1w2of2 {
            set controller(snap1) 1
            set controller(snap2) 2
        }
        2of1w1of2 {
            set controller(snap1) 2
            set controller(snap2) 1
        }
    }
    set title "Comparison of controller \#$controller(snap1) in [file tail $snapshot1] and controller \#$controller(snap2) in [file tail $snapshot2]"
    if [catch {exec sddsprocess $snapshot1 $tmpfile.snap1 \
                 -match=col,ControlName=SXDRV:$controller(snap1):* \
                 -edit=col,Rootname,ControlName,%/SXDRV:$controller(snap1)://
        exec sddsprocess $snapshot2 $tmpfile.snap2 \
                 -match=col,ControlName=SXDRV:$controller(snap2):* \
                 -edit=col,Rootname,ControlName,%/SXDRV:$controller(snap2)://
        
        exec sddscombine $tmpfile.snap1 $tmpfile.snap2 -pipe=out \
                 | sddsprocess -pipe \
                 -scan=column,Value,ValueString,%le,units=mm \
                 | sddssort -pipe -column=Rootname -unique \
                 | sddschanges -pipe=in $tmpfile.changes \
                 -copy=Rootname -changesIn=Value
        
        exec sddsconvert $tmpfile.changes -pipe=out \
                 -delete=col,ControlName \
                 -rename=column,ChangeInValue=Delta \
                 | sddsxref -pipe $tmpfile.snap1 \
                 -match=Rootname -take=ControlName,ValueString \
                 | sddsconvert -pipe \
                 -rename=col,ControlName=ControlNameSnap1 \
                 -rename=col,ValueString=ValueStringSnap1 \
                 | sddsxref -pipe $tmpfile.snap2 \
                 -match=Rootname -take=ControlName,ValueString \
                 | sddsconvert -pipe \
                 -rename=col,ControlName=ControlNameSnap2 \
                 -rename=col,ValueString=ValueStringSnap2 \
                 | sddsprocess -pipe \
                 -scan=col,ValueSnap1,ValueStringSnap1,%lf \
                 -scan=col,ValueSnap2,ValueStringSnap2,%lf \
                 | sddsprintout -pipe=in $tmpfile.print \
                  -formatDefaults=double=%12.6f \
                 -column=Rootname,format=%22s \
                 -column=(ValueSnap1,ValueSnap2,Delta) \
                 "-title=$title" \
             } result] {
        APSDeleteTmpFileList -ID $tmpID
        return -code error "$result"
    }
    
    APSFileDisplayWindow [APSUniqueName .] \
      -comment "$title" -fileName $tmpfile.print -deleteOnClose 1 -width 80 \
      -contextHelp "$title" -sddsExportableFile $tmpfile.exportable 
    return
}

#this procedures sets SR:TUNE:Mux4Sw2BO to NASA or VSA and
#SR:TUNE:Mux4MO in both mode
proc APSSetTuneMultiplexer {args} {
    set mode ""
    set sum 0
    APSStrictParseArguments {mode sum} 

    set mode [string toupper $mode]
    switch $mode {
        VSA {
            set drive VSA
        }
        NASA {
            set drive NASA
        }
        CAVITY {
            #set drive Cavity/VSA
            #set mode Cavity
            set drive VSA
            set mode1 "Cavity #1"
        }
        SUM {
            #set drive Cavity/VSA
            #set mode "S2 SUM"
            set drive VSA
            set mode1 "S4 Sum"
        }
        default {
            return -code error "Invalid mode given, should be either VSA or NASA"
        }
    }
    if [catch {exec cavget -list=SR:TUNE:Mux4Sw0BO -pend=10} origDrive] {
        return -code error "APSSetTuneMultiplexer0: Unable to read SR:TUNE:Mux4Sw0BO: $origDrive"
    }
    if [string compare $origDrive $drive] {
        if [catch {exec cavput -list=SR:TUNE:Mux4Sw0BO=$drive -pend=10} result] {
            return -code error "APSSetTuneMultiplexer: Unable to set SR:TUNE:Mux4Sw0BO: $result"
        }
    }
    switch $mode {
        NASA -
        VSA {
            if [catch {exec cavget -list=SR:TUNE:HP_1366A_C0P0_MBBO -pend=10} origMode] {
                return -code error "APSSetTuneMultiplexer(2): Unable to read  SR:TUNE:HP_1366A_C0P0_MBBO: $origMode"
            }
            if [string compare $mode $origMode] {
                if [catch {exec cavput -list=SR:TUNE:HP_1366A_C0P0_MBBO=$mode -pend=10} result] {
                    return -code error "APSSetTuneMultiplexer(2a): Unable to set  SR:TUNE:HP_1366A_C0P0_MBBO: $result"
                }
            }
        }
        CAVITY -
        SUM {
            #drive should be off for cavity/sum signal
            if [catch {exec cavget -list=SR:TUNE:HP_1366A_C0P1_MBBO -pend=30} origMode] {
                return -code error "APSSetTuneMultiplexer(3): $origMode"
            }
            if [string compare $origMode "OFF"]!=0 {
                if [catch {exec cavput -list=SR:TUNE:HP_1366A_C0P1_MBBO=OFF -pend=30} result] {
                    return -code error "APSSetTuneMultiplexer(4): unable to set SR:TUNE:HP_1366A_C0P1_MBBO to $mode: $result"
                }
            }
            #cavity sum mode
            if [catch {exec cavput "-list=SR:TUNE:HP_1366A_C2P1_MBBO=$mode1" } result] {
                return -code error "APSSetTuneMultiplexer(4): unable to set SR:TUNE:HP_1366A_C2P1_MBBO to $mode1: $result"
            }
        }
    }
}

proc APSSCRProcessXrayBPMSnapshot {args} {
    set inputFile ""
    set outputFile ""
    set bpmType ""
    set plane ""
    APSStrictParseArguments {inputFile outputFile bpmType plane} 
    if {![string length $inputFile]} {
        return -code error "APSSCRProcessXrayBPMSnapshot: input file is not provided!"
    }
    if {![string length $outputFile]} {
        return -code error "APSSCRProcessXrayBPMSnapshot: output filename is not provided!"
    }
    if ![string length $bpmType] {
        return -code error "APSSCRProcessXrayBPMSnapshot: Xray bpm type (ID or BM) is not provided!"
    }
    if ![string length $plane] {
        return -code error "APSSCRProcessXrayBPMSnapshot: Xray bpm plane (x or y) is not provided!"
    }
    set bpmType [string toupper $bpmType]
    set plane [string tolower $plane]
    if {$bpmType!="ID" && $bpmType!="BM"} {
        return -code error "APSSCRProcessXrayBPMSnapshot: invalid Xray bpm type, shoule be ID or BM"
    }
    if {$plane!= "x" && $plane !="y"} {
        return -code error "APSSCRProcessXrayBPMSnapshot: invalid Xray bpm plane, should be x or y"
    }
    if {$plane=="x" && $bpmType=="BM"} {
        return -code error "APSSCRProcessXrayBPMSnapshot: invalid plane input for BM xray, should be y only"
    }
    set tmpRoot /tmp/[APSTmpString]
    set fileList ""
    lappend fileList $tmpRoot
    if [catch {exec sddsprocess  $inputFile \
                 -match=col,IsNumerical=y \
                 -scan=col,Value,ValueString,%le -pipe=out \
                 | sddsconvert -pipe=in -retain=col,ControlName,Value $tmpRoot 
        exec sddsprocess $tmpRoot -pipe=out -match=col,ControlName=*${bpmType}* \
                 | sddstranspose -pipe=in ${tmpRoot}.$bpmType } result] {
        return -code error "APSSCRProcessXrayBPMSnapshot: $result"
    }
    lappend fileList ${tmpRoot}.$bpmType
    return -code error "APSSCRProcessXrayBPMSnapshot: The filters for xray bpms will have to be updated in the software. So we quit now."
    if [catch {exec sddscollect ${tmpRoot}.$bpmType -pipe=out \
                 -collect=suffix=:P1:msAve:${plane},column=${plane}bpm1 \
                 -collect=suffix=:P2:msAve:${plane},column=${plane}bpm2 \
                 | sddsprocess -pipe -scan=col,Sector,Rootname,S%ld,type=long \
                 | sddssort -pipe -col=Sector \
                 | sddsconvert -pipe=in -delete=col,Rootname ${tmpRoot}.bpm } result] {
        return -code error "APSSCRProcessXrayBPMSnapshot: $result"
    }
    lappend fileList ${tmpRoot}.bpm
    if {$bpmType=="ID"} {
        if [catch {exec sddscollect ${tmpRoot}.$bpmType -pipe=out \
                       -collect=suffix=:Gap,column=gap \
                       | sddsprocess -pipe=in ${tmpRoot}.gap \
                       -scan=col,Sector,Rootname,ID%2d,type=long
            exec sddsprocess ${tmpRoot}.gap -match=col,Rootname=*us* -pipe=out -nowarnings \
                       | sddsconvert -pipe=in ${tmpRoot}.us -rename=col,gap=USgap
            exec sddsprocess ${tmpRoot}.gap "-match=col,Rootname=*us*,!" -pipe=out \
                       -reedit=col,Rootname,%/ds// \
                       | sddsxref -pipe=in ${tmpRoot}.us ${tmpRoot}.gap1a -equate=Sector \
                       -fillin -take=USgap -nowarnings 
            exec sddsselect $tmpRoot.us $tmpRoot.gap1a -invert -equate=Sector -pipe=out \
                       | sddsprocess -pipe=in $tmpRoot.gap2 -define=col,gap,0.0 -nowarnings
            exec sddscombine $tmpRoot.gap1a $tmpRoot.gap2 -merge -pipe=out \
                       | sddssort -pipe=in -col=Rootname $tmpRoot.gap1 \
                   } result] {
            return -code error "APSSCRProcessXrayBPMSnapshot: $result"
        }
        lappend fileList "${tmpRoot}.gap ${tmpRoot}.us ${tmpRoot}.gap1 $tmpRoot.gap1a $tmpRoot.gap2"
    }
    foreach set {1 2} {
        if [catch {exec sddsconvert ${tmpRoot}.$bpmType -retain=col,*:P${set}:*:AI -pipe=out \
                     | sddscollect -pipe -collect=suffix=:AI,column=blade${set} \
                     | sddsprocess -pipe -scan=col,Sector,Rootname,S%ld,type=long \
                     | sddssort -pipe -col=Sector \
                     | sddsbreak -pipe -changeof=Sector \
                     | sddsprocess -pipe -process=blade${set},max,maxV${set} \
                     -process=Sector,first,Sector \
                     | sddsconvert -pipe -retain=par,Sector,max* \
                     | sddscollapse -pipe \
                     | sddscast -pipe=in ${tmpRoot}.blade${set} \
                     -cast=col,Sector,double,long } result] {
            return -code error "APSSCRProcessXrayBPMSnapshot: $result"
        }
        lappend fileList ${tmpRoot}.blade${set}
    }
    if {$bpmType=="ID"} {
        if [catch {exec sddsxref ${tmpRoot}.bpm ${tmpRoot}.gap1 ${tmpRoot}.bpmgap \
                     -equate=Sector -take=Rootname,gap,USgap -nowarnings } result] {
            return -code error "APSSCRProcessXrayBPMSnapshot: $result"
        }
        lappend fileList ${tmpRoot}.bpmgap
        set firstFile ${tmpRoot}.bpmgap
    } else {
        set firstFile ${tmpRoot}.bpm
    }
    if [catch {eval exec sddsxref ${tmpRoot}.blade1 ${tmpRoot}.blade2 ${tmpRoot}.blade \
                 -equate=Sector -take=maxV2 -nowarnings
        eval exec sddsxref $firstFile ${tmpRoot}.blade -pipe=out -equate=Sector \
                 -take=maxV1,maxV2 \
                 -nowarnings \
                 | sddsprocess -pipe \
                 -reprint=col,Rootname,${bpmType}%.2d,Sector \
                 | sddssort -pipe=in -col=Rootname $outputFile } result] {
        return -code error "APSSCRProcessXrayBPMSnapshot: $result"
    }
    lappend fileList ${tmpRoot}.blade
    APSAddToTmpFileList -ID processXraySnapshot -fileList $fileList
}

proc APSSRXrayBPMCustomCompare {args} {
    global apsSCRRequestDir
    set machine ""
    set snapshot1 ""
    set snapshot2 ""
    set snap1Label ""
    set snap2Label ""
    set Value1Label ""
    set Value2Label ""
    set DifferenceLabel ""
    set posDiffTolerance 0.1
    set gapDiffTolerance 0.1
    #minVoltage is the minimum acceptable blade voltage
    set minVoltage 0.01
    set bpmType ""
    set plane x
    set gapcompare 0
    set bladescompare 0
    set type Rate
    set group a
    if {[APSStrictParseArguments {machine snapshot1 snapshot2 snap1Label snap2Label DifferenceLabel \
                                    posDiffTolerance  gapDiffTolerance minVoltage \
                                    bpmType plane gapcompare \
                                    Value1Label Value2Label bladescompare type group\
                                } ]==-1} {
        return -code error "Bad arguments to APSSRXrayBPMCustomCompare"
    } 
    if {![string length $bpmType] || ![string length $plane] } {
        return -code error "APSSRXrayBPMCustomCompare: bpmType or plane is not given"
    }
    if {![file exist $snapshot1] || ![file exist $snapshot2] } {
        return -code error "APSSRXrayBPMCustomCompare: snapshot files do not exist!"
    }
    if ![string length $Value1Label] {set Value1Label dataset1}
    if ![string length $Value2Label] {set Value2Label dataset2}
    if ![string length $DifferenceLabel] {set DifferenceLabel data1-data2}
    if ![string length $snap1Label] {set snap1Label $snapshot1}
    if ![string length $snap2Label] {set snap2Label $snapshot2}
    if $gapcompare {
        set tmpfile /tmp/[APSTmpString].snap1
        if [catch {exec sddsprocess $snapshot1 $tmpfile \
                     "-match=col,ControlName=*ID*:Gap" } result] {
            return -code error "APSSRXrayBPMCustomCompare: Snapshot1 does not have ID gap readback bpms!"
        }
        if [catch {APSCompareMachine -machine SRXrayBPM -snapshot1 $tmpfile \
                     -snap1Label $snapshot1 \
                     -snapshot2 $snapshot2 -graphics 1} result] {
            return -code error "Error doing ID gap readbacks compare: $result"
        }
    } elseif $bladescompare  {
        set option ""
        switch $group {
            a {
                set option "-filter=col,DefaultA,0.5,1.5"
            }
            b {
                set option "-filter=col,DefaultB,0.5,1.5"
            }
        }
        set tmpRoot /tmp/[APSTmpString]
        if [catch {exec sddsprocess /home/helios/oagData/sr/IDs/devices.sdds -pipe=out $option \
                 | sdds2stream -pipe -col=DeviceName } IDList] {
            return -code error "error in getting devicenames: $IDList"
        }
        set option ""
        foreach id $IDList {
            set sector [scan $id ID%ld]
            if ![string length $option] {
                append option  -match=col,ControlName=S${sector}ID*${type}P
            } else {
                append option ,ControlName=S${sector}ID*${type}P,|
            }
        }
        if [catch {exec sddsprocess $snapshot1 $tmpRoot.1 "$option"
            exec sddsprocess $snapshot2 $tmpRoot.2 "$option"  } result] {
            return -code error "APSSRXrayBPMCustomCompare: Snapshots does not have ID blade rate or offsets: $result!"
        }
        if [catch {APSCompareMachine -machine SRXrayBPM -snapshot1 $tmpRoot.1 \
                     -snap1Label $snapshot1 \
                     -snapshot2 $tmpRoot.2  -graphics 1} result] {
            return -code error "Error doing ID gap readbacks compare: $result"
        }

    } else {
        set tmpRoot /tmp/[APSTmpString]
        set proc1 ${tmpRoot}.proc1
        set proc2 ${tmpRoot}.proc2
        APSAddToTmpFileList -ID compareXrayBPM -fileList "$proc1 $proc2"
        if [catch {APSSCRProcessXrayBPMSnapshot -inputFile $snapshot1 -outputFile $proc1 -bpmType $bpmType \
                     -plane $plane} result] {
            return -code error "APSSRXrayBPMCustomCompare: $result"
        }
        if [catch {APSSCRProcessXrayBPMSnapshot -inputFile $snapshot2 -outputFile $proc2 -bpmType $bpmType \
                     -plane $plane} result] {
            return -code error "APSSRXrayBPMCustomCompare: $result"
        }
        APSAddToTmpFileList -ID compareXrayBPM -fileList ${tmpRoot}.new
        if [catch {exec sddsconvert $proc2 ${tmpRoot}.new  \
                     -edit=col,*bpm*,ei/New/ \
                     -edit=col,gap,ei/New/ \
                     -edit=col,USgap,ei/New/ \
                     -edit=col,max*,ei/New/ \
                 } result ] {
            return -code error "APSSRXrayBPMCustomCompare: $result"
        }
        set resultsFile ${tmpRoot}.result
        APSAddToTmpFileList -ID compareXrayBPM -fileList "$resultsFile $resultsFile.help"
        if [catch {exec sddsxref $proc1 ${tmpRoot}.new -pipe=out -nowarning \
                     -match=Rootname -take=* \
                     | sddsprocess -pipe  \
                     "-def=col,%sDiff,%sNew %s -,select=*New,edit=%/New//,units=mm" \
                     | sddsprocess -pipe=in  $resultsFile \
                     "-def=col,%sAbs,%s abs,select=*Diff,units=mm" \
                 } result ] {
            return -code error "APSSRXrayBPMCustomCompare: $result"
        }
        if ![string compare $bpmType "ID"] {
            if [catch {exec sddsprocess $resultsFile $resultsFile.help -nowarning \
                         -filter=col,gapDiffAbs,0,$gapDiffTolerance \
                         -filter=col,USgapDiffAbs,0,$gapDiffTolerance \
                         "-def=col,minmaxV1,maxV1New maxV1 min2,units=V" \
                         "-def=col,minmaxV2,maxV2New maxV2 min2,units=V"} result] {
                return -code error "APSSRXrayBPMCustomCompare: $result"
            }
            set rows [exec sdds2stream $resultsFile.help -rows=bare]
            #	puts $rows
            if !$rows {
                return -code error "APSSRXrayBPMCustomCompare: all gap differences are bigger than $gapDiffTolerance (tolerance)"
            }              
        } else {
            APSAddToTmpFileList -ID compareXrayBPM -fileList "$resultsFile $resultsFile.help"
            if [catch {exec sddsprocess $resultsFile $resultsFile.help -nowarning \
                         "-def=col,minmaxV1,maxV1New maxV1 min2,units=V" \
                         "-def=col,minmaxV2,maxV2New maxV2 min2,units=V" \
                     } result ] {
                return -code error "CompareData: $result"
            }
        }
        if [catch {eval APSSCRPrintXrayBPMCompTable -resultsFile $resultsFile.help \
                     -snap1Label \"$snap1Label\" -snap2Label \"$snap2Label\" -DifferenceLabel \"$DifferenceLabel\" \
                     -Value1Label \"$Value1Label\" -Value2Label \"$Value2Label\" \
                     -posDiffTolerance $posDiffTolerance -minVoltage $minVoltage \
                     -bpmType $bpmType -plane $plane} status] {
            return -code error "APSSRXrayBPMCustomCompare: $status"
        }
        return $status
    }
    
}

proc APSSCRPrintXrayBPMCompTable {args} {
    set posDiffTolerance 0.1
    #minVoltage is the minimum acceptable blade voltage
    set minVoltage 0.01
    set resultsFile ""
    set DifferenceLabel ""
    set snap2Label ""
    set snap1Label ""
    set Value1Label ""
    set Value2Label ""
    set gapcompare 0
    set bpmType ""
    set plane ""
    if {[APSStrictParseArguments { resultsFile posDiffTolerance minVoltage \
                                     gapcompare snap1Label snap2Label Value1Label Value2Label \
                                     DifferenceLabel bpmType plane} ]==-1} {
        return -code error "Bad arguments to APSSCRPrintXrayBPMCompTable"
    }
    set good ""
    set questionable  "lowV"
    set mergeFiles ""
    set tmpRoot /tmp/[APSTmpString]
    set tmpfileList ""
    if [catch {exec sddsprocess $resultsFile ${tmpRoot}.print1 \
                 -filter=column,minmaxV1,0,$minVoltage,! \
                 -filter=column,minmaxV2,0,$minVoltage,! \
                 "-print=parameter,Title,Comparison of\n$snap1Label\n to \n$snap2Label\n \
               (minimal acceptable voltage $minVoltage V \n minimal acceptable position difference $posDiffTolerance mm)" \
                 -print=column,State1,$good -print=column,State2,$good -noWarning} result] {
        return -code error "APSSCRPrintXrayBPMCompTable: $result"
    } 
    set rows1 [exec sdds2stream ${tmpRoot}.print1 -rows=bare]
    if [catch {exec sddsprocess $resultsFile  ${tmpRoot}.print2 \
                 -filter=column,minmaxV1,0,$minVoltage \
                 -filter=column,minmaxV2,0,$minVoltage,! \
                 "-print=parameter,Title,Comparison of\n$snap1Label\n to \n$snap2Label\n \
               (minimal acceptable voltage $minVoltage V \n minimal acceptable position difference $posDiffTolerance mm)" \
                 -print=column,State1,$questionable -print=column,State2,$good -noWarning} result] {
        return -code error "APSSCRPrintXrayBPMCompTable: $result"
    }   
    set rows2 [exec sdds2stream ${tmpRoot}.print2 -rows=bare]
    
    if [catch {exec sddsprocess $resultsFile  ${tmpRoot}.print3 \
                 -filter=column,minmaxV1,0,$minVoltage,! \
                 -filter=column,minmaxV2,0,$minVoltage \
                 "-print=parameter,Title,Comparison of\n$snap1Label\n to \n$snap2Label\n \
               (minimal acceptable voltage $minVoltage V)" \
                 -print=column,State1,$good -print=column,State2,$questionable  -noWarning} result] {
        return -code error "APSSCRPrintXrayBPMCompTable: $result" 
    }
    set rows3 [exec sdds2stream ${tmpRoot}.print3 -rows=bare]
  
    if [catch {exec sddsprocess $resultsFile  ${tmpRoot}.print4 \
                 -filter=column,minmaxV1,0,$minVoltage \
                 -filter=column,minmaxV2,0,$minVoltage \
                 "-print=parameter,Title,Comparison of\n$snap1Label\n to \n$snap2Label\n \
               (minimal acceptable voltage $minVoltage V)" \
                 -print=column,State1,$questionable -print=column,State2,$questionable  -noWarning} result] {
        return -code error "APSSCRPrintXrayBPMCompTable: $result"  
    }  
    set rows4 [exec sdds2stream ${tmpRoot}.print4 -rows=bare]
    
    
    if {$rows1 > 0} {lappend mergedFiles ${tmpRoot}.print1}        
    if {$rows2 > 0} {lappend mergedFiles ${tmpRoot}.print2}
    if {$rows3 > 0} {lappend mergedFiles ${tmpRoot}.print3}
    if {$rows4 > 0} {lappend mergedFiles ${tmpRoot}.print4}
    
    APSAddToTmpFileList -ID compareXrayBPM -fileList $mergedFiles
    APSAddToTmpFileList -ID compareXrayBPM -fileList ${tmpRoot}.1
    catch {eval exec sddscombine $mergedFiles ${tmpRoot}.1 -merge -overWrite}
    if {$bpmType=="ID"} {
       # set gapThreshold 185
        foreach bpm {1 2} {
            if [catch {exec sddsconvert ${tmpRoot}.1 $tmpRoot.${plane}$bpm \
                         -retain=col,Rootname,gap,USgap,${plane}bpm${bpm}*,State${bpm}
                exec sddsprocess $tmpRoot.${plane}$bpm $tmpRoot.bad${plane}$bpm -noWarnings \
                           "-filter=col,${plane}bpm${bpm}Diff,-$posDiffTolerance,$posDiffTolerance,!" \
                         "-reprint=col,State$bpm,%s bad,State${bpm}" 
                exec sddsselect $tmpRoot.${plane}$bpm $tmpRoot.bad${plane}$bpm -match=Rootname \
                           -invert -nowarnings -pipe=out\
                         | sddsconvert -pipe=in $tmpRoot.good${plane}$bpm -rename=col,State=State$bpm
                exec sddscombine $tmpRoot.good${plane}$bpm $tmpRoot.bad${plane}$bpm -merge -pipe=out \
                         | sddssort -pipe=in -col=Rootname ${tmpRoot}.bpm$bpm } result] {
                return -code error "PrintCompareTable: $result"
            }
        }
        if [catch {exec sddsxref ${tmpRoot}.bpm1 ${tmpRoot}.bpm2 -match=Rootname \
                     -take=${plane}bpm2*,State2 ${tmpRoot}.${plane} } result] {
            return -code error "PrintCompareTable: $result"
        }
    } else {
        if {$plane!="y"} {
            return -code error "PrintCompareTable: invalid plane given for compare BM BPMs (has to be y)" 
        }
        foreach bpm {1 2} {
            if [catch {exec sddsconvert ${tmpRoot}.1 $tmpRoot.y$bpm \
                         -retain=col,Rootname,ybpm${bpm}*,State${bpm}
                exec sddsprocess $tmpRoot.y$bpm $tmpRoot.bady$bpm -noWarnings \
                         "-filter=col,ybpm${bpm}Diff,-$posDiffTolerance,$posDiffTolerance,!" \
                         "-reprint=col,State$bpm,%s bad,State${bpm}" 
                exec sddsselect $tmpRoot.y$bpm $tmpRoot.bady$bpm -match=Rootname \
                         -invert -nowarnings -pipe=out  \
                         | sddsconvert -pipe=in $tmpRoot.goody$bpm -rename=col,State=State$bpm
                exec sddscombine $tmpRoot.goody$bpm $tmpRoot.bady$bpm -merge -pipe=out \
                         | sddsprocess -pipe -noWarnings \
                         | sddssort -pipe=in -col=Rootname ${tmpRoot}.bpm$bpm } result] {
                return -code error "PrintCompareTable: $result"
            }
        }
        if [catch {exec sddsxref ${tmpRoot}.bpm1 ${tmpRoot}.bpm2 -match=Rootname \
                     -take=ybpm2*,State2 ${tmpRoot}.y } result] {
            return -code error "PrintCompareTable: $result"
        }
    }
    APSAddToTmpFileList -ID compareXrayBPM -fileList "${tmpRoot}.${plane}1 ${tmpRoot}.${plane}2 ${tmpRoot}.bad${plane}1 ${tmpRoot}.bad${plane}2 ${tmpRoot}.good${plane}1 ${tmpRoot}.good${plane}2 ${tmpRoot}.$plane ${tmpRoot}.bpm1 ${tmpRoot}.bpm2"
    set title [exec sdds2stream ${tmpRoot}.$plane -par=Title]
    switch $bpmType {
        ID {
            set dlina 105
            set title "$title\n\n                           --------------P1 ${plane}--------------------     -------------P2 ${plane}---------------------\n"
            exec sddsprintout ${tmpRoot}.${plane} ${tmpRoot}.printout "-title=$title" \
              -col=Rootname,label=ID,format=%6s \
              -col=gap,format=%6.2f,label=ds:gap \
              -col=USgap,format=%6.2f,label=us:gap \
              -col=${plane}bpm1,label=$Value1Label,format=%7.3f \
              -col=${plane}bpm1New,label=$Value2Label,format=%7.3f \
              "-col=${plane}bpm1Diff,label=$DifferenceLabel,format=%7.3f" \
              -col=State1,label=State,format=%8s \
              -col=${plane}bpm2,label=$Value1Label,format=%7.3f \
              -col=${plane}bpm2New,label=$Value2Label,format=%7.3f \
              "-col=${plane}bpm2Diff,label=$DifferenceLabel,format=%7.3f" \
              -col=State2,label=State,format=%8s
        }
        BM {    
            set dlina 75
            set title "$title\n\n         -----------------P1 ${plane}-----------------   -----------P2 ${plane}-----------------------\n"
            exec sddsprintout ${tmpRoot}.y ${tmpRoot}.printout "-title=$title" \
              -col=Rootname,label=BM,format=%6s \
              -col=ybpm1,label=$Value1Label,format=%7.3f \
              -col=ybpm1New,label=$Value2Label,format=%7.3f \
              "-col=ybpm1Diff,label=$DifferenceLabel,format=%7.3f" \
              -col=State1,label=State,format=%8s \
              -col=ybpm2,label=$Value1Label,format=%7.3f \
              -col=ybpm2New,label=$Value2Label,format=%7.3f \
              "-col=ybpm2Diff,label=$DifferenceLabel,format=%7.3f" \
              -col=State2,label=State,format=%8s
        }
    }
    APSFileDisplayWindow [APSUniqueName .] -fileName ${tmpRoot}.printout \
      -deleteOnClose 1 -width 110 -height 45 -printCommand "enscript -r"
    return $tmpRoot
}

proc APSSRPlotSCRBPMData {args} {
    set field OffsetAO
    set machine ""
    set snapshot ""
    APSStrictParseArguments {field machine snapshot}
    global SCRdebug apsSCRTopDirectory
    
    if {![string length $field] || ![string length $machine] || ![string length $snapshot]} {
        return -code error "APSSRPlotControlNameData: bad arguments"
    }

    set title "$field values from [file tail [file rootname $snapshot]]"
    set tmpRoot /tmp/[APSTmpString]
    set tmpID [APSUniqueName tmpID]
    APSAddToTmpFileList -ID $tmpID \
      -fileList [list $tmpRoot.x $tmpRoot.y $tmpRoot.print $tmpRoot.xy]

    foreach plane {x y} {
        if [catch {exec sddsprocess $snapshot -pipe=out -nowarning \
                     -match=column,ControlName=*$plane:$field \
                     -edit=column,BPMName,ControlName,%/$plane:$field// \
                     -scan=column,$plane:$field,ValueString,%le,type=double,units=mm \
                     | sddssort -pipe=in $tmpRoot.$plane -numericHigh -column=BPMName } result] {
            return -code error "APSSRPlotSCRBPMData: $result"
        }
    }
    if [catch {exec sddsxref $tmpRoot.x $tmpRoot.y -pipe=out -nowarning \
                 -take=* -match=BPMName -fillIn \
                 | tee $tmpRoot.xy  \
                 | sddsprintout -pipe=in $tmpRoot.print \
                 -column=BPMName -column=x:$field -column=y:$field} result] {
        return -code error "APSSRPlotSCRBPMData: $result"
    }

    exec sddsplot -layout=1,2 $tmpRoot.xy -graph=impulse -sep \
      -column=BPMName,x:$field -column=BPMName,y:$field & 
    APSFileDisplayWindow [APSUniqueName .] \
      -comment "$title" -fileName $tmpRoot.print -deleteOnClose 1 -width 80 \
      -contextHelp "$title" -sddsExportableFile $tmpRoot.xy
}


