Skip to content
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

Update/workshop 2024 #378

Merged
merged 5 commits into from
Jul 6, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions bmtk/builder/builder_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,8 @@ def check_properties_across_ranks(properties, graph_type='node'):
phash = hashlib.md5(pval.encode('utf-8')).hexdigest()

elif isinstance(pval, (int, float, bool)):
if np.isnan(pval):
pval = 'NONE'
phash = pval

elif isinstance(pval, (list, tuple)):
Expand Down
35 changes: 1 addition & 34 deletions bmtk/simulator/bionet/biosimulator.py
Original file line number Diff line number Diff line change
Expand Up @@ -376,41 +376,8 @@ def from_config(cls, config, network, set_recordings=True):
sim.add_mod(mods.IClampMod(input_type=sim_input.input_type, **sim_input.params))

elif sim_input.module == "SEClamp":
node_set = network.get_node_set(sim_input.node_set)
try:
len(sim_input.params['amps'])
except:
sim_input.params['amps']=[float(sim_input.params['amps'])]
sim.add_mod(mods.SEClamp(input_type=sim_input.input_type, **sim_input.params))

try:
len(sim_input.params['durations'])
except:
sim_input.params['durations']=[float(sim_input.params['durations'])]

amplitudes = sim_input.params['amps']
durations = sim_input.params['durations']
rs = None

if "rs" in sim_input.params.keys():
try:
len(sim_input.params['rs'])
except:
sim_input.params['rs']=[float(sim_input.params['rs'])]
if len(sim_input.params['rs'])>1:
sim_input.params['rs']=[float(i) for i in sim_input.params['rs']]
rs = sim_input.params["rs"]

try:
sim_input.params['gids']
except:
sim_input.params['gids'] = None
if sim_input.params['gids'] is not None:
gids = sim_input.params['gids']
else:
gids = list(node_set.gids())

sim.attach_se_voltage_clamp(amplitudes, durations, gids, rs)

elif sim_input.module == 'xstim':
sim.add_mod(mods.XStimMod(**sim_input.params))

Expand Down
1 change: 1 addition & 0 deletions bmtk/simulator/bionet/modules/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,3 +30,4 @@
from .iclamp import IClampMod
from .comsol import ComsolMod
from .ecephys_module import BioECEphysUnitsModule
from .seclamp import SEClamp
70 changes: 70 additions & 0 deletions bmtk/simulator/bionet/modules/seclamp.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import numpy as np
from neuron import h

from bmtk.simulator.bionet.modules.sim_module import SimulatorMod
from bmtk.simulator.bionet.io_tools import io
from bmtk.simulator.core.modules import iclamp


class SEClamp(SimulatorMod):
def __init__(self, input_type, **mod_args):

# Select location to place iclamp, if not specified use the center of the soma
self._section_name = mod_args.get('section_name', 'soma')
self._section_index = mod_args.get('section_index', 0)
self._section_dist = mod_args.get('section_dist', 0.5)

self._rs = mod_args.get('resistance', 1.0)
self._vc = mod_args.get('vc', 0.0)

self._delay = mod_args['delay']
self._amp = mod_args['amp']
self._duration = mod_args['duration']
self._ton = self._delay
self._toff = self._delay + self._duration

# Check f section_index is a range (ie. "section_index": [500.0, 1000.0])
self._ranged_index = isinstance(self._section_index, (list, tuple))

# SEClamp objects need to be saved in memory otherwise NRN will try to garbage collect them
# prematurly
self._seclamp = None

self._node_set = mod_args.get('node_set', 'all')

def initialize(self, sim):
select_gids = list(sim.net.get_node_set(self._node_set).gids())
gids_on_rank = list(set(select_gids) & set(select_gids))

for gid in gids_on_rank:
cell = sim.net.get_cell_gid(gid)

if self._ranged_index:
hobj_sec = self._find_section(cell)
else:
hobj_sec = getattr(cell.hobj, self._section_name)[self._section_index](self._section_dist)

self._seclamp = self.create_clamp(hobj_sec)

def step(self, sim, tstep):
if self._ton <= sim.dt*tstep <= self._toff:
self._seclamp.rs = self._rs
# print(sim.dt*tstep)
else:
self._seclamp.rs = 10.0e20


