LAST_REVISED = "Jan. 13, 2025"
LIFE123_VERSION = "1.0.0rc2" # Library version this experiment is based on
#import set_path # Using MyBinder? Uncomment this before running the next cell!
#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 ChemData, BioSim1D
from life123 import GraphicLog, HtmlLog as log
# 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")
-> Output will be LOGGED into the file 'reaction_8.log.htm'
# Initialize the system
chem_data = ChemData(names=["A", "B", "C", "D", "E"]) # NOTE: Diffusion not applicable (just 1 bin)
bio = BioSim1D(n_bins=1, chem_data=chem_data)
# Specify the reactions
reactions = bio.get_reactions()
# Reactions A + B <-> C and C + D <-> E , with 1st-order kinetics for each species
reactions.add_reaction(reactants=["A", "B"], products="C", forward_rate=5., reverse_rate=2.)
reactions.add_reaction(reactants=["C", "D"], products="E", forward_rate=8., reverse_rate=4.)
reactions.describe_reactions()
Number of reactions: 2 (at temp. 25 C)
0: A + B <-> C (kF = 5 / kR = 2 / delta_G = -2,271.4 / K = 2.5) | 1st order in all reactants & products
1: C + D <-> E (kF = 8 / kR = 4 / delta_G = -1,718.3 / K = 2) | 1st order in all reactants & products
Set of chemicals involved in the above reactions: {'B', 'D', 'E', 'A', 'C'}
# Send a header and a plot to the HTML log file
log.write("2 COUPLED reactions: A + B <-> C and C + D <-> E",
style=log.h2)
# Send the plot to the HTML log file
reactions.plot_reaction_network("vue_cytoscape_2")
2 COUPLED reactions: A + B C and C + D E [GRAPHIC ELEMENT SENT TO LOG FILE `reaction_8.log.htm`]
# Let's enable history - by default for all chemicals and all bins (we just have 1 bin)
bio.enable_history()
History enabled for bins None and chemicals None (None means 'all')
bio.set_all_uniform_concentrations( [3., 5., 1., 0.4, 0.1] ) # In the order the chemicals were added
bio.describe_state()
SYSTEM STATE at Time t = 0: 1 bins and 5 chemical species:
| Species | Diff rate | Bin 0 | |
|---|---|---|---|
| 0 | A | None | 3.0 |
| 1 | B | None | 5.0 |
| 2 | C | None | 1.0 |
| 3 | D | None | 0.4 |
| 4 | E | None | 0.1 |
bio.get_bin_history(bin_address=0)
| SYSTEM TIME | A | B | C | D | E | |
|---|---|---|---|---|---|---|
| 0 | 0.0 | 3.0 | 5.0 | 1.0 | 0.4 | 0.1 |
# First step
bio.react(time_step=0.01, n_steps=1)
System Time is now: 0.01
bio.describe_state()
SYSTEM STATE at Time t = 0.01: 1 bins and 5 chemical species:
| Species | Diff rate | Bin 0 | |
|---|---|---|---|
| 0 | A | None | 2.270 |
| 1 | B | None | 4.270 |
| 2 | C | None | 1.702 |
| 3 | D | None | 0.372 |
| 4 | E | None | 0.128 |
bio.get_bin_history(bin_address=0)
| SYSTEM TIME | A | B | C | D | E | |
|---|---|---|---|---|---|---|
| 0 | 0.00 | 3.00 | 5.00 | 1.000 | 0.400 | 0.100 |
| 1 | 0.01 | 2.27 | 4.27 | 1.702 | 0.372 | 0.128 |
# Identical 2nd step
bio.react(time_step=0.01, n_steps=1)
System Time is now: 0.02
bio.describe_state()
SYSTEM STATE at Time t = 0.02: 1 bins and 5 chemical species:
| Species | Diff rate | Bin 0 | |
|---|---|---|---|
| 0 | A | None | 1.819395 |
| 1 | B | None | 3.819395 |
| 2 | C | None | 2.107073 |
| 3 | D | None | 0.326468 |
| 4 | E | None | 0.173532 |
bio.get_bin_history(bin_address=0)
| SYSTEM TIME | A | B | C | D | E | |
|---|---|---|---|---|---|---|
| 0 | 0.00 | 3.000000 | 5.000000 | 1.000000 | 0.400000 | 0.100000 |
| 1 | 0.01 | 2.270000 | 4.270000 | 1.702000 | 0.372000 | 0.128000 |
| 2 | 0.02 | 1.819395 | 3.819395 | 2.107073 | 0.326468 | 0.173532 |
# Numerous more identical steps, to equilibrium
bio.react(time_step=0.01, n_steps=200)
System Time is now: 2.02
bio.describe_state()
SYSTEM STATE at Time t = 2.02: 1 bins and 5 chemical species:
| Species | Diff rate | Bin 0 | |
|---|---|---|---|
| 0 | A | None | 0.505080 |
| 1 | B | None | 2.505080 |
| 2 | C | None | 3.163167 |
| 3 | D | None | 0.068247 |
| 4 | E | None | 0.431753 |
# Verify that each reaction has reached equilibrium
bio.reaction_dynamics.is_in_equilibrium(rxn_index=0, conc=bio.bin_snapshot(bin_address = 0))
A + B <-> C
Final concentrations: [A] = 0.5051 ; [B] = 2.505 ; [C] = 3.163
1. Ratio of reactant/product concentrations, adjusted for reaction orders: 2.5
Formula used: [C] / ([A][B])
2. Ratio of forward/reverse reaction rates: 2.5
Discrepancy between the two values: 8.882e-14 %
Reaction IS in equilibrium (within 1% tolerance)
True
bio.reaction_dynamics.is_in_equilibrium(rxn_index=1, conc=bio.bin_snapshot(bin_address = 0))
C + D <-> E
Final concentrations: [C] = 3.163 ; [D] = 0.06825 ; [E] = 0.4318
1. Ratio of reactant/product concentrations, adjusted for reaction orders: 2
Formula used: [E] / ([C][D])
2. Ratio of forward/reverse reaction rates: 2
Discrepancy between the two values: 3.331e-14 %
Reaction IS in equilibrium (within 1% tolerance)
True
# Do a consistent check with the equilibrium concentrations:
A_eq = bio.bin_concentration(0, 0)
B_eq = bio.bin_concentration(0, 1)
C_eq = bio.bin_concentration(0, 2)
D_eq = bio.bin_concentration(0, 3)
E_eq = bio.bin_concentration(0, 4)
Rf0 = reactions.get_forward_rate(0)
Rb0 = reactions.get_reverse_rate(0)
Rf1 = reactions.get_forward_rate(1)
Rb1 = reactions.get_reverse_rate(1)
equil = -(Rf0 * A_eq * B_eq - Rf1 * C_eq * D_eq) + (Rb0 * C_eq - Rb1 * E_eq)
print("\nAt equilibrium: ", equil, " (this should be close to 0 at equilibrium)")
At equilibrium: -4.440892098500626e-15 (this should be close to 0 at equilibrium)
bio.get_bin_history(bin_address=0)
| SYSTEM TIME | A | B | C | D | E | |
|---|---|---|---|---|---|---|
| 0 | 0.00 | 3.000000 | 5.000000 | 1.000000 | 0.400000 | 0.100000 |
| 1 | 0.01 | 2.270000 | 4.270000 | 1.702000 | 0.372000 | 0.128000 |
| 2 | 0.02 | 1.819395 | 3.819395 | 2.107073 | 0.326468 | 0.173532 |
| 3 | 0.03 | 1.514087 | 3.514087 | 2.364291 | 0.278378 | 0.221622 |
| 4 | 0.04 | 1.295341 | 3.295341 | 2.539249 | 0.234590 | 0.265410 |
| ... | ... | ... | ... | ... | ... | ... |
| 198 | 1.98 | 0.505080 | 2.505080 | 3.163167 | 0.068247 | 0.431753 |
| 199 | 1.99 | 0.505080 | 2.505080 | 3.163167 | 0.068247 | 0.431753 |
| 200 | 2.00 | 0.505080 | 2.505080 | 3.163167 | 0.068247 | 0.431753 |
| 201 | 2.01 | 0.505080 | 2.505080 | 3.163167 | 0.068247 | 0.431753 |
| 202 | 2.02 | 0.505080 | 2.505080 | 3.163167 | 0.068247 | 0.431753 |
203 rows × 6 columns
bio.plot_history_single_bin(bin_address=0,
title="2 COUPLED reactions: A + B <-> C and C + D <-> E . Concentrations at bin 0")
A and B get consumed.
C gets produced by the 1st reaction more quickly than consumed by the 2nd one.
D gets consumed, while E gets produced.