Fluorescence emission of one Chlamydomonas reinhardtii cell depending on excitation wavelength

You can change

  • emission wavelength
  • emission intensity (log(I) where I is expressed in eins/m²/s)
  • integration time (log(T) where T is expressed is s)
#nbi:hide_in
%config IPCompleter.greedy=True
%load_ext autoreload
%autoreload 2
%matplotlib inline


import numpy as np

import pandas as pd 
import numpy as np
from scipy.interpolate import Rbf, InterpolatedUnivariateSpline
import matplotlib.pyplot as plt
from ipywidgets import interact, interactive, fixed, interact_manual
import ipywidgets as widgets
import alienlab.plot
import alienlab.radiometry
#nbi:hide_in
Na = 6.022e23
volume_chloroplast = 130e-18 #m3 https://bionumbers.hms.harvard.edu/bionumber.aspx?&id=110528&ver=2
mass_chloroplast = volume_chloroplast * 1e6 #g assuming same density as water
surface_chloroplast = 25e-12 #m2 https://bionumbers.hms.harvard.edu/bionumber.aspx?id=107012
volume_cell = 270e-18 #m3 https://bionumbers.hms.harvard.edu/bionumber.aspx?s=n&v=2&id=110530
mass_cell = volume_cell * 1e6 #g assuming algae density is water density
surface_cell = 48e-12 #m2 https://bionumbers.hms.harvard.edu/bionumber.aspx?s=n&v=2&id=107595
#nbi:hide_in
antenna_size = 230 #chlorophyll molecules https://bionumbers.hms.harvard.edu/bionumber.aspx?id=100847&ver=2&trm=chlorophyll&org=
chlorophyll_molecules_per_cell = 3e-15 * Na # https://bionumbers.hms.harvard.edu/bionumber.aspx?id=100852&ver=3&trm=chlorophyll&org=
chlorophyll_concentration_in_chloroplast = 30e-3 *1e3 #mol/m3 https://bionumbers.hms.harvard.edu/bionumber.aspx?id=100913&ver=1&trm=chloroplast&org=
sigma_chlorophyll = 0.29e-20 #m2 596nm ABSOLUTE ABSORPTION CROSS-SECTIONS FOR PHOTOSYSTEM II AND THE MINIMUM QUANTUM REQUIREMENT FOR PHOTOSYNTHESIS IN CHLORELLA VULGARIS
sigma_RC = 50e-20 #m2 596nm review Mauzerall 1996 and ABSOLUTE ABSORPTION CROSS-SECTIONS FOR PHOTOSYSTEM II AND THE MINIMUM QUANTUM REQUIREMENT FOR PHOTOSYNTHESIS IN CHLORELLA VULGARIS
sigma_cell_per_g_of_dry_weight = 0.3 #m2/g 596nm Impact of light color on photobioreactor productivity -and- Simple method for measuring the spectral absorption cross-section of microalgae

q_fluo_chlamy = 0.01 #quantum fluorescence yield
collection_angle = 60 #collection angle of the detector
#nbi:hide_in
#Intermediate growth light
intermediate_chlorophyll_per_cell = 3.3e-16 #chl (a+b)/cell
intermediate_sigma = 60e-20 #m2
intermediate_antenna_size = 210 #chl(a+b)/cell
intermediate_RC_per_cell = intermediate_chlorophyll_per_cell / intermediate_antenna_size #assuming RCII/RCI = 1 and antenna size are equal
#nbi:hide_in
light_intensity = 100 * 1e-6 #E/m2/s
wavelength = 450e-9 #m
integration_period = 1e-3 #s
LED_bandwidth = 5
LED_viewangle = 60
#nbi:hide_in
#Medium light
medium_light = 60e-20/230 * 3e-16 * Na #from table

sigma_chlamy = 1e-12 #m²
#nbi:hide_in
#Collect the data of the graph and interpolate for given wavelength

abs_chlamy = pd.read_csv("save_figures/graph_sigma.csv", names = ['wavelength', 'sigma'], sep = ';', decimal = ',') 
abs_chlamy.sigma = abs_chlamy.sigma * mass_cell * 0.1 #convert m²/g to m² assuming dry mass is 10% of cell mass

# Shift the graph to match intermediate growth light 
# Intepolate sigma = f(wavelength)
X = abs_chlamy.wavelength.values
Y = abs_chlamy.sigma.values
sigma_chlamy = InterpolatedUnivariateSpline(X, Y)
sigma_wavelength = sigma_chlamy(596) #from Intermediate values for Chlorella ABSOLUTE ABSORPTION CROSS-SECTIONS FOR PHOTOSYSTEM II AND THE MINIMUM QUANTUM REQUIREMENT FOR PHOTOSYNTHESIS IN CHLORELLA VULGARIS, Ley and Mauzerall
abs_chlamy.sigma = abs_chlamy.sigma * medium_light / sigma_wavelength # Shift graph values to obtain medium light growth references

fluo_chlamy = pd.read_csv("save_figures/fluo_chlamy.csv", names = ['wavelength', 'fluo'], sep = ';', decimal = ',') 
fluo_chlamy.fluo = fluo_chlamy.fluo/fluo_chlamy.fluo.max()
   
#nbi:hide_in
#Saturation : tau = 100 photons-/s per RC #Aquatic Photosynthesis Falkowski
#I_sat * sigma_lambda = tau * reaction_center_number
p = alienlab.plot.PlotFigure()
tau = 100 #photons-/s
I_sat = tau / abs_chlamy.sigma * intermediate_RC_per_cell
p.title = 'Saturation intensity for LED centered at X-axis wavelength \n for algae grown at 80 µeins/m²/s incandescent light '
p.ylabel = 'Saturation intensity µeins/m²/s'
p.xlabel = 'Central wavelength of excitation light (nm)'
#nbi:hide_in
class fluorophore:
    def __init__(self):
        self.abs_spectrum = [] # in m²
        self.fluo_spectrum = [] # normalized
        self.saturation = False # is there a light saturation process?
        self.q_fluo = 1 #fluorescence yield
        self.species = "Fluorophore name"
        self.min_wavelength = 400 #nm
        self.max_wavelength = 750 #nm
        self.turnover_rate = 100 #excitation/s
        self.x_total = np.arange(self.min_wavelength, self.max_wavelength, 1) #reference wavelength scale
        self.collection_angle = 60
        
    def complete_spectrum(self, X, Y):
        """ extrapolates to zero the values of the array y over the 
        wavelength range of x_total, knowing only the values over X"""
        Y = np.array([y for x, y in sorted(zip(X, Y))]) #preliminary sorting of the arrays along wavelength 
                                                            #(in case the graph in not properly ordered)
        X = np.sort(X)
        d = int(X.min())
        f = int(X.max())
        x_spectrum = np.arange(d, f, 1)
        func = InterpolatedUnivariateSpline(X, Y) # interpolate given values with step 1 nm
        y_func = func(x_spectrum)
        y = (self.x_total * 0).astype(float) # Set y to zero everywhere
        y[d-self.min_wavelength: f-self.min_wavelength] = y_func # Assign spectrum values on konwn portion of spectrum
        return func, y
        
    def photon_emitted(self, wavelength, light_intensity, integration_period):
        # Intepolate sigma = f(wavelength)
        X = self.abs_spectrum.wavelength.values
        Y = self.abs_spectrum.sigma.values
        self.sigma_func, y_abs = self.complete_spectrum(X, Y)
        
        # Intepolate emission = f(wavelength)
        X = self.fluo_spectrum.wavelength.values
        Y = self.fluo_spectrum.fluo.values
        self.fluofunc, y_emission = self.complete_spectrum(X, Y)    

        #Excitation source LED band_width = 20nm, viewangle = 60°, overall_power = light_intensity
        if self.saturation:
            waverange = np.arange(wavelength - LED_bandwidth, wavelength + LED_bandwidth, 1)
            I_sat = self.turnover_rate / np.mean(self.sigma_func(waverange)) * intermediate_RC_per_cell
            light_intensity = min(np.log(I_sat)/np.log(10), light_intensity)
        excitation = alienlab.radiometry.LED(wavelength, LED_bandwidth, LED_viewangle, 10**light_intensity)     
        excitation.X = self.x_total
        excitation_spectrum = excitation.spectrum(plot = False) #eins/m²/s/nm 

        #quantity of photons absorbed by the algae per sec
        I_abs = y_abs * excitation_spectrum * Na #photons/s/nm
        #p.plotting(excitation.X, excitation_spectrum*I_abs)

        #integrate over spectrum
        energy_absorbed = np.trapz(I_abs, self.x_total) #photons/s

        self.photons_emitted = self.collection_angle / 360 * self.q_fluo * energy_absorbed * 10**integration_period #fluorescecnce and collection angle
        #fig = p.plotting(excitation.X, I_abs)
        print('Number of photons emitted per algae during acquisition: %0.2f'%self.photons_emitted)

        full_fluo = np.trapz(y_emission, self.x_total)
        scaling = self.photons_emitted / full_fluo 
        self.fluo_output = y_emission * scaling
        
        # plotting
        p.title = "Photons emitted by %s"%self.species
        p.xlabel = "Emission wavelength (nm)"
        p.ylabel = 'Absorbption cross-section of \n %s (m² per unit)'%self.species
        p.y2label = 'Fluorescence emission (photons/unit/nm)'
        p.label_list = ['absorbption spectrum (m²)', 'light source spectrum (total energy %f E/m²/s)'%(10**light_intensity)]
        p.xval = self.x_total
        #print(abs_spectrum.sigma.values.max()/excitation_spectrum.max(), abs_spectrum.sigma.values.max(), excitation_spectrum.max())
        p.yval = [y_abs, excitation_spectrum * y_abs.max()/excitation_spectrum.max()]
        p.label2_list = ['fluorescence (photons/unit/nm)']
        p.x2val = self.x_total
        p.y2val = y_emission

        #print(p.xval.shape, p.x2val.shape)
        #print(p.yval[0].shape, p.yval[1].shape, p.y2val.shape)

        p.coplotting()


chlamy = fluorophore()
chlamy.abs_spectrum = abs_chlamy
chlamy.fluo_spectrum = fluo_chlamy
chlamy.q_fluo = q_fluo_chlamy     
chlamy.turnover_rate = tau
chlamy.saturation = True
chlamy.species = "Chlamydomonas reinhardtii"

dis = interact(chlamy.photon_emitted, wavelength = (400, 700), light_intensity = (-6, -2), integration_period = (-6, -1))