A down-regulates B ,¶A + 2 B <-> Y (mostly forward)¶1st-order kinetics.
If [A] is low and [B] is high, then [B] remains high. If [A] goes high, [B] goes low. However, at that point, A can no longer bring B up to any substantial extent.
See also 1D/reactions/down_regulation_1
LAST REVISED: May 23, 2023
import set_path # Importing this module will add the project's home directory to sys.path
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 'down_regulate_2.log.htm'
# Initialize the system
chem_data = chem(names=["A", "B", "Y"])
# Reaction A + 2 B <-> Y , with 1st-order kinetics for all species
chem_data.add_reaction(reactants=[("A") , (2, "B")], products=[("Y")],
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 + 2 B <-> Y (kF = 8 / kR = 2 / Delta_G = -3,436.56 / K = 4) | 1st order in all reactants & products [GRAPHIC ELEMENT SENT TO LOG FILE `down_regulate_2.log.htm`]
dynamics = ReactionDynamics(reaction_data=chem_data)
dynamics.set_conc(conc={"A": 5., "B": 100., "Y": 0.},
snapshot=True) # A is scarce, B is plentiful, Y is absent
dynamics.describe_state()
SYSTEM STATE at Time t = 0: 3 species: Species 0 (A). Conc: 5.0 Species 1 (B). Conc: 100.0 Species 2 (Y). Conc: 0.0
# All of these settings are currently close to the default values... but subject to change; set for repeatability
dynamics.set_thresholds(norm="norm_A", low=0.5, high=1.0, abort=1.44)
dynamics.set_thresholds(norm="norm_B", low=0.2, high=0.5, abort=1.5)
dynamics.set_step_factors(upshift=1.4, downshift=0.5, abort=0.5)
dynamics.set_error_step_factor(0.333)
dynamics.single_compartment_react(initial_step=0.0005, reaction_duration=0.015,
variable_steps=True, explain_variable_steps=False)
INFO: the tentative time step (0.0005) leads to a least one norm value > its ABORT threshold:
-> will backtrack, and re-do step with a SMALLER delta time, multiplied by 0.5 (set to 0.00025) [Step started at t=0, and will rewind there]
28 total step(s) taken
A, as the scarse limiting reagent, stops the reaction.
When A is low, B is also low.
dynamics.plot_curves(colors=['red', 'darkorange', 'green'],
title="Changes in concentrations (reaction A + 2 B <-> Y)")
dynamics.get_history()
| SYSTEM TIME | A | B | Y | caption | |
|---|---|---|---|---|---|
| 0 | 0.000000 | 5.000000 | 100.000000 | 0.000000 | Initial state |
| 1 | 0.000250 | 4.000000 | 98.000000 | 1.000000 | |
| 2 | 0.000500 | 3.216500 | 96.433000 | 1.783500 | |
| 3 | 0.000625 | 2.906769 | 95.813538 | 2.093231 | |
| 4 | 0.000800 | 2.517591 | 95.035182 | 2.482409 | |
| 5 | 0.001045 | 2.049858 | 94.099716 | 2.950142 | |
| 6 | 0.001388 | 1.522589 | 93.045178 | 3.477411 | |
| 7 | 0.001731 | 1.136233 | 92.272466 | 3.863767 | |
| 8 | 0.002074 | 0.851194 | 91.702389 | 4.148806 | |
| 9 | 0.002417 | 0.639853 | 91.279707 | 4.360147 | |
| 10 | 0.002760 | 0.482579 | 90.965159 | 4.517421 | |
| 11 | 0.003103 | 0.365222 | 90.730445 | 4.634778 | |
| 12 | 0.003446 | 0.277475 | 90.554949 | 4.722525 | |
| 13 | 0.003789 | 0.211767 | 90.423533 | 4.788233 | |
| 14 | 0.004132 | 0.162507 | 90.325015 | 4.837493 | |
| 15 | 0.004475 | 0.125548 | 90.251096 | 4.874452 | |
| 16 | 0.004818 | 0.097800 | 90.195600 | 4.902200 | |
| 17 | 0.005161 | 0.076958 | 90.153916 | 4.923042 | |
| 18 | 0.005504 | 0.061297 | 90.122594 | 4.938703 | |
| 19 | 0.005847 | 0.049526 | 90.099053 | 4.950474 | |
| 20 | 0.006327 | 0.037139 | 90.074277 | 4.962861 | |
| 21 | 0.006807 | 0.029054 | 90.058108 | 4.970946 | |
| 22 | 0.007288 | 0.023776 | 90.047553 | 4.976224 | |
| 23 | 0.007960 | 0.018952 | 90.037905 | 4.981048 | |
| 24 | 0.008632 | 0.016472 | 90.032944 | 4.983528 | |
| 25 | 0.009573 | 0.014686 | 90.029373 | 4.985314 | |
| 26 | 0.010891 | 0.013887 | 90.027773 | 4.986113 | |
| 27 | 0.012736 | 0.013833 | 90.027665 | 4.986167 | |
| 28 | 0.015318 | 0.013858 | 90.027716 | 4.986142 |
dynamics.explain_time_advance(use_history=True)
From time 0 to 0.0005, in 2 steps of 0.00025 From time 0.0005 to 0.000625, in 1 step of 0.000125 From time 0.000625 to 0.0008, in 1 step of 0.000175 From time 0.0008 to 0.001045, in 1 step of 0.000245 From time 0.001045 to 0.005847, in 14 steps of 0.000343 From time 0.005847 to 0.007288, in 3 steps of 0.00048 From time 0.007288 to 0.008632, in 2 steps of 0.000672 From time 0.008632 to 0.009573, in 1 step of 0.000941 From time 0.009573 to 0.01089, in 1 step of 0.00132 From time 0.01089 to 0.01274, in 1 step of 0.00184 From time 0.01274 to 0.01532, in 1 step of 0.00258 (28 steps total)
# Verify that the reaction has reached equilibrium
dynamics.is_in_equilibrium()
A + 2 B <-> Y
Final concentrations: [Y] = 4.986 ; [A] = 0.01386 ; [B] = 90.03
1. Ratio of reactant/product concentrations, adjusted for reaction orders: 3.99663
Formula used: [Y] / ([A][B])
2. Ratio of forward/reverse reaction rates: 4.0
Discrepancy between the two values: 0.08418 %
Reaction IS in equilibrium (within 1% tolerance)
True
dynamics.set_chem_conc(species_name="A", conc=40., snapshot=True)
dynamics.describe_state()
SYSTEM STATE at Time t = 0.015318388: 3 species: Species 0 (A). Conc: 40.0 Species 1 (B). Conc: 90.02771559198881 Species 2 (Y). Conc: 4.98614220400561
dynamics.history.get_dataframe(tail=5)
| SYSTEM TIME | A | B | Y | caption | |
|---|---|---|---|---|---|
| 25 | 0.009573 | 0.014686 | 90.029373 | 4.985314 | |
| 26 | 0.010891 | 0.013887 | 90.027773 | 4.986113 | |
| 27 | 0.012736 | 0.013833 | 90.027665 | 4.986167 | |
| 28 | 0.015318 | 0.013858 | 90.027716 | 4.986142 | |
| 29 | 0.015318 | 40.000000 | 90.027716 | 4.986142 | Set concentration of `A` |
dynamics.single_compartment_react(initial_step=0.0005, target_end_time=0.055,
variable_steps=True, explain_variable_steps=False)
INFO: the tentative time step (0.0005) leads to a least one norm value > its ABORT threshold:
-> will backtrack, and re-do step with a SMALLER delta time, multiplied by 0.5 (set to 0.00025) [Step started at t=0.015318, and will rewind there]
INFO: the tentative time step (0.00025) leads to a least one norm value > its ABORT threshold:
-> will backtrack, and re-do step with a SMALLER delta time, multiplied by 0.5 (set to 0.000125) [Step started at t=0.015318, and will rewind there]
INFO: the tentative time step (0.000125) leads to a least one norm value > its ABORT threshold:
-> will backtrack, and re-do step with a SMALLER delta time, multiplied by 0.5 (set to 6.25e-05) [Step started at t=0.015318, and will rewind there]
INFO: the tentative time step (6.25e-05) leads to a least one norm value > its ABORT threshold:
-> will backtrack, and re-do step with a SMALLER delta time, multiplied by 0.5 (set to 3.125e-05) [Step started at t=0.015318, and will rewind there]
47 total step(s) taken
dynamics.plot_curves(colors=['red', 'darkorange', 'green'],
title="Changes in concentrations (reaction A + 2 B <-> Y)")
A, still the limiting reagent, is again stopping the reaction.
The (transiently) high value of [A] led to a high value of [B]
dynamics.get_history()
| SYSTEM TIME | A | B | Y | caption | |
|---|---|---|---|---|---|
| 0 | 0.000000 | 5.000000 | 100.000000 | 0.000000 | Initial state |
| 1 | 0.000250 | 4.000000 | 98.000000 | 1.000000 | |
| 2 | 0.000500 | 3.216500 | 96.433000 | 1.783500 | |
| 3 | 0.000625 | 2.906769 | 95.813538 | 2.093231 | |
| 4 | 0.000800 | 2.517591 | 95.035182 | 2.482409 | |
| ... | ... | ... | ... | ... | ... |
| 72 | 0.034954 | 1.383073 | 12.793862 | 43.603069 | |
| 73 | 0.038427 | 1.194334 | 12.416383 | 43.791809 | |
| 74 | 0.043288 | 1.043380 | 12.114476 | 43.942762 | |
| 75 | 0.050094 | 0.953305 | 11.934325 | 44.032838 | |
| 76 | 0.059623 | 0.925189 | 11.878093 | 44.060953 |
77 rows × 5 columns
# Verify that the reaction has reached equilibrium
dynamics.is_in_equilibrium()
A + 2 B <-> Y
Final concentrations: [Y] = 44.06 ; [A] = 0.9252 ; [B] = 11.88
1. Ratio of reactant/product concentrations, adjusted for reaction orders: 4.00938
Formula used: [Y] / ([A][B])
2. Ratio of forward/reverse reaction rates: 4.0
Discrepancy between the two values: 0.2344 %
Reaction IS in equilibrium (within 1% tolerance)
True
dynamics.set_chem_conc(species_name="A", conc=30., snapshot=True)
dynamics.describe_state()
SYSTEM STATE at Time t = 0.059622836: 3 species: Species 0 (A). Conc: 30.0 Species 1 (B). Conc: 11.878093044952234 Species 2 (Y). Conc: 44.06095347752391
dynamics.history.get_dataframe(tail=5)
| SYSTEM TIME | A | B | Y | caption | |
|---|---|---|---|---|---|
| 73 | 0.038427 | 1.194334 | 12.416383 | 43.791809 | |
| 74 | 0.043288 | 1.043380 | 12.114476 | 43.942762 | |
| 75 | 0.050094 | 0.953305 | 11.934325 | 44.032838 | |
| 76 | 0.059623 | 0.925189 | 11.878093 | 44.060953 | |
| 77 | 0.059623 | 30.000000 | 11.878093 | 44.060953 | Set concentration of `A` |
dynamics.single_compartment_react(initial_step=0.001, target_end_time=0.09,
variable_steps=True, explain_variable_steps=False)
INFO: the tentative time step (0.001) leads to a least one norm value > its ABORT threshold:
-> will backtrack, and re-do step with a SMALLER delta time, multiplied by 0.5 (set to 0.0005) [Step started at t=0.059623, and will rewind there]
19 total step(s) taken
dynamics.plot_curves(colors=['red', 'darkorange', 'green'],
title="Changes in concentrations (reaction A + 2 B <-> Y)")
dynamics.get_history()
| SYSTEM TIME | A | B | Y | caption | |
|---|---|---|---|---|---|
| 0 | 0.000000 | 5.000000 | 100.000000 | 0.000000 | Initial state |
| 1 | 0.000250 | 4.000000 | 98.000000 | 1.000000 | |
| 2 | 0.000500 | 3.216500 | 96.433000 | 1.783500 | |
| 3 | 0.000625 | 2.906769 | 95.813538 | 2.093231 | |
| 4 | 0.000800 | 2.517591 | 95.035182 | 2.482409 | |
| ... | ... | ... | ... | ... | ... |
| 92 | 0.072916 | 24.315963 | 0.510018 | 49.744991 | |
| 93 | 0.076605 | 24.316986 | 0.512064 | 49.743968 | |
| 94 | 0.081771 | 24.316330 | 0.510753 | 49.744624 | |
| 95 | 0.089002 | 24.317286 | 0.512664 | 49.743668 | |
| 96 | 0.099126 | 24.314800 | 0.507693 | 49.746154 |
97 rows × 5 columns
# Verify that the reaction has reached equilibrium
dynamics.is_in_equilibrium()
A + 2 B <-> Y
Final concentrations: [Y] = 49.75 ; [A] = 24.31 ; [B] = 0.5077
1. Ratio of reactant/product concentrations, adjusted for reaction orders: 4.02984
Formula used: [Y] / ([A][B])
2. Ratio of forward/reverse reaction rates: 4.0
Discrepancy between the two values: 0.746 %
Reaction IS in equilibrium (within 1% tolerance)
True
A, again the scarse limiting reagent, stops the reaction yet again
dynamics.set_chem_conc(species_name="A", conc=0., snapshot=True) # Completely eliminate A
dynamics.describe_state()
SYSTEM STATE at Time t = 0.099125931: 3 species: Species 0 (A). Conc: 0.0 Species 1 (B). Conc: 0.5076929235350717 Species 2 (Y). Conc: 49.74615353823248
dynamics.single_compartment_react(initial_step=0.001, target_end_time=0.16,
variable_steps=True, explain_variable_steps=False)
19 total step(s) taken
dynamics.plot_curves(colors=['red', 'darkorange', 'green'],
title="Changes in concentrations (reaction A + 2 B <-> Y)")
dynamics.get_history()
| SYSTEM TIME | A | B | Y | caption | |
|---|---|---|---|---|---|
| 0 | 0.000000 | 5.000000 | 100.000000 | 0.000000 | Initial state |
| 1 | 0.000250 | 4.000000 | 98.000000 | 1.000000 | |
| 2 | 0.000500 | 3.216500 | 96.433000 | 1.783500 | |
| 3 | 0.000625 | 2.906769 | 95.813538 | 2.093231 | |
| 4 | 0.000800 | 2.517591 | 95.035182 | 2.482409 | |
| ... | ... | ... | ... | ... | ... |
| 112 | 0.124564 | 1.876146 | 4.259985 | 47.870007 | |
| 113 | 0.131943 | 2.110805 | 4.729304 | 47.635348 | |
| 114 | 0.142274 | 2.269994 | 5.047682 | 47.476159 | |
| 115 | 0.156737 | 2.317528 | 5.142749 | 47.428625 | |
| 116 | 0.176984 | 2.307597 | 5.122887 | 47.438557 |
117 rows × 5 columns
# Verify that the reaction has reached equilibrium
dynamics.is_in_equilibrium()
A + 2 B <-> Y
Final concentrations: [Y] = 47.44 ; [A] = 2.308 ; [B] = 5.123
1. Ratio of reactant/product concentrations, adjusted for reaction orders: 4.01289
Formula used: [Y] / ([A][B])
2. Ratio of forward/reverse reaction rates: 4.0
Discrepancy between the two values: 0.3221 %
Reaction IS in equilibrium (within 1% tolerance)
True
Le Chatelier's principle in action: "A change in one of the variables that describe a system at equilibrium produces a shift in the position of the equilibrium that counteracts the effect of this change."