rapidtide 3.0a10__py3-none-any.whl → 3.0a12__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 (37) hide show
  1. rapidtide/Colortables.py +45 -10
  2. rapidtide/RapidtideDataset.py +21 -3
  3. rapidtide/Refiner.py +464 -0
  4. rapidtide/__init__.py +1 -2
  5. rapidtide/_version.py +63 -93
  6. rapidtide/data/examples/src/testfmri +3 -119
  7. rapidtide/data/examples/src/testhappy +1 -6
  8. rapidtide/data/examples/src/testinitdelay +19 -0
  9. rapidtide/data/examples/src/testnewrefine +49 -0
  10. rapidtide/data/examples/src/testrefineonly +22 -0
  11. rapidtide/glmpass.py +8 -1
  12. rapidtide/refinedelay.py +72 -32
  13. rapidtide/refineregressor.py +38 -24
  14. rapidtide/tests/test_fastresampler.py +6 -2
  15. rapidtide/tests/test_fullrunhappy_v1.py +0 -1
  16. rapidtide/tests/test_fullrunhappy_v4.py +1 -0
  17. rapidtide/tests/test_runmisc.py +4 -4
  18. rapidtide/tidepoolTemplate.py +1 -0
  19. rapidtide/tidepoolTemplate.ui +1 -0
  20. rapidtide/tidepoolTemplate_alt.py +5 -4
  21. rapidtide/tidepoolTemplate_alt.ui +3 -2
  22. rapidtide/tidepoolTemplate_alt_qt6.py +5 -4
  23. rapidtide/tidepoolTemplate_big.py +1 -0
  24. rapidtide/tidepoolTemplate_big.ui +1 -0
  25. rapidtide/tidepoolTemplate_big_qt6.py +1 -0
  26. rapidtide/tidepoolTemplate_qt6.py +1 -0
  27. rapidtide/workflows/parser_funcs.py +10 -2
  28. rapidtide/workflows/rapidtide.py +197 -325
  29. rapidtide/workflows/rapidtide_parser.py +35 -13
  30. rapidtide/workflows/retroglm.py +145 -60
  31. rapidtide/workflows/tidepool.py +34 -15
  32. {rapidtide-3.0a10.dist-info → rapidtide-3.0a12.dist-info}/METADATA +1 -1
  33. {rapidtide-3.0a10.dist-info → rapidtide-3.0a12.dist-info}/RECORD +37 -33
  34. {rapidtide-3.0a10.dist-info → rapidtide-3.0a12.dist-info}/WHEEL +1 -1
  35. {rapidtide-3.0a10.dist-info → rapidtide-3.0a12.dist-info}/LICENSE +0 -0
  36. {rapidtide-3.0a10.dist-info → rapidtide-3.0a12.dist-info}/entry_points.txt +0 -0
  37. {rapidtide-3.0a10.dist-info → rapidtide-3.0a12.dist-info}/top_level.txt +0 -0
rapidtide/Colortables.py CHANGED
@@ -63,37 +63,55 @@ def setendalpha(thestate, alpha, debug=False):
63
63
  def gen_thermal_state():
64
64
  from pyqtgraph.graphicsItems.GradientEditorItem import Gradients
65
65
 
66
- return Gradients["thermal"]
66
+ thegradient = Gradients["thermal"]
67
+ thegradient["name"] = "thermal"
68
+ return thegradient
69
+ #return Gradients["thermal"]
67
70
 
68
71
 
69
72
  def gen_flame_state():
70
73
  from pyqtgraph.graphicsItems.GradientEditorItem import Gradients
71
74
 
72
- return Gradients["flame"]
75
+ thegradient = Gradients["flame"]
76
+ thegradient["name"] = "flame"
77
+ return thegradient
78
+ #return Gradients["flame"]
73
79
 
74
80
 
75
81
  def gen_yellowy_state():
76
82
  from pyqtgraph.graphicsItems.GradientEditorItem import Gradients
77
83
 
78
- return Gradients["yellowy"]
84
+ thegradient = Gradients["yellowy"]
85
+ thegradient["name"] = "yellowy"
86
+ return thegradient
87
+ #return Gradients["yellowy"]
79
88
 
