MuzammilMax commited on
Commit
2406611
·
verified ·
1 Parent(s): a01b13d

Upload app.py

Browse files
Files changed (1) hide show
  1. app.py +500 -733
app.py CHANGED
@@ -4,13 +4,13 @@
4
  Automatically generated by Colab.
5
 
6
  Original file is located at
7
- https://colab.research.google.com/drive/1GgGC-fVnA0fSxU859NjSi_jH8yiWUKOu
 
 
8
  """
9
 
10
  # !pip install tensorflow==2.15
11
 
12
- """# Chem simulation using scipy"""
13
-
14
  import numpy as np
15
  import matplotlib.pyplot as plt
16
  import pandas as pd
@@ -144,10 +144,10 @@ def ode1(A0, B0, C0, temp, Ea, A_factor):
144
  k = compute_k(temp, Ea, A_factor)
145
  k_1 = k * random.uniform(0.5, 0.9)
146
 
147
- t_span = (0, 8) # From time 0 to 10 seconds
148
- t_eval = np.linspace(0, 8, 11) # 11 points where you want the solution
149
 
150
- num = random.randint(0, 11) # For choosing between first or decay if not reversible
151
 
152
  match num:
153
  case 0:
@@ -225,7 +225,54 @@ def ode1(A0, B0, C0, temp, Ea, A_factor):
225
  results = []
226
 
227
  counter = 0
228
- while counter < 6000:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
229
  counter += 1
230
 
231
  A0 = round(random.uniform(1.0, 10.0), 2)
@@ -264,9 +311,16 @@ while counter < 6000:
264
  }
265
  results.append(row)
266
 
267
- df = pd.DataFrame(results)
268
- df_original = df.copy()
269
- # df
 
 
 
 
 
 
 
270
 
271
  """# Machine learning
272
 
@@ -283,25 +337,188 @@ order_map = {'zero': 0, 'first': 1, 'second': 2, 'third' : 3}
283
  df['structure'] = df['structure'].map(structure_map)
284
  df['catalyst'] = df['catalyst'].map(catalyst_map)
285
  df['order'] = df['order'].map(order_map)
286
- # df
287
 
288
- """## Models
289
 
290
- ## DNN (Deep Neural Networks)
 
291
 
292
- - saving file as csv
293
- """
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
294
 
295
- df_X = df_original.drop(['order'], axis=1)
296
- df_y = df_original['order']
297
 
298
- train_df = df_X.copy()
299
- train_df['order'] = df_y
300
 
301
- train_df.to_csv('chem_data_train.csv', index=False)
302
- train_df.to_csv('chem_data_test.csv', index=False)
 
303
 
304
- """- DNNs"""
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
305
 
306
  csv_columns = ['temp', 'pH', 'Ea', 'A_factor', 'pressure', 'log_pressure', 'weight', 'structure', 'catalyst', 'is_reversible', 'k', 'k_1']
307
  classes = ['First_Order','Second_Order','Third_Order']
@@ -312,21 +529,29 @@ test_path = './chem_data_train.csv'
312
  train = pd.read_csv(train_path)
313
  test = pd.read_csv(test_path)
314
 
315
- # train.head()
 
 
 
 
 
316
 
317
  if 'order' in train.columns:
318
  train_y = train.pop('order')
319
  if 'order' in test.columns:
320
  test_y = test.pop('order')
321
 
322
- # Fill missing values in the 'catalyst' column
323
- train['catalyst'] = train['catalyst'].fillna('None') #NaN values arenot accepted by classifier thats why convert every Nan values to none
324
  test['catalyst'] = test['catalyst'].fillna('None')
325
 
326
 
327
- # train.head() #the species column is now gone
 
 
 
 
328
 
329
- # Define categorical and numerical feature columns
330
  CATEGORICAL_COLUMNS = ['structure', 'catalyst'] #columns that have strings
331
  NUMERIC_COLUMNS = ['temp', 'pH', 'Ea', 'A_factor', 'pressure', 'log_pressure', 'weight',
332
  'is_reversible', 'k', 'k_1', 'A0', 'A1', 'A2', 'A3', 'A4', 'A5', 'A6', 'A7', 'A8', 'A9', 'A10',
@@ -335,7 +560,7 @@ NUMERIC_COLUMNS = ['temp', 'pH', 'Ea', 'A_factor', 'pressure', 'log_pressure', '
335
 
336
  feature_columns = []
337
  for feature_name in CATEGORICAL_COLUMNS:
338
- vocabulary = train[feature_name].unique() #Assining each string a numerical uinque value because our dumb ahh model canot understand english
339
  cat_column = tf.feature_column.categorical_column_with_vocabulary_list(feature_name, vocabulary)
340
  indicator_column = tf.feature_column.indicator_column(cat_column) #it creates binary coolumns that will be mapped in to feature columns and it will be steamlined to our DNN model
341
  feature_columns.append(indicator_column)
@@ -348,20 +573,22 @@ print(feature_columns)
348
  import logging
349
  tf.get_logger().setLevel(logging.INFO)
350
 
351
- #setting up input function
 
 
352
 
353
  def input_fn(features,labels,training=True,batch_size=500):
354
- #convert the inputs to a dataset
355
  dataset = tf.data.Dataset.from_tensor_slices((dict(features), labels)) #this cnonverts the dataset into tensorflow object
356
 
357
  if training:
358
- dataset = dataset.shuffle(1000).repeat()
359
 
360
  return dataset.batch(batch_size)
361
 
 
 
362
  from sklearn.preprocessing import StandardScaler
363
 
364
- # Normalize the numerical features in the training data
365
  scaler = StandardScaler()
366
  train_normalized = train.copy()
367
  train_normalized[NUMERIC_COLUMNS] = scaler.fit_transform(train[NUMERIC_COLUMNS])
@@ -369,9 +596,10 @@ train_normalized[NUMERIC_COLUMNS] = scaler.fit_transform(train[NUMERIC_COLUMNS])
369
  test_normalized = test.copy()
370
  test_normalized[NUMERIC_COLUMNS] = scaler.transform(test[NUMERIC_COLUMNS])
371
 
 
 
372
  from sklearn.preprocessing import LabelEncoder
373
 
374
- # Convert the 'order' labels to numerical values
375
  le = LabelEncoder()
376
  train_y_encoded = le.fit_transform(train_y) #we used sckit label encoder to encode the values
377
 
@@ -383,747 +611,286 @@ classifier = tf.estimator.DNNClassifier(
383
 
384
  classifier.train(
385
  input_fn=lambda: input_fn(train_normalized, train_y_encoded, training=True),
386
- steps=5000
387
  )
388
 
389
- test_y_encoded = le.fit_transform(test_y) #we used sckit label encoder to encode the values better than 1 2 3 4 5 blah blah
390
 
391
  classifier.evaluate(input_fn=lambda: input_fn(test_normalized,test_y_encoded,training=False))
392
 
393
  """- accuracy = 0.99983335
394
 
395
- # Interactive/sliders
396
-
397
- - TODO: be able to change chemical-initial-conc, temp, ea, A_factor, pH, molecular-weight using sliders/input
398
- - best ml model predicts the order of the differential equation from that
399
  """
400
 
401
- def ode2(A0, B0, C0, temp, Ea, A_factor, is_reversible, order):
402
- y0 = [A0, B0, C0]
403
-
404
- k = compute_k(temp, Ea, A_factor)
405
- k_1 = k * 0.7
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
406
 
407
- t_span = (0, 8)
408
- t_eval = np.linspace(0, 8, 11)
409
 
410
- if order == 'zero':
411
- solution = solve_ivp(zero, t_span, y0, args=(k,) ,t_eval=t_eval)
412
- elif is_reversible == 0 and order == 'first':
413
- solution = solve_ivp(first, t_span, y0, args=(k,) ,t_eval=t_eval)
414
- elif is_reversible == 1 and order == 'first':
415
- solution = solve_ivp(reversible_first, t_span, y0, args=(k, k_1) ,t_eval=t_eval)
416
- elif is_reversible == 0 and order == 'second':
417
- solution = solve_ivp(second1, t_span, y0, args=(k,) ,t_eval=t_eval)
418
- elif is_reversible == 1 and order == 'second':
419
- solution = solve_ivp(reversible_second1, t_span, y0, args=(k, k_1) ,t_eval=t_eval)
420
- elif is_reversible == 0 and order == 'third':
421
- solution = solve_ivp(third2, t_span, y0, args=(k,) ,t_eval=t_eval)
422
- elif is_reversible == 1 and order == 'third':
423
- solution = solve_ivp(reversible_third2, t_span, y0, args=(k, k_1) ,t_eval=t_eval)
424
-
425
- return solution.t, solution.y[0], solution.y[1], solution.y[2], k, k_1
426
-
427
- def predict_order(A, B, C, temp, Ea, A_factor, pH, pressure, is_reversible, structure, catalyst):
428
- """
429
- Predicts the order of a chemical reaction based on concentration time series data and reaction conditions.
430
- """
431
- try:
432
- # Create a dictionary with all the necessary inputs for the model
433
- inputs = {
434
- 'temp': temp,
435
- 'pH': pH,
436
- 'Ea': Ea,
437
- 'A_factor': A_factor,
438
- 'pressure': pressure,
439
- 'log_pressure': np.log(pressure),
440
- 'weight': 150, # Placeholder
441
- 'structure': structure,
442
- 'catalyst': catalyst,
443
- 'is_reversible': int(is_reversible),
444
- 'k': compute_k(temp, Ea, A_factor),
445
- 'k_1': compute_k(temp, Ea, A_factor) * 0.7, # Consistent with ode2
446
- 'A0': A[0], 'A1': A[1], 'A2': A[2], 'A3': A[3], 'A4': A[4],
447
- 'A5': A[5], 'A6': A[6], 'A7': A[7], 'A8': A[8], 'A9': A[9], 'A10': A[10],
448
- 'B0': B[0], 'B1': B[1], 'B2': B[2], 'B3': B[3], 'B4': B[4],
449
- 'B5': B[5], 'B6': B[6], 'B7': B[7], 'B8': B[8], 'B9': B[9], 'B10': B[10],
450
- 'C0': C[0], 'C1': C[1], 'C2': C[2], 'C3': C[3], 'C4': C[4],
451
- 'C5': C[5], 'C6': C[6], 'C7': C[7], 'C8': C[8], 'C9': C[9], 'C10': C[10]
452
- }
453
-
454
- # Create a pandas DataFrame from the input dictionary
455
- input_df = pd.DataFrame(inputs, index=[0])
456
-
457
- # Normalize the numerical features
458
- input_df[NUMERIC_COLUMNS] = scaler.transform(input_df[NUMERIC_COLUMNS])
459
-
460
- # Make a prediction
461
- predictions = classifier.predict(input_fn=lambda: input_fn(input_df, labels=None, training=False))
462
-
463
- # Get the predicted class and probability
464
- for pred_dict in predictions:
465
- class_id = pred_dict['class_ids'][0]
466
- probability = pred_dict['probabilities'][class_id]
467
- # Get the class name from the label encoder
468
- class_name = le.inverse_transform([class_id])[0]
469
- print('Order is "{}" ({:.1f}%)'.format(class_name, 100 * probability))
470
- return class_name
471
- except Exception as e:
472
- print(f"An error occurred: {e}")
473
- return None
474
-
475
- """## gradio"""
476
-
477
- # !pip install gradio
478
 
