From f93b5dbafbd099bb46ec27e72e8353e18111cf7d Mon Sep 17 00:00:00 2001 From: Espen Hagen <2492641+espenhgn@users.noreply.github.com> Date: Wed, 11 Jan 2023 22:44:17 +0100 Subject: [PATCH 1/5] inhomogeneous TC activity --- .../parameterization/base_network_params.py | 39 +++++++-- mesocircuit/simulation/network.py | 85 +++++++++++++++++++ scripts/parametersets.py | 35 ++++++++ 3 files changed, 153 insertions(+), 6 deletions(-) diff --git a/mesocircuit/parameterization/base_network_params.py b/mesocircuit/parameterization/base_network_params.py index 17bd5a6c..e199cbb9 100644 --- a/mesocircuit/parameterization/base_network_params.py +++ b/mesocircuit/parameterization/base_network_params.py @@ -262,12 +262,21 @@ # parameters for external stimulus # optional thalamic input # options are: - # False: thalamic neurons are created and connected, but they are not - # active - # 'poisson': persistent thalamic poisson input for a given duration to - # all thalamic neurons - # 'pulses': repetitive pulses from stimulating thalamic neurons in the - # center of the network + # False: + # thalamic neurons are created and connected, but they are not + # active + # 'poisson': + # persistent thalamic poisson input for a given duration to + # all thalamic neurons + # 'pulses': + # repetitive pulses from stimulating thalamic neurons in the + # center of the network + # 'inhomogeneous': + # create a n x n grid layer of inhomogeneous poisson processes + # connecting to the thalamac population using square masks + # of dimension L/n x L/n. The rate profile of each process + # is generated as 1/f^2 noise across the spatial and temporal + # dimensions. 'thalamic_input': False, # thalamic_input = 'poisson' @@ -289,6 +298,24 @@ # delay between the pulse spike generator and the thalamic neurons 'th_delay_pulse_generator': 1.0, + # thalamic_input = 'inhomogeneous' + # set up nx x ny grid of inhomogeneous poisson generators + # with a time-variable rate profile for each. + # number of generators across each axis: + 'th_inhomogeneous_n': 32, + # mean rate + 'th_inhomogeneous_mean': 5., + # standard deviation + 'th_inhomogeneous_std' : 5., + # start time + 'th_inhomogeneous_start': 100., + # time resolution (ms) + 'th_inhomogeneous_dt' : 1., + # period (timesteps) + 'th_inhomogeneous_nt': 500, + # repeats + 'th_inhomogeneous_repeats': 10, + # optional DC input # turn DC input on or off (True or False) 'dc_input': False, diff --git a/mesocircuit/simulation/network.py b/mesocircuit/simulation/network.py index 9e4393c1..cd0555f0 100644 --- a/mesocircuit/simulation/network.py +++ b/mesocircuit/simulation/network.py @@ -487,6 +487,71 @@ def __create_thalamic_stim_input(self): positions=nest.spatial.grid( shape=[1, 1], edge_wrap=True)) + elif self.net_dict['thalamic_input'] == 'inhomogeneous': + self.nonstationary_poisson_input_th = nest.Create( + 'inhomogeneous_poisson_generator', + positions=nest.spatial.grid( + shape=[self.net_dict['th_inhomogeneous_n']] * 2, + extent=[self.net_dict['extent']] * 2, + center=[0., 0.], + edge_wrap=True, + ), + ) + + # compute rates for each node on Rank 0 + # TODO: Move! + nt = self.net_dict['th_inhomogeneous_nt'] + nx, ny = [self.net_dict['th_inhomogeneous_n']] * 2 + if nest.Rank() == 0: + # create noise in Fourier domain: + n = np.zeros((nx, ny), dtype=complex) + x, t, y = np.meshgrid(np.arange(nx), + np.arange(nt), + np.arange(ny)) + n = np.exp( + 1j * np.random.uniform(0, 2 * np.pi, (nt, nx, ny)) + ) / (1E1 + x**2 + 1E-1 * t**2 + y**2)**2 + # transform to time domain: + nu = np.fft.ifftn(n).real + # normalize: + nu -= nu.mean() + nu /= nu.std() + # rescale: + nu *= self.net_dict['th_inhomogeneous_std'] + nu += self.net_dict['th_inhomogeneous_mean'] + # truncate and reshape: + nu[nu < 0] = 0. + nu = nu.reshape((nt, -1)) + + # store rate profiles + np.save(os.path.join(self.data_dir_circuit, 'th_inhomogeneous_nu.npy'), nu) + else: + nu = np.empty((nt, nx * ny), dtype=float) + + # broadcast + if MPI.COMM_WORLD.Get_size() > 1: + MPI.COMM_WORLD.Bcast(nu, root=0) + + # repeat the time series a certain number of times + nu = np.repeat( + nu, self.net_dict['th_inhomogeneous_repeats'], + axis=0) + times = np.arange(nu.shape[0]) * \ + self.net_dict['th_inhomogeneous_dt'] + \ + self.net_dict['th_inhomogeneous_start'] + + # set rate and time steps + for i in range(nx * ny): + nest.SetStatus( + self.nonstationary_poisson_input_th[i], + params=dict( + rate_times=times, + rate_values=nu[:, i] + ) + ) + # clear + del nu, times + return def __create_dc_stim_input(self): @@ -669,6 +734,26 @@ def __connect_thalamic_stim_input(self): nest.Connect(self.spike_pulse_input_th, self.pops[-1], conn_spec=conn_dict_pulse_th, syn_spec=syn_dict_pulse_th) + elif self.net_dict['thalamic_input'] == 'inhomogeneous': + d = self.net_dict['extent'] / self.net_dict['th_inhomogeneous_n'] + conn_spec_inhomogeneous = { + 'rule': 'fixed_indegree', + 'indegree': 1, + 'mask': { + 'rectangular': { + 'lower_left': [-d / 2, -d / 2], + 'upper_right': [d / 2, d / 2] + } + } + } + nest.Connect( + self.nonstationary_poisson_input_th, + self.pops[-1], + conn_spec=conn_spec_inhomogeneous, + ) + else: + mssg = f'self.net_dict["thalamic_input"]={self.net_dict["thalamic_input"]} not supported' # noqa 501 + raise NotImplementedError(mssg) return def __connect_dc_stim_input(self): diff --git a/scripts/parametersets.py b/scripts/parametersets.py index 5a8e9b98..3518c042 100644 --- a/scripts/parametersets.py +++ b/scripts/parametersets.py @@ -46,6 +46,22 @@ 'sys_dict': {'hpc': {'network': {'num_nodes': 16}}} }, + # inhomogeneous thalamic activity + 'mesocircuit_MAMV1_th_imhomogeneous': { + 'sim_dict': { + **local_sim_dict, + }, + 'net_dict': { + **net_dict_mesocircuit_MAMV1, + 'thalamic_input': 'inhomogeneous', + 'ext_indegree_scaling': np.array([ + [2, 0.9], # L4E + [3, 0.9], # L4I + [6, 0.9], # L6E + [7, 0.9] # L6I + ]) + }, + }, # Potjans & Diesmann (2014) microcircuit 'microcircuit_PD': { 'net_dict': { @@ -65,6 +81,25 @@ 'K_scaling': 0.5, }, }, + + # inhomogeneous thalamic activity + 'local_mesocircuit_MAMV1_th_imhomogeneous': { + 'sim_dict': { + **local_sim_dict, + }, + 'net_dict': { + **net_dict_mesocircuit_MAMV1, + 'N_scaling': 0.1, + 'K_scaling': 0.5, + 'thalamic_input': 'inhomogeneous', + 'ext_indegree_scaling': np.array([ + [2, 1], # L4E + [3, 0.9], # L4I + [6, 0.9], # L6E + [7, 0.9] # L6I + ]) + }, + }, # MAM V1 microcircuit 'microcircuit_MAMV1': { From 0f39fd53e83292911d1172b39bb21a7efe025d2c Mon Sep 17 00:00:00 2001 From: Espen Hagen <2492641+espenhgn@users.noreply.github.com> Date: Wed, 11 Jan 2023 23:05:09 +0100 Subject: [PATCH 2/5] sys_dict --- scripts/parametersets.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/scripts/parametersets.py b/scripts/parametersets.py index 3518c042..21e82ea0 100644 --- a/scripts/parametersets.py +++ b/scripts/parametersets.py @@ -48,9 +48,6 @@ # inhomogeneous thalamic activity 'mesocircuit_MAMV1_th_imhomogeneous': { - 'sim_dict': { - **local_sim_dict, - }, 'net_dict': { **net_dict_mesocircuit_MAMV1, 'thalamic_input': 'inhomogeneous', @@ -61,6 +58,7 @@ [7, 0.9] # L6I ]) }, + 'sys_dict': {'hpc': {'network': {'num_nodes': 16}}} }, # Potjans & Diesmann (2014) microcircuit 'microcircuit_PD': { From 4bda6b1d405505f7414c94f3dfd77bc3ac7a56fd Mon Sep 17 00:00:00 2001 From: Espen Hagen <2492641+espenhgn@users.noreply.github.com> Date: Fri, 13 Jan 2023 10:52:32 +0100 Subject: [PATCH 3/5] noise-generating function --- mesocircuit/simulation/network.py | 137 ++++++++++++++++++++---------- 1 file changed, 94 insertions(+), 43 deletions(-) diff --git a/mesocircuit/simulation/network.py b/mesocircuit/simulation/network.py index cd0555f0..f0b7cf0b 100644 --- a/mesocircuit/simulation/network.py +++ b/mesocircuit/simulation/network.py @@ -498,55 +498,16 @@ def __create_thalamic_stim_input(self): ), ) - # compute rates for each node on Rank 0 - # TODO: Move! - nt = self.net_dict['th_inhomogeneous_nt'] - nx, ny = [self.net_dict['th_inhomogeneous_n']] * 2 - if nest.Rank() == 0: - # create noise in Fourier domain: - n = np.zeros((nx, ny), dtype=complex) - x, t, y = np.meshgrid(np.arange(nx), - np.arange(nt), - np.arange(ny)) - n = np.exp( - 1j * np.random.uniform(0, 2 * np.pi, (nt, nx, ny)) - ) / (1E1 + x**2 + 1E-1 * t**2 + y**2)**2 - # transform to time domain: - nu = np.fft.ifftn(n).real - # normalize: - nu -= nu.mean() - nu /= nu.std() - # rescale: - nu *= self.net_dict['th_inhomogeneous_std'] - nu += self.net_dict['th_inhomogeneous_mean'] - # truncate and reshape: - nu[nu < 0] = 0. - nu = nu.reshape((nt, -1)) - - # store rate profiles - np.save(os.path.join(self.data_dir_circuit, 'th_inhomogeneous_nu.npy'), nu) - else: - nu = np.empty((nt, nx * ny), dtype=float) - - # broadcast - if MPI.COMM_WORLD.Get_size() > 1: - MPI.COMM_WORLD.Bcast(nu, root=0) - - # repeat the time series a certain number of times - nu = np.repeat( - nu, self.net_dict['th_inhomogeneous_repeats'], - axis=0) - times = np.arange(nu.shape[0]) * \ - self.net_dict['th_inhomogeneous_dt'] + \ - self.net_dict['th_inhomogeneous_start'] + # create spatiotemporally periodic filtered noise (1/f**2 like) + rates, times = self._create_th_inhomogeneous_rates_periodic_noise() # set rate and time steps - for i in range(nx * ny): + for i in range(self.net_dict['th_inhomogeneous_n']**2): nest.SetStatus( self.nonstationary_poisson_input_th[i], params=dict( rate_times=times, - rate_values=nu[:, i] + rate_values=rates[:, i] ) ) # clear @@ -554,6 +515,96 @@ def __create_thalamic_stim_input(self): return + def _create_th_inhomogeneous_rates_periodic_noise( + self, + min_denominator=1E1, + time_scaling=1E-1, + power_exponent=2, + save_rates_times=True): + '''Create rates profiles for each thalamic (or perhaps retinal) + inhomogeneous_poisson_generator node on Rank 0. + + This function returns filtered random noise in the Fourier domain + that in the time domain is periodic in both time and space + + Parameters + ---------- + min_denominator: float + positive factor added to the denominator + time_scaling: float + factor + power_exponent: float + factor + + save_rates_times: bool + if True (default), save rates and times in output dir + + Returns + ------- + rates: ndarray + shape (nt * repeats, n**2) array, where the first axis is time, + second over n x n nodes feeding into the TC parrot neuron layer + times: ndarray + shape (nt * repeats, ) ndarray of monotonically increasing + time points corresponding to each piecewise constant rate + ''' + nt = self.net_dict['th_inhomogeneous_nt'] + nx, ny = [self.net_dict['th_inhomogeneous_n']] * 2 + if nest.Rank() == 0: + # create noise in Fourier domain: + NU = np.zeros((nx, ny), dtype=complex) + x, t, y = np.meshgrid(np.arange(nx), + np.arange(nt), + np.arange(ny)) + NU = np.exp( + 1j * np.random.uniform(0, 2 * np.pi, (nt, nx, ny)) + ) / (min_denominator + x**2 + + time_scaling * t**2 + + y**2)**power_exponent + # transform to time domain: + nu = np.fft.ifftn(NU).real + # normalize: + nu -= nu.mean() + nu /= nu.std() + # rescale: + nu *= self.net_dict['th_inhomogeneous_std'] + nu += self.net_dict['th_inhomogeneous_mean'] + # truncate and reshape: + nu[nu < 0] = 0. + nu = nu.reshape((nt, -1)) + else: + nu = np.empty((nt, nx * ny), dtype=float) + + # broadcast + if MPI.COMM_WORLD.Get_size() > 1: + MPI.COMM_WORLD.Bcast(nu, root=0) + + # repeat the time series a certain number of times + nu = np.repeat( + nu, self.net_dict['th_inhomogeneous_repeats'], + axis=0) + times = np.arange(nu.shape[0]) * \ + self.net_dict['th_inhomogeneous_dt'] + \ + self.net_dict['th_inhomogeneous_start'] + + if save_rates_times: + # store rate profiles + if MPI.COMM_WORLD.Get_rank() == 0: + np.save( + os.path.join( + self.data_dir_circuit, + 'th_inhomogeneous_rates.npy'), + nu) + # store times + np.save( + os.path.join( + self.data_dir_circuit, + 'th_inhomogeneous_times.npy'), + times) + MPI.COMM_WORLD.Barrier() + + return nu, times + def __create_dc_stim_input(self): """ Creates DC generators for external stimulation if specified in ``net_dict``. From 55ec07f821b18afc9147fcbdfe80df431b423cad Mon Sep 17 00:00:00 2001 From: Espen Hagen <2492641+espenhgn@users.noreply.github.com> Date: Fri, 13 Jan 2023 10:53:51 +0100 Subject: [PATCH 4/5] fix --- mesocircuit/simulation/network.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/mesocircuit/simulation/network.py b/mesocircuit/simulation/network.py index f0b7cf0b..76c2c0e8 100644 --- a/mesocircuit/simulation/network.py +++ b/mesocircuit/simulation/network.py @@ -510,8 +510,6 @@ def __create_thalamic_stim_input(self): rate_values=rates[:, i] ) ) - # clear - del nu, times return From d073444eae898cd5105157a97c25d34a134d338b Mon Sep 17 00:00:00 2001 From: Espen Hagen <2492641+espenhgn@users.noreply.github.com> Date: Sun, 2 Apr 2023 23:43:39 +0200 Subject: [PATCH 5/5] backing up --- mesocircuit/parameterization/base_network_params.py | 8 ++++---- scripts/parametersets.py | 8 ++++---- scripts/run_mesocircuit.py | 9 +++++---- 3 files changed, 13 insertions(+), 12 deletions(-) diff --git a/mesocircuit/parameterization/base_network_params.py b/mesocircuit/parameterization/base_network_params.py index e199cbb9..ebac03f9 100644 --- a/mesocircuit/parameterization/base_network_params.py +++ b/mesocircuit/parameterization/base_network_params.py @@ -304,17 +304,17 @@ # number of generators across each axis: 'th_inhomogeneous_n': 32, # mean rate - 'th_inhomogeneous_mean': 5., + 'th_inhomogeneous_mean': -5, # standard deviation - 'th_inhomogeneous_std' : 5., + 'th_inhomogeneous_std' : 10, # start time 'th_inhomogeneous_start': 100., # time resolution (ms) 'th_inhomogeneous_dt' : 1., # period (timesteps) - 'th_inhomogeneous_nt': 500, + 'th_inhomogeneous_nt': 250, # repeats - 'th_inhomogeneous_repeats': 10, + 'th_inhomogeneous_repeats': 20, # optional DC input # turn DC input on or off (True or False) diff --git a/scripts/parametersets.py b/scripts/parametersets.py index 21e82ea0..e6bc7bcd 100644 --- a/scripts/parametersets.py +++ b/scripts/parametersets.py @@ -52,10 +52,10 @@ **net_dict_mesocircuit_MAMV1, 'thalamic_input': 'inhomogeneous', 'ext_indegree_scaling': np.array([ - [2, 0.9], # L4E - [3, 0.9], # L4I - [6, 0.9], # L6E - [7, 0.9] # L6I + #[2, 0.95], # L4E + #[3, 0.95], # L4I + [6, 0.95], # L6E + # [7, 0.95] # L6I ]) }, 'sys_dict': {'hpc': {'network': {'num_nodes': 16}}} diff --git a/scripts/run_mesocircuit.py b/scripts/run_mesocircuit.py index b0dd6991..45e61fc3 100644 --- a/scripts/run_mesocircuit.py +++ b/scripts/run_mesocircuit.py @@ -28,8 +28,9 @@ # choices. These models base on the original microcircuit # (Potjans and Diesmann, 2014) and are downscaled for execution on a laptop. -name = 'mesocircuit_MAMV1' +# name = 'mesocircuit_MAMV1' # name = 'local_mesocircuit_PD' +name = 'mesocircuit_MAMV1_th_imhomogeneous' custom_params = parametersets.ps_dicts[name] ################################################################################ @@ -65,9 +66,9 @@ jobs=[ 'network', 'analysis_and_plotting', - # 'lfp_simulation', - # 'lfp_postprocess', - # 'lfp_plotting', + #'lfp_simulation', + #'lfp_postprocess', + 'lfp_plotting', ], machine='hpc', # machine='local'