Reference#

cleo module#

class cleo.CLSimulator(network: brian2.core.network.Network)[source]#

Bases: cleo.base.NeoExportable

The centerpiece of cleo. Integrates simulation components and runs.

Method generated by attrs for class CLSimulator.

devices: set[cleo.base.InterfaceDevice]#
get_state() dict[source]#

Return current recorder measurements.

Returns

A dictionary of name: state pairs for all recorders in the simulator.

Return type

dict

inject(device: cleo.base.InterfaceDevice, *neuron_groups: brian2.groups.neurongroup.NeuronGroup, **kwparams: Any) cleo.base.CLSimulator[source]#

Inject InterfaceDevice into the network, connecting to specified neurons.

Calls connect_to_neuron_group() for each group with kwparams and adds the device’s brian_objects to the simulator’s network.

Parameters

device (InterfaceDevice) – Device to inject

Returns

self

Return type

CLSimulator

io_processor: cleo.base.IOProcessor#
network: brian2.core.network.Network#

The Brian network forming the core model

recorders: dict[str, cleo.base.Recorder]#
reset(**kwargs)[source]#

Reset the simulator to a neutral state

Restores the Brian Network to where it was when the CLSimulator was last modified (last injection, IOProcessor change). Calls reset() on devices and IOProcessor.

run(duration: brian2.units.fundamentalunits.Quantity, **kwparams) None[source]#

Run simulation.

Parameters
  • duration (brian2 temporal Quantity) – Length of simulation

  • **kwparams (additional arguments passed to brian2.run()) – level has a default value of 1

set_io_processor(io_processor, communication_period=None) cleo.base.CLSimulator[source]#

Set simulator IO processor

Will replace any previous IOProcessor so there is only one at a time. A Brian NetworkOperation is created to govern communication between the Network and the IOProcessor.

Parameters

io_processor (IOProcessor) –

Returns

self

Return type

CLSimulator

stimulators: dict[str, cleo.base.Stimulator]#
to_neo() neo.core.block.Block[source]#

Return a neo.core.AnalogSignal object with the device’s data

Returns

Neo object representing exported data

Return type

neo.core.BaseNeo

update_stimulators(ctrl_signals) None[source]#

Update stimulators with output from the IOProcessor

Parameters

ctrl_signals (dict) – {stimulator_name: ctrl_signal} dictionary with values to update each stimulator.

class cleo.IOProcessor[source]#

Bases: abc.ABC

Abstract class for implementing sampling, signal processing and control

This must be implemented by the user with their desired closed-loop use case, though most users will find the LatencyIOProcessor() class more useful, since delay handling is already defined.

abstract get_ctrl_signal(time) dict[source]#

Get per-stimulator control signal from the IOProcessor.

Parameters

time (Brian 2 temporal Unit) – Current timestep

Returns

A {‘stimulator_name’: value} dictionary for updating stimulators.

Return type

dict

abstract is_sampling_now(time) bool[source]#

Determines whether the processor will take a sample at this timestep.

Parameters

time (Brian 2 temporal Unit) – Current timestep.

Return type

bool

abstract put_state(state_dict: dict, time) None[source]#

Deliver network state to the IOProcessor.

Parameters
  • state_dict (dict) – A dictionary of recorder measurements, as returned by get_state()

  • time (brian2 temporal Unit) – The current simulation timestep. Essential for simulating control latency and for time-varying control.

reset(**kwargs) None[source]#
sample_period_ms: float#

Determines how frequently the processor takes samples

class cleo.InterfaceDevice(*, name: str = NOTHING, save_history: bool = True)[source]#

Bases: abc.ABC

Base class for devices to be injected into the network

Method generated by attrs for class InterfaceDevice.

add_self_to_plot(ax: mpl_toolkits.mplot3d.axes3d.Axes3D, axis_scale_unit: brian2.units.fundamentalunits.Unit, **kwargs) list[matplotlib.artist.Artist][source]#

Add device to an existing plot

Should only be called by plot().

Parameters
  • ax (Axes3D) – The existing matplotlib Axes object

  • axis_scale_unit (Unit) – The unit used to label axes and define chart limits

  • **kwargs (optional) –

Returns

A list of artists used to render the device. Needed for use in conjunction with VideoVisualizer.

Return type

list[Artist]

brian_objects: set#

All the Brian objects added to the network by this device. Must be kept up-to-date in connect_to_neuron_group() and other functions so that those objects can be automatically added to the network when the device is injected.

abstract connect_to_neuron_group(neuron_group: brian2.groups.neurongroup.NeuronGroup, **kwparams) None[source]#

Connect device to given neuron_group.

If your device introduces any objects which Brian must keep track of, such as a NeuronGroup, Synapses, or Monitor, make sure to add these to self.brian_objects.

Parameters
  • neuron_group (NeuronGroup) –

  • **kwparams (optional, passed from inject or) – inject

init_for_simulator(simulator: cleo.base.CLSimulator) None[source]#

Initialize device for simulator on initial injection

This function is called only the first time a device is injected into a simulator and performs any operations that are independent of the individual neuron groups it is connected to.

Parameters

simulator (CLSimulator) – simulator being injected into

name: str#

Unique identifier for device, used in sampling, plotting, etc. Name of the class by default.

reset(**kwargs) None[source]#

Reset the device to a neutral state

save_history: bool#

Determines whether times and inputs/outputs are recorded.

For stimulators, this is when update() is called. For recorders, it is when get_state() is called.

sim: cleo.base.CLSimulator#

The simulator the device is injected into

update_artists(artists: list[matplotlib.artist.Artist], *args, **kwargs) list[matplotlib.artist.Artist][source]#

Update the artists used to render the device

Used to set the artists’ state at every frame of a video visualization. The current state would be passed in *args or **kwargs

Parameters

artists (list[Artist]) – the artists used to render the device originally, i.e., which were returned from the first add_self_to_plot() call.

Returns

The artists that were actually updated. Needed for efficient blit rendering, where only updated artists are re-rendered.

Return type

list[Artist]

class cleo.Recorder(*, name: str = NOTHING, save_history: bool = True)[source]#

Bases: cleo.base.InterfaceDevice

Device for taking measurements of the network.

Method generated by attrs for class Recorder.

abstract get_state() Any[source]#

Return current measurement.

class cleo.Stimulator(default_value: Any = 0, *, name: str = NOTHING, save_history: bool = True)[source]#

Bases: cleo.base.InterfaceDevice, cleo.base.NeoExportable

Device for manipulating the network

Method generated by attrs for class Stimulator.

default_value: Any#

The default value of the device—used on initialization and on reset()

reset(**kwargs) None[source]#

Reset the stimulator device to a neutral state

t_ms: list[float]#

Times stimulator was updated, stored if save_history

to_neo()[source]#

Return a neo.core.AnalogSignal object with the device’s data

Returns

Neo object representing exported data

Return type

neo.core.BaseNeo

update(ctrl_signal) None[source]#

Set the stimulator value.

By default this simply sets value to ctrl_signal. You will want to implement this method if your stimulator requires additional logic. Use super.update(self, value) to preserve the self.value attribute logic

Parameters

ctrl_signal (any) – The value the stimulator is to take.

value: Any#

The current value of the stimulator device

values: list[Any]#

Values taken by the stimulator at each update() call, stored if save_history

class cleo.SynapseDevice(extra_namespace: dict = NOTHING, *, name: str = NOTHING, save_history: bool = True)[source]#

Bases: cleo.base.InterfaceDevice

Base class for devices that record from/stimulate neurons via a Synapses object with device-specific model. Used for opsin and indicator classes

Method generated by attrs for class SynapseDevice.

connect_to_neuron_group(neuron_group: brian2.groups.neurongroup.NeuronGroup, **kwparams) None[source]#

Transfect neuron group with device.

Parameters

neuron_group (NeuronGroup) – The neuron group to transform

Keyword Arguments
  • p_expression (float) – Probability (0 <= p <= 1) that a given neuron in the group will express the protein. 1 by default.

  • i_targets (array-like) – Indices of neurons in the group to transfect. recommended for efficiency when stimulating or imaging a small subset of the group. Incompatible with p_expression.

  • rho_rel (float) – The expression level, relative to the standard model fit, of the protein. 1 by default. For heterogeneous expression, this would have to be modified in the light-dependent synapse post-injection, e.g., opsin.syns["neuron_group_name"].rho_rel = ...

  • [default_name]_var_name (str) – See required_vars. Allows for custom variable names.

extra_namespace: dict#

Additional items (beyond parameters) to be added to the opto synapse namespace

init_syn_vars(syn: brian2.synapses.synapses.Synapses) None[source]#

Initializes appropriate variables in Synapses implementing the model

Can also be used to reset the variables.

Parameters

syn (Synapses) – The synapses object implementing this model

model: str#

Basic Brian model equations string.

Should contain a rho_rel term reflecting relative expression levels. Will likely also contain special NeuronGroup-dependent symbols such as V_VAR_NAME to be replaced on injection in modify_model_and_params_for_ng().

modify_model_and_params_for_ng(neuron_group: brian2.groups.neurongroup.NeuronGroup, injct_params: dict) Tuple[brian2.equations.equations.Equations, dict][source]#

Adapt model for given neuron group on injection

This enables the specification of variable names differently for each neuron group, allowing for custom names and avoiding conflicts.

Parameters
  • neuron_group (NeuronGroup) – NeuronGroup this opsin model is being connected to

  • injct_params (dict) – kwargs passed in on injection, could contain variable names to plug into the model

Keyword Arguments

model (str, optional) – Model to start with, by default that defined for the class. This allows for prior string manipulations before it can be parsed as an Equations object.

Returns

A tuple containing an Equations object and a parameter dictionary, constructed from model and params, respectively, with modified names for use in synapses

Return type

Equations, dict

on_pre: str#

Model string for Synapses reacting to spikes.

property params: dict#

Returns a dictionary of parameters for the model

per_ng_unit_replacements: list[Tuple[str, str]]#

List of (UNIT_NAME, neuron_group_specific_unit_name) tuples to be substituted in the model string on injection and before checking required variables.

required_vars: list[Tuple[str, brian2.units.fundamentalunits.Unit]]#

Default names of state variables required in the neuron group, along with units, e.g., [(‘Iopto’, amp)].

It is assumed that non-default values can be passed in on injection as a keyword argument [default_name]_var_name=[non_default_name] and that these are found in the model string as [DEFAULT_NAME]_VAR_NAME before replacement.

reset(**kwargs)[source]#

Reset the device to a neutral state

source_ngs: dict[str, brian2.groups.neurongroup.NeuronGroup]#

{target_ng.name: source_ng} dict of source neuron groups.

The source is the target itself by default or light aggregator neurons for LightDependent.

synapses: dict[str, brian2.synapses.synapses.Synapses]#

Stores the synapse objects implementing the model, connecting from source (light aggregator neurons or the target group itself) to target neuron groups, with NeuronGroup name keys and Synapses values.

cleo.coords module#

Contains functions for assigning neuron coordinates and visualizing

cleo.coords.assign_coords(neuron_group: brian2.groups.neurongroup.NeuronGroup, coords: brian2.units.fundamentalunits.Quantity)[source]#
cleo.coords.assign_coords_grid_rect_prism(neuron_group: brian2.groups.neurongroup.NeuronGroup, xlim: Tuple[float, float], ylim: Tuple[float, float], zlim: Tuple[float, float], shape: Tuple[int, int, int], unit: brian2.units.fundamentalunits.Unit = mmetre) None[source]#

Assign grid coordinates to neurons in a rectangular grid

