Rimjhim Mittal commited on
Commit
c4d242b
·
1 Parent(s): ef2a53a

mdf streamlit application

Browse files
Files changed (5) hide show
  1. .streamlit/config.toml +6 -0
  2. app.py +185 -0
  3. environment.yml +9 -0
  4. packages.txt +1 -0
  5. requirements.txt +9 -0
.streamlit/config.toml ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ [theme]
2
+ primaryColor="#f6b17a"
3
+ backgroundColor="#04043B"
4
+ secondaryBackgroundColor="#424971"
5
+ textColor="#ffffff"
6
+
app.py ADDED
@@ -0,0 +1,185 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import streamlit as st, pandas as pd, os, io
2
+ from modeci_mdf.mdf import Model, Graph, Node, Parameter, OutputPort
3
+ from modeci_mdf.utils import load_mdf_json, load_mdf, load_mdf_yaml
4
+ from modeci_mdf.execution_engine import EvaluableGraph
5
+ import json
6
+ st.set_page_config(layout="wide")
7
+ st.title("🔋 MDF Simulator")
8
+ import requests
9
+ # models: Purpose: To store the state of the model and update the model
10
+ def run_simulation(param_inputs, mdf_model):
11
+ mod_graph = mdf_model.graphs[0]
12
+ nodes = mod_graph.nodes
13
+ for node in nodes:
14
+ parameters = node.parameters
15
+ outputs = node.output_ports
16
+ eg = EvaluableGraph(mod_graph, verbose=False)
17
+ duration = param_inputs["Simulation Duration (s)"]
18
+ dt = param_inputs["Time Step (s)"]
19
+ t = 0
20
+ times = []
21
+ output_values = {op.value: [] for op in outputs}
22
+ while t <= duration:
23
+ times.append(t)
24
+ if t == 0:
25
+ eg.evaluate()
26
+ else:
27
+ eg.evaluate(time_increment=dt)
28
+
29
+ for param in output_values:
30
+ eval_param = eg.enodes[node.id].evaluable_parameters[param]
31
+ output_values[param].append(eval_param.curr_value)
32
+ t += dt
33
+ chart_data = pd.DataFrame(output_values)
34
+ chart_data['Time'] = times
35
+ chart_data.set_index('Time', inplace=True)
36
+ return chart_data
37
+
38
+ # views: Purpose: To display the state of the model
39
+ def show_simulation_results(chart_data):
40
+ st.line_chart(chart_data, use_container_width=True, height=400)
41
+ st.write("Output Values")
42
+ st.write(chart_data)
43
+
44
+ def show_mdf_graph(mdf_model):
45
+ st.subheader("MDF Graph")
46
+ mdf_model.to_graph_image(engine="dot", output_format="png", view_on_render=False, level=3, filename_root=mdf_model.id, only_warn_on_fail=(os.name == "nt"))
47
+ image_path = mdf_model.id + ".png"
48
+ st.image(image_path, caption="Model Graph Visualization")
49
+
50
+ def show_json_output(mdf_model):
51
+ st.subheader("JSON Output")
52
+ st.json(mdf_model.to_json())
53
+
54
+ def view_tabs(mdf_model, param_inputs): # view
55
+ tab1, tab2, tab3 = st.tabs(["Simulation Results", "MDF Graph", "Json Output"])
56
+ with tab1:
57
+ mod_graph = mdf_model.graphs[0]
58
+ nodes = mod_graph.nodes
59
+ for node in nodes:
60
+ st.write("Node Name: ", node.id)
61
+ node_parameters = {}
62
+ for param in node.parameters:
63
+ node_parameters[param.id] = node_parameters[param.id] = param.value if param.value else param.time_derivative
64
+ st.write("Node Parameters: ", node_parameters)
65
+ chart_data = run_simulation(param_inputs, mdf_model) # model
66
+ show_simulation_results(chart_data) # view
67
+ with tab2:
68
+ show_mdf_graph(mdf_model) # view
69
+ with tab3:
70
+ show_json_output(mdf_model) # view
71
+
72
+ def parameter_form_to_update_model_and_view(mdf_model, parameters, param_inputs, mod_graph, nodes):
73
+ form = st.form(key="parameter_form")
74
+ valid_inputs = True
75
+
76
+ for i, param in enumerate(parameters):
77
+ if isinstance(param.value, str) or param.value is None:
78
+ continue
79
+ key = f"{param.id}_{i}"
80
+ if mdf_model.metadata:
81
+ value = form.text_input(f"{param.metadata.get('description', param.id)} ({param.id})", value=str(param.value), key=key)
82
+ else:
83
+ value = form.text_input(f"{param.id}", value=str(param.value), key=key)
84
+
85
+ try:
86
+ param_inputs[param.id] = float(value)
87
+ except ValueError:
88
+ st.error(f"Invalid input for {param.id}. Please enter a valid number.")
89
+ valid_inputs = False
90
+
91
+ sim_duration = form.text_input("Simulation Duration (s)", value=str(param_inputs["Simulation Duration (s)"]), key="sim_duration")
92
+ time_step = form.text_input("Time Step (s)", value=str(param_inputs["Time Step (s)"]), key="time_step")
93
+
94
+ try:
95
+ param_inputs["Simulation Duration (s)"] = float(sim_duration)
96
+ except ValueError:
97
+ st.error("Invalid input for Simulation Duration. Please enter a valid number.")
98
+ valid_inputs = False
99
+ try:
100
+ param_inputs["Time Step (s)"] = float(time_step)
101
+ except ValueError:
102
+ st.error("Invalid input for Time Step. Please enter a valid number.")
103
+ valid_inputs = False
104
+
105
+ run_button = form.form_submit_button("Run Simulation")
106
+ if run_button:
107
+ if valid_inputs:
108
+ for param in parameters:
109
+ if param.id in param_inputs:
110
+ param.value = param_inputs[param.id]
111
+ view_tabs(mdf_model, param_inputs)
112
+ # else:
113
+ # st.error("Please correct the invalid inputs before running the simulation.")
114
+
115
+
116
+ def upload_file_and_load_to_model():
117
+ st.write("Choose how to load the model:")
118
+ load_option = st.radio("", ("Upload File", "GitHub URL"))
119
+
120
+ if load_option == "Upload File":
121
+ uploaded_file = st.file_uploader("Choose a JSON/YAML/BSON file", type=["json", "yaml", "bson"])
122
+ if uploaded_file is not None:
123
+ file_content = uploaded_file.getvalue()
124
+ file_extension = uploaded_file.name.split('.')[-1].lower()
125
+ return load_model_from_content(file_content, file_extension)
126
+ else:
127
+ st.write("sample_github_url = https://raw.githubusercontent.com/ModECI/MDF/development/examples/MDF/NewtonCoolingModel.json")
128
+ github_url = st.text_input("Enter GitHub raw file URL:", placeholder="Enter GitHub raw file URL")
129
+ if github_url:
130
+ try:
131
+ response = requests.get(github_url)
132
+ response.raise_for_status()
133
+ file_content = response.content
134
+ # print(file_content)
135
+ file_extension = github_url.split('.')[-1].lower()
136
+ return load_model_from_content(file_content, file_extension)
137
+ except requests.RequestException as e:
138
+ st.error(f"Error loading file from GitHub: {e}")
139
+ return None
140
+
141
+ return None
142
+
143
+ def load_model_from_content(file_content, file_extension):
144
+ try:
145
+ if file_extension == 'json':
146
+ json_data = json.loads(file_content)
147
+ mdf_model = Model.from_dict(json_data)
148
+ elif file_extension in ['yaml', 'yml']:
149
+ mdf_model = load_mdf_yaml(io.BytesIO(file_content))
150
+ else:
151
+ st.error("Unsupported file format. Please use JSON or YAML files.")
152
+ return None
153
+
154
+ st.session_state.original_mdf_model = mdf_model # Save the original model
155
+ st.session_state.mdf_model_yaml = mdf_model # Save the current model state
156
+ return mdf_model
157
+ except Exception as e:
158
+ st.error(f"Error loading model: {e}")
159
+ return None
160
+
161
+
162
+ def main():
163
+ st.write("Text box changed to input. Github URL is allowed. Added some warnings eg. on adding text in input fields. Now working on multiple parameters allow.")
164
+ mdf_model = upload_file_and_load_to_model() # controller
165
+ if mdf_model:
166
+ mod_graph = mdf_model.graphs[0]
167
+ nodes = mod_graph.nodes
168
+ for node in nodes:
169
+ parameters = node.parameters
170
+ param_inputs = {}
171
+ if mdf_model.metadata:
172
+ preferred_duration = float(mdf_model.metadata.get("preferred_duration", 10))
173
+ preferred_dt = float(mdf_model.metadata.get("preferred_dt", 0.1))
174
+ else:
175
+ preferred_duration = 100
176
+ preferred_dt = 0.1
177
+ param_inputs["Simulation Duration (s)"] = preferred_duration
178
+ param_inputs["Time Step (s)"] = preferred_dt
179
+ parameter_form_to_update_model_and_view(mdf_model, parameters, param_inputs, mod_graph, nodes)
180
+
181
+ if __name__ == "__main__":
182
+ main()
183
+
184
+
185
+
environment.yml ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
 
1
+ name: my_environment
2
+ channels:
3
+ - defaults
4
+ dependencies:
5
+ - python
6
+ - pip
7
+ - modeci_mdf
8
+ - streamlit
9
+ - matplotlib
packages.txt ADDED
@@ -0,0 +1 @@
 
 
1
+ graphviz
requirements.txt ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
 
1
+ streamlit
2
+ modeci_mdf
3
+ matplotlib==3.5.1
4
+ graphviz
5
+ ipython
6
+ torch
7
+ modelspec
8
+ graph_scheduler
9
+ streamlit-code-editor