ProjectE-11 / app.py
MuzammilMax's picture
Update app.py
f24b37c verified
Raw
History Blame
38.1 kB
# -*- coding: utf-8 -*-
"""chem-sim.ipynb
Automatically generated by Colab.
Original file is located at
https://colab.research.google.com/drive/1GgGC-fVnA0fSxU859NjSi_jH8yiWUKOu
"""
# !pip install tensorflow==2.15
"""# Chem simulation using scipy"""
import numpy as np
import matplotlib.pyplot as plt
import pandas as pd
from scipy.integrate import solve_ivp
import random
import tensorflow as tf
"""# Dataset
$$
\displaystyle
k = A \cdot e^{-\frac{E_a}{RT}}
$$
k : Rate constant (what we’re solving for)
A : Pre-exponential factor (frequency factor)
Ea : Activation energy (J/mol)
R : Gas constant 8.314 J/molΒ·K
T : Temperature (in Kelvin)
| temp: Kelvin | pH: 0–14 scale | Ea: in kJ/mol | A_factor: 1/s |
## Zero order
"""
def zero(t, y, k):
A, B, C = y
dA_dt = -k
dB_dt = 0
dC_dt = k
return [dA_dt, dB_dt, dC_dt]
"""## First Order"""
def first(t, y, k):
A, B, C = y
dA_dt = -k * A
dB_dt = 0
dC_dt = +k * A
return [dA_dt, dB_dt, dC_dt]
def decay_first(t, y, k):
A, B, C = y
dA_dt = -k * A
dB_dt = 0
dC_dt = 0
return [dA_dt, dB_dt, dC_dt]
def reversible_first(t, y, k, k_1):
A, B, C = y
dA_dt = -k * A + k_1 * C
dB_dt = 0
dC_dt = k * A - k_1 * C
return [dA_dt, dB_dt, dC_dt]
"""## Second Order"""
def second1(t, y, k):
A, B, C = y
dA_dt = -k * A * B
dB_dt = -k * A * B
dC_dt = +k * A * B
return [dA_dt, dB_dt, dC_dt]
def second2(t, y, k):
A, B, C = y
dA_dt = -2 * k * A**2
dB_dt = 0
dC_dt = +k * A**2
return [dA_dt, dB_dt, dC_dt]
def reversible_second1(t, y, k, k_1):
A, B, C = y
dA_dt = -k * A * B + k_1 * C
dB_dt = -k * A * B + k_1 * C
dC_dt = +k * A * B - k_1 * C
return [dA_dt, dB_dt, dC_dt]
def reversible_second2(t, y, k, k_1):
A, B, C = y
dA_dt = -2 * k * A**2 + 2 * k_1 * C
dB_dt = 0
dC_dt = +k * A**2 - k_1 * C
return [dA_dt, dB_dt, dC_dt]
"""## Third order"""
def third1(t, y, k):
A, B, C = y
dA_dt = -3 * k * A**3
dB_dt = 0
dC_dt = +k * A**3
return [dA_dt, dB_dt, dC_dt]
def third2(t, y, k):
A, B, C = y
dA_dt = -2 * k * A**2 * B
dB_dt = -1 * k * A**2 * B
dC_dt = +k * A**2 * B
return [dA_dt, dB_dt, dC_dt]
def reversible_third1(t, y, k, k_1):
A, B, C = y
dA_dt = -3 * k * A**3 + 3 * k_1 * C
dB_dt = 0
dC_dt = +k * A**3 - k_1 * C
return [dA_dt, dB_dt, dC_dt]
def reversible_third2(t, y, k, k_1):
A, B, C = y
dA_dt = -2 * k * A**2 * B + 2 * k_1 * C
dB_dt = -1 * k * A**2 * B + 1 * k_1 * C
dC_dt = +k * A**2 * B - k_1 * C
return [dA_dt, dB_dt, dC_dt]
"""## functions"""
def compute_k(temp, Ea, A_factor):
R = 8.314
Ea_J = Ea * 1000 # Convert Ea from kJ/mol to J/mol
k = A_factor * np.exp(-Ea_J / (R * temp))
return k
def ode1(A0, B0, C0, temp, Ea, A_factor):
y0 = [A0, B0, C0]
k = compute_k(temp, Ea, A_factor)
k_1 = k * random.uniform(0.5, 0.9)
t_span = (0, 8) # From time 0 to 10 seconds
t_eval = np.linspace(0, 8, 11) # 11 points where you want the solution
num = random.randint(0, 11) # For choosing between first or decay if not reversible
match num:
case 0:
func_name = zero
is_reversible = 0
order = 'zero'
case 1:
func_name = first
is_reversible = 0
order = 'first'
case 2:
func_name = decay_first
is_reversible = 0
order = 'first'
case 3:
func_name = reversible_first
is_reversible = 1
order = 'first'
case 4:
func_name = second1
is_reversible = 0
order = 'second'
case 5:
func_name = second2
is_reversible = 0
order = 'second'
case 6:
func_name = reversible_second1
is_reversible = 1
order = 'second'
case 7:
func_name = reversible_second2
is_reversible = 1
order = 'second'
case 8:
func_name = third1
is_reversible = 0
order = 'third'
case 9:
func_name = third2
is_reversible = 0
order = 'third'
case 10:
func_name = reversible_third1
is_reversible = 1
order = 'third'
case 11:
func_name = reversible_third2
is_reversible = 1
order = 'third'
if is_reversible == 1:
solution = solve_ivp(
func_name,
t_span,
y0,
args=(k, k_1),
t_eval=t_eval
)
elif is_reversible == 0:
solution = solve_ivp(
func_name,
t_span,
y0,
args=(k,),
t_eval=t_eval
)
return solution.t, solution.y[0], solution.y[1], solution.y[2], k, k_1, is_reversible, order
"""## dataframe"""
results = []
counter = 0
while counter < 6000:
counter += 1
A0 = round(random.uniform(1.0, 10.0), 2)
B0 = round(random.uniform(0.0, 5.0), 2)
C0 = round(random.uniform(0.0, 5.0), 2)
temp = random.randint(270, 280)
pH = round(random.uniform(1.0, 14.0), 2)
Ea = random.randint(90, 100)
A_factor = round(random.uniform(2e16, 5e17), 2)
pressure = round(random.uniform(0.5, 5.0), 2)
weight = round(random.uniform(20, 200), 1)
structure = random.choice(['Linear', 'Ring', 'Branched', 'Unknown'])
catalyst = random.choice(['None', 'Enzyme', 'Acid', 'Base'])
time, A, B, C, k, k_1, is_reversible, order = ode1(A0, B0, C0, temp, Ea, A_factor)
row = {
'order' : order,
'temp': temp,
'pH': pH,
'Ea': Ea,
'A_factor': A_factor,
'pressure': pressure,
'log_pressure' : np.log(pressure),
'weight': weight,
'structure': structure,
'catalyst': catalyst,
'is_reversible': is_reversible,
'k' : k,
'k_1' : k_1,
'A0': A[0], 'A1': A[1], 'A2': A[2], 'A3': A[3], 'A4': A[4],
'A5': A[5], 'A6': A[6], 'A7': A[7], 'A8': A[8], 'A9': A[9], 'A10': A[10],
'B0': B[0], 'B1': B[1], 'B2': B[2], 'B3': B[3], 'B4': B[4],
'B5': B[5], 'B6': B[6], 'B7': B[7], 'B8': B[8], 'B9': B[9], 'B10': B[10],
'C0': C[0], 'C1': C[1], 'C2': C[2], 'C3': C[3], 'C4': C[4],
'C5': C[5], 'C6': C[6], 'C7': C[7], 'C8': C[8], 'C9': C[9], 'C10': C[10]
}
results.append(row)
df = pd.DataFrame(results)
df_original = df.copy()
# df
"""# Machine learning
## Data preparation
- removing 'structure' and 'catalyst' from dataframe
- mapping 0 to zero , 1 to first, 2 to second and 3 to third in order column
- mapping structure and catalyst
"""
structure_map = {'Linear': 0, 'Ring': 1, 'Branched': 2, 'Unknown': 3}
catalyst_map = {'None': 0, 'Enzyme': 1, 'Acid': 2, 'Base': 3}
order_map = {'zero': 0, 'first': 1, 'second': 2, 'third' : 3}
df['structure'] = df['structure'].map(structure_map)
df['catalyst'] = df['catalyst'].map(catalyst_map)
df['order'] = df['order'].map(order_map)
# df
"""## Models
## DNN (Deep Neural Networks)
- saving file as csv
"""
df_X = df_original.drop(['order'], axis=1)
df_y = df_original['order']
train_df = df_X.copy()
train_df['order'] = df_y
train_df.to_csv('chem_data_train.csv', index=False)
train_df.to_csv('chem_data_test.csv', index=False)
"""- DNNs"""
csv_columns = ['temp', 'pH', 'Ea', 'A_factor', 'pressure', 'log_pressure', 'weight', 'structure', 'catalyst', 'is_reversible', 'k', 'k_1']
classes = ['First_Order','Second_Order','Third_Order']
train_path = './chem_data_train.csv'
test_path = './chem_data_train.csv'
train = pd.read_csv(train_path)
test = pd.read_csv(test_path)
# train.head()
if 'order' in train.columns:
train_y = train.pop('order')
if 'order' in test.columns:
test_y = test.pop('order')
# Fill missing values in the 'catalyst' column
train['catalyst'] = train['catalyst'].fillna('None') #NaN values arenot accepted by classifier thats why convert every Nan values to none
test['catalyst'] = test['catalyst'].fillna('None')
# train.head() #the species column is now gone
# Define categorical and numerical feature columns
CATEGORICAL_COLUMNS = ['structure', 'catalyst'] #columns that have strings
NUMERIC_COLUMNS = ['temp', 'pH', 'Ea', 'A_factor', 'pressure', 'log_pressure', 'weight',
'is_reversible', 'k', 'k_1', 'A0', 'A1', 'A2', 'A3', 'A4', 'A5', 'A6', 'A7', 'A8', 'A9', 'A10',
'B0', 'B1', 'B2', 'B3', 'B4', 'B5', 'B6', 'B7', 'B8', 'B9', 'B10',
'C0', 'C1', 'C2', 'C3', 'C4', 'C5', 'C6', 'C7', 'C8', 'C9', 'C10'] #columns that have numerical values
feature_columns = []
for feature_name in CATEGORICAL_COLUMNS:
vocabulary = train[feature_name].unique() #Assining each string a numerical uinque value because our dumb ahh model canot understand english
cat_column = tf.feature_column.categorical_column_with_vocabulary_list(feature_name, vocabulary)
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
feature_columns.append(indicator_column)
for feature_name in NUMERIC_COLUMNS:
feature_columns.append(tf.feature_column.numeric_column(feature_name, dtype=tf.float32))
print(feature_columns)
import logging
tf.get_logger().setLevel(logging.INFO)
#setting up input function
def input_fn(features,labels,training=True,batch_size=500):
#convert the inputs to a dataset
dataset = tf.data.Dataset.from_tensor_slices((dict(features), labels)) #this cnonverts the dataset into tensorflow object
if training:
dataset = dataset.shuffle(1000).repeat()
return dataset.batch(batch_size)
from sklearn.preprocessing import StandardScaler
# Normalize the numerical features in the training data
scaler = StandardScaler()
train_normalized = train.copy()
train_normalized[NUMERIC_COLUMNS] = scaler.fit_transform(train[NUMERIC_COLUMNS])
test_normalized = test.copy()
test_normalized[NUMERIC_COLUMNS] = scaler.transform(test[NUMERIC_COLUMNS])
from sklearn.preprocessing import LabelEncoder
# Convert the 'order' labels to numerical values
le = LabelEncoder()
train_y_encoded = le.fit_transform(train_y) #we used sckit label encoder to encode the values
classifier = tf.estimator.DNNClassifier(
feature_columns=feature_columns,
hidden_units=[50, 40],
n_classes=4, # We have 4 classes: zero, first, second, third
optimizer=tf.keras.optimizers.legacy.RMSprop(learning_rate=0.001))
classifier.train(
input_fn=lambda: input_fn(train_normalized, train_y_encoded, training=True),
steps=600
)
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
classifier.evaluate(input_fn=lambda: input_fn(test_normalized,test_y_encoded,training=False))
"""- accuracy = 0.99983335
# Interactive/sliders
- TODO: be able to change chemical-initial-conc, temp, ea, A_factor, pH, molecular-weight using sliders/input
- best ml model predicts the order of the differential equation from that
"""
def predict_order(inputs):
try:
# Create a pandas DataFrame from the input dictionary
input_df = pd.DataFrame(inputs, index=[0])
# Normalize the numerical features
input_df[NUMERIC_COLUMNS] = scaler.transform(input_df[NUMERIC_COLUMNS])
# Make a prediction
predictions = classifier.predict(input_fn=lambda: input_fn(input_df, labels=None, training=False))
# Get the predicted class and probability
for pred_dict in predictions:
class_id = pred_dict['class_ids'][0]
probability = pred_dict['probabilities'][class_id]
# Get the class name from the label encoder
class_name = le.inverse_transform([class_id])[0]
print('Order is "{}" ({:.1f}%)'.format(class_name, 100 * probability))
return class_name
except Exception as e:
print(f"An error occurred: {e}")
return None
def ode2(A0, B0, C0, temp, Ea, A_factor, is_reversible, order):
y0 = [A0, B0, C0]
k = compute_k(temp, Ea, A_factor)
k_1 = k * 0.7
t_span = (0, 8)
t_eval = np.linspace(0, 8, 11)
if order == 'zero':
solution = solve_ivp(zero, t_span, y0, args=(k,) ,t_eval=t_eval)
elif is_reversible == 0 and order == 'first':
solution = solve_ivp(first, t_span, y0, args=(k,) ,t_eval=t_eval)
elif is_reversible == 1 and order == 'first':
solution = solve_ivp(reversible_first, t_span, y0, args=(k, k_1) ,t_eval=t_eval)
elif is_reversible == 0 and order == 'second':
solution = solve_ivp(second1, t_span, y0, args=(k,) ,t_eval=t_eval)
elif is_reversible == 1 and order == 'second':
solution = solve_ivp(reversible_second1, t_span, y0, args=(k, k_1) ,t_eval=t_eval)
elif is_reversible == 0 and order == 'third':
solution = solve_ivp(third2, t_span, y0, args=(k,) ,t_eval=t_eval)
elif is_reversible == 1 and order == 'third':
solution = solve_ivp(reversible_third2, t_span, y0, args=(k, k_1) ,t_eval=t_eval)
return solution.t, solution.y[0], solution.y[1], solution.y[2], k, k_1
"""## gradio"""
# !pip install gradio
import gradio as gr
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
def run_simulation_and_plot(temp, Ea, A_factor, pH, pressure, is_reversible, structure, catalyst, A0, B0, C0):
#Data Preparation for Predictio
# Simullatqae the reaction using ode1 to get concentrations over time for prediction features
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)
# Create a dictionary with all the necessary inputs for the model
inputs = {
'temp': temp,
'pH': pH,
'Ea': Ea,
'A_factor': A_factor,
'pressure': pressure,
'log_pressure': np.log(pressure),
'weight': 150, # Using a placeholder value as it's not a user input
'structure': structure,
'catalyst': catalyst,
'is_reversible': int(is_reversible),
'k': k_pred, # Use simulated k
'k_1': k_1_pred, # Use simulated k_1
'A0': A_pred[0], 'A1': A_pred[1], 'A2': A_pred[2], 'A3': A_pred[3], 'A4': A_pred[4],
'A5': A_pred[5], 'A6': A_pred[6], 'A7': A_pred[7], 'A8': A_pred[8], 'A9': A_pred[9], 'A10': A_pred[10],
'B0': B_pred[0], 'B1': B_pred[1], 'B2': B_pred[2], 'B3': B_pred[3], 'B4': B_pred[4],
'B5': B_pred[5], 'B6': B_pred[6], 'B7': B_pred[7], 'B8': B_pred[8], 'B9': B_pred[9], 'B10': B_pred[10],
'C0': C_pred[0], 'C1': C_pred[1], 'C2': C_pred[2], 'C3': C_pred[3], 'C4': C_pred[4],
'C5': C_pred[5], 'C6': C_pred[6], 'C7': C_pred[7], 'C8': C_pred[8], 'C9': C_pred[9], 'C10': C_pred[10]
}
# --- 2. Prediction ---
predicted_order = predict_order(inputs)
# --- 3. Simulation with ode2 and Predicted Order ---
# Use ode2 for the final simulation and plotting
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)
# --- 4. Plotting ---
plt.figure()
plt.plot(time_sim, A_sim, label='A')
plt.plot(time_sim, B_sim, label='B')
plt.plot(time_sim, C_sim, label='C')
plt.xlabel('Time')
plt.ylabel('Concentration')
plt.title(f'Concentration vs. Time (Predicted Order: {predicted_order})')
plt.legend()
plt.grid(True)
return predicted_order, plt
# --- 5. Gradio Interface ---
with gr.Blocks() as iface:
gr.Markdown("# Chemical Reaction Order Prediction and Simulation")
gr.Markdown("Use the sliders and options to see the predicted reaction order and a plot of the concentrations over time.")
with gr.Row():
with gr.Column():
gr.Markdown("### Reaction Conditions")
temp = gr.Slider(270, 280, value=277, label="Temperature (K)")
Ea = gr.Slider(90, 100, value=93, label="Activation Energy (Ea, kJ/mol)")
A_factor = gr.Slider(2e16, 5e17, value=4.2e17, label="Pre-exponential Factor (A_factor)")
pH = gr.Slider(1.0, 14.0, value=6.5, label="pH")
pressure = gr.Slider(0.5, 5.0, value=3.0, label="Pressure")
is_reversible = gr.Checkbox(label="Is Reversible?")
structure = gr.Dropdown(['Linear', 'Ring', 'Branched', 'Unknown'], label="Structure")
catalyst = gr.Dropdown(['None', 'Enzyme', 'Acid', 'Base'], label="Catalyst")
with gr.Column():
gr.Markdown("### Initial Concentrations")
A0 = gr.Slider(0.0, 10.0, value=5.0, label="A0")
B0 = gr.Slider(0.0, 10.0, value=2.0, label="B0")
C0 = gr.Slider(0.0, 10.0, value=1.0, label="C0")
with gr.Row():
predict_button = gr.Button("Predict and Plot")
with gr.Row():
with gr.Column():
order_output = gr.Textbox(label="Predicted Order")
with gr.Column():
plot_output = gr.Plot()
predict_button.click(
fn=run_simulation_and_plot,
inputs=[temp, Ea, A_factor, pH, pressure, is_reversible, structure, catalyst, A0, B0, C0],
outputs=[order_output, plot_output]
)
iface.launch()
"""## Streamlit Stuff"""
!pip install -q streamlit
import streamlit as st
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
# 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.
st.set_page_config(layout="wide", page_title="Chemical Reaction Simulator") # Set page layout to wide and add a page title
st.title("πŸ§ͺ Chemical Reaction Order Prediction and Simulation ✨")
st.markdown("Adjust the parameters below to predict the reaction order and visualize the concentration changes over time. πŸ‘‡")
# Use columns for a better layout of inputs
col1, col2 = st.columns(2)
with col1:
st.header("βš™οΈ Reaction Conditions")
temp = st.slider("Temperature (K) 🌑️", 270.0, 280.0, value=277.0)
Ea = st.slider("Activation Energy (Ea, kJ/mol) πŸ”₯", 90.0, 100.0, value=93.0)
A_factor = st.slider("Pre-exponential Factor (A_factor) πŸ“ˆ", 2e16, 5e17, value=4.2e17, format="%e") # Use scientific notation format
pH = st.slider("pH πŸ§ͺ", 1.0, 14.0, value=6.5)
pressure = st.slider("Pressure 🌫️", 0.5, 5.0, value=3.0)
is_reversible = st.checkbox("Is Reversible? πŸ”„", value=False)
structure = st.selectbox("Structure βš›οΈ", ['Linear', 'Ring', 'Branched', 'Unknown'], index=1)
catalyst = st.selectbox("Catalyst ✨", ['None', 'Enzyme', 'Acid', 'Base'], index=2)
with col2:
st.header("πŸ“ˆ Initial Concentrations")
A0 = st.slider("Initial Concentration of A (Aβ‚€)", 0.0, 10.0, value=5.0)
B0 = st.slider("Initial Concentration of B (Bβ‚€)", 0.0, 10.0, value=2.0)
C0 = st.slider("Initial Concentration of C (Cβ‚€)", 0.0, 10.0, value=1.0)
st.markdown("---") # Add a horizontal rule for separation
if st.button("πŸš€ Predict and Plot Reaction"):
# Data Preparation for Prediction
# Simulate the reaction using ode1 to get concentrations over time for prediction features
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)
# Create a dictionary with all the necessary inputs for the model
inputs = {
'temp': temp,
'pH': pH,
'Ea': Ea,
'A_factor': A_factor,
'pressure': pressure,
'log_pressure': np.log(pressure),
'weight': 150, # Using a placeholder value as it's not a user input
'structure': structure,
'catalyst': catalyst,
'is_reversible': int(is_reversible),
'k': k_pred, # Use simulated k
'k_1': k_1_pred, # Use simulated k_1
'A0': A_pred[0], 'A1': A_pred[1], 'A2': A_pred[2], 'A3': A_pred[3], 'A4': A_pred[4],
'A5': A_pred[5], 'A6': A_pred[6], 'A7': A_pred[7], 'A8': A_pred[8], 'A9': A_pred[9], 'A10': A_pred[10],
'B0': B_pred[0], 'B1': B_pred[1], 'B2': B_pred[2], 'B3': B_pred[3], 'B4': B_pred[4],
'B5': B_pred[5], 'B6': B_pred[6], 'B7': B_pred[7], 'B8': B_pred[8], 'B9': B_pred[9], 'B10': B_pred[10],
'C0': C_pred[0], 'C1': C_pred[1], 'C2': C_pred[2], 'C3': C_pred[3], 'C4': C_pred[4],
'C5': C_pred[5], 'C6': C_pred[6], 'C7': C_pred[7], 'C8': C_pred[8], 'C9': C_pred[9], 'C10': C_pred[10]
}
# --- 2. Prediction ---
with st.spinner('Predicting reaction order...'):
predicted_order = predict_order(inputs)
st.success(f"βœ… Predicted Order: **{predicted_order}**")
# --- 3. Simulation with ode2 and Predicted Order ---
with st.spinner('Simulating reaction...'):
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)
# --- 4. Plotting ---
st.header("πŸ“Š Concentration vs. Time Plot")
fig, ax = plt.subplots()
ax.plot(time_sim, A_sim, label='A', marker='o') # Add markers to plot points
ax.plot(time_sim, B_sim, label='B', marker='x')
ax.plot(time_sim, C_sim, label='C', marker='s')
ax.set_xlabel('Time')
ax.set_ylabel('Concentration')
ax.set_title(f'Concentration vs. Time (Predicted Order: {predicted_order})')
ax.legend()
ax.grid(True)
st.pyplot(fig)
st.markdown("---")
st.markdown("App created with ❀️ using Streamlit")
"""Main code for Steamlit pipeline
first copy this code and then create a file named app.py and save it
"""
# import numpy as np
# import matplotlib.pyplot as plt
# import pandas as pd
# from scipy.integrate import solve_ivp
# import random
# import tensorflow as tf
# def compute_k(temp, Ea, A_factor):
# R = 8.314
# Ea_J = Ea * 1000 # Convert Ea from kJ/mol to J/mol
# k = A_factor * np.exp(-Ea_J / (R * temp))
# return k
# def zero(t, y, k):
# A, B, C = y
# dA_dt = -k
# dB_dt = 0
# dC_dt = k
# return [dA_dt, dB_dt, dC_dt]
# def first(t, y, k):
# A, B, C = y
# dA_dt = -k * A
# dB_dt = 0
# dC_dt = +k * A
# return [dA_dt, dB_dt, dC_dt]
# def decay_first(t, y, k):
# A, B, C = y
# dA_dt = -k * A
# dB_dt = 0
# dC_dt = 0
# return [dA_dt, dB_dt, dC_dt]
# def reversible_first(t, y, k, k_1):
# A, B, C = y
# dA_dt = -k * A + k_1 * C
# dB_dt = 0
# dC_dt = k * A - k_1 * C
# return [dA_dt, dB_dt, dC_dt]
# def second1(t, y, k):
# A, B, C = y
# dA_dt = -k * A * B
# dB_dt = -k * A * B
# dC_dt = +k * A * B
# return [dA_dt, dB_dt, dC_dt]
# def second2(t, y, k):
# A, B, C = y
# dA_dt = -2 * k * A**2
# dB_dt = 0
# dC_dt = +k * A**2
# return [dA_dt, dB_dt, dC_dt]
# def reversible_second1(t, y, k, k_1):
# A, B, C = y
# dA_dt = -k * A * B + k_1 * C
# dB_dt = -k * A * B + k_1 * C
# dC_dt = +k * A * B - k_1 * C
# return [dA_dt, dB_dt, dC_dt]
# def reversible_second2(t, y, k, k_1):
# A, B, C = y
# dA_dt = -2 * k * A**2 + 2 * k_1 * C
# dB_dt = 0
# dC_dt = +k * A**2 - k_1 * C
# return [dA_dt, dB_dt, dC_dt]
# def third1(t, y, k):
# A, B, C = y
# dA_dt = -3 * k * A**3
# dB_dt = 0
# dC_dt = +k * A**3
# return [dA_dt, dB_dt, dC_dt]
# def third2(t, y, k):
# A, B, C = y
# dA_dt = -2 * k * A**2 * B
# dB_dt = -1 * k * A**2 * B
# dC_dt = +k * A**2 * B
# return [dA_dt, dB_dt, dC_dt]
# def reversible_third1(t, y, k, k_1):
# A, B, C = y
# dA_dt = -3 * k * A**3 + 3 * k_1 * C
# dB_dt = 0
# dC_dt = +k * A**3 - k_1 * C
# return [dA_dt, dB_dt, dC_dt]
# def reversible_third2(t, y, k, k_1):
# A, B, C = y
# dA_dt = -2 * k * A**2 * B + 2 * k_1 * C
# dB_dt = -1 * k * A**2 * B + 1 * k_1 * C
# dC_dt = +k * A**2 * B - k_1 * C
# return [dA_dt, dB_dt, dC_dt]
# def ode1(A0, B0, C0, temp, Ea, A_factor):
# y0 = [A0, B0, C0]
# k = compute_k(temp, Ea, A_factor)
# k_1 = k * random.uniform(0.5, 0.9)
# t_span = (0, 8) # From time 0 to 10 seconds
# t_eval = np.linspace(0, 8, 11) # 11 points where you want the solution
# num = random.randint(0, 11) # For choosing between first or decay if not reversible
# match num:
# case 0:
# func_name = zero
# is_reversible = 0
# order = 'zero'
# case 1:
# func_name = first
# is_reversible = 0
# order = 'first'
# case 2:
# func_name = decay_first
# is_reversible = 0
# order = 'first'
# case 3:
# func_name = reversible_first
# is_reversible = 1
# order = 'first'
# case 4:
# func_name = second1
# is_reversible = 0
# order = 'second'
# case 5:
# func_name = second2
# is_reversible = 0
# order = 'second'
# case 6:
# func_name = reversible_second1
# is_reversible = 1
# order = 'second'
# case 7:
# func_name = reversible_second2
# is_reversible = 1
# order = 'second'
# case 8:
# func_name = third1
# is_reversible = 0
# order = 'third'
# case 9:
# func_name = third2
# is_reversible = 0
# order = 'third'
# case 10:
# func_name = reversible_third1
# is_reversible = 1
# order = 'third'
# case 11:
# func_name = reversible_third2
# is_reversible = 1
# order = 'third'
# if is_reversible == 1:
# solution = solve_ivp(
# func_name,
# t_span,
# y0,
# args=(k, k_1),
# t_eval=t_eval
# )
# elif is_reversible == 0:
# solution = solve_ivp(
# func_name,
# t_span,
# y0,
# args=(k,),
# t_eval=t_eval
# )
# return solution.t, solution.y[0], solution.y[1], solution.y[2], k, k_1, is_reversible, order
# results = []
# counter = 0
# while counter < 6000:
# counter += 1
# A0 = round(random.uniform(1.0, 10.0), 2)
# B0 = round(random.uniform(0.0, 5.0), 2)
# C0 = round(random.uniform(0.0, 5.0), 2)
# temp = random.randint(270, 280)
# pH = round(random.uniform(1.0, 14.0), 2)
# Ea = random.randint(90, 100)
# A_factor = round(random.uniform(2e16, 5e17), 2)
# pressure = round(random.uniform(0.5, 5.0), 2)
# weight = round(random.uniform(20, 200), 1)
# structure = random.choice(['Linear', 'Ring', 'Branched', 'Unknown'])
# catalyst = random.choice(['None', 'Enzyme', 'Acid', 'Base'])
# time, A, B, C, k, k_1, is_reversible, order = ode1(A0, B0, C0, temp, Ea, A_factor)
# row = {
# 'order' : order,
# 'temp': temp,
# 'pH': pH,
# 'Ea': Ea,
# 'A_factor': A_factor,
# 'pressure': pressure,
# 'log_pressure' : np.log(pressure),
# 'weight': weight,
# 'structure': structure,
# 'catalyst': catalyst,
# 'is_reversible': is_reversible,
# 'k' : k,
# 'k_1' : k_1,
# 'A0': A[0], 'A1': A[1], 'A2': A[2], 'A3': A[3], 'A4': A[4],
# 'A5': A[5], 'A6': A[6], 'A7': A[7], 'A8': A[8], 'A9': A[9], 'A10': A[10],
# 'B0': B[0], 'B1': B[1], 'B2': B[2], 'B3': B[3], 'B4': B[4],
# 'B5': B[5], 'B6': B[6], 'B7': B[7], 'B8': B[8], 'B9': B[9], 'B10': B[10],
# 'C0': C[0], 'C1': C[1], 'C2': C[2], 'C3': C[3], 'C4': C[4],
# 'C5': C[5], 'C6': C[6], 'C7': C[7], 'C8': C[8], 'C9': C[9], 'C10': C[10]
# }
# results.append(row)
# df = pd.DataFrame(results)
# df_original = df.copy()
# # display(df)
# structure_map = {'Linear': 0, 'Ring': 1, 'Branched': 2, 'Unknown': 3}
# catalyst_map = {'None': 0, 'Enzyme': 1, 'Acid': 2, 'Base': 3}
# order_map = {'zero': 0, 'first': 1, 'second': 2, 'third' : 3}
# df['structure'] = df['structure'].map(structure_map)
# df['catalyst'] = df['catalyst'].map(catalyst_map)
# df['order'] = df['order'].map(order_map)
# # display(df)
# csv_columns = ['temp', 'pH', 'Ea', 'A_factor', 'pressure', 'log_pressure', 'weight', 'structure', 'catalyst', 'is_reversible', 'k', 'k_1']
# classes = ['First_Order','Second_Order','Third_Order']
# train_path = './chem_data_train.csv'
# test_path = './chem_data_train.csv'
# train = pd.read_csv(train_path)
# test = pd.read_csv(test_path)
# # display(train.head())
# if 'order' in train.columns:
# train_y = train.pop('order')
# if 'order' in test.columns:
# test_y = test.pop('order')
# # Fill missing values in the 'catalyst' column
# train['catalyst'] = train['catalyst'].fillna('None') #NaN values arenot accepted by classifier thats why convert every Nan values to none
# test['catalyst'] = test['catalyst'].fillna('None')
# # display(train.head()) #the species column is now gone
# # Define categorical and numerical feature columns
# CATEGORICAL_COLUMNS = ['structure', 'catalyst'] #columns that have strings
# NUMERIC_COLUMNS = ['temp', 'pH', 'Ea', 'A_factor', 'pressure', 'log_pressure', 'weight',
# 'is_reversible', 'k', 'k_1', 'A0', 'A1', 'A2', 'A3', 'A4', 'A5', 'A6', 'A7', 'A8', 'A9', 'A10',
# 'B0', 'B1', 'B2', 'B3', 'B4', 'B5', 'B6', 'B7', 'B8', 'B9', 'B10',
# 'C0', 'C1', 'C2', 'C3', 'C4', 'C5', 'C6', 'C7', 'C8', 'C9', 'C10'] #columns that have numerical values
# feature_columns = []
# for feature_name in CATEGORICAL_COLUMNS:
# vocabulary = train[feature_name].unique() #Assining each string a numerical uinque value because our dumb ahh model canot understand english
# cat_column = tf.feature_column.categorical_column_with_vocabulary_list(feature_name, vocabulary)
# 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
# feature_columns.append(indicator_column)
# for feature_name in NUMERIC_COLUMNS:
# feature_columns.append(tf.feature_column.numeric_column(feature_name, dtype=tf.float32))
# # print(feature_columns)
# import logging
# tf.get_logger().setLevel(logging.INFO)
# #setting up input function
# def input_fn(features,labels,training=True,batch_size=500):
# #convert the inputs to a dataset
# dataset = tf.data.Dataset.from_tensor_slices((dict(features), labels)) #this cnonverts the dataset into tensorflow object
# if training:
# dataset = dataset.shuffle(1000).repeat()
# return dataset.batch(batch_size)
# from sklearn.preprocessing import StandardScaler
# # Normalize the numerical features in the training data
# scaler = StandardScaler()
# train_normalized = train.copy()
# train_normalized[NUMERIC_COLUMNS] = scaler.fit_transform(train[NUMERIC_COLUMNS])
# test_normalized = test.copy()
# test_normalized[NUMERIC_COLUMNS] = scaler.transform(test[NUMERIC_COLUMNS])
# from sklearn.preprocessing import LabelEncoder
# # Convert the 'order' labels to numerical values
# le = LabelEncoder()
# train_y_encoded = le.fit_transform(train_y) #we used sckit label encoder to encode the values
# classifier = tf.estimator.DNNClassifier(
# feature_columns=feature_columns,
# hidden_units=[50, 40],
# n_classes=4, # We have 4 classes: zero, first, second, third
# optimizer=tf.keras.optimizers.legacy.RMSprop(learning_rate=0.001))
# classifier.train(
# input_fn=lambda: input_fn(train_normalized, train_y_encoded, training=True),
# steps=300
# )
# 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
# classifier.evaluate(input_fn=lambda: input_fn(test_normalized,test_y_encoded,training=False))
# def predict_order(inputs):
# try:
# # Create a pandas DataFrame from the input dictionary
# input_df = pd.DataFrame(inputs, index=[0])
# # Normalize the numerical features
# input_df[NUMERIC_COLUMNS] = scaler.transform(input_df[NUMERIC_COLUMNS])
# # Make a prediction
# predictions = classifier.predict(input_fn=lambda: input_fn(input_df, labels=None, training=False))
# # Get the predicted class and probability
# for pred_dict in predictions:
# class_id = pred_dict['class_ids'][0]
# probability = pred_dict['probabilities'][class_id]
# # Get the class name from the label encoder
# class_name = le.inverse_transform([class_id])[0]
# print('Order is "{}" ({:.1f}%)'.format(class_name, 100 * probability))
# return class_name
# except Exception as e:
# print(f"An error occurred: {e}")
# return None
# def ode2(A0, B0, C0, temp, Ea, A_factor, is_reversible, order):
# y0 = [A0, B0, C0]
# k = compute_k(temp, Ea, A_factor)
# k_1 = k * 0.7
# t_span = (0, 8)
# t_eval = np.linspace(0, 8, 11)
# if order == 'zero':
# solution = solve_ivp(zero, t_span, y0, args=(k,) ,t_eval=t_eval)
# elif is_reversible == 0 and order == 'first':
# solution = solve_ivp(first, t_span, y0, args=(k,) ,t_eval=t_eval)
# elif is_reversible == 1 and order == 'first':
# solution = solve_ivp(reversible_first, t_span, y0, args=(k, k_1) ,t_eval=t_eval)
# elif is_reversible == 0 and order == 'second':
# solution = solve_ivp(second1, t_span, y0, args=(k,) ,t_eval=t_eval)
# elif is_reversible == 1 and order == 'second':
# solution = solve_ivp(reversible_second1, t_span, y0, args=(k, k_1) ,t_eval=t_eval)
# elif is_reversible == 0 and order == 'third':
# solution = solve_ivp(third2, t_span, y0, args=(k,) ,t_eval=t_eval)
# elif is_reversible == 1 and order == 'third':
# solution = solve_ivp(reversible_third2, t_span, y0, args=(k, k_1) ,t_eval=t_eval)
# return solution.t, solution.y[0], solution.y[1], solution.y[2], k, k_1
# import streamlit as st
# import pandas as pd
# import numpy as np
# import matplotlib.pyplot as plt
# # 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.
# st.set_page_config(layout="wide", page_title="Chemical Reaction Simulator") # Set page layout to wide and add a page title
# st.title("πŸ§ͺ Project E-11")
# st.markdown("πŸ§ͺ Chemical Reaction Order Prediction and Simulation ✨")
# st.markdown("Adjust the parameters below to predict the reaction order and visualize the concentration changes over time. πŸ‘‡")
# # Use columns for a better layout of inputs
# col1, col2 = st.columns(2)
# with col1:
# st.header("βš™οΈ Reaction Conditions")
# temp = st.slider("Temperature (K) 🌑️", 270.0, 280.0, value=277.0)
# Ea = st.slider("Activation Energy (Ea, kJ/mol) πŸ”₯", 90.0, 100.0, value=93.0)
# A_factor = st.slider("Pre-exponential Factor (A_factor) πŸ“ˆ", 2e16, 5e17, value=4.2e17, format="%e") # Use scientific notation format
# pH = st.slider("pH πŸ§ͺ", 1.0, 14.0, value=6.5)
# pressure = st.slider("Pressure 🌫️", 0.5, 5.0, value=3.0)
# is_reversible = st.checkbox("Is Reversible? πŸ”„", value=False)
# structure = st.selectbox("Structure βš›οΈ", ['Linear', 'Ring', 'Branched', 'Unknown'], index=1)
# catalyst = st.selectbox("Catalyst ✨", ['None', 'Enzyme', 'Acid', 'Base'], index=2)
# with col2:
# st.header("πŸ“ˆ Initial Concentrations")
# A0 = st.slider("Initial Concentration of A (Aβ‚€)", 0.0, 10.0, value=5.0)
# B0 = st.slider("Initial Concentration of B (Bβ‚€)", 0.0, 10.0, value=2.0)
# C0 = st.slider("Initial Concentration of C (Cβ‚€)", 0.0, 10.0, value=1.0)
# st.markdown("---") # Add a horizontal rule for separation
# if st.button("πŸš€ Predict and Plot Reaction"):
# # Data Preparation for Prediction
# # Simulate the reaction using ode1 to get concentrations over time for prediction features
# 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)
# # Create a dictionary with all the necessary inputs for the model
# inputs = {
# 'temp': temp,
# 'pH': pH,
# 'Ea': Ea,
# 'A_factor': A_factor,
# 'pressure': pressure,
# 'log_pressure': np.log(pressure),
# 'weight': 150, # Using a placeholder value as it's not a user input
# 'structure': structure,
# 'catalyst': catalyst,
# 'is_reversible': int(is_reversible),
# 'k': k_pred, # Use simulated k
# 'k_1': k_1_pred, # Use simulated k_1
# 'A0': A_pred[0], 'A1': A_pred[1], 'A2': A_pred[2], 'A3': A_pred[3], 'A4': A_pred[4],
# 'A5': A_pred[5], 'A6': A_pred[6], 'A7': A_pred[7], 'A8': A_pred[8], 'A9': A_pred[9], 'A10': A_pred[10],
# 'B0': B_pred[0], 'B1': B_pred[1], 'B2': B_pred[2], 'B3': B_pred[3], 'B4': B_pred[4],
# 'B5': B_pred[5], 'B6': B_pred[6], 'B7': B_pred[7], 'B8': B_pred[8], 'B9': B_pred[9], 'B10': B_pred[10],
# 'C0': C_pred[0], 'C1': C_pred[1], 'C2': C_pred[2], 'C3': C_pred[3], 'C4': C_pred[4],
# 'C5': C_pred[5], 'C6': C_pred[6], 'C7': C_pred[7], 'C8': C_pred[8], 'C9': C_pred[9], 'C10': C_pred[10]
# }
# # --- 2. Prediction ---
# with st.spinner('Predicting reaction order...'):
# predicted_order = predict_order(inputs)
# st.success(f"βœ… Predicted Order: **{predicted_order}**")
# # --- 3. Simulation with ode2 and Predicted Order ---
# with st.spinner('Simulating reaction...'):
# 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)
# # --- 4. Plotting ---
# st.header("πŸ“Š Concentration vs. Time Plot")
# fig, ax = plt.subplots()
# ax.plot(time_sim, A_sim, label='A', marker='o') # Add markers to plot points
# ax.plot(time_sim, B_sim, label='B', marker='x')
# ax.plot(time_sim, C_sim, label='C', marker='s')
# ax.set_xlabel('Time')
# ax.set_ylabel('Concentration')
# ax.set_title(f'Concentration vs. Time (Predicted Order: {predicted_order})')
# ax.legend()
# ax.grid(True)
# st.pyplot(fig)
# st.markdown("---")
# st.markdown("App created with ❀️ by Mujtaba , Muzammil , Taha and Ali Zain.")
# !streamlit run /content/app.py &>/content/logs.txt & #this starts the loca server
# !npx localtunnel --port 8501 #the tunnel
# get_ipython().run_line_magic('shell', 'curl https://loca.lt/mytunnelpassword') #getting ur home ip adress :cold:
# %%writefile requirements.txt
# gradio
# pandas
# numpy
# matplotlib
# scipy
# tensorflow==2.15
# scikit-learn