rapidtide 3.0.5__py3-none-any.whl → 3.0.7__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 (45) hide show
  1. rapidtide/RapidtideDataset.py +17 -0
  2. rapidtide/_version.py +3 -3
  3. rapidtide/calccoherence.py +51 -73
  4. rapidtide/calcnullsimfunc.py +65 -111
  5. rapidtide/calcsimfunc.py +73 -91
  6. rapidtide/correlate.py +25 -6
  7. rapidtide/data/examples/src/testatlasaverage +22 -0
  8. rapidtide/data/examples/src/testfmri +16 -1
  9. rapidtide/data/examples/src/testhappy +57 -60
  10. rapidtide/data/examples/src/testsimdata +45 -28
  11. rapidtide/genericmultiproc.py +122 -0
  12. rapidtide/happy_supportfuncs.py +608 -107
  13. rapidtide/linfitfiltpass.py +8 -1
  14. rapidtide/makelaggedtcs.py +49 -78
  15. rapidtide/multiproc.py +5 -17
  16. rapidtide/refineregressor.py +59 -81
  17. rapidtide/resample.py +24 -14
  18. rapidtide/tests/.coveragerc +9 -0
  19. rapidtide/tests/test_congrid.py +68 -79
  20. rapidtide/tests/test_externaltools.py +69 -0
  21. rapidtide/tests/test_fastresampler.py +1 -0
  22. rapidtide/tests/test_fullrunrapidtide_v2.py +1 -0
  23. rapidtide/tests/test_nullcorr.py +2 -5
  24. rapidtide/tests/test_parserfuncs.py +46 -15
  25. rapidtide/tests/test_zRapidtideDataset.py +2 -2
  26. rapidtide/voxelData.py +17 -3
  27. rapidtide/workflows/ccorrica.py +1 -2
  28. rapidtide/workflows/cleanregressor.py +3 -2
  29. rapidtide/workflows/happy.py +62 -3
  30. rapidtide/workflows/happy_parser.py +36 -0
  31. rapidtide/workflows/rapidtide.py +18 -13
  32. rapidtide/workflows/rapidtide_parser.py +8 -1
  33. rapidtide/workflows/regressfrommaps.py +0 -2
  34. rapidtide/workflows/showarbcorr.py +19 -6
  35. rapidtide/workflows/showxcorrx.py +4 -8
  36. rapidtide/workflows/simdata.py +149 -65
  37. {rapidtide-3.0.5.dist-info → rapidtide-3.0.7.dist-info}/METADATA +1 -1
  38. {rapidtide-3.0.5.dist-info → rapidtide-3.0.7.dist-info}/RECORD +42 -43
  39. {rapidtide-3.0.5.dist-info → rapidtide-3.0.7.dist-info}/WHEEL +1 -1
  40. rapidtide/DerivativeDelay.py +0 -209
  41. rapidtide/calcandfitcorrpairs.py +0 -262
  42. rapidtide/transformerdlfilter.py +0 -126
  43. {rapidtide-3.0.5.dist-info → rapidtide-3.0.7.dist-info}/entry_points.txt +0 -0
  44. {rapidtide-3.0.5.dist-info → rapidtide-3.0.7.dist-info}/licenses/LICENSE +0 -0
  45. {rapidtide-3.0.5.dist-info → rapidtide-3.0.7.dist-info}/top_level.txt +0 -0
@@ -22,13 +22,14 @@ import warnings
22
22
 
23
23
  import numpy as np
24
24
  from scipy.signal import savgol_filter, welch
25
- from scipy.stats import kurtosis, skew
25
+ from scipy.stats import kurtosis, skew, pearsonr
26
26
  from statsmodels.robust import mad
27
27
  from tqdm import tqdm
28
28
 
29
29
  import rapidtide.correlate as tide_corr
30
30
  import rapidtide.filter as tide_filt
31
31
  import rapidtide.fit as tide_fit
32
+ import rapidtide.genericmultiproc as tide_genericmultiproc
32
33
  import rapidtide.io as tide_io
33
34
  import rapidtide.miscmath as tide_math
34
35
  import rapidtide.resample as tide_resample
