interneuron_placement.py 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545
  1. import random as rng
  2. import matplotlib.pyplot as plt
  3. import noise
  4. import numpy as np
  5. from brian2.units import *
  6. from matplotlib.patches import Ellipse
  7. from tqdm import tqdm
  8. from scripts.spatial_maps.orientation_maps.orientation_map import OrientationMap
  9. class Pickle:
  10. def __init__(self, x, y, a, b, phi):
  11. self.x = x
  12. self.y = y
  13. self.a = a # Semimajor axis
  14. self.b = b # Semiminor axis
  15. self.phi = phi
  16. self.c = 2.0 * a # Sum distance
  17. self.foc_len = np.sqrt(a ** 2 - b ** 2)
  18. self.area = np.pi * a * b
  19. def get_p1(self):
  20. x1 = self.x - self.foc_len * np.cos(self.phi)
  21. y1 = self.y - self.foc_len * np.sin(self.phi)
  22. return x1, y1
  23. def get_p2(self):
  24. x2 = self.x + self.foc_len * np.cos(self.phi)
  25. y2 = self.y + self.foc_len * np.sin(self.phi)
  26. return x2, y2
  27. def get_ellipse(self):
  28. ell = Ellipse((self.x, self.y), 2.0 * self.a, 2.0 * self.b,
  29. angle=self.phi * 180. / np.pi, linewidth=1, fill=False, zorder=2)
  30. return ell
  31. def get_area(self):
  32. return np.pi * self.a * self.b
  33. def plot_neural_sheet(ex_positions, ex_tunings, axonal_clouds=None):
  34. X, Y = get_correct_position_mesh(ex_positions)
  35. n_ex = int(np.sqrt(len(ex_positions)))
  36. head_dir_preference = np.array(ex_tunings).reshape((n_ex, n_ex))
  37. fig = plt.figure(figsize=(4, 4))
  38. ax = fig.add_subplot(111)
  39. c = ax.pcolor(X, Y, head_dir_preference, vmin=-np.pi, vmax=np.pi, cmap="twilight")
  40. fig.colorbar(c, ax=ax, label="Orientation")
  41. if axonal_clouds is not None:
  42. for i, p in enumerate(axonal_clouds):
  43. ell = p.get_ellipse()
  44. # print(ell)
  45. ax.add_artist(ell)
  46. def get_position_mesh(ex_positions):
  47. n_ex = int(np.sqrt(len(ex_positions)))
  48. X = np.array([x for x, _ in ex_positions]).reshape((n_ex, n_ex))
  49. Y = np.array([y for _, y in ex_positions]).reshape((n_ex, n_ex))
  50. return X, Y
  51. def get_correct_position_mesh(ex_positions):
  52. n_ex = int(np.sqrt(len(ex_positions)))
  53. x_wrong = np.array([x for x, _ in ex_positions]).reshape((n_ex, n_ex))
  54. y_wrong = np.array([y for _, y in ex_positions]).reshape((n_ex, n_ex))
  55. x = x_wrong[0, :]
  56. y = y_wrong[:, 0]
  57. xmin = np.min(x)
  58. xmax = np.max(x)
  59. dx = (xmax - xmin) / (x.shape[0] - 1)
  60. ymin = np.min(y)
  61. ymax = np.max(y)
  62. dy = (ymax - ymin) / (y.shape[0] - 1)
  63. # print(np.arange(xmin, xmax + 2 * dx, dx) - dx / 2.)
  64. # X, Y = np.meshgrid(np.arange(xmin, xmax + 2 * dx, dx) - dx / 2., np.arange(ymin, ymax + 2 * dy, dy) - dy / 2.)
  65. # print(np.linspace(xmin, xmax + dx, n_ex + 1, endpoint=True) - dx / 2)
  66. X, Y = np.meshgrid(np.linspace(xmin, xmax + dx, n_ex + 1, endpoint=True) - dx / 2, np.linspace(ymin, ymax + dy, n_ex + 1, endpoint=True) - dy / 2)
  67. return X, Y
  68. def get_entropy_of_axonal_coverage(ex_neuron_tuning, ie_connections):
  69. ex_phase_vals_per_pickle = []
  70. phase_entropy_per_pickle = []
  71. n_hist_bins = 10
  72. for connected_idxs in ie_connections:
  73. ex_phase_vals_of_p = [ex_neuron_tuning[idx] for idx in connected_idxs]
  74. phase_entropy = 0.0
  75. ex_phase_vals_per_pickle.append(ex_phase_vals_of_p)
  76. ex_phase_hist, _ = np.histogram(ex_phase_vals_of_p, n_hist_bins)
  77. n_ex_of_p = float(len(ex_phase_vals_of_p))
  78. ex_phase_hist = 1. / n_ex_of_p * ex_phase_hist.astype(float)
  79. for n_phi in ex_phase_hist:
  80. if n_phi != 0:
  81. phase_entropy -= n_phi * np.log(n_phi)
  82. phase_entropy_per_pickle.append(phase_entropy)
  83. return phase_entropy_per_pickle
  84. def get_excitatory_neurons_in_inhibitory_axonal_clouds(ex_neuron_positions, inhibitory_axonal_clouds):
  85. ie_connections = []
  86. for p in inhibitory_axonal_clouds:
  87. ie_conn_p = []
  88. x_p_1, y_p_1 = p.get_p1()
  89. x_p_2, y_p_2 = p.get_p2()
  90. for ex_idx, ex_pos in enumerate(ex_neuron_positions):
  91. x_ex, y_ex = ex_pos
  92. d_1 = np.sqrt((x_ex - x_p_1) ** 2 + (y_ex - y_p_1) ** 2)
  93. d_2 = np.sqrt((x_ex - x_p_2) ** 2 + (y_ex - y_p_2) ** 2)
  94. if d_1 + d_2 < p.c:
  95. ie_conn_p.append(ex_idx)
  96. ie_connections.append(ie_conn_p)
  97. return ie_connections
  98. def get_excitatory_phases_in_inhibitory_axon(ex_neuron_positions, ex_neuron_tunings, inhibitory_neuron):
  99. ex_phase_vals = []
  100. x_p_1, y_p_1 = inhibitory_neuron.get_p1()
  101. x_p_2, y_p_2 = inhibitory_neuron.get_p2()
  102. for ex_idx, ex_pos in enumerate(ex_neuron_positions):
  103. x_ex, y_ex = ex_pos
  104. d_1 = np.sqrt((x_ex - x_p_1) ** 2 + (y_ex - y_p_1) ** 2)
  105. d_2 = np.sqrt((x_ex - x_p_2) ** 2 + (y_ex - y_p_2) ** 2)
  106. if d_1 + d_2 < inhibitory_neuron.c:
  107. ex_phase_vals.append(ex_neuron_tunings[ex_idx])
  108. return ex_phase_vals
  109. def get_interneuron_entropy(ex_phase_vals, entropy_bins):
  110. phase_entropy = 0.
  111. ex_phase_hist, _ = np.histogram(ex_phase_vals, entropy_bins)
  112. ex_phase_prob = ex_phase_hist / len(ex_phase_vals)
  113. for prob in ex_phase_prob:
  114. if prob > 0.0:
  115. phase_entropy += -prob * np.log(prob)
  116. return phase_entropy
  117. def create_interneuron_sheet_by_noise(ex_positions, ex_tunings, number_of_interneurons, long_axis, short_axis, max_x,
  118. max_y, random_seed=None,
  119. n_iterations=100):
  120. '''
  121. Start with uniform distribution
  122. '''
  123. if random_seed is not None:
  124. rng.seed(random_seed)
  125. pickle_a = long_axis
  126. pickle_b = short_axis
  127. pickle_n = number_of_interneurons
  128. x_n = int(np.sqrt(pickle_n))
  129. y_n = int(np.sqrt(pickle_n))
  130. x_step = int(max_x / (x_n + 1))
  131. y_step = int(max_y / (y_n + 1))
  132. inhibitory_axonal_clouds = []
  133. for n in range(pickle_n):
  134. inhibitory_axonal_clouds.append(Pickle(((n % x_n) + 1) * x_step, \
  135. (int(n / y_n) + 1) * y_step, \
  136. pickle_a, pickle_b, rng.random() * 2. * np.pi))
  137. '''
  138. Determine initial tunings and entropy values
  139. '''
  140. entropy_bins = np.linspace(-np.pi, np.pi, 30)
  141. ex_tunings_of_interneurons = []
  142. entropies_of_interneurons = []
  143. for i_neuron in inhibitory_axonal_clouds:
  144. ex_phase_vals = get_excitatory_phases_in_inhibitory_axon(ex_positions, ex_tunings, i_neuron)
  145. ex_tunings_of_interneurons.append(ex_phase_vals)
  146. entropies_of_interneurons.append(get_interneuron_entropy(ex_phase_vals, entropy_bins))
  147. '''
  148. (Randomly) perturb interneuron and see if entropy increases, if so update position and axonal tunings
  149. '''
  150. # print('Mean Entropy before rotation ', np.mean(entropies_of_interneurons))
  151. pert_phi = np.pi / 4.0
  152. pert_phi_decrease = pert_phi / (n_iterations + 1)
  153. for it in tqdm(range(n_iterations), desc="Optimizing axonal cloud distribution"):
  154. rotation_perturbation = pert_phi - it * pert_phi_decrease
  155. for i_neuron_id, i_neuron in enumerate(inhibitory_axonal_clouds):
  156. perturbed_interneuron = Pickle(i_neuron.x, i_neuron.y, long_axis, short_axis,
  157. i_neuron.phi + rotation_perturbation)
  158. perturbed_phase_vals = get_excitatory_phases_in_inhibitory_axon(ex_positions, ex_tunings,
  159. perturbed_interneuron)
  160. perturbed_entropy = get_interneuron_entropy(perturbed_phase_vals, entropy_bins)
  161. if perturbed_entropy > entropies_of_interneurons[i_neuron_id]:
  162. ex_tunings_of_interneurons.append(ex_phase_vals)
  163. entropies_of_interneurons[i_neuron_id] = perturbed_entropy
  164. i_neuron.phi = perturbed_interneuron.phi
  165. else:
  166. perturbed_interneuron = Pickle(i_neuron.x, i_neuron.y, long_axis, short_axis,
  167. i_neuron.phi - rotation_perturbation)
  168. perturbed_phase_vals = get_excitatory_phases_in_inhibitory_axon(ex_positions, ex_tunings,
  169. perturbed_interneuron)
  170. perturbed_entropy = get_interneuron_entropy(perturbed_phase_vals, entropy_bins)
  171. if perturbed_entropy > entropies_of_interneurons[i_neuron_id]:
  172. ex_tunings_of_interneurons.append(ex_phase_vals)
  173. entropies_of_interneurons[i_neuron_id] = perturbed_entropy
  174. i_neuron.phi = perturbed_interneuron.phi
  175. # print('Mean Entropy after rotation', np.mean(entropies_of_interneurons))
  176. return inhibitory_axonal_clouds, np.mean(entropies_of_interneurons)
  177. def create_interneuron_sheet_entropy_max_orientation(ex_positions, ex_tunings, number_of_interneurons, long_axis,
  178. short_axis, max_x, max_y, trial_orientations=30,
  179. number_of_bins=30, placement_jitter=0.0, seed=0):
  180. inhibitory_axonal_clouds = initialize_axonal_clouds_on_grid_with_random_orientation(number_of_interneurons,
  181. long_axis, short_axis, max_x,
  182. max_y, placement_jitter, seed)
  183. interneuron_positions = [(inh.x, inh.y) for inh in inhibitory_axonal_clouds]
  184. '''
  185. Determine initial tunings and entropy values
  186. '''
  187. entropies_of_interneurons = [0.]
  188. if trial_orientations > 0:
  189. entropies_of_interneurons, optimal_orientations = get_optimal_orientations_for_maximum_entropy(ex_positions,
  190. ex_tunings,
  191. interneuron_positions,
  192. long_axis,
  193. short_axis,
  194. number_of_bins,
  195. trial_orientations)
  196. for opt_orientation, axon in zip(optimal_orientations, inhibitory_axonal_clouds):
  197. axon.phi = opt_orientation
  198. return inhibitory_axonal_clouds, np.mean(entropies_of_interneurons)
  199. def create_interneuron_sheet_entropy_min_orientation(ex_positions, ex_tunings, number_of_interneurons, long_axis,
  200. short_axis, max_x, max_y, trial_orientations=30,
  201. number_of_bins=30, placement_jitter=0.0):
  202. inhibitory_axonal_clouds = initialize_axonal_clouds_on_grid_with_random_orientation(number_of_interneurons,
  203. long_axis, short_axis, max_x,
  204. max_y, placement_jitter)
  205. interneuron_positions = [(inh.x, inh.y) for inh in inhibitory_axonal_clouds]
  206. '''
  207. Determine initial tunings and entropy values
  208. '''
  209. entropies_of_interneurons, optimal_orientations = get_optimal_orientations_for_minimum_entropy(ex_positions,
  210. ex_tunings,
  211. interneuron_positions,
  212. long_axis,
  213. short_axis,
  214. number_of_bins,
  215. trial_orientations)
  216. for opt_orientation, axon in zip(optimal_orientations, inhibitory_axonal_clouds):
  217. axon.phi = opt_orientation
  218. return inhibitory_axonal_clouds, np.mean(entropies_of_interneurons)
  219. def get_optimal_orientations_for_maximum_entropy(ex_positions, ex_tunings, interneuron_positions, long_axis, short_axis,
  220. number_of_bins, trial_orientations):
  221. entropy_bins = np.linspace(-np.pi, np.pi, number_of_bins)
  222. entropies_of_interneurons = []
  223. optimal_orientations = []
  224. # for i_neuron in tqdm(inhibitory_axonal_clouds, desc="Maximizing entropy by rotation"):
  225. for x, y in interneuron_positions:
  226. orientations = np.linspace(-np.pi, np.pi, trial_orientations)
  227. entropy_for_orientation = []
  228. for orientation in orientations:
  229. perturbed_interneuron = Pickle(x, y, long_axis, short_axis, orientation)
  230. ex_phase_vals = get_excitatory_phases_in_inhibitory_axon(ex_positions, ex_tunings, perturbed_interneuron)
  231. entropy_for_orientation.append(get_interneuron_entropy(ex_phase_vals, entropy_bins))
  232. optimal_orientations.append(orientations[np.argmax(entropy_for_orientation)])
  233. entropies_of_interneurons.append(np.max(entropy_for_orientation))
  234. return entropies_of_interneurons, optimal_orientations
  235. def get_optimal_orientations_for_minimum_entropy(ex_positions, ex_tunings, interneuron_positions, long_axis, short_axis,
  236. number_of_bins, trial_orientations):
  237. entropy_bins = np.linspace(-np.pi, np.pi, number_of_bins)
  238. entropies_of_interneurons = []
  239. optimal_orientations = []
  240. # for i_neuron in tqdm(inhibitory_axonal_clouds, desc="Maximizing entropy by rotation"):
  241. for x, y in interneuron_positions:
  242. orientations = np.linspace(-np.pi, np.pi, trial_orientations)
  243. entropy_for_orientation = []
  244. for orientation in orientations:
  245. perturbed_interneuron = Pickle(x, y, long_axis, short_axis, orientation)
  246. ex_phase_vals = get_excitatory_phases_in_inhibitory_axon(ex_positions, ex_tunings, perturbed_interneuron)
  247. entropy_for_orientation.append(get_interneuron_entropy(ex_phase_vals, entropy_bins))
  248. optimal_orientations.append(orientations[np.argmin(entropy_for_orientation)])
  249. entropies_of_interneurons.append(np.min(entropy_for_orientation))
  250. return entropies_of_interneurons, optimal_orientations
  251. def initialize_axonal_clouds_on_grid_with_random_orientation(number_of_interneurons, long_axis, short_axis, sheet_x,
  252. sheet_y, placement_jitter=0.0, seed=0):
  253. '''
  254. Start with uniform distribution
  255. '''
  256. rng.seed(seed)
  257. pickle_a = long_axis
  258. pickle_b = short_axis
  259. pickle_n = number_of_interneurons
  260. x_n = int(np.sqrt(pickle_n))
  261. y_n = int(np.sqrt(pickle_n))
  262. x_step = int(sheet_x / (x_n + 1))
  263. y_step = int(sheet_y / (y_n + 1))
  264. inhibitory_axonal_clouds = []
  265. pj = placement_jitter
  266. for n in range(pickle_n):
  267. theta = rng.random() * 2. * np.pi
  268. pj_x = pj * np.cos(theta)
  269. pj_y = pj * np.sin(theta)
  270. inhibitory_axonal_clouds.append(Pickle(((n % x_n) + 1) * x_step + pj_x, \
  271. (int(n / y_n) + 1) * y_step + pj_y, \
  272. pickle_a, pickle_b, theta))
  273. return inhibitory_axonal_clouds
  274. def create_interneuron_sheet_by_repulsive_force(number_of_interneurons, long_axis, short_axis, max_x, max_y,
  275. random_seed=None,
  276. n_iterations=100):
  277. # '''
  278. # Start with random pickle distribution
  279. # '''
  280. # if random_seed is not None:
  281. # rng.seed(random_seed)
  282. # pickle_a = long_axis
  283. # pickle_b = short_axis
  284. # pickle_n = number_of_interneurons
  285. # x_rng_min = pickle_a
  286. # x_rng_max = max_x - pickle_a
  287. # y_rng_min = pickle_a
  288. # y_rng_max = max_y - pickle_a
  289. # inhibitory_axonal_clouds = []
  290. # for n in range(pickle_n):
  291. # inhibitory_axonal_clouds.append(Pickle(rng.uniform(x_rng_min, x_rng_max), \
  292. # rng.uniform(y_rng_min, y_rng_max), \
  293. # pickle_a, pickle_b, rng.random() * 2. * np.pi))
  294. '''
  295. Start with uniform distribution
  296. '''
  297. if random_seed is not None:
  298. rng.seed(random_seed)
  299. pickle_a = long_axis
  300. pickle_b = short_axis
  301. pickle_n = number_of_interneurons
  302. x_n = int(np.sqrt(pickle_n))
  303. y_n = int(np.sqrt(pickle_n))
  304. x_step = int(max_x / (x_n + 1))
  305. y_step = int(max_y / (y_n + 1))
  306. inhibitory_axonal_clouds = []
  307. for n in range(pickle_n):
  308. inhibitory_axonal_clouds.append(AxonalCloud(((n % x_n) + 1) * x_step, \
  309. (int(n / y_n) + 1) * y_step, \
  310. pickle_a, pickle_b, rng.random() * 2. * np.pi))
  311. # plotting()
  312. '''
  313. Distribute pickles by repulsive "force"
  314. '''
  315. f_scale = 0.2
  316. def point_repulsion(x_i, y_i, x_j, y_j):
  317. d_x = x_i - x_j
  318. d_y = y_i - y_j
  319. # Distance is torus-like as to approach more homogenous distribution
  320. if d_x > max_x / 2.:
  321. d_x = -max_x + d_x
  322. elif d_x < -max_x / 2.:
  323. d_x = max_x + d_x
  324. if d_y > max_y / 2.:
  325. d_y = -max_y + d_y
  326. elif d_y < -max_y / 2.:
  327. d_y = max_y + d_y
  328. d = np.sqrt(d_x ** 2 + d_y ** 2)
  329. f_i = f_scale * 1. / (d + 1) ** 2
  330. f_x = f_i * d_x / d
  331. f_y = f_i * d_y / d
  332. return f_x, f_y
  333. def pickle_repulsion(p_i, p_j):
  334. phi = p_i.phi
  335. p_i_x1, p_i_y1 = p_i.get_p1()
  336. p_i_x2, p_i_y2 = p_i.get_p2()
  337. p_j_x1, p_j_y1 = p_j.get_p1()
  338. p_j_x2, p_j_y2 = p_j.get_p2()
  339. f_p1p1_x, f_p1p1_y = point_repulsion(p_i_x1, p_i_y1, p_j_x1, p_j_y1) # p1-p1
  340. f_p1p2_x, f_p1p2_y = point_repulsion(p_i_x1, p_i_y1, p_j_x2, p_j_y2) # p1-p2
  341. f_p2p1_x, f_p2p1_y = point_repulsion(p_i_x2, p_i_y2, p_j_x1, p_j_y1) # p2-p1
  342. f_p2p2_x, f_p2p2_y = point_repulsion(p_i_x2, p_i_y2, p_j_x2, p_j_y2) # p2-p2
  343. f_p1_x = f_p1p1_x + f_p1p2_x
  344. f_p1_y = f_p1p1_y + f_p1p2_y
  345. f_p2_x = f_p2p1_x + f_p2p2_x
  346. f_p2_y = f_p2p1_y + f_p2p2_y
  347. m_p1 = (f_p1_x * np.sin(phi) - f_p1_y * np.cos(phi))
  348. m_p2 = (-f_p2_x * np.sin(phi) + f_p2_y * np.cos(phi))
  349. f_x_sum = f_p1_x + f_p2_x
  350. f_y_sum = f_p1_y + f_p2_y
  351. m_sum = m_p1 + m_p2
  352. return f_x_sum, f_y_sum, m_sum
  353. for i in tqdm(range(n_iterations), desc="Optimizing axonal cloud distribution"):
  354. delta_xyphi = []
  355. for i, p_i in enumerate(inhibitory_axonal_clouds):
  356. delta_x = 0.
  357. delta_y = 0.
  358. delta_phi = 0.
  359. for p_j in inhibitory_axonal_clouds:
  360. if p_i is not p_j:
  361. del_x, del_y, del_m = pickle_repulsion(p_i, p_j)
  362. delta_x += del_x
  363. delta_y += del_y
  364. delta_phi += del_m
  365. delta_xyphi.append([delta_x, delta_y, delta_phi])
  366. # plotting(delta_xy)
  367. for i, p_i in enumerate(inhibitory_axonal_clouds):
  368. x_new = p_i.x + delta_xyphi[i][0]
  369. y_new = p_i.y + delta_xyphi[i][1]
  370. p_i.phi = p_i.phi + delta_xyphi[i][2]
  371. # Torus-like distance so pickles can cross borders and behave like a subset of a bigger distribution
  372. if x_new < max_x and x_new > 0.0:
  373. p_i.x = x_new
  374. elif x_new < 0.:
  375. p_i.x = max_x + x_new
  376. elif x_new > max_x:
  377. p_i.x = x_new - max_x
  378. if y_new < max_y and y_new > 0.0:
  379. p_i.y = y_new
  380. elif y_new < 0.:
  381. p_i.y = max_y + y_new
  382. elif y_new > max_y:
  383. p_i.y = y_new - max_y
  384. # plotting()
  385. # plotting()
  386. return inhibitory_axonal_clouds
  387. def create_grid_of_excitatory_neurons(max_x, max_y, number_of_excitatory_neurons_per_row, tuning_map):
  388. grid_x = number_of_excitatory_neurons_per_row
  389. grid_y = number_of_excitatory_neurons_per_row
  390. x = np.linspace(0, max_x, grid_x)
  391. y = np.linspace(0, max_y, grid_y)
  392. ex_neuron_positions = []
  393. ex_neuron_tuning = []
  394. head_dir_preference = np.zeros((grid_x, grid_y))
  395. for y_idx, yy in enumerate(y):
  396. for x_idx, xx in enumerate(x):
  397. p_noise = tuning_map(xx, yy)
  398. head_dir_preference[x_idx, y_idx] = p_noise
  399. ex_neuron_positions.append([xx, yy])
  400. ex_neuron_tuning.append(p_noise)
  401. return ex_neuron_positions, ex_neuron_tuning
  402. def test_run():
  403. '''
  404. Neural sheet
  405. '''
  406. # To go from the 3d data obtained in Peng 2017 to a 2d sheet is not straightforward
  407. # Assuming a depth of 100um, the density becomes a 1000 interneurons/mm2 and thus about 3000-4000 exneurons/mm2
  408. # A long 200um short 50um interneuron axon would cover about 90 partners
  409. # On the other hand, the typical contacts per excitatory neuron would be A_total/(A_I*N_I) = 30
  410. N_E = 400
  411. N_I = 40
  412. sheet_x = 300 * um
  413. sheet_y = 300 * um
  414. inhibitory_axon_long_axis = 100 * um
  415. inhibitory_axon_short_axis = 25 * um
  416. number_of_excitatory_neurons_per_row = int(np.sqrt(N_E))
  417. '''
  418. Tuning Maps
  419. '''
  420. # tuning_label = "Perlin"
  421. tuning_label = "Orientation map"
  422. if tuning_label == "Perlin":
  423. tuning_map = lambda x, y: noise.pnoise2(x / 100.0, y / 100.0, octaves=2) * np.pi
  424. elif tuning_label == "Orientation map":
  425. map = OrientationMap(20, 20, 7, sheet_x / um, sheet_y / um)
  426. map.improve(10)
  427. tuning_map = lambda x, y: map.orientation_map_float(x, y)
  428. ex_positions, ex_tunings = create_grid_of_excitatory_neurons(sheet_x / um, sheet_y / um,
  429. number_of_excitatory_neurons_per_row, tuning_map)
  430. # inhibitory_axonal_clouds = create_interneuron_sheet(N_I, inhibitory_axon_long_axis / um,
  431. # inhibitory_axon_short_axis / um, sheet_x / um,
  432. # sheet_y / um, random_seed=2, n_iterations=1000)
  433. inhibitory_axonal_clouds = create_interneuron_sheet_by_noise(ex_positions, ex_tunings, N_I,
  434. inhibitory_axon_long_axis / um,
  435. inhibitory_axon_short_axis / um, sheet_x / um,
  436. sheet_y / um, random_seed=3, n_iterations=10)
  437. plot_neural_sheet(ex_positions, ex_tunings, inhibitory_axonal_clouds)
  438. if __name__ == "__main__":
  439. test_run()