run_simulation_pinwheel_map.py 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277
  1. import numpy as np
  2. from brian2 import BrianLogger
  3. from brian2.units import *
  4. import warnings
  5. warnings.simplefilter(action='ignore', category=FutureWarning) # Otherwise pypet's FutureWarning spams the console output
  6. from pypet import Environment, cartesian_product, Trajectory
  7. from pypet.brian2.parameter import Brian2MonitorResult
  8. from scripts.spatial_maps.spatial_network_layout import create_grid_of_excitatory_neurons, \
  9. create_interneuron_sheet_entropy_max_orientation, get_excitatory_neurons_in_inhibitory_axonal_clouds
  10. from scripts.spatial_network.spatial_network_setup import get_synaptic_weights, \
  11. create_head_direction_input, ex_in_network
  12. from scripts.spatial_network.models import *
  13. from scripts.spatial_maps.supplement_pinwheel_map.pinwheel_map import PinwheelMap
  14. POLARIZED = 'ellipsoid'
  15. CIRCULAR = 'circular'
  16. NO_SYNAPSES = 'no conn'
  17. DATA_FOLDER = "../../../data/"
  18. LOG_FOLDER = "../../../logs/"
  19. TRAJ_NAME = "spatial_network_pinwheel_map"
  20. TRAJ_NAME_PINWHEEL_MAPS = "precalculated_pinwheel_maps"
  21. # SCALE_RANGE = [200.0]
  22. # SEED_RANGE = [1]
  23. SCALE_RANGE = np.linspace(1.0, 650.0, 24, endpoint=True).tolist()
  24. SEED_RANGE = range(10)
  25. def get_uniform_pinwheel_map(scale, seed, sheet_size, N_E, data_folder=None):
  26. if data_folder is None:
  27. data_folder = DATA_FOLDER
  28. traj = Trajectory(filename=data_folder + TRAJ_NAME_PINWHEEL_MAPS + ".hdf5")
  29. traj.f_load(index=-1, load_parameters=2, load_results=2)
  30. available_scales = sorted(list(set(traj.f_get("scale").f_get_range())))
  31. closest_scale = available_scales[np.argmin(np.abs(np.array(available_scales)-scale))]
  32. if closest_scale != scale:
  33. print("Warning: desired correlation length {:.1f} not available. Taking {:.1f} instead".format(
  34. scale, closest_scale))
  35. map_by_params = lambda x, y: x == scale and y == seed
  36. idx_iterator = traj.f_find_idx(['scale', 'seed'], map_by_params)
  37. for idx in idx_iterator:
  38. traj.v_idx = idx
  39. map_angle_grid = traj.crun.pinwheel_map
  40. number_of_excitatory_neurons_per_row = int(np.sqrt(N_E))
  41. map = PinwheelMap(number_of_excitatory_neurons_per_row, number_of_excitatory_neurons_per_row,
  42. scale, sheet_size, sheet_size, seed)
  43. # Uniformize pinwheel map
  44. nrow = number_of_excitatory_neurons_per_row
  45. n = map_angle_grid / np.pi
  46. m = np.concatenate(n)
  47. sorted_idx = np.argsort(m)
  48. max_val = nrow * 2
  49. idx = len(m) // max_val
  50. for ii, val in enumerate(range(max_val)):
  51. m[sorted_idx[ii * idx:(ii + 1) * idx]] = val
  52. p_map = (m - nrow) / nrow
  53. map.angle_grid = p_map.reshape(nrow, -1) * np.pi
  54. return map.tuning
  55. def get_input_head_directions(traj):
  56. directions = np.linspace(-np.pi, np.pi, traj.input.number_of_directions, endpoint=False)
  57. return directions
  58. def spatial_network_with_entropy_maximisation(traj):
  59. sheet_size = traj.input_map.sheet_size
  60. N_E = traj.network.N_E
  61. N_I = traj.network.N_I
  62. pinwheel_map = get_uniform_pinwheel_map(traj.input_map.scale, traj.input_map.seed, sheet_size, N_E)
  63. ex_positions, ex_tunings = create_grid_of_excitatory_neurons(sheet_size, int(np.sqrt(N_E)), pinwheel_map)
  64. inhibitory_axon_long_axis = traj.morphology.long_axis
  65. inhibitory_axon_short_axis = traj.morphology.short_axis
  66. entropy_maximisation_trial_orientations = traj.interneuron.entropy_maximisation.trial_orientations if \
  67. inhibitory_axon_long_axis != inhibitory_axon_short_axis else 0
  68. inhibitory_axonal_clouds, ellipse_single_trial_entropy = create_interneuron_sheet_entropy_max_orientation(
  69. ex_positions, ex_tunings, N_I, inhibitory_axon_long_axis,
  70. inhibitory_axon_short_axis, sheet_size,
  71. sheet_size, trial_orientations=entropy_maximisation_trial_orientations)
  72. ie_connections = get_excitatory_neurons_in_inhibitory_axonal_clouds(ex_positions, inhibitory_axonal_clouds)
  73. inhibitory_synapse_strength = traj.synapse.inhibitory * nS
  74. excitatory_synapse_strength = traj.synapse.excitatory * mV
  75. if inhibitory_synapse_strength != 0.0 * nS and excitatory_synapse_strength != 0.0 * mV \
  76. and inhibitory_axon_long_axis == inhibitory_axon_short_axis:
  77. traj.f_add_derived_parameter("morphology.morph_label", CIRCULAR,
  78. comment="Interneuron morphology of this run is circular")
  79. elif inhibitory_synapse_strength != 0.0 * nS and excitatory_synapse_strength != 0.0 * mV:
  80. traj.f_add_derived_parameter("morphology.morph_label", POLARIZED,
  81. comment="Interneuron morphology of this run is ellipsoid")
  82. else:
  83. traj.f_add_derived_parameter("morphology.morph_label", NO_SYNAPSES,
  84. comment="There are no interneurons")
  85. ex_in_weights, in_ex_weights = get_synaptic_weights(N_E, N_I, ie_connections, excitatory_synapse_strength,
  86. inhibitory_synapse_strength)
  87. input_directions = get_input_head_directions(traj)
  88. for idx, direction in enumerate(input_directions):
  89. # We recreate the network here for every dir, which slows down the simulation quite considerably. Otherwise,
  90. # we get a problem with saving and restoring the spike times (0s spike for neuron 0)
  91. net = ex_in_network(N_E, N_I,
  92. hodgkin_huxley_eqs_with_synaptic_conductance,
  93. hodgkin_huxley_params,
  94. lif_interneuron_eqs,
  95. lif_interneuron_params,
  96. lif_interneuron_options,
  97. delta_synapse_model,
  98. delta_synapse_on_pre,
  99. delta_synapse_param,
  100. ex_in_weights,
  101. exponential_synapse,
  102. exponential_synapse_on_pre,
  103. exponential_synapse_params,
  104. in_ex_weights,
  105. random_seed=traj.input_map.seed)
  106. input_to_excitatory_population = create_head_direction_input(traj.input.baseline * nA, ex_tunings,
  107. traj.input.phase_dispersion,
  108. traj.input.amplitude * nA, direction)
  109. excitatory_neurons = net["excitatory_neurons"]
  110. excitatory_neurons.I = input_to_excitatory_population
  111. inhibitory_neurons = net["interneurons"]
  112. inhibitory_neurons.u_ext = traj.inh_input.baseline * mV
  113. inhibitory_neurons.tau = traj.interneuron.tau * ms
  114. net.run(traj.simulation.duration * ms)
  115. direction_id = 'dir{:d}'.format(idx)
  116. traj.f_add_result(Brian2MonitorResult, '{:s}.spikes.e'.format(direction_id), net["excitatory_spike_monitor"],
  117. comment='The spiketimes of the excitatory population')
  118. traj.f_add_result(Brian2MonitorResult, '{:s}.spikes.i'.format(direction_id), net["inhibitory_spike_monitor"],
  119. comment='The spiketimes of the inhibitory population')
  120. traj.f_add_result('ex_positions', np.array(ex_positions),
  121. comment='The positions of the excitatory neurons on the sheet')
  122. traj.f_add_result('ex_tunings', np.array(ex_tunings),
  123. comment='The input tunings of the excitatory neurons')
  124. ie_connections_save_array = np.zeros((N_I, N_E))
  125. for i_idx, ie_conn in enumerate(ie_connections):
  126. for e_idx in ie_conn:
  127. ie_connections_save_array[i_idx, e_idx] = 1
  128. traj.f_add_result('ie_adjacency', ie_connections_save_array,
  129. comment='Recurrent connection adjacency matrix')
  130. axon_cloud_save_list = [[p.x, p.y, p.phi] for p in inhibitory_axonal_clouds]
  131. axon_cloud_save_array = np.array(axon_cloud_save_list)
  132. traj.f_add_result('inhibitory_axonal_cloud_array', axon_cloud_save_array,
  133. comment='The inhibitory axonal clouds')
  134. return 1
  135. def main():
  136. BrianLogger.suppress_name('method_choice')
  137. # TODO: Set ncores to the desired number of processes to use by pypet
  138. env = Environment(trajectory=TRAJ_NAME,
  139. comment="Compare the head direction tuning for circular and polarized interneuron morphology, "
  140. "when tuning orientations to maximise entropy of connected excitatory tunings.",
  141. multiproc=True, filename=DATA_FOLDER, ncores=24, overwrite_file=True, log_folder=LOG_FOLDER)
  142. traj = env.trajectory
  143. traj.f_add_parameter_group("input_map")
  144. traj.f_add_parameter("input_map.scale", 200.0, comment="Scaling factor of the input map")
  145. traj.f_add_parameter("input_map.seed", 1, comment="Random seed for input map generation.")
  146. traj.f_add_parameter("input_map.sheet_size", 900, comment="Sheet size in um")
  147. traj.f_add_parameter_group("network")
  148. traj.f_add_parameter("network.N_E", 3600, comment="Number of excitatory neurons")
  149. traj.f_add_parameter("network.N_I", 400, comment="Number of inhibitory neurons")
  150. traj.f_add_parameter_group("interneuron")
  151. traj.f_add_parameter("interneuron.tau", 7., comment="Interneuron timescale in ms")
  152. traj.f_add_parameter("interneuron.entropy_maximisation.trial_orientations", 30,
  153. comment="Steps for entropy maximisation")
  154. traj.f_add_parameter_group("synapse")
  155. traj.f_add_parameter("synapse.inhibitory", 30.0, "Strength of conductance-based inhibitory synapse in nS.")
  156. traj.f_add_parameter("synapse.excitatory", 2.5, "Strength of conductance-based inhibitory synapse in mV.")
  157. traj.f_add_parameter_group("input")
  158. traj.f_add_parameter("input.phase_dispersion", 2.5, comment="Standard deviation of incoming head direction input.")
  159. traj.f_add_parameter("input.baseline", 0.05, comment="Head direction input baseline")
  160. traj.f_add_parameter("input.amplitude", 0.6, comment="Head direction input amplitude")
  161. traj.f_add_parameter("input.number_of_directions", 12, comment="Number of probed directions")
  162. traj.f_add_parameter_group("inh_input")
  163. traj.f_add_parameter("inh_input.baseline", -50., comment="Head direction input baseline")
  164. traj.f_add_parameter("inh_input.amplitude", 0., comment="Head direction input amplitude")
  165. traj.f_add_parameter_group("morphology")
  166. traj.f_add_parameter("morphology.long_axis", 100.0, comment="Long axis of axon ellipsoid")
  167. traj.f_add_parameter("morphology.short_axis", 25.0, comment="Short axis of axon ellipsoid")
  168. traj.f_add_parameter_group("simulation")
  169. traj.f_add_parameter("simulation.dt", 0.1, comment="Network simulation time step in ms")
  170. traj.f_add_parameter("simulation.duration", 1000, comment="Network simulation duration in ms")
  171. scale_range = SCALE_RANGE
  172. seed_range = SEED_RANGE
  173. ellipsoid_parameter_exploration = {
  174. "morphology.long_axis": [100.0],
  175. "morphology.short_axis": [25.0],
  176. "input_map.scale": scale_range,
  177. "input_map.seed": seed_range,
  178. "synapse.inhibitory": [30.],
  179. "synapse.excitatory": [2.5]
  180. }
  181. corresponding_circular_radius = float(np.sqrt(ellipsoid_parameter_exploration[
  182. "morphology.long_axis"][0] * ellipsoid_parameter_exploration[
  183. "morphology.short_axis"][0]))
  184. circle_parameter_exploration = {
  185. "morphology.long_axis": [corresponding_circular_radius],
  186. "morphology.short_axis": [corresponding_circular_radius],
  187. "input_map.scale": ellipsoid_parameter_exploration["input_map.scale"],
  188. "input_map.seed": ellipsoid_parameter_exploration["input_map.seed"],
  189. "synapse.inhibitory": ellipsoid_parameter_exploration["synapse.inhibitory"],
  190. "synapse.excitatory": ellipsoid_parameter_exploration["synapse.excitatory"]
  191. }
  192. no_conn_parameter_exploration = {
  193. "morphology.long_axis": [corresponding_circular_radius],
  194. "morphology.short_axis": [corresponding_circular_radius],
  195. "input_map.scale": ellipsoid_parameter_exploration["input_map.scale"],
  196. "input_map.seed": ellipsoid_parameter_exploration["input_map.seed"],
  197. "synapse.inhibitory": [0.],
  198. "synapse.excitatory": [0.]
  199. }
  200. expanded_dicts = [cartesian_product(dict) for dict in [ellipsoid_parameter_exploration,
  201. circle_parameter_exploration,
  202. no_conn_parameter_exploration]]
  203. final_dict = {}
  204. for key in expanded_dicts[0].keys():
  205. list_of_parameter_lists = [dict[key] for dict in expanded_dicts]
  206. final_dict[key] = sum(list_of_parameter_lists, [])
  207. traj.f_explore(final_dict)
  208. env.run(spatial_network_with_entropy_maximisation)
  209. env.disable_logging()
  210. if __name__ == "__main__":
  211. main()