#!/usr/bin/env python # coding: utf-8 # ### One-bin `A <-> 3B` reaction, with 1st-order kinetics in both directions, # ### taken to equilibrium # # Diffusion not applicable (just 1 bin) # # LAST REVISED: May 6, 2024 # # * [First Step](#reaction_2_sec_2_first_step) # * [Numerous more steps](#reaction_2_sec_2) # * [Equilibrium](#reaction_2_sec_2_equilibrium) # In[1]: import set_path # Importing this module will add the project's home directory to sys.path # In[2]: from experiments.get_notebook_info import get_notebook_basename from src.modules.chemicals.chem_data import ChemData as chem from src.life_1D.bio_sim_1d import BioSim1D import plotly.express as px from src.modules.visualization.graphic_log import GraphicLog # In[3]: # Initialize the HTML logging log_file = get_notebook_basename() + ".log.htm" # Use the notebook base filename for the log file # Set up the use of some specified graphic (Vue) components GraphicLog.config(filename=log_file, components=["vue_cytoscape_2"], extra_js="https://cdnjs.cloudflare.com/ajax/libs/cytoscape/3.21.2/cytoscape.umd.js") # In[4]: # Initialize the system chem_data = chem(names=["A", "B"]) # NOTE: Diffusion not applicable (just 1 bin) # Reaction A <-> 3B , with 1st-order kinetics in both directions chem_data.add_reaction(reactants=["A"], products=[(3,"B",1)], forward_rate=5., reverse_rate=2.) bio = BioSim1D(n_bins=1, chem_data=chem_data) bio.set_uniform_concentration(species_index=0, conc=10.) bio.set_uniform_concentration(species_index=1, conc=50.) bio.describe_state() # In[5]: chem_data.describe_reactions() # In[6]: # Save the state of the concentrations of all species at bin 0 bio.add_snapshot(bio.bin_snapshot(bin_address = 0), caption="Initial state") bio.get_history() # In[7]: # Send the plot to the HTML log file chem_data.plot_reaction_network("vue_cytoscape_2") # ### First step # In[8]: # First step bio.react(time_step=0.1, n_steps=1, snapshots={"sample_bin": 0}) bio.describe_state() # _Early in the reaction :_ # [A] = 15. [B] = 35. # In[9]: bio.get_history() # ### Numerous more steps # In[10]: # Numerous more steps bio.react(time_step=0.1, n_steps=10, snapshots={"sample_bin": 0}) bio.describe_state() # ### Equilibrium # Consistent with the 5/2 ratio of forward/reverse rates (and the 1st order reactions), # the systems settles in the equilibrium: [A] = 14.54545455 , [B] = 36.36363636 # In[11]: # Verify that the reaction has reached equilibrium bio.reaction_dynamics.is_in_equilibrium(conc=bio.bin_snapshot(bin_address = 0)) # In[12]: bio.get_history() # Note how the simulation initially **OVERSHOT** the equilibrium values; the first step was too large! # # Plots of changes of concentration with time # In[13]: fig = px.line(data_frame=bio.get_history(), x="SYSTEM TIME", y=["A", "B"], title="Changes in concentrations with time", color_discrete_sequence = ['navy', 'darkorange'], labels={"value":"concentration", "variable":"Chemical"}) fig.show() # In[14]: # Same plot, but with smooth line fig = px.line(data_frame=bio.get_history(), x="SYSTEM TIME", y=["A", "B"], title="Changes in concentrations with time (smoothed)", color_discrete_sequence = ['navy', 'darkorange'], labels={"value":"concentration", "variable":"Chemical"}, line_shape="spline") fig.show() # The early **OVERSHOOTING** of the equilibrium values shows prominently in the last plot! # In[ ]: