BOLD monitoring
BOLD monitoring utilities are provided in the module ANNarchy.extensions.bold
, which must be explicitly imported:
from ANNarchy import *
from ANNarchy.extensions.bold import BoldMonitor
ANNarchy.extensions.bold.BoldMonitor
:copyright: Copyright 2013 - now, see AUTHORS.
:license: GPLv2, see LICENSE for details.
BoldMonitor
Bases: object
Monitors the BOLD signal for several populations using a computational model.
The BOLD monitor transforms one or two input population variables (such as the mean firing rate) into a recordable BOLD signal according to a computational model (for example a variation of the Balloon model).
Source code in ANNarchy/extensions/bold/BoldMonitor.py
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 | class BoldMonitor(object):
"""
Monitors the BOLD signal for several populations using a computational model.
The BOLD monitor transforms one or two input population variables (such as the mean firing rate) into a recordable BOLD signal according to a computational model (for example a variation of the Balloon model).
"""
def __init__(self,
populations=None,
bold_model=balloon_RN,
mapping={'I_CBF': 'r'},
scale_factor=None,
normalize_input=None,
recorded_variables=None,
start=False,
net_id=0,
copied=False):
"""
:param populations: list of recorded populations.
:param bold_model: computational model for BOLD signal defined as a BoldModel class/object (see ANNarchy.extensions.bold.PredefinedModels for more predefined examples). Default is `balloon_RN`.
:param mapping: mapping dictionary between the inputs of the BOLD model (`I_CBF` for single inputs, `I_CBF` and `I_CMRO2` for double inputs in the provided examples) and the variables of the input populations. By default, `{'I_CBF': 'r'}` maps the firing rate `r` of the input population(s) to the variable `I_CBF` of the BOLD model.
:param scale_factor: list of float values to allow a weighting of signals between populations. By default, the input signal is weighted by the ratio of the population size to all populations within the recorded region.
:param normalize_input: list of integer values which represent a optional baseline per population. The input signals will require an additional normalization using a baseline value. A value different from 0 represents the time period for determing this baseline in milliseconds (biological time).
:param recorded_variables: which variables of the BOLD model should be recorded? (by default, the output variable of the BOLD model is added, e.g. ["BOLD"] for the provided examples).
"""
self.net_id = net_id
# instantiate if necessary, please note
# that population will make a deepcopy on this objects
if inspect.isclass(bold_model):
bold_model = bold_model()
# for reporting
bold_model._model_instantiated = True
# The usage of [] as default arguments in the __init__ call lead to strange side effects.
# We decided therefore to use None as default and create the lists locally.
if populations is None:
Global._error("Either a population or a list of populations must be provided to the BOLD monitor (populations=...)")
if scale_factor is None:
scale_factor = []
if normalize_input is None:
normalize_input = []
if recorded_variables is None:
recorded_variables = []
# argument check
if not(isinstance(populations, list)):
populations = [populations]
if not(isinstance(scale_factor, list)):
scale_factor = [scale_factor]*len(populations)
if not(isinstance(normalize_input, list)):
normalize_input = [normalize_input]*len(populations)
if isinstance(recorded_variables, str):
recorded_variables = [recorded_variables]
if len(scale_factor) > 0:
if len(populations) != len(scale_factor):
Global._error("BoldMonitor: Length of scale_factor must be equal to number of populations")
if len(normalize_input) > 0:
if len(populations) != len(normalize_input):
Global._error("BoldMonitor: Length of normalize_input must be equal to number of populations")
# Check mapping
for target, input_var in mapping.items():
if not target in bold_model._inputs:
Global._error("BoldMonitor: the key " + target + " of mapping is not part of the BOLD model.")
# Check recorded variables
if len(recorded_variables) == 0:
recorded_variables = bold_model._output
else:
# Add the output variables (and remove doublons)
l1 = bold_model._output
l2 = [recorded_variables] if isinstance(recorded_variables, str) else recorded_variables
recorded_variables = list(set(l2+l1))
recorded_variables.sort()
if not copied:
# Add the container to the object management
Global._network[0]['extensions'].append(self)
self.id = len(Global._network[self.net_id]['extensions'])
# create the population
self._bold_pop = Population(1, neuron=bold_model, name= bold_model.name )
self._bold_pop.enabled = start
# create the monitor
self._monitor = Monitor(self._bold_pop, recorded_variables, start=start)
# create the projection(s)
self._acc_proj = []
if len(scale_factor) == 0:
pop_overall_size = 0
for _, pop in enumerate(populations):
pop_overall_size += pop.size
# the conductance is normalized between [0 .. 1]. This scale factor
# should balance different population sizes
for _, pop in enumerate(populations):
scale_factor_conductance = float(pop.size)/float(pop_overall_size)
scale_factor.append(scale_factor_conductance)
if len(normalize_input) == 0:
normalize_input = [0] * len(populations)
# TODO: can we check if users used NormProjections? If not, this will crash ...
for target, input_var in mapping.items():
for pop, scale, normalize in zip(populations, scale_factor, normalize_input):
tmp_proj = AccProjection(pre = pop, post=self._bold_pop, target=target, variable=input_var, scale_factor=scale, normalize_input=normalize)
tmp_proj.connect_all_to_all(weights= 1.0)
self._acc_proj.append(tmp_proj)
else:
# Add the container to the object management
Global._network[net_id]['extensions'].append(self)
self.id = len(Global._network[self.net_id]['extensions'])
# instances are assigned by the copying instance
self._bold_pop = None
self._monitor = None
self._acc_proj = []
self.name = "bold_monitor"
# store arguments for copy
self._populations = populations
self._bold_model = bold_model
self._mapping = mapping
self._scale_factor = scale_factor
self._normalize_input = normalize_input
self._recorded_variables = recorded_variables
self._start = start
# Finalize initialization
self._initialized = True if not copied else False
#
# MONITOR functions
#
def start(self):
"""
Same as `ANNarchy.core.Monitor.start()`
"""
self._monitor.start()
# enable ODEs
self._bold_pop.cyInstance.activate(True)
# check if we have projections with baseline
for proj in self._acc_proj:
if proj._normalize_input > 0:
proj.cyInstance.start(proj._normalize_input/Global.config["dt"])
def stop(self):
"""
Same as `ANNarchy.core.Monitor.stop()`
"""
self._monitor.stop()
# enable ODEs
self._bold_pop.cyInstance.activate(False)
def get(self, variable):
"""
Same as `ANNarchy.core.Monitor.get()`
"""
return self._monitor.get(variable)
#
# POPULATION functions i. e. access to model parameter
#
# Method called when accessing an attribute.
# We overload the default to allow access to monitor variables.
def __getattr__(self, name):
if name == '_initialized' or not hasattr(self, '_initialized'): # Before the end of the constructor
return object.__getattribute__(self, name)
if self._initialized:
if self._bold_pop.initialized == False:
Global._error("BoldMonitor: attributes can not modified before compile()")
if name in self._bold_pop.attributes:
return getattr(self._bold_pop, name)
return object.__getattribute__(self, name)
# Method called when accessing an attribute.
# We overload the default to allow access to monitor variables.
def __setattr__(self, name, value):
if name == '_initialized' or not hasattr(self, '_initialized'): # Before the end of the constructor
return object.__setattr__(self, name, value)
if self._initialized:
if self._bold_pop.initialized == False:
Global._error("BoldMonitor: attributes can not modified before compile()")
if name in self._bold_pop.attributes:
setattr(self._bold_pop, name, value)
else:
raise AttributeError("the variable '"+str(name)+ "' is not an attribute of the bold model.")
else:
object.__setattr__(self, name, value)
#
# Destruction
def _clear(self):
pass
|
__init__(populations=None, bold_model=balloon_RN, mapping={'I_CBF': 'r'}, scale_factor=None, normalize_input=None, recorded_variables=None, start=False, net_id=0, copied=False)
Parameters:
-
populations
–
list of recorded populations.
-
bold_model
–
computational model for BOLD signal defined as a BoldModel class/object (see ANNarchy.extensions.bold.PredefinedModels for more predefined examples). Default is balloon_RN
.
-
mapping
–
mapping dictionary between the inputs of the BOLD model (I_CBF
for single inputs, I_CBF
and I_CMRO2
for double inputs in the provided examples) and the variables of the input populations. By default, {'I_CBF': 'r'}
maps the firing rate r
of the input population(s) to the variable I_CBF
of the BOLD model.
-
scale_factor
–
list of float values to allow a weighting of signals between populations. By default, the input signal is weighted by the ratio of the population size to all populations within the recorded region.
-
normalize_input
–
list of integer values which represent a optional baseline per population. The input signals will require an additional normalization using a baseline value. A value different from 0 represents the time period for determing this baseline in milliseconds (biological time).
-
recorded_variables
–
which variables of the BOLD model should be recorded? (by default, the output variable of the BOLD model is added, e.g. ["BOLD"] for the provided examples).
Source code in ANNarchy/extensions/bold/BoldMonitor.py
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 | def __init__(self,
populations=None,
bold_model=balloon_RN,
mapping={'I_CBF': 'r'},
scale_factor=None,
normalize_input=None,
recorded_variables=None,
start=False,
net_id=0,
copied=False):
"""
:param populations: list of recorded populations.
:param bold_model: computational model for BOLD signal defined as a BoldModel class/object (see ANNarchy.extensions.bold.PredefinedModels for more predefined examples). Default is `balloon_RN`.
:param mapping: mapping dictionary between the inputs of the BOLD model (`I_CBF` for single inputs, `I_CBF` and `I_CMRO2` for double inputs in the provided examples) and the variables of the input populations. By default, `{'I_CBF': 'r'}` maps the firing rate `r` of the input population(s) to the variable `I_CBF` of the BOLD model.
:param scale_factor: list of float values to allow a weighting of signals between populations. By default, the input signal is weighted by the ratio of the population size to all populations within the recorded region.
:param normalize_input: list of integer values which represent a optional baseline per population. The input signals will require an additional normalization using a baseline value. A value different from 0 represents the time period for determing this baseline in milliseconds (biological time).
:param recorded_variables: which variables of the BOLD model should be recorded? (by default, the output variable of the BOLD model is added, e.g. ["BOLD"] for the provided examples).
"""
self.net_id = net_id
# instantiate if necessary, please note
# that population will make a deepcopy on this objects
if inspect.isclass(bold_model):
bold_model = bold_model()
# for reporting
bold_model._model_instantiated = True
# The usage of [] as default arguments in the __init__ call lead to strange side effects.
# We decided therefore to use None as default and create the lists locally.
if populations is None:
Global._error("Either a population or a list of populations must be provided to the BOLD monitor (populations=...)")
if scale_factor is None:
scale_factor = []
if normalize_input is None:
normalize_input = []
if recorded_variables is None:
recorded_variables = []
# argument check
if not(isinstance(populations, list)):
populations = [populations]
if not(isinstance(scale_factor, list)):
scale_factor = [scale_factor]*len(populations)
if not(isinstance(normalize_input, list)):
normalize_input = [normalize_input]*len(populations)
if isinstance(recorded_variables, str):
recorded_variables = [recorded_variables]
if len(scale_factor) > 0:
if len(populations) != len(scale_factor):
Global._error("BoldMonitor: Length of scale_factor must be equal to number of populations")
if len(normalize_input) > 0:
if len(populations) != len(normalize_input):
Global._error("BoldMonitor: Length of normalize_input must be equal to number of populations")
# Check mapping
for target, input_var in mapping.items():
if not target in bold_model._inputs:
Global._error("BoldMonitor: the key " + target + " of mapping is not part of the BOLD model.")
# Check recorded variables
if len(recorded_variables) == 0:
recorded_variables = bold_model._output
else:
# Add the output variables (and remove doublons)
l1 = bold_model._output
l2 = [recorded_variables] if isinstance(recorded_variables, str) else recorded_variables
recorded_variables = list(set(l2+l1))
recorded_variables.sort()
if not copied:
# Add the container to the object management
Global._network[0]['extensions'].append(self)
self.id = len(Global._network[self.net_id]['extensions'])
# create the population
self._bold_pop = Population(1, neuron=bold_model, name= bold_model.name )
self._bold_pop.enabled = start
# create the monitor
self._monitor = Monitor(self._bold_pop, recorded_variables, start=start)
# create the projection(s)
self._acc_proj = []
if len(scale_factor) == 0:
pop_overall_size = 0
for _, pop in enumerate(populations):
pop_overall_size += pop.size
# the conductance is normalized between [0 .. 1]. This scale factor
# should balance different population sizes
for _, pop in enumerate(populations):
scale_factor_conductance = float(pop.size)/float(pop_overall_size)
scale_factor.append(scale_factor_conductance)
if len(normalize_input) == 0:
normalize_input = [0] * len(populations)
# TODO: can we check if users used NormProjections? If not, this will crash ...
for target, input_var in mapping.items():
for pop, scale, normalize in zip(populations, scale_factor, normalize_input):
tmp_proj = AccProjection(pre = pop, post=self._bold_pop, target=target, variable=input_var, scale_factor=scale, normalize_input=normalize)
tmp_proj.connect_all_to_all(weights= 1.0)
self._acc_proj.append(tmp_proj)
else:
# Add the container to the object management
Global._network[net_id]['extensions'].append(self)
self.id = len(Global._network[self.net_id]['extensions'])
# instances are assigned by the copying instance
self._bold_pop = None
self._monitor = None
self._acc_proj = []
self.name = "bold_monitor"
# store arguments for copy
self._populations = populations
self._bold_model = bold_model
self._mapping = mapping
self._scale_factor = scale_factor
self._normalize_input = normalize_input
self._recorded_variables = recorded_variables
self._start = start
# Finalize initialization
self._initialized = True if not copied else False
|
get(variable)
Same as ANNarchy.core.Monitor.get()
Source code in ANNarchy/extensions/bold/BoldMonitor.py
| def get(self, variable):
"""
Same as `ANNarchy.core.Monitor.get()`
"""
return self._monitor.get(variable)
|
start()
Same as ANNarchy.core.Monitor.start()
Source code in ANNarchy/extensions/bold/BoldMonitor.py
164
165
166
167
168
169
170
171
172
173
174
175
176 | def start(self):
"""
Same as `ANNarchy.core.Monitor.start()`
"""
self._monitor.start()
# enable ODEs
self._bold_pop.cyInstance.activate(True)
# check if we have projections with baseline
for proj in self._acc_proj:
if proj._normalize_input > 0:
proj.cyInstance.start(proj._normalize_input/Global.config["dt"])
|
stop()
Same as ANNarchy.core.Monitor.stop()
Source code in ANNarchy/extensions/bold/BoldMonitor.py
178
179
180
181
182
183
184
185 | def stop(self):
"""
Same as `ANNarchy.core.Monitor.stop()`
"""
self._monitor.stop()
# enable ODEs
self._bold_pop.cyInstance.activate(False)
|
BOLD models
The provided BOLD models follow the Balloon model (Buxton et al., 1998) with the different variations studied in (Stephan et al., 2007). Those models all compute the vascular response to neural activity through a dampened oscillator:
\[
\frac{ds}{dt} = \phi \, I_\text{CBF} - \kappa \, s - \gamma \, (f_{in} - 1)
\]
\[
\frac{df_{in}}{dt} = s
\]
This allows to compute the oxygen extraction fraction:
\[
E = 1 - (1 - E_{0})^{ \frac{1}{f_{in}} }
\]
The (normalized) venous blood volume is computed as:
\[
\tau_0 \, \frac{dv}{dt} = (f_{in} - f_{out})
\]
\[
f_{out} = v^{\frac{1}{\alpha}}
\]
The level of deoxyhemoglobin into the venous compartment is computed by:
\[
\tau_0 \, \frac{dq}{dt} = f_{in} \, \frac{E}{E_0} - \frac{q}{v} \, f_{out}
\]
Using the two signals \(v\) and \(q\), there are two ways to compute the corresponding BOLD signal:
- N: Non-linear BOLD equation:
\[
BOLD = v_0 \, ( k_1 \, (1-q) + k_2 \, (1- \dfrac{q}{v}) + k_3 \, (1 - v) )
\]
\[
BOLD = v_0 \, ((k_1 + k_2) \, (1 - q) + (k_3 - k_2) \, (1 - v))
\]
Additionally, the three coefficients \(k_1\), \(k_2\), \(k_3\) can be computed in two different ways:
- C: classical coefficients from (Buxton et al., 1998):
\[k_1 = (1 - v_0) \, 4.3 \, v_0 \, E_0 \, \text{TE}\]
\[k_2 = 2 \, E_0\]
\[k_3 = 1 - \epsilon\]
- R: revised coefficients from (Obata et al., 2004):
\[k_1 = 4.3 \, v_0 \, E_0 \, \text{TE}\]
\[k_2 = \epsilon \, r_0 \, E_0 \, \text{TE}\]
\[k_3 = 1 - \epsilon\]
This makes a total of four different BOLD model (RN, RL, CN, CL) which are provided by the extension. The different parameters can be modified in the constructor. Additionally, we also provide the model that was used in (Maith et al., 2021) and the two-inputs model of (Maith et al, 2022).
ANNarchy.extensions.bold.BoldModel
:copyright: Copyright 2013 - now, see AUTHORS.
:license: GPLv2, see LICENSE for details.
BoldModel
Bases: Neuron
Base class to define a BOLD model to be used in a BOLD monitor.
A BOLD model is quite similar to a regular rate-coded neuron. It gets a weighted sum of inputs with a specific target (e.g. I_CBF) and compute a single output variable (called BOLD
in the predefined models, but it could be anything).
The main difference is that a BOLD model should also declare which targets are used for the input signal:
bold_model = BoldModel(
parameters = '''
tau = 1000.
''',
equations = '''
I_CBF = sum(I_CBF)
# ...
tau * dBOLD/dt = I_CBF - BOLD
''',
inputs = "I_CBF"
)
Source code in ANNarchy/extensions/bold/BoldModel.py
8
9
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 | class BoldModel(Neuron):
"""
Base class to define a BOLD model to be used in a BOLD monitor.
A BOLD model is quite similar to a regular rate-coded neuron. It gets a weighted sum of inputs with a specific target (e.g. I_CBF) and compute a single output variable (called `BOLD` in the predefined models, but it could be anything).
The main difference is that a BOLD model should also declare which targets are used for the input signal:
```python
bold_model = BoldModel(
parameters = '''
tau = 1000.
''',
equations = '''
I_CBF = sum(I_CBF)
# ...
tau * dBOLD/dt = I_CBF - BOLD
''',
inputs = "I_CBF"
)
```
"""
def __init__(self, parameters, equations, inputs, output=["BOLD"], name="Custom BOLD model", description=""):
"""
See ANNarchy.extensions.bold.PredefinedModels.py for some example models.
:param parameters: parameters of the model and their initial value.
:param equations: equations defining the temporal evolution of variables.
:param inputs: single variable or list of input signals (e.g. 'I_CBF' or ['I_CBF', 'I_CMRO2']).
:param output: output variable of the model (default is 'BOLD').
:param name: optional model name.
:param description: optional model description.
"""
# The processing in BoldMonitor expects lists, but the interface
# should allow also single strings (if only one variable is considered)
self._inputs = [inputs] if isinstance(inputs, str) else inputs
self._output = [output] if isinstance(output, str) else output
Neuron.__init__(self, parameters=parameters, equations=equations, name=name, description=description)
self._model_instantiated = False # activated by BoldMonitor
|
__init__(parameters, equations, inputs, output=['BOLD'], name='Custom BOLD model', description='')
See ANNarchy.extensions.bold.PredefinedModels.py for some example models.
Parameters:
-
parameters
–
parameters of the model and their initial value.
-
equations
–
equations defining the temporal evolution of variables.
-
inputs
–
single variable or list of input signals (e.g. 'I_CBF' or ['I_CBF', 'I_CMRO2']).
-
output
–
output variable of the model (default is 'BOLD').
-
name
–
-
description
–
optional model description.
Source code in ANNarchy/extensions/bold/BoldModel.py
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48 | def __init__(self, parameters, equations, inputs, output=["BOLD"], name="Custom BOLD model", description=""):
"""
See ANNarchy.extensions.bold.PredefinedModels.py for some example models.
:param parameters: parameters of the model and their initial value.
:param equations: equations defining the temporal evolution of variables.
:param inputs: single variable or list of input signals (e.g. 'I_CBF' or ['I_CBF', 'I_CMRO2']).
:param output: output variable of the model (default is 'BOLD').
:param name: optional model name.
:param description: optional model description.
"""
# The processing in BoldMonitor expects lists, but the interface
# should allow also single strings (if only one variable is considered)
self._inputs = [inputs] if isinstance(inputs, str) else inputs
self._output = [output] if isinstance(output, str) else output
Neuron.__init__(self, parameters=parameters, equations=equations, name=name, description=description)
self._model_instantiated = False # activated by BoldMonitor
|
ANNarchy.extensions.bold.balloon_RN
Bases: BoldModel
A balloon model with revised coefficients and non-linear BOLD equation derived from Stephan et al. (2007).
Equivalent code:
balloon_RN = BoldModel(
parameters = '''
second = 1000.0
phi = 1.0
kappa = 1/1.54
gamma = 1/2.46
E_0 = 0.34
tau = 0.98
alpha = 0.33
V_0 = 0.02
v_0 = 40.3
TE = 40/1000.
epsilon = 1.43
r_0 = 25.
''',
equations = '''
# Single input
I_CBF = sum(I_CBF) : init=0
ds/dt = (phi * I_CBF - kappa * s - gamma * (f_in - 1))/second : init=0
df_in/dt = s / second : init=1, min=0.01
E = 1 - (1 - E_0)**(1 / f_in) : init=0.3424
dq/dt = (f_in * E / E_0 - (q / v) * f_out)/(tau*second) : init=1, min=0.01
dv/dt = (f_in - f_out)/(tau*second) : init=1, min=0.01
f_out = v**(1 / alpha) : init=1, min=0.01
# Revised coefficients
k_1 = 4.3 * v_0 * E_0 * TE
k_2 = epsilon * r_0 * E_0 * TE
k_3 = 1.0 - epsilon
# Non-linear equation
BOLD = V_0 * (k_1 * (1 - q) + k_2 * (1 - (q / v)) + k_3 * (1 - v)) : init=0
''',
inputs="I_CBF",
)
Source code in ANNarchy/extensions/bold/PredefinedModels.py
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 | class balloon_RN(BoldModel):
"""
A balloon model with revised coefficients and non-linear BOLD equation derived from Stephan et al. (2007).
Equivalent code:
```python
balloon_RN = BoldModel(
parameters = '''
second = 1000.0
phi = 1.0
kappa = 1/1.54
gamma = 1/2.46
E_0 = 0.34
tau = 0.98
alpha = 0.33
V_0 = 0.02
v_0 = 40.3
TE = 40/1000.
epsilon = 1.43
r_0 = 25.
''',
equations = '''
# Single input
I_CBF = sum(I_CBF) : init=0
ds/dt = (phi * I_CBF - kappa * s - gamma * (f_in - 1))/second : init=0
df_in/dt = s / second : init=1, min=0.01
E = 1 - (1 - E_0)**(1 / f_in) : init=0.3424
dq/dt = (f_in * E / E_0 - (q / v) * f_out)/(tau*second) : init=1, min=0.01
dv/dt = (f_in - f_out)/(tau*second) : init=1, min=0.01
f_out = v**(1 / alpha) : init=1, min=0.01
# Revised coefficients
k_1 = 4.3 * v_0 * E_0 * TE
k_2 = epsilon * r_0 * E_0 * TE
k_3 = 1.0 - epsilon
# Non-linear equation
BOLD = V_0 * (k_1 * (1 - q) + k_2 * (1 - (q / v)) + k_3 * (1 - v)) : init=0
''',
inputs="I_CBF",
)
```
"""
def __init__(self,
phi = 1.0,
kappa = 1/1.54,
gamma = 1/2.46,
E_0 = 0.34,
tau = 0.98,
alpha = 0.33,
V_0 = 0.02,
v_0 = 40.3,
TE = 40/1000.,
epsilon = 1.43,
r_0 = 25,
):
"""
:param phi: input coefficient
:param kappa: signal decay
:param gamma: feedback regulation
:param E_0: oxygen extraction fraction at rest
:param tau: time constant (in s!)
:param alpha: vessel stiffness
:param V_0: resting venous blood volume fraction
:param v_0: frequency offset at the outer surface of the magnetized vessel for fully deoxygenated blood at 1.5 T
:param TE: echo time
:param epsilon: ratio of intra- and extravascular signal
:param r_0: slope of the relation between the intravascular relaxation rate and oxygen saturation
"""
parameters = """
second = 1000.0 : population
phi = %(phi)s : population
kappa = %(kappa)s : population
gamma = %(gamma)s : population
E_0 = %(E_0)s : population
tau = %(tau)s : population
alpha = %(alpha)s : population
V_0 = %(V_0)s : population
v_0 = %(v_0)s : population
TE = %(TE)s : population
epsilon = %(epsilon)s : population
r_0 = %(r_0)s : population
""" % {
'phi': phi,
'kappa': kappa,
'gamma': gamma,
'E_0': E_0,
'tau': tau,
'alpha': alpha,
'V_0': V_0,
'v_0': v_0,
'TE': TE,
'epsilon': epsilon,
'r_0': r_0,
}
equations = """
# Single input
I_CBF = sum(I_CBF) : init=0
ds/dt = (phi * I_CBF - kappa * s - gamma * (f_in - 1))/second : init=0
df_in/dt = s / second : init=1, min=0.01
E = 1 - (1 - E_0)**(1 / f_in) : init=0.3424
dq/dt = (f_in * E / E_0 - (q / v) * f_out)/(tau*second) : init=1, min=0.01
dv/dt = (f_in - f_out)/(tau*second) : init=1, min=0.01
f_out = v**(1 / alpha) : init=1, min=0.01
# Revised coefficients
k_1 = 4.3 * v_0 * E_0 * TE
k_2 = epsilon * r_0 * E_0 * TE
k_3 = 1.0 - epsilon
# Non-linear equation
BOLD = V_0 * (k_1 * (1 - q) + k_2 * (1 - (q / v)) + k_3 * (1 - v)) : init=0
"""
name = "BOLD model RN"
description = "BOLD computation with revised coefficients and non-linear BOLD equation (Stephan et al., 2007)."
BoldModel.__init__(self,
parameters=parameters,
equations=equations,
inputs="I_CBF",
output="BOLD",
name=name, description=description
)
|
__init__(phi=1.0, kappa=1 / 1.54, gamma=1 / 2.46, E_0=0.34, tau=0.98, alpha=0.33, V_0=0.02, v_0=40.3, TE=40 / 1000.0, epsilon=1.43, r_0=25)
Parameters:
-
phi
–
-
kappa
–
-
gamma
–
-
E_0
–
oxygen extraction fraction at rest
-
tau
–
-
alpha
–
-
V_0
–
resting venous blood volume fraction
-
v_0
–
frequency offset at the outer surface of the magnetized vessel for fully deoxygenated blood at 1.5 T
-
TE
–
-
epsilon
–
ratio of intra- and extravascular signal
-
r_0
–
slope of the relation between the intravascular relaxation rate and oxygen saturation
Source code in ANNarchy/extensions/bold/PredefinedModels.py
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 | def __init__(self,
phi = 1.0,
kappa = 1/1.54,
gamma = 1/2.46,
E_0 = 0.34,
tau = 0.98,
alpha = 0.33,
V_0 = 0.02,
v_0 = 40.3,
TE = 40/1000.,
epsilon = 1.43,
r_0 = 25,
):
"""
:param phi: input coefficient
:param kappa: signal decay
:param gamma: feedback regulation
:param E_0: oxygen extraction fraction at rest
:param tau: time constant (in s!)
:param alpha: vessel stiffness
:param V_0: resting venous blood volume fraction
:param v_0: frequency offset at the outer surface of the magnetized vessel for fully deoxygenated blood at 1.5 T
:param TE: echo time
:param epsilon: ratio of intra- and extravascular signal
:param r_0: slope of the relation between the intravascular relaxation rate and oxygen saturation
"""
parameters = """
second = 1000.0 : population
phi = %(phi)s : population
kappa = %(kappa)s : population
gamma = %(gamma)s : population
E_0 = %(E_0)s : population
tau = %(tau)s : population
alpha = %(alpha)s : population
V_0 = %(V_0)s : population
v_0 = %(v_0)s : population
TE = %(TE)s : population
epsilon = %(epsilon)s : population
r_0 = %(r_0)s : population
""" % {
'phi': phi,
'kappa': kappa,
'gamma': gamma,
'E_0': E_0,
'tau': tau,
'alpha': alpha,
'V_0': V_0,
'v_0': v_0,
'TE': TE,
'epsilon': epsilon,
'r_0': r_0,
}
equations = """
# Single input
I_CBF = sum(I_CBF) : init=0
ds/dt = (phi * I_CBF - kappa * s - gamma * (f_in - 1))/second : init=0
df_in/dt = s / second : init=1, min=0.01
E = 1 - (1 - E_0)**(1 / f_in) : init=0.3424
dq/dt = (f_in * E / E_0 - (q / v) * f_out)/(tau*second) : init=1, min=0.01
dv/dt = (f_in - f_out)/(tau*second) : init=1, min=0.01
f_out = v**(1 / alpha) : init=1, min=0.01
# Revised coefficients
k_1 = 4.3 * v_0 * E_0 * TE
k_2 = epsilon * r_0 * E_0 * TE
k_3 = 1.0 - epsilon
# Non-linear equation
BOLD = V_0 * (k_1 * (1 - q) + k_2 * (1 - (q / v)) + k_3 * (1 - v)) : init=0
"""
name = "BOLD model RN"
description = "BOLD computation with revised coefficients and non-linear BOLD equation (Stephan et al., 2007)."
BoldModel.__init__(self,
parameters=parameters,
equations=equations,
inputs="I_CBF",
output="BOLD",
name=name, description=description
)
|
ANNarchy.extensions.bold.balloon_RL
Bases: BoldModel
A balloon model with revised coefficients and linear BOLD equation derived from Stephan et al. (2007).
Equivalent code:
balloon_RL = BoldModel(
parameters = '''
second = 1000.0
phi = 1.0
kappa = 1/1.54
gamma = 1/2.46
E_0 = 0.34
tau = 0.98
alpha = 0.33
V_0 = 0.02
v_0 = 40.3
TE = 40/1000.
epsilon = 1.43
r_0 = 25.
''',
equations = '''
# Single input
I_CBF = sum(I_CBF) : init=0
ds/dt = (phi * I_CBF - kappa * s - gamma * (f_in - 1))/second : init=0
df_in/dt = s / second : init=1, min=0.01
E = 1 - (1 - E_0)**(1 / f_in) : init=0.3424
dq/dt = (f_in * E / E_0 - (q / v) * f_out)/(tau*second) : init=1, min=0.01
dv/dt = (f_in - f_out)/(tau*second) : init=1, min=0.01
f_out = v**(1 / alpha) : init=1, min=0.01
# Revised coefficients
k_1 = 4.3 * v_0 * E_0 * TE
k_2 = epsilon * r_0 * E_0 * TE
k_3 = 1.0 - epsilon
# Linear equation
BOLD = V_0 * ((k_1 + k_2) * (1 - q) + (k_3 - k_2) * (1 - v)) : init=0
''',
inputs="I_CBF",
)
Source code in ANNarchy/extensions/bold/PredefinedModels.py
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531 | class balloon_RL(BoldModel):
"""
A balloon model with revised coefficients and linear BOLD equation derived from Stephan et al. (2007).
Equivalent code:
```python
balloon_RL = BoldModel(
parameters = '''
second = 1000.0
phi = 1.0
kappa = 1/1.54
gamma = 1/2.46
E_0 = 0.34
tau = 0.98
alpha = 0.33
V_0 = 0.02
v_0 = 40.3
TE = 40/1000.
epsilon = 1.43
r_0 = 25.
''',
equations = '''
# Single input
I_CBF = sum(I_CBF) : init=0
ds/dt = (phi * I_CBF - kappa * s - gamma * (f_in - 1))/second : init=0
df_in/dt = s / second : init=1, min=0.01
E = 1 - (1 - E_0)**(1 / f_in) : init=0.3424
dq/dt = (f_in * E / E_0 - (q / v) * f_out)/(tau*second) : init=1, min=0.01
dv/dt = (f_in - f_out)/(tau*second) : init=1, min=0.01
f_out = v**(1 / alpha) : init=1, min=0.01
# Revised coefficients
k_1 = 4.3 * v_0 * E_0 * TE
k_2 = epsilon * r_0 * E_0 * TE
k_3 = 1.0 - epsilon
# Linear equation
BOLD = V_0 * ((k_1 + k_2) * (1 - q) + (k_3 - k_2) * (1 - v)) : init=0
''',
inputs="I_CBF",
)
```
"""
def __init__(self,
phi = 1.0,
kappa = 1/1.54,
gamma = 1/2.46,
E_0 = 0.34,
tau = 0.98,
alpha = 0.33,
V_0 = 0.02,
v_0 = 40.3,
TE = 40/1000.,
epsilon = 1.43,
r_0 = 25,
):
"""
:param phi: input coefficient
:param kappa: signal decay
:param gamma: feedback regulation
:param E_0: oxygen extraction fraction at rest
:param tau: time constant (in s!)
:param alpha: vessel stiffness
:param V_0: resting venous blood volume fraction
:param v_0: frequency offset at the outer surface of the magnetized vessel for fully deoxygenated blood at 1.5 T
:param TE: echo time
:param epsilon: ratio of intra- and extravascular signal
:param r_0: slope of the relation between the intravascular relaxation rate and oxygen saturation
"""
parameters = """
second = 1000.0 : population
phi = %(phi)s : population
kappa = %(kappa)s : population
gamma = %(gamma)s : population
E_0 = %(E_0)s : population
tau = %(tau)s : population
alpha = %(alpha)s : population
V_0 = %(V_0)s : population
v_0 = %(v_0)s : population
TE = %(TE)s : population
epsilon = %(epsilon)s : population
r_0 = %(r_0)s : population
""" % {
'phi': phi,
'kappa': kappa,
'gamma': gamma,
'E_0': E_0,
'tau': tau,
'alpha': alpha,
'V_0': V_0,
'v_0': v_0,
'TE': TE,
'epsilon': epsilon,
'r_0': r_0,
}
equations = """
# Single input
I_CBF = sum(I_CBF) : init=0
ds/dt = (phi * I_CBF - kappa * s - gamma * (f_in - 1))/second : init=0
df_in/dt = s / second : init=1, min=0.01
E = 1 - (1 - E_0)**(1 / f_in) : init=0.3424
tau*dq/dt = f_in * E / E_0 - (q / v) * f_out : init=1, min=0.01
tau*dv/dt = f_in - f_out : init=1, min=0.01
f_out = v**(1 / alpha) : init=1, min=0.01
# Revised coeeficients
k_1 = 4.3 * v_0 * E_0 * TE
k_2 = epsilon * r_0 * E_0 * TE
k_3 = 1 - epsilon
# Linear equation
BOLD = V_0 * ((k_1 + k_2) * (1 - q) + (k_3 - k_2) * (1 - v)) : init=0
"""
name = "BOLD model RL"
description = "BOLD computation with revised coefficients and linear BOLD equation (Stephan et al., 2007)."
BoldModel.__init__(self,
parameters=parameters,
equations=equations,
inputs="I_CBF",
output="BOLD",
name=name, description=description
)
|
__init__(phi=1.0, kappa=1 / 1.54, gamma=1 / 2.46, E_0=0.34, tau=0.98, alpha=0.33, V_0=0.02, v_0=40.3, TE=40 / 1000.0, epsilon=1.43, r_0=25)
Parameters:
-
phi
–
-
kappa
–
-
gamma
–
-
E_0
–
oxygen extraction fraction at rest
-
tau
–
-
alpha
–
-
V_0
–
resting venous blood volume fraction
-
v_0
–
frequency offset at the outer surface of the magnetized vessel for fully deoxygenated blood at 1.5 T
-
TE
–
-
epsilon
–
ratio of intra- and extravascular signal
-
r_0
–
slope of the relation between the intravascular relaxation rate and oxygen saturation
Source code in ANNarchy/extensions/bold/PredefinedModels.py
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531 | def __init__(self,
phi = 1.0,
kappa = 1/1.54,
gamma = 1/2.46,
E_0 = 0.34,
tau = 0.98,
alpha = 0.33,
V_0 = 0.02,
v_0 = 40.3,
TE = 40/1000.,
epsilon = 1.43,
r_0 = 25,
):
"""
:param phi: input coefficient
:param kappa: signal decay
:param gamma: feedback regulation
:param E_0: oxygen extraction fraction at rest
:param tau: time constant (in s!)
:param alpha: vessel stiffness
:param V_0: resting venous blood volume fraction
:param v_0: frequency offset at the outer surface of the magnetized vessel for fully deoxygenated blood at 1.5 T
:param TE: echo time
:param epsilon: ratio of intra- and extravascular signal
:param r_0: slope of the relation between the intravascular relaxation rate and oxygen saturation
"""
parameters = """
second = 1000.0 : population
phi = %(phi)s : population
kappa = %(kappa)s : population
gamma = %(gamma)s : population
E_0 = %(E_0)s : population
tau = %(tau)s : population
alpha = %(alpha)s : population
V_0 = %(V_0)s : population
v_0 = %(v_0)s : population
TE = %(TE)s : population
epsilon = %(epsilon)s : population
r_0 = %(r_0)s : population
""" % {
'phi': phi,
'kappa': kappa,
'gamma': gamma,
'E_0': E_0,
'tau': tau,
'alpha': alpha,
'V_0': V_0,
'v_0': v_0,
'TE': TE,
'epsilon': epsilon,
'r_0': r_0,
}
equations = """
# Single input
I_CBF = sum(I_CBF) : init=0
ds/dt = (phi * I_CBF - kappa * s - gamma * (f_in - 1))/second : init=0
df_in/dt = s / second : init=1, min=0.01
E = 1 - (1 - E_0)**(1 / f_in) : init=0.3424
tau*dq/dt = f_in * E / E_0 - (q / v) * f_out : init=1, min=0.01
tau*dv/dt = f_in - f_out : init=1, min=0.01
f_out = v**(1 / alpha) : init=1, min=0.01
# Revised coeeficients
k_1 = 4.3 * v_0 * E_0 * TE
k_2 = epsilon * r_0 * E_0 * TE
k_3 = 1 - epsilon
# Linear equation
BOLD = V_0 * ((k_1 + k_2) * (1 - q) + (k_3 - k_2) * (1 - v)) : init=0
"""
name = "BOLD model RL"
description = "BOLD computation with revised coefficients and linear BOLD equation (Stephan et al., 2007)."
BoldModel.__init__(self,
parameters=parameters,
equations=equations,
inputs="I_CBF",
output="BOLD",
name=name, description=description
)
|
ANNarchy.extensions.bold.balloon_CL
Bases: BoldModel
A balloon model with classical coefficients and linear BOLD equation derived from Stephan et al. (2007).
Equivalent code:
balloon_CL = BoldModel(
parameters = '''
second = 1000.0
phi = 1.0
kappa = 1/1.54
gamma = 1/2.46
E_0 = 0.34
tau = 0.98
alpha = 0.33
V_0 = 0.02
v_0 = 40.3
TE = 40/1000.
epsilon = 1.43
''',
equations = '''
# Single input
I_CBF = sum(I_CBF) : init=0
ds/dt = (phi * I_CBF - kappa * s - gamma * (f_in - 1))/second : init=0
df_in/dt = s / second : init=1, min=0.01
E = 1 - (1 - E_0)**(1 / f_in) : init=0.3424
dq/dt = (f_in * E / E_0 - (q / v) * f_out)/(tau*second) : init=1, min=0.01
dv/dt = (f_in - f_out)/(tau*second) : init=1, min=0.01
f_out = v**(1 / alpha) : init=1, min=0.01
# Classic coefficients
k_1 = (1 - V_0) * 4.3 * v_0 * E_0 * TE
k_2 = 2 * E_0
k_3 = 1 - epsilon
# Linear equation
BOLD = V_0 * ((k_1 + k_2) * (1 - q) + (k_3 - k_2) * (1 - v)) : init=0
''',
inputs="I_CBF",
)
Source code in ANNarchy/extensions/bold/PredefinedModels.py
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 | class balloon_CL(BoldModel):
"""
A balloon model with classical coefficients and linear BOLD equation derived from Stephan et al. (2007).
Equivalent code:
```python
balloon_CL = BoldModel(
parameters = '''
second = 1000.0
phi = 1.0
kappa = 1/1.54
gamma = 1/2.46
E_0 = 0.34
tau = 0.98
alpha = 0.33
V_0 = 0.02
v_0 = 40.3
TE = 40/1000.
epsilon = 1.43
''',
equations = '''
# Single input
I_CBF = sum(I_CBF) : init=0
ds/dt = (phi * I_CBF - kappa * s - gamma * (f_in - 1))/second : init=0
df_in/dt = s / second : init=1, min=0.01
E = 1 - (1 - E_0)**(1 / f_in) : init=0.3424
dq/dt = (f_in * E / E_0 - (q / v) * f_out)/(tau*second) : init=1, min=0.01
dv/dt = (f_in - f_out)/(tau*second) : init=1, min=0.01
f_out = v**(1 / alpha) : init=1, min=0.01
# Classic coefficients
k_1 = (1 - V_0) * 4.3 * v_0 * E_0 * TE
k_2 = 2 * E_0
k_3 = 1 - epsilon
# Linear equation
BOLD = V_0 * ((k_1 + k_2) * (1 - q) + (k_3 - k_2) * (1 - v)) : init=0
''',
inputs="I_CBF",
)
```
"""
def __init__(self,
phi = 1.0,
kappa = 1/1.54,
gamma = 1/2.46,
E_0 = 0.34,
tau = 0.98,
alpha = 0.33,
V_0 = 0.02,
v_0 = 40.3,
TE = 40/1000.,
epsilon = 1.43,
):
"""
:param phi: input coefficient
:param kappa: signal decay
:param gamma: feedback regulation
:param E_0: oxygen extraction fraction at rest
:param tau: time constant (in s!)
:param alpha: vessel stiffness
:param V_0: resting venous blood volume fraction
:param v_0: frequency offset at the outer surface of the magnetized vessel for fully deoxygenated blood at 1.5 T
:param TE: echo time
:param epsilon: ratio of intra- and extravascular signal
"""
parameters = """
second = 1000.0 : population
phi = %(phi)s : population
kappa = %(kappa)s : population
gamma = %(gamma)s : population
E_0 = %(E_0)s : population
tau = %(tau)s : population
alpha = %(alpha)s : population
V_0 = %(V_0)s : population
v_0 = %(v_0)s : population
TE = %(TE)s : population
epsilon = %(epsilon)s : population
""" % {
'phi': phi,
'kappa': kappa,
'gamma': gamma,
'E_0': E_0,
'tau': tau,
'alpha': alpha,
'V_0': V_0,
'v_0': v_0,
'TE': TE,
'epsilon': epsilon,
}
equations = """
# Single input
I_CBF = sum(I_CBF) : init=0
ds/dt = (phi * I_CBF - kappa * s - gamma * (f_in - 1))/second : init=0
df_in/dt = s / second : init=1, min=0.01
E = 1 - (1 - E_0)**(1 / f_in) : init=0.3424
dq/dt = (f_in * E / E_0 - (q / v) * f_out)/(tau*second) : init=1, min=0.01
dv/dt = (f_in - f_out)/(tau*second) : init=1, min=0.01
f_out = v**(1 / alpha) : init=1, min=0.01
# Classic coefficients
k_1 = (1 - V_0) * 4.3 * v_0 * E_0 * TE
k_2 = 2 * E_0
k_3 = 1 - epsilon
# Linear equation
BOLD = V_0 * ((k_1 + k_2) * (1 - q) + (k_3 - k_2) * (1 - v)) : init=0
"""
name = "BoldNeuron CL"
description = "BOLD computation with classic coefficients and linear BOLD equation (Stephan et al., 2007)."
BoldModel.__init__(self,
parameters=parameters,
equations=equations,
inputs="I_CBF",
output="BOLD",
name=name, description=description
)
|
__init__(phi=1.0, kappa=1 / 1.54, gamma=1 / 2.46, E_0=0.34, tau=0.98, alpha=0.33, V_0=0.02, v_0=40.3, TE=40 / 1000.0, epsilon=1.43)
Parameters:
-
phi
–
-
kappa
–
-
gamma
–
-
E_0
–
oxygen extraction fraction at rest
-
tau
–
-
alpha
–
-
V_0
–
resting venous blood volume fraction
-
v_0
–
frequency offset at the outer surface of the magnetized vessel for fully deoxygenated blood at 1.5 T
-
TE
–
-
epsilon
–
ratio of intra- and extravascular signal
Source code in ANNarchy/extensions/bold/PredefinedModels.py
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 | def __init__(self,
phi = 1.0,
kappa = 1/1.54,
gamma = 1/2.46,
E_0 = 0.34,
tau = 0.98,
alpha = 0.33,
V_0 = 0.02,
v_0 = 40.3,
TE = 40/1000.,
epsilon = 1.43,
):
"""
:param phi: input coefficient
:param kappa: signal decay
:param gamma: feedback regulation
:param E_0: oxygen extraction fraction at rest
:param tau: time constant (in s!)
:param alpha: vessel stiffness
:param V_0: resting venous blood volume fraction
:param v_0: frequency offset at the outer surface of the magnetized vessel for fully deoxygenated blood at 1.5 T
:param TE: echo time
:param epsilon: ratio of intra- and extravascular signal
"""
parameters = """
second = 1000.0 : population
phi = %(phi)s : population
kappa = %(kappa)s : population
gamma = %(gamma)s : population
E_0 = %(E_0)s : population
tau = %(tau)s : population
alpha = %(alpha)s : population
V_0 = %(V_0)s : population
v_0 = %(v_0)s : population
TE = %(TE)s : population
epsilon = %(epsilon)s : population
""" % {
'phi': phi,
'kappa': kappa,
'gamma': gamma,
'E_0': E_0,
'tau': tau,
'alpha': alpha,
'V_0': V_0,
'v_0': v_0,
'TE': TE,
'epsilon': epsilon,
}
equations = """
# Single input
I_CBF = sum(I_CBF) : init=0
ds/dt = (phi * I_CBF - kappa * s - gamma * (f_in - 1))/second : init=0
df_in/dt = s / second : init=1, min=0.01
E = 1 - (1 - E_0)**(1 / f_in) : init=0.3424
dq/dt = (f_in * E / E_0 - (q / v) * f_out)/(tau*second) : init=1, min=0.01
dv/dt = (f_in - f_out)/(tau*second) : init=1, min=0.01
f_out = v**(1 / alpha) : init=1, min=0.01
# Classic coefficients
k_1 = (1 - V_0) * 4.3 * v_0 * E_0 * TE
k_2 = 2 * E_0
k_3 = 1 - epsilon
# Linear equation
BOLD = V_0 * ((k_1 + k_2) * (1 - q) + (k_3 - k_2) * (1 - v)) : init=0
"""
name = "BoldNeuron CL"
description = "BOLD computation with classic coefficients and linear BOLD equation (Stephan et al., 2007)."
BoldModel.__init__(self,
parameters=parameters,
equations=equations,
inputs="I_CBF",
output="BOLD",
name=name, description=description
)
|
ANNarchy.extensions.bold.balloon_CN
Bases: BoldModel
A balloon model with classic coefficients and non-linear BOLD equation derived from Stephan et al. (2007).
Equivalent code:
balloon_CN = BoldModel(
parameters = '''
second = 1000.0
phi = 1.0
kappa = 1/1.54
gamma = 1/2.46
E_0 = 0.34
tau = 0.98
alpha = 0.33
V_0 = 0.02
v_0 = 40.3
TE = 40/1000.
epsilon = 1.43
''',
equations = '''
# Single input
I_CBF = sum(I_CBF) : init=0
ds/dt = (phi * I_CBF - kappa * s - gamma * (f_in - 1))/second : init=0
df_in/dt = s / second : init=1, min=0.01
E = 1 - (1 - E_0)**(1 / f_in) : init=0.3424
dq/dt = (f_in * E / E_0 - (q / v) * f_out)/(tau*second) : init=1, min=0.01
dv/dt = (f_in - f_out)/(tau*second) : init=1, min=0.01
f_out = v**(1 / alpha) : init=1, min=0.01
# Classic coefficients
k_1 = (1 - V_0) * 4.3 * v_0 * E_0 * TE
k_2 = 2 * E_0
k_3 = 1 - epsilon
# Non-linear equation
BOLD = V_0 * (k_1 * (1 - q) + k_2 * (1 - (q / v)) + k_3 * (1 - v)) : init=0
''',
inputs="I_CBF",
)
Source code in ANNarchy/extensions/bold/PredefinedModels.py
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 | class balloon_CN(BoldModel):
"""
A balloon model with classic coefficients and non-linear BOLD equation derived from Stephan et al. (2007).
Equivalent code:
```python
balloon_CN = BoldModel(
parameters = '''
second = 1000.0
phi = 1.0
kappa = 1/1.54
gamma = 1/2.46
E_0 = 0.34
tau = 0.98
alpha = 0.33
V_0 = 0.02
v_0 = 40.3
TE = 40/1000.
epsilon = 1.43
''',
equations = '''
# Single input
I_CBF = sum(I_CBF) : init=0
ds/dt = (phi * I_CBF - kappa * s - gamma * (f_in - 1))/second : init=0
df_in/dt = s / second : init=1, min=0.01
E = 1 - (1 - E_0)**(1 / f_in) : init=0.3424
dq/dt = (f_in * E / E_0 - (q / v) * f_out)/(tau*second) : init=1, min=0.01
dv/dt = (f_in - f_out)/(tau*second) : init=1, min=0.01
f_out = v**(1 / alpha) : init=1, min=0.01
# Classic coefficients
k_1 = (1 - V_0) * 4.3 * v_0 * E_0 * TE
k_2 = 2 * E_0
k_3 = 1 - epsilon
# Non-linear equation
BOLD = V_0 * (k_1 * (1 - q) + k_2 * (1 - (q / v)) + k_3 * (1 - v)) : init=0
''',
inputs="I_CBF",
)
```
"""
def __init__(self,
phi = 1.0,
kappa = 1/1.54,
gamma = 1/2.46,
E_0 = 0.34,
tau = 0.98,
alpha = 0.33,
V_0 = 0.02,
v_0 = 40.3,
TE = 40/1000.,
epsilon = 1.43,
):
"""
:param phi: input coefficient
:param kappa: signal decay
:param gamma: feedback regulation
:param E_0: oxygen extraction fraction at rest
:param tau: time constant (in s!)
:param alpha: vessel stiffness
:param V_0: resting venous blood volume fraction
:param v_0: frequency offset at the outer surface of the magnetized vessel for fully deoxygenated blood at 1.5 T
:param TE: echo time
:param epsilon: ratio of intra- and extravascular signal
"""
parameters = """
second = 1000.0 : population
phi = %(phi)s : population
kappa = %(kappa)s : population
gamma = %(gamma)s : population
E_0 = %(E_0)s : population
tau = %(tau)s : population
alpha = %(alpha)s : population
V_0 = %(V_0)s : population
v_0 = %(v_0)s : population
TE = %(TE)s : population
epsilon = %(epsilon)s : population
""" % {
'phi': phi,
'kappa': kappa,
'gamma': gamma,
'E_0': E_0,
'tau': tau,
'alpha': alpha,
'V_0': V_0,
'v_0': v_0,
'TE': TE,
'epsilon': epsilon,
}
equations = """
# Single input
I_CBF = sum(I_CBF) : init=0
ds/dt = (phi * I_CBF - kappa * s - gamma * (f_in - 1))/second : init=0
df_in/dt = s / second : init=1, min=0.01
E = 1 - (1 - E_0)**(1 / f_in) : init=0.3424
dq/dt = (f_in * E / E_0 - (q / v) * f_out)/(tau*second) : init=1, min=0.01
dv/dt = (f_in - f_out)/(tau*second) : init=1, min=0.01
f_out = v**(1 / alpha) : init=1, min=0.01
# Classic coefficients
k_1 = (1 - V_0) * 4.3 * v_0 * E_0 * TE
k_2 = 2 * E_0
k_3 = 1 - epsilon
# Non-linear equation
BOLD = V_0 * (k_1 * (1 - q) + k_2 * (1 - (q / v)) + k_3 * (1 - v)) : init=0
"""
name = "BoldNeuron CN",
description = "BOLD computation with classic coefficients and non-linear BOLD equation (Stephan et al., 2007)."
BoldModel.__init__(self,
parameters=parameters,
equations=equations,
inputs="I_CBF",
output="BOLD",
name=name, description=description
)
|
__init__(phi=1.0, kappa=1 / 1.54, gamma=1 / 2.46, E_0=0.34, tau=0.98, alpha=0.33, V_0=0.02, v_0=40.3, TE=40 / 1000.0, epsilon=1.43)
Parameters:
-
phi
–
-
kappa
–
-
gamma
–
-
E_0
–
oxygen extraction fraction at rest
-
tau
–
-
alpha
–
-
V_0
–
resting venous blood volume fraction
-
v_0
–
frequency offset at the outer surface of the magnetized vessel for fully deoxygenated blood at 1.5 T
-
TE
–
-
epsilon
–
ratio of intra- and extravascular signal
Source code in ANNarchy/extensions/bold/PredefinedModels.py
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 | def __init__(self,
phi = 1.0,
kappa = 1/1.54,
gamma = 1/2.46,
E_0 = 0.34,
tau = 0.98,
alpha = 0.33,
V_0 = 0.02,
v_0 = 40.3,
TE = 40/1000.,
epsilon = 1.43,
):
"""
:param phi: input coefficient
:param kappa: signal decay
:param gamma: feedback regulation
:param E_0: oxygen extraction fraction at rest
:param tau: time constant (in s!)
:param alpha: vessel stiffness
:param V_0: resting venous blood volume fraction
:param v_0: frequency offset at the outer surface of the magnetized vessel for fully deoxygenated blood at 1.5 T
:param TE: echo time
:param epsilon: ratio of intra- and extravascular signal
"""
parameters = """
second = 1000.0 : population
phi = %(phi)s : population
kappa = %(kappa)s : population
gamma = %(gamma)s : population
E_0 = %(E_0)s : population
tau = %(tau)s : population
alpha = %(alpha)s : population
V_0 = %(V_0)s : population
v_0 = %(v_0)s : population
TE = %(TE)s : population
epsilon = %(epsilon)s : population
""" % {
'phi': phi,
'kappa': kappa,
'gamma': gamma,
'E_0': E_0,
'tau': tau,
'alpha': alpha,
'V_0': V_0,
'v_0': v_0,
'TE': TE,
'epsilon': epsilon,
}
equations = """
# Single input
I_CBF = sum(I_CBF) : init=0
ds/dt = (phi * I_CBF - kappa * s - gamma * (f_in - 1))/second : init=0
df_in/dt = s / second : init=1, min=0.01
E = 1 - (1 - E_0)**(1 / f_in) : init=0.3424
dq/dt = (f_in * E / E_0 - (q / v) * f_out)/(tau*second) : init=1, min=0.01
dv/dt = (f_in - f_out)/(tau*second) : init=1, min=0.01
f_out = v**(1 / alpha) : init=1, min=0.01
# Classic coefficients
k_1 = (1 - V_0) * 4.3 * v_0 * E_0 * TE
k_2 = 2 * E_0
k_3 = 1 - epsilon
# Non-linear equation
BOLD = V_0 * (k_1 * (1 - q) + k_2 * (1 - (q / v)) + k_3 * (1 - v)) : init=0
"""
name = "BoldNeuron CN",
description = "BOLD computation with classic coefficients and non-linear BOLD equation (Stephan et al., 2007)."
BoldModel.__init__(self,
parameters=parameters,
equations=equations,
inputs="I_CBF",
output="BOLD",
name=name, description=description
)
|
ANNarchy.extensions.bold.balloon_maith2021
Bases: BoldModel
The balloon model as used in Maith et al. (2021).
Source code in ANNarchy/extensions/bold/PredefinedModels.py
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653 | class balloon_maith2021(BoldModel):
"""
The balloon model as used in Maith et al. (2021).
"""
def __init__(self):
"Constructor"
parameters = """
second = 1000.0
phi = 1.0
kappa = 0.665
gamma = 0.412
E_0 = 0.3424
tau = 1.0368
alpha = 0.3215
V_0 = 0.02
"""
equations = """
I_CBF = sum(I_CBF) : init=0
ds/dt = (phi * I_CBF - kappa * s - gamma * (f_in - 1))/second : init=0
df_in/dt = s / second : init=1, min=0.01
E = 1 - (1 - E_0)**(1 / f_in) : init=0.3424
dq/dt = (f_in * E / E_0 - (q / v) * f_out)/(tau*second) : init=1, min=0.01
dv/dt = (f_in - f_out)/(tau*second) : init=1, min=0.01
f_out = v**(1 / alpha) : init=1, min=0.01
k_1 = 7 * E_0
k_2 = 2
k_3 = 2 * E_0 - 0.2
BOLD = V_0 * (k_1 * (1 - q) + k_2 * (1 - (q / v)) + k_3 * (1 - v)) : init=0
"""
name = "Maith2021 BOLD model"
description = "BOLD computation from Maith et al. (2021)."
BoldModel.__init__(self,
parameters=parameters,
equations=equations,
inputs="I_CBF",
output="BOLD",
name=name, description=description
)
|
__init__()
Constructor
Source code in ANNarchy/extensions/bold/PredefinedModels.py
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653 | def __init__(self):
"Constructor"
parameters = """
second = 1000.0
phi = 1.0
kappa = 0.665
gamma = 0.412
E_0 = 0.3424
tau = 1.0368
alpha = 0.3215
V_0 = 0.02
"""
equations = """
I_CBF = sum(I_CBF) : init=0
ds/dt = (phi * I_CBF - kappa * s - gamma * (f_in - 1))/second : init=0
df_in/dt = s / second : init=1, min=0.01
E = 1 - (1 - E_0)**(1 / f_in) : init=0.3424
dq/dt = (f_in * E / E_0 - (q / v) * f_out)/(tau*second) : init=1, min=0.01
dv/dt = (f_in - f_out)/(tau*second) : init=1, min=0.01
f_out = v**(1 / alpha) : init=1, min=0.01
k_1 = 7 * E_0
k_2 = 2
k_3 = 2 * E_0 - 0.2
BOLD = V_0 * (k_1 * (1 - q) + k_2 * (1 - (q / v)) + k_3 * (1 - v)) : init=0
"""
name = "Maith2021 BOLD model"
description = "BOLD computation from Maith et al. (2021)."
BoldModel.__init__(self,
parameters=parameters,
equations=equations,
inputs="I_CBF",
output="BOLD",
name=name, description=description
)
|
Bases: BoldModel
BOLD model with two input signals (CBF-driving and CMRO2-driving) for the ballon model and non-linear BOLD equation with revised coefficients based on Buxton et al. (2004), Friston et al. (2000) and Stephan et al. (2007).
Source code in ANNarchy/extensions/bold/PredefinedModels.py
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605 | class balloon_two_inputs(BoldModel):
"""
BOLD model with two input signals (CBF-driving and CMRO2-driving) for the ballon model and non-linear BOLD equation with revised coefficients based on Buxton et al. (2004), Friston et al. (2000) and Stephan et al. (2007).
"""
def __init__(self):
"Constructor"
# damped harmonic oscillators, gamma->spring coefficient, kappa->damping coefficient
# CBF --> gamma from Friston
# CMRO2 --> faster --> gamma=gamma_CBF*10 (therefore scaling of I_CMRO2 by (gamma_CMRO2 / gamma_CBF) --> if same input (I_CBF==I_CMRO2) CMRO2 and CBF same steady-state)
# critical kappa --> kappa**2-4*gamma = 0 --> kappa=sqrt(4*gamma)
# CBF underdamped for undershoot --> kappa = 0.6*sqrt(4*gamma)
# CMRO2 critical --> kappa = sqrt(4*gamma)
# after CBF and CMRO2 standard balloon model with revised coefficients, parameter values = Friston et al. (2000)
parameters = """
kappa_CBF = 0.7650920556760059
gamma_CBF = 1/2.46
kappa_CMRO2 = 4.032389192727559
gamma_CMRO2 = 10/2.46
phi_CBF = 1.0
phi_CMRO2 = 1.0
E_0 = 0.34
tau = 0.98
alpha = 0.33
V_0 = 0.02
v_0 = 40.3
TE = 40/1000.
epsilon = 1
r_0 = 25
tau_out1 = 0
tau_out2 = 20
second = 1000
"""
equations = """
# CBF input
I_CBF = sum(I_CBF) : init=0
second*ds_CBF/dt = phi_CBF * I_CBF - kappa_CBF * s_CBF - gamma_CBF * (f_in - 1) : init=0
second*df_in/dt = s_CBF : init=1, min=0.01
# CMRO2 input
I_CMRO2 = sum(I_CMRO2) : init=0
second*ds_CMRO2/dt = phi_CMRO2 * I_CMRO2 * (gamma_CMRO2 / gamma_CBF) - kappa_CMRO2 * s_CMRO2 - gamma_CMRO2 * (r - 1) : init=0
second*dr/dt = s_CMRO2 : init=1, min=0.01
dv = f_in - v**(1 / alpha)
tau_out = if dv>0: tau_out1 else: tau_out2
f_out = v**(1/alpha) + tau_out * dv / (tau + tau_out) : init=1, min=0.01
dq/dt = (r - (q / v) * f_out) / (second*tau) : init=1, min=0.01
dv/dt = dv / (tau + tau_out) / second : init=1, min=0.01
# Revised coefficients
k_1 = 4.3 * v_0 * E_0 * TE
k_2 = epsilon * r_0 * E_0 * TE
k_3 = 1 - epsilon
# Non-linear equation
BOLD = V_0 * (k_1 * (1 - q) + k_2 * (1 - (q / v)) + k_3 * (1 - v)) : init=0
"""
name = "BOLD model with two inputs"
description = "BOLD model with two inputs (CBF-driving and CMRO2-driving). Combination of neurovascular coupling of Friston et al. (2000) and non-linear Balloon model with revised coefficients (Buxton et al, 1998, Stephan et al, 2007)"
BoldModel.__init__(self,
parameters=parameters,
equations=equations,
inputs=['I_CBF', 'I_CMRO2'],
output="BOLD",
name=name,
description=description
)
|
Constructor
Source code in ANNarchy/extensions/bold/PredefinedModels.py
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605 | def __init__(self):
"Constructor"
# damped harmonic oscillators, gamma->spring coefficient, kappa->damping coefficient
# CBF --> gamma from Friston
# CMRO2 --> faster --> gamma=gamma_CBF*10 (therefore scaling of I_CMRO2 by (gamma_CMRO2 / gamma_CBF) --> if same input (I_CBF==I_CMRO2) CMRO2 and CBF same steady-state)
# critical kappa --> kappa**2-4*gamma = 0 --> kappa=sqrt(4*gamma)
# CBF underdamped for undershoot --> kappa = 0.6*sqrt(4*gamma)
# CMRO2 critical --> kappa = sqrt(4*gamma)
# after CBF and CMRO2 standard balloon model with revised coefficients, parameter values = Friston et al. (2000)
parameters = """
kappa_CBF = 0.7650920556760059
gamma_CBF = 1/2.46
kappa_CMRO2 = 4.032389192727559
gamma_CMRO2 = 10/2.46
phi_CBF = 1.0
phi_CMRO2 = 1.0
E_0 = 0.34
tau = 0.98
alpha = 0.33
V_0 = 0.02
v_0 = 40.3
TE = 40/1000.
epsilon = 1
r_0 = 25
tau_out1 = 0
tau_out2 = 20
second = 1000
"""
equations = """
# CBF input
I_CBF = sum(I_CBF) : init=0
second*ds_CBF/dt = phi_CBF * I_CBF - kappa_CBF * s_CBF - gamma_CBF * (f_in - 1) : init=0
second*df_in/dt = s_CBF : init=1, min=0.01
# CMRO2 input
I_CMRO2 = sum(I_CMRO2) : init=0
second*ds_CMRO2/dt = phi_CMRO2 * I_CMRO2 * (gamma_CMRO2 / gamma_CBF) - kappa_CMRO2 * s_CMRO2 - gamma_CMRO2 * (r - 1) : init=0
second*dr/dt = s_CMRO2 : init=1, min=0.01
dv = f_in - v**(1 / alpha)
tau_out = if dv>0: tau_out1 else: tau_out2
f_out = v**(1/alpha) + tau_out * dv / (tau + tau_out) : init=1, min=0.01
dq/dt = (r - (q / v) * f_out) / (second*tau) : init=1, min=0.01
dv/dt = dv / (tau + tau_out) / second : init=1, min=0.01
# Revised coefficients
k_1 = 4.3 * v_0 * E_0 * TE
k_2 = epsilon * r_0 * E_0 * TE
k_3 = 1 - epsilon
# Non-linear equation
BOLD = V_0 * (k_1 * (1 - q) + k_2 * (1 - (q / v)) + k_3 * (1 - v)) : init=0
"""
name = "BOLD model with two inputs"
description = "BOLD model with two inputs (CBF-driving and CMRO2-driving). Combination of neurovascular coupling of Friston et al. (2000) and non-linear Balloon model with revised coefficients (Buxton et al, 1998, Stephan et al, 2007)"
BoldModel.__init__(self,
parameters=parameters,
equations=equations,
inputs=['I_CBF', 'I_CMRO2'],
output="BOLD",
name=name,
description=description
)
|
References
Buxton, R. B., Wong, E. C., and Frank, L. R. (1998). Dynamics of blood flow and oxygenation changes during brain activation: the balloon model. Magnetic resonance in medicine 39, 855–864. doi:10.1002/mrm.1910390602
Friston et al. (2000). Nonlinear responses in fMRI: the balloon model, volterra kernels, and other hemodynamics. NeuroImage 12, 466–477
Buxton et al. (2004). Modeling the hemodynamic response to brain activation. Neuroimage 23, S220–S233. doi:10.1016/j.neuroimage.2004.07.013
Stephan et al. (2007). Comparing hemodynamic models with DCM. Neuroimage 38, 387–401. doi:10.1016/j.neuroimage.2007.07.040
Maith et al. (2021) A computational model-based analysis of basal ganglia pathway changes in Parkinson’s disease inferred from resting-state fMRI. European Journal of Neuroscience. 2021; 53: 2278– 2295. doi:10.1111/ejn.14868
Maith et al. (2022) BOLD monitoring in the neural simulator ANNarchy. Frontiers in Neuroinformatics 16. doi:10.3389/fninf.2022.790966.