-
Notifications
You must be signed in to change notification settings - Fork 0
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Raster Scanning Code #55
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. would this need to be updated on every injection? Also, it can't be right that there's a single There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. the Scope should optionally have an |
||
|
||
def i_targets_for_neuron_group(self, neuron_group): | ||
"""can handle multiple injections into same ng""" | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'd create a subclass RasterScanningLight to hide the scan_freq details from the typical Light object |
||
|
||
@coords.validator | ||
def _check_coords(self, attribute, value): | ||
if len(value.shape) != 2 or value.shape[1] != 3: | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. again, these would be at the level of individual lights, not the whole registry |
||
|
||
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 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'd put these in a separate function that you call both here (on injection) and when you change the params on the scope/imaging light (setter functions). like There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. like you've already done with |
||
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] = {} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are you sure we need to store the registry when we can just do
registry_for_sim(self.sim)
?