TABLE OF CONTENTS


::pwtk::run

SYNOPSIS

proc ::pwtk::run {args} {

USAGE

run [options] program input ?output?

Options are:

     -append
     -serial
     -prefix
     -postfix
     -exec
     -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

SOURCE

    variable state
    variable run_options
    variable remote_exec
    variable remote
    variable RUNopt
    variable run

    #
    # parse arguments
    #

    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]
    }

    set program [lindex $args 0]
    set input   [lindex $args 1]
    set output  [lindex $args 2]
    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
    }    
    
    # check for excluding options: (prefix || postfix) vs serial 
    
    if { $opt(serial) && $opt(prefix) != "" } {
        ::pwtk::error "cannot specify both -serial and -prefix; the latter is used exclusively for parallel execution" 1
    }
    if { $opt(serial) && $opt(postfix) != "" } {
        ::pwtk::error "cannot specify both -serial and -postfix; the latter is used exclusively for parallel execution" 1
    }

    # store the name of program, input & output files (they may be queried from other procs)
    
    set run(program) $program
    set run(input)  $input
    set run(output) $output

    #
    # determine prefix & postfix
    #

    if { ! $opt(serial) } {
        # parallel run 
        # (beware: do now swap below lines, because order matters !!!)
        set prefix  [::pwtk::getVar_ RUNopt(PREFIX)]
        set postfix [::pwtk::getVar_ RUNopt(POSTFIX)]

        if { [remote_mode_] && $remote_exec(rfull) } {
            set prefix  [remote_query_ {::pwtk::getVar_ RUNopt(PREFIX)}]
            set postfix [remote_query_ {::pwtk::getVar_ RUNopt(POSTFIX)}]
        }

        if { $opt(prefix)  != "" } { set prefix  $opt(prefix) }
        if { $opt(postfix) != "" } { set postfix $opt(postfix) }        
    } else {
        # serial run
        set prefix  [::pwtk::getVar_ RUNopt(SERIAL_PREFIX)]
        set 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 { [remote_mode_] } {
            remote_execok_ $prog complain
        } else {            
            if { [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 
    # (there must be a local copy of input in any case)

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

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

    #
    # RUN: either locally or remotely
    #
    set rr [string trim "$prefix [file tail $prog] $postfix"]

    if { ! [remote_mode_] } {
        #
        # run locally
        #

        ::pwtk::print "Running: $rr $ihandle $input $redirect $output\n"

        # check if the output file is writeable
        
        if { [catch {set fID [open $output a]}] } {
            close $fID
            ::pwtk::error "output file $output is not writable" 1
        }
        close $fID

        catch { set host_ [exec hostname] }
    
        if { $host_ != "" } {
            # Write to $output on which host the calculation is run 
            ::pwtk::writeFile $output "### Running on host: $host_" $mode
            set redirect ">>"
        }

        ########################################################################
        #
        if { [catch {eval exec $prefix $prog $postfix $ihandle $input $redirect $output} errMsg] } {
            ::pwtk::writeFile $output.error $errMsg
            checkForError $output.error $prog $state(stopOnError)
        }
        #
        ########################################################################

        checkForError $output $prog $state(stopOnError)

    } else {
        #
        # run remotely
        #

        global   env

        ::pwtk::print "Running remotely on $remote_exec(host): $rr $ihandle $input $redirect $output\n"

        # determine the calculation directory

        set dir [::fileutil::stripPath $env(HOME) [pwd]]

        if { $remote_exec(rdir) != "" } {
            set dir $remote_exec(rdir)
        }           

        # check if the input & output files are writeable on remote-host

        remote_writeable_ [file join $dir $input]
        remote_writeable_ [file join $dir $output]

        # make a remote shell-script wrapper

        set scriptFile [remote_scriptName_ sh]

        writeFile $scriptFile ""
        
        if { [info exists env(PATH)] } {
            writeFile $scriptFile "
PATH=$env(PATH)
export PATH
" a
        }
        if { [info exists env(LD_LIBRARY_PATH)] } {
            writeFile $scriptFile "                   
LD_LIBRARY_PATH=$env(LD_LIBRARY_PATH)
export LD_LIBRARY_PATH
" a
        }
        writeFile $scriptFile "
echo \"### Running on host: $remote_exec(host)\" $redirect $output
$prefix $prog $postfix $ihandle $input >> $output
rm -f $scriptFile
" a

        if { $remote_exec(rfs) } {                 
            # running directory is on remote-file system;
            # copy the input & script files to remote host          
            exec $remote(rcp) $input      $remote_exec(host):[file join $dir $input]
            exec $remote(rcp) $scriptFile $remote_exec(host):[file join $dir $scriptFile]
        }
        
        ########################################################################
        # run remotely  
        set head [file rootname $output]
        catch {
            eval {exec $remote(rsh)} $remote(rsh_bg_opts) {$remote_exec(host) "cd $dir; $remote(nohup) $remote(shell) $scriptFile $redirect $head.remote.log 2>&1 &"}
        }
        #
        ########################################################################

        if { ! $remote_exec(bg) } {
            #
            # wait for calculation to finish 
            # (i.e. when calculation finishes the script file is deleted)           
            #
            set finished 0
            while { ! $finished } {             

                after $remote(time_interval)

                if { $remote_exec(rfs) } {        
                    set finished [remote_execTclScript_ "
                        if { \[file exists \[file join $dir $scriptFile]] } {
                            puts 0
                        } else {
                            puts 1
                        }
                    "]

                } else {
                    if { ! [file exists $scriptFile] } {
                        set finished 1
                    }
                }
            }
        
            # calculation is finished; copy the output file and check for error

            if { $remote_exec(rfs) } {
                exec $remote(rcp)  $remote_exec(host):[file join $dir $output]  $output
            }
            checkForError $output $prog $state(stopOnError)
        }

        if { $remote_exec(rfs) } {
            # the local script file has not yet been deleted 
            #
            # BEWARE: if remote and local filesystems are identical
            # then there should be some delay before the script file
            # is deleted or else it may happen that it will be deleted
            # before the script is executed on remote host !!!
            
            if { $remote_exec(bg) } {
                # wait for 10 seconds, then delete the file
                delayed_exec 10000 catch "file delete $scriptFile"
            }
        }
    }
}