proc APSSetMainStatus {text} {
    global mainStatus
    set mainStatus $text
    update 
}

proc APSAffix {list args} {
    set prefix ""
    set suffix ""
    APSStrictParseArguments {prefix suffix}
    set result ""
    foreach item $list {
	lappend result ${prefix}${item}${suffix}
    }
    return  $result
}

proc APSOptimizeMakeDailyLogs {args} {
    set member ""
    APSParseArguments {member}
    global env using HomeDir directory optDir expert
    set homedir /home/helios/[string toupper $env(USER)]
    if !$expert {
	if [info exist using($member)] {
	    set optDir($member) $HomeDir/$directory($member)/$using($member)
	} else {
	    set optDir($member) $HomeDir/$directory($member)/
	}
	return
    }
    if ![file exist $homedir/optimizationExpertData] {
	exec mkdir $homedir/optimizationExpertData
    }
    set datestring [clock format [clock seconds] -format %Y-%m%d]
    set dir $homedir/optimizationExpertData/$datestring
    if ![file exist $dir] {
	exec mkdir $dir
    }
    if ![file exist $dir/$member] {
	exec mkdir $dir/$member
    }
    set logDir $dir/$member
    set refDir $HomeDir/$directory($member)
    if [info exist using($member)] {
	catch {exec mkdir $dir/$member/$using($member)}
	set logDir $dir/$member/$using($member)
	set refDir $HomeDir/$directory($member)/$using($member)
    }
    if [regexp {rg} $member] {
	foreach file {L3CM1observables L1CM2observables ParRegion8observables variables variables.all tests parameters constraints} {
	    if ![file exist $logDir/$file] {
		catch {exec cp $refDir/$file $logDir/$file}
	    }
	}
    } else {
	foreach file {variables observables tests parameters constraints} {
	    if ![file exist $logDir/$file] {
		catch {exec cp $refDir/$file $logDir/$file}
	    }
	}
    }
    set optDir($member) $logDir
}
proc APSOptimizeMakeWidgetGroup {widget args} {
    global groupDef HomeDir using
    global groupTitle
    global created dryRun optDir expert
    
    APSStrictParseArguments {parent group}
    
    set w $parent$widget
    if $dryRun {
	APSSetMainStatus "Doing frames for $groupTitle($group)... (dryRun mode: testing script)"
    } else {
	APSSetMainStatus "Doing frames for $groupTitle($group)..."
    }
    
    APSFrame $widget -parent $parent -label $groupTitle($group) \
      -contextHelp "Frame for controllaw script group $groupTitle($group)" 
    $w.frame configure -relief flat
    APSOptimizeMakeFullWidgetGroup .full -parent $w.frame -group $group
    APSUnmap $w.frame.full
    APSOptimizeMakeBriefWidgetGroup .brief -parent $w.frame -group $group
    
    set created($w) 1
}

proc APSOptimizeMakeBriefWidgetGroup {widget args} {
    global groupDef
    global groupTitle
    global created

    APSStrictParseArguments {parent group}

    set w $parent$widget
    set members $w.frame.members
    set option $w.frame.option
    
    if {[info exists created($w)] && $created($w)} {
        APSRemap $w
        return
    } else {
        set created($w) 1
    }
    APSFrame $widget -parent $parent -label "" \
      -contextHelp "Frame for controllaw script group $groupTitle($group)" 
    APSFrame .members -parent $w.frame -label "" \
      -contextHelp "Frame for controllaw script group $groupTitle($group)" 
    $members.frame configure -relief flat
    foreach member $groupDef($group) {
        APSOptimizeMakeBriefWidget .$member -parent $members.frame -member $member
    }
    # option frame
    APSFrame .option -parent $w.frame -label ""  \
      -packOption {-side left} \
      -contextHelp "Option frame for controllaw script group $groupTitle($group)"
    $option.frame configure -relief flat
    APSButton .details -parent $option.frame -text "More details" -width "" \
      -command "APSUnmap $w; APSOptimizeMakeFullWidgetGroup .full -parent $parent -group $group" \
        -contextHelp "Remaps the full $groupTitle($group) frames."
}

proc APSOptimizeMakeFullWidgetGroup {widget args} {
    global groupDef HomeDir using
    global groupTitle
    global created optDir expert
    
    APSStrictParseArguments {parent group}
    
    set w $parent$widget
    set members $w.frame.members
    set option $w.frame.option

    if {[info exists created($w)] && $created($w)} {
        APSRemap $w
        return
    } else {
        set created($w) 1
    }
    
    APSFrame $widget -parent $parent -label "" \
      -contextHelp "Frame for controllaw script group $groupTitle($group)" 
    APSFrame .members -parent $w.frame -label "" \
      -contextHelp "Frame for controllaw script group $groupTitle($group)" 
    $members.frame configure -relief flat
    foreach member $groupDef($group) {
        APSOptimizeMakeWidget .$member -parent $members.frame -member $member
    }
    # option frame
    APSFrame .option -parent $w.frame -label "" \
      -packOption {-side left} \
      -contextHelp "Option frame for controllaw script group $groupTitle($group)"
    $option.frame configure -relief flat
    APSButton .less -parent $option.frame -text "Status only" -width "" \
      -command "APSUnmap $w; APSOptimizeMakeBriefWidgetGroup .brief -parent $parent -group $group" \
      -contextHelp "Unmaps the full $groupTitle($group) frames."
}

proc APSOptimizeMakeWidget {widget args} {
    global status suspend abort rcPV optDir HomeDir using
    global directory title rcDesc rcPV Frame
    global connected
    global arguments
    global debug using restartFile expert

    APSStrictParseArguments {parent member}
    set restartFile($member) ""
    
    APSFrame $widget -parent $parent -label $title($member) -orientation horizontal \
      -contextHelp "Frame for $title($member) controllaw."
    set w $parent$widget.frame
    # this global variable should only be defined in procedure APSOptimizeMakeWidget
    # and not in APSOptimizeMakeBriefWidget, since array Frame is used to keep track
    # of the frames associated with buttons.
    set Frame($member) $w

    frame  $w.status
    pack $w.status -side top
    APSLabeledOutput .status -parent $w.status -label "Status: " \
      -width 50 -textVariable status($member) \
      -contextHelp "Status output line."
    #make a frame for common methods, collect_data or optimize
    frame $w.methods
    pack $w.methods -side top
    global method collectdata trustRegion
    set method($member) expected_improvement
    set method($member) sdds-simplex
    set collectdata($member) 0
    set trustRegion($member) 1
    APSComboboxFrame .method -packOption "-side left" -parent $w.methods -width 30 \
	-label method -itemList {sdds-simplex expected_improvement upper_confidence_bound latin_hypercube random extrem sdds-rcds simplex rcds} \
	-textVariable method($member)
    APSRadioButtonFrame .region -packOption "-side left" -parent $w.methods -label "Use trust region for BO?" \
	-buttonList {Yes No} -valueList {1 0} -variable trustRegion($member) -orientation horizontal
    
    # make a frame for special entries, e.g. energy, interval, etc.
    frame $w.entries
    pack $w.entries -side top
    # get labeled entry instruction from script ${w}Entries
    
    if {[file executable [set file $directory($member)/${member}Entries]]} {
        catch {exec $file -widget $w.entries -get defaults} DefaultCommands
        foreach command $DefaultCommands {
            # add to arguments list and globalize
            regexp {(.*)\((.*)\)} [lindex $command 1] {} variable
            if {[lsearch -exact $arguments $variable] == -1} {
                set arguments [concat $arguments $variable]
            }
            if {![llength [info vars $variable]]} {
                global $variable
            }
            eval  [subst $command]
        }
	catch { exec $file -widget $w.entries -get instructions} EntryCommands
        foreach command $EntryCommands {
            eval [subst $command] 
        }
    } else {
        APSInfoWindow .alert -name "Warning" \
          -infoMessage "Can't find or execute file $file for parameter entries generation. No parameter boxes generated."\
          -modal 1
    }
    # define buttons:
    # start resume suspend abort clear info
    ############################################
    APSOptimizeMakeDailyLogs  -member $member
    if $expert {
	APSLabeledEntry .optdir -parent $w -label "Optimize directory:" -textVariable optDir($member) -width 100 \
	    -contextHelp "optimization directory"
	APSButton .pick -parent $w.optdir -text "F"  -packOption "-side right" -command "APSSelectOptimizeDirectory -member $member"
    }
    APSLabeledEntry .restart -parent $w -label "Restart File:" -textVariable restartFile($member) -width 100 \
    	-contextHelp "provide the restart file for optimizer"
    if [info exist using($member)] {
	trace variable using($member) w "APSOptimizeMakeDailyLogs -member $member;APSOptimizeUpdateRestartFile -member $member -usingChanged 1"
	trace variable restartFile($member) w "APSOptimizeUpdateRestartFile -member $member -usingChanged 0"
    }
    
    APSButton .pick -parent $w.restart -text "F"  -packOption "-side right" -command "APSSelectRestartFile -member $member"
    APSFrame .f1 -parent $w
    APSFrame .f2 -parent $w
    set w1 $w.f1.frame
    set w2 $w.f2.frame
    set Frame($member) $w1
    APSButton .start -parent $w1 -text "Start" -width "" \
      -command "APSOptimizeStartButton -parent $w -member $member" \
      -contextHelp "Starts script for $title($member)"
    
    APSButton .resume -parent $w1 -text "Resume" -width "" \
      -command "APSOptimizeResumeButton -parent $w -member $member" \
      -contextHelp "Resumes associated run control for $title($member) after it was suspended"
    APSButton .suspend -parent $w1 -text "Suspend" -width "" \
      -command "APSOptimizeSuspendButton -parent $w -member $member" \
      -contextHelp "Suspends associated run control for $title($member) after it was started or resumed"
    APSButton .abort -parent $w1 -text "Abort" -width "" \
      -command "APSOptimizeAbortButton  -parent $w -member $member" \
      -contextHelp "Abort associated run control for $title($member)"
    APSButton .clear -parent $w1 -text "Clear" -width "" \
      -command "APSOptimizeClearButton  -parent $w -member $member" \
      -contextHelp "Clear associated run control for $title($member)"
    APSButton .info -parent $w1 -text "Info" -width "" \
      -command "APSOptimizeInfoButton  -parent $w -member $member" \
      -contextHelp "Brings up medm and tcl windows for more information on runcontrol."
    APSButton .testValues -parent $w1 -text "TestValues" -width "" \
      -command "APSOptimizeTestValuesButton -member $member" \
	-contextHelp "Brings up a window displaying values of tests. Useful when sddscontrollaw issues a out-of-range status."
    if {$member=="rg1" || $member=="rg2"} {
	APSButton .variables1 -parent $w2 -text "Choose Variables" -width "" \
	    -command "APSOptimizeLinacGunVariablesButton -member $member" \
	    -contextHelp "Brings up a window displaying the variables. Useful to see what PVs are varied."
    }
    APSButton .variables -parent $w2 -text "Variables" -width "" \
	-command "APSOptimizeVariablesButton -parent $w -member $member" \
	-contextHelp "Brings up a window displaying the variables. Useful to see what PVs are varied."
    APSButton .observ -parent $w2 -text "Objectives" -width "" \
      -command "APSOptimizeObjectivesButton -parent $w -member $member" \
	-contextHelp "Brings up a window displaying the variables. Useful to see what PVs are being optimized."
    APSButton .test -parent $w2 -text "Tests" -width "" \
      -command "APSOptimizeTestsButton -parent $w -member $member" \
	-contextHelp "Brings up a window displaying the tests. Useful to see what PVs are being tested."
    APSButton .par -parent $w2 -text "Parameters" -width "" \
      -command "APSOptimizeParametersButton -parent $w -member $member" \
	-contextHelp "Brings up a window displaying the tests. Useful to see what PVs are being tested."
    APSButton .plot -parent $w2 -text "RealTime Plot" -command "APSOptimizePlot -member $member" \
	-contextHelp "bring up the strip tool."
    APSButton .plot1 -parent $w2 -text "Plot History" -command "APSOptimizePlotHistory -member $member" \
	-contextHelp "bring up the strip tool."
   
    # check to see if controllaw with the same description $rcDesc($member) is already running.
    set PV $rcPV($member)
    # array "connected" is the inverse associative array of rcPV
    set connected($PV) $member
    if {[APSOptimizeIsSlotTimedOut -PV $PV]} {
        APSDisableButton $w1.start.button
        if [winfo exist $w1.start1.button] {
            APSDisableButton $w1.start1.button
        }
        APSDisableButton $w1.resume.button
        APSDisableButton $w1.suspend.button
        APSDisableButton $w1.abort.button
        APSEnableButton $w1.clear.button
        #        exec medm -x -attach -macro RCPV=$PV ./sr/psApp/APSRunControlSingle.adl & 
        APSInfoWindow .alert -name "Warning" -infoMessage "PV slot $PV is timed out. In order for sddscontrollaw to execute, this slot must be cleared. Press the corresponding CLEAR button." -modal 0
    } elseif {![APSOptimizeIsSlotUsed -PV $PV]} {
        APSEnableButton $w1.start.button
        if [winfo exist $w1.start1.button] {
            APSEnableButton $w1.start1.button
        }
        APSDisableButton $w1.resume.button
        APSDisableButton $w1.suspend.button
        APSDisableButton $w1.abort.button
        APSDisableButton $w1.clear.button
    } else {
        #check the description if it contains using info,
        if [catch {exec cavget -list=$PV.DESC -pend=10} desc] {
        } else {
            set use [lindex [split $desc "-"] 1]
            #H.Shang, add checking is subdirectory $use exist, do not set it to usig if it does not exist 
            if {[string length $use] && [file exist $directory($member)/$use]} {
                set using($member) $use
            }
        }
        # Disable entry boxes and refresh buttons because controllaw for that rc slot is running on some other
        # screen probably.
        foreach arg $arguments {
            if {[info exists ${arg}($member)]} {
                catch { $w.entries.$arg.entry configure -state readonly }
            }
        }
    }
    APSOptimizeStartMonitors -PV $PV
    APSOptimizeRefreshArrays -PV $PV
    APSOptimizeRefreshButtons -PV $PV
}


