vbi 0.1.3__cp310-cp310-manylinux2014_x86_64.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (121) hide show
  1. vbi/__init__.py +37 -0
  2. vbi/_version.py +17 -0
  3. vbi/dataset/__init__.py +0 -0
  4. vbi/dataset/connectivity_84/centers.txt +84 -0
  5. vbi/dataset/connectivity_84/centres.txt +84 -0
  6. vbi/dataset/connectivity_84/cortical.txt +84 -0
  7. vbi/dataset/connectivity_84/tract_lengths.txt +84 -0
  8. vbi/dataset/connectivity_84/weights.txt +84 -0
  9. vbi/dataset/connectivity_88/Aud_88.txt +88 -0
  10. vbi/dataset/connectivity_88/Bold.npz +0 -0
  11. vbi/dataset/connectivity_88/Labels.txt +17 -0
  12. vbi/dataset/connectivity_88/Region_labels.txt +88 -0
  13. vbi/dataset/connectivity_88/tract_lengths.txt +88 -0
  14. vbi/dataset/connectivity_88/weights.txt +88 -0
  15. vbi/feature_extraction/__init__.py +1 -0
  16. vbi/feature_extraction/calc_features.py +293 -0
  17. vbi/feature_extraction/features.json +535 -0
  18. vbi/feature_extraction/features.py +2124 -0
  19. vbi/feature_extraction/features_settings.py +374 -0
  20. vbi/feature_extraction/features_utils.py +1357 -0
  21. vbi/feature_extraction/infodynamics.jar +0 -0
  22. vbi/feature_extraction/utility.py +507 -0
  23. vbi/inference.py +98 -0
  24. vbi/models/__init__.py +0 -0
  25. vbi/models/cpp/__init__.py +0 -0
  26. vbi/models/cpp/_src/__init__.py +0 -0
  27. vbi/models/cpp/_src/__pycache__/mpr_sde.cpython-310.pyc +0 -0
  28. vbi/models/cpp/_src/_do.cpython-310-x86_64-linux-gnu.so +0 -0
  29. vbi/models/cpp/_src/_jr_sdde.cpython-310-x86_64-linux-gnu.so +0 -0
  30. vbi/models/cpp/_src/_jr_sde.cpython-310-x86_64-linux-gnu.so +0 -0
  31. vbi/models/cpp/_src/_km_sde.cpython-310-x86_64-linux-gnu.so +0 -0
  32. vbi/models/cpp/_src/_mpr_sde.cpython-310-x86_64-linux-gnu.so +0 -0
  33. vbi/models/cpp/_src/_vep.cpython-310-x86_64-linux-gnu.so +0 -0
  34. vbi/models/cpp/_src/_wc_ode.cpython-310-x86_64-linux-gnu.so +0 -0
  35. vbi/models/cpp/_src/bold.hpp +303 -0
  36. vbi/models/cpp/_src/do.hpp +167 -0
  37. vbi/models/cpp/_src/do.i +17 -0
  38. vbi/models/cpp/_src/do.py +467 -0
  39. vbi/models/cpp/_src/do_wrap.cxx +12811 -0
  40. vbi/models/cpp/_src/jr_sdde.hpp +352 -0
  41. vbi/models/cpp/_src/jr_sdde.i +19 -0
  42. vbi/models/cpp/_src/jr_sdde.py +688 -0
  43. vbi/models/cpp/_src/jr_sdde_wrap.cxx +18718 -0
  44. vbi/models/cpp/_src/jr_sde.hpp +264 -0
  45. vbi/models/cpp/_src/jr_sde.i +17 -0
  46. vbi/models/cpp/_src/jr_sde.py +470 -0
  47. vbi/models/cpp/_src/jr_sde_wrap.cxx +13406 -0
  48. vbi/models/cpp/_src/km_sde.hpp +158 -0
  49. vbi/models/cpp/_src/km_sde.i +19 -0
  50. vbi/models/cpp/_src/km_sde.py +671 -0
  51. vbi/models/cpp/_src/km_sde_wrap.cxx +17367 -0
  52. vbi/models/cpp/_src/makefile +52 -0
  53. vbi/models/cpp/_src/mpr_sde.hpp +327 -0
  54. vbi/models/cpp/_src/mpr_sde.i +19 -0
  55. vbi/models/cpp/_src/mpr_sde.py +711 -0
  56. vbi/models/cpp/_src/mpr_sde_wrap.cxx +18618 -0
  57. vbi/models/cpp/_src/utility.hpp +307 -0
  58. vbi/models/cpp/_src/vep.hpp +171 -0
  59. vbi/models/cpp/_src/vep.i +16 -0
  60. vbi/models/cpp/_src/vep.py +464 -0
  61. vbi/models/cpp/_src/vep_wrap.cxx +12968 -0
  62. vbi/models/cpp/_src/wc_ode.hpp +294 -0
  63. vbi/models/cpp/_src/wc_ode.i +19 -0
  64. vbi/models/cpp/_src/wc_ode.py +686 -0
  65. vbi/models/cpp/_src/wc_ode_wrap.cxx +24263 -0
  66. vbi/models/cpp/damp_oscillator.py +143 -0
  67. vbi/models/cpp/jansen_rit.py +543 -0
  68. vbi/models/cpp/km.py +187 -0
  69. vbi/models/cpp/mpr.py +289 -0
  70. vbi/models/cpp/vep.py +150 -0
  71. vbi/models/cpp/wc.py +216 -0
  72. vbi/models/cupy/__init__.py +0 -0
  73. vbi/models/cupy/bold.py +111 -0
  74. vbi/models/cupy/ghb.py +284 -0
  75. vbi/models/cupy/jansen_rit.py +473 -0
  76. vbi/models/cupy/km.py +224 -0
  77. vbi/models/cupy/mpr.py +475 -0
  78. vbi/models/cupy/mpr_modified_bold.py +12 -0
  79. vbi/models/cupy/utils.py +184 -0
  80. vbi/models/numba/__init__.py +0 -0
  81. vbi/models/numba/_ww_EI.py +444 -0
  82. vbi/models/numba/damp_oscillator.py +162 -0
  83. vbi/models/numba/ghb.py +208 -0
  84. vbi/models/numba/mpr.py +383 -0
  85. vbi/models/pytorch/__init__.py +0 -0
  86. vbi/models/pytorch/data/default_parameters.npz +0 -0
  87. vbi/models/pytorch/data/input/ROI_sim.mat +0 -0
  88. vbi/models/pytorch/data/input/fc_test.csv +68 -0
  89. vbi/models/pytorch/data/input/fc_train.csv +68 -0
  90. vbi/models/pytorch/data/input/fc_vali.csv +68 -0
  91. vbi/models/pytorch/data/input/fcd_test.mat +0 -0
  92. vbi/models/pytorch/data/input/fcd_test_high_window.mat +0 -0
  93. vbi/models/pytorch/data/input/fcd_test_low_window.mat +0 -0
  94. vbi/models/pytorch/data/input/fcd_train.mat +0 -0
  95. vbi/models/pytorch/data/input/fcd_vali.mat +0 -0
  96. vbi/models/pytorch/data/input/myelin.csv +68 -0
  97. vbi/models/pytorch/data/input/rsfc_gradient.csv +68 -0
  98. vbi/models/pytorch/data/input/run_label_testset.mat +0 -0
  99. vbi/models/pytorch/data/input/sc_test.csv +68 -0
  100. vbi/models/pytorch/data/input/sc_train.csv +68 -0
  101. vbi/models/pytorch/data/input/sc_vali.csv +68 -0
  102. vbi/models/pytorch/data/obs_kong0.npz +0 -0
  103. vbi/models/pytorch/ww_sde_kong.py +570 -0
  104. vbi/models/tvbk/__init__.py +9 -0
  105. vbi/models/tvbk/tvbk_wrapper.py +166 -0
  106. vbi/models/tvbk/utils.py +72 -0
  107. vbi/papers/__init__.py +0 -0
  108. vbi/papers/pavlides_pcb_2015/pavlides.py +211 -0
  109. vbi/tests/__init__.py +0 -0
  110. vbi/tests/_test_mpr_nb.py +36 -0
  111. vbi/tests/test_features.py +355 -0
  112. vbi/tests/test_ghb_cupy.py +90 -0
  113. vbi/tests/test_mpr_cupy.py +49 -0
  114. vbi/tests/test_mpr_numba.py +84 -0
  115. vbi/tests/test_suite.py +19 -0
  116. vbi/utils.py +402 -0
  117. vbi-0.1.3.dist-info/METADATA +166 -0
  118. vbi-0.1.3.dist-info/RECORD +121 -0
  119. vbi-0.1.3.dist-info/WHEEL +5 -0
  120. vbi-0.1.3.dist-info/licenses/LICENSE +201 -0
  121. vbi-0.1.3.dist-info/top_level.txt +1 -0