479
  import gradio as gr
480
  import pandas as pd
481
  import numpy as np
482
  import matplotlib.pyplot as plt
483
-
484
- def run_simulation_and_plot(temp, Ea, A_factor, pH, pressure, is_reversible, structure, catalyst, A0, B0, C0):
485
- # --- 1. Simulation with ode2 to get data for prediction ---
486
- # For prediction, we need a simulated order. We can use a default or a simplified logic.
487
- # Here, we'll arbitrarily use 'first' for the initial simulation to get data.
488
- time_pred, A_pred, B_pred, C_pred, k_pred, k_1_pred = ode2(A0, B0, C0, temp, Ea, A_factor, int(is_reversible), 'first')
489
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
490
 
491
  # --- 2. Prediction ---
492
- predicted_order = predict_order(A_pred, B_pred, C_pred, temp, Ea, A_factor, pH, pressure, is_reversible, structure, catalyst)
493
-
494
- # --- 3. Simulation with ode2 and Predicted Order ---
495
- # Use ode2 for the final simulation and plotting
496
- time_sim, A_sim, B_sim, C_sim, k_sim, k_1_sim = ode2(A0, B0, C0, temp, Ea, A_factor, int(is_reversible), predicted_order)
497
 
 
 
498
 
499
  # --- 4. Plotting ---
500
- plt.figure()
501
- plt.plot(time_sim, A_sim, label='A')
502
- plt.plot(time_sim, B_sim, label='B')
503
- plt.plot(time_sim, C_sim, label='C')
504
- plt.xlabel('Time')
505
- plt.ylabel('Concentration')
506
- plt.title(f'Concentration vs. Time (Predicted Order: {predicted_order})')
507
- plt.legend()
508
- plt.grid(True)
509
 
 
 
 
 
 
510
 
511
- return predicted_order, plt
 
 
 
 
 
512
 
513
  # --- 5. Gradio Interface ---
514
- with gr.Blocks() as iface:
515
- gr.Markdown("# Project E-11: Chemical Reaction Order Prediction and Simulation")
516
- gr.Markdown("Made by Mujtaba , Muzammil , Taha and Ali Zain ")
517
- gr.Markdown("Use the sliders and options to see the predicted reaction order and a plot of the concentrations over time.")
518
- with gr.Row():
519
- with gr.Column():
520
- gr.Markdown("### Reaction Conditions")
521
- temp = gr.Slider(270, 280, value=277, label="Temperature (K)")
522
- Ea = gr.Slider(90, 100, value=93, label="Activation Energy (Ea, kJ/mol)")
523
- A_factor = gr.Slider(2e16, 5e17, value=4.2e17, label="Pre-exponential Factor (A_factor)")
524
- pH = gr.Slider(1.0, 14.0, value=6.5, label="pH")
525
- pressure = gr.Slider(0.5, 5.0, value=3.0, label="Pressure")
526
- is_reversible = gr.Checkbox(label="Is Reversible?")
527
- structure = gr.Dropdown(['Linear', 'Ring', 'Branched', 'Unknown'], label="Structure")
528
- catalyst = gr.Dropdown(['None', 'Enzyme', 'Acid', 'Base'], label="Catalyst")
529
- with gr.Column():
530
- gr.Markdown("### Initial Concentrations")
531
- A0 = gr.Slider(0.0, 10.0, value=5.0, label="A0")
532
- B0 = gr.Slider(0.0, 10.0, value=2.0, label="B0")
533
- C0 = gr.Slider(0.0, 10.0, value=1.0, label="C0")
534
 
535
  with gr.Row():
536
- predict_button = gr.Button("Predict and Plot")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
537
  with gr.Row():
538
- with gr.Column():
539
- order_output = gr.Textbox(label="Predicted Order")
540
- with gr.Column():
541
- plot_output = gr.Plot()
542
 
543
  predict_button.click(
544
  fn=run_simulation_and_plot,
545
- inputs=[temp, Ea, A_factor, pH, pressure, is_reversible, structure, catalyst, A0, B0, C0],
546
  outputs=[order_output, plot_output]
547
  )
548
 
549
-
550
  iface.launch(debug=True)
551
 
552
- # !gradio deploy
553
-
554
- """## Streamlit Stuff"""
555
-
556
- # !pip install -q streamlit
557
-
558
- # import streamlit as st
559
- # import pandas as pd
560
- # import numpy as np
561
- # import matplotlib.pyplot as plt
562
-
563
- # # Assuming the functions compute_k, ode1, ode2, predict_order, and the classifier, scaler, and le objects are already defined and available in the notebook's global scope from previous cells.
564
-
565
- # st.set_page_config(layout="wide", page_title="Chemical Reaction Simulator") # Set page layout to wide and add a page title
566
-
567
- # st.title("🧪 Chemical Reaction Order Prediction and Simulation ✨")
568
- # st.markdown("Adjust the parameters below to predict the reaction order and visualize the concentration changes over time. 👇")
569
-
570
- # # Use columns for a better layout of inputs
571
- # col1, col2 = st.columns(2)
572
-
573
- # with col1:
574
- # st.header("⚙️ Reaction Conditions")
575
- # temp = st.slider("Temperature (K) 🌡️", 270.0, 280.0, value=277.0)
576
- # Ea = st.slider("Activation Energy (Ea, kJ/mol) 🔥", 90.0, 100.0, value=93.0)
577
- # A_factor = st.slider("Pre-exponential Factor (A_factor) 📈", 2e16, 5e17, value=4.2e17, format="%e") # Use scientific notation format
578
- # pH = st.slider("pH 🧪", 1.0, 14.0, value=6.5)
579
- # pressure = st.slider("Pressure 🌫️", 0.5, 5.0, value=3.0)
580
- # is_reversible = st.checkbox("Is Reversible? 🔄", value=False)
581
- # structure = st.selectbox("Structure ⚛️", ['Linear', 'Ring', 'Branched', 'Unknown'], index=1)
582
- # catalyst = st.selectbox("Catalyst ✨", ['None', 'Enzyme', 'Acid', 'Base'], index=2)
583
-
584
- # with col2:
585
- # st.header("📈 Initial Concentrations")
586
- # A0 = st.slider("Initial Concentration of A (A₀)", 0.0, 10.0, value=5.0)
587
- # B0 = st.slider("Initial Concentration of B (B₀)", 0.0, 10.0, value=2.0)
588
- # C0 = st.slider("Initial Concentration of C (C₀)", 0.0, 10.0, value=1.0)
589
-
590
- # st.markdown("---") # Add a horizontal rule for separation
591
-
592
- # if st.button("🚀 Predict and Plot Reaction"):
593
- # # Data Preparation for Prediction
594
- # # Simulate the reaction using ode1 to get concentrations over time for prediction features
595
- # time_pred, A_pred, B_pred, C_pred, k_pred, k_1_pred, is_reversible_simulated, order_simulated = ode1(A0, B0, C0, temp, Ea, A_factor)
596
-
597
- # # Create a dictionary with all the necessary inputs for the model
598
- # inputs = {
599
- # 'temp': temp,
600
- # 'pH': pH,
601
- # 'Ea': Ea,
602
- # 'A_factor': A_factor,
603
- # 'pressure': pressure,
604
- # 'log_pressure': np.log(pressure),
605
- # 'weight': 150, # Using a placeholder value as it's not a user input
606
- # 'structure': structure,
607
- # 'catalyst': catalyst,
608
- # 'is_reversible': int(is_reversible),
609
- # 'k': k_pred, # Use simulated k
610
- # 'k_1': k_1_pred, # Use simulated k_1
611
- # 'A0': A_pred[0], 'A1': A_pred[1], 'A2': A_pred[2], 'A3': A_pred[3], 'A4': A_pred[4],
612
- # 'A5': A_pred[5], 'A6': A_pred[6], 'A7': A_pred[7], 'A8': A_pred[8], 'A9': A_pred[9], 'A10': A_pred[10],
613
- # 'B0': B_pred[0], 'B1': B_pred[1], 'B2': B_pred[2], 'B3': B_pred[3], 'B4': B_pred[4],
614
- # 'B5': B_pred[5], 'B6': B_pred[6], 'B7': B_pred[7], 'B8': B_pred[8], 'B9': B_pred[9], 'B10': B_pred[10],
615
- # 'C0': C_pred[0], 'C1': C_pred[1], 'C2': C_pred[2], 'C3': C_pred[3], 'C4': C_pred[4],
616
- # 'C5': C_pred[5], 'C6': C_pred[6], 'C7': C_pred[7], 'C8': C_pred[8], 'C9': C_pred[9], 'C10': C_pred[10]
617
- # }
618
-
619
- # # --- 2. Prediction ---
620
- # with st.spinner('Predicting reaction order...'):
621
- # predicted_order = predict_order(inputs)
622
- # st.success(f"✅ Predicted Order: **{predicted_order}**")
623
-
624
- # # --- 3. Simulation with ode2 and Predicted Order ---
625
- # with st.spinner('Simulating reaction...'):
626
- # time_sim, A_sim, B_sim, C_sim, k_sim, k_1_sim = ode2(A0, B0, C0, temp, Ea, A_factor, int(is_reversible), predicted_order)
627
-
628
- # # --- 4. Plotting ---
629
- # st.header("📊 Concentration vs. Time Plot")
630
- # fig, ax = plt.subplots()
631
- # ax.plot(time_sim, A_sim, label='A', marker='o') # Add markers to plot points
632
- # ax.plot(time_sim, B_sim, label='B', marker='x')
633
- # ax.plot(time_sim, C_sim, label='C', marker='s')
634
- # ax.set_xlabel('Time')
635
- # ax.set_ylabel('Concentration')
636
- # ax.set_title(f'Concentration vs. Time (Predicted Order: {predicted_order})')
637
- # ax.legend()
638
- # ax.grid(True)
639
-
640
- # st.pyplot(fig)
641
-
642
- # st.markdown("---")
643
- # st.markdown("App created with ❤️ using Streamlit")
644
-
645
-
646
 
