
proc APSMpBTSMatrixInfo {} {
    return "This procedure measures the BTS response matrix in the horizontal and vertical planes, calculates the inverse matrix, and gives the user a choice to install this inverse matrix as the matrix for the BTS controllaw."
}

proc APSMpBTSMatrix {args} {
    global status

    APSStrictParseArguments {}

# the final result (.def and inverse matrix file) go in the resultsDir,
# i.e. the instalDir argument of the procedures.  The temporary results go
# the dataDir.
    set resultsDir /home/helios/oagData/bts/measurements/response/
    set dataDir $resultsDir/rawMeasurements
    set installName BTS.matrix
    set beamline BTS
    # sequence of elements for causality.
    # use /home/helios/oagData/ADTFiles/bts/bts.lat at some point?
    set beamlineFile $resultsDir/${beamline}.beamline
    # full {x,y} versus {xp,yp} matrix
    set matrix R13.24
    set templateFile $dataDir/${beamline}:template.exp
    set actuatorList {}
    # default for filterColumns in procedure formMatrix is "*:*P*"
    # may need to remove
    set filterColumns "$beamline:\[ABCD\]P*"
    set excludeColumns ""

    cd $dataDir

    # Setting up experiment parameters
    set halfRange 4.0
    set points 5
    set postChange 2.5
    set intermeasurement 1.0
    set average 5
    set checkResults 0
    set promptExperiments 1
    set useSeptum Both
    set useCorrectors 1

    APSMpStep init -promptDialog APSMpBTSMatrixInitDialog -vars {halfRange points postChange intermeasurement average checkResults filterColumns promptExperiments useSeptum useCorrectors excludeColumns}
        
    foreach param "halfRange points postChange intermeasurement average checkResults filterColumns promptExperiments useSeptum useCorrectors excludeColumns" {
        append paramString "$param=\"[set $param]\" "
    }
    if {[catch {APSLogScriptAction \
		    -procedure APSMpBTSMatrix \
		    -action initialize \
		    -state ok \
		    -parameters $paramString} results]} {
#	APSMpReturn error "APSMpBTSMatrix: $results"
    }

    switch $useSeptum {
        Both {set actuatorList "B:ES1 B:ES2"}
        ES1 {set actuatorList B:ES1}
        ES2 {set actuatorList B:ES2}
        None {}
        default {set actuatorList B:ES2}
    }
    if $useCorrectors {
        set hcorrList {AH1 AH2 AH3 BH1 BH2 BSQ1H BSQ5H CQ1H CQ3H DQ1H}
        set vcorrList {AV1 AV2 AV3 BV1 BV2 BSQ2V BSQ6V BV3  CQ2V DQ2V}
        set corrList [concat $hcorrList $vcorrList]
        eval lappend actuatorList [APSAffix $corrList -prefix ${beamline}:]
    }
    if ![llength $actuatorList] {
        APSMpReturn error "No actuators chosen"
    }

# this procedure establishes some default variables and arrays for parameters.
    set parameterList {PV halfRange points postChange intermeasurement average}
    APSMpRespMatrixSetParameterDefaults \
        -parameterList $parameterList \
        -halfRange $halfRange \
        -points $points \
        -postChange $postChange \
        -intermeasurement $intermeasurement \
        -average $average
    foreach actuator $actuatorList {
        switch -regexp $actuator {
            {B:ES[12]} { APSMpRespMatrixSetActuatorParameters \
                             -actuator $actuator \
                             -PV ${actuator}:VoltageSetSendAO \
                             -halfRange 5
            }
            # Before 4/9/2024 we didn't have aliases for the BTS:[AB] correctors.
            #            {BTS:[AB][HV][123]} { APSMpRespMatrixSetActuatorParameters \
                #                                      -actuator $actuator \
                #                                      -PV ${actuator}:CurrentAO 
            #            }
            default { APSMpRespMatrixSetActuatorParameters \
                             -actuator $actuator \
                             -PV ${actuator}:PS:SetCurrentC
            }
        }
    }
    set badActuators ""
    set badBpms ""

    # put pre-execution commands here
    # such as reseting the time-outs for the pulsed magnets.
    APSMpStep PreExecutionCommands -desc "Do pre-execution commands, such as reseting the time-outs for the pulsed magnets, or suspending controllaws."
    set rcList {BTS:ControlLawXRC}
    # presumably controllaw mode is not suspended, but "resume".
    if [catch {exec cavget -list=[join $rcList ,] -list=.SUSP -cavputForm} \
          controllawMode] {
        APSMpReturn error "APSMpBTSMatrix: Problem getting BTS controllaw status: $controllawMode"
        return
    }
    if [catch {exec cavput -list=[join $rcList ,] \
                 -list=.SUSP=1} result] {
        APSMpReturn error "APSMpBTSMatrix: Problem suspending BTS controllaws: $result"
    }

    if [catch {APSMpBES2Feedforward -action stop; after 1000; \
                 APSMpBES2Feedforward -action start \
             } result] {
        APSMpReturn error "APSMpBTSMatrix: Problem stopping and restarting BES2 feedforwar: $result"
    }

    # take data
    APSMpStep SDDSExperimentCommands -desc "Take data"
    # send a list of one actuator at a time so that the data can be reviewed
    # and restarted at every step

    set actuatorList1 ""
    foreach actuator $actuatorList {
        if [file exists $actuator.sdds] {
            exec mv $actuator.sdds $actuator.sdds~
        }
        if {!$promptExperiments || [APSYesNoPopUp "Do experiment on $actuator"]} {
            APSMpRespMatrixDoExperiment -actuatorList $actuator -templateFile $templateFile
            catch {eval file delete [glob *~]}
            if $checkResults {
                eval exec sddsplot -col=$actuator,(*) $actuator.sdds \
                  -grap=sym,conn,sca=3 -sep &
                while {[APSYesNoPopUp "Retake data? (wait for plot to appear)"]} {
                    APSMpRespMatrixSetActuatorParametersByDialog .dialog -actuator $actuator
                    APSMpRespMatrixDoExperiment -actuatorList $actuator \
                      -templateFile $templateFile
                    eval exec sddsplot -col=$actuator,(*) $actuator.sdds \
                      -grap=sym,conn,sca=3 -sep &
                }
            }
            lappend actuatorList1 $actuator
        }
    }
    set actuatorList $actuatorList1

    # put post-execution commands here
    APSMpStep PostExecutionCommands -desc "Do post-execution commands"
    if {[catch {exec cavput -list=$controllawMode} result]} {
        APSMpReturn error "APSMpBTSMatrix: Problem setting BTS controllaw mode: $result"
    }

    APSMpStep CombiningResults -desc "Combine results"
    if ![length $actuatorList] {
        APSMpReturn error "APSMpBTSMatrix: All actuators skipped. No results collected. Exiting"
    }
    set fileList [eval glob [APSAffix $actuatorList -suffix .def]]
    catch {eval exec sddscombine $fileList -pipe=output -merge -overWrite \
             | sddssort -pipe=input ${beamline}.def -col=ControlName  -unique}
    catch {eval file delete $fileList}
    
    APSMpStep CalculatingSlopes -desc "Calculate slopes" -proc "APSMpRespMatrixCalcSlopes"
    APSMpRespMatrixCalcSlopes -actuatorList $actuatorList 

    APSMpStep FormingMatrix -desc "Form matrix" -proc "APSMpRespMatrixFormMatrix"
    # I forgot that the beamline file is a sequence of bpm and correctors
    # to enforce causility.
    APSMpRespMatrixFormMatrix -actuatorList $actuatorList -badBpms $badBpms -badActuators $badActuators \
      -outFile ${beamline}.${matrix} -beamlineFile $beamlineFile -filterColumns $filterColumns \
      -excludeColumns $excludeColumns

    APSMpStep CalculatingInverse -desc "Calculate inverse" -proc "APSMpRespMatrixCalcInverse"
    APSMpRespMatrixCalcInverse -inFile ${beamline}.${matrix} -outFile ${beamline}.Inv${matrix} -minimum 0.1

    APSMpStep InstallMatrix -desc "Install matrix" -proc "APSMpRespMatrixInstallDialog"

    APSMpRespMatrixInstallDialog .install -fileName ${beamline}.Inv${matrix} \
      -installName $installName -installDir $resultsDir

    APSMpReturn ok
}


