Generate Models
Introduction
One can create a CompNeuroPy-model using the CompNeuroModel
class. The CompNeuroModel
class takes as one argument the model_creation_function
. In this function a classical ANNarchy model is created (populations, projections). The CompNeuroModel
class only adds a framework to the model. Neccessary for a CompNeuroPy-model is to define unique names for all populations and projections. Models are created in three steps:
- model initialization: the initialization of the
CompNeuroModel
object, initializes the framework of the model without creating the ANNarchy objects (populations, projections)
- model creation: create the ANNarchy objects (populations, projections), i.e., run the
model_creation function
- model compilation: compile all created models
Example
from CompNeuroPy import CompNeuroModel
my_model = CompNeuroModel(model_creation_function=create_model, ### the most important part, this function creates the model (populations, projections)
model_kwargs={'a':1, 'b':2}, ### define the two arguments a and b of function create_model
name='my_model', ### you can give the model a name
description='my simple example model', ### you can give the model a description
do_create=True, ### create the model directly
do_compile=True, ### let the model (and all models created before) compile directly
compile_folder_name='my_model') ### name of the saved compilation folder
The following function could be the corresponding model_creation_function:
from ANNarchy import Population, Izhikevich
def create_model(a, b):
pop = Population(geometry=a, neuron=Izhikevich, name='Izh_pop_a') ### first population, size a
pop.b = 0 ### some parameter adjustment
Population(geometry=b, neuron=Izhikevich, name='Izh_pop_b') ### second population, size b
Here, two populations are created (both use built-in Izhikevich neuron model of ANNarchy). The function does not require a return value. It is important that all populations and projections have unique names.
A more detailed example is available in the Examples.
CompNeuroPy.generate_model.CompNeuroModel
Class for creating and compiling a model.
Attributes:
Name |
Type |
Description |
name |
str
|
|
description |
str
|
|
model_creation_function |
function
|
function which creates the model
|
compile_folder_name |
str
|
name of the folder in which the model is compiled
|
model_kwargs |
dict
|
keyword arguments for model_creation_function
|
populations |
list
|
list of names of all populations of the model
|
projections |
list
|
list of names of all projections of the model
|
created |
bool
|
True if the model is created
|
compiled |
bool
|
True if the model is compiled
|
attribute_df |
pandas dataframe
|
dataframe containing all attributes of the model compartments
|
Source code in src/CompNeuroPy/generate_model.py
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405 | class CompNeuroModel:
"""
Class for creating and compiling a model.
Attributes:
name (str):
name of the model
description (str):
description of the model
model_creation_function (function):
function which creates the model
compile_folder_name (str):
name of the folder in which the model is compiled
model_kwargs (dict):
keyword arguments for model_creation_function
populations (list):
list of names of all populations of the model
projections (list):
list of names of all projections of the model
created (bool):
True if the model is created
compiled (bool):
True if the model is compiled
attribute_df (pandas dataframe):
dataframe containing all attributes of the model compartments
"""
_initialized_models = {}
_compiled_models = {}
_compiled_models_updated = False
@check_types()
def __init__(
self,
model_creation_function: Callable,
model_kwargs: dict | None = None,
name: str = "model",
description: str = "",
do_create: bool = True,
do_compile: bool = True,
compile_folder_name: str = "annarchy",
):
"""
Initializes the CompNeuroModel class.
Args:
model_creation_function (function):
Function which creates the model.
model_kwargs (dict):
Keyword arguments for model_creation_function. Default: None.
name (str):
Name of the model. Default: "model".
description (str):
Description of the model. Default: "".
do_create (bool):
If True the model is created directly. Default: True.
do_compile (bool):
If True the model is compiled directly. Default: True.
compile_folder_name (str):
Name of the folder in which the model is compiled. Default: "annarchy".
"""
self.name = name
if name == "model":
self.name = name + str(self._nr_models())
self.description = description
self.model_creation_function = model_creation_function
self.compile_folder_name = compile_folder_name
self.model_kwargs = model_kwargs
self.populations = []
self.projections = []
self.created = False
self.compiled = False
self._attribute_df = None
self._attribute_df_compiled = False
if do_create:
self.create(do_compile=do_compile, compile_folder_name=compile_folder_name)
@property
def compiled(self):
"""
True if the model is compiled.
"""
### check if ANNarchy was compiled and _compiled_models is not updated yet
if mf.annarchy_compiled() and not self._compiled_models_updated:
self._update_compiled_models()
return self._compiled_models[self.name]
@compiled.setter
def compiled(self, value):
"""
Setter for compiled property.
"""
self._compiled_models[self.name] = value
@property
def created(self):
"""
True if the model is created.
"""
return self._initialized_models[self.name]
@created.setter
def created(self, value):
"""
Setter for created property.
"""
self._initialized_models[self.name] = value
@property
def attribute_df(self):
"""
Dataframe containing all attributes of the model compartments.
"""
### check if ANNarchy was compiled and _attribute_df is not updated yet
if mf.annarchy_compiled() and not self._attribute_df_compiled:
self._update_attribute_df_weights()
return self._attribute_df
def _update_compiled_models(self):
"""
Updates _compiled_models to True for all models.
"""
### update _compiled_models
for key in self._compiled_models.keys():
self._compiled_models[key] = True
self._compiled_models_updated = True
def _update_attribute_df_weights(self):
"""
Updates _attribute_df for the weights of all projections.
"""
for proj_name in self.projections:
values = get_projection(proj_name).w
self._update_attribute_df(
compartment=proj_name, parameter_name="w", parameter_value=values
)
self._attribute_df_compiled = True
def compile(self, compile_folder_name=None):
"""
Compiles a created model.
Args:
compile_folder_name (str, optional):
Name of the folder in which the model is compiled. Default: value from
initialization.
"""
### check if this model is created
if self.created:
if compile_folder_name == None:
compile_folder_name = self.compile_folder_name
### check if other models were initialized but not created --> warn that they are not compiled
not_created_model_list = self._check_if_models_created()
if len(not_created_model_list) > 0:
print(
"\nWARNING during compile of model "
+ self.name
+ ": There are initialized models which are not created, thus not compiled! models:\n"
+ "\n".join(not_created_model_list)
+ "\n"
)
mf.compile_in_folder(compile_folder_name, silent=True)
self.compiled = True
### update attribute_df to compiled state, since weights are only available
### after compilation
self._update_attribute_df_weights()
else:
print("\n")
assert False, (
"ERROR during compile of model "
+ self.name
+ ": Only compile the model after it has been created!"
)
def create(self, do_compile=True, compile_folder_name=None):
"""
Creates a model and optionally compiles it directly.
Args:
do_compile (bool, optional):
If True the model is compiled directly. Default: True.
compile_folder_name (str, optional):
Name of the folder in which the model is compiled. Default: value from
initialization.
"""
if self.created:
print("model", self.name, "already created!")
else:
initial_existing_model = mf.get_full_model()
### create model populations and projections
if self.model_kwargs != None:
self.model_creation_function(**self.model_kwargs)
else:
self.model_creation_function()
self.created = True
### check which populations and projections have been added
post_existing_model = mf.get_full_model()
### save only added not all projections/populations
for initial_pop in initial_existing_model["populations"]:
post_existing_model["populations"].remove(initial_pop)
for initial_proj in initial_existing_model["projections"]:
post_existing_model["projections"].remove(initial_proj)
self.populations = post_existing_model["populations"]
self.projections = post_existing_model["projections"]
### check if names of populations and projections are unique
self._check_double_compartments()
### create parameter dictionary
self._attribute_df = self._get_attribute_df()
if do_compile:
self.compile(compile_folder_name)
def _check_if_models_created(self):
"""
Checks which CompNeuroPy models are created
Returns:
not_created_model_list (list):
list of names of all initialized CompNeuroPy models which are not
created yet
"""
not_created_model_list = []
for key in self._initialized_models.keys():
if self._initialized_models[key] == False:
not_created_model_list.append(key)
return not_created_model_list
def _nr_models(self):
"""
Returns:
nr_models (int):
The current number of initialized (not considering "created")
CompNeuroPy models
"""
return len(list(self._initialized_models.keys()))
def set_param(self, compartment, parameter_name, parameter_value):
"""
Sets the specified parameter of the specified compartment.
Args:
compartment (str):
name of model compartment
parameter_name (str):
name of parameter of the compartment
parameter_value (number or array-like with shape of compartment geometry):
the value or values of the parameter
Raises:
AssertionError: if model is not created
AssertionError: if compartment is neither a population nor a projection of
the model
"""
### catch if model is not created
assert (
self.created == True
), f"ERROR set_param: model {self.name} has to be created before setting parameters!"
### check if compartment is in populations or projections
comp_in_pop = compartment in self.populations
comp_in_proj = compartment in self.projections
if comp_in_pop:
comp_obj = get_population(compartment)
elif comp_in_proj:
comp_obj = get_projection(compartment)
else:
assert (
comp_in_pop or comp_in_proj
), f"ERROR set_param: setting parameter {parameter_name} of compartment {compartment}. The compartment is neither a population nor a projection of the model {self.name}!"
### set the parameter value
setattr(comp_obj, parameter_name, parameter_value)
### update the model attribute_df
self._update_attribute_df(compartment, parameter_name, parameter_value)
def _update_attribute_df(self, compartment, parameter_name, parameter_value):
"""
updates the attribute df for a specific paramter
Args:
compartment (str):
name of model compartment
parameter_name (str):
name of parameter of the compartment
parameter_value (number or array-like with shape of compartment geometry):
the value or values of the parameter
"""
paramter_mask = (
(self._attribute_df["compartment_name"] == compartment).astype(int)
* (self._attribute_df["attribute_name"] == parameter_name).astype(int)
).astype(bool)
parameter_idx = np.arange(paramter_mask.size).astype(int)[paramter_mask][0]
min_val = af.get_minimum(parameter_value)
max_val = af.get_maximum(parameter_value)
if min_val != max_val:
self._attribute_df.at[parameter_idx, "value"] = f"[{min_val}, {max_val}]"
else:
self._attribute_df.at[parameter_idx, "value"] = str(min_val)
self._attribute_df.at[parameter_idx, "definition"] = "modified"
def _check_double_compartments(self):
"""
Goes over all compartments of the model and checks if compartment is only a
population or a projection and not both.
Raises:
AssertionError: if model is not created
AssertionError: if compartment is both a population and a projection
"""
### cach if model is not created, only if created populations and projections are available
assert (
self.created == True
), f"ERROR model {self.name}: model has to be created before checking for double compartments!"
### only have to go over populations and check if they are also projections (go over projections not neccessary)
pop_in_projections_list = []
pop_in_projections = False
for pop_name in self.populations:
if pop_name in self.projections:
pop_in_projections_list.append(pop_name)
pop_in_projections = True
assert (
pop_in_projections == False
), f"ERROR model {self.name}: One or multiple compartments are both population and projection ({pop_in_projections_list}). Rename them!"
def _get_attribute_df(self):
"""
Creates a dataframe containing the attributes of all model compartments.
Returns:
attribute_df (pandas dataframe):
dataframe containing all attributes of the model compartments
Raises:
AssertionError: if model is not created
"""
### cach if model is not created, only if created populations and projections are available
assert (
self.created == True
), f"ERROR model {self.name}: model has to be created before creating paramteer dictionary!"
### create empty paramteter dict
attribute_dict = {
"compartment_type": [],
"compartment_name": [],
"attribute_name": [],
"value": [],
"definition": [],
}
### fill paramter dict with population attributes
for pop in self.populations:
for attribute in vars(get_population(pop))["attributes"]:
### store min and max of attribute
### create numpy array with getattr to use numpy min max function
values = np.array(
[getattr(get_population(pop), attribute)]
+ [getattr(get_population(pop), attribute)]
)
attribute_dict["compartment_type"].append("population")
attribute_dict["compartment_name"].append(pop)
attribute_dict["attribute_name"].append(attribute)
if values.min() != values.max():
attribute_dict["value"].append(f"[{values.min()}, {values.max()}]")
else:
attribute_dict["value"].append(str(values.min()))
attribute_dict["definition"].append("init")
### fill paramter dict with projection attributes
for proj in self.projections:
for attribute in vars(get_projection(proj))["attributes"]:
### store min and max of attribute
### create numpy array with getattr to use numpy min max function
values = np.array(
[getattr(get_projection(proj), attribute)]
+ [getattr(get_projection(proj), attribute)]
)
attribute_dict["compartment_type"].append("projection")
attribute_dict["compartment_name"].append(proj)
attribute_dict["attribute_name"].append(attribute)
if values.min() != values.max():
attribute_dict["value"].append(f"[{values.min()}, {values.max()}]")
else:
attribute_dict["value"].append(values.min())
attribute_dict["definition"].append("init")
### return dataframe
return pd.DataFrame(attribute_dict)
|
compiled
property
writable
True if the model is compiled.
created
property
writable
True if the model is created.
attribute_df
property
Dataframe containing all attributes of the model compartments.
__init__(model_creation_function, model_kwargs=None, name='model', description='', do_create=True, do_compile=True, compile_folder_name='annarchy')
Initializes the CompNeuroModel class.
Parameters:
Name |
Type |
Description |
Default |
model_creation_function |
function
|
Function which creates the model.
|
required
|
model_kwargs |
dict
|
Keyword arguments for model_creation_function. Default: None.
|
None
|
name |
str
|
Name of the model. Default: "model".
|
'model'
|
description |
str
|
Description of the model. Default: "".
|
''
|
do_create |
bool
|
If True the model is created directly. Default: True.
|
True
|
do_compile |
bool
|
If True the model is compiled directly. Default: True.
|
True
|
compile_folder_name |
str
|
Name of the folder in which the model is compiled. Default: "annarchy".
|
'annarchy'
|
Source code in src/CompNeuroPy/generate_model.py
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85 | @check_types()
def __init__(
self,
model_creation_function: Callable,
model_kwargs: dict | None = None,
name: str = "model",
description: str = "",
do_create: bool = True,
do_compile: bool = True,
compile_folder_name: str = "annarchy",
):
"""
Initializes the CompNeuroModel class.
Args:
model_creation_function (function):
Function which creates the model.
model_kwargs (dict):
Keyword arguments for model_creation_function. Default: None.
name (str):
Name of the model. Default: "model".
description (str):
Description of the model. Default: "".
do_create (bool):
If True the model is created directly. Default: True.
do_compile (bool):
If True the model is compiled directly. Default: True.
compile_folder_name (str):
Name of the folder in which the model is compiled. Default: "annarchy".
"""
self.name = name
if name == "model":
self.name = name + str(self._nr_models())
self.description = description
self.model_creation_function = model_creation_function
self.compile_folder_name = compile_folder_name
self.model_kwargs = model_kwargs
self.populations = []
self.projections = []
self.created = False
self.compiled = False
self._attribute_df = None
self._attribute_df_compiled = False
if do_create:
self.create(do_compile=do_compile, compile_folder_name=compile_folder_name)
|
compile(compile_folder_name=None)
Compiles a created model.
Parameters:
Name |
Type |
Description |
Default |
compile_folder_name |
str
|
Name of the folder in which the model is compiled. Default: value from
initialization.
|
None
|
Source code in src/CompNeuroPy/generate_model.py
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184 | def compile(self, compile_folder_name=None):
"""
Compiles a created model.
Args:
compile_folder_name (str, optional):
Name of the folder in which the model is compiled. Default: value from
initialization.
"""
### check if this model is created
if self.created:
if compile_folder_name == None:
compile_folder_name = self.compile_folder_name
### check if other models were initialized but not created --> warn that they are not compiled
not_created_model_list = self._check_if_models_created()
if len(not_created_model_list) > 0:
print(
"\nWARNING during compile of model "
+ self.name
+ ": There are initialized models which are not created, thus not compiled! models:\n"
+ "\n".join(not_created_model_list)
+ "\n"
)
mf.compile_in_folder(compile_folder_name, silent=True)
self.compiled = True
### update attribute_df to compiled state, since weights are only available
### after compilation
self._update_attribute_df_weights()
else:
print("\n")
assert False, (
"ERROR during compile of model "
+ self.name
+ ": Only compile the model after it has been created!"
)
|
create(do_compile=True, compile_folder_name=None)
Creates a model and optionally compiles it directly.
Parameters:
Name |
Type |
Description |
Default |
do_compile |
bool
|
If True the model is compiled directly. Default: True.
|
True
|
compile_folder_name |
str
|
Name of the folder in which the model is compiled. Default: value from
initialization.
|
None
|
Source code in src/CompNeuroPy/generate_model.py
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225 | def create(self, do_compile=True, compile_folder_name=None):
"""
Creates a model and optionally compiles it directly.
Args:
do_compile (bool, optional):
If True the model is compiled directly. Default: True.
compile_folder_name (str, optional):
Name of the folder in which the model is compiled. Default: value from
initialization.
"""
if self.created:
print("model", self.name, "already created!")
else:
initial_existing_model = mf.get_full_model()
### create model populations and projections
if self.model_kwargs != None:
self.model_creation_function(**self.model_kwargs)
else:
self.model_creation_function()
self.created = True
### check which populations and projections have been added
post_existing_model = mf.get_full_model()
### save only added not all projections/populations
for initial_pop in initial_existing_model["populations"]:
post_existing_model["populations"].remove(initial_pop)
for initial_proj in initial_existing_model["projections"]:
post_existing_model["projections"].remove(initial_proj)
self.populations = post_existing_model["populations"]
self.projections = post_existing_model["projections"]
### check if names of populations and projections are unique
self._check_double_compartments()
### create parameter dictionary
self._attribute_df = self._get_attribute_df()
if do_compile:
self.compile(compile_folder_name)
|
set_param(compartment, parameter_name, parameter_value)
Sets the specified parameter of the specified compartment.
Parameters:
Name |
Type |
Description |
Default |
compartment |
str
|
name of model compartment
|
required
|
parameter_name |
str
|
name of parameter of the compartment
|
required
|
parameter_value |
number or array-like with shape of compartment geometry
|
the value or values of the parameter
|
required
|
Raises:
Type |
Description |
AssertionError
|
|
AssertionError
|
if compartment is neither a population nor a projection of
the model
|
Source code in src/CompNeuroPy/generate_model.py
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291 | def set_param(self, compartment, parameter_name, parameter_value):
"""
Sets the specified parameter of the specified compartment.
Args:
compartment (str):
name of model compartment
parameter_name (str):
name of parameter of the compartment
parameter_value (number or array-like with shape of compartment geometry):
the value or values of the parameter
Raises:
AssertionError: if model is not created
AssertionError: if compartment is neither a population nor a projection of
the model
"""
### catch if model is not created
assert (
self.created == True
), f"ERROR set_param: model {self.name} has to be created before setting parameters!"
### check if compartment is in populations or projections
comp_in_pop = compartment in self.populations
comp_in_proj = compartment in self.projections
if comp_in_pop:
comp_obj = get_population(compartment)
elif comp_in_proj:
comp_obj = get_projection(compartment)
else:
assert (
comp_in_pop or comp_in_proj
), f"ERROR set_param: setting parameter {parameter_name} of compartment {compartment}. The compartment is neither a population nor a projection of the model {self.name}!"
### set the parameter value
setattr(comp_obj, parameter_name, parameter_value)
### update the model attribute_df
self._update_attribute_df(compartment, parameter_name, parameter_value)
|