647
  # !npm install -g localtunnel
648
 
649
- """Main code for Steamlit pipeline
650
-
651
- first copy this code and then create a file named app.py and save it
652
- """
653
-
654
- # import numpy as np
655
- # import matplotlib.pyplot as plt
656
- # import pandas as pd
657
- # from scipy.integrate import solve_ivp
658
- # import random
659
- # import tensorflow as tf
660
-
661
- # def compute_k(temp, Ea, A_factor):
662
- # R = 8.314
663
- # Ea_J = Ea * 1000 # Convert Ea from kJ/mol to J/mol
664
- # k = A_factor * np.exp(-Ea_J / (R * temp))
665
- # return k
666
-
667
- # def zero(t, y, k):
668
- # A, B, C = y
669
- # dA_dt = -k
670
- # dB_dt = 0
671
- # dC_dt = k
672
- # return [dA_dt, dB_dt, dC_dt]
673
-
674
- # def first(t, y, k):
675
- # A, B, C = y
676
- # dA_dt = -k * A
677
- # dB_dt = 0
678
- # dC_dt = +k * A
679
- # return [dA_dt, dB_dt, dC_dt]
680
-
681
- # def decay_first(t, y, k):
682
- # A, B, C = y
683
- # dA_dt = -k * A
684
- # dB_dt = 0
685
- # dC_dt = 0
686
- # return [dA_dt, dB_dt, dC_dt]
687
-
688
- # def reversible_first(t, y, k, k_1):
689
- # A, B, C = y
690
- # dA_dt = -k * A + k_1 * C
691
- # dB_dt = 0
692
- # dC_dt = k * A - k_1 * C
693
- # return [dA_dt, dB_dt, dC_dt]
694
-
695
- # def second1(t, y, k):
696
- # A, B, C = y
697
- # dA_dt = -k * A * B
698
- # dB_dt = -k * A * B
699
- # dC_dt = +k * A * B
700
- # return [dA_dt, dB_dt, dC_dt]
701
-
702
- # def second2(t, y, k):
703
- # A, B, C = y
704
- # dA_dt = -2 * k * A**2
705
- # dB_dt = 0
706
- # dC_dt = +k * A**2
707
- # return [dA_dt, dB_dt, dC_dt]
708
-
709
- # def reversible_second1(t, y, k, k_1):
710
- # A, B, C = y
711
- # dA_dt = -k * A * B + k_1 * C
712
- # dB_dt = -k * A * B + k_1 * C
713
- # dC_dt = +k * A * B - k_1 * C
714
- # return [dA_dt, dB_dt, dC_dt]
715
-
716
- # def reversible_second2(t, y, k, k_1):
717
- # A, B, C = y
718
- # dA_dt = -2 * k * A**2 + 2 * k_1 * C
719
- # dB_dt = 0
720
- # dC_dt = +k * A**2 - k_1 * C
721
- # return [dA_dt, dB_dt, dC_dt]
722
-
723
- # def third1(t, y, k):
724
- # A, B, C = y
725
- # dA_dt = -3 * k * A**3
726
- # dB_dt = 0
727
- # dC_dt = +k * A**3
728
- # return [dA_dt, dB_dt, dC_dt]
729
-
730
- # def third2(t, y, k):
731
- # A, B, C = y
732
- # dA_dt = -2 * k * A**2 * B
733
- # dB_dt = -1 * k * A**2 * B
734
- # dC_dt = +k * A**2 * B
735
- # return [dA_dt, dB_dt, dC_dt]
736
-
737
- # def reversible_third1(t, y, k, k_1):
738
- # A, B, C = y
739
- # dA_dt = -3 * k * A**3 + 3 * k_1 * C
740
- # dB_dt = 0
741
- # dC_dt = +k * A**3 - k_1 * C
742
- # return [dA_dt, dB_dt, dC_dt]
743
-
744
- # def reversible_third2(t, y, k, k_1):
745
- # A, B, C = y
746
- # dA_dt = -2 * k * A**2 * B + 2 * k_1 * C
747
- # dB_dt = -1 * k * A**2 * B + 1 * k_1 * C
748
- # dC_dt = +k * A**2 * B - k_1 * C
749
- # return [dA_dt, dB_dt, dC_dt]
750
-
751
-
752
- # def ode1(A0, B0, C0, temp, Ea, A_factor):
753
- # y0 = [A0, B0, C0]
754
- # k = compute_k(temp, Ea, A_factor)
755
- # k_1 = k * random.uniform(0.5, 0.9)
756
-
757
- # t_span = (0, 8) # From time 0 to 10 seconds
758
- # t_eval = np.linspace(0, 8, 11) # 11 points where you want the solution
759
-
760
- # num = random.randint(0, 11) # For choosing between first or decay if not reversible
761
-
762
- # match num:
763
- # case 0:
764
- # func_name = zero
765
- # is_reversible = 0
766
- # order = 'zero'
767
- # case 1:
768
- # func_name = first
769
- # is_reversible = 0
770
- # order = 'first'
771
- # case 2:
772
- # func_name = decay_first
773
- # is_reversible = 0
774
- # order = 'first'
775
- # case 3:
776
- # func_name = reversible_first
777
- # is_reversible = 1
778
- # order = 'first'
779
- # case 4:
780
- # func_name = second1
781
- # is_reversible = 0
782
- # order = 'second'
783
- # case 5:
784
- # func_name = second2
785
- # is_reversible = 0
786
- # order = 'second'
787
- # case 6:
788
- # func_name = reversible_second1
789
- # is_reversible = 1
790
- # order = 'second'
791
- # case 7:
792
- # func_name = reversible_second2
793
- # is_reversible = 1
794
- # order = 'second'
795
- # case 8:
796
- # func_name = third1
797
- # is_reversible = 0
798
- # order = 'third'
799
- # case 9:
800
- # func_name = third2
801
- # is_reversible = 0
802
- # order = 'third'
803
- # case 10:
804
- # func_name = reversible_third1
805
- # is_reversible = 1
806
- # order = 'third'
807
- # case 11:
808
- # func_name = reversible_third2
809
- # is_reversible = 1
810
- # order = 'third'
811
-
812
-
813
- # if is_reversible == 1:
814
- # solution = solve_ivp(
815
- # func_name,
816
- # t_span,
817
- # y0,
818
- # args=(k, k_1),
819
- # t_eval=t_eval
820
- # )
821
- # elif is_reversible == 0:
822
- # solution = solve_ivp(
823
- # func_name,
824
- # t_span,
825
- # y0,
826
- # args=(k,),
827
- # t_eval=t_eval
828
- # )
829
-
830
-
831
- # return solution.t, solution.y[0], solution.y[1], solution.y[2], k, k_1, is_reversible, order
832
-
833
- # results = []
834
-
835
- # counter = 0
836
- # while counter < 6000:
837
- # counter += 1
838
-
839
- # A0 = round(random.uniform(1.0, 10.0), 2)
840
- # B0 = round(random.uniform(0.0, 5.0), 2)
841
- # C0 = round(random.uniform(0.0, 5.0), 2)
842
- # temp = random.randint(270, 280)
843
- # pH = round(random.uniform(1.0, 14.0), 2)
844
- # Ea = random.randint(90, 100)
845
- # A_factor = round(random.uniform(2e16, 5e17), 2)
846
- # pressure = round(random.uniform(0.5, 5.0), 2)
847
- # weight = round(random.uniform(20, 200), 1)
848
- # structure = random.choice(['Linear', 'Ring', 'Branched', 'Unknown'])
849
- # catalyst = random.choice(['None', 'Enzyme', 'Acid', 'Base'])
850
- # time, A, B, C, k, k_1, is_reversible, order = ode1(A0, B0, C0, temp, Ea, A_factor)
851
-
852
- # row = {
853
- # 'order' : order,
854
- # 'temp': temp,
855
- # 'pH': pH,
856
- # 'Ea': Ea,
857
- # 'A_factor': A_factor,
858
- # 'pressure': pressure,
859
- # 'log_pressure' : np.log(pressure),
860
- # 'weight': weight,
861
- # 'structure': structure,
862
- # 'catalyst': catalyst,
863
- # 'is_reversible': is_reversible,
864
- # 'k' : k,
865
- # 'k_1' : k_1,
866
- # 'A0': A[0], 'A1': A[1], 'A2': A[2], 'A3': A[3], 'A4': A[4],
867
- # 'A5': A[5], 'A6': A[6], 'A7': A[7], 'A8': A[8], 'A9': A[9], 'A10': A[10],
868
- # 'B0': B[0], 'B1': B[1], 'B2': B[2], 'B3': B[3], 'B4': B[4],
869
- # 'B5': B[5], 'B6': B[6], 'B7': B[7], 'B8': B[8], 'B9': B[9], 'B10': B[10],
870
- # 'C0': C[0], 'C1': C[1], 'C2': C[2], 'C3': C[3], 'C4': C[4],
871
- # 'C5': C[5], 'C6': C[6], 'C7': C[7], 'C8': C[8], 'C9': C[9], 'C10': C[10]
872
- # }
873
- # results.append(row)
874
-
875
- # df = pd.DataFrame(results)
876
- # df_original = df.copy()
877
- # # display(df)
878
-
879
- # structure_map = {'Linear': 0, 'Ring': 1, 'Branched': 2, 'Unknown': 3}
880
- # catalyst_map = {'None': 0, 'Enzyme': 1, 'Acid': 2, 'Base': 3}
881
- # order_map = {'zero': 0, 'first': 1, 'second': 2, 'third' : 3}
882
- # df['structure'] = df['structure'].map(structure_map)
883
- # df['catalyst'] = df['catalyst'].map(catalyst_map)
884
- # df['order'] = df['order'].map(order_map)
885
- # # display(df)
886
-
887
-
888
- # csv_columns = ['temp', 'pH', 'Ea', 'A_factor', 'pressure', 'log_pressure', 'weight', 'structure', 'catalyst', 'is_reversible', 'k', 'k_1']
889
- # classes = ['First_Order','Second_Order','Third_Order']
890
-
891
- # train_path = './chem_data_train.csv'
892
- # test_path = './chem_data_train.csv'
893
-
894
- # train = pd.read_csv(train_path)
895
- # test = pd.read_csv(test_path)
896
-
897
- # # display(train.head())
898
-
899
- # if 'order' in train.columns:
900
- # train_y = train.pop('order')
901
- # if 'order' in test.columns:
902
- # test_y = test.pop('order')
903
-
904
- # # Fill missing values in the 'catalyst' column
905
- # train['catalyst'] = train['catalyst'].fillna('None') #NaN values arenot accepted by classifier thats why convert every Nan values to none
906
- # test['catalyst'] = test['catalyst'].fillna('None')
907
-
908
-
909
- # # display(train.head()) #the species column is now gone
910
-
911
- # # Define categorical and numerical feature columns
912
- # CATEGORICAL_COLUMNS = ['structure', 'catalyst'] #columns that have strings
913
- # NUMERIC_COLUMNS = ['temp', 'pH', 'Ea', 'A_factor', 'pressure', 'log_pressure', 'weight',
914
- # 'is_reversible', 'k', 'k_1', 'A0', 'A1', 'A2', 'A3', 'A4', 'A5', 'A6', 'A7', 'A8', 'A9', 'A10',
915
- # 'B0', 'B1', 'B2', 'B3', 'B4', 'B5', 'B6', 'B7', 'B8', 'B9', 'B10',
916
- # 'C0', 'C1', 'C2', 'C3', 'C4', 'C5', 'C6', 'C7', 'C8', 'C9', 'C10'] #columns that have numerical values
917
-
918
- # feature_columns = []
919
- # for feature_name in CATEGORICAL_COLUMNS:
920
- # vocabulary = train[feature_name].unique() #Assining each string a numerical uinque value because our dumb ahh model canot understand english
921
- # cat_column = tf.feature_column.categorical_column_with_vocabulary_list(feature_name, vocabulary)
922
- # indicator_column = tf.feature_column.indicator_column(cat_column) #it creates binary coolumns that will be mapped in to feature columns and it will be steamlined to our DNN model
923
- # feature_columns.append(indicator_column)
924
-
925
- # for feature_name in NUMERIC_COLUMNS:
926
- # feature_columns.append(tf.feature_column.numeric_column(feature_name, dtype=tf.float32))
927
-
928
- # # print(feature_columns)
929
-
930
- # import logging
931
- # tf.get_logger().setLevel(logging.INFO)
932
-
933
- # #setting up input function
934
-
935
- # def input_fn(features,labels,training=True,batch_size=500):
936
- # #convert the inputs to a dataset
937
- # dataset = tf.data.Dataset.from_tensor_slices((dict(features), labels)) #this cnonverts the dataset into tensorflow object
938
-
939
- # if training:
940
- # dataset = dataset.shuffle(1000).repeat()
941
-
942
- # return dataset.batch(batch_size)
943
-
944
- # from sklearn.preprocessing import StandardScaler
945
-
946
- # # Normalize the numerical features in the training data
947
- # scaler = StandardScaler()
948
- # train_normalized = train.copy()
949
- # train_normalized[NUMERIC_COLUMNS] = scaler.fit_transform(train[NUMERIC_COLUMNS])
950
-
951
- # test_normalized = test.copy()
952
- # test_normalized[NUMERIC_COLUMNS] = scaler.transform(test[NUMERIC_COLUMNS])
953
-
954
- # from sklearn.preprocessing import LabelEncoder
955
-
956
- # # Convert the 'order' labels to numerical values
957
- # le = LabelEncoder()
958
- # train_y_encoded = le.fit_transform(train_y) #we used sckit label encoder to encode the values
959
-
960
- # classifier = tf.estimator.DNNClassifier(
961
- # feature_columns=feature_columns,
962
- # hidden_units=[50, 40],
963
- # n_classes=4, # We have 4 classes: zero, first, second, third
964
- # optimizer=tf.keras.optimizers.legacy.RMSprop(learning_rate=0.001))
965
-
966
- # classifier.train(
967
- # input_fn=lambda: input_fn(train_normalized, train_y_encoded, training=True),
968
- # steps=300
969
- # )
970
-
971
- # test_y_encoded = le.fit_transform(test_y) #we used sckit label encoder to encode the values better than 1 2 3 4 5 blah blah
972
-
973
- # classifier.evaluate(input_fn=lambda: input_fn(test_normalized,test_y_encoded,training=False))
974
-
975
-
976
- # def predict_order(inputs):
977
-
978
- # try:
979
- # # Create a pandas DataFrame from the input dictionary
980
- # input_df = pd.DataFrame(inputs, index=[0])
981
-
982
- # # Normalize the numerical features
983
- # input_df[NUMERIC_COLUMNS] = scaler.transform(input_df[NUMERIC_COLUMNS])
984
-
985
- # # Make a prediction
986
- # predictions = classifier.predict(input_fn=lambda: input_fn(input_df, labels=None, training=False))
987
-
988
- # # Get the predicted class and probability
989
- # for pred_dict in predictions:
990
- # class_id = pred_dict['class_ids'][0]
991
- # probability = pred_dict['probabilities'][class_id]
992
- # # Get the class name from the label encoder
993
- # class_name = le.inverse_transform([class_id])[0]
994
- # print('Order is "{}" ({:.1f}%)'.format(class_name, 100 * probability))
995
- # return class_name
996
- # except Exception as e:
997
- # print(f"An error occurred: {e}")
998
- # return None
999
-
1000
- # def ode2(A0, B0, C0, temp, Ea, A_factor, is_reversible, order):
1001
- # y0 = [A0, B0, C0]
1002
-
1003
- # k = compute_k(temp, Ea, A_factor)
1004
- # k_1 = k * 0.7
1005
-
1006
- # t_span = (0, 8)
1007
- # t_eval = np.linspace(0, 8, 11)
1008
-
1009
- # if order == 'zero':
1010
- # solution = solve_ivp(zero, t_span, y0, args=(k,) ,t_eval=t_eval)
1011
- # elif is_reversible == 0 and order == 'first':
1012
- # solution = solve_ivp(first, t_span, y0, args=(k,) ,t_eval=t_eval)
1013
- # elif is_reversible == 1 and order == 'first':
1014
- # solution = solve_ivp(reversible_first, t_span, y0, args=(k, k_1) ,t_eval=t_eval)
1015
- # elif is_reversible == 0 and order == 'second':
1016
- # solution = solve_ivp(second1, t_span, y0, args=(k,) ,t_eval=t_eval)
1017
- # elif is_reversible == 1 and order == 'second':
1018
- # solution = solve_ivp(reversible_second1, t_span, y0, args=(k, k_1) ,t_eval=t_eval)
1019
- # elif is_reversible == 0 and order == 'third':
1020
- # solution = solve_ivp(third2, t_span, y0, args=(k,) ,t_eval=t_eval)
1021
- # elif is_reversible == 1 and order == 'third':
1022
- # solution = solve_ivp(reversible_third2, t_span, y0, args=(k, k_1) ,t_eval=t_eval)
1023
-
1024
- # return solution.t, solution.y[0], solution.y[1], solution.y[2], k, k_1
1025
-
1026
-
1027
-
1028
- # import streamlit as st
1029
- # import pandas as pd
1030
- # import numpy as np
1031
- # import matplotlib.pyplot as plt
1032
-
1033
- # # Assuming the functions compute_k, ode1, ode2, predict_order, and the classifier, scaler, and le objects are already defined and available in the notebook's global scope from previous cells.
1034
-
1035
- # st.set_page_config(layout="wide", page_title="Chemical Reaction Simulator") # Set page layout to wide and add a page title
1036
-
1037
- # st.title("🧪 Project E-11")
1038
- # st.markdown("🧪 Chemical Reaction Order Prediction and Simulation ✨")
1039
- # st.markdown("Adjust the parameters below to predict the reaction order and visualize the concentration changes over time. 👇")
1040
-
1041
- # # Use columns for a better layout of inputs
1042
- # col1, col2 = st.columns(2)
1043
-
1044
- # with col1:
1045
- # st.header("⚙️ Reaction Conditions")
1046
- # temp = st.slider("Temperature (K) 🌡️", 270.0, 280.0, value=277.0)
1047
- # Ea = st.slider("Activation Energy (Ea, kJ/mol) 🔥", 90.0, 100.0, value=93.0)
1048
- # A_factor = st.slider("Pre-exponential Factor (A_factor) 📈", 2e16, 5e17, value=4.2e17, format="%e") # Use scientific notation format
1049
- # pH = st.slider("pH 🧪", 1.0, 14.0, value=6.5)
1050
- # pressure = st.slider("Pressure 🌫️", 0.5, 5.0, value=3.0)
1051
- # is_reversible = st.checkbox("Is Reversible? 🔄", value=False)
1052
- # structure = st.selectbox("Structure ⚛️", ['Linear', 'Ring', 'Branched', 'Unknown'], index=1)
1053
- # catalyst = st.selectbox("Catalyst ✨", ['None', 'Enzyme', 'Acid', 'Base'], index=2)
1054
-
1055
- # with col2:
1056
- # st.header("📈 Initial Concentrations")
1057
- # A0 = st.slider("Initial Concentration of A (A₀)", 0.0, 10.0, value=5.0)
1058
- # B0 = st.slider("Initial Concentration of B (B₀)", 0.0, 10.0, value=2.0)
1059
- # C0 = st.slider("Initial Concentration of C (C₀)", 0.0, 10.0, value=1.0)
1060
-
1061
- # st.markdown("---") # Add a horizontal rule for separation
1062
-
1063
- # if st.button("🚀 Predict and Plot Reaction"):
1064
- # # Data Preparation for Prediction
1065
- # # Simulate the reaction using ode1 to get concentrations over time for prediction features
1066
- # time_pred, A_pred, B_pred, C_pred, k_pred, k_1_pred, is_reversible_simulated, order_simulated = ode1(A0, B0, C0, temp, Ea, A_factor)
1067
-
1068
- # # Create a dictionary with all the necessary inputs for the model
1069
- # inputs = {
1070
- # 'temp': temp,
1071
- # 'pH': pH,
1072
- # 'Ea': Ea,
1073
- # 'A_factor': A_factor,
1074
- # 'pressure': pressure,
1075
- # 'log_pressure': np.log(pressure),
1076
- # 'weight': 150, # Using a placeholder value as it's not a user input
1077
- # 'structure': structure,
1078
- # 'catalyst': catalyst,
1079
- # 'is_reversible': int(is_reversible),
1080
- # 'k': k_pred, # Use simulated k
1081
- # 'k_1': k_1_pred, # Use simulated k_1
1082
- # 'A0': A_pred[0], 'A1': A_pred[1], 'A2': A_pred[2], 'A3': A_pred[3], 'A4': A_pred[4],
1083
- # 'A5': A_pred[5], 'A6': A_pred[6], 'A7': A_pred[7], 'A8': A_pred[8], 'A9': A_pred[9], 'A10': A_pred[10],
1084
- # 'B0': B_pred[0], 'B1': B_pred[1], 'B2': B_pred[2], 'B3': B_pred[3], 'B4': B_pred[4],
1085
- # 'B5': B_pred[5], 'B6': B_pred[6], 'B7': B_pred[7], 'B8': B_pred[8], 'B9': B_pred[9], 'B10': B_pred[10],
1086
- # 'C0': C_pred[0], 'C1': C_pred[1], 'C2': C_pred[2], 'C3': C_pred[3], 'C4': C_pred[4],
1087
- # 'C5': C_pred[5], 'C6': C_pred[6], 'C7': C_pred[7], 'C8': C_pred[8], 'C9': C_pred[9], 'C10': C_pred[10]
1088
- # }
1089
-
1090
- # # --- 2. Prediction ---
1091
- # with st.spinner('Predicting reaction order...'):
1092
- # predicted_order = predict_order(inputs)
1093
- # st.success(f"✅ Predicted Order: **{predicted_order}**")
1094
-
1095
- # # --- 3. Simulation with ode2 and Predicted Order ---
1096
- # with st.spinner('Simulating reaction...'):
1097
- # time_sim, A_sim, B_sim, C_sim, k_sim, k_1_sim = ode2(A0, B0, C0, temp, Ea, A_factor, int(is_reversible), predicted_order)
1098
-
1099
- # # --- 4. Plotting ---
1100
- # st.header("📊 Concentration vs. Time Plot")
1101
- # fig, ax = plt.subplots()
1102
- # ax.plot(time_sim, A_sim, label='A', marker='o') # Add markers to plot points
1103
- # ax.plot(time_sim, B_sim, label='B', marker='x')
1104
- # ax.plot(time_sim, C_sim, label='C', marker='s')
1105
- # ax.set_xlabel('Time')
1106
- # ax.set_ylabel('Concentration')
1107
- # ax.set_title(f'Concentration vs. Time (Predicted Order: {predicted_order})')
1108
- # ax.legend()
1109
- # ax.grid(True)
1110
-
1111
- # st.pyplot(fig)
1112
-
1113
- # st.markdown("---")
1114
- # st.markdown("App created with ❤️ by Mujtaba , Muzammil , Taha and Ali Zain.")
1115
-
1116
  # !streamlit run /content/app.py &>/content/logs.txt & #this starts the loca server
1117
 
 
 
1118
  # !npx localtunnel --port 8501 #the tunnel
1119
 
1120
- # get_ipython().run_line_magic('shell', 'curl https://loca.lt/mytunnelpassword') #getting ur home ip adress :cold:
1121
 
1122
- # %%writefile requirements.txt
1123
- # gradio
1124
- # pandas
1125
- # numpy
1126
- # matplotlib
1127
- # scipy
1128
- # tensorflow==2.15
1129
- # scikit-learn
 
4
  Automatically generated by Colab.
5
 
6
  Original file is located at
7
+ https://colab.research.google.com/drive/1rpq0orE7c2E_K8SsmIeH6gxNjw8ucycA
8
+
9
+ # Chem simulation using scipy
10
  """
11
 
12
  # !pip install tensorflow==2.15
13
 
 
 
14
  import numpy as np
15
  import matplotlib.pyplot as plt
16
  import pandas as pd
 
144
  k = compute_k(temp, Ea, A_factor)
145
  k_1 = k * random.uniform(0.5, 0.9)
146
 
147
+ t_span = (0, 8)
148
+ t_eval = np.linspace(0, 8, 11)
149
 
150
+ num = random.randint(0, 11) # For choosing between different functions randomly
151
 
152
  match num:
153
  case 0:
 
225
  results = []
226
 
227
  counter = 0
228
+ while counter < 15000:
229
+ counter += 1
230
+
231
+ A0 = round(random.uniform(1.0, 10.0), 2)
232
+ B0 = round(random.uniform(0.0, 5.0), 2)
233
+ C0 = round(random.uniform(0.0, 5.0), 2)
234
+ temp = random.randint(270, 280)
235
+ pH = round(random.uniform(1.0, 14.0), 2)
236
+ Ea = random.randint(90, 100)
237
+ A_factor = round(random.uniform(2e16, 5e17), 2)
238
+ pressure = round(random.uniform(0.5, 5.0), 2)
239
+ weight = round(random.uniform(20, 200), 1)
240
+ structure = random.choice(['Linear', 'Ring', 'Branched', 'Unknown'])
241
+ catalyst = random.choice(['None', 'Enzyme', 'Acid', 'Base'])
242
+ time, A, B, C, k, k_1, is_reversible, order = ode1(A0, B0, C0, temp, Ea, A_factor)
243
+
244
+ row = {
245
+ 'order' : order,
246
+ 'temp': temp,
247
+ 'pH': pH,
248
+ 'Ea': Ea,
249
+ 'A_factor': A_factor,
250
+ 'pressure': pressure,
251
+ 'log_pressure' : np.log(pressure),
252
+ 'weight': weight,
253
+ 'structure': structure,
254
+ 'catalyst': catalyst,
255
+ 'is_reversible': is_reversible,
256
+ 'k' : k,
257
+ 'k_1' : k_1,
258
+ 'A0': A[0], 'A1': A[1], 'A2': A[2], 'A3': A[3], 'A4': A[4],
259
+ 'A5': A[5], 'A6': A[6], 'A7': A[7], 'A8': A[8], 'A9': A[9], 'A10': A[10],
260
+ 'B0': B[0], 'B1': B[1], 'B2': B[2], 'B3': B[3], 'B4': B[4],
261
+ 'B5': B[5], 'B6': B[6], 'B7': B[7], 'B8': B[8], 'B9': B[9], 'B10': B[10],
262
+ 'C0': C[0], 'C1': C[1], 'C2': C[2], 'C3': C[3], 'C4': C[4],
263
+ 'C5': C[5], 'C6': C[6], 'C7': C[7], 'C8': C[8], 'C9': C[9], 'C10': C[10]
264
+ }
265
+ results.append(row)
266
+
267
+ df_train = pd.DataFrame(results)
268
+
269
+ df_train.to_csv('chem_data_train.csv',index=False)
270
+ df_train
271
+
272
+ results = []
273
+
274
+ counter = 0
275
+ while counter < 5000:
276
  counter += 1
277
 
278
  A0 = round(random.uniform(1.0, 10.0), 2)
 
311
  }
312
  results.append(row)
313
 
314
+ df_test = pd.DataFrame(results)
315
+
316
+ df_test.to_csv('chem_data_test.csv',index=False)
317
+ df_test
318
+
319
+ """- To concatenate df_test and df_train into df"""
320
+
321
+ df = pd.concat([df_test, df_train])
322
+
323
+ df
324
 
325
  """# Machine learning
