TABLE OF CONTENTS


::pwtk::run

SYNOPSIS

proc ::pwtk::run {args} {

USAGE

   run [OPTIONS] PROGRAM  INPUT  ?OUTPUT?  ?&?

   Options are:
     -bg
     -append
     -serial
     -prefix PREFIX
     -postfix POSTFIX
     -exec EXECUTABLE
     -ihandle VALUE

PURPOSE

Run a given Quantum-ESPRESSO (QE) program. It is implicitly assumed that QE program reads from stdin and writes to stdout, that is, it is assumed that the standard usage from the terminal or shell-script is:

       PROGRAM < INPUT > OUTPUT

The equivalent PWTK statement is:

      run PROGRAM INPUT ?OUTPUT?

where INPUT is the name of the input file and OUTPUT is the name of the output file. Note that the OUTPUT argument is optional; if it is not specified it is automatically constructed from the input file name. For example, if the INPUT is "file.in" then the OUTPUT is "file.out", but if the input filename does not have .in or .inp extension, then the name of the output is simply file.out, where "file" is the input filename.

See the ::pwtk::findExecutable for how the executable is located.

OPTIONS

ARGUMENTS

RETURN VALUE

The name of the output file, unless the -bg option was specified in which case the ID of the backhound job is returned, which can be used for ::pwtk::run_wait.

SOURCE

    variable state
    variable run_options
    variable RUNopt
    variable run
    variable makeInputAndRun_

    # for prerun & remedy a recursive call to run is made, store how to call it
    
    set args_orig $args
    set run_cmd {
        ifexist makeInputAndRun_ {
            #set result [eval makeInputAndRun_ $makeInputAndRun_]
            set result [makeInputAndRun_ {*}$makeInputAndRun_]
        } else {
            #set result [eval run $args_orig]
            set result [run {*}$args_orig]
        }
        concat $result
    }
    
    #
    # parse arguments
    #

    set bg 0
    set lastarg [lindex $args end]
    if { $lastarg eq "&" } {
        set bg 1
        set args [lrange $args 0 end-1]
    }
    set usage "\n\nUsage: ::pwtk::run  ?OPTIONS?  PROGRAM  INPUT  ?OUTPUT?  ?&?\n\nOptions are:"

    array set opt [::cmdline::getoptions args $run_options $usage]

    if { [llength $args] < 2 || [llength $args] > 3 } {
        error [::cmdline::usage $run_options $usage] 1
    }

    # &" is synonymous with -bg
    if { $bg } {
        set opt(bg) 1
    }

    lassign $args program input output
    set ihandle $RUNopt(input_handle)
    
    if { $output == "" } {
        set output [outputName_ $input]
    }
    if { $opt(ihandle) != {} } {
        set ihandle $opt(ihandle)
    }

    # if in restart-mode & job is already done, do not run it again
    
    if { $state(restart) && [::pwtk::job_done $output] } {
        ::pwtk::print "The $program job \"$output\" already done.\n"
        return $output
    }    
    
    # check for excluding options: (prefix || postfix) vs serial 
    
    if { $opt(serial) && $opt(prefix) != "" } {
        ::pwtk::error "exclusive -serial and -prefix options were specified" 1
    }
    if { $opt(serial) && $opt(postfix) != "" } {
        ::pwtk::error "exclusive -serial and -postfix options were specified" 1
    }
    
    # store the name of program, input & output files (they may be queried from other procs)
    
    array set run [list program $program input $input output $output]
    set pname [file tail $program]

    # handle "prerun"

    set preruns [::pwtk::preruns_ $pname]
    if { $preruns ne {} } {
        ::pwtk::input::pushpop {
            foreach name $preruns {
                #::pwtk::print "Evaluating the prerun script:\n$state($name)"
                eval $state($name)
                unset state($name)
            }
            eval $run_cmd
        }
        return [varvalue result]
    }

    #
    # determine prefix & postfix
    #

    if { ! $opt(serial) } {
        # parallel run 
        # (beware: do not swap the below lines, because order matters !!!)
        set prefix  [list {*}[::pwtk::getVar_ RUNopt(NICE_CMD)] {*}[::pwtk::getVar_ RUNopt(CONTAINER_EXEC)] {*}[::pwtk::getVar_ RUNopt(PREFIX)]]
        set postfix [::pwtk::getVar_ RUNopt(POSTFIX)]
        if { $opt(prefix)  != "" } { set prefix  $opt(prefix) }
        if { $opt(postfix) != "" } { set postfix $opt(postfix) }        
    } else {
        # serial run
        set prefix  [list {*}[::pwtk::getVar_ RUNopt(NICE_CMD)] {*}[::pwtk::getVar_ RUNopt(CONTAINER_EXEC)] {*}[::pwtk::getVar_ RUNopt(SERIAL_PREFIX)]]
        set postfix [::pwtk::getVar_ RUNopt(SERIAL_POSTFIX)]
    }

    #
    # find the executable
    #
    if { $opt(exec) == "" } {
        set prog [findExecutable $program]
    } else {
        # executable was explicitly specified (check if it is OK)
        set prog $opt(exec)
        if { $state(bin_query) && [auto_execok $prog] == "" } {
            ::pwtk::error "explicitly specified program '$prog' is not executable" 1
        }       
    }
    ::pwtk::print "Executable: $prog"

    # check if the input file exists and is readable 

    if { ! [file readable $input] } {
        ::pwtk::error "file '$input' does not exist or is not readable" 1
    }
        
    # redirection and write mode

    set mode w
    set redirect ">"
    if { $opt(append) } {
        set mode a
        set redirect ">>"
    } else { 
        if { [backup_io] } {
            # make a backup copy of output
            file_backup $output
        }
    }

    # check if the output file is writeable

    try {
        close [open $output a]
    } on error errVar {
        ::pwtk::error "output file '$output' is not writable\n\n$errVar" 1
    }    
    
    # write to output the hostname where calculation is run 

    set redirect_orig $redirect
    set host_ [info hostname]    
    if { $host_ != "" } {
        ::pwtk::writeFile $output "### Running on host: $host_" $mode
        set redirect ">>"
    }

    # remove the error file
    
    if { [file exists $output.error] } {
        file delete $output.error
    }

    #### run the calculation ###############################################
    #
    set rr [string trim "$prefix [file tail $prog] $postfix"]
    try {
        if { ! $opt(bg) } {
            # foreground
            ::pwtk::print "Running: $rr $ihandle $input $redirect_orig $output\n"
            eval exec $prefix $prog $postfix $ihandle $input $redirect $output
        } else {
            # background;            
            # make a push to prevent stack-level == 0, for which ::pwtk::input::peek returns an empty string
            ::pwtk::input::pushpop {                
                ::pwtk::print "Running in background: $rr $ihandle $input $redirect_orig $output 2> $output.error &"
                set id [incr run(bg.ID)]                    
                set pid [eval exec $prefix $prog $postfix $ihandle $input $redirect $output 2> $output.error &]
                ::pwtk::print "PID of the background process = $pid\n"
                # tk
                array set run [list bg.prog,$id  $prog \
                                   bg.pname,$id  $pname \
                                   bg.output,$id $output  \
                                   bg.PID,$id    $pid \
                                   bg.peek,$id   [::pwtk::input::peek] \
                                   bg.run_cmd,$id $run_cmd]                           
                # tk_end
            }
            
            return $id
        }
    } on error errMsg {
        ::pwtk::writeFile $output.error $errMsg
    }
    #
    ########################################################################

    # handle "remedy"
    
    if { [remedy $pname] } {
        if { [checkForError $output $prog 0] } {
            set remedy [remedy $pname get]
            ::pwtk::infoMsg "Trying to remedy the $pname error by using the remedy script:\n$remedy"
            ::pwtk::input::pushpop {
                remedy $pname clear
                eval $remedy
                eval $run_cmd
            }
            return [varvalue result]
        }
    } else {
        checkForError $output $prog $state(stopOnError)
    }

    # handle "postrun"

    set postruns [::pwtk::postruns_ $pname]
    if { $postruns ne {} } {
        foreach name $postruns {
            # should a postrun be done inside pushpop? NO!
            #::pwtk::print "Evaluating the postrun script:\n$state($name)"
            eval $state($name)        
        }
    }

    return [varvalue output]
}