Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve scenario 5 import #289

Merged
merged 5 commits into from
Feb 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion mira/modeling/amr/stockflow.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,12 @@
class AMRStockFlowModel:
"""A class representing a Stock and Flow Model"""

SCHEMA_VERSION = "0.1"
SCHEMA_URL = (
f"https://raw.githubusercontent.com/DARPA-ASKEM/Model-Representations/"
f"stockflow_v{SCHEMA_VERSION}/stockflow/stockflow_schema.json"
)

def __init__(self, model: Model):
"""Instantiate a stock and flow model from a generic transition model.

Expand Down Expand Up @@ -189,7 +195,7 @@ def to_json(self):
return {
'header': {
'name': self.model_name,
'schema': '',
'schema': self.SCHEMA_URL,
'description': self.model_description,
'schema_name': 'stockflow',
'model_version': '0.1',
Expand Down
22 changes: 19 additions & 3 deletions mira/sources/system_dynamics/pysd.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
"""
__all__ = ["template_model_from_pysd_model"]

import copy
import re

import pandas as pd
Expand Down Expand Up @@ -35,7 +36,7 @@
SYMPY_FLOW_RATE_PLACEHOLDER = safe_parse_expr("xxplaceholderxx")


def template_model_from_pysd_model(pysd_model, expression_map) -> TemplateModel:
def template_model_from_pysd_model(pysd_model, expression_map, *, grounding_map=None) -> TemplateModel:
"""Given a model and its accompanying expression_map, extract information from the arguments
to create an equivalent MIRA template model.

Expand All @@ -45,6 +46,8 @@ def template_model_from_pysd_model(pysd_model, expression_map) -> TemplateModel:
The pysd model object
expression_map : dict[str,str]
Map of variable name to expression
grounding_map: dict[str, Concept]
A grounding map, a map from label to Concept

Returns
-------
Expand Down Expand Up @@ -91,7 +94,7 @@ def template_model_from_pysd_model(pysd_model, expression_map) -> TemplateModel:

# process states and build mapping of state to input rate laws and output rate laws
for index, state in model_states.iterrows():
concept_state = state_to_concept(state)
concept_state = state_to_concept(state, grounding_map=grounding_map)
concepts[concept_state.name] = concept_state
all_states.add(concept_state.name)
symbols[concept_state.name] = sympy.Symbol(concept_state.name)
Expand Down Expand Up @@ -353,13 +356,15 @@ def template_model_from_pysd_model(pysd_model, expression_map) -> TemplateModel:
)


def state_to_concept(state) -> Concept:
def state_to_concept(state, grounding_map=None) -> Concept:
"""Create a MIRA Concept from a state

Parameters
----------
state : pd.Series
The series that contains state data
grounding_map: dict[str, Concept]
A grounding map, a map from label to Concept

Returns
-------
Expand All @@ -376,6 +381,17 @@ def state_to_concept(state) -> Concept:
unit_expr = get_sympy(unit_dict, UNIT_SYMBOLS)
units_obj = Unit(expression=unit_expr) if unit_expr else None

# If there's something hacked in, use that directly,
# keeping the units and description from the model
if grounding_map is not None and name in grounding_map:
concept = copy.deepcopy(grounding_map[name])
concept.name = name
concept.description = description
concept.units = units_obj
return concept
else:
print("could not ground", name)

return Concept(name=name, units=units_obj, description=description)


Expand Down
16 changes: 8 additions & 8 deletions mira/sources/system_dynamics/vensim.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,13 +34,15 @@
CONTROL_VARIABLES = {"SAVEPER", "FINAL TIME", "INITIAL TIME", "TIME STEP"}


def template_model_from_mdl_file(fname) -> TemplateModel:
def template_model_from_mdl_file(fname, *, grounding_map=None) -> TemplateModel:
"""Return a template model from a local Vensim file

Parameters
----------
fname : str or pathlib.Path
The path to the local Vensim file
grounding_map: dict[str, Concept]
A grounding map, a map from label to Concept

Returns
-------
Expand All @@ -51,16 +53,18 @@ def template_model_from_mdl_file(fname) -> TemplateModel:
vensim_file = VensimFile(fname)
expression_map = extract_vensim_variable_expressions(vensim_file.model_text)

return template_model_from_pysd_model(pysd_model, expression_map)
return template_model_from_pysd_model(pysd_model, expression_map, grounding_map=grounding_map)


def template_model_from_mdl_url(url) -> TemplateModel:
def template_model_from_mdl_url(url, *, grounding_map=None) -> TemplateModel:
"""Return a template model from a Vensim file provided by an url

Parameters
----------
url : str
The url to the mdl file
grounding_map: dict[str, Concept]
A grounding map, a map from label to Concept

Returns
-------
Expand All @@ -75,11 +79,7 @@ def template_model_from_mdl_url(url) -> TemplateModel:
with temp_file as file:
file.write(data)

pysd_model = pysd.read_vensim(temp_file.name)
vensim_file = VensimFile(temp_file.name)
expression_map = extract_vensim_variable_expressions(vensim_file.model_text)

return template_model_from_pysd_model(pysd_model, expression_map)
return template_model_from_mdl_file(temp_file.name, grounding_map=grounding_map)


# look past control section
Expand Down
1,075 changes: 693 additions & 382 deletions notebooks/hackathon_2024.02/scenario5/Scenario 5 Notebook.ipynb

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion notebooks/hackathon_2024.02/scenario5/grounding_map.csv
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ recovered_isolated_symptomatic_mild,ido:0000592/immune population,isolation=ncit
infectious_symptomatic_mild,ido:0000511/infected population,mild=ncit:C70666
quarantined_symptomatic_mild,ido:0000511/infected population,quarantined=ncit:C71902/Quarantine|mild=ncit:C70666
recovered_mild,ido:0000592/immune population,mild=ncit:C70666
incoming_demand_on_hospital,hospitalization=ncit:C25179/Hospitalization,
incoming_demand_on_hospital,"",hospitalization=ncit:C25179/Hospitalization
infected_symptomatic_hospital_overflow,ido:0000511/infected population,hospitalization=ncit:C25179/Hospitalization|surge_capacity=ncit:C173775
infected_symptomatic_serious_hospital,ido:0000511/infected population,hospitalization=ncit:C25179/Hospitalization|serious_injury_illness_impairment=ncit:C172031
infected_symptomatic_icu_overflow,ido:0000511/infected population,intensive_care_unit=ncit:C53511|surge_capacity=ncit:C173775
Expand Down
Loading
Loading