326
 
 
337
  df['structure'] = df['structure'].map(structure_map)
338
  df['catalyst'] = df['catalyst'].map(catalyst_map)
339
  df['order'] = df['order'].map(order_map)
340
+ df
341
 
342
+ """- creating x and y datasets for train and test"""
343
 
344
+ X = df.drop(['order'], axis=1)
345
+ y = df['order']
346
 
347
+ from sklearn.model_selection import train_test_split
348
+
349
+ X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
350
+
351
+ """- scaling dataset"""
352
+
353
+ from sklearn.preprocessing import StandardScaler
354
+
355
+ scaler = StandardScaler()
356
+ X_train_scaled = scaler.fit_transform(X_train)
357
+ X_test_scaled = scaler.transform(X_test)
358
+
359
+ """## Models"""
360
+
361
+ from sklearn.metrics import accuracy_score
362
+
363
+ """### Logistic Regression"""
364
+
365
+ from sklearn.linear_model import LogisticRegression
366
+
367
+ lr = LogisticRegression(max_iter=1000, C=10, penalty='l2')
368
+ lr.fit(X_train_scaled, y_train)
369
+ lr_pred = lr.predict(X_test_scaled)
370
+
371
+ print("Logistic Regression Accuracy:", accuracy_score(y_test, lr_pred))
372
 
