diff --git a/mira/metamodel/io.py b/mira/metamodel/io.py
index 84c83a3e7..b268bd557 100644
--- a/mira/metamodel/io.py
+++ b/mira/metamodel/io.py
@@ -2,7 +2,7 @@
import json
import sympy
-from .template_model import TemplateModel
+from .template_model import TemplateModel, SympyExprStr
def model_from_json_file(fname) -> TemplateModel:
@@ -42,6 +42,8 @@ def expression_to_mathml(expression: sympy.Expr, *args, **kwargs) -> str:
Here we pay attention to not style underscores and numeric suffixes
in special ways.
"""
+ if isinstance(expression, SympyExprStr):
+ expression = expression.args[0]
mappings = {}
for sym in expression.atoms(sympy.Symbol):
name = '|' + str(sym).replace('_', 'QQQ') + '|'
diff --git a/mira/metamodel/schema.json b/mira/metamodel/schema.json
index 6621ec5ad..e32b2c46f 100644
--- a/mira/metamodel/schema.json
+++ b/mira/metamodel/schema.json
@@ -30,6 +30,11 @@
"description": "The name of the concept.",
"type": "string"
},
+ "display_name": {
+ "title": "Display Name",
+ "description": "An optional display name for the concept. If not provided, the name can be used for display purposes.",
+ "type": "string"
+ },
"description": {
"title": "Description",
"description": "An optional description of the concept.",
@@ -470,6 +475,11 @@
"description": "The name of the concept.",
"type": "string"
},
+ "display_name": {
+ "title": "Display Name",
+ "description": "An optional display name for the concept. If not provided, the name can be used for display purposes.",
+ "type": "string"
+ },
"description": {
"title": "Description",
"description": "An optional description of the concept.",
@@ -516,8 +526,7 @@
}
},
"required": [
- "name",
- "value"
+ "name"
]
},
"Initial": {
@@ -548,6 +557,11 @@
"description": "The name of the concept.",
"type": "string"
},
+ "display_name": {
+ "title": "Display Name",
+ "description": "An optional display name for the concept. If not provided, the name can be used for display purposes.",
+ "type": "string"
+ },
"description": {
"title": "Description",
"description": "An optional description of the concept.",
diff --git a/mira/metamodel/template_model.py b/mira/metamodel/template_model.py
index fef99bea4..05a00cd2f 100644
--- a/mira/metamodel/template_model.py
+++ b/mira/metamodel/template_model.py
@@ -31,7 +31,7 @@ class Distribution(BaseModel):
class Parameter(Concept):
"""A Parameter is a special type of Concept that carries a value."""
- value: float = Field(
+ value: Optional[float] = Field(
default_factory=None, description="Value of the parameter.")
distribution: Optional[Distribution] = Field(
diff --git a/mira/metamodel/templates.py b/mira/metamodel/templates.py
index cb80e3cf4..c2961e571 100644
--- a/mira/metamodel/templates.py
+++ b/mira/metamodel/templates.py
@@ -124,6 +124,10 @@ class Concept(BaseModel):
"""
name: str = Field(..., description="The name of the concept.")
+ display_name: str = \
+ Field(None, description="An optional display name for the concept. "
+ "If not provided, the name can be used for "
+ "display purposes.")
description: Optional[str] = \
Field(None, description="An optional description of the concept.")
identifiers: Mapping[str, str] = Field(
diff --git a/mira/modeling/__init__.py b/mira/modeling/__init__.py
index 647ccf24b..65551790c 100644
--- a/mira/modeling/__init__.py
+++ b/mira/modeling/__init__.py
@@ -108,8 +108,8 @@ def assemble_variable(
return var
def assemble_parameter(self, template: Template, tkey) -> ModelParameter:
- rate_parameters = self.template_model.get_parameters_from_rate_law(
- template.rate_law)
+ rate_parameters = sorted(
+ self.template_model.get_parameters_from_rate_law(template.rate_law))
if rate_parameters:
model_parameters = []
@@ -133,8 +133,8 @@ def assemble_parameter(self, template: Template, tkey) -> ModelParameter:
def make_model(self):
for name, observable in self.template_model.observables.items():
- params = observable.get_parameter_names(
- self.template_model.parameters)
+ params = sorted(
+ observable.get_parameter_names(self.template_model.parameters))
self.observables[observable.name] = \
ModelObservable(observable, params)
for key in params:
diff --git a/mira/modeling/askenet/petrinet.py b/mira/modeling/askenet/petrinet.py
index 469413cc1..dc93a35ba 100644
--- a/mira/modeling/askenet/petrinet.py
+++ b/mira/modeling/askenet/petrinet.py
@@ -55,6 +55,7 @@ def __init__(self, model: Model):
# Use the variable's concept name if possible but fall back
# on the key otherwise
vmap[key] = name = var.concept.name or str(key)
+ display_name = var.concept.display_name or name
# State structure
# {
# 'id': str,
@@ -63,7 +64,7 @@ def __init__(self, model: Model):
# }
states_dict = {
'id': name,
- 'name': name,
+ 'name': display_name,
'grounding': {
'identifiers': {k: v for k, v in
var.concept.identifiers.items()
@@ -258,10 +259,11 @@ def to_json_file(self, fname, name=None, description=None,
kwargs :
Additional keyword arguments to pass to :func:`json.dump`.
"""
+ indent = kwargs.pop('indent', 1)
js = self.to_json(name=name, description=description,
model_version=model_version)
with open(fname, 'w') as fh:
- json.dump(js, fh, **kwargs)
+ json.dump(js, fh, indent=indent, **kwargs)
class Initial(BaseModel):
diff --git a/mira/sources/askenet/petrinet.py b/mira/sources/askenet/petrinet.py
index 67e812851..7cb71ed6f 100644
--- a/mira/sources/askenet/petrinet.py
+++ b/mira/sources/askenet/petrinet.py
@@ -226,7 +226,11 @@ def state_to_concept(state):
# }
# }
# }
- name = state.get('name') or state['id']
+ # Note that in the shared representation we have id and name
+ # whereas for Concepts in MIRA we have names and display
+ # names
+ name = state['id']
+ display_name = state.get('name')
grounding = state.get('grounding', {})
identifiers = grounding.get('identifiers', {})
context = grounding.get('modifiers', {})
@@ -239,6 +243,7 @@ def state_to_concept(state):
units_expr = sympy.parse_expr(expr, local_dict=UNIT_SYMBOLS)
units_obj = Unit(expression=units_expr)
return Concept(name=name,
+ display_name=display_name,
identifiers=identifiers,
context=context,
units=units_obj)
diff --git a/mira/sources/sbml/processor.py b/mira/sources/sbml/processor.py
index 153c3129c..5171ba047 100644
--- a/mira/sources/sbml/processor.py
+++ b/mira/sources/sbml/processor.py
@@ -190,6 +190,14 @@ def _lookup_concepts_filtered(species_ids) -> List[Concept]:
product_species = [species.species for species in reaction.products]
rate_law = reaction.getKineticLaw()
+ # Some rate laws define parameters locally and so we need to
+ # extract them and add them to the global parameter list
+ for parameter in rate_law.parameters:
+ all_parameters[parameter.id] = {'value': parameter.value,
+ 'description': parameter.name if parameter.name else None,
+ 'units': self.get_object_units(parameter)}
+ parameter_symbols[clean_formula(parameter.id)] = \
+ sympy.Symbol(clean_formula(parameter.id))
rate_expr = sympy.parse_expr(clean_formula(rate_law.formula),
local_dict=all_locals)
diff --git a/notebooks/hackathon_2023.07/scenario1.ipynb b/notebooks/hackathon_2023.07/scenario1.ipynb
new file mode 100644
index 000000000..99a5e4bdf
--- /dev/null
+++ b/notebooks/hackathon_2023.07/scenario1.ipynb
@@ -0,0 +1,244 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "c947d97c",
+ "metadata": {},
+ "source": [
+ "### Step a-b: create the base model\n",
+ "Questions: You want to implement a masking intervention in a simple compartmental model and simulate epidemic trajectories under different compliance scenarios. You found an existing model that incorporates masking as a time-dependent modification to the β parameter (https://doi.org/10.3390/ijerph18179027 plus accompanying code), and you want to ensure that the model is working as expected by reproducing plots in the publication. \n",
+ "\n",
+ "Replicate an analysis from the paper.\n",
+ "- (TA1 Model Extraction Workflow, TA2 Model Representation) Extract the SEIRD model (equations 1-5, with time-varying β as defined in equations 8-9) and load into the workbench. In equation 8, let kappa = γR0, R0 = 5. In equation 9, let k = 5.\n",
+ "\n",
+ "- (TA3 Simulation Workflow, Unit Test): Replicate Figure 3 from the paper, which maps to the first scenario in the paper- implementing a masking intervention at several different timepoints (delays of 0 days, 50 days, 100 days, and control case, from the date of first infection) in the pandemic, with 100% compliance. Recreate the Fig. 3 curves (including peak infection times and levels), up to some reasonable margin of error. "
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "id": "11406f4a",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import sympy\n",
+ "from mira.metamodel import *\n",
+ "from mira.modeling import Model\n",
+ "from mira.modeling.askenet.petrinet import AskeNetPetriNetModel"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 2,
+ "id": "b2351930",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "person_units = Unit(expression=sympy.Symbol('person'))\n",
+ "day_units = Unit(expression=sympy.Symbol('day'))\n",
+ "per_day_units = Unit(expression=1/sympy.Symbol('day'))\n",
+ "dimensionless_units = Unit(expression=sympy.Integer('1'))\n",
+ "\n",
+ "c = {\n",
+ " 'S': Concept(name='S', units=person_units),\n",
+ " 'E': Concept(name='E', units=person_units),\n",
+ " 'I': Concept(name='I', units=person_units),\n",
+ " 'R': Concept(name='R', units=person_units),\n",
+ " 'D': Concept(name='D', units=person_units)\n",
+ "}\n",
+ "\n",
+ "\n",
+ "parameters = {\n",
+ " 'gamma': Parameter(name='gamma', value=1/11, units=per_day_units),\n",
+ " 'delta': Parameter(name='delta', value=1/5, units=per_day_units),\n",
+ " 'alpha': Parameter(name='alpha', value=0.000064, units=dimensionless_units),\n",
+ " 'rho': Parameter(name='rho', value=1/9, units=per_day_units),\n",
+ " 'N': Parameter(name='N', value=5_600_000, units=person_units),\n",
+ " 'beta_s': Parameter(name='beta_s', value=1),\n",
+ " 'beta_c': Parameter(name='beta_c', value=0.4),\n",
+ " 't_0': Parameter(name='t_0', value=89, unts=day_units),\n",
+ " # D=11, gamma = 1/D, R_0 = 5 and\n",
+ " # beta = R_0 * gamma * mask(t) so kappa = 5/11\n",
+ " 'kappa': Parameter(name='kappa', value=5/11),\n",
+ "}\n",
+ "\n",
+ "initials = {\n",
+ " 'S': Initial(concept=Concept(name='S'), value=5_600_000-1),\n",
+ " 'E': Initial(concept=Concept(name='E'), value=1),\n",
+ " 'I': Initial(concept=Concept(name='I'), value=0),\n",
+ " 'R': Initial(concept=Concept(name='R'), value=0),\n",
+ " 'D': Initial(concept=Concept(name='D'), value=0),\n",
+ "}"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 3,
+ "id": "28178230",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "S, E, I, R, D, N, kappa, beta_s, beta_c, k, t_0, t, alpha, delta, rho, gamma = \\\n",
+ " sympy.symbols('S E I R D N kappa beta_s beta_c k t_0 t alpha delta rho gamma')"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 4,
+ "id": "f2645cae",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "m_1 = (beta_s - beta_c) / (1 + sympy.exp(-k*(t_0-t))) + beta_c\n",
+ "beta = kappa*m_1\n",
+ "\n",
+ "t1 = ControlledConversion(subject=c['S'],\n",
+ " outcome=c['E'],\n",
+ " controller=c['E'],\n",
+ " rate_law=S*I*beta / N)\n",
+ "t2 = NaturalConversion(subject=c['E'],\n",
+ " outcome=c['I'],\n",
+ " rate_law=delta*E)\n",
+ "t3 = NaturalConversion(subject=c['I'],\n",
+ " outcome=c['R'],\n",
+ " rate_law=(1-alpha)*gamma*I)\n",
+ "t4 = NaturalConversion(subject=c['I'],\n",
+ " outcome=c['D'],\n",
+ " rate_law=alpha*rho*I)\n",
+ "templates = [t1, t2, t3, t4]\n",
+ "tm = TemplateModel(\n",
+ " templates=templates,\n",
+ " parameters=parameters,\n",
+ " initials=initials,\n",
+ " time=Time(name='t', units=day_units)\n",
+ ")\n",
+ "AskeNetPetriNetModel(Model(tm)).to_json_file('scenario1_a.json')"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "48e4ed6a",
+ "metadata": {},
+ "source": [
+ "### Step c: update beta\n",
+ "\n",
+ "(TA2 Model Modification Workflow, TA3 Simulation Workflow): Update the β(t) function to be defined as equations 8 and 10, with k1 = 5, and k2 = 1. This reflects the paper’s second scenario, gradual noncompliance with the masking policy over time. Rerun the simulation with several different delays in enforcing a mask policy (ranging from 0 to 140 days), and replicate Fig. 5, up to some reasonable margin of error."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 5,
+ "id": "85e41bc9",
+ "metadata": {
+ "scrolled": true
+ },
+ "outputs": [],
+ "source": [
+ "k_1, k_2, t_1, beta_nc = sympy.symbols('k_1 k_2 t_1 beta_nc')\n",
+ "parameters['k_1'] = Parameter(name='k_1')\n",
+ "parameters['k_2'] = Parameter(name='k_2')\n",
+ "parameters['t_1'] = Parameter(name='t_1', value=154, units=day_units)\n",
+ "parameters['beta_nc'] = Parameter(name='beta_nc', value=0.5)\n",
+ "m_2 = (beta_s - beta_c) / (1 + sympy.exp(-k_1*(t_0-t))) + (beta_c - beta_nc) / (1 + sympy.exp(-k_2*(t_1-t))) + beta_nc"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 6,
+ "id": "5fa367b5",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "t1.rate_law = SympyExprStr(kappa*m_2)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 7,
+ "id": "c073ca18",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/latex": [
+ "$\\displaystyle \\kappa \\left(\\beta_{nc} + \\frac{\\beta_{c} - \\beta_{nc}}{1 + e^{- k_{2} \\left(- t + t_{1}\\right)}} + \\frac{- \\beta_{c} + \\beta_{s}}{1 + e^{- k_{1} \\left(- t + t_{0}\\right)}}\\right)$"
+ ],
+ "text/plain": [
+ "kappa*(beta_nc + (beta_c - beta_nc)/(1 + exp(-k_2*(-t + t_1))) + (-beta_c + beta_s)/(1 + exp(-k_1*(-t + t_0))))"
+ ]
+ },
+ "execution_count": 7,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "t1.rate_law.args[0]"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 8,
+ "id": "b1c1abab",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "AskeNetPetriNetModel(Model(tm)).to_json_file('scenario1_c.json')"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "6e3374f9",
+ "metadata": {},
+ "source": [
+ "### Step d: update for reinfection\n",
+ "(TA2 Model Modification Workflow, TA3 Simulation Workflow): Update the system of equations to include equations 6 and 7. This adds the potential for reinfection. Compare with the outcomes from 1c. What impact does immunity loss and potential for reinfection have?"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 9,
+ "id": "6fab9358",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "epsilon = sympy.Symbol('epsilon')\n",
+ "parameters['epsilon'] = Parameter(name='epsilon', value=1/90)\n",
+ "t5 = NaturalConversion(subject=c['R'],\n",
+ " outcome=c['S'],\n",
+ " rate_law=epsilon*R)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 10,
+ "id": "00c70176",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "AskeNetPetriNetModel(Model(tm)).to_json_file('scenario1_d.json')"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.10.12"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/notebooks/hackathon_2023.07/scenario1_a.json b/notebooks/hackathon_2023.07/scenario1_a.json
new file mode 100644
index 000000000..2ce954672
--- /dev/null
+++ b/notebooks/hackathon_2023.07/scenario1_a.json
@@ -0,0 +1,258 @@
+{
+ "name": "Model",
+ "schema": "https://raw.githubusercontent.com/DARPA-ASKEM/Model-Representations/petrinet_v0.5/petrinet/petrinet_schema.json",
+ "schema_name": "petrinet",
+ "description": "Model",
+ "model_version": "0.1",
+ "properties": {},
+ "model": {
+ "states": [
+ {
+ "id": "S",
+ "name": "S",
+ "grounding": {
+ "identifiers": {},
+ "modifiers": {}
+ },
+ "units": {
+ "expression": "person",
+ "expression_mathml": "person"
+ }
+ },
+ {
+ "id": "E",
+ "name": "E",
+ "grounding": {
+ "identifiers": {},
+ "modifiers": {}
+ },
+ "units": {
+ "expression": "person",
+ "expression_mathml": "person"
+ }
+ },
+ {
+ "id": "I",
+ "name": "I",
+ "grounding": {
+ "identifiers": {},
+ "modifiers": {}
+ },
+ "units": {
+ "expression": "person",
+ "expression_mathml": "person"
+ }
+ },
+ {
+ "id": "R",
+ "name": "R",
+ "grounding": {
+ "identifiers": {},
+ "modifiers": {}
+ },
+ "units": {
+ "expression": "person",
+ "expression_mathml": "person"
+ }
+ },
+ {
+ "id": "D",
+ "name": "D",
+ "grounding": {
+ "identifiers": {},
+ "modifiers": {}
+ },
+ "units": {
+ "expression": "person",
+ "expression_mathml": "person"
+ }
+ }
+ ],
+ "transitions": [
+ {
+ "id": "t1",
+ "input": [
+ "E",
+ "S"
+ ],
+ "output": [
+ "E",
+ "E"
+ ],
+ "properties": {
+ "name": "t1"
+ }
+ },
+ {
+ "id": "t2",
+ "input": [
+ "E"
+ ],
+ "output": [
+ "I"
+ ],
+ "properties": {
+ "name": "t2"
+ }
+ },
+ {
+ "id": "t3",
+ "input": [
+ "I"
+ ],
+ "output": [
+ "R"
+ ],
+ "properties": {
+ "name": "t3"
+ }
+ },
+ {
+ "id": "t4",
+ "input": [
+ "I"
+ ],
+ "output": [
+ "D"
+ ],
+ "properties": {
+ "name": "t4"
+ }
+ }
+ ]
+ },
+ "semantics": {
+ "ode": {
+ "rates": [
+ {
+ "target": "t1",
+ "expression": "I*S*kappa*(beta_c + (-beta_c + beta_s)/(1 + exp(-k*(-t + t_0))))/N",
+ "expression_mathml": "ISkappabeta_cbeta_cbeta_s1kt_0tN"
+ },
+ {
+ "target": "t2",
+ "expression": "E*delta",
+ "expression_mathml": "Edelta"
+ },
+ {
+ "target": "t3",
+ "expression": "I*gamma*(1 - alpha)",
+ "expression_mathml": "Igamma1alpha"
+ },
+ {
+ "target": "t4",
+ "expression": "I*alpha*rho",
+ "expression_mathml": "Ialpharho"
+ }
+ ],
+ "initials": [
+ {
+ "target": "S",
+ "expression": "5599999.00000000",
+ "expression_mathml": "5599999.0"
+ },
+ {
+ "target": "E",
+ "expression": "1.00000000000000",
+ "expression_mathml": "1.0"
+ },
+ {
+ "target": "I",
+ "expression": "0.0",
+ "expression_mathml": "0.0"
+ },
+ {
+ "target": "R",
+ "expression": "0.0",
+ "expression_mathml": "0.0"
+ },
+ {
+ "target": "D",
+ "expression": "0.0",
+ "expression_mathml": "0.0"
+ }
+ ],
+ "parameters": [
+ {
+ "id": "N",
+ "value": 5600000.0,
+ "units": {
+ "expression": "person",
+ "expression_mathml": "person"
+ }
+ },
+ {
+ "id": "beta_c",
+ "value": 0.4
+ },
+ {
+ "id": "beta_s",
+ "value": 1.0
+ },
+ {
+ "id": "kappa",
+ "value": 0.45454545454545453
+ },
+ {
+ "id": "t_0",
+ "value": 89.0
+ },
+ {
+ "id": "delta",
+ "value": 0.2,
+ "units": {
+ "expression": "1/day",
+ "expression_mathml": "day-1"
+ }
+ },
+ {
+ "id": "alpha",
+ "value": 6.4e-05,
+ "units": {
+ "expression": "1",
+ "expression_mathml": "1"
+ }
+ },
+ {
+ "id": "gamma",
+ "value": 0.09090909090909091,
+ "units": {
+ "expression": "1/day",
+ "expression_mathml": "day-1"
+ }
+ },
+ {
+ "id": "rho",
+ "value": 0.1111111111111111,
+ "units": {
+ "expression": "1/day",
+ "expression_mathml": "day-1"
+ }
+ }
+ ],
+ "observables": [],
+ "time": {
+ "id": "t",
+ "units": {
+ "expression": "day",
+ "expression_mathml": "day"
+ }
+ }
+ }
+ },
+ "metadata": {
+ "annotations": {
+ "license": null,
+ "authors": [],
+ "references": [],
+ "time_scale": null,
+ "time_start": null,
+ "time_end": null,
+ "locations": [],
+ "pathogens": [],
+ "diseases": [],
+ "hosts": [],
+ "model_types": []
+ }
+ }
+}
\ No newline at end of file
diff --git a/notebooks/hackathon_2023.07/scenario1_c.json b/notebooks/hackathon_2023.07/scenario1_c.json
new file mode 100644
index 000000000..0511f2622
--- /dev/null
+++ b/notebooks/hackathon_2023.07/scenario1_c.json
@@ -0,0 +1,250 @@
+{
+ "name": "Model",
+ "schema": "https://raw.githubusercontent.com/DARPA-ASKEM/Model-Representations/petrinet_v0.5/petrinet/petrinet_schema.json",
+ "schema_name": "petrinet",
+ "description": "Model",
+ "model_version": "0.1",
+ "properties": {},
+ "model": {
+ "states": [
+ {
+ "id": "S",
+ "name": "S",
+ "grounding": {
+ "identifiers": {},
+ "modifiers": {}
+ },
+ "units": {
+ "expression": "person",
+ "expression_mathml": "person"
+ }
+ },
+ {
+ "id": "E",
+ "name": "E",
+ "grounding": {
+ "identifiers": {},
+ "modifiers": {}
+ },
+ "units": {
+ "expression": "person",
+ "expression_mathml": "person"
+ }
+ },
+ {
+ "id": "I",
+ "name": "I",
+ "grounding": {
+ "identifiers": {},
+ "modifiers": {}
+ },
+ "units": {
+ "expression": "person",
+ "expression_mathml": "person"
+ }
+ },
+ {
+ "id": "R",
+ "name": "R",
+ "grounding": {
+ "identifiers": {},
+ "modifiers": {}
+ },
+ "units": {
+ "expression": "person",
+ "expression_mathml": "person"
+ }
+ },
+ {
+ "id": "D",
+ "name": "D",
+ "grounding": {
+ "identifiers": {},
+ "modifiers": {}
+ },
+ "units": {
+ "expression": "person",
+ "expression_mathml": "person"
+ }
+ }
+ ],
+ "transitions": [
+ {
+ "id": "t1",
+ "input": [
+ "E",
+ "S"
+ ],
+ "output": [
+ "E",
+ "E"
+ ],
+ "properties": {
+ "name": "t1"
+ }
+ },
+ {
+ "id": "t2",
+ "input": [
+ "E"
+ ],
+ "output": [
+ "I"
+ ],
+ "properties": {
+ "name": "t2"
+ }
+ },
+ {
+ "id": "t3",
+ "input": [
+ "I"
+ ],
+ "output": [
+ "R"
+ ],
+ "properties": {
+ "name": "t3"
+ }
+ },
+ {
+ "id": "t4",
+ "input": [
+ "I"
+ ],
+ "output": [
+ "D"
+ ],
+ "properties": {
+ "name": "t4"
+ }
+ }
+ ]
+ },
+ "semantics": {
+ "ode": {
+ "rates": [
+ {
+ "target": "t1",
+ "expression": "kappa*(beta_nc + (beta_c - beta_nc)/(1 + exp(-k_2*(-t + t_1))) + (-beta_c + beta_s)/(1 + exp(-k_1*(-t + t_0))))",
+ "expression_mathml": "kappabeta_ncbeta_cbeta_nc1k_2t_1tbeta_cbeta_s1k_1t_0t"
+ },
+ {
+ "target": "t2",
+ "expression": "E*delta",
+ "expression_mathml": "Edelta"
+ },
+ {
+ "target": "t3",
+ "expression": "I*gamma*(1 - alpha)",
+ "expression_mathml": "Igamma1alpha"
+ },
+ {
+ "target": "t4",
+ "expression": "I*alpha*rho",
+ "expression_mathml": "Ialpharho"
+ }
+ ],
+ "initials": [
+ {
+ "target": "S",
+ "expression": "5599999.00000000",
+ "expression_mathml": "5599999.0"
+ },
+ {
+ "target": "E",
+ "expression": "1.00000000000000",
+ "expression_mathml": "1.0"
+ },
+ {
+ "target": "I",
+ "expression": "0.0",
+ "expression_mathml": "0.0"
+ },
+ {
+ "target": "R",
+ "expression": "0.0",
+ "expression_mathml": "0.0"
+ },
+ {
+ "target": "D",
+ "expression": "0.0",
+ "expression_mathml": "0.0"
+ }
+ ],
+ "parameters": [
+ {
+ "id": "beta_c",
+ "value": 0.4
+ },
+ {
+ "id": "beta_s",
+ "value": 1.0
+ },
+ {
+ "id": "kappa",
+ "value": 0.45454545454545453
+ },
+ {
+ "id": "t_0",
+ "value": 89.0
+ },
+ {
+ "id": "delta",
+ "value": 0.2,
+ "units": {
+ "expression": "1/day",
+ "expression_mathml": "day-1"
+ }
+ },
+ {
+ "id": "alpha",
+ "value": 6.4e-05,
+ "units": {
+ "expression": "1",
+ "expression_mathml": "1"
+ }
+ },
+ {
+ "id": "gamma",
+ "value": 0.09090909090909091,
+ "units": {
+ "expression": "1/day",
+ "expression_mathml": "day-1"
+ }
+ },
+ {
+ "id": "rho",
+ "value": 0.1111111111111111,
+ "units": {
+ "expression": "1/day",
+ "expression_mathml": "day-1"
+ }
+ }
+ ],
+ "observables": [],
+ "time": {
+ "id": "t",
+ "units": {
+ "expression": "day",
+ "expression_mathml": "day"
+ }
+ }
+ }
+ },
+ "metadata": {
+ "annotations": {
+ "license": null,
+ "authors": [],
+ "references": [],
+ "time_scale": null,
+ "time_start": null,
+ "time_end": null,
+ "locations": [],
+ "pathogens": [],
+ "diseases": [],
+ "hosts": [],
+ "model_types": []
+ }
+ }
+}
\ No newline at end of file
diff --git a/notebooks/hackathon_2023.07/scenario1_d.json b/notebooks/hackathon_2023.07/scenario1_d.json
new file mode 100644
index 000000000..0511f2622
--- /dev/null
+++ b/notebooks/hackathon_2023.07/scenario1_d.json
@@ -0,0 +1,250 @@
+{
+ "name": "Model",
+ "schema": "https://raw.githubusercontent.com/DARPA-ASKEM/Model-Representations/petrinet_v0.5/petrinet/petrinet_schema.json",
+ "schema_name": "petrinet",
+ "description": "Model",
+ "model_version": "0.1",
+ "properties": {},
+ "model": {
+ "states": [
+ {
+ "id": "S",
+ "name": "S",
+ "grounding": {
+ "identifiers": {},
+ "modifiers": {}
+ },
+ "units": {
+ "expression": "person",
+ "expression_mathml": "person"
+ }
+ },
+ {
+ "id": "E",
+ "name": "E",
+ "grounding": {
+ "identifiers": {},
+ "modifiers": {}
+ },
+ "units": {
+ "expression": "person",
+ "expression_mathml": "person"
+ }
+ },
+ {
+ "id": "I",
+ "name": "I",
+ "grounding": {
+ "identifiers": {},
+ "modifiers": {}
+ },
+ "units": {
+ "expression": "person",
+ "expression_mathml": "person"
+ }
+ },
+ {
+ "id": "R",
+ "name": "R",
+ "grounding": {
+ "identifiers": {},
+ "modifiers": {}
+ },
+ "units": {
+ "expression": "person",
+ "expression_mathml": "person"
+ }
+ },
+ {
+ "id": "D",
+ "name": "D",
+ "grounding": {
+ "identifiers": {},
+ "modifiers": {}
+ },
+ "units": {
+ "expression": "person",
+ "expression_mathml": "person"
+ }
+ }
+ ],
+ "transitions": [
+ {
+ "id": "t1",
+ "input": [
+ "E",
+ "S"
+ ],
+ "output": [
+ "E",
+ "E"
+ ],
+ "properties": {
+ "name": "t1"
+ }
+ },
+ {
+ "id": "t2",
+ "input": [
+ "E"
+ ],
+ "output": [
+ "I"
+ ],
+ "properties": {
+ "name": "t2"
+ }
+ },
+ {
+ "id": "t3",
+ "input": [
+ "I"
+ ],
+ "output": [
+ "R"
+ ],
+ "properties": {
+ "name": "t3"
+ }
+ },
+ {
+ "id": "t4",
+ "input": [
+ "I"
+ ],
+ "output": [
+ "D"
+ ],
+ "properties": {
+ "name": "t4"
+ }
+ }
+ ]
+ },
+ "semantics": {
+ "ode": {
+ "rates": [
+ {
+ "target": "t1",
+ "expression": "kappa*(beta_nc + (beta_c - beta_nc)/(1 + exp(-k_2*(-t + t_1))) + (-beta_c + beta_s)/(1 + exp(-k_1*(-t + t_0))))",
+ "expression_mathml": "kappabeta_ncbeta_cbeta_nc1k_2t_1tbeta_cbeta_s1k_1t_0t"
+ },
+ {
+ "target": "t2",
+ "expression": "E*delta",
+ "expression_mathml": "Edelta"
+ },
+ {
+ "target": "t3",
+ "expression": "I*gamma*(1 - alpha)",
+ "expression_mathml": "Igamma1alpha"
+ },
+ {
+ "target": "t4",
+ "expression": "I*alpha*rho",
+ "expression_mathml": "Ialpharho"
+ }
+ ],
+ "initials": [
+ {
+ "target": "S",
+ "expression": "5599999.00000000",
+ "expression_mathml": "5599999.0"
+ },
+ {
+ "target": "E",
+ "expression": "1.00000000000000",
+ "expression_mathml": "1.0"
+ },
+ {
+ "target": "I",
+ "expression": "0.0",
+ "expression_mathml": "0.0"
+ },
+ {
+ "target": "R",
+ "expression": "0.0",
+ "expression_mathml": "0.0"
+ },
+ {
+ "target": "D",
+ "expression": "0.0",
+ "expression_mathml": "0.0"
+ }
+ ],
+ "parameters": [
+ {
+ "id": "beta_c",
+ "value": 0.4
+ },
+ {
+ "id": "beta_s",
+ "value": 1.0
+ },
+ {
+ "id": "kappa",
+ "value": 0.45454545454545453
+ },
+ {
+ "id": "t_0",
+ "value": 89.0
+ },
+ {
+ "id": "delta",
+ "value": 0.2,
+ "units": {
+ "expression": "1/day",
+ "expression_mathml": "day-1"
+ }
+ },
+ {
+ "id": "alpha",
+ "value": 6.4e-05,
+ "units": {
+ "expression": "1",
+ "expression_mathml": "1"
+ }
+ },
+ {
+ "id": "gamma",
+ "value": 0.09090909090909091,
+ "units": {
+ "expression": "1/day",
+ "expression_mathml": "day-1"
+ }
+ },
+ {
+ "id": "rho",
+ "value": 0.1111111111111111,
+ "units": {
+ "expression": "1/day",
+ "expression_mathml": "day-1"
+ }
+ }
+ ],
+ "observables": [],
+ "time": {
+ "id": "t",
+ "units": {
+ "expression": "day",
+ "expression_mathml": "day"
+ }
+ }
+ }
+ },
+ "metadata": {
+ "annotations": {
+ "license": null,
+ "authors": [],
+ "references": [],
+ "time_scale": null,
+ "time_start": null,
+ "time_end": null,
+ "locations": [],
+ "pathogens": [],
+ "diseases": [],
+ "hosts": [],
+ "model_types": []
+ }
+ }
+}
\ No newline at end of file
diff --git a/tests/test_askenet_source.py b/tests/test_askenet_source.py
index e24ed28a5..dda00ee82 100644
--- a/tests/test_askenet_source.py
+++ b/tests/test_askenet_source.py
@@ -14,11 +14,12 @@ def test_petrinet_model_from_url():
assert len(template_model.templates) == 2
assert isinstance(template_model.templates[0], ControlledConversion)
assert isinstance(template_model.templates[1], NaturalConversion)
- assert template_model.templates[0].controller.name == 'Infected'
- assert template_model.templates[0].subject.name == 'Susceptible'
- assert template_model.templates[0].outcome.name == 'Infected'
- assert template_model.templates[1].subject.name == 'Infected'
- assert template_model.templates[1].outcome.name == 'Recovered'
+ assert template_model.templates[0].controller.display_name == 'Infected'
+ assert template_model.templates[0].controller.name == 'I'
+ assert template_model.templates[0].subject.display_name == 'Susceptible'
+ assert template_model.templates[0].outcome.display_name == 'Infected'
+ assert template_model.templates[1].subject.display_name == 'Infected'
+ assert template_model.templates[1].outcome.display_name == 'Recovered'
def test_regnet_model_from_url():