#!/usr/bin/env python
# coding: utf-8
# # "Crossing the border in disguise" : a chemical crosses a membrane impermeable to it,
# #### by first undergoing a reaction converting it into a different chemical, to which the membrane is permeable,
# #### and then re-constituting the first chemical outside of the membrane, thru the reverse reaction.
# #### Reaction-diffusion `A <-> B` in 1D, in the presence of membranes with selective permeability to passive transport.
#
# Eventually, the reaction, the passive membrane transport and the diffusion all come to an equilibrium.
# ### TAGS : "reactions 1D", "diffusion 1D", "membranes 1D"
# In[1]:
LAST_REVISED = "June 6, 2025"
LIFE123_VERSION = "1.0.0rc6" # Library version this experiment is based on
# In[2]:
#import set_path # Using MyBinder? Uncomment this before running the next cell!
# In[3]:
#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 check_version, BioSim1D, ChemData, UniformCompartment
# In[4]:
check_version(LIFE123_VERSION)
# In[ ]:
# ## Prepare the initial system, for starters with IM-PERMEABLE membranes
# with two chemicals `A` and `B`
# In[5]:
chem_data = ChemData(diffusion_rates=[2., 2.], plot_colors=["turquoise", "green"]) # Names "A", "B" automatically assigned
bio = BioSim1D(n_bins=9, chem_data=chem_data)
# In[6]:
reactions = bio.get_reactions()
# Reaction A <-> B , 1st-order kinetics, mostly (but not hugely) in the forward direction
reactions.add_reaction(reactants="A", products="B", forward_rate=8., reverse_rate=2.)
reactions.describe_reactions()
# In[7]:
bio.set_bin_conc(bin_address=4, chem_label="A", conc=10.) # Set the initial concentration of `A` in middle bin
bio.membranes().set_membranes(membranes=[ (4,5) ]) # By default impermeable
bio.describe_state()
# In[8]:
bio.system_heatmaps()
# In[ ]:
# ## Request history-keeping for some bins
# In[9]:
# Request to save the concentration history at the bin with the initial concentration injection,
# and at a couple of other bins
bio.enable_history(bins=[0, 2, 4], frequency=10, take_snapshot=True)
# In[ ]:
# In[ ]:
# ### Advance reaction to equilibrium
# The membranes are impermeable for now; so, no transport across them occurs
# In[10]:
delta_t = 0.002 # This will be our time "quantum" (fixed time step for reactions, passive transport and diffusion) for this experiment
# In[11]:
bio.react_diffuse(time_step=delta_t, n_steps=350)
bio.describe_state()
# In[12]:
bio.system_heatmaps()
# In[13]:
bio.plot_history_single_bin(bin_address=4)
# In[14]:
# Check the reaction equilibrium
bio.reaction_in_equilibrium(bin_address=4, rxn_index=0, explain=True)
#
# In[ ]:
# # Let's siphon off the product `B` from the central bin 4, by making the membrane permeable to it
# while still remaining impermeable to `A`. Note the system time when this happens:
# In[15]:
bio.get_system_time()
# In[16]:
bio.membranes().change_permeability("B", 1.) # Make the membrane permeable to `B` (and only to `B`!)
# In[ ]:
# ### Advance the reaction - and now also the passive transport of `B` across the membrane, and its diffusion outside
# In[17]:
bio.react_diffuse(time_step=delta_t, n_steps=30)
bio.describe_state()
# In[18]:
bio.system_heatmaps()
# Notice what's happening:
# 1. `B` is diffusing away (because we made the membranes permeable to it)
# 2. By Le Chatelier's principle, the reaction `A <-> B` in bin 4 is moving forward, because we're siphoning off the product `B`
# 3. In the other bins, `A` is re-forming from `B`, from the reverse reaction
# In[ ]:
# ### Continue advancing the reaction, passive transport of `B`, and diffusion
# In[19]:
bio.react_diffuse(time_step=delta_t, n_steps=50)
bio.describe_state()
# In[20]:
bio.system_heatmaps()
# Notice how the concentration of `A` in the central bin 4 is continuing to drop
# In[21]:
bio.plot_history_single_bin(bin_address=4, vertical_lines_to_add=[0.7],
title_prefix="Dashed vertical line at time when the membranes were made permeable to `B`")
# In[ ]:
# In[22]:
bio.react_diffuse(time_step=delta_t, n_steps=150)
bio.describe_state()
# In[23]:
bio.system_heatmaps()
# Notice how [A] in bin 4 is continuing to drop, as `A` keeps turns into `B`
# In[ ]:
# In[24]:
bio.react_diffuse(time_step=delta_t, n_steps=500)
bio.describe_state()
# In[25]:
bio.system_heatmaps()
# In[ ]:
# In[26]:
bio.react_diffuse(time_step=delta_t, n_steps=1500)
bio.describe_state()
# In[27]:
bio.system_heatmaps()
# In[ ]:
# ### Let's take the system to equilibrium, in reactions and diffusion
# In[28]:
bio.react_diffuse(time_step=delta_t, n_steps=3000)
bio.describe_state()
# In[29]:
bio.system_heatmaps()
# In[30]:
# Check the reaction equilibrium in one of the bins (doesn't matter which one, since all bin concentrations are now the same)
bio.reaction_in_equilibrium(bin_address=0, rxn_index=0, explain=True)
# ### From a casual glance at the past heatmaps, it might seem that `A` has diffused to equilibrium across all bins...
# ### But the actual mechanism was that `A` (trapped in bin 4 by a membrane impermeable to it) has transformed into `B`, which in turn has passively crossed the membrane, and then diffused across all bins, while at the same time forming `A` by the reverse reaction in all bins outside the membrane.
# #### All said and done, `A` has "found a way, thru its disguise as `B`" to indirectly pass thru an impermeable membrane!
# In[31]:
# Let's look at the central bin 4
bio.plot_history_single_bin(bin_address=4, vertical_lines_to_add=[0.7],
title_prefix="Dashed vertical line at time when the membranes were made permeable to `B`;" \
"
notice the syphoning off of `B` and the resumed advance of the reaction that consumes `A`.")
# In[32]:
# Let's look at a bin CLOSE to the central bin 4
bio.plot_history_single_bin(bin_address=2, vertical_lines_to_add=[0.7],
title_prefix="Dashed vertical line at time when the membranes were made permeable to `B`;" \
"
notice the QUICK arrival of `B` by diffusion, and the subsequent formation of `A` by reverse reaction.")
# In[33]:
# Let's look at a bin FAR from the central bin 4
bio.plot_history_single_bin(bin_address=0, vertical_lines_to_add=[0.7],
title_prefix="Dashed vertical line at time when the membranes were made permeable to `B`;" \
"
notice the SLOW arrival of `B` by diffusion, and the subsequent formation of `A` by reverse reaction.")
# In[ ]: