def _validate_resume(self, t: int, resume): """ Validate `resume`. An exception will be thrown if resume['time'][-1] is > t. """ if resume is None: return if t < resume["time"][-1]: raise gillespyError.ExecutionError( "'t' must be greater than previous simulations end time, or set in the run() method as the " "simulations next end time" )
def run(self=None, model=None, t=20, number_of_trajectories=1, increment=0.05, seed=None, debug=False, profile=False, show_labels=True, **kwargs): if self is None: self = SSACSolver(model) if self.compiled: self.simulation_data = None number_timesteps = int(t // increment + 1) # Execute simulation. args = [ os.path.join(self.output_directory, 'UserSimulation'), '-trajectories', str(number_of_trajectories), '-timesteps', str(number_timesteps), '-end', str(t) ] if isinstance(seed, int): args.append('-seed') args.append(str(seed)) simulation = subprocess.run(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE) # Parse/return results. if simulation.returncode == 0: trajectory_base = parse_binary_output(simulation.stdout, number_of_trajectories, number_timesteps, len(self.species)) # Format results if show_labels: self.simulation_data = [] for trajectory in range(number_of_trajectories): data = {'time': trajectory_base[trajectory, :, 0]} for i in range(len(self.species)): data[self.species[i]] = trajectory_base[ trajectory, :, i + 1] self.simulation_data.append(data) else: self.simulation_data = trajectory_base else: raise gillespyError.ExecutionError( "Error encountered while running simulation C++ file:\nReturn code: {0}.\nError:\n{1}\n" .format(simulation.returncode, simulation.stderr)) return self.simulation_data
def _handle_return_code(self, return_code: "int") -> "SimulationReturnCode": """ Default return code handler; determines whether the simulation succeeded or failed. Intended to be overridden by solver subclasses, which handles solver-specific return codes. Does nothing if the return code checks out, otherwise raises an error. :param return_code: Return code returned by a simulation. :type return_code: int """ if return_code == 33: return SimulationReturnCode.PAUSED if return_code == 0: return SimulationReturnCode.DONE raise gillespyError.ExecutionError("Error encountered while running simulation C++ file " f"(return code: {int(return_code)})")
def __run(self, model, curr_state, total_time, timeline, trajectory_base, live_grapher, t=20, number_of_trajectories=1, increment=0.05, seed=None, debug=False, show_labels=True, resume=None, timeout=None): # for use with resume, determines how much excess data to cut off due to # how species and time are initialized to 0 timeStopped = 0 if resume is not None: if resume[0].model != model: raise gillespyError.ModelError( 'When resuming, one must not alter the model being resumed.' ) if t < resume['time'][-1]: raise gillespyError.ExecutionError( "'t' must be greater than previous simulations end time, or set in the run() method as the " "simulations next end time") random.seed(seed) species_mappings, species, parameter_mappings, number_species = nputils.numpy_initialization( model) # create dictionary of all constant parameters for propensity evaluation parameters = {'V': model.volume} for paramName, param in model.listOfParameters.items(): parameters[parameter_mappings[paramName]] = param.value # create mapping of reaction dictionary to array indices reactions = list(model.listOfReactions.keys()) # create mapping of reactions, and which reactions depend on their reactants/products dependent_rxns = nputils.dependency_grapher(model, reactions) number_reactions = len(reactions) propensity_functions = {} # create an array mapping reactions to species modified species_changes = np.zeros((number_reactions, number_species)) # pre-evaluate propensity equations from strings: for i, reaction in enumerate(reactions): # replace all references to species with array indices for j, spec in enumerate(species): species_changes[i][j] = model.listOfReactions[reaction].products.get(model.listOfSpecies[spec], 0) \ - model.listOfReactions[reaction].reactants.get(model.listOfSpecies[spec], 0) if debug: print('species_changes: {0},i={1}, j={2}... {3}'.format( species, i, j, species_changes[i][j])) propensity_functions[reaction] = [ eval( 'lambda S:' + model. listOfReactions[reaction].sanitized_propensity_function( species_mappings, parameter_mappings), parameters), i ] if debug: print('propensity_functions', propensity_functions) # begin simulating each trajectory simulation_data = [] for trajectory_num in range(number_of_trajectories): total_time[0] = 0 if self.stop_event.is_set(): self.rc = 33 break elif self.pause_event.is_set(): timeStopped = timeline[entry_count] break # For multi trajectories, live_grapher needs to be informed of trajectory increment if live_grapher[0] is not None: live_grapher[0].increment_trajectory(trajectory_num) # copy initial state data trajectory = trajectory_base[trajectory_num] entry_count = 1 curr_state[0] = {} # curr_time and curr_state are list of len 1 so that __run receives reference if resume is not None: curr_time = [resume['time'][-1]] else: curr_time = [0] for spec in model.listOfSpecies: if resume is not None: curr_state[0][spec] = resume[spec][-1] else: curr_state[0][spec] = model.listOfSpecies[ spec].initial_value propensity_sums = np.zeros(number_reactions) # calculate initial propensity sums while entry_count < timeline.size: if self.stop_event.is_set(): self.rc = 33 break elif self.pause_event.is_set(): timeStopped = timeline[entry_count] break # determine next reaction species_states = list(curr_state[0].values()) for i in range(number_reactions): propensity_sums[i] = propensity_functions[reactions[i]][0]( species_states) if debug: print('propensity: ', propensity_sums[i]) propensity_sum = np.sum(propensity_sums) if debug: print('propensity_sum: ', propensity_sum) # if no more reactions, quit if propensity_sum <= 0: trajectory[entry_count:, 1:] = list(species_states) break cumulative_sum = random.uniform(0, propensity_sum) curr_time[0] += -math.log(random.random()) / propensity_sum total_time[0] += -math.log(random.random()) / propensity_sum if debug: print('cumulative sum: ', cumulative_sum) print('entry count: ', entry_count) print('timeline.size: ', timeline.size) print('curr_time: ', curr_time[0]) # determine time passed in this reaction while entry_count < timeline.size and timeline[ entry_count] <= curr_time[0]: if self.stop_event.is_set(): self.rc = 33 break elif self.pause_event.is_set(): timeStopped = timeline[entry_count] break trajectory[entry_count, 1:] = species_states entry_count += 1 for potential_reaction in range(number_reactions): cumulative_sum -= propensity_sums[potential_reaction] if debug: print('if <=0, fire: ', cumulative_sum) if cumulative_sum <= 0: for i, spec in enumerate(model.listOfSpecies): curr_state[0][spec] += species_changes[ potential_reaction][i] reacName = reactions[potential_reaction] if debug: print('current state: ', curr_state[0]) print('species_changes: ', species_changes) print('updating: ', potential_reaction) species_states = list(curr_state[0].values()) for i in dependent_rxns[reacName]['dependencies']: propensity_sums[propensity_functions[i] [1]] = propensity_functions[i][0]( species_states) if debug: print('new propensity sum: ', propensity_sums[i]) break data = {'time': timeline} for i in range(number_species): data[species[i]] = trajectory[:, i + 1] simulation_data.append(data) # If simulation has been paused, or tstopped !=0 if timeStopped != 0 or resume is not None: simulation_data = nputils.numpy_resume(timeStopped, simulation_data, resume=resume) self.result = simulation_data return self.result, self.rc
def run(self=None, model=None, t=20, number_of_trajectories=1, timeout=0, increment=0.05, seed=None, debug=False, profile=False, resume=None, **kwargs): pause = False if resume is not None: if t < resume['time'][-1]: raise gillespyError.ExecutionError( "'t' must be greater than previous simulations end time, or set in the run() method as the " "simulations next end time") if resume is not None: self = SSACSolver(model, resume=resume) else: if self is None or self.model is None: self = SSACSolver(model) if len(kwargs) > 0: for key in kwargs: log.warning( 'Unsupported keyword argument to {0} solver: {1}'.format( self.name, key)) unsupported_sbml_features = { 'Rate Rules': len(model.listOfRateRules), 'Assignment Rules': len(model.listOfAssignmentRules), 'Events': len(model.listOfEvents), 'Function Definitions': len(model.listOfFunctionDefinitions) } detected_features = [] for feature, count in unsupported_sbml_features.items(): if count: detected_features.append(feature) if len(detected_features): raise gillespyError.ModelError( 'Could not run Model. SBML Feature: {} not supported by SSACSolver.' .format(detected_features)) if self.__compiled: self.simulation_data = None if resume is not None: t = abs(t - resume['time'][-1]) number_timesteps = int(round(t / increment + 1)) # Execute simulation. args = [ os.path.join(self.output_directory, 'UserSimulation'), '-trajectories', str(number_of_trajectories), '-timesteps', str(number_timesteps), '-end', str(t) ] if seed is not None: if isinstance(seed, int): args.append('-seed') args.append(str(seed)) else: seed_int = int(seed) if seed_int > 0: args.append('-seed') args.append(str(seed_int)) else: raise gillespyError.ModelError( "seed must be a positive integer") # begin subprocess c simulation with timeout (default timeout=0 will not timeout) with subprocess.Popen(args, stdout=subprocess.PIPE, start_new_session=True) as simulation: return_code = 0 try: if timeout > 0: stdout, stderr = simulation.communicate( timeout=timeout) else: stdout, stderr = simulation.communicate() return_code = simulation.wait() except KeyboardInterrupt: os.killpg( simulation.pid, signal.SIGINT) # send signal to the process group stdout, stderr = simulation.communicate() pause = True return_code = 33 except subprocess.TimeoutExpired: os.killpg( simulation.pid, signal.SIGINT) # send signal to the process group stdout, stderr = simulation.communicate() pause = True return_code = 33 # Parse/return results. if return_code in [0, 33]: trajectory_base, timeStopped = cutils._parse_binary_output( stdout, number_of_trajectories, number_timesteps, len(model.listOfSpecies), pause=pause) if model.tspan[2] - model.tspan[1] == 1: timeStopped = int(timeStopped) # Format results self.simulation_data = [] for trajectory in range(number_of_trajectories): data = {'time': trajectory_base[trajectory, :, 0]} for i in range(len(self.species)): data[self.species[i]] = trajectory_base[trajectory, :, i + 1] self.simulation_data.append(data) else: raise gillespyError.ExecutionError( "Error encountered while running simulation C++ file:" "\nReturn code: {0}.\nError:\n{1}\n".format( simulation.returncode, simulation.stderr)) if resume is not None or timeStopped != 0: self.simulation_data = cutils.c_solver_resume( timeStopped, self.simulation_data, t, resume=resume) return self.simulation_data, return_code
def __run(self, curr_state, curr_time, timeline, trajectory_base, tmpSpecies, live_grapher, t=20, number_of_trajectories=1, increment=0.05, integrator='lsoda', integrator_options={}, resume=None, **kwargs): timeStopped = 0 if resume is not None: if resume[0].model != self.model: raise gillespyError.ModelError('When resuming, one must not alter the model being resumed.') if t < resume['time'][-1]: raise gillespyError.ExecutionError( "'t' must be greater than previous simulations end time, or set in the run() method as the " "simulations next end time") # compile reaction propensity functions for eval c_prop = OrderedDict() for r_name, reaction in self.model.listOfReactions.items(): c_prop[r_name] = compile(reaction.ode_propensity_function, '<string>', 'eval') result = trajectory_base[0] entry_count = 0 y0 = [0] * len(self.model.listOfSpecies) curr_state[0] = OrderedDict() if resume is not None: for i, s in enumerate(tmpSpecies): curr_state[0][s] = tmpSpecies[s] y0[i] = tmpSpecies[s] else: for i, s in enumerate(self.model.listOfSpecies.values()): curr_state[0][s.name] = s.initial_value y0[i] = s.initial_value for p_name, param in self.model.listOfParameters.items(): curr_state[0][p_name] = param.value if 'vol' not in curr_state[0]: curr_state[0]['vol'] = 1.0 rhs = ode(ODESolver.__f).set_integrator(integrator, **integrator_options) rhs.set_initial_value(y0, curr_time[0]).set_f_params(curr_state, self.model, c_prop) while entry_count < timeline.size - 1: if self.stop_event.is_set(): self.rc = 33 break if self.pause_event.is_set(): timeStopped = timeline[entry_count] break int_time = curr_time[0] + increment entry_count += 1 y0 = rhs.integrate(int_time) curr_time[0] += increment for i, spec in enumerate(self.model.listOfSpecies): curr_state[0][spec] = y0[i] result[entry_count][i+1] = curr_state[0][spec] results_as_dict = { 'time': timeline } for i, species in enumerate(self.model.listOfSpecies): results_as_dict[species] = result[:, i+1] results = [results_as_dict] * number_of_trajectories if timeStopped != 0 or resume is not None: results = nputils.numpy_resume(timeStopped, results, resume=resume) self.result = results return results, self.rc