# Note: by convention, this procedure has only one argument. It provides the
#    parent frame into which you should pack all widgets.
proc    APSMpBTSMatrixInitDialog {frame} {
  # Note: this dialog procedure has access only to those variables explicitly
  #    passed in via the -vars option of APSMpStep. You can access them here
  #    as elements of the following global array (which always has the same
  #    name as the machine procedure itself.
  global APSMpBTSMatrix
  label $frame.label -text "Enter default values for sddsexperiment"
  pack $frame.label
  APSLabeledEntry .le1 -parent $frame -label "half range" -textVariable \
    APSMpBTSMatrix(halfRange)
  APSLabeledEntry .le2 -parent $frame -label "no. points" -textVariable \
    APSMpBTSMatrix(points)
  APSLabeledEntry .le3 -parent $frame -label "post change pause" -textVariable \
    APSMpBTSMatrix(postChange)
  APSLabeledEntry .le4a -parent $frame -label "filter for bpm names" -textVariable \
    APSMpBTSMatrix(filterColumns)
  APSLabeledEntry .le4c -parent $frame -label "bpm names to exclude" -textVariable \
    APSMpBTSMatrix(excludeColumns)
  APSLabeledEntry .le4b -parent $frame -label "intermeasurement pause" -textVariable \
    APSMpBTSMatrix(intermeasurement)
  APSLabeledEntry .le5 -parent $frame -label "no. average" -textVariable \
    APSMpBTSMatrix(average)
  APSRadioButtonFrame .rb6 -parent $frame -label "Prompt for each experiment?" \
    -variable APSMpBTSMatrix(promptExperiments) -buttonList {Yes No} -valueList {1 0} \
    -orientation horizontal 
  APSRadioButtonFrame .rb7 -parent $frame -label "Check results?" -variable \
    APSMpBTSMatrix(checkResults) -buttonList {Yes No} -valueList {1 0} \
    -orientation horizontal 
  APSRadioButtonFrame .rb8 -parent $frame -label "Use correctors: " -variable \
    APSMpBTSMatrix(useCorrectors) -buttonList {Yes No} -valueList {1 0} \
    -orientation horizontal
  APSRadioButtonFrame .rb1 -parent $frame -label "Use septum: " -variable \
    APSMpBTSMatrix(useSeptum) -buttonList {ES1 ES2 Both None} \
    -valueList {ES1 ES2 Both None} -orientation horizontal 
}
