Tools
Submitting from a Rappture tool
How a Rappture wrapper script calls submit to run its simulation on a
cluster instead of in the tool session. The page is kept for hubs that
still run Rappture tools.
The pattern is the same in every language. Build a small shell script that
runs submit in the background, run that script through the Rappture
helper that forwards signals, and gather the job's output files afterwards.
Handling the signal matters: without it, pressing Abort in the tool
leaves the remote job running and consuming the hub's resource allocation.
TCL wrapper script
Catch the Abort interrupt first. Setting execctl to 1 terminates the
process and its children.
package require Rappture
Rappture::signal SIGHUP sHUP {
puts "Caught SIGHUP"
set execctl 1
}
Rappture::signal SIGTERM sTERM {
puts "Caught SIGTERM"
set execctl 1
}
Then build a script to run with Rappture::exec. The trap statement
catches the interrupt raised when the wrapper is aborted. Putting submit
in the background allows several submit commands in one script, and
wait holds the script open until they have all finished.
set submitScript "#!/bin/sh\n\n"
append submitScript "trap cleanup HUP INT QUIT ABRT TERM\n\n"
append submitScript "cleanup()\n"
append submitScript "{\n"
append submitScript " kill -TERM `jobs -p`\n"
append submitScript " exit 1\n"
append submitScript "}\n\n"
append submitScript "cd [pwd]\n"
append submitScript "submit -v cluster -n $cores -w $walltime\\\n"
append submitScript " COMMAND ARGUMENTS &\n"
append submitScript "sleep 5\n"
append submitScript "wait\n"
set submitScriptPath [file join [pwd] submit_script.sh]
set fid [open $submitScriptPath w]
puts $fid $submitScript
close $fid
file attributes $submitScriptPath -permissions 00755
Run it the usual way. The output of every submit command in the script is
streamed to the display and kept in out.
set status [catch {Rappture::exec $submitScriptPath} out]
Each submit command writes the command's standard output and error to
JOBID.stdout and JOBID.stderr, where JOBID is the run identifier
submit assigned. Gather them like this.
set out2 ""
foreach errfile [glob -nocomplain *.stderr] {
if [file size $errfile] {
if {[catch {open $errfile r} fid] == 0} {
set info [read $fid]
close $fid
append out2 $info
}
}
file delete -force $errfile
}
foreach outfile [glob -nocomplain *.stdout] {
if [file size $outfile] {
if {[catch {open $outfile r} fid] == 0} {
set info [read $fid]
close $fid
append out2 $info
}
}
file delete -force $outfile
}
Remove the script, then present the gathered text as the job's output log. Everything after that is ordinary result processing.
file delete -force $submitScriptPath
$driver put output.log $out2
Python wrapper script
Import the helper that runs a command and traps the signals the Abort
button raises. submit must finish before RapptureExec returns.
import os
import re
from Rappture.tools import executeCommand as RapptureExec
Build the command as a list and run it. Its output is streamed to the
display and kept in stdOutput.
submitCommand = ["submit", "-v", venue, "-n", cores,
"-w", walltime, COMMAND, ARGUMENTS]
exitStatus, stdOutput, stdError = RapptureExec(submitCommand)
Gather the job's own output files afterwards, then hand the text to the output log.
reStdout = re.compile(".*.stdout$")
reStderr = re.compile(".*.stderr$")
out2 = ""
errFiles = list(filter(reStderr.search, os.listdir(os.getcwd())))
for errFile in errFiles:
errFilePath = os.path.join(os.getcwd(), errFile)
if os.path.getsize(errFilePath) > 0:
f = open(errFilePath, 'r')
outFileLines = f.readlines()
f.close()
out2 += '\n' + ''.join(outFileLines)
os.remove(errFilePath)
outFiles = list(filter(reStdout.search, os.listdir(os.getcwd())))
for outFile in outFiles:
outFilePath = os.path.join(os.getcwd(), outFile)
if os.path.getsize(outFilePath) > 0:
f = open(outFilePath, 'r')
outFileLines = f.readlines()
f.close()
out2 += '\n' + ''.join(outFileLines)
os.remove(outFilePath)
lib.put("output.log", out2, append=1)
Perl wrapper
Catch the Abort interrupt.
use Rappture;
my $ChildPID = 0;
sub trapSig {
print "Signal @_ trapped\n";
if($ChildPID != 0) {
kill 'TERM', $ChildPID;
exit 1;
}
}
$SIG{TERM} = \&trapSig;
$SIG{HUP} = \&trapSig;
$SIG{INT} = \&trapSig;
Build the shell script. trap catches the interrupt raised on abort, and
wait holds the script open until submit finishes.
$SCRPT = "submit_app.sh";
open(FID,">$SCRPT");
print FID "#!/bin/sh\n";
print FID "\n";
print FID "trap cleanup HUP INT QUIT ABRT TERM\n\n";
print FID "cleanup()\n";
print FID "{\n";
print FID " kill -s TERM `jobs -p`\n";
print FID " exit 1\n";
print FID "}\n\n";
print FID "submit -v cluster -n $cores -w $wallTime COMMAND ARGUMENTS &\n";
print FID "wait %1\n";
print FID "exitStatus=\$?\n";
print FID "exit \$exitStatus\n";
close(FID);
chmod 0775, $SCRPT;
Run it with the usual fork and exec. This route cannot stream the command's output.
if (!defined($ChildPID = fork())) {
die "cannot fork: $!";
} elsif ($ChildPID == 0) {
exec("./$SCRPT") or die "cannot exec $SCRPT: $!";
exit(0);
} else {
waitpid($ChildPID,0);
}
The JOBID.stdout and JOBID.stderr files are gathered with ordinary Perl
file matching and reading, and result processing proceeds as normal.
Octave and MATLAB scripts
rpExec runs a command and terminates it on an interrupt, hangup or
terminate signal, so the process stops when Abort is pressed.
-- Function: [EXITSTATUS] = rpExec(COMMAND,STREAMOUTPUT)
-- Function: [EXITSTATUS, STDOUTPUT] = rpExec(COMMAND,STREAMOUTPUT)
-- Function: [EXITSTATUS, STDOUTPUT, STDERROR] = rpExec(COMMAND,STREAMOUTPUT)
COMMAND is the set of strings making up the command to run. When
STREAMOUTPUT is 1, the command's standard output and error are piped
back to the current process as it runs. EXITSTATUS is 0 when no error
occurred; STDOUTPUT and STDERROR, if asked for, hold copies of the two
streams.
[exitStatus,stdOutput,stdError] = rpExec({"submit","--wallTime","30","lammps-03Mar20-serial","-in","lmp.in"},1);
Reviewed against 2.4-main @ e097e0236d on 2026-09-10.