Skip to content

Models Module

Signal Dynamic API

asl_model_buxton(tau, w, m0, cbf, att, lambda_value=0.98, t1b=1650.0, alpha=0.85)

Buxton model to calculate the ASL magnetization values.

It is assumed that the LD and PLD values are coherent with the ASl Buxton model, i.e. the both has the same array size.

The calculations is given assuming a voxel value. Hence, all the tau, w, cbf and att values must representas a voxel in the image.

Note

The CBF value is the original scale, without assuming the normalized CBF value. See more details at the CBFMapping class documentation.

Parameters:

Name Type Description Default
tau list

LD values

required
w list

PLD values

required
m0 float

The M0 magnetization value

required
cbf float

The CBF value, not been assumed as normalized.

required
att float

The ATT value

required
lambda_value float

The blood-brain partition coefficient (0 to 1.0). Defaults to 0.98.

0.98
t1b float

The T1 relaxation value of the blood. Defaults to 1650.0.

1650.0
alpha float

The labeling efficiency. Defaults to 0.85.

0.85

Returns:

Type Description
ndarray

A numpy array with the magnetization values calculated

Source code in asltk/models/signal_dynamic.py
 6
 7
 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
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
def asl_model_buxton(
    tau: list,
    w: list,
    m0: float,
    cbf: float,
    att: float,
    lambda_value: float = 0.98,
    t1b: float = 1650.0,
    alpha: float = 0.85,
):
    """Buxton model to calculate the ASL magnetization values.

    It is assumed that the LD and PLD values are coherent with the ASl Buxton
    model, i.e. the both has the same array size.

    The calculations is given assuming a voxel value. Hence, all the `tau`,
    `w`, `cbf` and `att` values must representas a voxel in the image.

    Note:
        The CBF value is the original scale, without assuming the normalized
        CBF value. See more details at the CBFMapping class documentation.

    Args:
        tau (list): LD values
        w (list): PLD values
        m0 (float): The M0 magnetization value
        cbf (float): The CBF value, not been assumed as normalized.
        att (float): The ATT value
        lambda_value (float, optional): The blood-brain partition coefficient (0 to 1.0). Defaults to 0.98.
        t1b (float, optional): The T1 relaxation value of the blood. Defaults to 1650.0.
        alpha (float, optional): The labeling efficiency. Defaults to 0.85.

    Returns:
        (numpy.ndarray): A numpy array with the magnetization values calculated
    """
    tau = tau.tolist() if isinstance(tau, np.ndarray) else tau
    w = w.tolist() if isinstance(w, np.ndarray) else w

    if not (isinstance(tau, list) ^ isinstance(tau, tuple)):
        raise ValueError('tau parameter must be a list or tuple of values.')

    if not isinstance(w, list) ^ isinstance(w, tuple):
        raise ValueError('w parameter must be a list or tuple of values.')

    for v in tau:
        if not isinstance(v, float) ^ isinstance(v, int):
            raise ValueError('tau list must contain float or int values')

    for v in w:
        if not isinstance(v, float) ^ isinstance(v, int):
            raise ValueError('w list must contain float or int values')

    # if len(tau) != len(w):
    #     raise SyntaxError("tau and w parameters must be at the same size.")

    t = np.add(tau, w).tolist()

    t1bp = 1 / ((1 / t1b) + (cbf / lambda_value))
    m_values = np.zeros(len(tau))

    for i in range(0, len(tau)):
        try:
            if t[i] < att:
                m_values[i] = 0.0
            elif (att <= t[i]) and (t[i] < tau[i] + att):
                q = 1 - math.exp(-(t[i] - att) / t1bp)
                m_values[i] = (
                    2.0 * m0 * cbf * t1bp * alpha * q * math.exp(-att / t1b)
                )
            else:
                q = 1 - math.exp(-tau[i] / t1bp)
                m_values[i] = (
                    2.0
                    * m0
                    * cbf
                    * t1bp
                    * alpha
                    * q
                    * math.exp(-att / t1b)
                    * math.exp(-(t[i] - tau[i] - att) / t1bp)
                )
        except OverflowError:   # pragma: no cover
            m_values[i] = 0.0

    return m_values

asl_model_multi_te(tau, w, te, m0, cbf, att, t2b=165.0, t2csf=75.0, tblcsf=1400.0, alpha=0.85, t1b=1650.0, t1csf=1400.0)

Multi Time of Echos (TE) ASL model to calculate the T1 relaxation time for blood and Grey Matter exchange.

