AsynQueue : mcmandelbrot.main.py

#!/usr/bin/env python
#
# mcmandelbrot
#
# An example package for AsynQueue:
# Asynchronous task queueing based on the Twisted framework, with task
# prioritization and a powerful worker interface.
#
# Copyright (C) 2015 by Edwin A. Suominen,
# http://edsuom.com/AsynQueue
#
# See edsuom.com for API documentation as well as information about
# Ed's background and other projects, software and otherwise.
# 
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the
# License. You may obtain a copy of the License at
# 
#   http://www.apache.org/licenses/LICENSE-2.0
# 
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an "AS
# IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
# express or implied. See the License for the specific language
# governing permissions and limitations under the License.


"""
An example of C{AsynQueue} in action. Can be fun to play with if
you have a multicore CPU. You will need the following packages, which
you can get via C{pip install}: C{weave} (part of SciPy); C{numpy}
(part of SciPy); C{matplotlib}; and of course C{asynqueue}.

B{TODO:} If you want to run with the Qt GUI (-g option), you also need
C{qt4reactor} and C{pyqt4}.

Command line usage::

  mcmandelbrot
    [-d <description>] [-N <iterations>]
    [-o <imageFile>]
    [-g] [-s] [-a <aspect ratio>]
    Nx cr ci crPM [ciPM]

Writes PNG image to stdout unless B{-o} is set, then saves it to
I{imageFile}. In that case, prints some stats about the
multiprocessing computation to I{stdout}.

To see an overview displayed with ImageMagick's I{display} command::

  mcmandelbrot 2000 -0.630 0 1.4 1.2 |display

Write a detailed view to the image I{detail.png}::

  mcmandelbrot -o detail.png 3000 -0.73249 +0.21653 0.0112
"""

import sys

from twisted.internet import defer, reactor

from mcmandelbrot import runner, wire


def run(*args, **kw):
    """
    Call with::

      [-d, <description>,] [-N, <values>,]
      [-o, <imageFile>,]
      [-g,] [-s,]
      Nx, cr, ci, crPM, [ciPM]

    Writes PNG image to stdout unless -o is set, then saves it to
    C{imageFile}. In that case, prints some stats about the
    multiprocessing computation to stdout.

    Options-as-arguments:
    
      - B{d}: An endpoint I{description} of a server running a
        L{wire.server}.

      - B{s}: Show image (B{TODO})

    @keyword N_values: Integer number of possible values for
      Mandelbrot points during iteration. Can set with the C{-N
      values} arg instead.
    
    @keyword ignoreReactor: Set C{True} to let somebody else start and
      stop the reactor.
    """
    @defer.inlineCallbacks
    def reallyRun():
        if description:
            myRunner = wire.RemoteRunner(description)
            yield myRunner.setup(N_values=N_values)
        else:
            myRunner = runner.Runner(N_values, stats)
        runInfo = yield myRunner.run(fh, Nx, cr, ci, crPM, ciPM)
        if stats:
            yield myRunner.showStats(runInfo)
        yield myRunner.shutdown()
        if not ignoreReactor:
            reactor.stop()
        defer.returnValue(runInfo)
        
    def getOpt(opt, default=None):
        optCode = "-{}".format(opt)
        if optCode in args:
            k = args.index(optCode)
            args.pop(k)
            if default is None:
                return
            optType = type(default)
            return optType(args.pop(k))
        return default
        
    ignoreReactor = kw.pop('ignoreReactor', False)
    if not args:
        args = sys.argv[1:]
    args = list(args)
    show = getOpt('s')
    N_values = getOpt('N', 2000)
    fileName = getOpt('o', "")
    description = getOpt('d', "")
    useGUI = getOpt('g')
    if fileName:
        stats = True
        fh = open(fileName, 'w')
    else:
        stats = False
        fh = sys.stdout
    if len(args) < 4:
        print(
            "Usage: [-N values] "+\
            "[-o imageFile] [-d description] [-g] [-s] " +\
            "N cr ci crPM [ciPM]")
        sys.exit(1)
    Nx = int(args[0])
    cr, ci, crPM = [float(x) for x in args[1:4]]
    ciPM = float(args[4]) if len(args) > 4 else crPM
    if useGUI:
        raise NotImplementedError("GUI not yet implemented")
        # TODO
        from PyQt4 import QtGui
        import qt4reactor
        import gui
        app = QtGui.QApplication(sys.argv)
        qt4reactor.install()
        w = gui.MainWindow(Nx, cr, ci, crPM)
        reactor.run()
    elif ignoreReactor:
        return reallyRun()
    else:
        reactor.callWhenRunning(reallyRun)
        reactor.run()


if __name__ == '__main__':
    run()