1 /*plug_permtest.c - AFNI plugin that applies a permutation test to a 3D+time
2 dataset to create a fizt dataset.
3 Copyright (c) 2000 - 2005 Matthew Belmonte
4
5 This program is free software; you can redistribute it and/or
6 modify it under the terms of the GNU General Public License
7 as published by the Free Software Foundation; either version 2
8 of the License, or (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18
19 If you find this program useful, please send mail to Matthew Belmonte
20 <belmonte@mit.edu>.
21 */
22
23 #define NUM_ITERS 10000
24 #define NUM_COORDS 2
25
26 #define BLAST 33333.0
27 #include <sys/types.h>
28 #include <sys/param.h>
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <math.h>
32 #include <string.h>
33 #include "afni.h"
34
35 /*a macro that wraps THD_pval_to_stat() (which in turn evaluates to a call to
36 the one-tailed probability-to-z-score function normal_p2t()) so that it
37 behaves like Gary Perlman's two-tailed zcrit() function in Netlib*/
38 #define critz(p) \
39 (((p) >= 0.5)? THD_pval_to_stat(2.0*(1.0-(p)), FUNC_ZT_TYPE, (float *)0) \
40 : -THD_pval_to_stat(2.0*(p), FUNC_ZT_TYPE, (float *)0))
41
42 static char help[] =
43 "This plugin implements a permutation test, a nonparametric statistical\n"
44 "method that avoids the pitfall of over-correcting for multiple comparisons\n"
45 "since it implicitly takes into account spatial correlations in the data.\n"
46 "If you use this software, please take a moment to send mail to the author,\n"
47 "belmonte@mit.edu, and cite the following paper in your report:\n\n"
48
49 "Matthew K Belmonte and Deborah A Yurgelun-Todd, `Permutation Testing Made\n"
50 "Practical for Functional Magnetic Resonance Image Analysis',\n"
51 "IEEE Transactions on Medical Imaging 20(3):243-248 (March 2001).\n\n"
52
53 "USAGE\n\n"
54
55 "`Input' is the echo-planar dataset for which the permutation test is to be\n"
56 "computed.\n\n"
57
58 "`Ideal' is the ideal time series against which the echo-planar data are to\n"
59 "be correlated.\n\n"
60
61 "`Ort', an optional parameter, is a time series to which the echo-planar\n"
62 "data are to be orthogonalised. This feature is useful when one wants to\n"
63 "analyse responses to two superposed conditions independently. (Note that\n"
64 "the data are always detrended, i.e. orthogonalised to a linear series --\n"
65 "this optional orthogonalisation is in addition to the detrending step.)\n\n"
66
67 "`Output' is the output dataset. The activation data saved in this dataset\n"
68 "consist of a sub-brick of regression coefficients and a sub-brick of\n"
69 "probability values. As AFNI provides no standard format for storing\n"
70 "probabilities, these are mapped to z-scores and the entire dataset is\n"
71 "saved as a FIZT dataset.\n\n"
72
73 "`alpha level' is the tail probability at which to stop marking voxels as\n"
74 "activated. (Note that the slider in the `Define Overlay' panel will\n"
75 "have no effect below this value.) You should avoid setting this value\n"
76 "very high, lest the Phase 3 algorithm run out of substitute points in too\n"
77 "many cases (for an explanation of substitutes, see the article cited above).\n\n"
78
79 "`AR order', an optional parameter, is the order (i.e. the number of\n"
80 "samples of look-back) of the autoregressive model used to remove noise\n"
81 "colouring from the fMRI time series before permuting it, and to restore\n"
82 "this colouring after permutation. At field strengths (B0) of 3 Tesla or\n"
83 "more, or repetition times (TR) of 2 seconds or less, autocorrelation can\n"
84 "be non-negligible and you therefore should select this option. In most\n"
85 "cases an autoregressive order of 1 should suffice, though you may want to\n"
86 "try going up to 3. You can experiment with greater orders by examining\n"
87 "the automatically generated files DSET_autocorrelation.1D and\n"
88 "DSET_autoregression.1D, where DSET is the name of the 3D+time dataset to\n"
89 "which you've just applied the permutation test; if the Nth autocorrelation\n"
90 "coefficient is near zero then you can safely restrict the autoregressive\n"
91 "model to order N-1. (In extreme cases the program will detect this\n"
92 "condition and decrease the model order automatically.)\n"
93 "\tAutoregressive modelling was suggested early on as a method of\n"
94 "correcting for coloured noise as a preparatory step to permutation testing\n"
95 "of fMRI time series [1]. Although methods based around permuting in a\n"
96 "wavelet domain leave residuals that are more temporally independent in\n"
97 "comparison to those left by autoregressive methods [2], it's uclear how\n"
98 "much of this residual temporal dependence arises from coloured noise\n"
99 "versus how much may reflect the presence of (subthreshold) signal.\n"
100 "Recently it's been shown that wavelet methods, like Fourier methods, may\n"
101 "tend to underestimate thresholds for statistical significance (and\n"
102 "therefore risk producing false positive results) when the permuted series\n"
103 "include frequency-localised BOLD signal as well as noise [3] -- a\n"
104 "condition that applies especially in block designs. For these reasons as\n"
105 "as well as for simplicity of implementation, I've chosen to implement here\n"
106 "autoregressive rather than wavelet whitening.\n"
107 "[1] JJ Locascio, PJ Jennings, CI Moore, S Corkin, `Time Series Analysis in\n"
108 " the Time Domain and Resampling Methods for Studies of Functional\n"
109 " Magnetic Resonance Brain Imaging', Human Brain Mapping 5(3):168-193\n"
110 " (1997).\n"
111 "[2] ET Bullmore, C Long, J Suckling, J Fadili, G Calvert, F Zelaya,\n"
112 " TA Carpenter, MJ Brammer, `Colored Noise and Computational Inference\n"
113 " in Neurophysiological (fMRI) Time Series Analysis: Resampling Methods\n"
114 " in Time and Wavelet Domains', Human Brain Mapping 12(2):61-78\n"
115 " (February 2001).\n"
116 "[3] O Friman, C-F Westin, `Resampling fMRI Time Series', NeuroImage\n"
117 " 25(3):859-867 (15 April 2005).\n\n"
118
119 "`AR exclude', an optional parameter which has effect only when `AR order'\n"
120 "has been specified, is a vector of flags in which non-zero values specify\n"
121 "that the corresponding elements of the fMRI time series are to be excluded\n"
122 "from the autocorrelation computation. If this parameter is not specified,\n"
123 "all time points are included. Normally you won't need to specify this\n"
124 "parameter, although it may be useful in some block designs in which the\n"
125 "noise structure depends on the experimental condition.\n\n"
126
127 "`two-tailed', `one-tailed positive', and `one-tailed negative' select the\n"
128 "tail(s) of interest. Exactly one of these options must be selected.\n\n"
129
130 "`Mask', an optional parameter, is a FIM dataset whose three spatial\n"
131 "dimensions match those of the echo-planar dataset. Only those\n"
132 "coordinates whose mask values are between 1 and the largest positive\n"
133 "short integer are included in the permutation test. These inclusion\n"
134 "limits can be overridden using the optional `least mask value' and\n"
135 "`greatest mask value' parameters. Mask datasets can be generated\n"
136 "automatically using the Threshold plugin (q.v.), or using 3dAutomask.\n\n"
137
138 "AUTHOR\n\n"
139
140 "This plugin was written by Matthew Belmonte <belmonte@mit.edu> of the\n"
141 "MIT Student Information Processing Board, supported by a grant from the\n"
142 "National Alliance for Autism Research.\n\n"
143
144 "REVISION HISTORY\n\n"
145
146 "2.0 7 November 2005 added autoregressive correction for coloured noise\n"
147 "1.3 20 January 2005 added support for 3dAutomask and other byte-valued masks\n"
148 "1.2 19 December 2002 fixed a dtree bug that caused a rare crash in phase 3\n"
149 "1.1 14 June 2001 cosmetic changes only\n"
150 "1.0 4 January 2001 initial release\n\n"
151
152 "SEE ALSO\n\n"
153
154 "Threshold Plugin or 3dAutomask program\n"
155 "Draw Dataset Plugin\n"
156 "(These normally are applied before the permutation test.)",
157
158 hint[] = "compute FIM with permutation test",
159 input_label[] = "Input",
160 ts_label[] = "Ideal",
161 ort_label[] = "Ort",
162 output_label[] = "Output",
163 alpha_label[] = "alpha level (0,1]",
164 AR_order_label[] = "AR order",
165 AR_excl_label[] = "AR exclude",
166 tails2[] = "two-tailed",
167 tails1pos[] = "one-tailed positive",
168 tails1neg[] = "one-tailed negative",
169 mask_label[] = "Mask",
170 masklo_label[] = "least mask value",
171 maskhi_label[] = "greatest mask value";
172
173 /*data structures for trees*/
174
175 /*singly-indexed tree: ordered on correlations*/
176 typedef struct _snode {
177 double corr; /*correlation (key)*/
178 int coords; /*coordinates: x+xdim*(y+ydim*z) */
179 struct _snode *left, *right; /*children*/
180 } SNODE;
181
182 typedef struct {
183 SNODE *mem, /*base address of tree node storage*/
184 *next, /*next free tree storage address*/
185 *root; /*==tree_mem if tree is non-null*/
186 int xdim, ydim; /*maximum coordinate values*/
187 } STREE;
188
189 #define stree_null(t) ((t)->root == (SNODE *)0)
190
191 typedef struct { /*pairs (r, (x,y,z))*/
192 double corr;
193 int coords;
194 } CLIST;
195
196 /*doubly-indexed tree: ordered on correlations and on coordinates*/
197 typedef struct _dnode {
198 CLIST *data; /*correlations and coordinates*/
199 int dlen; /*# of valid entries in data[]*/
200 int size; /*size of this correlation subtree*/
201 struct _dnode *corr_lchild, /*children in correlation tree*/
202 *corr_rchild,
203 *corr_parent, /*parent in correlation tree*/
204 *coord_lchild, /*children in coordinate tree*/
205 *coord_rchild;
206 } DNODE;
207
208 typedef struct {
209 DNODE *mem, /*base address of tree node storage*/
210 *next, /*next free tree storage address*/
211 *corr_root, *coord_root; /*==mem if tree is non-null*/
212 int xdim, ydim; /*maximum coordinate values*/
213 } DTREE;
214
215 #define dtree_size(t) (((t)->corr_root == (DNODE *)0)? 0: ((t)->corr_root->size))
216
217 /*encoding and decoding functions for mapping a triple to a single integer*/
218 #define coord_encode(x, y, z, xdim, ydim) ((x) + (xdim)*((y) + (ydim)*(z)))
219
coord_decode(int coords,int * x,int * y,int * z,int xdim,int ydim)220 static void coord_decode(int coords, int *x, int *y, int *z, int xdim, int ydim)
221 {
222 *x = coords % xdim;
223 coords /= xdim;
224 *y = coords % ydim;
225 *z = coords / ydim;
226 }
227
228 #define sign(x) (((x)<0)? -1: 1)
229
230 #ifdef PERMTEST_DEBUG
231
232 /*flush output buffers on SIGUSR1 - useful for batch debugging*/
233 #include <signal.h>
flush(int sig)234 static void flush(int sig)
235 {
236 fflush(stdout);
237 fflush(stderr);
238 signal(SIGUSR1, flush);
239 }
240
241 /*slave routine to stree_traverse()*/
rcsv_stree_traverse(SNODE * t,int indent)242 void rcsv_stree_traverse(SNODE *t, int indent)
243 {
244 register int i;
245 while(t)
246 {
247 for(i = 0; i != indent; i++)
248 putchar(' ');
249 indent += 2;
250 printf("%lx: corr=%f coords=%d left=%lx right=%lx\n", (long)t, t->corr, t->coords, (long)(t->left), (long)(t->right));
251 rcsv_stree_traverse(t->left, indent);
252 t = t->right;
253 }
254 }
255
256 /*Print a traversal of the given stree.*/
stree_traverse(STREE * t)257 void stree_traverse(STREE *t)
258 {
259 printf("t=%lx\n mem=%lx next=%lx = mem+%ld root=%lx xdim=%d ydim=%d\n",
260 (long)t,
261 (long)(t->mem),
262 (long)(t->next),
263 (((long)(t->next))-(long)(t->mem))/sizeof(SNODE),
264 (long)(t->root),
265 t->xdim, t->ydim);
266 rcsv_stree_traverse(t->root, 0);
267 putchar('\n');
268 }
269
270 /*slave routine to dtree_traverse()*/
rcsv_dtree_traverse(DNODE * t,int indent,int order)271 void rcsv_dtree_traverse(DNODE *t, int indent, int order)
272 {
273 register int i;
274 while(t)
275 {
276 for(i = 0; i != indent; i++)
277 putchar(' ');
278 indent += 2;
279 printf("%lx: data=", (long)t);
280 for(i = 0; i != t->dlen; i++)
281 printf("%f %d ", t->data[i].corr, t->data[i].coords);
282 printf("size=%d corr_lchild=%lx corr_rchild=%lx corr_parent=%lx coord_lchild=%lx coord_rchild=%lx\n", t->size, (long)(t->corr_lchild), (long)(t->corr_rchild), (long)(t->corr_parent), (long)(t->coord_lchild), (long)(t->coord_rchild));
283 if(order)
284 {
285 rcsv_dtree_traverse(t->coord_lchild, indent, order);
286 t = t->coord_rchild;
287 }
288 else
289 {
290 rcsv_dtree_traverse(t->corr_lchild, indent);
291 t = t->corr_rchild;
292 }
293 }
294 }
295
296 /*Print a traversal of a dtree. Use corr links if order=0, coord links if
297 order=1.*/
dtree_traverse(DTREE * t,int order)298 void dtree_traverse(DTREE *t, int order)
299 {
300 printf("t=%lx\n mem=%lx next=%lx = mem+%ld coord_root=%lx corr_root=%lx xdim=%d ydim=%d\n",
301 (long)t,
302 (long)(t->mem),
303 (long)(t->next),
304 (((long)(t->next))-(long)(t->mem))/sizeof(DNODE),
305 (long)(t->coord_root),
306 (long)(t->corr_root),
307 t->xdim, t->ydim);
308 rcsv_dtree_traverse((order? t->coord_root: t->corr_root), 0, order);
309 putchar('\n');
310 }
311
312 /*slave routine to dtree_check_sizes()*/
rcsv_dtree_check_sizes(DNODE * t)313 int rcsv_dtree_check_sizes(DNODE *t)
314 {
315 int s;
316 if(t)
317 {
318 s = 1+rcsv_dtree_check_sizes(t->corr_lchild)+rcsv_dtree_check_sizes(t->corr_rchild);
319 if(s != t->size)
320 {
321 printf("%lx->size = %d should be %d\n", (long)t, t->size, s);
322 fflush(stdout);
323 }
324 return(t->size);
325 }
326 return 0;
327 }
328
329 /*Check that the size fields of a dtree are consistent with each other and with
330 the structure of the tree.*/
dtree_check_sizes(DTREE * t)331 int dtree_check_sizes(DTREE *t)
332 {
333 return(rcsv_dtree_check_sizes(t->corr_root));
334 }
335
336 /*slave routine to dtree_circtest()*/
rcsv_dtree_circtest(DNODE * t,DNODE * mem,char * mark,int n,int order)337 void rcsv_dtree_circtest(DNODE *t, DNODE *mem, char *mark, int n, int order)
338 {
339 register int m;
340 while(t)
341 {
342 m = (int)((((long)t)-(long)mem)/(((long)(mem+1))-((long)mem)));
343 if((m >= n) || (m < 0))
344 printf("out-of-bounds reference %lx (mem+%d)\n", (long)t, m);
345 else if(mark[m])
346 printf("duplicate reference %lx (mem+%d)\n", (long)t, m);
347 else
348 {
349 mark[m] = 1;
350 if(order)
351 {
352 rcsv_dtree_circtest(t->coord_lchild, mem, mark, n, order);
353 t = t->coord_rchild;
354 }
355 else
356 {
357 rcsv_dtree_circtest(t->corr_lchild, mem, mark, n, order);
358 t = t->corr_rchild;
359 }
360 }
361 }
362 }
363
364 /*Test the given dtree for circular or out-of-bounds references. Use corr links
365 if order=0, coord links if order=1.*/
dtree_circtest(DTREE * t,int order)366 void dtree_circtest(DTREE *t, int order)
367 {
368 char *mark;
369 int n;
370 n = (int)((((long)(t->next))-(long)(t->mem))/(((long)(t->mem+1))-((long)(t->mem))));
371 mark = calloc(n, 1);
372 if(mark)
373 {
374 rcsv_dtree_circtest((order? t->coord_root: t->corr_root), t->mem, mark, n, order);
375 free(mark);
376 }
377 else
378 fprintf(stderr, "dtree_circtest: couldn't calloc mark\n");
379 }
380
381 /*slave routine to dtree_check_parent_pointers()*/
rcsv_dtree_check_parent_pointers(DNODE * t)382 int rcsv_dtree_check_parent_pointers(DNODE *t)
383 {
384 int bad;
385 bad = 0;
386 while(t != (DNODE *)0)
387 {
388 if(t->corr_lchild)
389 {
390 if(t->corr_lchild->corr_parent != t)
391 {
392 printf("%lx->corr_lchild = %lx, but %lx->corr_parent = %lx\n",
393 (long)t, (long)(t->corr_lchild), (long)(t->corr_lchild),
394 (long)(t->corr_lchild->corr_parent));
395 bad = 1;
396 }
397 if(rcsv_dtree_check_parent_pointers(t->corr_lchild)) bad = 1;
398 }
399 if((t->corr_rchild) && (t->corr_rchild->corr_parent != t))
400 {
401 printf("%lx->corr_rchild = %lx, but %lx->corr_parent = %lx\n",
402 (long)t, (long)(t->corr_rchild), (long)(t->corr_rchild),
403 (long)(t->corr_rchild->corr_parent));
404 bad = 1;
405 }
406 t = t->corr_rchild;
407 }
408 return bad;
409 }
410
411 /*Verify that the corr_parent fields inside t are consistent with the
412 corr_lchild and corr_rchild fields.*/
dtree_check_parent_pointers(DTREE * t)413 int dtree_check_parent_pointers(DTREE *t)
414 {
415 return(rcsv_dtree_check_parent_pointers(t->corr_root));
416 }
417
418 /*Print hex dump of an IEEE double-precision floating-point number, MSB first.*/
fdump(double * x)419 void fdump(double *x)
420 {
421 double test = 2.0;
422 int i;
423 register char *c;
424 c = (char *)x;
425 if(*(char *)&test)
426 for(i = 7; i >= 0; i--)
427 printf("%02x", c[i]&0xff);
428 else
429 for(i = 0; i != 8; i++)
430 printf("%02x", c[i]&0xff);
431 }
432
433 #endif
434
435 /*Which metric is used for comparison of correlation values depends on which
436 tail(s) of the distribution interest us. For the two-tailed case, our
437 `maximum' should be the most extreme value from either tail, so we use the
438 absolute value function fabs() from libm. For the negative one-tailed case,
439 our `maximum' should be the most negative value, so we use the negation
440 function neg(). For the positive one-tailed case, our maximum should be the
441 most positive value, so we use the identity function id().*/
442
id(double r)443 static double id(double r)
444 {
445 return(r);
446 }
447
neg(double r)448 static double neg(double r)
449 {
450 return(-r);
451 }
452
453 static double (*magnitude)(double);
454
455 /*Allocate storage and initialise a tree that can contain up to nelem nodes.*/
stree_create(int xdim,int ydim,int nelem)456 static STREE *stree_create(int xdim, int ydim, int nelem)
457 {
458 STREE *t;
459 t = (STREE *)malloc(sizeof(*t));
460 if(t == (STREE *)0)
461 return((STREE *)0);
462 t->mem = (SNODE *)calloc(nelem, sizeof(*(t->mem)));
463 if(t->mem == (SNODE *)0)
464 {
465 free(t);
466 return((STREE *)0);
467 }
468 t->next = t->mem;
469 t->root = (SNODE *)0;
470 t->xdim = xdim;
471 t->ydim = ydim;
472 return(t);
473 }
474
475 /*Deallocate a tree.*/
stree_destroy(STREE * t)476 static void stree_destroy(STREE *t)
477 {
478 free(t->mem);
479 free(t);
480 }
481
482 /*Insert the given value into the tree.*/
stree_insert(STREE * t,double r,int x,int y,int z)483 static void stree_insert(STREE *t, double r, int x, int y, int z)
484 {
485 register SNODE **p;
486 double rmag;
487 p = &(t->root);
488 rmag = (*magnitude)(r);
489 /*inv: The path from t->root to p is labelled with values whose magnitudes
490 bound or equal that of r.*/
491 while(*p != (SNODE *)0)
492 p = (rmag < (*magnitude)((*p)->corr))? &((*p)->left): &((*p)->right);
493 t->next->corr = r;
494 t->next->coords = coord_encode(x, y, z, t->xdim, t->ydim);
495 t->next->left = (SNODE *)0;
496 t->next->right = (SNODE *)0;
497 *p = t->next++;
498 }
499
500 /*Delete the maximum correlation value from the given tree, and return that
501 value and its associated coordinates.*/
stree_extract_max(STREE * t,int * x,int * y,int * z)502 static double stree_extract_max(STREE *t, int *x, int *y, int *z)
503 {
504 register SNODE **p, **pp;
505 SNODE *target;
506 if(t->root == (SNODE *)0)
507 {
508 fprintf(stderr, "Error: STREE underflow\n- this happens when every voxel in the brain has been identified as activated\n");
509 return(0.0);
510 }
511 if((t->root->left == (SNODE *)0) && (t->root->right == (SNODE *)0))
512 {
513 target = t->root;
514 t->root = (SNODE *)0;
515 t->next = t->mem;
516 }
517 else
518 {
519 p = &(t->root);
520 /*inv: **pp and **p are successive links in a chain of right children
521 beginning at t->root.*/
522 do
523 {
524 pp = p;
525 p = &((*p)->right);
526 } while((*p) != (SNODE *)0);
527 target = *pp;
528 *pp = (*pp)->left;
529 }
530 coord_decode(target->coords, x, y, z, t->xdim, t->ydim);
531 return(target->corr);
532 }
533
534 /*Allocate storage and initialise a dtree that can contain up to nelem nodes.*/
dtree_create(int xdim,int ydim,int nelem)535 static DTREE *dtree_create(int xdim, int ydim, int nelem)
536 {
537 DTREE *t;
538 t = (DTREE *)malloc(sizeof(*t));
539 if(t == (DTREE *)0)
540 return((DTREE *)0);
541 t->mem = (DNODE *)calloc(nelem, sizeof(*(t->mem)));
542 if(t->mem == (DNODE *)0)
543 {
544 free(t);
545 return((DTREE *)0);
546 }
547 t->next = t->mem;
548 t->corr_root = (DNODE *)0;
549 t->coord_root = (DNODE *)0;
550 t->xdim = xdim;
551 t->ydim = ydim;
552 return(t);
553 }
554
555 /*Deallocate a dtree.*/
dtree_destroy(DTREE * t)556 static void dtree_destroy(DTREE *t)
557 {
558 free(t->mem);
559 free(t);
560 }
561
562 /*Insert the given value into the dtree, using the given storage location.*/
dtree_insert_at_node(DTREE * t,DNODE * node)563 static void dtree_insert_at_node(DTREE *t, DNODE *node)
564 {
565 register DNODE **p, /*pointer into the coord tree*/
566 *q, *qparent; /*pointers to adjacent corr tree nodes*/
567 p = &(t->coord_root);
568 /*inv: The path from t->coord_root to *p is labelled with values that bound or
569 equal node->data->coords.*/
570 while(*p != (DNODE *)0)
571 p = ((node->data->coords > (*p)->data->coords)? &((*p)->coord_rchild): &((*p)->coord_lchild));
572 /*link the node into the coord tree*/
573 node->coord_lchild = (DNODE *)0;
574 node->coord_rchild = (DNODE *)0;
575 *p = node;
576 /*link the node into the corr tree*/
577 node->size = 1;
578 node->corr_lchild = (DNODE *)0;
579 node->corr_rchild = (DNODE *)0;
580 if(t->corr_root == (DNODE *)0)
581 {
582 /*insertion into an empty tree is a special case*/
583 node->corr_parent = (DNODE *)0;
584 t->corr_root = node;
585 }
586 else
587 {
588 q = t->corr_root;
589 /*inv: The path from t->corr_root to q is labelled with values that bound or
590 equal r.*/
591 do
592 {
593 q->size++;
594 qparent = q;
595 q = ((node->data->corr > q->data->corr)? q->corr_rchild: q->corr_lchild);
596 } while(q != (DNODE *)0);
597 /*link the node into the correlation tree*/
598 node->corr_parent = qparent;
599 if(node->data->corr > qparent->data->corr)
600 qparent->corr_rchild = node;
601 else
602 qparent->corr_lchild = node;
603 }
604 }
605
606 static int num_coords;
607
608 /*Insert the given value into the dtree.*/
dtree_insert(DTREE * t,CLIST * clist)609 static void dtree_insert(DTREE *t, CLIST *clist)
610 {
611 t->next->data = clist;
612 t->next->dlen = num_coords;
613 dtree_insert_at_node(t, t->next++);
614 }
615
616 static int num_coords_exhausted;
617
618 /*p points to a coord_lchild, coord_rchild, or coord_root field that is to be
619 unlinked from its coord children and its corr children and corr parent within
620 the tree t.*/
dtree_unlink_node(DTREE * t,DNODE ** p)621 void dtree_unlink_node(DTREE *t, DNODE **p)
622 {
623 register DNODE **q;
624 DNODE *node, *parent, *temp;
625 node = *p;
626 if(node->coord_lchild == (DNODE *)0)
627 *p = node->coord_rchild;
628 else if(node->coord_rchild == (DNODE *)0)
629 *p = node->coord_lchild;
630 else
631 {
632 /*inv: *q is the rightmost node at the current level in the left subtree of
633 (*p).*/
634 for(q = &(node->coord_lchild); (*q)->coord_rchild != (DNODE *)0; q = &((*q)->coord_rchild))
635 ;
636 (*q)->coord_rchild = node->coord_rchild;
637 *p = *q;
638 if(q != &(node->coord_lchild))
639 {
640 DNODE *temp;
641 temp = (*q)->coord_lchild;
642 (*q)->coord_lchild = node->coord_lchild;
643 *q = temp;
644 }
645 }
646 /*The node has been unlinked from the coord tree. Now unlink it from the corr
647 tree, using a procedure analogous to that which was implemented above for the
648 coord tree. First, decrement the size counts from the current position back
649 to the corr root:*/
650 for(parent = node->corr_parent; parent != (DNODE *)0; parent = parent->corr_parent)
651 parent->size--;
652 /*Make p point to the link that leads into the subtree rooted at node.*/
653 p = ((node->corr_parent == (DNODE *)0)? &(t->corr_root):
654 (node == node->corr_parent->corr_lchild)?
655 &(node->corr_parent->corr_lchild):
656 &(node->corr_parent->corr_rchild));
657 /*The cases of fewer than two children are easy to handle:*/
658 if(node->corr_lchild == (DNODE *)0)
659 {
660 if(node->corr_rchild)
661 node->corr_rchild->corr_parent = node->corr_parent;
662 *p = node->corr_rchild;
663 }
664 else if(node->corr_rchild == (DNODE *)0)
665 {
666 if(node->corr_lchild)
667 node->corr_lchild->corr_parent = node->corr_parent;
668 *p = node->corr_lchild;
669 }
670 /*In the two-child case, we find the rightmost node of the left subtree and
671 promote it.*/
672 else
673 {
674 /*inv: *q is the rightmost node at the current level in the left subtree of
675 (*p).*/
676 for(q = &(node->corr_lchild); (*q)->corr_rchild != (DNODE *)0; q = &((*q)->corr_rchild))
677 (*q)->size--;
678 (*q)->corr_rchild = node->corr_rchild;
679 if(node->corr_rchild)
680 node->corr_rchild->corr_parent = *q;
681 *p = *q;
682 parent = (*q)->corr_parent;
683 (*q)->corr_parent = node->corr_parent;
684 if(q != &(node->corr_lchild))
685 {
686 /*If the left subtree of the rightmost node is non-null, promote it to fill
687 the place that has just been vacated by the promoted rightmost node.*/
688 temp = (*q)->corr_lchild;
689 (*q)->corr_lchild = node->corr_lchild;
690 node->corr_lchild->corr_parent = *q;
691 *q = temp;
692 if(temp)
693 temp->corr_parent = parent;
694 }
695 (*p)->size = 1
696 + ((*p)->corr_lchild? (*p)->corr_lchild->size: 0)
697 + ((*p)->corr_rchild? (*p)->corr_rchild->size: 0);
698 }
699 }
700
701 /*Delete from the dtree all nodes that are labelled with the given coordinates.
702 For each of the deleted nodes, if any substitute coordinates remain in the
703 coordinate list, use those substitute coordinates to re-insert the node into
704 the dtree. Otherwise increment num_coords_exhausted.*/
dtree_delete_coords(DTREE * t,int x,int y,int z,short * deleted)705 static void dtree_delete_coords(DTREE *t, int x, int y, int z, short *deleted)
706 /*deleted[x+xdim*(y+ydim*z)] is nonzero iff (x,y,z) has not yet been deleted*/
707 {
708 register DNODE **p, /*pointer into coord tree*/
709 *del; /*pointer to deleted node*/
710 int target_coords_not_found, /*flag indicates coords not yet found*/
711 coords; /*encoded form of target coordinates*/
712 coords = coord_encode(x, y, z, t->xdim, t->ydim);
713 p = &(t->coord_root);
714 target_coords_not_found = 1;
715 /*inv: All remaining nodes whose coordinates match the target coords are in the
716 subtree rooted at *p. All matching nodes outside this subtree have been
717 replaced by nodes with substitute coordinates and correlations.*/
718 while(target_coords_not_found && (*p != (DNODE *)0))
719 {
720 if(coords > (*p)->data->coords)
721 p = &((*p)->coord_rchild);
722 else if(coords < (*p)->data->coords)
723 p = &((*p)->coord_lchild);
724 else
725 {
726 /*found a matching node*/
727 target_coords_not_found = 0;
728 do
729 {
730 del = *p;
731 dtree_unlink_node(t, p); /*note: *p != del after this call!*/
732 /*re-insert the node with substitute data, if any substitutes remain*/
733 do {del->dlen--; del->data++;
734 /*check that substitutes haven't been exhausted (dlen != 0) and the
735 coordinates associated with the substitute at the head of the list are
736 still not valid (deleted[del->data->coords] != 0)*/
737 } while((del->dlen != 0) && deleted[del->data->coords]);
738 /*If valid substitute data are available, re-insert this node using those
739 substitutes. Otherwise, increment the count of occurrences of failed
740 substitutions.*/
741 if(del->dlen != 0)
742 dtree_insert_at_node(t, del);
743 else
744 num_coords_exhausted++;
745 } while(*p && (coords == (*p)->data->coords));
746 /*By clearing the flag target_coords_not_found on entry to the inner loop, we
747 ensure that the outer loop will terminate once the inner loop's guard has
748 become false. The correctness of this strategy depends on the structure of
749 the auxiliary routine dtree_unlink_node() and on the following line in
750 dtree_insert_at_node() above:
751 p = ((node->data->coords > (*p)->data->coords)? &((*p)->coord_rchild):
752 &((*p)->coord_lchild));
753 This line makes sets of equal coordinates into *left*-recursive rather than
754 right-recursive trees, and accordingly, dtree_unlink_node() looks in the
755 *left* subtree for a node to promote into the place of the deleted node as
756 (*p).*/
757 }
758 }
759 }
760
761 /*Return a fraction in the interval (0,1) that describes the ordinal position
762 that the given correlation value would occupy within the ordered contents of
763 the dtree, were it to be added to the tree.*/
dtree_position(DTREE * t,double r)764 static double dtree_position(DTREE *t, double r)
765 {
766 register DNODE *p;
767 register int rank;
768 p = t->corr_root;
769 if((p == (DNODE *)0) || (p->size == 1))
770 return(0.5);
771 rank = 0;
772 /*inv: rank/2 is the number of correlation values in the tree that are less
773 than r and are not within the subtree rooted at p, plus half of the number
774 of correlation values in the tree that equal r and are not within the subtree
775 rooted at p.*/
776 while(p != (DNODE *)0)
777 if(r > p->data->corr)
778 {
779 rank += 2*(1+(p->corr_lchild? p->corr_lchild->size: 0));
780 p = p->corr_rchild;
781 }
782 else
783 {
784 if(r == p->data->corr)
785 rank++; /*values equal to the target count only half*/
786 p = p->corr_lchild;
787 }
788 if(rank == 2*t->corr_root->size)
789 rank--;
790 else if(rank == 0)
791 rank++;
792 return(rank / (2.0*t->corr_root->size));
793 }
794
795 /*Randomly permute the integer array a[0..n-1].
796 Richard Durstenfeld, `Algorithm 235: Random Permutation [G6]',
797 Communications of the Association for Computing Machinery 7:7:420 (1964).*/
shuffle(int * a,int n)798 static void shuffle(int *a, int n)
799 {
800 register int i, j, b;
801 for(i = n-1; i != 0; i--)
802 {
803 j = (int)(random()%(i+1));
804 b = a[i]; a[i] = a[j]; a[j] = b;
805 }
806 }
807
808 /*Prepare static sums for correlate().*/
correlate_prep(float * x,float * y,int nxy,double * sy,double * syy)809 static void correlate_prep(float *x, float *y, int nxy, double *sy, double *syy)
810 {
811 register int n; /*length of time series, excluding ignored points*/
812 *sy = *syy = 0.0;
813 n = 0;
814 while(nxy--)
815 {
816 if(*x < BLAST)
817 {
818 *syy += *y**y;
819 *sy += *y;
820 n++;
821 }
822 x++; y++;
823 }
824 *syy -= *sy**sy/n;
825 }
826
827 /*Correlate the ideal time series x with the actual time series y, where both
828 series are of length nxy. If the pointers r, m, and b are non-null, they
829 receive, respectively, the correlation coefficient and the slope and
830 intercept of the regression line. A call to correlate() must be preceded by
831 calls to correlate_prep() of the following forms:
832 correlate_prep(x, y, nxy, &sx, &sxx);
833 correlate_prep(x, y, nxy, &sy, &syy);*/
correlate(float * x,float * y,int nxy,double sx,double sxx,double sy,double syy,double * r,double * m,double * b)834 static void correlate(
835 float *x, /*ideal time series (points >= BLAST are ignored)*/
836 float *y, /*actual time series*/
837 int nxy, /*length of time series (including any ignored points)*/
838 double sx, /*sum of x[i] | 0<=i<nxy and x[i]<BLAST*/
839 double sxx, /*sum of x[i]^2 | 0<=i<nxy and x[i]<BLAST*/
840 double sy, /*sum of y[i] | 0<=i<nxy and x[i]<BLAST*/
841 double syy, /*sum of y[i]^2 | 0<=i<nxy and x[i]<BLAST*/
842 double *r, /*correlation coefficient*/
843 double *m, /*slope*/
844 double *b) /*intercept*/
845 {
846 register double sxy;
847 register int n; /*length of time series, excluding ignored points*/
848 double slope;
849 if(sxx == 0.0)
850 {
851 if(r) *r = 0.0;
852 if(m) *m = 0.0;
853 if(b)
854 {
855 n = 0;
856 while(nxy--)
857 if(x[nxy] < BLAST)
858 n++;
859 *b = sy/n;
860 }
861 }
862 else
863 {
864 sxy = 0.0;
865 n = 0;
866 while(nxy--)
867 {
868 if(*x < BLAST)
869 {
870 sxy += *x**y;
871 n++;
872 }
873 x++; y++;
874 }
875 sxy -= sx*sy/n;
876 if(r)
877 *r = ((syy == 0.0)? 0.0: (sxy/sqrt(sxx*syy)));
878 slope = sxy/sxx;
879 if(m) *m = slope;
880 if(b) *b = (sy - slope*sx)/n;
881 }
882 }
883
884 /*Orthogonalise y to x, where m and b have been set by a call to correlate().
885 Store the result in new_y (which may point to the same location as y, in the
886 case in which the original value of y need not be saved). For linear
887 detrending, input x[i] = i, 0<=i<n.*/
orthogonalise(float * x,float * y,float * new_y,int n,double m,double b)888 static void orthogonalise(float *x, float *y, float *new_y, int n, double m, double b)
889 {
890 while(n--)
891 if(x[n] < BLAST)
892 new_y[n] = y[n]-(m*x[n]+b);
893 }
894
895 /*Initialise the numerator sums (*cov)[0..order-1], the denominator sum *var,
896 the number of included time points *n_incl, and optionally the exclusion
897 vector excl[order..n-1], for an AR(order) autocorrelation computation. If
898 the pointer excl_0 is non-null then excl_0[0..n-1] is a time series whose
899 elements are non-zero iff the corresponding element of the fMRI time series
900 is to be excluded from the autocorrelation computation. (For example, in the
901 context of a block design it may be desirable to exclude expected intervals of
902 activation, and to include only expected baseline intervals.) Compute
903 excl[order..n-1] such that excl_0[t] ==> excl[max(t, order) .. min(t+order,
904 n-1)] for all i in [0, n-1], that is, the exclusion of a time point also
905 excludes the following 'order' time points. (This requirement ensures that
906 looking back at lagging points yields valid data.) ((*excl)-order) and *cov
907 are dynamically allocated; the calling routine is responsible for invoking
908 autocorrelate_finish() after the last call to autocorrelate_compute() to free
909 ((*excl)-order), and for freeing *cov itself once the correlations are no
910 longer needed. Return 0 if successful, 1 if out of memory.*/
911 /* K&R to ANSI from Greg Balls 7 Aug 2006 [rickr] */
autocorrelate_init(float * excl_0,int n,int order,char ** excl,double ** cov,double * var,int * n_incl)912 static int autocorrelate_init(float *excl_0, int n, int order, char **excl,
913 double **cov, double *var, int *n_incl)
914 {
915 register int t, k;
916 *cov = (double *)calloc(order, sizeof(**cov));
917 if(*cov == (double *)0)
918 return(1);
919 /*no need to zero (*cov)[0..order-1], since calloc() has already done so*/
920 *var = 0.0;
921 *n_incl = n-order;
922 if(excl_0 != (float *)0)
923 {
924 *excl = calloc(n, sizeof(**excl));
925 if(*excl == (char *)0)
926 {
927 free(*cov);
928 return(1);
929 }
930 /*no need to initialise (*excl)[] to 0, since calloc() has already done so*/
931 /*compute (*excl)[] at its lower boundary*/
932 for(t = 0; t != order; t++)
933 if(excl_0[t] != 0.0)
934 {
935 for(k = order-t; k <= order; k++)
936 (*excl)[t+k] = 1;
937 *n_incl -= t+1;
938 }
939 /*compute (*excl)[] between its boundaries*/
940 while(t < n-order)
941 {
942 if(excl_0[t] != 0.0)
943 {
944 for(k = 0; k <= order; k++)
945 (*excl)[t+k] = 1;
946 *n_incl -= order+1;
947 }
948 t++;
949 }
950 /*compute (*excl)[] at its upper boundary*/
951 while(t < n)
952 {
953 if(excl_0[t] != 0.0)
954 {
955 for(k = 0; k < n-t; k++)
956 (*excl)[t+k] = 1;
957 *n_incl -= n-t;
958 }
959 t++;
960 }
961 }
962 else
963 *excl = (char *)0;
964 return(0);
965 }
966
967 /*Given ts[0..n-1], a voxel's detrended fMRI time series, and optionally
968 excl[0..n-1], a vector of flags computed by autocorrelate_init() that signify
969 exclusion from the autocorrelation computation, accumulate data from this
970 voxel's time series into the numerator sums cov[0..order-1] and the
971 denominator sum var for computing autocorrelation coefficients in an AR(order)
972 model.*/
973 /* K&R to ANSI from Greg Balls 7 Aug 2006 [rickr] */
autocorrelate_sum(float * ts,int n,int n_incl,int order,char * excl,double * cov,double * var)974 static void autocorrelate_sum(
975 float *ts, /* detrended fMRI time series from one voxel */
976 int n, /* length of ts[] */
977 int n_incl, /* number of 0's in excl[0..n-1], */
978 /* else n-order if no excl[] */
979 int order, /* AR order - i.e., number of lags modelled in r[]*/
980 char *excl, /* excl[i]=0 <==> include ts[i] in autocorrelation */
981 /* computation*/
982 double *cov,/*cov[k-1] accumulates Sigma[(ts[i]-ts_avg)*(ts[i-k]-ts_avg)],*/
983 /* !excl[i] & !excl[i-k], order<=i<n*/
984 double *var /** var accumulates Sigma[(ts[i]-ts_avg)^2], */
985 /* !excl[i] & !excl[i-k], order<=i<n */
986 )
987 {
988 register int t, /*time index*/
989 k; /*AR lag index*/
990 double avg, /*average of ts[] over all included time points*/
991 excursion; /*current sample's excursion from the mean*/
992 avg = 0.0;
993 if(excl == (char *)0)
994 {
995 /*if no exclusion vector has been provided, then all points are included*/
996 for(t = order; t < n; t++)
997 avg += ts[t];
998 avg /= n_incl;
999 for(t = order; t < n; t++)
1000 {
1001 excursion = ts[t]-avg;
1002 for(k = order; k; k--)
1003 cov[k-1] += excursion*(ts[t-k]-avg);
1004 *var += excursion*excursion;
1005 }
1006 }
1007 else
1008 {
1009 /*exclude the points specified by the exclusion vector*/
1010 for(t = order; t < n; t++)
1011 if(!excl[t])
1012 avg += ts[t];
1013 avg /= n_incl;
1014 for(t = order; t < n; t++)
1015 if(!excl[t])
1016 {
1017 excursion = ts[t]-avg;
1018 for(k = order; k; k--)
1019 cov[k-1] += excursion*(ts[t-k]-avg);
1020 *var += excursion*excursion;
1021 }
1022 }
1023 }
1024
1025 /*Finish the autocorrelation computation by dividing the numerator sums
1026 cov[0..order-1] by the denominator sum var, and leaving the resulting
1027 autocorrelations in cov[0..order-1]. Check for autocorrelations that are
1028 impossible (|r| > 1, possible in the event of some weird accumulation of
1029 rounding errors), or physiologically implausible (|r| = 1 or r < 0). If such
1030 values are found, eliminate them from the model by decreasing the model's
1031 order (*order). Also, deallocate the storage used for excl[order..n-1].*/
autocorrelate_finish(int * order,char * excl,double * cov,double var)1032 static void autocorrelate_finish(int *order, char *excl, double *cov,
1033 double var)
1034 /* int *order; char *excl; double *cov, var; */
1035 {
1036 register int k;
1037 if(excl != (char *)0)
1038 free(excl); /*exclusion vector is no longer needed*/
1039 k = *order;
1040 while(k--)
1041 {
1042 cov[k] /= var;
1043 if((cov[k] >= 1.0) || (cov[k] < 0.0))
1044 {
1045 fprintf(stderr, "Suspect AR(%d) autocorrelation %f; restricting model to AR(%d)\n", k+1, cov[k], k);
1046 #ifdef AR_DEBUG
1047 fprintf(stderr, "\tDEBUG MODE: OVERRIDING THIS RESTRICTION\n");
1048 #else
1049 *order = k;
1050 #endif
1051 }
1052 }
1053 }
1054
1055 /*Solve the system of equations represented by the augmented matrix
1056 m[0..n-1][0..n] (in row-major order), using simple Gaussian elimination.
1057 (n is assumed to be small enough so that LU decomposition wouldn't yield any
1058 substantial increase in speed.) If m is singular, 1 is returned. If m is
1059 non-singular, 0 is returned and the solutions are left in m[0..n-1][n].*/
1060 /* K&R to ANSI from Greg Balls 7 Aug 2006 [rickr] */
solve(double ** m,int n)1061 static int solve(double **m, int n)
1062 /* double **m; int n; */
1063 {
1064 register int i, j, k;
1065 int singular;
1066 double *tmprow;
1067 singular = 0;
1068 /*inv: m is a linear combination of the original m, and
1069 for all i where 0<=i<j, (m[ii]=1 and m[i][i+1..n-1]=0)*/
1070 for(j = 0; (!singular) && (j != n); j++)
1071 {
1072 /*inv: m[j..i-1][j]=0*/
1073 for(i = j; (i != n) && (m[i][j] == 0.0); i++)
1074 ;
1075 if(i == n)
1076 singular = 1;
1077 else
1078 {
1079 /*m[i][j] is the topmost nonzero element in column j - if row i isn't
1080 already the top row, make it the top row by exchanging rows:*/
1081 if(i != j)
1082 {
1083 tmprow = m[i];
1084 m[i] = m[j];
1085 m[j] = tmprow;
1086 }
1087 /*m[j][j] is nonzero; multiply row j by 1/m[j][j] to make m[j][j]=1*/
1088 for(i = n; i != j; i--)
1089 m[j][i] /= m[j][j];
1090 m[j][j] = 1.0;
1091 /*subtract scalar multiples of row j from rows j+1..n-1 so as to make
1092 the lower column m[j+1..n-1][j]=0*/
1093 /*inv: m is a linear combination of the original m, and m[j+1..i-1][j]=0*/
1094 for(i = j+1; i != n; i++)
1095 {
1096 for(k = n; k != j; k--)
1097 m[i][k] -= m[i][j]*m[j][k];
1098 m[i][j]= 0.0;
1099 }
1100 }
1101 }
1102 if(!singular)
1103 {
1104 /*inv: m is a linear combination of the original m with rows j+1..n-1 solved*/
1105 for(j = n-1; j; j--)
1106 /*inv: m is a linear combination of the original m and m[0..i-1][j]=0*/
1107 for(i = 0; i != j; i++)
1108 {
1109 m[i][n] -= m[i][j]*m[j][n];
1110 m[i][j] = 0.0;
1111 }
1112 }
1113 return(singular);
1114 }
1115
1116 /*On entry, r[0..order-1] are the autocorrelation coefficients for lags
1117 1..order. On successful exit, 0 is returned and r[0..order-1] are the
1118 autoregression coefficients for lags 1..order - i.e., they implement the
1119 AR(order) model ts[t] = r[0]*ts[t-1] + r[1]*ts[t-2] + ...
1120 + r[order-1]*ts[t-order] + e(t). If a singular matrix is encountered,
1121 or if a memory allocation error arises, r[] is zeroed and 1 is returned.*/
1122 /* K&R to ANSI from Greg Balls 7 Aug 2006 [rickr] */
yule_walker(double * r,int order)1123 static int yule_walker(
1124 double *r, /* r[0..order-1] are the autocorrelations for lags 1..order */
1125 int order )
1126 {
1127 register int i, k;
1128 int retval;
1129 double **m; /*the Yule-Walker matrix*/
1130 /*allocate storage for all rows m[0..order-1]*/
1131 m = (double **)calloc(order, sizeof(*m));
1132 if(m == (double **)0)
1133 retval = 1;
1134 else
1135 {
1136 /*set up row pointers*/
1137 *m = (double *)calloc(order*(order+1), sizeof(**m));
1138 if(*m == (double *)0)
1139 {
1140 free(m);
1141 retval = 1;
1142 }
1143 else
1144 {
1145 for(i = 1; i != order; i++)
1146 m[i] = m[i-1]+order+1; /*1 extra column for augmented matrix*/
1147 for(i = 0; i != order; i++)
1148 {
1149 for(k = i-1; k >= 0; k--)
1150 m[i][k] = r[i-k-1]; /*m[i][i-1..0] = r[0..i-1]*/
1151 m[i][i] = 1.0; /*diagonal is 1*/
1152 for(k = i+1; k != order; k++)
1153 m[i][k] = r[k-i-1]; /*m[i][i+1..order-1] = r[0..order-2-i]*/
1154 m[i][k] = r[i]; /*rightmost column is r[0..order-1]*/
1155 }
1156
1157 #ifdef AR_DEBUG
1158 {int i, j; printf("\nYULE-WALKER MATRIX:\n");
1159 for(i=0; i!=order; i++){
1160 for(j=0; j!=1+order; j++) printf("%f ", m[i][j]);
1161 putchar('\n');}}
1162 #endif
1163
1164 retval = solve(m, order);
1165
1166 #ifdef AR_DEBUG
1167 {int i, j; printf("YULE-WALKER SOLUTION:\n");
1168 for(i=0; i!=order; i++){
1169 for(j=0; j!=1+order; j++) printf("%f ", m[i][j]);
1170 putchar('\n');}}
1171 #endif
1172
1173 if(retval == 0)
1174 /*read out autoregression coefficients*/
1175 for(i = 0; i != order; i++)
1176 r[i] = m[i][order];
1177 free(*m);
1178 free(m);
1179 }
1180 }
1181 /*if there was a singularity or a memory error, zero r[]*/
1182 if(retval)
1183 for(i = 0; i != order; i++)
1184 r[i] = 0.0;
1185 return(retval);
1186 }
1187
1188 /*Apply the AR(order) autoregression coefficients reg[0..order-1] to whiten the
1189 coloured time series coloured[0..n-1]. Place the result in white[0..n-1].
1190 coloured[] and white[] must be distinct storage.*/
1191 /* K&R to ANSI from Greg Balls 7 Aug 2006 [rickr] */
whiten(const float * coloured,float * white,int n,double * reg,int order)1192 static void whiten(
1193 const float *coloured, /*coloured[0..n-1] (source)*/
1194 float *white, /*white[0..n-1] (destination)*/
1195 int n,
1196 double *reg, /*reg[0..order-1] (AR(order) regression coeff.*/
1197 int order)
1198 {
1199 register int t, k;
1200 *white = *coloured;
1201 for(t = 1; t < order; t++)
1202 {
1203 white[t] = coloured[t];
1204 for(k = 0; k != order; k++)
1205 white[t] -= reg[k]*coloured[(t-k<=0)? 0: (t-k-1)];
1206 }
1207 while(t < n)
1208 {
1209 white[t] = coloured[t];
1210 for(k = 0; k != order; k++)
1211 white[t] -= reg[k]*coloured[t-k-1];
1212 t++;
1213 }
1214 }
1215
1216 /*Apply the AR(order) autoregression coefficients reg[0..order-1] to colour
1217 the white time series white[0..n-1]. Place the result in coloured[0..n-1].
1218 coloured[] and white[] must be distinct storage.*/
colour(float * coloured,const float * white,int n,double * reg,int order)1219 static void colour(
1220 float *coloured, /*coloured[0..n-1] (source)*/
1221 const float *white, /*white[0..n-1] (destination)*/
1222 int n,
1223 double *reg, /*reg[0..order-1] (AR(order) regression coeff.*/
1224 int order)
1225 {
1226 register int t, k;
1227 *coloured = *white;
1228 for(t = 1; t < order; t++)
1229 {
1230 coloured[t] = white[t];
1231 for(k = 0; k != order; k++)
1232 coloured[t] += reg[k]*coloured[(t-k<=0)? 0: (t-k-1)];
1233 }
1234 while(t < n)
1235 {
1236 coloured[t] = white[t];
1237 for(k = 0; k != order; k++)
1238 coloured[t] += reg[k]*coloured[t-k-1];
1239 t++;
1240 }
1241 }
1242
1243 /*Write vec[0..len-1] to the ASCII file whose name is filename_prefix
1244 concatenated with filename_suffix concatenated with ".1D".*/
write_1D_file(const double * vec,int len,const char * filename_prefix,const char * filename_suffix)1245 static int write_1D_file(
1246 const double *vec,
1247 int len,
1248 const char *filename_prefix,
1249 const char *filename_suffix)
1250 {
1251 register int i, j;
1252 FILE *fp;
1253 char filename[1+MAXPATHLEN];
1254 for(i = 0; filename_prefix[i] != '\0'; i++)
1255 filename[i] = filename_prefix[i];
1256 for(j = 0; filename_suffix[j] != '\0'; j++)
1257 filename[i++] = filename_suffix[j];
1258 filename[i++] = '.';
1259 filename[i++] = '1';
1260 filename[i++] = 'D';
1261 filename[i++] = '\0';
1262 fp = fopen(filename, "w");
1263 if(fp == NULL)
1264 {
1265 perror(filename);
1266 return(1);
1267 }
1268 while(len--)
1269 fprintf(fp, "%f\n", *(vec++));
1270 fclose(fp);
1271 return(0);
1272 }
1273
1274 #ifdef AR_DEBUG
1275
1276 /*test driver: writes a coloured time series to "permtest_autoregr_series.dat",
1277 writes this time series' autocorrelation coefficients to "_autocorrelation"
1278 and its autoregression coefficients to "_autoregression", then writes the
1279 corresponding whitened time series to "permtest_autoregr_whitened.dat" and
1280 the recoloured time series to "permtest_autoregr_recoloured.dat" and prints
1281 the autocorrelation coefficients of this recoloured time series.*/
AR_test()1282 void AR_test()
1283 {
1284 FILE *tsfile;
1285 const int tslen = 200;
1286 int i, j, k;
1287 float ts[tslen], /*original, coloured time series*/
1288 white[tslen], /*whitened time series*/
1289 excl_0[tslen]; /*time points to be excluded from the computation*/
1290 char *excl; /*excl_0[] with time lags of length 'order'*/
1291 double *r, /*covariances, autocorrelations, autoregressions*/
1292 var, /*variance*/
1293 e0, e1, e2, e3; /*additive coloured noise terms*/
1294 int order, /*autoregressive order*/
1295 n_incl; /*# of included (i.e. non-excluded) points*/
1296 order = 3;
1297 tsfile = fopen("permtest_autoregr_series.dat", "w");
1298 if(tsfile == NULL) exit(1);
1299 e1 = e2 = e3 = 0.0;
1300 for(i = 0; i != tslen; i++)
1301 {
1302 /*10% + 20% + 30% = 60% coloured noise plus 40% white noise:*/
1303 e0 = 0.1*e3 + 0.2*e2 + 0.3*e1 + 0.4*((random()/(double)RAND_MAX)-0.5);
1304 ts[i] = e0 /* +sin((2.0*3.14159*i)/(tslen-order)) */ ;
1305 e3 = e2; e2 = e1; e1 = e0;
1306 fprintf(tsfile, "%f\n", ts[i]);
1307 }
1308 fclose(tsfile);
1309 j = order*order;
1310 k = 0;
1311 /*alternating included and excluded blocks of 9 samples each:*/
1312 for(i = 0; i != tslen; i++, j--)
1313 {
1314 if(j == 0)
1315 {
1316 j = order*order;
1317 k = !k;
1318 }
1319 excl_0[i] = k;
1320 }
1321 if(autocorrelate_init((float *)0, tslen, order, &excl, &r, &var, &n_incl))
1322 {
1323 fprintf(stderr, "autocorrelate_init: out of memory\n");
1324 return(1);
1325 }
1326 autocorrelate_sum(ts, tslen, n_incl, order, excl, r, &var);
1327 autocorrelate_finish(&order, excl, r, var);
1328 write_1D_file(r, order, "", "autocorrelation");
1329 if(order)
1330 {
1331 if(yule_walker(r, order))
1332 /*this never happens*/
1333 fprintf(stderr,
1334 "Cannot compute autoregression; Yule-Walker matrix is singular.\n");
1335 else
1336 {
1337 write_1D_file(r, order, "", "autoregression");
1338 whiten(ts, white, tslen, r, order);
1339 tsfile = fopen("permtest_autoregr_whitened.dat", "w");
1340 if(tsfile == NULL) exit(1);
1341 for(i = 0; i != tslen; i++)
1342 fprintf(tsfile, "%f\n", white[i]);
1343 fclose(tsfile);
1344 colour(ts, white, tslen, r, order);
1345 tsfile = fopen("permtest_autoregr_recoloured.dat", "w");
1346 if(tsfile == NULL) exit(1);
1347 for(i = 0; i != tslen; i++)
1348 fprintf(tsfile, "%f\n", ts[i]);
1349 fclose(tsfile);
1350 }
1351 free(r);
1352 if(autocorrelate_init((float *)0, tslen, order, &excl, &r, &var, &n_incl))
1353 {
1354 fprintf(stderr, "autocorrelate_init: out of memory\n");
1355 return(1);
1356 }
1357 autocorrelate_sum(white, tslen, n_incl, order, excl, r, &var);
1358 for(i = 1; i <= order; i++)
1359 printf("\t\tAR(%d)", i);
1360 autocorrelate_finish(&order, excl, r, var);
1361 printf("\nautocorrelations:");
1362 for(i = 0; i != order; i++)
1363 printf("\t%f", r[i]);
1364 putchar('\n');
1365 }
1366 free(r);
1367 }
1368
1369 #endif
1370
1371 /*Compute the permutation test. Return 0 if successful, 1 if error.*/
PERMTEST_compute(PLUGIN_interface * plint,THD_3dim_dataset * dset,MRI_IMAGE * ref_ts,MRI_IMAGE * ort_ts,double pcrit,int one_tailed,short ** intensities,short ** zvals,double * fim_scale,THD_3dim_dataset * mask,float masklo,float maskhi,int verbose,int AR_order,MRI_IMAGE * AR_excl_ts)1372 static int PERMTEST_compute(
1373 PLUGIN_interface *plint, /*AFNI plugin interface*/
1374 THD_3dim_dataset *dset, /*AFNI 3D+time dataset*/
1375 MRI_IMAGE *ref_ts, /*reference time series*/
1376 MRI_IMAGE *ort_ts, /*time series against which to orthogonalise*/
1377 double pcrit, /*critical probability*/
1378 int one_tailed, /*-1=one-tailed (-), 0=two-tailed, 1=one-tailed (+)*/
1379 /*returned parameters:*/
1380 short **intensities, /*address of pointer to intensities*/
1381 short **zvals, /*address of pointer to z-scores*/
1382 double *fim_scale, /*scaling factor for intensities*/
1383 THD_3dim_dataset *mask, /*mask dataset, or NULL for no mask*/
1384 float masklo, /*lower and upper bounds on masked range*/
1385 float maskhi,
1386 int verbose, /*1 for verbose info on coordinates, 0 otherwise*/
1387 int AR_order, /*autoregressive model order*/
1388 MRI_IMAGE *AR_excl_ts) /*autoregression exclusion flags*/
1389 {
1390 register int t, iter, xyz; /*indices and counters*/
1391 int x=0, y=0, z,
1392 xdim, ydim, zdim, /*spatial dimensions*/
1393 tdim, /*temporal dimension of dataset*/
1394 tsize, /*# of included (< BLAST) points, tsize<=tdim*/
1395 ignore, /*# of ignored (>=BLAST) pts at head of series*/
1396 t2,
1397 *tindex, /*temporal sequence of all included images*/
1398 *sequence; /*permuted temporal sequence*/
1399 float *vox_xyz, /*time series for one voxel*/
1400 *AR_ts=NULL, /*time series after whitening or colouring*/
1401 *vox, /*3D+time data indexed by z,y,x,t*/
1402 *ts, /*storage for linear series (ts[t]=t, 0<=t<tsize),
1403 and later for randomised time series*/
1404 *fit_coeff, /*fit coefficients*/
1405 mask_val; /*value of mask at current voxel*/
1406 STREE *actual_corr;
1407 DTREE *randomised_corr;
1408 CLIST *coord_mem, /*data area for coord-corr pair lists*/
1409 *coord_next; /*next free location in coord_mem*/
1410 double sx_trend, sx_ref, sx_ort, *sy, /*correlation parameters*/
1411 sxx_trend, sxx_ref, sxx_ort, *syy,
1412 corr, slope, intercept, /*regression coefficients*/
1413 max_corr; /*correlation w/ max absolute value*/
1414 int percent_done, prev_percent_done, /*statistics for progress meter*/
1415 not_done;
1416
1417 /*variables for the autoregression computation*/
1418 double *AR=NULL, /*autoregression coefficients*/
1419 AR_var; /*variance*/
1420 int AR_n_incl=0; /*# of points included in covariance calc.*/
1421 char *AR_excl=NULL; /*flags at each time point, 1=excluded*/
1422
1423 /*set dimensions*/
1424 xdim = dset->daxes->nxx;
1425 ydim = dset->daxes->nyy;
1426 zdim = dset->daxes->nzz;
1427 tdim = DSET_NUM_TIMES(dset);
1428 switch(one_tailed)
1429 {
1430 case -1: magnitude = neg; break;
1431 case 0: magnitude = fabs; break;
1432 case 1: magnitude = id;
1433 }
1434 num_coords = NUM_COORDS;
1435 num_coords_exhausted = 0;
1436 if(ort_ts != (MRI_IMAGE *)0) /*need to save extra points if orthogonalising*/
1437 num_coords *= 2;
1438 /*allocate storage for functional intensities*/
1439 *intensities = (short *)calloc(xdim*ydim*zdim, sizeof(**intensities));
1440 if(*intensities == (short *)0)
1441 return 1;
1442 /*allocate storage for z-scores*/
1443 *zvals = (short *)calloc(xdim*ydim*zdim, sizeof(**zvals));
1444 if(*zvals == (short *)0)
1445 {
1446 free(*intensities);
1447 return 1;
1448 }
1449 /*no need to initialise (*zvals)[] to zeroes, since calloc() does it for us*/
1450 /*Initialise temporal sequences: `tindex' is a mapping from the time index
1451 used in statistical tests to the time index used for storage in the AFNI
1452 dataset; it excludes ignored time points. `sequence' is initially the same
1453 as tindex but will be permuted during each iteration of the resampling
1454 procedure.*/
1455 tindex = (int *)calloc(tdim, sizeof(*tindex));
1456 if(tindex == (int *)0)
1457 {
1458 free(*zvals);
1459 free(*intensities);
1460 return 1;
1461 }
1462 sequence = (int *)calloc(tdim, sizeof(*sequence));
1463 if(sequence == (int *)0)
1464 {
1465 free(tindex);
1466 free(*zvals);
1467 free(*intensities);
1468 return 1;
1469 }
1470 for((t = 0), (tsize = 0); t != tdim; t++)
1471 if(MRI_FLOAT_PTR(ref_ts)[t] < BLAST)
1472 {
1473 tindex[tsize] = t;
1474 sequence[tsize++] = t;
1475 }
1476 if(tsize < 4) /*make sure we have enough points for regression*/
1477 {
1478 free(sequence);
1479 free(tindex);
1480 free(*zvals);
1481 free(*intensities);
1482 fprintf(stderr, "ERROR: %d time points aren't enough to perform regression\n", tsize);
1483 return 1;
1484 }
1485 /*initialise data*/
1486 vox = (float *)calloc(xdim*ydim*zdim*tdim, sizeof(*vox));
1487 if(vox == (float *)0)
1488 {
1489 free(sequence);
1490 free(tindex);
1491 free(*zvals);
1492 free(*intensities);
1493 return 1;
1494 }
1495 sy = (double *)calloc(xdim*ydim*zdim, sizeof(*sy));
1496 if(sy == (double *)0)
1497 {
1498 free(vox);
1499 free(sequence);
1500 free(tindex);
1501 free(*zvals);
1502 free(*intensities);
1503 return 1;
1504 }
1505 syy = (double *)calloc(xdim*ydim*zdim, sizeof(*syy));
1506 if(syy == (double *)0)
1507 {
1508 free(sy);
1509 free(vox);
1510 free(sequence);
1511 free(tindex);
1512 free(*zvals);
1513 free(*intensities);
1514 return 1;
1515 }
1516 ts = (float *)calloc(tdim, sizeof(*ts));
1517 if(ts == (float *)0)
1518 {
1519 free(syy);
1520 free(sy);
1521 free(vox);
1522 free(sequence);
1523 free(tindex);
1524 free(*zvals);
1525 free(*intensities);
1526 return 1;
1527 }
1528 actual_corr = stree_create(xdim, ydim, xdim*ydim*zdim);
1529 if(actual_corr == (STREE *)0)
1530 {
1531 free(syy);
1532 free(sy);
1533 free(ts);
1534 free(vox);
1535 free(sequence);
1536 free(tindex);
1537 free(*zvals);
1538 free(*intensities);
1539 return 1;
1540 }
1541 fit_coeff = (float *)calloc(xdim*ydim*zdim, sizeof(*fit_coeff));
1542 if(fit_coeff == (float *)0)
1543 {
1544 stree_destroy(actual_corr);
1545 free(syy);
1546 free(sy);
1547 free(ts);
1548 free(vox);
1549 free(sequence);
1550 free(tindex);
1551 free(*zvals);
1552 free(*intensities);
1553 return 1;
1554 }
1555
1556 /******************************************************************************
1557 * PHASE 1: Copy data, remove linear trend, optionally orthogonalise against *
1558 * a user-supplied series, and correlate with the ideal series. *
1559 ******************************************************************************/
1560 for(ignore = 0; MRI_FLOAT_PTR(ref_ts)[ignore] >= BLAST; ignore++)
1561 ;
1562 /*linear series to use in detrending*/
1563 for(t = 0; t != tdim; t++)
1564 ts[t] = (float)t;
1565 /*sum of the linear series, and sum of its squares*/
1566 sx_trend = (double)(((tdim-1)*tdim - (ignore-1)*ignore)/2);
1567 sxx_trend = ((double)((tdim*(tdim*(2*tdim-3)+1) - ignore*(ignore*(2*ignore-3)+1))/6)) - sx_trend*sx_trend/(tdim-ignore);
1568 /*compute the sum and sum of squares of the ideal time series*/
1569 correlate_prep(MRI_FLOAT_PTR(ref_ts)+ignore, MRI_FLOAT_PTR(ref_ts)+ignore, tdim-ignore, &sx_ref, &sxx_ref);
1570 /*compute the sum and sum of squares of the orthogonal series, if specified*/
1571 if(ort_ts != (MRI_IMAGE *)0)
1572 correlate_prep(MRI_FLOAT_PTR(ort_ts), MRI_FLOAT_PTR(ort_ts), tdim, &sx_ort, &sxx_ort);
1573 *fim_scale = 0.0;
1574 mask_val = masklo;
1575 /*if autoregressive correction for coloured noise has been requested,
1576 iniialise the autoregression computation:*/
1577 if(AR_order && autocorrelate_init(((AR_excl_ts != (MRI_IMAGE *)0)?
1578 MRI_FLOAT_PTR(AR_excl_ts)+ignore:
1579 (float *)0),
1580 tdim-ignore, AR_order, &AR_excl, &AR, &AR_var, &AR_n_incl))
1581 {
1582 fprintf(stderr, "autocorrelate_init: out of memory\n");
1583 return 1;
1584 }
1585 xyz = 0;
1586 for(z = 0; z != zdim; z++)
1587 for(y = 0; y != ydim; y++)
1588 for(x = 0; x != xdim; x++)
1589 {
1590 if(mask != NULL)
1591 {
1592 /*fetch the mask brick's scaling factor...*/
1593 mask_val = DSET_BRICK_FACTOR(mask, 0);
1594 if(mask_val == 0.0)
1595 mask_val = 1.0;
1596 /*...and multiply it by the mask datum at coordinates (x, y, z)*/
1597 if(DSET_BRICK_TYPE(mask, 0) == MRI_short)
1598 mask_val *= ((short *)DSET_ARRAY(mask, 0))[xyz];
1599 else
1600 mask_val *= ((char *)DSET_ARRAY(mask, 0))[xyz];
1601 }
1602 if((mask_val >= masklo) && (mask_val <= maskhi))
1603 {
1604 vox_xyz = vox + tdim*xyz;
1605 for(t = 0; t != tdim; t++)
1606 {
1607 /*fetch the time series brick's scaling factor...*/
1608 vox_xyz[t] = DSET_BRICK_FACTOR(dset, t);
1609 if(vox_xyz[t] == 0.0)
1610 vox_xyz[t] = 1.0;
1611 /*...and multiply it by the time series datum at (x, y, z, t)*/
1612 vox_xyz[t] *= ((short *)DSET_ARRAY(dset, t))[xyz];
1613 }
1614 /*detrend*/
1615 correlate_prep(ts+ignore, vox_xyz+ignore, tdim-ignore, sy+xyz, syy+xyz);
1616 correlate(ts+ignore, vox_xyz+ignore, tdim-ignore, sx_trend, sxx_trend, sy[xyz], syy[xyz], (double *)0, &slope, &intercept);
1617 orthogonalise(ts, vox_xyz, vox_xyz, tdim, slope, intercept+slope*ignore);
1618 /*remove the orthogonalisation time series, if one has been supplied*/
1619 if(ort_ts != (MRI_IMAGE *)0)
1620 {
1621 correlate_prep(MRI_FLOAT_PTR(ort_ts), vox_xyz, tdim, sy+xyz, syy+xyz);
1622 correlate(MRI_FLOAT_PTR(ort_ts), vox_xyz, tdim, sx_ort, sxx_ort, sy[xyz], syy[xyz], (double *)0, &slope, &intercept);
1623 orthogonalise(MRI_FLOAT_PTR(ort_ts), vox_xyz, vox_xyz, tdim, slope, intercept);
1624 }
1625 /*correlate*/
1626 correlate_prep(MRI_FLOAT_PTR(ref_ts)+ignore, vox_xyz+ignore, tdim-ignore, sy+xyz, syy+xyz);
1627 correlate(MRI_FLOAT_PTR(ref_ts)+ignore, vox_xyz+ignore, tdim-ignore, sx_ref, sxx_ref, sy[xyz], syy[xyz], &corr, &slope, (double *)0);
1628 /*save regression coefficient*/
1629 fit_coeff[xyz] = slope;
1630 /*retain greatest slope for use in computing scaling factor*/
1631 slope = fabs(slope);
1632 if(slope > *fim_scale)
1633 *fim_scale = slope;
1634 /*save correlation coefficient*/
1635 stree_insert(actual_corr, corr, x, y, z);
1636 /*compute sums for autocorregression computation, if requested*/
1637 if(AR_order)
1638 autocorrelate_sum(vox_xyz+ignore, tdim-ignore, AR_n_incl, AR_order, AR_excl, AR, &AR_var);
1639 }
1640 xyz++;
1641 }
1642 /*if autoregression has been requested, compute autocorrelations from sums...*/
1643 if(AR_order)
1644 autocorrelate_finish(&AR_order, AR_excl, AR, AR_var);
1645 /*...& solve the Yule-Walker equations to derive autoregression coefficients
1646 (note that autocorrelate_finish() may have decreased AR_order, perhaps all
1647 the way to zero, if it has detected unrealistic autocorrelations)*/
1648 if(AR_order)
1649 {
1650 /*write the autocorrelation coefficients to a .1D file*/
1651 write_1D_file(AR, AR_order, DSET_FILECODE(dset), "_autocorrelation");
1652 if(yule_walker(AR, AR_order))
1653 {
1654 /*this never happens*/
1655 fprintf(stderr,
1656 "Cannot compute autoregression; Yule-Walker matrix is singular.\n");
1657 AR_order = 0;
1658 }
1659 else
1660 {
1661 /*write the autoregression coefficients to a .1D file*/
1662 write_1D_file(AR, AR_order, DSET_FILECODE(dset), "_autoregression");
1663 /*apply the Yule-Walker autoregression coefficients to whiten the time
1664 series at each voxel, iterating through the voxels just as in the loop
1665 above*/
1666 AR_ts = (float *)calloc(tdim, sizeof(*AR_ts));
1667 if(AR_ts == (float *)0)
1668 {
1669 fprintf(stderr, "Cannot apply autoregression: out of memory\n");
1670 AR_order = 0;
1671 }
1672 else
1673 {
1674 xyz = 0;
1675 for(z = 0; z != zdim; z++)
1676 for(y = 0; y != ydim; y++)
1677 for(x = 0; x != xdim; x++)
1678 {
1679 if(mask != NULL)
1680 {
1681 /*fetch the mask brick's scaling factor...*/
1682 mask_val = DSET_BRICK_FACTOR(mask, 0);
1683 if(mask_val == 0.0)
1684 mask_val = 1.0;
1685 /*...and multiply it by the mask datum at coordinates (x, y, z)*/
1686 if(DSET_BRICK_TYPE(mask, 0) == MRI_short)
1687 mask_val *= ((short *)DSET_ARRAY(mask, 0))[xyz];
1688 else
1689 mask_val *= ((char *)DSET_ARRAY(mask, 0))[xyz];
1690 }
1691 if((mask_val >= masklo) && (mask_val <= maskhi))
1692 {
1693 vox_xyz = vox + tdim*xyz;
1694 for(t = 0; t != tdim; t++)
1695 {
1696 /*fetch the time series brick's scaling factor...*/
1697 vox_xyz[t] = DSET_BRICK_FACTOR(dset, t);
1698 if(vox_xyz[t] == 0.0)
1699 vox_xyz[t] = 1.0;
1700 /*...and multiply it by the time series datum at (x, y, z, t)*/
1701 vox_xyz[t] *= ((short *)DSET_ARRAY(dset, t))[xyz];
1702 }
1703 /*whiten, and copy the result over the original, coloured data*/
1704 whiten(vox_xyz, AR_ts, tdim, AR, AR_order);
1705 for(t = 0; t != tdim; t++)
1706 vox_xyz[t] = AR_ts[t];
1707 }
1708 xyz++;
1709 }
1710 }
1711 }
1712 }
1713 /*make sure that the mask left us *some* voxels*/
1714 if(stree_null(actual_corr))
1715 {
1716 fprintf(stderr, "PERMTEST: All voxels are masked!\n");
1717 return 1;
1718 }
1719 *fim_scale /= MRI_TYPE_maxval[MRI_short];
1720 /*copy fit coefficients for all voxels, scaled for storage in shorts*/
1721 for(t = 0; t != xdim*ydim*zdim; t++)
1722 (*intensities)[t] = (short)(fit_coeff[t] / *fim_scale);
1723 free(fit_coeff);
1724 randomised_corr = dtree_create(xdim, ydim, NUM_ITERS);
1725 if(randomised_corr == (DTREE *)0)
1726 {
1727 stree_destroy(actual_corr);
1728 free(syy);
1729 free(sy);
1730 free(ts);
1731 free(vox);
1732 free(sequence);
1733 free(tindex);
1734 free(*zvals);
1735 free(*intensities);
1736 return 1;
1737 }
1738 coord_mem = (CLIST *)calloc(NUM_ITERS*num_coords, sizeof(*coord_mem));
1739 if(coord_mem == (CLIST *)0)
1740 {
1741 dtree_destroy(randomised_corr);
1742 stree_destroy(actual_corr);
1743 free(syy);
1744 free(sy);
1745 free(ts);
1746 free(vox);
1747 free(sequence);
1748 free(tindex);
1749 free(*zvals);
1750 free(*intensities);
1751 return 1;
1752 }
1753 coord_next = coord_mem;
1754 /*initialise progress meter*/
1755 prev_percent_done = -1;
1756 PLUTO_popup_meter(plint);
1757
1758 /******************************************************************************
1759 * PHASE 2: Compute the empirical distribution. *
1760 ******************************************************************************/
1761 for(iter = 0; iter != NUM_ITERS; iter++)
1762 {
1763 percent_done = (100*iter)/NUM_ITERS;
1764 if(percent_done > prev_percent_done)
1765 {
1766 prev_percent_done = percent_done;
1767 PLUTO_set_meter(plint, percent_done);
1768 }
1769 shuffle(sequence, tsize);
1770 for(t = 0; t != num_coords; t++)
1771 coord_next[t].corr = 0.0;
1772 xyz = 0;
1773 for(z = 0; z != zdim; z++)
1774 for(y = 0; y != ydim; y++)
1775 for(x = 0; x != xdim; x++)
1776 {
1777 if(mask != NULL)
1778 {
1779 /*fetch the mask brick's scaling factor...*/
1780 mask_val = DSET_BRICK_FACTOR(mask, 0);
1781 if(mask_val == 0.0)
1782 mask_val = 1.0;
1783 /*...and multiply it by the mask datum at coordinates (x, y, z)*/
1784 if(DSET_BRICK_TYPE(mask, 0) == MRI_short)
1785 mask_val *= ((short *)DSET_ARRAY(mask, 0))[xyz];
1786 else
1787 mask_val *= ((char *)DSET_ARRAY(mask, 0))[xyz];
1788 }
1789 if((mask_val >= masklo) && (mask_val <= maskhi))
1790 {
1791 vox_xyz = vox + tdim*xyz;
1792 /*apply the autoregression coefficients to re-colour the permuted
1793 time series before correlating*/
1794 if(AR_order)
1795 {
1796 /*fetch the time series, in the permuted order given by sequence[],
1797 but with ignored and excluded points copied in their original
1798 positions - these are needed in order to fill in the whole array
1799 so that colour() below will have valid data at each time point.*/
1800 for(t = 0; t != ignore; t++)
1801 ts[t] = vox_xyz[t];
1802 for(t2 = 0; t != tdim; t++)
1803 ts[t] = ((MRI_FLOAT_PTR(ref_ts)[t] < BLAST)?
1804 vox_xyz[sequence[t2++]]:
1805 vox_xyz[t]);
1806 /*colour the permuted time series*/
1807 colour(AR_ts, ts, tdim, AR, AR_order);
1808 /*copy the coloured series into the work space*/
1809 for(t = 0; t != tdim; t++)
1810 ts[t] = AR_ts[t];
1811 /*compute new sums for the permuted & re-coloured time series*/
1812 correlate_prep(MRI_FLOAT_PTR(ref_ts)+ignore, ts+ignore, tdim-ignore, sy+xyz, syy+xyz);
1813 }
1814 else
1815 {
1816 /*fetch the time series, in the permuted order given by sequence[]*/
1817 for((t = ignore), (t2 = 0); t != tdim; t++)
1818 if(MRI_FLOAT_PTR(ref_ts)[t] < BLAST)
1819 ts[t] = vox_xyz[sequence[t2++]];
1820 }
1821 correlate(MRI_FLOAT_PTR(ref_ts)+ignore, ts+ignore, tdim-ignore, sx_ref, sxx_ref, sy[xyz], syy[xyz], &corr, (double *)0, (double *)0);
1822 /*Since num_coords is tiny, any sorting algorithm faster
1823 than linear insertion wouldn't be worth the trouble.*/
1824 for(t = 0; t < num_coords; t++)
1825 if((*magnitude)(corr) > (*magnitude)(coord_next[t].corr))
1826 {
1827 t2 = t;
1828 while(++t != num_coords)
1829 {
1830 coord_next[t].corr = coord_next[t-1].corr;
1831 coord_next[t].coords = coord_next[t-1].coords;
1832 }
1833 coord_next[t2].corr = corr;
1834 coord_next[t2].coords = coord_encode(x, y, z, xdim, ydim);
1835 }
1836 }
1837 xyz++;
1838 }
1839 dtree_insert(randomised_corr, coord_next);
1840 if(verbose)
1841 printf("iter=%d max_corr=%f\n", iter, coord_next->corr);
1842 coord_next += num_coords;
1843 }
1844 #ifdef PERMTEST_DEBUG
1845 dtree_traverse(randomised_corr, 0); /*dump distribution to stdout*/
1846 #endif
1847 if(AR_order)
1848 free(AR_ts);
1849 PLUTO_set_meter(plint, 100);
1850
1851 /******************************************************************************
1852 * PHASE 3: Rank correlations from the actual data set within the empirical *
1853 * distribution. *
1854 ******************************************************************************/
1855 do
1856 {
1857 not_done = 0;
1858 /*extract the most significant *correlation* (in [-1,1])*/
1859 max_corr = stree_extract_max(actual_corr, &x, &y, &z);
1860 /*map it to an adjusted *probability* (in [0,1])*/
1861 corr = dtree_position(randomised_corr, max_corr);
1862 if(verbose)
1863 printf("(%2d,%2d,%2d) raw r=%f adjusted p=%f", x, y, z, max_corr, corr);
1864 if(((one_tailed == 0) && (fabs(corr-0.5) >= 0.5-pcrit/2.0))
1865 ||((one_tailed == -1) && (corr <= pcrit))
1866 ||((one_tailed == 1) && (corr >= 1.0-pcrit)))
1867 {
1868 slope = critz(corr);
1869 if(verbose)
1870 printf(" zcrit=%f\n", slope);
1871 (*zvals)[x + xdim*(y + ydim*z)] = (short)(slope*FUNC_ZT_SCALE_SHORT);
1872 not_done = 1;
1873 /******************************************************************************
1874 *percent completion of this phase of the algorithm can be expressed as follows:
1875 * 100.0 * ((one_tailed == 1)? 1.0-corr: *
1876 * ((one_tailed == 0) && (corr > 0.5))? *
1877 * 2.0*(1.0-corr): *
1878 * corr) / pcrit; *
1879 ******************************************************************************/
1880 /*since this point is now defined as activated, exclude its data from the
1881 empirical distribution*/
1882 dtree_delete_coords(randomised_corr, x, y, z, *zvals);
1883 }
1884 } while(not_done && (dtree_size(randomised_corr) > NUM_ITERS/2));
1885 /*^^^ stop if we've deleted too many coordinates ^^^*/
1886 if(verbose)
1887 putchar('\n');
1888 free(coord_mem);
1889 dtree_destroy(randomised_corr);
1890 stree_destroy(actual_corr);
1891 free(syy);
1892 free(sy);
1893 free(ts);
1894 free(vox);
1895 free(sequence);
1896 free(tindex);
1897 return 0;
1898 }
1899
1900 /*In the event of a conflict with some future revision of the AFNI widgets
1901 code, PERMTEST_set_logo() and PERMTEST_reset_logo() can be redefined as null
1902 functions and everything will still work right (though it would be a shame to
1903 lose the free advertising!).*/
1904
1905 static Pixmap sipb_pixmap; /*pixmap of SIPB logo*/
1906
PERMTEST_set_logo(PLUGIN_interface * plint)1907 static void PERMTEST_set_logo(PLUGIN_interface *plint)
1908 {
1909 Pixel bg_pix=0, fg_pix=0; /*colours from control window*/
1910 #define sipb_width 90
1911 #define sipb_height 90
1912 static char sipb_bits[] = { /*bitmap of SIPB logo*/
1913 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x03,
1914 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x03,
1915 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x03,
1916 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x03,
1917 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x03,
1918 0x1f, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0xff, 0x03,
1919 0x1f, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0xf8, 0x03,
1920 0x1f, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0xf0, 0x03,
1921 0x1f, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0xf0, 0x03,
1922 0x3f, 0x00, 0x0c, 0xf0, 0x00, 0x7c, 0x00, 0x7e, 0x00, 0x03, 0xe0, 0x03,
1923 0x7f, 0x00, 0x18, 0xf0, 0x01, 0xfe, 0x00, 0xff, 0x00, 0x0f, 0xe0, 0x03,
1924 0x7f, 0x00, 0x30, 0xf0, 0x01, 0xfe, 0x00, 0xff, 0x00, 0x1f, 0xe0, 0x03,
1925 0xff, 0x00, 0x60, 0xf0, 0x01, 0xfe, 0x00, 0xff, 0x00, 0x1f, 0xe0, 0x03,
1926 0xff, 0x01, 0x60, 0xf0, 0x01, 0xfe, 0x00, 0xff, 0x00, 0x0f, 0xe0, 0x03,
1927 0xff, 0x03, 0xc0, 0xff, 0x01, 0xfe, 0x00, 0xff, 0x00, 0x0f, 0xe0, 0x03,
1928 0xff, 0x07, 0x80, 0xff, 0x01, 0xfe, 0x00, 0xff, 0x00, 0x03, 0xe0, 0x03,
1929 0xff, 0x0f, 0x00, 0xff, 0x01, 0xfe, 0x00, 0xff, 0x00, 0x00, 0xf0, 0x03,
1930 0xff, 0x1f, 0x00, 0xff, 0x01, 0xfe, 0x00, 0xff, 0x00, 0x00, 0xf8, 0x03,
1931 0xff, 0x3f, 0x00, 0xff, 0x01, 0xfe, 0x00, 0xff, 0x00, 0x00, 0xe0, 0x03,
1932 0xff, 0x3f, 0x00, 0xff, 0x01, 0xfe, 0x00, 0xff, 0x00, 0x00, 0xe0, 0x03,
1933 0xff, 0x1f, 0x80, 0xff, 0x01, 0xfe, 0x00, 0xff, 0x00, 0x03, 0xc0, 0x03,
1934 0xff, 0x0f, 0xc0, 0xff, 0x01, 0xfe, 0x00, 0xff, 0x00, 0x0f, 0xc0, 0x03,
1935 0xff, 0x07, 0xe0, 0xff, 0x01, 0xfe, 0x00, 0xff, 0x00, 0x1f, 0xc0, 0x03,
1936 0xff, 0x03, 0x70, 0xf0, 0x01, 0xfe, 0x00, 0xff, 0x00, 0x3f, 0xc0, 0x03,
1937 0xff, 0x01, 0x78, 0xf0, 0x01, 0xfe, 0x00, 0xff, 0x00, 0x3f, 0xc0, 0x03,
1938 0xff, 0x00, 0x3c, 0xf0, 0x01, 0xfe, 0x00, 0xff, 0x00, 0x1f, 0xc0, 0x03,
1939 0x7f, 0x00, 0x00, 0xf0, 0x01, 0xfe, 0x00, 0xff, 0x00, 0x0f, 0xc0, 0x03,
1940 0x3f, 0x00, 0x00, 0xf0, 0x00, 0x7c, 0x00, 0x7e, 0x00, 0x07, 0xc0, 0x03,
1941 0x1f, 0x00, 0x00, 0x30, 0x00, 0x10, 0x00, 0x18, 0x00, 0x00, 0xe0, 0x03,
1942 0x1f, 0x00, 0x00, 0x30, 0x00, 0x10, 0x00, 0x18, 0x00, 0x00, 0xf0, 0x03,
1943 0x1f, 0x00, 0x00, 0x30, 0x00, 0x10, 0x00, 0x18, 0x00, 0x00, 0xf8, 0x03,
1944 0x1f, 0x00, 0x00, 0x30, 0x00, 0x10, 0x00, 0x18, 0x00, 0x00, 0xff, 0x03,
1945 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x03,
1946 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x03,
1947 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x03,
1948 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x03,
1949 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x03,
1950 0xff, 0xff, 0x40, 0xfe, 0x3f, 0x9f, 0x04, 0xfe, 0xff, 0xff, 0xff, 0x03,
1951 0xff, 0xff, 0x73, 0xfe, 0x3f, 0x8e, 0x9c, 0xff, 0xff, 0xff, 0xff, 0x03,
1952 0xff, 0xff, 0x73, 0x38, 0x3e, 0x8e, 0x9c, 0xff, 0xff, 0xff, 0xff, 0x03,
1953 0xff, 0xff, 0x73, 0x92, 0x3c, 0x84, 0x9c, 0xff, 0xff, 0xff, 0xff, 0x03,
1954 0xff, 0xff, 0x73, 0x12, 0x3c, 0x95, 0x9c, 0xff, 0xff, 0xff, 0xff, 0x03,
1955 0xff, 0xff, 0x73, 0x92, 0x3f, 0x91, 0x9c, 0xff, 0xff, 0xff, 0xff, 0x03,
1956 0xff, 0xff, 0x73, 0x92, 0x3c, 0x9b, 0x9c, 0xff, 0xff, 0xff, 0xff, 0x03,
1957 0xff, 0xff, 0x73, 0x32, 0x3e, 0x9b, 0x9c, 0xff, 0xff, 0xff, 0xff, 0x03,
1958 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x03,
1959 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x03,
1960 0xff, 0xff, 0xc3, 0xfc, 0x9f, 0xff, 0xcf, 0xff, 0xff, 0xff, 0xff, 0x03,
1961 0xff, 0xff, 0x99, 0xfc, 0x9f, 0xff, 0xcf, 0xff, 0xff, 0xff, 0xff, 0x03,
1962 0xff, 0xff, 0xf1, 0x48, 0x86, 0xb1, 0x8c, 0xff, 0xff, 0xff, 0xff, 0x03,
1963 0xff, 0xff, 0xc3, 0x4c, 0x92, 0x24, 0xc9, 0xff, 0xff, 0xff, 0xff, 0x03,
1964 0xff, 0xff, 0x8f, 0x4c, 0x9a, 0x20, 0xc9, 0xff, 0xff, 0xff, 0xff, 0x03,
1965 0xff, 0xff, 0x9d, 0x4c, 0x9a, 0x3c, 0xc9, 0xff, 0xff, 0xff, 0xff, 0x03,
1966 0xff, 0xff, 0x99, 0x4c, 0x92, 0x24, 0xc9, 0xff, 0xff, 0xff, 0xff, 0x03,
1967 0xff, 0xff, 0xc3, 0x99, 0x86, 0x31, 0x99, 0xff, 0xff, 0xff, 0xff, 0x03,
1968 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x03,
1969 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x03,
1970 0xff, 0xff, 0xe1, 0x1f, 0xff, 0xff, 0xff, 0x99, 0xff, 0xff, 0xff, 0x03,
1971 0xff, 0xff, 0xf3, 0xcf, 0xff, 0xff, 0xff, 0xf9, 0xff, 0xff, 0xff, 0x03,
1972 0xff, 0xff, 0xb3, 0x8c, 0xb1, 0x48, 0x8e, 0x91, 0xb1, 0xfc, 0xff, 0x03,
1973 0xff, 0xff, 0x33, 0xc9, 0x24, 0x92, 0x34, 0x99, 0x24, 0xf9, 0xff, 0x03,
1974 0xff, 0xff, 0x33, 0xc9, 0x24, 0x93, 0x0c, 0x99, 0x24, 0xf9, 0xff, 0x03,
1975 0xff, 0xff, 0x33, 0xc9, 0x24, 0x93, 0x24, 0x99, 0x24, 0xf9, 0xff, 0x03,
1976 0xff, 0xff, 0x33, 0xc9, 0x24, 0x93, 0x24, 0x99, 0x24, 0xf9, 0xff, 0x03,
1977 0xff, 0xff, 0x21, 0xc9, 0x31, 0x93, 0x4c, 0x92, 0x31, 0xf9, 0xff, 0x03,
1978 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x03,
1979 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x03,
1980 0xff, 0xff, 0xc1, 0xff, 0xff, 0xff, 0xff, 0xf9, 0xff, 0xff, 0xff, 0x03,
1981 0xff, 0xff, 0x99, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x03,
1982 0xff, 0xff, 0x99, 0x12, 0xc7, 0x38, 0x8e, 0x29, 0xa7, 0xff, 0xff, 0x03,
1983 0xff, 0xff, 0x99, 0x48, 0x52, 0x92, 0x24, 0x49, 0x92, 0xff, 0xff, 0x03,
1984 0xff, 0xff, 0xc1, 0x4c, 0x72, 0x30, 0x8e, 0x49, 0x9a, 0xff, 0xff, 0x03,
1985 0xff, 0xff, 0xf9, 0x4c, 0x72, 0xfe, 0x3c, 0x49, 0x9a, 0xff, 0xff, 0x03,
1986 0xff, 0xff, 0xf9, 0x4c, 0x52, 0x92, 0x24, 0x49, 0x92, 0xff, 0xff, 0x03,
1987 0xff, 0xff, 0xf9, 0x1c, 0xc7, 0x38, 0x8e, 0x49, 0x86, 0xff, 0xff, 0x03,
1988 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x9f, 0xff, 0xff, 0x03,
1989 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc7, 0xff, 0xff, 0x03,
1990 0xff, 0xff, 0xc1, 0xff, 0xff, 0xe7, 0xff, 0xff, 0xff, 0xff, 0xff, 0x03,
1991 0xff, 0xff, 0x99, 0xff, 0xff, 0xe7, 0xff, 0xff, 0xff, 0xff, 0xff, 0x03,
1992 0xff, 0xff, 0x99, 0x71, 0x2c, 0xe1, 0xff, 0xff, 0xff, 0xff, 0xff, 0x03,
1993 0xff, 0xff, 0xc1, 0xa4, 0x89, 0xe4, 0xff, 0xff, 0xff, 0xff, 0xff, 0x03,
1994 0xff, 0xff, 0x99, 0x64, 0xc8, 0xe6, 0xff, 0xff, 0xff, 0xff, 0xff, 0x03,
1995 0xff, 0xff, 0x99, 0x24, 0xc9, 0xe6, 0xff, 0xff, 0xff, 0xff, 0xff, 0x03,
1996 0xff, 0xff, 0x99, 0x24, 0xc9, 0xe4, 0xff, 0xff, 0xff, 0xff, 0xff, 0x03,
1997 0xff, 0xff, 0xc1, 0x71, 0xc2, 0xe1, 0xff, 0xff, 0xff, 0xff, 0xff, 0x03,
1998 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x03,
1999 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x03,
2000 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x03,
2001 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x03,
2002 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x03,
2003 };
2004 /*Initialise SIPB logo, in the current controller window only. Leave all
2005 other controller windows with the default MCW logo. (Adapted from
2006 afni_widg:AFNI_make_widgets).*/
2007 XtVaGetValues(plint->im3d->vwid->top_form,
2008 XmNforeground, &bg_pix, /*note reversal of fg & bg colours*/
2009 XmNbackground, &fg_pix, NULL);
2010 sipb_pixmap = XCreatePixmapFromBitmapData(
2011 XtDisplay(plint->im3d->vwid->top_shell),
2012 RootWindowOfScreen(XtScreen(plint->im3d->vwid->top_shell)),
2013 sipb_bits, sipb_width, sipb_height,
2014 fg_pix, bg_pix,
2015 DefaultDepthOfScreen(XtScreen(plint->im3d->vwid->top_shell)));
2016 /*shameless self-aggrandisement (adapted from afni:AFNI_set_cursor)*/
2017 XtVaSetValues(plint->im3d->vwid->picture, XmNlabelPixmap, sipb_pixmap, NULL);
2018 }
2019
PERMTEST_reset_logo(PLUGIN_interface * plint)2020 static void PERMTEST_reset_logo(PLUGIN_interface *plint)
2021 {
2022 XtVaSetValues(plint->im3d->vwid->picture, XmNlabelPixmap, XmUNSPECIFIED_PIXMAP, NULL);
2023 XFreePixmap(XtDisplay(plint->im3d->vwid->top_shell), sipb_pixmap);
2024 }
2025
PERMTEST_main(PLUGIN_interface * plint)2026 char *PERMTEST_main(PLUGIN_interface *plint)
2027 {
2028 int t;
2029 char *prefix;
2030 MRI_IMAGE *ref_time_series, *orthogonal_time_series, *AR_excl_time_series;
2031 THD_3dim_dataset *dset, *mask, *new_dset;
2032 short *intensities, *zvals;
2033 double fim_scale, /*scaling factor for short image data*/
2034 pcrit; /*alpha level*/
2035 char *optiontag; /*one of tails2, tails1pos, tails1neg*/
2036 int one_tailed, /*0, 1, or -1*/
2037 AR_order; /*autoregressive model order*/
2038 float masklo, maskhi; /*bounds on mask dataset*/
2039 static char tails_err[] = "exactly one of two-tailed, one-tailed positive, or one-tailed negative must be chosen";
2040
2041 #ifdef PERMTEST_DEBUG
2042 void (*handler)(int);
2043 #endif
2044
2045 if(plint == (PLUGIN_interface *)0)
2046 return "PERMTEST_main: null input";
2047
2048 /*Make sure that the input dataset exists and is stored in a format that we can
2049 understand (MRI_short)*/
2050 PLUTO_next_option(plint);
2051 dset = PLUTO_find_dset(PLUTO_get_idcode(plint));
2052 if(dset == (THD_3dim_dataset *)0)
2053 return "bad dataset";
2054 for(t = 0; t != dset->dblk->nvals; t++)
2055 /*to do: make copies of this routine that work on MRI_byte and on MRI_float*/
2056 if(DSET_BRICK_TYPE(dset, t) != MRI_short)
2057 return("permutation test on non-short values is not implemented");
2058
2059 /*Make sure that the time series exists and is stored in a format that we can
2060 understand (MRI_float), and contains enough points to cover the time
2061 dimension of the specified dataset*/
2062 PLUTO_next_option(plint);
2063 ref_time_series = PLUTO_get_timeseries(plint);
2064 if((ref_time_series == (MRI_IMAGE *)0)
2065 ||(ref_time_series->kind != MRI_float)
2066 ||(ref_time_series->nx < DSET_NUM_TIMES(dset)))
2067 return("bad time series");
2068
2069 /*Read the orthogonalisation time series, if it exists*/
2070 optiontag = PLUTO_get_optiontag(plint);
2071 if(strcmp(optiontag, ort_label))
2072 orthogonal_time_series = (MRI_IMAGE *)0;
2073 else
2074 {
2075 orthogonal_time_series = PLUTO_get_timeseries(plint);
2076 if((orthogonal_time_series == (MRI_IMAGE *)0)
2077 ||(orthogonal_time_series->kind != MRI_float)
2078 ||(orthogonal_time_series->nx < DSET_NUM_TIMES(dset)))
2079 return("bad ort");
2080 PLUTO_next_option(plint);
2081 }
2082
2083 /*Make sure that the prefix specified for the new dataset is a valid prefix*/
2084 prefix = PLUTO_get_string(plint);
2085 if(!PLUTO_prefix_ok(prefix))
2086 return("bad prefix");
2087
2088 /*Read the alpha level*/
2089 PLUTO_next_option(plint);
2090 pcrit = PLUTO_get_number(plint);
2091
2092 /*Read the autoregressive model order, if autoregression has been specified*/
2093 optiontag = PLUTO_get_optiontag(plint);
2094 if(strcmp(optiontag, AR_order_label))
2095 AR_order = 0;
2096 else
2097 {
2098 AR_order = (int)PLUTO_get_number(plint);
2099 optiontag = PLUTO_get_optiontag(plint);
2100 }
2101
2102 /*Read the autoregression exclusion flags vector, if it exists*/
2103 if(strcmp(optiontag, AR_excl_label))
2104 AR_excl_time_series = (MRI_IMAGE *)0;
2105 else
2106 {
2107 AR_excl_time_series = PLUTO_get_timeseries(plint);
2108 if((AR_excl_time_series == (MRI_IMAGE *)0)
2109 ||(AR_excl_time_series->kind != MRI_float)
2110 ||(AR_excl_time_series->nx < DSET_NUM_TIMES(dset)))
2111 return("bad AR exclusion vector");
2112 optiontag = PLUTO_get_optiontag(plint);
2113 }
2114
2115 /*Exactly one of two-tailed, one-tailed positive, one-tailed negative*/
2116 if(optiontag == (char *)0)
2117 return(tails_err);
2118 if(strcmp(optiontag, tails2))
2119 {
2120 if(strcmp(optiontag, tails1pos))
2121 {
2122 if(strcmp(optiontag, tails1neg))
2123 return(tails_err);
2124 else
2125 one_tailed = -1;
2126 }
2127 else
2128 one_tailed = 1;
2129 }
2130 else
2131 one_tailed = 0;
2132 optiontag = PLUTO_get_optiontag(plint);
2133 if((optiontag != (char *)0) && strcmp(optiontag, mask_label))
2134 return(tails_err);
2135
2136 /*Optional mask dataset*/
2137 masklo = 1.0;
2138 maskhi = 32767.0;
2139 if(optiontag == (char *)0)
2140 mask = (THD_3dim_dataset *)0;
2141 else
2142 {
2143 mask = PLUTO_find_dset(PLUTO_get_idcode(plint));
2144 if(mask == (THD_3dim_dataset *)0)
2145 return("bad mask");
2146 if((DSET_BRICK_TYPE(mask, 0) != MRI_short)
2147 && (DSET_BRICK_TYPE(mask, 0) != MRI_byte))
2148 return("mask brick type must be byte or short integer");
2149 optiontag = PLUTO_get_optiontag(plint);
2150 if(optiontag != (char *)0)
2151 {
2152 if(strcmp(optiontag, masklo_label))
2153 maskhi = PLUTO_get_number(plint);
2154 else
2155 {
2156 masklo = PLUTO_get_number(plint);
2157 if(PLUTO_get_optiontag(plint) != (char *)0)
2158 maskhi = PLUTO_get_number(plint);
2159 }
2160 }
2161 DSET_load(mask);
2162 }
2163
2164 #ifdef PERMTEST_DEBUG
2165 handler = signal(SIGUSR1, flush);
2166 #endif
2167
2168 /*toot our own horn :-)*/
2169 PERMTEST_set_logo(plint);
2170 /*Make sure source dataset is in memory*/
2171 DSET_load(dset);
2172 if(PERMTEST_compute(plint, dset, ref_time_series, orthogonal_time_series, pcrit, one_tailed, &intensities, &zvals, &fim_scale, mask, masklo, maskhi, 0, AR_order, AR_excl_time_series))
2173 {
2174 PERMTEST_reset_logo(plint);
2175 return("out of memory");
2176 }
2177 if(num_coords_exhausted)
2178 printf("%d of %d points (%d%%) were deleted from the distribution due to\nexhausted coordinates. If this fraction is larger than about 10%%, consider\nrecompiling plug_permtest.so with a NUM_COORDS larger than the current value of\n%d.\n", num_coords_exhausted, NUM_ITERS, (100*num_coords_exhausted+NUM_ITERS/2)/NUM_ITERS, NUM_COORDS);
2179
2180 /*create the output dataset*/
2181 new_dset = EDIT_empty_copy(dset);
2182 if(EDIT_dset_items(new_dset,
2183 ADN_prefix, prefix,
2184 ADN_malloc_type, DATABLOCK_MEM_MALLOC, /*hold in r/w memory*/
2185 ADN_datum_all, MRI_short, /*store as (scaled) short ints*/
2186 ADN_nvals, 2, /*2 sub-bricks: intensity + z-score*/
2187 ADN_ntt, 0, /*no time dimension*/
2188 ADN_type, ISHEAD(dset)?
2189 HEAD_FUNC_TYPE: GEN_FUNC_TYPE, /*functional image*/
2190 ADN_func_type, FUNC_ZT_TYPE, /*intensity + z-score*/
2191 ADN_none))
2192 {
2193 PERMTEST_reset_logo(plint);
2194 return("EDIT_dset_items error");
2195 }
2196 EDIT_BRICK_LABEL(new_dset, 0, "Fit Coef");
2197 mri_fix_data_pointer(intensities, DSET_BRICK(new_dset, 0));
2198 EDIT_BRICK_FACTOR(new_dset, 0, (float)fim_scale);
2199 EDIT_BRICK_LABEL(new_dset, 1, "z-score");
2200 EDIT_BRICK_TO_FIZT(new_dset, 1);
2201 mri_fix_data_pointer(zvals, DSET_BRICK(new_dset, 1));
2202 EDIT_BRICK_FACTOR(new_dset, 1, (float)(1.0/FUNC_ZT_SCALE_SHORT));
2203 DSET_overwrite(new_dset);
2204 PLUTO_add_dset(plint, new_dset, DSET_ACTION_MAKE_CURRENT);
2205 #ifdef PERMTEST_DEBUG
2206 signal(SIGUSR1, handler);
2207 #endif
2208 PERMTEST_reset_logo(plint);
2209 return (char *)0;
2210 }
2211
2212
2213 DEFINE_PLUGIN_PROTOTYPE
2214
PLUGIN_init(int ncall)2215 PLUGIN_interface *PLUGIN_init(int ncall)
2216 {
2217 PLUGIN_interface *plint;
2218 if(ncall > 0) return (PLUGIN_interface *)0; /*only one interface*/
2219 CHECK_IF_ALLOWED("PERMUTATIONTEST","Permutation Test") ; /* 30 Sep 2016 */
2220 /*set titles and entry point*/
2221 plint = PLUTO_new_interface("Permutation Test", hint, help, PLUGIN_CALL_VIA_MENU, PERMTEST_main);
2222 PLUTO_add_hint(plint, hint);
2223 /*first line of dialogue box: input dataset*/
2224 PLUTO_add_option(plint, input_label, input_label, TRUE);
2225 PLUTO_add_dataset(plint, "Dataset", ANAT_SPGR_MASK | ANAT_EPI_MASK, 0, DIMEN_4D_MASK | BRICK_SHORT_MASK);
2226 /*second line of dialogue box: input time series*/
2227 PLUTO_add_option(plint, ts_label, ts_label, TRUE);
2228 PLUTO_add_timeseries(plint, "Reference Time Series");
2229 /*third line of dialogue box: time series against which to orthogonalise*/
2230 PLUTO_add_option(plint, ort_label, ort_label, FALSE);
2231 PLUTO_add_timeseries(plint, "Orthogonalisation Time Series");
2232 /*fourth line of dialogue box: output dataset*/
2233 PLUTO_add_option(plint, output_label, output_label, TRUE);
2234 PLUTO_add_string(plint, "Prefix", 0, (char **)0, 19);
2235 /*fifth line of dialogue box: alpha level (range 10^-4..1, default 0.05)*/
2236 PLUTO_add_option(plint, alpha_label, alpha_label, TRUE);
2237 PLUTO_add_number(plint, "alpha level", 1, 10000, 4, 500, 1);
2238 /*sixth line of dialogue box: autoregressive model order*/
2239 PLUTO_add_option(plint, AR_order_label, AR_order_label, FALSE);
2240 PLUTO_add_number(plint, "autoregressive model order", 0, 32, 0, 1, 1);
2241 /*seventh line of dialogue box: autoregression exclusion vector*/
2242 PLUTO_add_option(plint, AR_excl_label, AR_excl_label, FALSE);
2243 PLUTO_add_timeseries(plint, "Autoregression Exclusion Flags");
2244 /*penultimate lines of dialogue box: tail options*/
2245 PLUTO_add_option(plint, tails2, tails2, FALSE);
2246 PLUTO_add_option(plint, tails1pos, tails1pos, FALSE);
2247 PLUTO_add_option(plint, tails1neg, tails1neg, FALSE);
2248 /*last lines of dialogue box: mask dataset and bounds*/
2249 PLUTO_add_option(plint, mask_label, mask_label, FALSE);
2250 PLUTO_add_dataset(plint, "mask dataset", 0, FUNC_FIM_MASK, DIMEN_3D_MASK | BRICK_SHORT_MASK | BRICK_BYTE_MASK);
2251 PLUTO_add_option(plint, masklo_label, masklo_label, FALSE);
2252 PLUTO_add_number(plint, "voxel is masked if >=", 0, 0x7fff, 0, 1, 1);
2253 PLUTO_add_option(plint, maskhi_label, maskhi_label, FALSE);
2254 PLUTO_add_number(plint, "voxel is masked if <=", 0, 0x7fff, 0, 1, 1);
2255 return plint;
2256 }
2257