This model is directly used on the MultiTE_ASLMapping class.

Reference: Ultra-long-TE arterial spin labeling reveals rapid and brain-wide blood-to-CSF water transport in humans, NeuroImage, doi: 10.1016/j.neuroimage.2021.118755

Parameters:

Name Type Description Default
tau list

The LD values

required
w list

The PLD values

required
te list

The TE values

required
m0 float

The M0 voxel value

required
cbf float

The CBF voxel value

required
att float

The ATT voxel value

required
t2b float

The T2 relaxation value for blood. Defaults to 165.0.

165.0
t2csf float

The T2 relaxation value for CSF. Defaults to 75.0.

75.0
tblcsf float

The T1 relaxation value between blood and CSF. Defaults to 1400.0.

1400.0
alpha float

The pulse labeling efficiency. Defaults to 0.85.

0.85
t1b float

The T1 relaxation value for blood. Defaults to 1650.0.

1650.0
t1csf float

The T1 relaxation value for CSF. Defaults to 1400.0.

1400.0

Returns:

Type Description
ndarray

The magnetization values for T1-Blood-GM

Source code in asltk/models/signal_dynamic.py
 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
def asl_model_multi_te(
    tau: list,
    w: list,
    te: list,
    m0: float,
    cbf: float,
    att: float,
    t2b: float = 165.0,
    t2csf: float = 75.0,
    tblcsf: float = 1400.0,
    alpha: float = 0.85,
    t1b: float = 1650.0,
    t1csf: float = 1400.0,
):
    """Multi Time of Echos (TE) ASL model to calculate the T1 relaxation time for
    blood and Grey Matter exchange.

    This model is directly used on the MultiTE_ASLMapping class.

    Reference: Ultra-long-TE arterial spin labeling reveals rapid and
    brain-wide blood-to-CSF water transport in humans, NeuroImage,
    doi: 10.1016/j.neuroimage.2021.118755

    Args:
        tau (list): The LD values
        w (list): The PLD values
        te (list): The TE values
        m0 (float): The M0 voxel value
        cbf (float): The CBF voxel value
        att (float): The ATT voxel value
        t2b (float, optional): The T2 relaxation value for blood. Defaults to 165.0.
        t2csf (float, optional): The T2 relaxation value for CSF. Defaults to 75.0.
        tblcsf (float, optional): The T1 relaxation value between blood and CSF. Defaults to 1400.0.
        alpha (float, optional): The pulse labeling efficiency. Defaults to 0.85.
        t1b (float, optional): The T1 relaxation value for blood. Defaults to 1650.0.
        t1csf (float, optional): The T1 relaxation value for CSF. Defaults to 1400.0.

    Returns:
        (nd.ndarray): The magnetization values for T1-Blood-GM
    """
    t1bp = 1 / ((1 / t1b) + (1 / tblcsf))
    t1csfp = 1 / ((1 / t1csf) + (1 / tblcsf))

    t2bp = 1 / ((1 / t2b) + (1 / tblcsf))
    t2csfp = 1 / ((1 / t2csf) + (1 / tblcsf))

    t = np.add(tau, w).tolist()

    mag_total = np.zeros(len(tau))

    for i in range(0, len(tau)):
        try:
            if t[i] < att:
                S1b = 0.0
                S1csf = 0.0
                if te[i] < (att - t[i]):
                    Sb = 0
                    Scsf = 0
                elif (att - t[i]) <= te[i] and te[i] < (att + tau[i] - t[i]):
                    Sb = (
                        2
                        * alpha
                        * m0
                        * cbf
                        * t2bp
                        * math.exp(-att / t1b)
                        * math.exp(-te[i] / t2b)
                        * (1 - math.exp(-(te[i] - att + t[i]) / t2bp))
                    )   #% measured signal = S2
                    Scsf = (
                        2
                        * alpha
                        * m0
                        * cbf
                        * math.exp(-att / t1b)
                        * math.exp(-te[i] / t2b)
                        * (
                            t2csf
                            * (1 - math.exp(-(te[i] - att + t[i]) / t2csf))
                            - t2csfp
                            * (1 - math.exp(-(te[i] - att + t[i]) / t2csfp))
                        )
                    )
                else:   #% att + tau - t <= te
                    Sb = (
                        2
                        * alpha
                        * m0
                        * cbf
                        * t2bp
                        * math.exp(-att / t1b)
                        * math.exp(-te[i] / t2b)
                        * math.exp(-(te[i] - att + t[i]) / t2bp)
                        * (math.exp(tau[i] / t2bp) - 1)
                    )
                    Scsf = (
                        2
                        * alpha
                        * m0
                        * cbf
                        * math.exp(-att / t1b)
                        * math.exp(-te[i] / t2b)
                        * (
                            t2csf
                            * math.exp(-(te[i] - att + t[i]) / t2csf)
                            * (math.exp(tau[i] / t2csf) - 1)
                            - t2csfp
                            * math.exp(-(te[i] - att + t[i]) / t2csfp)
                            * (math.exp(tau[i] / t2csfp) - 1)
                        )
                    )
            elif (att <= t[i]) and (t[i] < (att + tau[i])):
                S1b = (
                    2
                    * alpha
                    * m0
                    * cbf
                    * t1bp
                    * math.exp(-att / t1b)
                    * (1 - math.exp(-(t[i] - att) / t1bp))
                )
                S1csf = (
                    2
                    * alpha
                    * m0
                    * cbf
                    * math.exp(-att / t1b)
                    * (
                        t1csf * (1 - math.exp(-(t[i] - att) / t1csf))
                        - t1csfp * (1 - math.exp(-(t[i] - att) / t1csfp))
                    )
                )
                if te[i] < (att + tau[i] - t[i]):
                    Sb = S1b * math.exp(
                        -te[i] / t2bp
                    ) + 2 * alpha * m0 * cbf * t2bp * math.exp(
                        -att / t1b
                    ) * math.exp(
                        -te[i] / t2b
                    ) * (
                        1 - math.exp(-te[i] / t2bp)
                    )
                    Scsf = (
                        S1b
                        * (1 - math.exp(-te[i] / tblcsf))
                        * math.exp(-te[i] / t2csf)
                        + S1csf * math.exp(-te[i] / t2csf)
                        + 2
                        * alpha
                        * m0
                        * cbf
                        * math.exp(-att / t1b)
                        * math.exp(-te[i] / t2b)
                        * (
                            t2csf * (1 - math.exp(-te[i] / t2csf))
                            - t2csfp * (1 - math.exp(-te[i] / t2csfp))
                        )
                    )
                else:   # att + tau - t <= te
                    Sb = S1b * math.exp(
                        -te[i] / t2bp
                    ) + 2 * alpha * m0 * cbf * t2bp * math.exp(
                        -att / t1b
                    ) * math.exp(
                        -te[i] / t2b
                    ) * math.exp(
                        -te[i] / t2bp
                    ) * (
                        math.exp((att + tau[i] - t[i]) / t2bp) - 1
                    )
                    Scsf = (
                        S1b
                        * (1 - math.exp(-te[i] / tblcsf))
                        * math.exp(-te[i] / t2csf)
                        + S1csf * math.exp(-te[i] / t2csf)
                        + 2
                        * alpha
                        * m0
                        * cbf
                        * math.exp(-att / t1b)
                        * math.exp(-te[i] / t2b)
                        * (
                            t2csf
                            * math.exp(-te[i] / t2csf)
                            * (math.exp((att + tau[i] - t[i]) / t2csf) - 1)
                            - t2csfp
                            * math.exp(-te[i] / t2csfp)
                            * (math.exp((att + tau[i] - t[i]) / t2csfp) - 1)
                        )
                    )
            else:   # att+tau < t
                S1b = (
                    2
                    * alpha
                    * m0
                    * cbf
                    * t1bp
                    * math.exp(-att / t1b)
                    * math.exp(-(t[i] - att) / t1bp)
                    * (math.exp(tau[i] / t1bp) - 1)
                )
                S1csf = (
                    2
                    * alpha
                    * m0
                    * cbf
                    * math.exp(-att / t1b)
                    * (
                        t1csf
                        * math.exp(-(t[i] - att) / t1csf)
                        * (math.exp(tau[i] / t1csf) - 1)
                        - t1csfp
                        * math.exp(-(t[i] - att) / t1csfp)
                        * (math.exp(tau[i] / t1csfp) - 1)
                    )
                )

                Sb = S1b * math.exp(-te[i] / t2bp)
                Scsf = S1b * (1 - math.exp(-te[i] / tblcsf)) * math.exp(
                    -te[i] / t2csf
                ) + S1csf * math.exp(-te[i] / t2csf)
        except (OverflowError, RuntimeError):   # pragma: no cover
            Sb = 0.0
            Scsf = 0.0

        mag_total[i] = Sb + Scsf

    return mag_total