proc APSOptimizeMakeBriefWidget {widget args} {
    global status suspend abort rcPV
    global directory title rcDesc Frame
    global arguments
    global debug

    APSStrictParseArguments {parent member}
    APSFrame $widget -parent $parent -label $title($member) -orientation horizontal \
      -contextHelp "Frame for $title($member) controllaw"
    set w $parent$widget.frame

    frame $w.status
    pack $w.status -side top
    APSLabeledOutput .status -parent $w.status -label "Status: " \
      -width 50 -textVariable status($member) \
      -contextHelp "Status output line."
}

# returns 1 is slot is used, i.e. the description field is non-zero
proc APSOptimizeIsSlotUsed {args} {
    global debug

    APSStrictParseArguments {PV}

    # simply check the length of the description field
    if {[string length [set result [exec cavget -list=$PV -list=.DESC -noquotes] ] ]} {
        return 1
    } else {
        return 0
    }
}

# returns 1 is slot is used, i.e. the description field is non-zero
proc APSOptimizeIsSlotTimedOut {args} {
    global debug

    APSStrictParseArguments {PV}

    # simply check that the timeout PV is off or on.
    if {![string compare [set result [exec cavget -list=$PV -list=.HBTO -noquotes] ] "Timeout" ]} {
        return 1
    } else {
        return 0
    }
}

# starts monitoring PV related to the slot PV argument.
proc APSOptimizeStartMonitors {args} {
    global errorCode
    global slotStatus slotSuspend slotAbort slotTimeOut slotDesc slotRunning
    global debug

    APSStrictParseArguments {PV}

    if { [string length $PV] } {
        # start monitors on status, suspend, abort, TimeOut, and Run variables
        if {[pv linkw \
               [list slotStatus($PV) slotSuspend($PV) slotAbort($PV) slotTimeOut($PV) slotDesc($PV) slotRunning($PV)] \
               [list $PV.MSG $PV.SUSP $PV.ABRT $PV.HBTO $PV.DESC $PV.RUN]] != 0} {
            APSAlertBox .alert -errorMessage "$errorCode"
            exit
        }
        if {[pv umon [list slotStatus($PV) slotSuspend($PV) slotAbort($PV) slotTimeOut($PV) slotDesc($PV) slotRunning($PV)]\
               [list APSOptimizeRefreshArraysAndButtons -PV $PV] ] != 0} {
            APSAlertBox .alert -errorMessage "$errorCode"
            exit
        }
        #if {[pv umon [list slotStatus($PV)] [list APSOptimizeRefreshArrays -PV $PV]] != 0} {
        #    APSAlertBox .alert -errorMessage "$errorCode"
         #   exit
        #}
        if {$debug} {
            puts stderr [pv info [list slotStatus($PV) slotSuspend($PV) slotAbort($PV) \
                                    slotTimeOut($PV) slotDesc($PV)] name]
        }
    } else {
        APSAlertBox .alert -errorMessage "Zero-length string PV passed to APSOptimizeStartMonitors procedure."
    }
}


proc APSOptimizeRefreshArraysAndButtons {args} {
    global debug

    if {$debug} {
        puts stderr "In APSRefreshArraysAndButtons: $args"
    }
    eval APSOptimizeRefreshArrays $args
    eval APSOptimizeRefreshButtons $args
}

proc APSOptimizeRefreshArrays {args} {
    global slotStatus slotSuspend slotAbort slotTimeOut connected slotRunning
    global status suspend abort timeOut
    global debug

    APSStrictParseArguments {PV}

    set member $connected($PV)
    if {$debug} {
        puts stderr "In APSOptimizeRefreshArrays, PV:$PV member:$member"
    }
    set status($member) $slotStatus($PV)
    set suspend($member) $slotSuspend($PV)
    set abort($member) $slotAbort($PV)
    set timeOut($member) $slotTimeOut($PV)
    set running($member) $slotRunning($PV)
}