80
89
 
81
90
  def gen_bipolar_state():
82
91
  from pyqtgraph.graphicsItems.GradientEditorItem import Gradients
83
92
 
84
- return Gradients["bipolar"]
93
+ thegradient = Gradients["bipolar"]
94
+ thegradient["name"] = "bipolar"
95
+ return thegradient
96
+ #return Gradients["bipolar"]
85
97
 
86
98
 
87
99
  def gen_spectrum_state():
88
100
  from pyqtgraph.graphicsItems.GradientEditorItem import Gradients
89
101
 
90
- return Gradients["spectrum"]
102
+ thegradient = Gradients["spectrum"]
103
+ thegradient["name"] = "spectrum"
104
+ return thegradient
105
+ #return Gradients["spectrum"]
91
106
 
92
107
 
93
108
  def gen_turbo_state():
94
109
  from pyqtgraph.graphicsItems.GradientEditorItem import Gradients
95
110
 
96
- return Gradients["turbo"]
111
+ thegradient = Gradients["turbo"]
112
+ thegradient["name"] = "turbo"
113
+ return thegradient
114
+ #return Gradients["turbo"]
97
115
 
98
116
 
99
117
  def gen_gray_state():
@@ -103,6 +121,7 @@ def gen_gray_state():
103
121
  (1.0000, (255, 255, 255, 255)),
104
122
  ],
105
123
  "mode": "rgb",
124
+ "name": "gray",
106
125
  }
107
126
 
108
127
 
@@ -113,31 +132,44 @@ def gen_grey_state():
113
132
  (1.0000, (255, 255, 255, 255)),
114
133
  ],
115
134
  "mode": "rgb",
135
+ "name": "grey",
116
136
  }
117
137
 
118
138
 
119
139
  def gen_viridis_state():
120
140
  from pyqtgraph.graphicsItems.GradientEditorItem import Gradients
121
141
 
122
- return Gradients["viridis"]
142
+ thegradient = Gradients["viridis"]
143
+ thegradient["name"] = "viridis"
144
+ return thegradient
145
+ #return Gradients["viridis"]
123
146
 
124
147
 
125
148
  def gen_inferno_state():
126
149
  from pyqtgraph.graphicsItems.GradientEditorItem import Gradients
127
150
 
128
- return Gradients["inferno"]
151
+ thegradient = Gradients["inferno"]
152
+ thegradient["name"] = "inferno"
153
+ return thegradient
154
+ #return Gradients["inferno"]
129
155
 
130
156
 
131
157
  def gen_plasma_state():
132
158
  from pyqtgraph.graphicsItems.GradientEditorItem import Gradients
133
159
 
134
- return Gradients["plasma"]
160
+ thegradient = Gradients["plasma"]
161
+ thegradient["name"] = "plasma"
162
+ return thegradient
163
+ #return Gradients["plasma"]
135
164
 
136
165
 
137
166
  def gen_magma_state():
138
167
  from pyqtgraph.graphicsItems.GradientEditorItem import Gradients
139
168
 
140
- return Gradients["magma"]
169
+ thegradient = Gradients["magma"]
170
+ thegradient["name"] = "magma"
171
+ return thegradient
172
+ #return Gradients["magma"]
141
173
 
142
174
 
143
175
  def gen_g2y2r_state():
@@ -150,6 +182,7 @@ def gen_g2y2r_state():
150
182
  (1.0000, (255, 0, 0, 0)),
151
183
  ],
152
184
  "mode": "rgb",
185
+ "name": "g2y2r",
153
186
  }
154
187
 
155
188
 
@@ -157,6 +190,7 @@ def gen_mask_state():
157
190
  return {
158
191
  "ticks": [(0.0000, (0, 0, 0, 255)), (1.0000, (255, 255, 255, 0))],
159
192
  "mode": "rgb",
193
+ "name": "mask",
160
194
  }
161
195
 
162
196
 
@@ -168,6 +202,7 @@ def gen_greyclip_state():
168
202
  (1.0, (255, 0, 0, 255)),
