rapidtide 3.0.6__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.
@@ -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,6 +365,41 @@ def getcardcoeffs(
364
365
  return peakfreq
365
366
 
366
367
 
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
+
367
403
  def normalizevoxels(
368
404
  fmri_data,
369
405
  detrendorder,
@@ -371,8 +407,12 @@ def normalizevoxels(
371
407
  time,
372
408
  timings,
373
409
  LGR=None,
410
+ mpcode=True,
374
411
  nprocs=1,
375
- showprogressbar=False,
412
+ alwaysmultiproc=False,
413
+ showprogressbar=True,
414
+ chunksize=1000,
415
+ debug=False,
376
416
  ):
377
417
  print("Normalizing voxels...")
378
418
  normdata = fmri_data * 0.0
@@ -382,17 +422,54 @@ def normalizevoxels(
382
422
  numspatiallocs = fmri_data.shape[0]
383
423
  if detrendorder > 0:
384
424
  print("Detrending to order", detrendorder, "...")
385
- for idx, thevox in enumerate(
386
- tqdm(
387
- validvoxels,
388
- desc="Voxel",
389
- unit="voxels",
390
- disable=(not showprogressbar),
391
- )
392
- ):
393
- fmri_data[thevox, :] = tide_fit.detrend(
394
- 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,
395
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
+
396
473
  timings.append(["Detrending finished", time.time(), numspatiallocs, "voxels"])
397
474
  print(" done")
398
475
 
@@ -969,6 +1046,7 @@ def cardiaccycleaverage(
969
1046
  congridbins,
970
1047
  gridkernel,
971
1048
  centric,
1049
+ cache=True,
972
1050
  cyclic=True,
973
1051
  ):
974
1052
  rawapp_bypoint = np.zeros(len(destinationphases), dtype=np.float64)
@@ -980,13 +1058,14 @@ def cardiaccycleaverage(
980
1058
  1.0,
981
1059
  congridbins,
982
1060
  kernel=gridkernel,
1061
+ cache=cache,
983
1062
  cyclic=cyclic,
984
1063
  )
985
1064
  for i in range(len(theindices)):
986
1065
  weight_bypoint[theindices[i]] += theweights[i]
987
1066
  rawapp_bypoint[theindices[i]] += theweights[i] * waveform[t]
988
1067
  rawapp_bypoint = np.where(
989
- weight_bypoint > np.max(weight_bypoint) / 50.0,
1068
+ weight_bypoint > (np.max(weight_bypoint) / 50.0),
990
1069
  np.nan_to_num(rawapp_bypoint / weight_bypoint),
991
1070
  0.0,
992
1071
  )
@@ -1007,6 +1086,285 @@ def circularderivs(timecourse):
1007
1086
  )
1008
1087
 
1009
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
+
1010
1368
  def phaseproject(
1011
1369
  input_data,
1012
1370
  demeandata_byslice,
@@ -1039,112 +1397,156 @@ def phaseproject(
1039
1397
  xsize, ysize, numslices, timepoints = input_data.getdims()
1040
1398
  fmri_data_byslice = input_data.byslice()
1041
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")
1042
1445
  for theslice in tqdm(
1043
1446
  range(numslices),
1044
1447
  desc="Slice",
1045
1448
  unit="slices",
1046
1449
  disable=(not args.showprogressbar),
1047
1450
  ):
1048
- if args.verbose:
1049
- print("Phase projecting for slice", theslice)
1050
- validlocs = np.where(projmask_byslice[:, theslice] > 0)[0]
1051
- # indexlist = range(0, len(cardphasevals[theslice, :]))
1451
+ # now do the flips
1452
+ validlocs = validlocslist[theslice]
1052
1453
  if len(validlocs) > 0:
1053
- for t in proctrs:
1054
- filteredmr = -demeandata_byslice[validlocs, theslice, t]
1055
- cinemr = fmri_data_byslice[validlocs, theslice, t]
1056
- thevals, theweights, theindices = tide_resample.congrid(
1057
- outphases,
1058
- cardphasevals[theslice, t],
1059
- 1.0,
1060
- args.congridbins,
1061
- kernel=args.gridkernel,
1062
- cyclic=True,
1063
- )
1064
- for i in range(len(theindices)):
1065
- weights_byslice[validlocs, theslice, theindices[i]] += theweights[i]
1066
- # rawapp_byslice[validlocs, theslice, theindices[i]] += (
1067
- # theweights[i] * filteredmr
1068
- # )
1069
- rawapp_byslice[validlocs, theslice, theindices[i]] += filteredmr
1070
- cine_byslice[validlocs, theslice, theindices[i]] += theweights[i] * cinemr
1071
- for d in range(args.destpoints):
1072
- if weights_byslice[validlocs[0], theslice, d] == 0.0:
1073
- weights_byslice[validlocs, theslice, d] = 1.0
1074
- rawapp_byslice[validlocs, theslice, :] = np.nan_to_num(
1075
- rawapp_byslice[validlocs, theslice, :] / weights_byslice[validlocs, theslice, :]
1454
+ appflips_byslice = np.where(
1455
+ -derivatives_byslice[:, :, 2] > derivatives_byslice[:, :, 0], -1.0, 1.0
1076
1456
  )
1077
- cine_byslice[validlocs, theslice, :] = np.nan_to_num(
1078
- 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]
1079
1507
  )
1080
- else:
1081
- rawapp_byslice[:, theslice, :] = 0.0
1082
- cine_byslice[:, theslice, :] = 0.0
1083
-
1084
- # smooth the projected data along the time dimension
1085
- if args.smoothapp:
1086
- for loc in validlocs:
1087
- rawapp_byslice[loc, theslice, :] = appsmoothingfilter.apply(
1088
- phaseFs, rawapp_byslice[loc, theslice, :]
1089
- )
1090
- derivatives_byslice[loc, theslice, :] = circularderivs(
1091
- rawapp_byslice[loc, theslice, :]
1092
- )
1093
- appflips_byslice = np.where(
1094
- -derivatives_byslice[:, :, 2] > derivatives_byslice[:, :, 0], -1.0, 1.0
1095
- )
1096
- timecoursemean = np.mean(rawapp_byslice[validlocs, theslice, :], axis=1).reshape((-1, 1))
1097
- if args.fliparteries:
1098
- corrected_rawapp_byslice[validlocs, theslice, :] = (
1099
- rawapp_byslice[validlocs, theslice, :] - timecoursemean
1100
- ) * appflips_byslice[validlocs, theslice, None] + timecoursemean
1101
- if args.doaliasedcorrelation and (thispass > 0):
1102
- for theloc in validlocs:
1103
- thecorrfunc_byslice[theloc, theslice, :] = theAliasedCorrelator.apply(
1104
- -appflips_byslice[theloc, theslice]
1105
- * demeandata_byslice[theloc, theslice, :],
1106
- int(sliceoffsets[theslice]),
1107
- )[corrstartloc : correndloc + 1]
1108
- maxloc = np.argmax(thecorrfunc_byslice[theloc, theslice, :])
1109
- wavedelay_byslice[theloc, theslice] = (
1110
- thealiasedcorrx[corrstartloc : correndloc + 1]
1111
- )[maxloc]
1112
- waveamp_byslice[theloc, theslice] = np.fabs(
1113
- thecorrfunc_byslice[theloc, theslice, maxloc]
1114
- )
1115
- wavedelayCOM_byslice[theloc, theslice] = theCOM(
1116
- thealiasedcorrx[corrstartloc : correndloc + 1],
1117
- np.fabs(thecorrfunc_byslice[theloc, theslice, :]),
1118
- )
1119
- else:
1120
- corrected_rawapp_byslice[validlocs, theslice, :] = rawapp_byslice[
1121
- validlocs, theslice, :
1122
- ]
1123
- if args.doaliasedcorrelation and (thispass > 0):
1124
- for theloc in validlocs:
1125
- thecorrfunc_byslice[theloc, theslice, :] = theAliasedCorrelator.apply(
1126
- -demeandata_byslice[theloc, theslice, :],
1127
- int(sliceoffsets[theslice]),
1128
- )[corrstartloc : correndloc + 1]
1129
- maxloc = np.argmax(np.abs(thecorrfunc_byslice[theloc, theslice, :]))
1130
- wavedelay_byslice[theloc, theslice] = (
1131
- thealiasedcorrx[corrstartloc : correndloc + 1]
1132
- )[maxloc]
1133
- waveamp_byslice[theloc, theslice] = np.fabs(
1134
- thecorrfunc_byslice[theloc, theslice, maxloc]
1135
- )
1136
- timecoursemin = np.min(corrected_rawapp_byslice[validlocs, theslice, :], axis=1).reshape(
1137
- (-1, 1)
1138
- )
1139
- app_byslice[validlocs, theslice, :] = (
1140
- corrected_rawapp_byslice[validlocs, theslice, :] - timecoursemin
1141
- )
1142
- normapp_byslice[validlocs, theslice, :] = np.nan_to_num(
1143
- app_byslice[validlocs, theslice, :] / means_byslice[validlocs, theslice, None]
1144
- )
1145
1508
  return appflips_byslice
1146
1509
 
1147
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
+
1148
1550
  def upsampleimage(input_data, numsteps, sliceoffsets, slicesamplerate, outputroot):
1149
1551
  fmri_data = input_data.byvol()
1150
1552
  timepoints = input_data.timepoints
@@ -1189,3 +1591,93 @@ def upsampleimage(input_data, numsteps, sliceoffsets, slicesamplerate, outputroo
1189
1591
  )
1190
1592
  tide_io.savetonifti(upsampleimage, theheader, outputroot + "_upsampled")
1191
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