proc APSOptimizeStartButton {args} {
    global directory using title rcDesc rcPV method trustRegion HomeDir
    global status suspend abort timeOut expert optDir
    global connected
    global arguments
    global debug dryRun restartFile
    
    set full 0
    APSStrictParseArguments {parent member full}

    set oldDir [pwd]
    if [info exist using($member)] {
	set dir $optDir($member)/$using($member)
    } else {
	set dir $optDir($member)
    }
    
    cd $HomeDir/$directory($member)
    
    set parameters {}
    foreach arg $arguments {
        global $arg
        if {[info exists ${arg}($member)]} {
            if $debug {
                puts stderr "APSOptimizeStartButton: -$arg  [subst $${arg}($member)]"
            }
            set parameters "$parameters -$arg  [subst $${arg}($member)]"
            catch {$parent.entries.$arg.entry configure -state readonly }
        }
    }
    if {![array exists rcPV] || ![info exists rcPV($member)]} {
        APSInfoWindwo .alert -name "Warning" -infoMessage "Something wrong with rcPV or rcPV($member)." -modal 1
	cd $oldDir
        return
    }
    set PV $rcPV($member)
    
    set parameters "$parameters -rcPV $PV -method $method($member) -trustRegion $trustRegion($member) -expert $expert"
    cd $optDir($member)
    set option {}
    if {[file executable [set file $HomeDir/$directory($member)/${member}Options]]} {
        # eval is important here otherwise $parameter will become a list of one element.
        if $debug {
            puts stderr "APSOptimizeStartButton: eval exec $file $parameters"
        }
        catch {eval exec $file $parameters} options
        if $debug {
            puts stderr "APSOptimizeStartButton: options: $options"
        }
    } else {
        APSInfoWindow .alert -name "Warning" -infoMessage "Can't find or execute file $file for generating the optimizer options." -modal 1
    }  
    #####################
    # run sddscontrollaw
    ####################
    #add abort and clear runcontrol before start it
    if [catch {exec cavget -list=$rcPV($member).RUN -printErrors} running] {
	cd $oldDir
	return -code error "Error checking runcontrol $rcPV($member) run status: $running"
    }
    if $running {
	if [catch {exec cavput -list=$rcPV($member).ABRT=1} result] {
	    cd $oldDir
	    return -code error "Error aborting $rcPV($member) before starting it: $result"
	}
	after 1000
	if [catch {exec cawait -waitfor=$rcPV($member).RUN,equal=0 -timeLimit=30} result] {
	    cd $oldDir
	    return -code error "Error waiting for  $rcPV($member) to abort before starting it: $result"
	}
    }
    if [catch {exec cavput -list=$rcPV($member).CLR=1 } result] {
	cd $oldDir
	return -code error "Error clear runcontrol $rcPV($member) record"
    }
    set realtimePlot 0
    if {[regexp "simplex=" $options] || [regexp "rcds=" $options]} {
	if $dryRun {
	    set command "sddsoptimize $options -verbose -dryRun"
	} else {
	    set command "sddsoptimize $options -verbose"
	}
	set realtimePlot 1
    } else {
	if {[string length $restartFile($member)] && [file exist $restartFile($member)]} {
	    set opt " -restartFile $restartFile($member)"
	} else {
	    set opt ""
	}
	set command "APSOptimization.py $options -verbose 1 -dryRun $dryRun $opt"
    }
    if $expert {
	cd $optDir($member)
	if [regexp "rg" $member] {
	    set command [regsub "variable/" $command ""]
	}
    }
    
    cd $optDir($member)
    if ![file exist logdata] {
	exec mkdir logdata
    }
    APSExecLog .${member}optimize   -width 95 -lineLimit 1024 \
	-unixCommand "$command"
    after 1000
    cd $oldDir
    if $realtimePlot {
	if {[regexp {\-logFile=([^ ]+)} $command match filename]} {
	    set file $optDir($member)/$filename
	    exec PlotFileLive.py -reverse 1 -xcol EvalIndex -ycol currentValue -file $file &
	}
    }
}

proc APSOptimizeResumeButton {args} {
    global rcPV directory using
    global status
    global debug

    APSStrictParseArguments {parent member}

    if {$debug} {
        puts stderr "APSOptimizeResumeButton: Pressed resume for $member in $rcPV($member)."
    }
    set status($member) "Resumed"
    exec caput $rcPV($member).SUSP 0
    if $debug {
        puts stderr "APSOptimizeResumeButton: caput -s $rcPV($member).ALRM NO_ALARM"
    }
    exec caput -s $rcPV($member).ALRM NO_ALARM
    if [ catch {exec logMessage -sourceId=controllawAudit\
                  -tag=Instance $rcPV($member) -tag=Action Resume \
              } result ] {
        APSAlertBox .alert -errorMessage "error with logMessage: $result"
        return
    }
    if [info exist using($member)] {
	if [file exists $directory($member)/$using($member)/$member.resume] {
	    exec $directory($member)/$using($member)/$member.resume
	}
    } else {
	if [file exists $directory($member)/$member.resume] {
	    exec $directory($member)/$member.resume
	}
    }
}

proc APSOptimizeSuspendButton {args} {
    global rcPV directory using
    global debug

    APSStrictParseArguments {parent member}
    
    if {$debug} {
        puts stderr "Pressed suspend for $member in $rcPV($member)."
    }
    set status($member) "Suspended"
    exec caput $rcPV($member).SUSP 1
    if $debug {
        puts stderr "APSOptimizeSuspendButton: caput -s $rcPV($member).ALRM MINOR"
    }
    exec caput -s $rcPV($member).ALRM MINOR
    if [ catch {exec logMessage  -sourceId=controllawAudit\
                  -tag=Instance $rcPV($member) -tag=Action Suspend \
              } result ] {
        APSAlertBox .alert -errorMessage "error with logMessage: $result"
        return
    }
    if [info exist using($member)] {
	if [file exists $directory($member)/$using($member)/$member.suspend] {
	    exec $directory($member)/$using($member)/$member.suspend
	}
    } else {
	if [file exists $directory($member)/$member.suspend] {
	    exec $directory($member)/$member.suspend
	}
    }
}

proc APSOptimizeAbortButton {args} {
    global rcPV abort suspend status timeOut directory using
    global connected
    global arguments
    global debug

    APSStrictParseArguments {parent member}

    set status($member) "Aborted"
    # exec caput $rcPV($member).ABRT 1
    if [catch {exec cavput -list=$rcPV($member).ABRT=1} result] {
	return -code error "Error aborting $rcPV($member) before starting it: $result"
    }
    # this sets the alarm state to NO_ALARM
    if $debug {
        puts stderr APSOptimizeAbortButton: "caput -s $rcPV($member).ALRM NO_ALARM"
    }
    exec caput -s $rcPV($member).ALRM NO_ALARM
    exec caput -s $rcPV($member).MSG "Abort Requested"
    if [ catch {exec logMessage -sourceId=controllawAudit\
                  -tag=Instance $rcPV($member) -tag=Action Abort \
              } result ] {
        APSAlertBox .alert -errorMessage "error with logMessage: $result"
        return
    }
    if [info exist using($member)] {
	if [file exists $directory($member)/$using($member)/${member}.abort] {
	    exec $directory($member)/$using($member)/${member}.abort
	}
    } else {
	if [file exists $directory($member)/${member}.abort] {
	    exec $directory($member)/${member}.abort
	}
    }
}

proc APSOptimizeClearButton {args} {
    global rcPV abort suspend status timeOut
    global connected
    global arguments
    global debug

    APSStrictParseArguments {parent member}

    set status($member) "Cleared"
    exec caput $rcPV($member).ABRT 1
    exec caput $rcPV($member).CLR 1
    if $debug {
        puts stderr "APSOptimizeClearButton: caput -s $rcPV($member).ALRM NO_ALARM"
    }
    exec caput -s $rcPV($member).ALRM NO_ALARM
}

