Modify the network¶
deNEST provides a convenient way of modifying the state of some units within a network with the Layer.set_state() and Network.set_state() methods
Network.set_state()andLayer.set_state()support constant, multiplicative or additive changes (change_typeparameter)- We can apply the same change for all units of the layer/population, or provide an array the same shape as the population to perform specific changes for each unit (
from_arrayparameter). The array can be directly provided or loaded from file
In this tutorial we: 1. Change the state of units within a single population with the Layer.set_state() method 1. Option 1 ('from_array' == False): provide a single value , used to change the state of all units of a layer or population 1. ‘constant’ changes 2. ‘multiplicative’ changes 3. ‘additive’ changes 1. Option 2 ('from_array' == True): provide an array of values, mapped to units in the population. You can provide 1. an NumPy array directly, or 2. the path to a NumPy array
stored on disk.
- Change the state of multiple populations at once with the
Network.set_state()method
[1]:
import nest
import yaml
from pathlib import Path
from pprint import pprint
from denest import *
import denest
[2]:
PARAMS_DIR = Path('./data/params/network')
Change the state of units within a population¶
Using Layer.set_state()
[3]:
nest.ResetKernel()
net = Network(ParamsTree.read(PARAMS_DIR/'network_tree.yml'))
net.create()
2020-06-29 12:31:19,497 [denest.network] INFO: Build N=2 ``Model`` objects
2020-06-29 12:31:19,499 [denest.network] INFO: Build N=2 ``SynapseModel`` objects
2020-06-29 12:31:19,501 [denest.network] INFO: Build N=3 ``Model`` objects
2020-06-29 12:31:19,502 [denest.network] INFO: Build N=2 ``Layer`` or ``InputLayer`` objects.
2020-06-29 12:31:19,504 [denest.utils.validation] INFO: Object `proj_1_AMPA`: params: using default value for optional parameters:
{'type': 'topological'}
2020-06-29 12:31:19,541 [denest.utils.validation] INFO: Object `proj_2_GABAA`: params: using default value for optional parameters:
{'type': 'topological'}
2020-06-29 12:31:19,550 [denest.network] INFO: Build N=2 ``ProjectionModel`` objects
2020-06-29 12:31:19,568 [denest.network] INFO: Build N=3 ``TopoProjection`` objects
2020-06-29 12:31:19,580 [denest.network] INFO: Build N=2 population recorders.
2020-06-29 12:31:19,585 [denest.network] INFO: Build N=1 projection recorders.
2020-06-29 12:31:19,591 [denest.network] INFO: Creating neuron models...
100%|██████████| 2/2 [00:00<00:00, 1960.41it/s]
2020-06-29 12:31:19,636 [denest.network] INFO: Creating synapse models...
100%|██████████| 2/2 [00:00<00:00, 1374.51it/s]
2020-06-29 12:31:19,651 [denest.network] INFO: Creating recorder models...
100%|██████████| 3/3 [00:00<00:00, 1195.64it/s]
2020-06-29 12:31:19,665 [denest.network] INFO: Creating layers...
0%| | 0/2 [00:00<?, ?it/s]/Users/tom/nest/nest-simulator-2.20.0/lib/python3.7/site-packages/nest/lib/hl_api_helper.py:127: UserWarning:
GetNodes is deprecated and will be removed in NEST 3.0. Use GIDCollection instead.
100%|██████████| 2/2 [00:00<00:00, 7.23it/s]
2020-06-29 12:31:19,947 [denest.network] INFO: Creating population recorders...
100%|██████████| 2/2 [00:00<00:00, 66.91it/s]
2020-06-29 12:31:19,982 [denest.network] INFO: Creating projection recorders...
100%|██████████| 1/1 [00:00<00:00, 293.60it/s]
2020-06-29 12:31:19,997 [denest.network] INFO: Connecting layers...
100%|██████████| 3/3 [00:00<00:00, 312.34it/s]
2020-06-29 12:31:20,012 [denest.network] INFO: Network size (including recorders and parrot neurons):
Number of nodes: 206
Number of projections: 6650
[4]:
layer_name = 'l1'
population_name = 'l1_exc'
layer = net.layers['l1']
print('layer shape: ', layer.shape)
print('population shapes: ', layer.population_shape)
layer shape: (5, 5)
population shapes: {'l1_exc': (5, 5, 4), 'l1_inh': (5, 5, 2)}
Option 1: provide a single value, used to change the state of all units of a layer or population¶
Use 'from_array'==False in in Layer.set_state().
“constant” change type¶
[5]:
nest_params = {
'V_m': -69.0,
'g_peak_AMPA': 0.2,
}
[6]:
print('Unique values for l1_exc: ', { param: set(nest.GetStatus(layer.gids(population='l1_exc'), param)) for param in nest_params.keys()} )
print('Unique values for l1_inh: ', { param: set(nest.GetStatus(layer.gids(population='l1_inh'), param)) for param in nest_params.keys()} )
Unique values for l1_exc: {'V_m': {-44.0}, 'g_peak_AMPA': {0.1}}
Unique values for l1_inh: {'V_m': {-55.0}, 'g_peak_AMPA': {0.1}}
[7]:
# Change param for a single population
layer.set_state(
nest_params=nest_params,
population_name='l1_exc',
change_type='constant',
from_array=False,
)
2020-06-29 12:31:20,467 [denest.network.layers] INFO: Layer='l1', pop='l1_exc': Applying 'constant' change, param='V_m', from single value')
2020-06-29 12:31:20,468 [denest.network.layers] INFO: Layer='l1', pop='l1_exc': Applying 'constant' change, param='g_peak_AMPA', from single value')
[8]:
print('Unique values for l1_exc: ', { param: set(nest.GetStatus(layer.gids(population='l1_exc'), param)) for param in nest_params.keys()} )
print('Unique values for l1_inh: ', { param: set(nest.GetStatus(layer.gids(population='l1_inh'), param)) for param in nest_params.keys()} )
Unique values for l1_exc: {'V_m': {-69.0}, 'g_peak_AMPA': {0.2}}
Unique values for l1_inh: {'V_m': {-55.0}, 'g_peak_AMPA': {0.1}}
[9]:
# Change param for all populations
layer.set_state(
nest_params=nest_params,
population_name=None,
# population_name='l1_inh',
change_type='constant',
from_array=False,
)
2020-06-29 12:31:21,402 [denest.network.layers] INFO: Layer='l1', pop='l1_exc': Applying 'constant' change, param='V_m', from single value')
2020-06-29 12:31:21,405 [denest.network.layers] INFO: Layer='l1', pop='l1_exc': Applying 'constant' change, param='g_peak_AMPA', from single value')
2020-06-29 12:31:22,323 [denest.network.layers] INFO: Layer='l1', pop='l1_inh': Applying 'constant' change, param='V_m', from single value')
2020-06-29 12:31:22,324 [denest.network.layers] INFO: Layer='l1', pop='l1_inh': Applying 'constant' change, param='g_peak_AMPA', from single value')
[10]:
print('Unique values for l1_exc: ', { param: set(nest.GetStatus(layer.gids(population='l1_exc'), param)) for param in nest_params.keys()} )
print('Unique values for l1_inh: ', { param: set(nest.GetStatus(layer.gids(population='l1_inh'), param)) for param in nest_params.keys()} )
Unique values for l1_exc: {'V_m': {-69.0}, 'g_peak_AMPA': {0.2}}
Unique values for l1_inh: {'V_m': {-69.0}, 'g_peak_AMPA': {0.2}}
“multiplicative” change¶
[11]:
# Double the value
nest_params = {
'g_peak_AMPA': 2.0,
}
[12]:
print('Unique values for l1_exc: ', { param: set(nest.GetStatus(layer.gids(population='l1_exc'), param)) for param in nest_params.keys()} )
print('Unique values for l1_inh: ', { param: set(nest.GetStatus(layer.gids(population='l1_inh'), param)) for param in nest_params.keys()} )
Unique values for l1_exc: {'g_peak_AMPA': {0.2}}
Unique values for l1_inh: {'g_peak_AMPA': {0.2}}
[13]:
# Change param for a single population
layer.set_state(
nest_params=nest_params,
population_name=None,
change_type='multiplicative',
from_array=False,
)
2020-06-29 12:31:23,101 [denest.network.layers] INFO: Layer='l1', pop='l1_exc': Applying 'multiplicative' change, param='g_peak_AMPA', from single value')
2020-06-29 12:31:23,890 [denest.network.layers] INFO: Layer='l1', pop='l1_inh': Applying 'multiplicative' change, param='g_peak_AMPA', from single value')
[14]:
print('Unique values for l1_exc: ', { param: set(nest.GetStatus(layer.gids(population='l1_exc'), param)) for param in nest_params.keys()} )
print('Unique values for l1_inh: ', { param: set(nest.GetStatus(layer.gids(population='l1_inh'), param)) for param in nest_params.keys()} )
Unique values for l1_exc: {'g_peak_AMPA': {0.4}}
Unique values for l1_inh: {'g_peak_AMPA': {0.4}}
“additive” change¶
[15]:
# Double the value
nest_params = {
'V_m': 5.0,
}
[16]:
print('Unique values for l1_exc: ', { param: set(nest.GetStatus(layer.gids(population='l1_exc'), param)) for param in nest_params.keys()} )
print('Unique values for l1_inh: ', { param: set(nest.GetStatus(layer.gids(population='l1_inh'), param)) for param in nest_params.keys()} )
Unique values for l1_exc: {'V_m': {-69.0}}
Unique values for l1_inh: {'V_m': {-69.0}}
[17]:
# Change param for a single population
layer.set_state(
nest_params=nest_params,
population_name=None,
change_type='additive',
from_array=False,
)
2020-06-29 12:31:24,668 [denest.network.layers] INFO: Layer='l1', pop='l1_exc': Applying 'additive' change, param='V_m', from single value')
2020-06-29 12:31:25,452 [denest.network.layers] INFO: Layer='l1', pop='l1_inh': Applying 'additive' change, param='V_m', from single value')
[18]:
print('Unique values for l1_exc: ', { param: set(nest.GetStatus(layer.gids(population='l1_exc'), param)) for param in nest_params.keys()} )
print('Unique values for l1_inh: ', { param: set(nest.GetStatus(layer.gids(population='l1_inh'), param)) for param in nest_params.keys()} )
Unique values for l1_exc: {'V_m': {-64.0}}
Unique values for l1_inh: {'V_m': {-64.0}}
Option 2: provide an array the same shape as the population¶
For more flexible setting of the state of each individual unit, use 'from_array'==True in in Layer.set_state().
This can be used to set stimulator state arbitrarily (e.g. “spike_times” of a spike generator).
We can provide the array directly¶
[19]:
# Set V_m=-70 for all units except those at location [0, 0]
pop_shape = layer.population_shapes['l1_exc']
V_m_array = -70.0 * np.ones(pop_shape)
V_m_array[0, 0, :] = -60
or load the array from file¶
The ‘input_dir’ kwarg sets the directory from which arrays are loaded
[20]:
# Set g_peak_AMPA=0.33 for all units except those at location [0, 0]
g_peak_AMPA_array = 0.33 * np.ones(pop_shape)
g_peak_AMPA_array[0, 0, :] = 1.0
# save the array to file
INPUT_DIR = Path('./data/input')
os.makedirs(INPUT_DIR, exist_ok=True)
array_path = INPUT_DIR/'g_peak_AMPA_array'
np.save(INPUT_DIR/'g_peak_AMPA_array', g_peak_AMPA_array)
np.load(INPUT_DIR/'g_peak_AMPA_array.npy').shape
[20]:
(5, 5, 4)
[21]:
# We provide either the array or the path to an array, relative to the 'input_dir' directory
nest_params = {
'V_m': V_m_array,
'g_peak_AMPA': Path('./g_peak_AMPA_array.npy'),
}
[22]:
print('Unique values for l1_exc: ', { param: set(nest.GetStatus(layer.gids(population='l1_exc'), param)) for param in nest_params.keys()} )
Unique values for l1_exc: {'V_m': {-64.0}, 'g_peak_AMPA': {0.4}}
[23]:
# Change param for a single population
layer.set_state(
nest_params=nest_params,
input_dir=INPUT_DIR,
population_name='l1_exc',
change_type='constant',
from_array=True,
)
2020-06-29 12:31:26,349 [denest.network.layers] INFO: Layer='l1', pop='l1_exc': Applying 'constant' change, param='V_m', from array')
2020-06-29 12:31:26,352 [denest.network.layers] INFO: Layer='l1', pop='l1_exc': Applying 'constant' change, param='g_peak_AMPA', from array')
[24]:
print('Unique values for l1_exc at location [0, 0]: ', { param: set(nest.GetStatus(layer.gids(population='l1_exc', location=(0, 0)), param)) for param in nest_params.keys()} )
print('Unique values for l1_exc at all locations: ', { param: set(nest.GetStatus(layer.gids(population='l1_exc'), param)) for param in nest_params.keys()} )
Unique values for l1_exc at location [0, 0]: {'V_m': {-60.0}, 'g_peak_AMPA': {1.0}}
Unique values for l1_exc at all locations: {'V_m': {-70.0, -60.0}, 'g_peak_AMPA': {0.33, 1.0}}
Change the state of units throughout the network¶
Using Network.set_state(), we can specify modifications for multiple populations at once.
[25]:
# Set the input layer rates:
input_layer = net.layers['input_layer']
input_layer_shape = input_layer.population_shapes[
input_layer.stimulator_model
]
# Build the spike times for each unit
spike_times = np.empty(input_layer_shape, dtype=np.object)
# Set the same spike times for all units...
for idx, _ in np.ndenumerate(spike_times):
spike_times[idx] = [1.0, 10.0]
# Except one unit
idx = (0, 0, 0)
spike_times[idx] = [5.0]
print(spike_times[:,:,0])
[[list([5.0]) list([1.0, 10.0]) list([1.0, 10.0]) list([1.0, 10.0])
list([1.0, 10.0])]
[list([1.0, 10.0]) list([1.0, 10.0]) list([1.0, 10.0]) list([1.0, 10.0])
list([1.0, 10.0])]
[list([1.0, 10.0]) list([1.0, 10.0]) list([1.0, 10.0]) list([1.0, 10.0])
list([1.0, 10.0])]
[list([1.0, 10.0]) list([1.0, 10.0]) list([1.0, 10.0]) list([1.0, 10.0])
list([1.0, 10.0])]
[list([1.0, 10.0]) list([1.0, 10.0]) list([1.0, 10.0]) list([1.0, 10.0])
list([1.0, 10.0])]]
[26]:
net.set_state(
[
{
'layers': ['l1'],
'population_name': None,
'change_type': 'constant',
'from_array': False,
'nest_params': {
'V_m': -69.9
}
},
{
'layers': ['input_layer'],
'population_name': 'spike_generator',
'change_type': 'constant',
'from_array': True,
'nest_params': {
'spike_times': spike_times,
}
},
]
)
2020-06-29 12:31:27,372 [denest.network.layers] INFO: Layer='input_layer', pop='spike_generator': Applying 'constant' change, param='spike_times', from array')
2020-06-29 12:31:27,445 [denest.network.layers] INFO: Layer='l1', pop='l1_exc': Applying 'constant' change, param='V_m', from single value')
2020-06-29 12:31:28,266 [denest.network.layers] INFO: Layer='l1', pop='l1_inh': Applying 'constant' change, param='V_m', from single value')
[27]:
# Get status of spike generators
print(
nest.GetStatus(net.layers['input_layer'].gids(population='spike_generator'), 'spike_times')
)
(array([5.]), array([ 1., 10.]), array([ 1., 10.]), array([ 1., 10.]), array([ 1., 10.]), array([ 1., 10.]), array([ 1., 10.]), array([ 1., 10.]), array([ 1., 10.]), array([ 1., 10.]), array([ 1., 10.]), array([ 1., 10.]), array([ 1., 10.]), array([ 1., 10.]), array([ 1., 10.]), array([ 1., 10.]), array([ 1., 10.]), array([ 1., 10.]), array([ 1., 10.]), array([ 1., 10.]), array([ 1., 10.]), array([ 1., 10.]), array([ 1., 10.]), array([ 1., 10.]), array([ 1., 10.]))
[28]:
# Get status of l1 units
print(
nest.GetStatus(net.layers['l1'].gids(), 'V_m')
)
(-69.9, -69.9, -69.9, -69.9, -69.9, -69.9, -69.9, -69.9, -69.9, -69.9, -69.9, -69.9, -69.9, -69.9, -69.9, -69.9, -69.9, -69.9, -69.9, -69.9, -69.9, -69.9, -69.9, -69.9, -69.9, -69.9, -69.9, -69.9, -69.9, -69.9, -69.9, -69.9, -69.9, -69.9, -69.9, -69.9, -69.9, -69.9, -69.9, -69.9, -69.9, -69.9, -69.9, -69.9, -69.9, -69.9, -69.9, -69.9, -69.9, -69.9, -69.9, -69.9, -69.9, -69.9, -69.9, -69.9, -69.9, -69.9, -69.9, -69.9, -69.9, -69.9, -69.9, -69.9, -69.9, -69.9, -69.9, -69.9, -69.9, -69.9, -69.9, -69.9, -69.9, -69.9, -69.9, -69.9, -69.9, -69.9, -69.9, -69.9, -69.9, -69.9, -69.9, -69.9, -69.9, -69.9, -69.9, -69.9, -69.9, -69.9, -69.9, -69.9, -69.9, -69.9, -69.9, -69.9, -69.9, -69.9, -69.9, -69.9, -69.9, -69.9, -69.9, -69.9, -69.9, -69.9, -69.9, -69.9, -69.9, -69.9, -69.9, -69.9, -69.9, -69.9, -69.9, -69.9, -69.9, -69.9, -69.9, -69.9, -69.9, -69.9, -69.9, -69.9, -69.9, -69.9, -69.9, -69.9, -69.9, -69.9, -69.9, -69.9, -69.9, -69.9, -69.9, -69.9, -69.9, -69.9, -69.9, -69.9, -69.9, -69.9, -69.9, -69.9, -69.9, -69.9, -69.9, -69.9, -69.9, -69.9)