373
+ """### RandomForestClassifier"""
 
374
 
375
+ from sklearn.ensemble import RandomForestClassifier
 
376
 
377
+ rf = RandomForestClassifier(class_weight='balanced', random_state=42, n_estimators=200, max_depth=None)
378
+ rf.fit(X_train, y_train)
379
+ rf_pred = rf.predict(X_test)
380
 
381
+ print("RandomForestClassifier Accuracy:", accuracy_score(y_test, rf_pred))
382
+
383
+ """### Gradient Boosting Classifier"""
384
+
385
+ from sklearn.ensemble import GradientBoostingClassifier
386
+
387
+ gb = GradientBoostingClassifier(n_estimators=200, max_depth=5, random_state=42)
388
+ gb.fit(X_train, y_train)
389
+ gb_pred = gb.predict(X_test)
390
+
391
+ print("Gradient Boosting Accuracy:", accuracy_score(y_test, gb_pred))
392
+
393
+ """### Support Vector Classifier"""
394
+
395
+ from sklearn.svm import SVC
396
+
397
+ svc = SVC(C=10, kernel='rbf', class_weight='balanced')
398
+ svc.fit(X_train_scaled, y_train)
399
+ svc_pred = svc.predict(X_test_scaled)
400
+
401
+ print("SVC Accuracy:", accuracy_score(y_test, svc_pred))
402
+
403
+ """### K-Nearest Neighbors"""
404
+
405
+ from sklearn.neighbors import KNeighborsClassifier
406
+
407
+ knn = KNeighborsClassifier(n_neighbors=7, weights='uniform')
408
+ knn.fit(X_train_scaled, y_train)
409
+ knn_pred = knn.predict(X_test_scaled)
410
+
411
+ print("KNN Accuracy:", accuracy_score(y_test, knn_pred))
412
+
413
+ """### XG Boost"""
414
+
415
+ from xgboost import XGBClassifier
416
+
417
+ xgb_model = XGBClassifier(learning_rate=0.1, max_depth=7, n_estimators=200, eval_metric='mlogloss', random_state=42)
418
+ xgb_model.fit(X_train, y_train)
419
+ xgb_pred = xgb_model.predict(X_test)
420
+
421
+ print("XGBoost Accuracy:", accuracy_score(y_test, xgb_pred))
422
+
423
+ """### Hyperparameter tuning"""
424
+
425
+ from sklearn.linear_model import LogisticRegression
426
+ from sklearn.svm import SVC
427
+ from sklearn.neighbors import KNeighborsClassifier
428
+ from sklearn.ensemble import RandomForestClassifier, GradientBoostingClassifier
429
+ import xgboost as xgb
430
+
431
+ models = {
432
+ 'LogisticRegression': LogisticRegression(class_weight='balanced', max_iter=1000),
433
+ 'SVC': SVC(class_weight='balanced'),
434
+ 'KNN': KNeighborsClassifier(),
435
+ 'RandomForest': RandomForestClassifier(class_weight='balanced', random_state=42),
436
+ 'GradientBoosting': GradientBoostingClassifier(random_state=42),
437
+ 'XGBoost': xgb.XGBClassifier(eval_metric='mlogloss', random_state=42)
438
+ }
439
+
440
+
441
+ param_grids = {
442
+ 'LogisticRegression': {
443
+ 'C': [0.1, 1, 10],
444
+ 'penalty': ['l2']
445
+ },
446
+ 'SVC': {
447
+ 'C': [0.1, 1, 10],
448
+ 'kernel': ['linear', 'rbf']
449
+ },
450
+ 'KNN': {
451
+ 'n_neighbors': [3, 5, 7],
452
+ 'weights': ['uniform', 'distance']
453
+ },
454
+ 'RandomForest': {
455
+ 'n_estimators': [100, 200],
456
+ 'max_depth': [5, 10, None]
457
+ },
458
+ 'GradientBoosting': {
459
+ 'n_estimators': [100, 200],
460
+ 'max_depth': [3, 5, 7]
461
+ },
462
+ 'XGBoost': {
463
+ 'n_estimators': [100, 200],
464
+ 'max_depth': [3, 5, 7],
465
+ 'learning_rate': [0.05, 0.1]
466
+ }
467
+ }
468
+
469
+ from sklearn.model_selection import GridSearchCV
470
+
471
+ best_models = {}
472
+
473
+ for name, model in models.items():
474
+ print(f"Running GridSearch for {name}...")
475
+ grid = GridSearchCV(model, param_grids[name], cv=5, scoring='accuracy')
476
+
477
+ if name in ['LogisticRegression', 'SVC', 'KNN']:
478
+ grid.fit(X_train_scaled, y_train)
479
+ else:
480
+ grid.fit(X_train, y_train)
481
+
482
+ best_models[name] = grid.best_estimator_
483
+ print(f"Best params for {name}:", grid.best_params_)
484
+ print("Best CV Score:", grid.best_score_)
485
+ print("=====================================")
486
+
487
+ """### BEST PARAMS
488
+ ==========================================================================
489
+ - LogisticRegression
490
+ ==========================================================================
491
+ Best params for LogisticRegression: {'C': 10, 'penalty': 'l2'}
492
+ Best CV Score: 0.8008333333333335
493
+ ==========================================================================
494
+ - SVC
495
+ ==========================================================================
496
+ Best params for SVC: {'C': 10, 'kernel': 'rbf'}
497
+ Best CV Score: 0.8791666666666668
498
+ ==========================================================================
499
+ - KNN
500
+ ==========================================================================
501
+ Best params for KNN: {'n_neighbors': 7, 'weights': 'uniform'}
502
+ Best CV Score: 0.5670833333333334
503
+ ==========================================================================
504
+ - RandomForest
505
+ ==========================================================================
506
+ Best params for RandomForest: {'max_depth': None, 'n_estimators': 200}
507
+ Best CV Score: 0.8362499999999999
508
+ ==========================================================================
509
+ - GradientBoosting
510
+ ==========================================================================
511
+ Best params for GradientBoosting: {'max_depth': 5, 'n_estimators': 200}
512
+ Best CV Score: 0.8945833333333333
513
+ ==========================================================================
514
+ - XGBOOST
515
+ ==========================================================================
516
+ Best params for XGBOOST: {'learning_rate': 0.1, 'max_depth': 7, 'n_estimators': 200}
517
+ Best CV Score: 0.8950000000000001
518
+ ==========================================================================
519
+
520
+ ## DNN
521
+ """
522
 
