rapidtide 3.0.11__py3-none-any.whl → 3.1__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/Colortables.py +492 -27
- rapidtide/OrthoImageItem.py +1049 -46
- rapidtide/RapidtideDataset.py +1533 -86
- rapidtide/_version.py +3 -3
- rapidtide/calccoherence.py +196 -29
- rapidtide/calcnullsimfunc.py +191 -40
- rapidtide/calcsimfunc.py +245 -42
- rapidtide/correlate.py +1210 -393
- rapidtide/data/examples/src/testLD +56 -0
- rapidtide/data/examples/src/testalign +1 -1
- rapidtide/data/examples/src/testdelayvar +0 -1
- rapidtide/data/examples/src/testfmri +19 -1
- rapidtide/data/examples/src/testglmfilt +5 -5
- rapidtide/data/examples/src/testhappy +25 -3
- rapidtide/data/examples/src/testppgproc +17 -0
- rapidtide/data/examples/src/testrolloff +11 -0
- rapidtide/data/models/model_cnn_pytorch/best_model.pth +0 -0
- rapidtide/data/models/model_cnn_pytorch/loss.png +0 -0
- rapidtide/data/models/model_cnn_pytorch/loss.txt +1 -0
- rapidtide/data/models/model_cnn_pytorch/model.pth +0 -0
- rapidtide/data/models/model_cnn_pytorch/model_meta.json +68 -0
- rapidtide/decorators.py +91 -0
- rapidtide/dlfilter.py +2225 -108
- rapidtide/dlfiltertorch.py +4843 -0
- rapidtide/externaltools.py +327 -12
- rapidtide/fMRIData_class.py +79 -40
- rapidtide/filter.py +1899 -810
- rapidtide/fit.py +2004 -574
- rapidtide/genericmultiproc.py +93 -18
- rapidtide/happy_supportfuncs.py +2044 -171
- rapidtide/helper_classes.py +584 -43
- rapidtide/io.py +2363 -370
- rapidtide/linfitfiltpass.py +341 -75
- rapidtide/makelaggedtcs.py +211 -20
- rapidtide/maskutil.py +423 -53
- rapidtide/miscmath.py +827 -121
- rapidtide/multiproc.py +210 -22
- rapidtide/patchmatch.py +234 -33
- rapidtide/peakeval.py +32 -30
- rapidtide/ppgproc.py +2203 -0
- rapidtide/qualitycheck.py +352 -39
- rapidtide/refinedelay.py +422 -57
- rapidtide/refineregressor.py +498 -184
- rapidtide/resample.py +671 -185
- rapidtide/scripts/applyppgproc.py +28 -0
- rapidtide/simFuncClasses.py +1052 -77
- rapidtide/simfuncfit.py +260 -46
- rapidtide/stats.py +540 -238
- rapidtide/tests/happycomp +9 -0
- rapidtide/tests/test_dlfiltertorch.py +627 -0
- rapidtide/tests/test_findmaxlag.py +24 -8
- rapidtide/tests/test_fullrunhappy_v1.py +0 -2
- rapidtide/tests/test_fullrunhappy_v2.py +0 -2
- rapidtide/tests/test_fullrunhappy_v3.py +1 -0
- rapidtide/tests/test_fullrunhappy_v4.py +2 -2
- rapidtide/tests/test_fullrunrapidtide_v7.py +1 -1
- rapidtide/tests/test_simroundtrip.py +8 -8
- rapidtide/tests/utils.py +9 -8
- rapidtide/tidepoolTemplate.py +142 -38
- rapidtide/tidepoolTemplate_alt.py +165 -44
- rapidtide/tidepoolTemplate_big.py +189 -52
- rapidtide/util.py +1217 -118
- rapidtide/voxelData.py +684 -37
- rapidtide/wiener.py +19 -12
- rapidtide/wiener2.py +113 -7
- rapidtide/wiener_doc.py +255 -0
- rapidtide/workflows/adjustoffset.py +105 -3
- rapidtide/workflows/aligntcs.py +85 -2
- rapidtide/workflows/applydlfilter.py +87 -10
- rapidtide/workflows/applyppgproc.py +522 -0
- rapidtide/workflows/atlasaverage.py +210 -47
- rapidtide/workflows/atlastool.py +100 -3
- rapidtide/workflows/calcSimFuncMap.py +294 -64
- rapidtide/workflows/calctexticc.py +201 -9
- rapidtide/workflows/ccorrica.py +97 -4
- rapidtide/workflows/cleanregressor.py +168 -29
- rapidtide/workflows/delayvar.py +163 -10
- rapidtide/workflows/diffrois.py +81 -3
- rapidtide/workflows/endtidalproc.py +144 -4
- rapidtide/workflows/fdica.py +195 -15
- rapidtide/workflows/filtnifti.py +70 -3
- rapidtide/workflows/filttc.py +74 -3
- rapidtide/workflows/fitSimFuncMap.py +206 -48
- rapidtide/workflows/fixtr.py +73 -3
- rapidtide/workflows/gmscalc.py +113 -3
- rapidtide/workflows/happy.py +801 -199
- rapidtide/workflows/happy2std.py +144 -12
- rapidtide/workflows/happy_parser.py +138 -9
- rapidtide/workflows/histnifti.py +118 -2
- rapidtide/workflows/histtc.py +84 -3
- rapidtide/workflows/linfitfilt.py +117 -4
- rapidtide/workflows/localflow.py +328 -28
- rapidtide/workflows/mergequality.py +79 -3
- rapidtide/workflows/niftidecomp.py +322 -18
- rapidtide/workflows/niftistats.py +174 -4
- rapidtide/workflows/pairproc.py +88 -2
- rapidtide/workflows/pairwisemergenifti.py +85 -2
- rapidtide/workflows/parser_funcs.py +1421 -40
- rapidtide/workflows/physiofreq.py +137 -11
- rapidtide/workflows/pixelcomp.py +208 -5
- rapidtide/workflows/plethquality.py +103 -21
- rapidtide/workflows/polyfitim.py +151 -11
- rapidtide/workflows/proj2flow.py +75 -2
- rapidtide/workflows/rankimage.py +111 -4
- rapidtide/workflows/rapidtide.py +272 -15
- rapidtide/workflows/rapidtide2std.py +98 -2
- rapidtide/workflows/rapidtide_parser.py +109 -9
- rapidtide/workflows/refineDelayMap.py +143 -33
- rapidtide/workflows/refineRegressor.py +682 -93
- rapidtide/workflows/regressfrommaps.py +152 -31
- rapidtide/workflows/resamplenifti.py +85 -3
- rapidtide/workflows/resampletc.py +91 -3
- rapidtide/workflows/retrolagtcs.py +98 -6
- rapidtide/workflows/retroregress.py +165 -9
- rapidtide/workflows/roisummarize.py +173 -5
- rapidtide/workflows/runqualitycheck.py +71 -3
- rapidtide/workflows/showarbcorr.py +147 -4
- rapidtide/workflows/showhist.py +86 -2
- rapidtide/workflows/showstxcorr.py +160 -3
- rapidtide/workflows/showtc.py +159 -3
- rapidtide/workflows/showxcorrx.py +184 -4
- rapidtide/workflows/showxy.py +185 -15
- rapidtide/workflows/simdata.py +262 -36
- rapidtide/workflows/spatialfit.py +77 -2
- rapidtide/workflows/spatialmi.py +251 -27
- rapidtide/workflows/spectrogram.py +305 -32
- rapidtide/workflows/synthASL.py +154 -3
- rapidtide/workflows/tcfrom2col.py +76 -2
- rapidtide/workflows/tcfrom3col.py +74 -2
- rapidtide/workflows/tidepool.py +2969 -130
- rapidtide/workflows/utils.py +19 -14
- rapidtide/workflows/utils_doc.py +293 -0
- rapidtide/workflows/variabilityizer.py +116 -3
- {rapidtide-3.0.11.dist-info → rapidtide-3.1.dist-info}/METADATA +3 -2
- {rapidtide-3.0.11.dist-info → rapidtide-3.1.dist-info}/RECORD +139 -122
- {rapidtide-3.0.11.dist-info → rapidtide-3.1.dist-info}/entry_points.txt +1 -0
- {rapidtide-3.0.11.dist-info → rapidtide-3.1.dist-info}/WHEEL +0 -0
- {rapidtide-3.0.11.dist-info → rapidtide-3.1.dist-info}/licenses/LICENSE +0 -0
- {rapidtide-3.0.11.dist-info → rapidtide-3.1.dist-info}/top_level.txt +0 -0
rapidtide/workflows/happy.py
CHANGED
|
@@ -22,8 +22,10 @@ import sys
|
|
|
22
22
|
import time
|
|
23
23
|
import warnings
|
|
24
24
|
from pathlib import Path
|
|
25
|
+
from typing import Any, Callable, Dict, List, Optional, Tuple, Union
|
|
25
26
|
|
|
26
27
|
import numpy as np
|
|
28
|
+
from numpy.typing import NDArray
|
|
27
29
|
|
|
28
30
|
import rapidtide.correlate as tide_corr
|
|
29
31
|
import rapidtide.filter as tide_filt
|
|
@@ -49,23 +51,104 @@ try:
|
|
|
49
51
|
except ImportError:
|
|
50
52
|
mklexists = False
|
|
51
53
|
|
|
52
|
-
try:
|
|
53
|
-
import rapidtide.dlfilter as tide_dlfilt
|
|
54
|
-
|
|
55
|
-
dlfilterexists = True
|
|
56
|
-
print("dlfilter exists")
|
|
57
|
-
except ImportError:
|
|
58
|
-
dlfilterexists = False
|
|
59
|
-
print("dlfilter does not exist")
|
|
60
54
|
|
|
61
|
-
|
|
62
|
-
|
|
55
|
+
def happy_main(argparsingfunc: Any) -> None:
|
|
56
|
+
"""
|
|
57
|
+
Process fMRI data to remove cardiac noise using temporal and/or spatial regression.
|
|
58
|
+
|
|
59
|
+
This function performs cardiac noise regression on fMRI data using either
|
|
60
|
+
temporal or spatial regression methods. It calculates cardiac noise signals
|
|
61
|
+
from the cardiac phase information and removes them from the fMRI data.
|
|
62
|
+
|
|
63
|
+
Parameters
|
|
64
|
+
----------
|
|
65
|
+
args : argparse.Namespace
|
|
66
|
+
Command line arguments containing processing options
|
|
67
|
+
infodict : dict
|
|
68
|
+
Dictionary containing processing information including shared memory settings
|
|
69
|
+
fmri_data : numpy.ndarray
|
|
70
|
+
4D fMRI data array (x, y, z, time)
|
|
71
|
+
mask : numpy.ndarray
|
|
72
|
+
3D mask array indicating valid voxels
|
|
73
|
+
projmask_byslice : numpy.ndarray
|
|
74
|
+
2D mask array for each slice indicating valid projection locations
|
|
75
|
+
cardphasevals : numpy.ndarray
|
|
76
|
+
2D array of cardiac phase values for each slice and timepoint
|
|
77
|
+
rawapp_byslice : numpy.ndarray
|
|
78
|
+
3D array of raw cardiac signals for each slice and timepoint
|
|
79
|
+
outphases : numpy.ndarray
|
|
80
|
+
Array of cardiac phases
|
|
81
|
+
timepoints : int
|
|
82
|
+
Number of timepoints in the fMRI data
|
|
83
|
+
xsize : int
|
|
84
|
+
X dimension of the fMRI data
|
|
85
|
+
ysize : int
|
|
86
|
+
Y dimension of the fMRI data
|
|
87
|
+
numslices : int
|
|
88
|
+
Number of slices in the fMRI data
|
|
89
|
+
outputroot : str
|
|
90
|
+
Root name for output files
|
|
91
|
+
tide_util : module
|
|
92
|
+
Utility module for memory management and other operations
|
|
93
|
+
tide_io : module
|
|
94
|
+
I/O module for reading/writing data
|
|
95
|
+
tide_linfitfiltpass : module
|
|
96
|
+
Linear fitting and filtering module
|
|
97
|
+
tide_filt : module
|
|
98
|
+
Filtering module
|
|
99
|
+
platform : module
|
|
100
|
+
Platform information module
|
|
101
|
+
Path : class
|
|
102
|
+
Path class from pathlib module
|
|
103
|
+
|
|
104
|
+
Returns
|
|
105
|
+
-------
|
|
106
|
+
None
|
|
107
|
+
Function performs in-place processing and saves results to files
|
|
108
|
+
|
|
109
|
+
Notes
|
|
110
|
+
-----
|
|
111
|
+
This function performs multiple steps:
|
|
112
|
+
1. Calculates cardiac noise signals from cardiac phase information
|
|
113
|
+
2. Applies temporal or spatial regression to remove cardiac noise
|
|
114
|
+
3. Saves filtered data and regression coefficients
|
|
115
|
+
4. Handles shared memory cleanup when needed
|
|
116
|
+
|
|
117
|
+
Examples
|
|
118
|
+
--------
|
|
119
|
+
>>> process_fmri_with_cardiac_regression(
|
|
120
|
+
... args, infodict, fmri_data, mask, projmask_byslice,
|
|
121
|
+
... cardphasevals, rawapp_byslice, outphases,
|
|
122
|
+
... timepoints, xsize, ysize, numslices,
|
|
123
|
+
... outputroot, tide_util, tide_io, tide_linfitfiltpass,
|
|
124
|
+
... tide_filt, platform, Path
|
|
125
|
+
... )
|
|
126
|
+
"""
|
|
63
127
|
timings = [["Start", time.time(), None, None]]
|
|
64
128
|
|
|
65
129
|
# get the command line parameters
|
|
66
130
|
args = argparsingfunc
|
|
67
131
|
infodict = vars(args)
|
|
68
132
|
|
|
133
|
+
if args.usepytorch:
|
|
134
|
+
try:
|
|
135
|
+
import rapidtide.dlfiltertorch as tide_dlfilt
|
|
136
|
+
|
|
137
|
+
dlfilterexists = True
|
|
138
|
+
print("pytorch dlfilter initialized")
|
|
139
|
+
except ImportError:
|
|
140
|
+
dlfilterexists = False
|
|
141
|
+
print("pytorch dlfilter could not be initialized")
|
|
142
|
+
else:
|
|
143
|
+
try:
|
|
144
|
+
import rapidtide.dlfilter as tide_dlfilt
|
|
145
|
+
|
|
146
|
+
dlfilterexists = True
|
|
147
|
+
print("tensorflow dlfilter initialized")
|
|
148
|
+
except ImportError:
|
|
149
|
+
dlfilterexists = False
|
|
150
|
+
print("tensorflow dlfilter could not be initialized")
|
|
151
|
+
|
|
69
152
|
fmrifilename = args.fmrifilename
|
|
70
153
|
slicetimename = args.slicetimename
|
|
71
154
|
outputroot = args.outputroot
|
|
@@ -92,7 +175,7 @@ def happy_main(argparsingfunc):
|
|
|
92
175
|
logger_filename=f"{outputroot}_log.txt",
|
|
93
176
|
timing_filename=f"{outputroot}_runtimings.tsv",
|
|
94
177
|
memory_filename=f"{outputroot}_memusage.tsv",
|
|
95
|
-
|
|
178
|
+
isverbose=args.verbose,
|
|
96
179
|
debug=args.debug,
|
|
97
180
|
)
|
|
98
181
|
|
|
@@ -113,6 +196,8 @@ def happy_main(argparsingfunc):
|
|
|
113
196
|
"***********************************************************************************************************************************")
|
|
114
197
|
print("")"""
|
|
115
198
|
|
|
199
|
+
infodict["pid"] = os.getpid()
|
|
200
|
+
|
|
116
201
|
infodict["fmrifilename"] = fmrifilename
|
|
117
202
|
infodict["slicetimename"] = slicetimename
|
|
118
203
|
infodict["outputroot"] = outputroot
|
|
@@ -139,6 +224,12 @@ def happy_main(argparsingfunc):
|
|
|
139
224
|
"CommandLineArgs": args.commandline,
|
|
140
225
|
}
|
|
141
226
|
|
|
227
|
+
# decide if we need to use shared memory
|
|
228
|
+
if args.nprocs > 1:
|
|
229
|
+
infodict["sharedmem"] = True
|
|
230
|
+
else:
|
|
231
|
+
infodict["sharedmem"] = False
|
|
232
|
+
|
|
142
233
|
# save the information file
|
|
143
234
|
if args.saveinfoasjson:
|
|
144
235
|
tide_io.writedicttojson(infodict, outputroot + "_info.json")
|
|
@@ -199,6 +290,7 @@ def happy_main(argparsingfunc):
|
|
|
199
290
|
args.processmask,
|
|
200
291
|
input_data.copyheader(numtimepoints=1),
|
|
201
292
|
xsize,
|
|
293
|
+
thresh=0.001,
|
|
202
294
|
maskname="process",
|
|
203
295
|
debug=args.debug,
|
|
204
296
|
)
|
|
@@ -209,10 +301,25 @@ def happy_main(argparsingfunc):
|
|
|
209
301
|
theheader = input_data.copyheader(numtimepoints=1)
|
|
210
302
|
timings.append(["Mask created", time.time(), None, None])
|
|
211
303
|
if args.outputlevel > 0:
|
|
212
|
-
maskfilename = outputroot + "_desc-processvoxels_mask"
|
|
213
304
|
bidsdict = bidsbasedict.copy()
|
|
214
|
-
|
|
215
|
-
|
|
305
|
+
maplist = [
|
|
306
|
+
(
|
|
307
|
+
mask.reshape((xsize, ysize, numslices)),
|
|
308
|
+
"processvoxels",
|
|
309
|
+
"mask",
|
|
310
|
+
None,
|
|
311
|
+
"fMRI voxels processed by happy",
|
|
312
|
+
),
|
|
313
|
+
]
|
|
314
|
+
tide_io.savemaplist(
|
|
315
|
+
outputroot,
|
|
316
|
+
maplist,
|
|
317
|
+
None,
|
|
318
|
+
(xsize, ysize, numslices),
|
|
319
|
+
theheader,
|
|
320
|
+
bidsdict,
|
|
321
|
+
debug=args.debug,
|
|
322
|
+
)
|
|
216
323
|
timings.append(["Mask saved", time.time(), None, None])
|
|
217
324
|
mask_byslice = mask.reshape((xsize * ysize, numslices))
|
|
218
325
|
|
|
@@ -277,25 +384,49 @@ def happy_main(argparsingfunc):
|
|
|
277
384
|
)
|
|
278
385
|
# save motionr2 map
|
|
279
386
|
theheader = input_data.copyheader(numtimepoints=1)
|
|
280
|
-
motionr2filename = outputroot + "_desc-motionr2_map"
|
|
281
387
|
bidsdict = bidsbasedict.copy()
|
|
282
|
-
tide_io.writedicttojson(bidsdict, motionr2filename + ".json")
|
|
283
388
|
outarray = np.zeros((xsize, ysize, numslices), dtype=float)
|
|
284
389
|
outarray.reshape(numspatiallocs)[validprojvoxels] = confoundr2
|
|
285
|
-
|
|
286
|
-
|
|
390
|
+
maplist = [
|
|
391
|
+
(
|
|
392
|
+
outarray.reshape((xsize, ysize, numslices)),
|
|
393
|
+
"motionr2",
|
|
394
|
+
"map",
|
|
395
|
+
None,
|
|
396
|
+
"R2 of motion regression",
|
|
397
|
+
),
|
|
398
|
+
]
|
|
399
|
+
tide_io.savemaplist(
|
|
400
|
+
outputroot,
|
|
401
|
+
maplist,
|
|
402
|
+
None,
|
|
403
|
+
(xsize, ysize, numslices),
|
|
404
|
+
theheader,
|
|
405
|
+
bidsdict,
|
|
406
|
+
debug=args.debug,
|
|
287
407
|
)
|
|
288
408
|
if args.savemotionglmfilt:
|
|
289
409
|
print("prior to save - fmri_data has shape", fmri_data.shape)
|
|
290
|
-
motionfilteredfilename = outputroot + "_desc-motionfiltered_bold"
|
|
291
410
|
bidsdict = bidsbasedict.copy()
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
411
|
+
maplist = [
|
|
412
|
+
(
|
|
413
|
+
fmri_data.reshape((xsize, ysize, numslices, timepoints)),
|
|
414
|
+
"motionfiltered",
|
|
415
|
+
"bold",
|
|
416
|
+
None,
|
|
417
|
+
"fMRI data after motion regression",
|
|
418
|
+
),
|
|
419
|
+
]
|
|
420
|
+
tide_io.savemaplist(
|
|
421
|
+
outputroot,
|
|
422
|
+
maplist,
|
|
423
|
+
None,
|
|
424
|
+
(xsize, ysize, numslices, timepoints),
|
|
296
425
|
theheader,
|
|
297
|
-
|
|
426
|
+
bidsdict,
|
|
427
|
+
debug=args.debug,
|
|
298
428
|
)
|
|
429
|
+
|
|
299
430
|
timings.append(["Motion filtered data saved", time.time(), numspatiallocs, "voxels"])
|
|
300
431
|
|
|
301
432
|
# get slice times
|
|
@@ -334,16 +465,39 @@ def happy_main(argparsingfunc):
|
|
|
334
465
|
|
|
335
466
|
# save means, medians, and mads
|
|
336
467
|
theheader = input_data.copyheader(numtimepoints=1)
|
|
337
|
-
meansfilename = outputroot + "_desc-means_map"
|
|
338
|
-
mediansfilename = outputroot + "_desc-medians_map"
|
|
339
|
-
madsfilename = outputroot + "_desc-mads_map"
|
|
340
468
|
bidsdict = bidsbasedict.copy()
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
469
|
+
maplist = [
|
|
470
|
+
(
|
|
471
|
+
means.reshape((xsize, ysize, numslices)),
|
|
472
|
+
"means",
|
|
473
|
+
"map",
|
|
474
|
+
None,
|
|
475
|
+
"fMRI timecourse mean over time",
|
|
476
|
+
),
|
|
477
|
+
(
|
|
478
|
+
medians.reshape((xsize, ysize, numslices)),
|
|
479
|
+
"medians",
|
|
480
|
+
"map",
|
|
481
|
+
None,
|
|
482
|
+
"fMRI timecourse median over time",
|
|
483
|
+
),
|
|
484
|
+
(
|
|
485
|
+
mads.reshape((xsize, ysize, numslices)),
|
|
486
|
+
"mads",
|
|
487
|
+
"map",
|
|
488
|
+
None,
|
|
489
|
+
"fMRI timecourse MAD over time",
|
|
490
|
+
),
|
|
491
|
+
]
|
|
492
|
+
tide_io.savemaplist(
|
|
493
|
+
outputroot,
|
|
494
|
+
maplist,
|
|
495
|
+
None,
|
|
496
|
+
(xsize, ysize, numslices),
|
|
497
|
+
theheader,
|
|
498
|
+
bidsdict,
|
|
499
|
+
debug=args.debug,
|
|
500
|
+
)
|
|
347
501
|
|
|
348
502
|
# read in estimation mask if present. Otherwise, otherwise use intensity mask.
|
|
349
503
|
infodict["estweightsname"] = args.estweightsname
|
|
@@ -381,10 +535,12 @@ def happy_main(argparsingfunc):
|
|
|
381
535
|
if numpasses > 1:
|
|
382
536
|
print()
|
|
383
537
|
print()
|
|
384
|
-
print("starting pass
|
|
385
|
-
passstring = " - pass
|
|
538
|
+
print(f"starting pass {thispass + 1} of {numpasses}")
|
|
539
|
+
passstring = f" - pass {thispass + 1}"
|
|
540
|
+
passnamefrag = f"pass{thispass + 1}"
|
|
386
541
|
else:
|
|
387
542
|
passstring = ""
|
|
543
|
+
passnamefrag = ""
|
|
388
544
|
# now get an estimate of the cardiac signal
|
|
389
545
|
print("estimating cardiac signal from fmri data")
|
|
390
546
|
tide_util.logmem("before cardiacfromimage")
|
|
@@ -412,6 +568,7 @@ def happy_main(argparsingfunc):
|
|
|
412
568
|
madnorm=args.domadnorm,
|
|
413
569
|
nprocs=args.nprocs,
|
|
414
570
|
notchpct=args.notchpct,
|
|
571
|
+
notchrolloff=args.notchrolloff,
|
|
415
572
|
fliparteries=args.fliparteries,
|
|
416
573
|
arteriesonly=args.arteriesonly,
|
|
417
574
|
usemask=args.usemaskcardfromfmri,
|
|
@@ -1415,9 +1572,24 @@ def happy_main(argparsingfunc):
|
|
|
1415
1572
|
)
|
|
1416
1573
|
|
|
1417
1574
|
theheader = input_data.copyheader(numtimepoints=1)
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
|
|
1575
|
+
maplist = [
|
|
1576
|
+
(
|
|
1577
|
+
wrightcorrs,
|
|
1578
|
+
f"wrightcorrspass{passnamefrag}",
|
|
1579
|
+
"map",
|
|
1580
|
+
None,
|
|
1581
|
+
"fMRI timecourse MAD over time",
|
|
1582
|
+
),
|
|
1583
|
+
]
|
|
1584
|
+
tide_io.savemaplist(
|
|
1585
|
+
outputroot,
|
|
1586
|
+
maplist,
|
|
1587
|
+
None,
|
|
1588
|
+
(xsize, ysize, numslices),
|
|
1589
|
+
theheader,
|
|
1590
|
+
bidsdict,
|
|
1591
|
+
debug=args.debug,
|
|
1592
|
+
)
|
|
1421
1593
|
timings.append(
|
|
1422
1594
|
[
|
|
1423
1595
|
"Wright mask generation completed" + passstring,
|
|
@@ -1545,23 +1717,49 @@ def happy_main(argparsingfunc):
|
|
|
1545
1717
|
numtimepoints=args.destpoints, tr=-np.pi, toffset=2.0 * np.pi / args.destpoints
|
|
1546
1718
|
)
|
|
1547
1719
|
if thispass == numpasses - 1:
|
|
1548
|
-
|
|
1549
|
-
|
|
1550
|
-
|
|
1551
|
-
|
|
1552
|
-
|
|
1553
|
-
|
|
1554
|
-
|
|
1555
|
-
|
|
1556
|
-
|
|
1557
|
-
|
|
1558
|
-
|
|
1559
|
-
|
|
1560
|
-
|
|
1561
|
-
|
|
1720
|
+
maplist = [
|
|
1721
|
+
(
|
|
1722
|
+
app,
|
|
1723
|
+
"app",
|
|
1724
|
+
"info",
|
|
1725
|
+
None,
|
|
1726
|
+
"Cardiac pulsatility waveform with minimum over time removed",
|
|
1727
|
+
),
|
|
1728
|
+
(
|
|
1729
|
+
normapp,
|
|
1730
|
+
"normapp",
|
|
1731
|
+
"info",
|
|
1732
|
+
"percent",
|
|
1733
|
+
"Cardiac pulsatility waveform in percentage change relative to mean",
|
|
1734
|
+
),
|
|
1735
|
+
(
|
|
1736
|
+
cine,
|
|
1737
|
+
"cine",
|
|
1738
|
+
"info",
|
|
1739
|
+
None,
|
|
1740
|
+
"fMRI signal averaged over a single cardiac cycle",
|
|
1741
|
+
),
|
|
1742
|
+
]
|
|
1562
1743
|
if args.outputlevel > 0:
|
|
1563
|
-
|
|
1564
|
-
|
|
1744
|
+
maplist += [
|
|
1745
|
+
(
|
|
1746
|
+
rawapp,
|
|
1747
|
+
"rawapp",
|
|
1748
|
+
"info",
|
|
1749
|
+
None,
|
|
1750
|
+
"Cardiac pulsatility waveform",
|
|
1751
|
+
),
|
|
1752
|
+
]
|
|
1753
|
+
# write the 4D phase projection maps
|
|
1754
|
+
tide_io.savemaplist(
|
|
1755
|
+
outputroot,
|
|
1756
|
+
maplist,
|
|
1757
|
+
None,
|
|
1758
|
+
(xsize, ysize, numslices, args.destpoints),
|
|
1759
|
+
theheader,
|
|
1760
|
+
bidsdict,
|
|
1761
|
+
debug=args.debug,
|
|
1762
|
+
)
|
|
1565
1763
|
timings.append(["Phase projected data saved" + passstring, time.time(), None, None])
|
|
1566
1764
|
|
|
1567
1765
|
if args.doaliasedcorrelation and thispass == numpasses - 1:
|
|
@@ -1570,21 +1768,57 @@ def happy_main(argparsingfunc):
|
|
|
1570
1768
|
tr=(thealiasedcorrx[1] - thealiasedcorrx[0]),
|
|
1571
1769
|
toffset=0.0,
|
|
1572
1770
|
)
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
|
|
1578
|
-
|
|
1579
|
-
|
|
1580
|
-
|
|
1581
|
-
|
|
1582
|
-
tide_io.
|
|
1583
|
-
|
|
1771
|
+
maplist = [
|
|
1772
|
+
(
|
|
1773
|
+
thecorrfunc,
|
|
1774
|
+
"corrfunc",
|
|
1775
|
+
"info",
|
|
1776
|
+
None,
|
|
1777
|
+
"Aliased correlation function",
|
|
1778
|
+
),
|
|
1779
|
+
]
|
|
1780
|
+
tide_io.savemaplist(
|
|
1781
|
+
outputroot,
|
|
1782
|
+
maplist,
|
|
1783
|
+
None,
|
|
1784
|
+
(xsize, ysize, numslices, aliasedcorrelationpts),
|
|
1785
|
+
theheader,
|
|
1786
|
+
bidsdict,
|
|
1787
|
+
debug=args.debug,
|
|
1788
|
+
)
|
|
1584
1789
|
theheader["dim"][4] = 1
|
|
1585
|
-
|
|
1586
|
-
|
|
1587
|
-
|
|
1790
|
+
maplist = [
|
|
1791
|
+
(
|
|
1792
|
+
wavedelay,
|
|
1793
|
+
"wavedelay",
|
|
1794
|
+
"map",
|
|
1795
|
+
"seconds",
|
|
1796
|
+
"Peak delay of aliased correlation function",
|
|
1797
|
+
),
|
|
1798
|
+
(
|
|
1799
|
+
wavedelayCOM,
|
|
1800
|
+
"wavedelayCOM",
|
|
1801
|
+
"map",
|
|
1802
|
+
"seconds",
|
|
1803
|
+
"Center of mass of aliased correlation function",
|
|
1804
|
+
),
|
|
1805
|
+
(
|
|
1806
|
+
waveamp,
|
|
1807
|
+
"waveamp",
|
|
1808
|
+
"map",
|
|
1809
|
+
None,
|
|
1810
|
+
"Peak amplitude of aliased correlation function",
|
|
1811
|
+
),
|
|
1812
|
+
]
|
|
1813
|
+
tide_io.savemaplist(
|
|
1814
|
+
outputroot,
|
|
1815
|
+
maplist,
|
|
1816
|
+
None,
|
|
1817
|
+
(xsize, ysize, numslices),
|
|
1818
|
+
theheader,
|
|
1819
|
+
bidsdict,
|
|
1820
|
+
debug=args.debug,
|
|
1821
|
+
)
|
|
1588
1822
|
|
|
1589
1823
|
# make and save a voxel intensity histogram
|
|
1590
1824
|
if args.unnormvesselmap:
|
|
@@ -1622,24 +1856,34 @@ def happy_main(argparsingfunc):
|
|
|
1622
1856
|
maskedapp2d[np.where(vesselmask.reshape(numspatiallocs) == 0)[0], :] = 0.0
|
|
1623
1857
|
if args.outputlevel > 1:
|
|
1624
1858
|
if thispass == numpasses - 1:
|
|
1625
|
-
maskedappfilename = outputroot + "_desc-maskedapp_info"
|
|
1626
1859
|
bidsdict = bidsbasedict.copy()
|
|
1627
|
-
|
|
1628
|
-
|
|
1629
|
-
|
|
1630
|
-
|
|
1860
|
+
maplist = [
|
|
1861
|
+
(
|
|
1862
|
+
maskedapp2d.reshape((xsize, ysize, numslices, args.destpoints)),
|
|
1863
|
+
"maskedapp",
|
|
1864
|
+
"info",
|
|
1865
|
+
None,
|
|
1866
|
+
"Masked analytic phase projection",
|
|
1867
|
+
),
|
|
1868
|
+
]
|
|
1869
|
+
tide_io.savemaplist(
|
|
1870
|
+
outputroot,
|
|
1871
|
+
maplist,
|
|
1872
|
+
None,
|
|
1873
|
+
(xsize, ysize, numslices, args.destpoints),
|
|
1631
1874
|
theheader,
|
|
1632
|
-
|
|
1875
|
+
bidsdict,
|
|
1876
|
+
debug=args.debug,
|
|
1877
|
+
)
|
|
1878
|
+
timings.append(
|
|
1879
|
+
[
|
|
1880
|
+
"Vessel masked phase projected data saved" + passstring,
|
|
1881
|
+
time.time(),
|
|
1882
|
+
None,
|
|
1883
|
+
None,
|
|
1884
|
+
]
|
|
1633
1885
|
)
|
|
1634
1886
|
del maskedapp2d
|
|
1635
|
-
timings.append(
|
|
1636
|
-
[
|
|
1637
|
-
"Vessel masked phase projected data saved" + passstring,
|
|
1638
|
-
time.time(),
|
|
1639
|
-
None,
|
|
1640
|
-
None,
|
|
1641
|
-
]
|
|
1642
|
-
)
|
|
1643
1887
|
|
|
1644
1888
|
# save multiple versions of the hard vessel mask
|
|
1645
1889
|
if args.unnormvesselmap:
|
|
@@ -1655,57 +1899,316 @@ def happy_main(argparsingfunc):
|
|
|
1655
1899
|
veins = np.where(appflips_byslice.reshape((xsize, ysize, numslices)) > 0, vesselmask, 0)
|
|
1656
1900
|
theheader = input_data.copyheader(numtimepoints=1)
|
|
1657
1901
|
if thispass == numpasses - 1:
|
|
1658
|
-
|
|
1659
|
-
|
|
1660
|
-
|
|
1661
|
-
|
|
1662
|
-
|
|
1663
|
-
|
|
1664
|
-
|
|
1665
|
-
|
|
1902
|
+
maplist = [
|
|
1903
|
+
(
|
|
1904
|
+
vesselmask,
|
|
1905
|
+
"vessels",
|
|
1906
|
+
"mask",
|
|
1907
|
+
None,
|
|
1908
|
+
"Vessel mask",
|
|
1909
|
+
),
|
|
1910
|
+
]
|
|
1666
1911
|
if args.outputlevel > 0:
|
|
1667
|
-
|
|
1668
|
-
|
|
1669
|
-
|
|
1670
|
-
|
|
1671
|
-
|
|
1672
|
-
|
|
1673
|
-
|
|
1674
|
-
|
|
1675
|
-
|
|
1912
|
+
maplist += [
|
|
1913
|
+
(
|
|
1914
|
+
minphase,
|
|
1915
|
+
"minphase",
|
|
1916
|
+
"map",
|
|
1917
|
+
"radians",
|
|
1918
|
+
"Cardiac phase where minimum pulsatility signal occurs",
|
|
1919
|
+
),
|
|
1920
|
+
(
|
|
1921
|
+
maxphase,
|
|
1922
|
+
"maxphase",
|
|
1923
|
+
"map",
|
|
1924
|
+
"radians",
|
|
1925
|
+
"Cardiac phase where maximum pulsatility signal occurs",
|
|
1926
|
+
),
|
|
1927
|
+
(
|
|
1928
|
+
arteries,
|
|
1929
|
+
"arteries",
|
|
1930
|
+
"map",
|
|
1931
|
+
None,
|
|
1932
|
+
"Arterial voxels (maybe)",
|
|
1933
|
+
),
|
|
1934
|
+
(
|
|
1935
|
+
veins,
|
|
1936
|
+
"veins",
|
|
1937
|
+
"map",
|
|
1938
|
+
None,
|
|
1939
|
+
"Venous voxels (maybe)",
|
|
1940
|
+
),
|
|
1941
|
+
]
|
|
1942
|
+
tide_io.savemaplist(
|
|
1943
|
+
outputroot,
|
|
1944
|
+
maplist,
|
|
1945
|
+
None,
|
|
1946
|
+
(xsize, ysize, numslices),
|
|
1947
|
+
theheader,
|
|
1948
|
+
bidsdict,
|
|
1949
|
+
debug=args.debug,
|
|
1950
|
+
)
|
|
1676
1951
|
timings.append(["Masks saved" + passstring, time.time(), None, None])
|
|
1677
1952
|
|
|
1678
1953
|
# save the mask we used for this pass
|
|
1679
|
-
tide_io.
|
|
1680
|
-
|
|
1954
|
+
tide_io.savemaplist(
|
|
1955
|
+
outputroot,
|
|
1956
|
+
[
|
|
1957
|
+
(
|
|
1958
|
+
estweights_byslice.reshape((xsize, ysize, numslices)),
|
|
1959
|
+
f"estweights{passnamefrag}",
|
|
1960
|
+
"map",
|
|
1961
|
+
None,
|
|
1962
|
+
f"Estweights{passstring}",
|
|
1963
|
+
),
|
|
1964
|
+
],
|
|
1965
|
+
None,
|
|
1966
|
+
(xsize, ysize, numslices),
|
|
1681
1967
|
theheader,
|
|
1682
|
-
|
|
1968
|
+
bidsdict,
|
|
1969
|
+
debug=args.debug,
|
|
1683
1970
|
)
|
|
1684
1971
|
|
|
1972
|
+
# estimate pulsatility
|
|
1973
|
+
(
|
|
1974
|
+
card_min,
|
|
1975
|
+
card_max,
|
|
1976
|
+
card_mean,
|
|
1977
|
+
card_std,
|
|
1978
|
+
card_median,
|
|
1979
|
+
card_mad,
|
|
1980
|
+
card_skew,
|
|
1981
|
+
card_kurtosis,
|
|
1982
|
+
) = tide_stats.fmristats(normapp.reshape(numspatiallocs, -1))
|
|
1983
|
+
maplist = [
|
|
1984
|
+
(
|
|
1985
|
+
card_min,
|
|
1986
|
+
"appmin",
|
|
1987
|
+
"map",
|
|
1988
|
+
None,
|
|
1989
|
+
"Minimum value of analytic phase projection across all phases",
|
|
1990
|
+
),
|
|
1991
|
+
(
|
|
1992
|
+
card_max,
|
|
1993
|
+
"appmax",
|
|
1994
|
+
"map",
|
|
1995
|
+
None,
|
|
1996
|
+
"Maximum value of analytic phase projection across all phases",
|
|
1997
|
+
),
|
|
1998
|
+
(
|
|
1999
|
+
card_mean,
|
|
2000
|
+
"appmean",
|
|
2001
|
+
"map",
|
|
2002
|
+
None,
|
|
2003
|
+
"Mean value of analytic phase projection across all phases",
|
|
2004
|
+
),
|
|
2005
|
+
(
|
|
2006
|
+
card_std,
|
|
2007
|
+
"appstd",
|
|
2008
|
+
"map",
|
|
2009
|
+
None,
|
|
2010
|
+
"Standard deviation of analytic phase projection across all phases",
|
|
2011
|
+
),
|
|
2012
|
+
(
|
|
2013
|
+
card_median,
|
|
2014
|
+
"appmedian",
|
|
2015
|
+
"map",
|
|
2016
|
+
None,
|
|
2017
|
+
"Median of analytic phase projection across all phases",
|
|
2018
|
+
),
|
|
2019
|
+
(
|
|
2020
|
+
card_mad,
|
|
2021
|
+
"appMAD",
|
|
2022
|
+
"map",
|
|
2023
|
+
None,
|
|
2024
|
+
"Median average deviate of analytic phase projection across all phases",
|
|
2025
|
+
),
|
|
2026
|
+
(
|
|
2027
|
+
card_skew,
|
|
2028
|
+
"appskew",
|
|
2029
|
+
"map",
|
|
2030
|
+
None,
|
|
2031
|
+
"Skewness of analytic phase projection across all phases",
|
|
2032
|
+
),
|
|
2033
|
+
(
|
|
2034
|
+
card_kurtosis,
|
|
2035
|
+
"appkurtosis",
|
|
2036
|
+
"map",
|
|
2037
|
+
None,
|
|
2038
|
+
"Kurtosis of analytic phase projection across all phases",
|
|
2039
|
+
),
|
|
2040
|
+
]
|
|
2041
|
+
# write the 3D maps
|
|
2042
|
+
tide_io.savemaplist(
|
|
2043
|
+
outputroot,
|
|
2044
|
+
maplist,
|
|
2045
|
+
None,
|
|
2046
|
+
(xsize, ysize, numslices),
|
|
2047
|
+
theheader,
|
|
2048
|
+
bidsdict,
|
|
2049
|
+
debug=args.debug,
|
|
2050
|
+
)
|
|
2051
|
+
|
|
2052
|
+
pulsatilitymap = 100.0 * (np.max(normapp, axis=3) - np.min(normapp, axis=3))
|
|
2053
|
+
rawrobustmax = tide_stats.getfracval(pulsatilitymap, 0.98, nozero=True)
|
|
2054
|
+
rawmedian = tide_stats.getfracval(pulsatilitymap, 0.50, nozero=True)
|
|
2055
|
+
infodict["pulsatilitythresh"] = rawmedian * 3.0
|
|
2056
|
+
pulsatilitymap = np.where(pulsatilitymap < rawrobustmax, pulsatilitymap, rawrobustmax)
|
|
2057
|
+
pulsatilitymask = np.where(pulsatilitymap > infodict["pulsatilitythresh"], 1.0, 0.0)
|
|
2058
|
+
|
|
1685
2059
|
# now get ready to start again with a new mask
|
|
1686
2060
|
if args.doaliasedcorrelation and thispass > 0:
|
|
1687
2061
|
estweights_byslice = waveamp_byslice * vesselmask.reshape((xsize * ysize, numslices))
|
|
1688
2062
|
else:
|
|
1689
|
-
|
|
1690
|
-
|
|
1691
|
-
|
|
1692
|
-
|
|
1693
|
-
|
|
2063
|
+
if args.useoriginalvesselmethod:
|
|
2064
|
+
estweights_byslice = vesselmask.reshape((xsize * ysize, numslices)) + 0
|
|
2065
|
+
else:
|
|
2066
|
+
estweights_byslice = pulsatilitymask.reshape((xsize * ysize, numslices)) + 0
|
|
2067
|
+
|
|
2068
|
+
# calculate the lf and hf pulsatility maps
|
|
2069
|
+
lfnormapp = normapp * 0.0
|
|
2070
|
+
hfnormapp = normapp * 0.0
|
|
2071
|
+
for thephase in range(args.destpoints):
|
|
2072
|
+
lfnormapp[:, :, :, thephase] = (
|
|
2073
|
+
tide_filt.ssmooth(
|
|
2074
|
+
xdim, ydim, slicethickness, args.pulsatilitysigma, normapp[:, :, :, thephase]
|
|
2075
|
+
)
|
|
2076
|
+
* pulsatilitymask
|
|
2077
|
+
)
|
|
2078
|
+
hfnormapp[:, :, :, thephase] = normapp[:, :, :, thephase] - lfnormapp[:, :, :, thephase]
|
|
2079
|
+
lfnormapp -= np.min(lfnormapp, axis=3)[:, :, :, None]
|
|
2080
|
+
hfnormapp -= np.min(hfnormapp, axis=3)[:, :, :, None]
|
|
2081
|
+
lfpulsatilitymap = (
|
|
2082
|
+
tide_filt.ssmooth(xdim, ydim, slicethickness, args.pulsatilitysigma, pulsatilitymap)
|
|
2083
|
+
* pulsatilitymask
|
|
2084
|
+
)
|
|
2085
|
+
hfpulsatilitymap = pulsatilitymap - lfpulsatilitymap
|
|
2086
|
+
lfpulsatilitymap2 = 100.0 * np.max(lfnormapp, axis=3)
|
|
2087
|
+
lfrobustmax = tide_stats.getfracval(lfpulsatilitymap2, 0.98, nozero=True)
|
|
2088
|
+
lfpulsatilitymap2 = np.where(lfpulsatilitymap2 < lfrobustmax, lfpulsatilitymap2, lfrobustmax)
|
|
2089
|
+
hfpulsatilitymap2 = 100.0 * np.max(hfnormapp, axis=3)
|
|
2090
|
+
hfrobustmax = tide_stats.getfracval(hfpulsatilitymap2, 0.98, nozero=True)
|
|
2091
|
+
hfpulsatilitymap2 = np.where(hfpulsatilitymap2 < hfrobustmax, hfpulsatilitymap2, hfrobustmax)
|
|
2092
|
+
|
|
2093
|
+
# make a vessel map
|
|
2094
|
+
if args.useoriginalvesselmethod:
|
|
2095
|
+
if args.unnormvesselmap:
|
|
2096
|
+
vesselmap = np.max(app, axis=3)
|
|
2097
|
+
else:
|
|
2098
|
+
# vesselmap = np.max(normapp, axis=3)
|
|
2099
|
+
vesselmap = np.where(hfpulsatilitymap > args.pulsatilitythreshold, 1.0, 0.0)
|
|
1694
2100
|
else:
|
|
1695
|
-
vesselmap =
|
|
1696
|
-
|
|
1697
|
-
|
|
1698
|
-
|
|
1699
|
-
|
|
1700
|
-
|
|
1701
|
-
|
|
2101
|
+
vesselmap = pulsatilitymask
|
|
2102
|
+
veinmap = np.where(appflips_byslice.reshape((xsize, ysize, numslices)) > 0, vesselmap, 0.0)
|
|
2103
|
+
arterymap = np.where(appflips_byslice.reshape((xsize, ysize, numslices)) < 0, vesselmap, 0.0)
|
|
2104
|
+
|
|
2105
|
+
# specify the 3D maps
|
|
2106
|
+
maplist = [
|
|
2107
|
+
(
|
|
2108
|
+
pulsatilitymap,
|
|
2109
|
+
"pulsatility",
|
|
2110
|
+
"map",
|
|
2111
|
+
"percent",
|
|
2112
|
+
"Cardiac pulsatility in percentage change relative to mean",
|
|
2113
|
+
),
|
|
2114
|
+
(
|
|
2115
|
+
pulsatilitymask,
|
|
2116
|
+
"pulsatility",
|
|
2117
|
+
"mask",
|
|
2118
|
+
None,
|
|
2119
|
+
"Valid cardiac pulsatility voxels",
|
|
2120
|
+
),
|
|
2121
|
+
(
|
|
2122
|
+
lfpulsatilitymap,
|
|
2123
|
+
"lfpulsatility",
|
|
2124
|
+
"map",
|
|
2125
|
+
"percent",
|
|
2126
|
+
"Low spatial frequency cardiac pulsatility in percentage change relative to mean",
|
|
2127
|
+
),
|
|
2128
|
+
(
|
|
2129
|
+
hfpulsatilitymap,
|
|
2130
|
+
"hfpulsatility",
|
|
2131
|
+
"map",
|
|
2132
|
+
"percent",
|
|
2133
|
+
"High spatial frequency cardiac pulsatility in percentage change relative to mean",
|
|
2134
|
+
),
|
|
2135
|
+
(
|
|
2136
|
+
lfpulsatilitymap2,
|
|
2137
|
+
"lfpulsatility2",
|
|
2138
|
+
"map",
|
|
2139
|
+
"percent",
|
|
2140
|
+
"Low spatial frequency cardiac pulsatility in percentage change relative to mean",
|
|
2141
|
+
),
|
|
2142
|
+
(
|
|
2143
|
+
hfpulsatilitymap2,
|
|
2144
|
+
"hfpulsatility2",
|
|
2145
|
+
"map",
|
|
2146
|
+
"percent",
|
|
2147
|
+
"High spatial frequency cardiac pulsatility in percentage change relative to mean",
|
|
2148
|
+
),
|
|
2149
|
+
(
|
|
2150
|
+
vesselmap,
|
|
2151
|
+
"vessels",
|
|
2152
|
+
"map",
|
|
2153
|
+
None,
|
|
2154
|
+
"Vessel voxels",
|
|
2155
|
+
),
|
|
2156
|
+
(
|
|
2157
|
+
arterymap,
|
|
2158
|
+
"arteries",
|
|
2159
|
+
"map",
|
|
2160
|
+
None,
|
|
2161
|
+
"Arterial voxels (maybe)",
|
|
2162
|
+
),
|
|
2163
|
+
(
|
|
2164
|
+
veinmap,
|
|
2165
|
+
"veins",
|
|
2166
|
+
"map",
|
|
2167
|
+
None,
|
|
2168
|
+
"Venous voxels (maybe)",
|
|
2169
|
+
),
|
|
2170
|
+
]
|
|
2171
|
+
# write the 3D maps
|
|
2172
|
+
tide_io.savemaplist(
|
|
2173
|
+
outputroot,
|
|
2174
|
+
maplist,
|
|
2175
|
+
None,
|
|
2176
|
+
(xsize, ysize, numslices),
|
|
1702
2177
|
theheader,
|
|
1703
|
-
|
|
2178
|
+
bidsdict,
|
|
2179
|
+
debug=args.debug,
|
|
1704
2180
|
)
|
|
1705
|
-
|
|
1706
|
-
|
|
2181
|
+
|
|
2182
|
+
# specify the 4D maps
|
|
2183
|
+
theheader = input_data.copyheader(
|
|
2184
|
+
numtimepoints=args.destpoints, tr=-np.pi, toffset=2.0 * np.pi / args.destpoints
|
|
2185
|
+
)
|
|
2186
|
+
maplist = [
|
|
2187
|
+
(
|
|
2188
|
+
lfnormapp,
|
|
2189
|
+
"lfnormapp",
|
|
2190
|
+
"info",
|
|
2191
|
+
"percent",
|
|
2192
|
+
"Low spatial frequency cardiac pulsatility waveform in percentage change relative to mean",
|
|
2193
|
+
),
|
|
2194
|
+
(
|
|
2195
|
+
hfnormapp,
|
|
2196
|
+
"hfnormapp",
|
|
2197
|
+
"info",
|
|
2198
|
+
"percent",
|
|
2199
|
+
"High spatial frequency cardiac pulsatility waveform in percentage change relative to mean",
|
|
2200
|
+
),
|
|
2201
|
+
]
|
|
2202
|
+
|
|
2203
|
+
# write the 4D maps
|
|
2204
|
+
tide_io.savemaplist(
|
|
2205
|
+
outputroot,
|
|
2206
|
+
maplist,
|
|
2207
|
+
None,
|
|
2208
|
+
(xsize, ysize, numslices, args.destpoints),
|
|
1707
2209
|
theheader,
|
|
1708
|
-
|
|
2210
|
+
bidsdict,
|
|
2211
|
+
debug=args.debug,
|
|
1709
2212
|
)
|
|
1710
2213
|
|
|
1711
2214
|
# now generate aliased cardiac signals and regress them out of the data
|
|
@@ -1731,34 +2234,85 @@ def happy_main(argparsingfunc):
|
|
|
1731
2234
|
theheader = input_data.copyheader()
|
|
1732
2235
|
timings.append(["Cardiac signal generated", time.time(), None, None])
|
|
1733
2236
|
if args.savecardiacnoise:
|
|
1734
|
-
|
|
1735
|
-
|
|
1736
|
-
|
|
1737
|
-
|
|
1738
|
-
|
|
1739
|
-
|
|
1740
|
-
|
|
1741
|
-
|
|
1742
|
-
|
|
2237
|
+
maplist = [
|
|
2238
|
+
(
|
|
2239
|
+
cardiacnoise.reshape((xsize, ysize, numslices, timepoints)),
|
|
2240
|
+
"cardiacnoise",
|
|
2241
|
+
"info",
|
|
2242
|
+
None,
|
|
2243
|
+
"Calculated cardiac noise EVs",
|
|
2244
|
+
),
|
|
2245
|
+
(
|
|
2246
|
+
phaseindices.reshape((xsize, ysize, numslices, timepoints)),
|
|
2247
|
+
"phaseindices",
|
|
2248
|
+
"info",
|
|
2249
|
+
None,
|
|
2250
|
+
"Phase indices",
|
|
2251
|
+
),
|
|
2252
|
+
]
|
|
2253
|
+
tide_io.savemaplist(
|
|
2254
|
+
outputroot,
|
|
2255
|
+
maplist,
|
|
2256
|
+
None,
|
|
2257
|
+
(xsize, ysize, numslices, timepoints),
|
|
1743
2258
|
theheader,
|
|
1744
|
-
|
|
2259
|
+
bidsdict,
|
|
2260
|
+
debug=args.debug,
|
|
1745
2261
|
)
|
|
1746
2262
|
timings.append(["Cardiac signal saved", time.time(), None, None])
|
|
1747
2263
|
|
|
1748
2264
|
# now remove them
|
|
1749
2265
|
tide_util.logmem("before cardiac removal")
|
|
1750
2266
|
print("Removing cardiac signal with GLM")
|
|
1751
|
-
filtereddata = 0.0 * fmri_data
|
|
1752
2267
|
validlocs = np.where(mask > 0)[0]
|
|
1753
2268
|
numvalidspatiallocs = len(validlocs)
|
|
2269
|
+
if args.focaldebug:
|
|
2270
|
+
print(f"{numvalidspatiallocs=}, {fmri_data.shape=}")
|
|
2271
|
+
filtereddata, filtereddata_shm = tide_util.allocarray(
|
|
2272
|
+
fmri_data.shape,
|
|
2273
|
+
"float64",
|
|
2274
|
+
shared=infodict["sharedmem"],
|
|
2275
|
+
name=f"filtereddata_{infodict['pid']}",
|
|
2276
|
+
)
|
|
2277
|
+
datatoremove, datatoremove_shm = tide_util.allocarray(
|
|
2278
|
+
fmri_data.shape,
|
|
2279
|
+
"float64",
|
|
2280
|
+
shared=infodict["sharedmem"],
|
|
2281
|
+
name=f"datatoremove_{infodict['pid']}",
|
|
2282
|
+
)
|
|
1754
2283
|
threshval = 0.0
|
|
1755
2284
|
if args.dospatialregression:
|
|
1756
|
-
|
|
1757
|
-
|
|
1758
|
-
|
|
1759
|
-
|
|
1760
|
-
|
|
1761
|
-
|
|
2285
|
+
regressiontype = "spatial"
|
|
2286
|
+
meanvals, meanvals_shm = tide_util.allocarray(
|
|
2287
|
+
(timepoints),
|
|
2288
|
+
"float64",
|
|
2289
|
+
shared=infodict["sharedmem"],
|
|
2290
|
+
name=f"meanvals_{infodict['pid']}",
|
|
2291
|
+
)
|
|
2292
|
+
rvals, rvals_shm = tide_util.allocarray(
|
|
2293
|
+
(timepoints),
|
|
2294
|
+
"float64",
|
|
2295
|
+
shared=infodict["sharedmem"],
|
|
2296
|
+
name=f"rvals_{infodict['pid']}",
|
|
2297
|
+
)
|
|
2298
|
+
r2vals, r2vals_shm = tide_util.allocarray(
|
|
2299
|
+
(timepoints),
|
|
2300
|
+
"float64",
|
|
2301
|
+
shared=infodict["sharedmem"],
|
|
2302
|
+
name=f"r2vals_{infodict['pid']}",
|
|
2303
|
+
)
|
|
2304
|
+
fitcoffs, fitcoffs_shm = tide_util.allocarray(
|
|
2305
|
+
(timepoints),
|
|
2306
|
+
"float64",
|
|
2307
|
+
shared=infodict["sharedmem"],
|
|
2308
|
+
name=f"fitcoffs_{infodict['pid']}",
|
|
2309
|
+
)
|
|
2310
|
+
fitNorm, fitNorm_shm = tide_util.allocarray(
|
|
2311
|
+
(timepoints),
|
|
2312
|
+
"float64",
|
|
2313
|
+
shared=infodict["sharedmem"],
|
|
2314
|
+
name=f"fitNorm_{infodict['pid']}",
|
|
2315
|
+
)
|
|
1762
2316
|
print("Running spatial regression on", timepoints, "timepoints")
|
|
1763
2317
|
tide_util.disablemkl(args.nprocs)
|
|
1764
2318
|
tide_linfitfiltpass.linfitfiltpass(
|
|
@@ -1778,8 +2332,10 @@ def happy_main(argparsingfunc):
|
|
|
1778
2332
|
nprocs=args.nprocs,
|
|
1779
2333
|
)
|
|
1780
2334
|
tide_util.enablemkl(args.mklthreads)
|
|
1781
|
-
|
|
1782
|
-
|
|
2335
|
+
datatoremove[validlocs, :] = np.multiply(cardiacnoise[validlocs, :], fitcoffs[None, :])
|
|
2336
|
+
print(f"{datatoremove.shape=}, {np.min(datatoremove)=}, {np.max(datatoremove)=}")
|
|
2337
|
+
print(f"{cardiacnoise.shape=}, {np.min(cardiacnoise)=}, {np.max(cardiacnoise)=}")
|
|
2338
|
+
print(f"{fitcoffs.shape=}, {np.min(fitcoffs)=}, {np.max(fitcoffs)=}")
|
|
1783
2339
|
filtereddata = fmri_data - datatoremove
|
|
1784
2340
|
timings.append(
|
|
1785
2341
|
[
|
|
@@ -1789,38 +2345,39 @@ def happy_main(argparsingfunc):
|
|
|
1789
2345
|
"timepoints",
|
|
1790
2346
|
]
|
|
1791
2347
|
)
|
|
1792
|
-
|
|
1793
|
-
|
|
1794
|
-
|
|
1795
|
-
|
|
1796
|
-
|
|
1797
|
-
|
|
1798
|
-
|
|
1799
|
-
|
|
1800
|
-
theheader,
|
|
1801
|
-
cardfiltresultfilename,
|
|
2348
|
+
|
|
2349
|
+
if args.dotemporalregression:
|
|
2350
|
+
regressiontype = "temporal"
|
|
2351
|
+
meanvals, meanvals_shm = tide_util.allocarray(
|
|
2352
|
+
(numspatiallocs),
|
|
2353
|
+
"float64",
|
|
2354
|
+
shared=infodict["sharedmem"],
|
|
2355
|
+
name=f"meanvals_{infodict['pid']}",
|
|
1802
2356
|
)
|
|
1803
|
-
|
|
1804
|
-
|
|
1805
|
-
|
|
1806
|
-
|
|
2357
|
+
rvals, rvals_shm = tide_util.allocarray(
|
|
2358
|
+
(numspatiallocs),
|
|
2359
|
+
"float64",
|
|
2360
|
+
shared=infodict["sharedmem"],
|
|
2361
|
+
name=f"rvals_{infodict['pid']}",
|
|
1807
2362
|
)
|
|
1808
|
-
|
|
1809
|
-
|
|
1810
|
-
|
|
1811
|
-
|
|
1812
|
-
|
|
1813
|
-
|
|
1814
|
-
|
|
2363
|
+
r2vals, r2vals_shm = tide_util.allocarray(
|
|
2364
|
+
(numspatiallocs),
|
|
2365
|
+
"float64",
|
|
2366
|
+
shared=infodict["sharedmem"],
|
|
2367
|
+
name=f"r2vals_{infodict['pid']}",
|
|
2368
|
+
)
|
|
2369
|
+
fitcoffs, fitcoffs_shm = tide_util.allocarray(
|
|
2370
|
+
(numspatiallocs),
|
|
2371
|
+
"float64",
|
|
2372
|
+
shared=infodict["sharedmem"],
|
|
2373
|
+
name=f"fitcoffs_{infodict['pid']}",
|
|
2374
|
+
)
|
|
2375
|
+
fitNorm, fitNorm_shm = tide_util.allocarray(
|
|
2376
|
+
(numspatiallocs),
|
|
2377
|
+
"float64",
|
|
2378
|
+
shared=infodict["sharedmem"],
|
|
2379
|
+
name=f"fitNorm_{infodict['pid']}",
|
|
1815
2380
|
)
|
|
1816
|
-
|
|
1817
|
-
if args.dotemporalregression:
|
|
1818
|
-
meanvals = np.zeros(numspatiallocs, dtype=np.float64)
|
|
1819
|
-
rvals = np.zeros(numspatiallocs, dtype=np.float64)
|
|
1820
|
-
r2vals = np.zeros(numspatiallocs, dtype=np.float64)
|
|
1821
|
-
fitcoffs = np.zeros(numspatiallocs, dtype=np.float64)
|
|
1822
|
-
fitNorm = np.zeros(numspatiallocs, dtype=np.float64)
|
|
1823
|
-
datatoremove = 0.0 * fmri_data
|
|
1824
2381
|
print("Running temporal regression on", numvalidspatiallocs, "voxels")
|
|
1825
2382
|
tide_util.disablemkl(args.nprocs)
|
|
1826
2383
|
tide_linfitfiltpass.linfitfiltpass(
|
|
@@ -1837,11 +2394,15 @@ def happy_main(argparsingfunc):
|
|
|
1837
2394
|
filtereddata[validlocs, :],
|
|
1838
2395
|
procbyvoxel=True,
|
|
1839
2396
|
nprocs=args.nprocs,
|
|
2397
|
+
debug=args.focaldebug,
|
|
1840
2398
|
)
|
|
1841
2399
|
tide_util.enablemkl(args.mklthreads)
|
|
1842
2400
|
datatoremove[validlocs, :] = np.multiply(
|
|
1843
2401
|
cardiacnoise[validlocs, :], fitcoffs[validlocs, None]
|
|
1844
2402
|
)
|
|
2403
|
+
print(f"{datatoremove.shape=}, {np.min(datatoremove)=}, {np.max(datatoremove)=}")
|
|
2404
|
+
print(f"{cardiacnoise.shape=}, {np.min(cardiacnoise)=}, {np.max(cardiacnoise)=}")
|
|
2405
|
+
print(f"{fitcoffs.shape=}, {np.min(fitcoffs)=}, {np.max(fitcoffs)=}")
|
|
1845
2406
|
filtereddata[validlocs, :] = fmri_data[validlocs, :] - datatoremove[validlocs, :]
|
|
1846
2407
|
timings.append(
|
|
1847
2408
|
[
|
|
@@ -1852,44 +2413,85 @@ def happy_main(argparsingfunc):
|
|
|
1852
2413
|
]
|
|
1853
2414
|
)
|
|
1854
2415
|
theheader = input_data.copyheader(numtimepoints=1)
|
|
1855
|
-
|
|
1856
|
-
|
|
1857
|
-
|
|
1858
|
-
|
|
1859
|
-
|
|
1860
|
-
|
|
1861
|
-
|
|
1862
|
-
|
|
1863
|
-
|
|
1864
|
-
|
|
2416
|
+
maplist = [
|
|
2417
|
+
(
|
|
2418
|
+
fitcoffs.reshape((xsize, ysize, numslices)),
|
|
2419
|
+
"cardfiltCoeffs",
|
|
2420
|
+
"map",
|
|
2421
|
+
None,
|
|
2422
|
+
"Coefficients for temporal cardiac noise regression",
|
|
2423
|
+
),
|
|
2424
|
+
(
|
|
2425
|
+
meanvals.reshape((xsize, ysize, numslices)),
|
|
2426
|
+
"cardfiltMean",
|
|
2427
|
+
"map",
|
|
2428
|
+
None,
|
|
2429
|
+
"Mean values after temporal cardiac noise regression",
|
|
2430
|
+
),
|
|
2431
|
+
(
|
|
2432
|
+
rvals.reshape((xsize, ysize, numslices)),
|
|
2433
|
+
"cardfiltR",
|
|
2434
|
+
"map",
|
|
2435
|
+
None,
|
|
2436
|
+
"R values for temporal cardiac noise regression",
|
|
2437
|
+
),
|
|
2438
|
+
]
|
|
2439
|
+
tide_io.savemaplist(
|
|
2440
|
+
outputroot,
|
|
2441
|
+
maplist,
|
|
2442
|
+
None,
|
|
2443
|
+
(xsize, ysize, numslices),
|
|
1865
2444
|
theheader,
|
|
1866
|
-
|
|
1867
|
-
|
|
1868
|
-
tide_io.savetonifti(
|
|
1869
|
-
rvals.reshape((xsize, ysize, numslices)), theheader, cardfiltRfilename
|
|
2445
|
+
bidsdict,
|
|
2446
|
+
debug=args.debug,
|
|
1870
2447
|
)
|
|
1871
2448
|
|
|
1872
|
-
|
|
1873
|
-
|
|
1874
|
-
|
|
1875
|
-
|
|
2449
|
+
# now write out the filtered data
|
|
2450
|
+
theheader = input_data.copyheader()
|
|
2451
|
+
maplist = [
|
|
2452
|
+
(
|
|
1876
2453
|
filtereddata.reshape((xsize, ysize, numslices, timepoints)),
|
|
1877
|
-
|
|
1878
|
-
|
|
1879
|
-
|
|
1880
|
-
|
|
2454
|
+
"cardfiltResult",
|
|
2455
|
+
"bold",
|
|
2456
|
+
None,
|
|
2457
|
+
f"Cardiac filtered BOLD data after {regressiontype} regression",
|
|
2458
|
+
),
|
|
2459
|
+
(
|
|
1881
2460
|
datatoremove.reshape((xsize, ysize, numslices, timepoints)),
|
|
1882
|
-
|
|
1883
|
-
|
|
1884
|
-
|
|
1885
|
-
|
|
1886
|
-
|
|
1887
|
-
|
|
1888
|
-
|
|
1889
|
-
|
|
1890
|
-
|
|
1891
|
-
|
|
1892
|
-
)
|
|
2461
|
+
"cardfiltRemoved",
|
|
2462
|
+
"bold",
|
|
2463
|
+
None,
|
|
2464
|
+
f"Cardiac noise removed with {regressiontype} regression",
|
|
2465
|
+
),
|
|
2466
|
+
]
|
|
2467
|
+
tide_io.savemaplist(
|
|
2468
|
+
outputroot,
|
|
2469
|
+
maplist,
|
|
2470
|
+
None,
|
|
2471
|
+
(xsize, ysize, numslices, timepoints),
|
|
2472
|
+
theheader,
|
|
2473
|
+
bidsdict,
|
|
2474
|
+
debug=args.debug,
|
|
2475
|
+
)
|
|
2476
|
+
timings.append(
|
|
2477
|
+
[
|
|
2478
|
+
f"Cardiac signal {regressiontype} regression files written",
|
|
2479
|
+
time.time(),
|
|
2480
|
+
None,
|
|
2481
|
+
None,
|
|
2482
|
+
]
|
|
2483
|
+
)
|
|
2484
|
+
|
|
2485
|
+
# clean up shared memory, if using
|
|
2486
|
+
if args.dotemporalregression or args.dospatialregression:
|
|
2487
|
+
if infodict["sharedmem"]:
|
|
2488
|
+
tide_util.cleanup_shm(filtereddata_shm)
|
|
2489
|
+
tide_util.cleanup_shm(datatoremove_shm)
|
|
2490
|
+
tide_util.cleanup_shm(meanvals_shm)
|
|
2491
|
+
tide_util.cleanup_shm(rvals_shm)
|
|
2492
|
+
tide_util.cleanup_shm(r2vals_shm)
|
|
2493
|
+
tide_util.cleanup_shm(fitcoffs_shm)
|
|
2494
|
+
tide_util.cleanup_shm(fitNorm_shm)
|
|
1893
2495
|
|
|
1894
2496
|
timings.append(["Done", time.time(), None, None])
|
|
1895
2497
|
|