169
203
  ],
170
204
  "mode": "rgb",
205
+ "name": "greyclip",
171
206
  }
172
207
 
173
208
 
@@ -161,6 +161,7 @@ class Timecourse:
161
161
 
162
162
  class Overlay:
163
163
  "Store a data overlay and some information about it"
164
+ LUTname = None
164
165
 
165
166
  def __init__(
166
167
  self,
@@ -193,6 +194,7 @@ class Overlay:
193
194
  self.namebase = namebase
194
195
  if self.verbose > 1:
195
196
  print("reading map ", self.name, " from ", self.filename, "...")
197
+ self.maskhash = 0
196
198
  self.invertonload = invertonload
197
199
  self.readImageData(isaMask=isaMask)
198
200
  self.mask = None
@@ -277,6 +279,7 @@ class Overlay:
277
279
 
278
280
  def updateStats(self):
279
281
  calcmaskeddata = self.data[np.where(self.mask != 0)]
282
+
280
283
  self.minval = calcmaskeddata.min()
281
284
  self.maxval = calcmaskeddata.max()
282
285
  (
@@ -290,6 +293,7 @@ class Overlay:
290
293
  calcmaskeddata, bins=np.linspace(self.minval, self.maxval, 200)
291
294
  )
292
295
  self.quartiles = [self.pct25, self.pct50, self.pct75]
296
+
293
297
  if self.verbose > 1:
294
298
  print(
295
299
  self.name,
@@ -402,9 +406,17 @@ class Overlay:
402
406
 
403
407
  def maskData(self):
404
408
  self.mask = self.geommask * self.funcmask
405
- self.maskeddata = self.data.copy()
406
- self.maskeddata[np.where(self.mask < 0.5)] = 0.0
407
- self.updateStats()
409
+ maskhash = hash(self.mask.tostring())
410
+ # these operations are expensive, so only do them if the mask is changed
411
+ if (maskhash == self.maskhash) and (self.verbose > 1):
412
+ print("mask has not changed")
413
+ else:
414
+ if self.verbose > 1:
415
+ print("mask changed - recalculating")
416
+ self.maskeddata = self.data.copy()
417
+ self.maskeddata[np.where(self.mask < 0.5)] = 0.0
418
+ self.updateStats()
419
+ self.maskhash = maskhash
408
420
 
409
421
  def setReport(self, report):
410
422
  self.report = report
@@ -433,6 +445,7 @@ class Overlay:
433
445
  self.lut_state = setendalpha(lut_state, endalpha)
434
446
  self.gradient.restoreState(self.lut_state)
435
447
  self.theLUT = self.gradient.getLookupTable(512, alpha=True)
448
+ self.LUTname = lut_state["name"]
436
449
 
437
450
  def setisdisplayed(self, display_state):
438
451
  self.display_state = display_state
@@ -505,6 +518,7 @@ class RapidtideDataset:
505
518
  fileroot,
506
519
  anatname=None,
507
520
  geommaskname=None,
521
+ funcmaskname=None,
508
522
  graymaskspec=None,
509
523
  whitemaskspec=None,
510
524
  userise=False,
@@ -523,6 +537,7 @@ class RapidtideDataset:
523
537
  self.fileroot = fileroot
524
538
  self.anatname = anatname
525
539
  self.geommaskname = geommaskname
540
+ self.funcmaskname = funcmaskname
526
541
  self.graymaskspec = graymaskspec
527
542
  self.whitemaskspec = whitemaskspec
528
543
  self.userise = userise
@@ -1355,3 +1370,6 @@ class RapidtideDataset:
1355
1370
  self.focusmap = whichmap
1356
1371
  except KeyError:
1357
1372
  self.focusmap = "lagtimes"
1373
+
1374
+ def setFuncMaskName(self, maskname):
1375
+ self.funcmaskname = maskname
rapidtide/Refiner.py ADDED
@@ -0,0 +1,464 @@
1
+ #!/usr/bin/env python
2
+ # -*- coding: utf-8 -*-
3
+ #
4
+ # Copyright 2016-2024 Blaise Frederick
5
+ #
6
+ # Licensed under the Apache License, Version 2.0 (the "License");
7
+ # you may not use this file except in compliance with the License.
8
+ # You may obtain a copy of the License at
9
+ #
10
+ # http://www.apache.org/licenses/LICENSE-2.0
11
+ #
12
+ # Unless required by applicable law or agreed to in writing, software
13
+ # distributed under the License is distributed on an "AS IS" BASIS,
14
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ # See the License for the specific language governing permissions and
16
+ # limitations under the License.
17
+ #
18
+ #
19
+ """
20
+ A class to impmement regressor refinement
21
+ """
22
+ import copy
23
+
24
+ import numpy as np
25
+
26
+ import rapidtide.fit as tide_fit
27
+ import rapidtide.io as tide_io
28
+ import rapidtide.miscmath as tide_math
29
+ import rapidtide.refineregressor as tide_refineregressor
30
+ import rapidtide.resample as tide_resample
31
+ import rapidtide.stats as tide_stats
32
+ import rapidtide.util as tide_util
33
+ from rapidtide.tests.utils import mse
34
+
35
+
36
+ class Refiner:
37
+
38
+ refinemaskvoxels = None
39
+
40
+ def __init__(
41
+ self,
42
+ internalvalidfmrishape,
43
+ internalvalidpaddedfmrishape,
44
+ pid,
45
+ outputname,
46
+ initial_fmri_x,
47
+ paddedinitial_fmri_x,
48
+ os_fmri_x,
49
+ sharedmem=False,
50
+ offsettime=0.0,
51
+ ampthresh=0.3,
52
+ lagminthresh=0.25,
53
+ lagmaxthresh=3.0,
54
+ sigmathresh=1000.0,
55
+ cleanrefined=False,
56
+ bipolar=False,
57
+ fixdelay=False,
58
+ includemask=None,
59
+ excludemask=None,
60
+ LGR=None,
61
+ nprocs=1,
62
+ detrendorder=1,
63
+ alwaysmultiproc=False,
64
+ showprogressbar=True,
65
+ chunksize=50000,
66
+ padtrs=10,
67
+ refineprenorm="var",
68
+ refineweighting=None,
69
+ refinetype="pca",
70
+ pcacomponents=0.8,
71
+ dodispersioncalc=False,
72
+ dispersioncalc_lower=-5.0,
73
+ dispersioncalc_upper=5.0,
74
+ dispersioncalc_step=0.5,
75
+ windowfunc="hamming",
76
+ passes=3,
77
+ maxpasses=15,
78
+ convergencethresh=None,
79
+ interptype="univariate",
80
+ usetmask=False,
81
+ tmask_y=None,
82
+ tmaskos_y=None,
83
+ fastresamplerpadtime=45.0,
84
+ debug=False,
85
+ rt_floattype="float64",
86
+ rt_floatset=np.float64,
87
+ ):
88
+ self.internalvalidfmrishape = internalvalidfmrishape
89
+ self.internalvalidpaddedfmrishape = internalvalidpaddedfmrishape
90
+ self.sharedmem = sharedmem
91
+ self.outputname = outputname
92
+ self.initial_fmri_x = initial_fmri_x
93
+ self.paddedinitial_fmri_x = paddedinitial_fmri_x
94
+ self.os_fmri_x = os_fmri_x
95
+
96
+ self.offsettime = offsettime
97
+ self.ampthresh = ampthresh
98
+ self.lagminthresh = lagminthresh
99
+ self.lagmaxthresh = lagmaxthresh
100
+ self.sigmathresh = sigmathresh
101
+ self.cleanrefined = cleanrefined
102
+ self.bipolar = bipolar
103
+ self.fixdelay = fixdelay
104
+ self.LGR = LGR
105
+ self.nprocs = nprocs
106
+ self.detrendorder = detrendorder
107
+ self.alwaysmultiproc = alwaysmultiproc
108
+ self.showprogressbar = showprogressbar
109
+ self.chunksize = chunksize
110
+ self.padtrs = padtrs
111
+ self.refineprenorm = refineprenorm
112
+ self.refineweighting = refineweighting
113
+ self.refinetype = refinetype
114
+ self.pcacomponents = pcacomponents
115
+ self.dodispersioncalc = dodispersioncalc
116
+ self.dispersioncalc_lower = dispersioncalc_lower
117
+ self.dispersioncalc_upper = dispersioncalc_upper
118
+ self.dispersioncalc_step = dispersioncalc_step
119
+ self.windowfunc = windowfunc
120
+ self.passes = passes
121
+ self.maxpasses = maxpasses
122
+ self.convergencethresh = convergencethresh
123
+ self.interptype = interptype
124
+ self.usetmask = usetmask
125
+ self.tmask_y = tmask_y
126
+ self.tmaskos_y = tmaskos_y
127
+ self.fastresamplerpadtime = fastresamplerpadtime
128
+ self.debug = debug
129
+ self.rt_floattype = rt_floattype
130
+ self.rt_floatset = rt_floatset
131
+
132
+ self.setmasks(includemask, excludemask)
133
+ self.totalrefinementbytes = self._allocatemem(pid)
134
+
135
+ def setmasks(self, includemask, excludemask):
136
+ self.includemask = includemask
137
+ self.excludemask = excludemask
138
+
139
+ def _allocatemem(self, pid):
140
+ if self.sharedmem:
141
+ self.shiftedtcs, self.shiftedtcs_shm = tide_util.allocshared(
142
+ self.internalvalidfmrishape, self.rt_floatset, name=f"shiftedtcs_{pid}"
143
+ )
144
+ self.weights, self.weights_shm = tide_util.allocshared(
145
+ self.internalvalidfmrishape, self.rt_floatset, name=f"weights_{pid}"
146
+ )
147
+ self.paddedshiftedtcs, self.paddedshiftedtcs_shm = tide_util.allocshared(
148
+ self.internalvalidpaddedfmrishape,
149
+ self.rt_floatset,
150
+ name=f"paddedshiftedtcs_{pid}",
151
+ )
152
+ self.paddedweights, self.paddedweights_shm = tide_util.allocshared(
153
+ self.internalvalidpaddedfmrishape,
154
+ self.rt_floatset,
155
+ name=f"paddedweights_{pid}",
156
+ )
157
+ ramlocation = "in shared memory"
158
+ else:
159
+ self.shiftedtcs = np.zeros(self.internalvalidfmrishape, dtype=self.rt_floattype)
160
+ self.weights = np.zeros(self.internalvalidfmrishape, dtype=self.rt_floattype)
161
+ self.paddedshiftedtcs = np.zeros(
162
+ self.internalvalidpaddedfmrishape, dtype=self.rt_floattype
163
+ )
164
+ self.paddedweights = np.zeros(
165
+ self.internalvalidpaddedfmrishape, dtype=self.rt_floattype
166
+ )
167
+ ramlocation = "locally"
168
+ totalrefinementbytes = (
169
+ self.shiftedtcs.nbytes
170
+ + self.weights.nbytes
171
+ + self.paddedshiftedtcs.nbytes
172
+ + self.paddedweights.nbytes
173
+ )
174
+ thesize, theunit = tide_util.format_bytes(totalrefinementbytes)
175
+ print(f"allocated {thesize:.3f} {theunit} {ramlocation} for refinement")
176
+ tide_util.logmem("after refinement array allocation")
177
+ return totalrefinementbytes
178
+
179
+ def cleanup(self):
180
+ del self.paddedshiftedtcs
181
+ del self.paddedweights
182
+ del self.shiftedtcs
183
+ del self.weights
184
+ if self.sharedmem:
185
+ tide_util.cleanup_shm(self.paddedshiftedtcs_shm)
186
+ tide_util.cleanup_shm(self.paddedweights_shm)
187
+ tide_util.cleanup_shm(self.shiftedtcs_shm)
188
+ tide_util.cleanup_shm(self.weights_shm)
189
+
190
+ def makemask(self, lagstrengths, lagtimes, lagsigma, fitmask):
191
+ # create the refinement mask
192
+ (
193
+ self.refinemaskvoxels,
194
+ self.refinemask,
195
+ self.locationfails,
196
+ self.ampfails,
197
+ self.lagfails,
198
+ self.sigmafails,
199
+ self.numinmask,
200
+ ) = tide_refineregressor.makerefinemask(
201
+ lagstrengths,
202
+ lagtimes,
203
+ lagsigma,
204
+ fitmask,
205
+ offsettime=self.offsettime,
206
+ ampthresh=self.ampthresh,
207
+ lagminthresh=self.lagminthresh,
208
+ lagmaxthresh=self.lagmaxthresh,
209
+ sigmathresh=self.sigmathresh,
210
+ cleanrefined=self.cleanrefined,
211
+ bipolar=self.bipolar,
212
+ includemask=self.includemask,
213
+ excludemask=self.excludemask,
214
+ fixdelay=self.fixdelay,
215
+ debug=self.debug,
216
+ )
217
+
218
+ if self.numinmask == 0:
219
+ self.LGR.critical("No voxels in refine mask - adjust thresholds or external masks")
220
+ return False
221
+ else:
222
+ return True
223
+
224
+ def getrefinemask(self):
225
+ return self.refinemask
226
+
227
+ def getpaddedshiftedtcs(self):
228
+ return self.paddedshiftedtcs
229
+
230
+ def alignvoxels(self, fmri_data_valid, fmritr, lagtimes):
231
+ # align timecourses to prepare for refinement
232
+ self.LGR.info("aligning timecourses")
233
+ voxelsprocessed_rra = tide_refineregressor.alignvoxels(
234
+ fmri_data_valid,
235
+ fmritr,
236
+ self.shiftedtcs,
237
+ self.weights,
238
+ self.paddedshiftedtcs,
239
+ self.paddedweights,
240
+ lagtimes,
241
+ self.refinemask,
242
+ nprocs=self.nprocs,
243
+ detrendorder=self.detrendorder,
244
+ offsettime=self.offsettime,
245
+ alwaysmultiproc=self.alwaysmultiproc,
246
+ showprogressbar=self.showprogressbar,
247
+ chunksize=self.chunksize,
248
+ padtrs=self.padtrs,
249
+ debug=self.debug,
250
+ rt_floatset=self.rt_floatset,
251
+ rt_floattype=self.rt_floattype,
252
+ )
253
+ return voxelsprocessed_rra
254
+ # self.LGR.info(f"align complete: {voxelsprocessed_rra=}")
255
+
256
+ def prenormalize(self, lagtimes, lagstrengths, R2):
257
+ tide_refineregressor.prenorm(
258
+ self.paddedshiftedtcs,
259
+ self.refinemask,
260
+ lagtimes,
261
+ self.lagmaxthresh,
262
+ lagstrengths,
263
+ R2,
264
+ self.refineprenorm,
265
+ self.refineweighting,
266
+ )
267
+
268
+ def refine(
269
+ self,
270
+ theprefilter,
271
+ fmritr,
272
+ thepass,
273
+ lagstrengths,
274
+ lagtimes,
275
+ previousnormoutputdata,
276
+ corrmasksize,
277
+ ):
278
+ (
279
+ voxelsprocessed_rr,
280
+ self.paddedoutputdata,
281
+ ) = tide_refineregressor.dorefine(
282
+ self.paddedshiftedtcs,
283
+ self.refinemask,
284
+ self.weights,
285
+ theprefilter,
286
+ fmritr,
287
+ thepass,
288
+ lagstrengths,
289
+ lagtimes,
290
+ self.refinetype,
291
+ 1.0 / fmritr,
292
+ self.outputname,
293
+ detrendorder=self.detrendorder,
294
+ pcacomponents=self.pcacomponents,
295
+ dodispersioncalc=self.dodispersioncalc,
296
+ dispersioncalc_lower=self.dispersioncalc_lower,
297
+ dispersioncalc_upper=self.dispersioncalc_upper,
298
+ dispersioncalc_step=self.dispersioncalc_step,
299
+ windowfunc=self.windowfunc,
300
+ cleanrefined=self.cleanrefined,
301
+ bipolar=self.bipolar,
302
+ debug=self.debug,
303
+ rt_floatset=self.rt_floatset,
304
+ rt_floattype=self.rt_floattype,
305
+ )
306
+ outputdict = {}
307
+ outputdict["refinemasksize_pass" + str(thepass)] = voxelsprocessed_rr
308
+ outputdict["refinemaskpct_pass" + str(thepass)] = 100.0 * voxelsprocessed_rr / corrmasksize
309
+ outputdict["refinelocationfails_pass" + str(thepass)] = self.locationfails
310
+ outputdict["refineampfails_pass" + str(thepass)] = self.ampfails
311
+ outputdict["refinelagfails_pass" + str(thepass)] = self.lagfails
312
+ outputdict["refinesigmafails_pass" + str(thepass)] = self.sigmafails
313
+
314
+ fmrifreq = 1.0 / fmritr
315
+ if voxelsprocessed_rr > 0:
316
+ paddednormoutputdata = tide_math.stdnormalize(
317
+ theprefilter.apply(fmrifreq, self.paddedoutputdata)
318
+ )
319
+ outputdata = self.paddedoutputdata[self.padtrs : -self.padtrs]
320
+ normoutputdata = tide_math.stdnormalize(theprefilter.apply(fmrifreq, outputdata))
321
+ normunfilteredoutputdata = tide_math.stdnormalize(outputdata)
322
+ tide_io.writebidstsv(
323
+ f"{self.outputname}_desc-refinedmovingregressor_timeseries",
324
+ normunfilteredoutputdata,
325
+ fmrifreq,
326
+ columns=["unfiltered_pass" + str(thepass)],
327
+ extraheaderinfo={
328
+ "Description": "The raw and filtered probe regressor produced by the refinement procedure, at the time resolution of the data"
329
+ },
330
+ append=(thepass > 1),
331
+ )
332
+ tide_io.writebidstsv(
333
+ f"{self.outputname}_desc-refinedmovingregressor_timeseries",
334
+ normoutputdata,
335
+ fmrifreq,
336
+ columns=["filtered_pass" + str(thepass)],
337
+ extraheaderinfo={
338
+ "Description": "The raw and filtered probe regressor produced by the refinement procedure, at the time resolution of the data"
339
+ },
340
+ append=True,
341
+ )
342
+
343
+ # check for convergence
344
+ regressormse = mse(normoutputdata, previousnormoutputdata)
345
+ outputdict["regressormse_pass" + str(thepass).zfill(2)] = regressormse
346
+ self.LGR.info(f"regressor difference at end of pass {thepass:d} is {regressormse:.6f}")
347
+ if self.convergencethresh is not None:
348
+ if thepass >= self.maxpasses:
349
+ self.LGR.info("refinement ended (maxpasses reached)")
350
+ stoprefining = True
351
+ refinestopreason = "maxpassesreached"
352
+ elif regressormse < self.convergencethresh:
353
+ self.LGR.info("refinement ended (refinement has converged")
354
+ stoprefining = True
355
+ refinestopreason = "convergence"
356
+ else:
357
+ stoprefining = False
358
+ elif thepass >= self.passes:
359
+ stoprefining = True
360
+ refinestopreason = "passesreached"
361
+ else:
362
+ stoprefining = False
363
+ refinestopreason = None
364
+ outputdict["refinestopreason"] = refinestopreason
365
+
366
+ if self.detrendorder > 0:
367
+ resampnonosref_y = tide_fit.detrend(
368
+ tide_resample.doresample(
369
+ self.paddedinitial_fmri_x,
370
+ paddednormoutputdata,
371
+ self.initial_fmri_x,
372
+ method=self.interptype,
373
+ ),
374
+ order=self.detrendorder,
375
+ demean=True,
376
+ )
377
+ resampref_y = tide_fit.detrend(
378
+ tide_resample.doresample(
379
+ self.paddedinitial_fmri_x,
380
+ paddednormoutputdata,
381
+ self.os_fmri_x,
382
+ method=self.interptype,
383
+ ),
384
+ order=self.detrendorder,
385
+ demean=True,
386
+ )
387
+ else:
388
+ resampnonosref_y = tide_resample.doresample(
389
+ self.paddedinitial_fmri_x,
390
+ paddednormoutputdata,
391
+ self.initial_fmri_x,
392
+ method=self.interptype,
393
+ )
394
+ resampref_y = tide_resample.doresample(
395
+ self.paddedinitial_fmri_x,
396
+ paddednormoutputdata,
397
+ self.os_fmri_x,
398
+ method=self.interptype,
399
+ )
400
+ if self.usetmask:
401
+ resampnonosref_y *= self.tmask_y
402
+ thefit, R2val = tide_fit.mlregress(self.tmask_y, resampnonosref_y)
403
+ resampnonosref_y -= thefit[0, 1] * self.tmask_y
404
+ resampref_y *= self.tmaskos_y
405
+ thefit, R2val = tide_fit.mlregress(self.tmaskos_y, resampref_y)
406
+ resampref_y -= thefit[0, 1] * self.tmaskos_y
407
+
408
+ # reinitialize genlagtc for resampling
409
+ previousnormoutputdata = np.zeros_like(normoutputdata)
410
+ genlagtc = tide_resample.FastResampler(
411
+ self.paddedinitial_fmri_x,
412
+ paddednormoutputdata,
413
+ padtime=self.fastresamplerpadtime,
414
+ )
415
+ genlagtc.save(f"{self.outputname}_desc-lagtcgenerator_timeseries")
416
+ if self.debug:
417
+ genlagtc.info()
418
+ (
419
+ outputdict[f"kurtosis_reference_pass{thepass + 1}"],
420
+ outputdict[f"kurtosisz_reference_pass{thepass + 1}"],
421
+ outputdict[f"kurtosisp_reference_pass{thepass + 1}"],
422
+ ) = tide_stats.kurtosisstats(resampref_y)
423
+ (
424
+ outputdict[f"skewness_reference_pass{thepass + 1}"],
425
+ outputdict[f"skewnessz_reference_pass{thepass + 1}"],
426
+ outputdict[f"skewnessp_reference_pass{thepass + 1}"],
427
+ ) = tide_stats.skewnessstats(resampref_y)
428
+ if not stoprefining:
429
+ tide_io.writebidstsv(
430
+ f"{self.outputname}_desc-movingregressor_timeseries",
431
+ tide_math.stdnormalize(resampnonosref_y),
432
+ 1.0 / fmritr,
433
+ columns=["pass" + str(thepass + 1)],
434
+ extraheaderinfo={
435
+ "Description": "The probe regressor used in each pass, at the time resolution of the data"
436
+ },
437
+ append=True,
438
+ )
439
+ oversampfreq = 1.0 / (self.os_fmri_x[1] - self.os_fmri_x[0])
440
+ tide_io.writebidstsv(
441
+ f"{self.outputname}_desc-oversampledmovingregressor_timeseries",
442
+ tide_math.stdnormalize(resampref_y),
443
+ oversampfreq,
444
+ columns=["pass" + str(thepass + 1)],
445
+ extraheaderinfo={
446
+ "Description": "The probe regressor used in each pass, at the time resolution used for calculating the similarity function"
447
+ },
448
+ append=True,
449
+ )
450
+ else:
451
+ self.LGR.warning(f"refinement failed - terminating at end of pass {thepass}")
452
+ stoprefining = True
453
+ refinestopreason = "emptymask"
454
+
455
+ return (
456
+ voxelsprocessed_rr,
457
+ outputdict,
458
+ previousnormoutputdata,
459
+ resampref_y,
460
+ resampnonosref_y,
461
+ stoprefining,
462
+ refinestopreason,
463
+ genlagtc,
464
+ )
rapidtide/__init__.py CHANGED
@@ -1,4 +1,3 @@
1
1
  # -*- coding: utf-8 -*-
2
2
  from . import _version
3
-
4
- __version__ = _version.get_versions()["version"]
3
+ __version__ = _version.get_versions()['version']