523
  csv_columns = ['temp', 'pH', 'Ea', 'A_factor', 'pressure', 'log_pressure', 'weight', 'structure', 'catalyst', 'is_reversible', 'k', 'k_1']
524
  classes = ['First_Order','Second_Order','Third_Order']
 
529
  train = pd.read_csv(train_path)
530
  test = pd.read_csv(test_path)
531
 
532
+ train.head()
533
+
534
+ """- Fill missing values in the 'catalyst' column
535
+ - NaN values arenot accepted by classifier thats why convert every Nan values to none
536
+ - the species column is now gone
537
+ """
538
 
539
  if 'order' in train.columns:
540
  train_y = train.pop('order')
541
  if 'order' in test.columns:
542
  test_y = test.pop('order')
543
 
544
+
545
+ train['catalyst'] = train['catalyst'].fillna('None')
546
  test['catalyst'] = test['catalyst'].fillna('None')
547
 
548
 
549
+ train.head()
550
+
551
+ """- Define categorical and numerical feature columns
552
+ - Assining each string a numerical uinque value because our dumb ahh model canot understand english
553
+ """
554
 
 
555
  CATEGORICAL_COLUMNS = ['structure', 'catalyst'] #columns that have strings
556
  NUMERIC_COLUMNS = ['temp', 'pH', 'Ea', 'A_factor', 'pressure', 'log_pressure', 'weight',
557
  'is_reversible', 'k', 'k_1', 'A0', 'A1', 'A2', 'A3', 'A4', 'A5', 'A6', 'A7', 'A8', 'A9', 'A10',
 
560
 
561
  feature_columns = []
562
  for feature_name in CATEGORICAL_COLUMNS:
563
+ vocabulary = train[feature_name].unique()
564
  cat_column = tf.feature_column.categorical_column_with_vocabulary_list(feature_name, vocabulary)
565
  indicator_column = tf.feature_column.indicator_column(cat_column) #it creates binary coolumns that will be mapped in to feature columns and it will be steamlined to our DNN model
566
  feature_columns.append(indicator_column)
 
573
  import logging
574
  tf.get_logger().setLevel(logging.INFO)
575
 
576
+ """- setting up input function
577
+ - convert the inputs to a dataset
578
+ """
579
 
580
  def input_fn(features,labels,training=True,batch_size=500):
 
581
  dataset = tf.data.Dataset.from_tensor_slices((dict(features), labels)) #this cnonverts the dataset into tensorflow object
582
 
583
  if training:
584
+ dataset = dataset.shuffle(3000).repeat()
585
 
586
  return dataset.batch(batch_size)
587
 
588
+ """- Normalize the numerical features in the training data"""
589
+
590
  from sklearn.preprocessing import StandardScaler
591
 
 
592
  scaler = StandardScaler()
593
  train_normalized = train.copy()
594
  train_normalized[NUMERIC_COLUMNS] = scaler.fit_transform(train[NUMERIC_COLUMNS])
 
596
  test_normalized = test.copy()
597
  test_normalized[NUMERIC_COLUMNS] = scaler.transform(test[NUMERIC_COLUMNS])
598
 
599
+ """- Convert the 'order' labels to numerical values"""
600
+
601
  from sklearn.preprocessing import LabelEncoder
602
 
 
603
  le = LabelEncoder()
604
  train_y_encoded = le.fit_transform(train_y) #we used sckit label encoder to encode the values
605
 
 
611
 
612
  classifier.train(
613
  input_fn=lambda: input_fn(train_normalized, train_y_encoded, training=True),
614
+ steps=1000
615
  )
616
 
617
+ test_y_encoded = le.fit_transform(test_y) #we used sckit label encoder to encode the values better than 1 2 3 4 5
618
 
619
  classifier.evaluate(input_fn=lambda: input_fn(test_normalized,test_y_encoded,training=False))
620
 
621
  """- accuracy = 0.99983335
622
 
623
+ ## Interactive
 
 
 
624
  """
625
 
626
+ def predict_order(inputs):
627
+
628
+ try:
629
+ # Create a pandas DataFrame from the input dictionary
630
+ input_df = pd.DataFrame(inputs, index=[0])
631
+
632
+ # Normalize the numerical features
633
+ input_df[NUMERIC_COLUMNS] = scaler.transform(input_df[NUMERIC_COLUMNS])
634
+
635
+ # Make a prediction
636
+ predictions = classifier.predict(input_fn=lambda: input_fn(input_df, labels=None, training=False))
637
+
638
+ # Get the predicted class and probability
639
+ for pred_dict in predictions:
640
+ class_id = pred_dict['class_ids'][0]
641
+ probability = pred_dict['probabilities'][class_id]
642
+ # Get the class name from the label encoder
643
+ class_name = le.inverse_transform([class_id])[0]
644
+ print('Order is "{}" ({:.1f}%)'.format(class_name, 100 * probability))
645
+ return class_name
646
+ except Exception as e:
647
+ print(f"An error occurred: {e}")
648
+ return None
649
+
650
+ #example input data
651
+
652
+ example_inputs = {
653
+ 'temp': 277,
654
+ 'pH': 6.5,
655
+ 'Ea': 93,
656
+ 'A_factor': 4.2e17,
657
+ 'pressure': 3.0,
658
+ 'log_pressure': 1.1,
659
+ 'weight': 150,
660
+ 'structure': 'Ring',
661
+ 'catalyst': 'Acid',
662
+ 'is_reversible': 1,
663
+ 'k': 0.05,
664
+ 'k_1': 0.02,
665
+ 'A0': 5.0,
666
+ 'A1': 4.5,
667
+ 'A2': 4.0,
668
+ 'A3': 3.5,
669
+ 'A4': 3.0,
670
+ 'A5': 2.5,
671
+ 'A6': 2.0,
672
+ 'A7': 1.5,
673
+ 'A8': 1.0,
674
+ 'A9': 0.5,
675
+ 'A10': 0.0,
676
+ 'B0': 2.0,
677
+ 'B1': 1.8,
678
+ 'B2': 1.6,
679
+ 'B3': 1.4,
680
+ 'B4': 1.2,
681
+ 'B5': 1.0,
682
+ 'B6': 0.8,
683
+ 'B7': 0.6,
684
+ 'B8': 0.4,
685
+ 'B9': 0.2,
686
+ 'B10': 0.0,
687
+ 'C0': 1.0,
688
+ 'C1': 1.2,
689
+ 'C2': 1.4,
690
+ 'C3': 1.6,
691
+ 'C4': 1.8,
692
+ 'C5': 2.0,
693
+ 'C6': 2.2,
694
+ 'C7': 2.4,
695
+ 'C8': 2.6,
696
+ 'C9': 2.8,
697
+ 'C10': 3.0
698
+ }
699
+
700
+ predict_order(example_inputs)
701
+
702
+ """- ode2"""
703
+
704
+ def ode2(A0, B0, C0, temp, Ea, A_factor, is_reversible, predicted_order):
705
+ y0 = [A0, B0, C0]
706
+ k = compute_k(temp, Ea, A_factor)
707
+ k_1 = k * random.uniform(0.5, 0.9) # Assuming k_1 is related to k, similar to ode1
708
+
709
+ t_span = (0, 8)
710
+ t_eval = np.linspace(0, 8, 11)
711
+
712
+ func_name = None
713
+ if predicted_order == 'zero':
714
+ func_name = zero
715
+ elif predicted_order == 'first':
716
+ if is_reversible:
717
+ func_name = reversible_first
718
+ else:
719
+ # Assuming decay_first is not used for plotting based on predicted order
720
+ func_name = first
721
+ elif predicted_order == 'second':
722
+ if is_reversible:
723
+ # Assuming reversible_second1 or reversible_second2 based on A and B concentrations
724
+ # For simplicity, let's use reversible_second1 if B0 > 0, otherwise reversible_second2
725
+ if B0 > 0:
726
+ func_name = reversible_second1
727
+ else:
728
+ func_name = reversible_second2
729
+ else:
730
+ # Assuming second1 or second2 based on A and B concentrations
731
+ # For simplicity, let's use second1 if B0 > 0, otherwise second2
732
+ if B0 > 0:
733
+ func_name = second1
734
+ else:
735
+ func_name = second2
736
+ elif predicted_order == 'third':
737
+ if is_reversible:
738
+ # Assuming reversible_third1 or reversible_third2 based on A and B concentrations
739
+ # For simplicity, let's use reversible_third2 if B0 > 0, otherwise reversible_third1
740
+ if B0 > 0:
741
+ func_name = reversible_third2
742
+ else:
743
+ func_name = reversible_third1
744
+ else:
745
+ # Assuming third1 or third2 based on A and B concentrations
746
+ # For simplicity, let's use third2 if B0 > 0, otherwise third1
747
+ if B0 > 0:
748
+ func_name = third2
749
+ else:
750
+ func_name = third1
751
+
752
+
753
+ if func_name is None:
754
+ raise ValueError(f"Could not determine ODE function for predicted order: {predicted_order}")
755
+
756
+ if is_reversible and predicted_order != 'zero': # Add condition to exclude zero order
757
+ solution = solve_ivp(
758
+ func_name,
759
+ t_span,
760
+ y0,
761
+ args=(k, k_1),
762
+ t_eval=t_eval
763
+ )
764
+ else: # Handle zero order separately, regardless of is_reversible
765
+ solution = solve_ivp(
766
+ func_name,
767
+ t_span,
768
+ y0,
769
+ args=(k,),
770
+ t_eval=t_eval
771
+ )
772
+
773
+ return solution.t, solution.y[0], solution.y[1], solution.y[2], k, k_1
774
+
775
+ """### Gradio"""
776
 
 
 
777
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
778
 
779
  import gradio as gr
780
  import pandas as pd
781
  import numpy as np
782
  import matplotlib.pyplot as plt
783
+ from scipy.integrate import solve_ivp
784
+ import random
785
+ import tensorflow as tf
786
+ from sklearn.preprocessing import StandardScaler, LabelEncoder
787
+
788
+ # Assuming all the necessary functions (compute_k, ode2, predict_order, etc.) and models are defined and trained in the previous cells.
789
+
790
+ def run_simulation_and_plot(temp, Ea, A_factor_base, A_factor_exponent, A_factor_std_perc, pH, pressure, is_reversible, structure, catalyst, A0, B0, C0):
791
+ # --- 1. Data Preparation for Prediction ---
792
+ # Reconstruct A_factor from user-friendly inputs
793
+ A_factor = A_factor_base * (10**A_factor_exponent)
794
+ A_factor_std = A_factor * (A_factor_std_perc / 100)
795
+
796
+ # Add randomness to A_factor using standard deviation
797
+ A_factor_randomized = np.random.normal(A_factor, A_factor_std)
798
+
799
+ k = compute_k(temp, Ea, A_factor_randomized)
800
+ k_1 = k * 0.7 # Using a fixed ratio for k_1 for consistency
801
+
802
+ # Simulate reaction to get concentration data for prediction
803
+ time_sim, A_sim, B_sim, C_sim, _, _ = ode2(A0, B0, C0, temp, Ea, A_factor_randomized, int(is_reversible), "zero")
804
+
805
+ inputs = {
806
+ 'temp': temp, 'pH': pH, 'Ea': Ea, 'A_factor': A_factor_randomized,
807
+ 'pressure': pressure, 'log_pressure': np.log(pressure), 'weight': 150,
808
+ 'structure': structure, 'catalyst': catalyst, 'is_reversible': int(is_reversible),
809
+ 'k': k, 'k_1': k_1,
810
+ 'A0': A_sim[0], 'A1': A_sim[1], 'A2': A_sim[2], 'A3': A_sim[3], 'A4': A_sim[4],
811
+ 'A5': A_sim[5], 'A6': A_sim[6], 'A7': A_sim[7], 'A8': A_sim[8], 'A9': A_sim[9], 'A10': A_sim[10],
812
+ 'B0': B_sim[0], 'B1': B_sim[1], 'B2': B_sim[2], 'B3': B_sim[3], 'B4': B_sim[4],
813
+ 'B5': B_sim[5], 'B6': B_sim[6], 'B7': B_sim[7], 'B8': B_sim[8], 'B9': B_sim[9], 'B10': B_sim[10],
814
+ 'C0': C_sim[0], 'C1': C_sim[1], 'C2': C_sim[2], 'C3': C_sim[3], 'C4': C_sim[4],
815
+ 'C5': C_sim[5], 'C6': C_sim[6], 'C7': C_sim[7], 'C8': C_sim[8], 'C9': C_sim[9], 'C10': C_sim[10],
816
+ }
817
 
818
  # --- 2. Prediction ---
819
+ predicted_order = predict_order(inputs)
 
 
 
 
820
 
821
+ # --- 3. Final Simulation with Predicted Order ---
822
+ time_final, A_final, B_final, C_final, _, _ = ode2(A0, B0, C0, temp, Ea, A_factor_randomized, int(is_reversible), predicted_order)
823
 
824
  # --- 4. Plotting ---
825
+ plt.style.use('seaborn-v0_8-whitegrid')
826
+ fig, ax = plt.subplots(figsize=(10, 6))
827
+ ax.plot(time_final, A_final, 'o-', label='[A]', color='royalblue', markersize=5)
828
+ ax.plot(time_final, B_final, 's--', label='[B]', color='forestgreen', markersize=5)
829
+ ax.plot(time_final, C_final, '^-.', label='[C]', color='darkorange', markersize=5)
 
 
 
 
830
 
831
+ ax.set_xlabel('Time (s)', fontsize=12)
832
+ ax.set_ylabel('Concentration (M)', fontsize=12)
833
+ ax.set_title(f'🧪 Concentration vs. Time (Predicted Order: {predicted_order})', fontsize=14)
834
+ ax.legend(loc='best', fontsize=10)
835
+ ax.grid(True, which='both', linestyle='--', linewidth=0.5)
836
 
837
+ # Add watermark
838
+ fig.text(0.99, 0.01, 'pinl',
839
+ fontsize=12, color='gray',
840
+ ha='right', va='bottom', alpha=0.5)
841
+
842
+ return f"Predicted Order: {predicted_order}", fig
843
 
844
  # --- 5. Gradio Interface ---
845
+ with gr.Blocks(theme=gr.themes.Soft()) as iface:
846
+ gr.Markdown("# Project E-11: 🧪 Chemical Reaction Simulator", elem_id="title" "made by Team PinlAI")
847
+ gr.Markdown("An interactive tool to predict reaction orders and visualize concentration changes over time.", elem_id="subtitle")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
848
 
849
  with gr.Row():
850
+ with gr.Column(scale=1):
851
+ gr.Markdown("### ⚙️ Reaction Parameters")
852
+ temp = gr.Slider(270, 280, value=277, label="🌡️ Temperature (K)")
853
+ Ea = gr.Slider(90, 100, value=93, label="⚡ Activation Energy (kJ/mol)")
854
+ A_factor_base = gr.Slider(1, 9, value=4, label="🅰️ Pre-exponential Factor (Base)")
855
+ A_factor_exponent = gr.Slider(16, 18, value=17, step=1, label="🅰️ Pre-exponential Factor (Exponent)")
856
+ A_factor_std_perc = gr.Slider(0, 50, value=10, label="📈 A Factor Std Dev (%)")
857
+ pH = gr.Slider(1.0, 14.0, value=6.5, label="💧 pH")
858
+ pressure = gr.Slider(0.5, 5.0, value=3.0, label="💨 Pressure (atm)")
859
+ is_reversible = gr.Checkbox(label="🔄 Reversible Reaction")
860
+ structure = gr.Dropdown(['Linear', 'Ring', 'Branched', 'Unknown'], label="🧬 Molecular Structure")
861
+ catalyst = gr.Dropdown(['None', 'Enzyme', 'Acid', 'Base'], label="🔬 Catalyst")
862
+
863
+ with gr.Column(scale=1):
864
+ gr.Markdown("### ⚛️ Initial Concentrations")
865
+ A0 = gr.Slider(0.0, 10.0, value=5.0, label="[A]₀")
866
+ B0 = gr.Slider(0.0, 10.0, value=2.0, label="[B]₀")
867
+ C0 = gr.Slider(0.0, 10.0, value=1.0, label="[C]₀")
868
+
869
+ with gr.Row():
870
+ predict_button = gr.Button("🚀 Predict & Plot", variant="primary")
871
+
872
  with gr.Row():
873
+ with gr.Column(scale=2):
874
+ order_output = gr.Textbox(label="📊 Predicted Reaction Order")
875
+ plot_output = gr.Plot(label="📈 Concentration vs. Time")
 
876
 
877
  predict_button.click(
878
  fn=run_simulation_and_plot,
879
+ inputs=[temp, Ea, A_factor_base, A_factor_exponent, A_factor_std_perc, pH, pressure, is_reversible, structure, catalyst, A0, B0, C0],
880
  outputs=[order_output, plot_output]
881
  )
882
 
 
883
  iface.launch(debug=True)
884
 
885
+ """### Streamlit"""
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
886
 
887
  # !npm install -g localtunnel
888
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
889
  # !streamlit run /content/app.py &>/content/logs.txt & #this starts the loca server
890
 
891
+ # get_ipython().run_line_magic('shell', 'curl https://loca.lt/mytunnelpassword') #getting ur home pass 🥶
892
+
893
  # !npx localtunnel --port 8501 #the tunnel
894
 
 
895
 
896
+