def create_clamp(self, hobj):
stim = h.SEClamp(hobj)

stim.dur1 = self._delay
stim.dur2 = self._duration
stim.dur3 = 0.0

stim.amp1 = 0.0
stim.amp2 = self._amp
stim.amp3 = 0.0
stim.vc = self._vc

return stim

2 changes: 1 addition & 1 deletion bmtk/simulator/bionet/modules/xstim_waveforms.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ def calculate(self, t): # TODO better name
class WaveformCustom(BaseWaveform):
"""Custom waveform defined by csv file"""
def __init__(self, waveform_file):
self.definition = pd.read_csv(waveform_file, sep='\t')
self.definition = pd.read_csv(waveform_file, sep=' ')

def calculate(self, t):
return np.interp(t, self.definition["time"], self.definition["amplitude"])
Expand Down
16 changes: 13 additions & 3 deletions bmtk/simulator/filternet/filtersimulator.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,16 @@ def add_movie(self, movie_type, params):
else:
raise Exception('Could not find movie "data_file" in config to use as input.')

# If file passed in is a npz compressed file then it is in a dictionary format and need to find
# the key-value pair containing the array
if isinstance(m_data, np.lib.npyio.NpzFile):
try:
for key in m_data:
m_data = m_data[key]
break
except IndexError as ie:
io.log_warning('Was unable to find array from compressed numpy matrix file.')

# contrast_min, contrast_max = m_data.min(), m_data.max()
normalize_data = params.get('normalize', False)
if normalize_data:
Expand Down Expand Up @@ -181,21 +191,21 @@ def run(self):
ten_percent = int(np.ceil(n_cells_on_rank*0.1))
rank_msg = '' if bmtk_world_comm.MPI_size < 2 else ' (on rank {})'.format(bmtk_world_comm.MPI_rank)

max_fr = np.empty(len(cells_on_rank))
# max_fr = np.empty(len(cells_on_rank))
for cell_num, cell in enumerate(cells_on_rank):
for movie, options in zip(self._movies, self._eval_options):
if cell_num > 0 and cell_num % ten_percent == 0:
io.log_debug(' Processing cell {} of {}{}.'.format(cell_num, n_cells_on_rank, rank_msg))
ts, f_rates = cell.lgn_cell_obj.evaluate(movie, **options)
max_fr[cell_num] = np.max(f_rates)
# max_fr[cell_num] = np.max(f_rates)
if movie.padding:
f_rates = f_rates[int(movie.data.shape[0]-movie.data_orig.shape[0]):]
ts = ts[int(movie.data.shape[0]-movie.data_orig.shape[0]):]
ts = ts-ts[0]

for mod in self._sim_mods:
mod.save(self, cell, ts, f_rates)
io.log_info('Max firing rate: {}'.format(np.max(max_fr)))
# io.log_info('Max firing rate: {}'.format(np.max(max_fr)))
io.log_info('Done.')
for mod in self._sim_mods:
mod.finalize(self)
Expand Down
12 changes: 9 additions & 3 deletions bmtk/simulator/filternet/lgnmodel/cursor.py
Original file line number Diff line number Diff line change
Expand Up @@ -225,14 +225,20 @@ def evaluate(self, threshold=0):
full_temporal_kernel = self.temporal_kernel.full()

# Convolve every frame in the movie with the spatial filter. First find the range of rows (range min and max)
# and columns in the filter that are above threshold, that way only portion of movie/filter are multiplied
# and columns in the filter that are above threshold, that way only portion of movie/filter are multiplied
# together

# Using > instead of >= makes the code faster if there are many zeros in the
# spatial kernel. This will not affect the results.
nonzero_inds = np.where(np.abs(full_spatial_kernel[0, :, :]) > threshold)
rm, rM = nonzero_inds[0].min(), nonzero_inds[0].max()
cm, cM = nonzero_inds[1].min(), nonzero_inds[1].max()
if len(nonzero_inds[0]) == 0:
# If spatial kernel is all 0's then don't try to segment the receptive filed. Use full frame during convolve.
rm, rM = 0, 0
cm, cM = full_spatial_kernel.shape[1], full_spatial_kernel.shape[2]
else:
rm, rM = nonzero_inds[0].min(), nonzero_inds[0].max()
cm, cM = nonzero_inds[1].min(), nonzero_inds[1].max()

