예제 #1
0
    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"
            )
예제 #2
0
 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
예제 #3
0
    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)})")
예제 #4
0
    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
예제 #5
0
    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
예제 #6
0
    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