rapidtide 3.0.10__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 +1053 -47
- 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 +30 -1
- 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/data/reference/JHU-ArterialTerritoriesNoVent-LVL1_space-MNI152NLin2009cAsym_2mm.nii.gz +0 -0
- rapidtide/data/reference/JHU-ArterialTerritoriesNoVent-LVL1_space-MNI152NLin2009cAsym_2mm_mask.nii.gz +0 -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 +813 -201
- rapidtide/workflows/happy2std.py +144 -12
- rapidtide/workflows/happy_parser.py +149 -8
- 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 +2972 -133
- rapidtide/workflows/utils.py +19 -14
- rapidtide/workflows/utils_doc.py +293 -0
- rapidtide/workflows/variabilityizer.py +116 -3
- {rapidtide-3.0.10.dist-info → rapidtide-3.1.dist-info}/METADATA +10 -9
- {rapidtide-3.0.10.dist-info → rapidtide-3.1.dist-info}/RECORD +141 -122
- {rapidtide-3.0.10.dist-info → rapidtide-3.1.dist-info}/entry_points.txt +1 -0
- {rapidtide-3.0.10.dist-info → rapidtide-3.1.dist-info}/WHEEL +0 -0
- {rapidtide-3.0.10.dist-info → rapidtide-3.1.dist-info}/licenses/LICENSE +0 -0
- {rapidtide-3.0.10.dist-info → rapidtide-3.1.dist-info}/top_level.txt +0 -0
rapidtide/workflows/happy.py
CHANGED
|
@@ -22,9 +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
|
|
27
|
-
from
|
|
28
|
+
from numpy.typing import NDArray
|
|
28
29
|
|
|
29
30
|
import rapidtide.correlate as tide_corr
|
|
30
31
|
import rapidtide.filter as tide_filt
|
|
@@ -50,23 +51,104 @@ try:
|
|
|
50
51
|
except ImportError:
|
|
51
52
|
mklexists = False
|
|
52
53
|
|
|
53
|
-
try:
|
|
54
|
-
import rapidtide.dlfilter as tide_dlfilt
|
|
55
|
-
|
|
56
|
-
dlfilterexists = True
|
|
57
|
-
print("dlfilter exists")
|
|
58
|
-
except ImportError:
|
|
59
|
-
dlfilterexists = False
|
|
60
|
-
print("dlfilter does not exist")
|
|
61
54
|
|
|
62
|
-
|
|
63
|
-
|
|
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
|
+
"""
|
|
64
127
|
timings = [["Start", time.time(), None, None]]
|
|
65
128
|
|
|
66
129
|
# get the command line parameters
|
|
67
130
|
args = argparsingfunc
|
|
68
131
|
infodict = vars(args)
|
|
69
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
|
+
|
|
70
152
|
fmrifilename = args.fmrifilename
|
|
71
153
|
slicetimename = args.slicetimename
|
|
72
154
|
outputroot = args.outputroot
|
|
@@ -93,7 +175,7 @@ def happy_main(argparsingfunc):
|
|
|
93
175
|
logger_filename=f"{outputroot}_log.txt",
|
|
94
176
|
timing_filename=f"{outputroot}_runtimings.tsv",
|
|
95
177
|
memory_filename=f"{outputroot}_memusage.tsv",
|
|
96
|
-
|
|
178
|
+
isverbose=args.verbose,
|
|
97
179
|
debug=args.debug,
|
|
98
180
|
)
|
|
99
181
|
|
|
@@ -114,6 +196,8 @@ def happy_main(argparsingfunc):
|
|
|
114
196
|
"***********************************************************************************************************************************")
|
|
115
197
|
print("")"""
|
|
116
198
|
|
|
199
|
+
infodict["pid"] = os.getpid()
|
|
200
|
+
|
|
117
201
|
infodict["fmrifilename"] = fmrifilename
|
|
118
202
|
infodict["slicetimename"] = slicetimename
|
|
119
203
|
infodict["outputroot"] = outputroot
|
|
@@ -140,6 +224,12 @@ def happy_main(argparsingfunc):
|
|
|
140
224
|
"CommandLineArgs": args.commandline,
|
|
141
225
|
}
|
|
142
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
|
+
|
|
143
233
|
# save the information file
|
|
144
234
|
if args.saveinfoasjson:
|
|
145
235
|
tide_io.writedicttojson(infodict, outputroot + "_info.json")
|
|
@@ -195,14 +285,41 @@ def happy_main(argparsingfunc):
|
|
|
195
285
|
|
|
196
286
|
# make and save a mask of the voxels to process based on image intensity
|
|
197
287
|
tide_util.logmem("before mask creation")
|
|
198
|
-
|
|
288
|
+
if args.processmask is not None:
|
|
289
|
+
mask = tide_mask.readamask(
|
|
290
|
+
args.processmask,
|
|
291
|
+
input_data.copyheader(numtimepoints=1),
|
|
292
|
+
xsize,
|
|
293
|
+
thresh=0.001,
|
|
294
|
+
maskname="process",
|
|
295
|
+
debug=args.debug,
|
|
296
|
+
)
|
|
297
|
+
mask = np.uint16(np.where(mask > 0, 1, 0).reshape(numspatiallocs))
|
|
298
|
+
else:
|
|
299
|
+
mask = np.uint16(tide_mask.makeepimask(input_data.nim).dataobj.reshape(numspatiallocs))
|
|
300
|
+
|
|
199
301
|
theheader = input_data.copyheader(numtimepoints=1)
|
|
200
302
|
timings.append(["Mask created", time.time(), None, None])
|
|
201
303
|
if args.outputlevel > 0:
|
|
202
|
-
maskfilename = outputroot + "_desc-processvoxels_mask"
|
|
203
304
|
bidsdict = bidsbasedict.copy()
|
|
204
|
-
|
|
205
|
-
|
|
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
|
+
)
|
|
206
323
|
timings.append(["Mask saved", time.time(), None, None])
|
|
207
324
|
mask_byslice = mask.reshape((xsize * ysize, numslices))
|
|
208
325
|
|
|
@@ -267,25 +384,49 @@ def happy_main(argparsingfunc):
|
|
|
267
384
|
)
|
|
268
385
|
# save motionr2 map
|
|
269
386
|
theheader = input_data.copyheader(numtimepoints=1)
|
|
270
|
-
motionr2filename = outputroot + "_desc-motionr2_map"
|
|
271
387
|
bidsdict = bidsbasedict.copy()
|
|
272
|
-
tide_io.writedicttojson(bidsdict, motionr2filename + ".json")
|
|
273
388
|
outarray = np.zeros((xsize, ysize, numslices), dtype=float)
|
|
274
389
|
outarray.reshape(numspatiallocs)[validprojvoxels] = confoundr2
|
|
275
|
-
|
|
276
|
-
|
|
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,
|
|
277
407
|
)
|
|
278
408
|
if args.savemotionglmfilt:
|
|
279
409
|
print("prior to save - fmri_data has shape", fmri_data.shape)
|
|
280
|
-
motionfilteredfilename = outputroot + "_desc-motionfiltered_bold"
|
|
281
410
|
bidsdict = bidsbasedict.copy()
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
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),
|
|
286
425
|
theheader,
|
|
287
|
-
|
|
426
|
+
bidsdict,
|
|
427
|
+
debug=args.debug,
|
|
288
428
|
)
|
|
429
|
+
|
|
289
430
|
timings.append(["Motion filtered data saved", time.time(), numspatiallocs, "voxels"])
|
|
290
431
|
|
|
291
432
|
# get slice times
|
|
@@ -324,16 +465,39 @@ def happy_main(argparsingfunc):
|
|
|
324
465
|
|
|
325
466
|
# save means, medians, and mads
|
|
326
467
|
theheader = input_data.copyheader(numtimepoints=1)
|
|
327
|
-
meansfilename = outputroot + "_desc-means_map"
|
|
328
|
-
mediansfilename = outputroot + "_desc-medians_map"
|
|
329
|
-
madsfilename = outputroot + "_desc-mads_map"
|
|
330
468
|
bidsdict = bidsbasedict.copy()
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
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
|
+
)
|
|
337
501
|
|
|
338
502
|
# read in estimation mask if present. Otherwise, otherwise use intensity mask.
|
|
339
503
|
infodict["estweightsname"] = args.estweightsname
|
|
@@ -371,10 +535,12 @@ def happy_main(argparsingfunc):
|
|
|
371
535
|
if numpasses > 1:
|
|
372
536
|
print()
|
|
373
537
|
print()
|
|
374
|
-
print("starting pass
|
|
375
|
-
passstring = " - pass
|
|
538
|
+
print(f"starting pass {thispass + 1} of {numpasses}")
|
|
539
|
+
passstring = f" - pass {thispass + 1}"
|
|
540
|
+
passnamefrag = f"pass{thispass + 1}"
|
|
376
541
|
else:
|
|
377
542
|
passstring = ""
|
|
543
|
+
passnamefrag = ""
|
|
378
544
|
# now get an estimate of the cardiac signal
|
|
379
545
|
print("estimating cardiac signal from fmri data")
|
|
380
546
|
tide_util.logmem("before cardiacfromimage")
|
|
@@ -402,6 +568,7 @@ def happy_main(argparsingfunc):
|
|
|
402
568
|
madnorm=args.domadnorm,
|
|
403
569
|
nprocs=args.nprocs,
|
|
404
570
|
notchpct=args.notchpct,
|
|
571
|
+
notchrolloff=args.notchrolloff,
|
|
405
572
|
fliparteries=args.fliparteries,
|
|
406
573
|
arteriesonly=args.arteriesonly,
|
|
407
574
|
usemask=args.usemaskcardfromfmri,
|
|
@@ -1405,9 +1572,24 @@ def happy_main(argparsingfunc):
|
|
|
1405
1572
|
)
|
|
1406
1573
|
|
|
1407
1574
|
theheader = input_data.copyheader(numtimepoints=1)
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
|
|
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
|
+
)
|
|
1411
1593
|
timings.append(
|
|
1412
1594
|
[
|
|
1413
1595
|
"Wright mask generation completed" + passstring,
|
|
@@ -1535,23 +1717,49 @@ def happy_main(argparsingfunc):
|
|
|
1535
1717
|
numtimepoints=args.destpoints, tr=-np.pi, toffset=2.0 * np.pi / args.destpoints
|
|
1536
1718
|
)
|
|
1537
1719
|
if thispass == numpasses - 1:
|
|
1538
|
-
|
|
1539
|
-
|
|
1540
|
-
|
|
1541
|
-
|
|
1542
|
-
|
|
1543
|
-
|
|
1544
|
-
|
|
1545
|
-
|
|
1546
|
-
|
|
1547
|
-
|
|
1548
|
-
|
|
1549
|
-
|
|
1550
|
-
|
|
1551
|
-
|
|
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
|
+
]
|
|
1552
1743
|
if args.outputlevel > 0:
|
|
1553
|
-
|
|
1554
|
-
|
|
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
|
+
)
|
|
1555
1763
|
timings.append(["Phase projected data saved" + passstring, time.time(), None, None])
|
|
1556
1764
|
|
|
1557
1765
|
if args.doaliasedcorrelation and thispass == numpasses - 1:
|
|
@@ -1560,21 +1768,57 @@ def happy_main(argparsingfunc):
|
|
|
1560
1768
|
tr=(thealiasedcorrx[1] - thealiasedcorrx[0]),
|
|
1561
1769
|
toffset=0.0,
|
|
1562
1770
|
)
|
|
1563
|
-
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
tide_io.
|
|
1573
|
-
|
|
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
|
+
)
|
|
1574
1789
|
theheader["dim"][4] = 1
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
|
|
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
|
+
)
|
|
1578
1822
|
|
|
1579
1823
|
# make and save a voxel intensity histogram
|
|
1580
1824
|
if args.unnormvesselmap:
|
|
@@ -1612,24 +1856,34 @@ def happy_main(argparsingfunc):
|
|
|
1612
1856
|
maskedapp2d[np.where(vesselmask.reshape(numspatiallocs) == 0)[0], :] = 0.0
|
|
1613
1857
|
if args.outputlevel > 1:
|
|
1614
1858
|
if thispass == numpasses - 1:
|
|
1615
|
-
maskedappfilename = outputroot + "_desc-maskedapp_info"
|
|
1616
1859
|
bidsdict = bidsbasedict.copy()
|
|
1617
|
-
|
|
1618
|
-
|
|
1619
|
-
|
|
1620
|
-
|
|
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),
|
|
1621
1874
|
theheader,
|
|
1622
|
-
|
|
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
|
+
]
|
|
1623
1885
|
)
|
|
1624
1886
|
del maskedapp2d
|
|
1625
|
-
timings.append(
|
|
1626
|
-
[
|
|
1627
|
-
"Vessel masked phase projected data saved" + passstring,
|
|
1628
|
-
time.time(),
|
|
1629
|
-
None,
|
|
1630
|
-
None,
|
|
1631
|
-
]
|
|
1632
|
-
)
|
|
1633
1887
|
|
|
1634
1888
|
# save multiple versions of the hard vessel mask
|
|
1635
1889
|
if args.unnormvesselmap:
|
|
@@ -1645,57 +1899,316 @@ def happy_main(argparsingfunc):
|
|
|
1645
1899
|
veins = np.where(appflips_byslice.reshape((xsize, ysize, numslices)) > 0, vesselmask, 0)
|
|
1646
1900
|
theheader = input_data.copyheader(numtimepoints=1)
|
|
1647
1901
|
if thispass == numpasses - 1:
|
|
1648
|
-
|
|
1649
|
-
|
|
1650
|
-
|
|
1651
|
-
|
|
1652
|
-
|
|
1653
|
-
|
|
1654
|
-
|
|
1655
|
-
|
|
1902
|
+
maplist = [
|
|
1903
|
+
(
|
|
1904
|
+
vesselmask,
|
|
1905
|
+
"vessels",
|
|
1906
|
+
"mask",
|
|
1907
|
+
None,
|
|
1908
|
+
"Vessel mask",
|
|
1909
|
+
),
|
|
1910
|
+
]
|
|
1656
1911
|
if args.outputlevel > 0:
|
|
1657
|
-
|
|
1658
|
-
|
|
1659
|
-
|
|
1660
|
-
|
|
1661
|
-
|
|
1662
|
-
|
|
1663
|
-
|
|
1664
|
-
|
|
1665
|
-
|
|
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
|
+
)
|
|
1666
1951
|
timings.append(["Masks saved" + passstring, time.time(), None, None])
|
|
1667
1952
|
|
|
1668
1953
|
# save the mask we used for this pass
|
|
1669
|
-
tide_io.
|
|
1670
|
-
|
|
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),
|
|
1671
1967
|
theheader,
|
|
1672
|
-
|
|
1968
|
+
bidsdict,
|
|
1969
|
+
debug=args.debug,
|
|
1673
1970
|
)
|
|
1674
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
|
+
|
|
1675
2059
|
# now get ready to start again with a new mask
|
|
1676
2060
|
if args.doaliasedcorrelation and thispass > 0:
|
|
1677
2061
|
estweights_byslice = waveamp_byslice * vesselmask.reshape((xsize * ysize, numslices))
|
|
1678
2062
|
else:
|
|
1679
|
-
|
|
1680
|
-
|
|
1681
|
-
|
|
1682
|
-
|
|
1683
|
-
|
|
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)
|
|
1684
2100
|
else:
|
|
1685
|
-
vesselmap =
|
|
1686
|
-
|
|
1687
|
-
|
|
1688
|
-
|
|
1689
|
-
|
|
1690
|
-
|
|
1691
|
-
|
|
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),
|
|
1692
2177
|
theheader,
|
|
1693
|
-
|
|
2178
|
+
bidsdict,
|
|
2179
|
+
debug=args.debug,
|
|
2180
|
+
)
|
|
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
|
|
1694
2185
|
)
|
|
1695
|
-
|
|
1696
|
-
|
|
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),
|
|
1697
2209
|
theheader,
|
|
1698
|
-
|
|
2210
|
+
bidsdict,
|
|
2211
|
+
debug=args.debug,
|
|
1699
2212
|
)
|
|
1700
2213
|
|
|
1701
2214
|
# now generate aliased cardiac signals and regress them out of the data
|
|
@@ -1721,34 +2234,85 @@ def happy_main(argparsingfunc):
|
|
|
1721
2234
|
theheader = input_data.copyheader()
|
|
1722
2235
|
timings.append(["Cardiac signal generated", time.time(), None, None])
|
|
1723
2236
|
if args.savecardiacnoise:
|
|
1724
|
-
|
|
1725
|
-
|
|
1726
|
-
|
|
1727
|
-
|
|
1728
|
-
|
|
1729
|
-
|
|
1730
|
-
|
|
1731
|
-
|
|
1732
|
-
|
|
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),
|
|
1733
2258
|
theheader,
|
|
1734
|
-
|
|
2259
|
+
bidsdict,
|
|
2260
|
+
debug=args.debug,
|
|
1735
2261
|
)
|
|
1736
2262
|
timings.append(["Cardiac signal saved", time.time(), None, None])
|
|
1737
2263
|
|
|
1738
2264
|
# now remove them
|
|
1739
2265
|
tide_util.logmem("before cardiac removal")
|
|
1740
2266
|
print("Removing cardiac signal with GLM")
|
|
1741
|
-
filtereddata = 0.0 * fmri_data
|
|
1742
2267
|
validlocs = np.where(mask > 0)[0]
|
|
1743
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
|
+
)
|
|
1744
2283
|
threshval = 0.0
|
|
1745
2284
|
if args.dospatialregression:
|
|
1746
|
-
|
|
1747
|
-
|
|
1748
|
-
|
|
1749
|
-
|
|
1750
|
-
|
|
1751
|
-
|
|
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
|
+
)
|
|
1752
2316
|
print("Running spatial regression on", timepoints, "timepoints")
|
|
1753
2317
|
tide_util.disablemkl(args.nprocs)
|
|
1754
2318
|
tide_linfitfiltpass.linfitfiltpass(
|
|
@@ -1768,8 +2332,10 @@ def happy_main(argparsingfunc):
|
|
|
1768
2332
|
nprocs=args.nprocs,
|
|
1769
2333
|
)
|
|
1770
2334
|
tide_util.enablemkl(args.mklthreads)
|
|
1771
|
-
|
|
1772
|
-
|
|
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)=}")
|
|
1773
2339
|
filtereddata = fmri_data - datatoremove
|
|
1774
2340
|
timings.append(
|
|
1775
2341
|
[
|
|
@@ -1779,38 +2345,39 @@ def happy_main(argparsingfunc):
|
|
|
1779
2345
|
"timepoints",
|
|
1780
2346
|
]
|
|
1781
2347
|
)
|
|
1782
|
-
|
|
1783
|
-
|
|
1784
|
-
|
|
1785
|
-
|
|
1786
|
-
|
|
1787
|
-
|
|
1788
|
-
|
|
1789
|
-
|
|
1790
|
-
theheader,
|
|
1791
|
-
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']}",
|
|
1792
2356
|
)
|
|
1793
|
-
|
|
1794
|
-
|
|
1795
|
-
|
|
1796
|
-
|
|
2357
|
+
rvals, rvals_shm = tide_util.allocarray(
|
|
2358
|
+
(numspatiallocs),
|
|
2359
|
+
"float64",
|
|
2360
|
+
shared=infodict["sharedmem"],
|
|
2361
|
+
name=f"rvals_{infodict['pid']}",
|
|
1797
2362
|
)
|
|
1798
|
-
|
|
1799
|
-
|
|
1800
|
-
|
|
1801
|
-
|
|
1802
|
-
|
|
1803
|
-
|
|
1804
|
-
|
|
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']}",
|
|
1805
2380
|
)
|
|
1806
|
-
|
|
1807
|
-
if args.dotemporalregression:
|
|
1808
|
-
meanvals = np.zeros(numspatiallocs, dtype=np.float64)
|
|
1809
|
-
rvals = np.zeros(numspatiallocs, dtype=np.float64)
|
|
1810
|
-
r2vals = np.zeros(numspatiallocs, dtype=np.float64)
|
|
1811
|
-
fitcoffs = np.zeros(numspatiallocs, dtype=np.float64)
|
|
1812
|
-
fitNorm = np.zeros(numspatiallocs, dtype=np.float64)
|
|
1813
|
-
datatoremove = 0.0 * fmri_data
|
|
1814
2381
|
print("Running temporal regression on", numvalidspatiallocs, "voxels")
|
|
1815
2382
|
tide_util.disablemkl(args.nprocs)
|
|
1816
2383
|
tide_linfitfiltpass.linfitfiltpass(
|
|
@@ -1827,11 +2394,15 @@ def happy_main(argparsingfunc):
|
|
|
1827
2394
|
filtereddata[validlocs, :],
|
|
1828
2395
|
procbyvoxel=True,
|
|
1829
2396
|
nprocs=args.nprocs,
|
|
2397
|
+
debug=args.focaldebug,
|
|
1830
2398
|
)
|
|
1831
2399
|
tide_util.enablemkl(args.mklthreads)
|
|
1832
2400
|
datatoremove[validlocs, :] = np.multiply(
|
|
1833
2401
|
cardiacnoise[validlocs, :], fitcoffs[validlocs, None]
|
|
1834
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)=}")
|
|
1835
2406
|
filtereddata[validlocs, :] = fmri_data[validlocs, :] - datatoremove[validlocs, :]
|
|
1836
2407
|
timings.append(
|
|
1837
2408
|
[
|
|
@@ -1842,44 +2413,85 @@ def happy_main(argparsingfunc):
|
|
|
1842
2413
|
]
|
|
1843
2414
|
)
|
|
1844
2415
|
theheader = input_data.copyheader(numtimepoints=1)
|
|
1845
|
-
|
|
1846
|
-
|
|
1847
|
-
|
|
1848
|
-
|
|
1849
|
-
|
|
1850
|
-
|
|
1851
|
-
|
|
1852
|
-
|
|
1853
|
-
|
|
1854
|
-
|
|
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),
|
|
1855
2444
|
theheader,
|
|
1856
|
-
|
|
1857
|
-
|
|
1858
|
-
tide_io.savetonifti(
|
|
1859
|
-
rvals.reshape((xsize, ysize, numslices)), theheader, cardfiltRfilename
|
|
2445
|
+
bidsdict,
|
|
2446
|
+
debug=args.debug,
|
|
1860
2447
|
)
|
|
1861
2448
|
|
|
1862
|
-
|
|
1863
|
-
|
|
1864
|
-
|
|
1865
|
-
|
|
2449
|
+
# now write out the filtered data
|
|
2450
|
+
theheader = input_data.copyheader()
|
|
2451
|
+
maplist = [
|
|
2452
|
+
(
|
|
1866
2453
|
filtereddata.reshape((xsize, ysize, numslices, timepoints)),
|
|
1867
|
-
|
|
1868
|
-
|
|
1869
|
-
|
|
1870
|
-
|
|
2454
|
+
"cardfiltResult",
|
|
2455
|
+
"bold",
|
|
2456
|
+
None,
|
|
2457
|
+
f"Cardiac filtered BOLD data after {regressiontype} regression",
|
|
2458
|
+
),
|
|
2459
|
+
(
|
|
1871
2460
|
datatoremove.reshape((xsize, ysize, numslices, timepoints)),
|
|
1872
|
-
|
|
1873
|
-
|
|
1874
|
-
|
|
1875
|
-
|
|
1876
|
-
|
|
1877
|
-
|
|
1878
|
-
|
|
1879
|
-
|
|
1880
|
-
|
|
1881
|
-
|
|
1882
|
-
)
|
|
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)
|
|
1883
2495
|
|
|
1884
2496
|
timings.append(["Done", time.time(), None, None])
|
|
1885
2497
|
|