From 4a2b35f347657ce66a91fdb0adeb6d79ab3ef800 Mon Sep 17 00:00:00 2001 From: Andreas Hellander Date: Thu, 6 Apr 2017 14:29:45 +0000 Subject: [PATCH 1/9] Working on bugfix for #21 --- gillespy/__init__.py | 3 +++ gillespy/gillespy.py | 19 ++++++++++++------- 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/gillespy/__init__.py b/gillespy/__init__.py index cd3a064..71b2f78 100644 --- a/gillespy/__init__.py +++ b/gillespy/__init__.py @@ -1 +1,4 @@ from .gillespy import * +import os +os.environ["PATH"] += os.pathsep + "/usr/local/stochss/StochKit/" +os.environ["PATH"] += os.pathsep + "/usr/local/stochss/ode/" diff --git a/gillespy/gillespy.py b/gillespy/gillespy.py index 3969d15..9373afc 100644 --- a/gillespy/gillespy.py +++ b/gillespy/gillespy.py @@ -318,7 +318,7 @@ class Reaction(): """ def __init__(self, name = "", reactants = {}, products = {}, - propensity_function = None, massaction = False, + propensity_function = None, massaction = True, rate=None, annotation=None): """ Initializes the reaction using short-hand notation. @@ -343,8 +343,8 @@ def __init__(self, name = "", reactants = {}, products = {}, self.name = name self.annotation = "" - if rate is None and propensity_function is None: - raise ReactionError("You must specify either a mass-action rate or a propensity function") + #if rate is None and propensity_function is None: + # raise ReactionError("You must specify either a mass-action rate or a propensity function") # We might use this flag in the future to automatically generate # the propensity function if set to True. @@ -378,10 +378,12 @@ def __init__(self, name = "", reactants = {}, products = {}, if self.massaction: self.type = "mass-action" if rate is None: - raise ReactionError("Reaction : A mass-action propensity has\ - to have a rate.") - self.marate = rate - self.create_mass_action() + self.marate=None + # raise ReactionError("Reaction : A mass-action propensity has\ + # to have a rate.") + else: + self.marate = rate + self.create_mass_action() else: self.type = "customized" @@ -642,6 +644,9 @@ def to_model(self,name): type = reac.find('Type').text except: raise InvalidStochMLError("No reaction type specified.") + + #reaction = Reaction(name,{},{},None,False,0.0,None) + reactants = reac.find('Reactants') try: From f9646713c4eb8965ffe7935dc5b9f95b640e5231 Mon Sep 17 00:00:00 2001 From: Andreas Hellander Date: Thu, 4 Oct 2018 12:49:18 +0200 Subject: [PATCH 2/9] added solver timeout --- gillespy/gillespy.py | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/gillespy/gillespy.py b/gillespy/gillespy.py index 9373afc..fb0559e 100644 --- a/gillespy/gillespy.py +++ b/gillespy/gillespy.py @@ -12,7 +12,7 @@ import matplotlib.pyplot as plt import tempfile import uuid -import subprocess +import subprocess32 as subprocess import types import random @@ -239,14 +239,14 @@ def delete_reaction(self, obj): def delete_all_reactions(self): self.listOfReactions.clear() - def run(self, number_of_trajectories=1, seed=None, report_level=0, solver=None, stochkit_home=None, debug=False): + def run(self, number_of_trajectories=1, seed=None, report_level=0, solver=None, stochkit_home=None, debug=False,timeout=None): if solver is not None: if isinstance(solver, (type, types.ClassType)) and issubclass(solver, GillesPySolver): - return solver.run(self,t=self.tspan[-1],increment=self.tspan[-1]-self.tspan[-2],seed=seed,number_of_trajectories=number_of_trajectories, stochkit_home=stochkit_home, debug=debug) + return solver.run(self,t=self.tspan[-1],increment=self.tspan[-1]-self.tspan[-2],seed=seed,number_of_trajectories=number_of_trajectories, stochkit_home=stochkit_home, debug=debug,timeout=None) else: raise SimuliationError('argument "solver" to run() must be a subclass of GillesPySolver') else: - return StochKitSolver.run(self,t=self.tspan[-1],increment=self.tspan[-1]-self.tspan[-2],seed=seed,number_of_trajectories=number_of_trajectories, stochkit_home=stochkit_home, debug=debug) + return StochKitSolver.run(self,t=self.tspan[-1],increment=self.tspan[-1]-self.tspan[-2],seed=seed,number_of_trajectories=number_of_trajectories, stochkit_home=stochkit_home, debug=debug,timeout=None) class Species(): @@ -825,7 +825,7 @@ class GillesPySolver(): def run(self, model, t=20, number_of_trajectories=1, increment=0.05, seed=None, stochkit_home=None, algorithm=None, - job_id=None, extra_args='', debug=False): + job_id=None, extra_args='', debug=False,timeout=None): """ Call out and run the solver. Collect the results. """ @@ -918,7 +918,14 @@ def run(self, model, t=20, number_of_trajectories=1, try: #print "CMD: {0}".format(cmd) handle = subprocess.Popen(cmd, stdout = subprocess.PIPE, stderr=subprocess.PIPE, shell=True) - return_code = handle.wait() + #return_code = handle.wait() + try: + outs, errs = handle.communicate(timeout=timeout) + except TimeoutExpired: + handle.kill() + outs, errs = handle.communicate() + raise SolverTimeoutError("Solver timed out") + except OSError as e: raise SimuliationError("Solver execution failed: \ {0}\n{1}".format(cmd, e)) @@ -966,7 +973,7 @@ class StochKitSolver(GillesPySolver): @classmethod def run(cls, model, t=20, number_of_trajectories=1, increment=0.05, seed=None, stochkit_home=None, algorithm='ssa', - job_id=None, method=None,debug=False): + job_id=None, method=None,debug=False,timeout=None): # all this is specific to StochKit if model.units == "concentration": @@ -998,7 +1005,7 @@ def run(cls, model, t=20, number_of_trajectories=1, self = StochKitSolver() - return GillesPySolver.run(self, model,t, number_of_trajectories, increment, seed, stochkit_home, algorithm, job_id, extra_args=args, debug=debug) + return GillesPySolver.run(self, model,t, number_of_trajectories, increment, seed, stochkit_home, algorithm, job_id, extra_args=args, debug=debug,timeout=timeout) def get_trajectories(self, outdir, debug=False): # Collect all the output data @@ -1053,6 +1060,9 @@ class InvalidStochMLError(Exception): class InvalidModelError(Exception): pass +class SolverTimeoutError(Exception): + pass + class SimulationError(Exception): pass From cf19fcc830b4d397724ba81f9d547de400f48bb9 Mon Sep 17 00:00:00 2001 From: Andreas Hellander Date: Thu, 4 Oct 2018 12:56:51 +0200 Subject: [PATCH 3/9] added solver timeout --- gillespy/gillespy.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gillespy/gillespy.py b/gillespy/gillespy.py index fb0559e..57bd8df 100644 --- a/gillespy/gillespy.py +++ b/gillespy/gillespy.py @@ -921,7 +921,7 @@ def run(self, model, t=20, number_of_trajectories=1, #return_code = handle.wait() try: outs, errs = handle.communicate(timeout=timeout) - except TimeoutExpired: + except subprocess.TimeoutExpired: handle.kill() outs, errs = handle.communicate() raise SolverTimeoutError("Solver timed out") From 0bd72141429d9a2c73957bb1b51798f6911396b5 Mon Sep 17 00:00:00 2001 From: Andreas Hellander Date: Thu, 4 Oct 2018 12:58:51 +0200 Subject: [PATCH 4/9] added solver timeout --- gillespy/gillespy.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/gillespy/gillespy.py b/gillespy/gillespy.py index 57bd8df..488aae7 100644 --- a/gillespy/gillespy.py +++ b/gillespy/gillespy.py @@ -921,9 +921,11 @@ def run(self, model, t=20, number_of_trajectories=1, #return_code = handle.wait() try: outs, errs = handle.communicate(timeout=timeout) + return_code = 0 except subprocess.TimeoutExpired: handle.kill() outs, errs = handle.communicate() + return_code=-1 raise SolverTimeoutError("Solver timed out") except OSError as e: From 63ae0234f773b3b5ce19123621afda5b3899f3de Mon Sep 17 00:00:00 2001 From: Andreas Hellander Date: Thu, 4 Oct 2018 14:26:02 +0200 Subject: [PATCH 5/9] added solver timeout --- gillespy/gillespy.py | 45 ++++++++++++++++++++++---------------------- 1 file changed, 23 insertions(+), 22 deletions(-) diff --git a/gillespy/gillespy.py b/gillespy/gillespy.py index 488aae7..19a6162 100644 --- a/gillespy/gillespy.py +++ b/gillespy/gillespy.py @@ -915,31 +915,32 @@ def run(self, model, t=20, number_of_trajectories=1, print "cmd: {0}".format(cmd) # Execute - try: + #try: #print "CMD: {0}".format(cmd) - handle = subprocess.Popen(cmd, stdout = subprocess.PIPE, stderr=subprocess.PIPE, shell=True) + #handle = subprocess.Popen(cmd, stdout = subprocess.PIPE, stderr=subprocess.PIPE, shell=True) + handle = subprocess.Popen(cmd) #return_code = handle.wait() - try: - outs, errs = handle.communicate(timeout=timeout) - return_code = 0 - except subprocess.TimeoutExpired: - handle.kill() - outs, errs = handle.communicate() - return_code=-1 - raise SolverTimeoutError("Solver timed out") - - except OSError as e: - raise SimuliationError("Solver execution failed: \ - {0}\n{1}".format(cmd, e)) - try: - stderr = handle.stderr.read() - except Exception as e: - stderr = 'Error reading stderr: {0}'.format(e) - try: - stdout = handle.stdout.read() - except Exception as e: - stdout = 'Error reading stdout: {0}'.format(e) + outs, errs = handle.communicate(timeout=timeout) + return_code = 0 + except subprocess.TimeoutExpired: + handle.kill() + outs, errs = handle.communicate() + return_code=-1 + raise SolverTimeoutError("Solver timed out") + + #except OSError as e: + # raise SimuliationError("Solver execution failed: \ + # {0}\n{1}".format(cmd, e)) + + #try: + # stderr = handle.stderr.read() + #except Exception as e: + # stderr = 'Error reading stderr: {0}'.format(e) + #try: + # stdout = handle.stdout.read() + #except Exception as e: + # stdout = 'Error reading stdout: {0}'.format(e) if return_code != 0: #print stdout From 425b65648b1bf00c755de6bfe4b2c2bc36fd5363 Mon Sep 17 00:00:00 2001 From: Andreas Hellander Date: Thu, 4 Oct 2018 14:29:37 +0200 Subject: [PATCH 6/9] added solver timeout --- gillespy/gillespy.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gillespy/gillespy.py b/gillespy/gillespy.py index 19a6162..8be7328 100644 --- a/gillespy/gillespy.py +++ b/gillespy/gillespy.py @@ -921,7 +921,7 @@ def run(self, model, t=20, number_of_trajectories=1, handle = subprocess.Popen(cmd) #return_code = handle.wait() try: - outs, errs = handle.communicate(timeout=timeout) + outs, errs = handle.communicate(timeout=timeout,shell=True) return_code = 0 except subprocess.TimeoutExpired: handle.kill() From c2c1d684979c11b6afd8656b40e9ffa488085a1f Mon Sep 17 00:00:00 2001 From: Andreas Hellander Date: Thu, 4 Oct 2018 14:31:14 +0200 Subject: [PATCH 7/9] added solver timeout --- gillespy/gillespy.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gillespy/gillespy.py b/gillespy/gillespy.py index 8be7328..ffa0471 100644 --- a/gillespy/gillespy.py +++ b/gillespy/gillespy.py @@ -918,10 +918,10 @@ def run(self, model, t=20, number_of_trajectories=1, #try: #print "CMD: {0}".format(cmd) #handle = subprocess.Popen(cmd, stdout = subprocess.PIPE, stderr=subprocess.PIPE, shell=True) - handle = subprocess.Popen(cmd) + handle = subprocess.Popen(cmd,shell=True) #return_code = handle.wait() try: - outs, errs = handle.communicate(timeout=timeout,shell=True) + outs, errs = handle.communicate(timeout=timeout) return_code = 0 except subprocess.TimeoutExpired: handle.kill() From ca4b3a75ce20ed1385921bb6bed3fde73ed4f0d4 Mon Sep 17 00:00:00 2001 From: Andreas Hellander Date: Thu, 4 Oct 2018 14:36:22 +0200 Subject: [PATCH 8/9] added solver timeout --- gillespy/gillespy.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/gillespy/gillespy.py b/gillespy/gillespy.py index ffa0471..04505df 100644 --- a/gillespy/gillespy.py +++ b/gillespy/gillespy.py @@ -242,11 +242,11 @@ def delete_all_reactions(self): def run(self, number_of_trajectories=1, seed=None, report_level=0, solver=None, stochkit_home=None, debug=False,timeout=None): if solver is not None: if isinstance(solver, (type, types.ClassType)) and issubclass(solver, GillesPySolver): - return solver.run(self,t=self.tspan[-1],increment=self.tspan[-1]-self.tspan[-2],seed=seed,number_of_trajectories=number_of_trajectories, stochkit_home=stochkit_home, debug=debug,timeout=None) + return solver.run(self,t=self.tspan[-1],increment=self.tspan[-1]-self.tspan[-2],seed=seed,number_of_trajectories=number_of_trajectories, stochkit_home=stochkit_home, debug=debug,timeout=timeout) else: raise SimuliationError('argument "solver" to run() must be a subclass of GillesPySolver') else: - return StochKitSolver.run(self,t=self.tspan[-1],increment=self.tspan[-1]-self.tspan[-2],seed=seed,number_of_trajectories=number_of_trajectories, stochkit_home=stochkit_home, debug=debug,timeout=None) + return StochKitSolver.run(self,t=self.tspan[-1],increment=self.tspan[-1]-self.tspan[-2],seed=seed,number_of_trajectories=number_of_trajectories, stochkit_home=stochkit_home, debug=debug,timeout=timeout) class Species(): @@ -925,7 +925,7 @@ def run(self, model, t=20, number_of_trajectories=1, return_code = 0 except subprocess.TimeoutExpired: handle.kill() - outs, errs = handle.communicate() + outs, errs = handle.communicate(timeout=timeout) return_code=-1 raise SolverTimeoutError("Solver timed out") From cda6a177f8591e4312cc0749a56f31b4ccd31c27 Mon Sep 17 00:00:00 2001 From: Andreas Hellander Date: Thu, 22 Nov 2018 22:49:51 +0000 Subject: [PATCH 9/9] kill chiled processes on timeout --- gillespy/gillespy.py | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/gillespy/gillespy.py b/gillespy/gillespy.py index 04505df..18043f6 100644 --- a/gillespy/gillespy.py +++ b/gillespy/gillespy.py @@ -15,6 +15,9 @@ import subprocess32 as subprocess import types import random +import os +import signal +import psutil try: import lxml.etree as etree @@ -878,6 +881,7 @@ def run(self, model, t=20, number_of_trajectories=1, algorithm)): executable = os.path.join(os.environ.get('STOCHKIT_HOME'), algorithm) + if executable is None: # try to find the executable in the path if os.environ.get('PATH') is not None: @@ -918,12 +922,17 @@ def run(self, model, t=20, number_of_trajectories=1, #try: #print "CMD: {0}".format(cmd) #handle = subprocess.Popen(cmd, stdout = subprocess.PIPE, stderr=subprocess.PIPE, shell=True) - handle = subprocess.Popen(cmd,shell=True) + handle = subprocess.Popen(cmd,shell=True, preexec_fn=os.setsid) #return_code = handle.wait() try: outs, errs = handle.communicate(timeout=timeout) return_code = 0 except subprocess.TimeoutExpired: + #os.killpg(os.getpgid(handle.pid),signal.SIGTERM) + #print os.getpgid(handle.pid) + parent = psutil.Process(handle.pid) + for child in parent.children(recursive=True): # or parent.children() for recursive=False + child.kill() handle.kill() outs, errs = handle.communicate(timeout=timeout) return_code=-1