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.
Files changed (141) hide show
  1. rapidtide/Colortables.py +492 -27
  2. rapidtide/OrthoImageItem.py +1053 -47
  3. rapidtide/RapidtideDataset.py +1533 -86
  4. rapidtide/_version.py +3 -3
  5. rapidtide/calccoherence.py +196 -29
  6. rapidtide/calcnullsimfunc.py +191 -40
  7. rapidtide/calcsimfunc.py +245 -42
  8. rapidtide/correlate.py +1210 -393
  9. rapidtide/data/examples/src/testLD +56 -0
  10. rapidtide/data/examples/src/testalign +1 -1
  11. rapidtide/data/examples/src/testdelayvar +0 -1
  12. rapidtide/data/examples/src/testfmri +19 -1
  13. rapidtide/data/examples/src/testglmfilt +5 -5
  14. rapidtide/data/examples/src/testhappy +30 -1
  15. rapidtide/data/examples/src/testppgproc +17 -0
  16. rapidtide/data/examples/src/testrolloff +11 -0
  17. rapidtide/data/models/model_cnn_pytorch/best_model.pth +0 -0
  18. rapidtide/data/models/model_cnn_pytorch/loss.png +0 -0
  19. rapidtide/data/models/model_cnn_pytorch/loss.txt +1 -0
  20. rapidtide/data/models/model_cnn_pytorch/model.pth +0 -0
  21. rapidtide/data/models/model_cnn_pytorch/model_meta.json +68 -0
  22. rapidtide/data/reference/JHU-ArterialTerritoriesNoVent-LVL1_space-MNI152NLin2009cAsym_2mm.nii.gz +0 -0
  23. rapidtide/data/reference/JHU-ArterialTerritoriesNoVent-LVL1_space-MNI152NLin2009cAsym_2mm_mask.nii.gz +0 -0
  24. rapidtide/decorators.py +91 -0
  25. rapidtide/dlfilter.py +2225 -108
  26. rapidtide/dlfiltertorch.py +4843 -0
  27. rapidtide/externaltools.py +327 -12
  28. rapidtide/fMRIData_class.py +79 -40
  29. rapidtide/filter.py +1899 -810
  30. rapidtide/fit.py +2004 -574
  31. rapidtide/genericmultiproc.py +93 -18
  32. rapidtide/happy_supportfuncs.py +2044 -171
  33. rapidtide/helper_classes.py +584 -43
  34. rapidtide/io.py +2363 -370
  35. rapidtide/linfitfiltpass.py +341 -75
  36. rapidtide/makelaggedtcs.py +211 -20
  37. rapidtide/maskutil.py +423 -53
  38. rapidtide/miscmath.py +827 -121
  39. rapidtide/multiproc.py +210 -22
  40. rapidtide/patchmatch.py +234 -33
  41. rapidtide/peakeval.py +32 -30
  42. rapidtide/ppgproc.py +2203 -0
  43. rapidtide/qualitycheck.py +352 -39
  44. rapidtide/refinedelay.py +422 -57
  45. rapidtide/refineregressor.py +498 -184
  46. rapidtide/resample.py +671 -185
  47. rapidtide/scripts/applyppgproc.py +28 -0
  48. rapidtide/simFuncClasses.py +1052 -77
  49. rapidtide/simfuncfit.py +260 -46
  50. rapidtide/stats.py +540 -238
  51. rapidtide/tests/happycomp +9 -0
  52. rapidtide/tests/test_dlfiltertorch.py +627 -0
  53. rapidtide/tests/test_findmaxlag.py +24 -8
  54. rapidtide/tests/test_fullrunhappy_v1.py +0 -2
  55. rapidtide/tests/test_fullrunhappy_v2.py +0 -2
  56. rapidtide/tests/test_fullrunhappy_v3.py +1 -0
  57. rapidtide/tests/test_fullrunhappy_v4.py +2 -2
  58. rapidtide/tests/test_fullrunrapidtide_v7.py +1 -1
  59. rapidtide/tests/test_simroundtrip.py +8 -8
  60. rapidtide/tests/utils.py +9 -8
  61. rapidtide/tidepoolTemplate.py +142 -38
  62. rapidtide/tidepoolTemplate_alt.py +165 -44
  63. rapidtide/tidepoolTemplate_big.py +189 -52
  64. rapidtide/util.py +1217 -118
  65. rapidtide/voxelData.py +684 -37
  66. rapidtide/wiener.py +19 -12
  67. rapidtide/wiener2.py +113 -7
  68. rapidtide/wiener_doc.py +255 -0
  69. rapidtide/workflows/adjustoffset.py +105 -3
  70. rapidtide/workflows/aligntcs.py +85 -2
  71. rapidtide/workflows/applydlfilter.py +87 -10
  72. rapidtide/workflows/applyppgproc.py +522 -0
  73. rapidtide/workflows/atlasaverage.py +210 -47
  74. rapidtide/workflows/atlastool.py +100 -3
  75. rapidtide/workflows/calcSimFuncMap.py +294 -64
  76. rapidtide/workflows/calctexticc.py +201 -9
  77. rapidtide/workflows/ccorrica.py +97 -4
  78. rapidtide/workflows/cleanregressor.py +168 -29
  79. rapidtide/workflows/delayvar.py +163 -10
  80. rapidtide/workflows/diffrois.py +81 -3
  81. rapidtide/workflows/endtidalproc.py +144 -4
  82. rapidtide/workflows/fdica.py +195 -15
  83. rapidtide/workflows/filtnifti.py +70 -3
  84. rapidtide/workflows/filttc.py +74 -3
  85. rapidtide/workflows/fitSimFuncMap.py +206 -48
  86. rapidtide/workflows/fixtr.py +73 -3
  87. rapidtide/workflows/gmscalc.py +113 -3
  88. rapidtide/workflows/happy.py +813 -201
  89. rapidtide/workflows/happy2std.py +144 -12
  90. rapidtide/workflows/happy_parser.py +149 -8
  91. rapidtide/workflows/histnifti.py +118 -2
  92. rapidtide/workflows/histtc.py +84 -3
  93. rapidtide/workflows/linfitfilt.py +117 -4
  94. rapidtide/workflows/localflow.py +328 -28
  95. rapidtide/workflows/mergequality.py +79 -3
  96. rapidtide/workflows/niftidecomp.py +322 -18
  97. rapidtide/workflows/niftistats.py +174 -4
  98. rapidtide/workflows/pairproc.py +88 -2
  99. rapidtide/workflows/pairwisemergenifti.py +85 -2
  100. rapidtide/workflows/parser_funcs.py +1421 -40
  101. rapidtide/workflows/physiofreq.py +137 -11
  102. rapidtide/workflows/pixelcomp.py +208 -5
  103. rapidtide/workflows/plethquality.py +103 -21
  104. rapidtide/workflows/polyfitim.py +151 -11
  105. rapidtide/workflows/proj2flow.py +75 -2
  106. rapidtide/workflows/rankimage.py +111 -4
  107. rapidtide/workflows/rapidtide.py +272 -15
  108. rapidtide/workflows/rapidtide2std.py +98 -2
  109. rapidtide/workflows/rapidtide_parser.py +109 -9
  110. rapidtide/workflows/refineDelayMap.py +143 -33
  111. rapidtide/workflows/refineRegressor.py +682 -93
  112. rapidtide/workflows/regressfrommaps.py +152 -31
  113. rapidtide/workflows/resamplenifti.py +85 -3
  114. rapidtide/workflows/resampletc.py +91 -3
  115. rapidtide/workflows/retrolagtcs.py +98 -6
  116. rapidtide/workflows/retroregress.py +165 -9
  117. rapidtide/workflows/roisummarize.py +173 -5
  118. rapidtide/workflows/runqualitycheck.py +71 -3
  119. rapidtide/workflows/showarbcorr.py +147 -4
  120. rapidtide/workflows/showhist.py +86 -2
  121. rapidtide/workflows/showstxcorr.py +160 -3
  122. rapidtide/workflows/showtc.py +159 -3
  123. rapidtide/workflows/showxcorrx.py +184 -4
  124. rapidtide/workflows/showxy.py +185 -15
  125. rapidtide/workflows/simdata.py +262 -36
  126. rapidtide/workflows/spatialfit.py +77 -2
  127. rapidtide/workflows/spatialmi.py +251 -27
  128. rapidtide/workflows/spectrogram.py +305 -32
  129. rapidtide/workflows/synthASL.py +154 -3
  130. rapidtide/workflows/tcfrom2col.py +76 -2
  131. rapidtide/workflows/tcfrom3col.py +74 -2
  132. rapidtide/workflows/tidepool.py +2972 -133
  133. rapidtide/workflows/utils.py +19 -14
  134. rapidtide/workflows/utils_doc.py +293 -0
  135. rapidtide/workflows/variabilityizer.py +116 -3
  136. {rapidtide-3.0.10.dist-info → rapidtide-3.1.dist-info}/METADATA +10 -9
  137. {rapidtide-3.0.10.dist-info → rapidtide-3.1.dist-info}/RECORD +141 -122
  138. {rapidtide-3.0.10.dist-info → rapidtide-3.1.dist-info}/entry_points.txt +1 -0
  139. {rapidtide-3.0.10.dist-info → rapidtide-3.1.dist-info}/WHEEL +0 -0
  140. {rapidtide-3.0.10.dist-info → rapidtide-3.1.dist-info}/licenses/LICENSE +0 -0
  141. {rapidtide-3.0.10.dist-info → rapidtide-3.1.dist-info}/top_level.txt +0 -0
@@ -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 scipy.stats import pearsonr
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
- def happy_main(argparsingfunc):
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
- verbose=args.verbose,
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
- mask = np.uint16(tide_mask.makeepimask(input_data.nim).dataobj.reshape(numspatiallocs))
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
- tide_io.writedicttojson(bidsdict, maskfilename + ".json")
205
- tide_io.savetonifti(mask.reshape((xsize, ysize, numslices)), theheader, maskfilename)
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
- tide_io.savetonifti(
276
- outarray.reshape((xsize, ysize, numslices)), theheader, motionr2filename
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
- bidsdict["Units"] = "second"
283
- tide_io.writedicttojson(bidsdict, motionfilteredfilename + ".json")
284
- tide_io.savetonifti(
285
- fmri_data.reshape((xsize, ysize, numslices, timepoints)),
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
- motionfilteredfilename,
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
- tide_io.writedicttojson(bidsdict, meansfilename + ".json")
332
- tide_io.writedicttojson(bidsdict, mediansfilename + ".json")
333
- tide_io.writedicttojson(bidsdict, madsfilename + ".json")
334
- tide_io.savetonifti(means.reshape((xsize, ysize, numslices)), theheader, meansfilename)
335
- tide_io.savetonifti(medians.reshape((xsize, ysize, numslices)), theheader, mediansfilename)
336
- tide_io.savetonifti(mads.reshape((xsize, ysize, numslices)), theheader, madsfilename)
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", thispass + 1, "of", numpasses)
375
- passstring = " - pass " + str(thispass + 1)
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
- wrightfilename = f"{outputroot}_desc-wrightcorrspass{thispass + 1}_map"
1409
- tide_io.writedicttojson(bidsbasedict, wrightfilename + ".json")
1410
- tide_io.savetonifti(wrightcorrs, theheader, wrightfilename)
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
- appfilename = outputroot + "_desc-app_info"
1539
- normappfilename = outputroot + "_desc-normapp_info"
1540
- cinefilename = outputroot + "_desc-cine_info"
1541
- rawappfilename = outputroot + "_desc-rawapp_info"
1542
- bidsdict = bidsbasedict.copy()
1543
- bidsdict["Units"] = "second"
1544
- tide_io.writedicttojson(bidsdict, appfilename + ".json")
1545
- tide_io.writedicttojson(bidsdict, normappfilename + ".json")
1546
- tide_io.writedicttojson(bidsdict, cinefilename + ".json")
1547
- if args.outputlevel > 0:
1548
- tide_io.writedicttojson(bidsdict, rawappfilename + ".json")
1549
- tide_io.savetonifti(app, theheader, appfilename)
1550
- tide_io.savetonifti(normapp, theheader, normappfilename)
1551
- tide_io.savetonifti(cine, theheader, cinefilename)
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
- tide_io.savetonifti(rawapp, theheader, rawappfilename)
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
- corrfuncfilename = outputroot + "_desc-corrfunc_info"
1564
- wavedelayfilename = outputroot + "_desc-wavedelay_map"
1565
- wavedelayCOMfilename = outputroot + "_desc-wavedelayCOM_map"
1566
- waveampfilename = outputroot + "_desc-waveamp_map"
1567
- bidsdict = bidsbasedict.copy()
1568
- tide_io.writedicttojson(bidsdict, waveampfilename + ".json")
1569
- bidsdict["Units"] = "second"
1570
- tide_io.writedicttojson(bidsdict, corrfuncfilename + ".json")
1571
- tide_io.writedicttojson(bidsdict, wavedelayfilename + ".json")
1572
- tide_io.writedicttojson(bidsdict, wavedelayCOMfilename + ".json")
1573
- tide_io.savetonifti(thecorrfunc, theheader, corrfuncfilename)
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
- tide_io.savetonifti(wavedelay, theheader, wavedelayfilename)
1576
- tide_io.savetonifti(wavedelayCOM, theheader, wavedelayCOMfilename)
1577
- tide_io.savetonifti(waveamp, theheader, waveampfilename)
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
- bidsdict["Units"] = "second"
1618
- tide_io.writedicttojson(bidsdict, maskedappfilename + ".json")
1619
- tide_io.savetonifti(
1620
- maskedapp2d.reshape((xsize, ysize, numslices, args.destpoints)),
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
- maskedappfilename,
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
- vesselmaskfilename = outputroot + "_desc-vessels_mask"
1649
- minphasefilename = outputroot + "_desc-minphase_map"
1650
- maxphasefilename = outputroot + "_desc-maxphase_map"
1651
- arterymapfilename = outputroot + "_desc-arteries_map"
1652
- veinmapfilename = outputroot + "_desc-veins_map"
1653
- bidsdict = bidsbasedict.copy()
1654
- tide_io.writedicttojson(bidsdict, vesselmaskfilename + ".json")
1655
- tide_io.savetonifti(vesselmask, theheader, vesselmaskfilename)
1902
+ maplist = [
1903
+ (
1904
+ vesselmask,
1905
+ "vessels",
1906
+ "mask",
1907
+ None,
1908
+ "Vessel mask",
1909
+ ),
1910
+ ]
1656
1911
  if args.outputlevel > 0:
1657
- tide_io.writedicttojson(bidsdict, arterymapfilename + ".json")
1658
- tide_io.writedicttojson(bidsdict, veinmapfilename + ".json")
1659
- bidsdict["Units"] = "radians"
1660
- tide_io.writedicttojson(bidsdict, minphasefilename + ".json")
1661
- tide_io.writedicttojson(bidsdict, maxphasefilename + ".json")
1662
- tide_io.savetonifti(minphase, theheader, minphasefilename)
1663
- tide_io.savetonifti(maxphase, theheader, maxphasefilename)
1664
- tide_io.savetonifti(arteries, theheader, arterymapfilename)
1665
- tide_io.savetonifti(veins, theheader, veinmapfilename)
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.savetonifti(
1670
- estweights_byslice.reshape((xsize, ysize, numslices)),
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
- f"{outputroot}_desc-estweightspass{thispass}_map",
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
- estweights_byslice = vesselmask.reshape((xsize * ysize, numslices)) + 0
1680
-
1681
- # save a vessel image
1682
- if args.unnormvesselmap:
1683
- vesselmap = np.max(app, axis=3)
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 = np.max(normapp, axis=3)
1686
- vesselmapfilename = outputroot + "_desc-vessels_map"
1687
- arterymapfilename = outputroot + "_desc-arteries_map"
1688
- veinmapfilename = outputroot + "_desc-veins_map"
1689
- tide_io.savetonifti(vesselmap, theheader, vesselmapfilename)
1690
- tide_io.savetonifti(
1691
- np.where(appflips_byslice.reshape((xsize, ysize, numslices)) < 0, vesselmap, 0.0),
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
- arterymapfilename,
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
- tide_io.savetonifti(
1696
- np.where(appflips_byslice.reshape((xsize, ysize, numslices)) > 0, vesselmap, 0.0),
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
- veinmapfilename,
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
- cardiacnoisefilename = outputroot + "_desc-cardiacnoise_info"
1725
- phaseindexfilename = outputroot + "_desc-phaseindices_info"
1726
- tide_io.savetonifti(
1727
- cardiacnoise.reshape((xsize, ysize, numslices, timepoints)),
1728
- theheader,
1729
- cardiacnoisefilename,
1730
- )
1731
- tide_io.savetonifti(
1732
- phaseindices.reshape((xsize, ysize, numslices, timepoints)),
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
- phaseindexfilename,
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
- meanvals = np.zeros(timepoints, dtype=np.float64)
1747
- rvals = np.zeros(timepoints, dtype=np.float64)
1748
- r2vals = np.zeros(timepoints, dtype=np.float64)
1749
- fitcoffs = np.zeros(timepoints, dtype=np.float64)
1750
- fitNorm = np.zeros(timepoints, dtype=np.float64)
1751
- datatoremove = 0.0 * fmri_data
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
- print(datatoremove.shape, cardiacnoise.shape, fitcoffs.shape)
1772
- # datatoremove[validlocs, :] = np.multiply(cardiacnoise[validlocs, :], fitcoffs[:, None])
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
- tide_io.writevec(fitcoffs, outputroot + "_fitcoff.txt")
1783
- tide_io.writevec(meanvals, outputroot + "_fitmean.txt")
1784
- tide_io.writevec(rvals, outputroot + "_fitR.txt")
1785
- theheader = input_data.copyheader()
1786
- cardfiltresultfilename = outputroot + "_desc-cardfiltResult_bold"
1787
- cardfiltremovedfilename = outputroot + "_desc-cardfiltRemoved_bold"
1788
- tide_io.savetonifti(
1789
- filtereddata.reshape((xsize, ysize, numslices, timepoints)),
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
- tide_io.savetonifti(
1794
- datatoremove.reshape((xsize, ysize, numslices, timepoints)),
1795
- theheader,
1796
- cardfiltremovedfilename,
2357
+ rvals, rvals_shm = tide_util.allocarray(
2358
+ (numspatiallocs),
2359
+ "float64",
2360
+ shared=infodict["sharedmem"],
2361
+ name=f"rvals_{infodict['pid']}",
1797
2362
  )
1798
- timings.append(
1799
- [
1800
- "Cardiac signal spatial regression files written",
1801
- time.time(),
1802
- None,
1803
- None,
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
- cardfiltcoeffsfilename = outputroot + "_desc-cardfiltCoeffs_map"
1846
- cardfiltmeanfilename = outputroot + "_desc-cardfiltMean_map"
1847
- cardfiltRfilename = outputroot + "_desc-cardfiltR_map"
1848
- tide_io.savetonifti(
1849
- fitcoffs.reshape((xsize, ysize, numslices)),
1850
- theheader,
1851
- cardfiltcoeffsfilename,
1852
- )
1853
- tide_io.savetonifti(
1854
- meanvals.reshape((xsize, ysize, numslices)),
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
- cardfiltmeanfilename,
1857
- )
1858
- tide_io.savetonifti(
1859
- rvals.reshape((xsize, ysize, numslices)), theheader, cardfiltRfilename
2445
+ bidsdict,
2446
+ debug=args.debug,
1860
2447
  )
1861
2448
 
1862
- theheader = input_data.copyheader()
1863
- cardfiltresultfilename = outputroot + "_desc-cardfiltResult_bold"
1864
- cardfiltremovedfilename = outputroot + "_desc-cardfiltRemoved_bold"
1865
- tide_io.savetonifti(
2449
+ # now write out the filtered data
2450
+ theheader = input_data.copyheader()
2451
+ maplist = [
2452
+ (
1866
2453
  filtereddata.reshape((xsize, ysize, numslices, timepoints)),
1867
- theheader,
1868
- cardfiltresultfilename,
1869
- )
1870
- tide_io.savetonifti(
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
- theheader,
1873
- cardfiltremovedfilename,
1874
- )
1875
- timings.append(
1876
- [
1877
- "Cardiac signal temporal regression files written",
1878
- time.time(),
1879
- None,
1880
- None,
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