-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathapp.py
More file actions
391 lines (347 loc) · 22 KB
/
Copy pathapp.py
File metadata and controls
391 lines (347 loc) · 22 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
import os
import streamlit as st
import pandas as pd
import numpy as np
import plotly.express as px
import silvio
from silvio.catalog.StrExpSim import DigLabSim
from silvio.experiment import ExperimentSettings
from silvio.extensions.common import myUnits, AnalyticsCosts
from silvio.extensions.utils.misc import Help_getTargetExchangeID
# from silvio.extensions.common import BIGG_dict
# from silvio.utils import coalesce
# get silvio version
from silvio import __version__ as silvio_version
# read variable names from Variables.py
from Variables import Budget
# # Initialize session state variables
st.session_state['date'] = pd.to_datetime('today').strftime('%y%m%d')
if 'ExpInit' not in st.session_state:
st.session_state['ExpInit'] = None
# st.session_state['ExpInit'] = False
if 'exp' not in st.session_state:
st.session_state['exp'] = None
if 'host' not in st.session_state:
st.session_state['host'] = None
if 'currency' not in st.session_state:
st.session_state['currency'] = None
if 'LabInvest' not in st.session_state:
st.session_state['LabInvest'] = None
if 'rand_seed' not in st.session_state:
st.session_state['rand_seed'] = None
if 'organism' not in st.session_state:
st.session_state['organism'] = None
if 'GSMM' not in st.session_state:
st.session_state['GSMM'] = None
# ## File locations
# if 'ModelFile' not in st.session_state:
# st.session_state['ModelFile'] = None
######################################################
######################################################
# Example Run
######################################################
######################################################
# if st.sidebar.button('Example Run'):
# myExp = ExperimentSettings(Test=True)
# myExp.set_SamplingVector()
# st.session_state['exp'] = DigLabSim(161710, Budget, Budget)
# st.session_state['host'] = st.session_state['exp'].create_host(myExp.HostName)
# Result = st.session_state['exp'].measure_TemperatureGrowth(myExp, Test='Example')
# # format Data as xlsx for download
# myExp.OutputFilePath = f'Data/{pd.to_datetime("today").strftime("%y%m%d")}_{myExp.HostName.replace(".","")}.xlsx'
# # run simulation
# Data = st.session_state['exp'].measure_TemperatureGrowth(myExp, Test='Example')
# fig_Bio, ax_Bio = Data.make_plot(XName='time (h)', YNames=['biomass (OD600)'])
# ax_Bio.set_ylabel('Biomass (OD600)')
# st.pyplot(fig_Bio)
# fig_HPLC, ax_HPLC = Data.make_3dplot('HPLC', 'time', 'signal')
# ax_HPLC.set_zlabel('HPLC signal', rotation=90)
# ax_HPLC.set_box_aspect(None, zoom=0.88)
# fig_HPLC.set_size_inches(8, 7)
# st.pyplot(fig_HPLC)
# with pd.ExcelWriter(myExp.OutputFilePath, engine='openpyxl') as writer:
# Data.value.to_excel(writer, sheet_name='ExampleExperiment', index=False)
# st.markdown(f'Data saved to {myExp.OutputFilePath}')
# st.download_button(
# label="Download data as Excel",
# data=open(myExp.OutputFilePath, 'rb').read(),
# file_name=os.path.split(myExp.OutputFilePath)[-1],
# mime="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
# )
# # st.session_state['exp'].record_experiment(myExp)
# st.success('Data simulation completed and file is ready for download.')
######################################################
######################################################
# st.title('Experiment Details')
######################################################
######################################################
st.sidebar.title('Experiment Selection')
st.sidebar.subheader('Experiment Setup')
if st.sidebar.toggle('Experiment Setup'):
st.title('Setup of Experiment')
st.markdown('Select the organism for the experiment and the investment into lab equipment.')
col1, col2 = st.columns(2)
with col1:
st.session_state['organism'] = st.selectbox('Select Organism', ['E.coli-core', 'E.coli'], index=0) #, 'E.coli', 'S.cerevisiae', 'B.subtilis'
# numerical input as number_input, with default value of date with six digits, range 0-100000, step 1
st.write(f'Default random seed based on date: {st.session_state["date"]}')
st.session_state['rand_seed'] = st.number_input('Random Seed for Simulation', min_value=0, max_value=999999, value=int(st.session_state['date']), step=1)
# st.session_state['ModelFile'] = f'Data/{BIGG_dict[st.session_state["organism"]]}.json'
with col2:
st.session_state['currency'] = st.selectbox('Currency', ['EURO', 'Dollar', 'Yuan', 'Rupee', 'Yen'], index=0)
st.session_state['LabInvest'] = st.slider('Investment into Lab Equipment', 0, Budget, 5000, step=100)
st.markdown(f'You selected {st.session_state["organism"]} as organism and an investment of {st.session_state["LabInvest"]} {st.session_state["currency"]} into lab equipment. The random seed for the simulation is set to {st.session_state["rand_seed"]}.')
# #################################################
# # horizontal line
# st.markdown('---')
# #################################################
# st.subheader('Data management and Analysis')
# st.markdown('Select the data management system and the analysis software.')
# DataExportType = st.selectbox('Data Management System', ['Excel', 'Google Sheets', 'LIMS', 'ELN'], index=0)
# AnalysisSoftware = st.selectbox('Analysis Software', ['Python', 'R', 'Matlab', 'BlueVis'], index=1)
# #################################################
# # horizontal line
# st.markdown('---')
# #################################################
if st.button('Intialize Experiment'):
st.session_state['exp'] = DigLabSim(st.session_state['rand_seed'], st.session_state['LabInvest'], Budget)
st.session_state['host'] = st.session_state['exp'].create_host(st.session_state['organism'])
# st.session_state['GSMM'] = Download_GSMM(st.session_state['organism'])
st.success('Experiment initialized. You can now run the experiment.')
st.session_state['ExpInit'] = True
######################################################
######################################################
# Details on experiment
######################################################
######################################################
# st.sidebar.subheader("Experiment Details")
# if st.sidebar.toggle('Show Experiment Details'):
# information box on the main page on the experiment details
with st.expander('Experiment Details', expanded=True):
if st.session_state['exp'] is not None:
st.markdown(f'Organism: {st.session_state["organism"]}')
st.markdown(f'Remaining budget: {st.session_state["exp"].budget} {st.session_state["currency"]}')
# st.sidebar.markdown(f'Model file: {st.session_state["GSMM"].id}')
st.markdown(f'Model file: {st.session_state["host"].metabolism.model.id}')
# check whether model is functional
if st.session_state['host'].metabolism.model.slim_optimize() > 1e-6:
st.success('Model is functional.')
else:
st.error('Model is not functional.')
# st.markdown(f'Optimal Temperature: {st.session_state["host"].opt_growth_temp} °C')
# st.markdown(f'OD2X: {st.session_state["host"].growth.OD2X} gCDW/OD600')
st.markdown(f'Silvio version: {silvio_version}')
# st.markdown(f'Experiment history: {len(st.session_state["exp"].experiment_history)} experiments recorded.')
option = st.selectbox('Select Experiment to View Details', st.session_state['exp'].experiment_history.keys(), index=None, placeholder='Select Experiment...')
# display details of selected experiment by looping over the attributes of the ExperimentSettings object
# only display attributes that are not None
if option:
for attr, value in vars(st.session_state['exp'].experiment_history[option]).items():
if attr not in ['CarbonID','CarbonUptakeRate','InitBiomass','GrowthRate','Yield','Capacity','SampleVector','OutputFilePath']:#'CarbonID','CarbonUptakeRate','InitBiomass','GrowthRate','Yield','Capacity','SampleVector','OutputFilePath']: # skip some attributes
st.markdown(f'**{attr}**: {value} {myUnits[attr] if attr in myUnits else ""}')
# allow downloading the OutputFilePath file
if attr == 'OutputFilePath' and value is not None:
st.download_button(
label="Download OutputFilePath File",
data=open(value, 'rb').read(),
file_name=os.path.split(value)[-1],
mime="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
)
# alternatively,
else:
st.info('Select an experiment from the dropdown to view details.')
######################################################
######################################################
# Experiment selection
######################################################
######################################################
st.sidebar.subheader("Experiment Section")
Experiment_select = st.sidebar.selectbox('Fermentation Type', ['Select', 'Batch'], key='1') #, 'Continuous'
if Experiment_select == 'Batch': # and st.session_state['exp'] is not None:
myExp = ExperimentSettings(Test=False)
myExp.ExperimentType = 'Batch'
myExp.HostName = st.session_state['organism'] # myExp.HostName
st.title('Batch Experiment in Shake Flask')
st.markdown('For the shake flask experiment, you can set the temperature, shaking speed (rpm), initial optical density (OD600), and glucose concentration in g/L. After setting the parameters, click on "Run Simulation" to start the experiment.')
# # Display image
# st.image('Figures/Icons/ShakeFlaskFermentation_SBI.jpg', caption='Shake Flask Experiment', width='stretch')
# Input parameters
st.subheader('Input parameters for batch shake flask experiment')
col1, col2 = st.columns(2)
with col1:
# User input for multiple temperatures (integers)
myExp.Temperature = int(st.slider('Choose temperature (°C)', min_value=20, max_value=40, value=30, step=1))
# try:
# _ = [int(x.strip()) for x in temp_str.split(',') if x.strip()] # myExp.Temperature
# except ValueError:
# st.error("Please enter only integer values separated by commas.")
myExp.InitBiomass = round(st.number_input('Optical density, OD600', min_value=0.0, max_value=0.3, value=0.1), 3) * st.session_state['host'].growth.OD2X # myExp.InitBiomass convert OD600 to gCDW/L
myExp.MediumVolume = st.slider('Culture Volume (mL) of 500 ml max', min_value=10, max_value=500, value=100, step=10)
# total cultivation time in hours
myExp.CultivationTime = st.slider('Total Cultivation Time (h)', min_value=1, max_value=48, value=24, step=1)
# sampling interval in hours
myExp.SamplingInterval = st.slider('Sampling Interval (h)', min_value=.5, max_value=12.0, value=1.0, step=0.5)
myExp.set_SamplingVector()
# the users selects the analytics sampling times from the sampling vector
myExp.AnalyticSampling = np.array(st.multiselect('Select Sampling Times for Analytics (h)', myExp.SampleVector, default=myExp.SampleVector[-1])) # myExp.AnalyticSampling
# if not myExp.AnalyticSampling:
# st.warning('Please select at least one sampling time for analytics.')
myExp.Analytics = st.multiselect('Select Analytics, multiple possible', list(AnalyticsCosts.keys()), default=[list(AnalyticsCosts.keys())[0]])
with col2:
# text input to narrow down to specific carbon source
Substrate_Filter = st.text_input('Filter Carbon Source (e.g. glc, lac, ace, glucose, Glucose etc)', value='glc')
model = st.session_state['host'].metabolism.model
if Substrate_Filter:
Fil1 = set(model.metabolites.query(Substrate_Filter, attribute='name'))
Fil2 = set(model.metabolites.query(Substrate_Filter, attribute='id'))
Fil2_unique = Fil2 - Fil1
Carbon_Substrates = list(Fil1) + list(Fil2_unique)
# coalesce(st.session_state['GSMM'].metabolites.query(Substrate_Filter[1:], attribute='name') + st.session_state['GSMM'].metabolites.query(Substrate_Filter[1:], attribute='id'))
sub_sel = st.selectbox('Select Carbon Source', Carbon_Substrates, index=0)
# find sustrate in exchange reactions
Exch_Reactions = [r for r in model.exchanges if sub_sel.id in r.reaction]
if not Exch_Reactions:
st.warning(f'No exchange reaction found for "{sub_sel}". Please select another substrate.')
else:
CarbonID = Exch_Reactions[0].id #myExp.CarbonID
myExp.CarbonName = [CarbonID] # sub_sel.name #myExp.CarbonName
st.markdown(f'Found exchange reaction "{CarbonID}"')
# selectbox for concentration unit, default g/L, options: g/L, mM, M
# the number input for concentration is only shown if the concentration unit is selected
Conc_Unit = st.selectbox('Select Concentration Unit', ['g/L', 'mM', 'M'], index=0)
if Conc_Unit == 'g/L':
conc_unit_factor = 1/(sub_sel.formula_weight/1000) # convert g/L to mmol/L
elif Conc_Unit == 'mM':
conc_unit_factor = 1
elif Conc_Unit == 'M':
conc_unit_factor = 1/1000 # convert M to mmol/L
else:
conc_unit_factor = 1 # default to g/L if something goes wrong
sub_val = round(st.number_input(f'Concentration ({Conc_Unit})', min_value=0., max_value=50., value=1., step=.1),2)
myExp.CarbonSubConc = {myExp.CarbonName[0]: round(abs(sub_val * conc_unit_factor),2)} # myExp.CarbonConc
# st.markdown(f'You selected {myExp.CarbonName} with {myExp.CarbonConc} mM.')
# Setting CO2 transfer rate by identifying the exchange reaction
CTR_Choices = Help_getTargetExchangeID(st.session_state['host'].metabolism.model, 'CO2')
myExp.CTR = st.selectbox('Select CO2 Exchange Reaction', CTR_Choices, index=0)
# Setting O2 transfer rate by identifying the exchange reaction
OTR_Choices = Help_getTargetExchangeID(st.session_state['host'].metabolism.model, 'O2')
myExp.OTR = st.selectbox('Select O2 Exchange Reaction', OTR_Choices, index=0)
# # find sustrate in exchange reactions
# Exch_Reactions = [r for r in model.exchanges if sub_sel.id in r.reaction]
# if not Exch_Reactions:
# st.warning(f'No exchange reaction found for "{sub_sel}". Please select another substrate.')
# else:
# CarbonID = Exch_Reactions[0].id #myExp.CarbonID
# myExp.CarbonName = [CarbonID] # sub_sel.name #myExp.CarbonName
# st.markdown(f'Found exchange reaction "{CarbonID}"')
# if st.button('Run FBA'):
# # set uptake rate of selected substrate
# st.session_state['host'].metabolism.set_resetCarbonExchanges({myExp.CarbonID: myExp.CarbonConc})
# GrowthRate = st.session_state['host'].metabolism.slim_optimize()
# ExchangeRates = st.session_state['host'].metabolism.optimize_ReportExchanges()
# UpRate = -ExchangeRates[myExp.CarbonID]
# Yield = round(GrowthRate/UpRate,2) if UpRate != 0 else 0 # gCDW/mmol
# # calculate biomass capacity in gCDW/L
# BioWeightConc = Yield * myExp.CarbonConc # gCDW/L
# CapacityWeight = BioWeightConc * (myExp.MediumVolume/1000) # gCDW in the flask
# CapacityOD = CapacityWeight / st.session_state['host'].growth.OD2X # convert gCDW to OD600
# Vmax = st.session_state["host"].metabolism.model_tmp.reactions.get_by_id(Exch_Reactions[0].id).Vmax
# Km = st.session_state["host"].metabolism.model_tmp.reactions.get_by_id(Exch_Reactions[0].id).Km
# st.success(f'FBA with {Exch_Reactions[0].id} and uptake rate of {UpRate} mmol/gCDW/h. Kinetics: {Vmax} mmol/gDW/h and {Km} mM. Growth rate {GrowthRate}/h.\n\n Yield: {Yield} gCDW/mmol ({round(Yield*1000/sub_sel.formula_weight,2)} gCDW/gSubstrate) substrate.\n\n Biomass capacity in flask: {round(CapacityOD,2)} OD600).')
# st.write(st.session_state['host'].metabolism.model_tmp.summary())
# text input for experiment id
myExp.ExperimentID = st.text_input('Experiment ID', value='Batch_v1')
if st.button('Run Simulation'):
# set uptake rate of selected substrate
# st.session_state['host'].metabolism.set_resetCarbonExchanges({myExp.CarbonID: myExp.CarbonConc})
# GrowthRate, ExchangeRates = st.session_state['host'].metabolism.optimize_ReportExchanges()
# UpRate = -ExchangeRates[myExp.CarbonID]
# Yield = round(GrowthRate/UpRate,2) if UpRate != 0 else 0 # gCDW/mmol
# # calculate biomass capacity in gCDW/L
# BioWeightConc = Yield * myExp.CarbonConc # gCDW/L
# CapacityWeight = BioWeightConc * (myExp.MediumVolume/1000) # gCDW in the flask
# CapacityOD = CapacityWeight / st.session_state['host'].growth.OD2X # convert gCDW to OD600
# format Data as xlsx for download
myExp.OutputFilePath = f'Data/{pd.to_datetime("today").strftime("%y%m%d")}_{st.session_state["organism"].replace(".","")}_{myExp.ExperimentID}.xlsx'
#export myExp to a txt file
with open(f'Data/{pd.to_datetime("today").strftime("%y%m%d")}_{st.session_state["organism"].replace(".","")}_{myExp.ExperimentID}_Settings.txt', 'w') as f:
for attr, value in vars(myExp).items():
f.write(f'{attr}: {value}\n')
############################################################################
############################################################################
# myExp = ExperimentSettings() #Test=True
# myExp.ExperimentID = 'Test'
# myExp.HostName = 'E.coli-core'
# myExp.Temperature = int(32)
# myExp.Analytics = ['Biomass']#, 'Carbon-Substrate', 'HPLC'] # , 'Carbon-Substrate','ProductsSol'
# myExp.CarbonName = ['EX_glc__D_e']
# myExp.CarbonSubConc = {'EX_glc__D_e':5.0}
# myExp.CultivationTime = 8.0
# myExp.SamplingInterval = 0.5
# myExp.AnalyticSampling = 4
# myExp.InitBiomass = 0.01
# myExp.set_SamplingVector()
############################################################################
############################################################################
# run simulation
Data = st.session_state['exp'].measure_TemperatureGrowth(myExp)
# st.write(myExp)
# Display OutputFilePath
st.write('### Simulation OutputFilePath')
st.write(Data.value)
for analytic in myExp.Analytics:
if analytic == 'HPLC':
fig_Bio, ax_Bio = Data.make_3dplot('HPLC', 'time', 'signal')
ax_Bio.set_ylabel('Sample time')
st.pyplot(fig_Bio)
elif analytic == 'Metabolites':
fig_mets, ax_mets = Data.make_plot(XName='time (h)', YNames=[f'{met} conc. (mM)' for met in myExp.CarbonConcDynamic.keys()])
st.pyplot(fig_mets)
elif analytic == 'GTR':
fig_GTR, ax_GTR = Data.make_plot(XName='time (h)', YNames=['OTR (mM/h)', 'CTR (mM/h)'])
ax_GTR.set_ylabel('Rate (mM/h)')
st.pyplot(fig_GTR)
else:
fig_Bio, ax_Bio = Data.make_plot(XName='time (h)', YNames=[analytic])
st.pyplot(fig_Bio)
with pd.ExcelWriter(myExp.OutputFilePath, engine='openpyxl') as writer:
Data.value.to_excel(writer, sheet_name=myExp.ExperimentID, index=False)
st.markdown(f'Data saved to {myExp.OutputFilePath}')
st.download_button(
label="Download data as Excel",
data=open(myExp.OutputFilePath, 'rb').read(),
file_name=os.path.split(myExp.OutputFilePath)[-1],
mime="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
)
# st.session_state['exp'].record_experiment(myExp)
st.success('Data simulation completed and file is ready for download.')
else:
if st.session_state['exp'] is None:
st.warning('Please initialize the experiment first.')
else:
st.info('Select "Shake Flask" from the dropdown to set parameters and run the simulation.')
if st.sidebar.toggle('Organism Details'):
if int(st.sidebar.number_input('Password', value=None)) == 150981: # Replace 1234 with your actual password
if st.session_state['host'] is not None:
st.sidebar.markdown(f'### Organism: {st.session_state["organism"]}')
st.sidebar.markdown(f'Model ID: {st.session_state["host"].metabolism.model.id}')
# st.sidebar.markdown(f'# reactions: {len(st.session_state["host"].metabolism.model.reactions)}')
# st.sidebar.markdown(f'# metabolites: {len(st.session_state["host"].metabolism.model.metabolites)}')
# st.sidebar.markdown(f'# genes: {len(st.session_state["host"].metabolism.model.genes)}')
# show optimal growth temperature
st.sidebar.markdown(f'Opt. Temp.: {st.session_state["host"].opt_growth_temp} °C')
st.sidebar.markdown(f'OD2DW factor: {st.session_state["host"].growth.OD2X} gCDW/OD600')
st.sidebar.markdown(f'Vmax, Km, KI: {st.session_state["host"].metabolism.model.reactions.get_by_id(myExp.CarbonName[0]).Vmax}, {st.session_state["host"].metabolism.model.reactions.get_by_id(myExp.CarbonName[0]).Km}, {st.session_state["host"].metabolism.model.reactions.get_by_id(myExp.CarbonName[0]).KI}')
else:
st.sidebar.info('Experiment not initialized yet.')
else:
st.sidebar.error('Incorrect password.')
st.sidebar.subheader("Reset Experiment")
if st.sidebar.button('Reset Experiment'):
st.session_state['ExpInit'] = None
st.session_state['exp'] = None
st.sidebar.success('Experiment reset. You can set up a new experiment now.')
# Stop button that resets any background computation
if st.sidebar.button('Stop Background Computation'):
st.session_state['stop'] = True
st.sidebar.success('Background computation will stop soon.')