rapidtide 3.0.1__py3-none-any.whl → 3.0.2__py3-none-any.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.
- rapidtide/DerivativeDelay.py +0 -4
- rapidtide/data/examples/src/testretro +9 -13
- rapidtide/happy_supportfuncs.py +70 -234
- rapidtide/io.py +19 -23
- rapidtide/refinedelay.py +4 -7
- rapidtide/tests/cleanposttest +0 -1
- rapidtide/tests/test_fullrunrapidtide_v3.py +10 -0
- rapidtide/tests/test_fullrunrapidtide_v6.py +0 -1
- rapidtide/tests/test_refinedelay.py +0 -3
- rapidtide/voxelData.py +125 -14
- rapidtide/workflows/delayestimation.py +8 -13
- rapidtide/workflows/delayvar.py +11 -13
- rapidtide/workflows/happy.py +72 -179
- rapidtide/workflows/rapidtide.py +99 -226
- rapidtide/workflows/regressfrommaps.py +12 -7
- rapidtide/workflows/retroregress.py +396 -336
- {rapidtide-3.0.1.dist-info → rapidtide-3.0.2.dist-info}/METADATA +1 -1
- {rapidtide-3.0.1.dist-info → rapidtide-3.0.2.dist-info}/RECORD +22 -22
- {rapidtide-3.0.1.dist-info → rapidtide-3.0.2.dist-info}/WHEEL +1 -1
- {rapidtide-3.0.1.dist-info → rapidtide-3.0.2.dist-info}/entry_points.txt +0 -0
- {rapidtide-3.0.1.dist-info → rapidtide-3.0.2.dist-info}/licenses/LICENSE +0 -0
- {rapidtide-3.0.1.dist-info → rapidtide-3.0.2.dist-info}/top_level.txt +0 -0
rapidtide/voxelData.py
CHANGED
|
@@ -16,14 +16,78 @@
|
|
|
16
16
|
# limitations under the License.
|
|
17
17
|
#
|
|
18
18
|
#
|
|
19
|
+
import copy
|
|
20
|
+
|
|
19
21
|
import numpy as np
|
|
20
|
-
from tf_keras.src.layers.preprocessing.benchmarks.index_lookup_forward_benchmark import (
|
|
21
|
-
get_vocab,
|
|
22
|
-
)
|
|
23
22
|
from tqdm import tqdm
|
|
24
23
|
|
|
25
24
|
import rapidtide.filter as tide_filt
|
|
26
25
|
import rapidtide.io as tide_io
|
|
26
|
+
import rapidtide.util as tide_util
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
class dataVolume:
|
|
30
|
+
xsize = None
|
|
31
|
+
ysize = None
|
|
32
|
+
numslices = None
|
|
33
|
+
numspatiallocs = None
|
|
34
|
+
timepoints = None
|
|
35
|
+
dtype = None
|
|
36
|
+
dimensions = None
|
|
37
|
+
data = None
|
|
38
|
+
data_shm = None
|
|
39
|
+
thepid = None
|
|
40
|
+
|
|
41
|
+
def __init__(
|
|
42
|
+
self,
|
|
43
|
+
shape,
|
|
44
|
+
shared=False,
|
|
45
|
+
dtype=np.float64,
|
|
46
|
+
thepid=0,
|
|
47
|
+
):
|
|
48
|
+
if len(shape) == 3:
|
|
49
|
+
self.xsize = int(shape[0])
|
|
50
|
+
self.ysize = int(shape[1])
|
|
51
|
+
self.numslices = int(shape[2])
|
|
52
|
+
self.timepoints = 1
|
|
53
|
+
self.dimensions = 3
|
|
54
|
+
elif len(shape) == 4:
|
|
55
|
+
self.xsize = int(shape[0])
|
|
56
|
+
self.ysize = int(shape[1])
|
|
57
|
+
self.numslices = int(shape[2])
|
|
58
|
+
self.timepoints = int(shape[3])
|
|
59
|
+
self.dimensions = 4
|
|
60
|
+
else:
|
|
61
|
+
print(f"illegal shape: {shape}")
|
|
62
|
+
self.numspatiallocs = self.xsize * self.ysize * self.numslices
|
|
63
|
+
self.dtype = dtype
|
|
64
|
+
if not shared:
|
|
65
|
+
self.data = np.zeros(shape, dtype=dtype)
|
|
66
|
+
else:
|
|
67
|
+
self.data, self.data_shm = tide_util.allocshared(
|
|
68
|
+
shape, self.dtype, name=f"filtereddata_{thepid}"
|
|
69
|
+
)
|
|
70
|
+
return self.data
|
|
71
|
+
|
|
72
|
+
def byvol(self):
|
|
73
|
+
return self.data
|
|
74
|
+
|
|
75
|
+
def byslice(self):
|
|
76
|
+
if self.dimensions == 3:
|
|
77
|
+
return self.data.reshape(self.xsize * self.ysize, -1)
|
|
78
|
+
else:
|
|
79
|
+
return self.data.reshape(self.xsize * self.ysize, self.numslices, -1)
|
|
80
|
+
|
|
81
|
+
def byvoxel(self):
|
|
82
|
+
if self.dimensions == 3:
|
|
83
|
+
return self.data.reshape(self.numspatiallocs)
|
|
84
|
+
else:
|
|
85
|
+
return self.data.reshape(self.numspatiallocs, -1)
|
|
86
|
+
|
|
87
|
+
def destroy(self):
|
|
88
|
+
del self.data
|
|
89
|
+
if self.data_shm is not None:
|
|
90
|
+
tide_util.cleanup_shm(self.data_shm)
|
|
27
91
|
|
|
28
92
|
|
|
29
93
|
class VoxelData:
|
|
@@ -36,14 +100,17 @@ class VoxelData:
|
|
|
36
100
|
ysize = None
|
|
37
101
|
numslices = None
|
|
38
102
|
timepoints = None
|
|
103
|
+
realtimepoints = None
|
|
39
104
|
xdim = None
|
|
40
105
|
ydim = None
|
|
41
106
|
slicethickness = None
|
|
42
107
|
timestep = None
|
|
43
108
|
thesizes = None
|
|
44
109
|
thedims = None
|
|
110
|
+
numslicelocs = None
|
|
45
111
|
numspatiallocs = None
|
|
46
112
|
nativespaceshape = None
|
|
113
|
+
nativefmrishape = None
|
|
47
114
|
validvoxels = None
|
|
48
115
|
cifti_hdr = None
|
|
49
116
|
filetype = None
|
|
@@ -71,7 +138,8 @@ class VoxelData:
|
|
|
71
138
|
self.xsize = self.theshape[0]
|
|
72
139
|
self.ysize = 1
|
|
73
140
|
self.numslices = 1
|
|
74
|
-
self.
|
|
141
|
+
self.numslicelocs = None
|
|
142
|
+
self.timepoints = int(self.theshape[1])
|
|
75
143
|
self.thesizes = [0, int(self.xsize), 1, 1, int(self.timepoints)]
|
|
76
144
|
self.toffset = 0.0
|
|
77
145
|
self.numspatiallocs = int(self.xsize)
|
|
@@ -81,7 +149,8 @@ class VoxelData:
|
|
|
81
149
|
if tide_io.checkifcifti(self.filename):
|
|
82
150
|
self.filetype = "cifti"
|
|
83
151
|
self.nim_affine = None
|
|
84
|
-
self.
|
|
152
|
+
self.numslicelocs = None
|
|
153
|
+
self.timepoints = int(self.nim_data.shape[1])
|
|
85
154
|
self.numspatiallocs = self.nim_data.shape[0]
|
|
86
155
|
self.nativespaceshape = (1, 1, 1, 1, self.numspatiallocs)
|
|
87
156
|
else:
|
|
@@ -90,6 +159,7 @@ class VoxelData:
|
|
|
90
159
|
self.xsize, self.ysize, self.numslices, self.timepoints = tide_io.parseniftidims(
|
|
91
160
|
self.thedims
|
|
92
161
|
)
|
|
162
|
+
self.numslicelocs = int(self.xsize) * int(self.ysize)
|
|
93
163
|
self.numspatiallocs = int(self.xsize) * int(self.ysize) * int(self.numslices)
|
|
94
164
|
self.cifti_hdr = None
|
|
95
165
|
self.nativespaceshape = (self.xsize, self.ysize, self.numslices)
|
|
@@ -120,6 +190,30 @@ class VoxelData:
|
|
|
120
190
|
self.setvalidtimes(validstart, validend)
|
|
121
191
|
self.resident = True
|
|
122
192
|
|
|
193
|
+
def copyheader(self, numtimepoints=None, tr=None, toffset=None):
|
|
194
|
+
if self.filetype == "text":
|
|
195
|
+
return None
|
|
196
|
+
else:
|
|
197
|
+
thisheader = copy.deepcopy(self.nim_hdr)
|
|
198
|
+
if self.filetype == "cifti":
|
|
199
|
+
timeindex = thisheader["dim"][0] - 1
|
|
200
|
+
spaceindex = thisheader["dim"][0]
|
|
201
|
+
thisheader["dim"][timeindex] = numtimepoints
|
|
202
|
+
thisheader["dim"][spaceindex] = self.numspatiallocs
|
|
203
|
+
else:
|
|
204
|
+
if numtimepoints is not None:
|
|
205
|
+
thisheader["dim"][4] = numtimepoints
|
|
206
|
+
if numtimepoints > 1:
|
|
207
|
+
thisheader["dim"][0] = 4
|
|
208
|
+
else:
|
|
209
|
+
thisheader["dim"][0] = 3
|
|
210
|
+
thisheader["pixdim"][4] = 1.0
|
|
211
|
+
if toffset is not None:
|
|
212
|
+
thisheader["toffset"] = toffset
|
|
213
|
+
if tr is not None:
|
|
214
|
+
thisheader["pixdim"][4] = tr
|
|
215
|
+
return thisheader
|
|
216
|
+
|
|
123
217
|
def getsizes(self):
|
|
124
218
|
return self.xdim, self.ydim, self.slicethickness, self.timestep
|
|
125
219
|
|
|
@@ -167,32 +261,48 @@ class VoxelData:
|
|
|
167
261
|
self.validend = self.timepoints - 1
|
|
168
262
|
else:
|
|
169
263
|
self.validend = validend
|
|
264
|
+
self.realtimepoints = self.validend - self.validstart + 1
|
|
265
|
+
if self.filetype == "nifti":
|
|
266
|
+
self.nativefmrishape = (self.xsize, self.ysize, self.numslices, self.realtimepoints)
|
|
267
|
+
elif self.filetype == "cifti":
|
|
268
|
+
self.nativefmrishape = (1, 1, 1, self.realtimepoints, self.numspatiallocs)
|
|
269
|
+
else:
|
|
270
|
+
self.nativefmrishape = (self.xsize, self.realtimepoints)
|
|
170
271
|
|
|
171
272
|
def setvalidvoxels(self, validvoxels):
|
|
172
273
|
self.validvoxels = validvoxels
|
|
173
274
|
self.numvalidspatiallocs = np.shape(self.validvoxels)[0]
|
|
174
275
|
|
|
175
|
-
def
|
|
276
|
+
def byvol(self):
|
|
176
277
|
if not self.resident:
|
|
177
278
|
self.load()
|
|
178
279
|
return self.nim_data
|
|
179
280
|
|
|
180
|
-
def
|
|
281
|
+
def byvoltrimmed(self):
|
|
181
282
|
if not self.resident:
|
|
182
283
|
self.load()
|
|
183
284
|
if self.filetype == "nifti":
|
|
184
285
|
return self.nim_data[:, :, :, self.validstart : self.validend + 1]
|
|
185
286
|
else:
|
|
186
|
-
return self.nim_data[:, self.validstart: self.validend + 1]
|
|
287
|
+
return self.nim_data[:, self.validstart : self.validend + 1]
|
|
288
|
+
|
|
289
|
+
def byvoxel(self):
|
|
290
|
+
return self.byvoltrimmed().reshape(self.numspatiallocs, -1)
|
|
187
291
|
|
|
188
|
-
def
|
|
189
|
-
return self.
|
|
292
|
+
def byslice(self):
|
|
293
|
+
return self.byvoltrimmed().reshape(self.numslicelocs, self.numslices, -1)
|
|
190
294
|
|
|
191
|
-
def
|
|
295
|
+
def validdata(self):
|
|
192
296
|
if self.validvoxels is None:
|
|
193
|
-
return self.
|
|
297
|
+
return self.byvoxel()
|
|
194
298
|
else:
|
|
195
|
-
return self.
|
|
299
|
+
return self.byvoxel()[self.validvoxels, :]
|
|
300
|
+
|
|
301
|
+
# def validdatabyslice(self):
|
|
302
|
+
# if self.validvoxels is None:
|
|
303
|
+
# return self.byslice()
|
|
304
|
+
# else:
|
|
305
|
+
# return self.byvoxel()[self.validvoxels, :].reshape(self.numslicelocs, self.numslices, -1)
|
|
196
306
|
|
|
197
307
|
def smooth(
|
|
198
308
|
self,
|
|
@@ -241,7 +351,7 @@ class VoxelData:
|
|
|
241
351
|
f"applying gaussian spatial filter to timepoints {self.validstart} "
|
|
242
352
|
f"to {self.validend} with sigma={gausssigma}"
|
|
243
353
|
)
|
|
244
|
-
sourcedata = self.
|
|
354
|
+
sourcedata = self.byvol()
|
|
245
355
|
for i in tqdm(
|
|
246
356
|
range(self.validstart, self.validend + 1),
|
|
247
357
|
desc="Timepoint",
|
|
@@ -271,6 +381,7 @@ class VoxelData:
|
|
|
271
381
|
print(f"\t{self.timestep=}")
|
|
272
382
|
print(f"\t{self.thesizes=}")
|
|
273
383
|
print(f"\t{self.thedims=}")
|
|
384
|
+
print(f"\t{self.numslicelocs=}")
|
|
274
385
|
print(f"\t{self.numspatiallocs=}")
|
|
275
386
|
print(f"\t{self.nativespaceshape=}")
|
|
276
387
|
print(f"\t{self.cifti_hdr=}")
|
|
@@ -130,7 +130,7 @@ def estimateDelay(voxeldata, datatimeaxis, osdatatimeaxis, theMutualInformationa
|
|
|
130
130
|
if optiondict["checkpoint"]:
|
|
131
131
|
outcorrarray[:, :] = 0.0
|
|
132
132
|
outcorrarray[validvoxels, :] = corrout[:, :]
|
|
133
|
-
if
|
|
133
|
+
if theinputdata.filetype == "text":
|
|
134
134
|
tide_io.writenpvecs(
|
|
135
135
|
outcorrarray.reshape(nativecorrshape),
|
|
136
136
|
f"{outputname}_corrout_prefit_pass" + str(thepass) + ".txt",
|
|
@@ -320,8 +320,8 @@ def estimateDelay(voxeldata, datatimeaxis, osdatatimeaxis, theMutualInformationa
|
|
|
320
320
|
if optiondict["savedespecklemasks"] and (optiondict["despeckle_passes"] > 0):
|
|
321
321
|
despecklesavemask = np.where(internaldespeckleincludemask[validvoxels] == 0.0, 0, 1)
|
|
322
322
|
if thepass == optiondict["passes"]:
|
|
323
|
-
if
|
|
324
|
-
if
|
|
323
|
+
if theinputdata.filetype != "text":
|
|
324
|
+
if theinputdata.filetype == "cifti":
|
|
325
325
|
timeindex = theheader["dim"][0] - 1
|
|
326
326
|
spaceindex = theheader["dim"][0]
|
|
327
327
|
theheader["dim"][timeindex] = 1
|
|
@@ -346,8 +346,7 @@ def estimateDelay(voxeldata, datatimeaxis, osdatatimeaxis, theMutualInformationa
|
|
|
346
346
|
nativespaceshape,
|
|
347
347
|
theheader,
|
|
348
348
|
bidsbasedict,
|
|
349
|
-
|
|
350
|
-
fileiscifti=fileiscifti,
|
|
349
|
+
filetype=theinputdata.filetype,
|
|
351
350
|
rt_floattype=rt_floattype,
|
|
352
351
|
cifti_hdr=cifti_hdr,
|
|
353
352
|
)
|
|
@@ -384,8 +383,7 @@ def estimateDelay(voxeldata, datatimeaxis, osdatatimeaxis, theMutualInformationa
|
|
|
384
383
|
nativespaceshape,
|
|
385
384
|
theheader,
|
|
386
385
|
bidsbasedict,
|
|
387
|
-
|
|
388
|
-
fileiscifti=fileiscifti,
|
|
386
|
+
filetype=theinputdata.filetype,
|
|
389
387
|
rt_floattype=rt_floattype,
|
|
390
388
|
cifti_hdr=cifti_hdr,
|
|
391
389
|
)
|
|
@@ -417,8 +415,7 @@ def estimateDelay(voxeldata, datatimeaxis, osdatatimeaxis, theMutualInformationa
|
|
|
417
415
|
nativespaceshape,
|
|
418
416
|
theheader,
|
|
419
417
|
bidsbasedict,
|
|
420
|
-
|
|
421
|
-
fileiscifti=fileiscifti,
|
|
418
|
+
filetype=theinputdata.filetype,
|
|
422
419
|
rt_floattype=rt_floattype,
|
|
423
420
|
cifti_hdr=cifti_hdr,
|
|
424
421
|
)
|
|
@@ -442,8 +439,7 @@ def estimateDelay(voxeldata, datatimeaxis, osdatatimeaxis, theMutualInformationa
|
|
|
442
439
|
nativespaceshape,
|
|
443
440
|
theheader,
|
|
444
441
|
bidsbasedict,
|
|
445
|
-
|
|
446
|
-
fileiscifti=fileiscifti,
|
|
442
|
+
filetype=theinputdata.filetype,
|
|
447
443
|
rt_floattype=rt_floattype,
|
|
448
444
|
cifti_hdr=cifti_hdr,
|
|
449
445
|
)
|
|
@@ -478,8 +474,7 @@ def estimateDelay(voxeldata, datatimeaxis, osdatatimeaxis, theMutualInformationa
|
|
|
478
474
|
nativespaceshape,
|
|
479
475
|
theheader,
|
|
480
476
|
bidsbasedict,
|
|
481
|
-
|
|
482
|
-
fileiscifti=fileiscifti,
|
|
477
|
+
filetype=theinputdata.filetype,
|
|
483
478
|
rt_floattype=rt_floattype,
|
|
484
479
|
cifti_hdr=cifti_hdr,
|
|
485
480
|
)
|
rapidtide/workflows/delayvar.py
CHANGED
|
@@ -36,6 +36,7 @@ import rapidtide.refinedelay as tide_refinedelay
|
|
|
36
36
|
import rapidtide.resample as tide_resample
|
|
37
37
|
import rapidtide.stats as tide_stats
|
|
38
38
|
import rapidtide.util as tide_util
|
|
39
|
+
import rapidtide.voxelData as tide_voxelData
|
|
39
40
|
import rapidtide.workflows.parser_funcs as pf
|
|
40
41
|
import rapidtide.workflows.regressfrommaps as tide_regressfrommaps
|
|
41
42
|
|
|
@@ -381,19 +382,19 @@ def delayvar(args):
|
|
|
381
382
|
|
|
382
383
|
# read the fmri input files
|
|
383
384
|
print("reading fmrifile")
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
)
|
|
385
|
+
theinputdata = tide_voxelData.VoxelData(args.fmrifile)
|
|
386
|
+
xsize, ysize, numslices, timepoints = theinputdata.getdims()
|
|
387
|
+
xdim, ydim, slicethickness, fmritr = theinputdata.getsizes()
|
|
388
|
+
fmri_header = theinputdata.copyheader()
|
|
389
|
+
fmri_data = theinputdata.byvol()
|
|
390
|
+
numspatiallocs = theinputdata.numspatiallocs
|
|
387
391
|
|
|
388
392
|
# create the canary file
|
|
389
393
|
Path(f"{outputname}_DELAYVARISRUNNING.txt").touch()
|
|
390
394
|
|
|
391
395
|
if args.debug:
|
|
392
396
|
print(f"{fmri_data.shape=}")
|
|
393
|
-
|
|
394
|
-
xsize, ysize, numslices, timepoints = tide_io.parseniftidims(fmri_dims)
|
|
395
|
-
numspatiallocs = int(xsize) * int(ysize) * int(numslices)
|
|
396
|
-
fmri_data_spacebytime = fmri_data.reshape((numspatiallocs, timepoints))
|
|
397
|
+
fmri_data_spacebytime = theinputdata.byvoxel()
|
|
397
398
|
if args.debug:
|
|
398
399
|
print(f"{fmri_data_spacebytime.shape=}")
|
|
399
400
|
|
|
@@ -530,7 +531,7 @@ def delayvar(args):
|
|
|
530
531
|
|
|
531
532
|
if args.windelayoffsetgausssigma < 0.0:
|
|
532
533
|
# set gausssigma automatically
|
|
533
|
-
args.windelayoffsetgausssigma = np.mean([xdim, ydim,
|
|
534
|
+
args.windelayoffsetgausssigma = np.mean([xdim, ydim, slicethickness]) / 2.0
|
|
534
535
|
|
|
535
536
|
wintrs = int(np.round(args.windowsize / fmritr, 0))
|
|
536
537
|
wintrs += wintrs % 2
|
|
@@ -590,8 +591,7 @@ def delayvar(args):
|
|
|
590
591
|
(xsize, ysize, numslices, validtimepoints),
|
|
591
592
|
theheader,
|
|
592
593
|
bidsbasedict,
|
|
593
|
-
|
|
594
|
-
fileiscifti=False,
|
|
594
|
+
filetype=theinputdata.filetype,
|
|
595
595
|
rt_floattype=rt_floattype,
|
|
596
596
|
cifti_hdr=None,
|
|
597
597
|
)
|
|
@@ -737,11 +737,9 @@ def delayvar(args):
|
|
|
737
737
|
windowedregressderivratios[:, thewin],
|
|
738
738
|
(xsize, ysize, numslices),
|
|
739
739
|
validvoxels,
|
|
740
|
-
(xdim, ydim,
|
|
740
|
+
(xdim, ydim, slicethickness),
|
|
741
741
|
gausssigma=args.windelayoffsetgausssigma,
|
|
742
742
|
patchthresh=args.delaypatchthresh,
|
|
743
|
-
fileiscifti=False,
|
|
744
|
-
textio=False,
|
|
745
743
|
rt_floattype=rt_floattype,
|
|
746
744
|
verbose=args.verbose,
|
|
747
745
|
debug=args.debug,
|