Parameters
  • neuron_group (NeuronGroup) – The neuron group to assign coordinates to

  • xlim (Tuple[float, float]) – xmin, xmax, with no unit

  • ylim (Tuple[float, float]) – ymin, ymax, with no unit

  • zlim (Tuple[float, float]) – zmin, zmax with no unit

  • shape (Tuple[int, int, int]) – n_x, n_y, n_z tuple representing the shape of the resulting grid

  • unit (Unit, optional) – Brian unit determining what scale to use for coordinates, by default mm

Raises

ValueError – When the shape is incompatible with the number of neurons in the group

cleo.coords.assign_coords_rand_cylinder(neuron_group: brian2.groups.neurongroup.NeuronGroup, xyz_start: Tuple[float, float, float], xyz_end: Tuple[float, float, float], radius: float, unit: brian2.units.fundamentalunits.Unit = mmetre) None[source]#

Assign random coordinates within a cylinder.

Parameters
  • neuron_group (NeuronGroup) – neurons to assign coordinates to

  • xyz_start (Tuple[float, float, float]) – starting position of cylinder without unit

  • xyz_end (Tuple[float, float, float]) – ending position of cylinder without unit

  • radius (float) – radius of cylinder without unit

  • unit (Unit, optional) – Brian unit to scale other params, by default mm

cleo.coords.assign_coords_rand_rect_prism(neuron_group: brian2.groups.neurongroup.NeuronGroup, xlim: Tuple[float, float], ylim: Tuple[float, float], zlim: Tuple[float, float], unit: brian2.units.fundamentalunits.Unit = mmetre) None[source]#

Assign random coordinates to neurons within a rectangular prism

Parameters
  • neuron_group (NeuronGroup) – neurons to assign coordinates to

  • xlim (Tuple[float, float]) – xmin, xmax without unit

  • ylim (Tuple[float, float]) – ymin, ymax without unit

  • zlim (Tuple[float, float]) – zmin, zmax without unit

  • unit (Unit, optional) – Brian unit to specify scale implied in limits, by default mm

cleo.coords.assign_coords_uniform_cylinder(neuron_group: brian2.groups.neurongroup.NeuronGroup, xyz_start: Tuple[float, float, float], xyz_end: Tuple[float, float, float], radius: float, unit: brian2.units.fundamentalunits.Unit = mmetre) None[source]#

Assign uniformly spaced coordinates within a cylinder.

Parameters
  • neuron_group (NeuronGroup) – neurons to assign coordinates to

  • xyz_start (Tuple[float, float, float]) – starting position of cylinder without unit

  • xyz_end (Tuple[float, float, float]) – ending position of cylinder without unit

  • radius (float) – radius of cylinder without unit

  • unit (Unit, optional) – Brian unit to scale other params, by default mm

cleo.coords.assign_xyz(neuron_group: brian2.groups.neurongroup.NeuronGroup, x: numpy.ndarray, y: numpy.ndarray, z: numpy.ndarray, unit: brian2.units.fundamentalunits.Unit = mmetre)[source]#

Assign arbitrary coordinates to neuron group.

Parameters
  • neuron_group (NeuronGroup) – neurons to be assigned coordinates

  • x (np.ndarray) – x positions to assign (preferably 1D with no unit)

  • y (np.ndarray) – y positions to assign (preferably 1D with no unit)

  • z (np.ndarray) – z positions to assign (preferably 1D with no unit)

  • unit (Unit, optional) – Brian unit determining what scale to use for coordinates, by default mm

cleo.coords.concat_coords(*coords: brian2.units.fundamentalunits.Quantity) brian2.units.fundamentalunits.Quantity[source]#

Combine multiple coordinate Quantity arrays into one

Parameters

*coords (Quantity) – Multiple coordinate n x 3 Quantity arrays to combine

Returns

A single n x 3 combined Quantity array

Return type

Quantity

cleo.coords.coords_from_ng(ng: brian2.groups.neurongroup.NeuronGroup) brian2.units.fundamentalunits.Quantity[source]#

Get nx3 coordinate array from NeuronGroup.

cleo.coords.coords_from_xyz(x: brian2.units.fundamentalunits.Quantity, y: brian2.units.fundamentalunits.Quantity, z: brian2.units.fundamentalunits.Quantity) brian2.units.fundamentalunits.Quantity[source]#

Get …x3 coordinate array from x, y, z arrays (with units).

cleo.ephys module#

Contains probes, coordinate convenience functions, signals, spiking, and LFP

class cleo.ephys.MultiUnitSpiking(r_perfect_detection: brian2.units.fundamentalunits.Quantity, r_half_detection: brian2.units.fundamentalunits.Quantity, cutoff_probability: float = 0.01, *, name: str = NOTHING)[source]#

Bases: cleo.ephys.spiking.Spiking

Detects spikes per channel, that is, unsorted.

Method generated by attrs for class MultiUnitSpiking.

connect_to_neuron_group(neuron_group: brian2.groups.neurongroup.NeuronGroup, **kwparams) None[source]#

Configure signal to record from specified neuron group

Parameters

neuron_group (NeuronGroup) – group to record from

get_state() tuple[NDArray[Any, ..., UInt[64]], NDArray[Any, ..., Float[64]], NDArray[Any, ..., UInt[64]]][source]#

Return spikes since method was last called (i, t_ms, y)

Returns

(i, t_ms, y) where i is channel (for multi-unit) or neuron (for sorted) spike indices, t_ms is spike times, and y is a spike count vector suitable for control- theoretic uses—i.e., a 0 for every channel/neuron that hasn’t spiked and a 1 for a single spike.

Return type

tuple[NDArray[np.uint], NDArray[float], NDArray[np.uint]]

to_neo() neo.core.group.Group[source]#

Return a neo.core.AnalogSignal object with the device’s data

Returns

Neo object representing exported data

Return type

neo.core.BaseNeo

class cleo.ephys.Probe(coords: brian2.units.fundamentalunits.Quantity, signals: list[cleo.ephys.probes.Signal] = NOTHING, *, name: str = NOTHING, save_history: bool = True)[source]#

Bases: cleo.base.Recorder, cleo.base.NeoExportable

Picks up specified signals across an array of electrodes.

Visualization kwargs
  • marker (str, optional) – The marker used to represent each contact. “x” by default.

  • size (float, optional) – The size of each contact marker. 40 by default.

  • color (Any, optional) – The color of contact markers. “xkcd:dark gray” by default.

Method generated by attrs for class Probe.

add_self_to_plot(ax: mpl_toolkits.mplot3d.axes3d.Axes3D, axis_scale_unit: brian2.units.fundamentalunits.Unit, **kwargs) list[matplotlib.artist.Artist][source]#

Add device to an existing plot

Should only be called by plot().

Parameters
  • ax (Axes3D) – The existing matplotlib Axes object

  • axis_scale_unit (Unit) – The unit used to label axes and define chart limits

  • **kwargs (optional) –

Returns

A list of artists used to render the device. Needed for use in conjunction with VideoVisualizer.

Return type

list[Artist]

add_signals(*signals: cleo.ephys.probes.Signal) None[source]#

Add signals to the probe for recording

Parameters

*signals (Signal) – signals to add

connect_to_neuron_group(neuron_group: brian2.groups.neurongroup.NeuronGroup, **kwparams: Any) None[source]#

Configure probe to record from given neuron group

Will call Signal.connect_to_neuron_group() for each signal

Parameters
  • neuron_group (NeuronGroup) – neuron group to connect to, i.e., record from

  • **kwparams (Any) – Passed in to signals’ connect functions, needed for some signals

coords: Quantity#

Coordinates of n electrodes. Must be an n x 3 array (with unit) where columns represent x, y, and z

get_state() dict[source]#

Get current state from probe, i.e., all signals

Returns

{‘signal_name’: value} dict with signal states

Return type

dict

property n#

Number of electrode contacts in the probe

probe: Probe#
reset(**kwargs)[source]#

Reset the probe to a neutral state

Calls reset() on each signal

signals: list[Signal]#

Signals recorded by the probe. Can be added to post-init with add_signals().

to_neo() neo.core.group.Group[source]#

Return a neo.core.AnalogSignal object with the device’s data

Returns

Neo object representing exported data

Return type

neo.core.BaseNeo

property xs: brian2.units.fundamentalunits.Quantity#

x coordinates of recording contacts

Returns

x coordinates represented as a Brian quantity, that is, including units. Should be like a 1D array.

Return type

Quantity

property ys: brian2.units.fundamentalunits.Quantity#

y coordinates of recording contacts

Returns

y coordinates represented as a Brian quantity, that is, including units. Should be like a 1D array.

Return type

Quantity

property zs: brian2.units.fundamentalunits.Quantity#

z coordinates of recording contacts

Returns

z coordinates represented as a Brian quantity, that is, including units. Should be like a 1D array.

Return type

Quantity

class cleo.ephys.Signal(*, name: str = NOTHING)[source]#

Bases: abc.ABC

Base class representing something an electrode can record

Method generated by attrs for class Signal.

brian_objects: set#

All Brian objects created by the signal. Must be kept up-to-date for automatic injection into the network

abstract connect_to_neuron_group(neuron_group: brian2.groups.neurongroup.NeuronGroup, **kwparams)[source]#

Configure signal to record from specified neuron group

Parameters

neuron_group (NeuronGroup) – group to record from

abstract get_state() Any[source]#

Get the signal’s current value

init_for_probe(probe: cleo.ephys.probes.Probe) None[source]#

Called when attached to a probe.

Ensures signal can access probe and is only attached to one

Parameters

probe (Probe) – Probe to attach to

Raises

ValueError – When signal already attached to another probe

name: str#

Unique identifier used to organize probe output. Name of the class by default.

probe: cleo.ephys.probes.Probe#

The probe the signal is configured to record for.

reset(**kwargs) None[source]#

Reset signal to a neutral state

class cleo.ephys.SortedSpiking(r_perfect_detection: brian2.units.fundamentalunits.Quantity, r_half_detection: brian2.units.fundamentalunits.Quantity, cutoff_probability: float = 0.01, *, name: str = NOTHING)[source]#

Bases: cleo.ephys.spiking.Spiking

Detect spikes identified by neuron indices.

The indices used by the probe do not correspond to those coming from neuron groups, since the probe must consider multiple potential groups and within a group ignores those neurons that are too far away to be easily detected.

Method generated by attrs for class SortedSpiking.

connect_to_neuron_group(neuron_group: brian2.groups.neurongroup.NeuronGroup, **kwparams) None[source]#

Configure sorted spiking signal to record from given neuron group

Parameters

neuron_group (NeuronGroup) – group to record from

get_state() tuple[NDArray[Any, ..., UInt[64]], NDArray[Any, ..., Float[64]], NDArray[Any, ..., UInt[64]]][source]#

Return spikes since method was last called (i, t_ms, y)

Returns

(i, t_ms, y) where i is channel (for multi-unit) or neuron (for sorted) spike indices, t_ms is spike times, and y is a spike count vector suitable for control- theoretic uses—i.e., a 0 for every channel/neuron that hasn’t spiked and a 1 for a single spike.

Return type

tuple[NDArray[np.uint], NDArray[float], NDArray[np.uint]]

class cleo.ephys.Spiking(r_perfect_detection: brian2.units.fundamentalunits.Quantity, r_half_detection: brian2.units.fundamentalunits.Quantity, cutoff_probability: float = 0.01, *, name: str = NOTHING)[source]#

Bases: cleo.ephys.probes.Signal, cleo.base.NeoExportable

Base class for probabilistically detecting spikes

Method generated by attrs for class Spiking.

connect_to_neuron_group(neuron_group: brian2.groups.neurongroup.NeuronGroup, **kwparams) numpy.ndarray[source]#

Configure signal to record from specified neuron group

Parameters

neuron_group (NeuronGroup) – Neuron group to record from

Returns

num_neurons_to_consider x num_channels array of spike detection probabilities, for use in subclasses

Return type

np.ndarray

cutoff_probability: float#

Spike detection probability below which neurons will not be considered. For computational efficiency.

abstract get_state() tuple[NDArray[Any, ..., UInt[64]], NDArray[Any, ..., Float[64]], NDArray[Any, ..., UInt[64]]][source]#

Return spikes since method was last called (i, t_ms, y)

Returns

(i, t_ms, y) where i is channel (for multi-unit) or neuron (for sorted) spike indices, t_ms is spike times, and y is a spike count vector suitable for control- theoretic uses—i.e., a 0 for every channel/neuron that hasn’t spiked and a 1 for a single spike.

Return type

tuple[NDArray[np.uint], NDArray[float], NDArray[np.uint]]

i: NDArray[Any, np.uint]#

Channel (for multi-unit) or neuron (for sorted) indices of spikes, stored if save_history on probe

i_probe_by_i_ng: bidict#

(neuron_group, i_ng) keys, i_probe values. bidict for converting between neuron group indices and the indices the probe uses

r_half_detection: Quantity#

Radius (with Brian unit) within which half of all spikes are detected

r_perfect_detection: Quantity#

Radius (with Brian unit) within which all spikes are detected

reset(**kwargs) None[source]#

Reset signal to a neutral state

t_ms: NDArray[Any, float]#

Spike times in ms, stored if save_history on probe

t_samp_ms: NDArray[Any, float]#

Sample times in ms when each spike was recorded, stored if save_history on probe

to_neo() neo.core.group.Group[source]#

Return a neo.core.AnalogSignal object with the device’s data

Returns

Neo object representing exported data

Return type

neo.core.BaseNeo

class cleo.ephys.TKLFPSignal(uLFP_threshold_uV: float = 0.001, *, name: str = NOTHING)[source]#

Bases: cleo.ephys.probes.Signal, cleo.base.NeoExportable

Records the Teleńczuk kernel LFP approximation.

Requires tklfp_type='exc'|'inh' to specify cell type on injection.

An orientation keyword argument can also be specified on injection, which should be an array of shape (n_neurons, 3) representing which way is “up,” that is, towards the surface of the cortex, for each neuron. If a single vector is given, it is taken to be the orientation for all neurons in the group. [0, 0, -1] is the default, meaning the negative z axis is “up.” As stated elsewhere, Cleo’s convention is that z=0 corresponds to the cortical surface and increasing z values represent increasing depth.

TKLFP is computed from spikes using the tklfp package.

Method generated by attrs for class TKLFPSignal.

connect_to_neuron_group(neuron_group: brian2.groups.neurongroup.NeuronGroup, **kwparams)[source]#

Configure signal to record from specified neuron group

Parameters

neuron_group (NeuronGroup) – group to record from

get_state() numpy.ndarray[source]#

Get the signal’s current value

init_for_probe(probe: cleo.ephys.probes.Probe)[source]#

Called when attached to a probe.

Ensures signal can access probe and is only attached to one

Parameters

probe (Probe) – Probe to attach to

Raises

ValueError – When signal already attached to another probe

lfp_uV: nptyping.types._ndarray.NDArray[Any, Any, nptyping.types._number.Float]#

Approximated LFP from every call to get_state(). Shape is (n_samples, n_channels). Stored if save_history on probe

reset(**kwargs) None[source]#

Reset signal to a neutral state

t_ms: nptyping.types._ndarray.NDArray[Any, nptyping.types._number.Float]#

Times at which LFP is recorded, in ms, stored if save_history on probe

to_neo() neo.AnalogSignal[source]#

Return a neo.core.AnalogSignal object with the device’s data

Returns

Neo object representing exported data

Return type

neo.core.BaseNeo

uLFP_threshold_uV: float#

Threshold, in microvolts, above which the uLFP for a single spike is guaranteed to be considered, by default 1e-3. This determines the buffer length of past spikes, since the uLFP from a long-past spike becomes negligible and is ignored.

cleo.ephys.linear_shank_coords(array_length: brian2.units.fundamentalunits.Quantity, channel_count: int, start_location: brian2.units.fundamentalunits.Quantity = array([0., 0., 0.]) * metre, direction: Tuple[float, float, float] = (0, 0, 1)) brian2.units.fundamentalunits.Quantity[source]#

Generate coordinates in a linear pattern

Parameters
  • array_length (Quantity) – Distance from the first to the last contact (with a Brian unit)

  • channel_count (int) – Number of coordinates to generate, i.e. electrode contacts

  • start_location (Quantity, optional) – x, y, z coordinate (with unit) for the start of the electrode array, by default (0, 0, 0)*mm

  • direction (Tuple[float, float, float], optional) – x, y, z vector indicating the direction in which the array extends, by default (0, 0, 1), meaning pointing straight down

Returns

channel_count x 3 array of coordinates, where the 3 columns represent x, y, and z

Return type

Quantity

cleo.ephys.poly2_shank_coords(array_length: brian2.units.fundamentalunits.Quantity, channel_count: int, intercol_space: brian2.units.fundamentalunits.Quantity, start_location: brian2.units.fundamentalunits.Quantity = array([0., 0., 0.]) * metre, direction: Tuple[float, float, float] = (0, 0, 1)) brian2.units.fundamentalunits.Quantity[source]#

Generate NeuroNexus-style Poly2 array coordinates

Poly2 refers to 2 parallel columns with staggered contacts. See https://www.neuronexus.com/products/electrode-arrays/up-to-15-mm-depth for more detail.

Parameters
  • array_length (Quantity) – Length from the beginning to the end of the two-column array, as measured in the center

  • channel_count (int) – Total (not per-column) number of coordinates (recording contacts) desired

  • intercol_space (Quantity) – Distance between columns (with Brian unit)

  • start_location (Quantity, optional) – Where to place the beginning of the array, by default (0, 0, 0)*mm

  • direction (Tuple[float, float, float], optional) – x, y, z vector indicating the direction in which the two columns extend; by default (0, 0, 1), meaning straight down.

Returns

channel_count x 3 array of coordinates, where the 3 columns represent x, y, and z

Return type

Quantity

cleo.ephys.poly3_shank_coords(array_length: brian2.units.fundamentalunits.Quantity, channel_count: int, intercol_space: brian2.units.fundamentalunits.Quantity, start_location: brian2.units.fundamentalunits.Quantity = array([0., 0., 0.]) * metre, direction: Tuple[float, float, float] = (0, 0, 1)) brian2.units.fundamentalunits.Quantity[source]#

Generate NeuroNexus Poly3-style array coordinates

Poly3 refers to three parallel columns of electrodes. The middle column will be longest if the channel count isn’t divisible by three and the side columns will be centered vertically with respect to the middle.

Parameters
  • array_length (Quantity) – Length from beginning to end of the array as measured along the center column

  • channel_count (int) – Total (not per-column) number of coordinates to generate (i.e., electrode contacts)

  • intercol_space (Quantity) – Spacing between columns, with Brian unit

  • start_location (Quantity, optional) – Location of beginning of the array, that is, the first contact in the center column, by default (0, 0, 0)*mm

  • direction (Tuple[float, float, float], optional) – x, y, z vector indicating the direction along which the array extends, by default (0, 0, 1), meaning straight down

Returns

channel_count x 3 array of coordinates, where the 3 columns represent x, y, and z

Return type

Quantity

cleo.ephys.tetrode_shank_coords(array_length: brian2.units.fundamentalunits.Quantity, tetrode_count: int, start_location: brian2.units.fundamentalunits.Quantity = array([0., 0., 0.]) * metre, direction: Tuple[float, float, float] = (0, 0, 1), tetrode_width: brian2.units.fundamentalunits.Quantity = 25. * umetre) brian2.units.fundamentalunits.Quantity[source]#

Generate coordinates for a linear array of tetrodes

See https://www.neuronexus.com/products/electrode-arrays/up-to-15-mm-depth to visualize NeuroNexus-style arrays.

Parameters
  • array_length (Quantity) – Distance from the center of the first tetrode to the last (with a Brian unit)

  • tetrode_count (int) – Number of tetrodes desired

  • start_location (Quantity, optional) – Center location of the first tetrode in the array, by default (0, 0, 0)*mm

  • direction (Tuple[float, float, float], optional) – x, y, z vector determining the direction in which the linear array extends, by default (0, 0, 1), meaning straight down.

  • tetrode_width (Quantity, optional) – Distance between contacts in a single tetrode. Not the diagonal distance, but the length of one side of the square. By default 25*umeter, as in NeuroNexus probes.

Returns

(tetrode_count*4) x 3 array of coordinates, where 3 columns represent x, y, and z

Return type

Quantity

cleo.ephys.tile_coords(coords: brian2.units.fundamentalunits.Quantity, num_tiles: int, tile_vector: brian2.units.fundamentalunits.Quantity) brian2.units.fundamentalunits.Quantity[source]#

Tile (repeat) coordinates to produce multi-shank/matrix arrays

Parameters
  • coords (Quantity) – The n x 3 coordinates array to tile

  • num_tiles (int) – Number of times to tile (repeat) the coordinates. For example, if you are tiling linear shank coordinates to produce multi-shank coordinates, this would be the desired number of shanks

  • tile_vector (Quantity) – x, y, z array with Brian unit determining both the length and direction of the tiling

Returns

(n * num_tiles) x 3 array of coordinates, where the 3 columns represent x, y, and z

Return type

Quantity

cleo.light module#

class cleo.light.GaussianEllipsoid(sigma_axial: brian2.units.fundamentalunits.Quantity = 18. * umetre, sigma_lateral: brian2.units.fundamentalunits.Quantity = 8. * umetre)[source]#

Bases: cleo.light.light.LightModel

Method generated by attrs for class GaussianEllipsoid.

sigma_axial: brian2.units.fundamentalunits.Quantity#

Standard deviation distance along the focal axis.

Standard deviations estimated by taking point where response is ~60% of peak:

Publication

axial

lateral

measure

Prakash et al., 2012

13 μm

7 μm

photocurrent

Rickgauer et al., 2014

8 μm

4 μm

Ca2+ dF/F response

Packer et al., 2015

18 μm

8 μm

AP probability

Chen et al., 2019

18/11 μm

8/? μm

AP probability/photocurrent

sigma_lateral: brian2.units.fundamentalunits.Quantity#

Standard deviation distance along the focal plane.

transmittance(source_coords: brian2.units.fundamentalunits.Quantity, source_dir_uvec: nptyping.types._ndarray.NDArray[Any, 3, Any], target_coords: brian2.units.fundamentalunits.Quantity) nptyping.types._ndarray.NDArray[Any, Any, nptyping.types._number.Float][source]#

Output must be between 0 and shape (n_sources, n_targets).

viz_params(coords: brian2.units.fundamentalunits.Quantity, direction: nptyping.types._ndarray.NDArray[Any, 3, Any], T_threshold: float, n_points_per_source: int = 4000, **kwargs) brian2.units.fundamentalunits.Quantity[source]#

Outputs (m x n_points_per_source x 3 viz_points array, markersize_um, intensity_scale)

