A NEST-based framework unlocks massively parallel simulation of networks of multi-compartment neurons with customizable subcellular dynamics.
The 5 matches
- [1] § Methods › Simulation details › Winner-take-all network ↔ prepare_nest_parameters.py, lines 46 to 109 · score 0.79 · Poisson noise, excitatory populations, Poisson generators, inhibitory neurons, stimulated, recurrently · Report a mismatch
- [2] § Methods › Simulation details › Benchmarking and scaling experiments ↔ nest_reset_create_connect_simulate.py, lines 187 to 225 · score 0.70 · inh connections, inh exc, inhibitory neurons, excitatory neurons, synapses, weight · Report a mismatch
- [3] § Results › Toolchain overview ↔ cm_neuron.py, lines 25 to 68 · score 0.63 · reversal potential, coupling conductance, leak conductance, capacitance · Report a mismatch
- [4] § Results › Toolchain overview ↔ cm_neuron_nestml.py, lines 37 to 107 · score 0.63 · reversal potential, coupling conductance, leak conductance, capacitance · Report a mismatch
- [5] § Methods › Simulation details › Winner-take-all network ↔ nest_reset_create_connect_simulate.py, lines 12 to 69 · score 0.53 · Ca AdEx, excitatory neurons, plastic, populations, connected, NESTML · Report a mismatch
Paper
Loaded from Europe PMC by your browser; OSCR does not store it: doi.org · Europe PMC
The paper is loaded when this pane is shown.
The authors' code
Python · 637 lines · 32 KB · no license · 2 matches
- import nest
- from cm_neuron import create_cm_neuron
- from cm_neuron_nestml import create_nestml_neuron, create_receptor_mapping
- from synaptic_io import *
- # 2024-1002
- # List of receptors used in Ca-AdEx neuron
- # It should be moved in a different file (eg. Ca-AdEx_neural_params.yaml)
- GABA_soma, AMPA_soma, GABA_dist, AMPA_dist, REFRACT_soma, ADAPT_soma, BETA_dist, NMDA_soma, AMPA_NMDA_soma, ALPHAexc_soma, ALPHAinh_soma, ALPHAexc_dist, ALPHAinh_dist, NMDA_dist, AMPA_NMDA_dist = 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14
- def nest_reset_create_connect_simulate(nest_pms, num_threads, verbose):
- sim_completed=False
- sim_pms=nest_pms["sim_pms"]
- use_nestml=nest_pms["use_nestml"]
- nest.ResetKernel()
- nest.local_num_threads = 4
- if use_nestml:
- nest.Install("ca_adex_2expsyn_module")
- nest.SetKernelStatus({"resolution": sim_pms["resolution_ms"]})
- nest.SetKernelStatus({'local_num_threads':num_threads})
- num_exc_neu_per_pop = nest_pms["network"]["num_exc_neu_per_pop"]
- num_exc_pop = nest_pms["network"]["num_exc_pop"]
- conn_rule = nest_pms["network"]["conn_rule"]
- p_conn_exc = nest_pms["network"]["p_conn_exc"]
- p_conn_inh = nest_pms["network"]["p_conn_exc"]
- default_plasticity = nest_pms["network"]["default_plasticity"]
- use_single_compartment_environment = nest_pms["use_single_compartment_environment"]
- print("IN nest_reset_create_connect_simulate: use_single_compartment_environment =", use_single_compartment_environment)
- print("IN nest_reset_create_connect_simulate: use_nestml =", use_nestml)
- exc_neu_params=nest_pms['exc_neu_params']
- if not use_nestml:
- if use_single_compartment_environment:
- # Create excitatory neuron populations
- params=exc_neu_params['equation_params']
- params["tau_minus"]={}
- params["tau_minus"]=20.0
- #nest.Create("iaf_psc_alpha", params={"tau_minus": 20.0})
- neurons = [
- nest.Create(
- "aeif_cond_alpha",
- num_exc_neu_per_pop,
- params=params
- )
- for _ in range(num_exc_pop)
- ]
- else:
- # Create excitatory Ca-AdEx neuron populations
- nest.CopyModel('static_synapse', 'REFRACT_syn')
- nest.CopyModel('static_synapse', 'ADAPT_syn')
- nest.CopyModel('static_synapse', 'BAP_syn')
- neurons = [
- create_cm_neuron(num_exc_neu_per_pop, params=exc_neu_params['equation_params']) for _ in range(num_exc_pop)
- ]
- else:
- neurons = [
- create_nestml_neuron(
- num_exc_neu_per_pop,
- params=exc_neu_params['equation_params'],
- multi_comp=not(use_single_compartment_environment)
- ) for _ in range(num_exc_pop)
- ]
- ri = create_receptor_mapping(multi_comp=not(use_single_compartment_environment))
- # Create inhibitory neurons
- inh_neu_params = nest_pms["inh_neu_params"]
- num_inh_neu = nest_pms["network"]["num_inh_neu"]
- inh_neurons = nest.Create(
- "aeif_cond_alpha",
- num_inh_neu,
- params=inh_neu_params,
- )
- # Spike recorders for excitatory and inhibitory populations
- recording_pms=nest_pms["recording_pms"]
- spike_recorders = [nest.Create("spike_recorder",
- {"start": recording_pms["start_ms"], "stop": recording_pms["stop_ms"]})
- for _ in range(num_exc_pop)]
- inh_spike_recorder = nest.Create("spike_recorder",
- {"start": recording_pms["start_ms"], "stop": recording_pms["stop_ms"]})
- # Connect spike detectors
- for i in range(num_exc_pop):
- nest.Connect(neurons[i], spike_recorders[i])
- nest.Connect(inh_neurons, inh_spike_recorder)
- # 2024-1002
- # Added multimeter on Ca-AdEx only (temporary solution)
- # Target pop and neu and all the parameters to be specified in a yaml
- if not use_nestml:
- if use_single_compartment_environment:
- multimeter = nest.Create('multimeter', 1, {'record_from': ['V_m'], 'interval': .1,
- 'start': recording_pms['start_ms'], 'stop': recording_pms['stop_ms']})
- pop = 0
- neu = 0
- # nest.Connect(multimeter, neurons[pop])
- nest.Connect(multimeter, neurons[pop][neu])
- else:
- # create multimeter to record compartment voltages and various state variables
- rec_list = ['v_comp0', 'v_comp1', 'w_5','m_Ca_1','h_Ca_1','i_AMPA_9']
- pop = 0
- neu = 0
- multimeter = nest.Create('multimeter', 1, {'record_from': rec_list, 'interval': .1,
- 'start': recording_pms['start_ms'], 'stop': recording_pms['stop_ms']})
- # nest.Connect(multimeter, neurons[pop])
- nest.Connect(multimeter, neurons[pop][neu])
- else:
- # create multimeter to record compartment voltages and various state variables
- rec_list = ['v_comp0', f'syn_2exp{ri.ALPHAexc_soma}']
- if not use_single_compartment_environment:
- rec_list.append('v_comp1')
- pop = 0
- neu = 0
- multimeter = nest.Create('multimeter', 1, {'record_from': rec_list, 'interval': .1,
- 'start': recording_pms['start_ms'], 'stop': recording_pms['stop_ms']})
- # nest.Connect(multimeter, neurons[pop])
- nest.Connect(multimeter, neurons[pop][neu])
- # Connection specifications
- exc_t_ref_ms=nest_pms["exc_t_ref_ms"]
- min_syn_delay_ms=nest_pms["network"]["min_syn_delay_ms"]
- use_recurrency=nest_pms["network"]["use_exc_recurrency"]
- recurrent_weight = nest_pms["network"]["weights"]["exc_to_exc"]
- inh_to_exc_weight = nest_pms["network"]["weights"]["inh_to_exc_weight"]
- exc_to_inh_weight = nest_pms["network"]["weights"]["exc_to_inh_weight"]
- inh_to_inh_weight = nest_pms["network"]["weights"]["inh_to_inh_weight"]
- exc_to_exc_delay_ms = min_syn_delay_ms + 1.
- inh_to_inh_delay_ms = min_syn_delay_ms + exc_t_ref_ms + 1.0
- assert(conn_rule == 'pairwise_bernoulli')
- conn_spec_dict_exc = {"rule": conn_rule, "p": p_conn_exc}
- conn_spec_dict_inh = {"rule": conn_rule, "p": p_conn_inh}
- conn_spec_dict_exc = {"rule": 'all_to_all', "allow_autapses":False}
- conn_spec_dict_inh = {"rule": 'all_to_all', "allow_autapses":False}
- #set to false the book-keeping of intra-pop and inter pop syn types
- present_exc_conn={}
- for i in range(num_exc_pop):
- present_exc_conn[i]={}
- for j in range(num_exc_pop):
- present_exc_conn[i][j] = {'synapse_model': False}
- #set initial intra-pop connections
- for i in range(num_exc_pop):
- static_synapse_i_i='static_synapse_'+str(i)+'_'+str(i)
- nest.CopyModel('static_synapse',static_synapse_i_i)
- syn_spec={"synapse_model": static_synapse_i_i, "weight": recurrent_weight, "delay": exc_to_exc_delay_ms}
- if not use_nestml:
- if(not use_single_compartment_environment):
- syn_spec.update({'receptor_type': ALPHAexc_soma})
- else:
- syn_spec.update({'receptor_type': ri.ALPHAexc_soma})
- nest.Connect(neurons[i], neurons[i], conn_spec=conn_spec_dict_exc, syn_spec=syn_spec)
- present_exc_conn[i][i] = {'synapse_model': static_synapse_i_i}
- #inter assemblies connections: initial set-up
- if nest_pms["network"]["inter_pop_conn"] == True:
- inter_pop_weight = nest_pms["network"]["weights"]["inter_pop_weight"]
- for i in range(num_exc_pop):
- for j in range(num_exc_pop):
- if i != j:
- static_synapse_i_j='static_synapse_'+str(i)+'_'+str(j)
- nest.CopyModel('static_synapse',static_synapse_i_j)
- syn_spec={"synapse_model":static_synapse_i_j,"weight": inter_pop_weight * cf_mc, "delay": exc_to_exc_delay_ms}
- if not use_nestml:
- if(not use_single_compartment_environment):
- syn_spec.update({'receptor_type': ALPHAexc_soma})
- else:
- syn_spec_dict.update({'receptor_type': ri.ALPHAexc_soma})
- nest.Connect(neurons[i], neurons[j], conn_spec=conn_spec_dict_exc, syn_spec=syn_spec)
- present_exc_conn[i][j]['synapse_model'] = static_synapse_i_j
- #inh to inh connections: initial setup
- nest.CopyModel('static_synapse','static_synapse_inh_inh')
- nest.Connect(inh_neurons, inh_neurons, conn_spec=conn_spec_dict_inh,\
- syn_spec={"synapse_model": 'static_synapse_inh_inh', "weight": inh_to_inh_weight, "delay": inh_to_inh_delay_ms})
- # Connect inhibitory neurons to all excitatory neurons and vice versa
- #before 2024-1006 (QUESTA NON ROMPE IL KERNEL)
- inh_to_exc_delay_ms = min_syn_delay_ms + exc_t_ref_ms + 0.55
- exc_to_inh_delay_ms = min_syn_delay_ms + 0.5
- #IN PROVA QUESTA DOPO FUNZIONA ANCORA
- #inh_to_exc_delay_ms = min_syn_delay_ms + 0.55
- #exc_to_inh_delay_ms = min_syn_delay_ms + 0.5
- #IN PROVA
- #inh_to_exc_delay_ms = min_syn_delay_ms + 0.1
- #exc_to_inh_delay_ms = min_syn_delay_ms + 0.1
- #QUESTA CONFIGURAZIONE FA CRASHARE IL KERNEL
- #inh_to_exc_delay_ms = min_syn_delay_ms
- #exc_to_inh_delay_ms = min_syn_delay_ms
- for i in range(num_exc_pop):
- # inh to exc(i)
- new_syn_model_inh_exc_n = 'static_synapse_inh_exc_'+str(i)
- nest.CopyModel('static_synapse', new_syn_model_inh_exc_n)
- syn_spec={"synapse_model": new_syn_model_inh_exc_n, "weight": inh_to_exc_weight, "delay": inh_to_exc_delay_ms}
- if not use_nestml:
- if(not use_single_compartment_environment):
- syn_spec.update({"weight": -inh_to_exc_weight, 'receptor_type': ALPHAinh_soma})
- else:
- syn_spec.update({
- "weight": -inh_to_exc_weight,
- "receptor_type": ri.ALPHAinh_soma,
- })
- nest.Connect(inh_neurons, neurons[i], conn_spec=conn_spec_dict_inh, syn_spec=syn_spec)
- # exc(i) to inh
- new_syn_model_exc_n_inh = 'static_synapse_exc_' + str(i) + '_inh'
- nest.CopyModel('static_synapse', new_syn_model_exc_n_inh)
- syn_spec={"synapse_model": new_syn_model_exc_n_inh, "weight": exc_to_inh_weight, "delay": exc_to_inh_delay_ms}
- nest.Connect(neurons[i], inh_neurons, conn_spec=conn_spec_dict_exc, syn_spec=syn_spec)
- # Create and connect Poisson generators if enabled
- use_poisson_generators=nest_pms["network"]["use_poisson_generators"]
- if use_poisson_generators:
- num_poisson_generators=nest_pms["network"]["num_poisson_generators"]
- poisson_rate=nest_pms["poisson"]["poisson_rate"]
- pgs = nest.Create("poisson_generator", num_poisson_generators, params={"rate": poisson_rate, 'start': 200.})
- poisson_weight=nest_pms["poisson"]["poisson_weight"]
- syn_spec={"weight": poisson_weight, "delay": 1.0}
- for i in range(num_exc_pop):
- if not use_nestml:
- if not use_single_compartment_environment:
- syn_spec.update({'receptor_type': ALPHAexc_soma})
- else:
- syn_spec.update({'receptor_type': ri.ALPHAexc_soma})
- nest.Connect(pgs, neurons[i], syn_spec=syn_spec)
- # Add contextual poisson signal if configured
- if 'contextual_poisson' in nest_pms and \
- nest_pms['brain_state'] in nest_pms['contextual_poisson']:
- # Extract the upper-level configuration parameters
- contextual_poisson_config = nest_pms['contextual_poisson'][nest_pms['brain_state']]
- # Ensure all required keys are present in the configuration
- if all(key in contextual_poisson_config for key in ['events', 'spreading_factor', 'basic_rate', 'poisson_weight']):
- events = contextual_poisson_config['events']
- spreading_factor = contextual_poisson_config['spreading_factor']
- basic_rate = contextual_poisson_config['basic_rate']
- poisson_weight = contextual_poisson_config['poisson_weight']
- # Iterate through each event in the events list
- for event in events:
- target_pop = event['target_population']
- start_time = event['start_time_ms']
- stop_time = event['stop_time_ms']
- # Create a Poisson generator for the event
- contextual_poisson_gen = nest.Create('poisson_generator', 1, {'rate': basic_rate})
- # Set the start and stop times for the generator
- nest.SetStatus(contextual_poisson_gen, {'start': start_time, 'stop': stop_time})
- # Define the synapse specifications
- syn_spec = {'weight': poisson_weight * spreading_factor, "delay": 1.0}
- # Connect the generator to the target population
- if not use_nestml:
- if not use_single_compartment_environment:
- syn_spec.update({'receptor_type': AMPA_NMDA_dist})
- else:
- # if use_single_compartment_environment:
- # syn_spec.update({'receptor_type': ri.AMPA_NMDA_soma})
- # else:
- # syn_spec.update({'receptor_type': ri.AMPA_NMDA_dist})
- syn_spec.update({'receptor_type': ri.PSC_context})
- nest.Connect(contextual_poisson_gen, neurons[target_pop], syn_spec=syn_spec)
- # Add contextual inhibiton signal if configured
- if 'contextual_inhibition' in nest_pms and \
- nest_pms['brain_state'] in nest_pms['contextual_inhibition']:
- # Extract the upper-level configuration parameters
- contextual_poisson_config = nest_pms['contextual_inhibition'][nest_pms['brain_state']]
- # Ensure all required keys are present in the configuration
- if all(key in contextual_poisson_config for key in ['events', 'spreading_factor', 'basic_rate', 'poisson_weight']):
- events = contextual_poisson_config['events']
- spreading_factor = contextual_poisson_config['spreading_factor']
- basic_rate = contextual_poisson_config['basic_rate']
- poisson_weight = contextual_poisson_config['poisson_weight']
- # Iterate through each event in the events list
- for event in events:
- target_pop = event['target_population']
- start_time = event['start_time_ms']
- stop_time = event['stop_time_ms']
- # Create a Poisson generator for the event
- contextual_poisson_gen = nest.Create('poisson_generator', 1, {'rate': basic_rate})
- # Set the start and stop times for the generator
- nest.SetStatus(contextual_poisson_gen, {'start': start_time, 'stop': stop_time})
- # Define the synapse specifications
- syn_spec = {'weight': poisson_weight * spreading_factor, "delay": 1.0}
- # Connect the generator to the target population
- if not use_nestml:
- if not use_single_compartment_environment:
- syn_spec.update({'receptor_type': AMPA_NMDA_dist})
- else:
- # @Willem, please modify the code in the comment towards your nestml specifics
- # assert False, "use_nestml option not yet supported: under construction"
- if use_single_compartment_environment:
- syn_spec.update({'receptor_type': ri.ALPHAinh_soma})
- else:
- syn_spec.update({'receptor_type': ri.ALPHAinh_dist})
- nest.Connect(contextual_poisson_gen, neurons[target_pop], syn_spec=syn_spec)
- # DC current injection for all neurons if enabled
- use_dc_exc_injectors=nest_pms["use_dc_exc_injectors"]
- if use_dc_exc_injectors:
- dc_exc_start_ms=nest_pms["dc_exc"]["start_ms"]
- dc_exc_stop_ms=nest_pms["dc_exc"]["stop_ms"]
- dc_exc_amplitudes=nest_pms["dc_exc"]["dc_exc_amplitudes"]
- dc_exc_weight=nest_pms["dc_exc"]["dc_exc_weight"]
- dc_exc_delay_ms=nest_pms["dc_exc"]["dc_exc_delay_ms"]
- dcgs = [nest.Create("dc_generator", 1,\
- {"start": dc_exc_start_ms, "stop": dc_exc_stop_ms, "amplitude": amp})\
- for amp in dc_exc_amplitudes]
- for i in range(num_exc_pop):
- if use_single_compartment_environment:
- nest.Connect(dcgs[i], neurons[i],\
- syn_spec={'weight': dc_exc_weight, 'delay': dc_exc_delay_ms})
- else:
- #assert("MC neuron not yet implemented")
- nest.Connect(dcgs[i], neurons[i], syn_spec={'weight': dc_exc_weight, 'delay': dc_exc_delay, 'receptor_type': 0})
- # Specific DC current injection for inhibitory neurons
- use_dc_inh_injector=nest_pms["use_dc_inh_injector"]
- if use_dc_inh_injector:
- dc_inh_start_ms = nest_pms["dc_inh"]["start_ms"]
- dc_inh_stop_ms = nest_pms["dc_inh"]["stop_ms"]
- dc_inh_amplitude = nest_pms["dc_inh"]["dc_inh_amplitude"]
- dc_inh_weight = nest_pms["dc_inh"]["weight"]
- dc_inh_delay_ms = nest_pms["dc_inh"]["delay_ms"]
- dc_inh_generator = nest.Create("dc_generator", 1,\
- {"start": dc_inh_start_ms, "stop": dc_inh_stop_ms,
- "amplitude": dc_inh_amplitude})
- nest.Connect(dc_inh_generator, inh_neurons,\
- syn_spec={'weight': dc_inh_weight, 'delay': dc_inh_delay_ms})
- def make_plastic_conn(source_exc_pop, target_exc_pop, Wmax, verbose):
- if verbose:
- print("in make_plastic_conn: source and target pops", source_exc_pop, target_exc_pop)
- assert(source_exc_pop >= 0 and source_exc_pop < num_exc_pop)
- assert(target_exc_pop >= 0 and target_exc_pop < num_exc_pop)
- new_syn_model = default_plasticity['synapse_model']+'_'+str(source_exc_pop)+'_'+str(target_exc_pop)
- if verbose:
- print("in make_plastic_conn: new_syn_model = ", new_syn_model)
- if new_syn_model not in nest.Models(mtype='synapses'):
- if verbose:
- print("in make_plastic_conn: new_syn_model not already among Models")
- if present_exc_conn[source_exc_pop][target_exc_pop]['synapse_model'] != False:
- if verbose:
- print("in make_plastic_conn: present_exc_conn =",present_exc_conn[source_exc_pop][target_exc_pop]['synapse_model'])
- print("in make_plastic_conn: before GetConnections (old set)")
- existing_conns = nest.GetConnections(neurons[source_exc_pop],
- neurons[target_exc_pop],
- synapse_model=present_exc_conn[source_exc_pop][target_exc_pop]['synapse_model'])
- if verbose:
- print("in make_plastic_conn: before Disconnect (old set)")
- nest.Disconnect(existing_conns)
- if verbose:
- print("in make_plastic_conn: after Disconnect (old set)")
- present_exc_conn[source_exc_pop][target_exc_pop] = {'synapse_model': False}
- conn_spec_dict = conn_spec_dict_exc
- nest.CopyModel(default_plasticity['synapse_model'],new_syn_model)
- syn_spec_dict = {"synapse_model": new_syn_model,
- "Wmax": Wmax,
- "tau_plus": default_plasticity['tau_plus'],
- "lambda": default_plasticity['lambda'],
- "alpha": default_plasticity['alpha'],
- "mu_plus": default_plasticity['mu_plus'],
- "mu_minus": default_plasticity['mu_minus'],
- "weight": default_plasticity['weight'],
- "delay": exc_to_exc_delay_ms}
- if not use_nestml:
- if not use_single_compartment_environment:
- syn_spec_dict.update({'receptor_type': ALPHAexc_soma})
- else:
- syn_spec_dict.update({'receptor_type': ri.ALPHAexc_soma})
- if verbose:
- print("in make_plastic_conn: before connecting ",new_syn_model)
- nest.Connect(neurons[source_exc_pop], neurons[target_exc_pop],
- conn_spec=conn_spec_dict, syn_spec=syn_spec_dict)
- if verbose:
- print("in make_plastic_conn: after connecting ",new_syn_model)
- present_exc_conn[source_exc_pop][target_exc_pop] = {'synapse_model': new_syn_model}
- if verbose:
- print("Wmax =", Wmax, "initial_weight", default_plasticity['weight'])
- return
- def disconnect_conn(source_exc_pop, target_exc_pop, verbose):
- if verbose:
- print("in disconnect_conn: source_exc_pop -> target_exc_pop",source_exc_pop, target_exc_pop)
- assert(source_exc_pop >= 0 and source_exc_pop < num_exc_pop)
- assert(target_exc_pop >= 0 and target_exc_pop < num_exc_pop)
- if present_exc_conn[source_exc_pop][target_exc_pop]['synapse_model'] != False:
- synapse_model = present_exc_conn[source_exc_pop][target_exc_pop]['synapse_model']
- existing_conns = nest.GetConnections(neurons[source_exc_pop],
- neurons[target_exc_pop], synapse_model=synapse_model)
- nest.Disconnect(existing_conns)
- present_exc_conn[source_exc_pop][target_exc_pop] = {'synapse_model': False}
- # Next lines reconnect with zero values
- conn_spec_dict = conn_spec_dict_exc
- new_disconnected_static_syn_model = \
- 'static_synapse_weight_zero_'+str(source_exc_pop)+'_'+str(target_exc_pop)
- nest.CopyModel('static_synapse',new_disconnected_static_syn_model)
- syn_spec_dict = {"synapse_model":new_disconnected_static_syn_model,"weight": 0.0, "delay": exc_to_exc_delay_ms}
- if not use_nestml:
- if not use_single_compartment_environment:
- syn_spec_dict.update({'receptor_type': ALPHAexc_soma})
- else:
- syn_spec_dict.update({'receptor_type': ri.ALPHAexc_soma})
- nest.Connect(neurons[source_exc_pop], neurons[target_exc_pop],
- conn_spec=conn_spec_dict, syn_spec=syn_spec_dict)
- present_exc_conn[source_exc_pop][target_exc_pop] = {'synapse_model': new_disconnected_static_syn_model, 'weight': 0.0}
- return
- def perform_event_action(requested_action, tot_simulated_time_ms, verbose):
- if verbose:
- print("in perform_event_action: requested action:", requested_action, "at time (ms)", tot_simulated_time_ms)
- if requested_action['kind']=='store_syn':
- #STORE SYN MATRIX
- store_syn(requested_action['syn_file_name'], tot_simulated_time_ms, verbose)
- elif requested_action['kind']=='disconnect_exc_pop_syn':
- #DISCONNECT (several options to select target intra and inter pops)
- #can be an integer, a list of integers, or a string
- target_exc_pop = requested_action['target_exc_pop']
- if isinstance(target_exc_pop, int):
- # Perform actions for integer value
- disconnect_conn(target_exc_pop, target_exc_pop, verbose)
- elif isinstance(target_exc_pop, list):
- # The value is a list
- # Check that all elements in the list are integers
- if all(isinstance(item, int) for item in target_exc_pop):
- # Perform actions for list of integers
- for item in target_exc_pop:
- disconnect_conn(item, item, verbose)
- else:
- raise TypeError("All items in 'target_exc_pop' list must be integers.")
- elif isinstance(target_exc_pop, str):
- # The value is a string
- # Perform actions for string value
- if target_exc_pop == 'all_intra_exc':
- for index_target_pop in range(0,num_exc_pop):
- disconnect_conn(index_target_pop, index_target_pop, verbose)
- elif target_exc_pop == 'all_inter_exc':
- for index_source_pop in range(0,num_exc_pop):
- for index_target_pop in range(0,num_exc_pop):
- if index_source_pop!=index_target_pop:
- disconnect_conn(index_source_pop, index_target_pop, verbose)
- elif target_exc_pop == 'all_intra_inter_exc':
- for index_source_pop in range(0,num_exc_pop):
- for index_target_pop in range(0,num_exc_pop):
- disconnect_conn(index_source_pop, index_target_pop, verbose)
- else:
- print("unrecognized command in set plastic synapses")
- assert(False)
- else:
- # Handle unexpected types
- raise TypeError(f"Invalid type for 'target_exc_pop': {type(target_exc_pop)}")
- elif requested_action['kind']=='exc_plasticity_ON':
- #make PLASTIC exc synapses (several options to select target intra and inter pops)
- Wmax = recurrent_weight * requested_action['W_max_factor']
- #can be an integer, a list of integers, or a string
- target_exc_pop = requested_action['target_exc_pop']
- if isinstance(target_exc_pop, int):
- # Perform actions for integer value
- make_plastic_conn(target_exc_pop, target_exc_pop, Wmax, verbose)
- elif isinstance(target_exc_pop, list):
- # The value is a list
- # Check that all elements in the list are integers
- if all(isinstance(item, int) for item in target_exc_pop):
- # Perform actions for list of integers
- for item in target_exc_pop:
- make_plastic_conn(item, item, Wmax, verbose)
- else:
- raise TypeError("All items in 'target_exc_pop' list must be integers.")
- elif isinstance(target_exc_pop, str):
- # The value is a string
- # Perform actions for string value
- if target_exc_pop == 'all_intra_exc':
- for index_target_pop in range(0,num_exc_pop):
- make_plastic_conn(index_target_pop, index_target_pop, Wmax, verbose)
- elif target_exc_pop == 'all_inter_exc':
- for index_source_pop in range(0,num_exc_pop):
- for index_target_pop in range(0,num_exc_pop):
- if index_source_pop!=index_target_pop:
- make_plastic_conn(index_source_pop, index_target_pop, Wmax, verbose)
- elif target_exc_pop == 'all_intra_inter_exc':
- for index_source_pop in range(0,num_exc_pop):
- for index_target_pop in range(0,num_exc_pop):
- make_plastic_conn(index_source_pop, index_target_pop, Wmax, verbose)
- else:
- print("unrecognized command in set plastic synapses")
- assert(False)
- else:
- # Handle unexpected types
- raise TypeError(f"Invalid type for 'target_exc_pop': {type(target_exc_pop)}")
- elif requested_action['kind']=='set_learning':
- # Set learning rate
- learning_rate = default_plasticity['lambda']
- alpha = default_plasticity['alpha']
- if 'lambda' in requested_action:
- learning_rate = requested_action['lambda']
- if 'alpha' in requested_action:
- alpha = requested_action['alpha']
- target_exc_pop = requested_action['target_exc_pop']
- assert(target_exc_pop >= 0 and target_exc_pop < num_exc_pop)
- # add check if target_exc_pop is in the list of plastic populations (issue #34)
- existing_conns_plastic = nest.GetConnections(neurons[target_exc_pop],
- neurons[target_exc_pop], synapse_model='stdp_synapse')
- nest.SetStatus(existing_conns_plastic, {'lambda': learning_rate, 'alpha': alpha})
- print('Set lambda =', learning_rate, 'alpha =', alpha, 'in population', target_exc_pop)
- else:
- #UNRECOGNIZED
- print("in perform_event_action: requested action:",requested_action['kind'],"NOT SUPPORTED")
- assert False
- return
- list_of_syn_matrix_file_names=[]
- def store_syn(file_name, tot_simulated_time_ms, verbose):
- if(verbose):
- print("in store_syn:")
- print("will save to file:", file_name)
- print("at time (ms):", tot_simulated_time_ms)
- array_of_dicts = []
- for i in range(num_exc_pop):
- synapse_model = present_exc_conn[i][i]['synapse_model']
- array_of_dicts.append(\
- {"time (ms)": tot_simulated_time_ms,\
- "conn_index": i,\
- "synapse_model":present_exc_conn[i][i]['synapse_model'],\
- "connections": nest.GetConnections(source=neurons[i],target=neurons[i],
- synapse_model=synapse_model).get(("source", "target", "weight"), output="pandas")})
- with open(file_name, "wb") as f:
- pickle.dump(array_of_dicts, f, pickle.HIGHEST_PROTOCOL)
- list_of_syn_matrix_file_names.append(file_name)
- return
- def simulate(verbose):
- # Run the simulation
- if verbose:
- print("in nest_..._simulate: LIST OF PLANNED ACTIONS")
- for item in nest_pms['events_pms']:
- if 'action' in item:
- print("ACTION",item['action'])
- if 'sim_period_ms' in item:
- if verbose:
- print("expected NEXT SIM PERIOD ms",item['sim_period_ms'])
- print("in nest_..._simulate: JUST BEFORE ACTUAL EXECUTION")
- tot_simulated_time_ms=0.0
- if 'events_pms' in nest_pms:
- for item in nest_pms['events_pms']:
- if 'action' in item:
- if verbose:
- print("ACTION",item['action'])
- #performing the action
- perform_event_action(item['action'], tot_simulated_time_ms, verbose)
- if 'sim_period_ms' in item:
- if verbose:
- print("expected NEXT SIM PERIOD ms",item['sim_period_ms'])
- next_sim_period_ms = item['sim_period_ms']
- else:
- next_sim_period_ms = 0.0
- if next_sim_period_ms + tot_simulated_time_ms > sim_pms["stop_ms"]:
- next_sim_period_ms = sim_pms["stop_ms"] - tot_simulated_time_ms
- store_syn('syn_matrix-end_of_sim',sim_pms["stop_ms"],verbose)
- if verbose:
- print("reduced last sim time ms to", next_sim_period_ms)
- print("launching next period of ", next_sim_period_ms, "ms of simulation")
- #launching simulation period
- if next_sim_period_ms > 0:
- nest.Simulate(next_sim_period_ms)
- tot_simulated_time_ms += next_sim_period_ms
- if verbose:
- print("performed until now:",tot_simulated_time_ms, "TOTAL ms of simulation")
- if tot_simulated_time_ms < sim_pms["stop_ms"]:
- next_sim_period_ms = sim_pms["stop_ms"] - tot_simulated_time_ms
- if verbose:
- print("ADDING ", next_sim_period_ms, "ms sim to complete expected" ,sim_pms["stop_ms"], "TOTAL ms of simulation")
- #possible last simulation period
- assert(next_sim_period_ms>0)
- nest.Simulate(next_sim_period_ms)
- tot_simulated_time_ms += next_sim_period_ms
- store_syn('syn_matrix-end_of_sim', tot_simulated_time_ms, verbose)
- if verbose:
- print("performed until now:",tot_simulated_time_ms, "TOTAL ms of simulation")
- assert(tot_simulated_time_ms==sim_pms["stop_ms"])
- return
- #HERE IS THE SIMULATION
- verbose=True
- simulate(verbose)
- sim_completed=True
- return sim_completed, spike_recorders, inh_spike_recorder, multimeter, list_of_syn_matrix_file_names
nest_reset_create_connect_simulate.py at commit 3331128, no license · at the source
Overview
- Peter Grünberg Institute 15 – Neuromorphic Software Ecosystems (PGI-15), Forschungszentrum Jülich, Aachen, Germany
- Institute for Advanced Simulation (IAS-6), Computational and Systems Neuroscience, Forschungszentrum Jülich, Jülich, Germany
- Simulation and Data Lab Neuroscience, Jülich Supercomputer Centre, Institute for Advanced Simulation, Jülich-Aachen Research Alliance, Forschungszentrum Jülich, Jülich, Germany
- Software Engineering, Faculty of Computer Science, RWTH Aachen University, Aachen, Germany
- Istituto Nazionale di Fisica Nucleare, Sezione di Roma, Rome, Italy
Abstract
While subcellular mechanisms in the dendrites of neurons govern the implementation of learning and memory in the brain, large-scale network simulations featuring such processes remain challenging to achieve. This can be attributed to a lack of appropriate software tools, as neuroscientific simulators focus on the one hand on highly detailed models, and on the other hand on massive networks featuring point neurons. Here, we fill this gap by implementing a framework for the massively parallel simulation of simplified dendrite models with customizable subcellular dynamics. We leverage the NEural Simulation Tool (NEST), the neuroscientific reference with respect to efficient massively parallel simulations of point-neuron networks. By co-opting the model description language NESTML, we generate C++ code implementing user-configurable subcellular dynamics. We show that the generated models run efficiently, leading to scalable NEST network simulations. To showcase relevant functionalities, we provide a proof-of-concept demonstration that a key sensory computation – the association of top-down context arriving at distal dendrites in layer 1 and feedforward sensory input arriving perisomatically – can be achieved in a single-shot fashion through apical calcium dynamics. Our work thus unlocks the study of how dendritic processes shape network function and learning at scale.
Reproduced under the paper's license (CC BY), from the paper cited above.
Repositories
Its files are read in the Code ↔ Paper reader above, with 5 matches between paragraphs and lines of code.
Zenodo 22878144
Availability: 1 check, the latest on 30 October 2026: the link answers (HTTP 200)
- 30 October 2026: the link answers (HTTP 200)
willemwybo/wta-states
33311287c43fb73cddacb163c4b66064c961787e, 30 June 2025Availability: 1 check, the latest on 30 October 2026: the link answers
- 30 October 2026: the link answers
16 files
- WTA-awake-sleep.ipynb, Jupyter, 9 lines
- WTA-awake-sleep.py, Python, 5 lines
- WTA_awake_sleep.py, Python, 80 lines
- WTA_figure.py, Python, 412 lines
- activity_analysis.py, Python, 273 lines
- analysis_functions.py, Python, 533 lines
- asserting_functions.py, Python, 13 lines
- cm_neuron.py, Python, 150 lines, 1 match
- cm_neuron_nestml.py, Python, 201 lines, 1 match
- matplotlibsettings.py, Python, 349 lines
- nest_reset_create_connec
t_simulate.py , Python, 637 lines, 2 matches - prepare_nest_parameters.
py , Python, 286 lines, 1 match - synaptic_analysis.py, Python, 182 lines
- synaptic_io.py, Python, 27 lines
- yaml_io.py, Python, 210 lines
- README.md, Text, 78 lines
jugit.fz-juelich.de/w.wybo/ca-adex
Availability: 1 check, the latest on 30 October 2026: the link answers (HTTP 200)
- 30 October 2026: the link answers (HTTP 200)
Zenodo 10125416
Availability: 1 check, the latest on 1 October 2026: the link answers (HTTP 200)
- 1 October 2026: the link answers (HTTP 200)
Zenodo 20757797
Availability: 1 check, the latest on 30 October 2026: the link answers (HTTP 200)
- 30 October 2026: the link answers (HTTP 200)
Code availability
Code to reproduce the simulations in this paper is available at https://
Reproduced under the paper's license (CC BY), from the paper cited above.
Tracing map
Proposed by the machine: these links were found in the paper and verified at the source, without human review. The map will receive a Zenodo DOI once one of the paper's authors has validated it with their ORCID.
What the map holds:
- 5 repositories of the authors' code, each at its verified commit, with its license and how the link was found in the paper;
- 15 scripts, each with its path and the digest of its content;
- 5 matches between paragraphs of the paper and lines of the code (method lexical-v1);
- neither the text of the paper nor the code itself.
Its JSON (tracing-map.json) is deposited on Zenodo with its DOI once the map is validated.
Data
No dataset and no data link were found in the paper.
Data availability
Benchmarking results are available at https://
Reproduced under the paper's license (CC BY), from the paper cited above.
Versions
The history of this record: each version stored by the harvester or made by a correction of its authors or of the maintainers of its code, and what changed in its facts. The texts of the paper (its abstract, its availability statements) are not part of it; versions that changed only those are not listed.
Version 1, 30 October 2026: the first record
Recorded: type, language, journal, volume, issue, pages, dates, 7 authors, 2 keywords, 8 MeSH terms, 1 funder, 78 references.
Cite
This paper
Wybo, W. A. M., Ewert, L., Linssen, C., Babu, P., Pastorelli, E., Paolucci, P. S., & Morrison, A. (2026). A NEST-based framework unlocks massively parallel simulation of networks of multi-compartment neurons with customizable subcellular dynamics. Communications biology, 9(1), 1411. https://
BibTeX
@article{wybo2026nest,
author = {Wybo, Willem A M and Ewert, Leander and Linssen, Charl and Babu, Pooja and Pastorelli, Elena and Paolucci, Pier Stanislao and Morrison, Abigail},
title = {{A NEST-based framework unlocks massively parallel simulation of networks of multi-compartment neurons with customizable subcellular dynamics}},
journal = {Communications biology},
year = {2026},
month = oct,
volume = {9},
number = {1},
pages = {1411},
publisher = {Nature Publishing Group},
issn = {2399-3642},
doi = {10.1038/
url = {https://
pmid = {42946780},
pmcid = {PMC13714284}
}
RIS
TY - JOUR
AU - Wybo, Willem A M
AU - Ewert, Leander
AU - Linssen, Charl
AU - Babu, Pooja
AU - Pastorelli, Elena
AU - Paolucci, Pier Stanislao
AU - Morrison, Abigail
TI - A NEST-based framework unlocks massively parallel simulation of networks of multi-compartment neurons with customizable subcellular dynamics
T2 - Communications biology
J2 - Commun Biol
PY - 2026
DA - 2026/
VL - 9
IS - 1
SP - 1411
SN - 2399-3642
PB - Nature Publishing Group
DO - 10.1038/
UR - https://
LA - en
ER -
CSL-JSON
{
"id": "10.1038/
"type": "article-journal",
"title": "A NEST-based framework unlocks massively parallel simulation of networks of multi-compartment neurons with customizable subcellular dynamics",
"container-title": "Communications biology",
"author": [
{
"family": "Wybo",
"given": "Willem A M"
},
{
"family": "Ewert",
"given": "Leander"
},
{
"family": "Linssen",
"given": "Charl"
},
{
"family": "Babu",
"given": "Pooja"
},
{
"family": "Pastorelli",
"given": "Elena"
},
{
"family": "Paolucci",
"given": "Pier Stanislao"
},
{
"family": "Morrison",
"given": "Abigail"
}
],
"container-title-short":
"volume": "9",
"issue": "1",
"page": "1411",
"DOI": "10.1038/
"PMID": "42946780",
"PMCID": "PMC13714284",
"ISSN": "2399-3642",
"publisher": "Nature Publishing Group",
"URL": "https://
"language": "en",
"issued": {
"date-parts": [
[
2026,
10,
27
]
]
}
}
The tracing map gets a citation of its own once an author has validated it and it has a DOI.
Similar papers
The papers with a page that share the most with this one: the tools found in their code, their categories, datasets, cited references and authors, the rarest counting most.
- [1] doi:10.3389/fncom.2025.1566196 [code]
- Simplified two-compartment neuron with calcium dynamics capturing brain-state specific apical-amplification, -isolation and -drive.Journal: Frontiers in computational neuroscienceIn common: computational, 20 references, author Pier Stanislao Paolucci
- [2] doi:10.3389/fninf.2022.883333 [code]
- Fast Simulation of a Multi-Area Spiking Network Model of Macaque Cortex on an MPI-GPU Cluster.Journal: Frontiers in neuroinformaticsIn common: NEST Simulator, SciPy, Matplotlib, 1 other tool, computational, computational modeling (no new data), 10 references, author Pier Stanislao Paolucci
- [3] doi:10.1007/s12021-025-09766-x [code]
- The Neural Analysis Toolkit Unifies Semi-Analytical Techniques to Simplify, Understand, and Simulate Dendrites.Journal: NeuroinformaticsIn common: computational modeling (no new data), 14 references
- [4] doi:10.3389/fninf.2023.941696 [code]
- Efficient parameter calibration and real-time simulation of large-scale spiking neural networks with GeNN and NEST.Journal: Frontiers in neuroinformaticsIn common: NEST Simulator, SciPy, Matplotlib, 1 other tool, computational, computational modeling (no new data), 9 references
- [5] doi:10.1038/s41467-023-41553-7 [code]
- A GPU-based computational framework that bridges neuron simulation and artificial intelligence.Journal: Nature communicationsIn common: SciPy, Matplotlib, NumPy, computational modeling (no new data), 12 references
- [6] doi:10.7554/elife.79535 [code]
- Ultrafast simulation of large-scale neocortical microcircuitry with biophysically realistic neurons.Journal: eLifeIn common: SciPy, Matplotlib, NumPy, computational, computational modeling (no new data), 11 references
- [7] doi:10.1371/journal.pcbi.1013926 [code]
- Plastic Arbor: A modern simulation framework for synaptic plasticity-From single synapses to networks of morphological neurons.Journal: PLoS computational biologyIn common: NEST Simulator, SciPy, Matplotlib, 1 other tool, computational modeling (no new data), 9 references
- [8] doi:10.7554/elife.103324 [code]
- DendroTweaks, an interactive approach for unraveling dendritic dynamics.Journal: eLifeIn common: SciPy, Matplotlib, NumPy, computational modeling (no new data), 11 references
- [9] doi:10.1038/s41467-025-56297-9 [code]
- Dendrites endow artificial neural networks with accurate, robust and parameter-efficient learning.Journal: Nature communicationsIn common: SciPy, Matplotlib, NumPy, computational modeling (no new data), 10 references
- [10] doi:10.1371/journal.pcbi.1010353 [code]
- Brain signal predictions from multi-scale networks using a linearized framework.Journal: PLoS computational biologyIn common: NEST Simulator, SciPy, Matplotlib, 1 other tool, computational, computational modeling (no new data), 4 references, author Pooja Babu
Contribute
The authors of this paper can claim it, correct its record and validate its tracing map, and the maintainers of its code (its owner, or a public member of its organization) correct what it says of their repository; anyone signed in can ask for its removal. Every request goes to OSCR's own machine, which answers it; your account page follows them.
Sign in with ORCID to claim this paper as one of its authors, correct its record or validate its tracing map: when the paper's metadata lists your ORCID iD, you are recognized at once. Maintainers of its code: sign in with GitHub, then claim the repository on your account page.
Claim this paper
Correct its record
Say what each link of this record is, remove the ones that are not the paper's, add the ones that are missing. The correction becomes a new version of the record, in its Versions section.
Validate its tracing map
You validate the map as this page shows it: 5 repositories of the authors' code, each at its verified commit and with its license, 15 scripts, and 5 matches between paragraphs and code (see the Code and Map sections). It then receives a DOI on Zenodo, with you (your ORCID iD) and OSCR as its creators; the code itself is not deposited.
The map's fingerprint: sha256:5c5f0e7655390d0c…
Add the badge to the code's README
If you are an author or a maintainer of this paper's code, you can add this badge. It says what OSCR knows of the paper (its code, its validated tracing map) and links the code to this page. Paste one of these snippets under the README's title. Keep the two marks around it, so that the badge can be replaced in place and is never added twice. OSCR changes nothing in your repository.
Markdown
<!-- oscr-badge:start -->
[](https://openscicode.org/badge/doi/10.1038/s42003-026-11157-0)
<!-- oscr-badge:end -->reStructuredText
.. oscr-badge:start
.. image:: https://openscicode.org/badge/doi/10.1038/s42003-026-11157-0.svg
:target: https://openscicode.org/badge/doi/10.1038/s42003-026-11157-0
:alt: OSCR
.. oscr-badge:endHTML
<!-- oscr-badge:start -->
<a href="https://openscicode.org/badge/doi/10.1038/s42003-026-11157-0"><img src="https://openscicode.org/badge/doi/10.1038/s42003-026-11157-0.svg" alt="OSCR"></a>
<!-- oscr-badge:end -->On GitHub, open the README, choose Edit (the pencil), paste the snippet under the title, then "Commit changes".
If you choose to, you can have the badge kept up to date for you, with oscr badge --write from the command line or with the GitHub Action in your repository's workflows. Every other form and option (a card, AsciiDoc, LaTeX, shields.io) is on the badge page.
Request its removal
To ask OSCR to remove this record, the copies of its authors' scripts or its tracing map, use the removal request page: signed in, you say who you are, what to remove and why, then review and confirm the request. Published rules decide every request (how).
Discussion, reproductions, activity
Discussion: code errors and mismatches between the code and the paper about this paper and its code, from readers and its authors, beside the paper and its tracing map.
Report a mismatch between the code and the paper · Report a code error (signed in)
Reproductions: reports from readers who ran the authors' code and did not get the paper's result, what they ran, with which environment, commit and data.
Report a reproduction failure (signed in)
Versions of its code: the releases of its code tied to a version of this paper (the preprint, the accepted manuscript, the version of record…), each with the tracing map versioned with it.
Activity: what happens around this paper: new versions of its record, its map's validation, discussions and reproductions. It opens with sign-in.
