bmtool 0.4.2__py3-none-any.whl → 0.5.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- bmtool/bmplot.py +274 -100
- bmtool/connectors.py +45 -51
- bmtool/util/util.py +65 -8
- bmtool-0.5.1.dist-info/METADATA +519 -0
- {bmtool-0.4.2.dist-info → bmtool-0.5.1.dist-info}/RECORD +9 -9
- bmtool-0.4.2.dist-info/METADATA +0 -550
- {bmtool-0.4.2.dist-info → bmtool-0.5.1.dist-info}/LICENSE +0 -0
- {bmtool-0.4.2.dist-info → bmtool-0.5.1.dist-info}/WHEEL +0 -0
- {bmtool-0.4.2.dist-info → bmtool-0.5.1.dist-info}/entry_points.txt +0 -0
- {bmtool-0.4.2.dist-info → bmtool-0.5.1.dist-info}/top_level.txt +0 -0
bmtool/connectors.py
CHANGED
@@ -288,9 +288,22 @@ def pr_2_rho(p0, p1, pr):
|
|
288
288
|
return (pr - p0 * p1) / (p0 * (1 - p0) * p1 * (1 - p1)) ** .5
|
289
289
|
|
290
290
|
|
291
|
+
def rho_2_pr(p0, p1, rho):
|
292
|
+
"""Calculate reciprocal probability pr given correlation coefficient rho"""
|
293
|
+
for p in (p0, p1):
|
294
|
+
assert(p > 0 and p < 1)
|
295
|
+
pr = p0 * p1 + rho * (p0 * (1 - p0) * p1 * (1 - p1)) ** .5
|
296
|
+
if not (pr >= 0 and pr <= p0 and pr <= p1 and pr >= p0 + p1 - 1):
|
297
|
+
pr0, pr = pr, np.max((0., p0 + p1 - 1, np.min((p0, p1, pr))))
|
298
|
+
rho0, rho = rho, (pr - p0 * p1) / (p0 * (1 - p0) * p1 * (1 - p1)) ** .5
|
299
|
+
print('rho changed from %.3f to %.3f; pr changed from %.3f to %.3f'
|
300
|
+
% (rho0, rho, pr0, pr))
|
301
|
+
return pr
|
302
|
+
|
303
|
+
|
291
304
|
class ReciprocalConnector(AbstractConnector):
|
292
305
|
"""
|
293
|
-
Object for
|
306
|
+
Object for building connections in bmtk network model with reciprocal
|
294
307
|
probability within a single population (or between two populations).
|
295
308
|
|
296
309
|
Algorithm:
|
@@ -479,7 +492,7 @@ class ReciprocalConnector(AbstractConnector):
|
|
479
492
|
"""Must run this before building connections"""
|
480
493
|
if self.stage:
|
481
494
|
# check whether the correct populations
|
482
|
-
if (source is None or target is None or
|
495
|
+
if (source is None or target is None or
|
483
496
|
not self.is_same_pop(source, self.target) or
|
484
497
|
not self.is_same_pop(target, self.source)):
|
485
498
|
raise ValueError("Source or target population not consistent.")
|
@@ -701,13 +714,13 @@ class ReciprocalConnector(AbstractConnector):
|
|
701
714
|
self.callable_set = callable_set
|
702
715
|
|
703
716
|
# Make callable variables except a few, accept index input instead
|
704
|
-
for name in callable_set -
|
717
|
+
for name in callable_set - {'p0', 'p1', 'pr'}:
|
705
718
|
var = self.vars[name]
|
706
719
|
setattr(self, name, self.node_2_idx_input(var, '1' in name))
|
707
720
|
|
708
721
|
def cache_variables(self):
|
709
722
|
# Select cacheable attrilbutes
|
710
|
-
cache_set =
|
723
|
+
cache_set = {'p0', 'p0_arg', 'p1', 'p1_arg'}
|
711
724
|
if self.symmetric_p1:
|
712
725
|
cache_set.remove('p1')
|
713
726
|
if self.symmetric_p1_arg:
|
@@ -823,8 +836,9 @@ class ReciprocalConnector(AbstractConnector):
|
|
823
836
|
if backward:
|
824
837
|
n_backward = self.n_syn1(j, i)
|
825
838
|
if self.recurrent:
|
826
|
-
|
827
|
-
|
839
|
+
if i != j:
|
840
|
+
self.conn_mat[0, j, i] = n_backward
|
841
|
+
self.add_conn_prop(j, i, p1_arg, 0)
|
828
842
|
else:
|
829
843
|
self.conn_mat[1, i, j] = n_backward
|
830
844
|
self.add_conn_prop(i, j, p1_arg, 1)
|
@@ -901,9 +915,11 @@ class ReciprocalConnector(AbstractConnector):
|
|
901
915
|
n_poss = np.array(self.possible_count)
|
902
916
|
n_pair = conn_mat.size / 2
|
903
917
|
if self.recurrent:
|
904
|
-
n_recp =
|
905
|
-
|
906
|
-
|
918
|
+
n_recp = np.count_nonzero(conn_mat[0] & conn_mat[0].T)
|
919
|
+
if self.autapses:
|
920
|
+
n_recp -= np.count_nonzero(np.diag(conn_mat[0]))
|
921
|
+
n_recp //= 2
|
922
|
+
n_conn -= n_recp
|
907
923
|
n_poss = n_poss[None]
|
908
924
|
n_pair += (1 if self.autapses else -1) * self.n_source / 2
|
909
925
|
else:
|
@@ -933,7 +949,7 @@ class ReciprocalConnector(AbstractConnector):
|
|
933
949
|
|
934
950
|
class UnidirectionConnector(AbstractConnector):
|
935
951
|
"""
|
936
|
-
Object for
|
952
|
+
Object for building unidirectional connections in bmtk network model with
|
937
953
|
given probability within a single population (or between two populations).
|
938
954
|
|
939
955
|
Parameters:
|
@@ -1067,7 +1083,7 @@ class UnidirectionConnector(AbstractConnector):
|
|
1067
1083
|
|
1068
1084
|
class CorrelatedGapJunction(UnidirectionConnector):
|
1069
1085
|
"""
|
1070
|
-
Object for
|
1086
|
+
Object for building gap junction connections in bmtk network model with
|
1071
1087
|
given probabilities within a single population which could be correlated
|
1072
1088
|
with the recurrent chemical synapses in this population.
|
1073
1089
|
|
@@ -1091,6 +1107,7 @@ class CorrelatedGapJunction(UnidirectionConnector):
|
|
1091
1107
|
Important attributes:
|
1092
1108
|
Similar to `UnidirectionConnector`.
|
1093
1109
|
"""
|
1110
|
+
|
1094
1111
|
def __init__(self, p_non=1., p_uni=1., p_rec=1., p_arg=None,
|
1095
1112
|
connector=None, verbose=True):
|
1096
1113
|
super().__init__(p=p_non, p_arg=p_arg, verbose=verbose)
|
@@ -1105,9 +1122,10 @@ class CorrelatedGapJunction(UnidirectionConnector):
|
|
1105
1122
|
|
1106
1123
|
def setup_nodes(self, source=None, target=None):
|
1107
1124
|
super().setup_nodes(source=source, target=target)
|
1108
|
-
if len(self.source) != len(self.
|
1125
|
+
if len(self.source) != len(self.target):
|
1109
1126
|
raise ValueError("Source and target must be the same for "
|
1110
1127
|
"gap junction.")
|
1128
|
+
self.n_source = len(self.source)
|
1111
1129
|
|
1112
1130
|
def conn_exist(self, sid, tid):
|
1113
1131
|
trg_dict = self.ref_conn_prop.get(sid)
|
@@ -1122,11 +1140,11 @@ class CorrelatedGapJunction(UnidirectionConnector):
|
|
1122
1140
|
return conn0 + conn1, prop0 if conn0 else prop1
|
1123
1141
|
|
1124
1142
|
def initialize(self):
|
1125
|
-
super().initialize()
|
1126
1143
|
self.has_p_arg = self.vars['p_arg'] is not None
|
1127
1144
|
if not self.has_p_arg:
|
1128
1145
|
var = self.connector.vars
|
1129
|
-
self.
|
1146
|
+
self.vars['p_arg'] = var.get('p_arg', var.get('p0_arg', None))
|
1147
|
+
super().initialize()
|
1130
1148
|
self.ps = [self.p_non, self.p_uni, self.p_rec]
|
1131
1149
|
|
1132
1150
|
def make_connection(self, source, target, *args, **kwargs):
|
@@ -1140,7 +1158,7 @@ class CorrelatedGapJunction(UnidirectionConnector):
|
|
1140
1158
|
|
1141
1159
|
# Consider each pair only once
|
1142
1160
|
nsyns = 0
|
1143
|
-
i, j = divmod(self.iter_count, self.
|
1161
|
+
i, j = divmod(self.iter_count, self.n_source)
|
1144
1162
|
if i < j:
|
1145
1163
|
sid, tid = source.node_id, target.node_id
|
1146
1164
|
conn_type, p_arg = self.connection_type(sid, tid)
|
@@ -1172,7 +1190,7 @@ class CorrelatedGapJunction(UnidirectionConnector):
|
|
1172
1190
|
|
1173
1191
|
|
1174
1192
|
class OneToOneSequentialConnector(AbstractConnector):
|
1175
|
-
"""Object for
|
1193
|
+
"""Object for building one to one correspondence connections in bmtk
|
1176
1194
|
network model with between two populations. One of the population can
|
1177
1195
|
consist of multiple sub-populations. These sub-populations need to be added
|
1178
1196
|
sequentially using setup_nodes() and edge_params() methods followed by BMTK
|
@@ -1208,7 +1226,7 @@ class OneToOneSequentialConnector(AbstractConnector):
|
|
1208
1226
|
source: NodePool object for the single population.
|
1209
1227
|
targets: List of NodePool objects for the multiple sub-populations.
|
1210
1228
|
"""
|
1211
|
-
|
1229
|
+
|
1212
1230
|
def __init__(self, n_syn=1, partition_source=False, verbose=True):
|
1213
1231
|
self.n_syn = int(n_syn)
|
1214
1232
|
self.partition_source = partition_source
|
@@ -1315,10 +1333,13 @@ class OneToOneSequentialConnector(AbstractConnector):
|
|
1315
1333
|
|
1316
1334
|
SYN_MIN_DELAY = 0.8 # ms
|
1317
1335
|
SYN_VELOCITY = 1000. # um/ms
|
1336
|
+
FLUC_STDEV = 0.2 # ms
|
1337
|
+
DELAY_LOWBOUND = 0.2 # ms must be greater than h.dt
|
1338
|
+
DELAY_UPBOUND = 2.0 # ms
|
1318
1339
|
|
1319
1340
|
def syn_dist_delay_feng(source, target,
|
1320
1341
|
min_delay=SYN_MIN_DELAY, velocity=SYN_VELOCITY,
|
1321
|
-
fluc_stdev=
|
1342
|
+
fluc_stdev=FLUC_STDEV, connector=None):
|
1322
1343
|
"""Synpase delay linearly dependent on distance.
|
1323
1344
|
min_delay: minimum delay (ms)
|
1324
1345
|
velocity: synapse conduction velocity (micron/ms)
|
@@ -1329,7 +1350,8 @@ def syn_dist_delay_feng(source, target,
|
|
1329
1350
|
else:
|
1330
1351
|
dist = connector.get_conn_prop(source.node_id, target.node_id)
|
1331
1352
|
del_fluc = fluc_stdev * rng.normal()
|
1332
|
-
delay =
|
1353
|
+
delay = dist / SYN_VELOCITY + SYN_MIN_DELAY + del_fluc
|
1354
|
+
delay = min(max(delay, DELAY_LOWBOUND), DELAY_UPBOUND)
|
1333
1355
|
return delay
|
1334
1356
|
|
1335
1357
|
|
@@ -1348,35 +1370,7 @@ def syn_dist_delay_feng_section_PN(source, target, p=0.9,
|
|
1348
1370
|
s_id, s_x = syn_section_PN(source, target, p=p, sec_id=sec_id, sec_x=sec_x)
|
1349
1371
|
return delay, s_id, s_x
|
1350
1372
|
|
1351
|
-
|
1352
|
-
|
1353
|
-
|
1354
|
-
|
1355
|
-
'CTH': 1, 'CC': 1,
|
1356
|
-
'FSI': 0, 'LTS': 0
|
1357
|
-
}
|
1358
|
-
|
1359
|
-
def get_target_sec_id(source, target):
|
1360
|
-
# 0 - Target soma, 1 - Target basal dendrite
|
1361
|
-
sec_id = TARGET_SEC_ID.get(source['pop_name'], None)
|
1362
|
-
if sec_id is None:
|
1363
|
-
if source['model_type'] == 'virtual':
|
1364
|
-
sec_id = 1
|
1365
|
-
print('virtual cell') # Testing
|
1366
|
-
else: # We really don't want a default case so we can catch errors
|
1367
|
-
# return 0
|
1368
|
-
import pdb; pdb.set_trace()
|
1369
|
-
return sec_id
|
1370
|
-
|
1371
|
-
def syn_dist_delay_feng_section(source, target, connector=None,
|
1372
|
-
sec_id=None, sec_x=0.9):
|
1373
|
-
if sec_id is None:
|
1374
|
-
sec_id = get_target_sec_id(source, target)
|
1375
|
-
return syn_dist_delay_feng(source, target, connector), sec_id, sec_x
|
1376
|
-
|
1377
|
-
|
1378
|
-
def syn_uniform_delay_section(source, target, low=0.5, high=1,
|
1379
|
-
sec_id=None, sec_x=0.9, **kwargs):
|
1380
|
-
if sec_id is None:
|
1381
|
-
sec_id = get_target_sec_id(source, target)
|
1382
|
-
return rng.uniform(low, high), sec_id, sec_x
|
1373
|
+
|
1374
|
+
def syn_uniform_delay_section(source, target, low=DELAY_LOWBOUND,
|
1375
|
+
high=DELAY_UPBOUND, **kwargs):
|
1376
|
+
return rng.uniform(low, high)
|
bmtool/util/util.py
CHANGED
@@ -559,6 +559,7 @@ def relation_matrix(config=None, nodes=None,edges=None,sources=[],targets=[],sid
|
|
559
559
|
return stdev
|
560
560
|
|
561
561
|
for s_type_ind,s_type in enumerate(source_uids[sm]):
|
562
|
+
|
562
563
|
for t_type_ind,t_type in enumerate(target_uids[tm]):
|
563
564
|
source_index = int(s_type_ind+sources_start[sm])
|
564
565
|
target_index = int(t_type_ind+target_start[tm])
|
@@ -586,12 +587,12 @@ def relation_matrix(config=None, nodes=None,edges=None,sources=[],targets=[],sid
|
|
586
587
|
syn_info[source_index,target_index] = ""
|
587
588
|
else:
|
588
589
|
syn_info[source_index,target_index] = syn_list
|
589
|
-
|
590
|
+
|
590
591
|
e_matrix[source_index,target_index]=total
|
591
592
|
|
592
593
|
return syn_info, e_matrix, source_pop_names, target_pop_names
|
593
594
|
|
594
|
-
def connection_totals(config=None,nodes=None,edges=None,sources=[],targets=[],sids=[],tids=[],prepend_pop=True,synaptic_info='0'):
|
595
|
+
def connection_totals(config=None,nodes=None,edges=None,sources=[],targets=[],sids=[],tids=[],prepend_pop=True,synaptic_info='0',include_gap=True):
|
595
596
|
|
596
597
|
def total_connection_relationship(**kwargs):
|
597
598
|
edges = kwargs["edges"]
|
@@ -600,12 +601,60 @@ def connection_totals(config=None,nodes=None,edges=None,sources=[],targets=[],si
|
|
600
601
|
source_id = kwargs["source_id"]
|
601
602
|
target_id = kwargs["target_id"]
|
602
603
|
|
603
|
-
total = edges[(edges[source_id_type] == source_id) & (edges[target_id_type]==target_id)]
|
604
|
+
total = edges[(edges[source_id_type] == source_id) & (edges[target_id_type]==target_id)]
|
605
|
+
if include_gap == False:
|
606
|
+
total = total[total['is_gap_junction'] != True]
|
607
|
+
total = total.count()
|
604
608
|
total = total.source_node_id # may not be the best way to pick
|
605
609
|
return total
|
606
610
|
return relation_matrix(config,nodes,edges,sources,targets,sids,tids,prepend_pop,relation_func=total_connection_relationship,synaptic_info=synaptic_info)
|
607
611
|
|
608
|
-
def
|
612
|
+
def percent_connections(config=None,nodes=None,edges=None,sources=[],targets=[],sids=[],tids=[],prepend_pop=True,method=None,include_gap=True):
|
613
|
+
|
614
|
+
def precent_func(**kwargs):
|
615
|
+
edges = kwargs["edges"]
|
616
|
+
source_id_type = kwargs["sid"]
|
617
|
+
target_id_type = kwargs["tid"]
|
618
|
+
source_id = kwargs["source_id"]
|
619
|
+
target_id = kwargs["target_id"]
|
620
|
+
t_list = kwargs["target_nodes"]
|
621
|
+
s_list = kwargs["source_nodes"]
|
622
|
+
|
623
|
+
cons = edges[(edges[source_id_type] == source_id) & (edges[target_id_type]==target_id)]
|
624
|
+
if include_gap == False:
|
625
|
+
cons = cons[cons['is_gap_junction'] != True]
|
626
|
+
total_cons = cons.count().source_node_id
|
627
|
+
# to determine reciprocal connectivity
|
628
|
+
# create a copy and flip source/dest
|
629
|
+
cons_flip = edges[(edges[source_id_type] == target_id) & (edges[target_id_type]==source_id)]
|
630
|
+
cons_flip = cons_flip.rename(columns={'source_node_id':'target_node_id','target_node_id':'source_node_id'})
|
631
|
+
# append to original
|
632
|
+
cons_recip = pd.concat([cons, cons_flip])
|
633
|
+
|
634
|
+
# determine dropped duplicates (keep=False)
|
635
|
+
cons_recip_dedup = cons_recip.drop_duplicates(subset=['source_node_id','target_node_id'])
|
636
|
+
|
637
|
+
# note counts
|
638
|
+
num_bi = (cons_recip.count().source_node_id - cons_recip_dedup.count().source_node_id)
|
639
|
+
num_uni = total_cons - num_bi
|
640
|
+
|
641
|
+
num_sources = s_list.apply(pd.Series.value_counts)[source_id_type].dropna().sort_index().loc[source_id]
|
642
|
+
num_targets = t_list.apply(pd.Series.value_counts)[target_id_type].dropna().sort_index().loc[target_id]
|
643
|
+
|
644
|
+
total = round(total_cons / (num_sources*num_targets) * 100,2)
|
645
|
+
uni = round(num_uni / (num_sources*num_targets) * 100,2)
|
646
|
+
bi = round(num_bi / (num_sources*num_targets) * 100,2)
|
647
|
+
if method == 'total':
|
648
|
+
return total
|
649
|
+
if method == 'uni':
|
650
|
+
return uni
|
651
|
+
if method == 'bi':
|
652
|
+
return bi
|
653
|
+
|
654
|
+
|
655
|
+
return relation_matrix(config,nodes,edges,sources,targets,sids,tids,prepend_pop,relation_func=precent_func)
|
656
|
+
|
657
|
+
def connection_divergence(config=None,nodes=None,edges=None,sources=[],targets=[],sids=[],tids=[],prepend_pop=True,convergence=False,method='mean',include_gap=True):
|
609
658
|
|
610
659
|
import pandas as pd
|
611
660
|
|
@@ -620,6 +669,8 @@ def connection_divergence(config=None,nodes=None,edges=None,sources=[],targets=[
|
|
620
669
|
count = 1
|
621
670
|
|
622
671
|
cons = edges[(edges[source_id_type] == source_id) & (edges[target_id_type]==target_id)]
|
672
|
+
if include_gap == False:
|
673
|
+
cons = cons[cons['is_gap_junction'] != True]
|
623
674
|
|
624
675
|
if convergence:
|
625
676
|
if method == 'min':
|
@@ -646,12 +697,16 @@ def connection_divergence(config=None,nodes=None,edges=None,sources=[],targets=[
|
|
646
697
|
std = cons.apply(pd.Series.value_counts).source_node_id.dropna().std()
|
647
698
|
return round(std,2)
|
648
699
|
else: #mean
|
649
|
-
vc = s_list.apply(pd.Series.value_counts)[source_id_type].dropna().sort_index().loc[source_id]
|
700
|
+
#vc = s_list.apply(pd.Series.value_counts)[source_id_type].dropna().sort_index().loc[source_id]
|
701
|
+
vc = s_list.apply(pd.Series.value_counts)
|
650
702
|
vc = vc[source_id_type].dropna().sort_index()
|
651
703
|
count = vc.loc[source_id]#count = s_list[s_list[source_id_type]==source_id]
|
652
704
|
|
653
705
|
# Only executed when mean
|
654
|
-
total = edges[(edges[source_id_type] == source_id) & (edges[target_id_type]==target_id)]
|
706
|
+
total = edges[(edges[source_id_type] == source_id) & (edges[target_id_type]==target_id)]
|
707
|
+
if include_gap == False:
|
708
|
+
total = total[total['is_gap_junction'] != True]
|
709
|
+
total = total.count()
|
655
710
|
total = total.source_node_id # may not be the best way to pick
|
656
711
|
ret = round(total/count,1)
|
657
712
|
if ret == 0:
|
@@ -661,7 +716,7 @@ def connection_divergence(config=None,nodes=None,edges=None,sources=[],targets=[
|
|
661
716
|
return relation_matrix(config,nodes,edges,sources,targets,sids,tids,prepend_pop,relation_func=total_connection_relationship)
|
662
717
|
|
663
718
|
def connection_probabilities(config=None,nodes=None,edges=None,sources=[],
|
664
|
-
targets=[],sids=[],tids=[],prepend_pop=True,dist_X=True,dist_Y=True,dist_Z=True,num_bins=10):
|
719
|
+
targets=[],sids=[],tids=[],prepend_pop=True,dist_X=True,dist_Y=True,dist_Z=True,num_bins=10,include_gap=True):
|
665
720
|
|
666
721
|
import pandas as pd
|
667
722
|
from scipy.spatial import distance
|
@@ -736,7 +791,9 @@ def connection_probabilities(config=None,nodes=None,edges=None,sources=[],
|
|
736
791
|
return ret
|
737
792
|
|
738
793
|
relevant_edges = edges[(edges[source_id_type] == source_id) & (edges[target_id_type]==target_id)]
|
739
|
-
|
794
|
+
if include_gap == False:
|
795
|
+
relevant_edges = relevant_edges[relevant_edges['is_gap_junction'] != True]
|
796
|
+
connected_distances = eudist(relevant_edges,dist_X,dist_Y,dist_Z).values.tolist()
|
740
797
|
if len(connected_distances)>0:
|
741
798
|
if connected_distances[0]==0:
|
742
799
|
return -1
|