class cleo.light.Light(coords=array([0., 0., 0.]) * metre, direction: brian2.units.fundamentalunits.Quantity = (0, 0, 1), *, name: str = NOTHING, save_history: bool = True, light_model: cleo.light.light.LightModel, wavelength: brian2.units.fundamentalunits.Quantity = 0.473 * umetre, max_Irr0_mW_per_mm2: Optional[float] = None, max_Irr0_mW_per_mm2_viz: Optional[float] = None, default_value: nptyping.types._ndarray.NDArray[Any, nptyping.types._number.Float] = NOTHING)[source]#

Bases: cleo.base.Stimulator

Delivers photostimulation of the network.

Essentially “transfects” neurons and provides a light source. Under the hood, it delivers current via a Brian Synapses object.

Requires neurons to have 3D spatial coordinates already assigned. Also requires that the neuron model has a current term (by default Iopto) which is assumed to be positive (unlike the convention in many opsin modeling papers, where the current is described as negative).

See connect_to_neuron_group() for optional keyword parameters that can be specified when calling cleo.CLSimulator.inject().

Visualization kwargs
  • n_points_per_source (int, optional) – The number of points per light source used to represent light intensity in space. Default varies by light_model. Alias n_points.

  • T_threshold (float, optional) – The transmittance below which no points are plotted. By default 1e-3.

  • intensity (float, optional) – How bright the light appears, should be between 0 and 1. By default 0.5.

  • rasterized (bool, optional) – Whether to render as rasterized in vector output, True by default. Useful since so many points makes later rendering and editing slow.

Method generated by attrs for class Light.

add_self_to_plot(ax, axis_scale_unit, **kwargs) list[matplotlib.collections.PathCollection][source]#

Add device to an existing plot

Should only be called by plot().

Parameters
  • ax (Axes3D) – The existing matplotlib Axes object

  • axis_scale_unit (Unit) – The unit used to label axes and define chart limits

  • **kwargs (optional) –

Returns

A list of artists used to render the device. Needed for use in conjunction with VideoVisualizer.

Return type

list[Artist]

connect_to_neuron_group(neuron_group: brian2.groups.neurongroup.NeuronGroup, **kwparams: Any) None[source]#

Connect device to given neuron_group.

If your device introduces any objects which Brian must keep track of, such as a NeuronGroup, Synapses, or Monitor, make sure to add these to self.brian_objects.

Parameters
  • neuron_group (NeuronGroup) –

  • **kwparams (optional, passed from inject or) – inject

coords: Quantity#

(x, y, z) coords with Brian unit specifying where to place the base of the light source, by default (0, 0, 0)*mm. Can also be an nx3 array for multiple sources.

default_value: NDArray[Any, float]#

The default value of the device—used on initialization and on reset()

direction: NDArray[Any, 3, Any]#

(x, y, z) vector specifying direction in which light source is pointing, by default (0, 0, 1).

Will be converted to unit magnitude.

init_for_simulator(sim: CLSimulator) None[source]#

Initialize device for simulator on initial injection

This function is called only the first time a device is injected into a simulator and performs any operations that are independent of the individual neuron groups it is connected to.

Parameters

simulator (CLSimulator) – simulator being injected into

light_model: LightModel#

LightModel object defining how light is emitted. See OpticFiber for an example.

max_Irr0_mW_per_mm2: float#

The maximum irradiance the light source can emit.

Usually determined by hardware in a real experiment.

max_Irr0_mW_per_mm2_viz: float#

Maximum irradiance for visualization purposes.

i.e., the level at or above which the light appears maximally bright. Only relevant in video visualization.

property n#

Number of light sources

property source: brian2.groups.subgroup.Subgroup#
to_neo()[source]#

Return a neo.core.AnalogSignal object with the device’s data

Returns

Neo object representing exported data

Return type

neo.core.BaseNeo

transmittance(target_coords) numpy.ndarray[source]#
update(value: Union[float, numpy.ndarray]) None[source]#

Set the light intensity, in mW/mm2 (without unit) for 1P excitation or laser power (mW) for 2P excitation (GaussianEllipsoid light model).

Parameters

Irr0_mW_per_mm2 (float) – Desired light intensity for light source

update_artists(artists: list[matplotlib.artist.Artist], value, *args, **kwargs) list[matplotlib.artist.Artist][source]#

Update the artists used to render the device

Used to set the artists’ state at every frame of a video visualization. The current state would be passed in *args or **kwargs

Parameters

artists (list[Artist]) – the artists used to render the device originally, i.e., which were returned from the first add_self_to_plot() call.

Returns

The artists that were actually updated. Needed for efficient blit rendering, where only updated artists are re-rendered.

Return type

list[Artist]

wavelength: Quantity#

light wavelength with unit (usually nmeter)

class cleo.light.LightDependent(spectrum: list[tuple[float, float]] = NOTHING, spectrum_interpolator: typing.Callable = <function cubic_interpolator>)[source]#

Bases: object

Mix-in class for opsin and indicator. TODO

We approximate dynamics under multiple wavelengths using a weighted sum of photon fluxes, where the ε factor indicates the activation relative to the peak-sensitivity wavelength for a equivalent power, which most papers report. When they report the action spectrum for equivalent photon flux instead (see Mager et al, 2018), use equal_photon_flux_spectrum(). This weighted sum is an approximation of a nonlinear peak-non-peak wavelength relation; see notebooks/multi_wavelength_model.ipynb for details.

Method generated by attrs for class LightDependent.

epsilon(lambda_new) float[source]#

Returns the epsilon value for a given lambda (in nm) representing the relative sensitivity of the opsin to that wavelength.

property light_agg_ngs#
spectrum: list[tuple[float, float]]#

List of (wavelength, epsilon) tuples representing the action (opsin) or excitation (indicator) spectrum.

spectrum_interpolator: Callable#

Function of signature (lambdas_nm, epsilons, lambda_new_nm) that interpolates the action spectrum data and returns \(\varepsilon \in [0,1]\) for the new wavelength.

class cleo.light.LightModel[source]#

Bases: abc.ABC

Method generated by attrs for class LightModel.

abstract transmittance(source_coords: brian2.units.fundamentalunits.Quantity, source_direction: nptyping.types._ndarray.NDArray[Any, 3, Any], target_coords: brian2.units.fundamentalunits.Quantity) nptyping.types._ndarray.NDArray[Any, Any, nptyping.types._number.Float][source]#

Output must be between 0 and shape (n_sources, n_targets).

abstract viz_params(coords: brian2.units.fundamentalunits.Quantity, direction: nptyping.types._ndarray.NDArray[Any, 3, Any], T_threshold: float, n_points_per_source: Optional[int] = None, **kwargs) brian2.units.fundamentalunits.Quantity[source]#

Outputs (m x n_points_per_source x 3 viz_points array, markersize_um, intensity_scale)

class cleo.light.OpticFiber(R0: brian2.units.fundamentalunits.Quantity = 100. * umetre, NAfib: brian2.units.fundamentalunits.Quantity = 0.37, K: brian2.units.fundamentalunits.Quantity = 125. * metre ** - 1, S: brian2.units.fundamentalunits.Quantity = 7370. * metre ** - 1, ntis: brian2.units.fundamentalunits.Quantity = 1.36)[source]#

Bases: cleo.light.light.LightModel

Optic fiber light model from Foutz et al., 2012.

Defaults are from paper for 473 nm wavelength.

Method generated by attrs for class OpticFiber.

K: brian2.units.fundamentalunits.Quantity#

absorbance coefficient (wavelength/tissue dependent)

NAfib: brian2.units.fundamentalunits.Quantity#

optical fiber numerical aperture

R0: brian2.units.fundamentalunits.Quantity#

optical fiber radius

S: brian2.units.fundamentalunits.Quantity#

scattering coefficient (wavelength/tissue dependent)

ntis: brian2.units.fundamentalunits.Quantity#

tissue index of refraction (wavelength/tissue dependent)

transmittance(source_coords: brian2.units.fundamentalunits.Quantity, source_dir_uvec: nptyping.types._ndarray.NDArray[Any, 3, Any], target_coords: brian2.units.fundamentalunits.Quantity) nptyping.types._ndarray.NDArray[Any, Any, nptyping.types._number.Float][source]#

Output must be between 0 and shape (n_sources, n_targets).

viz_params(coords: brian2.units.fundamentalunits.Quantity, direction: nptyping.types._ndarray.NDArray[Any, 3, Any], T_threshold: float, n_points_per_source: int = 4000, **kwargs) brian2.units.fundamentalunits.Quantity[source]#

Outputs (m x n_points_per_source x 3 viz_points array, markersize_um, intensity_scale)

cleo.light.cubic_interpolator(lambdas_nm, epsilons, lambda_new_nm)[source]#
cleo.light.equal_photon_flux_spectrum(spectrum: list[tuple[float, float]]) list[tuple[float, float]][source]#

Converts an equival photon flux spectrum to an equal power density spectrum.

cleo.light.fiber473nm(R0=100. * umetre, NAfib=0.37, K=125. * metre ** - 1, S=7370. * metre ** - 1, ntis=1.36) cleo.light.light.OpticFiber[source]#

Light parameters for 473 nm wavelength delivered via an optic fiber.

From Foutz et al., 2012. See OpticFiber for parameter descriptions.

cleo.light.linear_interpolator(lambdas_nm, epsilons, lambda_new_nm)[source]#
cleo.light.plot_spectra(*ldds: cleo.light.light_dependence.LightDependent)[source]#
cleo.light.tp_light_from_scope(scope, wavelength=1.06 * umetre, **kwargs)[source]#

cleo.opto module#

Contains opsin models, light sources, and some parameters

class cleo.opto.BansalFourStateOpsin(extra_namespace: dict = NOTHING, spectrum: list[tuple[float, float]] = NOTHING, spectrum_interpolator: typing.Callable = <function cubic_interpolator>, Gd1: brian2.units.fundamentalunits.Quantity = 66. * hertz, Gd2: brian2.units.fundamentalunits.Quantity = 10. * hertz, Gr0: brian2.units.fundamentalunits.Quantity = 0.333 * hertz, g0: brian2.units.fundamentalunits.Quantity = 3.2 * nsiemens, phim: brian2.units.fundamentalunits.Quantity = 1.e+22 * metre ** -2 * second ** -1, k1: brian2.units.fundamentalunits.Quantity = 0.4 * khertz, k2: brian2.units.fundamentalunits.Quantity = 120. * hertz, Gf0: brian2.units.fundamentalunits.Quantity = 18. * hertz, Gb0: brian2.units.fundamentalunits.Quantity = 8. * hertz, kf: brian2.units.fundamentalunits.Quantity = 10. * hertz, kb: brian2.units.fundamentalunits.Quantity = 8. * hertz, gamma: brian2.units.fundamentalunits.Quantity = 0.05, p: brian2.units.fundamentalunits.Quantity = 1, q: brian2.units.fundamentalunits.Quantity = 1, E: brian2.units.fundamentalunits.Quantity = 0. * volt, *, name: str = NOTHING, save_history: bool = True)[source]#

Bases: cleo.opto.opsins.MarkovOpsin

4-state model from Bansal et al. 2020.

The difference from the PyRhO model is that there is no voltage dependence.

rho_rel is channel density relative to standard model fit; modifying it post-injection allows for heterogeneous opsin expression.

IOPTO_VAR_NAME and V_VAR_NAME are substituted on injection.

Method generated by attrs for class BansalFourStateOpsin.

E: Quantity#
Gb0: Quantity#
Gd1: Quantity#
Gd2: Quantity#
Gf0: Quantity#
Gr0: Quantity#
g0: Quantity#
gamma: Quantity#
init_syn_vars(opto_syn: brian2.synapses.synapses.Synapses) None[source]#

Initializes appropriate variables in Synapses implementing the model

Can also be used to reset the variables.

Parameters

