Source code for bluecellulab.connection
# Copyright 2023-2024 Blue Brain Project / EPFL
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
# http://www.apache.org/licenses/LICENSE-2.0
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""Class that represents a connection between two cells in bluecellulab."""
from typing import Optional
import neuron
import numpy as np
from bluecellulab.cell.core import Cell
from bluecellulab.circuit import SynapseProperty
[docs]
class Connection:
"""Class that represents a connection between two cells in bluecellulab."""
def __init__(
self,
post_synapse,
pre_spiketrain: Optional[np.ndarray] = None,
pre_gid: Optional[int] = None,
pre_cell: Optional[Cell] = None,
stim_dt=None,
parallel_context=None,
spike_threshold: float = -30.0,
spike_location="soma"):
self.persistent = []
self.delay = post_synapse.syn_description[SynapseProperty.AXONAL_DELAY]
self.weight = post_synapse.syn_description[SynapseProperty.G_SYNX]
self.pre_cell = pre_cell
self.pre_gid = pre_gid
self.pre_spiketrain = pre_spiketrain
self.post_synapse = post_synapse
self.pc = parallel_context
if post_synapse.weight is not None:
self.weight_scalar = post_synapse.weight
else:
self.weight_scalar = 1.0
self.post_netcon = None
self.post_netcon_delay = self.delay
self.post_netcon_weight = self.weight * self.weight_scalar
if self.pre_spiketrain is not None:
if np.any(self.pre_spiketrain < 0):
raise ValueError("bluecellulab Connection: a spiketrain contains "
"a negative time, this is not supported by "
"NEURON's Vecstim: %s" %
str(self.pre_spiketrain))
t_vec = neuron.h.Vector(self.pre_spiketrain)
vecstim = neuron.h.VecStim()
vecstim.play(t_vec, stim_dt)
self.post_netcon = neuron.h.NetCon(
vecstim, self.post_synapse.hsynapse,
spike_threshold,
self.post_netcon_delay,
self.post_netcon_weight)
# set netcon type
nc_param_name = 'nc_type_param_{}'.format(
self.post_synapse.hsynapse).split('[')[0]
if hasattr(neuron.h, nc_param_name):
nc_type_param = int(getattr(neuron.h, nc_param_name))
self.post_netcon.weight[nc_type_param] = 2 # NC_REPLAY
self.persistent.append(t_vec)
self.persistent.append(vecstim)
elif self.pre_cell is not None or (self.pc is not None and pre_gid is not None):
if self.pre_cell is not None and self.pc is None:
# serial/local
self.post_netcon = self.pre_cell.create_netcon_spikedetector(
self.post_synapse.hsynapse, location=spike_location, threshold=spike_threshold
)
else:
# MPI gid-based (works across ranks)
if pre_gid is None:
raise ValueError("pre_gid must be provided when using ParallelContext")
self.post_netcon = self.pc.gid_connect(int(pre_gid), self.post_synapse.hsynapse)
# NetCon setup
self.set_netcon_weight(self.post_netcon_weight)
self.set_netcon_delay(self.post_netcon_delay)
self.post_netcon.threshold = spike_threshold
# set netcon type
nc_param_name = 'nc_type_param_{}'.format(
self.post_synapse.hsynapse).split('[')[0]
if hasattr(neuron.h, nc_param_name):
nc_type_param = int(getattr(neuron.h, nc_param_name))
self.post_netcon.weight[nc_type_param] = 0 # NC_PRESYN
def set_netcon_weight(self, w: float) -> None:
self.post_netcon_weight = float(w)
if self.post_netcon is not None:
self.post_netcon.weight[0] = self.post_netcon_weight
def set_weight_scalar(self, scalar: float) -> None:
self.weight_scalar = float(scalar)
self.set_netcon_weight(self.weight * self.weight_scalar)
def set_netcon_delay(self, d: float) -> None:
self.post_netcon_delay = float(d)
if self.post_netcon is not None:
self.post_netcon.delay = self.post_netcon_delay
@property
def info_dict(self):
"""Return dict that contains information that can restore this conn."""
connection_dict = {}
connection_dict['pre_cell_id'] = self.post_synapse.pre_gid
connection_dict['post_cell_id'] = self.post_synapse.post_cell_id.id
connection_dict['post_synapse_id'] = self.post_synapse.syn_id.sid
connection_dict['post_netcon'] = {}
connection_dict['post_netcon']['weight'] = self.post_netcon_weight
connection_dict['post_netcon']['delay'] = self.post_netcon_delay
return connection_dict
[docs]
def delete(self):
"""Delete the connection."""
for persistent_object in self.persistent:
del persistent_object
def __del__(self):
self.delete()