#!/usr/bin/env python
# coding: utf-8
# ## The attenuation over time of a single-frequency component in the initial concentration
#
# ### The initial system state is a sine wave of frequency 2 (i.e. 2 cycles across the system's length), of amplitude 10, with a baseline (bias) of 30
# ### Afterward, the process is restarted and repeated with a frequency 5 times larger
# ### TAGS : "diffusion 1D"
# In[1]:
LAST_REVISED = "June 4, 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 BioSim1D, ChemData, PlotlyHelper, check_version
# In[4]:
check_version(LIFE123_VERSION)
# In[ ]:
# In[5]:
# Initialize the system. We use a RELATIVELY LARGE NUMBER OF BINS,
# to captures the finer changes in the frequency components of the concentration function
chem_data = ChemData(names="A", diffusion_rates=0.5)
bio = BioSim1D(n_bins=500, chem_data=chem_data)
# In[ ]:
# ## Initial Preparation -
# ### Start with a sinusoidal concentration, with exactly 2 cycles over the length of the system
# #### (of amplitude 10 and bias value of 30)
# In[6]:
bio.inject_sine_conc(chem_label="A", amplitude=10, bias=30, number_cycles=2)
# In[7]:
bio.show_system_snapshot()
# In[8]:
# Visualize the system's initial state
bio.visualize_system(title_prefix="Initial System State")
# In[9]:
# Show as heatmap
bio.system_heatmaps(title_prefix="Initial System State (as a heatmap)")
# In[10]:
# Take a look at the frequency domain of the concentration values
frequency_data = bio.frequency_analysis(chem_label="A")
frequency_data
# In[11]:
# The ratio of the frequency-2 wave over the constant part (the bias)
ratio = frequency_data.loc[1, "Relative Amplitude"] / frequency_data.loc[0, "Relative Amplitude"]
ratio
# #### Start saving the value of this type of ratio
# In[12]:
bio.save_value(data_snapshot={"ratio": ratio})
bio.get_saved_values()
# In[ ]:
# # Start the diffusion - to time t=10
# In[13]:
bio.diffuse(total_duration=10, n_steps=100)
# In[14]:
# Take a look at the frequency domain of the concentration values
frequency_data = bio.frequency_analysis(chem_label="A")
frequency_data
# In[15]:
ratio = frequency_data.loc[2, "Relative Amplitude"] / frequency_data.loc[0, "Relative Amplitude"]
ratio
# In[16]:
bio.save_value(data_snapshot={"ratio": ratio})
bio.get_saved_values()
# In[ ]:
# ## Do 49 more rounds of diffusion - to time t = 500
# In[17]:
for i in range(49):
bio.diffuse(total_duration=10, n_steps=100)
frequency_data = bio.frequency_analysis(chem_label="A")
ratio = frequency_data.loc[2, "Relative Amplitude"] / frequency_data.loc[0, "Relative Amplitude"]
bio.save_value(data_snapshot={"ratio": ratio})
# In[18]:
bio.get_saved_values()
# In[19]:
bio.visualize_system()
# #### Note how the curve is beginning to flatten; the peaks are no longer at 20 and 40
# In[ ]:
# ## Do 150 more rounds of diffusion - to time t = 2000
# In[20]:
for i in range(150):
bio.diffuse(total_duration=10, n_steps=75) # Notice the gradual decreas of the number of intermediate steps, given the smaller gradient
frequency_data = bio.frequency_analysis(chem_label="A")
ratio = frequency_data.loc[2, "Relative Amplitude"] / frequency_data.loc[0, "Relative Amplitude"]
bio.save_value(data_snapshot={"ratio": ratio})
# In[21]:
bio.get_saved_values()
# In[22]:
bio.visualize_system()
# #### Note how the curve is flatter still - and even beginning to lose shape at the boundary
# In[ ]:
# ## Do 800 more rounds of diffusion - to time t = 10000
# In[23]:
for i in range(800):
bio.diffuse(total_duration=10, n_steps=20) # Note how we're gradually increasing the number of intermediate steps, because the gradiants are now smaller
frequency_data = bio.frequency_analysis(chem_label="A")
ratio = frequency_data.loc[2, "Relative Amplitude"] / frequency_data.loc[0, "Relative Amplitude"]
bio.save_value(data_snapshot={"ratio": ratio})
# In[24]:
bio.get_saved_values()
# In[25]:
bio.visualize_system()
# #### Getting decisively flatter, as it approaches equilibrium
# In[ ]:
# ## Now, let's look how the amplitude of the sine signal, relative to the constant bias, changed over time
# In[26]:
PlotlyHelper.plot_pandas(df=bio.get_saved_values(), x_var="SYSTEM TIME", fields="ratio",
y_label="ratio",
title= "Component of frequency=2, relative to amplitude of constant bias",
colors="orange")
# In[27]:
# Same, but wigh log scale for y-axis (and save the figure object in a variable)
fig_freq_2 = PlotlyHelper.plot_pandas(df=bio.get_saved_values(), x_var="SYSTEM TIME", fields="ratio",
log_y=True, y_label="ratio",
title= "Component of frequency=2, relative to amplitude of constant bias
(log scale in y-axis)",
colors="orange")
fig_freq_2.show()
# In[ ]:
# In[ ]:
# # Start a NEW system
# #### Everything same as before EXCEPT the frequency is now 5 times bigger (10 cycles over the length of the system)
# In[28]:
bio = BioSim1D(n_bins=500, chem_data=chem_data)
# In[29]:
bio.inject_sine_conc(chem_label="A", amplitude=10, bias=30, number_cycles=10) # x5 higher frequency than before
# In[30]:
bio.visualize_system(title_prefix="Initial System State")
# In[31]:
# Show as heatmap
bio.system_heatmaps(title_prefix="Initial System State (as a heatmap)")
# In[32]:
# Take a look at the frequency domain of the concentration values
frequency_data = bio.frequency_analysis(chem_label="A")
frequency_data
# In[33]:
ratio = frequency_data.loc[1, "Relative Amplitude"] / frequency_data.loc[0, "Relative Amplitude"]
ratio
# In[34]:
bio.save_value(data_snapshot={"ratio": ratio})
bio.get_saved_values()
# In[ ]:
# ### Start the diffusion
# In[35]:
bio.diffuse(total_duration=10, n_steps=100)
# In[36]:
# Take a look at the frequency domain of the concentration values
frequency_data = bio.frequency_analysis(chem_label="A")
frequency_data.loc[10]
# In[37]:
ratio = frequency_data.loc[10, "Relative Amplitude"] / frequency_data.loc[0, "Relative Amplitude"]
ratio
# In[38]:
bio.save_value(data_snapshot={"ratio": ratio})
bio.get_saved_values()
# In[39]:
bio.visualize_system()
# ### Continue the diffusion
# In[40]:
for i in range(4):
bio.diffuse(total_duration=10, n_steps=100)
frequency_data = bio.frequency_analysis(chem_label="A")
ratio = frequency_data.loc[10, "Relative Amplitude"] / frequency_data.loc[0, "Relative Amplitude"]
bio.save_value(data_snapshot={"ratio": ratio})
# In[41]:
bio.visualize_system()
# In[42]:
bio.get_saved_values()
# In[43]:
for i in range(10):
bio.diffuse(total_duration=10, n_steps=100)
frequency_data = bio.frequency_analysis(chem_label="A")
ratio = frequency_data.loc[10, "Relative Amplitude"] / frequency_data.loc[0, "Relative Amplitude"]
bio.save_value(data_snapshot={"ratio": ratio})
# In[44]:
bio.visualize_system()
# In[45]:
bio.get_saved_values()
# In[46]:
for i in range(35):
bio.diffuse(total_duration=10, n_steps=100)
frequency_data = bio.frequency_analysis(chem_label="A")
ratio = frequency_data.loc[10, "Relative Amplitude"] / frequency_data.loc[0, "Relative Amplitude"]
bio.save_value(data_snapshot={"ratio": ratio})
# In[47]:
bio.visualize_system()
# In[48]:
bio.get_saved_values()
# In[49]:
for i in range(50):
bio.diffuse(total_duration=10, n_steps=100)
frequency_data = bio.frequency_analysis(chem_label="A")
ratio = frequency_data.loc[10, "Relative Amplitude"] / frequency_data.loc[0, "Relative Amplitude"]
bio.save_value(data_snapshot={"ratio": ratio})
# In[50]:
bio.visualize_system()
# #### **Most of the concentration graph is now flat as a board!**
# In[51]:
bio.get_saved_values()
# In[ ]:
# ## Like done earlier for the smaller frequency, let's look how the amplitude of the sine signal, relative to the constant bias, changed over time
# In[52]:
PlotlyHelper.plot_pandas(df=bio.get_saved_values(), x_var="SYSTEM TIME", fields="ratio",
y_label="ratio",
title= "Component of frequency=10, relative to amplitude of constant bias",
colors="red")
# In[53]:
# Same, but wigh log scale for y-axis (and save the figure object in a variable)
fig_freq_10 = PlotlyHelper.plot_pandas(df=bio.get_saved_values(), x_var="SYSTEM TIME", fields="ratio",
log_y=True, y_label="ratio",
title= "Component of frequency=10, relative to amplitude of constant bias
(log scale in y-axis)",
colors="red")
fig_freq_10.show()
# ### Resurrect the earlier plot for frequency=2 (stored in a variable)
# ### and then superpose them
# In[54]:
fig_freq_2
# In[55]:
# Combine the last 2 plots
PlotlyHelper.combine_plots(fig_list=[fig_freq_2, fig_freq_10],
title="Superposed plots for frequency 2 and 10",
curve_labels=["Component of frequency=2", "Component of frequency=10"])
# ## Note how more more substantial the attenuation of the higher frequency (red) is!
# In[ ]: