run_orientation_map.py 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320
  1. import json
  2. import os
  3. import numpy as np
  4. from brian2.units import *
  5. from pypet import Environment, cartesian_product, Trajectory
  6. from pypet.brian2.parameter import Brian2MonitorResult
  7. from scripts.interneuron_placement import create_grid_of_excitatory_neurons, \
  8. create_interneuron_sheet_entropy_max_orientation, get_excitatory_neurons_in_inhibitory_axonal_clouds
  9. from scripts.ring_network.head_direction import ex_in_network
  10. from scripts.spatial_maps.orientation_maps.orientation_map import OrientationMap
  11. from scripts.spatial_maps.orientation_maps.orientation_map_generator_pypet import TRAJ_NAME_ORIENTATION_MAPS
  12. from scripts.spatial_maps.uniform_perlin_map import UniformPerlinMap
  13. from scripts.spatial_network.head_direction_index_over_noise_scale import excitatory_eqs, excitatory_params, \
  14. lif_interneuron_eqs, lif_interneuron_params, lif_interneuron_options, ei_synapse_model, ei_synapse_on_pre, \
  15. ei_synapse_param, ie_synapse_model, ie_synapse_on_pre, ie_synapse_param, get_synaptic_weights, \
  16. create_head_direction_input
  17. POLARIZED = 'ellipsoid'
  18. CIRCULAR = 'circular'
  19. NO_SYNAPSES = 'no conn'
  20. def get_local_data_folder():
  21. data_folder = "../../../data/"
  22. config_file_name = ".config.json"
  23. if os.path.isfile(config_file_name):
  24. with open(config_file_name) as config_file:
  25. config_dict = json.load(config_file)
  26. data_folder = os.path.abspath(config_dict["data"])
  27. print(data_folder)
  28. return data_folder
  29. DATA_FOLDER = "../../../data/"
  30. LOG_FOLDER = "../../../logs/"
  31. TRAJ_NAME = "full_figure_orientation_map"
  32. def get_orientation_map(correlation_length, seed, sheet_size, N_E, data_folder=None):
  33. if data_folder is None:
  34. data_folder = DATA_FOLDER
  35. traj = Trajectory(filename=data_folder + TRAJ_NAME_ORIENTATION_MAPS + ".hdf5")
  36. traj.f_load(index=-1, load_parameters=2, load_results=2)
  37. available_lengths = sorted(list(set(traj.f_get("corr_len").f_get_range())))
  38. closest_length = available_lengths[np.argmin(np.abs(np.array(available_lengths)-correlation_length))]
  39. if closest_length!=correlation_length:
  40. print("Warning: desired correlation length {:.1f} not available. Taking {:.1f} instead".format(
  41. correlation_length, closest_length))
  42. corr_len = closest_length
  43. seed = seed
  44. map_by_params = lambda x, y: x == corr_len and y == seed
  45. idx_iterator = traj.f_find_idx(['corr_len', 'seed'], map_by_params)
  46. # TODO: Since it has only one entry, maybe iterator can be replaced
  47. for idx in idx_iterator:
  48. traj.v_idx = idx
  49. map_angle_grid = traj.crun.map
  50. number_of_excitatory_neurons_per_row = int(np.sqrt(N_E))
  51. map = OrientationMap(number_of_excitatory_neurons_per_row, number_of_excitatory_neurons_per_row,
  52. corr_len, sheet_size, sheet_size, seed)
  53. map.angle_grid = map_angle_grid
  54. return map.tuning
  55. def get_uniform_orientation_map(correlation_length, seed, sheet_size, N_E, data_folder=None):
  56. if data_folder is None:
  57. data_folder = DATA_FOLDER
  58. traj = Trajectory(filename=data_folder + TRAJ_NAME_ORIENTATION_MAPS + ".hdf5")
  59. traj.f_load(index=-1, load_parameters=2, load_results=2)
  60. available_lengths = sorted(list(set(traj.f_get("corr_len").f_get_range())))
  61. closest_length = available_lengths[np.argmin(np.abs(np.array(available_lengths)-correlation_length))]
  62. if closest_length!=correlation_length:
  63. print("Warning: desired correlation length {:.1f} not available. Taking {:.1f} instead".format(
  64. correlation_length, closest_length))
  65. corr_len = closest_length
  66. seed = seed
  67. map_by_params = lambda x, y: x == corr_len and y == seed
  68. idx_iterator = traj.f_find_idx(['corr_len', 'seed'], map_by_params)
  69. # TODO: Since it has only one entry, maybe iterator can be replaced
  70. for idx in idx_iterator:
  71. traj.v_idx = idx
  72. map_angle_grid = traj.crun.map
  73. number_of_excitatory_neurons_per_row = int(np.sqrt(N_E))
  74. map = OrientationMap(number_of_excitatory_neurons_per_row, number_of_excitatory_neurons_per_row,
  75. corr_len, sheet_size, sheet_size, seed)
  76. # Uniformize orientation map
  77. nrow = number_of_excitatory_neurons_per_row
  78. size = sheet_size
  79. scale = corr_len # TODO: Probably this needs to be a linear interpolation
  80. n = map_angle_grid / np.pi
  81. m = np.concatenate(n)
  82. sorted_idx = np.argsort(m)
  83. max_val = nrow * 2
  84. idx = len(m) // max_val
  85. for ii, val in enumerate(range(max_val)):
  86. m[sorted_idx[ii * idx:(ii + 1) * idx]] = val
  87. p_map = (m - nrow) / nrow
  88. map.angle_grid = p_map.reshape(nrow, -1) * np.pi
  89. # self.map *= np.pi
  90. # map.angle_grid = map_angle_grid
  91. return map.tuning
  92. def spatial_network_with_entropy_maximisation(traj):
  93. sheet_size = traj.map.sheet_size
  94. N_E = traj.network.N_E
  95. N_I = traj.network.N_I
  96. orientation_map = get_uniform_orientation_map(traj.map.correlation_length, traj.map.seed, sheet_size, N_E)
  97. ex_positions, ex_tunings = create_grid_of_excitatory_neurons(sheet_size,
  98. sheet_size,
  99. int(np.sqrt(N_E)), orientation_map)
  100. inhibitory_axon_long_axis = traj.morphology.long_axis
  101. inhibitory_axon_short_axis = traj.morphology.short_axis
  102. entropy_maximisation_steps = traj.simulation.entropy_maximisation.steps if inhibitory_axon_long_axis != \
  103. inhibitory_axon_short_axis else 1
  104. inhibitory_axonal_clouds, ellipse_single_trial_entropy = create_interneuron_sheet_entropy_max_orientation(
  105. ex_positions, ex_tunings, N_I, inhibitory_axon_long_axis,
  106. inhibitory_axon_short_axis, sheet_size,
  107. sheet_size, trial_orientations=entropy_maximisation_steps)
  108. ie_connections = get_excitatory_neurons_in_inhibitory_axonal_clouds(ex_positions, inhibitory_axonal_clouds)
  109. inhibitory_synapse_strength = traj.synapse.inhibitory * nS
  110. excitatory_synapse_strength = traj.synapse.excitatory * mV
  111. if inhibitory_synapse_strength != 0.0 * nS and excitatory_synapse_strength != 0.0 * mV \
  112. and inhibitory_axon_long_axis == inhibitory_axon_short_axis:
  113. traj.f_add_derived_parameter("morphology.morph_label", CIRCULAR,
  114. comment="Interneuron morphology of this run is circular")
  115. elif inhibitory_synapse_strength != 0.0 * nS and excitatory_synapse_strength != 0.0 * mV:
  116. traj.f_add_derived_parameter("morphology.morph_label", POLARIZED,
  117. comment="Interneuron morphology of this run is ellipsoid")
  118. else:
  119. traj.f_add_derived_parameter("morphology.morph_label", NO_SYNAPSES,
  120. comment="There are no interneurons")
  121. ex_in_weights, in_ex_weights = get_synaptic_weights(N_E, N_I, ie_connections, excitatory_synapse_strength,
  122. inhibitory_synapse_strength)
  123. sharpness = 1.0 / (traj.input.width) ** 2
  124. directions = get_input_head_directions(traj)
  125. for idx, dir in enumerate(directions):
  126. # We recreate the network here for every dir, which slows down the simulation quite considerably. Otherwise,
  127. # we get a problem with saving and restoring the spike times (0s spike for neuron 0)
  128. net = ex_in_network(N_E, N_I, excitatory_eqs, excitatory_params, lif_interneuron_eqs,
  129. lif_interneuron_params,
  130. lif_interneuron_options, ei_synapse_model, ei_synapse_on_pre,
  131. ei_synapse_param,
  132. ex_in_weights, ie_synapse_model, ie_synapse_on_pre,
  133. ie_synapse_param, in_ex_weights, random_seed=2)
  134. input_to_excitatory_population = create_head_direction_input(traj.input.baseline * nA, ex_tunings,
  135. sharpness,
  136. traj.input.amplitude * nA, dir)
  137. excitatory_neurons = net["excitatory_neurons"]
  138. excitatory_neurons.I = input_to_excitatory_population
  139. inhibitory_neurons = net["interneurons"]
  140. inhibitory_neurons.u_ext = traj.inh_input.baseline * mV
  141. inhibitory_neurons.tau = traj.interneuron.tau * ms
  142. net.run(traj.simulation.duration * ms)
  143. direction_id = 'dir{:d}'.format(idx)
  144. traj.f_add_result(Brian2MonitorResult, '{:s}.spikes.e'.format(direction_id), net["excitatory_spike_monitor"],
  145. comment='The spiketimes of the excitatory population')
  146. traj.f_add_result(Brian2MonitorResult, '{:s}.spikes.i'.format(direction_id), net["inhibitory_spike_monitor"],
  147. comment='The spiketimes of the inhibitory population')
  148. traj.f_add_result('ex_positions', np.array(ex_positions),
  149. comment='The positions of the excitatory neurons on the sheet')
  150. traj.f_add_result('ex_tunings', np.array(ex_tunings),
  151. comment='The input tunings of the excitatory neurons')
  152. ie_connections_save_array = np.zeros((N_I, N_E))
  153. for i_idx, ie_conn in enumerate(ie_connections):
  154. for e_idx in ie_conn:
  155. ie_connections_save_array[i_idx, e_idx] = 1
  156. traj.f_add_result('ie_adjacency', ie_connections_save_array,
  157. comment='Recurrent connection adjacency matrix')
  158. axon_cloud_save_list = [[p.x, p.y, p.phi] for p in inhibitory_axonal_clouds]
  159. axon_cloud_save_array = np.array(axon_cloud_save_list)
  160. traj.f_add_result('inhibitory_axonal_cloud_array', axon_cloud_save_array,
  161. comment='The inhibitory axonal clouds')
  162. return 1
  163. def get_input_head_directions(traj):
  164. directions = np.linspace(-np.pi, np.pi, traj.input.number_of_directions, endpoint=False)
  165. return directions
  166. def main():
  167. env = Environment(trajectory=TRAJ_NAME,
  168. comment="Compare the head direction tuning for circular and ellipsoid interneuron morphology, "
  169. "when tuning orientations to maximise entropy of connected excitatory tunings.",
  170. multiproc=True, filename=DATA_FOLDER, ncores=0, overwrite_file=True, log_folder=LOG_FOLDER)
  171. traj = env.trajectory
  172. traj.f_add_parameter_group("map")
  173. traj.f_add_parameter("map.correlation_length", 200.0,
  174. comment="Correlation length of orientations in um")
  175. traj.f_add_parameter("map.seed", 1, comment="Random seed for map generation.")
  176. traj.f_add_parameter("map.sheet_size", 900, comment="Sheet size in um")
  177. traj.f_add_parameter_group("network")
  178. traj.f_add_parameter("network.N_E", 3600, comment="Number of excitatory neurons")
  179. traj.f_add_parameter("network.N_I", 400, comment="Number of inhibitory neurons")
  180. traj.f_add_parameter_group("interneuron")
  181. traj.f_add_parameter("interneuron.tau", 7., comment="Interneuron timescale in ms")
  182. traj.f_add_parameter_group("synapse")
  183. traj.f_add_parameter("synapse.inhibitory", 30.0, "Strength of conductance-based inhibitory synapse in nS.")
  184. traj.f_add_parameter("synapse.excitatory", 2.5, "Strength of conductance-based inhibitory synapse in mV.")
  185. traj.f_add_parameter_group("input")
  186. traj.f_add_parameter("input.width", 1. / np.sqrt(2.5), comment="Standard deviation of incoming head direction input.")
  187. traj.f_add_parameter("input.baseline", 0.05, comment="Head direction input baseline")
  188. traj.f_add_parameter("input.amplitude", 0.6, comment="Head direction input amplitude")
  189. traj.f_add_parameter("input.number_of_directions", 12, comment="Number of probed directions")
  190. traj.f_add_parameter_group("inh_input")
  191. traj.f_add_parameter("inh_input.baseline", -50., comment="Head direction input baseline")
  192. traj.f_add_parameter("inh_input.amplitude", 0., comment="Head direction input amplitude")
  193. traj.f_add_parameter_group("morphology")
  194. traj.f_add_parameter("morphology.long_axis", 100.0, comment="Long axis of axon ellipsoid")
  195. traj.f_add_parameter("morphology.short_axis", 25.0, comment="Short axis of axon ellipsoid")
  196. traj.f_add_parameter_group("simulation")
  197. traj.f_add_parameter("simulation.entropy_maximisation.steps", 30, comment="Steps for entropy maximisation")
  198. traj.f_add_parameter("simulation.dt", 0.1, comment="Network simulation time step in ms")
  199. traj.f_add_parameter("simulation.duration", 1000, comment="Network simulation duration in ms")
  200. correlation_length_range = np.linspace(1.0, 800.0, 12, endpoint=True).tolist()
  201. # correlation_length_range = [200.0]
  202. seed_range = range(10)
  203. # seed_range = [1]
  204. ellipsoid_parameter_exploration = {
  205. "morphology.long_axis": [100.0],
  206. "morphology.short_axis": [25.0],
  207. "map.correlation_length": correlation_length_range,
  208. "map.seed": seed_range,
  209. "synapse.inhibitory": [30.],
  210. "synapse.excitatory": [2.5]
  211. # "map.correlation_length": np.arange(0.0, 200.0, 50).tolist()
  212. }
  213. corresponding_circular_radius = float(np.sqrt(ellipsoid_parameter_exploration[
  214. "morphology.long_axis"][0] * ellipsoid_parameter_exploration[
  215. "morphology.short_axis"][0]))
  216. circle_parameter_exploration = {
  217. "morphology.long_axis": [corresponding_circular_radius],
  218. "morphology.short_axis": [corresponding_circular_radius],
  219. "map.correlation_length": ellipsoid_parameter_exploration["map.correlation_length"],
  220. "map.seed": ellipsoid_parameter_exploration["map.seed"],
  221. "synapse.inhibitory": ellipsoid_parameter_exploration["synapse.inhibitory"],
  222. "synapse.excitatory": ellipsoid_parameter_exploration["synapse.excitatory"]
  223. }
  224. no_conn_parameter_exploration = {
  225. "morphology.long_axis": [corresponding_circular_radius],
  226. "morphology.short_axis": [corresponding_circular_radius],
  227. "map.correlation_length": ellipsoid_parameter_exploration["map.correlation_length"],
  228. "map.seed": ellipsoid_parameter_exploration["map.seed"],
  229. "synapse.inhibitory": [0.],
  230. "synapse.excitatory": [0.]
  231. }
  232. expanded_dicts = [cartesian_product(dict) for dict in [ellipsoid_parameter_exploration,
  233. circle_parameter_exploration,
  234. no_conn_parameter_exploration]]
  235. final_dict = {}
  236. for key in expanded_dicts[0].keys():
  237. list_of_parameter_lists = [dict[key] for dict in expanded_dicts]
  238. final_dict[key] = sum(list_of_parameter_lists, [])
  239. traj.f_explore(final_dict)
  240. env.run(spatial_network_with_entropy_maximisation)
  241. env.disable_logging()
  242. if __name__ == "__main__":
  243. main()