def setUp(self): self.parameter = Parameter(name="test_parameter", expression="0.5")
def to_model(self, name): """ Instantiates a Model object from a StochMLDocument. """ # Empty model model = Model(name=name) root = self.document # Try to set name from document if model.name == "": name = root.find('Name') if name.text is None: raise NameError("The Name cannot be none") else: model.name = name.text # Set annotiation ann = root.find('Description') if ann is not None: units = ann.get('units') if units: units = units.strip().lower() if units == "concentration": model.units = "concentration" elif units == "population": model.units = "population" else: # Default model.units = "population" if ann.text is None: model.annotation = "" else: model.annotation = ann.text # Set units units = root.find('Units') if units is not None: if units.text.strip().lower() == "concentration": model.units = "concentration" elif units.text.strip().lower() == "population": model.units = "population" else: # Default model.units = "population" # Create parameters for px in root.iter('Parameter'): name = px.find('Id').text expr = px.find('Expression').text if name.lower() == 'vol' or name.lower() == 'volume': model.volume = float(expr) else: p = Parameter(name, expression=expr) # Try to evaluate the expression in the empty namespace # (if the expr is a scalar value) p.evaluate() model.add_parameter(p) # Create species for spec in root.iter('Species'): name = spec.find('Id').text val = spec.find('InitialPopulation').text if '.' in val: val = float(val) else: val = int(val) s = Species(name, initial_value=val) model.add_species([s]) # The namespace_propensity for evaluating the propensity function # for reactions must contain all the species and parameters. namespace_propensity = OrderedDict() all_species = model.get_all_species() all_parameters = model.get_all_parameters() for param in all_species: namespace_propensity[param] = all_species[param].initial_value for param in all_parameters: namespace_propensity[param] = all_parameters[param].value # Create reactions for reac in root.iter('Reaction'): try: name = reac.find('Id').text except: raise InvalidStochMLError("Reaction has no name.") reaction = Reaction(name=name, reactants={}, products={}) # Type may be 'mass-action','customized' try: type = reac.find('Type').text except: raise InvalidStochMLError("No reaction type specified.") reactants = reac.find('Reactants') try: for ss in reactants.iter('SpeciesReference'): specname = ss.get('id') # The stochiometry should be an integer value, but some # exising StoxhKit models have them as floats. This is # why we need the slightly odd conversion below. stoch = int(float(ss.get('stoichiometry'))) # Select a reference to species with name specname sref = model.listOfSpecies[specname] try: # The sref list should only contain one element if # the XML file is valid. reaction.reactants[sref] = stoch except Exception as e: StochMLImportError(e) except: # Yes, this is correct. 'reactants' can be None pass products = reac.find('Products') try: for ss in products.iter('SpeciesReference'): specname = ss.get('id') stoch = int(float(ss.get('stoichiometry'))) sref = model.listOfSpecies[specname] try: # The sref list should only contain one element if # the XML file is valid. reaction.products[sref] = stoch except Exception as e: raise StochMLImportError(e) except: # Yes, this is correct. 'products' can be None pass if type == 'mass-action': reaction.massaction = True reaction.type = 'mass-action' # If it is mass-action, a parameter reference is needed. # This has to be a reference to a species instance. We # explicitly disallow a scalar value to be passed as the # parameter. try: ratename = reac.find('Rate').text try: reaction.marate = model.listOfParameters[ratename] except KeyError as k: # No paramter name is given. This is a valid use case # in StochKit. We generate a name for the paramter, # and create a new parameter instance. The parameter's # value should now be found in 'ratename'. generated_rate_name = "Reaction_" + name + \ "_rate_constant" p = Parameter(name=generated_rate_name, expression=ratename) # Try to evaluate the parameter to set its value p.evaluate() model.add_parameter(p) reaction.marate = model.listOfParameters[ generated_rate_name] reaction.__create_mass_action() except Exception as e: raise elif type == 'customized': try: propfunc = reac.find('PropensityFunction').text except Exception as e: raise InvalidStochMLError( "Found a customized propensity function, but no expression was given. {}" .format(e)) reaction.propensity_function = propfunc else: raise InvalidStochMLError( "Unsupported or no reaction type given for reaction" + name) model.add_reaction(reaction) return model
class TestParameter(unittest.TestCase): ''' ################################################################################################ Unit tests for gillespy2.Parameter. ################################################################################################ ''' def setUp(self): self.parameter = Parameter(name="test_parameter", expression="0.5") def test_constructor(self): """ Test the Parameter constructor. """ parameter = Parameter(name="test_parameter", expression="0.5") self.assertEqual(parameter.name, "test_parameter") self.assertEqual(parameter.expression, "0.5") def test_constructor__no_name(self): """ Test the Parameter constructor without name. """ with self.assertRaises(ParameterError): Parameter(expression="0.5") def test_constructor__invalid_name(self): """ Test the Parameter constructor with non-str name. """ test_names = ["", None, 0, 0.5, [0]] for test_name in test_names: with self.subTest(name=test_name): with self.assertRaises(ParameterError): Parameter(name=test_name, expression="0.5") def test_constructor__no_expression(self): """ Test the Parameter constructor without expression. """ with self.assertRaises(ParameterError): Parameter(name="test_parameter") def test_constructor__int_expression(self): """ Test the Parameter constructor with int expression. """ parameter = Parameter(name="test_parameter", expression=1) self.assertEqual(parameter.expression, "1") def test_constructor__float_expression(self): """ Test the Parameter constructor with float expression. """ parameter = Parameter(name="test_parameter", expression=0.5) self.assertEqual(parameter.expression, "0.5") def test_constructor__invaild_expression(self): """ Test the Parameter constructor with an invalid expression. """ test_exps = [None, "", [2]] for test_exp in test_exps: with self.subTest(expression=test_exp): with self.assertRaises(ParameterError): Parameter(name="test_name", expression=test_exp) def test___str__(self): """ Test Parameter.__str__ method. """ self.assertIsInstance(str(self.parameter), str) def test__evaluate(self): """ Test Parameter._evaluate method. """ self.parameter._evaluate() self.assertEqual(self.parameter.value, 0.5) def test__evaluate__int_expression(self): """ Test Parameter._evaluate method with int expression. """ self.parameter.expression = 5 self.parameter._evaluate() self.assertEqual(self.parameter.value, 5) def test__evaluate__float_expression(self): """ Test Parameter._evaluate method with float expression. """ self.parameter.expression = 0.5 self.parameter._evaluate() self.assertEqual(self.parameter.value, 0.5) def test__evaluate__improper_expression(self): """ Test Parameter._evaluate method with invalid expression. """ self.parameter.expression = "[0.5]" with self.assertRaises(ParameterError): self.parameter._evaluate() def test__evaluate__invaild_expression(self): """ Test Parameter._evaluate with an invalid expression. """ test_exps = [None, "", []] for test_exp in test_exps: with self.subTest(expression=test_exp): with self.assertRaises(ParameterError): self.parameter.expression = test_exp self.parameter._evaluate() def test__evaluate__parameter_in_namespace(self): """ Test Parameter._evaluate method with parameter in namespace. """ self.parameter.expression = "k1 + 0.5" self.parameter._evaluate(namespace={"k1": 3}) self.assertEqual(self.parameter.value, 3.5) def test__evaluate__species_in_namespace(self): """ Test Parameter._evaluate method with species in namespace. """ self.parameter.expression = "S0 + 0.5" self.parameter._evaluate(namespace={"S0": 100}) self.assertEqual(self.parameter.value, 100.5) def test__evaluate__component_not_in_namespace(self): """ Test Parameter._evaluate method with component missing from namespace. """ test_comps = ["SO", "k1"] for test_comp in test_comps: with self.subTest(component=test_comp): self.parameter.expression = f"{test_comp} + 0.5" with self.assertRaises(ParameterError): self.parameter._evaluate() def test_validate__invalid_name(self): """ Test Parameter.validate with non-str name. """ test_names = ["", None, 0, 0.5, [0]] for test_name in test_names: with self.subTest(name=test_name): with self.assertRaises(ParameterError): self.parameter.name = test_name self.parameter.validate() def test_validate__invaild_expression(self): """ Test Parameter.validate with an invalid expression. """ test_exps = [None, "", [2]] for test_exp in test_exps: with self.subTest(expression=test_exp): with self.assertRaises(ParameterError): self.parameter.expression = test_exp self.parameter.validate() def test_comp_time_of_validate(self): """ Check the computation time of validate. """ import time from datetime import datetime start = time.time() self.parameter.validate() tic = datetime.utcfromtimestamp(time.time() - start) print( f"Total time to run validate: {tic.strftime('%M mins %S secs %f msecs')}" )
def from_model(cls, model): """ Creates an StochKit XML document from an exisiting Mdoel object. This method assumes that all the parameters in the model are already resolved to scalar floats (see Model.resolveParamters). Note, this method is intended to be used interanally by the models 'serialization' function, which performs additional operations and tests on the model prior to writing out the XML file. You should NOT \ do: document = StochMLDocument.fromModel(model) print document.toString() You SHOULD do print model.serialize() """ # Description md = cls() d = eTree.Element('Description') # if model.units.lower() == "concentration": d.set('units', model.units.lower()) d.text = model.annotation md.document.append(d) # Number of Reactions nr = eTree.Element('NumberOfReactions') nr.text = str(len(model.listOfReactions)) md.document.append(nr) # Number of Species ns = eTree.Element('NumberOfSpecies') ns.text = str(len(model.listOfSpecies)) md.document.append(ns) # Species spec = eTree.Element('SpeciesList') for sname in model.listOfSpecies: spec.append(md.__species_to_element(model.listOfSpecies[sname])) md.document.append(spec) # Parameters params = eTree.Element('ParametersList') for pname in model.listOfParameters: params.append( md.__parameter_to_element(model.listOfParameters[pname])) params.append( md.__parameter_to_element( Parameter(name='vol', expression=model.volume))) md.document.append(params) # Reactions reacs = eTree.Element('ReactionsList') for rname in model.listOfReactions: reacs.append( md.__reaction_to_element(model.listOfReactions[rname], model.volume)) md.document.append(reacs) return md