vbi/models/cupy/mpr.py ADDED
@@ -0,0 +1,475 @@
1
+ import os
2
+ import tqdm
3
+ import logging
4
+ import numpy as np
5
+ from copy import copy
6
+ from vbi.models.cupy.utils import *
7
+
8
+ try:
9
+ import cupy as cp
10
+ except ImportError:
11
+ logging.warning("Cupy is not installed. Using Numpy instead.")
12
+
13
+
14
+ class Bold:
15
+
16
+ def __init__(self, par: dict = {}) -> None:
17
+
18
+ self._par = self.get_default_parameters()
19
+ self.valid_parameters = list(self._par.keys())
20
+ self.check_parameters(par)
21
+ self._par.update(par)
22
+
23
+ for item in self._par.items():
24
+ setattr(self, item[0], item[1])
25
+ self.update_dependent_parameters()
26
+
27
+
28
+ def get_default_parameters(self):
29
+ """get balloon model parameters."""
30
+
31
+ vo = 0.08
32
+ theta = 40.3
33
+ TE = 0.04
34
+ Eo = 0.4
35
+ r0 = 25.0
36
+ epsilon = 0.34
37
+ k1 = 4.3 * theta * Eo * TE
38
+ k2 = epsilon * r0 * Eo * TE
39
+ k3 = 1 - epsilon
40
+
41
+ par = {
42
+ "kappa": 0.65,
43
+ "gamma": 0.41,
44
+ "tau": 0.98,
45
+ "alpha": 0.32,
46
+ "epsilon": epsilon,
47
+ "Eo": Eo,
48
+ "TE": TE,
49
+ "vo": vo,
50
+ "r0": r0,
51
+ "theta": theta,
52
+ "t_min": 0.0,
53
+ "rtol": 1e-5,
54
+ "atol": 1e-8,
55
+ "k1": k1,
56
+ "k2": k2,
57
+ "k3": k3
58
+ }
59
+ return par
60
+
61
+ def update_dependent_parameters(self):
62
+ self.k1 = 4.3 * self.theta * self.Eo * self.TE
63
+ self.k2 = self.epsilon * self.r0 * self.Eo * self.TE
64
+ self.k3 = 1 - self.epsilon
65
+
66
+ def check_parameters(self, par):
67
+ for key in par.keys():
68
+ if key not in self.valid_parameters:
69
+ raise ValueError(f"Invalid parameter {key:s} provided.")
70
+
71
+ def allocate_memory(self, xp, nn, ns, n_steps, bold_decimate, dtype):
72
+
73
+ self.s = xp.zeros((2, nn, ns), dtype=dtype)
74
+ self.f = xp.zeros((2, nn, ns), dtype=dtype)
75
+ self.ftilde = xp.zeros((2, nn, ns), dtype=dtype)
76
+ self.vtilde = xp.zeros((2, nn, ns), dtype=dtype)
77
+ self.qtilde = xp.zeros((2, nn, ns), dtype=dtype)
78
+ self.v = xp.zeros((2, nn, ns), dtype=dtype)
79
+ self.q = xp.zeros((2, nn, ns), dtype=dtype)
80
+ self.vv = np.zeros((n_steps // bold_decimate, nn, ns), dtype="f")
81
+ self.qq = np.zeros((n_steps // bold_decimate, nn, ns), dtype="f")
82
+ self.s[0] = 1
83
+ self.f[0] = 1
84
+ self.v[0] = 1
85
+ self.q[0] = 1
86
+ self.ftilde[0] = 0
87
+ self.vtilde[0] = 0
88
+ self.qtilde[0] = 0
89
+
90
+ def do_bold_step(self, r_in, dtt):
91
+
92
+ Eo = self.Eo
93
+ tau = self.tau
94
+ kappa = self.kappa
95
+ gamma = self.gamma
96
+ alpha = self.alpha
97
+ ialpha = 1 / alpha
98
+
99
+ v = self.v
100
+ q = self.q
101
+ s = self.s
102
+ f = self.f
103
+ ftilde = self.ftilde
104
+ vtilde = self.vtilde
105
+ qtilde = self.qtilde
106
+
107
+ s[1] = s[0] + dtt * (r_in - kappa * s[0] - gamma * (f[0] - 1))
108
+ f[0] = np.clip(f[0], 1, None)
109
+ ftilde[1] = ftilde[0] + dtt * (s[0] / f[0])
110
+ fv = v[0] ** ialpha # outflow
111
+ vtilde[1] = vtilde[0] + dtt * ((f[0] - fv) / (tau * v[0]))
112
+ q[0] = np.clip(q[0], 0.01, None)
113
+ ff = (1 - (1 - Eo) ** (1 / f[0])) / Eo # oxygen extraction
114
+ qtilde[1] = qtilde[0] + dtt * ((f[0] * ff - fv * q[0] / v[0]) / (tau * q[0]))
115
+
116
+ f[1] = np.exp(ftilde[1])
117
+ v[1] = np.exp(vtilde[1])
118
+ q[1] = np.exp(qtilde[1])
119
+
120
+ f[0] = f[1]
121
+ s[0] = s[1]
122
+ ftilde[0] = ftilde[1]
123
+ vtilde[0] = vtilde[1]
124
+ qtilde[0] = qtilde[1]
125
+ v[0] = v[1]
126
+ q[0] = q[1]
127
+
128
+
129
+
130
+ class MPR_sde:
131
+ """
132
+ Montbrio-Pazo-Roxin model Cupy and Numpy implementation.
133
+
134
+ Parameters
135
+ ----------
136
+
137
+ G: float. np.ndarray
138
+ global coupling strength
139
+ dt: float
140
+ time step
141
+ dt_bold: float
142
+ time step for Balloon model
143
+ J: float, np.ndarray
144
+ model parameter
145
+ eta: float, np.ndarray
146
+ model parameter
147
+ tau:
148
+ model parameter
149
+ delta:
150
+ model parameter
151
+ tr: float
152
+ repetition time of fMRI
153
+ noise_amp: float
154
+ amplitude of noise
155
+ same_noise_per_sim:
156
+ same noise for all simulations
157
+ iapp: float, np.ndarray
158
+ external input
159
+ t_start: float
160
+ initial time
161
+ t_cut: float
162
+ transition time
163
+ t_end: float
164
+ end time
165
+ num_nodes: int
166
+ number of nodes
167
+ weights: np.ndarray
168
+ weighted connection matrix
169
+ rv_decimate: int
170
+ sampling step from r and v
171
+ output: str
172
+ output directory
173
+ RECORD_TS: bool
174
+ store r and v time series
175
+ num_sim: int
176
+ number of simulations
177
+ method: str
178
+ integration method
179
+ engine: str
180
+ cpu or gpu
181
+ seed: int
182
+ seed for random number generator
183
+ dtype: str
184
+ float or f
185
+ initial_state: np.ndarray
186
+ initial state
187
+ same_initial_state: bool
188
+ same initial state for all simulations
189
+
190
+ """
191
+
192
+ def __init__(self, par: dict = {}, Bpar:dict = {}) -> None:
193
+
194
+ self._par = self.get_default_parameters()
195
+ self.valid_parameters = list(self._par.keys())
196
+ self.check_parameters(par)
197
+ self._par.update(par)
198
+
199
+ for item in self._par.items():
200
+ name = item[0]
201
+ value = item[1]
202
+ setattr(self, name, value)
203
+
204
+ self.B = Bold(Bpar)
205
+
206
+ self.xp = get_module(self.engine)
207
+ if self.seed is not None:
208
+ self.xp.random.seed(self.seed)
209
+
210
+ os.makedirs(self.output, exist_ok=True)
211
+
212
+ def __call__(self):
213
+ print("Montbrió, Pazó, Roxin model.")
214
+ return self._par
215
+
216
+ def __str__(self) -> str:
217
+ print("Montbrió, Pazó, Roxin model.")
218
+ print("----------------")
219
+ for item in self._par.items():
220
+ name = item[0]
221
+ value = item[1]
222
+ print(f"{name} = {value}")
223
+ return ""
224
+
225
+ def set_initial_state(self):
226
+ self.initial_state = set_initial_state(
227
+ self.nn,
228
+ self.num_sim,
229
+ self.engine,
230
+ self.seed,
231
+ self.same_initial_state,
232
+ self.dtype,
233
+ )
234
+
235
+ def get_default_parameters(self):
236
+
237
+ par = {
238
+ "G": 0.72, # global coupling strength
239
+ "dt": 0.01, # dt for mpr model [ms]
240
+ "dt_bold": 0.001, # dt for Balloon model [s]
241
+ "J": 14.5, # model parameter
242
+ "eta": -4.6,
243
+ "tau": 1.0, # model parameter
244
+ "delta": 0.7, # model parameter
245
+ "tr": 500.0, # repetition time [ms]
246
+ "noise_amp": 0.037, # amplitude of noise
247
+ "same_noise_per_sim": False, # same noise for all simulations
248
+ "sti_apply": False, # apply stimulation
249
+ "iapp": 0.0, # external input
250
+ "t_start": 0.0, # initial time [ms]
251
+ "t_cut": 0, # transition time [ms]
252
+ "t_end": 300_000, # end time [ms]
253
+ "num_nodes": None, # number of nodes
254
+ "weights": None, # weighted connection matrix
255
+ "rv_decimate": 10, # sampling step from r and v
256
+ "output": "output", # output directory
257
+ "RECORD_RV": False, # store r and v time series
258
+ "RECORD_BOLD": True, # store BOLD signal
259
+ "RECORD_AVG_r": False, # store average_r
260
+ "num_sim": 1,
261
+ "method": "heun",
262
+ "engine": "cpu",
263
+ "seed": None,
264
+ "dtype": "float",
265
+ "initial_state": None,
266
+ "same_initial_state": False,
267
+ }
268
+ dt = par["dt"]
269
+ noise_amp = par["noise_amp"]
270
+ sigma_r = np.sqrt(dt) * np.sqrt(2 * noise_amp)
271
+ sigma_v = np.sqrt(dt) * np.sqrt(4 * noise_amp)
272
+ par["sigma_r"] = sigma_r
273
+ par["sigma_v"] = sigma_v
274
+ # par.update(self.get_balloon_parameters())
275
+
276
+ return par
277
+
278
+ def check_parameters(self, par):
279
+ for key in par.keys():
280
+ if key not in self.valid_parameters:
281
+ raise ValueError(f"Invalid parameter {key:s} provided.")
282
+
283
+ def prepare_input(self):
284
+
285
+ self.G = self.xp.array(self.G)
286
+ assert self.weights is not None, "weights must be provided"
287
+ self.weights = self.xp.array(self.weights).T # ! Directed network #!TODO: check
288
+ self.weights = move_data(self.weights, self.engine)
289
+ self.nn = self.num_nodes = self.weights.shape[0]
290
+
291
+ if self.initial_state is None:
292
+ self.set_initial_state()
293
+
294
+ self.t_end = self.t_end / 10.0
295
+ self.t_start = self.t_start / 10.0
296
+ self.t_cut = self.t_cut / 10.0
297
+ self.eta = prepare_vec(self.eta, self.num_sim, self.engine, self.dtype)
298
+ self.J = prepare_vec(self.J, self.num_sim, self.engine, self.dtype)
299
+ self.delta = prepare_vec(self.delta, self.num_sim, self.engine, self.dtype)
300
+
301
+ def f_mpr(self, x, t):
302
+ """
303
+ MPR model
304
+ """
305
+
306
+ G = self.G
307
+ J = self.J
308
+ xp = self.xp
309
+ weights = self.weights
310
+ tau = self.tau
311
+ eta = self.eta
312
+ iapp = self.iapp
313
+ ns = self.num_sim
314
+ delta = self.delta
315
+ nn = self.num_nodes
316
+ rtau = 1.0 / tau
317
+ x0 = x[:nn, :]
318
+ x1 = x[nn:, :]
319
+ dxdt = xp.zeros((2 * nn, ns)).astype(self.dtype)
320
+ tau_pi_inv = 1.0 / (tau * np.pi)
321
+ pi2 = np.pi * np.pi
322
+ tau2 = tau * tau
323
+
324
+ coupling = weights @ x0
325
+ dxdt[:nn, :] = rtau * (delta * tau_pi_inv + 2 * x0 * x1)
326
+ dxdt[nn:, :] = rtau * (
327
+ x1 * x1 + eta + iapp + J * tau * x0 - (pi2 * tau2 * x0 * x0) + G * coupling
328
+ )
329
+
330
+ return dxdt
331
+
332
+ def heunStochastic(self, y, t, dt):
333
+ """Heun scheme to integrate MPR model with noise."""
334
+
335
+ xp = self.xp
336
+ nn = self.num_nodes
337
+ ns = self.num_sim
338
+
339
+ if not self.same_noise_per_sim:
340
+ dW_r = self.sigma_r * xp.random.randn(nn, ns)
341
+ dW_v = self.sigma_v * xp.random.randn(nn, ns)
342
+ else:
343
+ dW_r = self.sigma_r * xp.random.randn(nn, 1)
344
+ dW_v = self.sigma_v * xp.random.randn(nn, 1)
345
+
346
+ k1 = self.f_mpr(y, t)
347
+ tmp = y + dt * k1
348
+ tmp[:nn, :] += dW_r
349
+ tmp[nn:, :] += dW_v
350
+
351
+ k2 = self.f_mpr(tmp, t + dt)
352
+ y += 0.5 * dt * (k1 + k2)
353
+ y[:nn, :] += dW_r
354
+ y[:nn, :] = (y[:nn, :] > 0) * y[:nn, :] # set zero if negative
355
+ y[nn:, :] += dW_v
356
+
357
+ def sync_(self, engine="gpu"):
358
+ if engine == "gpu":
359
+ cp.cuda.Stream.null.synchronize()
360
+ else:
361
+ pass
362
+
363
+ def run(self, verbose=True):
364
+
365
+ self.prepare_input()
366
+ dt = self.dt
367
+ rv_decimate = self.rv_decimate
368
+ r_period = dt * 10 # extenting time
369
+ dtt = r_period / 1000.0 # in seconds
370
+ tr = self.tr
371
+ xp = self.xp
372
+ ns = self.num_sim
373
+ nn = self.num_nodes
374
+ engine = self.engine
375
+
376
+ n_steps = int(self.t_end / dt)
377
+ bold_decimate = int(np.round(tr / r_period))
378
+
379
+ B = self.B
380
+ B.allocate_memory(xp, nn, ns, n_steps, bold_decimate, self.dtype)
381
+
382
+ rv_curr = copy(self.initial_state)
383
+ rv_d = np.array([])
384
+ rv_t = np.array([])
385
+ avg_r = np.array([])
386
+ bold_d = np.array([])
387
+ bold_t = np.array([])
388
+
389
+ if self.RECORD_RV:
390
+ rv_d = np.zeros((n_steps // rv_decimate, 2 * nn, ns), dtype="f")
391
+ rv_t = np.zeros((n_steps // rv_decimate), dtype="f")
392
+
393
+ if self.RECORD_AVG_r:
394
+ avg_r = np.zeros((nn, ns), dtype="f")
395
+
396
+ cc = 0
397
+ for i in tqdm.trange(n_steps - 1, disable=not verbose, desc="Integrating"):
398
+
399
+ t_curr = i * dt
400
+ self.heunStochastic(rv_curr, t_curr, dt)
401
+
402
+ if ((i % rv_decimate) == 0) and ((i // rv_decimate) < rv_d.shape[0]):
403
+
404
+ if self.RECORD_RV:
405
+ rv_d[i // rv_decimate] = get_(rv_curr, engine, "f")
406
+ rv_t[i // rv_decimate] = t_curr
407
+
408
+ if self.RECORD_AVG_r and i > n_steps // 2:
409
+ avg_r += get_(rv_curr[:nn, :], engine, "f")
410
+ cc += 1
411
+
412
+ if self.RECORD_BOLD:
413
+ B.do_bold_step(rv_curr[:nn, :], dtt)
414
+
415
+ if (i % bold_decimate == 0) and ((i // bold_decimate) < B.vv.shape[0]):
416
+ B.vv[i // bold_decimate] = get_(B.v[1], engine, "f")
417
+ B.qq[i // bold_decimate] = get_(B.q[1], engine, "f")
418
+
419
+ if self.RECORD_BOLD:
420
+ bold_d = B.vo * (B.k1 * (1 - B.qq) + B.k2 * (1 - B.qq / B.vv) + B.k3 * (1 - B.vv))
421
+ bold_t = np.linspace(0, self.t_end - dt * bold_decimate, len(bold_d))
422
+ bold_d = bold_d[bold_t > self.t_cut, ...]
423
+ bold_t = bold_t[bold_t > self.t_cut]
424
+ bold_t = bold_t * 10.0
425
+ avg_r = avg_r / cc
426
+
427
+ if self.RECORD_RV:
428
+ rv_t = np.asarray(rv_t).astype("f")
429
+ rv_d = rv_d[rv_t > self.t_cut, ...]
430
+ rv_t = rv_t[rv_t > self.t_cut] * 10.0
431
+
432
+ return {
433
+ "rv_t": rv_t,
434
+ "rv_d": rv_d,
435
+ "fmri_t": bold_t,
436
+ "fmri_d": bold_d,
437
+ "avg_r": avg_r,
438
+ }
439
+
440
+
441
+ def set_initial_state(nn, ns, engine, seed=None, same_initial_state=False, dtype=float):
442
+ """
443
+ Set initial state
444
+
445
+ Parameters
446
+ ----------
447
+ nn : int
448
+ number of nodes
449
+ ns : int
450
+ number of simulations
451
+ engine : str
452
+ cpu or gpu
453
+ same_initial_condition : bool
454
+ same initial condition for all simulations
455
+ seed : int
456
+ random seed
457
+ dtype : str
458
+ float: float64
459
+ f : float32
460
+ """
461
+
462
+ if seed is not None:
463
+ np.random.seed(seed)
464
+
465
+ if same_initial_state:
466
+ y0 = np.random.rand(2 * nn)
467
+ y0 = repmat_vec(y0, ns, engine)
468
+ else:
469
+ y0 = np.random.rand(2 * nn, ns)
470
+ y0 = move_data(y0, engine)
471
+
472
+ y0[:nn, :] = y0[:nn, :] * 1.5
473
+ y0[nn:, :] = y0[nn:, :] * 4 - 2
474
+
475
+ return y0.astype(dtype)
@@ -0,0 +1,12 @@
1
+ import warnings
2
+ from vbi.models.cupy.mpr import MPR_sde
3
+
4
+ warnings.warn(
5
+ "The module 'vbi.models.cupy.mpr_modified_bold' is deprecated and will be removed in a future version. "
6
+ "Please use 'vbi.models.cupy.mpr' instead.",
7
+ DeprecationWarning,
8
+ stacklevel=2,
9
+ )
10
+
11
+ # Re-export the object(s) from the new module for backward compatibility
12
+ __all__ = ["MPR_sde"]
@@ -0,0 +1,184 @@
1
+ import numpy as np
2
+
3
+ try:
4
+ import cupy as cp
5
+ except:
6
+ cp = None
7
+
8
+
9
+ def get_module(engine="gpu"):
10
+ """
11
+ Switches the computational engine between GPU and CPU.
12
+
13
+ Parameters
14
+ ----------
15
+ engine : str, optional
16
+ The computational engine to use. Can be either "gpu" or "cpu".
17
+ Default is "gpu".
18
+
19
+ Returns
20
+ -------
21
+ module
22
+ The appropriate array module based on the specified engine.
23
+ If "gpu", returns the CuPy module. If "cpu", returns the NumPy module.
24
+
25
+ Raises
26
+ ------
27
+ ValueError
28
+ - If the specified engine is not "gpu" or "cpu".
29
+ - If CuPy is not installed.
30
+ """
31
+
32
+ if engine == "gpu":
33
+ if cp is None:
34
+ raise ValueError("CuPy is not installed.")
35
+ else:
36
+ return cp.get_array_module(cp.array([1]))
37
+ else:
38
+ return np
39
+ # return cp.get_array_module(np.array([1]))
40
+
41
+
42
+ def tohost(x):
43
+ '''
44
+ move data to cpu if it is on gpu
45
+
46
+ Parameters
47
+ ----------
48
+ x: array
49
+ data
50
+
51
+ Returns
52
+ -------
53
+ array
54
+ data moved to cpu
55
+ '''
56
+ if cp is not None and isinstance(x, cp.ndarray):
57
+ return cp.asnumpy(x)
58
+ return x
59
+
60
+
61
+ def todevice(x):
62
+ '''
63
+ move data to gpu
64
+
65
+ Parameters
66
+ ----------
67
+ x: array
68
+ data
69
+
70
+ Returns
71
+ -------
72
+ array
73
+ data moved to gpu
74
+
75
+ '''
76
+ return cp.asarray(x)
77
+
78
+
79
+ def move_data(x, engine):
80
+ if engine == "cpu":
81
+ return tohost(x)
82
+ elif engine == "gpu":
83
+ return todevice(x)
84
+
85
+
86
+ def repmat_vec(vec, ns, engine):
87
+ '''
88
+ repeat vector ns times
89
+
90
+ Parameters
91
+ ----------
92
+ vec: array 1d
93
+ vector to be repeated
94
+ ns: int
95
+ number of repetitions
96
+ engine: str
97
+ cpu or gpu
98
+
99
+ Returns
100
+ -------
101
+ vec: array [len(vec), n_sim]
102
+ repeated vector
103
+
104
+ '''
105
+ vec = np.tile(vec, (ns, 1)).T
106
+ vec = move_data(vec, engine)
107
+ return vec
108
+
109
+
110
+ def is_seq(x):
111
+ '''
112
+ check if x is a sequence
113
+
114
+ Parameters
115
+ ----------
116
+ x: any
117
+ variable to be checked
118
+
119
+ Returns
120
+ -------
121
+ bool
122
+ True if x is a sequence
123
+
124
+ '''
125
+ return hasattr(x, '__iter__')
126
+
127
+
128
+ def prepare_vec(x, ns, engine, dtype="float"):
129
+ '''
130
+ check and prepare vector dimension and type
131
+
132
+ Parameters
133
+ ----------
134
+ x: array 1d
135
+ vector to be prepared, if x is a scalar, only the type is changed
136
+ ns: int
137
+ number of simulations
138
+ engine: str
139
+ cpu or gpu
140
+
141
+ Returns
142
+ -------
143
+ x: array [len(x), n_sim]
144
+ prepared vector
145
+
146
+ '''
147
+ xp = get_module(engine)
148
+
149
+ if not is_seq(x):
150
+ return eval(f"{dtype}({x})")
151
+ else:
152
+ x = np.array(x)
153
+ if x.ndim == 1:
154
+ x = repmat_vec(x, ns, engine)
155
+ elif x.ndim == 2:
156
+ assert(x.shape[1] == ns), "second dimension of x must be equal to ns"
157
+ x = move_data(x, engine)
158
+ else:
159
+ raise ValueError("x.ndim must be 1 or 2")
160
+ return x.astype(dtype)
161
+
162
+
163
+ def get_(x, engine="cpu", dtype="f"):
164
+ """
165
+ Parameters
166
+ ----------
167
+ x : array-like
168
+ The input array to be converted.
169
+ engine : str, optional
170
+ The computation engine to use. If "gpu", the array is transferred from GPU to CPU. Defaults to "cpu".
171
+ dtype : str, optional
172
+ The desired data type for the output array. Defaults to "f".
173
+
174
+ Returns
175
+ -------
176
+ array-like
177
+ The converted array with the specified data type.
178
+
179
+ """
180
+
181
+ if engine == "gpu":
182
+ return x.get().astype(dtype)
183
+ else:
184
+ return x.astype(dtype)
File without changes