ring_network_pauls_idea.py 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280
  1. # Contrast the output of a ring network with unidirectional inhibition with one that has IE reciprocity
  2. import brian2 as br
  3. import matplotlib.pyplot as plt
  4. import numpy as np
  5. from brian2.units import *
  6. import scripts.models as modellib
  7. from brian2 import seed
  8. seed(2)
  9. N_E = 100
  10. ex_angles = np.arange(-np.pi, np.pi, 2 * np.pi / N_E)
  11. N_I = 20
  12. in_angles = np.arange(-np.pi, np.pi, 2 * np.pi / N_I)
  13. '''
  14. Excitatory neurons
  15. '''
  16. excitatory_eqs = modellib.hodgkin_huxley_eqs_with_synaptic_conductance + modellib.eqs_ih
  17. excitatory_params = modellib.hodgkin_huxley_params
  18. excitatory_params.update(modellib.ih_params)
  19. excitatory_params.update({"E_i": -80 * mV})
  20. excitatory_neurons = br.NeuronGroup(N_E, excitatory_eqs, namespace=excitatory_params,
  21. threshold='v>0*mV', refractory='v>0*mV', method='exponential_euler')
  22. ex_input_baseline = 0.05 * nA
  23. excitatory_neurons.I = ex_input_baseline
  24. excitatory_neurons.v = modellib.hodgkin_huxley_params["El"] * np.random.normal(1, 0.1, N_E)
  25. excitatory_spike_monitor = br.SpikeMonitor(excitatory_neurons)
  26. recorded_excitatory_neuron_idx = int(N_E / 2)
  27. excitatory_trace_recorder = br.StateMonitor(excitatory_neurons, 'v', record=[recorded_excitatory_neuron_idx])
  28. excitatory_params['ghbar'] = 20. * nS
  29. '''
  30. Inhibitory neurons
  31. '''
  32. lif_interneuron_eqs = """
  33. dv/dt =1.0/tau* (-v + u_ext) :volt (unless refractory)
  34. u_ext = u_ext_const : volt
  35. """
  36. lif_interneuron_params = {
  37. "tau": 7 * ms,
  38. "v_threshold": -40 * mV,
  39. "v_reset": -60 * mV,
  40. "tau_refractory": 0.0 * ms,
  41. "u_ext_const": -50 * mV
  42. }
  43. lif_interneuron_options = {
  44. "threshold": "v>v_threshold",
  45. "reset": "v=v_reset",
  46. "refractory": "tau_refractory",
  47. 'method': 'euler'
  48. }
  49. inhibitory_neurons = br.NeuronGroup(N_I, lif_interneuron_eqs, namespace=lif_interneuron_params,
  50. **lif_interneuron_options)
  51. inhibitory_neurons.v = lif_interneuron_params["u_ext_const"]
  52. recorded_interneuron_idx = int(N_I / 2)
  53. inhibitory_trace_recorder = br.StateMonitor(inhibitory_neurons, 'v', record=[recorded_interneuron_idx])
  54. inhibitory_spike_monitor = br.SpikeMonitor(inhibitory_neurons)
  55. '''
  56. Connectivities
  57. '''
  58. # EI Profile from Brunel: every excitatory neuron projects on inhibitory neurons of the same direction with a spread
  59. # of 80 degrees
  60. def get_phase_difference(total_difference):
  61. """
  62. Map accumulated phase difference to shortest possible difference
  63. :param total_difference:
  64. :return: relative_difference
  65. """
  66. return (total_difference + np.pi) % (2 * np.pi) - np.pi
  67. ex_in_differences = np.tile(ex_angles, (N_I, 1)).T - np.tile(in_angles, (N_E, 1))
  68. ei_offset = 0
  69. ei_offset_in_rad = ei_offset / 180.0 * np.pi
  70. ei_width = 80.0 / 180.0 * np.pi
  71. ei_weight_threshold = 0.1
  72. max_excitatory_strength = 1 * mV
  73. ex_in_weights = np.exp(-(get_phase_difference((ex_in_differences + ei_offset_in_rad))) ** 2 / 2 / ei_width ** 2)
  74. ex_in_weights[np.where(ex_in_weights < ei_weight_threshold)] = 0.0
  75. ex_indices, in_indices = ex_in_weights.nonzero()
  76. ei_synapses = br.Synapses(source=excitatory_neurons, target=inhibitory_neurons, model=modellib.delta_synapse_model,
  77. on_pre=modellib.delta_synapse_on_pre, namespace=modellib.delta_synapse_param)
  78. ei_synapses.connect()
  79. for ex_idx, in_idx in zip(ex_indices, in_indices):
  80. ei_synapses.synaptic_strength[ex_idx, in_idx] = max_excitatory_strength * ex_in_weights[ex_idx, in_idx]
  81. ie_offset = 0
  82. ie_offset_in_rad = ie_offset / 180.0 * np.pi
  83. in_ex_difference = ex_in_differences.T
  84. ie_width = 160.0 / 180.0 * np.pi
  85. in_ex_weights = np.exp(
  86. -get_phase_difference(in_ex_difference + ie_offset_in_rad) ** 2 / 2 / ie_width ** 2)
  87. ie_synapses = br.Synapses(source=inhibitory_neurons, target=excitatory_neurons, model=modellib.exponential_synapse,
  88. on_pre=modellib.exponential_synapse_on_pre, namespace=modellib.exponential_synapse_params)
  89. ie_synapses.connect()
  90. ie_synapses.tau_syn = 2 * ms
  91. max_inhibitory_strength = 50 * nS
  92. in_indices, ex_indices = in_ex_weights.nonzero()
  93. for in_idx, ex_idx in zip(in_indices, ex_indices):
  94. ie_synapses.synaptic_strength[in_idx, ex_idx] = max_inhibitory_strength * in_ex_weights[in_idx, ex_idx]
  95. '''
  96. Net
  97. '''
  98. net = br.Network(excitatory_neurons)
  99. net.add(inhibitory_neurons)
  100. net.add(ei_synapses)
  101. net.add(ie_synapses)
  102. net.add(excitatory_spike_monitor)
  103. net.add(excitatory_trace_recorder)
  104. net.add(inhibitory_spike_monitor)
  105. net.add(inhibitory_trace_recorder)
  106. '''
  107. Transient head direction input
  108. '''
  109. start = 1000 * ms
  110. length = 1000 * ms
  111. phase_dispersion = 4
  112. head_direction_input_amplitude = 1 * nA
  113. def get_head_direction_input(peak_phase, phase_dispersion, excitatory_direction_preference):
  114. """
  115. Returns drive to a neuron with a certain preferred direction assuming that the input is distributed as a von Mises (
  116. Gaussian on a ring) distribution with a peak phase and an uncertainty given by the phase dispersion. Normalized
  117. to one at the peak phase.
  118. :param peak_phase:
  119. :param phase_dispersion:
  120. :param excitatory_direction_preference:
  121. :return:
  122. """
  123. head_direction_input_shape = np.exp(
  124. phase_dispersion * np.cos(excitatory_direction_preference - peak_phase)) / np.exp(phase_dispersion)
  125. return head_direction_input_shape
  126. '''
  127. Run simulation
  128. '''
  129. max_head_direction_input_amplitude = 0.5 * nA
  130. first_peak_phase = np.pi/2.0
  131. second_peak_phase = -np.pi / 2.0
  132. input_dispersion = 3
  133. length_of_input = 200 * ms
  134. length_of_pause = 500 * ms
  135. events = []
  136. events.append((0*ms, 'Start'))
  137. net.run(length_of_pause)
  138. events.append((excitatory_trace_recorder.t[-1], "Input at {:.1f}".format(first_peak_phase/np.pi*180.0)))
  139. excitatory_neurons.I = ex_input_baseline + max_head_direction_input_amplitude * get_head_direction_input(
  140. first_peak_phase,
  141. input_dispersion,
  142. ex_angles)
  143. net.run(length_of_input)
  144. events.append((excitatory_trace_recorder.t[-1], "No input".format(first_peak_phase/np.pi*180.0)))
  145. excitatory_neurons.I = ex_input_baseline
  146. net.run(length_of_pause)
  147. events.append((excitatory_trace_recorder.t[-1], "Input at {:.1f}".format(second_peak_phase/np.pi*180.0)))
  148. excitatory_neurons.I = ex_input_baseline + max_head_direction_input_amplitude * get_head_direction_input(
  149. second_peak_phase,
  150. input_dispersion,
  151. ex_angles)
  152. net.run(length_of_input)
  153. events.append((excitatory_trace_recorder.t[-1], "No input".format(first_peak_phase/np.pi*180.0)))
  154. excitatory_neurons.I = ex_input_baseline
  155. net.run(length_of_pause)
  156. ### Set synapses to zero to compare
  157. events.append((excitatory_trace_recorder.t[-1], "Set synapses to zero".format(first_peak_phase/np.pi*180.0)))
  158. ei_synapses.synaptic_strength = 0*mV
  159. net.run(length_of_pause)
  160. excitatory_neurons.I = ex_input_baseline + max_head_direction_input_amplitude * get_head_direction_input(
  161. first_peak_phase,
  162. input_dispersion,
  163. ex_angles)
  164. net.run(length_of_input)
  165. events.append((excitatory_trace_recorder.t[-1], "Input at {:.1f}".format(second_peak_phase/np.pi*180.0)))
  166. excitatory_neurons.I = ex_input_baseline
  167. net.run(length_of_pause)
  168. '''
  169. Plot
  170. '''
  171. duration = excitatory_trace_recorder.t[-1]
  172. fig, axes = plt.subplots(5, 1, sharex=True)
  173. ax_text = axes[0]
  174. for t, comment in events:
  175. ax_text.text(t/ms, 0.5, " "+comment,fontsize=12 )
  176. ax_text.axis('off')
  177. ax_ex_trace = axes[1]
  178. ax_ex_trace.plot(excitatory_trace_recorder.t / ms, excitatory_trace_recorder.v[0] / mV, 'r')
  179. ax_ex_trace.set_ylabel("V ex (mV)")
  180. ax_ex_trace.set_ylabel("E {:.0f}° (mV)".format(ex_angles[recorded_excitatory_neuron_idx]))
  181. ax_in_trace = axes[2]
  182. ax_in_trace.plot(inhibitory_trace_recorder.t / ms, inhibitory_trace_recorder.v[0] / mV, 'b')
  183. ax_in_trace.set_ylabel("I {:.0f}° (mV)".format(in_angles[recorded_interneuron_idx]))
  184. ax_ex = axes[3]
  185. ax_ex.set_ylim(-180, 180)
  186. ax_ex.set_ylabel("E angles")
  187. ax_ex_raster = ax_ex.twinx()
  188. ex_spike_trains = excitatory_spike_monitor.spike_trains()
  189. for neuron_idx, spike_times in ex_spike_trains.items():
  190. ax_ex_raster.plot(spike_times / ms, neuron_idx + 1 * np.ones(spike_times.shape), 'r|')
  191. ax_ex_raster.set_xlim(0, duration / ms)
  192. ax_ex_raster.set_ylim(0, N_E + 1)
  193. ax_ex_raster.set_ylabel("Excitatory neurons")
  194. ax_in = axes[4]
  195. ax_in.set_ylim(-180, 180)
  196. ax_in.set_ylabel("I angles")
  197. ax_in_raster = ax_in.twinx()
  198. in_spike_trains = inhibitory_spike_monitor.spike_trains()
  199. for neuron_idx, spike_times in in_spike_trains.items():
  200. ax_in_raster.plot(spike_times / ms, neuron_idx + 1 * np.ones(spike_times.shape), 'b|')
  201. ax_in_raster.set_xlim(0, duration / ms)
  202. ax_in_raster.set_ylim(0, N_I + 1)
  203. ax_in_raster.set_ylabel("Inhibitory neurons")
  204. for ax in axes:
  205. ymin, ymax = ax.get_ylim()
  206. for t, _ in events:
  207. ax.vlines(t/ms, ymin, ymax, 'k', linestyles='--' )
  208. plt.show()