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
@@ -19,8 +19,11 @@
19
19
  import gc
20
20
  import logging
21
21
  import sys
22
+ from typing import Any, Callable
22
23
 
23
24
  import numpy as np
25
+ import statsmodels as sm
26
+ from numpy.typing import NDArray
24
27
  from scipy.stats import pearsonr
25
28
  from sklearn.decomposition import PCA, FastICA
26
29
 
@@ -35,10 +38,10 @@ LGR = logging.getLogger("GENERAL")
35
38
 
36
39
 
37
40
  def _procOneVoxelTimeShift(
38
- vox,
39
- voxelargs,
40
- **kwargs,
41
- ):
41
+ vox: int,
42
+ voxelargs: tuple,
43
+ **kwargs: Any,
44
+ ) -> tuple[int, NDArray, NDArray, NDArray, NDArray]:
42
45
  options = {
43
46
  "detrendorder": 1,
44
47
  "offsettime": 0.0,
@@ -67,108 +70,247 @@ def _procOneVoxelTimeShift(
67
70
  return vox, shiftedtc, weights, paddedshiftedtc, paddedweights
68
71
 
69
72
 
70
- def _packvoxeldata(voxnum, voxelargs):
73
+ def _packvoxeldata(voxnum: int, voxelargs: tuple) -> list:
74
+ """
75
+ Pack voxel data into a list structure.
76
+
77
+ Parameters
78
+ ----------
79
+ voxnum : int
80
+ The voxel index to extract data from.
81
+ voxelargs : tuple
82
+ A tuple containing voxel data with the following structure:
83
+ - voxelargs[0]: 2D array of shape (n_voxels, n_features) containing voxel features
84
+ - voxelargs[1]: 1D array of shape (n_voxels,) containing voxel labels or values
85
+ - voxelargs[2]: Additional voxel parameter (type depends on context)
86
+ - voxelargs[3]: Additional voxel parameter (type depends on context)
87
+
88
+ Returns
89
+ -------
90
+ list
91
+ A list containing:
92
+ - [0]: 1D array of shape (n_features,) representing voxel features at voxnum
93
+ - [1]: scalar value representing voxel label or value at voxnum
94
+ - [2]: third element from voxelargs tuple
95
+ - [3]: fourth element from voxelargs tuple
96
+
97
+ Notes
98
+ -----
99
+ This function is typically used for extracting and packaging voxel data for further processing
100
+ in neuroimaging or 3D data analysis workflows.
101
+
102
+ Examples
103
+ --------
104
+ >>> voxel_features = np.array([[1, 2, 3], [4, 5, 6]])
105
+ >>> voxel_labels = np.array([10, 20])
106
+ >>> extra_param1 = "param1"
107
+ >>> extra_param2 = "param2"
108
+ >>> result = _packvoxeldata(0, (voxel_features, voxel_labels, extra_param1, extra_param2))
109
+ >>> print(result)
110
+ [[1, 2, 3], 10, 'param1', 'param2']
111
+ """
71
112
  return [(voxelargs[0])[voxnum, :], (voxelargs[1])[voxnum], voxelargs[2], voxelargs[3]]
72
113
 
73
114
 
74
- def _unpackvoxeldata(retvals, voxelproducts):
115
+ def _unpackvoxeldata(retvals: tuple, voxelproducts: list) -> None:
116
+ """
117
+ Unpack voxel data from retvals into voxelproducts arrays.
118
+
119
+ Parameters
120
+ ----------
121
+ retvals : tuple
122
+ Tuple containing voxel data to be unpacked. Expected to contain at least 5 elements
123
+ where retvals[0] is the index for assignment and retvals[1:5] are the data arrays.
124
+ voxelproducts : list
125
+ List of arrays where voxel data will be unpacked. Expected to contain exactly 4 arrays
126
+ that will be modified in-place.
127
+
128
+ Returns
129
+ -------
130
+ None
131
+ This function modifies the voxelproducts arrays in-place and does not return anything.
132
+
133
+ Notes
134
+ -----
135
+ This function performs in-place assignment of voxel data. The first element of retvals
136
+ is used as an index for row-wise assignment into each of the four arrays in voxelproducts.
137
+ All arrays in voxelproducts must have sufficient dimensions to accommodate the assignment.
138
+
139
+ Examples
140
+ --------
141
+ >>> import numpy as np
142
+ >>> voxel_data = [np.zeros((10, 5)), np.zeros((10, 5)), np.zeros((10, 5)), np.zeros((10, 5))]
143
+ >>> retvals = (2, np.array([1, 2, 3, 4, 5]), np.array([6, 7, 8, 9, 10]),
144
+ ... np.array([11, 12, 13, 14, 15]), np.array([16, 17, 18, 19, 20]))
145
+ >>> _unpackvoxeldata(retvals, voxel_data)
146
+ >>> print(voxel_data[0][2, :]) # Should print [1 2 3 4 5]
147
+ """
75
148
  (voxelproducts[0])[retvals[0], :] = retvals[1]
76
149
  (voxelproducts[1])[retvals[0], :] = retvals[2]
77
150
  (voxelproducts[2])[retvals[0], :] = retvals[3]
78
151
  (voxelproducts[3])[retvals[0], :] = retvals[4]
79
152
 
80
153
 
81
- def alignvoxels(
82
- fmridata,
83
- fmritr,
84
- shiftedtcs,
85
- weights,
86
- paddedshiftedtcs,
87
- paddedweights,
88
- lagtimes,
89
- lagmask,
90
- detrendorder=1,
91
- offsettime=0.0,
92
- nprocs=1,
93
- alwaysmultiproc=False,
94
- showprogressbar=True,
95
- chunksize=1000,
96
- padtrs=60,
97
- debug=False,
98
- rt_floatset=np.float64,
99
- rt_floattype="float64",
100
- ):
154
+ def findecho(
155
+ nlags: int,
156
+ shiftedtcs: NDArray,
157
+ sigmav: NDArray,
158
+ arcoefs: NDArray,
159
+ pacf: NDArray,
160
+ sigma: NDArray,
161
+ phi: NDArray,
162
+ ) -> None:
101
163
  """
102
- This routine applies a timeshift to every voxel in the image.
103
- Inputs are:
104
- fmridata - the fmri data, filtered to the passband
105
- fmritr - the timestep of the data
106
- shiftedtcs,
107
- weights,
108
- paddedshiftedtcs,
109
- paddedweights,
110
- lagtimes, lagmask - the results of the correlation fit.
111
- detrendorder - the order of the polynomial to use to detrend the data
112
- offsettime - the global timeshift to apply to all timecourses
113
- nprocs - the number of processes to use if multiprocessing is enabled
164
+ Compute autoregressive parameters and related statistics for each voxel using Levinson-Durbin recursion.
165
+
166
+ This function applies the Levinson-Durbin algorithm to estimate autoregressive coefficients
167
+ and associated statistics for time series data from multiple voxels. The algorithm computes
168
+ the variance, autoregressive coefficients, partial autocorrelations, and other related
169
+ parameters for each voxel's time series.
170
+
171
+ Parameters
172
+ ----------
173
+ nlags : int
174
+ Number of lags to compute for the autoregressive model.
175
+ shiftedtcs : NDArray
176
+ Input time series data with shape (n_voxels, n_timepoints), where each row represents
177
+ a voxel's time series.
178
+ sigmav : NDArray
179
+ Output array for variance estimates, shape (n_voxels,).
180
+ arcoefs : NDArray
181
+ Output array for autoregressive coefficients, shape (n_voxels, nlags).
182
+ pacf : NDArray
183
+ Output array for partial autocorrelations, shape (n_voxels, nlags).
184
+ sigma : NDArray
185
+ Output array for sigma values, shape (n_voxels, nlags).
186
+ phi : NDArray
187
+ Output array for phi values, shape (n_voxels, nlags).
188
+
189
+ Returns
190
+ -------
191
+ None
192
+ This function modifies the input arrays in-place and does not return any value.
193
+
194
+ Notes
195
+ -----
196
+ The function uses `statsmodels.tsa.stattools.levinson_durbin` to compute the autoregressive
197
+ parameters. This algorithm is efficient for computing autoregressive parameters and is
198
+ commonly used in time series analysis for estimating model parameters.
199
+
200
+ Examples
201
+ --------
202
+ >>> import numpy as np
203
+ >>> from statsmodels.tsa import stattools
204
+ >>> nlags = 5
205
+ >>> shiftedtcs = np.random.randn(100, 1000)
206
+ >>> sigmav = np.zeros(100)
207
+ >>> arcoefs = np.zeros((100, 5))
208
+ >>> pacf = np.zeros((100, 5))
209
+ >>> sigma = np.zeros((100, 5))
210
+ >>> phi = np.zeros((100, 5))
211
+ >>> findecho(nlags, shiftedtcs, sigmav, arcoefs, pacf, sigma, phi)
212
+ """
213
+ inputshape = np.shape(shiftedtcs)
214
+ for voxel in range(inputshape[0]):
215
+ sigmav[voxel], arcoefs[voxel, :], pacf[voxel, :], sigma[voxel, :], phi[voxel, :] = (
216
+ sm.tsa.stattools.levinson_durbin(shiftedtcs[voxel, :], nlags=nlags, isacov=False)
217
+ )
114
218
 
115
- Explicit outputs are:
116
- volumetotal - the number of voxels processed
117
219
 
118
- Implicit outputs:
119
- shiftedtcs - voxelwise fmri data timeshifted to zero lag
120
- weights - the weights of every timepoint in the final regressor
121
- paddedshiftedtcs - voxelwise fmri data timeshifted to zero lag, with a buffer of padtrs on each end
122
- paddedweights - the weights of every timepoint in the final regressor, with a buffer of padtrs on each end
220
+ def alignvoxels(
221
+ fmridata: NDArray,
222
+ fmritr: float,
223
+ shiftedtcs: NDArray,
224
+ weights: NDArray,
225
+ paddedshiftedtcs: NDArray,
226
+ paddedweights: NDArray,
227
+ lagtimes: NDArray,
228
+ lagmask: NDArray,
229
+ detrendorder: int = 1,
230
+ offsettime: float = 0.0,
231
+ nprocs: int = 1,
232
+ alwaysmultiproc: bool = False,
233
+ showprogressbar: bool = True,
234
+ chunksize: int = 1000,
235
+ padtrs: int = 60,
236
+ debug: bool = False,
237
+ rt_floatset: type = np.float64,
238
+ rt_floattype: str = "float64",
239
+ ) -> int:
240
+ """
241
+ Apply temporal alignment (timeshift) to all voxels in fMRI data based on correlation peaks.
123
242
 
243
+ This routine applies a time shift to every voxel in the fMRI data based on the lag times
244
+ determined from cross-correlation with a reference signal. The function modifies the input
245
+ arrays in-place to store the aligned timecourses and associated weights.
124
246
 
125
247
  Parameters
126
248
  ----------
127
- fmridata : 4D numpy float array
128
- fMRI data
249
+ fmridata : 4D numpy.ndarray
250
+ fMRI data, filtered to the passband, with shape (nx, ny, nz, nt)
129
251
  fmritr : float
130
- Data repetition rate, in seconds
131
- shiftedtcs : 4D numpy float array
132
- Destination array for time aligned voxel timecourses
133
- weights : unknown
134
- unknown
135
- passnum : int
136
- Number of the pass (for labelling output)
137
- lagstrengths : 3D numpy float array
138
- Maximum correlation coefficient in every voxel
139
- lagtimes : 3D numpy float array
140
- Time delay of maximum crosscorrelation in seconds
141
- lagsigma : 3D numpy float array
142
- Gaussian width of the crosscorrelation peak, in seconds.
143
- lagmask : 3D numpy float array
144
- Mask of voxels with successful correlation fits.
145
- R2 : 3D numpy float array
146
- Square of the maximum correlation coefficient in every voxel
147
- theprefilter : function
148
- The filter function to use
149
- optiondict : dict
150
- Dictionary of all internal rapidtide configuration variables.
252
+ Data repetition time (TR), in seconds
253
+ shiftedtcs : 4D numpy.ndarray
254
+ Destination array for time-aligned voxel timecourses, shape (nx, ny, nz, nt)
255
+ weights : 4D numpy.ndarray
256
+ Weights for each timepoint in the final regressor, shape (nx, ny, nz, nt)
257
+ paddedshiftedtcs : 4D numpy.ndarray
258
+ Time-aligned voxel timecourses with padding, shape (nx, ny, nz, nt + 2*padtrs)
259
+ paddedweights : 4D numpy.ndarray
260
+ Weights for each timepoint in the padded regressor, shape (nx, ny, nz, nt + 2*padtrs)
261
+ lagtimes : 3D numpy.ndarray
262
+ Time delay of maximum crosscorrelation in seconds, shape (nx, ny, nz)
263
+ lagmask : 3D numpy.ndarray
264
+ Mask of voxels with successful correlation fits, shape (nx, ny, nz)
265
+ detrendorder : int, optional
266
+ Order of polynomial used to detrend the data (default is 1)
267
+ offsettime : float, optional
268
+ Global time shift to apply to all timecourses in seconds (default is 0.0)
269
+ nprocs : int, optional
270
+ Number of processes to use for multiprocessing (default is 1)
271
+ alwaysmultiproc : bool, optional
272
+ If True, always use multiprocessing even for small datasets (default is False)
273
+ showprogressbar : bool, optional
274
+ If True, show a progress bar during processing (default is True)
275
+ chunksize : int, optional
276
+ Number of voxels to process per chunk in multiprocessing (default is 1000)
151
277
  padtrs : int, optional
152
- Number of timepoints to pad onto each end
153
- includemask : 3D array
154
- Mask of voxels to include in refinement. Default is None (all voxels).
155
- excludemask : 3D array
156
- Mask of voxels to exclude from refinement. Default is None (no voxels).
157
- debug : bool
158
- Enable additional debugging output. Default is False
159
- rt_floatset : function
160
- Function to coerce variable types
161
- rt_floattype : {'float32', 'float64'}
162
- Data type for internal variables
278
+ Number of timepoints to pad on each end of the timecourses (default is 60)
279
+ debug : bool, optional
280
+ If True, enable additional debugging output (default is False)
281
+ rt_floatset : type, optional
282
+ Function to coerce variable types (default is np.float64)
283
+ rt_floattype : str, optional
284
+ Data type for internal variables ('float32' or 'float64') (default is 'float64')
163
285
 
164
286
  Returns
165
287
  -------
166
288
  volumetotal : int
167
- Number of voxels processed
168
- outputdata : float array
169
- New regressor
170
- maskarray : 3D array
171
- Mask of voxels used for refinement
289
+ Total number of voxels processed
290
+
291
+ Notes
292
+ -----
293
+ This function modifies the input arrays `shiftedtcs`, `weights`, `paddedshiftedtcs`, and
294
+ `paddedweights` in-place. The `lagtimes` and `lagmask` arrays are used to determine the
295
+ appropriate time shifts for each voxel.
296
+
297
+ Examples
298
+ --------
299
+ >>> import numpy as np
300
+ >>> from rapidtide import alignvoxels
301
+ >>> fmridata = np.random.rand(64, 64, 32, 100)
302
+ >>> fmritr = 2.0
303
+ >>> shiftedtcs = np.zeros_like(fmridata)
304
+ >>> weights = np.ones_like(fmridata)
305
+ >>> paddedshiftedtcs = np.zeros((64, 64, 32, 100 + 2*60))
306
+ >>> paddedweights = np.ones((64, 64, 32, 100 + 2*60))
307
+ >>> lagtimes = np.random.rand(64, 64, 32)
308
+ >>> lagmask = np.ones((64, 64, 32))
309
+ >>> volumetotal = alignvoxels(
310
+ ... fmridata, fmritr, shiftedtcs, weights, paddedshiftedtcs, paddedweights,
311
+ ... lagtimes, lagmask, nprocs=4
312
+ ... )
313
+ >>> print(f"Processed {volumetotal} voxels")
172
314
  """
173
315
  inputshape = np.shape(fmridata)
174
316
  voxelargs = [fmridata, lagtimes, padtrs, fmritr]
@@ -220,81 +362,111 @@ def alignvoxels(
220
362
 
221
363
 
222
364
  def makerefinemask(
223
- lagstrengths,
224
- lagtimes,
225
- lagsigma,
226
- lagmask,
227
- offsettime=0.0,
228
- ampthresh=0.3,
229
- lagmaskside="both",
230
- lagminthresh=0.5,
231
- lagmaxthresh=5.0,
232
- sigmathresh=100,
233
- cleanrefined=False,
234
- bipolar=False,
235
- includemask=None,
236
- excludemask=None,
237
- fixdelay=False,
238
- debug=False,
239
- rt_floatset=np.float64,
240
- rt_floattype="float64",
241
- ):
365
+ lagstrengths: NDArray,
366
+ lagtimes: NDArray,
367
+ lagsigma: NDArray,
368
+ lagmask: NDArray,
369
+ offsettime: float = 0.0,
370
+ ampthresh: float = 0.3,
371
+ lagmaskside: str = "both",
372
+ lagminthresh: float = 0.5,
373
+ lagmaxthresh: float = 5.0,
374
+ sigmathresh: float = 100,
375
+ cleanrefined: bool = False,
376
+ bipolar: bool = False,
377
+ includemask: NDArray | None = None,
378
+ excludemask: NDArray | None = None,
379
+ fixdelay: bool = False,
380
+ debug: bool = False,
381
+ rt_floatset: type = np.float64,
382
+ rt_floattype: str = "float64",
383
+ ) -> tuple[int, NDArray | None, int, int, int, int, int]:
242
384
  """
243
- This routine determines which voxels should be used for regressor refinement.
385
+ Determine which voxels should be used for regressor refinement based on correlation strength,
386
+ time delay, and peak width criteria.
387
+
388
+ This routine evaluates a set of voxels defined by their correlation properties and applies
389
+ various thresholds to determine which ones are suitable for refinement. It supports optional
390
+ masking, bipolar correlation handling, and debugging output.
244
391
 
245
392
  Parameters
246
393
  ----------
247
- lagstrengths : 3D numpy float array
248
- Maximum correlation coefficient in every voxel
249
- lagtimes : 3D numpy float array
250
- Time delay of maximum crosscorrelation in seconds
251
- lagsigma : 3D numpy float array
252
- Gaussian width of the crosscorrelation peak, in seconds.
253
- lagmask : 3D numpy float array
254
- Mask of voxels with successful correlation fits.
255
- offsettime: float
256
- The offset time in seconds to apply to all regressors
257
- ampthresh: float
258
- The lower limit of correlation values to consider for refine mask inclusion
259
- lagmaskside: str
260
- Which side of the lag values to consider - upper, lower, or both
261
- lagminthresh: float
262
- The lower limit of absolute lag values to consider for refine mask inclusion
263
- lagmaxthresh: float
264
- The upper limit of absolute lag values to consider for refine mask inclusion
265
- sigmathresh: float
266
- The upper limit of lag peak width for refine mask inclusion
267
- cleanrefined: bool
268
- If True,
269
- bipolar : bool
270
- If True, consider positive and negative correlation peaks
271
- includemask : 3D array
272
- Mask of voxels to include in refinement. Default is None (all voxels).
273
- excludemask : 3D array
274
- Mask of voxels to exclude from refinement. Default is None (no voxels).
275
- debug : bool
276
- Enable additional debugging output. Default is False
277
- rt_floatset : function
278
- Function to coerce variable types
279
- rt_floattype : {'float32', 'float64'}
280
- Data type for internal variables
394
+ lagstrengths : ndarray
395
+ 3D numpy float array of maximum correlation coefficients in every voxel.
396
+ lagtimes : ndarray
397
+ 3D numpy float array of time delays (in seconds) of maximum crosscorrelation.
398
+ lagsigma : ndarray
399
+ 3D numpy float array of Gaussian widths (in seconds) of the crosscorrelation peaks.
400
+ lagmask : ndarray
401
+ 3D numpy float array masking voxels with successful correlation fits.
402
+ offsettime : float, optional
403
+ Offset time in seconds to apply to all regressors. Default is 0.0.
404
+ ampthresh : float, optional
405
+ Lower limit of correlation values to consider for refine mask inclusion.
406
+ If negative, treated as percentile. Default is 0.3.
407
+ lagmaskside : str, optional
408
+ Which side of the lag values to consider: 'upper', 'lower', or 'both'.
409
+ Default is 'both'.
410
+ lagminthresh : float, optional
411
+ Lower limit of absolute lag values to consider for inclusion. Default is 0.5.
412
+ lagmaxthresh : float, optional
413
+ Upper limit of absolute lag values to consider for inclusion. Default is 5.0.
414
+ sigmathresh : float, optional
415
+ Upper limit of lag peak width (in seconds) for inclusion. Default is 100.
416
+ cleanrefined : bool, optional
417
+ If True, uses the full location mask for refinement; otherwise, uses the refined mask.
418
+ Default is False.
419
+ bipolar : bool, optional
420
+ If True, considers both positive and negative correlation peaks. Default is False.
421
+ includemask : ndarray, optional
422
+ 3D array masking voxels to include in refinement. Default is None (all voxels).
423
+ excludemask : ndarray, optional
424
+ 3D array masking voxels to exclude from refinement. Default is None (no voxels).
425
+ fixdelay : bool, optional
426
+ If True, uses the raw `lagmask` without applying delay thresholds. Default is False.
427
+ debug : bool, optional
428
+ Enable additional debugging output. Default is False.
429
+ rt_floatset : callable, optional
430
+ Function to coerce variable types. Default is `np.float64`.
431
+ rt_floattype : str, optional
432
+ Data type for internal variables. Must be 'float32' or 'float64'. Default is 'float64'.
281
433
 
282
434
  Returns
283
435
  -------
284
436
  volumetotal : int
285
- Number of voxels processed
286
- maskarray : 3D array
287
- Mask of voxels used for refinement
288
- locationfails: int
289
- Number of locations eliminated due to the include and exclude masks
290
- ampfails: int
291
- Number of locations eliminated because the correlation value was too low
292
- lagfails: int
293
- Number of locations eliminated because the lag values were out of range
294
- sigmafails: int
295
- Number of locations eliminated because the correlation peak was too wide
437
+ Number of voxels processed for refinement.
438
+ maskarray : ndarray or None
439
+ 3D mask of voxels used for refinement. Returns None if no voxels remain after filtering.
440
+ locationfails : int
441
+ Number of voxels eliminated due to include/exclude mask constraints.
442
+ ampfails : int
443
+ Number of voxels eliminated due to low correlation amplitude.
444
+ lagfails : int
445
+ Number of voxels eliminated due to lag value out of range.
446
+ sigmafails : int
447
+ Number of voxels eliminated due to wide correlation peak.
448
+ numinmask : int
449
+ Total number of voxels in the original `lagmask`.
450
+
451
+ Notes
452
+ -----
453
+ - The function applies multiple filtering steps: amplitude, lag time, and sigma (peak width).
454
+ - If `ampthresh` is negative, it is interpreted as a percentile threshold.
455
+ - The `lagmaskside` parameter controls which direction of the lag values to consider:
456
+ 'upper' for positive lags, 'lower' for negative lags, 'both' for both.
457
+ - If no voxels remain after filtering, an error is printed and the function returns early.
458
+
459
+ Examples
460
+ --------
461
+ >>> import numpy as np
462
+ >>> lagstrengths = np.random.rand(10, 10, 10)
463
+ >>> lagtimes = np.random.rand(10, 10, 10) * 10
464
+ >>> lagsigma = np.random.rand(10, 10, 10) * 50
465
+ >>> lagmask = np.ones((10, 10, 10))
466
+ >>> volumetotal, maskarray, locfails, ampfails, lagfails, sigfails, numinmask = makerefinemask(
467
+ ... lagstrengths, lagtimes, lagsigma, lagmask, ampthresh=0.4, lagminthresh=1.0
468
+ ... )
296
469
  """
297
-
298
470
  if ampthresh < 0.0:
299
471
  if bipolar:
300
472
  theampthresh = tide_stats.getfracval(np.fabs(lagstrengths), -ampthresh, nozero=True)
@@ -401,16 +573,66 @@ def makerefinemask(
401
573
 
402
574
 
403
575
  def prenorm(
404
- shiftedtcs,
405
- refinemask,
406
- lagtimes,
407
- lagmaxthresh,
408
- lagstrengths,
409
- R2vals,
410
- refineprenorm,
411
- refineweighting,
412
- debug=False,
413
- ):
576
+ shiftedtcs: NDArray,
577
+ refinemask: NDArray,
578
+ lagtimes: NDArray,
579
+ lagmaxthresh: float,
580
+ lagstrengths: NDArray,
581
+ R2vals: NDArray,
582
+ refineprenorm: str,
583
+ refineweighting: str,
584
+ debug: bool = False,
585
+ ) -> None:
586
+ """
587
+ Apply pre-normalization and weighting to shifted time correlation data.
588
+
589
+ This function performs normalization and weighting of time correlation data
590
+ based on specified criteria. It modifies the input `shiftedtcs` array in-place.
591
+
592
+ Parameters
593
+ ----------
594
+ shiftedtcs : NDArray
595
+ Array of shifted time correlation data, shape (n_samples, n_timepoints).
596
+ refinemask : NDArray
597
+ Boolean mask for refining data, shape (n_samples,).
598
+ lagtimes : NDArray
599
+ Array of lag times, shape (n_samples,).
600
+ lagmaxthresh : float
601
+ Threshold for lag time normalization.
602
+ lagstrengths : NDArray
603
+ Array of lag strengths, shape (n_samples,).
604
+ R2vals : NDArray
605
+ Array of R-squared values, shape (n_samples,).
606
+ refineprenorm : str
607
+ Normalization method to use: 'mean', 'var', 'std', or 'invlag'.
608
+ If any other value is provided, unit normalization is applied.
609
+ refineweighting : str
610
+ Weighting method to use: 'R', 'R2', or other (default weighting based on lagstrengths).
611
+ debug : bool, optional
612
+ If True, print debug information about input shapes and intermediate values.
613
+
614
+ Returns
615
+ -------
616
+ None
617
+ The function modifies `shiftedtcs` in-place.
618
+
619
+ Notes
620
+ -----
621
+ The function applies normalization using a divisor computed according to the
622
+ `refineprenorm` parameter and then applies weights based on `refineweighting`.
623
+ The `shiftedtcs` array is updated in-place.
624
+
625
+ Examples
626
+ --------
627
+ >>> import numpy as np
628
+ >>> shiftedtcs = np.random.rand(10, 5)
629
+ >>> refinemask = np.ones(10, dtype=bool)
630
+ >>> lagtimes = np.arange(10)
631
+ >>> lagmaxthresh = 2.0
632
+ >>> lagstrengths = np.random.rand(10)
633
+ >>> R2vals = np.random.rand(10)
634
+ >>> prenorm(shiftedtcs, refinemask, lagtimes, lagmaxthresh, lagstrengths, R2vals, "mean", "R", debug=True)
635
+ """
414
636
  if debug:
415
637
  print(f"{shiftedtcs.shape=}"),
416
638
  print(f"{refinemask.shape=}"),
@@ -450,30 +672,122 @@ def prenorm(
450
672
 
451
673
 
452
674
  def dorefine(
453
- shiftedtcs,
454
- refinemask,
455
- weights,
456
- theprefilter,
457
- fmritr,
458
- passnum,
459
- lagstrengths,
460
- lagtimes,
461
- refinetype,
462
- fmrifreq,
463
- outputname,
464
- detrendorder=1,
465
- pcacomponents=0.8,
466
- dodispersioncalc=False,
467
- dispersioncalc_lower=0.0,
468
- dispersioncalc_upper=0.0,
469
- dispersioncalc_step=0.0,
470
- windowfunc="hamming",
471
- cleanrefined=False,
472
- bipolar=False,
473
- debug=False,
474
- rt_floatset=np.float64,
475
- rt_floattype="float64",
476
- ):
675
+ shiftedtcs: NDArray,
676
+ refinemask: NDArray,
677
+ weights: NDArray,
678
+ theprefilter: Any,
679
+ fmritr: float,
680
+ passnum: int,
681
+ lagstrengths: NDArray,
682
+ lagtimes: NDArray,
683
+ refinetype: str,
684
+ fmrifreq: float,
685
+ outputname: str,
686
+ detrendorder: int = 1,
687
+ pcacomponents: float | str = 0.8,
688
+ dodispersioncalc: bool = False,
689
+ dispersioncalc_lower: float = 0.0,
690
+ dispersioncalc_upper: float = 0.0,
691
+ dispersioncalc_step: float = 0.0,
692
+ windowfunc: str = "hamming",
693
+ cleanrefined: bool = False,
694
+ bipolar: bool = False,
695
+ debug: bool = False,
696
+ rt_floatset: type = np.float64,
697
+ rt_floattype: str = "float64",
698
+ ) -> tuple[int, NDArray]:
699
+ """
700
+ Refine timecourses using specified method (ICA, PCA, weighted average, or unweighted average).
701
+
702
+ This function applies a refinement process to a set of timecourses based on a mask and
703
+ weights. It supports multiple refinement techniques including ICA, PCA, and averaging,
704
+ and can optionally perform dispersion calculation and cleaning of refined data.
705
+
706
+ Parameters
707
+ ----------
708
+ shiftedtcs : ndarray
709
+ Array of shape (n_voxels, n_timepoints) containing the shifted timecourses.
710
+ refinemask : ndarray
711
+ Boolean mask indicating which voxels to include in refinement.
712
+ weights : ndarray
713
+ Array of shape (n_voxels, n_timepoints) containing weights for each voxel.
714
+ theprefilter : Any
715
+ Pre-filter object with an `apply` method to filter the data.
716
+ fmritr : float
717
+ fMRI repetition time in seconds.
718
+ passnum : int
719
+ Pass number for output file naming.
720
+ lagstrengths : ndarray
721
+ Array of lag strengths for each voxel.
722
+ lagtimes : ndarray
723
+ Array of lag times for each voxel.
724
+ refinetype : str
725
+ Type of refinement to perform: 'ica', 'pca', 'weighted_average', or 'unweighted_average'.
726
+ fmrifreq : float
727
+ fMRI frequency in Hz.
728
+ outputname : str
729
+ Base name for output files.
730
+ detrendorder : int, optional
731
+ Order of detrending for correlation normalization (default is 1).
732
+ pcacomponents : float or str, optional
733
+ Number of PCA components to use. If < 1, treated as fraction of variance; if 'mle', uses MLE.
734
+ Default is 0.8.
735
+ dodispersioncalc : bool, optional
736
+ If True, compute dispersion calculation across lag ranges (default is False).
737
+ dispersioncalc_lower : float, optional
738
+ Lower bound for dispersion calculation lag range (default is 0.0).
739
+ dispersioncalc_upper : float, optional
740
+ Upper bound for dispersion calculation lag range (default is 0.0).
741
+ dispersioncalc_step : float, optional
742
+ Step size for dispersion calculation lag range (default is 0.0).
743
+ windowfunc : str, optional
744
+ Window function for correlation normalization (default is "hamming").
745
+ cleanrefined : bool, optional
746
+ If True, remove linearly fitted discard data from refined output (default is False).
747
+ bipolar : bool, optional
748
+ If True, flip sign of negative lag strengths (default is False).
749
+ debug : bool, optional
750
+ If True, print debug information (default is False).
751
+ rt_floatset : type, optional
752
+ Data type for floating-point numbers (default is np.float64).
753
+ rt_floattype : str, optional
754
+ String representation of floating-point data type (default is "float64").
755
+
756
+ Returns
757
+ -------
758
+ tuple[int, ndarray]
759
+ A tuple containing:
760
+ - `volumetotal`: int, total number of voxels included in refinement.
761
+ - `outputdata`: ndarray, refined timecourse of shape (n_timepoints,).
762
+
763
+ Notes
764
+ -----
765
+ - The function supports multiple refinement methods: ICA, PCA, weighted average, and
766
+ unweighted average.
767
+ - If `cleanrefined` is True, a linear regression is performed to remove discard data
768
+ from the refined output.
769
+ - If `dodispersioncalc` is True, dispersion calculation is performed across lag ranges
770
+ and outputs are saved to files with the prefix `outputname`.
771
+
772
+ Examples
773
+ --------
774
+ >>> import numpy as np
775
+ >>> shiftedtcs = np.random.rand(100, 200)
776
+ >>> refinemask = np.ones(100)
777
+ >>> weights = np.ones((100, 200))
778
+ >>> theprefilter = SomeFilter()
779
+ >>> fmritr = 2.0
780
+ >>> passnum = 1
781
+ >>> lagstrengths = np.random.rand(100)
782
+ >>> lagtimes = np.random.rand(100)
783
+ >>> refinetype = "pca"
784
+ >>> fmrifreq = 0.1
785
+ >>> outputname = "test_output"
786
+ >>> volumetotal, outputdata = dorefine(
787
+ ... shiftedtcs, refinemask, weights, theprefilter, fmritr, passnum,
788
+ ... lagstrengths, lagtimes, refinetype, fmrifreq, outputname
789
+ ... )
790
+ """
477
791
  # now generate the refined timecourse(s)
478
792
  inputshape = np.shape(shiftedtcs)
479
793
  validlist = np.where(refinemask > 0)[0]