Templates are stored in the templates
attribute of template model objects
templates
: List[Templates]
Users can index on the list of templates or iterate throughout the list of templates to access templates.
Example: Accessing templates through list indexing and iteration
from mira.examples.sir import sir_petrinet as sir
# access the second template using list indexing
template = sir.templates[1]
# go through all the templates in the model using a for loop
for template in sir.templates:
pass
All template objects have 3 optional attributes
rate_law
: Optional[SympyExprStr]
name
: Optional[str]
display_name
: Optional[str]
The least error-prone way to create a rate-law to be used in a template is to use the
safe_parse_expr
method while passing in a local_dict
mapping of symbols used in the rate law to
their sympy equivalent. The returned expression from safe_parse_expr
can either be used as
stand-alone expression to be used in templates or passed to the SympyExprStr
constructor.
safe_parse_expr(s, local_dict)
s
: str
local_dict
: Dict[str, sympy.Symbol]
sympy.Expr
Creating a rate-law using safe_parse_expr
import sympy
from mira.metamodel.utils import safe_parse_expr
# Create symbols to be used as values in the local_dict mapping
beta_symbol = sympy.Symbol("beta")
mu_symbol = sympy.Symbol("mu")
# Create the string expression to be parsed and converted to a sympy expression
str_expression = "5*beta*mu"
# Define the mapping of symbols
local_dict = {"beta": beta_symbol, "mu": mu_symbol}
# Create a sympy.Expr object
expression = safe_parse_expr(str_expression, local_dict)
The expression created can now be passed into any method or constructor that requires a rate-law. We can also pass the
result of safe_parse_expr
to the SympyExprStr
constructor which accepts types str
, float
,int
,
and sympy.Expr
to convert it to a SympyExprStr
object which is a subclass of the sympy.Expr
class.
sympy.Expr
and SympyExprStr
objects can be used interchangeably.
Additionally, there will be code examples used in this document that pass in a sympy.Symbol
, sympy.Float
, or sympy.Integer
object to an argument that expects a sympy.Expr
or SympyExprStr
object. This is allowed because the three former
sympy object classes mentioned are all subclasses of sympy.Expr
.
Creating a rate-law using safe_parse_expr
and passing it into SympyExprStr
import sympy
from mira.metamodel.utils import SympyExprStr, safe_parse_expr
beta_symbol = sympy.Symbol("beta")
mu_symbol = sympy.Symbol("mu")
str_expression = "5*beta*mu"
local_dict = {"beta": beta_symbol, "mu": mu_symbol}
expression = safe_parse_expr(str_expression, local_dict)
# We now have a SympyExprStr expression that can be used interchangeably with the result from safe_parse_expr
expression = SympyExprStr(expression)
subject
attribute
subject
: Concept
outcome
attribute
outcome
: Concept
subject
and outcome
attributes
subject
: Concept
outcome
: Concept
controller
attribute which represents a single compartment
controller
: Concept
controllers
attributes that represent a list of compartments
controllers
: List[Concept]
We can extract all the concepts in template by using the get_concepts
method.
get_concepts()
List[Union[Concept, List[Concept]]]
Example: Return a list of all concepts in the template
from mira.examples.sir import sir_petrinet as sir
concepts_list = sir.templates[0].get_concepts()
We can get all the controllers in a template by employing the get_controllers
method.
get_controllers()
List[Concept]
Example: Get all the controllers present in a template
from mira.examples.sir import sir_petrinet as sir
controller_list = sir.templates[0].get_controllers()
We can change the rate law of a template using the template instance method set_rate_law
.
set_rate_law(rate_law, local_dict)
rate_law
: Union[str, sympy.Expr, SympyExprStr]
local_dict
: Optional[Dict[str,str]]
Example: Setting a custom rate-law for a template
import sympy
from mira.metamodel.utils import SympyExprStr,safe_parse_expr
from mira.examples.sir import sir_petrinet as sir
# Define a dictionary of symbols present in the new rate-law to sympy symbol objects
# for parsing of rate-law strings
local_dict = {"I": sympy.Symbol("I"), "beta": sympy.Symbol("beta")}
# We can just pass in the return value from safe_parse_expr as well
# The SympyExprStr constructor can take in a string, int, float, or sympy.Expr object
sir.templates[0].set_rate_law(SympyExprStr(safe_parse_expr("I*beta", local_dict)))
We can update the names of parameters in a rate law using the template instance method update_parameter_name
.
update_parameter_name(old_name, new_name)
old_name
: str
new_name
: str
Example: Updating the parameter name in a template’s rate-law
from mira.examples.sir import sir_petrinet as sir
sir.templates[0].update_parameter_name("beta", "sigma")
Observables associated with a template model can be accessed using the
observables
attribute of a template model object.
observables
: Dict[str,Observable]
observables
attribute to perform
any observable specific operations.A user might want to add a new observable to keep track of a new combination of compartment values
Users can define a key-value pair where the key represents the id of the observable and the value is a newly created observable object to add to the template model. We create a new observable object with name and expression to keep track of the total number of infected in a SIR epidemiology model.
If there already exists a key-value pair in the observables
dictionary using
the same key, then the old observable object will
be overwritten by the new one.
Example: Adding a single observable using key-based indexing
import sympy
from mira.metamodel import *
from mira.examples.sir import sir_petrinet as sir
key = "total_infections"
# Since the expression is only represented by a single symbol "I", we can pass in a
# sympy.Symbol object to the expression field when creating the observable
expression = sympy.Symbol("I")
total_infections_observable = Observable(name=key, expression=expression)
sir.observables[key] = total_infections_observable
Users can also add multiple observables at once using the Python dictionary
update
method. The update
method is a dictionary instance method that can
take in another dictionary and combines both dictionaries.
The passed-in dictionary takes priority and will overwrite the key-value pairs of the original dictionary if they share the same key.
Example: Adding multiple observables using the dictionary update method
import sympy
from mira.metamodel import *
from mira.examples.sir import sir_petrinet as sir
key_infections = "total_infections"
expression_infections = sympy.Symbol("I")
total_infections_observable = Observable(name=key_infections,
expression=expression_infections)
key_susceptible = "total_susceptible"
expression_susceptible = sympy.Symbol("S")
total_susceptible_observable = Observable(name=key_susceptible,
expression=expression_susceptible)
new_observables = {key_infections: total_infections_observable,
key_susceptible: total_susceptible_observable}
sir.observables.update(new_observables)
A user might want to remove an observable because it’s no longer needed.
We can utilize the dictionary pop
method that takes in a key and removes
the key-value pair from the dictionary if
it exists in the dictionary.
Example: Removing an observable using the dictionary pop method
import sympy
from mira.metamodel import *
from mira.examples.sir import sir_petrinet as sir
key = "total_infections"
expression = sympy.Symbol("I")
total_infections_observable = Observable(name=key, expression=expression)
sir.observables[key] = total_infections_observable
sir.observables.pop(key)
A user might want to modify the expression of an observable to keep track of a different combination of compartments
We can use the Python dictionary method get
on the observables dictionary which takes in a key and returns a
reference to the observable object
that we’d like to modify if its key exists in the observables
dictionary.
Example: Modifying the expression of an existing observable
import sympy
from mira.metamodel import *
from mira.examples.sir import sir_petrinet as sir
# Add the observable
key = "total_infections"
expression = sympy.Symbol("I")
total_infections_observable = Observable(name=key, expression=expression)
sir.observables[key] = total_infections_observable
# stratify to add a species specific strata for the infected compartment
model = stratify(sir, "species", ["human", "pet"], concepts_to_stratify=["I"])
local_dict = {"I_human": sympy.Symbol("I_human"), "I_pet": sympy.Symbol("I_pet")}
# keep track of both human and pet infections for the total number of infected
new_expression = safe_parse_expr("I_human+I_pet", local_dict)
sir.observables.get(key).expression = SympyExprStr(new_expression)
Initials associated with a template model can be accessed using the initials
attribute of a template model object.
initials
: Dict[str,Initials]
initials
attribute of the template model
object to add, remove, or modify initials just like how we do for observables.A user might want to add a new initial to introduce a starting value for a compartment for simulation purposes.
Users can define a key-value pair where the key represents the id of the initial and the value is a newly created initial object to add to the template model. We create a new initial object with name and expression to keep track of the total number of infected in a SIR epidemiology model.
If there already exists a key-value pair in the initial dictionary using the same key, then the old initial object will be overwritten by the new one.
Example: Adding a single initial for the susceptible compartment in a SIR model using key-based indexing
import sympy
from mira.metamodel import *
from mira.examples.sir import sir_petrinet as sir
susceptible_concept = sir.get_concept("S")
key_susceptible = susceptible_concept.name
# Though initial values for compartments can be numbers, the Python object type
# passed into the expression argument for the Initial constructor must be of type
# (SympyExprStr, sympy.Expr), sympy.Float and sympy.Integer are subclasses of sympy.Expr
initial_expression = SympyExprStr(sympy.Float(1000))
# The Initial constructor takes in a concept object
susceptible_initial = Initial(concept=susceptible_concept,
expression=initial_expression)
sir.initials[key_susceptible] = susceptible_initial
Users can also add multiple initials at once using the Python dictionary update method. The update method is a dictionary instance method that can take in another dictionary and combines both dictionaries.
The passed-in dictionary takes priority and will overwrite the key-value pairs of the original dictionary if they share the same key.
Example: Adding multiple initials using the dictionary update method
import sympy
from mira.metamodel import *
from mira.examples.sir import sir_petrinet as sir
susceptible_concept = sir.get_concept("S")
infected_concept = sir.get_concept("I")
key_susceptible = susceptible_concept.name
key_infected = infected_concept.name
susceptible_initial_expression = SympyExprStr(sympy.Float(1000))
infected_initial_expression = SympyExprStr(sympy.Float(0))
susceptible_initial = Initial(concept=susceptible_concept,
expression=susceptible_initial_expression)
infection_initial = Initial(concept=infected_concept,
expression=infected_initial_expression)
sir.initials[key_susceptible] = susceptible_initial
sir.initials[key_infected] = infection_initial
new_initials = {key_susceptible: susceptible_initial,
key_infected: infection_initial}
sir.initials.update(new_initials)
A user might want to remove an initial because the compartment value it represents is no longer used for simulation purposes.
We can utilize the dictionary pop
method that takes in a key and removes the key-value pair from the dictionary if it exists in the dictionary.
Example: Removing an initial using the dictionary pop method
import sympy
from mira.metamodel import *
from mira.examples.sir import sir_petrinet as sir
susceptible_concept = sir.get_concept("S")
key_susceptible = susceptible_concept.name
susceptible_initial_expression = SympyExprStr(sympy.Float(5))
susceptible_initial = Initial(concept=susceptible_concept,
expression=susceptible_initial_expression)
sir.initials[key_susceptible] = susceptible_initial
sir.initials.pop(key_susceptible)
A user might want to modify the initial of an expression to change the starting value for a compartment during simulation.
We can use the Python dictionary method get
on the initials dictionary
which takes in a key and returns a reference to the initial object that we’d
like to modify if its key exists in the initials
dictionary.
There are two types of values that an initial object’s expression can take. Users can either pass in a value or parameter to an initial expression to represent the initial value for a compartment.
Though we can use a number to represent the initial expression semantically, we must pass in
a sympy
object to the expression field for the Initial
constructor.
Example: Setting the expression of an initial to be represented by a number
import sympy
from mira.metamodel import *
from mira.examples.sir import sir_petrinet as sir
susceptible_concept = sir.get_concept("S")
key_susceptible = susceptible_concept.name
sir.initials.get(key_susceptible).expression = SympyExprStr(sympy.Float(1000))
We can define the expression of an initial to be represented by an actual expression.
Example: Setting the expression of an initial to be represented by a parameter
import sympy
from mira.metamodel import *
from mira.examples.sir import sir_petrinet as sir
susceptible_concept = sir.get_concept("S")
key_susceptible = susceptible_concept.name
# Add the parameter that represents the initial value for the susceptible compartment
# to the template model
sir.add_parameter(parameter_id="S0", value=1000)
local_dict = {"S0": sympy.Symbol("S0")}
# Set the parameter "S0" to represent the initial value for the susceptible compartment
sir.initials.get(key_susceptible).expression = SympyExprStr(
safe_parse_expr("S0", local_dict))
There are multiple ways in which a user can retrieve concepts present in a template model object. We can either retrieve a single concept object by name or return a mapping of concept keys to concept objects.
We can use the get_concept
method to return a single concept object.
get_concept(name)
name
: str
Concept
None
object will be returned.Example: Retrieve a single concept object by name
from mira.examples.sir import sir_petrinet as sir
susceptible_concept = sir.get_concept("S")
If we want to retrieve all the concepts present in a template model,
we can use the get_concepts_map
method to return a mapping of concepts.
get_concepts_map()
Dict[str, Concept]
Example: Return the mapping of concepts in a template model
from mira.examples.sir import sir_petrinet as sir
concepts_map = sir.get_concepts_map()
Users can use the add_parameter
method which is a template model instance
method that adds a parameter
to the template model. The only required parameter is the id of the parameter.
Example: Adding a parameter only using a parameter id to the template model
from mira.examples.sir import sir_petrinet as sir
sir.add_parameter("mu")
add_parameter(parameter_id, name, description, value, distribution, units_mathml)
parameter_id
: str
name
: Optional[str]
description
: Optional[str]
value
: Optional[float]
distribution
: Optional[Dict[str, Any]]
units_mathml
: Optional[str]
If we added pet-specific compartments to a human-centric SIR epidemiology model, but don’t have accompanying parameters, we can add pet specific parameters with values for simulation purposes.
Example: Add a new parameter with a value to the template model
from mira.examples.sir import sir_petrinet as sir
sir.add_parameter("mu_pet", value=0.0003)
There are three ways that a template can be added to a template model object. A user might want to add a template to an existing template model object to extend its capabilities or customize the model to fit the specific problem scenario.
add_template
We can use the add_template
template model instance method to add a template.
add_template(template, parameter_mapping, initial_mapping)
template
: Template
parameter_mapping
: Optional[Mapping[str, Parameter]]
initial_mapping
: Optional[Mapping[str,Initial]]
TemplateModel
Example: Using the add_template
method to add a template to the model
import sympy
from mira.examples.sir import sir_petrinet as sir
from mira.metamodel.templates import *
from mira.metamodel.template_model import *
from mira.metamodel.utils import SympyExprStr, safe_parse_expr
recovered_concept = sir.get_concept("R")
local_dict = {"eta": sympy.Symbol("eta"), "R": sympy.Symbol("R")}
# Define the template to add
template = NaturalConversion(subject=recovered_concept,
outcome=sir.get_concept("I"),
rate_law=safe_parse_expr("eta*R", local_dict))
# Add the new template "eta" that appears in the added rate law
parameter_mapping = {"eta": Parameter(name="eta", value=5)}
# Update the initial for the recovered compartment
initial_mapping = {"R": Initial(concept=recovered_concept,
expression=SympyExprStr(sympy.Float(5)))}
sir = sir.add_template(template, parameter_mapping=parameter_mapping,
initial_mapping=initial_mapping)
add_transition
We can use the add_transition
template model instance method to infer the template type to be added from
the arguments passed and add it to the template model. Currently, this method only supports adding natural type templates.
add_transition(transition_name, subject_concept, outcome_concept, rate_law_sympy, params_dict, mass_action_parameter)
transition_name
: Optional[str]
subject_concept
: Optional[Concept]
outcome_concept
: Optional[Concept]
rate_law_sympy
: Optional[SympyExprStr]
params_dict
: Optional[Mapping[str, Mapping[str,Any]]]
mass_action_parameter
: Optional[Parameter]
TemplateModel
Example: Using the add_transition
method to add a template to the model
import sympy
from mira.examples.sir import sir_petrinet as sir
from mira.metamodel.utils import SympyExprStr, safe_parse_expr
recovered_concept = sir.get_concept("I")
susceptible_concept = sir.get_concept("S")
local_dict = {"eta": sympy.Symbol("eta"), "R": sympy.Symbol("R")}
rate_law_sympy = SympyExprStr(safe_parse_expr("eta*R", local_dict))
params_dict = {"eta": {"display_name": "eta", "value": 5}}
sir = sir.add_transition(subject_concept=recovered_concept, outcome_concept=susceptible_concept,
rate_law_sympy=rate_law_sympy, params_dict=params_dict)
templates
attribute of a template model objectRather than using a method, users can also add templates by directly appending a template to the templates
attribute
which is a list of templates.
Example: Adding a template directly accessing the templates
attribute
import sympy
from mira.examples.sir import sir_petrinet as sir
from mira.metamodel.templates import *
from mira.metamodel.utils import SympyExprStr, safe_parse_expr
recovered_concept = sir.get_concept("R")
local_dict = {"eta": sympy.Symbol("eta"), "R": sympy.Symbol("R")}
# Define the template to add
template = NaturalConversion(subject=recovered_concept,
outcome=sir.get_concept("I"),
rate_law=SympyExprStr(
safe_parse_expr("R*eta", local_dict)))
sir.templates.append(template)
# After the template it added, manually add the new parameter that appears in the template
sir.add_parameter(parameter_id="eta", value=.02)
The stratification method can take in an exhaustive list of arguments and multiplies a template model into several strata.
The three required arguments are the input template model, key, and strata
Example: Stratification on a basic SIR model by vaccination status
from mira.examples.sir import sir_petrinet as sir
from mira.metamodel.ops import stratify
key = "vaccination_status"
strata = ["unvaccinated", "vaccinated"]
sir = stratify(sir, key, strata)
stratify(model, key, strata)
model
: TemplateModel
key
:str
strata
: Collections[str]
TemplateModel
concepts_to_stratify
and params_to_stratify
respectively.
concepts_to_stratify
: Optional[Collection[str]]
params_to_stratify
: Optional[Collection[str]]
Example: Stratification on a SIR model while selecting certain concepts and parameters to stratify
from mira.examples.sir import sir_petrinet as sir
from mira.metamodel.ops import stratify
key = "vaccination_status"
strata = ["unvaccinated", "vaccinated"]
sir = stratify(sir, key, strata, concepts_to_stratify=["S", "I"],
params_to_stratify=["c", "beta", "m"])
If the number of concepts and parameters that require stratification is too long, users can alternatively opt to
select the concepts and parameters they’d like to preserve from stratification. Users can pass in an optional
collection of concept and parameter names to stratify method under arguments concepts_to_preserve
and parameters_to_preserve
respectively.
concepts_to_preserve
: Optional[Collection[str]]
parameters_to_preserve
: Optional[Collection[str]]
Example: Stratification on a SIR model while selecting certain concepts and parameters to preserve
from mira.examples.sir import sir_petrinet as sir
from mira.metamodel.ops import stratify
key = "vaccination_status"
strata = ["unvaccinated", "vaccinated"]
sir = stratify(sir, key, strata, concepts_to_preserve=["S", "I"],
params_to_preserve=["c", "beta", "m"])
modify_names
and param_renaming_uses_strata_names
flags.
modify_name
: Optional[bool]
param_renaming_uses_strata_names
: Optional[bool]
Example: Stratification on a SIR model while renaming specific compartment and parameters to include strata name
from mira.examples.sir import sir_petrinet as sir
from mira.metamodel.ops import stratify
key = "vaccination_status"
strata = ["unvaccinated", "vaccinated"]
sir = stratify(sir, key, strata, concepts_to_stratify=["S", "I"],
params_to_stratify=["c", "beta", "m"],
param_renaming_uses_strata_names=True,
modify_names=True)
structure
argument.
structure
: Optional[Iterable[Tuple[str, str]]]
An example where we wouldn’t want any structure is if we were to stratify the model by age. This is because for the purpose of modeling, people do not age.
Example: Stratifying a SIR model by age with no transitions between strata
from mira.examples.sir import sir_petrinet as sir
from mira.metamodel.ops import stratify
key = "age"
strata = ["under50", "50+"]
sir = stratify(sir, key, strata, structure=[])
An example where we would want to specify some structure but not assume complete transition network structure is if we were to stratify a model based on vaccination status. This is because people can transition from being unvaccinated to vaccinated; however, it’s impossible once someone is vaccinated, to transition to unvaccinated.
We would pass in an iterable that contains a single tuple pair
("unvaccinated", "vaccinated")
that represents
people getting vaccinated in a SIR epidemiological model.
Example: Stratifying a SIR model by vaccination status with some transitions between strata
from mira.examples.sir import sir_petrinet as sir
from mira.metamodel.ops import stratify
key = "vaccination_status"
strata = ["unvaccinated", "vaccinated"]
sir = stratify(sir, key, strata, structure=[("unvaccinated", "vaccinated")])
cartesian_control
argument to true will split all control based
relationships based on the stratification.
cartesian_control
: Optional[bool]
The cartesian_control
argument should be set to true for a SIR epidemiology model stratified on
age. As the transition from the susceptible
to the infected compartment for a certain age group is controlled by the
infected compartment of other age groups.
Example: Stratifying a SIR model by age while splitting control based relationships
from mira.examples.sir import sir_petrinet as sir
from mira.metamodel.ops import stratify
key = "age"
strata = ["under50", "50+"]
sir = stratify(sir, key, strata, cartesian_control=True)
We would set cartesian_control
to false for a SIR epidemiology model based on
city, since the infected population in one city will not
affect the infection of the susceptible population in another city.
Example: Stratifying a SIR model by city with no splitting of control based relationships
from mira.examples.sir import sir_petrinet as sir
from mira.metamodel.ops import stratify
key = "city"
strata = ["Boston", "Miami"]
sir = stratify(sir, key, strata, cartesian_control=False)
The composition method takes in a list of template models and composes them into a single template model. The list must contain at least two template models.
Example: Compose a list of two SIR based epidemiological models
from mira.examples.sir import sir, sir_2_city
from mira.metamodel.composition import compose
tm_list = [sir, sir_2_city]
composed_tm = compose(tm_list)
tm_list
: List[TemplateModel]
TemplateModel
The composition functionality prioritizes template model attributes (parameters, initials, templates, annotation, time, model time, etc.) of the first template model in the list.
If we had five different template models representing variations of the base SIR epidemiological model, we can combine them using model composition.
Example: Compose five different SIR based models
from mira.metamodel import *
susceptible = Concept(name="susceptible_population",
identifiers={"ido": "0000514"})
hospitalized = Concept(name="hospitalized", identifiers={"ncit": "C25179"})
infected = Concept(name="infected_population", identifiers={"ido": "0000511"})
recovered = Concept(name="immune_population", identifiers={"ido": "0000592"})
dead = Concept(name="dead", identifiers={"ncit": "C28554"})
quarantined = Concept(name="quarantined", identifiers={})
infection = ControlledConversion(
subject=susceptible,
outcome=infected,
controller=infected,
)
recovery = NaturalConversion(
subject=infected,
outcome=recovered,
)
reinfection = ControlledConversion(
subject=recovered,
outcome=infected,
controller=infected,
)
to_quarantine = NaturalConversion(
subject=susceptible,
outcome=quarantined
)
from_quarantine = NaturalConversion(
subject=quarantined,
outcome=susceptible
)
dying = NaturalConversion(
subject=infected,
outcome=dead
)
hospitalization = NaturalConversion(
subject=infected,
outcome=hospitalized
)
hospitalization_to_recovery = NaturalConversion(
subject=hospitalized,
outcome=recovered
)
hospitalization_to_death = NaturalConversion(
subject=hospitalized,
outcome=dead
)
sir = TemplateModel(
templates=[
infection,
recovery,
]
)
sir_reinfection = TemplateModel(
templates=[
infection,
recovery,
reinfection
]
)
sir_quarantined = TemplateModel(
templates=[
infection,
to_quarantine,
from_quarantine,
recovery
]
)
sir_dying = TemplateModel(
templates=[
infection,
dying,
recovery,
]
)
sir_hospitalized = TemplateModel(
templates=[
infection,
hospitalization,
hospitalization_to_recovery,
hospitalization_to_death,
]
)
model_list = [
sir_reinfection,
sir_quarantined,
sir_dying,
sir_hospitalized,
sir,
]
composed_model = compose(tm_list=model_list)
In this section we will discuss the behavior of how concepts are composed under different circumstances.
from mira.metamodel import *
S1 = Concept(name="Susceptible", identifiers={"ido": "0000514"})
I1 = Concept(name="Infected", identifiers={"ido": "0000511"})
R1 = Concept(name="Recovery", identifiers={"ido": "0000592"})
S2 = Concept(name="Susceptible", identifiers={"ido": "0000513"})
I2 = Concept(name="Infected", identifiers={"ido": "0000512"})
R2 = Concept(name="Recovery", identifiers={"ido": "0000593"})
S3 = Concept(name="S", identifiers={"ido": "0000514"})
I3 = Concept(name="I", identifiers={"ido": "0000511"})
R3 = Concept(name="R", identifiers={"ido": "0000592"})
S4 = Concept(name="S")
I4 = Concept(name="I")
R4 = Concept(name="R")
model_A1 = TemplateModel(
templates=[
ControlledConversion(
name='Infection',
subject=S1,
outcome=I1,
controller=I1
)
],
parameters={
'b': Parameter(name='b', value=1.0)
}
)
model_B1 = TemplateModel(
templates=[
NaturalConversion(
name='Recovery',
subject=I1,
outcome=R1
)
],
parameters={
'g': Parameter(name='g', value=1.0)
}
)
model_B2 = TemplateModel(
templates=[
NaturalConversion(
name='Recovery',
subject=I2,
outcome=R2
)
],
parameters={
'g': Parameter(name='g', value=1.0)
}
)
model_B3 = TemplateModel(
templates=[
NaturalConversion(
name='Recovery',
subject=I3,
outcome=R3
)
],
parameters={
'g': Parameter(name='g', value=1.0)
}
)
model_B4 = TemplateModel(
templates=[
NaturalConversion(
name='Recovery',
subject=I4,
outcome=R4
)
],
parameters={
'g': Parameter(name='g', value=1.0)
}
)
model_A3 = TemplateModel(
templates=[
ControlledConversion(
name='Infection',
subject=S3,
outcome=I3,
controller=I3
)
],
parameters={
'b': Parameter(name='b', value=1.0)
}
)
model_A4 = TemplateModel(
templates=[
ControlledConversion(
name='Infection',
subject=S4,
outcome=I4,
controller=I4
)
],
parameters={
'b': Parameter(name='b', value=1.0)
}
)
# (matching name and ids)
# composed into a single concept
model_AB11 = compose([model_A1, model_B1])
# matching names, mismatched ids
# composed into a separate concepts
model_AB12 = compose([model_A1, model_B2])
# mismatched names, matching ids
# composed into a single concept
model_AB13 = compose([model_A1, model_B3])
# matching names, no id + yes id
# composed into a single concept
model_AB34 = compose([model_A3, model_B4])
# matching names, no id + no id
# composed into a single concept
model_AB44 = compose([model_A4, model_B4])