Rodent silent substitution

Silent substitution has been applied to study the effects of melanopic stimulation on circadian responses in mice (e.g., Mouland et al., 2021). This example demonstrates how to create a custom Rodent observer class and prepare cone-silent melanopsin modulations for a BGRW projector. Let’s assume that the device will project onto a pane of diffusive material above a chamber containing the mouse. Note that the the following workflow may be applied for any custom observer whose action spectra are available.

These action spectra were obtained from the Rodent Toolbox (Lucas et al., 2014). Note that mice do not possess a third cone, and that the spectral sensitivities peak at different locations in the visual spectrum in comparison to humans. In particular, S-cone sensitivity is shifted leftwards towards the near-UV portion of the spectrum and there is increased overlap of the M-cone, melanopic and rhodopic action spectra.

[1]:
import pandas as pd
import matplotlib.pyplot as plt
from pysilsub import problems, observers

# Load the rodent action spectra
rodent_action_spectra = pd.read_csv(
    '../../pysilsub/data/rodent_action_spectra.csv',
    index_col='Wavelength'
)
rodent_action_spectra
[1]:
sc mel rh mc
Wavelength
300 0.004086 0.000754 0.000676 0.000577
301 0.005899 0.001042 0.000905 0.000804
302 0.008776 0.001530 0.001312 0.001195
303 0.012715 0.002220 0.001898 0.001749
304 0.017718 0.003110 0.002662 0.002467
... ... ... ... ...
776 0.000000 0.000000 0.000000 0.000000
777 0.000000 0.000000 0.000000 0.000000
778 0.000000 0.000000 0.000000 0.000000
779 0.000000 0.000000 0.000000 0.000000
780 0.000000 0.000000 0.000000 0.000000

481 rows × 4 columns

[2]:
# Create custom rodent model using the _Observer base class
class Rodent(observers._Observer):
    def __init__(self):
        super().__init__()

# Instantiate observer class
mouse = Rodent()

# Assign rodent action spectra
mouse.action_spectra = rodent_action_spectra

# Override list of photoreceptors and colors used for plotting
mouse.photoreceptors = mouse.action_spectra.columns.tolist()
mouse.photorecptor_colors = {
        "sc": "tab:blue",
        "mel": "tab:cyan",
        "rh": "tab:grey",
        "mc": "tab:green"
}

# Plot action spectra
mouse.plot_action_spectra(figsize=(8, 3));
Assigned new (probably not suitable) colors for action spectra.
_images/05c_custom_observer_2_1.png

Now that we have prepared the Rodent observer we need to set up the problem. Here, we will use example package data for a BGRW overhead projection system.

The trick to making things go smoothly is to ensure that the calibration spectra of the stimulation device are sampled at the same wavelengths as the photoreceptor action spectra of the observer. The calibration spectra for the projector were originally sampled from 380-780 nm, so we need to reindex them in order to align the matrices.

[3]:
# Load example data for BGRW projector
ssp = problems.SilentSubstitutionProblem.from_package_data('VirtualSky')

# Align the matrices for spds and spectral sensitivities. This
# just adds a bunch of zeros to the left of each calibration spectrum.
ssp.calibration = ssp.calibration.reindex(range(300, 781, 1), axis=1).fillna(0)

# Plot spds
fig, ax = plt.subplots(figsize=(8, 3))
ssp.plot_calibration_spds(ax=ax);
_images/05c_custom_observer_4_0.png

Now we can assign the Rodent as the observer, define the silent substitution problem, and look for a solution. Today, we just want to find a cone-silent melanopsin modulation whilst ignoring the influence of rods.

[4]:
# Define the problem
ssp.observer = mouse  # Plug in the custom mousey
ssp.ignore = ['rh']
ssp.silence = ['sc', 'mc']
ssp.target = ['mel']
ssp.target_contrast = 'max'
ssp.print_problem()

# Find solution
solution = ssp.optim_solve(**{'options':{'disp':False}})
solution
************************************************************
*************** Silent Substitution Problem ****************
************************************************************
Device: VirtualSky (BGRW projector)
Observer: Rodent
Ignoring: ['rh']
Silencing: ['sc', 'mc']
Targeting: ['mel']
Target contrast: [inf]
Background: None


~~~~~~~~~~~~~~~~~~~~~~~ optim_solve ~~~~~~~~~~~~~~~~~~~~~~~~
> No background specified, will optimise background.
> Aiming to maximise contrast.
> Performing local optimization with SLSQP.
[4]:
     fun: -0.0963582342011021
     jac: array([  1.24298624e+00,   5.10005513e-01,   1.90887507e-03,
         3.62796021e-01,  -1.00484468e+00,  -4.40679822e-01,
        -4.63194214e-04,  -4.33027646e-01])
 message: 'Optimization terminated successfully'
    nfev: 894
     nit: 85
    njev: 85
  status: 0
 success: True
       x: array([ 0.58504834,  0.66774773,  0.61869707,  0.94980023,  0.80000283,
        0.79103615,  0.07958705,  0.42589015])
[5]:
# Plot solution
fig, axs = plt.subplots(1, 2, figsize=(10, 4))

ssp.plot_solution_spds(solution.x, ax=axs[0])
ssp.plot_solution_aopic(solution.x, ax=axs[1])
axs[1].set_ylabel('W/m$^2$');
_images/05c_custom_observer_7_0.png

In general, silent substitution is challenging in mice because of the significant overlap of the M-cone, melanopic and rhodopic action spectra. Some studies have got around this problem by using red-cone knock-in mouse models (e.g., Storchi et al., 2015; Allen et al., 2014) where the spectral sensitivity of the M-cone is shifted rightward. A stimulation system with optimised LED wavelengths will also help with the spectral separation of the photopigments.