Source code for gillespy2.core.species

# GillesPy2 is a modeling toolkit for biochemical simulation.
# Copyright (C) 2019-2023 GillesPy2 developers.

# 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 3 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, see <http://www.gnu.org/licenses/>.
from gillespy2.core.jsonify import Jsonify
from gillespy2.core.sortableobject import SortableObject

from gillespy2.core.gillespyError import SpeciesError

[docs]class Species(SortableObject, Jsonify): """ Chemical species. Can be added to Model object to interact with other species or time. :param name: The name by which this species will be called in reactions and within the model. :type name: str :param initial_value: Initial population (discrete) or concentration (continuous) of this species. :type initial_value: int | float :param constant: If true, the value of the species cannot be changed (currently TauHybridSolver only) :type constant: bool :param boundary_condition: If true, species can be changed by events and rate rules, but not by reactions. (TauHybridSolver only) :type boundary_condition: bool :param mode: ***FOR USE WITH TauHybridSolver ONLY*** Sets the mode of representation of this species for the TauHybridSolver, can be discrete, continuous, or dynamic. mode='dynamic' - Allows a species to be represented as either discrete or continuous mode='continuous' - Species will only be represented as continuous mode='discrete' - Species will only be represented as discrete :type mode: str :param allow_negative_populations: If true, population can be reduced below 0. :type allow_negative_populations: bool :param switch_tol: ***FOR USE WITH TauHybridSolver ONLY*** Tolerance level for considering a dynamic species deterministically, value is compared to an estimated sd/mean population of a species after a given time step. This value will be used if a switch_min is not provided. The default value is 0.03 :type switch_tol: float :param switch_min: ***FOR USE WITH TauHybridSolver ONLY*** Minimum population value at which species will be represented as continuous. If a value is given, switch_min will be used instead of switch_tol :type switch_min: float :raises SpeciesError: Arg is of invalid type. Required arg set to None. Arg value is outside of accepted bounds. """ def __init__(self, name=None, initial_value=0, constant=False, boundary_condition=False, mode=None, allow_negative_populations=False, switch_min=0, switch_tol=0.03): # A species has a name (string) and an initial value (positive integer) self.name = name self.constant = constant self.boundary_condition = boundary_condition self.mode = mode self.allow_negative_populations = allow_negative_populations self.switch_min = switch_min self.switch_tol = switch_tol if initial_value is None: raise SpeciesError("initial_value can't be None type.") if isinstance(initial_value, str): try: initial_value = float(initial_value) except ValueError: pass self.validate(initial_value=initial_value) self.initial_value = float(initial_value) if self.mode == "continuous" else int(initial_value) def __str__(self): print_string = self.name print_string += ': ' + str(self.initial_value) return print_string
[docs] def set_initial_value(self, initial_value): """ Setter method for initial_value of a population :param initial_value: Initial population (discrete) or concentration (continuous) of this species. :type initial_value: int | float :raises SpeciesError: initial_value is of invalid type. initial_value set to None. \ initial_value is a float when mode != 'continuous'. \ initial_value is negative when allow_negative_populations=False. """ if initial_value is None: raise SpeciesError("initial_value can't be None type.") if isinstance(initial_value, str): try: initial_value = float(initial_value) except ValueError: pass self.validate(initial_value=initial_value, coverage="initial_value") self.initial_value = float(initial_value) if self.mode == "continuous" else int(initial_value)
[docs] def validate(self, initial_value=None, coverage="all"): """ Validate the species. :param initial_value: Initial population (discrete) or concentration (continuous) of this species. :type initial_value: int | float :param coverage: The scope of attributes to validate. Set to an attribute name to restrict validation \ to a specific attribute. :type coverage: str :raises SpeciesError: Attribute is of invalid type. Required attribute set to None. \ Attribute is value outside of accepted bounds. """ # Check name if coverage in ("all", "name"): if self.name is None: raise SpeciesError("name can't be None type.") if not isinstance(self.name, str): raise SpeciesError(f"name must be of type str not {type(self.name)}.") if self.name == "": raise SpeciesError("name can't be an empty string.") # Check initial_value if coverage in ("all", "initial_value"): if initial_value is None: initial_value = self.initial_value if initial_value is None: raise SpeciesError("initial_value can't be None type.") if not isinstance(initial_value, (float, int)): raise SpeciesError(f"initial_value must be of type float or int not {type(initial_value)}.") if self.mode != "continuous" and int(initial_value) != initial_value: raise SpeciesError( """ initial_value with mode='discrete' must be an integer value. Change to mode='continuous' to use floating point values. """ ) if not self.allow_negative_populations and initial_value < 0: raise SpeciesError( 'A species initial value must be non-negative unless allow_negative_populations=True' ) # Check constant if coverage in ("all", "constant"): if not isinstance(self.constant, bool): errmsg = f"constant must be of type bool not {type(self.constant)}." raise SpeciesError(errmsg) # Check boundary_condition if coverage in ("all", "boundary_condition"): if not isinstance(self.boundary_condition, bool): errmsg = f"boundary_condition must be of type bool not {type(self.boundary_condition)}." raise SpeciesError(errmsg) # Check mode if coverage in ("all", "mode"): mode_list = ['continuous', 'dynamic', 'discrete', None] if self.mode not in mode_list: raise SpeciesError( f""" mode must be 'continuous', 'dynamic', 'discrete', or unspecified (defaults to 'dynamic' for TauHybridSolver) not {self.mode}. """ ) # Check allow_negative_populations if coverage in ("all", "allow_negative_populations"): if not isinstance(self.allow_negative_populations, bool): errmsg = f"allow_negative_populations must be of type bool not {type(self.allow_negative_populations)}." raise SpeciesError(errmsg) # Check switch_tol if coverage in ("all", "switch_tol"): if self.switch_tol is None: raise SpeciesError("switch_tol can't be None type.") if not isinstance(self.switch_tol, (float, int)): raise SpeciesError(f"switch_tol must of type float or int not {type(self.switch_tol)}") if self.switch_tol < 0: raise SpeciesError(f"switch_tol must be a positive value not {self.switch_tol}") # Check switch_min if coverage in ("all", "switch_min"): if self.switch_min is None: raise SpeciesError("switch_min can't be None type.") if not isinstance(self.switch_min, (float, int)): raise SpeciesError(f"switch_min must of type float or int not {type(self.switch_min)}") if self.switch_min < 0: raise SpeciesError(f"switch_min must be a positive value not {self.switch_min}")