syn (Synapses) – The synapses object implementing this model

k1: Quantity#
k2: Quantity#
kb: Quantity#
kf: Quantity#
model: str#

Basic Brian model equations string.

Should contain a rho_rel term reflecting relative expression levels. Will likely also contain special NeuronGroup-dependent symbols such as V_VAR_NAME to be replaced on injection in modify_model_and_params_for_ng().

p: Quantity#
phim: Quantity#
q: Quantity#
class cleo.opto.FourStateOpsin(spectrum: list[tuple[float, float]] = NOTHING, spectrum_interpolator: typing.Callable = <function cubic_interpolator>, g0: brian2.units.fundamentalunits.Quantity = 114. * nsiemens, gamma: brian2.units.fundamentalunits.Quantity = 0.00742, phim: brian2.units.fundamentalunits.Quantity = 2.33e+23 * metre ** -2 * second ** -1, k1: brian2.units.fundamentalunits.Quantity = 4.15 * khertz, k2: brian2.units.fundamentalunits.Quantity = 0.868 * khertz, p: brian2.units.fundamentalunits.Quantity = 0.833, Gf0: brian2.units.fundamentalunits.Quantity = 37.3 * hertz, kf: brian2.units.fundamentalunits.Quantity = 58.1 * hertz, Gb0: brian2.units.fundamentalunits.Quantity = 16.1 * hertz, kb: brian2.units.fundamentalunits.Quantity = 63. * hertz, q: brian2.units.fundamentalunits.Quantity = 1.94, Gd1: brian2.units.fundamentalunits.Quantity = 105. * hertz, Gd2: brian2.units.fundamentalunits.Quantity = 13.8 * hertz, Gr0: brian2.units.fundamentalunits.Quantity = 0.33 * hertz, E: brian2.units.fundamentalunits.Quantity = 0. * volt, v0: brian2.units.fundamentalunits.Quantity = 43. * mvolt, v1: brian2.units.fundamentalunits.Quantity = 17.1 * mvolt, *, name: str = NOTHING, save_history: bool = True)[source]#

Bases: cleo.opto.opsins.MarkovOpsin

4-state model from PyRhO (Evans et al. 2016).

rho_rel is channel density relative to standard model fit; modifying it post-injection allows for heterogeneous opsin expression.

IOPTO_VAR_NAME and V_VAR_NAME are substituted on injection.

Defaults are for ChR2.

Method generated by attrs for class FourStateOpsin.

E: Quantity#
Gb0: Quantity#
Gd1: Quantity#
Gd2: Quantity#
Gf0: Quantity#
Gr0: Quantity#
extra_namespace: dict[str, Any]#

Additional items (beyond parameters) to be added to the opto synapse namespace

g0: Quantity#
gamma: Quantity#
init_syn_vars(opto_syn: brian2.synapses.synapses.Synapses) None[source]#

Initializes appropriate variables in Synapses implementing the model

Can also be used to reset the variables.

Parameters

syn (Synapses) – The synapses object implementing this model

k1: Quantity#
k2: Quantity#
kb: Quantity#
kf: Quantity#
model: str#

Basic Brian model equations string.

Should contain a rho_rel term reflecting relative expression levels. Will likely also contain special NeuronGroup-dependent symbols such as V_VAR_NAME to be replaced on injection in modify_model_and_params_for_ng().

p: Quantity#
phim: Quantity#
q: Quantity#
v0: Quantity#
v1: Quantity#
class cleo.opto.Opsin(extra_namespace: dict = NOTHING, spectrum: list[tuple[float, float]] = NOTHING, spectrum_interpolator: typing.Callable = <function cubic_interpolator>, *, name: str = NOTHING, save_history: bool = True)[source]#

Bases: cleo.light.light_dependence.LightDependent, cleo.base.SynapseDevice

Base class for opsin model.

We approximate dynamics under multiple wavelengths using a weighted sum of photon fluxes, where the ε factor indicates the activation relative to the peak-sensitivy wavelength for an equivalent number of photons (see Mager et al, 2018). This weighted sum is an approximation of a nonlinear peak-non-peak wavelength relation; see notebooks/multi_wavelength_model.ipynb for details.

Method generated by attrs for class Opsin.

property action_spectrum#

Alias for light_receptor.spectrum

spectrum: list[tuple[float, float]]#

List of (wavelength, epsilon) tuples representing the action (opsin) or excitation (indicator) spectrum.

spectrum_interpolator: Callable#

Function of signature (lambdas_nm, epsilons, lambda_new_nm) that interpolates the action spectrum data and returns \(\varepsilon \in [0,1]\) for the new wavelength.

class cleo.opto.ProportionalCurrentOpsin(extra_namespace: dict = NOTHING, spectrum: list[tuple[float, float]] = NOTHING, spectrum_interpolator: typing.Callable = <function cubic_interpolator>, *, name: str = NOTHING, save_history: bool = True, I_per_Irr: brian2.units.fundamentalunits.Quantity)[source]#

Bases: cleo.opto.opsins.Opsin

A simple model delivering current proportional to light intensity

Method generated by attrs for class ProportionalCurrentOpsin.

I_per_Irr: Quantity#

How much current (in amps or unitless, depending on neuron model) to deliver per mW/mm2.

model: str#

Basic Brian model equations string.

Should contain a rho_rel term reflecting relative expression levels. Will likely also contain special NeuronGroup-dependent symbols such as V_VAR_NAME to be replaced on injection in modify_model_and_params_for_ng().

required_vars: list[Tuple[str, Unit]]#

Default names of state variables required in the neuron group, along with units, e.g., [(‘Iopto’, amp)].

It is assumed that non-default values can be passed in on injection as a keyword argument [default_name]_var_name=[non_default_name] and that these are found in the model string as [DEFAULT_NAME]_VAR_NAME before replacement.

cleo.opto.chr2_4s() cleo.opto.opsins.FourStateOpsin[source]#

Returns a 4-state ChR2 model.

Params taken from try.projectpyrho.org’s default 4-state configuration. Action spectrum from Nagel et al., 2003, Fig. 4a, extracted using Plot Digitizer.

Parameters can be changed after initialization but before injection.

cleo.opto.chr2_b4s() cleo.opto.opsins.BansalFourStateOpsin[source]#

Returns a 4-state Vf-Chrimson model.

Params given in Bansal et al., 2020. Action spectrum from Nagel et al., 2003, Fig. 4a, extracted using Plot Digitizer.

Parameters can be changed after initialization but before injection.

cleo.opto.chrimson_4s() cleo.opto.opsins.BansalFourStateOpsin[source]#

Returns a 4-state Chrimson model.

Params given in Bansal et al., 2020. Action spectrum from Mager et al., 2018, Supp. Fig. 1a, extracted using Plot Digitizer.

Parameters can be changed after initialization but before injection.

cleo.opto.gtacr2_4s() cleo.opto.opsins.BansalFourStateOpsin[source]#

Returns a 4-state model of GtACR2, an anion channel.

Params given in Bansal et al., 2020. Action spectra from Govorunova et al., 2015, Fig. 1f, extracted using Plot Digitizer.

Parameters can be changed after initialization but before injection.

cleo.opto.vfchrimson_4s() cleo.opto.opsins.BansalFourStateOpsin[source]#

Returns a 4-state Vf-Chrimson model.

Params given in Bansal et al., 2020. Action spectrum from Mager et al., 2018, Supp. Fig. 1a, extracted using Plot Digitizer.

Parameters can be changed after initialization but before injection.

cleo.imaging module#

class cleo.imaging.CalBindingActivationModel(model: str)[source]#

Bases: object

Base class for modeling calcium binding/activation

Method generated by attrs for class CalBindingActivationModel.

model: str#
class cleo.imaging.CalciumModel(model: str)[source]#

Bases: object

Base class for how GECI computes calcium concentration

Must provide variable Ca (molar) in model.

Method generated by attrs for class CalciumModel.

model: str#
on_pre: str#
class cleo.imaging.DoubExpCalBindingActivation(*, A: float, tau_on: brian2.units.fundamentalunits.Quantity, tau_off: brian2.units.fundamentalunits.Quantity, Ca_rest: brian2.units.fundamentalunits.Quantity)[source]#

Bases: cleo.imaging.sensors.CalBindingActivationModel

Double exponential kernel convolution representing CaB binding/activation.

Convolution is implemented via ODEs; see notebooks/double_exp_conv_as_ode.ipynb for derivation.

A, tau_on, and tau_off are the versions with proper scale and units of NAOMi’s ca_amp, t_on, and t_off.

Some parameters found here. Parameters fit here.

Method generated by attrs for class DoubExpCalBindingActivation.

A: float#

amplitude of double exponential kernel

Ca_rest: brian2.units.fundamentalunits.Quantity#

Resting Ca2+ concentration (molar).

init_syn_vars(syn: brian2.synapses.synapses.Synapses) None[source]#
model: str#
tau_off: brian2.units.fundamentalunits.Quantity#

CaB unbinding/deactivation time constant (sec)

tau_on: brian2.units.fundamentalunits.Quantity#

CaB binding/activation time constant (sec)

class cleo.imaging.DynamicCalcium(*, Ca_rest: brian2.units.fundamentalunits.Quantity, gamma: brian2.units.fundamentalunits.Quantity, B_T: brian2.units.fundamentalunits.Quantity, kappa_S: float, dCa_T: brian2.units.fundamentalunits.Quantity)[source]#

Bases: cleo.imaging.sensors.CalciumModel

Pieced together from Lütke et al., 2013; Helmchen and Tank, 2015; and Song et al., 2021. (code)

Method generated by attrs for class DynamicCalcium.

B_T: brian2.units.fundamentalunits.Quantity#

total indicator (buffer) concentration (molar)

Ca_rest: brian2.units.fundamentalunits.Quantity#

resting Ca2+ concentration (molar)

dCa_T: brian2.units.fundamentalunits.Quantity#

total Ca2+ concentration increase per spike (molar)

gamma: brian2.units.fundamentalunits.Quantity#

clearance/extrusion rate (1/sec)

init_syn_vars(syn: brian2.synapses.synapses.Synapses) None[source]#
kappa_S: float#

Ca2+ binding ratio of the endogenous buffer

model: str#

from eq 8 in Lütke et al., 2013

on_pre: str#

from eq 9 in Lütke et al., 2013

class cleo.imaging.ExcitationModel(model: str)[source]#

Bases: object

Defines exc_factor

Method generated by attrs for class ExcitationModel.

model: str#
class cleo.imaging.GECI(extra_namespace: dict = NOTHING, *, name: str = NOTHING, save_history: bool = True, sigma_noise: float, dFF_1AP: float, cal_model: cleo.imaging.sensors.CalciumModel, bind_act_model: cleo.imaging.sensors.CalBindingActivationModel, exc_model: cleo.imaging.sensors.ExcitationModel, K_d: brian2.units.fundamentalunits.Quantity, n_H: float, dFF_max: float)[source]#

Bases: cleo.imaging.sensors.Sensor

GECI model based on Song et al., 2021, with interchangeable components.

See geci() for a convenience function for creating GECI models.

As a potentially simpler alternative for future work, see the phenomological S2F model from Zhang et al., 2023. While parameter count looks similar, at least they have parameters fit already, and directly to data, rather than to biophysical processes before the data.

Method generated by attrs for class GECI.

K_d: Quantity#

indicator dissociation constant (binding affinity) (molar)

bind_act_model: CalBindingActivationModel#
cal_model: CalciumModel#
dFF_max: float#

amplitude of Hill equation for conversion from Ca2+ to ΔF/F, Fmax/F0. May be approximated from ‘dynamic range’ in literature Fmax/Fmin

exc_model: ExcitationModel#
fluor_model: str#

Uses a Hill equation to convert from Ca2+ to ΔF/F, as in Song et al., 2021

get_state() dict[brian2.groups.neurongroup.NeuronGroup, numpy.ndarray][source]#

Returns a list of arrays in the order neuron groups/targets were received.

Signals should be normalized to baseline of 0 and 1 corresponding to an action potential peak.

init_syn_vars(syn: brian2.synapses.synapses.Synapses) None[source]#

Initializes appropriate variables in Synapses implementing the model

Can also be used to reset the variables.

Parameters

syn (Synapses) – The synapses object implementing this model

location: str#

cytoplasm or membrane

n_H: float#

Hill coefficient for conversion from Ca2+ to ΔF/F

property params: dict#

Returns a dictionary of parameters for the model

class cleo.imaging.LightExcitation[source]#

Bases: cleo.imaging.sensors.ExcitationModel

Method generated by attrs for class LightExcitation.

model: str#
class cleo.imaging.NullBindingActivation[source]#

Bases: cleo.imaging.sensors.CalBindingActivationModel

Doesn’t model binding/activation; i.e., goes straight from [Ca2+] to ΔF/F

Method generated by attrs for class NullBindingActivation.

model: str#
class cleo.imaging.NullExcitation[source]#

Bases: cleo.imaging.sensors.ExcitationModel

Method generated by attrs for class NullExcitation.

model: str#
class cleo.imaging.PreexistingCalcium[source]#

Bases: cleo.imaging.sensors.CalciumModel

Calcium concentration is pre-existing in neuron model

Method generated by attrs for class PreexistingCalcium.

model: str#
class cleo.imaging.Scope(sensor: cleo.imaging.sensors.Sensor, img_width: brian2.units.fundamentalunits.Quantity, focus_depth: Optional[brian2.units.fundamentalunits.Quantity] = None, location: brian2.units.fundamentalunits.Quantity = array([0., 0., 0.]) * metre, direction: brian2.units.fundamentalunits.Quantity = (0, 0, 1), soma_radius: brian2.units.fundamentalunits.Quantity = 10. * umetre, snr_cutoff: float = 1, rand_seed: Optional[int] = None, *, name: str = NOTHING, save_history: bool = True)[source]#

Bases: cleo.base.Recorder

rho_rel_generator : callable, takes n, outputs float array

Method generated by attrs for class Scope.

add_self_to_plot(ax: mpl_toolkits.mplot3d.axes3d.Axes3D, axis_scale_unit: brian2.units.fundamentalunits.Unit, **kwargs) list[matplotlib.artist.Artist][source]#

Add device to an existing plot

Should only be called by plot().

Parameters
  • ax (Axes3D) – The existing matplotlib Axes object

  • axis_scale_unit (Unit) – The unit used to label axes and define chart limits

  • **kwargs (optional) –

Returns

A list of artists used to render the device. Needed for use in conjunction with VideoVisualizer.

Return type

list[Artist]

connect_to_neuron_group(neuron_group: brian2.groups.neurongroup.NeuronGroup, **kwparams) None[source]#

Connect device to given neuron_group.

If your device introduces any objects which Brian must keep track of, such as a NeuronGroup, Synapses, or Monitor, make sure to add these to self.brian_objects.

Parameters
  • neuron_group (NeuronGroup) –

  • **kwparams (optional, passed from inject or) – inject

dFF: list[NDArray[Any, float]]#

ΔF/F from every call to get_state(). Shape is (n_samples, n_ROIs). Stored if save_history

property dFF_1AP#

gets dFF_1AP for all targets, in order injected. Varies with expression levels.

direction: NDArray[3, float]#
focus_coords_per_injct: list[NDArray[Any, float]]#
focus_depth: Quantity#
get_state() nptyping.types._ndarray.NDArray[Any, nptyping.types._number.Float][source]#

Return current measurement.

i_targets_for_neuron_group(neuron_group)[source]#

can handle multiple injections into same ng

i_targets_per_injct: list[NDArray[Any, int]]#
img_width: Quantity#
inject_sensor_for_targets(**kwparams) None[source]#
location: Quantity#
property n#
neuron_groups: list[NeuronGroup]#
rand_seed: int#
reset(**kwargs) None[source]#

Reset the device to a neutral state

rho_rel_per_injct: list[NDArray[Any, float]]#
sensor: Sensor#
property sigma_noise#

gets noise for all targets, in order injected.

sigma_per_injct: list[NDArray[Any, float]]#
snr_cutoff: float#

applied only when not focus_depth is not None

soma_radius: Quantity#
t_ms: list[float]#

Times at which sensor traces are recorded, in ms, stored if save_history

target_neurons_in_plane(ng, focus_depth: Optional[brian2.units.fundamentalunits.Quantity] = None, soma_radius: Optional[brian2.units.fundamentalunits.Quantity] = None) tuple[NDArray[Any, Int[64]], NDArray[Any, Float[64]]][source]#
class cleo.imaging.Sensor(extra_namespace: dict = NOTHING, *, name: str = NOTHING, save_history: bool = True, sigma_noise: float, dFF_1AP: float, location: str)[source]#

Bases: cleo.base.SynapseDevice

Base class for sensors

Method generated by attrs for class Sensor.

dFF_1AP: float#

ΔF/F for 1 AP, only used for scope SNR cutoff

property exc_spectrum: list[tuple[float, float]]#

Excitation spectrum, alias for spectrum

get_state() dict[brian2.groups.neurongroup.NeuronGroup, numpy.ndarray][source]#

Returns a list of arrays in the order neuron groups/targets were received.

Signals should be normalized to baseline of 0 and 1 corresponding to an action potential peak.

location: str#

cytoplasm or membrane

sigma_noise: float#

standard deviation of Gaussian noise in ΔF/F measurement

property snr: float#

Signal-to-noise ratio for 1 AP

cleo.imaging.gcamp3(light_dependent=False, doub_exp_conv=True, pre_existing_cal=False, K_d=287. * nmolar, n_H=2.52, dFF_max=12, sigma_noise=0.018571428571428572, dFF_1AP=0.039, ca_amp=0.05, t_on=1, t_off=1, Ca_rest=50. * nmolar, kappa_S=110, gamma=292.3 * hertz, B_T=200. * umolar, dCa_T=7.6 * umolar, name='gcamp3', **kwparams)#

Returns a GECI model with parameters given in NAOMi’s code (Song et al., 2021) as well as Dana et al., 2019 and Zhang et al., 2023.

Only those parameters used in chosen model components apply. If the default is None, then we don’t have it fit yet.

cleo.imaging.gcamp6f(light_dependent=False, doub_exp_conv=True, pre_existing_cal=False, K_d=290. * nmolar, n_H=2.7, dFF_max=25.2, sigma_noise=0.03748181818181818, dFF_1AP=0.09775500000000001, ca_amp=76.1251, t_on=0.8535, t_off=98.6173, Ca_rest=50. * nmolar, kappa_S=110, gamma=292.3 * hertz, B_T=200. * umolar, dCa_T=7.6 * umolar, name='gcamp6f', **kwparams)#

Returns a GECI model with parameters given in NAOMi’s code (Song et al., 2021) as well as Dana et al., 2019 and Zhang et al., 2023.

Only those parameters used in chosen model components apply. If the default is None, then we don’t have it fit yet.

cleo.imaging.gcamp6rs06(light_dependent=False, doub_exp_conv=True, pre_existing_cal=False, K_d=0.32 * umolar, n_H=3, dFF_max=15, sigma_noise=0.030227272727272728, dFF_1AP=None, ca_amp=None, t_on=None, t_off=None, Ca_rest=50. * nmolar, kappa_S=110, gamma=292.3 * hertz, B_T=200. * umolar, dCa_T=7.6 * umolar, name='gcamp6rs06', **kwparams)#

Returns a GECI model with parameters given in NAOMi’s code (Song et al., 2021) as well as Dana et al., 2019 and Zhang et al., 2023.

Only those parameters used in chosen model components apply. If the default is None, then we don’t have it fit yet.

Don’t know sigma_noise

cleo.imaging.gcamp6rs09(light_dependent=False, doub_exp_conv=True, pre_existing_cal=False, K_d=0.52 * umolar, n_H=3.2, dFF_max=25, sigma_noise=0.030227272727272728, dFF_1AP=None, ca_amp=None, t_on=None, t_off=None, Ca_rest=50. * nmolar, kappa_S=110, gamma=292.3 * hertz, B_T=200. * umolar, dCa_T=7.6 * umolar, name='gcamp6rs09', **kwparams)#

Returns a GECI model with parameters given in NAOMi’s code (Song et al., 2021) as well as Dana et al., 2019 and Zhang et al., 2023.

Only those parameters used in chosen model components apply. If the default is None, then we don’t have it fit yet.

Don’t know sigma_noise

cleo.imaging.gcamp6s(light_dependent=False, doub_exp_conv=True, pre_existing_cal=False, K_d=147. * nmolar, n_H=2.45, dFF_max=27.2, sigma_noise=0.030227272727272728, dFF_1AP=0.133, ca_amp=54.6943, t_on=0.4526, t_off=68.5461, Ca_rest=50. * nmolar, kappa_S=110, gamma=292.3 * hertz, B_T=200. * umolar, dCa_T=7.6 * umolar, name='gcamp6s', **kwparams)#

Returns a GECI model with parameters given in NAOMi’s code (Song et al., 2021) as well as Dana et al., 2019 and Zhang et al., 2023.

Only those parameters used in chosen model components apply. If the default is None, then we don’t have it fit yet.

cleo.imaging.geci(light_dependent, doub_exp_conv, pre_existing_cal, **kwparams)[source]#
cleo.imaging.jgcamp7b(light_dependent=False, doub_exp_conv=True, pre_existing_cal=False, K_d=82. * nmolar, n_H=3.06, dFF_max=22.1, sigma_noise=0.007556818181818182, dFF_1AP=None, ca_amp=None, t_on=None, t_off=None, Ca_rest=50. * nmolar, kappa_S=110, gamma=292.3 * hertz, B_T=200. * umolar, dCa_T=7.6 * umolar, name='jgcamp7b', **kwparams)#

Returns a GECI model with parameters given in NAOMi’s code (Song et al., 2021) as well as Dana et al., 2019 and Zhang et al., 2023.

Only those parameters used in chosen model components apply. If the default is None, then we don’t have it fit yet.

cleo.imaging.jgcamp7c(light_dependent=False, doub_exp_conv=True, pre_existing_cal=False, K_d=298. * nmolar, n_H=2.44, dFF_max=145.6, sigma_noise=0.011788636363636364, dFF_1AP=None, ca_amp=None, t_on=None, t_off=None, Ca_rest=50. * nmolar, kappa_S=110, gamma=292.3 * hertz, B_T=200. * umolar, dCa_T=7.6 * umolar, name='jgcamp7c', **kwparams)#

Returns a GECI model with parameters given in NAOMi’s code (Song et al., 2021) as well as Dana et al., 2019 and Zhang et al., 2023.

Only those parameters used in chosen model components apply. If the default is None, then we don’t have it fit yet.

cleo.imaging.jgcamp7f(light_dependent=False, doub_exp_conv=True, pre_existing_cal=False, K_d=174. * nmolar, n_H=2.3, dFF_max=30.2, sigma_noise=0.021763636363636363, dFF_1AP=None, ca_amp=None, t_on=None, t_off=None, Ca_rest=50. * nmolar, kappa_S=110, gamma=292.3 * hertz, B_T=200. * umolar, dCa_T=7.6 * umolar, name='jgcamp7f', **kwparams)#

Returns a GECI model with parameters given in NAOMi’s code (Song et al., 2021) as well as Dana et al., 2019 and Zhang et al., 2023.

Only those parameters used in chosen model components apply. If the default is None, then we don’t have it fit yet.

cleo.imaging.jgcamp7s(light_dependent=False, doub_exp_conv=True, pre_existing_cal=False, K_d=68. * nmolar, n_H=2.49, dFF_max=40.4, sigma_noise=0.009975000000000001, dFF_1AP=None, ca_amp=None, t_on=None, t_off=None, Ca_rest=50. * nmolar, kappa_S=110, gamma=292.3 * hertz, B_T=200. * umolar, dCa_T=7.6 * umolar, name='jgcamp7s', **kwparams)#

Returns a GECI model with parameters given in NAOMi’s code (Song et al., 2021) as well as Dana et al., 2019 and Zhang et al., 2023.

Only those parameters used in chosen model components apply. If the default is None, then we don’t have it fit yet.

cleo.imaging.ogb1(light_dependent=False, doub_exp_conv=True, pre_existing_cal=False, K_d=250. * nmolar, n_H=1, dFF_max=14, sigma_noise=0.030227272727272728, dFF_1AP=None, ca_amp=None, t_on=None, t_off=None, Ca_rest=50. * nmolar, kappa_S=110, gamma=292.3 * hertz, B_T=200. * umolar, dCa_T=7.6 * umolar, name='ogb1', **kwparams)#

Returns a GECI model with parameters given in NAOMi’s code (Song et al., 2021) as well as Dana et al., 2019 and Zhang et al., 2023.

Only those parameters used in chosen model components apply. If the default is None, then we don’t have it fit yet.

Don’t know sigma_noise

cleo.imaging.target_neurons_in_plane(ng, scope_focus_depth, scope_img_width, scope_location=array([0., 0., 0.]) * metre, scope_direction=(0, 0, 1), soma_radius=10. * umetre, sensor_location='cytoplasm')[source]#

Returns a tuple of (i_targets, noise_focus_factor, coords_on_plane)

cleo.ioproc module#

Classes and functions for constructing and configuring an IOProcessor.

class cleo.ioproc.ConstantDelay(delay_ms: float)[source]#

Bases: cleo.ioproc.delays.Delay

Simply adds a constant delay to the computation

Parameters

delay_ms (float) – Desired delay in milliseconds

compute()[source]#

Compute delay.

class cleo.ioproc.Delay[source]#

Bases: abc.ABC

Abstract base class for computing delays.

abstract compute() float[source]#

Compute delay.

class cleo.ioproc.FiringRateEstimator(tau_ms: float, sample_period_ms: float, **kwargs)[source]#

Bases: cleo.ioproc.base.ProcessingBlock

Exponential filter to estimate firing rate.

Requires sample_time_ms kwarg when process is called.

Parameters
  • tau_ms (float) – Time constant of filter

  • sample_period_ms (float) – Sampling period in milliseconds

compute_output(input: nptyping.types._ndarray.NDArray[Any, nptyping.types._number.UInt], **kwargs) nptyping.types._ndarray.NDArray[Any, nptyping.types._number.Float][source]#

Estimate firing rate given past and current spikes.

Parameters

input (NDArray[(n,), np.uint]) – n-length vector of spike counts

Keyword Arguments

sample_time_ms (float) – Time measurement was taken in milliseconds

Returns

n-length vector of firing rates

Return type

NDArray[(n,), float]

delay: Delay#

The delay object determining compute latency for the block

save_history: bool#

Whether to record t_in_ms, t_out_ms, and values with every timestep

t_in_ms: list[float]#

The walltime the block received each input. Only recorded if save_history

t_out_ms: list[float]#

The walltime of each of the block’s outputs. Only recorded if save_history

values: list[Any]#

Each of the block’s outputs. Only recorded if save_history

class cleo.ioproc.GaussianDelay(loc: float, scale: float)[source]#

Bases: cleo.ioproc.delays.Delay

Generates normal-distributed delay.

Will return 0 when a negative value is sampled.

Parameters
  • loc (float) – Center of distribution

  • scale (float) – Standard deviation of delay distribution

compute() float[source]#

Compute delay.

class cleo.ioproc.LatencyIOProcessor(sample_period_ms: float, **kwargs)[source]#

Bases: cleo.base.IOProcessor

IOProcessor capable of delivering stimulation some time after measurement.

Parameters

sample_period_ms (float) – Determines how frequently samples are taken from the network.

Keyword Arguments
  • sampling (str) –

    “fixed” or “when idle”; “fixed” by default

    ”fixed” sampling means samples are taken on a fixed schedule, with no exceptions.

    ”when idle” sampling means no samples are taken before the previous sample’s output has been delivered. A sample is taken ASAP after an over-period computation: otherwise remains on schedule.

  • processing (str) –

    “parallel” or “serial”; “parallel” by default

    ”parallel” computes the output time by adding the delay for a sample onto the sample time, so if the delay is 2 ms, for example, while the sample period is only 1 ms, some of the processing is happening in parallel. Output order matches input order even if the computed output time for a sample is sooner than that for a previous sample.

    ”serial” computes the output time by adding the delay for a sample onto the output time of the previous sample, rather than the sampling time. Note this may be of limited utility because it essentially means the entire round trip cannot be in parallel at all. More realistic is that simply each block or phase of computation must be serial. If anyone cares enough about this, it will have to be implemented in the future.

Note

It doesn’t make much sense to combine parallel computation with “when idle” sampling, because “when idle” sampling only produces one sample at a time to process.

Raises

ValueError – For invalid sampling or processing kwargs

get_ctrl_signal(query_time_ms)[source]#

Get per-stimulator control signal from the IOProcessor.

Parameters

time (Brian 2 temporal Unit) – Current timestep

Returns

A {‘stimulator_name’: value} dictionary for updating stimulators.

Return type

dict

is_sampling_now(query_time_ms)[source]#

Determines whether the processor will take a sample at this timestep.

Parameters

time (Brian 2 temporal Unit) – Current timestep.

Return type

bool

abstract process(state_dict: dict, sample_time_ms: float) Tuple[dict, float][source]#

Process network state to generate output to update stimulators.

This is the function the user must implement to define the signal processing pipeline.

Parameters
  • state_dict (dict) – {recorder_name: state} dictionary from get_state()

  • time_ms (float) –

Returns

{‘stim_name’: ctrl_signal} dictionary and output time in milliseconds.

Return type

Tuple[dict, float]

put_state(state_dict: dict, sample_time_ms)[source]#

Deliver network state to the IOProcessor.

Parameters
  • state_dict (dict) – A dictionary of recorder measurements, as returned by get_state()

  • time (brian2 temporal Unit) – The current simulation timestep. Essential for simulating control latency and for time-varying control.

t_samp_ms: list[float]#

Record of sampling times—each time put_state() is called.

class cleo.ioproc.PIController(ref_signal: callable, Kp: float, Ki: float = 0, sample_period_ms: float = 0, **kwargs: Any)[source]#

Bases: cleo.ioproc.base.ProcessingBlock

Simple PI controller.

compute_output() requires a sample_time_ms keyword argument. Only tested on controlling scalar values, but could be easily adapted to controlling a multi-dimensional state.

Parameters
  • ref_signal (callable) – Must return the target as a function of time in ms

  • Kp (float) – Gain on the proportional error

  • Ki (float, optional) – Gain on the integral error, by default 0

  • sample_period_ms (float, optional) – Rate at which processor takes samples, by default 0. Only used to compute integrated error on first sample

compute_output(input: float, **kwargs) float[source]#

Compute control input to the system using previously specified gains.

Parameters

input (Any) – Current system state

Returns

Control signal

Return type

float

ref_signal: callable[[float], Any]#

Callable returning the target as a function of time in ms

class cleo.ioproc.ProcessingBlock(**kwargs)[source]#

Bases: abc.ABC

Abstract signal processing stage or control block.

It’s important to use super().__init__(**kwargs) in the base class to use the parent-class logic here.

Keyword Arguments

delay (Delay) – Delay object which adds to the compute time

Raises

TypeError – When delay is not a Delay object.

abstract compute_output(input: Any, **kwargs) Any[source]#

Computes output for given input.

This is where the user will implement the desired functionality of the ProcessingBlock without regard for latency.

Parameters
  • input (Any) – Data to be processed. Passed in from process().

  • **kwargs (Any) – optional key-value argument pairs passed from process(). Could be used to pass in such values as the IO processor’s walltime or the measurement time for time- dependent functions.

Returns

output

Return type

Any

delay: cleo.ioproc.delays.Delay#

The delay object determining compute latency for the block

process(input: Any, t_in_ms: float, **kwargs) Tuple[Any, float][source]#

Computes and saves output and output time given input and input time.

The user should implement compute_output() for their child classes, which performs the computation itself without regards for timing or saving variables.

Parameters
  • input (Any) – Data to be processed

  • t_in_ms (float) – Time the block receives the input data

  • **kwargs (Any) – Key-value list of arguments passed to compute_output()

Returns

output, out time in milliseconds

Return type

Tuple[Any, float]

save_history: bool#

Whether to record t_in_ms, t_out_ms, and values with every timestep

t_in_ms: list[float]#

The walltime the block received each input. Only recorded if save_history

t_out_ms: list[float]#

The walltime of each of the block’s outputs. Only recorded if save_history

values: list[Any]#

Each of the block’s outputs. Only recorded if save_history

class cleo.ioproc.RecordOnlyProcessor(sample_period_ms, **kwargs)[source]#

Bases: cleo.ioproc.base.LatencyIOProcessor

Take samples without performing any control.

Use this if all you are doing is recording.

Parameters

sample_period_ms (float) – Determines how frequently samples are taken from the network.

Keyword Arguments
  • sampling (str) –

    “fixed” or “when idle”; “fixed” by default

    ”fixed” sampling means samples are taken on a fixed schedule, with no exceptions.

    ”when idle” sampling means no samples are taken before the previous sample’s output has been delivered. A sample is taken ASAP after an over-period computation: otherwise remains on schedule.

  • processing (str) –

    “parallel” or “serial”; “parallel” by default

    ”parallel” computes the output time by adding the delay for a sample onto the sample time, so if the delay is 2 ms, for example, while the sample period is only 1 ms, some of the processing is happening in parallel. Output order matches input order even if the computed output time for a sample is sooner than that for a previous sample.

    ”serial” computes the output time by adding the delay for a sample onto the output time of the previous sample, rather than the sampling time. Note this may be of limited utility because it essentially means the entire round trip cannot be in parallel at all. More realistic is that simply each block or phase of computation must be serial. If anyone cares enough about this, it will have to be implemented in the future.

Note

It doesn’t make much sense to combine parallel computation with “when idle” sampling, because “when idle” sampling only produces one sample at a time to process.

Raises

ValueError – For invalid sampling or processing kwargs

process(state_dict: dict, sample_time_ms: float) Tuple[dict, float][source]#

Process network state to generate output to update stimulators.

This is the function the user must implement to define the signal processing pipeline.

Parameters
  • state_dict (dict) – {recorder_name: state} dictionary from get_state()

  • time_ms (float) –

Returns

{‘stim_name’: ctrl_signal} dictionary and output time in milliseconds.

Return type

Tuple[dict, float]

sample_period_ms: float#

Determines how frequently the processor takes samples

t_samp_ms: list[float]#

Record of sampling times—each time put_state() is called.

cleo.viz module#

Tools for visualizing models and simulations

