From f043f013d6f8bbe285794758b4344c2541149e14 Mon Sep 17 00:00:00 2001
From: Daniel Brown <ddb@star.sr.bham.ac.uk>
Date: Fri, 24 Jul 2015 19:04:25 +0100
Subject: [PATCH] adding in parakat object to run multiple kat objects at once
 using ipython cluster feature.

---
 pykat/finesse.py  | 15 ++++++--
 pykat/parallel.py | 91 +++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 103 insertions(+), 3 deletions(-)
 create mode 100644 pykat/parallel.py

diff --git a/pykat/finesse.py b/pykat/finesse.py
index e582425..760c072 100644
--- a/pykat/finesse.py
+++ b/pykat/finesse.py
@@ -1107,7 +1107,7 @@ class kat(object):
         except pkex.BasePyKatException as ex:
             print (ex)
 
-    def run(self, printout=0, printerr=0, plot=None, save_output=False, save_kat=False, kat_name=None, cmd_args=None, getTraceData=False):
+    def run(self, printout=0, printerr=0, plot=None, save_output=False, save_kat=False, kat_name=None, cmd_args=None, getTraceData=False, rethrowExceptions=False):
         """ 
         Runs the current simulation setup that has been built thus far.
         It returns a katRun or katRun2D object which is populated with the various
@@ -1124,6 +1124,8 @@ class kat(object):
         that Finesse performs, the keys are the node names and the values
         are the x and y beam parameters. If no tracing is done a None
         is returned.
+        
+        rethrowExceptions - if true exceptions will be thrown again rather than being excepted and calling sys.exit()
         """
         start = datetime.datetime.now()
         
@@ -1423,9 +1425,16 @@ class kat(object):
         except KeyboardInterrupt as ex:
             print("Keyboard interrupt caught, stopped simulation.")
         except pkex.FinesseRunError as ex:
-            pkex.PrintError("Error from Finesse:", ex)
+            if rethrowExceptions:
+                raise ex 
+            else:
+                pkex.PrintError("Error from Finesse:", ex)
+                
         except pkex.BasePyKatException as ex:
-            pkex.PrintError("Error from pykat:", ex)
+            if rethrowExceptions:
+                raise ex 
+            else:
+                pkex.PrintError("Error from pykat:", ex)
         finally:
             if self.verbose: print ("")
             if self.verbose: print ("Finished in " + str(datetime.datetime.now()-start))
diff --git a/pykat/parallel.py b/pykat/parallel.py
new file mode 100644
index 0000000..5fec9a5
--- /dev/null
+++ b/pykat/parallel.py
@@ -0,0 +1,91 @@
+# -*- coding: utf-8 -*-
+"""
+Created on Sun Jan 27 09:56:53 2013
+
+PyKat - Python interface and wrapper for FINESSE
+Copyright (C) 2013 Daniel David Brown
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along
+with this program; if not, write to the Free Software Foundation, Inc.,
+51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+Contact at ddb@star.sr.bham.ac.uk
+
+@author: Daniel Brown
+"""
+
+from IPython.parallel import Client
+import sys
+import os
+
+def _run(commands, pwd):
+    import os
+    os.chdir(pwd)
+    
+    import pykat
+
+    kat = pykat.finesse.kat()
+    kat.parseCommands(commands)
+    out = kat.run(rethrowExceptions=True)
+    
+    return out
+
+class parakat(object):
+    """
+    Uses the ipython clustering for running kat objects in parallel.
+    
+    To use this you must have started an ipython cluster on your computer.
+    From a new terminal use the command:
+        
+        ipcluster start -n 4
+        
+    This will start a cluster with 4 workers.
+    
+    To run a kat object use:
+    
+        pk = parakat()
+        pk.run(kat1)
+        pk.run(kat2)
+        pk.run(kat3)
+        
+        outs = pk.getResults()
+    
+    The list 'outs' will contain the katRun object you'd normal get if you 
+    had just called, kat1.run(), etc. The results list is matched to order
+    in which you run the kats.
+    
+    If you need to stop long running kat processes the chances are you will
+    also need to kill the ipython cluster process, as sometimes they carry
+    on running.
+    """
+    
+    def __init__(self):
+        self._rc = Client()
+        self._lview = self._rc.load_balanced_view()
+        self._lview.block = False
+        self._results = []
+        
+    def run(self, kat):
+        print(kat)
+        self._results.append(self._lview.apply_async(_run, "".join(kat.generateKatScript()), os.getcwd()))
+        print(self._results)
+        
+    def getResults(self):
+        out = []
+        
+        self._lview.wait(self._results)
+        
+        for done in self._results:
+            out.append(done.get())
+            
+        return out
-- 
GitLab