A, the chemical injected into the organelle, diffuses slowly - and gets converted into C (which cannot cross the membranes) by the reaction A + B <-> C , before it has a chance to leave the organelle. Trapped!¶A diffuses fast enough to "escape" out of the organelle before getting completely trapped there¶Note: B is plentiful everywhere
Recommended background:
1D/diffusion/membrane_gradient_diffusion_11D/reaction_diffusion/transient_getting_mopped_upLAST_REVISED = "Aug. 28, 2025"
LIFE123_VERSION = "1.0.0rc6" # 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, PlotlyHelper, check_version
check_version(LIFE123_VERSION)
OK
# Initialize the chemical data
chem_data = ChemData(names=["A", "B", "C"],
diffusion_rates=[100., 800., 500.], # The diffusion rate of `A` will later be increased in scenario 2
plot_colors=["red", "turquoise", "green"])
rxns = ReactionRegistry(chem_data=chem_data)
# Reaction A + B <-> C , with 1st-order kinetics for each species; note that it's mostly in the forward direction
# The reaction is mostly in the forward direction
rxns.add_reaction(reactants=["A", "B"], products="C", kF=0.1, kR=0.02)
rxns.describe_reactions()
Number of reactions: 1
0: A + B <-> C (Elementary Synthesis reaction) (kF = 0.1 / kR = 0.02 / K = 5)
Chemicals involved in the above reactions: {"A" (red), "B" (turquoise), "C" (green)}
A diffuses slowly, relatively to the reaction A + B <-> C¶bio = BioSim1D(n_bins=30, chem_data=chem_data, reactions=rxns)
bio.membranes().set_membranes(membranes=[ (2, 18) ])
bio.membranes().membrane_list
[(2, 18)]
# We'll use 1/2 of the diffusion rate of `A` and `B`
# as their respective membrane permeability (by passive transport)
# `C`, by constrast, keeps the default 0 permeability (i.e., can't cross membranes)
bio.membranes().change_permeability("A", 50.)
bio.membranes().change_permeability("B", 400.)
# Set up the initial bell-shape concentration of `A`, with a narrow peak close to one end of the system,
# centered at 20% of the width of the system, i.e. at bin 6
bio.inject_bell_curve(chem_label="A", center=0.2, sd=0.05, max_amplitude=200., bias=0., clip=(2,17))
# Chemical `B`, by contrast, is uniformly distributed
bio.set_uniform_concentration(chem_label="B", conc=80.)
# Show as heatmap (including the membranes, shown in brown)
bio.system_heatmaps(title_prefix="Initial strong, localized transient of chemical `A` (membranes shown in brown)")
A is localized within the compartment (organelle) between bins 2 and 18¶# Visualize the system state so far
bio.visualize_system(title_prefix=["Initial strong, localized transient of chemical `A` (membranes shown in brown).",
"Notice that `B` is plentiful everywhere"])
df = bio.describe_state()
df
SYSTEM STATE at Time t = 0: 30 bins and 3 chemical species Membranes present: [(2, 18)]
| 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 | A | 100.0 | 0.0 | 0.0 | 6.451484 | 30.996376 | 92.555278 | 171.763341 | 198.106523 | 142.0058 | ... | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 |
| 1 | B | 800.0 | 80.0 | 80.0 | 80.000000 | 80.000000 | 80.000000 | 80.000000 | 80.000000 | 80.0000 | ... | 80.0 | 80.0 | 80.0 | 80.0 | 80.0 | 80.0 | 80.0 | 80.0 | 80.0 | 80.0 |
| 2 | C | 500.0 | 0.0 | 0.0 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.0000 | ... | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 |
3 rows × 32 columns
df[df.columns[2:21]] # Zoom in where the action is
| Bin 0 | Bin 1 | 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 | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | 0.0 | 0.0 | 6.451484 | 30.996376 | 92.555278 | 171.763341 | 198.106523 | 142.0058 | 63.263381 | 17.516112 | 3.014131 | 0.322348 | 0.021425 | 0.000885 | 0.000023 | 3.625508e-07 | 3.595235e-09 | 2.215770e-11 | 0.0 |
| 1 | 80.0 | 80.0 | 80.000000 | 80.000000 | 80.000000 | 80.000000 | 80.000000 | 80.0000 | 80.000000 | 80.000000 | 80.000000 | 80.000000 | 80.000000 | 80.000000 | 80.000000 | 8.000000e+01 | 8.000000e+01 | 8.000000e+01 | 80.0 |
| 2 | 0.0 | 0.0 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.0000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000e+00 | 0.000000e+00 | 0.000000e+00 | 0.0 |
# Request to save the concentration history at the bins with the initial concentration injection,
# and the bins at, or near, both ends of the system
bio.enable_history(bins=[0, 6, 29], frequency=15, take_snapshot=True)
History enabled for bins [0, 6, 29], for ALL chemicals
# The first round of reaction-diffusion, over a small time duration
bio.react_diffuse(total_duration=0.025, fraction_max_step=0.5, show_status=True)
bio.visualize_system(title_prefix=["The localized transient `A` starts turning into `C` by `A + B <-> C`, ",
"before it can diffuse away much. Notice the production of `C`, which can't cross the membrane"])
{'steps': 121, 'system time': '0.025208', 'time_step': 0.00020833125}
# SAME IN HEATMAP VIEW
bio.system_heatmaps(title_prefix=["The localized transient `A` starts turning into `C` by `A + B <-> C`, ",
"before it can diffuse away much. Notice the production of `C`, which can't cross the membrane"])
bio.react_diffuse(total_duration=0.025, fraction_max_step=0.5, show_status=True)
bio.visualize_system()
{'steps': 121, 'system time': '0.050416', 'time_step': 0.00020833125}
A is crossing to some extent the nearby left membrane, but not making it in time to reach the right membrane, before getting consumed¶bio.react_diffuse(total_duration=0.025, fraction_max_step=0.5, show_status=True)
bio.visualize_system()
{'steps': 121, 'system time': '0.075624', 'time_step': 0.00020833125}
bio.react_diffuse(total_duration=0.025, fraction_max_step=0.5, show_status=True)
bio.visualize_system()
{'steps': 121, 'system time': '0.10083', 'time_step': 0.00020833125}
bio.react_diffuse(total_duration=0.05, fraction_max_step=0.5, show_status=True)
bio.visualize_system()
{'steps': 241, 'system time': '0.15104', 'time_step': 0.00020833125}
bio.react_diffuse(total_duration=0.15, fraction_max_step=0.5, show_status=True)
bio.visualize_system()
{'steps': 721, 'system time': '0.30125', 'time_step': 0.00020833125}
bio.react_diffuse(total_duration=1.2, fraction_max_step=0.9, show_status=True)
bio.visualize_system()
{'steps': 3201, 'system time': '1.5016', 'time_step': 0.00037499625000000003}
bio.system_heatmaps()
bio.plot_history_single_bin(title_prefix=["Diffusion, membrane passive transport, and reaction `A + B <-> C`",
"Bin where the transient originates."],
bin_address=6)
bio.plot_history_single_bin(title_prefix=["Diffusion, membrane passive transport, and reaction `A + B <-> C`",
"At left-most edge of system."],
bin_address=0)
A reaches bin 0 early on, and later converts to C¶# Save this plot, for later comparison with the counterpart from scenario 2
scenario_1 = bio.plot_history_single_bin(title_prefix=["Diffusion, membrane passive transport, and reaction `A + B <-> C`",
"Faraway bin."],
bin_address=29)
scenario_1
A ever reaches the faraway bins!¶
A diffuses quickly¶Let's repeat, starting like before, but with a much higher diffusion rate of A
# Initial conditioned just like before
bio = BioSim1D(n_bins=30, chem_data=chem_data, reactions=rxns)
bio.membranes().set_membranes(membranes=[ (2, 18) ])
bio.inject_bell_curve(chem_label="A", center=0.2, sd=0.05, max_amplitude=200., bias=0., clip=(2,17))
bio.set_uniform_concentration(chem_label="B", conc=80.)
# 15 times faster diffusion rate of 'A', and of its membrane permeability, than before
chem_data.set_diffusion_rate(chem_label="A", diff_rate = 1500) # **** x15 from scenario 1
bio.membranes().change_permeability("A", 750.) # **** x15 from scenario 1
bio.membranes().change_permeability("B", 400.) # Same as before
# `C` keeps the default 0 permeability (i.e., can't cross membranes)
# Request history-keeping for some bins
bio.enable_history(bins=[0, 6, 29], frequency=15, take_snapshot=True)
History enabled for bins [0, 6, 29], for ALL chemicals
# Visualize the system state so far
bio.visualize_system(title_prefix=["Initial strong, localized transient of chemical `A` (membranes shown in brown)",
"Same as in the earlier scenario."])
# The first round of reaction-diffusion, over a small time duration
bio.react_diffuse(total_duration=0.025, fraction_max_step=0.5, show_status=True)
bio.visualize_system(title_prefix=["This time, the localized transient `A` diffuses more substantially across the membrane,",
"before being converted into `C`, which can't cross the membrane"])
{'steps': 226, 'system time': '0.025111', 'time_step': 0.00011111}
bio.react_diffuse(total_duration=0.025, fraction_max_step=0.5, show_status=True)
bio.visualize_system()
{'steps': 226, 'system time': '0.050222', 'time_step': 0.00011111}
A is managing to cross both membranes, to some extent, before getting consumed¶bio.react_diffuse(total_duration=0.025, fraction_max_step=0.5, show_status=True)
bio.visualize_system()
{'steps': 226, 'system time': '0.075333', 'time_step': 0.00011111}
bio.react_diffuse(total_duration=0.025, fraction_max_step=0.5, show_status=True)
bio.visualize_system()
{'steps': 226, 'system time': '0.10044', 'time_step': 0.00011111}
bio.react_diffuse(total_duration=0.05, fraction_max_step=0.5, show_status=True)
bio.visualize_system()
{'steps': 451, 'system time': '0.15055', 'time_step': 0.00011111}
bio.react_diffuse(total_duration=0.15, fraction_max_step=0.5, show_status=True)
bio.visualize_system()
{'steps': 1351, 'system time': '0.30066', 'time_step': 0.00011111}
C (green) on the right is from A that managed to cross the membrane, and then converted to C¶bio.react_diffuse(total_duration=1.2, fraction_max_step=0.9, show_status=True)
bio.visualize_system()
{'steps': 6001, 'system time': '1.5009', 'time_step': 0.000199998}
scenario_2 = bio.plot_history_single_bin(title_prefix=["Diffusion, membrane passive transport, and reaction `A + B <-> C`",
"Faraway bin."],
bin_address=29)
scenario_2
A (eventually converted into C) reaches the faraway bins, compared to the earlier scenario!¶PlotlyHelper.combine_plots(fig_list = [scenario_1, scenario_2],
title="Diffusion, membrane passive transport, and reaction `A + B <-> C`<br>Concentrations in faraway bin 29<br>Comparison of scenario 1 (dotted) and 2 (solid)",
layout_index=0, modify = {0: "dot"})
Magnify plot to separate the red and green dots (very close to each other)!
Side note: B eventually equilibrates to the same value under either scenario - since B diffuses freely across membranes, and is the excess reactant: it diffuses throughout to bind to A, wherever A might be...