As in experiment membranes_racing_condition_1, a racing condition between diffusion and reaction.
Like before, the "window of opportunity to escape" closes fast!
This time, however, the initial concentration of A is outside the compartment, and the reaction is an enzyme-catalyed unimolecular A + E -> B + E . The enzyme E cannot cross membranes.
If, metaphorically speaking, we think of A as a "traveler", then:
A diffuses so slowly that, in its journey across the compartment, it "falls under the spell of the enzyme" (gets converted into a form B that cannot cross membranes), and thus "can never leave"...¶A diffuses so fast that it "stays a step ahead of trouble", and is largely out of the compartment prior to getting entangled into it by the "magic spell" (reaction) that would have "trapped it into the island"¶Recommended background:
1D/reaction_diffusion/membranes_racing_condition_1LAST_REVISED = "Sep. 29, 2025"
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
from life123 import BioSim1D, ChemData, ReactionRegistry, ReactionEnzyme, PlotlyHelper, check_version
check_version(LIFE123_VERSION)
OK
A) in both scenarios¶# Initialize the chemical data.
# The enzyme `E`, typically a large molecule, is given a relatively sall diffusion rate (not too important,
# because of our initial condition later, of `E` already uniformly diffused)
# We'll let the simulator estimate a diffusion rate constant for `EU` (so, passing None for now)
chem_data = ChemData( names=["U", "L", "E", "EU", "P", "UP"],
diffusion_rates=[200., 250., 80., None, 120., 90.], # The diffusion rate of `U` will later be increased in scenario 2
plot_colors=["red", "green", "violet", "darkturquoise", "pink", "black"])
rxns = ReactionRegistry(chem_data=chem_data)
# Enzymatic reaction A + E -> B + E
r = ReactionEnzyme(substrate="U", product="L", enzyme="E",
k1_F=10., k1_R=2., k2_F=50.)
rxns.register_reaction(r)
rxns.add_reaction(reactants=["U", "P"], products="UP",
kF=20., kR=1.)
rxns.describe_reactions()
register_reaction() INFO: diffusion rate for the reaction intermediates (`EU`), not yet specified, roughly estimated as 72.0
Number of reactions: 2
0: E + U <-> EU -> E + L (Enzymatic reaction) (k1_F = 10 / k1_R = 2 / k2_F = 50 / kM = 5.2 / kcat = 50)
1: U + P <-> UP (Elementary Synthesis reaction) (kF = 20 / kR = 1 / K = 20)
Chemicals involved in the above reactions (not counting enzymes): {"U" (red), "L" (green), "EU" (darkturquoise), "P" (pink), "UP" (black)}
Enzymes involved in the above reactions:
"E" (violet)
chem_data.all_chemicals()
| name | label | diff rate | plot_color | |
|---|---|---|---|---|
| 0 | U | U | 200.0 | red |
| 1 | L | L | 250.0 | green |
| 2 | E | E | 80.0 | violet |
| 3 | EU | EU | 72.0 | darkturquoise |
| 4 | P | P | 120.0 | pink |
| 5 | UP | UP | 90.0 | black |
U diffuses slowly, relatively to the Enzymatic reaction U + E -> L + E¶bio = BioSim1D(n_bins=30, chem_data=chem_data, reactions=rxns)
bio.membranes().set_membranes(membranes=[ (11, 21) ])
bio.membranes().membrane_list
[(11, 21)]
# We'll use 1/2 of the diffusion rate of `A` as its membrane permeability (by passive transport)
# The conversion product `B` and the enzyne `E`, by constrast, keep their default 0 permeability (i.e., can't cross membranes)
bio.membranes().change_permeability("U", 50.)
bio.membranes().show_permeability() # Values not shown mean 0
{'U': 50.0}
# Turning into into a function, for convenience of later re-using
def initialize_initial_concs():
# Set up the initial bell-shape concentration of `U` ("Ulysses"),
# with a narrow peak close to the left end of the system,
# centered at bin 5
bio.inject_bell_curve(chem_label="U", center_bin=5, sd=0.05, max_amplitude=200., bias=0., clip=(0,9))
# The enzyme `E`, by contrast, is uniformly distributed within the membranes of the 1st (and only) compartment
bio.set_compartment_uniform_concentration(compartment_id=0, chem_label="E", conc=15.)
# Set up the initial bell-shape concentration of `P` ("Penelope"),
# with a narrow peak close to the right end of the system, at bin 25
bio.inject_bell_curve(chem_label="P", center_bin=25, sd=0.05, max_amplitude=30., bias=0., clip=(21,29))
#for bin in range(21, 30):
#bio.set_bin_conc(bin_address=bin, conc=10, chem_label="P")
initialize_initial_concs()
# Show as heatmap (including the membranes, shown in brown)
bio.system_heatmaps(title_prefix="Initial strong, localized transient of chemical `U` (membranes shown in brown)")
U is localized to the left of the compartment that spans the space between bins 10 and 20¶The enzyme E is uniformly localized in that compartment.
L, UP and the reaction intermerdiate EU are not present anywhere.
P is localized to the right of the compartment (but, unlike U can't cross membranes)
# Visualize the system state so far
bio.visualize_system(title_prefix=["Initial strong, localized transient of chemical `U` (membranes shown in brown).",
"Notice that the enzyme `E` is found inside the compartment"])
df = bio.describe_state()
df
SYSTEM STATE at Time t = 0: 30 bins and 6 chemical species Membranes present: [(11, 21)]
| Species | Diff rate | Bin 0 | Bin 1 | Bin 2 | Bin 3 | Bin 4 | Bin 5 | Bin 6 | Bin 7 | ... | Bin 20 | Bin 21 | Bin 22 | Bin 23 | Bin 24 | Bin 25 | Bin 26 | Bin 27 | Bin 28 | Bin 29 | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | U | 200.0 | 0.523622 | 4.451866 | 23.523695 | 77.251695 | 157.670157 | 200.0 | 157.670157 | 77.251695 | ... | 0.0 | 0.00000 | 0.000000 | 0.000000 | 0.000000 | 0.0 | 0.000000 | 0.000000 | 0.000000 | 0.00000 |
| 1 | L | 250.0 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.0 | 0.000000 | 0.000000 | ... | 0.0 | 0.00000 | 0.000000 | 0.000000 | 0.000000 | 0.0 | 0.000000 | 0.000000 | 0.000000 | 0.00000 |
| 2 | E | 80.0 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.0 | 0.000000 | 0.000000 | ... | 15.0 | 0.00000 | 0.000000 | 0.000000 | 0.000000 | 0.0 | 0.000000 | 0.000000 | 0.000000 | 0.00000 |
| 3 | EU | 72.0 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.0 | 0.000000 | 0.000000 | ... | 0.0 | 0.00000 | 0.000000 | 0.000000 | 0.000000 | 0.0 | 0.000000 | 0.000000 | 0.000000 | 0.00000 |
| 4 | P | 120.0 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.0 | 0.000000 | 0.000000 | ... | 0.0 | 0.66778 | 3.528554 | 11.587754 | 23.650524 | 30.0 | 23.650524 | 11.587754 | 3.528554 | 0.66778 |
| 5 | UP | 90.0 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.0 | 0.000000 | 0.000000 | ... | 0.0 | 0.00000 | 0.000000 | 0.000000 | 0.000000 | 0.0 | 0.000000 | 0.000000 | 0.000000 | 0.00000 |
6 rows × 32 columns
df[df.columns[4:24]] # Zoom in where the action is
| Bin 2 | Bin 3 | Bin 4 | Bin 5 | Bin 6 | Bin 7 | Bin 8 | Bin 9 | Bin 10 | Bin 11 | Bin 12 | Bin 13 | Bin 14 | Bin 15 | Bin 16 | Bin 17 | Bin 18 | Bin 19 | Bin 20 | Bin 21 | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | 23.523695 | 77.251695 | 157.670157 | 200.0 | 157.670157 | 77.251695 | 23.523695 | 4.451866 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.00000 |
| 1 | 0.000000 | 0.000000 | 0.000000 | 0.0 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.00000 |
| 2 | 0.000000 | 0.000000 | 0.000000 | 0.0 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.0 | 15.0 | 15.0 | 15.0 | 15.0 | 15.0 | 15.0 | 15.0 | 15.0 | 15.0 | 15.0 | 0.00000 |
| 3 | 0.000000 | 0.000000 | 0.000000 | 0.0 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.00000 |
| 4 | 0.000000 | 0.000000 | 0.000000 | 0.0 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.66778 |
| 5 | 0.000000 | 0.000000 | 0.000000 | 0.0 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.00000 |
# Request to save the concentration history
# at the bin with the initial concentration injection, on the left of the system,
# plus 2 bins inside the compartment, and one on the far side on the right
bio.enable_history(bins=[5,11,15,25], frequency=30, take_snapshot=True)
History enabled for bins [5, 11, 15, 25], for ALL chemicals
# The first round of reaction-diffusion, over a small time duration
bio.react_diffuse(total_duration=0.05, fraction_max_step=0.5, show_status=True)
bio.visualize_system(title_prefix=["The transient `U` starts diffusing into the compartment, and turning into `L` by `U + E -> L + E` ",
"Notice the production of `L`, which can't cross the membranes"])
{'steps': 76, 'system time': '0.050666', 'time_step': 0.00066666}
At this point, some of the enzyme E is in the form of the intermediate EU, especially in the left of the compartment (near bin 11), where U is diffusing in from the left, and initiating the reaction
# SAME IN HEATMAP VIEW
bio.system_heatmaps(title_prefix=["The transient `U` starts diffusing into the compartment, and turning into `B` by `A + E -> B + E`"])
bio.react_diffuse(total_duration=0.05, fraction_max_step=0.5, show_status=True)
bio.visualize_system()
{'steps': 76, 'system time': '0.10133', 'time_step': 0.00066666}
bio.react_diffuse(total_duration=0.1, fraction_max_step=0.5, show_status=True)
bio.visualize_system(title_prefix="Here we turned off the curve smoothing in the plot!",smoothed=False)
{'steps': 151, 'system time': '0.202', 'time_step': 0.00066666}
bio.react_diffuse(total_duration=0.2, fraction_max_step=0.5, show_status=True)
bio.visualize_system(smoothed=False)
{'steps': 301, 'system time': '0.40266', 'time_step': 0.00066666}
bio.react_diffuse(total_duration=0.2, fraction_max_step=0.5, show_status=True)
bio.visualize_system(smoothed=False)
{'steps': 301, 'system time': '0.60333', 'time_step': 0.00066666}
bio.react_diffuse(total_duration=1, fraction_max_step=0.5, show_status=True)
bio.visualize_system(smoothed=False)
{'steps': 1501, 'system time': '1.604', 'time_step': 0.00066666}
bio.react_diffuse(total_duration=0.9, fraction_max_step=0.5, show_status=True)
bio.visualize_system(smoothed=False)
{'steps': 1351, 'system time': '2.5046', 'time_step': 0.00066666}
U is crossing to some extent the nearby left membrane, but not making it in time to reach the right membrane, before getting consumed¶bio.system_heatmaps()
bio.plot_history_single_bin(title_prefix=["Diffusion, membrane passive transport, and reaction `U + E -> L + E`",
"Time evolution at bin where the transient originates."],
bin_address=5)
bio.plot_history_single_bin(title_prefix=["Time evolution inside the compartment, at the very left of it"],
bin_address=11)
U, albeit short-lasting. Also notice the transient buildup of the intermediary EU (and its corresponding transient dip in E)¶bio.plot_history_single_bin(title_prefix=["Time evolution at a bin in the middle of the compartment"],
bin_address=15)
U enters the compartment from the left (bin 11), thru passive transport across the membrane), but barely has a chance to diffuse even to the middle of the compartment (bin 15) because of its quick conversion to L¶bio.plot_history_single_bin(title_prefix=["Time evolution several bins to the right of the compartment"],
bin_address=25)
U ever reach the faraway bins to the right of the compartment!¶
U diffuses quickly¶Let's repeat, starting like before, but with a much higher diffusion rate of U
# Initial conditioned just like before, with same reaction, membrane layout and concentrations
bio = BioSim1D(n_bins=30, chem_data=chem_data, reactions=rxns)
bio.membranes().set_membranes(membranes=[ (11, 21) ])
# All same as in scenario 1
initialize_initial_concs()
# 15 times faster diffusion rate of 'A', and of its membrane permeability, than before
chem_data.set_diffusion_rate(chem_label="U", diff_rate = 3000) # **** x15 from scenario 1
bio.membranes().change_permeability("U", 750.) # **** x15 from scenario 1
chem_data.all_chemicals() # Notice that the plot_color for `EA` was automatically-assigned earlier
| name | label | diff rate | plot_color | |
|---|---|---|---|---|
| 0 | U | U | 3000.0 | red |
| 1 | L | L | 250.0 | green |
| 2 | E | E | 80.0 | violet |
| 3 | EU | EU | 72.0 | darkturquoise |
| 4 | P | P | 120.0 | pink |
| 5 | UP | UP | 90.0 | black |
bio.membranes().membrane_list
[(11, 21)]
bio.membranes().show_permeability() # Values not shown mean 0
{'U': 750.0}
# Request to save the concentration history
# at the bin with the initial concentration injection, on the left of the system,
# plus 2 bins inside the compartment, and one on the far side on the right
bio.enable_history(bins=[5,11,15,25], frequency=30, take_snapshot=True)
History enabled for bins [5, 11, 15, 25], for ALL chemicals
# Visualize the system state so far
bio.visualize_system(title_prefix=["Initial strong, localized transient of chemical `U` (membranes shown in brown).",
"Notice that the enzyme `E` is found inside the compartment"])
# The first round of reaction-diffusion, over a small time duration
bio.react_diffuse(total_duration=0.05, fraction_max_step=0.5, show_status=True)
bio.visualize_system(title_prefix=["The transient `U` starts diffusing into the compartment, and turning into `L` by `U + E -> L + E` ",
"Notice the production of `L`, which can't cross the membranes"])
{'steps': 901, 'system time': '0.050055', 'time_step': 5.5555e-05}
# SAME IN HEATMAP VIEW
bio.system_heatmaps(title_prefix=["The transient `A` starts diffusing into the compartment, and turning into `B` by `A + E -> B + E`"])
bio.react_diffuse(total_duration=0.05, fraction_max_step=0.5, show_status=True)
bio.visualize_system()
{'steps': 901, 'system time': '0.10011', 'time_step': 5.5555e-05}
bio.react_diffuse(total_duration=0.1, fraction_max_step=0.5, show_status=True)
bio.visualize_system(title_prefix="Here we turned off the curve smoothing in the plot!",smoothed=False)
{'steps': 1801, 'system time': '0.20016', 'time_step': 5.5555e-05}
bio.react_diffuse(total_duration=2.3, fraction_max_step=0.5, show_status=True)
bio.visualize_system(smoothed=False)
{'steps': 41401, 'system time': '2.5002', 'time_step': 5.5555e-05}
bio.system_heatmaps()
bio.plot_history_single_bin(title_prefix=["Diffusion, membrane passive transport, and reaction `U + E -> L + E`",
"Time evolution at bin where the transient originates."],
bin_address=5)
bio.plot_history_single_bin(title_prefix=["Time evolution inside the compartment, at the very left of it"],
bin_address=11)
bio.plot_history_single_bin(title_prefix=["Time evolution at a bin in the middle of the compartment"],
bin_address=15)
bio.plot_history_single_bin(title_prefix=["Time evolution several bins to the right of the compartment"],
bin_address=25)