convolution_answer_sep_spatial = (self.movie.data[:, rm:rM+1, cm:cM+1] *
full_spatial_kernel[:, rm:rM+1, cm:cM+1]).sum(axis=1).sum(axis=1)

Expand Down
4 changes: 2 additions & 2 deletions bmtk/simulator/pointnet/modules/spikes_inputs.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
from bmtk.simulator.pointnet.modules.sim_module import SimulatorMod
from bmtk.simulator.pointnet.io_tools import io
from bmtk.utils.reports.spike_trains import SpikeTrains
from bmtk.simulator.bionet.pyfunction_cache import py_modules
from bmtk.simulator.pointnet.pyfunction_cache import py_modules


class SpikesInputsMod(SimulatorMod):
Expand All @@ -48,7 +48,7 @@ def initialize(self, sim):
io.log_exception(f'Could not find @spikes_generator function "{spikes_generator}" required for {self._name} inputs.')
spikes_func = py_modules.spikes_generator(name=spikes_generator)

self._spike_trains = SpikeTrains(cace_to_disk=False)
self._spike_trains = SpikeTrains(cache_to_disk=False)
for node in node_set.fetch_nodes():
timestamps = spikes_func(node, sim)
self._spike_trains.add_spikes(
Expand Down
6 changes: 6 additions & 0 deletions bmtk/simulator/pointnet/pointnetwork.py
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,8 @@ def __init__(self, **properties):
self._nodes_table = {}
self._gid2nestid = {}

self._nest_modules = []

self._gid_map = GidPool()
self._virtual_gids = GidPool()

Expand Down Expand Up @@ -131,6 +133,10 @@ def add_weight_function(self, fnc, name=None, **kwargs):
fnc_name = name if name is not None else function.__name__
self.__weight_functions[fnc_name] = functools.partial(fnc)

def add_nest_module(self, module_path):
if module_path not in self._nest_modules:
self._nest_modules.append(module_path)

def set_default_weight_function(self, fnc):
self.add_weight_function(fnc, 'default_weight_fnc', overwrite=True)

Expand Down
51 changes: 51 additions & 0 deletions bmtk/simulator/pointnet/pointsimulator.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@
import nest
from six import string_types
from six import moves
from pathlib import Path
import platform

from bmtk.simulator.core.simulator import Simulator
from bmtk.simulator.pointnet.config import Config
Expand Down Expand Up @@ -72,6 +74,7 @@ def __init__(self, graph, dt=0.001, overwrite=True, print_time=False, n_thread=1
# TODO: move this into it's own function and make sure it is called before network is built
nest.ResetKernel()
nest.SetKernelStatus({"resolution": self._dt, "overwrite_files": self._overwrite, "print_time": print_time, "local_num_threads": n_thread})
self._load_nest_modules()

@property
def tstart(self):
Expand Down Expand Up @@ -131,6 +134,54 @@ def _get_block_trial(self, duration):
data_res = -1
return n, res, data_res

def _add_library_path(self, lib_path):
if isinstance(lib_path, Path):
lib_path = lib_path.as_posix()
system = platform.system()
env_var = "LD_LIBRARY_PATH" if system in ['Linux', 'Windows', 'Java'] else 'DYLD_LIBRARY_PATH'
env_val = os.environ.get(env_var, '')

if lib_path not in env_val:
os.environ[env_var] = os.pathsep.join([lib_path, env_val])


def _load_nest_modules(self):
# If there is a "nest_modules" entry in the configuration "components" then go through and add them to
# the network _nest_modules list. They will be processed the same as calling network.add_nest_module().
components_path = self.net._components.get('nest_modules', [])
if isinstance(components_path, str):
self.net.add_nest_module(components_path)
elif isinstance(components_path, list):
for cpath in components_path:
self.net.add_nest_module(cpath)
else:
raise ValueError('Unable to load components/nest_modules value.')

# Go through all added nest modules and try to call nest.Install() for them.
for module in self.net._nest_modules:
if Path(module).is_dir():
# If module is a directory then add path to LD_LIBRARY_PATH then try to load all the .so/.a library binaries in directory
lib_dir = Path(module).resolve()
self._add_library_path(lib_dir)
so_search = Path(lib_dir) / '*.so'
a_search = Path(lib_dir) / '*.a'

for lib_file in glob.glob(so_search.as_posix()) + glob.glob(a_search.as_posix()): # lib_path.parent.resolve()
module_name = Path(lib_file).name
nest.Install(module_name)

elif Path(module).is_file():
# If user tries to pass in a path to a library binary
lib_path = Path(module)
lib_dir = lib_path.parent.resolve()
lib_filename = lib_path.name
self._add_library_path(lib_dir)
nest.Install(lib_filename)

else:
# If user just tries nest.Install('mymodule')
nest.Install(module)

'''
def set_spikes_recordings(self):
# TODO: Pass in output-dir and file name to save to
Expand Down
2 changes: 1 addition & 1 deletion bmtk/utils/create_environment/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ def __split_list(options, opt_name):
parser.add_option('-c', '--components-dir', dest='components_dir', default=None,
help="Directory to use for parameter files, morphology, and other used components.")
parser.add_option('--tstop', type='float', dest='tstop', default=1000.0)
parser.add_option('--dt', type=float, dest='dt', help='simulation time step dt', default=0.001)
parser.add_option('--dt', type=float, dest='dt', help='simulation time step dt', default=None)
parser.add_option('--report-vars', dest='report_vars', type='string', action='callback',
callback=__list_parser, default=[],
help='A list of membrane variables to record from; v, cai, etc.')
Expand Down
4 changes: 2 additions & 2 deletions bmtk/utils/create_environment/create_environment.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ def create_environment(simulator,
se_voltage_clamp=None,
tstart=0.0,
tstop=1000.0,
dt=0.001,
dt=None,
dL=20.0,
spikes_threshold=-15.0,
nsteps_block=5000,
Expand All @@ -50,7 +50,7 @@ def create_environment(simulator,
compile_mechanisms=False,
use_relative_paths=True,
include_examples=False
):
):
"""
:param simulator:
Expand Down
9 changes: 9 additions & 0 deletions bmtk/utils/create_environment/env_builder.py
Original file line number Diff line number Diff line change
Expand Up @@ -776,6 +776,15 @@ def target_simulator(self):
@property
def bmtk_simulator(self):
return 'filternet'

def _add_run_params(self, tstart=0.0, tstop=1000.0, dt=None, **kwargs):
self._simulation_config['run'] = {
'tstart': tstart,
'tstop': tstop
}

if dt is not None:
self._simulation_config['run']['dt'] = dt

def _add_output_section(self):
super(FilterNetEnvBuilder, self)._add_output_section()
Expand Down
38 changes: 38 additions & 0 deletions examples/point_nestml_izh/config.circuit.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
{
"manifest": {
"$BASE_DIR": ".",
"$NETWORK_DIR": "$BASE_DIR/network",
"$MODELS_DIR": "$BASE_DIR/../point_components"
},

"components": {
"point_neuron_models_dir": "$MODELS_DIR/cell_models",
"synaptic_models_dir": "$MODELS_DIR/synaptic_models",
"nest_modules": "components/nestml/nestml_izh_module.so"
},

"networks": {
"nodes": [
{
"nodes_file": "$NETWORK_DIR/cortex_nodes.h5",
"node_types_file": "$NETWORK_DIR/cortex_node_types.csv"
},
{
"nodes_file": "$NETWORK_DIR/thalamus_nodes.h5",
"node_types_file": "$NETWORK_DIR/thalamus_node_types.csv"
}
],
"edges": [
{
"edges_file": "$NETWORK_DIR/cortex_cortex_edges.h5",
"edge_types_file": "$NETWORK_DIR/cortex_cortex_edge_types.csv",
"enabled": false
},
{
"edges_file": "$NETWORK_DIR/thalamus_cortex_edges.h5",
"edge_types_file": "$NETWORK_DIR/thalamus_cortex_edge_types.csv",
"enabled": true
}
]
}
}
Loading
Loading