Part 5: A More Complex Example: Mandelbrot (OSG VERSION)¶
Description… why is this different from XSEDE?
Hands-On: Mandelbrot with Condor on OSG¶
This examples assumes that you are logged in to an OSG gateway node and that you can submit regular Condor jobs from that node to OSG.
In order for this example to work, we need to install an additional Python module, the Python Image Library (PIL). This is done via pip:
pip install PIL
Next, we need to download the Mandelbrot fractal generator itself as well as the shell wrapper scrip. It is really just a very simple python script that, if invoked on the command line, outputs a full or part of a Mandelbrot fractal as a PNG image. Download the scripts into your $HOME directory:
curl --insecure -Os https://raw.githubusercontent.com/radical-cybertools/radical.saga/devel/examples/tutorial/mandelbrot/mandelbrot.py
curl --insecure -Os https://raw.githubusercontent.com/radical-cybertools/radical.saga/devel/examples/tutorial/mandelbrot/mandelbrot.sh
You can give mandelbrot.py a test-drive locally by calculating a single-tiled 1024x1024 Mandelbrot fractal:
python mandelbrot.py 1024 1024 0 1024 0 1024 frac.gif
In your $HOME
directory, open a new file saga_mandelbrot_osg.py with your
favorite editor and paste the following content here
:
__author__ = "Ole Weidner"
__copyright__ = "Copyright 2012-2013, The SAGA Project"
__license__ = "MIT"
import sys
import time
from PIL import Image
import radica.saga as rs
REMOTE_JOB_ENDPOINT = "condor://localhost"
# the dimension (in pixel) of the whole fractal
IMGX = 2048
IMGY = 2048
# the number of tiles in X and Y direction
TILESX = 2
TILESY = 2
if __name__ == "__main__":
try:
# list that holds the jobs
jobs = []
jobservice = rs.job.Service(REMOTE_JOB_ENDPOINT)
for x in range(0, TILESX):
for y in range(0, TILESY):
# describe a single Mandelbrot job. we're using the
# directory created above as the job's working directory
outputfile = 'tile_x%s_y%s.gif' % (x, y)
jd = rs.job.Description()
# candidate hosts can be changed / and or commented out
# the list below seems to be a good working set for OSG
#jd.candidate_hosts = ["FNAL_FERMIGRID", "cinvestav", "SPRACE",
# "NYSGRID_CORNELL_NYS1", "Purdue-Steele",
# "MIT_CMS_CE2", "SWT2_CPB", "AGLT2_CE_2",
# "UTA_SWT2", "GridUNESP_CENTRAL",
# "USCMS-FNAL-WC1-CE3"]
# on OSG we need to stage in the data with the jobs. we
# can't use the saga filesystem API to copy data around since
# the execution location of the jobs is not known a priori
jd.file_transfer = ["mandelbrot.sh > mandelbrot.sh",
"mandelbrot.py > mandelbrot.py",
"%s < %s" % (outputfile, outputfile)]
jd.wall_time_limit = 10
jd.total_cpu_count = 1
jd.executable = '/bin/sh'
jd.arguments = ['mandelbrot.sh', IMGX, IMGY,
(IMGX/TILESX*x), (IMGX/TILESX*(x+1)),
(IMGY/TILESY*y), (IMGY/TILESY*(y+1)),
outputfile]
# create the job from the description
# above, launch it and add it to the list of jobs
job = jobservice.create_job(jd)
job.run()
jobs.append(job)
print(' * Submitted %s. Output will be written to: %s' % (job.id, outputfile))
# wait for all jobs to finish
while len(jobs) > 0:
for job in jobs:
jobstate = job.get_state()
print(' * Job %s status: %s' % (job.id, jobstate))
if jobstate in [rs.job.DONE, rs.job.FAILED]:
jobs.remove(job)
time.sleep(5)
# stitch together the final image
fullimage = Image.new('RGB', (IMGX, IMGY), (255, 255, 255))
print(' * Stitching together the whole fractal: mandelbrot_full.gif')
for x in range(0, TILESX):
for y in range(0, TILESY):
partimage = Image.open('tile_x%s_y%s.gif' % (x, y))
fullimage.paste(partimage,
(IMGX/TILESX*x, IMGY/TILESY*y,
IMGX/TILESX*(x+1), IMGY/TILESY*(y+1)))
fullimage.save("mandelbrot_full.gif", "GIF")
sys.exit(0)
except rs.SagaException as ex:
# Catch all saga exceptions
print("An exception occured: (%s) %s " % (ex.type, (str(ex))))
# Trace back the exception. That can be helpful for debugging.
print(" \n*** Backtrace:\n %s" % ex.traceback)
sys.exit(-1)
except KeyboardInterrupt:
# ctrl-c caught: try to cancel our jobs before we exit
# the program, otherwise we'll end up with lingering jobs.
for job in jobs:
job.cancel()
sys.exit(-1)