proc APSOptimizeRefreshButtons {args} {
    global suspend status abort timeOut
    global slotSuspend slotStatus slotAbort slotTimeOut slotDesc connected slotRunning
    global arguments
    global debug
    global Frame

    APSStrictParseArguments {PV}

    if {$debug} {
        puts stderr "APSOptimizeRefreshButtons: PV:$PV connected to: $connected($PV)"
    }
    set member $connected($PV)
    set w $Frame($member)
    if {$debug} {
        puts stderr "button parent widget:$w"
        puts stderr "slotAbort($PV):$slotAbort($PV)"
        puts stderr "slotSuspend($PV):$slotSuspend($PV)"
        puts stderr "slotTimeOut($PV):$slotTimeOut($PV)"
        puts stderr "slotDesc($PV):$slotDesc($PV)"
	puts stderr "slotRunning($PV):$slotRunning($PV)"
	puts stderr "slotStatus($PV):$slotStatus($PV)"
    }
    # possible combinations of array values
    #       suspend         abort      timeOut
    # ----------------------------------------
    #       resume          run
    #       suspend         run
    #       resume/resume   abort         0      ! in case of abort, disable all but start, and skip the other tests
    #       resume/resume   run/abort     1      ! enable clear buuton only 
    if {![string compare $slotTimeOut($PV) "Timeout"]} {
        APSDisableButton $w.start.button
        if [winfo exist $w.start1.button] {
            APSDisableButton $w.start1.button
        }
        APSDisableButton $w.resume.button
        APSDisableButton $w.suspend.button
        APSDisableButton $w.abort.button
        APSEnableButton $w.clear.button
        set status($member) "Timed out. Press clear"
    }  elseif {![string compare $slotSuspend($PV) "Suspend"]} {
        APSDisableButton $w.start.button
        if [winfo exist $w.start1.button] {
            APSDisableButton $w.start1.button
        }
        APSEnableButton $w.resume.button
        APSDisableButton $w.suspend.button
        APSEnableButton $w.abort.button
        APSDisableButton $w.clear.button
        set connected($PV) $member
    } elseif {![string compare $slotAbort($PV) "Abort"] || ![string length $slotDesc($PV)] || !$slotRunning($PV) } {
        if {$debug} {
            puts stderr "APSEnableButton $w.start.button"
            puts stderr "APSDisableButton $w.resume.button"
            puts stderr "APSDisableButton $w.suspend.button"
            puts stderr "APSDisableButton $w.abort.button"
            puts stderr "APSDisableButton $w.clear.button"
        }
        APSEnableButton $w.start.button
        if [winfo exist $w.start1.button] {
            APSEnableButton $w.start1.button
        }
        APSDisableButton $w.resume.button
        APSDisableButton $w.suspend.button
        APSDisableButton $w.abort.button
        APSDisableButton $w.clear.button
        set status($member) "Aborted or cleared. Press Start."
        # enable entry boxes
        foreach arg $arguments {
            global $arg
            if {[info exists ${arg}($member)]} {
                catch { $w.entries.$arg.entry configure -state normal}
            }
        }
    } elseif {![string compare $slotSuspend($PV) "Resume"]} {
        APSDisableButton $w.start.button
        if [winfo exist $w.start1.button] {
            APSDisableButton $w.start1.button
        }
        APSDisableButton $w.resume.button
        APSEnableButton $w.suspend.button
        APSEnableButton $w.abort.button
        APSDisableButton $w.clear.button
        set connected($PV) $member
    }
    if ![string length $slotStatus($PV)] {
	APSEnableButton $w.start.button
        if [winfo exist $w.start1.button] {
            APSEnableButton $w.start1.button
        }
        APSDisableButton $w.resume.button
        APSDisableButton $w.suspend.button
        APSDisableButton $w.abort.button
        APSDisableButton $w.clear.button
    }
}

proc APSOptimizeInfoButton {args} {
    global arguments
    global directory
    global rcPV
    global HomeDir
    foreach arg $arguments {
        global $arg
    }
    APSStrictParseArguments {parent member}
    if {![array exists rcPV] || ![info exists rcPV($member)]} {
        APSInfoWindow .infoError -name "InfoError" -infoMessage "$member controllaw not assigned to any slot yet."
        return
    }
    if ![string length $rcPV($member)] {
        APSInfoWindow .infoError -name "InfoError" \
          -infoMessage "Empty string for runcontrol PV slot. No info available." -modal 1
        return
    }
    
    exec medm -x -attach -macro "RCPV=$rcPV($member)" ./sr/psApp/APSRunControlSingle.adl &
    return
    # The Info program uses rsh.
    # There are problems with using rsh currently.
    if {[file exists [set file $HomeDir/Info]] } {
        APSExecLog .${member}Info -unixCommand "$file -slot $rcPV($member)" \
          -width 80
    } else {
        APSInfoWindow .infoError -name "InfoError" \
          -infoMessage "Can't find file $file. No info available" -modal 1
        return
    }
}

proc APSOptimizeTestValuesButton {args} {
    global arguments expert optDir
    global directory
    global rcPV
    global HomeDir
    global using
    foreach arg $arguments {
        global $arg
    }
    APSStrictParseArguments {parent member}
   
    set testFile $optDir($member)/tests
    
    set command \
      "sddssnapshot $testFile -pipe=output | sddsprocess -pipe \"-def=col,InBounds,MinimumValue Value < pop pop ? Value MaximumValue < pop pop ? 1 : 0 $ : 0 $,type=long\" | sddssort -pipe -col=InBounds -col=ControlName | sddsprintout -pipe=in -col=ControlName,format=%28s -col=(MinimumValue,Value,MaximumValue,InBounds)"
    APSExecLog .${member}TestInfo -unixCommand $command -width 88
    APSWaitWithUpdate -waitSeconds 1
    set data [.${member}TestInfo.userFrame.text.text get 1.0 end]
    set indexList ""
    set n 1
    foreach line [split $data \n] {
        if {[lindex $line end] == 0} {
            append indexList "$n.0 [expr {$n + 1}].0 "
        }
        incr n
    }
    if {[llength $indexList]} {
        eval .${member}TestInfo.userFrame.text.text tag add tag1 $indexList
    }
    .${member}TestInfo.userFrame.text.text tag configure tag1 -foreground red -background white
    
}

proc APSOptimizeObjectivesButton {args} {
    global arguments expert optDir
    global directory objective
    global rcPV
    global HomeDir
    global using
    global debug expert
    foreach arg $arguments {
        global $arg
    }

    APSStrictParseArguments {parent member}
    
    if [info exist objective($member)] {
	set objFile $optDir($member)/$objective($member)observables
    } else {
	set objFile $optDir($member)/observables
    }
    if $debug {
        puts stderr "APSOptimizeObjectivesButton:  sddsedit $objFile"
    }
    catch {exec sddsedit $objFile &}
}

