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.
- rapidtide/Colortables.py +45 -10
- rapidtide/RapidtideDataset.py +21 -3
- rapidtide/Refiner.py +464 -0
- rapidtide/__init__.py +1 -2
- rapidtide/_version.py +63 -93
- rapidtide/data/examples/src/testfmri +3 -119
- rapidtide/data/examples/src/testhappy +1 -6
- rapidtide/data/examples/src/testinitdelay +19 -0
- rapidtide/data/examples/src/testnewrefine +49 -0
- rapidtide/data/examples/src/testrefineonly +22 -0
- rapidtide/glmpass.py +8 -1
- rapidtide/refinedelay.py +72 -32
- rapidtide/refineregressor.py +38 -24
- rapidtide/tests/test_fastresampler.py +6 -2
- rapidtide/tests/test_fullrunhappy_v1.py +0 -1
- rapidtide/tests/test_fullrunhappy_v4.py +1 -0
- rapidtide/tests/test_runmisc.py +4 -4
- rapidtide/tidepoolTemplate.py +1 -0
- rapidtide/tidepoolTemplate.ui +1 -0
- rapidtide/tidepoolTemplate_alt.py +5 -4
- rapidtide/tidepoolTemplate_alt.ui +3 -2
- rapidtide/tidepoolTemplate_alt_qt6.py +5 -4
- rapidtide/tidepoolTemplate_big.py +1 -0
- rapidtide/tidepoolTemplate_big.ui +1 -0
- rapidtide/tidepoolTemplate_big_qt6.py +1 -0
- rapidtide/tidepoolTemplate_qt6.py +1 -0
- rapidtide/workflows/parser_funcs.py +10 -2
- rapidtide/workflows/rapidtide.py +197 -325
- rapidtide/workflows/rapidtide_parser.py +35 -13
- rapidtide/workflows/retroglm.py +145 -60
- rapidtide/workflows/tidepool.py +34 -15
- {rapidtide-3.0a10.dist-info → rapidtide-3.0a12.dist-info}/METADATA +1 -1
- {rapidtide-3.0a10.dist-info → rapidtide-3.0a12.dist-info}/RECORD +37 -33
- {rapidtide-3.0a10.dist-info → rapidtide-3.0a12.dist-info}/WHEEL +1 -1
- {rapidtide-3.0a10.dist-info → rapidtide-3.0a12.dist-info}/LICENSE +0 -0
- {rapidtide-3.0a10.dist-info → rapidtide-3.0a12.dist-info}/entry_points.txt +0 -0
- {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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
rapidtide/RapidtideDataset.py
CHANGED
|
@@ -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
|
-
|
|
406
|
-
|
|
407
|
-
self.
|
|
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