A up-regulates B ,¶A + X <-> 2B (mostly forward), where X is plentiful¶1st-order kinetics.
If [A] is low, [B] remains low, too. Then, if [A] goes high, then so does [B]. However, at that point, A can no longer bring B down to any substantial extent.
See also the experiment "1D/reactions/up_regulation_1"
LAST REVISED: Feb. 5, 2023
# Extend the sys.path variable, to contain the project's root directory
import set_path
set_path.add_ancestor_dir_to_syspath(2) # The number of levels to go up
# to reach the project's home, from the folder containing this notebook
Added 'D:\Docs\- MY CODE\BioSimulations\life123-Win7' to sys.path
from experiments.get_notebook_info import get_notebook_basename
from src.modules.reactions.reaction_data import ReactionData as chem
from src.modules.reactions.reaction_dynamics import ReactionDynamics
import numpy as np
import plotly.express as px
from src.modules.visualization.graphic_log import GraphicLog
# 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_1"],
extra_js="https://cdnjs.cloudflare.com/ajax/libs/cytoscape/3.21.2/cytoscape.umd.js")
-> Output will be LOGGED into the file 'up_regulate_1.log.htm'
# Initialize the system
chem_data = chem(names=["A", "X", "B"])
# Reaction A + X <-> 2B , with 1st-order kinetics for all species
chem_data.add_reaction(reactants=[("A") , ("X")], products=[(2, "B")],
forward_rate=8., reverse_rate=2.)
chem_data.describe_reactions()
# Send the plot of the reaction network to the HTML log file
graph_data = chem_data.prepare_graph_network()
GraphicLog.export_plot(graph_data, "vue_cytoscape_1")
Number of reactions: 1 (at temp. 25 C) 0: A + X <-> 2 B (kF = 8 / kR = 2 / Delta_G = -3,436.56 / K = 4) | 1st order in all reactants & products [GRAPHIC ELEMENT SENT TO LOG FILE `up_regulate_1.log.htm`]
dynamics = ReactionDynamics(reaction_data=chem_data)
dynamics.set_conc(conc={"A": 5., "X": 100., "B": 0.},
snapshot=True) # A is scarce, X is plentiful, B is absent
dynamics.describe_state()
SYSTEM STATE at Time t = 0: 3 species: Species 0 (A). Conc: 5.0 Species 1 (X). Conc: 100.0 Species 2 (B). Conc: 0.0
dynamics.set_diagnostics() # To save diagnostic information about the call to single_compartment_react()
dynamics.single_compartment_react(time_step=0.0005, stop_time=0.015,
dynamic_substeps=2, rel_fast_threshold=15)
df = dynamics.get_history()
df
single_compartment_react(): setting abs_fast_threshold to 300.0 30 total step(s) taken
| SYSTEM TIME | A | X | B | caption | |
|---|---|---|---|---|---|
| 0 | 0.00000 | 5.000000 | 100.000000 | 0.000000 | Initial state |
| 1 | 0.00025 | 4.000000 | 99.000000 | 2.000000 | Interm. step, due to the fast rxns: [0] |
| 2 | 0.00050 | 3.209000 | 98.209000 | 3.582000 | |
| 3 | 0.00075 | 2.580486 | 97.580486 | 4.839029 | Interm. step, due to the fast rxns: [0] |
| 4 | 0.00100 | 2.079295 | 97.079295 | 5.841410 | |
| 5 | 0.00125 | 1.678503 | 96.678503 | 6.642994 | Interm. step, due to the fast rxns: [0] |
| 6 | 0.00150 | 1.357274 | 96.357274 | 7.285452 | |
| 7 | 0.00175 | 1.099350 | 96.099350 | 7.801299 | Interm. step, due to the fast rxns: [0] |
| 8 | 0.00200 | 0.891957 | 95.891957 | 8.216086 | |
| 9 | 0.00225 | 0.725002 | 95.725002 | 8.549996 | Interm. step, due to the fast rxns: [0] |
| 10 | 0.00250 | 0.590476 | 95.590476 | 8.819049 | |
| 11 | 0.00275 | 0.481997 | 95.481997 | 9.036005 | Interm. step, due to the fast rxns: [0] |
| 12 | 0.00300 | 0.394471 | 95.394471 | 9.211058 | |
| 13 | 0.00325 | 0.323816 | 95.323816 | 9.352368 | Interm. step, due to the fast rxns: [0] |
| 14 | 0.00350 | 0.266757 | 95.266757 | 9.466485 | |
| 15 | 0.00375 | 0.220664 | 95.220664 | 9.558671 | Interm. step, due to the fast rxns: [0] |
| 16 | 0.00400 | 0.183420 | 95.183420 | 9.633160 | |
| 17 | 0.00450 | 0.123219 | 95.123219 | 9.753562 | |
| 18 | 0.00500 | 0.086089 | 95.086089 | 9.827823 | |
| 19 | 0.00550 | 0.063173 | 95.063173 | 9.873654 | |
| 20 | 0.00600 | 0.049025 | 95.049025 | 9.901950 | |
| 21 | 0.00650 | 0.040288 | 95.040288 | 9.919424 | |
| 22 | 0.00700 | 0.034891 | 95.034891 | 9.930217 | |
| 23 | 0.00750 | 0.031558 | 95.031558 | 9.936884 | |
| 24 | 0.00800 | 0.029499 | 95.029499 | 9.941002 | |
| 25 | 0.00850 | 0.028227 | 95.028227 | 9.943546 | |
| 26 | 0.00900 | 0.027441 | 95.027441 | 9.945118 | |
| 27 | 0.00950 | 0.026956 | 95.026956 | 9.946089 | |
| 28 | 0.01000 | 0.026656 | 95.026656 | 9.946689 | |
| 29 | 0.01050 | 0.026470 | 95.026470 | 9.947059 | |
| 30 | 0.01100 | 0.026356 | 95.026356 | 9.947288 | |
| 31 | 0.01150 | 0.026285 | 95.026285 | 9.947430 | |
| 32 | 0.01200 | 0.026241 | 95.026241 | 9.947517 | |
| 33 | 0.01250 | 0.026214 | 95.026214 | 9.947571 | |
| 34 | 0.01300 | 0.026198 | 95.026198 | 9.947604 | |
| 35 | 0.01350 | 0.026187 | 95.026187 | 9.947625 | |
| 36 | 0.01400 | 0.026181 | 95.026181 | 9.947638 | |
| 37 | 0.01450 | 0.026177 | 95.026177 | 9.947646 | |
| 38 | 0.01500 | 0.026175 | 95.026175 | 9.947650 |
A, as the scarse limiting reagent, stops the reaction.
When A is low, B is also low.
dynamics.explain_time_advance()
From time 0 to 0.004, in 16 substeps of 0.00025 (each 1/2 of full step) From time 0.004 to 0.015, in 22 FULL steps of 0.0005
# Verify that the reaction has reached equilibrium
dynamics.is_in_equilibrium()
A + X <-> 2 B
Final concentrations: [B] = 9.948 ; [A] = 0.02617 ; [X] = 95.03
1. Ratio of reactant/product concentrations, adjusted for reaction orders: 3.9994
Formula used: [B] / ([A][X])
2. Ratio of forward/reverse reaction rates: 4.0
Discrepancy between the two values: 0.01508 %
Reaction IS in equilibrium (within 1% tolerance)
True
dynamics.plot_curves(colors=['red', 'darkorange', 'green'])
dynamics.set_chem_conc(species_name="A", conc=50., snapshot=True)
dynamics.describe_state()
SYSTEM STATE at Time t = 0.015: 3 species: Species 0 (A). Conc: 50.0 Species 1 (X). Conc: 95.02617476453239 Species 2 (B). Conc: 9.947650470935224
dynamics.get_history(tail=5)
| SYSTEM TIME | A | X | B | caption | |
|---|---|---|---|---|---|
| 35 | 0.0135 | 0.026187 | 95.026187 | 9.947625 | |
| 36 | 0.0140 | 0.026181 | 95.026181 | 9.947638 | |
| 37 | 0.0145 | 0.026177 | 95.026177 | 9.947646 | |
| 38 | 0.0150 | 0.026175 | 95.026175 | 9.947650 | |
| 39 | 0.0150 | 50.000000 | 95.026175 | 9.947650 | Set concentration of `A` |
dynamics.single_compartment_react(time_step=0.0005, stop_time=0.035,
dynamic_substeps=2, rel_fast_threshold=15)
df = dynamics.get_history()
df
single_compartment_react(): setting abs_fast_threshold to 300.0 40 total step(s) taken
| SYSTEM TIME | A | X | B | caption | |
|---|---|---|---|---|---|
| 0 | 0.00000 | 5.000000 | 100.000000 | 0.000000 | Initial state |
| 1 | 0.00025 | 4.000000 | 99.000000 | 2.000000 | Interm. step, due to the fast rxns: [0] |
| 2 | 0.00050 | 3.209000 | 98.209000 | 3.582000 | |
| 3 | 0.00075 | 2.580486 | 97.580486 | 4.839029 | Interm. step, due to the fast rxns: [0] |
| 4 | 0.00100 | 2.079295 | 97.079295 | 5.841410 | |
| ... | ... | ... | ... | ... | ... |
| 97 | 0.03300 | 0.612358 | 45.638533 | 108.722934 | |
| 98 | 0.03350 | 0.609293 | 45.635467 | 108.729065 | |
| 99 | 0.03400 | 0.606800 | 45.632975 | 108.734050 | |
| 100 | 0.03450 | 0.604774 | 45.630949 | 108.738103 | |
| 101 | 0.03500 | 0.603126 | 45.629301 | 108.741398 |
102 rows × 5 columns
dynamics.explain_time_advance()
From time 0 to 0.004, in 16 substeps of 0.00025 (each 1/2 of full step) From time 0.004 to 0.015, in 22 FULL steps of 0.0005 From time 0.015 to 0.026, in 44 substeps of 0.00025 (each 1/2 of full step) From time 0.026 to 0.035, in 18 FULL steps of 0.0005
# Verify that the reaction has reached equilibrium
dynamics.is_in_equilibrium(tolerance=2)
A + X <-> 2 B
Final concentrations: [B] = 108.7 ; [A] = 0.6031 ; [X] = 45.63
1. Ratio of reactant/product concentrations, adjusted for reaction orders: 3.95133
Formula used: [B] / ([A][X])
2. Ratio of forward/reverse reaction rates: 4.0
Discrepancy between the two values: 1.217 %
Reaction IS in equilibrium (within 2% tolerance)
True
dynamics.plot_curves(colors=['red', 'darkorange', 'green'])
A, still the limiting reagent, is again stopping the reaction.
The (transiently) high value of [A] led to a high value of [B]
dynamics.set_chem_conc(species_name="A", conc=30., snapshot=True)
dynamics.describe_state()
SYSTEM STATE at Time t = 0.035: 3 species: Species 0 (A). Conc: 30.0 Species 1 (X). Conc: 45.62930114786792 Species 2 (B). Conc: 108.74139770426417
dynamics.get_history(tail=5)
| SYSTEM TIME | A | X | B | caption | |
|---|---|---|---|---|---|
| 98 | 0.0335 | 0.609293 | 45.635467 | 108.729065 | |
| 99 | 0.0340 | 0.606800 | 45.632975 | 108.734050 | |
| 100 | 0.0345 | 0.604774 | 45.630949 | 108.738103 | |
| 101 | 0.0350 | 0.603126 | 45.629301 | 108.741398 | |
| 102 | 0.0350 | 30.000000 | 45.629301 | 108.741398 | Set concentration of `A` |
dynamics.single_compartment_react(time_step=0.0005, stop_time=0.070,
dynamic_substeps=2, rel_fast_threshold=15)
df = dynamics.history.get()
df
single_compartment_react(): setting abs_fast_threshold to 300.0 70 total step(s) taken
| SYSTEM TIME | A | X | B | caption | |
|---|---|---|---|---|---|
| 0 | 0.00000 | 5.000000 | 100.000000 | 0.000000 | Initial state |
| 1 | 0.00025 | 4.000000 | 99.000000 | 2.000000 | Interm. step, due to the fast rxns: [0] |
| 2 | 0.00050 | 3.209000 | 98.209000 | 3.582000 | |
| 3 | 0.00075 | 2.580486 | 97.580486 | 4.839029 | Interm. step, due to the fast rxns: [0] |
| 4 | 0.00100 | 2.079295 | 97.079295 | 5.841410 | |
| ... | ... | ... | ... | ... | ... |
| 200 | 0.06800 | 2.330535 | 17.959837 | 164.080327 | |
| 201 | 0.06850 | 2.327192 | 17.956493 | 164.087015 | |
| 202 | 0.06900 | 2.324126 | 17.953427 | 164.093146 | |
| 203 | 0.06950 | 2.321315 | 17.950616 | 164.098768 | |
| 204 | 0.07000 | 2.318737 | 17.948039 | 164.103923 |
205 rows × 5 columns
dynamics.explain_time_advance()
From time 0 to 0.004, in 16 substeps of 0.00025 (each 1/2 of full step) From time 0.004 to 0.015, in 22 FULL steps of 0.0005 From time 0.015 to 0.026, in 44 substeps of 0.00025 (each 1/2 of full step) From time 0.026 to 0.035, in 18 FULL steps of 0.0005 From time 0.035 to 0.051, in 64 substeps of 0.00025 (each 1/2 of full step) From time 0.051 to 0.07, in 38 FULL steps of 0.0005
# Verify that the reaction has reached equilibrium
dynamics.is_in_equilibrium(tolerance=2)
A + X <-> 2 B
Final concentrations: [B] = 164.1 ; [A] = 2.319 ; [X] = 17.95
1. Ratio of reactant/product concentrations, adjusted for reaction orders: 3.94321
Formula used: [B] / ([A][X])
2. Ratio of forward/reverse reaction rates: 4.0
Discrepancy between the two values: 1.42 %
Reaction IS in equilibrium (within 2% tolerance)
True
dynamics.plot_curves(colors=['red', 'darkorange', 'green'])
A, again the scarce limiting reagent, stops the reaction yet again.
And, again, the (transiently) high value of [A] up-regulated [B]
Notes:
A can up-regulate B, but it cannot bring it down.
X will soon need to be replenished, if A is to continue being the limiting reagent.
# Look up the some of the intersections of the [A] and [B] curves
dynamics.curve_intersection(t_start=0, t_end=0.01, var1="A", var2="B")
Min abs distance found at row: 2
(0.0004607037505267594, 3.333333333333333)
dynamics.curve_intersection(t_start=0.0151, t_end=0.02, var1="A", var2="B")
Min abs distance found at row: 41
(0.01538932900514749, 36.64921682364508)
Note: the curve_intersection() function currently cannot location the intersection at t=0.015 (the vertical rise in the red line); this issue will get addressed in future versions...