proc APSOptimizeParametersButton {args} {
    global optDir debug
    APSStrictParseArguments {parent member}
    
    set parFile $optDir($member)/parameters
    if ![file exist $parFile] {
	APSInfoWindow .alert -name "Warning" -infoMessage "$parFile does not exist." -modal 1
	return
    }
    if $debug {
        puts stderr "APSOptimizeTestsButton:  sddsedit $parFile"
    }
    catch {exec sddsedit $parFile &}
}

proc APSOptimizeTestsButton {args} {
    global optDir debug
    APSStrictParseArguments {parent member}
    
    set testFile $optDir($member)/tests
    if $debug {
        puts stderr "APSOptimizeTestsButton:  sddsedit $testFile"
    }
    catch {exec sddsedit $testFile &}
}

proc APSOptimizeSaveVariables {args} {
    global arguments expert optDir
    global directory status
    global rcPV
    global HomeDir
    global using
    global debug
    foreach arg $arguments {
        global $arg
    }
    global useVar
    APSStrictParseArguments {parent member}
    if [catch {APSOptimizeUpdateVariables -member $member} result] {
	return -code error "Error updating database: $result"
    }
    if $expert {
	set allvarFile $optDir($member)/variables.all
    } else {
	set allvarFile  $HomeDir/$directory($member)/variables.all
    }
    set pvs [exec sdds2stream -col=ControlName $allvarFile]
    set pvList ""
    foreach pv $pvs {
	if $useVar($member.$pv) {
	    lappend pvList $pv
	}
    }
    if ![llength $pvList] {
	set status($member) "No variables chosen"
	return
	#return -code error "Error: NO variables chosen for linac $member optimization"
    }
    if $expert {
	set varFile $optDir($member)/variables
    } else {
	set varFile  $HomeDir/$directory($member)/variable/variables
    }
    if [file exist $varFile] {
	set existPVs [exec sdds2stream -col=ControlName $varFile]
	if [string equal [lsort $pvList] [lsort $existPVs]] {
	    #check if the initial change and relative limit changed
	    set steps [exec sdds2stream -col=InitialChange $varFile]
	    set limits [exec sdds2stream -col=RelativeLimit $varFile]
	    set changed 0
	    foreach pv $existPVs step $steps limit $limits {
		if {$step!=$useVar($member.$pv.step) || $limit!=$useVar($member.$pv.limit)} {
		    set changed 1
		    break
		}
	    }
	    if !$changed {
		set status($member) "variables do not changed."
		return
	    }
	}
	#changed, need make a new variable file
    }
    set tmpRoot /tmp/[APSTmpString]
    if [catch {exec sddsmakedataset $tmpRoot.1 -col=ControlName,type=string -data=[join $pvList ,] } result] {
	return -code error "Error1 creating variables for $member: $result"
    }
    APSAddToTmpFileList -ID xopt -fileList $tmpRoot.1
    if $expert {
	if [catch {exec sddsxref $tmpRoot.1 $allvarFile -match=ControlName -leave=ControlName -transfer=par,* \
		       $optDir($member)/variables -nowarn} result] {
	    return -code error "Error2 creating variables for $member: $result"
	}
    } else {
	set dir $HomeDir/$directory($member)/variable
	set newName [APSNextGenerationedName -directory $dir/variable \
			 -name variables-0000 -separator - -newFile 1]
	
	set oldDir [pwd]
	if [catch {exec sddsxref $tmpRoot.1 $allvarFile -match=ControlName -leave=ControlName -transfer=par,* $dir/$newName} result] {
	    return -code error "Error2 creating variables for $member: $result"
	}
	cd $dir
	catch {exec rm variables}
	exec ln -s $newName variables
	cd $oldDir
	set status($member) "A new variable file - $newName is created."
    }
}


proc SelectLinacGunVariables {args} {
    global arguments
    global directory
    global rcPV
    global HomeDir
    global using
    global debug
    foreach arg $arguments {
        global $arg
    }
    global useVar LinacGunVariable
    APSStrictParseArguments {parent member option}
    set file $HomeDir/$directory($member)/$option.vars
    set pvs [exec sdds2stream -col=ControlName $file]
    foreach pv $pvs {
	set useVar($member.$pv) $LinacGunVariable($member.$option)
    }
}

proc APSOptimizeAddNewVariableWidget {args} {
    set member ""
    APSParseArguments {member}
    global optDir NewVar
    APSDialogBox .newPV$member -name "Add New $member variables"  \
	-okCommand "APSOptimizeAddNewVariable -member $member"
    set NewVar($member.PV) ""
    set NewVar($member.readback) ""
    set NewVar($member.InitChange) 0.2
    set NewVar($member.RelativeLimit) 0.5
    set NewVar($member.Tolerance) 0.05
    set NewVar($member.StepLimit) 0.1
    set width 25
    APSLabeledEntry .pv -parent .newPV$member.userFrame -label "PV name:         " -textVariable NewVar($member.PV) -width $width
    APSLabeledEntry .re -parent .newPV$member.userFrame -label "Readback PV name:" -textVariable NewVar($member.readback) -width $width
    APSLabeledEntry .int -parent .newPV$member.userFrame -label "Initial Step:" -textVariable NewVar($member.InitChange) -width $width
    APSLabeledEntry .lim -parent  .newPV$member.userFrame  -label "Relative Limit:" -textVariable NewVar($member.RelativeLimit) -width $width
    APSLabeledEntry .tol -parent  .newPV$member.userFrame  -label "Setpoint/Readback Tolerance:" -textVariable NewVar($member.Tolerance) -width $width
     APSLabeledEntry .step -parent  .newPV$member.userFrame  -label "Step Limit:" -textVariable NewVar($member.StepLimit) -width $width
}

