#!/usr/bin/env python # coding: utf-8 # ### One-bin A <-> 3B reaction, taken to equilibrium. # #### A hypothetical scenario with 1st-order kinetics in both directions. # ### Examine State Space trajectory, using [A] and [B] as state variables # # Based on experiment `1D/reaction/reaction_2` # # Diffusion not applicable (just 1 bin). # # This is the 1D version of the single-compartment reaction by the same name. # ### TAGS : "reactions 1D" # In[1]: LAST_REVISED = "May 5, 2025" LIFE123_VERSION = "1.0.0rc3" # Library version this experiment is based on # In[2]: #import set_path # Using MyBinder? Uncomment this before running the next cell! # In[3]: #import sys #sys.path.append("C:/some_path/my_env_or_install") # CHANGE to the folder containing your venv or libraries installation! # NOTE: If any of the imports below can't find a module, uncomment the lines above, or try: import set_path from experiments.get_notebook_info import get_notebook_basename from life123 import check_version, UniformCompartment, BioSim1D, PlotlyHelper, GraphicLog import plotly.express as px # In[4]: # 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[5]: # Initialize the system. NOTE: Diffusion not applicable (just 1 bin) uc = UniformCompartment(names=["A", "B"]) # Reaction A <-> 3B , with 1st-order kinetics in both directions uc.add_reaction(reactants="A", products=[(3,"B",1)], forward_rate=5., reverse_rate=2.) uc.describe_reactions() # In[6]: bio = BioSim1D(n_bins=1, reaction_handler=uc) bio.set_uniform_concentration(chem_label="A", conc=10.) bio.set_uniform_concentration(chem_label="B", conc=50.) bio.describe_state() # In[ ]: # In[7]: # Let's enable history - by default for all chemicals and all bins (we're only using one) bio.enable_history(take_snapshot=True, caption="Initial setup") # In[8]: bio.get_bin_history(bin_address=0) # In[ ]: # In[9]: # Send the plot to the HTML log file uc.plot_reaction_network("vue_cytoscape_2") # In[ ]: # ### To equilibrium # In[10]: # Using smaller steps that in experiment reaction_2, to avoid the initial overshooting bio.react(time_step=0.05, n_steps=10) # In[11]: bio.describe_state() # In[12]: bio.get_bin_history(bin_address=0) # In[13]: # Verify that the reaction has reached equilibrium bio.reaction_dynamics.is_in_equilibrium(rxn_index=0, conc=bio.bin_snapshot(bin_address = 0)) # # Plots of changes of concentration with time # In[14]: bio.plot_history_single_bin(bin_address=0, title_prefix="Reaction A <-> 3B") # In[ ]: # ## Same data, but shown differently # In[15]: df = bio.get_bin_history(bin_address=0) # In[16]: fig0 = px.line(data_frame=df, x="A", y="B", title="State space of reaction A <-> 3B : [A] vs. [B]", color_discrete_sequence = ['#C83778'], labels={"value":"concentration", "variable":"Chemical"}) fig0.show() # In[17]: # Now show the individual data points df['SYSTEM TIME'] = round(df['SYSTEM TIME'], 2) # To avoid clutter from too many digits, in the column fig1 = px.scatter(data_frame=df, x="A", y="B", title="Trajectory in State space: [A] vs. [B]", hover_data=['SYSTEM TIME']) fig1.update_traces(marker={"size": 6, "color": "#2FAC74"}) # Modify the style of the dots # Add annotations (showing the System Time value) to SOME of the points, to avoid clutter for ind in df.index: label = df["SYSTEM TIME"][ind] if ind == 0: label = f"t={label}" label_x = ind*16 label_y = 20 + ind*8 # A greater y value here means further DOWN!! if (ind <= 3) or (ind%2 == 0): fig1.add_annotation(x=df["A"][ind], y=df["B"][ind], text=label, font=dict( size=10, color="grey" ), showarrow=True, arrowhead=0, ax=label_x, ay=label_y, arrowcolor="#b0b0b0", bordercolor="#c7c7c7") fig1.show() # In[18]: # Combine the two above plots, # while using the layout of fig1 (which includes the title and annotations) PlotlyHelper.combine_plots(fig_list = [fig0, fig1], layout_index=1) # ### Note how the trajectory is progressively slowing down towards the dynamical system's "attractor" (equilibrium state of the reaction) # In[ ]: