LAST_REVISED = "Feb. 16, 2026"
LIFE123_VERSION = "1.0.0rc7" # 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
import ipynbname
from life123 import check_version, UniformCompartment, GraphicLog
check_version(LIFE123_VERSION)
OK
# Initialize the HTML logging (for the graphics)
log_file = ipynbname.name() + ".log.htm" # Use the notebook base filename for the log file
# IN CASE OF PROBLEMS, set manually to any desired name
Specify the chemicals, the reactions, and the initial concentrations
# Instantiate the simulator and specify the chemicals
uc = UniformCompartment(preset="fast")
# Elementary reaction A + B <-> C
uc.add_reaction(reactants=["A" , "B"], products="C", kF=5., kR=2.)
uc.describe_reactions()
add_reaction(): detected reaction type `ReactionSynthesis` Number of reactions: 1 0: A + B <-> C Elementary Synthesis reaction (kF = 5 / kR = 2 / delta_G = -2,271.4 / K = 2.5 / Temp = 25 C) Chemicals involved in the above reactions: ['A', 'B', 'C']
# Send a plot of the network of reactions to the HTML log file
uc.plot_reaction_network(log_file=log_file)
[GRAPHIC ELEMENT SENT TO FILE `react_3_a.log.htm`]
uc.enable_diagnostics() # To save diagnostic information
# Set the initial concentrations of all the chemicals
uc.set_conc({"A": 10., "B": 50., "C": 20.}, snapshot=True)
uc.describe_state()
SYSTEM STATE at Time t = 0: 3 species: Species 0 (A). Conc: 10.0 Species 1 (B). Conc: 50.0 Species 2 (C). Conc: 20.0 Chemicals involved in reactions: ['B', 'C', 'A']
uc.get_history()
| SYSTEM TIME | A | B | C | step | caption | |
|---|---|---|---|---|---|---|
| 0 | 0.0 | 10.0 | 50.0 | 20.0 | Set concentration |
we can preview the final equilibrium concentrations without actually running the simulation
uc.find_equilibrium_conc(rxn_index=0) # This is an EXACT solution
{'A': 0.2948774087575341, 'B': 40.294877408757536, 'C': 29.705122591242464}
The reaction will proceed forward, with A and B being consumed, and C being produced
uc.single_compartment_react(initial_step=0.004, duration=0.06,
variable_steps=True)
23 total variable step(s) taken in 0.133 sec
Number of step re-do's because of elective soft aborts: 3
Norm usage: {'norm_A': 13, 'norm_B': 9, 'norm_C': 9, 'norm_D': 9}
System Time is now: 0.0674
uc.get_history()
| SYSTEM TIME | A | B | C | step | caption | |
|---|---|---|---|---|---|---|
| 0 | 0.000000 | 10.000000 | 50.000000 | 20.000000 | Set concentration | |
| 1 | 0.000864 | 7.874560 | 47.874560 | 22.125440 | 1 | 1st reaction step |
| 2 | 0.001555 | 6.602265 | 46.602265 | 23.397735 | 2 | |
| 3 | 0.002246 | 5.571266 | 45.571266 | 24.428734 | 3 | |
| 4 | 0.002938 | 4.727594 | 44.727594 | 25.272406 | 4 | |
| 5 | 0.003629 | 4.031746 | 44.031746 | 25.968254 | 5 | |
| 6 | 0.004666 | 3.165305 | 43.165305 | 26.834695 | 6 | |
| 7 | 0.005702 | 2.512652 | 42.512652 | 27.487348 | 7 | |
| 8 | 0.006739 | 2.015898 | 42.015898 | 27.984102 | 8 | |
| 9 | 0.007776 | 1.634842 | 41.634842 | 28.365158 | 9 | |
| 10 | 0.008813 | 1.340804 | 41.340804 | 28.659196 | 10 | |
| 11 | 0.009850 | 1.112883 | 41.112883 | 28.887117 | 11 | |
| 12 | 0.010886 | 0.935595 | 40.935595 | 29.064405 | 12 | |
| 13 | 0.011923 | 0.797321 | 40.797321 | 29.202679 | 13 | |
| 14 | 0.013478 | 0.635211 | 40.635211 | 29.364789 | 14 | |
| 15 | 0.015034 | 0.525833 | 40.525833 | 29.474167 | 15 | |
| 16 | 0.016589 | 0.451805 | 40.451805 | 29.548195 | 16 | |
| 17 | 0.018922 | 0.376490 | 40.376490 | 29.623510 | 17 | |
| 18 | 0.021254 | 0.337393 | 40.337393 | 29.662607 | 18 | |
| 19 | 0.024754 | 0.306871 | 40.306871 | 29.693129 | 19 | |
| 20 | 0.030002 | 0.293965 | 40.293965 | 29.706035 | 20 | |
| 21 | 0.037876 | 0.295437 | 40.295437 | 29.704563 | 21 | |
| 22 | 0.049685 | 0.294082 | 40.294082 | 29.705918 | 22 | |
| 23 | 0.067400 | 0.296969 | 40.296969 | 29.703031 | 23 | last reaction step |
A (now largely depleted) is the limiting reagent¶uc.diagnostics.explain_time_advance()
From time 0 to 0.000864, in 1 step of 0.000864 From time 0.000864 to 0.003629, in 4 steps of 0.000691 From time 0.003629 to 0.01192, in 8 steps of 0.00104 From time 0.01192 to 0.01659, in 3 steps of 0.00156 From time 0.01659 to 0.02125, in 2 steps of 0.00233 From time 0.02125 to 0.02475, in 1 step of 0.0035 From time 0.02475 to 0.03, in 1 step of 0.00525 From time 0.03 to 0.03788, in 1 step of 0.00787 From time 0.03788 to 0.04969, in 1 step of 0.0118 From time 0.04969 to 0.0674, in 1 step of 0.0177 (23 steps total)
uc.plot_step_sizes(show_intervals=True)
uc.plot_history(show_intervals=True)
# Verify that the reaction has reached equilibrium
uc.is_in_equilibrium()
0: A + B <-> C
Current concentrations: [A] = 0.297 ; [B] = 40.3 ; [C] = 29.7
1. Ratio of reactant/product concentrations, adjusted for reaction orders: 2.48209
Formula used: [C] / ([A][B])
2. Ratio of forward/reverse reaction rates: 2.5
Discrepancy between the two values: 0.7163 %
Reaction IS in equilibrium (within 1% tolerance)
True
Compare with the values we saw earlier for the exact solution of the equilibrium values:
{'A': 0.2948774087575341, 'B': 40.294877408757536, 'C': 29.705122591242464}
It's instructive to compare the exact values with the last few points from the simulation:
uc.get_history(tail=3)
| SYSTEM TIME | A | B | C | step | caption | |
|---|---|---|---|---|---|---|
| 21 | 0.037876 | 0.295437 | 40.295437 | 29.704563 | 21 | |
| 22 | 0.049685 | 0.294082 | 40.294082 | 29.705918 | 22 | |
| 23 | 0.067400 | 0.296969 | 40.296969 | 29.703031 | 23 | last reaction step |
The 2nd-to-last simulation point, rather than the last one, is actually closer to the exact equilibrium values.
That's because by that time the variable steps are getting so large that they introduce some error.
If we were to run the simulation longer (not shown), we'd see the variable steps continuing to grow, and then suddenly being reduced;
then continued cycles of growth and reduction ("hitting the brakes whenever getting too fast")
uc.get_diagnostics().get_decisions_data() # diagnostic data about concentration changes at every step - EVEN aborted ones
| START_TIME | Delta A | Delta B | Delta C | norm_A | norm_B | norm_C | norm_D | action | step_factor | time_step | caption | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | 0.000000 | -9.840000 | -9.840000 | 9.840000 | 3.227520e+01 | NaN | None | None | ABORT | 0.6 | 0.004000 | excessive norm value(s) |
| 1 | 0.000000 | -5.904000 | -5.904000 | 5.904000 | 1.161907e+01 | NaN | None | None | ABORT | 0.6 | 0.002400 | excessive norm value(s) |
| 2 | 0.000000 | -3.542400 | -3.542400 | 3.542400 | 4.182866e+00 | NaN | None | None | ABORT | 0.6 | 0.001440 | excessive norm value(s) |
| 3 | 0.000000 | -2.125440 | -2.125440 | 2.125440 | 1.505832e+00 | 0.212544 | None | None | OK (high) | 0.8 | 0.000864 | |
| 4 | 0.000864 | -1.272295 | -1.272295 | 1.272295 | 5.395782e-01 | 0.161570 | None | None | OK (stay) | 1.0 | 0.000691 | |
| 5 | 0.001555 | -1.030999 | -1.030999 | 1.030999 | 3.543195e-01 | 0.156158 | None | None | OK (stay) | 1.0 | 0.000691 | |
| 6 | 0.002246 | -0.843672 | -0.843672 | 0.843672 | 2.372610e-01 | 0.151433 | None | None | OK (stay) | 1.0 | 0.000691 | |
| 7 | 0.002938 | -0.695848 | -0.695848 | 0.695848 | 1.614015e-01 | 0.147189 | None | None | OK (low) | 1.5 | 0.000691 | |
| 8 | 0.003629 | -0.866441 | -0.866441 | 0.866441 | 2.502399e-01 | 0.214905 | None | None | OK (stay) | 1.0 | 0.001037 | |
| 9 | 0.004666 | -0.652653 | -0.652653 | 0.652653 | 1.419851e-01 | 0.206189 | None | None | OK (stay) | 1.0 | 0.001037 | |
| 10 | 0.005702 | -0.496755 | -0.496755 | 0.496755 | 8.225505e-02 | 0.197701 | None | None | OK (stay) | 1.0 | 0.001037 | |
| 11 | 0.006739 | -0.381056 | -0.381056 | 0.381056 | 4.840115e-02 | 0.189025 | None | None | OK (stay) | 1.0 | 0.001037 | |
| 12 | 0.007776 | -0.294038 | -0.294038 | 0.294038 | 2.881949e-02 | 0.179857 | None | None | OK (stay) | 1.0 | 0.001037 | |
| 13 | 0.008813 | -0.227921 | -0.227921 | 0.227921 | 1.731599e-02 | 0.169988 | None | None | OK (stay) | 1.0 | 0.001037 | |
| 14 | 0.009850 | -0.177288 | -0.177288 | 0.177288 | 1.047695e-02 | 0.159305 | None | None | OK (stay) | 1.0 | 0.001037 | |
| 15 | 0.010886 | -0.138275 | -0.138275 | 0.138275 | 6.373314e-03 | 0.147793 | None | None | OK (low) | 1.5 | 0.001037 | |
| 16 | 0.011923 | -0.162110 | -0.162110 | 0.162110 | 8.759877e-03 | 0.203318 | None | None | OK (stay) | 1.0 | 0.001555 | |
| 17 | 0.013478 | -0.109377 | -0.109377 | 0.109377 | 3.987793e-03 | 0.172190 | None | None | OK (stay) | 1.0 | 0.001555 | |
| 18 | 0.015034 | -0.074029 | -0.074029 | 0.074029 | 1.826757e-03 | 0.140784 | None | None | OK (low) | 1.5 | 0.001555 | |
| 19 | 0.016589 | -0.075315 | -0.075315 | 0.075315 | 1.890774e-03 | 0.166698 | None | None | OK (stay) | 1.0 | 0.002333 | |
| 20 | 0.018922 | -0.039097 | -0.039097 | 0.039097 | 5.095229e-04 | 0.103846 | None | None | OK (low) | 1.5 | 0.002333 | |
| 21 | 0.021254 | -0.030522 | -0.030522 | 0.030522 | 3.105277e-04 | 0.090464 | None | None | OK (low) | 1.5 | 0.003499 | |
| 22 | 0.024754 | -0.012906 | -0.012906 | 0.012906 | 5.551890e-05 | 0.042056 | None | None | OK (low) | 1.5 | 0.005249 | |
| 23 | 0.030002 | 0.001472 | 0.001472 | -0.001472 | 7.220164e-07 | 0.005007 | None | None | OK (low) | 1.5 | 0.007873 | |
| 24 | 0.037876 | -0.001355 | -0.001355 | 0.001355 | 6.116239e-07 | 0.004585 | None | None | OK (low) | 1.5 | 0.011810 | |
| 25 | 0.049685 | 0.002886 | 0.002886 | -0.002886 | 2.776401e-06 | 0.009814 | None | None | OK (low) | 1.5 | 0.017715 |
uc.get_diagnostics().get_rxn_data(rxn_index=0) # diagnostic run data of the requested SINGLE reaction
Reaction: A + B <-> C
| START_TIME | time_step | aborted | Delta A | Delta B | Delta C | rate | caption | |
|---|---|---|---|---|---|---|---|---|
| 0 | 0.000000 | 0.004000 | True | -9.840000 | -9.840000 | 9.840000 | 2460.000000 | aborted: excessive norm value(s) |
| 1 | 0.000000 | 0.002400 | True | -5.904000 | -5.904000 | 5.904000 | 2460.000000 | aborted: excessive norm value(s) |
| 2 | 0.000000 | 0.001440 | True | -3.542400 | -3.542400 | 3.542400 | 2460.000000 | aborted: excessive norm value(s) |
| 3 | 0.000000 | 0.000864 | False | -2.125440 | -2.125440 | 2.125440 | 2460.000000 | |
| 4 | 0.000864 | 0.000691 | False | -1.272295 | -1.272295 | 1.272295 | 1840.704596 | |
| 5 | 0.001555 | 0.000691 | False | -1.030999 | -1.030999 | 1.030999 | 1491.607041 | |
| 6 | 0.002246 | 0.000691 | False | -0.843672 | -0.843672 | 0.843672 | 1220.590807 | |
| 7 | 0.002938 | 0.000691 | False | -0.695848 | -0.695848 | 0.695848 | 1006.724671 | |
| 8 | 0.003629 | 0.001037 | False | -0.866441 | -0.866441 | 0.866441 | 835.687508 | |
| 9 | 0.004666 | 0.001037 | False | -0.652653 | -0.652653 | 0.652653 | 629.487372 | |
| 10 | 0.005702 | 0.001037 | False | -0.496755 | -0.496755 | 0.496755 | 479.122900 | |
| 11 | 0.006739 | 0.001037 | False | -0.381056 | -0.381056 | 0.381056 | 367.530575 | |
| 12 | 0.007776 | 0.001037 | False | -0.294038 | -0.294038 | 0.294038 | 283.601647 | |
| 13 | 0.008813 | 0.001037 | False | -0.227921 | -0.227921 | 0.227921 | 219.831166 | |
| 14 | 0.009850 | 0.001037 | False | -0.177288 | -0.177288 | 0.177288 | 170.994900 | |
| 15 | 0.010886 | 0.001037 | False | -0.138275 | -0.138275 | 0.138275 | 133.366974 | |
| 16 | 0.011923 | 0.001555 | False | -0.162110 | -0.162110 | 0.162110 | 104.237355 | |
| 17 | 0.013478 | 0.001555 | False | -0.109377 | -0.109377 | 0.109377 | 70.330011 | |
| 18 | 0.015034 | 0.001555 | False | -0.074029 | -0.074029 | 0.074029 | 47.600851 | |
| 19 | 0.016589 | 0.002333 | False | -0.075315 | -0.075315 | 0.075315 | 32.285157 | |
| 20 | 0.018922 | 0.002333 | False | -0.039097 | -0.039097 | 0.039097 | 16.759651 | |
| 21 | 0.021254 | 0.003499 | False | -0.030522 | -0.030522 | 0.030522 | 8.722521 | |
| 22 | 0.024754 | 0.005249 | False | -0.012906 | -0.012906 | 0.012906 | 2.458788 | |
| 23 | 0.030002 | 0.007873 | False | 0.001472 | 0.001472 | -0.001472 | -0.186932 | |
| 24 | 0.037876 | 0.011810 | False | -0.001355 | -0.001355 | 0.001355 | 0.114699 | |
| 25 | 0.049685 | 0.017715 | False | 0.002886 | 0.002886 | -0.002886 | -0.162918 |
uc.get_diagnostics().get_diagnostic_conc_data()
# Diagnostic concentration data saved during the run, regardless of how much history we requested to save
| TIME | A | B | C | caption | |
|---|---|---|---|---|---|
| 0 | 0.000000 | 10.000000 | 50.000000 | 20.000000 | Set concentration |
| 1 | 0.000864 | 7.874560 | 47.874560 | 22.125440 | |
| 2 | 0.001555 | 6.602265 | 46.602265 | 23.397735 | |
| 3 | 0.002246 | 5.571266 | 45.571266 | 24.428734 | |
| 4 | 0.002938 | 4.727594 | 44.727594 | 25.272406 | |
| 5 | 0.003629 | 4.031746 | 44.031746 | 25.968254 | |
| 6 | 0.004666 | 3.165305 | 43.165305 | 26.834695 | |
| 7 | 0.005702 | 2.512652 | 42.512652 | 27.487348 | |
| 8 | 0.006739 | 2.015898 | 42.015898 | 27.984102 | |
| 9 | 0.007776 | 1.634842 | 41.634842 | 28.365158 | |
| 10 | 0.008813 | 1.340804 | 41.340804 | 28.659196 | |
| 11 | 0.009850 | 1.112883 | 41.112883 | 28.887117 | |
| 12 | 0.010886 | 0.935595 | 40.935595 | 29.064405 | |
| 13 | 0.011923 | 0.797321 | 40.797321 | 29.202679 | |
| 14 | 0.013478 | 0.635211 | 40.635211 | 29.364789 | |
| 15 | 0.015034 | 0.525833 | 40.525833 | 29.474167 | |
| 16 | 0.016589 | 0.451805 | 40.451805 | 29.548195 | |
| 17 | 0.018922 | 0.376490 | 40.376490 | 29.623510 | |
| 18 | 0.021254 | 0.337393 | 40.337393 | 29.662607 | |
| 19 | 0.024754 | 0.306871 | 40.306871 | 29.693129 | |
| 20 | 0.030002 | 0.293965 | 40.293965 | 29.706035 | |
| 21 | 0.037876 | 0.295437 | 40.295437 | 29.704563 | |
| 22 | 0.049685 | 0.294082 | 40.294082 | 29.705918 | |
| 23 | 0.067400 | 0.296969 | 40.296969 | 29.703031 |