proc APSOptimizeAddNewVariable {args} {
    set member ""
    APSParseArguments {member}
    global optDir NewVar
    set NewVar($member.PV) [string trim $NewVar($member.PV)]
    set NewVar($member.readback) [string trim $NewVar($member.readback)]
    if ![string length $NewVar($member.PV)] {
	return -code error "PV name not provided!"
    }
    if ![string length $NewVar($member.readback)] {
	set NewVar($member.readback) $NewVar($member.PV).VAL
    }
    set file $optDir($member)/variables.all
    set pvList [exec sdds2stream -col=ControlName $file]
    if [lsearch -exact $pvList $NewVar($member.PV)]>=0 {
	APSInfoWindow .alert -name "Warning" -infoMessage "$NewVar($member.PV) already exist." -modal 1
	return
    }
    if [catch {exec caget $NewVar($member.PV)} result] {
	APSInfoWindow .alert -name "Error" -infoMessage "New PV $NewVar($member.PV) does not exist: $result." -modal 1
	return
    }
    if [catch {exec caget $NewVar($member.readback)} result] {
	APSInfoWindow .alert -name "Error" -infoMessage "New Readback $NewVar($member.readback) does not exist: $result." -modal 1
	return
    }
    if [catch {exec cavget -list=$NewVar($member.PV) -list=.DRVL,.DRVH -pend=5 -printErrors} valList] {
	return -code error "Error reading DRVL and DRVH of $NewVar($member.PV): $valList"
    }
    set lower [lindex $valList 0]
    set upper [lindex $valList 1]
    
    set tmpRoot /tmp/[APSTmpString]
    if [catch {exec sddsmakedataset -col=ControlName,type=string -data=$NewVar($member.PV) \
		   -col=InitialChange,type=double -data=$NewVar($member.InitChange) \
		   -col=RelativeLimit,type=double -data=$NewVar($member.RelativeLimit) \
		   -col=ReadbackName,type=string -data=$NewVar($member.readback) \
		   -col=UpperLimit,type=double -data=$upper \
		   -col=LowerLimit,type=double -data=$lower \
		   -col=StepLimit,type=double -data=$NewVar($member.StepLimit) \
		   -col=Tolerance,type=double -data=$NewVar($member.Tolerance) $tmpRoot.1} result] {
	return -code error "error adding new pv1: $result"
    }
    if [catch {exec sddscombine $file $tmpRoot.1 -merge $tmpRoot.2} result] {
	return -code erro "error adding new pv2: $result"
    }
    exec cp $tmpRoot.2 $file
    file delete -force $tmpRoot.1 $tmpRoot.2
    if [winfo exist .$member] {
	destroy .$member
    }
     APSOptimizeLinacGunVariablesButton  -member $member
}

proc APSOptimizeLinacGunVariablesButton {args} {
    global arguments expert optDir
    global directory
    global rcPV
    global HomeDir
    global using
    global debug
    foreach arg $arguments {
        global $arg
    }
    global useVar
    APSStrictParseArguments {member}
    APSDialogBox .$member -name "Select Linac $member variables"  \
	-okCommand "APSOptimizeSaveVariables  -member $member"
    #APSDialogBoxAddButton .update -parent .$member -text "edit variable database" \
#	-command "APSOptimizeEditVariables -member $member" \
#	-contextHelp "Update the variables initial steps and relative limit in variables database (variables.all)"
    APSDialogBoxAddButton .add -parent .$member -text "Add New PV" \
	-command "APSOptimizeAddNewVariableWidget -member $member" \
	-contextHelp "Add new variable"
    
    set oldDir [pwd]
    cd $HomeDir/$directory($member)
    set files [glob -nocomplain *.vars]
    cd $oldDir
    if [llength $files] {
	set choiceList [regsub -all ".vars" $files ""]
	set varList ""
	set commList ""
	foreach choice $choiceList {
	    set LinacGunVariable($member.$choice) 0
	    lappend varList LinacGunVariable($member.$choice)
	    lappend commList "SelectLinacGunVariables -member $member -option $choice"
	}
	APSCheckButtonFrame .select -parent .$member -label "" -buttonList $choiceList \
	    -variableList $varList  -allNone 1 \
	    -orientation horizontal  \
	    -commandList $commList
    }
    if $expert {
	set file $optDir($member)/variables.all
    } else {
	set file $HomeDir/$directory($member)/variables.all
    }
    if ![file exist $file] {
	return -code error "Error: the variables file - $file does not exist!"
    }
    set varpvs [exec sdds2stream $file -col=ControlName]
    set initsteps [exec sdds2stream $file -col=InitialChange]
    set relativeLimit [exec sdds2stream $file -col=RelativeLimit]
    set readbacks [exec sdds2stream $file -col=ReadbackName]
    set varList ""
    set maxLen 1
    foreach pv $varpvs {
	set useVar($member.$pv) 0
	lappend varList useVar($member.$pv)
	if {[string length $pv]>$maxLen} {
	    set maxLen [string length $pv]
	}
    }
    
    APSLabel .label -parent .$member.userFrame -text "[format %[expr $maxLen+5]s ControlName]               Initial_Change         Relative_Limit" \
	-font bold
    set index 1
    foreach pv $varpvs step $initsteps limit $relativeLimit {
	set useVar($member.$pv.step) [format %.1f $step]
	set useVar($member.$pv.limit) [format %.1f $limit]
	APSFrame .c$index -parent .$member.userFrame
	set w .$member.userFrame.c$index.frame 
	$w configure -bd 0
	checkbutton $w.button -text "" -variable useVar($member.$pv)
	pack $w.button -side left -fill x
	APSLabeledEntryFrame .entry -parent $w -label "[format %${maxLen}s $pv]" -width 20 -variableList [list useVar($member.$pv.step) useVar($member.$pv.limit)] -packOption "-side left" -orientation horizontal
	incr index
    }
    #APSCheckButtonFrame .var -parent .$member.userFrame -label "" -buttonList $varpvs \
    #-variableList $varList 
}

proc APSOptimizeVariablesButton {args} {
    global arguments expert optDir
    global directory
    global rcPV
    global HomeDir
    global using
    global debug
    foreach arg $arguments {
        global $arg
    }

    APSStrictParseArguments {parent member}
    if {!$expert && ($member=="rg1" || $member=="rg2")} {
	set dir $optDir($member)/variable
    } else {
	set dir $optDir($member)
    }
    if $debug {
	puts stderr "APSOptimizeVariablesButton:  sddsedit $dir/variables"
    }
    catch {exec sddsedit $dir/variables &}
}

proc APSSelectOptimizeDirectory {args} {
    global optDir expert env status using
    set member ""
    APSParseArguments {member}
    set oldDir [pwd]
    if !$expert {
	return
    }
    set dir /home/helios/[string toupper $env(USER)]/optimizationExpertData
    cd $dir
    set files [glob -nocomplain ????-????/$member]
    if ![llength $files] {
	set status($member) "No directories found for $member"
	cd $oldDir
	return
    }
    cd $oldDir
    global selectDir
    set selectDir ""
    APSScrolledListWindow .bmscan -height 10 -name "Select A Directory" -itemList $files \
	-selectionVar selectDir
    tkwait variable selectDir
    if ![string length $selectDir] {
	return
    }
    if [info exist using($member)] {
	set optDir($member) $dir/$selectDir/$using($member)
    } else {
	set optDir($member) $dir/$selectDir
    }
}

proc APSSelectRestartFile {args} {
    global directory restartFile using status HomeDir optDir
    set member ""
    APSParseArguments {member}
    set oldDir [pwd]
    cd $optDir($member)/logdata
    set files [lsort -decreasing [glob -nocomplain *.xopt]]
    if ![llength $files] {
	set status($member) "No files found in $dir."
	set restartFile($member) ""
	cd $oldDir
	return
    }
    cd $oldDir
    global selectFile
    APSScrolledListWindow .bmscan -height 10 -name "Select A File" -itemList $files \
	-selectionVar selectFile
    tkwait variable selectFile
    set restartFile($member) $optDir($member)/logdata/$selectFile
}

proc APSOptimizeUpdateRestartFile {args} {
    global using restartFile
    set member ""
    set usingChange 0
    APSParseArguments {member usingChanged}
    if !$usingChanged {
	set restartFile($member.$using($member)) $restartFile($member)
	return
    }
    if [info exist using($member)] {
	if [info exist restartFile($member.$using($member))] {
	    set restartFile($member) $restartFile($member.$using($member))
	} else {
	    set restartFile($member) ""
	    set restartFile($member.$using($member)) ""
	}
    }
}

proc APSOptimizePlotHistory {args} {
    global optDir using status
    set member ""
    APSParseArguments {member}
    set dir $optDir($member)
    set oldDir [pwd]
    if ![file exist $dir/logdata] {
	APSInfoWindow .alert -name "Warning" -infoMessage "No log data found." -modal 1
	return
    }
    cd $dir/logdata
    set files1 [glob -nocomplain *.sdds]
    set files2 [glob -nocomplain *.xopt]
    cd $oldDir
    set files [lsort -decreasing [concat $files1 $files2]]
    
    if ![llength $files] {
	set status($member)  "No log data found!"
	return
    }
    global selectLog
    APSScrolledListWindow .bmscan -height 10 -name "Select A File" -itemList $files \
	-selectionVar selectLog
    tkwait variable selectLog
    set file $optDir($member)/logdata/$selectLog
    if [regexp "sdds" $file] {
	exec sddsplot -col=EvalIndex,currentValue $file -grap=sym,sub=1,scale=2,conn -title=$file  &
    } else {
	exec sddsplot -col=f $file -grap=sym,sub=1,scale=2,conn -title=$file &
    }
}
proc APSOptimizePlot {args} {
    global directory status optDir expert objective directory HomeDir
    set member ""
    APSParseArguments {member}
    if {!$expert} {
	set file $HomeDir/$directory($member)/plot.sdds
	if ![file exist $file] {
	    exec PlotPVs.py  &
	} else {
	    exec PlotPVs.py -input $file &
	}
	return
    }
    set file $optDir($member)/plot.sdds
    set variables $optDir($member)/variables
    set objFile $optDir($member)/observables
    if {$member=="rg1" || $member=="rg2"} {
	set objFile $optDir($member)/$objective($member)observables
	if !$expert {
	    set variables $optDir($member)/variable/variables
	} 
	set file $optDir($member)/plot.$objective($member).sdds
    } elseif {$member=="rg1Test"} {
	set objFile $optDir($member)/$objective($member)observables
    }
    if {![file exist $file] || [file mtime $file]<[file mtime $variables] || [file mtime $file]<[file mtime $objFile]} {
	if [catch {exec sddscombine -merge $objFile $variables -pipe=out \
		       | sddsprocess -pipe=in $file \
		       -redefine=col,MinimumValue,LowerLimit -define=col,MaximumValue,UpperLimit } result] {
	    return -code error "Error creating $file: $result"
	}
    }
    exec PlotPVs.py -input $file &
    
}

proc APSOptimizeChangeRG1RG2Objective {args} {
    global using objective
    set member ""
    APSParseArguments {member}
    if [regexp "phase" $using($member)] {
	set objective($member) L3CM1
    } else {
	set objective($member) L1CM2
    }
}

proc APSOptimizeEditVariables {args} {
    set member ""
    APSParseArguments {member}
    global optDir
    set file $optDir($member)/variables.all
    exec sddsedit $file &
}
   

proc APSOptimizeUpdateVariables {args} {
    global HomeDir directory status optDir expert
    set member ""
    APSStrictParseArguments {member}

    global useVar
    if !$expert {
	set file $HomeDir/$directory($member)/variables.all
    } else {
	set file $optDir($member)/variables.all
    }
    if ![file exist $file] {
	return -code error "Error in updating initial step and relative limit1: $file does not exist!"
    }
    set varpvs [exec sdds2stream $file -col=ControlName]
    set steps [exec sdds2stream $file -col=InitialChange]
    set limits [exec sdds2stream $file -col=RelativeLimit]
    set initsteps ""
    set relativeLimit ""
    set tmpRoot /tmp/[APSTmpString]
    set changed 0
    foreach pv $varpvs step $steps limit $limits {
	lappend initsteps $useVar($member.$pv.step)
	lappend relativeLimit $useVar($member.$pv.limit)
	if {$step!=$useVar($member.$pv.step) || $limit!=$useVar($member.$pv.limit)} {
	    set changed 1
	}
    }
    if !$changed {
	#set status($member) "initial step and relative limits did not change, no changes made."
	return 0
    }
    
    if [catch {exec sddsmakedataset -col=ControlName,type=string -data=[join $varpvs ,] \
		   -col=InitialChange,type=double -data=[join $initsteps ,] \
		   -col=RelativeLimit,type=double -data=[join $relativeLimit ,] $tmpRoot.1 } result] {
	return -code error "Error updating the variables initial step and relative limit1: $result"
    }
    APSAddToTmpFileList -ID optimize -fileList $tmpRoot.1
    set dir [file dir $file]
    set newFile [APSNextGenerationedName -directory $dir \
		     -name variables.all-0000 -separator - -newFile 1]
    if [catch {exec sddsconvert $file -pipe=out -del=col,InitialChange,RelativeLimit \
		   | sddsxref -pipe=in $tmpRoot.1 -match=ControlName -take=InitialChange,RelativeLimit $dir/$newFile} result] {
	return -code error "Error updating the variables initial step and relative limit2: $result"
    }
    set oldDir [pwd]
    cd $dir
    catch {exec rm variables.all}
    exec ln -s $newFile variables.all
    cd $oldDir
    return 1
}

