diff --git a/cleo/imaging/scope.py b/cleo/imaging/scope.py index c4688c6..28e0fd8 100644 --- a/cleo/imaging/scope.py +++ b/cleo/imaging/scope.py @@ -11,6 +11,7 @@ from cleo.base import Recorder +from cleo.registry import DeviceInteractionRegistry, registry_for_sim from cleo.imaging.sensors import Sensor from cleo.coords import coords_from_ng from cleo.utilities import normalize_coords, rng @@ -83,6 +84,10 @@ def target_neurons_in_plane( return i_targets, noise_focus_factor[i_targets], coords_on_plane[i_targets] +''' +def fov_change_observation(instance, attribute, value): + instance.Registry.update_fov(value) +''' @define(eq=False) class Scope(Recorder): @@ -146,6 +151,7 @@ class Scope(Recorder): factory=list, repr=False, init=False ) """relative expression levels of neurons selected from each injection""" + Registry: DeviceInteractionRegistry = None @property def n(self) -> int: @@ -291,6 +297,8 @@ def connect_to_neuron_group(self, neuron_group: NeuronGroup, **kwparams) -> None self.sigma_per_injct.append(sigma_noise) self.focus_coords_per_injct.append(focus_coords) self.rho_rel_per_injct.append(rho_rel) + self.Registry = registry_for_sim(self.sim) + self.Registry.update_fov(self.img_width) def i_targets_for_neuron_group(self, neuron_group): """can handle multiple injections into same ng""" diff --git a/cleo/light/light.py b/cleo/light/light.py index 0f8cad7..e12049a 100644 --- a/cleo/light/light.py +++ b/cleo/light/light.py @@ -294,6 +294,8 @@ class Light(Stimulator): wavelength: Quantity = field(default=473 * nmeter, kw_only=True) """light wavelength with unit (usually nmeter)""" + scan_freq : int = field(default=30, kw_only=True) + @coords.validator def _check_coords(self, attribute, value): if len(value.shape) != 2 or value.shape[1] != 3: diff --git a/cleo/registry.py b/cleo/registry.py index c275f1d..aae6cbb 100644 --- a/cleo/registry.py +++ b/cleo/registry.py @@ -8,11 +8,15 @@ from attrs import define, field from brian2 import NeuronGroup, Subgroup, Synapses +from brian2 import defaultclock from brian2.units.allunits import joule, kgram, meter, meter2, nmeter, second +from numpy import pi from cleo.coords import coords_from_ng from cleo.utilities import brian_safe_name +import warnings + @define(repr=False) class DeviceInteractionRegistry: @@ -46,11 +50,21 @@ class DeviceInteractionRegistry: """Set of (light, light-dependent device, neuron group) tuples representing previously created connections.""" + raster_fov: int = field(default=500 * 1e-6 * meter, kw_only=True) + + raster_enable: int = field(default=0, kw_only=True) + light_prop_model = """ T : 1 + scale : 1 epsilon : 1 Ephoton : joule - Irr_post = epsilon * T * Irr0_pre : watt/meter**2 (summed) + raster_enable : 1 + scan_period : second + raster_dwell_time: second + Irr_norm = epsilon * T * Irr0_pre : watt/meter**2 + Irr_raster = epsilon * T * Irr0_pre * int(((t + scan_period * (i/N)) % (scan_period)) < (raster_dwell_time * scale * 10)) / (scale * 10): watt/meter**2 + Irr_post = Irr_norm * (1 - raster_enable) + Irr_raster * raster_enable : watt/meter**2 (summed) phi_post = Irr_post / Ephoton : 1/second/meter**2 (summed) """ """Model used in light propagation synapses""" @@ -104,6 +118,10 @@ def connect_light_to_ldd_for_ng( i_source = self.subgroup_idx_for_light[light] light_prop_syn.epsilon[i_source, :] = epsilon light_prop_syn.T[i_source, :] = light.transmittance(coords_from_ng(ng)).ravel() + light_prop_syn.scan_period = second / light.scan_freq + light_prop_syn.raster_dwell_time = (pi * 10 ** -10 * meter2)/ (pi*(self.raster_fov/2)**2) * second / light.scan_freq + light_prop_syn.scale = 1 + (defaultclock.dt > light_prop_syn.raster_dwell_time).astype(int) * (defaultclock.dt / (light_prop_syn.raster_dwell_time) - 1) + light_prop_syn.raster_enable = self.raster_enable # fmt: off # Ephoton = h*c/lambda light_prop_syn.Ephoton[i_source, :] = ( @@ -195,6 +213,15 @@ def source_for_light(self, light: "Light") -> Subgroup: """Returns the subgroup representing the given light source""" i = self.subgroup_idx_for_light[light] return self.light_source_ng[i] + + def update_fov(self, new_fov: float): + self.raster_enable = 1 + def custom_warning_format(message, category, filename, lineno, line=None): + return f"{category.__name__}: {message}\n" + warnings.formatwarning = custom_warning_format + if self.raster_fov != new_fov: + self.raster_fov = new_fov + warnings.warn("Warning: cleo currently supports use of single scanning fov in simulation, the latest update parameter will be used", UserWarning) registries: dict["CLSimulator", DeviceInteractionRegistry] = {}