def build(self): """Builds the nodes and edges for the network. """ self.net = NetworkBuilder("biophysical") self.net.add_nodes(N=1, pop_name='Pyrc', potental='exc', model_type='biophysical', model_template='hoc:L5PCtemplate', morphology=None) self._build_exc() self._build_inh() self._save_nets() self._make_rasters() #Final build step. build_env_bionet( base_dir='./', network_dir='./network', dt=self.params["dt"], tstop=self.params["time"]["stop"] * 1000.0, report_vars=['v'], dL=self.params["dL"], #target length (um) of segments spikes_threshold=-10, spikes_inputs=[('exc_stim', 'exc_stim_spikes.h5'), ('prox_inh_stim', 'prox_inh_stim_spikes.h5'), ('dist_inh_stim', 'dist_inh_stim_spikes.h5')], components_dir='../biophys_components', compile_mechanisms=False)
def test_add_edges_custom_params(): # Uses connection map functionality to create edges with unique parameters net = NetworkBuilder('V1') net.add_nodes(N=10, arg_list=range(10), arg_ctype='e') net.add_nodes(N=5, arg_list=range(10, 15), arg_ctype='i') cm = net.add_edges( source={'arg_ctype': 'e'}, target={'arg_ctype': 'i'}, connection_rule=2 ) cm.add_properties('syn_weight', rule=0.5, dtypes=float) cm.add_properties( ['src_num', 'trg_num'], rule=lambda s, t: [s['node_id'], t['node_id']], dtypes=[int, int] ) net.build() assert(net.nedges == 2*50) assert(net.edges_built is True) for e in net.edges(): assert(e['syn_weight'] == 0.5) assert(e['src_num'] == e.source_node_id) assert(e['trg_num'] == e.target_node_id)
def test_no_name(): # Fail if network name is invalid with pytest.raises(ValueError): NetworkBuilder(name='') with pytest.raises(ValueError): NetworkBuilder(name=None)
def _build_exc(self): """Builds the excitatory input cells and their synapses. """ # External excitatory inputs self.exc_stim = NetworkBuilder('exc_stim') #DataFrame of all segments on the cell. segs = pd.read_csv(self.params["cell"]["segments_file"]) dends = segs[(segs["Type"] == "dend") & (segs["Distance"] >= 50)] apics = segs[(segs["Type"] == "apic")] np.random.seed(self.seed + 1) apic_start, self.dend_groups = self._build_exc_nodes( dends, "dend", self.n_dend_exc) np.random.seed(self.seed + 2) _, self.apic_groups = self._build_exc_nodes(apics, "apic", self.n_apic_exc, start=apic_start) np.random.seed(self.seed + 3) self._build_exc_edges(self.dend_groups) np.random.seed(self.seed + 4) self._build_exc_edges(self.apic_groups)
def test_single_node(): net = NetworkBuilder('NET1') net.add_nodes(prop1='prop1', prop2='prop2', param1=['param1']) nodes = list(net.nodes()) assert (len(nodes) == 1) assert (nodes[0]['param1'] == 'param1') assert (nodes[0]['prop1'] == 'prop1') assert (nodes[0]['prop2'] == 'prop2')
def test_node_sets(): net = NetworkBuilder('NET1') net.add_nodes(N=100, prop_n='prop1', pool1='p1', sp='sp', param1=range(100)) net.add_nodes(N=100, prop_n='prop2', pool2='p2', sp='sp', param1=range(100)) net.add_nodes(N=100, prop_n='prop3', pool3='p3', sp='sp', param1=range(100)) node_pool_1 = net.nodes(prop_n='prop1') assert(len(node_pool_1) == 100) assert(node_pool_1.filter_str == "prop_n=='prop1'") for n in node_pool_1: assert('pool1' in n and n['prop_n'] == 'prop1') node_pool_2 = net.nodes(sp='sp') assert(node_pool_2.filter_str == "sp=='sp'") assert(len(node_pool_2) == 300) for n in node_pool_2: assert(n['sp'] == 'sp') node_pool_3 = net.nodes(param1=10) assert(len(node_pool_3) == 3) assert(node_pool_3.filter_str == "param1=='10'") nodes = list(node_pool_3) assert(nodes[0]['node_id'] == 10) assert(nodes[1]['node_id'] == 110) assert(nodes[2]['node_id'] == 210) assert(nodes[0]['node_type_id'] != nodes[1]['node_type_id'] != nodes[2]['node_type_id'])
def test_basic(): net = NetworkBuilder('CA1') assert(net.name == 'CA1') assert(net.nnodes == 0) assert(net.nedges == 0) assert(net.nodes_built is False) assert(net.edges_built is False) assert(len(net.nodes()) == 0) assert(len(net.edges()) == 0) assert(net.nodes_built is True) assert(net.edges_built is True)
def test_node_set(): net = NetworkBuilder('NET1') net.add_nodes(N=100, prop1='prop1', param1=range(100)) node_pool = net.nodes() assert (node_pool.filter_str == '*') nodes = list(node_pool) assert (len(nodes) == 100) assert (nodes[0]['prop1'] == 'prop1') assert (nodes[0]['param1'] == 0) assert (nodes[99]['prop1'] == 'prop1') assert (nodes[99]['param1'] == 99) assert (nodes[0]['node_type_id'] == nodes[99]['node_type_id']) assert (nodes[0]['node_id'] != nodes[99]['node_id'])
def test_create_network(): net = NetworkBuilder('NET1') assert (net.name == 'NET1') assert (net.nnodes == 0) assert (net.nedges == 0) assert (net.nodes_built is False) assert (net.edges_built is False)
def test_add_node_ids_mixed(): net = NetworkBuilder('V1') net.add_nodes(N=3, node_id=[0, 2, 4], vals=[0, 2, 4]) net.add_nodes(N=3, vals=[1, 1, 1]) net.add_nodes(nodes_ids=[6], vals=[6]) unique_ids = set() for n in net.nodes(): unique_ids.add(n.node_id) if n.node_id % 2 == 0: assert(n['vals'] == n.node_id) else: assert(n['vals'] == 1) assert(len(unique_ids) == 7)
def build(self): """Builds the nodes and edges for the network. """ np.random.seed(self.seed) self._set_prefixed_directory("mechanisms") self._set_prefixed_directory("templates") self.net = NetworkBuilder("biophysical") self.net.add_nodes( N=1, pop_name='Pyrc', potental='exc', model_type='biophysical', dynamics_params=self.params["cell"]["dynamic_params"], model_template=self.params["cell"]["model_template"], model_processing=self.params["cell"]["model_processing"], morphology=self.params["cell"]["morphology"]) self._build_exc() self._build_inh() self._save_nets() self._make_rasters() #Final build step. build_env_bionet( base_dir='./', network_dir='./network', dt=self.params["dt"], tstop=self.params["time"]["stop"] * 1000.0, report_vars=self.params["record_cellvars"]["vars"], dL=self.params["dL"], #target length (um) of segments spikes_threshold=-10, file_current_clamp=self.file_current_clamp, spikes_inputs=[('exc_stim', 'exc_stim_spikes.h5'), ('prox_inh_stim', 'prox_inh_stim_spikes.h5'), ('dist_inh_stim', 'dist_inh_stim_spikes.h5')], components_dir='../biophys_components', compile_mechanisms=True) self._modify_jsons()
def test_multi_search(): net = NetworkBuilder('NET1') net.add_nodes(N=10, prop_n='prop1', sp='sp1', param1=range(0, 10)) net.add_nodes(N=10, prop_n='prop1', sp='sp2', param1=range(5, 15)) net.add_nodes(N=20, prop_n='prop2', sp='sp2', param1=range(20)) node_pool = net.nodes(prop_n='prop1', param1=5) assert (len(node_pool) == 2) nodes = list(node_pool) assert (nodes[0]['node_id'] == 5) assert (nodes[1]['node_id'] == 10)
def test_duplicate_node_ids(): # Check if the same node_id is being used twice net = NetworkBuilder('V1') net.add_nodes(N=1, node_id=[100]) with pytest.raises(ValueError): net.add_nodes(N=1, node_id=[100])
def test_failed_search(): net = NetworkBuilder('NET1') net.add_nodes(N=100, p1='p1', q1=range(100)) node_pool = net.nodes(p1='p2') assert (len(node_pool) == 0) node_pool = net.nodes(q2=10) assert (len(node_pool) == 0)
def test_add_node_ids(): # Special case if parameters node_id and node_type_id are explicitly defined by the user net = NetworkBuilder('V1') net.add_nodes(N=3, node_id=[100, 200, 300], node_type_id=101, name=['one', 'two', 'three']) net.build() node_one = list(net.nodes(name='one'))[0] assert(node_one['name'] == 'one') assert(node_one['node_id'] == 100) assert(node_one.node_id == 100) assert(node_one['node_type_id'] == 101) node_three = list(net.nodes(name='three'))[0] assert(node_three['name'] == 'three') assert(node_three['node_id'] == 300) assert (node_one.node_id == 100) assert(node_three['node_type_id'] == 101)
def build_source_network(target_net): input_network_model = { 'external': { 'N': 1, 'ei': 'e', 'pop_name': 'input_network', 'model_type': 'virtual' } } inputNetwork = NetworkBuilder("external") inputNetwork.add_nodes(**input_network_model['external']) inputNetwork.add_edges(target=target_net.nodes(pop_name='LIF_exc'), connection_rule=random_connections, connection_params={'p': 0.1}, syn_weight=400, delay=D, dynamics_params='ExcToExc.json', model_template='static_synapse') inputNetwork.add_edges(target=target_net.nodes(pop_name='LIF_inh'), connection_rule=random_connections, connection_params={'p': 0.1}, syn_weight=400, delay=D, dynamics_params='ExcToExc.json', model_template='static_synapse') inputNetwork.build() net.save(output_dir='network') #inputNetwork.save_nodes(nodes_file_name='one_input_node.h5', node_types_file_name='one_input_node_type.csv', # output_dir='lif_network') #inputNetwork.save_edges(edges_file_name='one_input_edges.h5', edge_types_file_name='one_input_edge_type.csv', # output_dir='lif_network') return inputNetwork
def _build_exc(self): """Builds the excitatory input cells and their synapses. """ np.random.seed(1000) # External excitatory inputs self.exc_stim = NetworkBuilder('exc_stim') #DataFrame of all segments on the cell. segs = pd.read_csv("Segments.csv") dends = segs[(segs["Type"] == "dend") & (segs["Distance"] >= 50)] apics = segs[(segs["Type"] == "apic")] apic_start, self.dend_groups = self._build_exc_nodes( dends, "dend", self.n_dend_exc) _, self.apic_groups = self._build_exc_nodes(apics, "apic", self.n_apic_exc, start=apic_start) self._build_exc_edges(self.dend_groups) self._build_exc_edges(self.apic_groups)
def test_build_nodes1(): net = NetworkBuilder('NET1') net.add_nodes(N=3, node_id=[100, 200, 300], node_type_id=101, name=['one', 'two', 'three']) node_one = list(net.nodes(name='one'))[0] assert(node_one['name'] == 'one') assert(node_one['node_id'] == 100) assert(node_one['node_type_id'] == 101) node_three = list(net.nodes(name='three'))[0] assert(node_three['name'] == 'three') assert(node_three['node_id'] == 300) assert(node_three['node_type_id'] == 101)
def test_add_nodes_tuples(): # Should be able to store tuples of values in single parameters for a given node net = NetworkBuilder('V1') net.add_nodes(N=10, arg_list=range(10), arg_tuples=[(r, r+1) for r in range(10)], arg_const=('a', 'b')) net.build() assert(net.nodes_built is True) assert(net.nnodes == 10) for node in net.nodes(): assert(len(node['arg_tuples']) == 2) assert(node['arg_tuples'][0] == node['arg_list'] and node['arg_tuples'][1] == node['arg_list']+1) assert(len(node['arg_const']) == 2) assert(node['arg_const'][0] == 'a' and node['arg_const'][1] == 'b')
from bmtk.builder import NetworkBuilder net = NetworkBuilder('brunel') net.add_nodes(pop_name='excitatory', ei='e', model_type='population', model_template='dipde:Internal', dynamics_params='exc_model.json') net.add_nodes(pop_name='inhibitory', ei='i', model_type='population', model_template='dipde:Internal', dynamics_params='inh_model.json') net.add_edges(source={'ei': 'e'}, target={'ei': 'i'}, syn_weight=0.005, nsyns=20, delay=0.002, dynamics_params='ExcToInh.json') net.add_edges(source={'ei': 'i'}, target={'ei': 'e'}, syn_weight=-0.002, nsyns=10, delay=0.002, dynamics_params='InhToExc.json') net.build() net.save_nodes(nodes_file_name='brunel_nodes.h5', node_types_file_name='brunel_node_types.csv', output_dir='network') net.save_edges(edges_file_name='brunel_edges.h5', edge_types_file_name='brunel_edge_types.csv', output_dir='network')
from bmtk.builder import NetworkBuilder from bmtk.utils.reports.spike_trains import PoissonSpikeGenerator from bmtk.utils.sim_setup import build_env_bionet import numpy as np import sys import synapses synapses.load() syn = synapses.syn_params_dicts() # Initialize our network net = NetworkBuilder("biophysical") num_inh = [1] num_exc = [1] ################################################################################## ###################################BIOPHY######################################### net.add_nodes(N=5, pop_name='PyrA', mem_potential='e', model_type='biophysical', model_template='hoc:feng_typeA', morphology=None) net.add_nodes(N=3, pop_name='PyrC', mem_potential='e',
# if __name__ == '__main__': # if __file__ != sys.argv[-1]: # inp = sys.argv[-1] # else: # raise Exception("no work" + str(sys.argv[-1])) N = 1#int(inp) np.random.seed(2129) #np.random.seed(42) # synapses.load() # syn = synapses.syn_params_dicts() net = NetworkBuilder("biophysical") net.add_nodes(N=N, pop_name='Pyrc', potental='exc', model_type='biophysical', model_template='hoc:L5PCtemplate', morphology = None) # exc_stim = NetworkBuilder('exc_stim') # exc_stim.add_nodes(N=1, # pop_name='exc_stim', # potential='exc', # model_type='virtual') # # Create connections between Exc --> Pyr cells
from bmtk.builder import NetworkBuilder import numpy as np import sys import synapses synapses.load() syn = synapses.syn_params_dicts() # Initialize our network net = NetworkBuilder("biophysical") #num_inh = [int(lognormal(43, 13)) for i in range(N)] num_inh = [1] #num_exc = [int(lognormal(25, 10)) for i in range(N)] num_exc = [1] ################################################################################## ###################################Pyr Type C##################################### net.add_nodes(N=1, pop_name='PyrC', mem_potential='e', model_type='biophysical', model_template='hoc:feng_typeC', morphology=None) ################################################################################## ###################################External Networks##############################
from bmtk.builder import NetworkBuilder import numpy as np from bmtk.builder.auxi.node_params import positions_cuboid, positions_list, xiter_random import synapses import pdb np.random.seed(123412) # Initialize our network net = NetworkBuilder("SPWR_biophysical") # Create the possible x,y,z coordinates xside_length = 1400; yside_length = 1400; height = 400; min_dist = 20; # was x = 700 height = 200 x_grid = np.arange(0, xside_length + min_dist, min_dist) y_grid = np.arange(0, yside_length + min_dist, min_dist) z_grid = np.arange(0, height + min_dist, min_dist) xx, yy, zz = np.meshgrid(x_grid, y_grid, z_grid) pos_list = np.vstack([xx.ravel(), yy.ravel(), zz.ravel()]).T # 10.5 minutes with add properties # 3.5 minutes without # 4 minutes my hacking # 7 minutes with just delay # 6 minutes just delay but no calculation # Number of cells in each population numPN_A = 2057 # 8229 numPN_C = 2057 # 8229 numBask = 927 # 3708 numAAC = 101 # 406
from bmtk.builder import NetworkBuilder import numpy as np from bmtk.builder.auxi.node_params import positions_cuboid, positions_list import math import random np.random.seed(91) # Initialize our network netff = NetworkBuilder("ff_model") # Create the possible x,y,z coordinates xside_length = 600 yside_length = 600 height = 600 min_dist = 25 ILxside_length = 800 ILyside_length = 800 IL_height13 = 1200 IL_height56 = 900 x_grid = np.arange(0, xside_length + min_dist, min_dist) y_grid = np.arange(0, yside_length + min_dist, min_dist) ILx_grid = np.arange(-200, ILxside_length + min_dist, min_dist) ILy_grid = np.arange(-200, ILyside_length + min_dist, min_dist) z_grid = np.arange(0, height + min_dist, min_dist) IL13_z_grid = np.arange(600 + 30 + 232 + 236 + 180, 600 + 30 + 232 + 236 + 180 + 101 + min_dist, min_dist) IL56_z_grid = np.arange(600 + 30 + 232, 600 + 30 + 232 + 264 + min_dist, min_dist) xxBL, yyBL, zzBL = np.meshgrid(x_grid, y_grid, z_grid) xxIL13, yyIL13, zzIL13 = np.meshgrid(x_grid, y_grid, IL13_z_grid)
def _build_inh(self): """Creates inhibitory input nodes and their connections onto the biophysical cell """ #####################Perisomatic Inhibition############################## self.prox_inh_stim = NetworkBuilder('prox_inh_stim') #Nodes that connect to soma. self.prox_inh_stim.add_nodes(N=self.n_soma_inh, pop_name='on_soma', potential='exc', model_type='virtual') #Nodes that connect to proximal dendrites. self.prox_inh_stim.add_nodes(N=self.n_prox_dend_inh, pop_name='on_dend', potential='exc', model_type='virtual') div_params = self.params["divergence"]["peri_inh"] #On soma. np.random.seed(self.seed + 5) self.net.add_edges( source=self.prox_inh_stim.nodes(pop_name='on_soma'), target=self.net.nodes(), connection_rule=SimulationBuilder._norm_connect, connection_params={ "m": div_params["m"], "s": div_params["s"], "low": div_params["min"], "high": div_params["max"] }, syn_weight=1, delay=0.1, dynamics_params='PV2PN.json', model_template=self.syn['PV2PN.json']['level_of_detail'], distance_range=[-2000, 2000.0], target_sections=['somatic']) #On dendrites within 50 um np.random.seed(self.seed + 6) self.net.add_edges( source=self.prox_inh_stim.nodes(pop_name='on_dend'), target=self.net.nodes(), connection_rule=SimulationBuilder._norm_connect, connection_params={ "m": div_params["m"], "s": div_params["s"], "low": div_params["min"], "high": div_params["max"] }, syn_weight=1, delay=0.1, dynamics_params='PV2PN.json', model_template=self.syn['PV2PN.json']['level_of_detail'], distance_range=[0, 50.0], target_sections=['dend']) ####################################################################################### #############################Dendritic Inhibition###################################### self.dist_inh_stim = NetworkBuilder('dist_inh_stim') self.dist_inh_stim.add_nodes(N=self.n_dend_inh, pop_name='dend', potential='exc', model_type='virtual') self.dist_inh_stim.add_nodes(N=self.n_apic_inh, pop_name='apic', potential='exc', model_type='virtual') div_params = self.params["divergence"]["basal_inh"] #Basal edges. np.random.seed(self.seed + 7) self.net.add_edges( source=self.dist_inh_stim.nodes(pop_name="dend"), target=self.net.nodes(), connection_rule=SimulationBuilder._norm_connect, connection_params={ "m": div_params["m"], "s": div_params["s"], "low": div_params["min"], "high": div_params["max"] }, syn_weight=1, delay=0.1, dynamics_params='SOM2PN.json', model_template=self.syn['SOM2PN.json']['level_of_detail'], distance_range=[50, 2000.0], target_sections=['dend']) div_params = self.params["divergence"]["apic_inh"] #Apic edges. np.random.seed(self.seed + 8) self.net.add_edges( source=self.dist_inh_stim.nodes(pop_name="apic"), target=self.net.nodes(), connection_rule=SimulationBuilder._norm_connect, connection_params={ "m": div_params["m"], "s": div_params["s"], "low": div_params["min"], "high": div_params["max"] }, syn_weight=1, delay=0.1, dynamics_params='SOM2PN.json', model_template=self.syn['SOM2PN.json']['level_of_detail'], distance_range=[50, 2000.0], target_sections=['apic'])
#find 0.2 mv synapses.load() syn = synapses.syn_params_dicts() if __name__ == '__main__': if __file__ != sys.argv[-1]: inp = sys.argv[-1] else: raise Exception("no work" + str(sys.argv[-1])) N = int(inp) # Initialize our network net = NetworkBuilder("biophysical") def lognormal(m, s): mean = np.log(m) - 0.5 * np.log((s / m)**2 + 1) std = np.sqrt(np.log((s / m)**2 + 1)) return max(np.random.lognormal(mean, std, 1), 0) num_inh = [int(lognormal(43, 13)) for i in range(N)] print(num_inh) inh_bounds = [] sum = 0 for num in num_inh: sum += num inh_bounds.append(sum)
if __file__ != sys.argv[-1]: inp = sys.argv[-1] else: raise Exception("no work" + str(sys.argv[-1])) N = int(inp) # exc_fr = float(frs[0]) # inh_fr = float(frs[1]) # print(exc_fr, inh_fr) #N = 10 # Initialize our network net = NetworkBuilder("biophysical") def lognormal(m, s): mean = np.log(m) - 0.5 * np.log((s/m)**2+1) std = np.sqrt(np.log((s/m)**2 + 1)) return max(np.random.lognormal(mean, std, 1), 0) # Dend Excitatory: 8998.0 # Apic Excitatory: 12380.0 # Soma Inhibitory: 2285.0 # num_inh = [231, 405, 61]#[int(lognormal(56, 7.5)) for i in range(N)] # print(num_inh) # inh_bounds = [] # sum = 0 # for num in num_inh:
'model_template': 'nml:nml/Cell_472363762.cell.nml' if use_nml else 'ctdb:Biophys1.hoc', 'dynamics_params': 'NONE' if use_nml else 'json/472363762_fit.json' }, { 'model_name': 'Rorb', 'ei': 'e', 'morphology': 'Rorb_325404214_m', 'model_template': 'nml:nml/Cell_473863510.cell.nml' if use_nml else 'ctdb:Biophys1.hoc', 'dynamics_params': 'NONE' if use_nml else 'json/473863510_fit.json' }, { 'model_name': 'Nr5a1', 'ei': 'e', 'morphology': 'Nr5a1_471087815_m', 'model_template': 'nml:nml/Cell_473863035.cell.nml' if use_nml else 'ctdb:Biophys1.hoc', 'dynamics_params': 'NONE' if use_nml else 'json/473863035_fit.json' } ] cortex = NetworkBuilder("cortex") for i, model_props in enumerate(cell_models): cortex.add_nodes(N=3, x=[i*30.0 + j for j in range(3)], y=[0.0]*3, z=[0.0]*3, # space cells every 10nm along x axs model_type='biophysical', model_processing='aibs_perisomatic', **model_props) cortex.build() cortex.save_nodes(output_dir='network') morphologies = {p['model_name']: SWCReader(os.path.join('../shared_components/morphologies', p['morphology'])) for p in cell_models} def build_edges(src, trg, sections=['basal', 'apical'], dist_range=[50.0, 150.0]):
class SimulationBuilder: """Class used to build our BMTK simulation. Attributes ---------- params : dict contains parameters for the network seed : int base random seed for the simulation syn : dict contains synaptic templates n_dend_exc : int number of excitatory input cells on the basal dendrites n_apic_exc : int number of excitatory input cells on the apical dendrites n_dend_inh : int number of inhibitory (SOM+) input cells on the basal dendrites more than 50 um from the soma. n_apic_inh : int number of inhibitory (SOM+) input cells on the apical dendrites n_prox_dend_inh : int number of inhibitory (PV+) input cells on the basal dendrites less than 50 um from the soma n_soma_inh : int number of inhibitory (PV+) input cells on the soma clust_per_group : int number of clusters per functional group net : NetworkBuilder the BMTK network for the biophysical cell exc_stim : NetworkBuilder the BMTK network for excitatory inputs prox_inh_stim : NetworkBuilder the BMTK network for perisomatic inhibition dist_inh_stim : NetworkBuilder the BMTK network for dendritic inhibition dend_groups : list all excitatory functional groups on the basal dendrites apic_groups : list all excitatory functional groups on the apical dendrites Methods ------- build() builds the network save_groups() saves the functional groups to a csv _set_prefixed_directory(base_dir_name : str) sets up the correct biophy_components structure based on the cell prefix in params for the given directory base _build_exc() creates excitatory input nodes and edges _build_exc_nodes(segs : pandas.DataFrame, base_name : str, n_cells : int, start=0 : int) builds excitatory nodes _build_exc_edges(group_list : list) builds excitatory edges _save_nets() builds and saves the BMTK NetworkBuilders _build_inh() creates inhibitory input nodes and edges _make_rasters() creates the inhibitory and excitatory input rasters _gen_exc_spikes(fname : str) generates and saves the excitatory spike rasters _gen_inh_spikes(n_cells : int, mean_fr : float, std_fr : float, key : str, fname : str) creates inhibitory spike rasters, using a noise trace based on averaging excitation and shifting it _modify_jsons() modifies the various json files however is needed after they are built _modify_sim_config() modifies the simulation_config.json however is needed _update_cellvar_record_locs(sim_config : dict) modifies the location of cellvar recordings in the given JSON simulation_config Static Methods -------------- _get_directory_prefix(directory : str) reads the prefix.txt fil in directory and returns the contents _connector_func(sources : list, targets : list, cells : list) sets the number of synapses from the given cells _set_location(source : dict, target : dict, cells : list, start_id : int) sets the location of the given edge _norm_connect(source : dict, target : dict, m : float, s : float, low : int, high : int) used to normally distribute connection counts _gen_group_spikes(writer : SonataWriter, group : FunctionalGroup, seconds : float, start_time : float, dist : func) creates and saves a functional group's spike raster _norm_rvs(mean : float, std : float) generates a random float from a normal distribution with a near zero minimum """ def __init__(self, params_file, seed=123): """Initializes the simulation builder, setting up attributes but not actually building the BMTK network. Parameters ---------- params_file : str path to the JSON file with network parameters seed : int base random seed for the simulation """ #Loads the JSON file with information about the network. with open(params_file) as f: self.params = json.load(f) self.seed = seed #Loads synapse templates. synapses.load() self.syn = synapses.syn_params_dicts() avg_exc_div = np.mean(list(self.params["divergence"]["exc"].values())) self.n_dend_exc = int( (self.params["lengths"]["basal_dist"] * self.params["syn_density"]["exc"]) / avg_exc_div) self.n_apic_exc = int( (self.params["lengths"]["apic"] * self.params["syn_density"]["exc"]) / avg_exc_div) self.n_dend_inh = int((self.params["lengths"]["basal_dist"] * self.params["syn_density"]["inh"]) / self.params["divergence"]["basal_inh"]["m"]) self.n_apic_inh = int((self.params["lengths"]["apic"] * self.params["syn_density"]["inh"]) / self.params["divergence"]["apic_inh"]["m"]) self.n_prox_dend_inh = int((self.params["lengths"]["basal_prox"] * self.params["syn_density"]["inh"]) / self.params["divergence"]["peri_inh"]["m"]) self.n_soma_inh = int(self.params["n_soma_syns"] / self.params["divergence"]["peri_inh"]["m"]) self.clust_per_group = int( (self.params["groups"]["cells_per_group"] * avg_exc_div) // (self.params["syn_density"]["exc"] * 10)) if self.params["file_current_clamp"]["input_file"] == "None": self.file_current_clamp = None else: self.file_current_clamp = self.params["file_current_clamp"] def build(self): """Builds the nodes and edges for the network. """ np.random.seed(self.seed) self._set_prefixed_directory("mechanisms") self._set_prefixed_directory("templates") self.net = NetworkBuilder("biophysical") self.net.add_nodes( N=1, pop_name='Pyrc', potental='exc', model_type='biophysical', dynamics_params=self.params["cell"]["dynamic_params"], model_template=self.params["cell"]["model_template"], model_processing=self.params["cell"]["model_processing"], morphology=self.params["cell"]["morphology"]) self._build_exc() self._build_inh() self._save_nets() self._make_rasters() #Final build step. build_env_bionet( base_dir='./', network_dir='./network', dt=self.params["dt"], tstop=self.params["time"]["stop"] * 1000.0, report_vars=self.params["record_cellvars"]["vars"], dL=self.params["dL"], #target length (um) of segments spikes_threshold=-10, file_current_clamp=self.file_current_clamp, spikes_inputs=[('exc_stim', 'exc_stim_spikes.h5'), ('prox_inh_stim', 'prox_inh_stim_spikes.h5'), ('dist_inh_stim', 'dist_inh_stim_spikes.h5')], components_dir='../biophys_components', compile_mechanisms=True) self._modify_jsons() def save_groups(self): """saves the apic and dend groups into a csv. one row for each node containgin the id of the functional group it is in. """ all_groups = self.dend_groups + self.apic_groups node_ids = [] func_groups = [] for func_id, group in enumerate(all_groups): for i in range(group.start_id, group.start_id + group.n_cells): node_ids.append(i) func_groups.append(func_id) df = pd.DataFrame() df["Node ID"] = node_ids df["Functional Group"] = func_groups df.to_csv("FunctionalGroups.csv", index=False) def _set_prefixed_directory(self, base_dir_name): """Fixes the biophy_components directory. There should be only one directory named <base_dir_name> and it should be the one with the prefix.txt file in it that has the same prefix as params. Parameters ---------- base_dir_name : str base name of the set of directories to be fixed """ #import pdb; pdb.set_trace() components_path = "../biophys_components/" biophys_subdirs = [ f.name for f in os.scandir(components_path) if f.is_dir() ] for dir_name in biophys_subdirs: if base_dir_name == dir_name: prefix = SimulationBuilder._get_directory_prefix( components_path + dir_name) if prefix == self.params["cell"]["prefix"]: return else: os.rename(components_path + base_dir_name, components_path + prefix + base_dir_name) for dir_name in biophys_subdirs: if base_dir_name in dir_name and self.params["cell"][ "prefix"] in dir_name: os.rename(components_path + dir_name, components_path + base_dir_name) def _get_directory_prefix(directory): """Returns the contents of the prefix.txt file in the given directory. Parameters ---------- directory : str directory to look in Returns ------- str contents of prefix.txt """ with open(directory + "/prefix.txt", 'r') as f: return f.read() def _build_exc(self): """Builds the excitatory input cells and their synapses. """ # External excitatory inputs self.exc_stim = NetworkBuilder('exc_stim') #DataFrame of all segments on the cell. segs = pd.read_csv(self.params["cell"]["segments_file"]) dends = segs[(segs["Type"] == "dend") & (segs["Distance"] >= 50)] apics = segs[(segs["Type"] == "apic")] np.random.seed(self.seed + 1) apic_start, self.dend_groups = self._build_exc_nodes( dends, "dend", self.n_dend_exc) np.random.seed(self.seed + 2) _, self.apic_groups = self._build_exc_nodes(apics, "apic", self.n_apic_exc, start=apic_start) np.random.seed(self.seed + 3) self._build_exc_edges(self.dend_groups) np.random.seed(self.seed + 4) self._build_exc_edges(self.apic_groups) #Sets the number of synapses for each input cell. def _connector_func(sources, target, cells): """Used to set the number of synapses from each excitatory input cell in a functional group. Use with "all_to_one" iterator. Parameters ---------- sources : list presynaptic nodes (represented as dicts) target : dict postsynaptic node cells : list list of Cells in the FunctionalGroup Returns ------- list list of synapses for each pairing """ return [cell.n_syns for cell in cells] #Sets the location of synapses based on the given cell list. def _set_location(source, target, cells, start_id): """Sets the location of the given synapse. Parameters ---------- source : dict source node information target : dict target node information cells : list Cells in the functional group start_id : int start_id for the functional groups the cells come from Returns ------- int BMTK section id float distance along the section """ #Gets the proper index within the cell list. index = source.node_id - start_id seg = cells[index].get_seg() return seg.bmtk_id, seg.x #Creates the functional groups and adds the virtual cells to the #BMTK NetworkBuilder. def _build_exc_nodes(self, segs, base_name, n_cells, start=0): """Creates the functional groups and adds the virtual cells to the BMTK NetworkBuilder Parameters ---------- segs : pandas.DataFrame all the segments available for the functional groups base_name : str the string that is appended to to make the group names. groups get 0 - n_groups appended to their names. n_cells : int total number of input cells that should be added. start : int, optional starting id to be associated with the functional groups, by default 0 this is used later to associate cells in functional groups with the correct locations and synapses. Returns ------- int what the start parameter should be for the next call to _build_exc_nodes list list of functional groups that were created """ start_id = start n_groups = n_cells // self.params["groups"]["cells_per_group"] n_extra = n_cells % self.params["groups"][ "cells_per_group"] #number of extra cells that don't evenly fit into groups group_list = [] for i in range(n_groups): name = base_name + str(i) #Spreads out the extra cells. N = self.params["groups"]["cells_per_group"] if i < n_extra: N += 1 self.exc_stim.add_nodes(N=N, pop_name=name, potential="exc", model_type='virtual') new_group = FunctionalGroup( segs, segs.sample().iloc[0], N, self.clust_per_group, name, start_id, partial(make_seg_sphere, radius=self.params["groups"]["group_radius"]), partial(make_seg_sphere, radius=self.params["groups"]["cluster_radius"])) group_list.append(new_group) start_id += N return start_id, group_list def _build_exc_edges(self, group_list): """Creates the connections between each cell in the list of groups and the biophysical cell. Parameters ---------- group_list : list list of functional groups """ for i in range(len(group_list)): group = group_list[i] #Creates the edges from each excitatory input cells in the group. conn = self.net.add_edges( source=self.exc_stim.nodes(pop_name=group.name), target=self.net.nodes(), iterator="all_to_one", connection_rule=SimulationBuilder._connector_func, connection_params={'cells': group.cells}, syn_weight=1, delay=0.1, dynamics_params='PN2PN.json', model_template=self.syn['PN2PN.json']['level_of_detail'], ) #Sets the postsynaptic locations of the connections. conn.add_properties(['sec_id', "sec_x"], rule=SimulationBuilder._set_location, rule_params={ 'cells': group.cells, 'start_id': group.start_id }, dtypes=[np.int, np.float]) def _save_nets(self): """builds and saves the BMTK NetworkBuilders """ # Build and save our networks np.random.seed(self.seed + 12) self.net.build() self.net.save_nodes(output_dir='network') np.random.seed(self.seed + 16) self.net.save_edges(output_dir='network') np.random.seed(self.seed + 13) self.exc_stim.build() self.exc_stim.save_nodes(output_dir='network') np.random.seed(self.seed + 14) self.prox_inh_stim.build() self.prox_inh_stim.save_nodes(output_dir='network') np.random.seed(self.seed + 15) self.dist_inh_stim.build() self.dist_inh_stim.save_nodes(output_dir='network') def _build_inh(self): """Creates inhibitory input nodes and their connections onto the biophysical cell """ #####################Perisomatic Inhibition############################## self.prox_inh_stim = NetworkBuilder('prox_inh_stim') #Nodes that connect to soma. self.prox_inh_stim.add_nodes(N=self.n_soma_inh, pop_name='on_soma', potential='exc', model_type='virtual') #Nodes that connect to proximal dendrites. self.prox_inh_stim.add_nodes(N=self.n_prox_dend_inh, pop_name='on_dend', potential='exc', model_type='virtual') div_params = self.params["divergence"]["peri_inh"] #On soma. np.random.seed(self.seed + 5) self.net.add_edges( source=self.prox_inh_stim.nodes(pop_name='on_soma'), target=self.net.nodes(), connection_rule=SimulationBuilder._norm_connect, connection_params={ "m": div_params["m"], "s": div_params["s"], "low": div_params["min"], "high": div_params["max"] }, syn_weight=1, delay=0.1, dynamics_params='PV2PN.json', model_template=self.syn['PV2PN.json']['level_of_detail'], distance_range=[-2000, 2000.0], target_sections=['somatic']) #On dendrites within 50 um np.random.seed(self.seed + 6) self.net.add_edges( source=self.prox_inh_stim.nodes(pop_name='on_dend'), target=self.net.nodes(), connection_rule=SimulationBuilder._norm_connect, connection_params={ "m": div_params["m"], "s": div_params["s"], "low": div_params["min"], "high": div_params["max"] }, syn_weight=1, delay=0.1, dynamics_params='PV2PN.json', model_template=self.syn['PV2PN.json']['level_of_detail'], distance_range=[0, 50.0], target_sections=['dend']) ####################################################################################### #############################Dendritic Inhibition###################################### self.dist_inh_stim = NetworkBuilder('dist_inh_stim') self.dist_inh_stim.add_nodes(N=self.n_dend_inh, pop_name='dend', potential='exc', model_type='virtual') self.dist_inh_stim.add_nodes(N=self.n_apic_inh, pop_name='apic', potential='exc', model_type='virtual') div_params = self.params["divergence"]["basal_inh"] #Basal edges. np.random.seed(self.seed + 7) self.net.add_edges( source=self.dist_inh_stim.nodes(pop_name="dend"), target=self.net.nodes(), connection_rule=SimulationBuilder._norm_connect, connection_params={ "m": div_params["m"], "s": div_params["s"], "low": div_params["min"], "high": div_params["max"] }, syn_weight=1, delay=0.1, dynamics_params='SOM2PN.json', model_template=self.syn['SOM2PN.json']['level_of_detail'], distance_range=[50, 2000.0], target_sections=['dend']) div_params = self.params["divergence"]["apic_inh"] #Apic edges. np.random.seed(self.seed + 8) self.net.add_edges( source=self.dist_inh_stim.nodes(pop_name="apic"), target=self.net.nodes(), connection_rule=SimulationBuilder._norm_connect, connection_params={ "m": div_params["m"], "s": div_params["s"], "low": div_params["min"], "high": div_params["max"] }, syn_weight=1, delay=0.1, dynamics_params='SOM2PN.json', model_template=self.syn['SOM2PN.json']['level_of_detail'], distance_range=[50, 2000.0], target_sections=['apic']) def _norm_connect(source, target, m, s, low, high): """Returns a random number of synapses based on the given distribution. Parameters ---------- source : dict source node target : dict target node m : float mean number of connections s : float standard deviation of number of connections low : int minimum number of connections high : int maximum number of connections Returns ------- int number of connections """ return int(min(max(np.random.normal(m, s), low), high)) def _make_rasters(self): """Generates excitatory and inhibitory input rasters """ np.random.seed(self.seed + 9) self._gen_exc_spikes('exc_stim_spikes.h5') inh_frs = self.params["inh_frs"] #Makes perisomatic inhibitory raster. np.random.seed(self.seed + 10) self._gen_inh_spikes(self.n_soma_inh + self.n_prox_dend_inh, inh_frs["proximal"]["m"], inh_frs["proximal"]["s"], inh_frs["proximal"]["rhythmicity"], "prox_inh_stim", 'prox_inh_stim_spikes.h5') #Makes dendritic inhibitory raster. np.random.seed(self.seed + 11) self._gen_inh_spikes(self.n_apic_inh + self.n_dend_inh, inh_frs["distal"]["m"], inh_frs["distal"]["s"], inh_frs["distal"]["rhythmicity"], "dist_inh_stim", 'dist_inh_stim_spikes.h5') #Generates the spike raster for a given group. #The group has the same noise. def _gen_group_spikes(writer, group, seconds, start_time, dist): """Generates and writes to a h5 file the given functional group's spike trains Parameters ---------- writer : SonataWriter how the spike trains are saved group : FunctionalGroup the functional group that the spike trains are being made for seconds : float length of the spike trains in seconds start_time : float what time (ms) the spike trains should start at dist : func function for random distribution used for an individual cell's firing rate """ z = make_noise( num_samples=(int(seconds * 1000)) - 1, num_traces=1 ) #generates the noise trace common to each cell in the functional group. make_save_spikes(writer, True, dist(size=group.n_cells), numUnits=group.n_cells, rateProf=np.tile(z[0, :], (group.n_cells, 1)), start_id=group.start_id, start_time=start_time) #Creates the excitatory input raster from the functional groups. def _gen_exc_spikes(self, fname): """Generates the excitatory input raster for all of the functional groups Parameters ---------- fname : str name of the file to save the rasters in (.h5) """ #distribution used for generating excitatory firing rates. levy_dist = partial(st.levy_stable.rvs, alpha=1.37, beta=-1.00, loc=0.92, scale=0.44, size=1) length = self.params["time"]["stop"] - self.params["time"]["start"] buffer = self.params["time"]["start"] writer = SonataWriter(fname, ["spikes", "exc_stim"], ["timestamps", "node_ids"], [np.float, np.int]) for group in (self.dend_groups + self.apic_groups): SimulationBuilder._gen_group_spikes(writer, group, length, buffer * 1000, levy_dist) #Blocks off the bottom of a normal distribution. def _norm_rvs(mean, std): """Generates a random float from a normal distribution with a near zero minimum Parameters ---------- mean : float mean of the distribution std : float standard deviation of the distribution Returns ------- float random float """ return max(st.norm.rvs(loc=mean, scale=std, size=1), 0.001) # #Makes a spike raster with each cell having its own noise trace. # def gen_inh_spikes(n_cells, mean_fr, std_fr, key, file, times): # # node_ids = [] # # timestamps = [] # length = times[1] - times[0] # buffer = times[0] # writer = SonataWriter(file, ["spikes", key], ["timestamps", "node_ids"], [np.float, np.int]) # z = make_noise(num_samples=(int(length*1000))-1,num_traces=1) # make_save_spikes(writer, False, partial(positive_normal, mean=mean_fr, std=std_fr), numUnits=n_cells,rateProf=z[0,:],start_time=buffer*1000) #Creates a spike raster with each cell having the same noise coming from the a shifted average of excitation. def _gen_inh_spikes(self, n_cells, mean_fr, std_fr, rhythmic_dict, key, fname): """Generates a spike raster with each train having the noise trace from averaging excitation. Distributes firing rates normally. Parameters ---------- n_cells : int number of spike trains mean_fr : float mean firing rate std_fr : float standard deviation of the firing rate rhythmic_dict : dict dictionary with keys f - frequency, mod - depth of modulation key : str name of the second group in the h5 file fname : str name of file to save the raster to """ # node_ids = [] # timestamps = [] a, b = (0 - mean_fr) / std_fr, (100 - mean_fr) / std_fr d = partial(st.truncnorm.rvs, a=a, b=b, loc=mean_fr, scale=std_fr) if rhythmic_dict['f'] == "None": f = h5py.File("exc_stim_spikes.h5", "r") ts = f['spikes']["exc_stim"]['timestamps'] nid = f['spikes']["exc_stim"]['node_ids'] #Creates a noise trace based on the excitatory spike raster. z = shift_exc_noise(ts, nid, self.params["time"]["stop"], time_shift=self.params["inh_shift"]) z = np.tile(z, (n_cells, 1)) writer = SonataWriter(fname, ["spikes", key], ["timestamps", "node_ids"], [np.float, np.int]) make_save_spikes(writer, False, d(size=n_cells), numUnits=n_cells, rateProf=z) else: # make an array of modulated sin waves # make_save_spikes should be written so that the firing rates are generated # outside instead of inside the function. frs = d(size=n_cells) t = np.arange(0, self.params["time"]["stop"], 0.001) z = np.zeros((n_cells, t.shape[0])) P = 0 for i in np.arange(0, n_cells): offset = frs[i] A = offset / ((1 / rhythmic_dict['mod']) - 1) z[i, :] = A * np.sin( (2 * np.pi * rhythmic_dict['f'] * t) + P) + offset writer = SonataWriter(fname, ["spikes", key], ["timestamps", "node_ids"], [np.float, np.int]) make_save_spikes(writer, False, np.ones((n_cells, 1)), numUnits=n_cells, rateProf=z) def _modify_jsons(self): """modifies the various json files however is needed after they are built""" self._modify_sim_config() def _modify_sim_config(self): """modifies the simulation_config.json however is needed""" with open("simulation_config.json", "r") as jsonFile: sim_config = json.load(jsonFile) self._update_cellvar_record_locs(sim_config) with open("simulation_config.json", "w") as jsonFile: json.dump(sim_config, jsonFile, indent=2) def _update_cellvar_record_locs(self, sim_config): """modifies the location of cellvar recordings in the given JSON simulation_config Parameters ---------- sim_config : dict simulation_config to modify """ reports = sim_config["reports"] cellvar_reports = [ report for report in reports.values() if report["module"] == "membrane_report" ] for loc, report in zip(self.params["record_cellvars"]["locs"], cellvar_reports): report["sections"] = loc