@@ -364,7 +365,55 @@ def getcardcoeffs(
364
365
  return peakfreq
365
366
 
366
367
 
367
- def normalizevoxels(fmri_data, detrendorder, validvoxels, time, timings, showprogressbar=False):
368
+ def _procOneVoxelDetrend(
369
+ vox,
370
+ voxelargs,
371
+ **kwargs,
372
+ ):
373
+ # unpack arguments
374
+ options = {
375
+ "detrendorder": 1,
376
+ "demean": False,
377
+ "debug": False,
378
+ }
379
+ options.update(kwargs)
380
+ detrendorder = options["detrendorder"]
381
+ demean = options["demean"]
382
+ debug = options["debug"]
383
+ [fmri_voxeldata] = voxelargs
384
+ if debug:
385
+ print(f"{vox=}, {detrendorder=}, {demean=}, {fmri_voxeldata.shape=}")
386
+
387
+ detrended_voxeldata = tide_fit.detrend(fmri_voxeldata, order=detrendorder, demean=demean)
388
+
389
+ return (
390
+ vox,
391
+ detrended_voxeldata,
392
+ )
393
+
394
+
395
+ def _packDetrendvoxeldata(voxnum, voxelargs):
396
+ return [(voxelargs[0])[voxnum, :]]
397
+
398
+
399
+ def _unpackDetrendvoxeldata(retvals, voxelproducts):
400
+ (voxelproducts[0])[retvals[0], :] = retvals[1]
401
+
402
+
403
+ def normalizevoxels(
404
+ fmri_data,
405
+ detrendorder,
406
+ validvoxels,
407
+ time,
408
+ timings,
409
+ LGR=None,
410
+ mpcode=True,
411
+ nprocs=1,
412
+ alwaysmultiproc=False,
413
+ showprogressbar=True,
414
+ chunksize=1000,
415
+ debug=False,
416
+ ):
368
417
  print("Normalizing voxels...")
369
418
  normdata = fmri_data * 0.0
370
419
  demeandata = fmri_data * 0.0
@@ -373,17 +422,54 @@ def normalizevoxels(fmri_data, detrendorder, validvoxels, time, timings, showpro
373
422
  numspatiallocs = fmri_data.shape[0]
374
423
  if detrendorder > 0:
375
424
  print("Detrending to order", detrendorder, "...")
376
- for idx, thevox in enumerate(
377
- tqdm(
378
- validvoxels,
379
- desc="Voxel",
380
- unit="voxels",
381
- disable=(not showprogressbar),
382
- )
383
- ):
384
- fmri_data[thevox, :] = tide_fit.detrend(
385
- fmri_data[thevox, :], order=detrendorder, demean=False
425
+ if mpcode:
426
+ if debug:
427
+ print(f"detrend multiproc path: {detrendorder=}")
428
+ inputshape = fmri_data.shape
429
+ voxelargs = [
430
+ fmri_data,
431
+ ]
432
+ voxelfunc = _procOneVoxelDetrend
433
+ packfunc = _packDetrendvoxeldata
434
+ unpackfunc = _unpackDetrendvoxeldata
435
+ voxelmask = fmri_data[:, 0] * 0.0
436
+ voxelmask[validvoxels] = 1
437
+ voxeltargets = [fmri_data]
438
+
439
+ numspatiallocs = tide_genericmultiproc.run_multiproc(
440
+ voxelfunc,
441
+ packfunc,
442
+ unpackfunc,
443
+ voxelargs,
444
+ voxeltargets,
445
+ inputshape,
446
+ voxelmask,
447
+ LGR,
448
+ nprocs,
449
+ alwaysmultiproc,
450
+ showprogressbar,
451
+ chunksize,
452
+ debug=debug,
453
+ detrendorder=detrendorder,
454
+ demean=False,
386
455
  )
456
+ else:
457
+ if debug:
458
+ print(f"detrend nonmultiproc path: {detrendorder=}")
459
+ for idx, thevox in enumerate(
460
+ tqdm(
461
+ validvoxels,
462
+ desc="Voxel",
463
+ unit="voxels",
464
+ disable=(not showprogressbar),
465
+ )
466
+ ):
467
+ fmri_data[thevox, :] = tide_fit.detrend(
468
+ fmri_data[thevox, :], order=detrendorder, demean=False
469
+ )
470
+ timings.append(["Detrending finished", time.time(), numspatiallocs, "voxels"])
471
+ print(" done")
472
+
387
473
  timings.append(["Detrending finished", time.time(), numspatiallocs, "voxels"])
388
474
  print(" done")
389
475
 
@@ -960,6 +1046,7 @@ def cardiaccycleaverage(
960
1046
  congridbins,
961
1047
  gridkernel,
962
1048
  centric,
1049
+ cache=True,
963
1050
  cyclic=True,
964
1051
  ):
965
1052
  rawapp_bypoint = np.zeros(len(destinationphases), dtype=np.float64)
@@ -971,13 +1058,14 @@ def cardiaccycleaverage(
971
1058
  1.0,
972
1059
  congridbins,
973
1060
  kernel=gridkernel,
1061
+ cache=cache,
974
1062
  cyclic=cyclic,
975
1063
  )
976
1064
  for i in range(len(theindices)):
977
1065
  weight_bypoint[theindices[i]] += theweights[i]
978
1066
  rawapp_bypoint[theindices[i]] += theweights[i] * waveform[t]
979
1067
  rawapp_bypoint = np.where(
980
- weight_bypoint > np.max(weight_bypoint) / 50.0,
1068
+ weight_bypoint > (np.max(weight_bypoint) / 50.0),
981
1069
  np.nan_to_num(rawapp_bypoint / weight_bypoint),
982
1070
  0.0,
983
1071
  )
@@ -998,6 +1086,285 @@ def circularderivs(timecourse):
998
1086
  )
999
1087
 
1000
1088
 
1089
+ def _procOnePhaseProject(slice, sliceargs, **kwargs):
1090
+ options = {
1091
+ "cache": True,
1092
+ "debug": False,
1093
+ }
1094
+ options.update(kwargs)
1095
+ cache = options["cache"]
1096
+ debug = options["debug"]
1097
+ (
1098
+ validlocslist,
1099
+ proctrs,
1100
+ demeandata_byslice,
1101
+ fmri_data_byslice,
1102
+ outphases,
1103
+ cardphasevals,
1104
+ congridbins,
1105
+ gridkernel,
1106
+ weights_byslice,
1107
+ cine_byslice,
1108
+ destpoints,
1109
+ rawapp_byslice,
1110
+ ) = sliceargs
1111
+ # now smooth the projected data along the time dimension
1112
+ validlocs = validlocslist[slice]
1113
+ if len(validlocs) > 0:
1114
+ for t in proctrs:
1115
+ filteredmr = -demeandata_byslice[validlocs, slice, t]
1116
+ cinemr = fmri_data_byslice[validlocs, slice, t]
1117
+ thevals, theweights, theindices = tide_resample.congrid(
1118
+ outphases,
1119
+ cardphasevals[slice, t],
1120
+ 1.0,
1121
+ congridbins,
1122
+ kernel=gridkernel,
1123
+ cache=cache,
1124
+ cyclic=True,
1125
+ )
1126
+ for i in range(len(theindices)):
1127
+ weights_byslice[validlocs, slice, theindices[i]] += theweights[i]
1128
+ rawapp_byslice[validlocs, slice, theindices[i]] += filteredmr
1129
+ cine_byslice[validlocs, slice, theindices[i]] += theweights[i] * cinemr
1130
+ for d in range(destpoints):
1131
+ if weights_byslice[validlocs[0], slice, d] == 0.0:
1132
+ weights_byslice[validlocs, slice, d] = 1.0
1133
+ rawapp_byslice[validlocs, slice, :] = np.nan_to_num(
1134
+ rawapp_byslice[validlocs, slice, :] / weights_byslice[validlocs, slice, :]
1135
+ )
1136
+ cine_byslice[validlocs, slice, :] = np.nan_to_num(
1137
+ cine_byslice[validlocs, slice, :] / weights_byslice[validlocs, slice, :]
1138
+ )
1139
+ else:
1140
+ rawapp_byslice[:, slice, :] = 0.0
1141
+ cine_byslice[:, slice, :] = 0.0
1142
+
1143
+ return (
1144
+ slice,
1145
+ rawapp_byslice[:, slice, :],
1146
+ cine_byslice[:, slice, :],
1147
+ weights_byslice[:, slice, :],
1148
+ validlocs,
1149
+ )
1150
+
1151
+
1152
+ def _packslicedataPhaseProject(slicenum, sliceargs):
1153
+ return [
1154
+ sliceargs[0],
1155
+ sliceargs[1],
1156
+ sliceargs[2],
1157
+ sliceargs[3],
1158
+ sliceargs[4],
1159
+ sliceargs[5],
1160
+ sliceargs[6],
1161
+ sliceargs[7],
1162
+ sliceargs[8],
1163
+ sliceargs[9],
1164
+ sliceargs[10],
1165
+ sliceargs[11],
1166
+ ]
1167
+
1168
+
1169
+ def _unpackslicedataPhaseProject(retvals, voxelproducts):
1170
+ (voxelproducts[0])[retvals[4], retvals[0], :] = (retvals[1])[retvals[4], :]
1171
+ (voxelproducts[1])[retvals[4], retvals[0], :] = (retvals[2])[retvals[4], :]
1172
+ (voxelproducts[2])[retvals[4], retvals[0], :] = (retvals[3])[retvals[4], :]
1173
+
1174
+
1175
+ def preloadcongrid(outphases, congridbins, gridkernel="kaiser", cyclic=True, debug=False):
1176
+ outphasestep = outphases[1] - outphases[0]
1177
+ outphasecenter = outphases[int(len(outphases) / 2)]
1178
+ fillargs = outphasestep * (
1179
+ np.linspace(-0.5, 0.5, 10001, endpoint=True, dtype=float) + outphasecenter
1180
+ )
1181
+ for thearg in fillargs:
1182
+ dummy, dummy, dummy = tide_resample.congrid(
1183
+ outphases,
1184
+ thearg,
1185
+ 1.0,
1186
+ congridbins,
1187
+ kernel=gridkernel,
1188
+ cyclic=cyclic,
1189
+ cache=True,
1190
+ debug=debug,
1191
+ )
1192
+
1193
+
1194
+ def phaseprojectpass(
1195
+ numslices,
1196
+ demeandata_byslice,
1197
+ fmri_data_byslice,
1198
+ validlocslist,
1199
+ proctrs,
1200
+ weights_byslice,
1201
+ cine_byslice,
1202
+ rawapp_byslice,
1203
+ outphases,
1204
+ cardphasevals,
1205
+ congridbins,
1206
+ gridkernel,
1207
+ destpoints,
1208
+ mpcode=False,
1209
+ nprocs=1,
1210
+ alwaysmultiproc=False,
1211
+ showprogressbar=True,
1212
+ cache=True,
1213
+ debug=False,
1214
+ ):
1215
+ if mpcode:
1216
+ inputshape = rawapp_byslice.shape
1217
+ sliceargs = [
1218
+ validlocslist,
1219
+ proctrs,
1220
+ demeandata_byslice,
1221
+ fmri_data_byslice,
1222
+ outphases,
1223
+ cardphasevals,
1224
+ congridbins,
1225
+ gridkernel,
1226
+ weights_byslice,
1227
+ cine_byslice,
1228
+ destpoints,
1229
+ rawapp_byslice,
1230
+ ]
1231
+ slicefunc = _procOnePhaseProject
1232
+ packfunc = _packslicedataPhaseProject
1233
+ unpackfunc = _unpackslicedataPhaseProject
1234
+ slicetargets = [rawapp_byslice, cine_byslice, weights_byslice]
1235
+ slicemask = rawapp_byslice[0, :, 0] * 0.0 + 1
1236
+
1237
+ slicetotal = tide_genericmultiproc.run_multiproc(
1238
+ slicefunc,
1239
+ packfunc,
1240
+ unpackfunc,
1241
+ sliceargs,
1242
+ slicetargets,
1243
+ inputshape,
1244
+ slicemask,
1245
+ None,
1246
+ nprocs,
1247
+ alwaysmultiproc,
1248
+ showprogressbar,
1249
+ 8,
1250
+ indexaxis=1,
1251
+ procunit="slices",
1252
+ cache=cache,
1253
+ debug=debug,
1254
+ )
1255
+ else:
1256
+ for theslice in tqdm(
1257
+ range(numslices),
1258
+ desc="Slice",
1259
+ unit="slices",
1260
+ disable=(not showprogressbar),
1261
+ ):
1262
+ validlocs = validlocslist[theslice]
1263
+ if len(validlocs) > 0:
1264
+ for t in proctrs:
1265
+ filteredmr = -demeandata_byslice[validlocs, theslice, t]
1266
+ cinemr = fmri_data_byslice[validlocs, theslice, t]
1267
+ thevals, theweights, theindices = tide_resample.congrid(
1268
+ outphases,
1269
+ cardphasevals[theslice, t],
1270
+ 1.0,
1271
+ congridbins,
1272
+ kernel=gridkernel,
1273
+ cyclic=True,
1274
+ cache=cache,
1275
+ debug=debug,
1276
+ )
1277
+ for i in range(len(theindices)):
1278
+ weights_byslice[validlocs, theslice, theindices[i]] += theweights[i]
1279
+ rawapp_byslice[validlocs, theslice, theindices[i]] += filteredmr
1280
+ cine_byslice[validlocs, theslice, theindices[i]] += theweights[i] * cinemr
1281
+ for d in range(destpoints):
1282
+ if weights_byslice[validlocs[0], theslice, d] == 0.0:
1283
+ weights_byslice[validlocs, theslice, d] = 1.0
1284
+ rawapp_byslice[validlocs, theslice, :] = np.nan_to_num(
1285
+ rawapp_byslice[validlocs, theslice, :]
1286
+ / weights_byslice[validlocs, theslice, :]
1287
+ )
1288
+ cine_byslice[validlocs, theslice, :] = np.nan_to_num(
1289
+ cine_byslice[validlocs, theslice, :] / weights_byslice[validlocs, theslice, :]
1290
+ )
1291
+ else:
1292
+ rawapp_byslice[:, theslice, :] = 0.0
1293
+ cine_byslice[:, theslice, :] = 0.0
1294
+
1295
+
1296
+ def _procOneSliceSmoothing(slice, sliceargs, **kwargs):
1297
+ options = {
1298
+ "debug": False,
1299
+ }
1300
+ options.update(kwargs)
1301
+ debug = options["debug"]
1302
+ (validlocslist, rawapp_byslice, appsmoothingfilter, phaseFs, derivatives_byslice) = sliceargs
1303
+ # now smooth the projected data along the time dimension
1304
+ validlocs = validlocslist[slice]
1305
+ if len(validlocs) > 0:
1306
+ for loc in validlocs:
1307
+ rawapp_byslice[loc, slice, :] = appsmoothingfilter.apply(
1308
+ phaseFs, rawapp_byslice[loc, slice, :]
1309
+ )
1310
+ derivatives_byslice[loc, slice, :] = circularderivs(rawapp_byslice[loc, slice, :])
1311
+ return slice, rawapp_byslice[:, slice, :], derivatives_byslice[:, slice, :]
1312
+
1313
+
1314
+ def _packslicedataSliceSmoothing(slicenum, sliceargs):
1315
+ return [
1316
+ sliceargs[0],
1317
+ sliceargs[1],
1318
+ sliceargs[2],
1319
+ sliceargs[3],
1320
+ sliceargs[4],
1321
+ ]
1322
+
1323
+
1324
+ def _unpackslicedataSliceSmoothing(retvals, voxelproducts):
1325
+ (voxelproducts[0])[:, retvals[0], :] = retvals[1]
1326
+ (voxelproducts[1])[:, retvals[0], :] = retvals[2]
1327
+
1328
+
1329
+ def tcsmoothingpass(
1330
+ numslices,
1331
+ validlocslist,
1332
+ rawapp_byslice,
1333
+ appsmoothingfilter,
1334
+ phaseFs,
1335
+ derivatives_byslice,
1336
+ nprocs=1,
1337
+ alwaysmultiproc=False,
1338
+ showprogressbar=True,
1339
+ debug=False,
1340
+ ):
1341
+ inputshape = rawapp_byslice.shape
1342
+ sliceargs = [validlocslist, rawapp_byslice, appsmoothingfilter, phaseFs, derivatives_byslice]
1343
+ slicefunc = _procOneSliceSmoothing
1344
+ packfunc = _packslicedataSliceSmoothing
1345
+ unpackfunc = _unpackslicedataSliceSmoothing
1346
+ slicetargets = [rawapp_byslice, derivatives_byslice]
1347
+ slicemask = rawapp_byslice[0, :, 0] * 0.0 + 1
1348
+
1349
+ slicetotal = tide_genericmultiproc.run_multiproc(
1350
+ slicefunc,
1351
+ packfunc,
1352
+ unpackfunc,
1353
+ sliceargs,
1354
+ slicetargets,
1355
+ inputshape,
1356
+ slicemask,
1357
+ None,
1358
+ nprocs,
1359
+ alwaysmultiproc,
1360
+ showprogressbar,
1361
+ 16,
1362
+ indexaxis=1,
1363
+ procunit="slices",
1364
+ debug=debug,
1365
+ )
1366
+
1367
+
1001
1368
  def phaseproject(
1002
1369
  input_data,
1003
1370
  demeandata_byslice,
@@ -1030,112 +1397,156 @@ def phaseproject(
1030
1397
  xsize, ysize, numslices, timepoints = input_data.getdims()
1031
1398
  fmri_data_byslice = input_data.byslice()
1032
1399
 
1400
+ # first find the validlocs for each slice
1401
+ validlocslist = []
1402
+ if args.verbose:
1403
+ print("Finding validlocs")
1404
+ for theslice in range(numslices):
1405
+ validlocslist.append(np.where(projmask_byslice[:, theslice] > 0)[0])
1406
+
1407
+ # phase project each slice
1408
+ print("Phase projecting")
1409
+ phaseprojectpass(
1410
+ numslices,
1411
+ demeandata_byslice,
1412
+ fmri_data_byslice,
1413
+ validlocslist,
1414
+ proctrs,
1415
+ weights_byslice,
1416
+ cine_byslice,
1417
+ rawapp_byslice,
1418
+ outphases,
1419
+ cardphasevals,
1420
+ args.congridbins,
1421
+ args.gridkernel,
1422
+ args.destpoints,
1423
+ cache=args.congridcache,
1424
+ mpcode=args.mpphaseproject,
1425
+ nprocs=args.nprocs,
1426
+ showprogressbar=args.showprogressbar,
1427
+ )
1428
+
1429
+ # smooth the phase projection, if requested
1430
+ if args.smoothapp:
1431
+ print("Smoothing timecourses")
1432
+ tcsmoothingpass(
1433
+ numslices,
1434
+ validlocslist,
1435
+ rawapp_byslice,
1436
+ appsmoothingfilter,
1437
+ phaseFs,
1438
+ derivatives_byslice,
1439
+ nprocs=args.nprocs,
1440
+ showprogressbar=args.showprogressbar,
1441
+ )
1442
+
1443
+ # now do the flips
1444
+ print("Doing flips")
1033
1445
  for theslice in tqdm(
1034
1446
  range(numslices),
1035
1447
  desc="Slice",
1036
1448
  unit="slices",
1037
1449
  disable=(not args.showprogressbar),
1038
1450
  ):
1039
- if args.verbose:
1040
- print("Phase projecting for slice", theslice)
1041
- validlocs = np.where(projmask_byslice[:, theslice] > 0)[0]
1042
- # indexlist = range(0, len(cardphasevals[theslice, :]))
1451
+ # now do the flips
1452
+ validlocs = validlocslist[theslice]
1043
1453
  if len(validlocs) > 0:
1044
- for t in proctrs:
1045
- filteredmr = -demeandata_byslice[validlocs, theslice, t]
1046
- cinemr = fmri_data_byslice[validlocs, theslice, t]
1047
- thevals, theweights, theindices = tide_resample.congrid(
1048
- outphases,
1049
- cardphasevals[theslice, t],
1050
- 1.0,
1051
- args.congridbins,
1052
- kernel=args.gridkernel,
1053
- cyclic=True,
1054
- )
1055
- for i in range(len(theindices)):
1056
- weights_byslice[validlocs, theslice, theindices[i]] += theweights[i]
1057
- # rawapp_byslice[validlocs, theslice, theindices[i]] += (
1058
- # theweights[i] * filteredmr
1059
- # )
1060
- rawapp_byslice[validlocs, theslice, theindices[i]] += filteredmr
1061
- cine_byslice[validlocs, theslice, theindices[i]] += theweights[i] * cinemr
1062
- for d in range(args.destpoints):
1063
- if weights_byslice[validlocs[0], theslice, d] == 0.0:
1064
- weights_byslice[validlocs, theslice, d] = 1.0
1065
- rawapp_byslice[validlocs, theslice, :] = np.nan_to_num(
1066
- rawapp_byslice[validlocs, theslice, :] / weights_byslice[validlocs, theslice, :]
1454
+ appflips_byslice = np.where(
1455
+ -derivatives_byslice[:, :, 2] > derivatives_byslice[:, :, 0], -1.0, 1.0
1067
1456
  )
1068
- cine_byslice[validlocs, theslice, :] = np.nan_to_num(
1069
- cine_byslice[validlocs, theslice, :] / weights_byslice[validlocs, theslice, :]
1457
+ timecoursemean = np.mean(rawapp_byslice[validlocs, theslice, :], axis=1).reshape(
1458
+ (-1, 1)
1459
+ )
1460
+ if args.fliparteries:
1461
+ corrected_rawapp_byslice[validlocs, theslice, :] = (
1462
+ rawapp_byslice[validlocs, theslice, :] - timecoursemean
1463
+ ) * appflips_byslice[validlocs, theslice, None] + timecoursemean
1464
+ if args.doaliasedcorrelation and (thispass > 0):
1465
+ for theloc in validlocs:
1466
+ thecorrfunc_byslice[theloc, theslice, :] = theAliasedCorrelator.apply(
1467
+ -appflips_byslice[theloc, theslice]
1468
+ * demeandata_byslice[theloc, theslice, :],
1469
+ int(sliceoffsets[theslice]),
1470
+ )[corrstartloc : correndloc + 1]
1471
+ maxloc = np.argmax(thecorrfunc_byslice[theloc, theslice, :])
1472
+ wavedelay_byslice[theloc, theslice] = (
1473
+ thealiasedcorrx[corrstartloc : correndloc + 1]
1474
+ )[maxloc]
1475
+ waveamp_byslice[theloc, theslice] = np.fabs(
1476
+ thecorrfunc_byslice[theloc, theslice, maxloc]
1477
+ )
1478
+ wavedelayCOM_byslice[theloc, theslice] = theCOM(
1479
+ thealiasedcorrx[corrstartloc : correndloc + 1],
1480
+ np.fabs(thecorrfunc_byslice[theloc, theslice, :]),
1481
+ )
1482
+ else:
1483
+ corrected_rawapp_byslice[validlocs, theslice, :] = rawapp_byslice[
1484
+ validlocs, theslice, :
1485
+ ]
1486
+ if args.doaliasedcorrelation and (thispass > 0):
1487
+ for theloc in validlocs:
1488
+ thecorrfunc_byslice[theloc, theslice, :] = theAliasedCorrelator.apply(
1489
+ -demeandata_byslice[theloc, theslice, :],
1490
+ int(sliceoffsets[theslice]),
1491
+ )[corrstartloc : correndloc + 1]
1492
+ maxloc = np.argmax(np.abs(thecorrfunc_byslice[theloc, theslice, :]))
1493
+ wavedelay_byslice[theloc, theslice] = (
1494
+ thealiasedcorrx[corrstartloc : correndloc + 1]
1495
+ )[maxloc]
1496
+ waveamp_byslice[theloc, theslice] = np.fabs(
1497
+ thecorrfunc_byslice[theloc, theslice, maxloc]
1498
+ )
1499
+ timecoursemin = np.min(
1500
+ corrected_rawapp_byslice[validlocs, theslice, :], axis=1
1501
+ ).reshape((-1, 1))
1502
+ app_byslice[validlocs, theslice, :] = (
1503
+ corrected_rawapp_byslice[validlocs, theslice, :] - timecoursemin
1504
+ )
1505
+ normapp_byslice[validlocs, theslice, :] = np.nan_to_num(
1506
+ app_byslice[validlocs, theslice, :] / means_byslice[validlocs, theslice, None]
1070
1507
  )
1071
- else:
1072
- rawapp_byslice[:, theslice, :] = 0.0
1073
- cine_byslice[:, theslice, :] = 0.0
1074
-
1075
- # smooth the projected data along the time dimension
1076
- if args.smoothapp:
1077
- for loc in validlocs:
1078
- rawapp_byslice[loc, theslice, :] = appsmoothingfilter.apply(
1079
- phaseFs, rawapp_byslice[loc, theslice, :]
1080
- )
1081
- derivatives_byslice[loc, theslice, :] = circularderivs(
1082
- rawapp_byslice[loc, theslice, :]
1083
- )
1084
- appflips_byslice = np.where(
1085
- -derivatives_byslice[:, :, 2] > derivatives_byslice[:, :, 0], -1.0, 1.0
1086
- )
1087
- timecoursemean = np.mean(rawapp_byslice[validlocs, theslice, :], axis=1).reshape((-1, 1))
1088
- if args.fliparteries:
1089
- corrected_rawapp_byslice[validlocs, theslice, :] = (
1090
- rawapp_byslice[validlocs, theslice, :] - timecoursemean
1091
- ) * appflips_byslice[validlocs, theslice, None] + timecoursemean
1092
- if args.doaliasedcorrelation and (thispass > 0):
1093
- for theloc in validlocs:
1094
- thecorrfunc_byslice[theloc, theslice, :] = theAliasedCorrelator.apply(
1095
- -appflips_byslice[theloc, theslice]
1096
- * demeandata_byslice[theloc, theslice, :],
1097
- int(sliceoffsets[theslice]),
1098
- )[corrstartloc : correndloc + 1]
1099
- maxloc = np.argmax(thecorrfunc_byslice[theloc, theslice, :])
1100
- wavedelay_byslice[theloc, theslice] = (
1101
- thealiasedcorrx[corrstartloc : correndloc + 1]
1102
- )[maxloc]
1103
- waveamp_byslice[theloc, theslice] = np.fabs(
1104
- thecorrfunc_byslice[theloc, theslice, maxloc]
1105
- )
1106
- wavedelayCOM_byslice[theloc, theslice] = theCOM(
1107
- thealiasedcorrx[corrstartloc : correndloc + 1],
1108
- np.fabs(thecorrfunc_byslice[theloc, theslice, :]),
1109
- )
1110
- else:
1111
- corrected_rawapp_byslice[validlocs, theslice, :] = rawapp_byslice[
1112
- validlocs, theslice, :
1113
- ]
1114
- if args.doaliasedcorrelation and (thispass > 0):
1115
- for theloc in validlocs:
1116
- thecorrfunc_byslice[theloc, theslice, :] = theAliasedCorrelator.apply(
1117
- -demeandata_byslice[theloc, theslice, :],
1118
- int(sliceoffsets[theslice]),
1119
- )[corrstartloc : correndloc + 1]
1120
- maxloc = np.argmax(np.abs(thecorrfunc_byslice[theloc, theslice, :]))
1121
- wavedelay_byslice[theloc, theslice] = (
1122
- thealiasedcorrx[corrstartloc : correndloc + 1]
1123
- )[maxloc]
1124
- waveamp_byslice[theloc, theslice] = np.fabs(
1125
- thecorrfunc_byslice[theloc, theslice, maxloc]
1126
- )
1127
- timecoursemin = np.min(corrected_rawapp_byslice[validlocs, theslice, :], axis=1).reshape(
1128
- (-1, 1)
1129
- )
1130
- app_byslice[validlocs, theslice, :] = (
1131
- corrected_rawapp_byslice[validlocs, theslice, :] - timecoursemin
1132
- )
1133
- normapp_byslice[validlocs, theslice, :] = np.nan_to_num(
1134
- app_byslice[validlocs, theslice, :] / means_byslice[validlocs, theslice, None]
1135
- )
1136
1508
  return appflips_byslice
1137
1509
 
1138
1510
 
1511
+ def findvessels(
1512
+ app,
1513
+ normapp,
1514
+ validlocs,
1515
+ numspatiallocs,
1516
+ outputroot,
1517
+ unnormvesselmap,
1518
+ destpoints,
1519
+ softvesselfrac,
1520
+ histlen,
1521
+ outputlevel,
1522
+ debug=False,
1523
+ ):
1524
+ if unnormvesselmap:
1525
+ app2d = app.reshape((numspatiallocs, destpoints))
1526
+ else:
1527
+ app2d = normapp.reshape((numspatiallocs, destpoints))
1528
+ histinput = app2d[validlocs, :].reshape((len(validlocs), destpoints))
1529
+ if outputlevel > 0:
1530
+ namesuffix = "_desc-apppeaks_hist"
1531
+ tide_stats.makeandsavehistogram(
1532
+ histinput,
1533
+ histlen,
1534
+ 0,
1535
+ outputroot + namesuffix,
1536
+ debug=debug,
1537
+ )
1538
+
1539
+ # find vessel thresholds
1540
+ tide_util.logmem("before making vessel masks")
1541
+ hardvesselthresh = tide_stats.getfracvals(np.max(histinput, axis=1), [0.98])[0] / 2.0
1542
+ softvesselthresh = softvesselfrac * hardvesselthresh
1543
+ print(
1544
+ "hard, soft vessel thresholds set to",
1545
+ "{:.3f}".format(hardvesselthresh),
1546
+ "{:.3f}".format(softvesselthresh),
1547
+ )
1548
+
1549
+
1139
1550
  def upsampleimage(input_data, numsteps, sliceoffsets, slicesamplerate, outputroot):
1140
1551
  fmri_data = input_data.byvol()
1141
1552
  timepoints = input_data.timepoints
@@ -1180,3 +1591,93 @@ def upsampleimage(input_data, numsteps, sliceoffsets, slicesamplerate, outputroo
1180
1591
  )
1181
1592
  tide_io.savetonifti(upsampleimage, theheader, outputroot + "_upsampled")
1182
1593
  print("upsampling complete")
1594
+
1595
+
1596
+ def wrightmap(
1597
+ input_data,
1598
+ demeandata_byslice,
1599
+ rawapp_byslice,
1600
+ projmask_byslice,
1601
+ outphases,
1602
+ cardphasevals,
1603
+ proctrs,
1604
+ congridbins,
1605
+ gridkernel,
1606
+ destpoints,
1607
+ iterations=100,
1608
+ nprocs=-1,
1609
+ verbose=False,
1610
+ debug=False,
1611
+ ):
1612
+ xsize = input_data.xsize
1613
+ ysize = input_data.ysize
1614
+ numslices = input_data.numslices
1615
+ # make a vessel map using Wright's method
1616
+ wrightcorrs_byslice = np.zeros((xsize * ysize, numslices, iterations))
1617
+ # first find the validlocs for each slice
1618
+ validlocslist = []
1619
+ if verbose:
1620
+ print("Finding validlocs")
1621
+ for theslice in range(numslices):
1622
+ validlocslist.append(np.where(projmask_byslice[:, theslice] > 0)[0])
1623
+ for theiteration in range(iterations):
1624
+ print(f"wright iteration: {theiteration + 1} of {iterations}")
1625
+ # split timecourse into two sets
1626
+ scrambledprocs = np.random.permutation(proctrs)
1627
+ proctrs1 = scrambledprocs[: int(len(scrambledprocs) // 2)]
1628
+ proctrs2 = scrambledprocs[int(len(scrambledprocs) // 2) :]
1629
+ if debug:
1630
+ print(f"{proctrs1=}, {proctrs2=}")
1631
+
1632
+ # phase project each slice
1633
+ rawapp_byslice1 = rawapp_byslice * 0.0
1634
+ cine_byslice1 = rawapp_byslice * 0.0
1635
+ weights_byslice1 = rawapp_byslice * 0.0
1636
+ phaseprojectpass(
1637
+ numslices,
1638
+ demeandata_byslice,
1639
+ input_data.byslice(),
1640
+ validlocslist,
1641
+ proctrs1,
1642
+ weights_byslice1,
1643
+ cine_byslice1,
1644
+ rawapp_byslice1,
1645
+ outphases,
1646
+ cardphasevals,
1647
+ congridbins,
1648
+ gridkernel,
1649
+ destpoints,
1650
+ nprocs=nprocs,
1651
+ showprogressbar=False,
1652
+ )
1653
+ rawapp_byslice2 = rawapp_byslice * 0.0
1654
+ cine_byslice2 = rawapp_byslice * 0.0
1655
+ weights_byslice2 = rawapp_byslice * 0.0
1656
+ phaseprojectpass(
1657
+ numslices,
1658
+ demeandata_byslice,
1659
+ input_data.byslice(),
1660
+ validlocslist,
1661
+ proctrs2,
1662
+ weights_byslice2,
1663
+ cine_byslice2,
1664
+ rawapp_byslice2,
1665
+ outphases,
1666
+ cardphasevals,
1667
+ congridbins,
1668
+ gridkernel,
1669
+ destpoints,
1670
+ nprocs=nprocs,
1671
+ showprogressbar=False,
1672
+ )
1673
+ for theslice in range(numslices):
1674
+ for thepoint in validlocslist[theslice]:
1675
+ theRvalue, thepvalue = pearsonr(
1676
+ rawapp_byslice1[thepoint, theslice, :],
1677
+ rawapp_byslice2[thepoint, theslice, :],
1678
+ )
1679
+ if debug:
1680
+ print("theRvalue = ", theRvalue)
1681
+ wrightcorrs_byslice[thepoint, theslice, theiteration] = theRvalue
1682
+ wrightcorrs = np.mean(wrightcorrs_byslice, axis=2).reshape(xsize, ysize, numslices)
1683
+ return wrightcorrs