class cleo.viz.VideoVisualizer(devices: collections.abc.Iterable[Union[cleo.base.InterfaceDevice, Tuple[cleo.base.InterfaceDevice, dict]]] = NOTHING, dt: brian2.units.fundamentalunits.Quantity = 1. * msecond, *, name: str = NOTHING, save_history: bool = True)[source]#

Bases: cleo.base.InterfaceDevice

Device for visualizing a simulation.

Must be injected after all other devices and before the simulation is run.

Method generated by attrs for class VideoVisualizer.

ax: matplotlib.axes._axes.Axes#
connect_to_neuron_group(neuron_group: brian2.groups.neurongroup.NeuronGroup, **kwparams) None[source]#

Connect device to given neuron_group.

If your device introduces any objects which Brian must keep track of, such as a NeuronGroup, Synapses, or Monitor, make sure to add these to self.brian_objects.

Parameters
  • neuron_group (NeuronGroup) –

  • **kwparams (optional, passed from inject or) – inject

devices: collections.abc.Iterable[Union[cleo.base.InterfaceDevice, Tuple[cleo.base.InterfaceDevice, dict]]]#

list of devices or (device, vis_kwargs) tuples to include in the plot, just as in the plot() function, by default “all”, which will include all recorders and stimulators currently injected when this visualizer is injected into the simulator.

dt: brian2.units.fundamentalunits.Quantity#

length of each frame—that is, every dt the visualizer takes a snapshot of the network, by default 1*ms

fig: matplotlib.figure.Figure#
generate_Animation(plotargs: dict, slowdown_factor: float = 10, **figargs: Any) matplotlib.animation.Animation[source]#

Create a matplotlib Animation object from the recorded simulation

Parameters
  • plotargs (dict) – dictionary of arguments as taken by plot(). can include xlim, ylim, zlim, colors, axis_scale_unit, invert_z, and/or scatterargs. neuron groups and devices are automatically added and **figargs are specified separately.

  • slowdown_factor (float, optional) – how much slower the animation will be rendered, as a multiple of real-time, by default 10

  • **figargs (Any, optional) – keyword arguments passed to plt.figure(), such as figsize

Returns

An Animation object capturing the desired visualization. See matplotlib’s docs for saving and rendering options.

Return type

matplotlib.animation.Animation

init_for_simulator(simulator: cleo.base.CLSimulator)[source]#

Initialize device for simulator on initial injection

This function is called only the first time a device is injected into a simulator and performs any operations that are independent of the individual neuron groups it is connected to.

Parameters

simulator (CLSimulator) – simulator being injected into

neuron_groups: list[brian2.groups.neurongroup.NeuronGroup]#
cleo.viz.plot(*neuron_groups: brian2.groups.neurongroup.NeuronGroup, xlim: Optional[Tuple[float, float]] = None, ylim: Optional[Tuple[float, float]] = None, zlim: Optional[Tuple[float, float]] = None, colors: Optional[collections.abc.Iterable] = None, axis_scale_unit: brian2.units.fundamentalunits.Unit = umetre, devices: collections.abc.Iterable[Union[cleo.base.InterfaceDevice, Tuple[cleo.base.InterfaceDevice, dict]]] = [], invert_z: bool = True, scatterargs: dict = {}, sim: Optional[cleo.base.CLSimulator] = None, **figargs: Any) None[source]#

Visualize neurons and interface devices

Parameters
  • xlim (Tuple[float, float], optional) – xlim for plot, determined automatically by default

  • ylim (Tuple[float, float], optional) – ylim for plot, determined automatically by default

  • zlim (Tuple[float, float], optional) – zlim for plot, determined automatically by default

  • colors (Iterable, optional) – colors, one for each neuron group, automatically determined by default

  • axis_scale_unit (Unit, optional) – Brian unit to scale lim params, by default mm

  • devices (Iterable[Union[InterfaceDevice, Tuple[InterfaceDevice, dict]]], optional) – devices to add to the plot or (device, kwargs) tuples. add_self_to_plot() is called for each, using the kwargs dict if given. By default []

  • invert_z (bool, optional) – whether to invert z-axis, by default True to reflect the convention that +z represents depth from cortex surface

  • scatterargs (dict, optional) – arguments passed to plt.scatter() for each neuron group, such as marker

  • sim (CLSimulator, optional) – Optional shortcut to include all neuron groups and devices

  • **figargs (Any, optional) – keyword arguments passed to plt.figure(), such as figsize

Raises

ValueError – When neuron group doesn’t have x, y, and z already defined

cleo.recorders module#

Contains basic recorders.

class cleo.recorders.GroundTruthSpikeRecorder(*, name: str = NOTHING, save_history: bool = True)[source]#

Bases: cleo.base.Recorder

Reports the number of spikes seen since last queried for each neuron.

This amounts effectively to the number of spikes per control period. Note: this will only work for one neuron group at the moment.

Method generated by attrs for class GroundTruthSpikeRecorder.

connect_to_neuron_group(neuron_group)[source]#

Connect device to given neuron_group.

If your device introduces any objects which Brian must keep track of, such as a NeuronGroup, Synapses, or Monitor, make sure to add these to self.brian_objects.

Parameters
  • neuron_group (NeuronGroup) –

  • **kwparams (optional, passed from inject or) – inject

get_state() nptyping.types._ndarray.NDArray[Any, nptyping.types._number.UInt][source]#
Returns

n_neurons-length array with spike counts over the latest control period.

Return type

NDArray[(n_neurons,), np.uint]

neuron_group: brian2.groups.neurongroup.NeuronGroup#
class cleo.recorders.RateRecorder(i: int, *, name: str = NOTHING, save_history: bool = True)[source]#

Bases: cleo.base.Recorder

Records firing rate from a single neuron.

Firing rate comes from Brian’s PopulationRateMonitor

Method generated by attrs for class RateRecorder.

connect_to_neuron_group(neuron_group)[source]#

Connect device to given neuron_group.

If your device introduces any objects which Brian must keep track of, such as a NeuronGroup, Synapses, or Monitor, make sure to add these to self.brian_objects.

Parameters
  • neuron_group (NeuronGroup) –

  • **kwparams (optional, passed from inject or) – inject

get_state()[source]#

Return current measurement.

i: int#

index of neuron to record

mon: brian2.monitors.ratemonitor.PopulationRateMonitor#
class cleo.recorders.VoltageRecorder(voltage_var_name: str = 'v', *, name: str = NOTHING, save_history: bool = True)[source]#

Bases: cleo.base.Recorder

Records the voltage of a single neuron group.

Method generated by attrs for class VoltageRecorder.

connect_to_neuron_group(neuron_group)[source]#

Connect device to given neuron_group.

If your device introduces any objects which Brian must keep track of, such as a NeuronGroup, Synapses, or Monitor, make sure to add these to self.brian_objects.

Parameters
  • neuron_group (NeuronGroup) –

  • **kwparams (optional, passed from inject or) – inject

get_state() brian2.units.fundamentalunits.Quantity[source]#
Returns

Current voltage of target neuron group

Return type

Quantity

mon: brian2.monitors.statemonitor.StateMonitor#
voltage_var_name: str#

Name of variable representing membrane voltage

cleo.stimulators module#

Contains basic stimulators.

class cleo.stimulators.StateVariableSetter(default_value: Any = 0, *, name: str = NOTHING, save_history: bool = True, variable_to_ctrl: str, unit: Unit)[source]#

Bases: cleo.base.Stimulator

Sets the given state variable of target neuron groups.

Method generated by attrs for class StateVariableSetter.

connect_to_neuron_group(neuron_group)[source]#

Connect device to given neuron_group.

If your device introduces any objects which Brian must keep track of, such as a NeuronGroup, Synapses, or Monitor, make sure to add these to self.brian_objects.

Parameters
  • neuron_group (NeuronGroup) –

  • **kwparams (optional, passed from inject or) – inject

neuron_groups: list[NeuronGroup]#
unit: Unit#

will be used in update()

Type

Unit of controlled variable

update(ctrl_signal: float) None[source]#

Set state variable of target neuron groups

Parameters

ctrl_signal (float) – Value to update variable to, without unit. The unit provided on initialization is automatically multiplied.

variable_to_ctrl: str#

Name of state variable to control

cleo.utilities module#

Assorted utilities for developers.

cleo.utilities.add_to_neo_segment(segment: neo.core.segment.Segment, *objects: neo.core.dataobject.DataObject)[source]#

Taken from neo.core.group.Group.

cleo.utilities.analog_signal(t_ms, values_no_unit, units) neo.core.basesignal.BaseSignal[source]#
cleo.utilities.get_orth_vectors_for_V(V)[source]#

For nx3 block of row vectors V, return nx3 W1, W2 orthogonal vector blocks

cleo.utilities.modify_model_with_eqs(neuron_group, eqs_to_add)[source]#

Adapted from _create_variables() from neurongroup.py from Brian2 source code v2.3.0.2

cleo.utilities.normalize_coords(coords: brian2.units.fundamentalunits.Quantity) brian2.units.fundamentalunits.Quantity[source]#

Normalize coordinates to unit vectors.

cleo.utilities.style_plots_for_docs(dark=True)[source]#
cleo.utilities.times_are_regular(times)[source]#
cleo.utilities.uniform_cylinder_rθz(n, rmax, zmax)[source]#
cleo.utilities.wavelength_to_rgb(wavelength_nm, gamma=0.8)[source]#

taken from http://www.noah.org/wiki/Wavelength_to_RGB_in_Python This converts a given wavelength of light to an approximate RGB color value. The wavelength must be given in nanometers in the range from 380 nm through 750 nm (789 THz through 400 THz).

Based on code by Dan Bruton http://www.physics.sfasu.edu/astro/color/spectra.html

cleo.utilities.xyz_from_rθz(rs, thetas, zs, xyz_start, xyz_end)[source]#

Convert from cylindrical to Cartesian coordinates.

cleo.registry module#

class cleo.registry.DeviceInteractionRegistry(sim: CLSimulator)[source]#

Bases: object

Facilitates the creation and maintenance of ‘neurons’ and ‘synapses’ implementing many-to-many light-opsin/indicator optogenetics

Method generated by attrs for class DeviceInteractionRegistry.

connect_light_to_ldd_for_ng(light: Light, ldd: LightDependent, ng: NeuronGroup)[source]#
connections: set[Tuple['Light', 'LightDependent', NeuronGroup]]#
init_register_light(light: Light)[source]#
ldds_for_ng: dict[NeuronGroup, set['LightDependent']]#
light_prop_model = '\n        T : 1\n        epsilon : 1\n        Ephoton : joule\n        Irr_post = epsilon * T * Irr0_pre : watt/meter**2 (summed)\n        phi_post = Irr_post / Ephoton : 1/second/meter**2 (summed)\n    '#
light_prop_syns: dict[Tuple['LightDependent', NeuronGroup], Synapses]#
light_source_ng: NeuronGroup#

Represents ALL light sources (multiple devices)

lights_for_ng: dict[NeuronGroup, set['Light']]#
register(device: InterfaceDevice, ng: NeuronGroup)[source]#

Registers a device with the registry

register_ldd(ldd: LightDependent, ng: NeuronGroup)[source]#

Connects lights previously injected into this neuron group to this opsin

register_light(light: Light, ng: NeuronGroup)[source]#

Connects light to opsins and indicators already injected into this neuron group

sim: CLSimulator#
source_for_light(light: Light) Subgroup[source]#
subgroup_idx_for_light: dict['Light', slice]#
cleo.registry.registry_for_sim(sim: CLSimulator) DeviceInteractionRegistry[source]#

Returns the registry for the given simulator