1 /*****************************************************************************
2 Major portions of this software are copyrighted by the Medical College
3 of Wisconsin, 1998-2003, and are released under the Gnu General Public
4 License, Version 2. See the file README.Copyright for details.
5 ******************************************************************************/
6
7 #ifdef USE_SUNPERF /** for Solaris **/
8 # include <sunperf.h>
9 #endif
10
11 /*---------------------------------------------------------------------------*/
12 /*
13 Program to calculate the deconvolution of a measurement 3D+time dataset
14 with a specified input stimulus time series. This program will also
15 perform multiple linear regression using multiple input stimulus time
16 series. Output consists of an AFNI 'bucket' type dataset containing the
17 least squares estimates of the linear regression coefficients, t-statistics
18 for significance of the coefficients, partial F-statistics for significance
19 of the individual input stimuli, and the F-statistic for significance of
20 the overall regression. Additional output consists of a 3D+time dataset
21 containing the estimated system impulse response function.
22
23 File: 3dDeconvolve.c
24 Author: B. Douglas Ward
25 Date: 02 September 1998
26
27 Mod: Minor corrections involving -fdisp option and get_options.
28 Date: 29 October 1998
29
30 Mod: Restructured matrix calculations to improve execution speed.
31 Date: 16 December 1998
32
33 Mod: Minor correction to -stim_label option.
34 Date: 17 December 1998
35
36 Mod: Allow fitting of baseline alone (i.e., no input stimulus functions
37 are required). Also, removed restriction on length of input time
38 series.
39 Date: 31 December 1998
40
41 Mod: Accept mean square error from full model.
42 Date: 04 January 1999
43
44 Mod: Incorporated THD_extract_series routine.
45 Date: 19 April 1999
46
47 Mod: Change NLast default value.
48 Date: 27 May 1999
49
50 Mod: Added "no data" option.
51 Date: 10 June 1999
52
53 Mod: Add use of the argument list extension routine addto_args
54 to allow the last switch '-@' to get further command line
55 arguments from stdin (RWC)
56 Date: 28 June 1999
57
58 Mod: Added option for matrix calculation of general linear tests.
59 Date: 02 July 1999
60
61 Mod: Increased max. allowed number of input stimulus functions.
62 Date: 24 August 1999
63
64 Mod: Additional statistical output (partial R^2 statistics).
65 Date: 07 September 1999
66
67 Mod: Added changes for incorporating History notes.
68 Date: 09 September 1999
69
70 Mod: Use cubic spline interpolation to time shift the estimated
71 impulse response function, in order to correct for differences
72 in slice acquisition times.
73 Date: 27 October 1999
74
75 Mod: Allow reading of multiple input stimulus functions from a single
76 file by selection of individual columns.
77 Date: 09 November 1999
78
79 Mod: Automatic removal of input stimulus functions which consist of
80 all zeros.
81 Date: 10 November 1999
82
83 Mod: Added options to allow operator more control over amount and
84 contents of output bucket dataset. (-fout, -rout, -tout)
85 Date: 11 November 1999
86
87 Mod: Added option to output the sample variance (MSE) for the
88 full model. (-vout)
89 Date: 12 November 1999
90
91 Mod: Added options for writing the fitted full model time series (-fitts)
92 and the residual error time series (-errts) to 3D+time datasets.
93 Date: 22 November 1999
94
95 Mod: Added option to perform analysis on a single (fMRI) measurement
96 time series instead of a 3D+time dataset (-input1D).
97 Date: 23 November 1999
98
99 Mod: Added test for maximum number of full model parameters.
100 Date: 24 November 1999
101
102 Mod: Added test for minimum IRF length for compatibility with -tshift
103 option. Also, added necessary duplicate initialization of total
104 number of parameters in the full model.
105 Date: 29 November 1999
106
107 Mod: Increased maximum number of GLT matrices and linear constraints.
108 Date: 03 January 2000
109
110 Mod: Added -mask option to speed up processing by performing calculations
111 on brain voxels only.
112 Date: 11 January 2000
113
114 Mod: Modified matrix_file_read to use mri_read_ascii routine.
115 Date: 12 January 2000
116
117 Mod: Added test for missing stim function time series file name.
118 Date: 08 May 2000
119
120 Mod: Added -censor1D option to allow operator to eliminate individual
121 time points from the analysis.
122 Date: 21 June 2000
123
124 Mod: Added screen display of p-values.
125 Date: 22 June 2000
126
127 Mod: Added -xout option for writing the X design matrix as well as
128 the (X'X) inverse matrix to the screen.
129 Date: 22 June 2000
130
131 Mod: Added -glt_label option for labeling the GLT matrix.
132 Date: 23 June 2000
133
134 Mod: Added -concat option for analysis of a concatenated 3D+time dataset.
135 Date: 26 June 2000
136
137 Mod: Increased max. allowed number of input stimulus functions, GLTs,
138 and linear constraints per GLT. Also, increased size of screen
139 output buffer.
140 Date: 27 July 2000
141
142 Mod: Additional output with -nodata option (norm.std.dev.'s for
143 GLT linear constraints).
144 Date: 11 August 2000
145
146 Mod: Added -nocout option, to suppress the fit coefficient output.
147 Date: 08 September 2000
148
149 Mod: Added -stim_nptr option, to allow input stim functions which are
150 sampled at a multiple of the 1/TR rate.
151 Date: 03 January 2001
152
153 Mod: Added error message if user requests bucket dataset output with
154 no sub-bricks.
155 Date: 10 January 2001
156
157 Mod: Set slice offset times to 0 if -tshift option is used.
158 Date: 11 January 2001
159
160 Mod: Increased max. number of input stimulus time series.
161 Date: 19 March 2001
162
163 Mod: Extended -iresp, -sresp, -fitts, and -errts output options
164 to work with -input1D input option.
165 Date: 03 May 2001
166
167 Mod: Changes to eliminate constraints on number of stimulus time series,
168 number of regressors, number of GLTs, and number of GLT linear
169 constraints. Added -num_glt option.
170 Date: 10 May 2001
171
172 Mod: Changes to reduce the volume memory allocation requirements; i.e.,
173 a better match between what is saved and what is needed for output.
174 Date: 14 May 2001
175
176 Mod: Removed automatic override of -nfirst option.
177 Date: 08 June 2001
178
179 Mod: Added -progress option to print periodic progress reports.
180 Date: 14 June 2001
181
182 Mod: Minor changes to input error checking routine.
183 Date: 06 July 2001
184
185 Mod: Added call to AFNI_logger.
186 Date: 15 August 2001
187
188 Mod: Corrected error in the baseline t-stat output.
189 Date: 26 September 2001
190
191 Mod: Extended -bucket output option to work with -input1D input option.
192 Date: 16 Oct 2001
193
194 Mod: Changed initialization of nt from -nlast input option. This
195 required major changes in read_input_data routine. Also, added
196 protection against invalid -concat inputs in check_for_valid_inputs
197 routine.
198 Date: 23 January 2002
199
200 Mod: Enhanced screen output: Display of p-values for individual stim
201 function regression coefficients. Display of t-stats and p-values
202 for individual linear constraints within a GLT.
203 Date: 29 January 2002
204
205 Mod: Modified input routines to use THD_makemask.
206 Date: 29 January 2002
207
208 Mod: Extended -tout option to write a t-statistic sub-brick for each
209 of the GLT linear combinations (i.e., each row of each GLT matrix).
210 Date: 08 February 2002
211
212 Mod: Allow user to specify no baseline parameters in the model with
213 command "-polort -1".
214 Date: 26 February 2002
215
216 Mod: Added -nobout option, to suppress the bucket dataset output
217 of baseline parameters and statistics.
218 Date: 27 February 2002
219
220 Mod: Allow user to specify which input stimulus functions are part of
221 the baseline model.
222 Date: 02 May 2002
223
224 Mod: Corrected problem in allocate_memory routine, which would result in
225 memory error if both -stim_base and -nobout options are used
226 simultaneously.
227 Date: 10 October 2002
228
229 Mod: Increased size of screen output buffer (again).
230 Date: 02 December 2002
231
232 Mod: Added "multi-get" feature with USE_GET macro -- RWCox.
233 Date: 27 Feb 2003
234
235 Mod: If FLOATIZE is defined, uses floats instead of doubles -- RWCox.
236 Date: 03 Mar 2003 (triple trinity day)
237
238 Mod: Added -quiet option to suppress initial screen output.
239 Date: 12 March 2003
240
241 Mod: Changes to allow -jobs option to run multiple processes.
242 Date: 04 May 2003 -- RWCox
243
244 Mod: Suppress final timing output without -jobs option.
245 Date: 15 August 2003 -- rickr
246
247 Mod: In check_for_valid_inputs(), instead of failing when a stim_length
248 is too short, zeropad the time series. To turn this off, look
249 for the ALLOW_EXTEND macro in this code.
250 Date 22 Oct 2003 -- RWCox
251
252 Mod: Various checks for bad matrix input:
253 * duplicate -stim_file input filenames
254 * collinear column pairs, and all zero columnns
255 * matrix condition numbers
256 Also - disable 3dDeconvolve_f (FLOATIZE)
257 Date: 14 Jul 2004 - RWCox
258
259 Mod: Added -legendre, -nolegendre, -nocond options
260 Date 15 Jul 2004 - RWCox
261
262 Mod: Replace matrix inversion by Gaussian elimination by SVD, and
263 add -svd and -nosvd options.
264 Date 20 Jul 2004 - RWCox
265
266 Mod: If SVD is on, don't eliminate all-zero stim files.
267 Also, add -xjpeg option.
268 Date 21 Jul 2004 - RWCox
269
270 Mod: -xsave and -xrestore options, to be able to run extra GLTs
271 Date 28 Jul 2004 - RWCox
272
273 Mod: -gltsym option
274 Date 29 Jul 2004 - RWCox
275
276 Mod: Multiple files (auto-tcat) for -input
277 Date 05 Aug 2004
278 */
279
280 /*---------------------------------------------------------------------------*/
281
282 #ifndef FLOATIZE
283 # define PROGRAM_NAME "3dDeconvolve" /* name of this program */
284 #else
285 # define PROGRAM_NAME "3dDeconvolve_f" /* name of this program */
286 #endif
287
288 #define PROGRAM_AUTHOR "B. Douglas Ward, et al." /* program author */
289 #define PROGRAM_INITIAL "02 September 1998" /* initial program release date*/
290 #define PROGRAM_LATEST "04 March 2005 - RWCox" /* latest program revision date*/
291
292 /*---------------------------------------------------------------------------*/
293
294 #define RA_error DC_error
295
296 #define USE_GET /* RWCox: extract multiple timeseries at once for speed */
297
298 /*---------------------------------------------------------------------------*/
299 /* Decide on the inclusion of mri_matrix.h before including mri_lib.h
300 The latter now ends up including mri_matrix.h in a roundabout way
301 via suma_utils.h ZSS Nov. 21 2014 */
302 #ifndef FLOATIZE
303 # include "matrix.h" /* double precision */
304 # define MTYPE double
305 # define NI_MTYPE NI_DOUBLE
306 # define QEPS 1.e-6
307 # define MPAIR double_pair
308 #else
309 # include "matrix_f.h" /* single precision */
310 # define MTYPE float
311 # define NI_MTYPE NI_FLOAT
312 # define QEPS 1.e-4
313 # define MPAIR float_pair
314 #endif
315
316 #include "mrilib.h" /* Keep after decision about matrix.h inclusion
317 ZSS Nov. 21 2014*/
318 #include "coxplot.h"
319
320 #ifdef isfinite
321 # define IS_GOOD_FLOAT(x) isfinite(x)
322 #else
323 # define IS_GOOD_FLOAT(x) finite(x)
324 # define isfinite finite
325 #endif
326
327 /* 01 Feb 2011 -- minor adjustments */
328
329 #define myceil(x) ceil((x)-0.00005)
330 #define myfloor(x) floor((x)+0.00005)
331
332 /*---------------------------------------------------------------------------*/
333 /*--------- Global variables for multiple process execution - RWCox. --------*/
334 /*--------- All names start with "proc_", so search for that string. --------*/
335
336 #if !defined(DONT_USE_SHM) && !defined(DONT_USE_FORK) && !defined(CYGWIN)
337
338 # include "thd_iochan.h" /* prototypes for shm stuff */
339
340 # define PROC_MAX 32 /* max num processes */
341
342 static int proc_numjob = 1 ; /* num processes */
343 static pid_t proc_pid[PROC_MAX] ; /* IDs of processes */
344 static int proc_shmid = 0 ; /* shared memory ID */
345 static char *proc_shmptr = NULL; /* pointer to shared memory */
346 static long long proc_shmsize = 0 ; /* total size of shared memory */
347
348 static int proc_shm_arnum = 0 ; /* num arrays in shared memory */
349 static float ***proc_shm_ar = NULL; /* *proc_shm_ar[i] = ptr to array #i */
350 static int *proc_shm_arsiz = NULL; /* proc_shm_arsiz[i] = floats in #i */
351
352 static int proc_vox_bot[PROC_MAX] ; /* 1st voxel to use in each process */
353 static int proc_vox_top[PROC_MAX] ; /* last voxel (+1) in each process */
354
355 static int proc_ind ; /* index of THIS job */
356
357 static int virtu_mrv = 0 ; /* use a virtual vectim? [26 Dec 2012] */
358 static char *fname_mrv = NULL;
359 static MRI_vectim *inset_mrv = NULL;
360
361 #else /* can't use multiple processes */
362
363 # define proc_numjob 1 /* flag that only 1 process is in use */
364 # define proc_ind 0 /* index of THIS job */
365
366 # define virtu_mrv 0 /* 26 Dec 2012 */
367 # define fname_mrv NULL
368 # define inset_mrv NULL
369
370 #endif
371
372 static int proc_use_jobs = 0 ; /* jobs opt given - 2003.08.15[rickr] */
373
374 /*---------------------------------------------------------------------------*/
375
376
377 #define MEM_MESSAGE \
378 do{ long long val = MCW_MALLOC_total ; \
379 if( val > 0 ) \
380 INFO_message("current memory malloc-ated = %s bytes (about %s)" , \
381 commaized_integer_string(val) , \
382 approximate_number_string((double)val) ) ; \
383 } while(0)
384
385 static int aa_len_AA ;
386 #undef ALEN
387 #define ALEN(na) (aa_len_AA=strlen(argv[na])+16 , MAX(aa_len_AA,THD_MAX_NAME))
388
389 /*------------ prototypes for routines far below (RWCox) ------------------*/
390
391 void JPEG_matrix_gray( matrix X, char *fname ); /* save X matrix to JPEG */
392 void ONED_matrix_save( matrix X, char *fname, /* save X matrix to .1D */
393 void *,int,int *, matrix *Xf ,
394 int nbl, int *bl, void *gst, void *sst ) ;
395
396 void XSAVE_output( char * ) ; /* save X matrix into file */
397
398 static int check_matrix_condition( matrix xdata, char *xname ); /* 07 Mar 2007 */
399
400 static int xsave=0 ; /* globals for -xsave */
401 static int nGoodList=0 , *GoodList=NULL ;
402 static int nParam=0 , *ParamIndex=NULL , *ParamStim=NULL ;
403 static char **ParamLabel=NULL ;
404 static char *InputFilename=NULL, *BucketFilename=NULL, *CoefFilename=NULL ;
405
406 static matrix X , XtXinv , XtXinvXt ; /* global copies */
407
408 static int *Xcol_inbase ;
409 static float *Xcol_mean ;
410 static int voxel_num ;
411 static float *voxel_base = NULL ;
412
413 static int dofsub=0 ;
414
415 float baseline_mean( vector coef ) ; /* compute mean of baseline stuff */
416
417 static int xrestore = 0 ; /* globals for -xrestore */
418 static char *xrestore_filename = NULL ;
419 static int NumTimePoints=0 , NumRegressors=0 ;
420
421 static int verb = 1 ;
422 static char *commandline = NULL ;
423
424 static int goforit = 0 ; /* 07 Mar 2007 */
425 static int badlev = 0 ;
426 static int floatout= 1 ; /* 13 Mar 2007 ; 15 Jul 2010: now defaults on */
427
428 static int dont_do_satcheck = 1 ; /* 23 Dec 2011 */
429
430 /* include other dset types for float output 2 Apr 2009 [rickr] */
431 #define CHECK_NEEDS_FLOATS(fn) \
432 do{ if( !floatout && \
433 ( strstr((fn),".nii") || strstr((fn),".niml.dset") || \
434 strstr((fn),".gii") ) ){ \
435 WARNING_message( \
436 "output prefix is '%s' ==> forcing '-float'" , (fn)) ; \
437 floatout = 2 ; \
438 }} while(0)
439
440 static int allzero_OK = 0 ; /* 30 May 2007 */
441
442 struct DC_options ; /* incomplete struct definition */
443
444 void do_xrestore_stuff( int, char **, struct DC_options * ) ;
445
446 #define XSAVE_version "0.5"
447
448 static int nSymStim = 0 ; /* 29 Jul 2004: symbols for stimuli */
449 static SYM_irange *SymStim = NULL ;
450
451 void read_glt_matrix( char *fname, int *nrows, int ncol, matrix *cmat ) ;
452 static void vstep_print(void) ;
453
454 static int show_singvals = 0 ;
455
456 static int num_CENSOR = 0 ; /* 01 Mar 2007 */
457 static int_triple *abc_CENSOR = NULL ;
458
459 static int do_FDR = 1 ; /* 23 Jan 2008 */
460
461 static byte *gmask = NULL ; /* 03 Feb 2009 -- global mask array */
462
463 static bytevec *statmask = NULL ; /* 15 Jul 2010 -- ditto */
464 static char *statmask_name = NULL ;
465
466 /** for -stim_times_FSL [15 Nov 2013] **/
467
468 MRI_IMAGE * convert_FSL_to_fvect( MRI_IMAGE *fslim , int do_amp1 ) ;
469
470 /*---------- Typedefs for basis function expansions of the IRF ----------*/
471
472 #include "parser.h" /* for EXPR, et cetera */
473
474 /***** Search for 'basis_' to find all stuff related to this *****/
475
476 #define USE_BASIS /*** for Deconvolve.c ***/
477
478 /*! One basis function f(t,a,b,c). */
479
480 typedef struct {
481 float a , b , c ; /* up to 3 parameters */
482 float ffac ; /* scale factor [28 Apr 2005] */
483 void *q ; /* other parameters? */
484 float (*f)(float,float,float,float,void *) ; /* function: f(t,a,b,c,q) */
485 } basis_func ;
486
487 /*! Macro to evaluate a basis_func at a particular point. */
488
489 #define basis_funceval(bf,x) ((bf).f( (x), (bf).a,(bf).b,(bf).c,(bf).q )*(bf).ffac)
490
491 /*! Macro to change the parameters in a basis_func structure **/
492
493 #define basis_func_setparn(bf,nn,pv) \
494 do{ if( (nn) <= 0 ) (bf).a = (pv) ; \
495 else if( (nn) == 1 ) (bf).b = (pv) ; \
496 else (bf).c = (pv) ; } while(0)
497
498 /** Macros to define the meaning of the IRF times [08 Mar 2007] ('type') **/
499
500 #define BASIS_SINGLE 1 /* same IRF for all times */
501 #define BASIS_MODULATED_MONO 2 /* amplitude modulated IRF */
502 #define BASIS_MODULATED_PAIR 3 /* mean and delta amplitude modulated IRF */
503 #define BASIS_MODULATED_INDV 9 /* each stim gets own basis func [16 Jul 2007] */
504
505 #define BASIS_MAX_VDIM 21 /* max number dimens in -stim_times_AM2 */
506 #define BASIS_MAX_VFUN 3 /* max number of nonlinear parameters */
507
508 #define BASIS_MIN_DURATION 0.1f /* min stimulus duration in seconds */
509 #define BASIS_MAX_DURATION 999.0f /* max stimulus duration in seconds */
510
511 static float stime_sub = 0.0f ; /* 24 Mar 2009: stimulus time subtractor */
512 static float stime_fac = 1.0f ; /* stimulus time scale fac */
513
514 /*! A whole set of basis functions (generated by -stim_times 3rd argument). */
515
516 typedef struct {
517 int type , nfunc , nparm , pbot , timetype , vfun,vmod,vdim , no_iresp ;
518 float tbot,ttop ;
519 basis_func *bfunc ;
520 char *name , *symfun , *option ;
521 float *modsub ; /* 12 Jul 2012: modulation subtractors */
522 } basis_expansion ;
523
524 /** Extra baseline orts **/
525
526 static MRI_IMARR *ortar = NULL ; /* 02 Dec 2011 */
527
528 /** Prototypes for some basis expansion functions appearing (much) later. **/
529
530 basis_expansion * basis_parser( char *sym ) ;
531 float basis_evaluation( basis_expansion *be , float *wt , float x ) ;
532 void basis_write_iresp( int argc , char *argv[] ,
533 struct DC_options *option_data ,
534 basis_expansion *be , float dt ,
535 float **wtar , char *output_filename ) ;
536 void basis_write_iresp_1D( int argc , char *argv[] ,
537 struct DC_options *option_data ,
538 basis_expansion *be , float dt ,
539 float **wtar , char *output_filename ) ;
540 void basis_write_sresp( int argc , char *argv[] ,
541 struct DC_options *option_data ,
542 basis_expansion *be , float dt ,
543 float *mse ,
544 int pbot, matrix cvar, char *output_filename ) ;
545 void basis_write_sresp_1D( int argc , char *argv[] ,
546 struct DC_options *option_data ,
547 basis_expansion *be , float dt ,
548 float *mse ,
549 int pbot, matrix cvar, char *output_filename ) ;
550
551 /** global variables for stimulus basis expansions **/
552
553 static basis_expansion **basis_stim = NULL ; /* equations for response model */
554 static MRI_IMAGE **basis_times = NULL ; /* times for each response */
555 static MRI_IMAGE **basis_vect = NULL ; /* vectors generated from above */
556 static int basis_nstim = 0 ; /* number of basis_stim entries */
557 static int basis_nused = 0 ; /* number that are not NULL */
558 static float basis_TR = 1.0f ; /* data time step in seconds */
559 static int basis_count = 0 ; /* any -stim_times inputs? */
560 static float basis_dtout = 0.0f ; /* IRF time step in seconds */
561 static float irc_dt = 0.0f ;
562
563 static int basis_need_mse = 0 ; /* need MSE volume */
564
565 static float basis_normall = 0.0f ; /* 28 Apr 2005 */
566
567 #define GUESS_TIMES 0
568 #define GLOBAL_TIMES 1
569 #define LOCAL_TIMES 2
570 static int basis_timetype = GUESS_TIMES ; /* 16 Nov 2007 */
571
572 #define basis_filler 3.e+33 /* filler in basis_times for missing entries */
573 #define big_time 1.e+9 /* a very long time (31+ years) */
574
575 /*...........................................................................*/
576
577 typedef struct { /** structure to hold one -IRC_times stuff **/
578 int npar , pbot ;
579 float *ww ; /* [npar] */
580 float scale_fac ; /* fixed multiplier */
581 int denom_flag ; /* what to put in denominator? */
582 char *name ;
583 } basis_irc ;
584
585 #if 0
586 typedef struct { float a,b ; } float_pair ; /* moved to mrilib.h */
587 #endif
588
589 #define denom_BASELINE (1)
590
591 static int num_irc = 0 ; /* number of IRCs */
592 static basis_irc **irc = NULL ; /* array of IRCs */
593
594 float_pair evaluate_irc( basis_irc *birc , vector coef ,
595 float base , float mse , matrix cvar ) ;
596
597 /*---------------------------------------------------------------------------*/
598
599 #define CM_BASELINE_MASK (1<<0)
600 #define CM_POLORT_MASK (1<<1)
601
602 typedef struct {
603 unsigned int mask ; /* binary properties of column */
604 int group ; /* -1=polort 0=other baseline, larger=stimulus */
605 char name[64] ; /* string describing this column */
606 } column_metadata ;
607
608 static int ncoldat = 0 ;
609 static column_metadata *coldat = NULL ; /* global info about matrix columns */
610
611 static char index_prefix = '#' ; /* 11 Jun 2019 */
612
613 #define COLUMN_LABEL(n) ( ( (n) < ncoldat ) ? coldat[n].name : "unknown" )
614
615 #undef USE_OLD_LABELS
616
617 #define FIX_CONFLICTS /* 23 Mar 2007 */
618
619 /*---------------------------------------------------------------------------*/
620 /* 31 July 2008: stuff to store all GLT and stim label/column correspondence */
621
622 typedef struct {
623 int glt_num ;
624 char **glt_lab ;
625 matrix *glt_mat ;
626 } glt_stuff ;
627
628 typedef struct {
629 int nstim ;
630 int *cbot , *ctop ;
631 char **label ;
632 } stimlabel_stuff ;
633
634 static glt_stuff *GLT_stuff = NULL ;
635 static stimlabel_stuff *STIMLABEL_stuff = NULL ;
636
637 /*---------------------------------------------------------------------------*/
638
639 #include "Deconvolve.c"
640
641 /*---------------------------------------------------------------------------*/
642
643 typedef struct DC_options
644 {
645 int nxyz; /* number of voxels in the input dataset */
646 int nt; /* number of input 3D+time dataset time points */
647 int NFirst; /* first image from input 3D+time dataset to use */
648 int NLast; /* last image from input 3D+time dataset to use */
649 int N; /* number of usable data points from input data */
650 int polort; /* degree of polynomial for baseline model */
651 float rms_min; /* minimum rms error to reject reduced model */
652 int quiet; /* flag to suppress screen output */
653 int progress; /* print periodic progress reports */
654 float fdisp; /* minimum f-statistic for display */
655 char * input_filename; /* input 3D+time dataset */
656 char * mask_filename; /* input mask dataset */
657 char * input1D_filename; /* input fMRI measurement time series */
658 float input1D_TR; /* TR for input 1D time series */
659 float force_TR; /* force use of this TR for 3D time series */
660 char * censor_filename; /* input censor time series filename */
661 char * concat_filename; /* filename for list of concatenated runs */
662 int nodata; /* flag for 'no data' option */
663 int p; /* number of parameters in the full model */
664 int q; /* number of parameters in the baseline model */
665 int qp; /* number of polynomial trend parameters
666 in the baseline model Note: qp <= q <= p */
667 int nbricks; /* number of sub-bricks in bucket dataset output */
668
669 int num_stimts; /* number of stimulus time series */
670 char ** stim_filename; /* input stimulus time series */
671 char ** stim_label; /* label for stimulus time series */
672 int * stim_base; /* flag for stim fn. is part of baseline model */
673 int * stim_minlag; /* min. time lag for impulse response */
674 int * stim_maxlag; /* max. time lag for impulse response */
675 int * stim_nptr; /* number of stim fn. points per TR */
676 int * slice_base ; /* number of columns in a -slice_base file */
677 int num_slice_base ; /* number of -slice_base inputs */
678
679 int num_glt; /* number of general linear tests */
680 int * glt_rows; /* number of linear constraints in glt */
681 char ** glt_filename; /* file containing glt matrix */
682 char ** glt_label; /* label for general linear tests */
683
684 char * bucket_filename; /* bucket dataset file name */
685 char ** iresp_filename; /* impulse response 3D+time output */
686 char ** sresp_filename; /* std. dev. 3D+time output */
687 char * fitts_filename; /* fitted time series 3D+time output */
688 char * errts_filename; /* error time series 3D+time output */
689 int nobucket ; /* don't output a -bucket file! */
690
691 int tshift; /* flag to time shift the impulse response */
692 int fout; /* flag to output F-statistics */
693 int do_fullf ; /* flag to do full F, even if fout==0 */
694 int rout; /* flag to output R^2 statistics */
695 int tout; /* flag to output t-statistics */
696 int vout; /* flag to output variance map */
697 int nobout; /* flag to suppress output of baseline coefficients */
698 int nocout; /* flag to suppress output of fit coefficients */
699 int xout; /* flag to write X and inv(X'X) matrices to screen */
700 int full_first; /* flag to output full model stats first */
701
702 int nocond ; /* flag to disable condition numbering [15 Jul 2004] */
703
704 char *xjpeg_filename; /* plot file for -xjpeg option [21 Jul 2004] */
705 char *x1D_filename; /* save filename for -x1D option [28 Mar 2006] */
706 int nox1D ; /* 20 Mar 2007 */
707 char *x1D_unc ; /* 25 Jun 2007 - uncensored matrix */
708 char *x1D_regcen ; /* 16 Aug 2019 - censoring via regression */
709 int x1D_stop ; /* 28 Jun 2007 */
710
711 int automask ; /* flag to do automasking [15 Apr 2005] */
712
713 int nodata_NT ; /* optional values after -nodata [27 Apr 2005] */
714 float nodata_TR ;
715
716 int tcat_noblock ; /* 06 Jan 2011 */
717
718 column_metadata *coldat ; /* info about each column [06 Mar 2007] */
719 } DC_options;
720
721
722 /*---------------------------------------------------------------------------*/
723 /*
724 Print error message and stop.
725 */
726
727 #if 1
DC_error(char * message)728 void DC_error (char * message)
729 {
730 ERROR_exit( PROGRAM_NAME " dies: %s",message) ;
731 }
732 #else
733 # define DC_error(m) ERROR_exit("3dDeconvolve dies: %s",(m))
734 #endif
735
736 /*---------------------------------------------------------------------------*/
737
identify_software()738 void identify_software ()
739 {
740
741 /*----- Identify software -----*/
742 #if 1
743 PRINT_VERSION(PROGRAM_NAME) ; AUTHOR(PROGRAM_AUTHOR) ;
744 THD_check_AFNI_version(PROGRAM_NAME) ;
745 #else
746 printf ("\n\n");
747 printf ("Program: %s \n", PROGRAM_NAME);
748 printf ("Author: %s \n", PROGRAM_AUTHOR);
749 printf ("Initial Release: %s \n", PROGRAM_INITIAL);
750 printf ("Latest Revision: %s \n", PROGRAM_LATEST);
751 #endif
752
753 #ifdef USE_ACCELERATE
754 INFO_message ("Compiled with vector acceleration for Mac OS X\n") ;
755 #elif defined(USE_SUNPERF) && !defined(FLOATIZE)
756 INFO_message ("Compiled with BLAS-1 acceleration for Solaris\n") ;
757 #elif defined(USE_SCSLBLAS)
758 INFO_message ("Compiled with BLAS-1 acceleration for SGI Altix\n") ;
759 #endif
760 }
761
762 /*---------------------------------------------------------------------------*/
763 /*
764 Routine to display 3dDeconvolve help menu.
765 */
766
display_help_menu(int detail)767 void display_help_menu(int detail)
768 {
769 identify_software();
770
771 printf ("\n"
772 "------------------------------------------------------------------------\n"
773 "----- DESCRIPTION and PROLEGOMENON -----\n"
774 "------------------------------------------------------------------------\n"
775 "Program to calculate the deconvolution of a measurement 3D+time dataset \n"
776 "with a specified input stimulus time series. This program can also \n"
777 "perform multiple linear regression using multiple input stimulus time \n"
778 "series. Output consists of an AFNI 'bucket' type dataset containing \n"
779 "(for each voxel) \n"
780 " * the least squares estimates of the linear regression coefficients \n"
781 " * t-statistics for significance of the coefficients \n"
782 " * partial F-statistics for significance of individual input stimuli \n"
783 " * the F-statistic for significance of the overall regression model \n"
784 "The program can optionally output extra datasets containing \n"
785 " * the estimated impulse response function \n"
786 " * the fitted model and error (residual) time series \n"
787 "------------------------------------------------------------------------\n"
788 "* Program 3dDeconvolve does Ordinary Least Squares (OLSQ) regression. \n"
789 "* Program 3dREMLfit can be used to do Generalized Least Squares (GLSQ) \n"
790 " regression (AKA 'pre-whitened' least squares) combined with REML \n"
791 " estimation of an ARMA(1,1) temporal correlation structure: \n"
792 " https://afni.nimh.nih.gov/pub/dist/doc/program_help/3dREMLfit.html \n"
793 "* The input to 3dREMLfit is the .xmat.1D matrix file output by \n"
794 " 3dDeconvolve, which also writes a 3dREMLfit command line to a file \n"
795 " to make it relatively easy to use the latter program. \n"
796 "* 3dREMLfit also allows for voxel-specific regressors, unlike \n"
797 " 3dDeconvolve. This feature is used with the '-fanaticor' option \n"
798 " to afni_proc.py, for example. \n"
799 "* Nonlinear time series model fitting can be done with program 3dNLfim: \n"
800 " https://afni.nimh.nih.gov/pub/dist/doc/program_help/3dNLfim.html \n"
801 "* Preprocessing of the time series input can be done with various AFNI \n"
802 " programs, or with the 'uber-script' afni_proc.py: \n"
803 " https://afni.nimh.nih.gov/pub/dist/doc/program_help/afni_proc.py.html\n"
804 "------------------------------------------------------------------------\n"
805 "------------------------------------------------------------------------\n"
806 "**** The recommended way to use 3dDeconvolve is via afni_proc.py, ****\n"
807 "**** which will pre-process the data, and also provide some useful ****\n"
808 "**** diagnostic tools/outputs for assessing the data's quality. ****\n"
809 "**** It can also run 3dREMLfit for you 'at no extra charge'. ****\n"
810 "**** [However, it will not wax your car or wash your windows.] ****\n"
811 "------------------------------------------------------------------------\n"
812 "------------------------------------------------------------------------\n"
813 "Consider the time series model Z(t) = K(t)*S(t) + baseline + noise, \n"
814 "where Z(t) = data \n"
815 " K(t) = kernel (e.g., hemodynamic response function or HRF) \n"
816 " S(t) = stimulus time series \n"
817 " baseline = constant, drift, etc. [regressors of no interest] \n"
818 " and * = convolution \n"
819 "Then 3dDeconvolve solves for K(t) given S(t). If you want to process \n"
820 "the reverse problem and solve for S(t) given the kernel K(t), use the \n"
821 "program 3dTfitter with the '-FALTUNG' option. The difference between \n"
822 "the two cases is that K(t) is presumed to be causal and have limited \n"
823 "support, whereas S(t) is a full-length time series. Note that program \n"
824 "3dTfitter does not have all the capabilities of 3dDeconvolve for \n"
825 "calculating output statistics; on the other hand, 3dTfitter can solve \n"
826 "a deconvolution problem (in either direction) with L1 or L2 regression, \n"
827 "and with sign constraints on the computed values (e.g., requiring that \n"
828 "the output S(t) or K(t) be non-negative): \n"
829 " https://afni.nimh.nih.gov/pub/dist/doc/program_help/3dTfitter.html \n"
830 "------------------------------------------------------------------------\n"
831 "The 'baseline model' in 3dDeconvolve (and 3dREMLfit) does not mean just \n"
832 "a constant (mean) level of the signal, or even just the slow drifts that\n"
833 "happen in FMRI time series. 'Baseline' here also means the model that \n"
834 "forms the null hypothesis. The Full_Fstat result is the F-statistic \n"
835 "of the full model (all regressors) vs. the baseline model. Thus, it \n"
836 "it common to include irregular time series, such as estimated motion \n"
837 "parameters, in the baseline model via the -stim_file/-stim_base options,\n"
838 "or by using the -ortvec option (to include multiple regressors at once).\n"
839 "Thus, the 'baseline model' is really the 'null hypothesis model'. \n"
840 "------------------------------------------------------------------------\n"
841 "It is VERY important to realize that statistics (F, t, R^2) computed in \n"
842 "3dDeconvolve are MARGINAL (or partial) statistics. For example, the \n"
843 "t-statistic for a single beta coefficient measures the significance of \n"
844 "that beta value against the regression model where ONLY that one column \n"
845 "of the matrix is removed; that is, the null hypothesis for that \n"
846 "t-statistic is the full regression model minus just that single \n"
847 "regressor. Similarly, the F-statistic for a set of regressors measures \n"
848 "the significance of that set of regressors (eg, a set of TENT functions)\n"
849 "against the full model with just that set of regressors removed. If \n"
850 "this explanation or its consequences are unclear, you need to consult \n"
851 "with a statistician, or with the AFNI message board guru entities \n"
852 "(when they can be lured down from the peak of Mt Taniquetil or Kailash).\n"
853 "------------------------------------------------------------------------\n"
854 "Regression Programs in the AFNI Package: \n"
855 "* At its core, 3dDeconvolve solves a linear regression problem z = X b \n"
856 " for the parameter vector b, given the data vector z in each voxel, and\n"
857 " given the SAME matrix X in each voxel. The solution is calculated in \n"
858 " the Ordinary Least Squares (OLSQ) sense. \n"
859 "* Program 3dREMLfit does something similar, but allows for ARMA(1,1) \n"
860 " serial correlation in the data, so the solution method is called \n"
861 " Generalized Least Squares (GLSQ). \n"
862 "* If you want to solve a problem where some of the matrix columns in X \n"
863 " (the regressors) are different in different voxels (spatially variable),\n"
864 " then use program 3dTfitter, which uses OLSQ, or used 3dREMLfit. \n"
865 "* 3dTfitter can also use L1 and LASSO regression, instead of OLSQ; if you\n"
866 " want to use such 'robust' fitting methods, this program is your friend.\n"
867 " It can also impose sign constraints (positivity or negativity) on the \n"
868 " parameters b, and can (as mentioned above) do deconvolution. \n"
869 "* 3dBandpass and 3dTproject can do a sequence of 'time series cleanup' \n"
870 " operations, including 'regressing out' (via OLSQ) a set of nuisance \n"
871 " vectors (columns). \n"
872 "* 3dLSS can be used to solve -stim_times_IM systems using an alternative\n"
873 " linear technique that gives biased results, but with smaller variance.\n"
874 "------------------------------------------------------------------------\n"
875 ) ;
876 printf("\n"
877 "Usage Details: \n"
878 PROGRAM_NAME " command-line-arguments ...\n"
879 " \n"
880 "**** Input data and control options **** \n"
881 "\n"
882 "-input fname fname = filename of 3D+time input dataset \n"
883 " [more than one filename can be given] \n"
884 " [here, and these datasets will be] \n"
885 " [auto-catenated in time; if you do this,] \n"
886 " ['-concat' is not needed and is ignored.] \n"
887 " **** You can input a 1D time series file here, \n"
888 " but the time axis should run along the \n"
889 " ROW direction, not the COLUMN direction as \n"
890 " in the -input1D option. You can automatically \n"
891 " transpose a 1D file on input using the \\' \n"
892 " operator at the end of the filename, as in \n"
893 " -input fred.1D\\' \n"
894 " ** This is the only way to use 3dDeconvolve \n"
895 " with a multi-column 1D time series file. \n"
896 " * The output datasets by default will then \n"
897 " be in 1D format themselves. To have them \n"
898 " formatted as AFNI datasets instead, use \n"
899 " -DAFNI_WRITE_1D_AS_PREFIX=YES \n"
900 " on the command line. \n"
901 " * You should use '-force_TR' to set the TR of \n"
902 " the 1D 'dataset' if you use '-input' rather \n"
903 " than '-input1D' [the default is 1.0 sec]. \n"
904 "\n"
905 "-sat OR -trans * 3dDeconvolve can check the dataset time series \n"
906 " for initial saturation transients, which should \n"
907 " normally have been excised before data analysis. \n"
908 " (Or should be censored out: see '-censor' below.) \n"
909 " If you want to have it do this somewhat time \n"
910 " consuming check, use the option '-sat'. \n"
911 " * Or set environment variable AFNI_SKIP_SATCHECK to NO.\n"
912 " * Program 3dSatCheck does this check, also. \n"
913 "\n"
914 "[-noblock] Normally, if you input multiple datasets with \n"
915 " '-input', then the separate datasets are taken to \n"
916 " be separate image runs that get separate baseline \n"
917 " models. If you want to have the program consider \n"
918 " these to be all one big run, use -noblock. \n"
919 " * If any of the input datasets has only 1 sub-brick,\n"
920 " then this option is automatically invoked! \n"
921 " * If the auto-catenation feature isn't used, then \n"
922 " this option has no effect, no how, no way. \n"
923 "\n"
924 "[-force_TR TR] Use this value of TR instead of the one in \n"
925 " the -input dataset. \n"
926 " (It's better to fix the input using 3drefit.) \n"
927 "\n"
928 "[-input1D dname] dname = filename of single (fMRI) .1D time series \n"
929 " where time run downs the column. \n"
930 " * If you want to analyze multiple columns from a \n"
931 " .1D file, see the '-input' option above for \n"
932 " the technique. \n"
933 "\n"
934 "[-TR_1D tr1d] tr1d = TR for .1D time series [default 1.0 sec]. \n"
935 " This option has no effect without -input1D \n"
936 "\n"
937 "[-nodata [NT [TR]] Evaluate experimental design only (no input data) \n"
938 " * Optional, but highly recommended: follow the \n"
939 " '-nodata' with two numbers, NT=number of time \n"
940 " points, and TR=time spacing between points (sec) \n"
941 "\n"
942 "[-mask mname] mname = filename of 3D mask dataset \n"
943 " Only data time series from within the mask \n"
944 " will be analyzed; results for voxels outside \n"
945 " the mask will be set to zero. \n"
946 "\n"
947 "[-automask] Build a mask automatically from input data \n"
948 " (will be slow for long time series datasets) \n"
949 " ** If you don't specify ANY mask, the program will \n"
950 " build one automatically (from each voxel's RMS) \n"
951 " and use this mask solely for the purpose of \n"
952 " reporting truncation-to-short errors (if '-short'\n"
953 " is used) AND for computing the FDR curves in the \n"
954 " bucket dataset's header (unless '-noFDR' is used,\n"
955 " of course). \n"
956 " * If you don't want the FDR curves to be computed \n"
957 " inside this automatically generated mask, then \n"
958 " use '-noFDR' and later run '3drefit -addFDR' on \n"
959 " the bucket dataset. \n"
960 " * To be precise, the above default masking only \n"
961 " happens when you use '-input' to run the program \n"
962 " with a 3D+time dataset; not with '-input1D'. \n"
963 "\n"
964 "[-STATmask sname] Build a mask from file 'sname', and use this \n"
965 " mask for the purpose of reporting truncation-to \n"
966 " float issues AND for computing the FDR curves. \n"
967 " The actual results ARE not masked with this \n"
968 " option (only with '-mask' or '-automask' options)\n"
969 " * If you don't use '-STATmask', then the mask \n"
970 " from '-mask' or '-automask' is used for these \n"
971 " purposes. If neither of those is given, then \n"
972 " the automatically generated mask described \n"
973 " just above is used for these purposes. \n"
974 "\n"
975 "[-censor cname] cname = filename of censor .1D time series \n"
976 " * This is a file of 1s and 0s, indicating which \n"
977 " time points are to be included (1) and which are \n"
978 " to be excluded (0). \n"
979 " * Option '-censor' can only be used once! \n"
980 " * The option below may be simpler to use! \n"
981 "\n"
982 "[-CENSORTR clist] clist = list of strings that specify time indexes \n"
983 " to be removed from the analysis. Each string is\n"
984 " of one of the following forms: \n"
985 " 37 => remove global time index #37 \n"
986 " 2:37 => remove time index #37 in run #2 \n"
987 " 37..47 => remove global time indexes #37-47 \n"
988 " 37-47 => same as above \n"
989 " 2:37..47 => remove time indexes #37-47 in run #2 \n"
990 " *:0-2 => remove time indexes #0-2 in all runs \n"
991 " +Time indexes within each run start at 0. \n"
992 " +Run indexes start at 1 (just be to confusing). \n"
993 " +Multiple -CENSORTR options may be used, or \n"
994 " multiple -CENSORTR strings can be given at \n"
995 " once, separated by spaces or commas. \n"
996 " +N.B.: 2:37,47 means index #37 in run #2 and \n"
997 " global time index 47; it does NOT mean \n"
998 " index #37 in run #2 AND index #47 in run #2. \n"
999 "\n"
1000 "[-concat rname] rname = filename for list of concatenated runs \n"
1001 " * 'rname' can be in the format \n"
1002 " '1D: 0 100 200 300' \n"
1003 " which indicates 4 runs, the first of which \n"
1004 " starts at time index=0, second at index=100, \n"
1005 " and so on. \n"
1006 "\n"
1007 "[-nfirst fnum] fnum = number of first dataset image to use in the\n"
1008 " deconvolution procedure. [default = max maxlag] \n"
1009 "\n"
1010 "[-nlast lnum] lnum = number of last dataset image to use in the \n"
1011 " deconvolution procedure. [default = last point] \n"
1012 "\n"
1013 "[-polort pnum] pnum = degree of polynomial corresponding to the \n"
1014 " null hypothesis [default: pnum = 1] \n"
1015 " ** For pnum > 2, this type of baseline detrending \n"
1016 " is roughly equivalent to a highpass filter \n"
1017 " with a cutoff of (p-2)/D Hz, where 'D' is the \n"
1018 " duration of the imaging run: D = N*TR \n"
1019 " ** If you use 'A' for pnum, the program will \n"
1020 " automatically choose a value based on the \n"
1021 " time duration D of the longest run: \n"
1022 " pnum = 1 + int(D/150) \n"
1023 " ==>>** 3dDeconvolve is the ONLY AFNI program with the \n"
1024 " -polort option that allows the use of 'A' to \n"
1025 " set the polynomial order automatically!!! \n"
1026 " ** Use '-1' for pnum to specifically NOT include \n"
1027 " any polynomials in the baseline model. Only \n"
1028 " do this if you know what this means! \n"
1029 "\n"
1030 "[-legendre] use Legendre polynomials for null hypothesis \n"
1031 " (baseline model) \n"
1032 "\n"
1033 "[-nolegendre] use power polynomials for null hypotheses \n"
1034 " [default is -legendre] \n"
1035 " ** Don't do this unless you are crazy! \n"
1036 "\n"
1037 "[-nodmbase] don't de-mean baseline time series \n"
1038 " (i.e., polort>0 and -stim_base inputs) \n"
1039 "[-dmbase] de-mean baseline time series [default if polort>=0]\n"
1040 "\n"
1041 "[-svd] Use SVD instead of Gaussian elimination [default] \n"
1042 "[-nosvd] Use Gaussian elimination instead of SVD \n"
1043 " (only use for testing + backwards compatibility)\n"
1044 "\n"
1045 "[-rmsmin r] r = minimum rms error to reject reduced model \n"
1046 " (default = 0; don't use this option normally!) \n"
1047 "\n"
1048 "[-nocond] DON'T calculate matrix condition number \n"
1049 " ** This value is NOT the same as Matlab! \n"
1050 "\n"
1051 "[-singvals] Print out the matrix singular values \n"
1052 " (useful for some testing/debugging purposes) \n"
1053 " Also see program 1dsvd. \n"
1054 "\n"
1055 "[-GOFORIT [g]] Use this to proceed even if the matrix has \n"
1056 " bad problems (e.g., duplicate columns, large \n"
1057 " condition number, etc.). \n"
1058 " *N.B.: Warnings that you should particularly heed have \n"
1059 " the string '!!' somewhere in their text. \n"
1060 " *N.B.: Error and Warning messages go to stderr and \n"
1061 " also to file " PROGRAM_NAME ".err. \n"
1062 " ++ You can disable the creation of this .err \n"
1063 " file by setting environment variable \n"
1064 " AFNI_USE_ERROR_FILE to NO before running \n"
1065 " this program. \n"
1066 " *N.B.: The optional number 'g' that appears is the \n"
1067 " number of warnings that can be ignored. \n"
1068 " That is, if you use -GOFORIT 7 and 9 '!!' \n"
1069 " matrix warnings appear, then the program will \n"
1070 " not run. If 'g' is not present, 1 is used. \n"
1071 "\n"
1072 "[-allzero_OK] Don't consider all zero matrix columns to be \n"
1073 " the type of error that -GOFORIT is needed to \n"
1074 " ignore. \n"
1075 " * Please know what you are doing when you use \n"
1076 " this option! \n"
1077 "\n"
1078 "[-Dname=val] = Set environment variable 'name' to 'val' for this \n"
1079 " run of the program only. \n"
1080 " \n"
1081 "******* Input stimulus options ******* \n"
1082 " \n"
1083 "-num_stimts num num = number of input stimulus time series \n"
1084 " (0 <= num) [default: num = 0] \n"
1085 " *N.B.: '-num_stimts' must come before any of the \n"
1086 " following '-stim' options! \n"
1087 " *N.B.: Most '-stim' options have as their first argument\n"
1088 " an integer 'k', ranging from 1..num, indicating \n"
1089 " which stimulus class the argument is defining. \n"
1090 " *N.B.: The purpose of requiring this option is to make \n"
1091 " sure your model is complete -- that is, you say \n"
1092 " you are giving 5 '-stim' options, and then the \n"
1093 " program makes sure that all of them are given \n"
1094 " -- that is, that you don't forget something. \n"
1095 " \n"
1096 "-stim_file k sname sname = filename of kth time series input stimulus\n"
1097 " *N.B.: This option directly inserts a column into the \n"
1098 " regression matrix; unless you are using the 'old'\n"
1099 " method of deconvolution (cf below), you would \n"
1100 " normally only use '-stim_file' to insert baseline\n"
1101 " model components such as motion parameters. \n"
1102 " \n"
1103 "[-stim_label k slabel] slabel = label for kth input stimulus \n"
1104 " *N.B.: This option is highly recommended, so that \n"
1105 " output sub-bricks will be labeled for ease of \n"
1106 " recognition when you view them in the AFNI GUI. \n"
1107 " \n"
1108 "[-stim_base k] kth input stimulus is part of the baseline model \n"
1109 " *N.B.: 'Baseline model' == Null Hypothesis model \n"
1110 " *N.B.: The most common baseline components to add are \n"
1111 " the 6 estimated motion parameters from 3dvolreg. \n"
1112 "\n"
1113 "-ortvec fff lll This option lets you input a rectangular array \n"
1114 " of 1 or more baseline vectors from file 'fff', \n"
1115 " which will get the label 'lll'. Functionally, \n"
1116 " it is the same as using '-stim_file' on each \n"
1117 " column of 'fff' separately (plus '-stim_base'). \n"
1118 " This method is just a faster and simpler way to \n"
1119 " include a lot of baseline regressors in one step. \n"
1120 " -->>**N.B.: This file is NOT included in the '-num_stimts' \n"
1121 " count that you provide. \n"
1122 " *N.B.: These regression matrix columns appear LAST \n"
1123 " in the matrix, after everything else. \n"
1124 " *N.B.: You can use column '[..]' and/or row '{..}' \n"
1125 " selectors on the filename 'fff' to pick out \n"
1126 " a subset of the numbers in that file. \n"
1127 " *N.B.: The q-th column of 'fff' will get a label \n"
1128 " like 'lll[q]' in the 3dDeconvolve results. \n"
1129 " *N.B.: This option is known as the 'Inati Option'. \n"
1130 " *N.B.: Unlike the original 'Inati' (who is unique), it \n"
1131 " is allowed to have more than one '-ortvec' option.\n"
1132 " *N.B.: Program 1dBport is one place to generate a file \n"
1133 " for use with '-ortvec'; 1deval might be another. \n"
1134 "\n"
1135 "**N.B.: You must have -num_stimts > 0 AND/OR \n"
1136 " You must use -ortvec AND/OR \n"
1137 " You must have -polort >= 0 \n"
1138 " Otherwise, there is no regression model! \n"
1139 " An example using -polort only: \n"
1140 " 3dDeconvolve -x1D_stop -polort A -nodata 300 2 -x1D stdout: | 1dplot -one -stdin\n"
1141 "\n"
1142 "**N.B.: The following 3 options are for the 'old' style of explicit \n"
1143 " deconvolution. For most purposes, their usage is no longer \n"
1144 " recommended. Instead, you should use the '-stim_times' options\n"
1145 " to directly input the stimulus times, rather than code the \n"
1146 " stimuli as a sequence of 0s and 1s in this 'old' method! \n"
1147 "\n"
1148 "[-stim_minlag k m] m = minimum time lag for kth input stimulus \n"
1149 " [default: m = 0] \n"
1150 "[-stim_maxlag k n] n = maximum time lag for kth input stimulus \n"
1151 " [default: n = 0] \n"
1152 "[-stim_nptr k p] p = number of stimulus function points per TR \n"
1153 " Note: This option requires 0 slice offset times \n"
1154 " [default: p = 1] \n"
1155 " \n"
1156 "**N.B.: The '-stim_times' options below are the recommended way of \n"
1157 " analyzing FMRI time series data now. The options directly \n"
1158 " above are only maintained for the sake of backwards \n"
1159 " compatibility! For most FMRI users, the 'BLOCK' and 'TENT' \n"
1160 " (or 'CSPLIN') response models will serve their needs. The \n"
1161 " other models are for users with specific needs who understand \n"
1162 " clearly what they are doing. \n"
1163 " \n"
1164 "[-stim_times k tname Rmodel] \n"
1165 " Generate the k-th response model from a set of stimulus times \n"
1166 " given in file 'tname'. \n"
1167 " *** The format of file 'tname' is one line per imaging run \n"
1168 " (cf. '-concat' above), and each line contains the list of START\n"
1169 " times (in seconds) for the stimuli in class 'k' for its \n"
1170 " corresponding run of data; times are relative to the start of \n"
1171 " the run (i.e., sub-brick #0 occurring at time=0). \n"
1172 " *** The DURATION of the stimulus is encoded in the 'Rmodel' \n"
1173 " argument, described below. Units are in seconds, not TRs! \n"
1174 " -- If different stimuli in the same class 'k' have different \n"
1175 " durations, you'll have to use the dmBLOCK response model \n"
1176 " and '-stim_times_AM1' or '-stim_times_AM2', described below.\n"
1177 " *** Different lines in the 'tname' file can contain different \n"
1178 " numbers of start times. Each line must contain at least 1 time.\n"
1179 " *** If there is no stimulus in class 'k' in a particular imaging \n"
1180 " run, there are two ways to indicate that: \n"
1181 " (a) put a single '*' on the line, or \n"
1182 " (b) put a very large number or a negative number \n"
1183 " (e.g., 99999, or -1) on the line \n"
1184 " -- times outside the range of the imaging run will cause \n"
1185 " a warning message, but the program will soldier on. \n"
1186 " *** In the case where the stimulus doesn't actually exist in the \n"
1187 " data model (e.g., every line in 'tname' is a '*'), you will \n"
1188 " also have to use the '-allzero_OK' option to force 3dDeconvolve\n"
1189 " to run with regressor matrix columns that are filled with zeros.\n"
1190 " \n"
1191 " The response model is specified by the third argument after \n"
1192 " '-stim_times' ('Rmodel'), and can be one of the following: \n"
1193 " *** In the descriptions below, a '1 parameter' model has a fixed \n"
1194 " shape, and only the estimated amplitude ('Coef') varies: \n"
1195 " BLOCK GAM TWOGAM SPMG1 WAV MION \n"
1196 " *** Models with more than 1 parameter have multiple basis \n"
1197 " functions, and the estimated parameters ('Coef') are their \n"
1198 " amplitudes. The estimated shape of the response to a stimulus \n"
1199 " will be different in different voxels: \n"
1200 " TENT CSPLIN SPMG2 SPMG3 POLY SIN EXPR \n"
1201 " *** Many models require the input of the start and stop times for \n"
1202 " the response, 'b' and 'c'. Normally, 'b' would be zero, but \n"
1203 " in some cases, 'b' could be negative -- for example, if you \n"
1204 " are concerned about anticipatory effects. The stop time 'c' \n"
1205 " should be based on how long you realistically expect the \n"
1206 " hemodynamic response to last after the onset of the stimulus; \n"
1207 " e.g., the duration of the stimulus plus 14 seconds for BOLD. \n"
1208 " *** If you use '-tout', each parameter will get a separate \n"
1209 " t-statistic. As mentioned far above, this is a marginal \n"
1210 " statistic, measuring the impact of that model component on the \n"
1211 " regression fit, relative to the fit with that one component \n"
1212 " (matrix column) removed. \n"
1213 " *** If you use '-fout', each stimulus will also get an F-statistic,\n"
1214 " which is the collective impact of all the model components \n"
1215 " it contains, relative to the regression fit with the entire \n"
1216 " stimulus removed. (If there is only 1 parameter, then F = t*t.)\n"
1217 " *** Some models below are described in terms of a simple response \n"
1218 " function that is then convolved with a square wave whose \n"
1219 " duration is a parameter you give (duration is NOT a parameter \n"
1220 " that will be estimated). Read the descriptions below carefully:\n"
1221 " not all functions are (or can be) convolved in this way: \n"
1222 " * ALWAYS convolved: BLOCK dmBLOCK MION MIONN \n"
1223 " * OPTIONALLY convolved: GAM TWOGAM SPMGx WAV \n"
1224 " * NEVER convolved: TENT CSPLIN POLY SIN EXPR \n"
1225 " Convolution is specified by providing the duration parameter \n"
1226 " as described below for each particular model function. \n"
1227 "\n"
1228 " 'BLOCK(d,p)' = 1 parameter block stimulus of duration 'd' \n"
1229 " ** There are 2 variants of BLOCK: \n"
1230 " BLOCK4 [the default] and BLOCK5 \n"
1231 " which have slightly different delays: \n"
1232 " HRF(t) = int( g(t-s) , s=0..min(t,d) ) \n"
1233 " where g(t) = t^q * exp(-t) /(q^q*exp(-q)) \n"
1234 " and q = 4 or 5. The case q=5 is delayed by \n"
1235 " about 1 second from the case q=4. \n"
1236 " ==> ** Despite the name, you can use 'BLOCK' for event-\n"
1237 " related analyses just by setting the duration to\n"
1238 " a small value; e.g., 'BLOCK5(1,1)' \n"
1239 " ** The 'p' parameter is the amplitude of the \n"
1240 " basis function, and should usually be set to 1. \n"
1241 " If 'p' is omitted, the amplitude will depend on \n"
1242 " the duration 'd', which is useful only in \n"
1243 " special circumstances!! \n"
1244 " ** For bad historical reasons, the peak amplitude \n"
1245 " 'BLOCK' without the 'p' parameter does not go to\n"
1246 " 1 as the duration 'd' gets large. Correcting \n"
1247 " this oversight would break some people's lives, \n"
1248 " so that's just the way it is. \n"
1249 " ** The 'UBLOCK' function (U for Unit) is the same \n"
1250 " as the 'BLOCK' function except that when the \n"
1251 " 'p' parameter is missing (or 0), the peak \n"
1252 " amplitude goes to 1 as the duration gets large. \n"
1253 " If p > 0, 'UBLOCK(d,p)' and 'BLOCK(d,p)' are \n"
1254 " identical. \n"
1255 "\n"
1256 " 'TENT(b,c,n)' = n parameter tent function expansion from times \n"
1257 " b..c after stimulus time [piecewise linear] \n"
1258 " [n must be at least 2; time step is (c-b)/(n-1)]\n"
1259 " 'CSPLIN(b,c,n)'= n parameter cubic spline function expansion \n"
1260 " from times b..c after stimulus time \n"
1261 " [n must be at least 4] \n"
1262 " ** CSPLIN is a drop-in upgrade of TENT to a \n"
1263 " differentiable set of functions. \n"
1264 " ** TENT and CSPLIN are 'cardinal' interpolation \n"
1265 " functions: their parameters are the values \n"
1266 " of the HRF model at the n 'knot' points \n"
1267 " b , b+dt , b+2*dt , ... [dt = (c-b)/(n-1)] \n"
1268 " In contrast, in a model such as POLY or SIN, \n"
1269 " the parameters output are not directly the \n"
1270 " hemodynamic response function values at any \n"
1271 " particular point. \n"
1272 " ==> ** You can also use 'TENTzero' and 'CSPLINzero', \n"
1273 " which means to eliminate the first and last \n"
1274 " basis functions from each set. The effect \n"
1275 " of these omissions is to force the deconvolved \n"
1276 " HRF to be zero at t=b and t=c (to start and \n"
1277 " and end at zero response). With these 'zero' \n"
1278 " response models, there are n-2 parameters \n"
1279 " (thus for 'TENTzero', n must be at least 3). \n"
1280 " ** These 'zero' functions will force the HRF to \n"
1281 " be continuous, since they will now be unable \n"
1282 " to suddenly rise up from 0 at t=b and/or drop \n"
1283 " down to 0 at t=c. \n"
1284 "\n"
1285 " 'GAM(p,q)' = 1 parameter gamma variate \n"
1286 " (t/(p*q))^p * exp(p-t/q) \n"
1287 " Defaults: p=8.6 q=0.547 if only 'GAM' is used \n"
1288 " ** The peak of 'GAM(p,q)' is at time p*q after \n"
1289 " the stimulus. The FWHM is about 2.35*sqrt(p)*q;\n"
1290 " this approximation is accurate for p > 0.3*q. \n"
1291 " ** To check this approximation, try the command \n"
1292 " 1deval -num 100 -del 0.02 -xzero 0.02 \\\n"
1293 " -expr 'sqrt(gamp(x,1))/2.35/x' | \\\n"
1294 " 1dplot -stdin -del 0.02 -xzero 0.02 -yaxis 1:1.4:4:10 \n"
1295 " If the two functions gamp(x,1) and 2.35*x \n"
1296 " were equal, the plot would be constant y=1. \n"
1297 " ==> ** If you add a third argument 'd', then the GAM \n"
1298 " function is convolved with a square wave of \n"
1299 " duration 'd' seconds; for example: \n"
1300 " 'GAM(8.6,.547,17)' \n"
1301 " for a 17 second stimulus. [09 Aug 2010] \n"
1302 " 'GAMpw(K,W)' = Same as 'GAM(p,q)' but where the shape parameters \n"
1303 " are specified at time to peak 'K' and full \n"
1304 " width at half max (FWHM) 'W'. You can also \n"
1305 " add a third argument as the duration. The (K,W) \n"
1306 " parameters are converted to (p,q) values for \n"
1307 " the actual computations; the (p,q) parameters \n"
1308 " are printed to the text (stderr) output. \n"
1309 " ** Note that if you give weird values for K and W,\n"
1310 " weird things will happen: (tcsh syntax) \n"
1311 " set pp = `ccalc 'gamp(2,8)'` \n"
1312 " set qq = `ccalc 'gamq(2,8)'` \n"
1313 " 1deval -p=$pp -q=$qq -num 200 -del 0.1 \\\n"
1314 " -expr '(t/p/q)^p*exp(p-t/q)' | \\\n"
1315 " 1dplot -stdin -del 0.1 \n"
1316 " Here, K is significantly smaller than W, \n"
1317 " so a gamma variate that fits peak=2 width=8 \n"
1318 " must be weirdly shaped. [Also note use of the \n"
1319 " 'calc' functions gamp(K,W) and gamq(K,W) to \n"
1320 " calculate p and q from K and W in the script.] \n"
1321 "\n"
1322 " 'TWOGAM(p1,q1,r,p2,q2)' \n"
1323 " = 1 parameter (amplitude) model: \n"
1324 " = A combination of two 'GAM' functions: \n"
1325 " GAM(p1,q1) - r*GAM(p2,q2) \n"
1326 " This model is intended to let you use a HRF \n"
1327 " similar to BrainVoyager (e.g.). You can \n"
1328 " add a sixth argument as the duration. \n"
1329 " ** Note that a positive 'r' parameter means to \n"
1330 " subtract the second GAM function (undershoot). \n"
1331 " 'TWOGAMpw(K1,W1,r,K2,W2)' \n"
1332 " = Same as above, but where the peaks and widths \n"
1333 " of the 2 component gamma variates are given \n"
1334 " instead of the less intuitive p and q. \n"
1335 " For FMRI work, K2 > K1 is usual, as the \n"
1336 " second (subtracted) function is intended \n"
1337 " to model the 'undershoot' after the main \n"
1338 " positive part of the model. You can also \n"
1339 " add a sixth argument as the duration. \n"
1340 " ** Example (no duration given): \n"
1341 " 3dDeconvolve -num_stimts 1 -polort -1 -nodata 81 0.5 \\\n"
1342 " -stim_times 1 '1D: 0' 'TWOGAMpw(3,6,0.2,10,12)' \\\n"
1343 " -x1D stdout: | 1dplot -stdin -THICK -del 0.5 \n"
1344 "\n"
1345 " 'SPMG1' = 1 parameter SPM gamma variate basis function \n"
1346 " exp(-t)*(A1*t^P1-A2*t^P2) where \n"
1347 " A1 = 0.0083333333 P1 = 5 (main positive lobe) \n"
1348 " A2 = 1.274527e-13 P2 = 15 (undershoot part) \n"
1349 " This function is NOT normalized to have peak=1! \n"
1350 " 'SPMG2' = 2 parameter SPM: gamma variate + d/dt derivative \n"
1351 " [For backward compatibility: 'SPMG' == 'SPMG2'] \n"
1352 " 'SPMG3' = 3 parameter SPM basis function set \n"
1353 " ==> ** The SPMGx functions now can take an optional \n"
1354 " (duration) argument, specifying that the primal\n"
1355 " SPM basis functions should be convolved with \n"
1356 " a square wave 'duration' seconds long and then \n"
1357 " be normalized to have peak absolute value = 1; \n"
1358 " e.g., 'SPMG3(20)' for a 20 second duration with\n"
1359 " three basis function. [28 Apr 2009] \n"
1360 " ** Note that 'SPMG1(0)' will produce the usual \n"
1361 " 'SPMG1' wavefunction shape, but normalized to \n"
1362 " have peak value = 1 (for example). \n"
1363 "\n"
1364 " 'POLY(b,c,n)' = n parameter Legendre polynomial expansion \n"
1365 " from times b..c after stimulus time \n"
1366 " [n can range from 1 (constant) to 20] \n"
1367 "\n"
1368 " 'SIN(b,c,n)' = n parameter sine series expansion \n"
1369 " from times b..c after stimulus time \n"
1370 " [n must be at least 1] \n"
1371 "\n"
1372 " 'WAV(d)' = 1 parameter block stimulus of duration 'd'. \n"
1373 " * This is the '-WAV' function from program waver!\n"
1374 " * If you wish to set the shape parameters of the \n"
1375 " WAV function, you can do that by adding extra \n"
1376 " arguments, in the order \n"
1377 " delay time , rise time , fall time , \n"
1378 " undershoot fraction, undershoot restore time \n"
1379 " * The default values are 'WAV(d,2,4,6,0.2,2)' \n"
1380 " * Omitted parameters get the default values. \n"
1381 " * 'WAV(d,,,,0)' (setting undershoot=0) is \n"
1382 " very similar to 'BLOCK5(d,1)', for d > 0. \n"
1383 " * Setting duration d to 0 (or just using 'WAV') \n"
1384 " gives the pure '-WAV' impulse response function\n"
1385 " from waver. \n"
1386 " * If d > 0, the WAV(0) function is convolved with\n"
1387 " a square wave of duration d to make the HRF, \n"
1388 " and the amplitude is scaled back down to 1. \n"
1389 "\n"
1390 " 'EXPR(b,c) exp1 ... expn' \n"
1391 " = n parameter; arbitrary expressions from times \n"
1392 " b..c after stimulus time \n"
1393 " * Expressions are separated by spaces, so \n"
1394 " each expression must be a contiguous block \n"
1395 " of non-whitespace characters \n"
1396 " * The entire model, from 'EXPR' to the final \n"
1397 " expression must be enclosed in one set of \n"
1398 " quotes. The individual component expressions \n"
1399 " are separated by blanks. Example: \n"
1400 " '-EXPR(0,20) sin(PI*t/20)^2' \n"
1401 " * Expressions use the same format as 3dcalc \n"
1402 " * Symbols that can be used in an expression: \n"
1403 " t = time in sec since stimulus time \n"
1404 " x = time scaled to be x= 0..1 for t=bot..top \n"
1405 " z = time scaled to be z=-1..1 for t=bot..top \n"
1406 " * Spatially dependent regressors are not allowed!\n"
1407 " * Other symbols are set to 0 (silently). \n"
1408 " ==> ** There is no convolution of the 'EXPR' functions\n"
1409 " with a square wave implied. The expressions \n"
1410 " you input are what you get, evaluated over \n"
1411 " times b..c after each stimulus time. To be \n"
1412 " sure of what your response model is, you should\n"
1413 " plot the relevant columns from the matrix \n"
1414 " .xmat.1D output file. \n"
1415 "\n"
1416 " 'MION(d)' = 1 parameter block stimulus of duration 'd', \n"
1417 " intended to model the response of MION. \n"
1418 " The zero-duration impulse response 'MION(0)' is \n"
1419 " h(t) = 16.4486 * ( -0.184/ 1.5 * exp(-t/ 1.5) \n"
1420 " +0.330/ 4.5 * exp(-t/ 4.5) \n"
1421 " +0.670/13.5 * exp(-t/13.5) ) \n"
1422 " which is adapted from the paper \n"
1423 " FP Leite, et al. NeuroImage 16:283-294 (2002) \n"
1424 " http://dx.doi.org/10.1006/nimg.2002.1110 \n"
1425 " ** Note that this is a positive function, but MION \n"
1426 " produces a negative response to activation, so the\n"
1427 " beta and t-statistic for MION are usually negative.\n"
1428 " ***** If you want a negative MION function (so you get \n"
1429 " a positive beta), use the name 'MIONN' instead. \n"
1430 " ** After convolution with a square wave 'd' seconds \n"
1431 " long, the resulting single-trial waveform is \n"
1432 " scaled to have magnitude 1. For example, try \n"
1433 " this fun command to compare BLOCK and MION: \n"
1434 " 3dDeconvolve -nodata 300 1 -polort -1 -num_stimts 2 \\\n"
1435 " -stim_times 1 '1D: 10 150' 'MION(70)' \\\n"
1436 " -stim_times 2 '1D: 10 150' 'BLOCK(70,1)' \\\n"
1437 " -x1D stdout: | 1dplot -stdin -one -thick \n"
1438 " You will see that the MION curve rises and falls \n"
1439 " much more slowly than the BLOCK curve. \n"
1440 " ==> ** Note that 'MION(d)' is already convolved with a \n"
1441 " square wave of duration 'd' seconds. Do not \n"
1442 " convolve it again by putting in multiple closely \n"
1443 " spaced stimulus times (this mistake has been made)!\n"
1444 " ** Scaling the single-trial waveform to have magnitude\n"
1445 " 1 means that trials with different durations 'd' \n"
1446 " will have the same magnitude for their regression \n"
1447 " models. \n"
1448 " \n"
1449 " * 3dDeconvolve does LINEAR regression, so the model parameters are \n"
1450 " amplitudes of the basis functions; 1 parameter models are 'simple' \n"
1451 " regression, where the shape of the impulse response function is \n"
1452 " fixed and only the magnitude/amplitude varies. Models with more \n"
1453 " free parameters have 'variable' shape impulse response functions. \n"
1454 "\n"
1455 " * LINEAR regression means that each data time series (thought of as \n"
1456 " a single column of numbers = a vector) is fitted to a sum of the \n"
1457 " matrix columns, each one multiplied by an amplitude parameter to \n"
1458 " be calculated ('Coef'). The purpose of the various options \n"
1459 " '-stim_times', '-polort', '-ortvec', and/or '-stim_file' \n"
1460 " is to build the columns of the regression matrix. \n"
1461 " \n"
1462 " * If you want NONLINEAR regression, see program 3dNLfim. \n"
1463 " \n"
1464 " * If you want LINEAR regression with allowance for non-white noise, \n"
1465 " use program 3dREMLfit, after using 3dDeconvolve to set up the \n"
1466 " regression model (in the form of a matrix file). \n"
1467 " \n"
1468 "** When in any doubt about the shape of the response model you are **\n"
1469 "* asking for, you should plot the relevant columns from the X matrix *\n"
1470 "* to help develop some understanding of the analysis. The 'MION' *\n"
1471 "* example above can be used as a starting point for how to easily *\n"
1472 "* setup a quick command pipeline to graph response models. In that *\n"
1473 "* example, '-polort -1' is used to suppress the usual baseline model *\n"
1474 "* since graphing that part of the matrix would just be confusing. *\n"
1475 "* Another example, for example, comparing the similar models *\n"
1476 "** 'WAV(10)', 'BLOCK4(10,1)', and 'SPMG1(10)': **\n"
1477 " \n"
1478 " 3dDeconvolve -nodata 100 1.0 -num_stimts 3 -polort -1 \\\n"
1479 " -local_times -x1D stdout: \\\n"
1480 " -stim_times 1 '1D: 10 60' 'WAV(10)' \\\n"
1481 " -stim_times 2 '1D: 10 60' 'BLOCK4(10,1)' \\\n"
1482 " -stim_times 3 '1D: 10 60' 'SPMG1(10)' \\\n"
1483 " | 1dplot -thick -one -stdin -xlabel Time -ynames WAV BLOCK4 SPMG1\n"
1484 " \n"
1485 " * For the format of the 'tname' file, see the last part of \n"
1486 " https://afni.nimh.nih.gov/pub/dist/doc/misc/Decon/DeconSummer2004.html \n"
1487 " and also see the other documents stored in the directory below: \n"
1488 " https://afni.nimh.nih.gov/pub/dist/doc/misc/Decon/ \n"
1489 " and also read the presentation below: \n"
1490 " https://afni.nimh.nih.gov/pub/dist/edu/latest/afni_handouts/afni05_regression.pdf\n"
1491 " ** Note Well: \n"
1492 " * The contents of the 'tname' file are NOT just 0s and 1s, \n"
1493 " but are the actual times of the stimulus events IN SECONDS. \n"
1494 " * You can give the times on the command line by using a string \n"
1495 " of the form '1D: 3.2 7.9 | 8.2 16.2 23.7' in place of 'tname', \n"
1496 " where the '|' character indicates the start of a new line \n"
1497 " (so this example is for a case with 2 catenated runs). \n"
1498 "=> * You CANNOT USE the '1D:' form of input for any of the more \n"
1499 " complicated '-stim_times_*' options below!! \n"
1500 " * The '1D:' form of input is mostly useful for quick tests, as \n"
1501 " in the examples above, rather than for production analyses with \n"
1502 " lots of different stimulus times and multiple imaging runs. \n"
1503 " \n"
1504 "[-stim_times_AM1 k tname Rmodel] \n"
1505 " Similar, but generates an amplitude modulated response model. \n"
1506 " The 'tname' file should consist of 'time*amplitude' pairs. \n"
1507 " As in '-stim_times', the '*' character can be used as a placeholder \n"
1508 " when an imaging run doesn't have any stimulus of a given class. \n"
1509 " *N.B.: What I call 'amplitude' modulation is called 'parametric' \n"
1510 " modulation in Some other PrograM. \n"
1511 " ***N.B.: If NO run at all has a stimulus of a given class, then you \n"
1512 " must have at least 1 time that is not '*' for -stim_times_* \n"
1513 " to work (so that the proper number of regressors can be set \n"
1514 " up). You can use a negative time for this purpose, which \n"
1515 " will produce a warning message but otherwise will be \n"
1516 " ignored, as in: \n"
1517 " -1*37 \n"
1518 " * \n"
1519 " for a 2 run 'tname' file to be used with -stim_times_*. \n"
1520 " ** In such a case, you will also need the -allzero_OK option, \n"
1521 " and probably -GOFORIT as well. \n"
1522 " ** It is possible to combine '-stim_times_AM1' with the Rmodel \n"
1523 " being TENT. If you have an amplitude parameter at each TR, \n"
1524 " and you want to try to deconvolve its impact on the data, \n"
1525 " you can try the following: \n"
1526 " a) create a 1D column file with the amplitude parameter, \n"
1527 " one value per TR, matching the length of the data; \n"
1528 " say this file is called Akk.1D \n"
1529 " b) create a 1D column file with the actual TR time in \n"
1530 " each row; for example, if you have 150 time points \n"
1531 " and TR=2 s, then \n"
1532 " 1deval -num 150 -expr '2*i' > Att.1D \n"
1533 " c) glue these files together for use with -stim_times_AM1: \n"
1534 " echo `1dMarry Att.1D Akk.1D` > Atk.1D \n"
1535 " d) Use option \n"
1536 " -stim_times 1 Atk.1D 'TENT(0,20,11)' -stim_label 1 TENT \n"
1537 " which gives a TENT response lasting 20s with 11 parameters \n"
1538 " -- one every TR. \n"
1539 " e) Use all the other clever options you need in 3dDeconvolve, \n"
1540 " such as censoring, baseline, motion parameters, .... \n"
1541 " Variations on the options chosen here can be made to \n"
1542 " constrain the deconvolution; e.g., use CSPLIN vs. TENT, or \n"
1543 " CSPLINzero; use fewer parameters in the TENT/CSPLIN to force \n"
1544 " a smoother deconvolution, etc. \n"
1545 " Graphing the regression matrix is useful in this type of \n"
1546 " analysis, to be sure you are getting the analysis you want; \n"
1547 " for example: \n"
1548 " 1dplot -sep_scl prefix.xmat.1D \n"
1549 "\n"
1550 "[-stim_times_AM2 k tname Rmodel] \n"
1551 " Similar, but generates 2 response models: one with the mean \n"
1552 " amplitude and one with the differences from the mean. \n"
1553 " *** Please note that 'AM2' is the option you should probably use! \n"
1554 " *** 'AM1' is for special cases, and normally should not be used \n"
1555 " for FMRI task activation analyses!! \n"
1556 " *** 'AM2' will give you the ability to detect voxels that activate \n"
1557 " but do not change proportional to the amplitude factor, as well \n"
1558 " as provide a direct measure of the proportionality of the \n"
1559 " activation to changes in the input amplitude factors. 'AM1' \n"
1560 " will do neither of these things. \n"
1561 " *** Normally, 3dDeconvolve removes the mean of the auxiliary \n"
1562 " parameter(s) from the modulated regressor(s). However, if you \n"
1563 " set environment variable AFNI_3dDeconvolve_rawAM2 to YES, then \n"
1564 " the mean will NOT be removed from the auxiliary parameter(s). \n"
1565 " This ability is provided for users who want to center their \n"
1566 " parameters using their own method. \n"
1567 " *** [12 Jul 2012] You can now specify the value to subtract from \n"
1568 " each modulation parameter -- this value will replace the \n"
1569 " subtraction of the average parameter value that usually happens. \n"
1570 " To do this, add an extra parameter after the option, as in \n"
1571 " -stim_times_AM2 1 timesAM.1D 'BLOCK(2,1)' :5.2:x:2.0 \n"
1572 " The extra argument must start with the colon ':' character, and \n"
1573 " there should be as many different values (separated by ':') as \n"
1574 " there are parameters in the timing file (timesAM.1D above). \n"
1575 " ==> In the example above, ':5.2:x:2.0' means \n"
1576 " subtract 5.2 from each value of the first parameter in timesAM.1D\n"
1577 " subtract the MEAN from each value of the second parameter \n"
1578 " (since 'x' doesn't translate to a number) \n"
1579 " subtract 2.0 from each value of the third parameter \n"
1580 " ==> What is this option for, anyway? The purpose is to facilitate \n"
1581 " GROUP analysis the results from a collection of subjects, where \n"
1582 " you want to treat each subject's analysis exactly the same \n"
1583 " way -- and thus, the subtraction value for a parameter (e.g., \n"
1584 " reaction time) should then be the mean over all the reaction \n"
1585 " times from all trials in all subjects. \n"
1586 " \n"
1587 "** NOTE [04 Dec 2008] ** \n"
1588 " -stim_times_AM1 and -stim_times_AM2 now take files with more \n"
1589 " than 1 amplitude attached to each time; for example, \n"
1590 " 33.7*9,-2,3 \n"
1591 " indicates a stimulus at time 33.7 seconds with 3 amplitudes \n"
1592 " attached (9 and -2 and 3). In this example, -stim_times_AM2 would \n"
1593 " generate 4 response models: 1 for the constant response case \n"
1594 " and 1 scaled by each of the amplitude sets. \n"
1595 " ** Please don't carried away and use too many parameters!! ** \n"
1596 " For more information on modulated regression, see \n"
1597 " https://afni.nimh.nih.gov/pub/dist/doc/misc/Decon/AMregression.pdf \n"
1598 " \n"
1599 "** NOTE [08 Dec 2008] ** \n"
1600 " -stim_times_AM1 and -stim_times_AM2 now have 1 extra response model \n"
1601 " function available: \n"
1602 " dmBLOCK (or dmBLOCK4 or dmBLOCK5) \n"
1603 " where 'dm' means 'duration modulated'. If you use this response \n"
1604 " model, then the LAST married parameter in the timing file will \n"
1605 " be used to modulate the duration of the block stimulus. Any \n"
1606 " earlier parameters will be used to modulate the amplitude, \n"
1607 " and should be separated from the duration parameter by a ':' \n"
1608 " character, as in '30*5,3:12' which means (for dmBLOCK): \n"
1609 " a block starting at 30 s, \n"
1610 " with amplitude modulation parameters 5 and 3, \n"
1611 " and with duration 12 s. \n"
1612 " The unmodulated peak response of dmBLOCK depends on the duration \n"
1613 " of the stimulus, as the BOLD response accumulates. \n"
1614 " If you want the peak response to be a set to a fixed value, use \n"
1615 " dmBLOCK(p) \n"
1616 " where p = the desired peak value (e.g., 1). \n"
1617 " *** Understand what you doing when you use dmBLOCK, and look at *** \n"
1618 " *** the regression matrix! Otherwise, you will end up confused. *** \n"
1619 " *N.B.: The maximum allowed dmBLOCK duration is 999 s. \n"
1620 " *N.B.: You cannot use '-iresp' or '-sresp' with dmBLOCK! \n"
1621 " *N.B.: If you are NOT doing amplitude modulation at the same time \n"
1622 " (and so you only have 1 'married' parameter per time), use \n"
1623 " '-stim_times_AM1' with dmBLOCK. If you also want to do \n"
1624 " amplitude modulation at the same time as duration modulation \n"
1625 " (and so you have 2 or more parameters with each time), use \n"
1626 " '-stim_times_AM2' instead. If you use '-stim_times_AM2' and \n"
1627 " there is only 1 'married' parameter, the program will print \n"
1628 " a warning message, then convert to '-stim_times_AM1', and \n"
1629 " continue -- so nothing bad will happen to your analysis! \n"
1630 " (But you will be embarassed in front of your friends.) \n"
1631 " *N.B.: If you are using AM2 (amplitude modulation) with dmBLOCK, you \n"
1632 " might want to use 'dmBLOCK(1)' to make each block have native \n"
1633 " amplitude 1 before it is scaled by the amplitude parameter. \n"
1634 " Or maybe not -- this is a matter for fine judgment. \n"
1635 " *N.B.: You can also use dmBLOCK with -stim_times_IM, in which case \n"
1636 " each time in the 'tname' file should have just ONE extra \n"
1637 " parameter -- the duration -- married to it, as in '30:15', \n"
1638 " meaning a block of duration 15 seconds starting at t=30 s. \n"
1639 " *N.B.: For bad historical reasons, the peak amplitude dmBLOCK without \n"
1640 " the 'p' parameter does not go to 1 as the duration gets large. \n"
1641 " Correcting this oversight would break some people's lives, so \n"
1642 " that's just the way it is. \n"
1643 " *N.B.: The 'dmUBLOCK' function (U for Unit) is the same as the \n"
1644 " 'dmBLOCK' function except that when the 'p' parameter is \n"
1645 " missing (or 0), the peak amplitude goes to 1 as the duration \n"
1646 " gets large. If p > 0, 'dmUBLOCK(p)' and 'dmBLOCK(p)' are \n"
1647 " identical \n"
1648 " For some graphs of what dmBLOCK regressors look like, see \n"
1649 " https://afni.nimh.nih.gov/pub/dist/doc/misc/Decon/AMregression.pdf \n"
1650 " and/or try the following command: \n"
1651 " 3dDeconvolve -nodata 350 1 -polort -1 -num_stimts 1 \\\n"
1652 " -stim_times_AM1 1 q.1D 'dmBLOCK' \\\n"
1653 " -x1D stdout: | 1dplot -stdin -thick -thick \n"
1654 " where file q.1D contains the single line \n"
1655 " 10:1 40:2 70:3 100:4 130:5 160:6 190:7 220:8 250:9 280:30 \n"
1656 " Change 'dmBLOCK' to 'dmBLOCK(1)' and see how the matrix plot changes. \n"
1657 " \n"
1658 " **************** Further notes on dmBLOCK [Nov 2013] **************** \n"
1659 " \n"
1660 " Basically (IMHO), there are 2 rational choices to use: \n"
1661 " \n"
1662 " (a) 'dmUBLOCK' = allow the amplitude of the response model to \n"
1663 " vary with the duration of the stimulus; getting \n"
1664 " larger with larger durations; for durations longer \n"
1665 " than about 15s, the amplitude will become 1. \n"
1666 " -->> This choice is equivalent to 'dmUBLOCK(0)', but \n"
1667 " is NOT equivalent to 'dmBLOCK(0)' due to the \n"
1668 " historical scaling issue alluded to above. \n"
1669 " \n"
1670 " (b) 'dmUBLOCK(1)' = all response models will get amplitude 1, \n"
1671 " no matter what the duration of the stimulus. \n"
1672 " -->> This choice is equivalent to 'dmBLOCK(1)'. \n"
1673 " \n"
1674 " Some users have expressed the desire to allow the amplitude to \n"
1675 " vary with duration, as in case (a), BUT to specify the duration \n"
1676 " at which the amplitude goes to 1. This desideratum has now been \n"
1677 " implemented, and provides the case below: \n"
1678 " \n"
1679 " (a1) 'dmUBLOCK(-X)' = set the amplitude to be 1 for a duration \n"
1680 " of 'X' seconds; e.g., 'dmBLOCK(-5)' means \n"
1681 " that a stimulus with duration 5 gets \n"
1682 " amplitude 1, shorter durations get amplitudes \n"
1683 " smaller than 1, and longer durations get \n"
1684 " amplitudes larger than 1. \n"
1685 " -->> Please note that 'dmBLOCK(-X)' is NOT the \n"
1686 " same as this case (a1), and in fact it \n"
1687 " has no meaning. \n"
1688 " \n"
1689 " I hope this clarifies things and makes your life simpler, happier, \n"
1690 " and more carefree. (If not, please blame Gang Chen, not me.) \n"
1691 " \n"
1692 " An example to clarify the difference between these cases: \n"
1693 " 3dDeconvolve -nodata 350 1 -polort -1 -num_stimts 3 \\\n"
1694 " -stim_times_AM1 1 q.1D 'dmUBLOCK' \\\n"
1695 " -stim_times_AM1 2 q.1D 'dmUBLOCK(1)' \\\n"
1696 " -stim_times_AM1 3 q.1D 'dmUBLOCK(-4)' \\\n"
1697 " -x1D stdout: | \\\n"
1698 " 1dplot -stdin -thick \\\n"
1699 " -ynames 'dmUBLOCK' 'dmUB(1)' 'dmUB(-4)' \n"
1700 " where file q.1D contains the single line \n"
1701 " 10:1 60:2 110:4 160:10 210:20 260:30 \n"
1702 " Note how the 'dmUBLOCK(-4)' curve (green) peaks at 1 for the 3rd \n"
1703 " stimulus, and peaks at larger values for the later (longer) blocks. \n"
1704 " Whereas the 'dmUBLOCK' curve (black) peaks at 1 at only the longest \n"
1705 " blocks, and the 'dmUBLOCK(1)' curve (red) peaks at 1 for ALL blocks. \n"
1706 " ********************************************************************* \n"
1707 " \n"
1708 "[-stim_times_FSL k tname Rmodel] \n"
1709 " This option allows you to input FSL-style 3-column timing files, \n"
1710 " where each line corresponds to one stimulus event/block; the \n"
1711 " line '40 20 1' means 'stimulus starts at 40 seconds, lasts for \n"
1712 " 20 seconds, and is given amplitude 1'. Since in this format, \n"
1713 " each stimulus can have a different duration and get a different \n"
1714 " response amplitude, the 'Rmodel' must be one of the 'dm' \n"
1715 " duration-modulated options above ['dmUBLOCK(1)' is probably the \n"
1716 " most useful]. The amplitude modulation is taken to be like \n"
1717 " '-stim_times_AM1', where the given amplitude in the 'tname' file \n"
1718 " multiplies the basic response shape. \n"
1719 " *** We DO NOT advocate the use of this '_FSL' option, but it's here \n"
1720 " to make some scripting easier for some (unfortunate) people. \n"
1721 " *** The results of 3dDeconvolve (or 3dREMLfit) cannot be expected \n"
1722 " to be exactly the same as FSL FEAT, since the response model \n"
1723 " shapes are different, among myriad other details. \n"
1724 " *** You can also use '-stim_times_FS1' to indicate that the \n"
1725 " amplitude factor in the 'tname' file should be ignored and \n"
1726 " replaced with '1' in all cases. \n"
1727 " *** FSL FEAT only analyzes contiguous time series -- nothing like \n"
1728 " '-concat' allowing for multiple EPI runs is possible in FSL \n"
1729 " (AFAIK). So the FSL stimulus time format doesn't allow for \n"
1730 " this possibility. In 3dDeconvolve, you can get around this \n"
1731 " problem by using a line consisting of '* * *' to indicate the \n"
1732 " break between runs, as in the example below: \n"
1733 " 1 2 3 \n"
1734 " 4 5 6 \n"
1735 " * * * \n"
1736 " 7 8 9 \n"
1737 " that indicates 2 runs, the first of which has 2 stimuli and \n"
1738 " the second of which has just 1 stimulus. If there is a run \n"
1739 " that has NO copies of this type of stimulus, then you would \n"
1740 " use two '* * *' lines in succession. \n"
1741 " Of course, a file using the '* * *' construction will NOT be \n"
1742 " compatible with FSL! \n"
1743 " \n"
1744 "[-stim_times_IM k tname Rmodel] \n"
1745 " Similar, but each separate time in 'tname' will get a separate \n"
1746 " regressor; 'IM' means 'Individually Modulated' -- that is, each \n"
1747 " event will get its own amplitude estimated. Presumably you will \n"
1748 " collect these many amplitudes afterwards and do some sort of \n"
1749 " statistics or analysis on them. \n"
1750 " *N.B.: Each time in the 'tname' file will get a separate regressor. \n"
1751 " If some time is outside the duration of the imaging run(s), \n"
1752 " or if the response model for that time happens to hit only \n"
1753 " censored-out data values, then the corresponding regressor \n"
1754 " will be all zeros. Normally, 3dDeconvolve will not run \n"
1755 " if the matrix has any all zero columns. To carry out the \n"
1756 " analysis, use the '-allzero_OK' option. Amplitude estimates \n"
1757 " for all zero columns will be zero, and should be excluded \n"
1758 " from any subsequent analysis. (Probably you should fix the \n"
1759 " times in the 'tname' file instead of using '-allzero_OK'.) \n"
1760 " \n"
1761 "[-global_times] \n"
1762 "[-local_times] \n"
1763 " By default, 3dDeconvolve guesses whether the times in the 'tname' \n"
1764 " files for the various '-stim_times' options are global times \n"
1765 " (relative to the start of run #1) or local times (relative to \n"
1766 " the start of each run). With one of these options, you can force \n"
1767 " the times to be considered as global or local for '-stim_times' \n"
1768 " options that are AFTER the '-local_times' or '-global_times'. \n"
1769 " ** Using one of these options (most commonly, '-local_times') is \n"
1770 " VERY highly recommended. \n"
1771 " \n"
1772 "[-stim_times_millisec] \n"
1773 " This option scales all the times in any '-stim_times_*' option by \n"
1774 " 0.001; the purpose is to allow you to input the times in ms instead \n"
1775 " of in s. This factor will be applied to ALL '-stim_times' inputs, \n"
1776 " before or after this option on the command line. This factor will \n"
1777 " be applied before -stim_times_subtract, so the subtraction value \n"
1778 " (if present) must be given in seconds, NOT milliseconds! \n"
1779 " \n"
1780 "[-stim_times_subtract SS] \n"
1781 " This option means to subtract 'SS' seconds from each time encountered \n"
1782 " in any '-stim_times*' option. The purpose of this option is to make \n"
1783 " it simple to adjust timing files for the removal of images from the \n"
1784 " start of each imaging run. Note that this option will be useful \n"
1785 " only if both of the following are true: \n"
1786 " (a) each imaging run has exactly the same number of images removed \n"
1787 " (b) the times in the 'tname' files were not already adjusted for \n"
1788 " these image removal (i.e., the times refer to the image runs \n"
1789 " as acquired, not as input to 3dDeconvolve). \n"
1790 " In other words, use this option with understanding and care! \n"
1791 " ** Note that the subtraction of 'SS' applies to ALL '-stim_times' \n"
1792 " inputs, before or after this option on the command line! \n"
1793 " ** And it applies to global times and local times alike! \n"
1794 " ** Any time (thus subtracted) below 0 will be ignored, as falling \n"
1795 " before the start of the imaging run. \n"
1796 " ** This option, and the previous one, are simply for convenience, to \n"
1797 " help you in setting up your '-stim_times*' timing files from \n"
1798 " whatever source you get them. \n"
1799 " \n"
1800 "[-basis_normall a] \n"
1801 " Normalize all basis functions for '-stim_times' to have \n"
1802 " amplitude 'a' (must have a > 0). The peak absolute value \n"
1803 " of each basis function will be scaled to be 'a'. \n"
1804 " NOTES: \n"
1805 " * -basis_normall only affect -stim_times options that \n"
1806 " appear LATER on the command line \n"
1807 " * The main use for this option is for use with the \n"
1808 " 'EXPR' basis functions. \n"
1809 #if 0
1810 " \n"
1811 "[-slice_base k sname] \n"
1812 " Inputs the k'th stimulus time series from file sname, \n"
1813 " AND specifies that this regressor belongs to the baseline, \n"
1814 " AND specifies that the regressor is different for each slice in \n"
1815 " the input 3D+time dataset. The sname file should have exactly \n"
1816 " nz columns of input, where nz=number of slices, OR it should \n"
1817 " have exactly 1 column, in which case this input is the same \n"
1818 " as using '-stim_file k sname' and '-stim_base k'. \n"
1819 " N.B.: * You can't use -stim_minlag or -stim_maxlag or -stim_nptr \n"
1820 " with this value of k. \n"
1821 " * You can't use this option with -input1D or -nodata. \n"
1822 " * The intended use of this option is to provide slice- \n"
1823 " dependent physiological noise regressors, e.g., from program \n"
1824 " 1dCRphase. \n"
1825 " *** NOT YET IMPLEMENTED *** \n"
1826 #endif
1827 " \n"
1828 "******* General linear test (GLT) options ******* \n"
1829 " \n"
1830 "-num_glt num num = number of general linear tests (GLTs) \n"
1831 " (0 <= num) [default: num = 0] \n"
1832 " **N.B.: You only need this option if you have \n"
1833 " more than 10 GLTs specified; the program \n"
1834 " has built-in space for 10 GLTs, and \n"
1835 " this option is used to expand that space. \n"
1836 " If you use this option, you should place \n"
1837 " it on the command line BEFORE any of the \n"
1838 " other GLT options. \n"
1839 "[-glt s gltname] Perform s simultaneous linear tests, as specified \n"
1840 " by the matrix contained in file 'gltname' \n"
1841 "[-glt_label k glabel] glabel = label for kth general linear test \n"
1842 "[-gltsym gltname] Read the GLT with symbolic names from the file \n"
1843 " 'gltname'; see the document below for details: \n"
1844 " https://afni.nimh.nih.gov/pub/dist/doc/misc/Decon/DeconSummer2004.html\n"
1845 #if 0
1846 "[-TR_irc dt] \n"
1847 " Use 'dt' as the stepsize for computation of integrals in -IRC_times \n"
1848 " options. Default is to use value given in '-TR_times'. \n"
1849 #endif
1850 " \n"
1851 "******* Options to create 3D+time datasets ******* \n"
1852 " \n"
1853 "[-iresp k iprefix] iprefix = prefix of 3D+time output dataset which \n"
1854 " will contain the kth estimated impulse response \n"
1855 "[-tshift] Use cubic spline interpolation to time shift the \n"
1856 " estimated impulse response function, in order to\n"
1857 " correct for differences in slice acquisition \n"
1858 " times. Note that this effects only the 3D+time \n"
1859 " output dataset generated by the -iresp option. \n"
1860 " **N.B.: This option only applies to the 'old' style of \n"
1861 " deconvolution analysis. Do not use this with \n"
1862 " -stim_times analyses! \n"
1863 "[-sresp k sprefix] sprefix = prefix of 3D+time output dataset which \n"
1864 " will contain the standard deviations of the \n"
1865 " kth impulse response function parameters \n"
1866 "[-fitts fprefix] fprefix = prefix of 3D+time output dataset which \n"
1867 " will contain the (full model) time series fit \n"
1868 " to the input data \n"
1869 "[-errts eprefix] eprefix = prefix of 3D+time output dataset which \n"
1870 " will contain the residual error time series \n"
1871 " from the full model fit to the input data \n"
1872 "[-TR_times dt] \n"
1873 " Use 'dt' as the stepsize for output of -iresp and -sresp file \n"
1874 " for response models generated by '-stim_times' options. \n"
1875 " Default is same as time spacing in the '-input' 3D+time dataset. \n"
1876 " The units here are in seconds! \n"
1877 " \n"
1878 "**** Options to control the contents of the output bucket dataset **** \n"
1879 " \n"
1880 "[-fout] Flag to output the F-statistics for each stimulus \n"
1881 " ** F tests the null hypothesis that each and every \n"
1882 " beta coefficient in the stimulus set is zero \n"
1883 " ** If there is only 1 stimulus class, then its \n"
1884 " '-fout' value is redundant with the Full_Fstat \n"
1885 " computed for all stimulus coefficients together.\n"
1886 "[-rout] Flag to output the R^2 statistics \n"
1887 "[-tout] Flag to output the t-statistics \n"
1888 " ** t tests a single beta coefficient against zero \n"
1889 " ** If a stimulus class has only one regressor, then\n"
1890 " F = t^2 and the F statistic is redundant with t.\n"
1891 "[-vout] Flag to output the sample variance (MSE) map \n"
1892 "[-nobout] Flag to suppress output of baseline coefficients \n"
1893 " (and associated statistics) [** DEFAULT **] \n"
1894 "[-bout] Flag to turn on output of baseline coefs and stats. \n"
1895 " ** Will make the output dataset larger. \n"
1896 "[-nocout] Flag to suppress output of regression coefficients \n"
1897 " (and associated statistics) \n"
1898 " ** Useful if you just want GLT results. \n"
1899 "[-full_first] Flag to specify that the full model statistics will \n"
1900 " be first in the bucket dataset [** DEFAULT **] \n"
1901 "[-nofull_first] Flag to specify that full model statistics go last \n"
1902 "[-nofullf_atall] Flag to turn off the full model F statistic \n"
1903 " ** DEFAULT: the full F is always computed, even if\n"
1904 " sub-model partial F's are not ordered with -fout. \n"
1905 "[-bucket bprefix] Create one AFNI 'bucket' dataset containing various \n"
1906 " parameters of interest, such as the estimated IRF \n"
1907 " coefficients, and full model fit statistics. \n"
1908 " Output 'bucket' dataset is written to bprefix. \n"
1909 "[-nobucket] Don't output a bucket dataset. By default, the \n"
1910 " program uses '-bucket Decon' if you don't give \n"
1911 " either -bucket or -nobucket on the command line. \n"
1912 "[-noFDR] Don't compute the statistic-vs-FDR curves for the \n"
1913 " bucket dataset. \n"
1914 " [same as 'setenv AFNI_AUTOMATIC_FDR NO'] \n"
1915 " \n"
1916 "[-xsave] Flag to save X matrix into file bprefix.xsave \n"
1917 " (only works if -bucket option is also given) \n"
1918 "[-noxsave] Don't save X matrix [this is the default] \n"
1919 "[-cbucket cprefix] Save the regression coefficients (no statistics) \n"
1920 " into a dataset named 'cprefix'. This dataset \n"
1921 " will be used in a -xrestore run instead of the \n"
1922 " bucket dataset, if possible. \n"
1923 " ** Also, the -cbucket and -x1D output can be combined \n"
1924 " in 3dSynthesize to produce 3D+time datasets that \n"
1925 " are derived from subsets of the regression model \n"
1926 " [generalizing the -fitts option, which produces] \n"
1927 " [a 3D+time dataset derived from the full model]. \n"
1928 " \n"
1929 "[-xrestore f.xsave] Restore the X matrix, etc. from a previous run \n"
1930 " that was saved into file 'f.xsave'. You can \n"
1931 " then carry out new -glt tests. When -xrestore \n"
1932 " is used, most other command line options are \n"
1933 " ignored. \n"
1934 " \n"
1935 "[-float] Write output datasets in float format, instead of \n"
1936 " as scaled shorts [** now the default **] \n"
1937 "[-short] Write output as scaled shorts [no longer default] \n"
1938 " \n"
1939 "***** The following options control miscellanous outputs ***** \n"
1940 " \n"
1941 "[-quiet] Flag to suppress most screen output \n"
1942 "[-xout] Flag to write X and inv(X'X) matrices to screen \n"
1943 "[-xjpeg filename] Write a JPEG file graphing the X matrix \n"
1944 " * If filename ends in '.png', a PNG file is output\n"
1945 "[-x1D filename] Save X matrix to a .xmat.1D (ASCII) file [default]\n"
1946 " ** If 'filename' is 'stdout:', the file is written \n"
1947 " to standard output, and could be piped into \n"
1948 " 1dplot (some examples are given earlier). \n"
1949 " * This can be used for quick checks to see if your\n"
1950 " inputs are setting up a 'reasonable' matrix. \n"
1951 "[-nox1D] Don't save X matrix [a very bad idea] \n"
1952 "[-x1D_uncensored ff] Save X matrix to a .xmat.1D file, but WITHOUT \n"
1953 " ANY CENSORING. Might be useful in 3dSynthesize. \n"
1954 "[-x1D_regcensored f] Save X matrix to a .xmat.1D file with the \n"
1955 " censoring imposed by adding 0-1 columns instead \n"
1956 " excising the censored rows. \n"
1957 "[-x1D_stop] Stop running after writing .xmat.1D files. \n"
1958 " * Useful for testing, or if you are going to \n"
1959 " run 3dREMLfit instead -- that is, you are just \n"
1960 " using 3dDeconvolve to set up the matrix file. \n"
1961 "[-progress n] Write statistical results for every nth voxel \n"
1962 " * To let you know that something is happening! \n"
1963 "[-fdisp fval] Write statistical results to the screen, for those\n"
1964 " voxels whose full model F-statistic is > fval \n"
1965 "[-help] Oh go ahead, try it! \n"
1966 );
1967
1968 #ifdef PROC_MAX
1969 printf( "\n"
1970 "**** Multiple CPU option (local CPUs only, no networking) ****\n"
1971 "\n"
1972 " -jobs J Run the program with 'J' jobs (sub-processes).\n"
1973 " On a multi-CPU machine, this can speed the\n"
1974 " program up considerably. On a single CPU\n"
1975 " machine, using this option would be silly.\n"
1976 " * J should be a number from 1 up to the\n"
1977 " number of CPUs sharing memory on the system.\n"
1978 " * J=1 is normal (single process) operation.\n"
1979 " * The maximum allowed value of J is %d.\n"
1980 " * Unlike other parallelized AFNI programs, this one\n"
1981 " does not use OpenMP; it directly uses fork()\n"
1982 " and shared memory to run multiple processes.\n"
1983 " * For more information on parallelizing, see\n"
1984 " https://afni.nimh.nih.gov/afni/doc/misc/afni_parallelize\n"
1985 " * Also use -mask or -automask to get more speed; cf. 3dAutomask.\n"
1986 , PROC_MAX ) ;
1987
1988 printf( "\n"
1989 "-virtvec To save memory, write the input dataset to a temporary file\n"
1990 " and then read data vectors from it only as needed. This option\n"
1991 " is for Javier and will probably not be useful for anyone else.\n"
1992 " And it only takes effect if -jobs is greater than 1.\n"
1993 ) ;
1994 #endif
1995
1996 printf("\n"
1997 "** NOTE **\n"
1998 "This version of the program has been compiled to use\n"
1999 #ifdef FLOATIZE
2000 "single precision arithmetic for most internal calculations.\n"
2001 #else
2002 "double precision arithmetic for most internal calculations.\n"
2003 #endif
2004 ) ;
2005
2006 PRINT_COMPILE_DATE; exit(0);
2007 }
2008
2009
2010 /*---------------------------------------------------------------------------*/
2011 /*
2012 Routine to initialize the input options.
2013 */
2014
initialize_options(DC_options * option_data)2015 void initialize_options
2016 (
2017 DC_options * option_data /* deconvolution program options */
2018 )
2019
2020 {
2021 int is; /* input stimulus time series index */
2022
2023 /*----- Initialize default values -----*/
2024 option_data->nxyz = -1;
2025 option_data->nt = -1;
2026 option_data->NFirst = -1;
2027 option_data->NLast = -1;
2028 option_data->N = 0;
2029 option_data->polort = 1;
2030 option_data->rms_min = 0.0;
2031 option_data->quiet = 0;
2032 option_data->progress = 0;
2033 option_data->fdisp = -1.0;
2034 option_data->nodata = 0;
2035 option_data->p = 0;
2036 option_data->q = 0;
2037 option_data->qp = 0;
2038 option_data->nbricks = 0;
2039 option_data->nocond = 0; /* 15 Jul 2004 */
2040 option_data->nodata_NT= 0; /* 27 Apr 2005 */
2041 option_data->nodata_TR= 0.0;
2042 option_data->force_TR = 0.0; /* 18 Aug 2008 */
2043 option_data->coldat = NULL; /* 06 Mar 2007 */
2044
2045 option_data->tcat_noblock = 0 ; /* 06 Jan 2011 */
2046
2047 option_data->xjpeg_filename = NULL ; /* 21 Jul 2004 */
2048 option_data->x1D_filename = NULL ;
2049 option_data->x1D_unc = NULL ;
2050 option_data->x1D_regcen = NULL ; /* 16 Aug 2019 */
2051 option_data->nox1D = 0 ;
2052 option_data->x1D_stop = 0 ;
2053
2054 /*----- Initialize stimulus options -----*/
2055 option_data->num_stimts = 0;
2056 option_data->stim_filename = NULL;
2057 option_data->stim_label = NULL;
2058 option_data->stim_base = NULL;
2059 option_data->stim_minlag = NULL;
2060 option_data->stim_maxlag = NULL;
2061 option_data->stim_nptr = NULL;
2062 option_data->iresp_filename = NULL;
2063 option_data->sresp_filename = NULL;
2064 option_data->slice_base = NULL ;
2065 option_data->num_slice_base = 0 ;
2066
2067 /*----- Initialize glt options -----*/
2068 option_data->num_glt = 0;
2069 option_data->glt_filename = NULL;
2070 option_data->glt_label = NULL;
2071 option_data->glt_rows = NULL;
2072
2073 /*----- Initialize output flags -----*/
2074 option_data->tshift = 0;
2075 option_data->fout = 0;
2076 option_data->do_fullf = 1 ; /* 23 Mar 2007 */
2077 option_data->rout = 0;
2078 option_data->tout = 0;
2079 option_data->vout = 0;
2080 option_data->xout = 0;
2081 option_data->nobout = 1; /* 13 Mar 2007: on by default now */
2082 option_data->nocout = 0;
2083 option_data->full_first = 1; /* 13 Mar 2007; on by default now */
2084
2085 /*----- Initialize character strings -----*/
2086 option_data->input_filename = NULL;
2087 option_data->mask_filename = NULL;
2088 option_data->input1D_filename = NULL;
2089 option_data->input1D_TR = 0.0;
2090 option_data->censor_filename = NULL;
2091 option_data->concat_filename = NULL;
2092 option_data->bucket_filename = NULL;
2093 option_data->fitts_filename = NULL;
2094 option_data->errts_filename = NULL;
2095
2096 option_data->automask = 0 ; /* 15 Apr 2005 */
2097 option_data->nobucket = 0 ; /* 03 May 2007 */
2098
2099 if( AFNI_noenv("AFNI_SKIP_SATCHECK") ) dont_do_satcheck = 0; /* 23 Dec 2011 */
2100 }
2101
2102
2103 /*---------------------------------------------------------------------------*/
2104 /*
2105 Routine to initialize the stimulus options.
2106 */
2107
initialize_stim_options(DC_options * option_data,int num_stimts)2108 void initialize_stim_options
2109 (
2110 DC_options * option_data, /* deconvolution program options */
2111 int num_stimts /* number of input stimulus time series */
2112 )
2113
2114 {
2115 int is; /* input stimulus time series index */
2116
2117 ENTRY("initialize_stim_options") ;
2118
2119 /*----- Set number of input stimulus time series -----*/
2120 option_data->num_stimts = num_stimts;
2121
2122
2123 /*----- Allocate memory for stimulus options -----*/
2124 option_data->stim_filename = (char **) malloc (sizeof(char *) * num_stimts);
2125 MTEST (option_data->stim_filename);
2126 option_data->stim_label = (char **) malloc (sizeof(char *) * num_stimts);
2127 MTEST (option_data->stim_label);
2128 option_data->stim_base = (int *) malloc (sizeof(int) * num_stimts);
2129 MTEST (option_data->stim_base);
2130 option_data->stim_minlag = (int *) malloc (sizeof(int) * num_stimts);
2131 MTEST (option_data->stim_minlag);
2132 option_data->stim_maxlag = (int *) malloc (sizeof(int) * num_stimts);
2133 MTEST (option_data->stim_maxlag);
2134 option_data->stim_nptr = (int *) malloc (sizeof(int) * num_stimts);
2135 MTEST (option_data->stim_nptr);
2136 option_data->iresp_filename = (char **) malloc (sizeof(char *) * num_stimts);
2137 MTEST (option_data->iresp_filename);
2138 option_data->sresp_filename = (char **) malloc (sizeof(char *) * num_stimts);
2139 MTEST (option_data->sresp_filename);
2140 option_data->slice_base = (int *) malloc (sizeof(int) * num_stimts);
2141 MTEST (option_data->slice_base);
2142
2143 /* 10 Aug 2004: add space for basis function expansions */
2144
2145 basis_stim = (basis_expansion **)malloc(sizeof(basis_expansion *)*num_stimts);
2146 basis_times = (MRI_IMAGE **) malloc(sizeof(MRI_IMAGE *) *num_stimts);
2147 basis_vect = (MRI_IMAGE **) malloc(sizeof(MRI_IMAGE *) *num_stimts);
2148
2149 /*----- Initialize stimulus options -----*/
2150 for (is = 0; is < num_stimts; is++)
2151 {
2152 option_data->stim_filename[is] = NULL;
2153 option_data->stim_label[is] = malloc (sizeof(char)*THD_MAX_NAME);
2154 MTEST (option_data->stim_label[is]);
2155 sprintf (option_data->stim_label[is], "Stim#%d", is+1);
2156
2157 option_data->stim_base[is] = 0;
2158 option_data->stim_minlag[is] = 0;
2159 option_data->stim_maxlag[is] = 0;
2160 option_data->stim_nptr[is] = 1;
2161 option_data->slice_base[is] = 0;
2162
2163 option_data->iresp_filename[is] = NULL;
2164 option_data->sresp_filename[is] = NULL;
2165
2166 basis_stim [is] = NULL ; /* 10 Aug 2004 */
2167 basis_times[is] = NULL ;
2168 basis_vect [is] = NULL ;
2169 }
2170
2171 EXRETURN ;
2172 }
2173
2174 /*---------------------------------------------------------------------------*/
2175
extend_stim_options(DC_options * option_data,int nadd)2176 void extend_stim_options( DC_options *option_data , int nadd )
2177 {
2178 int is , num_old , num_new ;
2179
2180 ENTRY("extend_stim_options") ;
2181
2182 if( option_data == NULL || nadd <= 0 ) EXRETURN ;
2183
2184
2185 num_old = option_data->num_stimts ;
2186 num_new = num_old + nadd ;
2187
2188 option_data->stim_filename = (char **)realloc(option_data->stim_filename ,sizeof(char *)*num_new);
2189 option_data->stim_label = (char **)realloc(option_data->stim_label ,sizeof(char *)*num_new);
2190 option_data->stim_base = (int *) realloc(option_data->stim_base ,sizeof(int) *num_new);
2191 option_data->stim_minlag = (int *) realloc(option_data->stim_minlag ,sizeof(int) *num_new);
2192 option_data->stim_maxlag = (int *) realloc(option_data->stim_maxlag ,sizeof(int) *num_new);
2193 option_data->stim_nptr = (int *) realloc(option_data->stim_nptr ,sizeof(int) *num_new);
2194 option_data->iresp_filename = (char **)realloc(option_data->iresp_filename,sizeof(char *)*num_new);
2195 option_data->sresp_filename = (char **)realloc(option_data->sresp_filename,sizeof(char *)*num_new);
2196 option_data->slice_base = (int *) realloc(option_data->slice_base ,sizeof(int) *num_new);
2197
2198 basis_stim = (basis_expansion **)realloc(basis_stim ,sizeof(basis_expansion *)*num_new);
2199 basis_times = (MRI_IMAGE **) realloc(basis_times,sizeof(MRI_IMAGE *) *num_new);
2200 basis_vect = (MRI_IMAGE **) realloc(basis_vect ,sizeof(MRI_IMAGE *) *num_new);
2201
2202 for (is = num_old; is < num_new; is++)
2203 {
2204 option_data->stim_filename[is] = NULL;
2205 option_data->stim_label[is] = malloc (sizeof(char)*THD_MAX_NAME);
2206 sprintf (option_data->stim_label[is], "Stim#%d", is+1);
2207
2208 option_data->stim_base[is] = 0;
2209 option_data->stim_minlag[is] = 0;
2210 option_data->stim_maxlag[is] = 0;
2211 option_data->stim_nptr[is] = 1;
2212 option_data->slice_base[is] = 0;
2213
2214 option_data->iresp_filename[is] = NULL;
2215 option_data->sresp_filename[is] = NULL;
2216
2217 basis_stim [is] = NULL ;
2218 basis_times[is] = NULL ;
2219 basis_vect [is] = NULL ;
2220 }
2221
2222 option_data->num_stimts = num_new ;
2223
2224 EXRETURN ;
2225 }
2226
2227 /*---------------------------------------------------------------------------*/
2228 /*
2229 Routine to initialize the general linear test options.
2230 */
2231
initialize_glt_options(DC_options * option_data,int num_glt)2232 void initialize_glt_options
2233 (
2234 DC_options * option_data, /* deconvolution program options */
2235 int num_glt /* number of general linear tests */
2236 )
2237
2238 {
2239 int iglt; /* glt index */
2240
2241 ENTRY("initialize_glt_options") ;
2242
2243
2244 /*----- Set number of general linear tests -----*/
2245 if (num_glt <= 0) EXRETURN ;
2246 else option_data->num_glt = num_glt;
2247
2248
2249 /*----- Allocate memory for glt options -----*/
2250 option_data->glt_filename = (char **) malloc (sizeof(char *) * num_glt);
2251 MTEST (option_data->glt_filename);
2252 option_data->glt_label = (char **) malloc (sizeof(char *) * num_glt);
2253 MTEST (option_data->glt_label);
2254 option_data->glt_rows = (int *) malloc (sizeof(int) * num_glt);
2255 MTEST (option_data->glt_rows);
2256
2257
2258 /*----- Initialize glt options -----*/
2259 for (iglt = 0; iglt < num_glt; iglt++)
2260 {
2261 option_data->glt_filename[iglt] = NULL;
2262 option_data->glt_label[iglt] = malloc (sizeof(char)*THD_MAX_NAME);
2263 MTEST (option_data->glt_label[iglt]);
2264 sprintf (option_data->glt_label[iglt], "GLT#%d ", iglt+1);
2265 option_data->glt_rows[iglt] = 0;
2266 }
2267
2268
2269 EXRETURN ;
2270 }
2271
2272
2273 /*---------------------------------------------------------------------------*/
2274 /*
2275 Routine to get user specified input options.
2276 */
2277
get_options(int argc,char ** argv,DC_options * option_data)2278 void get_options
2279 (
2280 int argc, /* number of input arguments */
2281 char ** argv, /* array of input arguments */
2282 DC_options * option_data /* deconvolution program options */
2283 )
2284
2285 {
2286 int nopt = 1; /* input option argument counter */
2287 int ival, index; /* integer input */
2288 float fval; /* float input */
2289 char message[THD_MAX_NAME]; /* error message */
2290 int k; /* stimulus time series index */
2291 int s; /* number of linear constraints in GLT */
2292 int iglt = 0; /* general linear test index */
2293 int nerr ;
2294 float ttmax=big_time ; /* 28 Aug 2015 */
2295 float gtmax=big_time ; /* same, for global timing 19 Jul 2017 [rickr] */
2296
2297 /*-- addto the arglist, if user wants to --*/
2298 { int new_argc ; char **new_argv ;
2299 addto_args( argc , argv , &new_argc , &new_argv ) ;
2300 if( new_argv != NULL ){ argc = new_argc ; argv = new_argv ; }
2301 }
2302
2303
2304 /*----- add to program log -----*/
2305 AFNI_logger (PROGRAM_NAME,argc,argv);
2306
2307
2308 /*----- initialize the input options -----*/
2309 initialize_options (option_data);
2310
2311 if( AFNI_yesenv("AFNI_FLOATIZE") ) floatout = 1 ; /* 17 Jan 2008 */
2312 else if( AFNI_yesenv("AFNI_SHORTIZE") ) floatout = 0 ; /* 15 Jun 2010 */
2313
2314 if( AFNI_yesenv("AFNI_3dDeconvolve_GOFORIT") ) goforit++ ; /* 07 Mar 2007 */
2315
2316 if( argc < 2 ) { /* for us lazy people 18 Jul 2013 [rickr] */
2317 display_help_menu(1);
2318 exit(0);
2319 }
2320
2321 /*----- main loop over input options -----*/
2322 while (nopt < argc )
2323 {
2324 /*----- does user request help menu? -----*/
2325 if (strcmp(argv[nopt], "-h") == 0 || strcmp(argv[nopt], "-help") == 0) {
2326 display_help_menu(strlen(argv[nopt])>3 ? 2:1);
2327 exit(0);
2328 }
2329
2330 if( strcmp(argv[nopt],"-OK") == 0 ){ nopt++; continue; } /* 14 Jul 2004 */
2331
2332 if( strcmp(argv[nopt],"-notrans") == 0 || strcmp(argv[nopt],"-nosat") == 0 ){
2333 dont_do_satcheck = 1 ; nopt++ ; continue ;
2334 }
2335 if( strcmp(argv[nopt],"-trans") == 0 || strcmp(argv[nopt],"-sat") == 0 ){
2336 dont_do_satcheck = 0 ; nopt++ ; continue ;
2337 }
2338
2339 /*----- -nocond ------*/
2340
2341 if( strcmp(argv[nopt],"-nocond") == 0 ){ /* 15 Jul 2004 */
2342 #ifndef FLOATIZE
2343 option_data->nocond = 1 ; /* only allow this for double precision */
2344 #else
2345 INFO_message("-nocond is ignored in 3dDeconvolve_f!") ;
2346 #endif
2347 nopt++ ; continue ;
2348 }
2349
2350 if( strcasecmp(argv[nopt],"-goforit") == 0 ){ /* 07 Mar 2007 */
2351 nopt++ ;
2352 if( nopt < argc && isdigit(argv[nopt][0]) )
2353 goforit += (int)strtod(argv[nopt++],NULL) ; /* 04 May 2007 */
2354 else
2355 goforit++ ;
2356 continue ;
2357 }
2358
2359 if( strcasecmp(argv[nopt],"-allzero_OK") == 0 ){ /* 30 May 2007 */
2360 allzero_OK++ ; use_psinv = 1 ; nopt++ ; continue ;
2361 }
2362
2363 if( strncmp(argv[nopt],"-sing",5) == 0 ){ /* 13 Aug 2004 */
2364 show_singvals = 1 ; option_data->nocond = 0 ;
2365 nopt++ ; continue ;
2366 }
2367
2368 /*----- -xjpeg filename ------*/
2369 if (strcmp(argv[nopt], "-xjpeg") == 0) /* 21 Jul 2004 */
2370 {
2371 nopt++;
2372 if (nopt >= argc) DC_error ("need argument after -xjpeg ");
2373 option_data->xjpeg_filename = malloc (sizeof(char)*ALEN(nopt));
2374 MTEST (option_data->xjpeg_filename);
2375 strcpy (option_data->xjpeg_filename, argv[nopt]);
2376 if( !STRING_HAS_SUFFIX_CASE(option_data->xjpeg_filename,".jpg") &&
2377 !STRING_HAS_SUFFIX_CASE(option_data->xjpeg_filename,".png") )
2378 strcat( option_data->xjpeg_filename , ".jpg" ) ;
2379 nopt++; continue;
2380 }
2381
2382 /*----- -x1D filename ------*/
2383 if (strcmp(argv[nopt], "-x1D") == 0) /* 28 Mar 2006 */
2384 {
2385 nopt++;
2386 if (nopt >= argc) DC_error ("need argument after -x1D ");
2387 option_data->x1D_filename = malloc (sizeof(char)*ALEN(nopt));
2388 MTEST (option_data->x1D_filename);
2389 strcpy (option_data->x1D_filename, argv[nopt]);
2390 if( strstr(option_data->x1D_filename,"1D") == NULL )
2391 strcat( option_data->x1D_filename , ".xmat.1D" ) ;
2392 nopt++; continue;
2393 }
2394
2395 if( strcmp(argv[nopt],"-nox1D") == 0 ){ /* 20 Mar 2007 */
2396 option_data->nox1D = 1 ; nopt++ ; continue ;
2397 }
2398
2399 if( strcmp(argv[nopt],"-x1D_stop") == 0 ){ /* 20 Mar 2007 */
2400 option_data->x1D_stop = 1; option_data->nox1D = 0; nopt++; continue;
2401 }
2402
2403 /*----- -x1D_unc filename ------*/
2404 if (strncmp(argv[nopt], "-x1D_unc",8) == 0) /* 25 Jun 2007 */
2405 {
2406 nopt++;
2407 if (nopt >= argc) DC_error ("need argument after -x1D_uncensored ");
2408 option_data->x1D_unc = malloc (sizeof(char)*ALEN(nopt));
2409 MTEST (option_data->x1D_unc);
2410 strcpy (option_data->x1D_unc, argv[nopt]);
2411 if( strstr(option_data->x1D_unc,"1D") == NULL )
2412 strcat( option_data->x1D_unc , ".xmat.1D" ) ;
2413 nopt++; continue;
2414 }
2415
2416 /*----- -x1D_regcen filename ------*/
2417 if (strncmp(argv[nopt], "-x1D_regcen",11) == 0) /* 16 Aug 2019 */
2418 {
2419 nopt++;
2420 if (nopt >= argc) DC_error ("need argument after -x1D_regcensored ");
2421 option_data->x1D_regcen = malloc (sizeof(char)*ALEN(nopt));
2422 MTEST (option_data->x1D_regcen);
2423 strcpy (option_data->x1D_regcen, argv[nopt]);
2424 if( strstr(option_data->x1D_regcen,"1D") == NULL )
2425 strcat( option_data->x1D_regcen , ".xmat.1D" ) ;
2426 nopt++; continue;
2427 }
2428
2429 /*----- 06 Jan 2011 -----*/
2430 if( strcmp(argv[nopt],"-noblock") == 0 ){
2431 option_data->tcat_noblock = 1 ; nopt++ ; continue ;
2432 }
2433
2434 /*----- -input filename -----*/
2435 if (strcmp(argv[nopt], "-input") == 0)
2436 {
2437 int iopt , slen ;
2438 nopt++;
2439 if (nopt >= argc) DC_error ("need argument after -input ");
2440 #if 0
2441 option_data->input_filename = malloc (sizeof(char)*ALEN(nopt));
2442 MTEST (option_data->input_filename);
2443 strcpy (option_data->input_filename, argv[nopt]);
2444 nopt++;
2445 #else /* 05 Aug 2004: multiple input datasets */
2446 slen = 0 ;
2447 for( iopt=nopt ; iopt < argc && argv[iopt][0] != '-' ; iopt++ )
2448 slen += strlen(argv[iopt])+8 ;
2449 option_data->input_filename = calloc(sizeof(char),slen) ;
2450 MTEST (option_data->input_filename);
2451 for( iopt=nopt ; iopt < argc && argv[iopt][0] != '-' ; iopt++ ){
2452 strcat( option_data->input_filename , argv[iopt] ) ;
2453 strcat( option_data->input_filename , " " ) ;
2454 }
2455 slen = strlen(option_data->input_filename) ;
2456 option_data->input_filename[slen-1] = '\0' ; /* trim last blank */
2457 nopt = iopt ;
2458 #endif
2459 { THD_3dim_dataset *dset ; int lmax ;
2460 dset = THD_open_dataset (option_data->input_filename);
2461 CHECK_OPEN_ERROR(dset,option_data->input_filename) ;
2462 lmax = DSET_NVALS(dset) ;
2463 /* compute gtmax, as ttmax for global timing 19 Jul 2017 [rickr] */
2464 /* (init to lmax if not in TCAT case) 4 Dec 2017 [rickr] */
2465 gtmax = lmax;
2466 if( DSET_IS_TCAT(dset) && !option_data->tcat_noblock ){
2467 int it ;
2468 gtmax = 0.0;
2469 for( lmax=2,it=0 ; it < dset->tcat_num ; it++ ) {
2470 lmax = MAX( lmax , dset->tcat_len[it] ) ;
2471 /* accumulate time points, scale by TR later */
2472 gtmax += dset->tcat_len[it];
2473 }
2474 }
2475
2476 /* if force_TR is set, apply it 5 Jul 2017 [rickr] */
2477 if( option_data->force_TR > 0.0 ) {
2478 ttmax = lmax * option_data->force_TR ;
2479 gtmax *= option_data->force_TR ; /* scale NT by TR */
2480 } else {
2481 ttmax = lmax * DSET_TR(dset) ;
2482 gtmax *= DSET_TR(dset) ; /* scale NT by TR */
2483 if( DSET_TR(dset) == 0.0 ) /* 23 Oct 2017 [rickr] */
2484 WARNING_message("-input dataset seems to have TR = 0.0");
2485 }
2486 DSET_delete(dset) ;
2487 }
2488
2489 continue;
2490 }
2491
2492 /*----- -STATmask fname -----*/
2493
2494 if( strcasecmp(argv[nopt],"-STATmask") == 0 ||
2495 strcasecmp(argv[nopt],"-FDRmask") == 0 ){
2496 nopt++ ;
2497 if( statmask != NULL ) DC_error("can't use -STATmask twice") ;
2498 if( nopt >= argc ) DC_error("need argument after -STATmask") ;
2499 statmask_name = strdup(argv[nopt]) ;
2500 statmask = THD_create_mask_from_string(statmask_name) ;
2501 if( statmask == NULL ){
2502 WARNING_message("-STATmask being ignored: can't use it") ;
2503 free(statmask_name) ; statmask_name = NULL ;
2504 }
2505 nopt++ ; continue ;
2506 }
2507
2508 /*----- -mask filename -----*/
2509 if (strcmp(argv[nopt], "-mask") == 0)
2510 {
2511 nopt++;
2512 if (nopt >= argc) DC_error ("need argument after -mask ");
2513 if( option_data->automask ) DC_error("can't use -mask AND -automask!") ;
2514 option_data->mask_filename = malloc (sizeof(char)*ALEN(nopt));
2515 MTEST (option_data->mask_filename);
2516 strcpy (option_data->mask_filename, argv[nopt]);
2517 nopt++;
2518 continue;
2519 }
2520
2521 /*---- -automask -----*/
2522 if( strcmp(argv[nopt],"-automask") == 0 ){ /* 15 Apr 2005 */
2523 if( option_data->mask_filename != NULL )
2524 DC_error("can't use -automask AND -mask!") ;
2525 option_data->automask = 1 ;
2526 nopt++ ; continue ;
2527 }
2528
2529
2530 /*----- -input1D filename -----*/
2531 if (strcmp(argv[nopt], "-input1D") == 0)
2532 {
2533 nopt++;
2534 if (nopt >= argc) DC_error ("need argument after -input1D ");
2535 option_data->input1D_filename =
2536 malloc (sizeof(char)*ALEN(nopt));
2537 MTEST (option_data->input1D_filename);
2538 strcpy (option_data->input1D_filename, argv[nopt]);
2539 nopt++;
2540 continue;
2541 }
2542
2543 /*----- -force_TR -------*/
2544 if (strcmp(argv[nopt], "-force_TR") == 0) /* 18 Aug 2008 */
2545 {
2546 /* if ttmax is alreay set (from -input), suggest putting -force_TR
2547 * earlier (this is for _IM, at least) 5 Jul 2017 [rickr] */
2548 if (ttmax < big_time)
2549 ERROR_exit("please apply -force_TR before -input\n"
2550 " (or use 3drefit so it is not needed)") ;
2551
2552 nopt++;
2553 if (nopt >= argc) DC_error ("need argument after -force_TR ");
2554 option_data->force_TR = (float)strtod(argv[nopt++],NULL) ;
2555 continue;
2556 }
2557
2558 /*----- -input1D TR --------*/
2559 if (strcmp(argv[nopt], "-TR_1D") == 0)
2560 {
2561 nopt++;
2562 if (nopt >= argc) DC_error ("need argument after -TR_1D ");
2563 option_data->input1D_TR = (float)strtod(argv[nopt++],NULL) ;
2564 continue;
2565 }
2566
2567 /*----- -noFDR [23 Jan 2008] -----*/
2568
2569 if( strcmp(argv[nopt],"-noFDR") == 0 ){
2570 do_FDR = 0 ; nopt++ ; continue ;
2571 }
2572
2573 /*----- -censor filename -----*/
2574 if (strcmp(argv[nopt], "-censor") == 0)
2575 {
2576 nopt++;
2577 if (nopt >= argc) DC_error ("need argument after -censor ");
2578 if( option_data->censor_filename != NULL )
2579 WARNING_message("second -censor option replacing first one!") ;
2580 option_data->censor_filename =
2581 malloc (sizeof(char)*ALEN(nopt));
2582 MTEST (option_data->censor_filename);
2583 strcpy (option_data->censor_filename, argv[nopt]);
2584 nopt++;
2585 continue;
2586 }
2587
2588 /*----- -CENSOR clist -----*/
2589
2590 if( strncmp(argv[nopt],"-CENSOR",7) == 0 ||
2591 strncmp(argv[nopt],"-censorTR",9) == 0 ){ /* RWCox - 01 Mar 2007 */
2592
2593 NI_str_array *nsar ;
2594 char *src=malloc(1), *cpt, *dpt ;
2595 int ns, r,a,b, nerr=0 ; int_triple rab ;
2596
2597 *src = '\0' ; /* cat all following options until starts with '-' */
2598 for( nopt++ ; nopt < argc && argv[nopt][0] != '-' ; nopt++ ){
2599 ns = strlen(argv[nopt]) ; if( ns == 0 ) continue ;
2600 src = realloc(src,strlen(src)+ns+2) ;
2601 strcat(src," ") ; strcat(src,argv[nopt]) ;
2602 }
2603 if( *src == '\0' ) DC_error("Bad argument after -CENSORTR") ;
2604 nsar = NI_decode_string_list( src , "," ) ; /* break into substrings */
2605 for( ns=0 ; ns < nsar->num ; ns++ ){ /* loop over substrings */
2606 cpt = nsar->str[ns] ; dpt = strchr(cpt,':') ; r = 0 ;
2607 if( *cpt == '\0' ) continue ; /* skip an empty string */
2608 if( dpt != NULL ){ /* found 'run:' */
2609 if( *cpt == '*' ){ /* wildcard = all runs */
2610 r = -666 ;
2611 } else {
2612 r = (int)strtol(cpt,NULL,10) ;
2613 if( r <= 0 ){ /* skip out */
2614 ERROR_message("-CENSORTR %s -- run index '%d' is bad! [nopt=%d]",nsar->str[ns],r,nopt);
2615 nerr++ ; continue ;
2616 }
2617 }
2618 cpt = dpt+1 ; /* skip to character after ':' */
2619 if( *cpt == '\0' ){ /* skip out */
2620 ERROR_message("-CENSORTR %s -- no data after run index! [nopt=%d]",nsar->str[ns],nopt);
2621 nerr++ ; continue ;
2622 }
2623 }
2624 a = (int)strtol(cpt,&dpt,10) ; /* get first index number */
2625 if( a < 0 ){ /* skip out */
2626 ERROR_message("-CENSORTR %s -- time index '%d' is bad! [nopt=%d]",nsar->str[ns],a,nopt);
2627 nerr++ ; continue ;
2628 }
2629 if( *dpt == '\0' ){ /* no second number */
2630 b = a ;
2631 } else { /* get second number */
2632 for( dpt++ ; *dpt != '\0' && !isdigit(*dpt) ; dpt++ ) ; /*nada*/
2633 b = (int)strtol(dpt,NULL,10) ;
2634 if( b < a || b < 0 ){ /* skip out */
2635 ERROR_message("-CENSORTR %s -- time indexes '%d' to '%d' is bad! [nopt=%d]",
2636 nsar->str[ns],a,b,nopt);
2637 nerr++ ; continue ;
2638 }
2639 }
2640 abc_CENSOR = (int_triple *)realloc( abc_CENSOR ,
2641 sizeof(int_triple)*(num_CENSOR+1) );
2642 rab.i = r; rab.j = a; rab.k = b; abc_CENSOR[num_CENSOR++] = rab ;
2643 } /* end of loop over -CENSORTR strings */
2644 if( nerr > 0 ) ERROR_exit("Can't proceed after -CENSORTR errors! [nopt=%d]",nopt) ;
2645 NI_delete_str_array(nsar) ; free(src) ;
2646 continue ; /* next option */
2647 }
2648
2649 /*----- -concat filename -----*/
2650 if (strcmp(argv[nopt], "-concat") == 0)
2651 {
2652 nopt++;
2653 if (nopt >= argc) DC_error ("need argument after -concat ");
2654 option_data->concat_filename =
2655 malloc (sizeof(char)*ALEN(nopt));
2656 MTEST (option_data->concat_filename);
2657 strcpy (option_data->concat_filename, argv[nopt]);
2658 nopt++;
2659 continue;
2660 }
2661
2662
2663 /*----- -nodata [NT [TR]] -----*/
2664 if (strcmp(argv[nopt], "-nodata") == 0){
2665 option_data->nodata = 1; nopt++;
2666
2667 /* 27 Apr 2005: check for additional numeric values */
2668
2669 if( nopt < argc && isdigit(argv[nopt][0]) ){ /* get NT */
2670 option_data->nodata_NT = (int)strtol(argv[nopt++],NULL,10) ;
2671 if( nopt < argc && isdigit(argv[nopt][0]) ){ /* also get TR */
2672 option_data->nodata_TR = (float)strtod(argv[nopt++],NULL) ;
2673 }
2674 }
2675 continue;
2676 }
2677
2678
2679 /*----- -nfirst num -----*/
2680 if (strcmp(argv[nopt], "-nfirst") == 0)
2681 {
2682 nopt++;
2683 if (nopt >= argc) DC_error ("need argument after -nfirst ");
2684 ival = -1 ; sscanf (argv[nopt], "%d", &ival);
2685 if (ival < 0)
2686 DC_error ("illegal argument after -nfirst ");
2687 option_data->NFirst = ival;
2688 nopt++;
2689 continue;
2690 }
2691
2692
2693 /*----- -nlast num -----*/
2694 if (strcmp(argv[nopt], "-nlast") == 0)
2695 {
2696 nopt++;
2697 if (nopt >= argc) DC_error ("need argument after -nlast ");
2698 ival = -1 ; sscanf (argv[nopt], "%d", &ival);
2699 if (ival < 0)
2700 DC_error ("illegal argument after -nlast ");
2701 option_data->NLast = ival;
2702 nopt++;
2703 continue;
2704 }
2705
2706 /*----- -dofsub ddd -----*/
2707
2708 if( strcmp(argv[nopt],"-dofsub") == 0 ){
2709 nopt++ ;
2710 if (nopt >= argc) DC_error ("need argument after -dofsub ");
2711 dofsub = (int)strtod(argv[nopt++],NULL) ;
2712 if( dofsub < 0 ) WARNING_message("-dofsub value is negative!") ;
2713 continue ;
2714 }
2715
2716 /*----- -polort num -----*/
2717 if (strcmp(argv[nopt], "-polort") == 0)
2718 {
2719 nopt++;
2720 if (nopt >= argc) DC_error ("need argument after -polort ");
2721 if( toupper(argv[nopt][0]) == 'A' ){ /* 16 Mar 2006: Automatic */
2722 ival = -666 ;
2723 } else {
2724 char *qpt ;
2725 ival = (int)strtod(argv[nopt],&qpt) ;
2726 if( *qpt != '\0' ) WARNING_message("Illegal non-numeric value after -polort") ;
2727 if (ival < -1)
2728 DC_error ("illegal argument after -polort ");
2729 }
2730 option_data->polort = ival;
2731 nopt++;
2732 continue;
2733 }
2734
2735 /*----- -legendre AND -nolegendre [15 Jul 2004] -----*/
2736
2737 if( strstr(argv[nopt],"legendre") != NULL ){
2738 legendre_polort = (strncmp(argv[nopt],"-leg",4) == 0) ;
2739 nopt++ ; continue ;
2740 }
2741
2742 /*----- -nosvd [20 Jul 2004] -----*/
2743
2744 if( strstr(argv[nopt],"svd") != NULL ){
2745 use_psinv = (strncmp(argv[nopt],"-svd",4) == 0) ;
2746 nopt++ ; continue ;
2747 }
2748
2749 /*----- -nodmbase [12 Aug 2004] -----*/
2750
2751 if( strstr(argv[nopt],"dmbase") != NULL ){
2752 demean_base = (strncmp(argv[nopt],"-dmb",4) == 0) ;
2753 nopt++ ; continue ;
2754 }
2755
2756 /*----- -noxsave [25 Jul 2004] -----*/
2757
2758 if( strstr(argv[nopt],"xsave") != NULL ){
2759 xsave = (strncmp(argv[nopt],"-xsave",5) == 0) ;
2760 nopt++ ; continue ;
2761 }
2762
2763 /*----- -xrestore [26 Jul 2004] -----*/
2764
2765 if( strcmp(argv[nopt],"-xrestore") == 0 ){
2766 nopt++;
2767 if( nopt >= argc) DC_error ("need argument after -xrestore ");
2768 xrestore_filename = strdup( argv[nopt] ) ;
2769 if( !THD_is_file(xrestore_filename) )
2770 DC_error("file named after -xrestore doesn't exist") ;
2771 xrestore = 1 ; nopt++ ; continue ;
2772 }
2773
2774 /*----- -quiet -----*/
2775 if (strcmp(argv[nopt], "-quiet") == 0)
2776 {
2777 option_data->quiet = 1; verb = 0 ;
2778 nopt++; continue;
2779 }
2780
2781 if (strncmp(argv[nopt],"-verb",5) == 0){ /* 01 Mar 2007 */
2782 verb++ ; nopt++ ; continue ;
2783 }
2784
2785 /*----- -float, etc. -----*/
2786 if( strncmp(argv[nopt],"-float",6) == 0 ){ /* 13 Mar 2007 */
2787 floatout = 1 ; nopt++ ; continue ;
2788 }
2789 if( strcmp(argv[nopt],"-short") == 0 ){
2790 if( floatout < 2 ) floatout = 0 ; /* 2 ==> floatout was forced on */
2791 nopt++ ; continue ;
2792 }
2793 if( strcmp(argv[nopt],"-datum") == 0 ){
2794 nopt++ ;
2795 if( nopt >= argc ) DC_error("need argument after -datum");
2796 if( strcmp(argv[nopt],"float") == 0 ) floatout = 1 ;
2797 else if( strcmp(argv[nopt],"short") == 0 ) floatout = 0 ;
2798 else DC_error("illegal type name after -datum") ;
2799 nopt++ ; continue ;
2800 }
2801
2802 /*----- -progress n -----*/
2803 if (strcmp(argv[nopt], "-progress") == 0)
2804 {
2805 nopt++;
2806 if (nopt >= argc) DC_error ("need argument after -progress ");
2807 ival = -1 ; sscanf (argv[nopt], "%d", &ival);
2808 if (ival < 0)
2809 DC_error ("illegal argument after -progress ");
2810 option_data->progress = ival;
2811 nopt++;
2812 continue;
2813 }
2814
2815
2816 /*----- -rmsmin r -----*/
2817 if (strcmp(argv[nopt], "-rmsmin") == 0)
2818 {
2819 nopt++;
2820 if (nopt >= argc) DC_error ("need argument after -rmsmin ");
2821 fval = -666.0 ; sscanf (argv[nopt], "%f", &fval);
2822 if (fval < 0.0)
2823 DC_error ("illegal argument after -rmsmin ");
2824 option_data->rms_min = fval;
2825 nopt++;
2826 continue;
2827 }
2828
2829
2830 /*----- -fdisp fval -----*/
2831 if (strcmp(argv[nopt], "-fdisp") == 0)
2832 {
2833 nopt++;
2834 if (nopt >= argc) DC_error ("need argument after -fdisp ");
2835 sscanf (argv[nopt], "%f", &fval);
2836 option_data->fdisp = fval;
2837 nopt++;
2838 continue;
2839 }
2840
2841
2842 /*----- -num_stimts num -----*/
2843 if (strcmp(argv[nopt], "-num_stimts") == 0)
2844 {
2845 nopt++;
2846 if (nopt >= argc) DC_error ("need argument after -num_stimts ");
2847 ival = -1 ; sscanf (argv[nopt], "%d", &ival);
2848 if (ival < 0)
2849 {
2850 DC_error ("-num_stimts num Require: num >= 0 ");
2851 }
2852
2853 initialize_stim_options (option_data, ival);
2854
2855 nopt++;
2856 continue;
2857 }
2858
2859 /*----- -TR_times basis_dtout [16 Aug 2004] -----*/
2860 if( strcmp(argv[nopt],"-TR_times") == 0 ){
2861 nopt++ ;
2862 if( nopt >= argc ) DC_error("need argument after -TR_times") ;
2863 basis_dtout = -1.0 ; sscanf( argv[nopt] , "%f" , &basis_dtout ) ;
2864 if( basis_dtout <= 0.0f )
2865 ERROR_exit("-TR_times '%s' is illegal [nopt=%d]\n",argv[nopt],nopt) ;
2866 nopt++ ; continue ;
2867 }
2868
2869 /*----- -TR_irc irc_dt [08 Sep 2004] -----*/
2870 if( strcmp(argv[nopt],"-TR_irc") == 0 ){
2871 nopt++ ;
2872 if( nopt >= argc ) DC_error("need argument after -TR_irc") ;
2873 irc_dt = -1.0 ; sscanf( argv[nopt] , "%f" , &irc_dt ) ;
2874 if( irc_dt <= 0.0f )
2875 ERROR_exit("-TR_irc '%s' is illegal [nopt=%d]",argv[nopt],nopt) ;
2876 nopt++ ; continue ;
2877 }
2878
2879 /*----- -basis_normall a [28 Apr 2005] -----*/
2880
2881 if( strcmp(argv[nopt],"-basis_normall") == 0 ){
2882 nopt++ ;
2883 if( nopt >= argc ) DC_error("need argument after -basis_normall") ;
2884 basis_normall = strtod( argv[nopt] , NULL ) ;
2885 if( basis_normall <= 0.0f )
2886 DC_error("value after -basis_normall is illegal!") ;
2887 nopt++ ; continue ;
2888 }
2889
2890 /*----- -local_times AND -global_times [16 Nov 2007] -----*/
2891
2892 if( strcmp(argv[nopt],"-local_times") == 0 ){
2893 basis_timetype = LOCAL_TIMES ; nopt++ ; continue ;
2894 }
2895 if( strcmp(argv[nopt],"-global_times") == 0 ){
2896 basis_timetype = GLOBAL_TIMES ; nopt++ ; continue ;
2897 }
2898 if( strcmp(argv[nopt],"-guess_times") == 0 ){
2899 basis_timetype = GUESS_TIMES ; nopt++ ; continue ;
2900 }
2901
2902 if( strcmp(argv[nopt],"-stim_times_subtract") == 0 ){ /** 24 Mar 2009 **/
2903 char *ept ;
2904 if( nopt+1 >= argc ) ERROR_exit("need 1 argument after %s [nopt=%d]",argv[nopt],nopt) ;
2905 stime_sub = (float)strtod(argv[++nopt],&ept) ;
2906 if( ept == argv[nopt] ){
2907 WARNING_message("%s %s doesn't make sense!",argv[nopt-1],argv[nopt]) ;
2908 stime_sub = 0.0f ;
2909 }
2910 nopt++ ; continue ;
2911 }
2912
2913 if( strcmp(argv[nopt],"-stim_times_millisec") == 0 ){ /** 24 Mar 2009 **/
2914 stime_fac = 0.001f ; nopt++ ; continue ;
2915 }
2916
2917 /*----- -stim_times k sname rtype [10 Aug 2004] -----*/
2918
2919 if( strncmp(argv[nopt],"-stim_times",11) == 0 ){
2920 char *suf = argv[nopt]+11 , *sopt=argv[nopt] , *model=NULL ;
2921 int nc=0,vdim=0,vmod=0 ; MRI_IMAGE *tim ;
2922 int do_FSL=0 ;
2923
2924 nopt++ ;
2925
2926 /* check for errors */
2927
2928 if( *suf != '\0' &&
2929 strcmp(suf,"_AM1") != 0 &&
2930 strcmp(suf,"_AM2") != 0 &&
2931 strcmp(suf,"_AMx") != 0 &&
2932 strcmp(suf,"_IM" ) != 0 &&
2933 strcmp(suf,"_FSL") != 0 &&
2934 strcmp(suf,"_FS1") != 0 )
2935 ERROR_exit("Unrecognized -stim_times variant: '%s' [nopt=%d]",sopt,nopt) ;
2936
2937 do_FSL = ( strcmp(suf,"_FSL") == 0 || strcmp(suf,"_FS1") == 0 ) ;
2938
2939 if( nopt+2 >= argc )
2940 ERROR_exit("need 3 arguments after %s [nopt=%d]",sopt,nopt) ;
2941
2942 /* get stim number */
2943
2944 ival = -1 ; sscanf( argv[nopt] , "%d" , &ival ) ;
2945
2946 if( ival < 1 || ival > option_data->num_stimts )
2947 ERROR_exit("'-stim_times %d' value out of range 1..%d [nopt=%d]\n",
2948 ival , option_data->num_stimts , nopt ) ;
2949
2950 k = ival-1 ; nopt++ ; /* k = stim array index */
2951
2952 /* get stim timing image */
2953
2954 if( option_data->stim_filename[k] != NULL )
2955 ERROR_exit("'%s %d' trying to over-write previous stimulus?! [nopt=%d]",
2956 sopt , ival , nopt ) ;
2957
2958 option_data->stim_filename[k] = strdup( argv[nopt] ) ;
2959
2960 basis_times[k] = mri_read_ascii_ragged_fvect(argv[nopt],basis_filler,0);
2961
2962 if( basis_times[k] == NULL || basis_times[k]->vdim <= 0 )
2963 ERROR_exit("'%s %d' can't read file '%s' [nopt=%d]\n",
2964 sopt , ival , argv[nopt] , nopt ) ;
2965
2966 if( do_FSL && basis_times[k]->vdim > 1 )
2967 ERROR_exit("'%s %d' file '%s' does not have correct FSL format [nopt=%d]",
2968 sopt , ival , argv[nopt] , nopt ) ;
2969
2970 if( basis_times[k]->vdim == 1 ){ /* scalar image */
2971 basis_times[k]->vdim = 0 ;
2972 basis_times[k]->kind = MRI_float ; /* mark as pure float type */
2973 tim = basis_times[k] ;
2974 } else {
2975 tim = mri_fvect_subimage( basis_times[k] , 0 ) ; /* extract times */
2976 }
2977
2978 if( do_FSL && tim->nx > 1 ){
2979 MRI_IMAGE *qim = mri_new(1,tim->ny,MRI_float) ;
2980 float *qar = MRI_FLOAT_PTR(qim) , *tar = MRI_FLOAT_PTR(tim) ;
2981 int qq ;
2982 for( qq=0 ; qq < tim->ny ; qq++ ) qar[qq] = tar[qq*tim->nx] ;
2983 tim = qim ;
2984 }
2985
2986 /* check number of reasonable times */
2987
2988 /* allow for global timing 19 Jul 2017 [rickr] */
2989 if( basis_timetype == GLOBAL_TIMES )
2990 nc = mri_counter( tim , 0.0f , gtmax ) ;
2991 else
2992 nc = mri_counter( tim , 0.0f , ttmax ) ;
2993
2994 if( tim != basis_times[k] ) mri_free(tim) ;
2995
2996 if( nc == 0 ) { /* 0 is okay, < 0 is not 26 Jul 2007 [rickr] */
2997 WARNING_message("'%s %d' didn't read any good times from file '%s'",
2998 sopt , ival , argv[nopt] ) ;
2999 /* but 0 might be a symptom of something bad 23 Oct 2017 [rickr] */
3000 if( (basis_timetype == GLOBAL_TIMES && gtmax == 0.0) ||
3001 (basis_timetype != GLOBAL_TIMES && ttmax == 0.0) )
3002 WARNING_message("run time seen as 0.0, verify TR and NT");
3003 } else if( nc < 0 )
3004 ERROR_exit("'%s %d' couldn't read valid times from file '%s' [nopt=%d]",
3005 sopt , ival , argv[nopt] , nopt ) ;
3006
3007 /** case: 1 number per time point: -stim_times **/
3008
3009 if( *suf == '\0' ){
3010
3011 if( basis_times[k]->vdim > 0 )
3012 ERROR_exit("'%s %d' file '%s' has %d auxiliary values per time point [nopt=%d]",
3013 sopt , ival , argv[nopt] , basis_times[k]->vdim-1 , nopt ) ;
3014
3015 /** case: 1 or more numbers per time point: -stim_times_IM **/
3016
3017 } else if( strcmp(suf,"_IM") == 0 ){
3018
3019 vdim = basis_times[k]->vdim ; /* will be 0 if there is aux data */
3020
3021 /** cases: multiple numbers per time point: -stim_times_AM* **/
3022
3023 } else if( strncmp(suf,"_AM",3) == 0 ){
3024
3025 vdim = basis_times[k]->vdim ; /* number of values per point */
3026 if( vdim < 2 ){ /* need at least 2 (time & amplitude) */
3027 if( strncmp(argv[nopt],"1D:",3) == 0 )
3028 ERROR_exit(
3029 "'%s %d' doesn't allow '1D:' type of input -- use a file [nopt=%d] :-(",
3030 sopt , ival , nopt ) ;
3031 else
3032 ERROR_exit(
3033 "'%s %d' file '%s' doesn't have any auxiliary values per time point! [nopt=%d] :-(\n%s",
3034 sopt , ival , argv[nopt] , nopt ,
3035 (nc > 0) ? " ==> You need at least 1 extra value 'married' to each stimulus start time\n"
3036 : " ==> To have NO valid times, use a time of '-1' and 'marry' it as desired\n"
3037 ) ;
3038 }
3039 else if( vdim-1 > BASIS_MAX_VDIM ) /* over the limit */
3040 ERROR_exit(
3041 "'%s %d' file '%s' has too many auxiliary values per time point! [nopt=%d] :-(",
3042 sopt , ival , argv[nopt] , nopt ) ;
3043 else /* juuusst right */
3044 INFO_message(
3045 "'%s %d %s' has %d auxiliary values per time point",
3046 sopt , ival , argv[nopt] , vdim-1 ) ;
3047
3048 } else if( do_FSL ){ /* 14 Nov 2013: FSL-like input */
3049
3050 MRI_IMAGE *newbt ;
3051
3052 /** mangle FSL 3 column input into a
3053 -stim_times_AM1 format for dmUBLOCK = time:amplitude:duration **/
3054
3055 if( basis_times[k]->nx > 3 )
3056 WARNING_message("'%s %d' file '%s' has more than 3 columns per row -- these will be ignored [nopt=%d]",
3057 sopt , ival , argv[nopt] , nopt ) ;
3058
3059 newbt = convert_FSL_to_fvect( basis_times[k] , strcmp(suf,"_FS1")==0 ) ;
3060 if( newbt == NULL )
3061 ERROR_exit("'%s %d' file '%s' -- can't convert from FSL format for some reason [nopt=%d]",
3062 sopt , ival , argv[nopt] , nopt ) ;
3063
3064 mri_free(basis_times[k]) ; basis_times[k] = newbt ; vdim = 3 ;
3065
3066 } else { /* should not happen */
3067
3068 ERROR_exit("Unknown -stim_times type of option: '%s' [nopt=%d]",sopt,nopt) ;
3069
3070 }
3071
3072 /** build regression model from symbolic name **/
3073 /** [05 Dec 2008] will also set vfun component
3074 = # of nonlinear function parameters from timing file **/
3075
3076 nopt++ ;
3077 model = argv[nopt] ;
3078 if( do_FSL && strncmp(model,"dm",2) != 0 ){
3079 WARNING_message("'%s %d' file '%s' -- model '%s' is not of 'dm' type -- replacing with 'dmUBLOCK(1)'",
3080 sopt , ival , argv[nopt-1] , model ) ;
3081 model = "dmUBLOCK(1)" ;
3082 }
3083 basis_stim[k] = basis_parser(model) ;
3084
3085 if( basis_stim[k] == NULL )
3086 ERROR_exit("'%s %d': don't understand basis function model '%s' [nopt=%d]",
3087 sopt , ival , model , nopt ) ;
3088
3089 /** Allow for vfun parameters to basis function [05 Dec 2008], **/
3090 /** and then vmod = number of amplitude modulation parameters. **/
3091 /** + Note that vmod = 0 and vfun > 0 is perfectly legitimate; **/
3092 /** + Note that vmod+vfun+1 = vdim is required when vdim > 0; **/
3093 /** the extra '+1' is for the actual stimulus time itself! **/
3094 /** + The order of 'married' parameters in the timing file is: **/
3095 /** stimtime*amp#1,...,amp#vmod:parm#1,...parm#vfun **/
3096 /** where 'amp#k' is the k-th amplitude modulation parameter **/
3097 /** and 'parm#j' is the j-th nonlinear parameter that will **/
3098 /** be passed to the basis function evaluator (e.g., width) **/
3099
3100 if( basis_stim[k]->vfun > 0 ){
3101
3102 if( basis_stim[k]->vfun > BASIS_MAX_VFUN ) /* should not happen! */
3103 ERROR_exit(
3104 "'%s %d': basis function model '%s' uses %d parameters;\n"
3105 " which is more than maximum allowed %d -- internal error!! [nopt=%d]" ,
3106 sopt , ival , model ,
3107 basis_stim[k]->vfun , BASIS_MAX_VFUN , nopt ) ;
3108
3109 basis_stim[k]->vmod = vmod = vdim - 1 - basis_stim[k]->vfun ;
3110
3111 if( vmod < 0 )
3112 ERROR_exit(
3113 "'%s %d': basis function model '%s' uses %d parameters,\n"
3114 " more than the %d found in timing file '%s' [nopt=%d]" ,
3115 sopt , ival , model ,
3116 basis_stim[k]->vfun , vdim-1 , argv[nopt-1] , nopt ) ;
3117
3118 INFO_message(
3119 "'%s %d': basis function model '%s' uses %d parameters,\n"
3120 " out of the %d found in timing file '%s'" ,
3121 sopt , ival , model ,
3122 basis_stim[k]->vfun , vdim-1 , argv[nopt-1] ) ;
3123
3124 } else if( vdim > 1 ){ /* vfun is 0, so all params are amplitudes */
3125
3126 basis_stim[k]->vmod = vmod = vdim - 1 ;
3127
3128 } else { /* no auxiliary parameters */
3129
3130 basis_stim[k]->vmod = vmod = 0 ;
3131
3132 }
3133
3134 basis_stim[k]->vdim = vdim ;
3135
3136 /** number of parameters = multiple of number of basis functions **/
3137
3138 basis_stim[k]->nparm = basis_stim[k]->nfunc ; /* # of params */
3139
3140 if( *suf == '\0' ){ /* 08 Mar 2007 */
3141
3142 basis_stim[k]->type = BASIS_SINGLE ; /* simplest possible case */
3143
3144 } else if( strcmp(suf,"_IM") == 0 ){ /* 16 Jul 2007 */
3145
3146 basis_stim[k]->type = BASIS_MODULATED_INDV;
3147 basis_stim[k]->nparm *= nc ; /* nc = number of time points */
3148 INFO_message("'%s %d %s' will have %d regressors",
3149 sopt,ival,argv[nopt-1],basis_stim[k]->nparm) ;
3150
3151 if( vmod != 0 )
3152 ERROR_exit("'%s %d %s' has %d amplitude modulation parameters - not legal! [nopt=%d]",
3153 sopt,ival,argv[nopt-1],vmod,nopt) ;
3154 if( basis_stim[k]->vfun > 0 && basis_stim[k]->vfun != vdim-1 )
3155 ERROR_exit("'%s %d %s' needs %d functional parameters but has %d [nopt=%d]",
3156 sopt,ival,argv[nopt-1],basis_stim[k]->vfun,vdim-1, nopt ) ;
3157
3158 } else if( strcmp(suf,"_AM1") == 0 || do_FSL ){
3159 /* amplitude */
3160 basis_stim[k]->type = BASIS_MODULATED_MONO; /* modulation */
3161
3162 } else if( strcmp(suf,"_AM2") == 0 || strcmp(suf,"_AMx") == 0 ){
3163
3164 if( vmod == 0 ){
3165 basis_stim[k]->type = BASIS_MODULATED_MONO;
3166 WARNING_message(
3167 "'%s %d %s' has 0 amplitude modulation parameters;"
3168 " ==> converting to be like -stim_times_AM1" ,
3169 sopt,ival,argv[nopt-1] ) ;
3170 } else {
3171 basis_stim[k]->type = BASIS_MODULATED_PAIR;
3172 basis_stim[k]->nparm *= (vmod+1) ; /* one for each amplitude */
3173
3174 if( nopt < argc-1 && argv[nopt+1][0] == ':' ){ /* 12 Jul 2012 */
3175 char *mss = strdup(argv[++nopt]) , *ccc,*ddd ; int iss ;
3176 basis_stim[k]->modsub = (float *)malloc(sizeof(float)*vmod) ;
3177 for( iss=0 ; iss < vmod ; iss++ ) basis_stim[k]->modsub[iss] = basis_filler ;
3178 for( ccc=mss ; *ccc != '\0' ; ccc++ ){ if( *ccc == ':' || *ccc == ',' ) *ccc = ' ' ; }
3179 INFO_message("'%s %d %s' has modulation parameter centering string '%s'",
3180 sopt,ival,argv[nopt-2],mss) ;
3181 for( ccc=mss,iss=0 ; iss < vmod ; iss++ ){
3182 for( ; isspace(*ccc) ; ccc++ ) ; /*nada*/
3183 if( isnumeric(*ccc) ){
3184 basis_stim[k]->modsub[iss] = (float)strtod(ccc,&ddd) ;
3185 ccc = ddd ;
3186 ININFO_message("'%s %d %s' will subtract %g from input modulation parameter #%d",
3187 sopt,ival,argv[nopt-2],basis_stim[k]->modsub[iss],iss+1) ;
3188 } else { /* skip to next nonblank location */
3189 for( ccc++ ; !isspace(*ccc) ; ccc++ ) ; /*nada*/
3190 ININFO_message("'%s %d %s' will subtract MEAN from modulation parameter #%d",
3191 sopt,ival,argv[nopt-2],iss+1) ;
3192 }
3193 }
3194 }
3195 }
3196 INFO_message("'%s %d %s' will have %d regressors",
3197 sopt,ival,argv[nopt-1],basis_stim[k]->nparm) ;
3198
3199 } else {
3200
3201 ERROR_exit("'%s %d' -- unrecognized sub-type of '-stim_times' option! [nopt=%d]",
3202 sopt , ival , nopt ) ;
3203
3204 }
3205
3206 basis_stim[k]->option = strdup(sopt) ; /* 08 Mar 2007 */
3207 basis_stim[k]->timetype = basis_timetype ; /* 16 Nov 2007 */
3208 basis_count++ ;
3209 nopt++ ; continue ;
3210 }
3211
3212 #if 0
3213 /*----- -slice_base k sname [12 Aug 2005] ------*/
3214
3215 if( strcmp(argv[nopt],"-slice_base") == 0 ){
3216 DC_error(" -slice_base ***NOT IMPLEMENTED YET*** !!!") ;
3217
3218 nopt++;
3219 if (nopt+1 >= argc) DC_error ("need 2 arguments after -slice_base");
3220
3221 ival = -1 ; sscanf (argv[nopt], "%d", &ival);
3222 if ((ival < 1) || (ival > option_data->num_stimts))
3223 DC_error ("-slice_base k sname Require: 1 <= k <= num_stimts");
3224 k = ival-1;
3225 nopt++;
3226 if( option_data->stim_filename[k] != NULL )
3227 ERROR_exit("'-slice_base %d' trying to overwrite previous stimulus [nopt=%d]",
3228 ival , nopt ) ;
3229
3230 option_data->stim_filename[k] = malloc(sizeof(char)*ALEN(nopt));
3231 MTEST(option_data->stim_filename[k]);
3232 strcpy(option_data->stim_filename[k], argv[nopt]);
3233 option_data->slice_base[k] = 1;
3234 option_data->stim_base[k] = 1; /* mark as being in the baseline */
3235 nopt++;
3236 continue;
3237 }
3238 #endif
3239
3240 /*----- -stim_file k sname -----*/
3241 if (strcmp(argv[nopt], "-stim_file") == 0)
3242 {
3243 nopt++;
3244 if (nopt+1 >= argc) DC_error ("need 2 arguments after -stim_file");
3245
3246 ival = -1 ; sscanf (argv[nopt], "%d", &ival);
3247 if ((ival < 1) || (ival > option_data->num_stimts))
3248 DC_error ("-stim_file k sname Require: 1 <= k <= num_stimts");
3249 k = ival-1;
3250 nopt++;
3251 if( option_data->stim_filename[k] != NULL )
3252 ERROR_exit("'-stim_file %d' trying to overwrite previous stimulus [nopt=%d]",
3253 ival , nopt ) ;
3254
3255 option_data->stim_filename[k] = malloc (sizeof(char)*ALEN(nopt));
3256 MTEST (option_data->stim_filename[k]);
3257 strcpy (option_data->stim_filename[k], argv[nopt]);
3258 nopt++;
3259 continue;
3260 }
3261
3262
3263 /*----- -stim_label k slabel -----*/
3264 if (strcmp(argv[nopt], "-stim_label") == 0)
3265 {
3266 char *qq ;
3267 nopt++;
3268 if (nopt+1 >= argc) DC_error ("need 2 arguments after -stim_label");
3269
3270 ival = -1 ; sscanf (argv[nopt], "%d", &ival);
3271 if ((ival < 1) || (ival > option_data->num_stimts))
3272 DC_error ("-stim_label k slabel Require: 1 <= k <= num_stimts");
3273 k = ival-1;
3274 nopt++;
3275
3276 if( strncmp(option_data->stim_label[k],"Stim#",5) != 0 )
3277 WARNING_message("-stim_label %d '%s' replacing old label '%s'",
3278 ival , argv[nopt] , option_data->stim_label[k] ) ;
3279
3280 strcpy (option_data->stim_label[k], argv[nopt]);
3281 nopt++; continue;
3282 }
3283
3284 /*----- -ortvec filename label -----*/
3285 if( strcasecmp(argv[nopt],"-ortvec") == 0 ||
3286 strcasecmp(argv[nopt],"-inati" ) == 0 ){
3287 MRI_IMAGE *oim ;
3288 if( ++nopt >= argc-1 ) DC_error ("need 2 arguments after -ortvec") ;
3289 oim = mri_read_1D( argv[nopt] ) ;
3290 if( oim == NULL ) ERROR_exit("3dDeconvolve: -ortvec can't read file '%s'",argv[nopt]) ;
3291 if( oim->nx < 2 ) ERROR_exit("3dDeconvolve: -ortvec %s has nx < 2" ,argv[nopt]) ;
3292 nopt++ ;
3293 if( argv[nopt][0] != '-' && THD_filename_ok(argv[nopt]) )
3294 mri_add_name( argv[nopt] , oim ) ;
3295 else
3296 mri_add_name( "ortvec" , oim ) ;
3297 if( ortar == NULL ) INIT_IMARR(ortar) ;
3298 ADDTO_IMARR(ortar,oim) ;
3299 nopt++ ; continue ;
3300 }
3301
3302 /*----- -stim_base k -----*/
3303 if (strcmp(argv[nopt], "-stim_base") == 0)
3304 {
3305 nopt++;
3306 if (nopt >= argc)
3307 DC_error ("need 1 argument after -stim_base");
3308
3309 ival = -1 ; sscanf (argv[nopt], "%d", &ival);
3310 if ((ival < 1) || (ival > option_data->num_stimts))
3311 DC_error ("-stim_base k Require: 1 <= k <= num_stimts");
3312 k = ival-1;
3313 option_data->stim_base[k] = 1; /* mark as being in the baseline */
3314 nopt++;
3315 continue;
3316 }
3317
3318
3319 /*----- -stim_minlag k lag -----*/
3320 if (strcmp(argv[nopt], "-stim_minlag") == 0)
3321 {
3322 nopt++;
3323 if (nopt+1 >= argc)
3324 DC_error ("need 2 arguments after -stim_minlag");
3325
3326 ival = -1 ; sscanf (argv[nopt], "%d", &ival);
3327 if ((ival < 1) || (ival > option_data->num_stimts))
3328 DC_error ("-stim_minlag k lag Require: 1 <= k <= num_stimts");
3329 k = ival-1;
3330 nopt++;
3331
3332 ival = -1 ; sscanf (argv[nopt], "%d", &ival);
3333 if (ival < 0)
3334 DC_error ("-stim_minlag k lag Require: 0 <= lag");
3335 option_data->stim_minlag[k] = ival;
3336 nopt++;
3337 continue;
3338 }
3339
3340
3341 /*----- -stim_maxlag k lag -----*/
3342 if (strcmp(argv[nopt], "-stim_maxlag") == 0)
3343 {
3344 nopt++;
3345 if (nopt+1 >= argc)
3346 DC_error ("need 2 arguments after -stim_maxlag");
3347
3348 ival = -1 ; sscanf (argv[nopt], "%d", &ival);
3349 if ((ival < 1) || (ival > option_data->num_stimts))
3350 DC_error ("-stim_maxlag k lag Require: 1 <= k <= num_stimts");
3351 k = ival-1;
3352 nopt++;
3353
3354 ival = -1 ; sscanf (argv[nopt], "%d", &ival);
3355 if (ival < 0)
3356 DC_error ("-stim_maxlag k lag Require: 0 <= lag");
3357 option_data->stim_maxlag[k] = ival;
3358 nopt++;
3359 continue;
3360 }
3361
3362
3363 /*----- -stim_nptr k p -----*/
3364 if (strcmp(argv[nopt], "-stim_nptr") == 0)
3365 {
3366 nopt++;
3367 if (nopt+1 >= argc)
3368 DC_error ("need 2 arguments after -stim_nptr");
3369
3370 ival = -1 ; sscanf (argv[nopt], "%d", &ival);
3371 if ((ival < 1) || (ival > option_data->num_stimts))
3372 DC_error ("-stim_nptr k p Require: 1 <= k <= num_stimts");
3373 k = ival-1;
3374 nopt++;
3375
3376 ival = -1 ; sscanf (argv[nopt], "%d", &ival);
3377 if (ival < 1)
3378 DC_error ("-stim_nptr k p Require: 1 <= p");
3379 option_data->stim_nptr[k] = ival;
3380 nopt++;
3381 continue;
3382 }
3383
3384
3385 /*----- -num_glt num -----*/
3386 if (strcmp(argv[nopt], "-num_glt") == 0)
3387 {
3388 nopt++;
3389 if (nopt >= argc) DC_error ("need argument after -num_glt ");
3390 ival = -1 ; sscanf (argv[nopt], "%d", &ival);
3391 if (ival < 0)
3392 {
3393 DC_error ("-num_glt num Require: num >= 0 ");
3394 }
3395
3396 if (option_data->num_glt > 0)
3397 DC_error ("-num_glt option must precede any -glt options ");
3398
3399 initialize_glt_options (option_data, ival);
3400
3401 nopt++;
3402 continue;
3403 }
3404
3405
3406 /*----- -glt s gltname -----*/
3407 if (strcmp(argv[nopt], "-glt") == 0)
3408 {
3409 nopt++;
3410 if (nopt+1 >= argc) DC_error ("need 2 arguments after -glt");
3411
3412 ival = -1 ; sscanf (argv[nopt], "%d", &ival);
3413 if (ival < 1)
3414 {
3415 DC_error ("-glt s gltname Require: s >= 1 (s = #rows in GLT)");
3416 }
3417 s = ival; /* number of rows to read in matrix file */
3418
3419 if (option_data->num_glt == 0)
3420 initialize_glt_options (option_data, 10); /* default limit on GLTs */
3421
3422 if (iglt+1 > option_data->num_glt)
3423 DC_error ("Use -num_glt option to specify number of GLTs when more than 10");
3424
3425 option_data->glt_rows[iglt] = s;
3426 nopt++;
3427
3428 option_data->glt_filename[iglt] = malloc (sizeof(char)*ALEN(nopt));
3429 MTEST (option_data->glt_filename[iglt]);
3430 strcpy (option_data->glt_filename[iglt], argv[nopt]);
3431 iglt++;
3432
3433 nopt++; continue;
3434 }
3435
3436 /*---- -gltsym gltname [29 Jul 2004] -----*/
3437
3438 if( strcmp(argv[nopt],"-gltsym") == 0 ){
3439 nopt++ ;
3440 if( nopt >= argc ) DC_error("need 1 argument after -gltsym") ;
3441
3442 if( option_data->num_glt == 0 )
3443 initialize_glt_options(option_data,10) ; /* default limit on GLTs */
3444
3445 if( iglt+1 > option_data->num_glt )
3446 DC_error("Use -num_glt option to specify number of GLTs when more than 10") ;
3447
3448 option_data->glt_rows[iglt] = -1 ; /* flag for symbolic read */
3449
3450 option_data->glt_filename[iglt] = strdup( argv[nopt] ) ;
3451 if (option_data->glt_filename[iglt]) { /* ZSS May 08:remove trailing '\'
3452 or go into inf. loops */
3453 int ss;
3454 char *fdup=option_data->glt_filename[iglt];
3455 ss = strlen(fdup)-1;
3456 while ( ss >= 0 &&
3457 ( fdup[ss] == '\\' || isspace(fdup[ss]) ) ) {
3458 fdup[ss]='\0';
3459 --ss;
3460 }
3461 }
3462
3463 iglt++ ; nopt++ ; continue ;
3464 }
3465
3466
3467 /*----- -glt_label k glabel -----*/
3468 if (strcmp(argv[nopt], "-glt_label") == 0)
3469 {
3470 nopt++;
3471 if (nopt+1 >= argc) DC_error ("need 2 arguments after -glt_label");
3472
3473 ival = -1 ; sscanf (argv[nopt], "%d", &ival);
3474 if ((ival < 1) || (ival > option_data->num_glt))
3475 DC_error ("-glt_label k slabel Require: 1 <= k <= num_glt");
3476 k = ival-1;
3477 nopt++;
3478
3479 strcpy (option_data->glt_label[k], argv[nopt]);
3480 nopt++;
3481 continue;
3482 }
3483
3484
3485 /*----- -iresp k iprefix -----*/
3486 if (strcmp(argv[nopt], "-iresp") == 0)
3487 {
3488 nopt++;
3489 if (nopt+1 >= argc) DC_error ("need 2 arguments after -iresp");
3490
3491 ival = -1 ; sscanf (argv[nopt], "%d", &ival);
3492 if ((ival < 1) || (ival > option_data->num_stimts))
3493 DC_error ("-iresp k iprefix Require: 1 <= k <= num_stimts");
3494 k = ival-1;
3495 nopt++;
3496
3497 option_data->iresp_filename[k]
3498 = malloc (sizeof(char)*ALEN(nopt));
3499 MTEST (option_data->iresp_filename[k]);
3500 strcpy (option_data->iresp_filename[k], argv[nopt]);
3501 CHECK_NEEDS_FLOATS(argv[nopt]) ;
3502 nopt++;
3503 continue;
3504 }
3505
3506
3507 /*----- -tshift -----*/
3508 if (strcmp(argv[nopt], "-tshift") == 0)
3509 {
3510 option_data->tshift = 1;
3511 nopt++;
3512 continue;
3513 }
3514
3515
3516 /*----- -sresp k sprefix -----*/
3517 if (strcmp(argv[nopt], "-sresp") == 0)
3518 {
3519 nopt++;
3520 if (nopt+1 >= argc) DC_error ("need 2 arguments after -sresp");
3521
3522 ival = -1 ; sscanf (argv[nopt], "%d", &ival);
3523 if ((ival < 1) || (ival > option_data->num_stimts))
3524 DC_error ("-sresp k iprefix Require: 1 <= k <= num_stimts");
3525 k = ival-1;
3526 nopt++;
3527
3528 option_data->sresp_filename[k]
3529 = malloc (sizeof(char)*ALEN(nopt));
3530 MTEST (option_data->sresp_filename[k]);
3531 strcpy (option_data->sresp_filename[k], argv[nopt]);
3532 CHECK_NEEDS_FLOATS(argv[nopt]) ;
3533 nopt++;
3534 continue;
3535 }
3536
3537
3538 /*----- -fout -----*/
3539 if (strcmp(argv[nopt], "-fout") == 0)
3540 {
3541 option_data->fout = 1;
3542 nopt++;
3543 continue;
3544 }
3545
3546
3547 /*----- -rout -----*/
3548 if (strcmp(argv[nopt], "-rout") == 0)
3549 {
3550 option_data->rout = 1;
3551 nopt++;
3552 continue;
3553 }
3554
3555
3556 /*----- -tout -----*/
3557 if (strcmp(argv[nopt], "-tout") == 0)
3558 {
3559 option_data->tout = 1;
3560 nopt++;
3561 continue;
3562 }
3563
3564
3565 /*----- -vout -----*/
3566 if (strcmp(argv[nopt], "-vout") == 0)
3567 {
3568 option_data->vout = 1;
3569 nopt++;
3570 continue;
3571 }
3572
3573
3574 /*----- -xout -----*/
3575 if (strcmp(argv[nopt], "-xout") == 0)
3576 {
3577 option_data->xout = 1;
3578 nopt++;
3579 continue;
3580 }
3581
3582
3583 /*----- -nobout -----*/
3584 if (strcmp(argv[nopt], "-nobout") == 0)
3585 {
3586 option_data->nobout = 1; nopt++; continue;
3587 }
3588 if( strcmp(argv[nopt],"-bout") == 0 ){ /* 13 Mar 2007 */
3589 option_data->nobout = 0 ; nopt++ ; continue ;
3590 }
3591
3592
3593 /*----- -nocout -----*/
3594 if (strcmp(argv[nopt], "-nocout") == 0)
3595 {
3596 option_data->nocout = 1; nopt++; continue;
3597 }
3598
3599
3600 /*----- -full_first -----*/
3601 if (strcmp(argv[nopt], "-full_first") == 0)
3602 {
3603 option_data->full_first = 1; nopt++; continue;
3604 }
3605 if (strcmp(argv[nopt], "-nofull_first") == 0){ /* 13 Mar 2007 */
3606 option_data->full_first = 0; nopt++; continue;
3607 }
3608 if (strcmp(argv[nopt], "-nofullf_atall") == 0){ /* 23 Mar 2007 */
3609 option_data->do_fullf = 0; nopt++; continue;
3610 }
3611
3612
3613 /*----- -bucket filename -----*/
3614 if (strcmp(argv[nopt], "-bucket") == 0 || strcmp(argv[nopt],"-prefix") == 0 )
3615 {
3616 nopt++;
3617 if (nopt >= argc) DC_error ("need file prefixname after -bucket ");
3618 option_data->bucket_filename = malloc (sizeof(char)*ALEN(nopt));
3619 MTEST (option_data->bucket_filename);
3620 strcpy (option_data->bucket_filename, argv[nopt]);
3621 CHECK_NEEDS_FLOATS(argv[nopt]) ;
3622 nopt++;
3623 continue;
3624 }
3625
3626 /*----- -nobucket [03 May 2007] -----*/
3627 if( strcmp(argv[nopt],"-nobucket") == 0 ){
3628 option_data->nobucket = 1 ; nopt++ ; continue ;
3629 }
3630
3631 /*----- -cbucket filename -----*/
3632 if (strcmp(argv[nopt], "-cbucket") == 0 || strcmp(argv[nopt],"-cprefix") == 0 )
3633 {
3634 nopt++;
3635 if (nopt >= argc) DC_error ("need file prefixname after -cbucket ");
3636 CoefFilename = strdup( argv[nopt] ) ;
3637 CHECK_NEEDS_FLOATS(argv[nopt]) ;
3638 nopt++; continue;
3639 }
3640
3641
3642 /*----- -fitts filename -----*/
3643 if (strcmp(argv[nopt], "-fitts") == 0)
3644 {
3645 nopt++;
3646 if (nopt >= argc) DC_error ("need file prefixname after -fitts ");
3647 option_data->fitts_filename = malloc (sizeof(char)*ALEN(nopt));
3648 MTEST (option_data->fitts_filename);
3649 strcpy (option_data->fitts_filename, argv[nopt]);
3650 CHECK_NEEDS_FLOATS(argv[nopt]) ;
3651 nopt++;
3652 continue;
3653 }
3654
3655
3656 /*----- -errts filename -----*/
3657 if (strcmp(argv[nopt], "-errts") == 0)
3658 {
3659 nopt++;
3660 if (nopt >= argc) DC_error ("need file prefixname after -errts ");
3661 option_data->errts_filename = malloc (sizeof(char)*ALEN(nopt));
3662 MTEST (option_data->errts_filename);
3663 strcpy (option_data->errts_filename, argv[nopt]);
3664 CHECK_NEEDS_FLOATS(argv[nopt]) ;
3665 nopt++;
3666 continue;
3667 }
3668
3669 /*----- -jobs J -----*/
3670 if( strcmp(argv[nopt],"-jobs") == 0 ){ /* RWCox */
3671 nopt++ ;
3672 if (nopt >= argc) DC_error ("need J parameter after -jobs ");
3673 #ifdef PROC_MAX
3674 proc_numjob = strtol(argv[nopt],NULL,10) ;
3675 if( proc_numjob < 1 ){
3676 INFO_message("setting number of processes to 1!") ;
3677 proc_numjob = 1 ;
3678 } else if( proc_numjob > PROC_MAX ){
3679 INFO_message("setting number of processes to %d!",PROC_MAX);
3680 proc_numjob = PROC_MAX ;
3681 }
3682 #else
3683 WARNING_message("-jobs not supported in this version\n") ;
3684 #endif
3685 proc_use_jobs = 1 ; /* -jobs opt given 2003.08.15 [rickr] */
3686 nopt++; continue;
3687 }
3688
3689 #ifdef PROC_MAX
3690 if( strcmp(argv[nopt],"-virtvec") == 0 ){ /* 26 Dec 2012 */
3691 virtu_mrv = 1 ; nopt++ ; continue ;
3692 }
3693 #endif
3694
3695 #if 0
3696 /*----- -Dname=val to set environment variable [07 Dec 2007] -----*/
3697
3698 if( strncmp(argv[nopt],"-D",2) == 0 && strchr(argv[nopt],'=') != NULL ){
3699 (void) AFNI_setenv( argv[nopt]+2 ) ;
3700 nopt++ ; continue ;
3701 }
3702 #endif
3703
3704 /*----- unknown command -----*/
3705 sprintf(message,"Unrecognized command line option: %s\n", argv[nopt]);
3706 if( isspace(argv[nopt][0]) ) {
3707 sprintf(message,"Unknown command line option '%s'\n"
3708 "** Is there a blank after a '\\' character?",argv[nopt]) ;
3709 DC_error (message);
3710 } else {
3711 sprintf(message,"Unrecognized command line option: '%s'\n", argv[nopt]);
3712 ERROR_message( PROGRAM_NAME " dies: %s",message) ;
3713 suggest_best_prog_option(argv[0], argv[nopt]);
3714 exit(1);
3715 }
3716
3717 } /***** end of loop over input arguments ****/
3718
3719 /*----- does user request help menu? -----*/
3720 if (nopt < 2) {
3721 sprintf(message,"Too few options");
3722 DC_error (message);
3723 }
3724
3725 /*----- 23 Mar 2007: full first stuff? -----*/
3726
3727 if( option_data->fout ) option_data->do_fullf = 1 ;
3728
3729 if( allzero_OK ) use_psinv = 1 ; /* 30 May 2007 */
3730
3731 if( option_data->x1D_stop ){ /* 28 Jun 2007 */
3732 option_data->automask = 0 ;
3733 option_data->nox1D = 0 ;
3734 }
3735
3736 /*----- Set number of GLTs actually present -----*/
3737 option_data->num_glt = iglt;
3738
3739 /*---- if -jobs is given, make sure are processing 3D data ----*/
3740
3741 #ifdef PROC_MAX
3742 if( (xrestore || option_data->input1D_filename != NULL) && proc_numjob > 1 ){
3743 proc_numjob = 1 ;
3744 if( verb ) INFO_message("-jobs reset to 1") ;
3745 }
3746 #endif
3747
3748 /*---- 09 Mar 2007: manufacture -bucket name if needed ----*/
3749
3750 if( option_data->bucket_filename == NULL &&
3751 option_data->input_filename != NULL && !option_data->nobucket ){
3752 option_data->bucket_filename = strdup("Decon") ;
3753 INFO_message("No '-bucket' option given ==> using '-bucket %s'",
3754 option_data->bucket_filename) ;
3755 }
3756
3757 /*---- 09 Mar 2007: output -x1D file always ----*/
3758
3759 if( option_data->x1D_filename != NULL && /* 10 Aug 2010 */
3760 option_data->nodata &&
3761 strncmp(option_data->x1D_filename,"stdout:",7) == 0 ) option_data->x1D_stop = 2 ;
3762
3763 if( option_data->x1D_filename == NULL && !option_data->nox1D ){
3764 char *pref=NULL , *cpt ;
3765 if( option_data->bucket_filename != NULL ){ /* use bucket name? */
3766 pref = strdup(option_data->bucket_filename) ;
3767 cpt = strstr(pref,".") ; if( cpt != NULL ) *cpt = '\0' ;
3768 } else if( option_data->input1D_filename != NULL ){ /* use 1D filename? */
3769 pref = strdup(option_data->input1D_filename) ;
3770 cpt = strstr(pref,".1D") ; if( cpt != NULL ) *cpt = '\0' ;
3771 cpt = strstr(pref,"1D:") ; if( cpt != NULL ) strcpy(pref,"1D") ;
3772 } else if( option_data->nodata ){ /* no data? */
3773 pref = strdup("nodata") ;
3774 } else { /* default */
3775 pref = strdup("Decon") ;
3776 }
3777 option_data->x1D_filename = malloc(strlen(pref)+32) ;
3778 strcpy(option_data->x1D_filename,pref) ;
3779 strcat(option_data->x1D_filename,".xmat.1D") ;
3780 free(pref) ;
3781 }
3782
3783 if( !legendre_polort && option_data->polort == -666 ){
3784 WARNING_message("-nolegendre and -polort A are incompatible!") ;
3785 legendre_polort = 1 ;
3786 }
3787
3788 /**--- Test various combinations for legality [11 Aug 2004] ---**/
3789
3790 #if 0
3791 if (option_data->input1D_TR > 0.0 && !option_data->input1D_filename) {
3792 option_data->input1D_TR = 0.0;
3793 if( verb ) WARNING_message("-TR_1D is meaningless without -input1D");
3794 }
3795 #endif
3796
3797 if( option_data->polort == -1 ) demean_base = 0 ; /* 12 Aug 2004 */
3798
3799 /**** check if we have any data ****/
3800
3801 if( option_data->num_stimts == 0 && ortar == NULL && option_data->polort == -1 ){
3802 ERROR_message("'-num_stimts' is 0 AND no '-ortvec' AND '-polort' is -1") ;
3803 DC_error( "==> don't you want to DO anything? :-(") ;
3804 }
3805
3806 /**** Add -ortvec (ortar) stuff to stimulus file list [02 Dec 2011] ****/
3807
3808 if( ortar != NULL ){
3809 int nort=0 , nsold=option_data->num_stimts , nsnew , rr,nn ;
3810 MRI_IMAGE *oim ;
3811 for( rr=0 ; rr < IMARR_COUNT(ortar) ; rr++ ) nort += IMARR_SUBIM(ortar,rr)->ny ;
3812 extend_stim_options( option_data , nort ) ;
3813 nsnew = option_data->num_stimts ;
3814 INFO_message("3dDeconvolve extending num_stimts from %d to %d due to -ortvec",nsold,nsnew) ;
3815 for( nn=nsold,rr=0 ; rr < IMARR_COUNT(ortar) ; rr++ ){
3816 oim = IMARR_SUBIM(ortar,rr) ;
3817 for( s=0 ; s < oim->ny ; s++,nn++ ){
3818 option_data->stim_filename[nn] = (char *)malloc(sizeof(char)*32) ;
3819 sprintf(option_data->stim_filename[nn],"ortvec:%d,%d",rr,s) ;
3820 sprintf(option_data->stim_label[nn],"%s[%d]",oim->name,s) ;
3821 option_data->stim_base[nn] = 1;
3822 }
3823 }
3824 }
3825
3826 /**** loop and check each stimulus for decent and humane values ****/
3827
3828 nerr = 0 ; basis_nstim = option_data->num_stimts ; basis_nused = 0 ;
3829 for( k=0 ; k < option_data->num_stimts ; k++ ){
3830
3831 if( strncmp(option_data->stim_label[k],"Stim#",5) == 0 )
3832 WARNING_message("no -stim_label given for stim #%d ==> label = '%s'",
3833 k+1 , option_data->stim_label[k] ) ;
3834
3835 for( s=0 ; s < k ; s++ ){
3836 if( strcmp(option_data->stim_label[k],option_data->stim_label[s]) == 0 )
3837 WARNING_message("-stim_label '%s' the same for stim #%d and #%d",
3838 option_data->stim_label[k] , s+1 , k+1 ) ;
3839 }
3840
3841 if( basis_stim[k] != NULL ){ /* checking -stim_times input */
3842
3843 basis_stim[k]->name = strdup( option_data->stim_label[k] ) ;
3844
3845 basis_nused++ ;
3846
3847 if( option_data->sresp_filename[k] != NULL ) basis_need_mse = 1 ;
3848
3849 if( option_data->stim_nptr[k] != 1 ){
3850 ERROR_message(
3851 "'-stim_nptr %d %d' illegal with '%s'",
3852 k+1 , option_data->stim_nptr[k] , basis_stim[k]->option ) ;
3853 nerr++ ;
3854 }
3855 if( option_data->stim_base[k] != 0 ){
3856 ERROR_message(
3857 "'-stim_base %d' illegal with '%s'\n",
3858 k+1 , basis_stim[k]->option ) ;
3859 nerr++ ;
3860 }
3861 if( option_data->stim_minlag[k] != 0 ){
3862 ERROR_message(
3863 "'-stim_minlag %d %d' illegal with '%s'\n",
3864 k+1 , option_data->stim_minlag[k] , basis_stim[k]->option ) ;
3865 nerr++ ;
3866 }
3867 if( option_data->stim_maxlag[k] != 0 ){
3868 ERROR_message(
3869 "'-stim_maxlag %d %d' illegal with '%s'\n",
3870 k+1 , option_data->stim_maxlag[k] , basis_stim[k]->option ) ;
3871 nerr++ ;
3872 }
3873
3874 } else { /* checking -stim_file type of input */
3875
3876 if( option_data->stim_filename[k] == NULL ){
3877 ERROR_message("no stimulus #%d given\n",k+1) ;
3878 nerr++ ;
3879 }
3880
3881 if( option_data->slice_base[k] ){ /* not yet implemented! */
3882 if( option_data->stim_minlag[k] != 0 ){
3883 ERROR_message(
3884 "'-stim_minlag %d %d' illegal with '-slice_base'\n",
3885 k+1 , option_data->stim_minlag[k] ) ;
3886 nerr++ ;
3887 }
3888 if( option_data->stim_maxlag[k] != 0 ){
3889 ERROR_message(
3890 "'-stim_maxlag %d %d' illegal with '-slice_base'\n",
3891 k+1 , option_data->stim_maxlag[k] ) ;
3892 nerr++ ;
3893 }
3894 if( option_data->stim_nptr[k] != 1 ){
3895 ERROR_message(
3896 "'-stim_nptr %d %d' illegal with '-slice_base'\n",
3897 k+1 , option_data->stim_nptr[k] ) ;
3898 nerr++ ;
3899 }
3900 }
3901 }
3902
3903 } /* end of loop over stimuli */
3904
3905 /* check CENSOR command for run indexes: should all have them, or none */
3906
3907 if( abc_CENSOR != NULL ){
3908 int ic , rr , nzr=0 ;
3909 for( ic=0 ; ic < num_CENSOR ; ic++ ) /* count number with run != 0 */
3910 if( abc_CENSOR[ic].i ) nzr++ ;
3911 if( nzr > 0 && nzr < num_CENSOR )
3912 WARNING_message(
3913 "%d -CENSORTR commands have 'run:' numbers and %d do not!\n"
3914 " (either all should have 'run:' numbers or none)",nzr,num_CENSOR-nzr);
3915 }
3916
3917 /*-- check if we can continue! --*/
3918
3919 if( nerr > 0 ) ERROR_exit("Can't continue after above problems!") ;
3920 return ;
3921 }
3922
3923
3924 /*---------------------------------------------------------------------------*/
3925 /*
3926 Read time series from specified file name. This file name may have
3927 a column selector attached.
3928 */
3929
read_time_series(char * ts_filename,int * ts_length)3930 float * read_time_series
3931 (
3932 char *ts_filename, /* time series file name (plus column index) */
3933 int *ts_length /* output value for time series length */
3934 )
3935 {
3936 char message[THD_MAX_NAME]; /* error message */
3937 char *cpt; /* pointer to column suffix */
3938 char filename[THD_MAX_NAME]; /* time series file name w/o column index */
3939 char subv[THD_MAX_NAME]; /* string containing column index */
3940 MRI_IMAGE *im, *flim; /* pointers to image structures
3941 -- used to read 1D ASCII */
3942 float *far; /* pointer to MRI_IMAGE floating point data */
3943 int nx; /* number of time points in time series */
3944 int ny; /* number of columns in time series file */
3945 int ipt; /* time point index */
3946 float *ts_data = NULL; /* input time series data */
3947
3948
3949 ENTRY("read_time_series") ;
3950
3951 /*----- First, check for empty filename -----*/
3952 if (ts_filename == NULL)
3953 DC_error ("Missing input time series file name");
3954
3955 /*** Special case: -ortvec stuff [02 Dec 2011] ***/
3956
3957 if( ortar != NULL && strncmp(ts_filename,"ortvec:",7) == 0 ){
3958 int rr=-1 , ss=-1 ; MRI_IMAGE *oim ; float *oar ;
3959 sscanf(ts_filename+7,"%d,%d",&rr,&ss) ;
3960 if( rr < 0 || rr >= IMARR_COUNT(ortar) ) ERROR_exit("3dDeconvolve: %s failure!!!",ts_filename) ;
3961 oim = IMARR_SUBIM(ortar,rr) ; nx = oim->nx ; ny = oim->ny ;
3962 if( ss < 0 || ss >= ny ) ERROR_exit("3dDeconvolve: %s failure :-(",ts_filename) ;
3963 flim = mri_new( nx , 1 , MRI_float ) ;
3964 far = MRI_FLOAT_PTR(flim) ;
3965 oar = MRI_FLOAT_PTR(oim) + nx*ss ;
3966 memcpy( far , oar , sizeof(float)*nx ) ;
3967
3968 } else { /*----- Read the time series file -----*/
3969
3970 flim = mri_read_1D( ts_filename ) ;
3971 if (flim == NULL){
3972 sprintf (message, "Unable to read time series file: %s", ts_filename);
3973 DC_error (message);
3974 }
3975 }
3976
3977 /*-- at this point, data is in the flim struct, however we got it --*/
3978
3979 far = MRI_FLOAT_PTR(flim);
3980 nx = flim->nx;
3981 ny = flim->ny;
3982 if( ny > 1 ){
3983 if( nx == 1 ){
3984 MRI_IMAGE *tim = mri_transpose(flim) ;
3985 mri_free(flim) ; flim = tim ;
3986 far = MRI_FLOAT_PTR(flim); nx = flim->nx; ny = flim->ny;
3987 INFO_message("1D time series file %s has %d rows and %d columns: tranposing it",ts_filename,nx,ny);
3988 } else {
3989 WARNING_message("1D file %s has %d rows and %d columns: ignoring later columns",ts_filename,nx,ny);
3990 }
3991 }
3992
3993 /*----- Save the time series data -----*/
3994 *ts_length = nx;
3995 ts_data = (float *) malloc (sizeof(float) * nx);
3996 memcpy( ts_data , far , sizeof(float)*nx ) ;
3997 mri_free(flim) ;
3998 RETURN (ts_data);
3999 }
4000
4001
4002 /*---------------------------------------------------------------------------*/
4003 /*
4004 Read the input data files.
4005 */
4006
read_input_data(DC_options * option_data,THD_3dim_dataset ** dset_time,byte ** mask_vol,float ** fmri_data,int * fmri_length,float ** censor_array,int * censor_length,int ** block_list,int * num_blocks,float *** stimulus,int ** stim_length,matrix ** glt_cmat)4007 void read_input_data
4008 (
4009 DC_options * option_data, /* deconvolution program options */
4010 THD_3dim_dataset ** dset_time, /* input 3D+time data set */
4011 byte ** mask_vol, /* input mask volume */
4012 float ** fmri_data, /* input fMRI time series data */
4013 int * fmri_length, /* length of fMRI time series */
4014 float ** censor_array, /* input censor time series array */
4015 int * censor_length, /* length of censor time series */
4016 int ** block_list, /* list of block (run) starting points */
4017 int * num_blocks, /* number of blocks (runs) */
4018 float *** stimulus, /* stimulus time series arrays */
4019 int ** stim_length, /* length of stimulus time series */
4020 matrix ** glt_cmat /* general linear test matrices */
4021 )
4022
4023 {
4024 char message[THD_MAX_NAME]; /* error message */
4025 int it; /* time point index */
4026 int nt=0; /* number of input data time points */
4027 int nxyz=0; /* number of voxels */
4028 int num_stimts; /* number of stimulus time series arrays */
4029 int * baseline; /* flag for baseline stimulus function */
4030 int * min_lag; /* minimum time delay for impulse response */
4031 int * max_lag; /* maximum time delay for impulse response */
4032 int qp; /* number of polynomial trend baseline parameters */
4033 int q; /* number of baseline model parameters */
4034 int p; /* number of full model parameters */
4035 int is; /* stimulus time series index */
4036 int num_glt; /* number of general linear tests */
4037 int iglt; /* general linear test index */
4038 column_metadata cd ; /* 05 Mar 2007 */
4039 int nblk,npol , p1,nc , nsl ;
4040 unsigned int mk,gp ;
4041 float dtloc=0.0f ;
4042 float ttmax=big_time ; /* 28 Aug 2015 */
4043
4044
4045 ENTRY("read_input_data") ;
4046
4047 /*----- Initialize local variables -----*/
4048
4049 num_stimts = option_data->num_stimts;
4050 num_glt = option_data->num_glt;
4051 baseline = option_data->stim_base;
4052 min_lag = option_data->stim_minlag;
4053 max_lag = option_data->stim_maxlag;
4054
4055
4056 /*----- Read the input stimulus time series -----*/
4057
4058 if (num_stimts > 0)
4059 {
4060 int nerr=0 ;
4061
4062 *stimulus = (float **) calloc (sizeof(float *) , num_stimts);
4063 MTEST (*stimulus);
4064 *stim_length = (int *) calloc (sizeof(int) , num_stimts);
4065 MTEST (*stim_length);
4066
4067 /** 14 Jul 2004: check for duplicate filename - RWCox **/
4068
4069 { int js ;
4070 for( is=0 ; is < num_stimts ; is++ ){
4071 for( js=is+1 ; js < num_stimts ; js++ ){
4072 if( strcmp( option_data->stim_filename[is] ,
4073 option_data->stim_filename[js] ) == 0 ){
4074 WARNING_message(
4075 "!! stimulus filename #%d:'%s' same as #%d:'%s'" ,
4076 is+1,option_data->stim_filename[is] ,
4077 js+1,option_data->stim_filename[js] ) ; nerr++ ;
4078 badlev++ ;
4079 }
4080 }
4081 }
4082 }
4083
4084 if( nerr > 0 && AFNI_yesenv("AFNI_3dDeconvolve_nodup") )
4085 ERROR_exit("Can't continue after above warnings!");
4086
4087 for (is = 0; is < num_stimts; is++)
4088 {
4089 if( basis_stim[is] != NULL ) continue ; /* 11 Aug 2004: skip this'n */
4090
4091 if( !option_data->slice_base[is] ){ /**** ordinary input file ****/
4092
4093 (*stimulus)[is] = read_time_series (option_data->stim_filename[is],
4094 &((*stim_length)[is]));
4095
4096 if ((*stimulus)[is] == NULL)
4097 {
4098 sprintf (message, "Unable to read '-stim_file %d %s'",
4099 is+1 , option_data->stim_filename[is]);
4100 DC_error (message);
4101 }
4102
4103 } else { /**** read a -slice_base file ****/
4104
4105 MRI_IMAGE *sim ;
4106 sim = mri_read_1D( option_data->stim_filename[is] ) ;
4107 if( sim == NULL ){
4108 sprintf (message, "Unable to read '-slice_base %d %s'",
4109 is+1 , option_data->stim_filename[is]);
4110 DC_error (message);
4111 }
4112 (*stim_length)[is] = sim->nx ; /* save length */
4113 if( sim->ny > 1 ){ /* multicolumn */
4114 option_data->slice_base[is] = sim->ny ;
4115 option_data->num_slice_base++ ;
4116 } else { /* uni-column! */
4117 option_data->slice_base[is] = 0 ;
4118 WARNING_message("'slice_base %d %s' has only 1 column",
4119 is+1 , option_data->stim_filename[is] ) ;
4120 }
4121 (*stimulus)[is] = MRI_FLOAT_PTR(sim) ;
4122 if( sim->nx < 2 )
4123 WARNING_message("-slice_base %d %s: %d rows, %d cols ???",
4124 is+1 , option_data->stim_filename[is] , sim->nx,sim->ny ) ;
4125 }
4126
4127 }
4128 } /* end of input of -stim_file and -slice_base files */
4129
4130
4131 *num_blocks = 0 ; /* 04 Aug 2004 */
4132
4133 /*----- Read the input fMRI measurement data -----*/
4134
4135 if (option_data->nodata) /*----- No input data -----*/
4136 {
4137 #if 0
4138 if (num_stimts <= 0)
4139 DC_error ("Must have num_stimts > 0 for -nodata option");
4140 #endif
4141
4142 if( option_data->num_slice_base > 0 )
4143 ERROR_exit("'-nodata' and '-slice_base' are incompatible!") ;
4144
4145 if( option_data->nodata_TR > 0.0 ) dtloc = option_data->nodata_TR ;
4146
4147 if( basis_count > 0 ){
4148 if( option_data->nodata_TR > 0.0 ) basis_TR = option_data->nodata_TR ;
4149 else if( basis_dtout > 0.0 ) basis_TR = basis_dtout ;
4150 else if( option_data->force_TR > 0.0 ) basis_TR = option_data->force_TR ;
4151 INFO_message("using TR=%g seconds for -stim_times and -nodata\n",basis_TR);
4152 }
4153
4154 *dset_time = NULL;
4155
4156 /* with no actual data, must determine matrix size somehow */
4157
4158 if( option_data->nodata_NT > 0 ) /* user gave it to us directly? */
4159 nt = option_data->nodata_NT ;
4160 else if( option_data->NLast > 0 ) /* a little indirectly? */
4161 nt = option_data->NLast+1 ;
4162 else { /* use the longest -stim_file input? */
4163 int qt ;
4164 for( qt=nt=is=0 ; is < num_stimts ; is++ ){
4165 if( basis_stim[is] == NULL ){
4166 qt = (*stim_length)[is] / option_data->stim_nptr[is] ;
4167 nt = MAX(nt,qt) ;
4168 }
4169 }
4170 if( nt == 0 )
4171 ERROR_exit("-nodata has no way to determine time series length to model");
4172 }
4173 INFO_message("using NT=%d time points for -nodata",nt) ;
4174
4175 ttmax = basis_TR * nt ; /* 28 Aug 2015 */
4176
4177 nxyz = 0; /* signal that there is no data */
4178 }
4179
4180 else if (option_data->input1D_filename != NULL) /*----- 1D input file -----*/
4181 {
4182
4183 if( option_data->num_slice_base > 0 )
4184 ERROR_exit("'-input1D' and '-slice_base' are incompatible!") ;
4185
4186 /*----- Read the input fMRI 1D time series -----*/
4187 *fmri_data = read_time_series (option_data->input1D_filename,
4188 fmri_length);
4189 if (*fmri_data == NULL)
4190 {
4191 sprintf (message, "Unable to read time series file: %s",
4192 option_data->input1D_filename);
4193 DC_error (message);
4194 }
4195 *dset_time = NULL;
4196 nt = *fmri_length;
4197 nxyz = 1;
4198 option_data->nobout = 0 ;
4199
4200 if (option_data->input1D_TR > 0.0)
4201 dtloc = basis_TR = option_data->input1D_TR;
4202 else if( option_data->force_TR > 0.0 )
4203 dtloc = basis_TR = option_data->force_TR;
4204 if (verb) INFO_message("1D TR is %.3f seconds", basis_TR);
4205
4206 ttmax = basis_TR * nt ; /* 28 Aug 2015 */
4207 }
4208
4209 else if (option_data->input_filename != NULL) /*----- 3D+time dataset -----*/
4210 {
4211 int nxd , nyd , nzd , lmax=0 ;
4212
4213 *dset_time = THD_open_dataset (option_data->input_filename);
4214 CHECK_OPEN_ERROR(*dset_time,option_data->input_filename);
4215 if( !option_data->x1D_stop ){
4216 if( verb ) MEM_MESSAGE ;
4217 if( verb ) INFO_message("loading dataset %s",option_data->input_filename);
4218 DSET_load(*dset_time) ; CHECK_LOAD_ERROR(*dset_time) ;
4219 if( verb ) MEM_MESSAGE ;
4220 }
4221
4222 if( option_data->force_TR > 0.0 || (*dset_time)->taxis == NULL ){ /* 18 Aug 2008 */
4223 float ttt = option_data->force_TR ; if( ttt <= 0.0f ) ttt = 1.0f ;
4224 EDIT_dset_items( *dset_time ,
4225 ADN_ttdel , ttt ,
4226 ADN_ntt , DSET_NVALS(*dset_time) ,
4227 ADN_tunits, UNITS_SEC_TYPE ,
4228 ADN_none ) ;
4229 INFO_message("forcibly using TR=%.4f seconds for -input dataset" ,
4230 ttt) ;
4231 }
4232
4233 nt = DSET_NVALS(*dset_time); lmax = nt ;
4234 nxyz = DSET_NVOX (*dset_time);
4235 nxd = DSET_NX(*dset_time) ;
4236 nyd = DSET_NY(*dset_time) ;
4237 nzd = DSET_NZ(*dset_time) ;
4238
4239 DSET_UNMSEC( *dset_time ) ; /* 12 Aug 2005: surgery on the time units? */
4240
4241 if( option_data->num_slice_base > 0 ){ /* check slice counts */
4242 int nz=DSET_NZ(*dset_time) , nerr=0 ;
4243 for( is=0 ; is < num_stimts ; is++ ){
4244 if( option_data->slice_base[is] > 0 &&
4245 option_data->slice_base[is] != nz ){
4246 nerr++ ;
4247 ERROR_message("Dataset nz=%d but '-slice_base %d' has nz=%d",
4248 nz, is+1, option_data->slice_base[is] ) ;
4249 }
4250 }
4251 if( nerr > 0 ) ERROR_exit("Can't continue from nz mismatch!") ;
4252
4253 if( nz == 1 ){ /* only 1 slice? */
4254 for( is=0 ; is < num_stimts ; is++ ) /* get rid of */
4255 option_data->slice_base[is] = 0 ; /* slice_base */
4256 option_data->num_slice_base = 0 ; /* markings! */
4257 }
4258 }
4259
4260 dtloc = basis_TR = DSET_TR(*dset_time) ; /* 11 Aug 2004 */
4261 if( basis_TR <= 0.0f ){
4262 if( option_data->input1D_TR > 0.0f ){
4263 dtloc = basis_TR = option_data->input1D_TR ;
4264 WARNING_message("no TR in dataset: using -TR_1D=%.3f s",dtloc) ;
4265 } else {
4266 dtloc = basis_TR = 1.0f;
4267 WARNING_message("no TR in dataset; setting TR=1 s (?)");
4268 }
4269 } else if( basis_TR <= 0.10f ){
4270 INFO_message("TR in dataset = %g s (less than 0.100 s) -- FYI",
4271 basis_TR ) ; /* one symptom of the PSFB syndrome */
4272 }
4273
4274 if( DSET_IS_TCAT(*dset_time) ){ /** 04 Aug 2004: manufacture block list **/
4275 int lmin=9999 ;
4276 if( option_data->concat_filename != NULL ){
4277 WARNING_message(
4278 "'-concat %s' ignored: input dataset is auto-catenated\n" ,
4279 option_data->concat_filename ) ;
4280 option_data->concat_filename = NULL ;
4281 }
4282 if( !option_data->tcat_noblock ){
4283 for( it=0 ; it < (*dset_time)->tcat_num ; it++ ){
4284 lmin = MIN( lmin , (*dset_time)->tcat_len[it] ) ;
4285 lmax = MAX( lmax , (*dset_time)->tcat_len[it] ) ; /* 28 Aug 2015 */
4286 }
4287 option_data->tcat_noblock = (lmin < 2) ;
4288 }
4289 if( option_data->tcat_noblock ){
4290 INFO_message("Auto-catenated input datasets treated as one imaging run") ;
4291 *num_blocks = 1;
4292 *block_list = (int *) malloc (sizeof(int) * 1);
4293 (*block_list)[0] = 0;
4294 } else {
4295 INFO_message("Auto-catenated input datasets treated as multiple imaging runs") ;
4296 *num_blocks = (*dset_time)->tcat_num ;
4297 *block_list = (int *) malloc (sizeof(int) * (*num_blocks));
4298 (*block_list)[0] = 0;
4299 for( it=0 ; it < (*num_blocks)-1 ; it++ )
4300 (*block_list)[it+1] = (*block_list)[it] + (*dset_time)->tcat_len[it] ;
4301 if( verb ){
4302 char *buf=calloc((*num_blocks),8) ;
4303 for( it=0 ; it < (*num_blocks) ; it++ )
4304 sprintf(buf+strlen(buf)," %d",(*block_list)[it]) ;
4305 INFO_message("Auto-catenated datasets start at: %s", buf) ;
4306 free(buf) ;
4307 }
4308 }
4309 }
4310
4311 ttmax = dtloc * lmax ; /* 28 Aug 2015 */
4312
4313 if( option_data->automask ){ /* 15 Apr 2005: automasking */
4314 MRI_IMAGE *qim ; int mc ;
4315 qim = THD_rms_brick( *dset_time ) ;
4316 *mask_vol = mri_automask_image( qim ) ;
4317 mri_free( qim ) ;
4318 if( *mask_vol == NULL ){
4319 WARNING_message("unable to generate automask?!") ;
4320 } else {
4321 mc = THD_countmask( nxyz , *mask_vol ) ;
4322 if( mc <= 1 ){
4323 WARNING_message("automask is empty!?") ;
4324 free(*mask_vol) ; *mask_vol = NULL ;
4325 } else {
4326 INFO_message("%d voxels in automask (out of %d)", mc,nxyz) ;
4327 }
4328 }
4329 gmask = *mask_vol ; /* save global mask -- 03 Feb 2009 */
4330 }
4331
4332 if (option_data->mask_filename != NULL) /* read mask from file */
4333 {
4334 THD_3dim_dataset *mask_dset = NULL;
4335
4336 /*----- Read the input mask dataset -----*/
4337 mask_dset = THD_open_dataset (option_data->mask_filename);
4338 CHECK_OPEN_ERROR(mask_dset,option_data->mask_filename);
4339
4340 /*----- If mask is used, check for compatible dimensions -----*/
4341 if ( (DSET_NX(*dset_time) != DSET_NX(mask_dset))
4342 || (DSET_NY(*dset_time) != DSET_NY(mask_dset))
4343 || (DSET_NZ(*dset_time) != DSET_NZ(mask_dset)) )
4344 {
4345 sprintf (message, "datasets '%s' and '%s' have incompatible dimensions",
4346 option_data->input_filename, option_data->mask_filename);
4347 DC_error (message);
4348 }
4349
4350 if (DSET_NVALS(mask_dset) != 1 )
4351 DC_error ("Must specify exactly 1 sub-brick from mask dataset");
4352
4353 *mask_vol = THD_makemask( mask_dset , 0 , 1.0,0.0 ) ;
4354 if (*mask_vol == NULL) DC_error ("Unable to read mask dataset");
4355
4356 DSET_delete(mask_dset) ;
4357 gmask = *mask_vol ; /* global mask save -- 03 Feb 2009 */
4358 }
4359
4360 /* 15 Jul 2010: use -STATmask? */
4361
4362 if( statmask != NULL ){
4363 if( statmask->nar != nxyz ){
4364 WARNING_message("-STATmask ignored: doesn't match -input dataset size!") ;
4365 KILL_bytevec(statmask) ; free(statmask_name) ; statmask_name = NULL ;
4366 } else {
4367 int mc ; byte *qmask=gmask ;
4368 gmask = statmask->ar ; mc = THD_countmask( nxyz , gmask ) ;
4369 if( mc <= 99 ){
4370 gmask = qmask ;
4371 KILL_bytevec(statmask) ; free(statmask_name) ; statmask_name = NULL ;
4372 WARNING_message("-STATmask ignored: only has %d nonzero voxels",mc) ;
4373 } else if( verb )
4374 INFO_message("-STATmask has %d voxels (out of %d = %.1f%%)",
4375 mc, nxyz, (100.0f*mc)/nxyz ) ;
4376 }
4377 }
4378
4379 /* 03 Feb 2009 -- make a global mask if not provided thus far */
4380
4381 if( gmask == NULL && nxd > 15 && nyd > 15 && nzd > 15 ){
4382 MRI_IMAGE *qim ; int mc ;
4383 qim = THD_rms_brick( *dset_time ) ;
4384 gmask = mri_automask_image( qim ) ;
4385 mri_free( qim ) ;
4386 mc = THD_countmask( nxyz , gmask ) ;
4387 if( mc <= 99 ){ if( gmask != NULL ){ free(gmask) ; gmask = NULL ; } }
4388 else if( verb && (!floatout || do_FDR) )
4389 INFO_message("STAT automask has %d voxels (out of %d = %.1f%%)",
4390 mc, nxyz, (100.0f*mc)/nxyz ) ;
4391 }
4392
4393 EDIT_set_misfit_mask(gmask) ; mri_fdr_setmask(gmask) ;
4394
4395 /* 23 Dec 2011 -- check for saturation transients */
4396
4397 if( !dont_do_satcheck ){
4398 float sum ; int isum ; double qtim = COX_clock_time() ;
4399 INFO_message("Checking for initial transients") ;
4400 sum = THD_saturation_check_multi( *dset_time,gmask, *num_blocks,*block_list ) ;
4401 isum = (int)(sum+0.56789f) ;
4402 if( isum > 0 ){
4403 WARNING_message("Dataset seems to have about %d initial transient time points",isum) ;
4404 if( *num_blocks > 1 )
4405 WARNING_message(" (This estimate is summed across all imaging runs)" ) ;
4406 } else {
4407 ININFO_message("No widespread significant initial transients found") ;
4408 }
4409 ININFO_message("Transient check elapsed time = %.2f s",COX_clock_time()-qtim) ;
4410 } else {
4411 INFO_message("Skipping check for initial transients") ;
4412 }
4413
4414 } else { /*------------------------- no input data? --------------------*/
4415
4416 DC_error ("Must specify some sort of input data, or use '-nodata'");
4417
4418 }
4419
4420
4421 /*----- Check number of data (time) points -----*/
4422
4423 if (nt <= 0) DC_error ("No time points?");
4424 option_data->nt = nt;
4425 if (nxyz < 0) DC_error ("Program initialization error: nxyz < 0");
4426 option_data->nxyz = nxyz;
4427
4428 voxel_num = nxyz ; /* 31 Aug 2004 */
4429
4430 /*----- Read the block list (-concat option) -----*/
4431
4432 if (option_data->concat_filename == NULL)
4433 {
4434 if( *num_blocks <= 0 ){ /* make one big block, if not already set */
4435 *num_blocks = 1;
4436 *block_list = (int *) malloc (sizeof(int) * 1);
4437 (*block_list)[0] = 0;
4438 }
4439 }
4440 else
4441 {
4442 float *f = NULL;
4443
4444 f = read_time_series (option_data->concat_filename, num_blocks);
4445 if (*num_blocks < 1)
4446 {
4447 sprintf (message, "Problem reading concat file: %s ",
4448 option_data->concat_filename);
4449 DC_error (message);
4450 }
4451 else
4452 {
4453 *block_list = (int *) malloc (sizeof(int) * (*num_blocks));
4454 for (it = 0; it < *num_blocks; it++)
4455 (*block_list)[it] = myfloor (f[it]+0.5);
4456 }
4457 }
4458
4459 /*** 16 Mar 2007:
4460 estimate desirable polort level from max block duration,
4461 and print warning if actual polort is smaller than this. ***/
4462
4463 { int nbl=*num_blocks , *bl=*block_list ;
4464 int ibot , itop , ilen , lmax=0 ; float dmax ;
4465 for( it=0 ; it < nbl ; it++ ){ /* find longest block */
4466 ibot = bl[it] ;
4467 itop = (it < nbl-1) ? bl[it+1] : nt ;
4468 ilen = itop-ibot ;
4469 if( ilen > lmax ) lmax = ilen ;
4470 }
4471 if( dtloc <= 0.0f ) dtloc = 1.0f ;
4472 dmax = dtloc * lmax ; /* duration of longest block */
4473 /* removed special cases of 150->1, 300->2 3 Oct 2007 [rickr] */
4474 ilen = 1+(int)myfloor(dmax/150.0) ;
4475 switch( option_data->polort ){
4476 default: /* user supplied non-negative polort */
4477 if( option_data->polort < ilen )
4478 WARNING_message(
4479 "Input polort=%d; Longest run=%.1f s; Recommended minimum polort=%d",
4480 option_data->polort , dmax , ilen ) ;
4481 else
4482 INFO_message(
4483 "Input polort=%d; Longest run=%.1f s; Recommended minimum polort=%d ++ OK ++",
4484 option_data->polort , dmax , ilen ) ;
4485 break ;
4486
4487 case -1: break ; /* user orders no baseline at all */
4488
4489 case -666: /* user orders automatic polort */
4490 INFO_message("Imaging duration=%.1f s; Automatic polort=%d",dmax,ilen) ;
4491 option_data->polort = ilen ;
4492 break ;
4493 }
4494 }
4495
4496 /*-- Create timing for each -stim_times input [11 Aug 2004] --*/
4497 /*-- Modified to deal with amplitude modulation [08 Mar 2007] --*/
4498 /*-- Modified to deal with multiple amplitudes [03 Dec 2008] --*/
4499
4500 if( basis_count > 0 ){ /* if there are any, that is */
4501 MRI_IMAGE *tim , *qim ;
4502 float *tar , *qar , *aar[BASIS_MAX_VDIM] , *zar[BASIS_MAX_VDIM] ;
4503 float toff , tmax,tt,ss , zbar[BASIS_MAX_VDIM] ;
4504 int ii,jj , kk , ngood , nx,ny , nf,dd , btyp , nbas ;
4505 int nbl=*num_blocks , *bst=*block_list ;
4506 basis_expansion *be ;
4507 char *glprefix = "\0" ; /* 21 May 2008 */
4508 MRI_IMARR *vimar ; int vdim , vmod , vfun , vv ;
4509
4510 if( basis_TR <= 0.0f ) basis_TR = 1.0f ;
4511 if( basis_dtout <= 0.0f ) basis_dtout = basis_TR ;
4512
4513 INFO_message("-stim_times using TR=%g s for stimulus timing conversion",
4514 basis_TR) ;
4515 INFO_message("-stim_times using TR=%g s for any -iresp output datasets",
4516 basis_dtout) ;
4517 if( basis_dtout == basis_TR )
4518 INFO_message(" [you can alter the -iresp TR via the -TR_times option]");
4519
4520 if( basis_timetype == GUESS_TIMES ){
4521 INFO_message(
4522 "** -stim_times NOTE ** guessing GLOBAL times if 1 time per line; LOCAL otherwise");
4523 glprefix = "** GUESSED ** " ;
4524 }
4525
4526 for( is=0 ; is < num_stimts ; is++ ){
4527 be = basis_stim[is] ;
4528 if( be == NULL ) continue ; /* old style -stim_file: BAH! */
4529
4530 vimar = NULL ; vdim = vmod = vfun = 0 ; /* default = no aux params */
4531 for( vv=0 ; vv < BASIS_MAX_VDIM ; vv++ ){
4532 aar[vv] = zar[vv] = NULL ; zbar[vv] = 0.0f ;
4533 }
4534
4535 btyp = be->type ; /* 08 Mar 2007: sub-type of -stim_times */
4536
4537 /** 29 Oct 2007: check TR of -iresp vs. TR of local basis functions **/
4538
4539 if( strncmp(be->symfun,"TENT" ,4) == 0 ||
4540 strncmp(be->symfun,"CSPLIN",6) == 0 ){
4541
4542 float dx = (be->ttop - be->tbot)/(be->nfunc-1) ;
4543 if( dx < basis_dtout )
4544 WARNING_message("%s %d .. %s has inter-knot TR=%g but -iresp output TR=%g",
4545 be->option , is+1 , be->symfun , dx , basis_dtout ) ;
4546 }
4547
4548 /** convert time entries in seconds to global time indexes **/
4549
4550 tim = basis_times[is] ; /* image that contains times */
4551 nx = tim->nx ; ny = tim->ny ; /* read in from user's file */
4552
4553 if( tim->kind == MRI_fvect ){ /* modulation */
4554
4555 STATUS("unpacking fvect image") ;
4556
4557 vimar = mri_fvect_to_imarr(tim) ; /* split them up */
4558 tar = MRI_FLOAT_PTR( IMARR_SUBIM(vimar,0) ) ;
4559 vdim = IMARR_COUNT(vimar) ;
4560 for( vv=0 ; vv < vdim-1 ; vv++ )
4561 aar[vv] = MRI_FLOAT_PTR( IMARR_SUBIM(vimar,vv+1) ) ;
4562
4563 vmod = be->vmod ; vfun = be->vfun ;
4564
4565 if( vmod+vfun+1 != vdim ) /* these conditions should not happen */
4566 ERROR_exit("Error at -stim_times_AM #%d: vmod+vfun+1 != vdim",is+1) ;
4567 if( vdim != be->vdim )
4568 ERROR_exit("Error at -stim_times_AM #%d: vdim != be->vdim",is+1) ;
4569
4570 } else {
4571
4572 tar = MRI_FLOAT_PTR(tim); /* just times, no paired value */
4573
4574 }
4575
4576 { /** check if all input times are 0s or 1s (a mistake) [15 Aug 2007] **/
4577 int nzo , nsm ;
4578 for( nsm=nzo=ii=0 ; ii < nx*ny ; ii++ ){
4579 if( tar[ii] < big_time ){
4580 nsm++ ; /* number of 'small' values */
4581 if( tar[ii] == 0.0f || tar[ii] == 1.0f ) nzo++ ; /* number of 0-1 */
4582 }
4583 }
4584 if( nzo > 0 && nzo == nsm )
4585 WARNING_message("%s %d has all times equal to 0 or 1 ?!?!",
4586 be->option , is+1 ) ;
4587 else if( nsm == 0 )
4588 WARNING_message("%s %d has all times equal to '*' ?!?!",
4589 be->option , is+1 ) ;
4590 }
4591
4592 /** 24 Mar 2009: scale all times? **/
4593
4594 if( stime_fac != 1.0f ){
4595 int nfac = 0 ;
4596 for( ii=0 ; ii < nx*ny ; ii++ ){ /* loop over all input times */
4597 if( tar[ii] > 0.0f && tar[ii] < big_time ){ tar[ii] *= stime_fac ; nfac++ ; }
4598 }
4599 if( nfac > 0 )
4600 INFO_message("Scaled %d times from msec to sec for %s %d" ,
4601 nfac , be->option , is+1 ) ;
4602 }
4603
4604 /** 24 Mar 2009: subtract from all times? **/
4605
4606 if( stime_sub != 0.0f ){
4607 int nsub = 0 , nneg = 0 ;
4608 for( ii=0 ; ii < nx*ny ; ii++ ){ /* loop over all input times */
4609 if( tar[ii] < big_time ){
4610 tar[ii] -= stime_sub ; nsub++ ; if( tar[ii] < 0.0f ) nneg++ ;
4611 }
4612 }
4613 if( nsub > 0 && nneg == 0 )
4614 INFO_message(
4615 "Subtracted %.2f sec from %d times for %s %d",
4616 stime_sub , nsub , be->option , is+1 ) ;
4617 else if( nsub > 0 && nneg > 0 )
4618 WARNING_message(
4619 "Subtracted %.2f sec from %d times for %s %d; %d times < 0 resulted!",
4620 stime_sub , nsub , be->option , is+1 , nneg ) ;
4621
4622 }
4623
4624 if( be->timetype == GUESS_TIMES )
4625 be->timetype = (nx==1) ? GLOBAL_TIMES : LOCAL_TIMES ;
4626
4627 ngood = 0 ; /* number of good time values found */
4628 qar = (float *)calloc(sizeof(float),nx*ny) ; /* collects times */
4629
4630 for( vv=0 ; vv < vmod+vfun ; vv++ ) /* space to collect amplitudes */
4631 zar[vv] = (float *)calloc(sizeof(float),nx*ny) ;
4632
4633 /** convert time in sec (tar) to time in indexes (qar) **/
4634
4635 if( be->timetype == GLOBAL_TIMES ){ /****------ global times ------****/
4636 int nbad=0 , nout=0 ; float *psfb=NULL ;
4637
4638 INFO_message("%s%s %d using GLOBAL times",glprefix,be->option,is+1) ;
4639 tmax = (nt-1)*basis_TR ; /* max allowed time offset */
4640 STATUS("loading GLOBAL times and aux params") ;
4641 for( ii=0 ; ii < nx*ny ; ii++ ){ /* loop over all input times */
4642 tt = tar[ii] ;
4643 if( tt >= 0.0f && tt <= tmax ){ /* a good time value */
4644 for( vv=0 ; vv < vmod+vfun ; vv++ ) zar[vv][ngood] = aar[vv][ii] ;
4645 qar[ngood++] = tt / basis_TR ;
4646 } else if( tt >= big_time ) nbad++ ; /* '*' entries */
4647 else { /* PSFB entries */
4648 nout++ ; psfb = (float *)realloc(psfb,sizeof(float)*nout) ;
4649 psfb[nout-1] = tt ;
4650 }
4651 }
4652 if( nbad ) /* warn about '*' times in GLOBAL input */
4653 WARNING_message(
4654 "'%s %d' (GLOBAL) has %d '*' fillers; do you want LOCAL times?",
4655 be->option , is+1 , nbad ) ;
4656 if( nout ){ /* warn about times outside the legal range */
4657 WARNING_message(
4658 "'%s %d' (GLOBAL) has %d times outside range 0 .. %g [PSFB syndrome]",
4659 be->option , is+1 , nout , tmax ) ;
4660 ININFO_message("dataset TR being used is %g s -- unusable times follow",
4661 basis_TR) ;
4662 for( ii=0 ; ii < nout ; ii++ ) fprintf(stderr," %g",psfb[ii]) ;
4663 fprintf(stderr,"\n") ; free(psfb) ; psfb = NULL ;
4664 }
4665
4666 /* check for possibility of 1 stim per run 19 Feb 2014 [rickr] */
4667 /* i.e. nRUNS>1, ny==nRUNS, nx==1, all times fit in respective run */
4668 if( ny == *num_blocks && ny > 1 && nx == 1 ){
4669 int ibot, itop, *bl=*block_list;
4670 for( it=0; it < ny; it++ ) {
4671 ibot = bl[it] ;
4672 itop = (it < ny-1) ? bl[it+1] : nt;
4673 if( tar[it] > (basis_TR*(itop-ibot-1)) ) break;
4674 }
4675 if( it == ny ) /* then might be LOCAL times */
4676 WARNING_message(
4677 "'%s %d' (GLOBAL) has %d runs and %d early events;"
4678 " do you want LOCAL times?",
4679 be->option, is+1, ny, *num_blocks);
4680 }
4681
4682 } else { /****---------- local times => 1 row per block ----------****/
4683 int nout ; float *psfb=NULL ;
4684
4685 INFO_message("%s%s %d using LOCAL times",glprefix,be->option,is+1) ;
4686 if( ny != nbl ){ /* times are relative to block */
4687 WARNING_message(
4688 "'%s %d' file '%s' has %d rows,"
4689 " but dataset has %d time blocks" ,
4690 be->option, is+1, option_data->stim_filename[is], ny,nbl ) ;
4691 if( ny > nbl ) ny = nbl ;
4692 }
4693 STATUS("loading LOCAL times and aux params") ;
4694 for( jj=0 ; jj < ny ; jj++ ){ /* jj=row index=block index */
4695 if( jj < nbl-1 ) tmax = (bst[jj+1]-1-bst[jj])*basis_TR ;
4696 else tmax = (nt -1-bst[jj])*basis_TR ;
4697 for( nout=ii=0 ; ii < nx ; ii++ ){
4698 tt = tar[ii+jj*nx] ;
4699 if( tt >= 0.0f && tt <= tmax ){
4700 for( vv=0 ; vv < vmod+vfun ; vv++ ) zar[vv][ngood] = aar[vv][ii+jj*nx] ;
4701 qar[ngood++] = tt / basis_TR + bst[jj] ;
4702 } else if( tt < big_time ){ /* PSFB entries */
4703 nout++ ; psfb = (float *)realloc(psfb,sizeof(float)*nout) ;
4704 psfb[nout-1] = tt ;
4705 }
4706 }
4707 if( nout ){ /* PSFB strikes again! */
4708 WARNING_message(
4709 "'%s %d' (LOCAL) run#%d has %d times outside range 0 .. %g [PSFB syndrome]",
4710 be->option , is+1 , jj+1 , nout , tmax ) ;
4711 ININFO_message("dataset TR being used is %g s -- unusable times follow",
4712 basis_TR) ;
4713 for( ii=0 ; ii < nout ; ii++ ) fprintf(stderr," %g",psfb[ii]) ;
4714 fprintf(stderr,"\n") ; free(psfb) ; psfb = NULL ;
4715 }
4716 } /* end of loop over row index */
4717
4718 } /** end of converting times into indexes **/
4719
4720 STATUS("loading times/params done") ;
4721
4722 if( ngood > 1 ){ /** check for duplicates [16 Aug 2007] **/
4723 int ndup=0 , nndup=0 ; float qt , dt ;
4724 for( ii=0 ; ii < ngood ; ii++ ){
4725 qt = qar[ii] ;
4726 for( jj=ii+1 ; jj < ngood ; jj++ ){
4727 dt = fabsf(qt-qar[jj]) ;
4728 if( dt == 0.0f ) ndup++ ; /* identical */
4729 else if( dt < 0.50f ) nndup++ ; /* only 50% of a TR apart */
4730 }
4731 }
4732 if( ndup > 0 || nndup > 0 ){
4733 WARNING_message(
4734 "'%s %d' file '%s' has %d duplicate and %d near-duplicate times ???",
4735 be->option , is+1 , option_data->stim_filename[is] , ndup,nndup ) ;
4736 if( nndup > 0 )
4737 ININFO_message(" Where 'near-duplicate' means within 50%% of one TR") ;
4738 if( be->timetype == GLOBAL_TIMES )
4739 ININFO_message(" You are using global times: do you want local times?") ;
4740 }
4741 }
4742
4743 /** create qim image to hold time indexes (and paired vals, if present) **/
4744
4745 if( ngood == 0 ){ /* WTF? no good values found */
4746
4747 WARNING_message(
4748 "!! '%s %d' file '%s' has no good stimulus time values\n",
4749 be->option , is+1 , option_data->stim_filename[is] ) ;
4750 free((void *)qar) ; qim = NULL ; qar = NULL ;
4751 for( vv=0 ; vv < vmod+vfun ; vv++ ) free(zar[vv]) ;
4752 badlev++ ;
4753
4754 } else if( vmod+vfun == 0 ){ /* no paired values */
4755
4756 qim = mri_new( ngood,1 , MRI_float ) ;
4757 qar = (float *)realloc((void *)qar,sizeof(float)*ngood) ;
4758 memcpy(MRI_FLOAT_PTR(qim),qar,sizeof(float)*ngood) ; /* image of times */
4759
4760 } else { /* 08 Mar 2007: have paired values */
4761
4762 MRI_IMAGE *yim, *zim ; int nzb , nbad ;
4763 MRI_IMARR *zimar ;
4764
4765 STATUS("creating new qim") ;
4766
4767 yim = mri_new_vol_empty(ngood,1,1,MRI_float) ;
4768 qar = (float *)realloc((void *)qar,sizeof(float)*ngood) ;
4769 mri_fix_data_pointer( qar , yim ) ; /* image of times */
4770
4771 INIT_IMARR(zimar) ; ADDTO_IMARR(zimar,yim) ;
4772 for( vv=0 ; vv < vmod+vfun ; vv++ ){ /* add images of paired values */
4773 zim = mri_new_vol_empty(ngood,1,1,MRI_float) ;
4774 zar[vv] = (float *)realloc((void *)zar[vv],sizeof(float)*ngood) ;
4775 mri_fix_data_pointer( zar[vv] , zim ) ; /* image of paired vals */
4776 ADDTO_IMARR(zimar,zim) ;
4777 }
4778
4779 qim = mri_imarr_to_fvect(zimar) ;
4780 FREE_IMARR(zimar) ; /* keeps the data, not the MRI_IMAGE junk */
4781
4782 STATUS("checking for bad param values") ;
4783 for( nzb=nbad=kk=0 ; kk < ngood ; kk++ ){ /* check for bad vals */
4784 for( jj=vv=0 ; vv < vmod+vfun ; vv++ ){
4785 if( zar[vv][kk] >= basis_filler ){ jj++; nbad++; zar[vv][kk] = 0.0f; }
4786 else { zbar[vv] += zar[vv][kk] ; }
4787 }
4788 if( jj < vmod+vfun ) nzb++ ;
4789 }
4790 if( nbad > 0 ){ /* report bad paired vals */
4791 WARNING_message(
4792 "!! '%s %d' file '%s': #times=%d #undefined amplitudes=%d",
4793 be->option, is+1, option_data->stim_filename[is] , ngood,nbad );
4794 badlev++ ;
4795 }
4796 if( nzb > 0 && vmod > 0 ){
4797 if( AFNI_yesenv("AFNI_3dDeconvolve_rawAM2") ){
4798 for( vv=0 ; vv < vmod ; vv ++ ) zbar[vv] = 0.0f ;
4799 INFO_message("'%s %d': not centering amplitude parameters",
4800 be->option , is+1 ) ;
4801 } else {
4802 for( vv=0 ; vv < vmod ; vv++ ){
4803 if( be->modsub == NULL || be->modsub[vv] >= basis_filler ){
4804 zbar[vv] /= nzb ; /* average */
4805 INFO_message("'%s %d' average amplitude#%d=%g",
4806 be->option, is+1,vv+1,zbar[vv] ) ;
4807 } else if( btyp == BASIS_MODULATED_PAIR ){
4808 INFO_message("'%s %d' average amplitude#%d=%g -- but subtracting %g",
4809 be->option, is+1,vv+1,zbar[vv],be->modsub[vv] ) ;
4810 zbar[vv] = be->modsub[vv] ;
4811 }
4812 }
4813 }
4814 }
4815
4816 }
4817
4818 /*** replace input times image with time indexes image created above ***/
4819 /** (at present, is not ever used again, but you never know, do you?) **/
4820
4821 mri_free(basis_times[is]) ; basis_times[is] = qim ;
4822
4823 /*-- create basis vectors for this model now --*/
4824 /*-- qar[] = array of time indexes
4825 zar[] = array of amplitudes (if not NULL) --*/
4826
4827 nf = basis_stim[is]->nfunc ; nbas = basis_stim[is]->nparm ;
4828 basis_vect[is] = mri_new( nt , nbas , MRI_float ) ; /* all zeros */
4829
4830 if( qar != NULL ){
4831 int imin,imax , ibot,itop ;
4832 float *bv = MRI_FLOAT_PTR(basis_vect[is]) ;
4833 float dbot,dtop , fnt=(float)nt , z1 , z2[BASIS_MAX_VDIM] , eps ;
4834
4835 #if 0
4836 fprintf(stderr,"%s %d: adjusted time indexes follow:\n",be->option,is+1) ;
4837 for( kk=0 ; kk < ngood ; kk++ ) fprintf(stderr," %g",qar[kk]) ;
4838 fprintf(stderr,"\n") ;
4839 #endif
4840
4841 dbot = be->tbot / basis_TR ; /* range of indexes about each stim time */
4842 dtop = be->ttop / basis_TR ;
4843 imin = 0 ; imax = nt-1 ; /* for the case of nbl=1 */
4844 eps = 0.001f * basis_TR ;
4845
4846 for( kk=0 ; kk < ngood ; kk++ ){ /* for the kk-th stim time */
4847 tt = qar[kk] ; if( tt < 0.0f || tt >= fnt ) continue ;
4848
4849 z1 = 1.0f ; /* default amplitude for first function set */
4850 if( vmod > 0 ){ /* compute modulated amplitude(s) */
4851 if( btyp == BASIS_MODULATED_MONO ) z1 = 0.0f ;
4852 for( vv=0 ; vv < vmod ; vv++ ){
4853 switch( btyp ){
4854 case BASIS_MODULATED_MONO: z1 += zar[vv][kk] ; break;
4855 case BASIS_MODULATED_PAIR: z2[vv] = zar[vv][kk]-zbar[vv]; break;
4856 }
4857 }
4858 }
4859
4860 if( nbl > 1 ){
4861 for( jj=1 ; jj < nbl ; jj++ ) if( tt < bst[jj] ) break ;
4862 jj-- ; /* time index tt is in block #jj */
4863 imin = bst[jj] ; /* first index in block */
4864 if( jj < nbl-1 ) imax = bst[jj+1] - 1 ; /* last index in block */
4865 else imax = nt - 1 ;
4866 }
4867
4868 /* range of indexes to load with the response model */
4869
4870 ibot = (int)myceil ( tt + dbot ) ; if( ibot < imin ) ibot = imin ;
4871 itop = (int)myfloor( tt + dtop ) ; if( itop > imax ) itop = imax ;
4872
4873 #if 0
4874 INFO_message("stim timedex=%g dbot=%g dtop=%g ibot=%d itop=%d",tt,dbot,dtop,ibot,itop) ;
4875 #endif
4876
4877 if( vfun > 0 ){ /* set vfun params in basis functions [08 Dec 2008] */
4878 for( jj=0 ; jj < nf ; jj++ ){
4879 for( vv=0 ; vv < vfun ; vv++ )
4880 basis_func_setparn( be->bfunc[jj] , vv , zar[vv+vmod][kk] ) ;
4881 }
4882 }
4883
4884 for( ii=ibot ; ii <= itop ; ii++ ){ /* loop over active interval */
4885 ss = basis_TR*(ii-tt) ; /* shifted time */
4886 #if 0
4887 ININFO_message("ss=%g tbot=%g ttop=%g ss-ttop=%g",ss,be->tbot,be->ttop,ss-be->ttop) ;
4888 #endif
4889 if( ss+eps < be->tbot || ss-eps > be->ttop ) continue ; /* nugatory */
4890 if( z1 != 0.0f ){
4891 for( jj=0 ; jj < nf ; jj++ )
4892 bv[ii+jj*nt] +=
4893 z1 * basis_funceval( be->bfunc[jj], basis_TR*(ii-tt) );
4894 }
4895
4896 if( vmod > 0 && btyp == BASIS_MODULATED_PAIR ){
4897 for( vv=0 ; vv < vmod ; vv++ )
4898 for( jj=0 ; jj < nf ; jj++ )
4899 bv[ii+(jj+(vv+1)*nf)*nt] +=
4900 z2[vv] * basis_funceval( be->bfunc[jj], basis_TR*(ii-tt) );
4901 }
4902 }
4903 if( btyp == BASIS_MODULATED_INDV ) bv += nf*nt ; /* 16 Jul 2007 */
4904 } /* end of loop over stimulus times */
4905 #if 0
4906 fprintf(stderr,"-stim_times %d: basis vectors follow:\n",is+1) ;
4907 bv = MRI_FLOAT_PTR(basis_vect[is]) ;
4908 for( ii=0 ; ii < nt ; ii++ ){
4909 fprintf(stderr,"%d:",ii) ;
4910 for( jj=0 ; jj < nbas ; jj++ ) fprintf(stderr," %g",bv[ii+jj*nt]) ;
4911 fprintf(stderr,"\n") ;
4912 }
4913 #endif
4914
4915 free(qar) ;
4916 for( vv=0 ; vv < vmod+vfun ; vv++ ) free(zar[vv]) ;
4917 DESTROY_IMARR(vimar) ;
4918
4919 } /* end of creating basis vectors */
4920
4921 } /* end of loop over stim functions */
4922 } /* end of if we have any -stim_times inputs */
4923
4924
4925 /*----- Determine total number of parameters in the model -----*/
4926
4927 qp = (option_data->polort + 1) * (*num_blocks);
4928 q = qp; /* number of baseline parameters */
4929 p = qp; /* number of total parameters */
4930 for (is = 0; is < num_stimts; is++){
4931 if( basis_stim[is] != NULL ){ /* 11 Aug 2004 */
4932 basis_stim[is]->pbot = p ; /* 1st parameter for this model */
4933 p += basis_stim[is]->nparm ; /* number of parameters in model */
4934 } else {
4935 if (max_lag[is] < min_lag[is])
4936 DC_error ("Require min lag <= max lag for all stimuli");
4937 p += max_lag[is] - min_lag[is] + 1;
4938 if (baseline[is]) q += max_lag[is] - min_lag[is] + 1;
4939 }
4940 }
4941
4942 option_data->p = p; /* total number of parameters */
4943 option_data->q = q; /* number of baseline parameters (polort+stim_base) */
4944 option_data->qp = qp; /* number of polort baseline parameters */
4945
4946 /*----- Save info about each column, for later storage [06 Mar 2007] -----*/
4947
4948 option_data->coldat = (column_metadata *)calloc(sizeof(column_metadata),p) ;
4949 ncoldat = p ; /* 16 Aug 2019 */
4950 nblk = *num_blocks ;
4951 npol = option_data->polort ;
4952
4953 p1 = 0 ;
4954 for( is=0 ; is < nblk ; is++ ){
4955 for( it=0 ; it <= npol ; it++ ){
4956 cd.mask = CM_BASELINE_MASK | CM_POLORT_MASK ;
4957 cd.group = -1 ; /* polort group = -1 */
4958 sprintf(cd.name,"Run%c%dPol%c%d",index_prefix,is+1,index_prefix,it) ;
4959 option_data->coldat[p1++] = cd ;
4960 }
4961 }
4962
4963 STIMLABEL_stuff = (stimlabel_stuff *)malloc(sizeof(stimlabel_stuff)) ;
4964 STIMLABEL_stuff->cbot = (int *) malloc(sizeof(int)*num_stimts) ;
4965 STIMLABEL_stuff->ctop = (int *) malloc(sizeof(int)*num_stimts) ;
4966 STIMLABEL_stuff->label = (char **) malloc(sizeof(char *)*num_stimts);
4967
4968 for( nsl=is=0 ; is < num_stimts ; is++ ){
4969 if( basis_stim[is] != NULL ){
4970 nc = basis_stim[is]->nparm ;
4971 mk = 0 ; gp = is+1 ;
4972 } else {
4973 nc = max_lag[is] - min_lag[is] + 1 ;
4974 if( baseline[is] ){ mk = CM_BASELINE_MASK; gp = 0 ; }
4975 else { mk = 0 ; gp = is+1; }
4976 }
4977 if( gp > 0 ){
4978 STIMLABEL_stuff->cbot[nsl] = p1 ;
4979 STIMLABEL_stuff->ctop [nsl] = p1+nc-1 ;
4980 STIMLABEL_stuff->label[nsl] = option_data->stim_label[is] ; nsl++ ;
4981 }
4982 for( it=0 ; it < nc ; it++ ){
4983 cd.mask = mk ; cd.group = gp ;
4984 sprintf(cd.name,"%-1.60s%c%d",option_data->stim_label[is],index_prefix,it) ;
4985 DEBLANK(cd.name) ;
4986 option_data->coldat[p1++] = cd ;
4987 }
4988 }
4989 coldat = option_data->coldat ; /* global variable */
4990 STIMLABEL_stuff->nstim = nsl ;
4991
4992 /*----- Read the censorship file (John Ashcroft, we miss you) -----*/
4993
4994 if (option_data->censor_filename != NULL)
4995 {
4996 /*----- Read the input censor time series array -----*/
4997 *censor_array = read_time_series (option_data->censor_filename,
4998 censor_length);
4999 if (*censor_array == NULL)
5000 {
5001 sprintf (message, "Unable to read censor time series file: %s",
5002 option_data->censor_filename);
5003 DC_error (message);
5004 }
5005 }
5006 else
5007 {
5008 /*----- Create non-censoring censor time series array -----*/
5009 *censor_array = (float *) malloc (sizeof(float) * nt);
5010 MTEST (*censor_array);
5011 *censor_length = nt;
5012 for (it = 0; it < nt; it++)
5013 (*censor_array)[it] = 1.0;
5014 }
5015
5016 /*----- 01 Mar 2007: apply the -CENSORTR commands to censor_array -----*/
5017
5018 if( abc_CENSOR != NULL ){
5019 int ic , rr , aa,bb , nerr=0 , bbot,btop , nblk=*num_blocks ;
5020 for( ic=0 ; ic < num_CENSOR ; ic++ ){ /* loop over CENSOR commands */
5021 rr = abc_CENSOR[ic].i ;
5022 aa = abc_CENSOR[ic].j ; if( aa < 0 ) continue ; /* shouldn't happen */
5023 bb = abc_CENSOR[ic].k ; if( bb < aa ) continue ; /* shouldn't happen */
5024 if( rr == -666 ){ /* run = wildcard ==> expand to nblk new triples */
5025 int_triple rab ;
5026 abc_CENSOR = (int_triple *)realloc( abc_CENSOR ,
5027 sizeof(int_triple)*(num_CENSOR+nblk) );
5028 for( rr=1 ; rr <= nblk ; rr++ ){
5029 rab.i = rr; rab.j = aa; rab.k = bb; abc_CENSOR[num_CENSOR++] = rab;
5030 }
5031 continue ; /* skip to next one */
5032 }
5033 if( rr > 0 ){ /* convert local indexes to global */
5034 if( rr > nblk ){ /* stupid user */
5035 ERROR_message("-CENSORTR %d:%d-%d has run index out of range 1..%d",
5036 rr,aa,bb , nblk ) ;
5037 nerr++ ; aa = -66666666 ;
5038 } else {
5039 bbot = (*block_list)[rr-1] ; /* start index of block #rr */
5040 btop = (rr < nblk) ? (*block_list)[rr]-1 : nt-1 ; /* last index */
5041 if( aa+bbot > btop ){ /* WTF? */
5042 WARNING_message(
5043 "-CENSORTR %d:%d-%d has start index past end of run (%d) - IGNORING",
5044 rr,aa,bb,btop-bbot ) ; aa = -66666666 ;
5045 } else if( bb+bbot > btop ){ /* oopsie */
5046 WARNING_message(
5047 "-CENSORTR %d:%d-%d has stop index past end of run (%d) - STOPPING THERE",
5048 rr,aa,bb,btop-bbot ) ;
5049 }
5050 aa += bbot ; bb += bbot ; if( bb > btop ) bb = btop ;
5051 }
5052 } else { /* global indexes: check for stupidities */
5053 if( aa >= nt ){
5054 WARNING_message(
5055 "-CENSORTR %d..%d has start index past end of data (%d) - IGNORING",
5056 rr,aa,bb,nt-1 ) ; aa = -66666666 ;
5057 } else if( bb > nt ){
5058 WARNING_message(
5059 "-CENSORTR %d..%d has stop index past end of data (%d) - STOPPING THERE",
5060 rr,aa,bb,nt-1 ) ; bb = nt-1 ;
5061 }
5062 }
5063 if( aa < 0 || aa >= nt ) continue ; /* nothing to do */
5064 if( bb < aa || bb >= nt ) continue ;
5065 if( verb > 1 )
5066 ININFO_message("applying -CENSORTR global time indexes %d..%d",aa,bb) ;
5067 for( it=aa ; it <= bb ; it++ ) (*censor_array)[it] = 0.0f ;
5068 } /* end of loop over CENSOR commands */
5069 if( nerr > 0 ) ERROR_exit("Can't continue! Fix the -CENSORTR error%s",
5070 (nerr==1) ? "." : "s." ) ;
5071 free((void *)abc_CENSOR) ; abc_CENSOR = NULL ; num_CENSOR = 0 ;
5072 }
5073
5074 /*----- Build symbolic list of stim names and index ranges [29 Jul 2004] -----*/
5075
5076 nSymStim = num_stimts+1 ;
5077 SymStim = (SYM_irange *)calloc(sizeof(SYM_irange),nSymStim) ;
5078
5079 strcpy( SymStim[num_stimts].name , "Ort" ) ;
5080 SymStim[num_stimts].nbot = 0 ;
5081 SymStim[num_stimts].ntop = qp-1 ;
5082 SymStim[num_stimts].gbot = 0 ;
5083 it = qp ;
5084 for( is=0 ; is < num_stimts ; is++ ){
5085 MCW_strncpy( SymStim[is].name , option_data->stim_label[is] , 64 ) ;
5086 if( basis_stim[is] != NULL ){
5087 SymStim[is].nbot = 0 ;
5088 SymStim[is].ntop = basis_stim[is]->nparm-1 ;
5089 } else {
5090 SymStim[is].nbot = min_lag[is] ;
5091 SymStim[is].ntop = max_lag[is] ;
5092 }
5093 SymStim[is].gbot = it ;
5094 it += SymStim[is].ntop - SymStim[is].nbot + 1 ;
5095 if( strchr(SymStim[is].name,' ') != NULL ||
5096 strchr(SymStim[is].name,'*') != NULL ||
5097 strchr(SymStim[is].name,';') != NULL ){
5098 WARNING_message(
5099 "-stim_label #%d '%s' has characters bad for -gltsym",
5100 is+1 , SymStim[is].name ) ;
5101 }
5102 }
5103
5104 /*----- Read the general linear test matrices -----*/
5105
5106 if (num_glt > 0)
5107 {
5108 int ngerr ;
5109 *glt_cmat = (matrix *) malloc (sizeof(matrix) * num_glt);
5110
5111 /*----- Initialize general linear test matrices -----*/
5112 for (iglt = 0; iglt < num_glt; iglt++)
5113 matrix_initialize (&((*glt_cmat)[iglt]));
5114
5115
5116 for (iglt = 0; iglt < num_glt; iglt++)
5117 {
5118 #if 1
5119 ngerr = SYM_expand_errcount() ;
5120 read_glt_matrix( option_data->glt_filename[iglt] ,
5121 option_data->glt_rows + iglt ,
5122 p , *glt_cmat + iglt ) ;
5123 ngerr = SYM_expand_errcount() - ngerr ;
5124 if( ngerr > 0 )
5125 ERROR_message("-gltsym errors immediately above from file '%s'",
5126 option_data->glt_filename[iglt] ) ;
5127 #else
5128 matrix_file_read (option_data->glt_filename[iglt], /* uses MRI_read_1D() */
5129 option_data->glt_rows[iglt],
5130 p, &((*glt_cmat)[iglt]), 1);
5131 if ((*glt_cmat)[iglt].elts == NULL)
5132 {
5133 sprintf (message, "Unable to read GLT matrix from file: %s",
5134 option_data->glt_filename[iglt]);
5135 DC_error (message);
5136 }
5137 #endif
5138 }
5139
5140 if( SYM_expand_errcount() > 0 )
5141 ERROR_exit("Can't continue after the above -gltsym problems!") ;
5142 }
5143
5144 /*----- done done done -----*/
5145
5146 EXRETURN ;
5147 }
5148
5149
5150 /*---------------------------------------------------------------------------*/
5151 /*
5152 Check whether any of the input stimulus functions consists of all zeros.
5153 Remove any trace of all-zero stimulus functions.
5154 */
5155
remove_zero_stimfns(DC_options * option_data,float ** stimulus,int * stim_length,matrix * glt_cmat)5156 void remove_zero_stimfns
5157 (
5158 DC_options * option_data, /* deconvolution program options */
5159 float ** stimulus, /* stimulus time series arrays */
5160 int * stim_length, /* length of stimulus time series */
5161 matrix * glt_cmat /* general linear test matrices */
5162 )
5163
5164 {
5165 int num_stimts; /* number of stimulus time series arrays */
5166 int is, isp; /* stimulus time series index */
5167 int it; /* time point index */
5168 int num_glt; /* number of general linear tests */
5169 int iglt; /* general linear test index */
5170 int all_zero; /* boolean for stim function contains all zeros */
5171
5172
5173 ENTRY("remove_zero_stimfns") ;
5174
5175 /*----- Initialize local variables -----*/
5176 num_stimts = option_data->num_stimts;
5177 num_glt = option_data->num_glt;
5178
5179
5180 /*----- Loop over all stimulus funcitons -----*/
5181 is = 0;
5182 while (is < num_stimts)
5183 {
5184 if( basis_stim[is] != NULL ){ is++ ; continue ; } /* 12 Aug 2004 */
5185
5186 /*----- Check whether stim function consists of all zeros -----*/
5187 all_zero = TRUE;
5188 for (it = 0; it < stim_length[is]; it++)
5189 {
5190 if (stimulus[is][it] != 0.0)
5191 {
5192 all_zero = FALSE;
5193 break;
5194 }
5195 }
5196
5197 if (all_zero) /*----- Remove this stimulus function -----*/
5198 {
5199 WARNING_message("!! -stim_file function %s comprises all zeros!",
5200 option_data->stim_filename[is]); fflush(stdout); badlev++ ;
5201
5202 if (option_data->num_glt > 0)
5203 DC_error
5204 ("Cannot process -glt option(s) when -stim_file function is all zero");
5205 if( basis_count > 0 )
5206 DC_error
5207 ("Cannot process -stim_times option(s) when -stim_file function is all zero");
5208
5209 option_data->p -=
5210 option_data->stim_maxlag[is] - option_data->stim_minlag[is] + 1;
5211 if (option_data->stim_base[is])
5212 option_data->q -=
5213 option_data->stim_maxlag[is] - option_data->stim_minlag[is] + 1;
5214 for (isp = is; isp < num_stimts-1; isp++)
5215 {
5216 stimulus[isp] = stimulus[isp+1];
5217 stim_length[isp] = stim_length[isp+1];
5218 option_data->stim_filename[isp]
5219 = option_data->stim_filename[isp+1];
5220 option_data->stim_label[isp] = option_data->stim_label[isp+1];
5221 option_data->stim_base[isp]
5222 = option_data->stim_base[isp+1];
5223 option_data->stim_minlag[isp] = option_data->stim_minlag[isp+1];
5224 option_data->stim_maxlag[isp] = option_data->stim_maxlag[isp+1];
5225 option_data->iresp_filename[isp]
5226 = option_data->iresp_filename[isp+1];
5227 option_data->sresp_filename[isp]
5228 = option_data->sresp_filename[isp+1];
5229 }
5230
5231 num_stimts--;
5232 option_data->num_stimts = num_stimts;
5233 }
5234 else
5235 is++;
5236 }
5237
5238 EXRETURN ;
5239 }
5240
5241
5242 /*---------------------------------------------------------------------------*/
5243 /*
5244 Routine to check whether one output file already exists.
5245 */
5246
check_one_output_file(THD_3dim_dataset * dset_time,char * filename)5247 void check_one_output_file
5248 (
5249 THD_3dim_dataset * dset_time, /* input 3D+time data set */
5250 char * filename /* name of output file */
5251 )
5252
5253 {
5254 char message[THD_MAX_NAME]; /* error message */
5255 THD_3dim_dataset * new_dset=NULL; /* output afni data set pointer */
5256 int ierror; /* number of errors in editing data */
5257
5258
5259 /*----- make an empty copy of input dataset -----*/
5260 new_dset = EDIT_empty_copy( dset_time ) ;
5261
5262
5263 ierror = EDIT_dset_items( new_dset ,
5264 ADN_prefix , filename ,
5265 ADN_label1 , filename ,
5266 ADN_self_name , filename ,
5267 ADN_type , ISHEAD(dset_time) ? HEAD_FUNC_TYPE :
5268 GEN_FUNC_TYPE ,
5269 ADN_none ) ;
5270
5271 if( ierror > 0 )
5272 {
5273 sprintf (message,
5274 "*** %d errors in attempting to create output dataset!\n",
5275 ierror);
5276 DC_error (message);
5277 }
5278
5279 #ifdef FIX_CONFLICTS
5280 ierror = THD_deconflict_prefix( new_dset ) ;
5281 if( ierror > 0 && !THD_ok_overwrite() ){ /* ZSS: Dec. 16 08 */
5282 char *pfx = DSET_PREFIX(new_dset) ;
5283 WARNING_message("Filename conflict: changing '%s' to '%s'",
5284 filename , pfx ) ;
5285 strcpy(filename,pfx) ;
5286 }
5287 #else
5288 if( THD_is_file(new_dset->dblk->diskptr->header_name) )
5289 {
5290 sprintf (message,
5291 "Output dataset file %s already exists "
5292 " -- cannot continue! ",
5293 new_dset->dblk->diskptr->header_name);
5294 DC_error (message);
5295 }
5296 #endif
5297
5298 /*----- deallocate memory -----*/
5299 THD_delete_3dim_dataset( new_dset , False ) ; new_dset = NULL ;
5300
5301 }
5302
5303
5304 /*---------------------------------------------------------------------------*/
5305 /*
5306 Routine to check whether output files already exist.
5307 */
5308
check_output_files(DC_options * option_data,THD_3dim_dataset * dset_time)5309 void check_output_files
5310 (
5311 DC_options * option_data, /* deconvolution program options */
5312 THD_3dim_dataset * dset_time /* input 3D+time data set */
5313 )
5314
5315 {
5316 int is; /* stimulus time series index */
5317
5318
5319 /* 03 May 2007: allow default 'Decon' bucket file to be overwritten */
5320
5321 if( option_data->bucket_filename != NULL &&
5322 strcmp(option_data->bucket_filename,"Decon") != 0 )
5323 check_one_output_file (dset_time, option_data->bucket_filename);
5324
5325 if (option_data->fitts_filename != NULL)
5326 check_one_output_file (dset_time, option_data->fitts_filename);
5327
5328 if (option_data->errts_filename != NULL)
5329 check_one_output_file (dset_time, option_data->errts_filename);
5330
5331 for (is = 0; is < option_data->num_stimts; is++)
5332 {
5333 if (option_data->iresp_filename[is] != NULL)
5334 check_one_output_file (dset_time, option_data->iresp_filename[is]);
5335
5336 if (option_data->sresp_filename[is] != NULL)
5337 check_one_output_file (dset_time, option_data->sresp_filename[is]);
5338 }
5339 }
5340
5341
5342 /*---------------------------------------------------------------------------*/
5343 /*
5344 Routine to check for valid inputs.
5345 */
5346
check_for_valid_inputs(DC_options * option_data,THD_3dim_dataset * dset_time,int fmri_length,float * censor_array,int censor_length,int * block_list,int num_blocks,int * stim_length,float ** stimulus,int ** good_list)5347 void check_for_valid_inputs
5348 (
5349 DC_options * option_data, /* deconvolution program options */
5350 THD_3dim_dataset * dset_time, /* input 3D+time data set */
5351 int fmri_length, /* length of input fMRI time series */
5352 float * censor_array, /* input censor time series array */
5353 int censor_length, /* length of censor array */
5354 int * block_list, /* list of block (run) starting points */
5355 int num_blocks, /* number of blocks (runs) */
5356 int * stim_length, /* length of stimulus time series arrays */
5357 float **stimulus , /* 22 Oct 2003: stimulus time series arrays */
5358 int ** good_list /* list of usable time points */
5359 )
5360
5361 {
5362 char message[THD_MAX_NAME]; /* error message */
5363 int is; /* stimulus index */
5364 int num_stimts; /* number of stimulus time series */
5365 int * min_lag; /* minimum time delay for impulse response */
5366 int * max_lag; /* maximum time delay for impulse response */
5367 int * nptr; /* number of stim fn. time points per TR */
5368 int m; /* number of time delays for impulse response */
5369 int qp; /* number of polynomial trend baseline parameters */
5370 int q; /* number of baseline model parameters */
5371 int p; /* number of full model parameters */
5372 int nbricks; /* number of sub-bricks in bucket dataset output */
5373 int it; /* time point index */
5374 int nt; /* number of images in input 3D+time dataset */
5375 int NFirst; /* first image from input 3D+time dataset to use */
5376 int NLast; /* last image from input 3D+time dataset to use */
5377 int N; /* number of usable time points */
5378 int ib; /* block (run) index */
5379 int irb; /* time index relative to start of block (run) */
5380 int num_glt; /* number of general linear tests */
5381 int * glt_rows; /* number of linear constraints in glt */
5382 int iglt; /* general linear test index */
5383 int nerr=0 ; /* 22 Oct 2003 */
5384
5385
5386 /*----- Initialize local variables -----*/
5387 nt = option_data->nt;
5388 num_stimts = option_data->num_stimts;
5389 min_lag = option_data->stim_minlag;
5390 max_lag = option_data->stim_maxlag;
5391 num_glt = option_data->num_glt;
5392 glt_rows = option_data->glt_rows;
5393 nptr = option_data->stim_nptr;
5394 p = option_data->p;
5395 q = option_data->q;
5396 qp = option_data->qp;
5397
5398 /*----- Check if -xsave was given without -bucket ------*/
5399 if( xsave && option_data->bucket_filename == NULL ){
5400 WARNING_message("-xsave given without -bucket; -xsave is disabled!") ;
5401 xsave = 0 ;
5402 }
5403
5404 /*----- Check length of censor array -----*/
5405 if (censor_length < nt)
5406 {
5407 sprintf (message, "Input censor time series file %s is too short (%d < %d)",
5408 option_data->censor_filename,censor_length,nt);
5409 DC_error (message);
5410 }
5411 else if( censor_length > nt ){ /* 19 Jul 2013 */
5412 WARNING_message("Input censor time series file %s is too long (%d > %d)",
5413 option_data->censor_filename,censor_length,nt);
5414 }
5415
5416
5417 /*----- Check validity of concatenated runs list -----*/
5418 for (ib = 0; ib < num_blocks; ib++)
5419 if ((block_list[ib] < 0) || (block_list[ib] >= nt))
5420 {
5421 sprintf (message, "Invalid -concat input: %d ", block_list[ib]);
5422 DC_error (message);
5423 }
5424 if (num_blocks > 1)
5425 for (ib = 1; ib < num_blocks; ib++)
5426 if (block_list[ib] <= block_list[ib-1])
5427 DC_error ("Invalid concatenated runs list");
5428
5429
5430 /*----- Create list of good (usable) time points -----*/
5431 *good_list = (int *) malloc (sizeof(int) * nt); MTEST (*good_list);
5432 NFirst = option_data->NFirst;
5433 if (NFirst < 0){
5434 for (is = 0; is < num_stimts; is++)
5435 if( basis_stim[is] == NULL && NFirst < (max_lag[is]+nptr[is]-1)/nptr[is] )
5436 NFirst = (max_lag[is]+nptr[is]-1)/nptr[is];
5437 if( NFirst > 0 ) /* 04 Oct 2007: warn the user about this 'feature' */
5438 INFO_message(
5439 "First time point used in analysis = index #%d (from max maxlag)",NFirst) ;
5440 }
5441 NLast = option_data->NLast;
5442 if (NLast < 0) NLast = nt;
5443
5444 N = 0;
5445 ib = 0;
5446 for (it = block_list[0]; it < nt; it++)
5447 {
5448 if (ib+1 < num_blocks)
5449 if (it >= block_list[ib+1]) ib++;
5450
5451 irb = it - block_list[ib];
5452
5453 if ((irb >= NFirst) && (irb <= NLast) && (censor_array[it] != 0.0f))
5454 {
5455 (*good_list)[N] = it;
5456 N++;
5457 }
5458 }
5459
5460 if( N < nt ) /* 03 Nov 2010 [Tea Party Day] */
5461 INFO_message("Number of time points: %d (before censor) ; %d (after)",nt,N) ;
5462 else
5463 INFO_message("Number of time points: %d (no censoring)",nt) ;
5464 ININFO_message("Number of parameters: %d [%d baseline ; %d signal]",p,q,p-q) ;
5465
5466 /*----- Check for sufficient data -----*/
5467 if (N == 0) DC_error ("No usable time points? :(");
5468 if (N <= p)
5469 {
5470 if( nt > p ) /* Better grieving when death happens [13 Feb 2018] */
5471 ERROR_message(" *** Censoring has made regression impossible :( ***") ;
5472 else
5473 ERROR_message("Regression model has too many parameters for dataset length :(") ;
5474 sprintf (message, "Insufficient data (%d) for estimating %d parameters", N,p);
5475 DC_error (message);
5476 }
5477 option_data->N = N;
5478
5479 /* save some things in global variables for later reference */
5480
5481 GoodList = *good_list ;
5482 nGoodList = N ;
5483 nParam = p ;
5484
5485 /*----- Check number of stimulus time series -----*/
5486 if (num_stimts < 0)
5487 {
5488 DC_error ("Require: 0 <= num_stimts (DUH! --or-- D'oh!)");
5489 }
5490
5491
5492 /*----- Check lengths of stimulus time series -----*/
5493
5494 #define ALLOW_EXTEND
5495 for (is = 0; is < num_stimts; is++)
5496 {
5497 if( basis_stim[is] != NULL ) continue ; /* 12 Aug 2004 */
5498
5499 if (stim_length[is] < nt*nptr[is])
5500 {
5501 #ifndef ALLOW_EXTEND
5502 sprintf (message, "Input stimulus time series file %s is too short",
5503 option_data->stim_filename[is]);
5504 DC_error (message);
5505 #else
5506 int nlen=nt*nptr[is], qq ;
5507 WARNING_message(
5508 "input stimulus time series file %s is too short:\n"
5509 " length = %d, but should be at least %d." ,
5510 option_data->stim_filename[is] , stim_length[is] , nlen ) ;
5511
5512 if( option_data->slice_base[is] == 0 ){
5513 stimulus[is] = (float *) realloc( stimulus[is] , sizeof(float)*nlen ) ;
5514 for( qq=stim_length[is] ; qq < nlen ; qq++ ) stimulus[is][qq] = 0.0 ;
5515 } else {
5516 int ny=option_data->slice_base[is] , nx=stim_length[is] ;
5517 MRI_IMAGE *tim, *sim=mri_new_vol_empty(nx,ny,1,MRI_float) ;
5518 mri_fix_data_pointer( stimulus[is] , sim ) ;
5519 tim = mri_zeropad_2D( 0,nlen-nx , 0,0 , sim ) ;
5520 stimulus[is] = MRI_FLOAT_PTR(tim) ; mri_free(sim) ;
5521 }
5522 stim_length[is] = nlen ; nerr++ ;
5523 #endif
5524 } else if( stim_length[is] > nt*nptr[is] ){ /* 02 Jul 2009 */
5525
5526 WARNING_message(
5527 "-stim_file %d: file length is %d, longer than expected %d (from dataset)",
5528 is+1 , stim_length[is] , nt*nptr[is] ) ;
5529 }
5530 }
5531 #ifdef ALLOW_EXTEND
5532 if( nerr > 0 ){
5533 char *eee = getenv("AFNI_3dDeconvolve_extend") ;
5534 if( eee != NULL && (*eee=='n' || *eee=='N') )
5535 ERROR_exit("Can't continue with too short files!\n"
5536 " AFNI_3dDeconvolve_extend = %s",eee ) ;
5537
5538 INFO_message("EXTENDING short files with zero values\n"
5539 " (to stop this behavior, setenv AFNI_3dDeconvolve_extend NO)") ;
5540 }
5541 #endif
5542
5543
5544 #undef TMESS
5545 #define TMESS WARNING_message /* WARNING_message or ERROR_exit */
5546
5547 /*----- Check whether time lags are reasonable -----*/
5548 for (is = 0; is < num_stimts; is++)
5549 {
5550 if( basis_stim[is] != NULL ) continue ; /* 12 Aug 2004 */
5551
5552 m = max_lag[is] - min_lag[is] + 1;
5553 if (m < 2)
5554 {
5555 if (option_data->iresp_filename[is] != NULL)
5556 {
5557 TMESS("Only %d time point for output dataset %s",
5558 m, option_data->iresp_filename[is]);
5559 }
5560
5561 if (option_data->sresp_filename[is] != NULL)
5562 {
5563 TMESS("Only %d time point for output dataset %s",
5564 m, option_data->sresp_filename[is]);
5565 }
5566 }
5567 if ((m < 4) && (option_data->tshift))
5568 {
5569 if (option_data->iresp_filename[is] != NULL)
5570 {
5571 sprintf (message, "Only %d time points for 3D+time dataset %s\n",
5572 m, option_data->iresp_filename[is]);
5573 strcat (message, "Require >= 4 data points for -tshift option");
5574 DC_error (message);
5575 }
5576 }
5577 }
5578
5579
5580 /*----- Calculate number of sub-bricks in the bucket dataset,
5581 and check for illegal number of sub-bricks -----*/
5582 nbricks = 0;
5583 if (option_data->bucket_filename != NULL)
5584 {
5585 if (! option_data->nocout)
5586 {
5587 if (! option_data->nobout) /* baseline coefs + t stats */
5588 nbricks += qp * (1 + option_data->tout);
5589
5590 for (is = 0; is < num_stimts; is++) /* individual -stim coefs + stats */
5591 {
5592 if ((!option_data->stim_base[is]) || (!option_data->nobout))
5593 {
5594 if( basis_stim[is] != NULL ) m = basis_stim[is]->nparm ;
5595 else m = max_lag[is] - min_lag[is] + 1;
5596 nbricks += m * (1 + option_data->tout);
5597 nbricks += option_data->rout + option_data->fout;
5598 }
5599 }
5600 }
5601
5602 /* full model stats */
5603
5604 nbricks += option_data->rout + option_data->do_fullf + option_data->vout;
5605
5606 if (num_glt > 0)
5607 for (iglt = 0; iglt < num_glt; iglt++) /* GLT coefs + stats */
5608 {
5609 nbricks += glt_rows[iglt] * (1 + option_data->tout);
5610 nbricks += option_data->rout + option_data->fout;
5611 }
5612
5613 if (nbricks <= 0)
5614 {
5615 sprintf (message,
5616 "User requested bucket dataset with only %d sub-bricks",
5617 nbricks);
5618 DC_error (message);
5619 }
5620
5621 }
5622 option_data->nbricks = nbricks;
5623
5624
5625 /*----- Check for zero slice offsets with nptr option -----*/
5626 if (dset_time != NULL)
5627 if (dset_time->taxis->nsl > 0)
5628 for (is = 0; is < num_stimts; is++)
5629 if (nptr[is] > 1)
5630 {
5631 sprintf (message, "Must align all slices to 0 offset time, \n ");
5632 strcat (message, "before using -stim_nptr option. ");
5633 strcat (message, "See program 3dTshift. ");
5634 DC_error (message);
5635 }
5636
5637
5638 /*----- Check for -tshift and -input1D option -----*/
5639 if ((option_data->tshift) && (option_data->input1D_filename != NULL))
5640 DC_error ("-tshift option is not compatible with -input1D option");
5641
5642
5643 /*----- Check whether any of the output files already exist -----*/
5644 #ifndef FIX_CONFLICTS
5645 if (option_data->input_filename != NULL)
5646 check_output_files (option_data, dset_time);
5647 #endif
5648
5649 }
5650
5651
5652 /*---------------------------------------------------------------------------*/
5653 /*
5654 Allocate volume memory and fill with zeros.
5655 */
5656
5657 static long long zvf_totalbytes = 0 ; /* 04 Mar 2008 */
5658
zero_fill_volume(float ** fvol,int nxyz)5659 void zero_fill_volume (float ** fvol, int nxyz)
5660 {
5661 int ixyz;
5662
5663 zvf_totalbytes += (long long) (sizeof(float) * nxyz) ; /* 04 Mar 2008 */
5664
5665 if( proc_numjob == 1 ){ /* 1 process ==> allocate locally */
5666
5667 *fvol = (float *) malloc (sizeof(float) * nxyz);
5668
5669 if( *fvol == NULL ){ /* 04 Mar 2008 */
5670 MEM_MESSAGE ;
5671 ERROR_message("Memory allocation for output sub-bricks fails!") ;
5672 ERROR_message("Have allocated %s bytes (about %s) for output, up to now",
5673 commaized_integer_string(zvf_totalbytes) ,
5674 approximate_number_string((double)zvf_totalbytes) ) ;
5675 ERROR_message("Potential lenitives or palliatives:\n"
5676 " ++ Use 3dZcutup to cut input dataset into\n"
5677 " smaller volumes, then 3dZcat to put\n"
5678 " the results datasets back together.\n"
5679 " ++ Reduce the number of output sub-bricks.\n"
5680 " ++ Use a system with more memory and/or swap space."
5681 ) ;
5682 ERROR_exit("Alas, 3dDeconvolve cannot continue under these circumstances.") ;
5683 }
5684
5685 for (ixyz = 0; ixyz < nxyz; ixyz++) (*fvol)[ixyz] = 0.0;
5686
5687 }
5688 #ifdef PROC_MAX
5689 else { /* multiple processes ==> prepare for shared memory */
5690 /* by remembering what to do */
5691
5692 proc_shm_arnum++ ;
5693 proc_shm_arsiz = (int *) realloc( proc_shm_arsiz ,
5694 sizeof(int) *proc_shm_arnum ) ;
5695 proc_shm_ar = (float ***) realloc( proc_shm_ar ,
5696 sizeof(float **)*proc_shm_arnum ) ;
5697 proc_shm_arsiz[proc_shm_arnum-1] = nxyz ;
5698 proc_shm_ar[proc_shm_arnum-1] = fvol ;
5699
5700 /* actual allocation and pointer assignment (to *fvol)
5701 will take place in function proc_finalize_shm_volumes() */
5702 }
5703 #endif
5704 }
5705
5706 /*---------------------------------------------------------------------------*/
5707
5708 #ifdef PROC_MAX
5709
5710 /*** signal handler for fatal errors -- make sure shared memory is deleted ***/
5711
5712 #include <signal.h>
5713
proc_sigfunc(int sig)5714 void proc_sigfunc(int sig)
5715 {
5716 char * sname ; int ii ;
5717 static volatile int fff=0 ;
5718 if( fff ) _exit(1); else fff=1 ;
5719 switch(sig){
5720 default: sname = "unknown" ; break ;
5721 case SIGHUP: sname = "SIGHUP" ; break ;
5722 case SIGTERM: sname = "SIGTERM" ; break ;
5723 case SIGILL: sname = "SIGILL" ; break ;
5724 case SIGKILL: sname = "SIGKILL" ; break ;
5725 case SIGPIPE: sname = "SIGPIPE" ; break ;
5726 case SIGSEGV: sname = "SIGSEGV" ; break ;
5727 case SIGBUS: sname = "SIGBUS" ; break ;
5728 case SIGINT: sname = "SIGINT" ; break ;
5729 case SIGFPE: sname = "SIGFPE" ; break ;
5730 }
5731 if( proc_shmid > 0 ){
5732 shmctl( proc_shmid , IPC_RMID , NULL ) ; proc_shmid = 0 ;
5733 }
5734 fprintf(stderr,"Fatal Signal %d (%s) received in job #%d\n",
5735 sig,sname,proc_ind) ;
5736 exit(1) ;
5737 }
5738
5739 /*---------------------------------------------------------------*/
5740
proc_atexit(void)5741 void proc_atexit( void ) /*** similarly - atexit handler ***/
5742 {
5743 if( proc_shmid > 0 )
5744 shmctl( proc_shmid , IPC_RMID , NULL ) ;
5745 }
5746
5747 /*---------------------------------------------------------------*/
5748 /*** This function is called to allocate all output
5749 volumes at once in shared memory, and set their pointers ***/
5750
5751 /** 24 Oct 2005: use mmap() instead of shared memory, if possible **/
5752
5753 #include <sys/mman.h>
5754 #if !defined(MAP_ANON) && defined(MAP_ANONYMOUS)
5755 # define MAP_ANON MAP_ANONYMOUS
5756 #endif
5757
proc_finalize_shm_volumes(void)5758 void proc_finalize_shm_volumes(void)
5759 {
5760 char kstr[32] ; int ii ;
5761 long long psum , twogig = 2ll * 1024ll * 1024ll * 1024ll ;
5762
5763 if( proc_shm_arnum == 0 ) return ; /* should never happen */
5764
5765 /** 21 Oct 2005: check in big arithmetic how much mem we need **/
5766
5767 psum = 0 ;
5768 for( ii=0 ; ii < proc_shm_arnum ; ii++ )
5769 psum += (long long)proc_shm_arsiz[ii] ;
5770 psum *= sizeof(float) ;
5771 #ifdef MAP_ANON
5772 if( psum >= twogig &&
5773 ( sizeof(void *) < 8 || sizeof(size_t) < 8 ) ) /* too much for 32-bit */
5774 #else
5775 if( psum >= twogig ) /* too much for shmem */
5776 #endif
5777 ERROR_exit(
5778 "Total shared memory needed = %s >= %s (2 GB)\n"
5779 "** SUGGESTION 1: Use 3dAutobox to automatically eliminate non-brain\n"
5780 " areas from the 3d+time input dataset and reduce memory \n"
5781 " requirements, e.g.\n"
5782 " 3dAutobox -prefix Subj1AllRuns_Smaller -input Subj1AllRuns\n"
5783 " Then run 3dDeconvolve again with the smaller 3d+time input dataset\n"
5784 "\n"
5785 "** SUGGESTION 2: Use 3dZcutup to slice dataset into smaller pieces\n"
5786 "** and then 3dZcat to glue results back together.\n"
5787 "\n"
5788 "** SUGGESTION 3: Run on a 64-bit computer system, instead of 32-bit.\n"
5789 , commaized_integer_string(psum) , commaized_integer_string(twogig) ) ;
5790 else {
5791 INFO_message("total shared memory needed = %s bytes (about %s)" ,
5792 commaized_integer_string(psum) ,
5793 approximate_number_string((double)psum) ) ;
5794 if( verb ) MEM_MESSAGE ;
5795 }
5796
5797 proc_shmsize = psum ; /* global variable */
5798
5799 /*------- create shared memory segment -------*/
5800
5801 #ifdef MAP_ANON /** 24 Oct 2005: use mmap() instead of shmem **/
5802
5803 #undef MY_MMAP_FLAGS
5804 #ifdef MAP_NORESERVE /* Solaris */
5805 # define MY_MMAP_FLAGS (MAP_ANON | MAP_SHARED | MAP_NORESERVE)
5806 #else
5807 # define MY_MMAP_FLAGS (MAP_ANON | MAP_SHARED)
5808 #endif
5809
5810 proc_shmptr = mmap( (void *)0 , (size_t)psum ,
5811 PROT_READ | PROT_WRITE , MY_MMAP_FLAGS ,
5812 -1 , 0 ) ;
5813 if( proc_shmptr == NULL || proc_shmptr == (void *)(-1) ){
5814 perror("** FATAL ERROR: Can't create shared mmap() segment\n"
5815 "** Unix message") ;
5816 exit(1) ;
5817 }
5818
5819 #else /** old code: shared memory segment **/
5820
5821 UNIQ_idcode_fill( kstr ) ; /* unique string "key" */
5822 proc_shmid = shm_create( kstr , proc_shmsize ) ; /* thd_iochan.c */
5823 if( proc_shmid < 0 ){
5824 fprintf(stderr,"\n** Can't create shared memory of size %s!\n"
5825 "** Try re-running without -jobs option!\n" ,
5826 commaized_integer_string(proc_shmsize) ) ;
5827
5828 /** if failed, print out some advice on how to tune SHMMAX **/
5829
5830 { char *cmd=NULL ;
5831 #if defined(LINUX)
5832 cmd = "cat /proc/sys/kernel/shmmax" ;
5833 #elif defined(SOLARIS)
5834 cmd = "/usr/sbin/sysdef | grep SHMMAX" ;
5835 #elif defined(DARWIN)
5836 cmd = "sysctl -n kern.sysv.shmmax" ;
5837 #endif
5838 if( cmd != NULL ){
5839 FILE *fp = popen( cmd , "r" ) ;
5840 if( fp != NULL ){
5841 long long smax=0 ;
5842 fscanf(fp,"%lld",&smax) ; pclose(fp) ;
5843 if( smax > 0 )
5844 fprintf(stderr ,
5845 "\n"
5846 "** POSSIBLY USEFUL ADVICE:\n"
5847 "** Current max shared memory size = %lld bytes.\n"
5848 "** For information on how to change this, see\n"
5849 "** https://afni.nimh.nih.gov/afni/doc/misc/afni_parallelize\n"
5850 "** and also contact your Unix system administrator.\n"
5851 , smax ) ;
5852 }
5853 }
5854 }
5855 exit(1) ;
5856 }
5857
5858 #endif /* MAP_ANON */
5859
5860 /* set a signal handler to catch most fatal errors and
5861 delete the shared memory segment if program crashes */
5862
5863 signal(SIGPIPE,proc_sigfunc) ; signal(SIGSEGV,proc_sigfunc) ;
5864 signal(SIGINT ,proc_sigfunc) ; signal(SIGFPE ,proc_sigfunc) ;
5865 signal(SIGBUS ,proc_sigfunc) ; signal(SIGHUP ,proc_sigfunc) ;
5866 signal(SIGTERM,proc_sigfunc) ; signal(SIGILL ,proc_sigfunc) ;
5867 signal(SIGKILL,proc_sigfunc) ; signal(SIGPIPE,proc_sigfunc) ;
5868 atexit(proc_atexit) ; /* or when the program exits */
5869
5870 #ifdef MAP_ANON
5871 INFO_message("mmap() memory allocated: %s bytes (about %s)\n" ,
5872 commaized_integer_string(proc_shmsize),
5873 approximate_number_string((double)proc_shmsize) );
5874 #else
5875 INFO_message("Shared memory allocated: %s bytes at id=%d\n" ,
5876 commaized_integer_string(proc_shmsize) , proc_shmid ) ;
5877 #endif
5878
5879 /* get pointer to shared memory segment we just created */
5880
5881 #ifndef MAP_ANON
5882 if( proc_shmid > 0 ){
5883 proc_shmptr = shm_attach( proc_shmid ) ; /* thd_iochan.c */
5884 if( proc_shmptr == NULL ){
5885 fprintf(stderr,"\n** Can't attach to shared memory!?\n"
5886 "** This is bizarre.\n" ) ;
5887 shmctl( proc_shmid , IPC_RMID , NULL ) ;
5888 exit(1) ;
5889 }
5890 }
5891 #endif
5892
5893 /* clear all shared memory to zero */
5894
5895 memset( proc_shmptr , 0 , proc_shmsize ) ;
5896
5897 /* fix the local pointers to arrays in shared memory */
5898
5899 *proc_shm_ar[0] = (float *) proc_shmptr ;
5900 for( ii=1 ; ii < proc_shm_arnum ; ii++ )
5901 *proc_shm_ar[ii] = *proc_shm_ar[ii-1] + proc_shm_arsiz[ii] ;
5902
5903 return ;
5904 }
5905
5906 /*-------------------------------------------------------------*/
5907 /*** This function replaces free();
5908 it won't try to free things stored in the shared memory ***/
5909
proc_free(void * ptr)5910 void proc_free( void *ptr )
5911 {
5912 int ii ;
5913
5914 if( ptr == NULL ) return ;
5915 if( proc_shmptr == NULL ){ free(ptr); return; } /* no shm */
5916 for( ii=0 ; ii < proc_shm_arnum ; ii++ )
5917 if( ((float *)ptr) == *proc_shm_ar[ii] ) return;
5918 free(ptr); return;
5919 }
5920
5921 #undef free /* replace use of library free() */
5922 #define free proc_free /* with proc_free() function */
5923
5924 #endif /* PROC_MAX */
5925
5926 /*---------------------------------------------------------------------------*/
5927 /*
5928 Allocate memory for output volumes.
5929 */
5930
allocate_memory(DC_options * option_data,float *** coef_vol,float *** scoef_vol,float *** tcoef_vol,float *** fpart_vol,float *** rpart_vol,float ** mse_vol,float ** ffull_vol,float ** rfull_vol,float **** glt_coef_vol,float **** glt_tcoef_vol,float *** glt_fstat_vol,float *** glt_rstat_vol,float *** fitts_vol,float *** errts_vol)5931 void allocate_memory
5932 (
5933 DC_options * option_data, /* deconvolution algorithm options */
5934
5935 float *** coef_vol, /* array of volumes of signal model parameters */
5936 float *** scoef_vol, /* array of volumes of parameter std. devs. */
5937 float *** tcoef_vol, /* array of volumes of parameter t-statistics */
5938 float *** fpart_vol, /* array of volumes of partial F-statistics */
5939 float *** rpart_vol, /* array of volumes of partial R^2 stats. */
5940 float ** mse_vol, /* volume of full model mean square error */
5941 float ** ffull_vol, /* volume of full model F-statistics */
5942 float ** rfull_vol, /* volume of full model R^2 stats. */
5943
5944 float **** glt_coef_vol, /* volumes for GLT linear combinations */
5945 float **** glt_tcoef_vol, /* volumes for GLT t-statistics */
5946 float *** glt_fstat_vol, /* volumes for GLT F-statistics */
5947 float *** glt_rstat_vol, /* volumes for GLT R^2 stats. */
5948
5949 float *** fitts_vol, /* volumes for full model fit to input data */
5950 float *** errts_vol /* volumes for residual errors */
5951 )
5952
5953 {
5954 int ip; /* parameter index */
5955 int qp; /* number of polynomial trend baseline parameters */
5956 int q; /* number of baseline model parameters */
5957 int p; /* number of full model parameters */
5958 int nxyz; /* total number of voxels */
5959 int ixyz; /* voxel index */
5960 int is; /* stimulus index */
5961 int num_stimts; /* number of stimulus time series */
5962 int num_glt; /* number of general linear tests */
5963 int iglt; /* general linear test index */
5964 int nlc; /* number of linear combinations in a GLT */
5965 int ilc; /* linear combination index */
5966 int it; /* time point index */
5967 int nt; /* number of images in input 3D+time dataset */
5968 int * min_lag; /* minimum time delay for impulse response */
5969 int * max_lag; /* maximum time delay for impulse response */
5970
5971 int fout; /* flag to output F-statistics */
5972 int rout; /* flag to output R^2 statistics */
5973 int tout; /* flag to output t-statistics */
5974 int vout; /* flag to output variance map */
5975 int bout; /* flag to output baseline coefficients */
5976 int cout; /* flag to output fit coefficients */
5977 int ibot,itop ;
5978
5979
5980 ENTRY("allocate_memory") ;
5981
5982 /*----- Initialize local variables -----*/
5983 nxyz = option_data->nxyz;
5984 num_stimts = option_data->num_stimts;
5985 num_glt = option_data->num_glt;
5986 qp = option_data->qp;
5987 q = option_data->q;
5988 p = option_data->p;
5989 nt = option_data->nt;
5990 min_lag = option_data->stim_minlag;
5991 max_lag = option_data->stim_maxlag;
5992
5993 fout = option_data->fout;
5994 rout = option_data->rout;
5995 tout = option_data->tout;
5996 vout = option_data->vout;
5997 bout = 1 - (option_data->nobout || option_data->nocout);
5998 cout = 1 - option_data->nocout;
5999
6000 if( CoefFilename != NULL ){ bout = cout = 1 ; } /* 26 Jul 2004 */
6001
6002 /*----- Allocate memory space for volume data -----*/
6003 *coef_vol = (float **) malloc (sizeof(float *) * p); MTEST(*coef_vol);
6004 *scoef_vol = (float **) malloc (sizeof(float *) * p); MTEST(*scoef_vol);
6005 *tcoef_vol = (float **) malloc (sizeof(float *) * p); MTEST(*tcoef_vol);
6006 for (ip = 0; ip < p; ip++)
6007 {
6008 (*coef_vol)[ip] = NULL;
6009 (*scoef_vol)[ip] = NULL;
6010 (*tcoef_vol)[ip] = NULL;
6011 }
6012
6013 if (bout)
6014 for (ip = 0; ip < qp; ip++)
6015 {
6016 zero_fill_volume (&((*coef_vol)[ip]), nxyz);
6017 if (tout) zero_fill_volume (&((*tcoef_vol)[ip]), nxyz);
6018 }
6019
6020 ip = qp - 1;
6021 for (is = 0; is < num_stimts; is++)
6022 {
6023 if( basis_stim[is] != NULL ){ ibot=0; itop=basis_stim[is]->nparm-1; }
6024 else { ibot=min_lag[is]; itop=max_lag[is]; }
6025 for (it = ibot; it <= itop; it++)
6026 {
6027 ip++;
6028 if (option_data->stim_base[is])
6029 {
6030 if (bout || (option_data->iresp_filename[is] != NULL))
6031 zero_fill_volume (&((*coef_vol)[ip]), nxyz);
6032 if (bout && tout)
6033 zero_fill_volume (&((*tcoef_vol)[ip]), nxyz);
6034 }
6035 else
6036 {
6037 if (cout || (option_data->iresp_filename[is] != NULL))
6038 zero_fill_volume (&((*coef_vol)[ip]), nxyz);
6039 if (cout && tout)
6040 zero_fill_volume (&((*tcoef_vol)[ip]), nxyz);
6041 }
6042 if (option_data->sresp_filename[is] != NULL)
6043 zero_fill_volume (&((*scoef_vol)[ip]), nxyz);
6044 }
6045 }
6046
6047
6048 if (fout)
6049 {
6050 *fpart_vol = (float **) malloc (sizeof(float *) * num_stimts);
6051 MTEST(*fpart_vol);
6052 for (is = 0; is < num_stimts; is++)
6053 if ((! option_data->stim_base[is]) || (! option_data->nobout))
6054 zero_fill_volume (&((*fpart_vol)[is]), nxyz);
6055 else
6056 (*fpart_vol)[is] = NULL;
6057 }
6058
6059
6060 if (rout)
6061 {
6062 *rpart_vol = (float **) malloc (sizeof(float *) * num_stimts);
6063 MTEST(*rpart_vol);
6064 for (is = 0; is < num_stimts; is++)
6065 if ((! option_data->stim_base[is]) || (! option_data->nobout))
6066 zero_fill_volume (&((*rpart_vol)[is]), nxyz);
6067 else
6068 (*rpart_vol)[is] = NULL;
6069 }
6070
6071
6072 if (vout || basis_need_mse) zero_fill_volume (&(*mse_vol), nxyz);
6073 if (option_data->do_fullf) zero_fill_volume (&(*ffull_vol), nxyz);
6074 if (rout) zero_fill_volume (&(*rfull_vol), nxyz);
6075
6076
6077 /*----- Allocate memory space for GLT volume data -----*/
6078 if (num_glt > 0)
6079 {
6080 *glt_coef_vol = (float ***) malloc (sizeof(float **) * num_glt);
6081 MTEST(*glt_coef_vol);
6082
6083 if (tout)
6084 {
6085 *glt_tcoef_vol = (float ***) malloc (sizeof(float **) * num_glt);
6086 MTEST(*glt_tcoef_vol);
6087 }
6088
6089 if (fout)
6090 {
6091 *glt_fstat_vol = (float **) malloc (sizeof(float *) * num_glt);
6092 MTEST(*glt_fstat_vol);
6093 }
6094
6095 if (rout)
6096 {
6097 *glt_rstat_vol = (float **) malloc (sizeof(float *) * num_glt);
6098 MTEST(*glt_rstat_vol);
6099 }
6100
6101 for (iglt = 0; iglt < num_glt; iglt++)
6102 {
6103 nlc = option_data->glt_rows[iglt];
6104
6105 (*glt_coef_vol)[iglt] = (float **) malloc (sizeof(float *) * nlc);
6106 MTEST((*glt_coef_vol)[iglt]);
6107
6108 if (tout)
6109 {
6110 (*glt_tcoef_vol)[iglt]
6111 = (float **) malloc (sizeof(float *) * nlc);
6112 MTEST((*glt_tcoef_vol)[iglt]);
6113 }
6114
6115 for (ilc = 0; ilc < nlc; ilc++)
6116 {
6117 zero_fill_volume (&((*glt_coef_vol)[iglt][ilc]), nxyz);
6118 if (tout)
6119 zero_fill_volume (&((*glt_tcoef_vol)[iglt][ilc]), nxyz);
6120 }
6121
6122 if (fout) zero_fill_volume (&((*glt_fstat_vol)[iglt]), nxyz);
6123 if (rout) zero_fill_volume (&((*glt_rstat_vol)[iglt]), nxyz);
6124 }
6125 }
6126
6127
6128 /*----- Allocate memory for fitted time series -----*/
6129 /* do not allocate when using x1D_stop [20 Oct 2021 rickr] */
6130 if (option_data->fitts_filename != NULL && !option_data->x1D_stop)
6131 {
6132 *fitts_vol = (float **) malloc (sizeof(float **) * nt);
6133 MTEST (*fitts_vol);
6134 for (it = 0; it < nt; it++)
6135 {
6136 zero_fill_volume (&((*fitts_vol)[it]), nxyz);
6137 }
6138 }
6139
6140 /*----- Allocate memory for residual errors -----*/
6141 if (option_data->errts_filename != NULL && !option_data->x1D_stop)
6142 {
6143 *errts_vol = (float **) malloc (sizeof(float **) * nt);
6144 MTEST (*errts_vol);
6145 for (it = 0; it < nt; it++)
6146 {
6147 zero_fill_volume (&((*errts_vol)[it]), nxyz);
6148 }
6149 }
6150
6151 #ifdef PROC_MAX
6152 if( proc_numjob > 1 ) proc_finalize_shm_volumes() ; /* RWCox */
6153 #endif
6154
6155 EXRETURN ;
6156 }
6157
6158
6159 /*---------------------------------------------------------------------------*/
6160 /*
6161 Perform all program initialization.
6162 */
6163
initialize_program(int argc,char ** argv,DC_options ** option_data,THD_3dim_dataset ** dset_time,byte ** mask_vol,float ** fmri_data,int * fmri_length,float ** censor_array,int * censor_length,int ** good_list,int ** block_list,int * num_blocks,float *** stimulus,int ** stim_length,matrix ** glt_cmat,float *** coef_vol,float *** scoef_vol,float *** tcoef_vol,float *** fpart_vol,float *** rpart_vol,float ** mse_vol,float ** ffull_vol,float ** rfull_vol,float **** glt_coef_vol,float **** glt_tcoef_vol,float *** glt_fstat_vol,float *** glt_rstat_vol,float *** fitts_vol,float *** errts_vol)6164 void initialize_program
6165 (
6166 int argc, /* number of input arguments */
6167 char ** argv, /* array of input arguments */
6168 DC_options ** option_data, /* deconvolution algorithm options */
6169 THD_3dim_dataset ** dset_time, /* input 3D+time data set */
6170 byte ** mask_vol, /* input mask volume */
6171 float ** fmri_data, /* input fMRI time series data */
6172 int * fmri_length, /* length of fMRI time series */
6173 float ** censor_array, /* input censor time series array */
6174 int * censor_length, /* length of censor time series */
6175 int ** good_list, /* list of usable time points */
6176 int ** block_list, /* list of block (run) starting points */
6177 int * num_blocks, /* number of blocks (runs) */
6178 float *** stimulus, /* stimulus time series arrays */
6179 int ** stim_length, /* length of stimulus time series */
6180 matrix ** glt_cmat, /* general linear test matrices */
6181
6182 float *** coef_vol, /* array of volumes of signal model parameters */
6183 float *** scoef_vol, /* array of volumes of parameter std. devs. */
6184 float *** tcoef_vol, /* array of volumes of parameter t-statistics */
6185 float *** fpart_vol, /* array of volumes of partial F-statistics */
6186 float *** rpart_vol, /* array of volumes of partial R^2 stats. */
6187 float ** mse_vol, /* volume of full model mean square error */
6188 float ** ffull_vol, /* volume of full model F-statistics */
6189 float ** rfull_vol, /* volume of full model R^2 stats. */
6190
6191 float **** glt_coef_vol, /* volumes for GLT linear combinations */
6192 float **** glt_tcoef_vol, /* volumes for GLT t-statistics */
6193 float *** glt_fstat_vol, /* volumes for GLT F-statistics */
6194 float *** glt_rstat_vol, /* volumes for GLT R^2 stats. */
6195
6196 float *** fitts_vol, /* volumes for full model fit to input data */
6197 float *** errts_vol /* volumes for residual errors */
6198 )
6199
6200 {
6201 int iglt; /* general linear test index */
6202
6203 ENTRY("initialize_program") ;
6204
6205 set_obliquity_report(0); /* silence obliquity */
6206
6207 /*----- Allocate memory -----*/
6208 *option_data = (DC_options *) malloc (sizeof(DC_options));
6209
6210
6211 /*----- Get command line inputs -----*/
6212 get_options (argc, argv, *option_data);
6213
6214
6215 /*----- Identify software -----*/
6216 if (!(*option_data)->quiet) identify_software();
6217
6218 if( xrestore ) EXRETURN ; /* 26 Jul 2004 - special operations to do! */
6219
6220 /*----- Tell the user if he is being foolish -----*/
6221 if( !(*option_data)->quiet &&
6222 !legendre_polort &&
6223 (*option_data)->polort > 1 ){ /* 20 Jul 2004 */
6224 WARNING_message("you have polynomials of order %d for the baseline\n"
6225 " but disabled use of the Legendre polynomials!\n"
6226 " Check the matrix condition and accuracy of results!" ,
6227 (*option_data)->polort ) ;
6228 (*option_data)->nocond = 0 ;
6229 }
6230
6231 /*----- Read input data -----*/
6232 read_input_data (*option_data, dset_time, mask_vol, fmri_data, fmri_length,
6233 censor_array, censor_length, block_list, num_blocks,
6234 stimulus, stim_length, glt_cmat);
6235
6236
6237 /*----- Remove all-zero stimulus functions -----*/
6238 if( !use_psinv )
6239 remove_zero_stimfns (*option_data, *stimulus, *stim_length, *glt_cmat);
6240
6241
6242 /*----- Check for valid inputs -----*/
6243 check_for_valid_inputs (*option_data, *dset_time,
6244 *fmri_length, *censor_array, *censor_length,
6245 *block_list, *num_blocks, *stim_length, *stimulus, good_list);
6246
6247
6248 /*----- Allocate memory for output volumes -----*/
6249 if (!(*option_data)->nodata){
6250 allocate_memory (*option_data, coef_vol, scoef_vol, tcoef_vol,
6251 fpart_vol, rpart_vol, mse_vol, ffull_vol, rfull_vol,
6252 glt_coef_vol, glt_tcoef_vol, glt_fstat_vol, glt_rstat_vol,
6253 fitts_vol, errts_vol);
6254
6255 INFO_message("Memory required for output bricks = %s bytes (about %s)",
6256 commaized_integer_string(zvf_totalbytes) ,
6257 approximate_number_string((double)zvf_totalbytes) ) ;
6258 }
6259
6260 EXRETURN ;
6261 }
6262
6263
6264 /*---------------------------------------------------------------------------*/
6265 /*
6266 Get the time series for one voxel from the AFNI 3D+time data set.
6267 */
6268
extract_ts_array(THD_3dim_dataset * dset_time,int iv,float * ts_array)6269 void extract_ts_array
6270 (
6271 THD_3dim_dataset * dset_time, /* input 3D+time dataset */
6272 int iv, /* get time series for this voxel */
6273 float * ts_array /* time series data for voxel #iv */
6274 )
6275
6276 {
6277 MRI_IMAGE * im; /* intermediate float data */
6278 float * ar; /* pointer to float data */
6279 int ts_length; /* length of input 3D+time data set */
6280 int it; /* time index */
6281
6282
6283 /*----- Extract time series from 3D+time data set into MRI_IMAGE -----*/
6284 im = THD_extract_series (iv, dset_time, 0);
6285
6286
6287 /*----- Verify extraction -----*/
6288 if (im == NULL) DC_error ("Unable to extract data from 3D+time dataset");
6289
6290
6291 /*----- Now extract time series from MRI_IMAGE -----*/
6292 ts_length = DSET_NVALS(dset_time);
6293 ar = MRI_FLOAT_PTR (im);
6294 #if 0
6295 for (it = 0; it < ts_length; it++)
6296 {
6297 ts_array[it] = ar[it];
6298 }
6299 #else
6300 memcpy( ts_array , ar , sizeof(float)*ts_length ) ; /* RWCox */
6301 #endif
6302
6303
6304 /*----- Release memory -----*/
6305 mri_free (im); im = NULL;
6306
6307 }
6308
6309
6310 /*---------------------------------------------------------------------------*/
6311 /*
6312 Save results for this voxel.
6313 */
6314
save_voxel(DC_options * option_data,int iv,vector coef,vector scoef,vector tcoef,float * fpart,float * rpart,float mse,float ffull,float rfull,vector * glt_coef,vector * glt_tcoef,float * fglt,float * rglt,int nt,float * ts_array,int * good_list,float * fitts,float * errts,float ** coef_vol,float ** scoef_vol,float ** tcoef_vol,float ** fpart_vol,float ** rpart_vol,float * mse_vol,float * ffull_vol,float * rfull_vol,float *** glt_coef_vol,float *** glt_tcoef_vol,float ** glt_fstat_vol,float ** glt_rstat_vol,float ** fitts_vol,float ** errts_vol)6315 void save_voxel
6316 (
6317 DC_options * option_data, /* deconvolution algorithm options */
6318 int iv, /* current voxel index */
6319 vector coef, /* regression parameters */
6320 vector scoef, /* regression parameter standard deviations */
6321 vector tcoef, /* t-statistics for regression parameters */
6322 float * fpart, /* array of partial F-statistics */
6323 float * rpart, /* array of partial R^2 stats. */
6324 float mse, /* full model mean square error */
6325 float ffull, /* full model F-statistic */
6326 float rfull, /* full model R^2 stat. */
6327 vector * glt_coef, /* linear combinations from GLT matrices */
6328 vector * glt_tcoef, /* t-statistics for the general linear tests */
6329 float * fglt, /* F-statistics for the general linear tests */
6330 float * rglt, /* R^2 stats. for the general linear tests */
6331 int nt, /* number of images in input 3D+time dataset */
6332 float * ts_array, /* array of measured data for one voxel */
6333 int * good_list, /* list of usable time points */
6334 float * fitts, /* full model fitted time series */
6335 float * errts, /* full model residual error time series */
6336
6337 float ** coef_vol, /* array of volumes of signal model parameters */
6338 float ** scoef_vol, /* array of volumes of parameter std. devs. */
6339 float ** tcoef_vol, /* array of volumes of parameter t-statistics */
6340 float ** fpart_vol, /* array of volumes of partial F-statistics */
6341 float ** rpart_vol, /* array of volumes of partial R^2 stats. */
6342 float * mse_vol, /* volume of full model mean square error */
6343 float * ffull_vol, /* volume of full model F-statistics */
6344 float * rfull_vol, /* volume of full model R^2 stats. */
6345 float *** glt_coef_vol, /* volumes for GLT linear combinations */
6346 float *** glt_tcoef_vol, /* volumes for GLT t-statistics */
6347 float ** glt_fstat_vol, /* volumes for GLT F-statistics */
6348 float ** glt_rstat_vol, /* volumes for GLT R^2 stats. */
6349 float ** fitts_vol, /* volumes for full model fit to input data */
6350 float ** errts_vol /* volumes for residual errors */
6351
6352 )
6353
6354 {
6355 int ip; /* parameter index */
6356 int p; /* total number of parameters */
6357 int is; /* stimulus time series index */
6358 int num_stimts; /* number of stimulus time series */
6359 int num_glt; /* number of general linear tests */
6360 int * glt_rows; /* number of linear constraints in glt */
6361 int iglt; /* general linear test index */
6362 int ilc; /* linear combination index */
6363 int it; /* time point index */
6364 int N; /* number of usable data points */
6365
6366
6367 /*----- Initialize local variables -----*/
6368 num_stimts = option_data->num_stimts;
6369 p = option_data->p;
6370 num_glt = option_data->num_glt;
6371 glt_rows = option_data->glt_rows;
6372 N = option_data->N;
6373
6374
6375 /*----- Saved regression coefficients, std.dev.'s, and t-statistics -----*/
6376 if (coef_vol != NULL)
6377 for (ip = 0; ip < p; ip++)
6378 if (coef_vol[ip] != NULL)
6379 coef_vol[ip][iv] = coef.elts[ip];
6380 if (scoef_vol != NULL)
6381 for (ip = 0; ip < p; ip++)
6382 if (scoef_vol[ip] != NULL)
6383 scoef_vol[ip][iv] = scoef.elts[ip];
6384 if (tcoef_vol != NULL)
6385 for (ip = 0; ip < p; ip++)
6386 if (tcoef_vol[ip] != NULL)
6387 tcoef_vol[ip][iv] = tcoef.elts[ip];
6388
6389
6390 /*----- Save partial F-statistics and R^2 statistics -----*/
6391 if (fpart_vol != NULL)
6392 for (is = 0; is < num_stimts; is++)
6393 if (fpart_vol[is] != NULL)
6394 fpart_vol[is][iv] = fpart[is];
6395 if (rpart_vol != NULL)
6396 for (is = 0; is < num_stimts; is++)
6397 if (rpart_vol[is] != NULL)
6398 rpart_vol[is][iv] = rpart[is];
6399
6400
6401 /*----- Save full model mean square error -----*/
6402 if (mse_vol != NULL) mse_vol[iv] = mse;
6403
6404
6405 /*----- Save regression F-statistic -----*/
6406 if (ffull_vol != NULL) ffull_vol[iv] = ffull;
6407
6408
6409 /*----- Save R^2 values -----*/
6410 if (rfull_vol != NULL) rfull_vol[iv] = rfull;
6411
6412
6413 /*----- If general linear test -----*/
6414 if (num_glt > 0)
6415 {
6416 /*----- Save linear combinations -----*/
6417 if (glt_coef_vol != NULL)
6418 for (iglt = 0; iglt < num_glt; iglt++)
6419 if (glt_coef_vol[iglt] != NULL)
6420 for (ilc = 0; ilc < glt_rows[iglt]; ilc++)
6421 glt_coef_vol[iglt][ilc][iv] = glt_coef[iglt].elts[ilc];
6422
6423 /*----- Save GLT t-statistics -----*/
6424 if (glt_tcoef_vol != NULL)
6425 for (iglt = 0; iglt < num_glt; iglt++)
6426 if (glt_tcoef_vol[iglt] != NULL)
6427 for (ilc = 0; ilc < glt_rows[iglt]; ilc++)
6428 glt_tcoef_vol[iglt][ilc][iv] = glt_tcoef[iglt].elts[ilc];
6429
6430 /*----- Save GLT F-statistics -----*/
6431 if (glt_fstat_vol != NULL)
6432 for (iglt = 0; iglt < num_glt; iglt++)
6433 if (glt_fstat_vol[iglt] != NULL)
6434 glt_fstat_vol[iglt][iv] = fglt[iglt];
6435
6436 /*----- Save GLT R^2 statistics -----*/
6437 if (glt_rstat_vol != NULL)
6438 for (iglt = 0; iglt < num_glt; iglt++)
6439 if (glt_rstat_vol[iglt] != NULL)
6440 glt_rstat_vol[iglt][iv] = rglt[iglt];
6441 }
6442
6443
6444 /*----- Save the fitted time series and residual errors -----*/
6445 if (fitts_vol != NULL)
6446 {
6447 for (it = 0; it < nt; it++) /* for bad points */
6448 fitts_vol[it][iv] = ts_array[it];
6449
6450 for (it = 0; it < N; it++) /* for good points */
6451 fitts_vol[good_list[it]][iv] = fitts[it];
6452 }
6453
6454 if (errts_vol != NULL)
6455 {
6456 for (it = 0; it < nt; it++) /* for bad points */
6457 errts_vol[it][iv] = 0.0;
6458
6459 for (it = 0; it < N; it++) /* for good points */
6460 errts_vol[good_list[it]][iv] = errts[it];
6461 }
6462
6463 }
6464
6465
6466 /*---------------------------------------------------------------------------*/
6467 /*
6468 Report the results from evaluation of the experimental design.
6469 */
6470
report_evaluation(int qp,int num_stimts,char ** stim_label,int * min_lag,int * max_lag,matrix x_full,matrix xtxinv_full,int num_glt,char ** glt_label,int * glt_rows,matrix * cxtxinvct)6471 void report_evaluation
6472 (
6473 int qp, /* number of polynomial trend baseline parameters */
6474 int num_stimts, /* number of stimulus time series */
6475 char ** stim_label, /* label for each stimulus */
6476 int * min_lag, /* minimum time delay for impulse response */
6477 int * max_lag, /* maximum time delay for impulse response */
6478 matrix x_full , /* matrix: X for full model */
6479 matrix xtxinv_full, /* matrix: 1/(X'X) for full model */
6480 int num_glt, /* number of general linear tests */
6481 char ** glt_label, /* label for general linear test */
6482 int * glt_rows, /* number of linear constraints in glt */
6483 matrix * cxtxinvct /* array of matrices: C(1/(X'X))C' for glt */
6484 )
6485
6486 {
6487 int m; /* parameter index */
6488 int is; /* stimulus index */
6489 int ilag=0; /* time lag index */
6490 int iglt; /* general linear test index */
6491 int ilc; /* linear combination index */
6492 float stddev; /* normalized parameter standard deviation */
6493 int ibot,itop ;
6494 int j , do_extras ; float jnorm ;
6495
6496
6497 /*----- Print the normalized parameter standard deviations -----*/
6498 do_extras = AFNI_yesenv("AFNI_3dDeconvolve_nodata_extras") ;
6499 if( do_extras ){
6500 printf("\nBaseline -polort parameters:\n") ;
6501 for( m=0 ; m < qp ; m++ ){
6502 jnorm = 0.0 ;
6503 for( j=0 ; j < x_full.rows ; j++ ) jnorm += SQR(x_full.elts[j][m]) ;
6504 jnorm = sqrt(jnorm) ;
6505 stddev = sqrt ( xtxinv_full.elts[m][m] );
6506 printf (" h[%2d] norm. std. dev. = %8.4f X col. norm = %8.4f\n",
6507 ilag, stddev, jnorm );
6508 }
6509 }
6510
6511 /*----- Print the normalized parameter standard deviations -----*/
6512 m = qp;
6513 for (is = 0; is < num_stimts; is++)
6514 {
6515 printf ("\nStimulus: %s \n", stim_label[is]);
6516 if( basis_stim[is] != NULL ){ ibot = 0; itop = basis_stim[is]->nparm-1; }
6517 else { ibot = min_lag[is]; itop = max_lag[is]; }
6518 for (ilag = ibot; ilag <= itop; ilag++)
6519 {
6520 jnorm = 0.0 ;
6521 for( j=0 ; j < x_full.rows ; j++ ) jnorm += SQR(x_full.elts[j][m]) ;
6522 jnorm = sqrt(jnorm) ;
6523 stddev = sqrt ( xtxinv_full.elts[m][m] );
6524 if( do_extras )
6525 printf (" h[%2d] norm. std. dev. = %8.4f X col. norm = %8.4f\n",
6526 ilag, stddev, jnorm );
6527 else
6528 printf (" h[%2d] norm. std. dev. = %8.4f\n",
6529 ilag, stddev );
6530 m++;
6531 }
6532 }
6533
6534 /*----- Print normalized standard deviations for GLTs -----*/
6535 if (num_glt > 0)
6536 {
6537 for (iglt = 0; iglt < num_glt; iglt++)
6538 {
6539 printf ("\nGeneral Linear Test: %s \n", glt_label[iglt]);
6540
6541 for (ilc = 0; ilc < glt_rows[iglt]; ilc++)
6542 {
6543 stddev = sqrt ( 1.0 * cxtxinvct[iglt].elts[ilc][ilc] );
6544 printf (" LC[%d] norm. std. dev. = %8.4f \n",
6545 ilc, stddev);
6546 }
6547 }
6548 }
6549
6550 fflush(stdout);
6551 }
6552
6553 /*---------------------------------------------------------------------------*/
6554
6555 typedef struct {
6556 int qp , /* number of polynomial baseline parameters */
6557 q , /* total number of baseline parameters */
6558 p , /* total number of parameters */
6559 nstim , /* number of stim functions = number of rdcd matrices */
6560 nglt , /* number of glt matrices */
6561 status ; /* are all matrices computed? */
6562
6563 matrix xdata ; /* regression model, without censoring */
6564 matrix x_full ; /* with censoring = [X] */
6565 matrix xtxinv_full ; /* inv{ [X][X]' } */
6566 matrix xtxinvxt_full; /* inv{ [X][X]' } [X]' = solution matrix */
6567
6568 matrix x_base ; /* baseline model */
6569 matrix xtxinvxt_base; /* solution matrix for baseline model */
6570
6571 matrix *x_rdcd ; /* reduced models (with 1 stim function omitted) */
6572 matrix *xtxinvxt_rdcd;/* solution matrices for reduced models */
6573
6574 matrix *glt_cxtxinvct;/* matrices for GLT calculations */
6575 matrix *glt_amat ;
6576
6577 } regression_matrices ;
6578
6579 /*...........................................................................*/
6580
6581 #define INIT_RMAT(rm,ns,ng) \
6582 do{ int ii ; \
6583 matrix_initialize( &(rm).xdata ) ; \
6584 matrix_initialize( &(rm).x_full ) ; \
6585 matrix_initialize( &(rm).xtxinv_full ) ; \
6586 matrix_initialize( &(rm).xtxinvxt_full ) ; \
6587 matrix_initialize( &(rm).x_base ) ; \
6588 matrix_initialize( &(rm).xtxinvxt_base ) ; \
6589 (rm).x_rdcd = (matrix *)malloc(sizeof(matrix)*(ns)) ; \
6590 (rm).xtxinvxt_rdcd = (matrix *)malloc(sizeof(matrix)*(ns)) ; \
6591 for( ii=0 ; ii < (ns) ; ii++ ){ \
6592 matrix_initialize( &(rm).x_rdcd[ii] ) ; \
6593 matrix_initialize( &(rm).xtxinvxt_rdcd[ii] ) ; \
6594 } \
6595 (rm).glt_cxtxinvct = (matrix *)malloc(sizeof(matrix)*(ng)) ; \
6596 (rm).glt_amat = (matrix *)malloc(sizeof(matrix)*(ng)) ; \
6597 for( ii=0 ; ii < (ng) ; ii++ ){ \
6598 matrix_initialize( &(rm).glt_cxtxinvct[ii] ) ; \
6599 matrix_initialize( &(rm).glt_amat[ii] ) ; \
6600 } \
6601 (rm).nstim = (ns) ; (rm).nglt = (ng) ; (rm).status = 0 ; \
6602 } while(0)
6603
6604 /*...........................................................................*/
6605
6606 #define FREE_RMAT(rm) \
6607 do{ int ii ; \
6608 matrix_destroy( &(rm).xdata ) ; \
6609 matrix_destroy( &(rm).x_full ) ; \
6610 matrix_destroy( &(rm).xtxinv_full ) ; \
6611 matrix_destroy( &(rm).xtxinvxt_full ) ; \
6612 matrix_destroy( &(rm).x_base ) ; \
6613 matrix_destroy( &(rm).xtxinvxt_base ) ; \
6614 for( ii=0 ; ii < (rm).nstim ; ii++ ){ \
6615 matrix_destroy( &(rm).x_rdcd[ii] ) ; \
6616 matrix_destroy( &(rm).xtxinvxt_rdcd[ii] ) ; \
6617 } \
6618 for( ii=0 ; ii < (rm).nglt ; ii++ ){ \
6619 matrix_destroy( &(rm).glt_cxtxinvct[ii] ) ; \
6620 matrix_destroy( &(rm).glt_amat[ii] ) ; \
6621 } \
6622 (rm).status = -1 ; \
6623 } while(0)
6624
6625 /*...........................................................................*/
6626
6627 static int num_Rmat = 0 ;
6628 static regression_matrices *Rmat = NULL ;
6629
6630 /*---------------------------------------------------------------------------*/
6631
setup_regression_matrices(DC_options * option_data,int * good_list,int * block_list,int num_blocks,float ** stimulus,int * stim_length)6632 void setup_regression_matrices( DC_options *option_data ,
6633 int *good_list ,
6634 int *block_list , int num_blocks ,
6635 float **stimulus , int *stim_length )
6636 {
6637 int is , mm , nz=1 ;
6638 float **sstim ;
6639
6640 num_Rmat = 1 ;
6641 for( is=0 ; is < option_data->num_stimts && nz < 2 ; is++ )
6642 if( option_data->slice_base[is] > 0 )
6643 nz = num_Rmat = option_data->slice_base[is] ;
6644
6645 Rmat = (regression_matrices *)malloc(sizeof(regression_matrices)*num_Rmat) ;
6646
6647 for( mm=0 ; mm < num_Rmat ; mm++ )
6648 INIT_RMAT( Rmat[mm] , option_data->num_stimts , option_data->num_glt ) ;
6649
6650 sstim = (float **) malloc( sizeof(float *)*option_data->num_stimts ) ;
6651 memcpy( sstim , stimulus , sizeof(float *)*option_data->num_stimts ) ;
6652
6653 /*- loop over slices:
6654 substituting slice-dependent regressors,
6655 making matrices from those collections of vectors -*/
6656
6657 for( mm=0 ; mm < num_Rmat ; mm++ ){
6658
6659 for( is=0 ; is < option_data->num_stimts ; is++ )
6660 if( mm > 0 && option_data->slice_base[is] > 0 )
6661 sstim[is] = stimulus[is] + (mm*stim_length[is]) ;
6662
6663 init_indep_var_matrix( option_data->p,
6664 option_data->qp,
6665 option_data->polort,
6666 option_data->nt,
6667 option_data->N,
6668 good_list, block_list, num_blocks,
6669 option_data->num_stimts,
6670 sstim, stim_length,
6671 option_data->stim_minlag,
6672 option_data->stim_maxlag,
6673 option_data->stim_nptr, option_data->stim_base ,
6674 &Rmat[mm].xdata);
6675 Rmat[mm].qp = option_data->qp ;
6676 Rmat[mm].q = option_data->q ;
6677 Rmat[mm].p = option_data->p ;
6678 }
6679
6680 free((void *)sstim) ; return ;
6681 }
6682
6683 /*---------------------------------------------------------------------------*/
6684 /*
6685 Calculate the impulse response function and associated statistics.
6686 */
6687
calculate_results(DC_options * option_data,THD_3dim_dataset * dset,byte * mask_vol,float * fmri_data,int fmri_length,int * good_list,int * block_list,int num_blocks,float ** stimulus,int * stim_length,matrix * glt_cmat,float ** coef_vol,float ** scoef_vol,float ** tcoef_vol,float ** fpart_vol,float ** rpart_vol,float * mse_vol,float * ffull_vol,float * rfull_vol,float *** glt_coef_vol,float *** glt_tcoef_vol,float ** glt_fstat_vol,float ** glt_rstat_vol,float ** fitts_vol,float ** errts_vol)6688 void calculate_results
6689 (
6690 DC_options * option_data, /* deconvolution algorithm options */
6691 THD_3dim_dataset * dset, /* input 3D+time data set */
6692 byte * mask_vol, /* input mask volume */
6693 float * fmri_data, /* input fMRI time series data */
6694 int fmri_length, /* length of fMRI time series */
6695 int * good_list, /* list of usable time points */
6696 int * block_list, /* list of block (run) starting points */
6697 int num_blocks, /* number of blocks (runs) */
6698 float ** stimulus, /* stimulus time series arrays */
6699 int * stim_length, /* length of stimulus time series */
6700 matrix * glt_cmat, /* general linear test matrices */
6701
6702 float ** coef_vol, /* array of volumes of signal model parameters */
6703 float ** scoef_vol, /* array of volumes of parameter std. devs. */
6704 float ** tcoef_vol, /* array of volumes of parameter t-statistics */
6705 float ** fpart_vol, /* array of volumes of partial F-statistics */
6706 float ** rpart_vol, /* array of volumes of partial R^2 stats. */
6707 float * mse_vol, /* volume of full model mean square error */
6708 float * ffull_vol, /* volume of F-statistic for the full model */
6709 float * rfull_vol, /* volume of R^2 for the full model */
6710 float *** glt_coef_vol, /* volumes for GLT linear combinations */
6711 float *** glt_tcoef_vol, /* volumes for GLT t-statistics */
6712 float ** glt_fstat_vol, /* volumes for GLT F-statistics */
6713 float ** glt_rstat_vol, /* volumes for GLT R^2 stats. */
6714 float ** fitts_vol, /* volumes for full model fit to input data */
6715 float ** errts_vol /* volumes for residual errors */
6716 )
6717
6718 {
6719 float * ts_array = NULL; /* array of measured data for one voxel */
6720
6721 #ifdef USE_GET
6722 int do_get = 0 ; /* flag to use multi-gets */
6723 #else
6724 # define do_get 0
6725 #endif
6726
6727 int qp; /* number of poly. trend baseline parameters */
6728 int q; /* number of baseline model parameters */
6729 int p; /* number of full model parameters */
6730 int polort; /* degree of polynomial for baseline model */
6731 int m; /* parameter index */
6732 int n; /* data point index */
6733
6734 vector coef; /* regression parameters */
6735 vector scoef; /* std. devs. for regression parameters */
6736 vector tcoef; /* t-statistics for regression parameters */
6737 float * fpart = NULL; /* partial F-statistics for the stimuli */
6738 float * rpart = NULL; /* partial R^2 stats. for the stimuli */
6739 float ffull; /* full model F-statistic */
6740 float rfull; /* full model R^2 stat. */
6741 float mse; /* mean square error from full model */
6742
6743 matrix xdata; /* independent variable matrix */
6744 matrix x_full; /* extracted X matrix for full model */
6745 matrix xtxinv_full; /* matrix: 1/(X'X) for full model */
6746 matrix xtxinvxt_full; /* matrix: (1/(X'X))X' for full model */
6747 matrix x_base; /* extracted X matrix for baseline model */
6748 matrix xtxinvxt_base; /* matrix: (1/(X'X))X' for baseline model */
6749 matrix * x_rdcd = NULL; /* extracted X matrices for reduced models */
6750 matrix * xtxinvxt_rdcd = NULL;
6751 /* matrix: (1/(X'X))X' for reduced models */
6752 vector y; /* vector of measured data */
6753
6754 int ixyz; /* voxel index */
6755 int nxyz; /* number of voxels per dataset */
6756
6757 int nt; /* number of images in input 3D+time dataset */
6758 int N; /* number of usable data points */
6759
6760 int num_stimts; /* number of stimulus time series */
6761 int * baseline; /* flag for stim function in baseline model */
6762 int * min_lag; /* minimum time delay for impulse response */
6763 int * max_lag; /* maximum time delay for impulse response */
6764 int * nptr; /* number of stim fn. time points per TR */
6765 char ** stim_label; /* label for stimulus time series */
6766
6767 int i; /* data point index */
6768 int is; /* stimulus index */
6769 int ilag; /* time lag index */
6770 float stddev; /* normalized parameter standard deviation */
6771 float rms_min; /* minimum variation in data to fit full model */
6772 char * label; /* string containing stat. summary of results */
6773 int nodata; /* flag for 'no data' option */
6774 int novar; /* flag for insufficient variation in data */
6775
6776 int iglt; /* general linear test index */
6777 int ilc; /* linear combination index */
6778 int num_glt; /* number of general linear tests */
6779 char ** glt_label; /* label for general linear test */
6780 int * glt_rows; /* number of linear constraints in glt */
6781 matrix * cxtxinvct = NULL; /* matrices: C(1/(X'X))C' for GLT */
6782 matrix * glt_amat = NULL; /* constant GLT matrices for later use */
6783 vector * glt_coef = NULL; /* linear combinations from GLT matrices */
6784 vector * glt_tcoef = NULL; /* t-statistics for GLT linear combinations */
6785 float * fglt = NULL; /* F-statistics for the general linear tests */
6786 float * rglt = NULL; /* R^2 stats. for the general linear tests */
6787
6788 float * fitts = NULL; /* full model fitted time series */
6789 float * errts = NULL; /* full model residual error time series */
6790
6791 int vstep ; /* interval progress meter dots */
6792 double ct ; /* clock time */
6793 FILE *mfp=NULL ; /* 26 Dec 2012 */
6794
6795 ENTRY("calculate_results") ;
6796
6797 /*----- Initialize local variables -----*/
6798 nodata = option_data->nodata;
6799 nxyz = option_data->nxyz;
6800 nt = option_data->nt;
6801 rms_min = option_data->rms_min;
6802 num_stimts = option_data->num_stimts;
6803 stim_label = option_data->stim_label;
6804 baseline = option_data->stim_base;
6805 min_lag = option_data->stim_minlag;
6806 max_lag = option_data->stim_maxlag;
6807 nptr = option_data->stim_nptr;
6808
6809 num_glt = option_data->num_glt;
6810 glt_label = option_data->glt_label;
6811 glt_rows = option_data->glt_rows;
6812
6813 if( num_glt > 0 ){
6814 GLT_stuff = (glt_stuff *)malloc(sizeof(glt_stuff)) ;
6815 GLT_stuff->glt_num = num_glt ;
6816 GLT_stuff->glt_lab = glt_label ;
6817 GLT_stuff->glt_mat = glt_cmat ;
6818 }
6819
6820 polort = option_data->polort;
6821 qp = option_data->qp;
6822 q = option_data->q;
6823 p = option_data->p;
6824
6825 N = option_data->N;
6826
6827
6828 /*----- Initialize matrices and vectors -----*/
6829 matrix_initialize (&xdata);
6830 matrix_initialize (&x_full);
6831 matrix_initialize (&xtxinv_full);
6832 matrix_initialize (&xtxinvxt_full);
6833 matrix_initialize (&x_base);
6834 matrix_initialize (&xtxinvxt_base);
6835 vector_initialize (&coef) ;
6836 vector_initialize (&scoef);
6837 vector_initialize (&tcoef);
6838 vector_initialize (&y);
6839
6840 if (num_stimts > 0)
6841 {
6842 x_rdcd = (matrix *) malloc (sizeof(matrix) * num_stimts);
6843 MTEST (x_rdcd);
6844 xtxinvxt_rdcd = (matrix *) malloc (sizeof(matrix) * num_stimts);
6845 MTEST (xtxinvxt_rdcd);
6846
6847 for (is =0; is < num_stimts; is++)
6848 {
6849 matrix_initialize (&x_rdcd[is]);
6850 matrix_initialize (&xtxinvxt_rdcd[is]);
6851 }
6852 }
6853
6854 if (num_glt > 0)
6855 {
6856 cxtxinvct = (matrix *) malloc (sizeof(matrix) * num_glt);
6857 glt_amat = (matrix *) malloc (sizeof(matrix) * num_glt);
6858 glt_coef = (vector *) malloc (sizeof(vector) * num_glt);
6859 glt_tcoef = (vector *) malloc (sizeof(vector) * num_glt);
6860
6861 for (iglt =0; iglt < num_glt; iglt++)
6862 {
6863 matrix_initialize (&cxtxinvct[iglt]);
6864 matrix_initialize (&glt_amat[iglt]);
6865 vector_initialize (&glt_coef[iglt]);
6866 vector_initialize (&glt_tcoef[iglt]);
6867 }
6868 }
6869
6870
6871 /*----- Allocate memory -----*/
6872 if (num_stimts > 0)
6873 {
6874 fpart = (float *) malloc (sizeof(float) * num_stimts); MTEST (fpart);
6875 rpart = (float *) malloc (sizeof(float) * num_stimts); MTEST (rpart);
6876 }
6877 if (num_glt > 0)
6878 {
6879 fglt = (float *) malloc (sizeof(float) * num_glt); MTEST (fglt);
6880 rglt = (float *) malloc (sizeof(float) * num_glt); MTEST (rglt);
6881 }
6882
6883 if (option_data->input1D_filename == NULL)
6884 {
6885 #ifdef USE_GET
6886 do_get = 1 ; /* don't need a pre-malloc-ed array for multi-gets */
6887 #else
6888 ts_array = (float *) malloc (sizeof(float) * nt); MTEST (ts_array);
6889 #endif
6890 }
6891 fitts = (float *) malloc (sizeof(float) * nt); MTEST (fitts);
6892 errts = (float *) malloc (sizeof(float) * nt); MTEST (errts);
6893
6894
6895 /*----- Initialize the independent variable matrix -----*/
6896
6897 ct = COX_clock_time() ;
6898
6899 init_indep_var_matrix (p, qp, polort, nt, N, good_list, block_list,
6900 num_blocks, num_stimts, stimulus, stim_length,
6901 min_lag, max_lag, nptr, option_data->stim_base , &xdata);
6902
6903 /*-- save the matrix in various ways, depending on the user's whimsy --*/
6904
6905 if (option_data->xout) matrix_sprint ("X matrix:", xdata);
6906
6907 if( option_data->xjpeg_filename != NULL ) /* 21 Jul 2004 - a picture */
6908 JPEG_matrix_gray( xdata , option_data->xjpeg_filename ) ;
6909
6910 if( option_data->x1D_filename != NULL ){ /* 28 Mar 2006 - a file */
6911 void *cd=(void *)coldat ; int *gl=good_list ;
6912 if( AFNI_noenv("AFNI_3dDeconvolve_NIML") &&
6913 strstr(option_data->x1D_filename,"niml") == NULL ) cd = NULL ;
6914 ONED_matrix_save( xdata , option_data->x1D_filename , cd , N,gl ,
6915 (is_xfull) ? &xfull : NULL , num_blocks,block_list ,
6916 (void *)GLT_stuff , (void *)STIMLABEL_stuff ) ;
6917
6918 /*-- 22 Aug 2008: 3dREMLfit notice, and other announcements --*/
6919
6920 if( !option_data->nodata && cd != NULL && verb ){
6921 char *iname=NULL ; /* input filename for command echo below */
6922 char *cname=NULL ; /* command to be output for user's wisdom */
6923 char *pref , *cpt ;
6924 FILE *fp ;
6925 int iadd=0 , ilen , oneline=AFNI_yesenv("AFNI_3dDeconvolve_oneline") ;
6926 char *lbreak ;
6927 char *mod_prefix; /* non-AFNI?, for surface datasets 14 Nov 2018 [rickr] */
6928
6929 if( option_data->input_filename != NULL ){
6930 iname = calloc( sizeof(char) , strlen(option_data->input_filename)+9 ) ;
6931 if( THD_filename_ok(option_data->input_filename) ){
6932 strcpy(iname,option_data->input_filename) ;
6933 } else {
6934 strcpy(iname,"\"") ;
6935 strcat(iname,option_data->input_filename) ; strcat(iname,"\"") ;
6936 }
6937 }
6938 cname = THD_zzprintf( cname ,
6939 "3dREMLfit -matrix %s", option_data->x1D_filename );
6940 lbreak = (oneline) ? "" : " \\\n" ;
6941 if( iname != NULL ){
6942 if( *iname != '"' )
6943 cname = THD_zzprintf( cname , " -input %s%s" , iname,lbreak ) ;
6944 else
6945 cname = THD_zzprintf( cname , "%s -input %s%s" , lbreak,iname,lbreak ) ;
6946 free(iname) ;
6947 } else if( !oneline ){
6948 cname = THD_zzprintf( cname , "%s" , lbreak ) ;
6949 }
6950 if( option_data->mask_filename ){
6951 ilen = strlen(cname) ;
6952 cname = THD_zzprintf( cname , " -mask %s" , option_data->mask_filename );
6953 iadd += strlen(cname)-ilen ;
6954 } else if( option_data->automask ){
6955 ilen = strlen(cname) ;
6956 cname = THD_zzprintf( cname , " -automask" );
6957 iadd += strlen(cname)-ilen ;
6958 }
6959 if( CoefFilename != NULL ){
6960 if( iadd > 50 && !oneline ){ cname = THD_zzprintf(cname," \\\n"); iadd=0; }
6961 ilen = strlen(cname) ;
6962 cname = THD_zzprintf( cname ,
6963 " -Rbeta %s_REML" , CoefFilename ) ;
6964 iadd += strlen(cname)-ilen ;
6965 }
6966 if( option_data->bucket_filename != NULL ){
6967 /* handle non-AFNI dataset formats, like niml.dset for surface data */
6968 mod_prefix = option_data->bucket_filename; /* init to current dset */
6969 if( has_known_non_afni_extension(mod_prefix) )
6970 mod_prefix = without_afni_filename_extension(mod_prefix); /* no free */
6971
6972 if( iadd > 50 && !oneline ){ cname = THD_zzprintf(cname," \\\n"); iadd=0; }
6973 ilen = strlen(cname) ;
6974 if( option_data->fout ) cname = THD_zzprintf( cname , " -fout") ;
6975 if( option_data->tout ) cname = THD_zzprintf( cname , " -tout") ;
6976 if( option_data->rout ) cname = THD_zzprintf( cname , " -rout") ;
6977 iadd += strlen(cname)-ilen ; ilen = strlen(cname) ;
6978 if( iadd > 40 && !oneline ){ cname = THD_zzprintf(cname," \\\n"); iadd=0; }
6979 cname = THD_zzprintf( cname , " -Rbuck %s_REML" , mod_prefix );
6980 cname = THD_zzprintf( cname , " -Rvar %s_REMLvar", mod_prefix );
6981 iadd += strlen(cname)-ilen ;
6982 }
6983 if( option_data->fitts_filename != NULL ){
6984 mod_prefix = option_data->fitts_filename; /* handle non-AFNI formats */
6985 if( has_known_non_afni_extension(mod_prefix) )
6986 mod_prefix = without_afni_filename_extension(mod_prefix); /* no free */
6987
6988 if( iadd > 50 && !oneline ){ cname = THD_zzprintf(cname," \\\n"); iadd=0; }
6989 ilen = strlen(cname) ;
6990 cname = THD_zzprintf( cname , " -Rfitts %s_REML", mod_prefix );
6991 iadd += strlen(cname)-ilen ;
6992 }
6993 if( option_data->errts_filename != NULL ){
6994 mod_prefix = option_data->errts_filename; /* handle non-AFNI formats */
6995 if( has_known_non_afni_extension(mod_prefix) )
6996 mod_prefix = without_afni_filename_extension(mod_prefix); /* no free */
6997
6998 if( iadd > 50 && !oneline ){ cname = THD_zzprintf(cname," \\\n"); iadd=0; }
6999 ilen = strlen(cname) ;
7000 cname = THD_zzprintf( cname , " -Rerrts %s_REML", mod_prefix );
7001 iadd += strlen(cname)-ilen ;
7002 }
7003 #if 0
7004 if( iadd > 70 && !oneline ){ cname = THD_zzprintf(cname," \\\n"); iadd=0; }
7005 #endif
7006 ilen = strlen(cname) ;
7007 cname = THD_zzprintf( cname , " -verb" ) ;
7008 iadd += strlen(cname)-ilen ;
7009
7010 INFO_message("========= Things you can do with the matrix file =========");
7011 INFO_message(
7012 "(a) Linear regression with ARMA(1,1) modeling of serial correlation:\n\n"
7013 "%s\n " , cname ) ;
7014
7015 if( option_data->bucket_filename != NULL ){ /* use bucket name? */
7016 pref = strdup(option_data->bucket_filename) ;
7017 cpt = strstr(pref,".") ; if( cpt != NULL ) *cpt = '\0' ;
7018 } else if( option_data->input1D_filename != NULL ){ /* use 1D filename? */
7019 pref = strdup(option_data->input1D_filename) ;
7020 cpt = strstr(pref,".1D") ; if( cpt != NULL ) *cpt = '\0' ;
7021 cpt = strstr(pref,"1D:") ; if( cpt != NULL ) strcpy(pref,"1D") ;
7022 } else if( option_data->nodata ){ /* no data? */
7023 pref = strdup("nodata") ;
7024 } else { /* default */
7025 pref = strdup("3dDeconvolve") ;
7026 }
7027 pref = (char *)realloc(pref,strlen(pref)+16) ; strcat(pref,".REML_cmd") ;
7028 fp = fopen(pref,"w") ;
7029 if( fp != NULL ){
7030 fprintf( fp, "# %s\n", (commandline!=NULL) ? commandline : PROGRAM_NAME );
7031 /* allow options (should apply to bash or tcsh) 23 Apr 2010 [rickr] */
7032 fprintf( fp, "\n%s $*\n", cname ) ;
7033 fclose(fp) ;
7034 INFO_message("N.B.: 3dREMLfit command above written to file %s",pref) ;
7035 }
7036 free(pref) ; free(cname) ;
7037
7038 INFO_message("(b) Visualization/analysis of the matrix via ExamineXmat.R");
7039 INFO_message("(c) Synthesis of sub-model datasets using 3dSynthesize") ;
7040 INFO_message("==========================================================");
7041 }
7042 }
7043
7044 if( is_xfull && option_data->x1D_unc != NULL ){ /* 25 Mar 2007 - full matrix? */
7045 void *cd=(void *)coldat ; int *gl=good_list ;
7046 if( AFNI_noenv("AFNI_3dDeconvolve_NIML") &&
7047 strstr(option_data->x1D_filename,"niml") == NULL ) cd = NULL ;
7048 ONED_matrix_save( xfull , option_data->x1D_unc , cd , xfull.rows,NULL , &xfull,
7049 num_blocks,block_list , NULL, (void *)STIMLABEL_stuff ) ;
7050 }
7051
7052 if( is_xfull_plus && option_data->x1D_regcen != NULL ){ /* 16 Aug 2019 - full+ matrix? */
7053 void *cd=(void *)coldat ; int *gl=good_list ;
7054 if( AFNI_noenv("AFNI_3dDeconvolve_NIML") &&
7055 strstr(option_data->x1D_filename,"niml") == NULL ) cd = NULL ;
7056 ONED_matrix_save( xfull_plus , option_data->x1D_regcen , cd , xfull_plus.rows,NULL , &xfull_plus,
7057 num_blocks,block_list , NULL, (void *)STIMLABEL_stuff ) ;
7058 }
7059
7060 /*----- 14 Jul 2004: check matrix for bad columns - RWCox -----*/
7061
7062 { int *iar , k , nerr=0 ;
7063 iar = matrix_check_columns( xdata , QEPS ) ;
7064 if( iar != NULL ){
7065 WARNING_message("-------------------------------------------------") ;
7066 WARNING_message("Problems with the X matrix columns, listed below:") ;
7067 for( k=0 ; iar[2*k] >= 0 ; k++ ){
7068 if( iar[2*k+1] >= 0 ){
7069 WARNING_message(
7070 "!! * Columns %d [%s] and %d [%s] are (nearly?) collinear!",
7071 iar[2*k] ,COLUMN_LABEL(iar[2*k] ),
7072 iar[2*k+1],COLUMN_LABEL(iar[2*k+1]) ) ;
7073 nerr++ ; badlev++ ;
7074 } else {
7075 char *ww = (allzero_OK) ? (" ") : ("!!") ;
7076 WARNING_message("%s * Column %d [%s] is all zeros",
7077 ww , iar[2*k] , COLUMN_LABEL(iar[2*k]) ) ;
7078 if( !allzero_OK ) badlev++ ;
7079 }
7080 }
7081 WARNING_message("-------------------------------------------------") ;
7082 if( nerr > 0 && AFNI_yesenv("AFNI_3dDeconvolve_nodup") )
7083 ERROR_exit("Can't continue after above problems/warnings!");
7084 free(iar) ;
7085 }
7086 }
7087
7088 /*-- 14 Jul 2004: calculate matrix condition number - RWCox --*/
7089
7090 if( !option_data->nocond ){
7091 int qbad , *clist , nlist , jj ; matrix xext ;
7092
7093 /* examine full matrix */
7094
7095 qbad = check_matrix_condition( xdata, "Signal+Baseline" ); badlev += qbad;
7096
7097 /* extract columns for signal model only */
7098
7099 clist = (int *)malloc(sizeof(int)*xdata.cols) ;
7100 for( nlist=jj=0 ; jj < xdata.cols ; jj++ )
7101 if( coldat[jj].group > 0 ) clist[nlist++] = jj ;
7102 if( nlist > 0 ){
7103 matrix_initialize (&xext);
7104 matrix_extract( xdata , nlist , clist , &xext ) ;
7105 qbad = check_matrix_condition( xext, "Signal-only" ); badlev += qbad;
7106 matrix_destroy( &xext ) ;
7107 }
7108
7109 /* extract columns for baseline model only */
7110
7111 for( nlist=jj=0 ; jj < xdata.cols ; jj++ )
7112 if( coldat[jj].group <= 0 ) clist[nlist++] = jj ;
7113 if( nlist > 0 ){
7114 matrix_initialize (&xext);
7115 matrix_extract( xdata , nlist , clist , &xext ) ;
7116 qbad = check_matrix_condition( xext, "Baseline-only" ); badlev += qbad;
7117 matrix_destroy( &xext ) ;
7118 }
7119
7120 /* extract columns for -stim_base model only */
7121
7122 for( nlist=jj=0 ; jj < xdata.cols ; jj++ )
7123 if( coldat[jj].group == 0 ) clist[nlist++] = jj ;
7124 if( nlist > 0 ){
7125 matrix_initialize (&xext);
7126 matrix_extract( xdata , nlist , clist , &xext ) ;
7127 qbad = check_matrix_condition( xext, "stim_base-only" ); badlev += qbad;
7128 matrix_destroy( &xext ) ;
7129 }
7130
7131 /* extract columns for -polort model only */
7132
7133 for( nlist=jj=0 ; jj < xdata.cols ; jj++ )
7134 if( coldat[jj].group < 0 ) clist[nlist++] = jj ;
7135 if( nlist > 0 ){
7136 matrix_initialize (&xext);
7137 matrix_extract( xdata , nlist , clist , &xext ) ;
7138 qbad = check_matrix_condition( xext, "polort-only" ); badlev += qbad;
7139 matrix_destroy( &xext ) ;
7140 }
7141 }
7142
7143 /** 22 Jul 2010: move the exit to AFTER condition number reports **/
7144
7145 if( option_data->x1D_stop ){ /* 28 Jun 2007 -- my work here is done */
7146 if( option_data->x1D_stop == 1 )
7147 INFO_message("3dDeconvolve exits: -x1D_stop option was invoked") ;
7148 exit(0) ;
7149 }
7150
7151 /*----- Initialization for the regression analysis -----*/
7152
7153 init_regression_analysis (p, qp, num_stimts, baseline, min_lag, max_lag,
7154 xdata, &x_full, &xtxinv_full, &xtxinvxt_full,
7155 &x_base, &xtxinvxt_base, x_rdcd, xtxinvxt_rdcd);
7156 if( option_data->xout )
7157 matrix_sprint ("(X'X) inverse matrix:", xtxinv_full);
7158
7159 if( nodata && option_data->x1D_filename != NULL &&
7160 strncmp(option_data->x1D_filename,"stdout:",7) != 0 ){
7161 char fn[THD_MAX_NAME] , *jpt ;
7162 strcpy(fn,option_data->x1D_filename) ;
7163 jpt = strstr(fn,".xmat") ;
7164 if( jpt == NULL ) jpt = strstr(fn,".1D") ;
7165 if( jpt == NULL ) jpt = fn + strlen(fn) ;
7166 strcpy(jpt,"_XtXinv.xmat.1D") ;
7167 ONED_matrix_save( xtxinv_full,fn,
7168 NULL,0,NULL,NULL,0,NULL,NULL,NULL ) ; /* no column metadata */
7169 }
7170
7171 /*----- Save some of this stuff for later, dude -----*/
7172 X = x_full ; /* 25 Jul 2004 (RWCox) */
7173 XtXinv = xtxinv_full ;
7174 XtXinvXt = xtxinvxt_full ;
7175
7176 { int m , npar , j ; /* 31 Aug 2004 (RWCox) */
7177 register double sum ;
7178 float mmax ;
7179
7180 Xcol_inbase = (int *) calloc(sizeof(int) ,p) ;
7181 Xcol_mean = (float *)calloc(sizeof(float),p) ;
7182
7183 STATUS("storing Xcol_inbase") ;
7184 for( is=0 ; is < qp ; is++ ) Xcol_inbase[is] = 1 ; /* mark baseline columns */
7185 m = qp ;
7186 for( is=0 ; is < num_stimts ; is++ ){
7187 npar = (basis_stim[is] != NULL)
7188 ? basis_stim[is]->nparm
7189 : option_data->stim_maxlag[is] - option_data->stim_minlag[is] + 1 ;
7190
7191 if( baseline[is] ) for( j=0 ; j < npar ; j++ ) Xcol_inbase[m+j] = 1 ;
7192 m += npar ;
7193 }
7194
7195 STATUS("computing Xcol_mean") ;
7196 mmax = 0.0f ;
7197 for( j=0 ; j < p ; j++ ){ /* compute mean of each column */
7198 sum = 0.0 ;
7199 for( i=0 ; i < X.rows ; i++ ) sum += X.elts[i][j] ;
7200 Xcol_mean[j] = (float)(sum/X.rows) ;
7201 if( Xcol_inbase[j] && fabs(Xcol_mean[j]) > mmax ) /* find largest */
7202 mmax = fabs(Xcol_mean[j]) ; /* mean of baseline cols */
7203 }
7204
7205 if( mmax > 0.0f ){ /* mark baseline cols that have nontrivial means */
7206 STATUS("re-marking Xcol_inbase") ;
7207 mmax *= 9.99e-6 ;
7208 for( j=0 ; j < p ; j++ )
7209 if( Xcol_inbase[j] && fabs(Xcol_mean[j]) > mmax ) Xcol_inbase[j] = 2 ;
7210 }
7211 }
7212
7213 /*--- Compute abs sum of matrix [xtxinvxt][xdata]-I [19 Aug 2004]---*/
7214 if( !option_data->nocond ){
7215 double esum , sum ;
7216 int nn=xdata.rows , mm=xdata.cols , ii,jj,kk ;
7217 char *www ;
7218 esum = 0.0 ;
7219 STATUS("computing [xtxinvxt_full] [xdata] - I") ;
7220 for( ii=0 ; ii < mm ; ii++ ){
7221 for( jj=0 ; jj < mm ; jj++ ){
7222 sum = (ii==jj) ? -1.0 : 0.0 ;
7223 for( kk=0 ; kk < nn ; kk++ )
7224 sum += xtxinvxt_full.elts[ii][kk]*xdata.elts[kk][jj] ;
7225 esum += fabs(sum) ;
7226 }
7227 }
7228 STATUS("computing message from esum") ;
7229 esum /= (mm*mm) ;
7230 if( esum > 1.e-3 || !IS_GOOD_FLOAT(esum) )
7231 { www = " ** BEWARE **" ; badlev++; }
7232 else if( esum > 1.e-4 ){ www = " ++ OK ++" ; }
7233 else if( esum > 1.e-6 ){ www = " ++ GOOD ++" ; }
7234 else { www = " ++ VERY GOOD ++"; }
7235 if( strstr(www,"**") != NULL )
7236 WARNING_message("+++++ !! Matrix inverse average error = %g %s",esum,www) ;
7237 else
7238 INFO_message("+++++ Matrix inverse average error = %g %s",esum,www) ;
7239 }
7240
7241 #if 0
7242 /*-- 19 Aug 2004: plot matrix pseudoinverse as well --*/
7243 if( option_data->xjpeg_filename != NULL || option_data->x1D_filename != NULL ){
7244 char *jpt , *jsuf ;
7245 char *fn = calloc( sizeof(char) , THD_MAX_NAME+16 ) ;
7246 matrix xpsinv ;
7247
7248 matrix_initialize( &xpsinv ) ;
7249 matrix_transpose( xtxinvxt_full , &xpsinv ) ;
7250
7251 if( option_data->xjpeg_filename != NULL ){
7252 strcpy(fn,option_data->xjpeg_filename) ;
7253 jpt = strstr(fn,".jpg") ; jsuf = ".jpg" ;
7254 if( jpt == NULL ){ jpt = strstr(fn,".JPG") ; jsuf = ".JPG" ; }
7255 if( jpt == NULL ){ jpt = strstr(fn,".png") ; jsuf = ".png" ; }
7256 if( jpt == NULL ){ jpt = strstr(fn,".PNG") ; jsuf = ".PNG" ; }
7257 if( jpt == NULL ) jpt = fn + strlen(fn) ;
7258 strcpy(jpt,"_psinv") ; strcat(fn,jsuf) ;
7259 JPEG_matrix_gray( xpsinv , fn ) ;
7260 }
7261
7262 #if 0
7263 if( option_data->x1D_filename != NULL ){
7264 strcpy(fn,option_data->x1D_filename) ;
7265 jpt = strstr(fn,".1D") ; jsuf = ".1D" ;
7266 if( jpt == NULL ) jpt = fn + strlen(fn) ;
7267 strcpy(jpt,"_psinv") ; strcat(fn,jsuf) ;
7268 ONED_matrix_save( xpsinv , fn ,
7269 NULL,0,NULL,NULL,0,NULL,NULL,NULL ) ; /* no column metadata */
7270 }
7271 #endif
7272
7273 free((void *)fn) ; matrix_destroy( &xpsinv ) ;
7274 }
7275 #endif
7276
7277 /*----- Initialization for the general linear test analysis -----*/
7278 if (num_glt > 0)
7279 init_glt_analysis (xtxinv_full, num_glt, glt_cmat, glt_amat, cxtxinvct);
7280
7281 ct = COX_clock_time() - ct ;
7282 INFO_message("Matrix setup time = %.2f s\n",ct) ; /* 25 Apr 2005 */
7283
7284 vector_create (N, &y);
7285
7286 if (nodata)
7287 {
7288 report_evaluation(qp, num_stimts, stim_label, min_lag, max_lag,
7289 x_full, xtxinv_full,
7290 num_glt, glt_label, glt_rows, cxtxinvct);
7291 }
7292
7293 else
7294 { /*============== actually process data ====================*/
7295
7296 int ixyz_bot=0 , ixyz_top=nxyz ; /* voxel indexes to process */
7297
7298 #ifdef USE_GET
7299 #define NGET 128 /* number to get at one time */
7300 int nget=0 , /* number of time series current gotten */
7301 cget=0 , /* index of next timeseries in iget & imget */
7302 jget , /* loop index for iget */
7303 iget[NGET] ; /* voxel index of timeseries */
7304 MRI_IMARR *imget=NULL ; /* array of timeseries */
7305 #endif
7306
7307 if( badlev > 0 ){ /*--- 07 Mar 2007 ---*/
7308 if( goforit >= badlev ){
7309 WARNING_message(
7310 "!! " PROGRAM_NAME " -GOFORIT is set to %d: running despite %d matrix warnings",
7311 goforit , badlev ) ;
7312 WARNING_message(
7313 "!! See file " PROGRAM_NAME ".err for all WARNING and ERROR messages !!") ;
7314 WARNING_message(
7315 "!! Please be sure you understand what you are doing !!") ;
7316 WARNING_message(
7317 "!! If in doubt, consult with someone or with the AFNI message board !!") ;
7318 } else {
7319 ERROR_message(
7320 "!! " PROGRAM_NAME ": Can't run past %d matrix warnings without '-GOFORIT %d'",
7321 badlev , badlev ) ;
7322 ERROR_message(
7323 "!! Currently at -GOFORIT %d",goforit) ;
7324 ERROR_message(
7325 "!! See file " PROGRAM_NAME ".err for all WARNING and ERROR messages !!") ;
7326 ERROR_message(
7327 "!! Be sure you understand what you are doing before using -GOFORIT !!") ;
7328 ERROR_message(
7329 "!! If in doubt, consult with someone or with the AFNI message board !!") ;
7330 ERROR_exit(
7331 "!! " PROGRAM_NAME " (regretfully) shuts itself down !!") ;
7332 }
7333 }
7334
7335 #ifdef PROC_MAX
7336 if( proc_numjob > 1 ){ /*---- set up multiple processes ----*/
7337 int vv , nvox=nxyz , nper , pp , nv ;
7338 pid_t newpid ;
7339
7340 /* count number of voxels to compute with into nvox */
7341
7342 if( mask_vol != NULL ){
7343 for( vv=nvox=0 ; vv < nxyz ; vv++ )
7344 if( mask_vol[vv] != 0 ) nvox++ ;
7345 }
7346
7347 if( nvox < proc_numjob ){ /* too few voxels for multiple jobs? */
7348
7349 proc_numjob = 1 ; virtu_mrv = 0 ;
7350
7351 } else { /* prepare jobs */
7352
7353 /* split voxels between jobs evenly */
7354
7355 nper = nvox / proc_numjob ; /* # voxels per job */
7356 if( mask_vol == NULL ){
7357 proc_vox_bot[0] = 0 ;
7358 for( pp=0 ; pp < proc_numjob ; pp++ ){
7359 proc_vox_top[pp] = proc_vox_bot[pp] + nper ;
7360 if( pp < proc_numjob-1 ) proc_vox_bot[pp+1] = proc_vox_top[pp] ;
7361 }
7362 proc_vox_top[proc_numjob-1] = nxyz ;
7363 } else {
7364 proc_vox_bot[0] = 0 ;
7365 for( pp=0 ; pp < proc_numjob ; pp++ ){
7366 for( nv=0,vv=proc_vox_bot[pp] ; /* count ahead until */
7367 nv < nper && vv < nxyz ; vv++ ){ /* find nper voxels */
7368 if( mask_vol[vv] != 0 ) nv++ ; /* inside the mask */
7369 }
7370 proc_vox_top[pp] = vv ;
7371 if( pp < proc_numjob-1 ) proc_vox_bot[pp+1] = proc_vox_top[pp] ;
7372 }
7373 proc_vox_top[proc_numjob-1] = nxyz ;
7374 }
7375
7376 /* make sure dataset is in memory before forks */
7377
7378 DSET_load(dset) ; /* so dataset will be common */
7379
7380 if( virtu_mrv ){ /* create a vectim and virtualize it, for Javier */
7381 INFO_message("-virtvec: Starting creation of virtual vector image") ;
7382 MEM_MESSAGE ;
7383 inset_mrv = THD_dset_to_vectim( dset , mask_vol , 0 ) ;
7384 if( inset_mrv == NULL ){
7385 ERROR_message("Can't create vector image in RAM?!") ; virtu_mrv = 0 ;
7386 } else {
7387 DSET_unload(dset) ;
7388 INFO_message("vector image created in RAM") ;
7389 MEM_MESSAGE ;
7390 fname_mrv = mri_get_tempfilename("JUNK") ;
7391 pp = THD_vectim_data_tofile( inset_mrv , fname_mrv ) ;
7392 if( pp == 0 ){
7393 ERROR_message("Can't write vector image to temp file %s",fname_mrv) ;
7394 virtu_mrv = 0 ; free(fname_mrv) ; VECTIM_destroy(inset_mrv) ;
7395 DSET_load(dset) ; MEM_MESSAGE ;
7396 } else {
7397 free(inset_mrv->fvec) ; inset_mrv->fvec = NULL ;
7398 INFO_message("vector image stored in temp file %s",fname_mrv) ;
7399 MEM_MESSAGE ;
7400 #ifdef USE_GET
7401 do_get = 0 ;
7402 #endif
7403 }
7404 }
7405 }
7406
7407 /* start processes */
7408
7409 if( !option_data->quiet ) INFO_message("Voxels in dataset: %d",nxyz);
7410 if( nvox < nxyz )
7411 if( !option_data->quiet ) INFO_message("Voxels in mask: %d",nvox);
7412 if( !option_data->quiet ) INFO_message("Voxels per job: %d",nper);
7413
7414 for( pp=1 ; pp < proc_numjob ; pp++ ){
7415 ixyz_bot = proc_vox_bot[pp] ; /* these 3 variables */
7416 ixyz_top = proc_vox_top[pp] ; /* are for the process */
7417 proc_ind = pp ; /* we're about to fork */
7418 errno = 0 ;
7419 newpid = fork() ;
7420 if( newpid == -1 ){
7421 ERROR_message("Can't fork job #%d! Danger, Wil Robinson!",pp);
7422 if( errno != 0 ) perror("** Unix ERROR message") ;
7423 if( pp > 1 ){
7424 int qq ;
7425 for( qq=1 ; qq < pp ; qq++ ){
7426 ERROR_message("Killing fork-ed job %d (pid=%u)",
7427 qq , (unsigned int)proc_pid[qq] ) ;
7428 kill( proc_pid[qq] ,SIGTERM ) ; iochan_sleep(10) ;
7429 waitpid( proc_pid[qq] , NULL , 0 ) ;
7430 }
7431 }
7432 ERROR_exit("3dDeconvolve main process now stopping -- SORRY") ;
7433 }
7434
7435 if( newpid == 0 ) break ; /* I'm the child */
7436 proc_pid[pp] = newpid ; /* I'm the parent */
7437 iochan_sleep(10) ; /* 10 ms, to let the child get going */
7438 }
7439 if( pp == proc_numjob ){ /* only in the parent */
7440 ixyz_bot = proc_vox_bot[0] ; /* set the 3 control */
7441 ixyz_top = proc_vox_top[0] ; /* variables needed */
7442 proc_ind = 0 ; /* below */
7443 }
7444 if( !option_data->quiet )
7445 INFO_message("Job #%d: processing voxels %d to %d; elapsed time=%.3f",
7446 proc_ind,ixyz_bot,ixyz_top-1,COX_clock_time()) ;
7447 }
7448 } else if ( virtu_mrv ) { /* only if virtu_mrv 17 Jan 2013 [rickr] */
7449
7450 WARNING_message("-virtvec: ignoring option since -jobs isn't greater than 1") ;
7451 virtu_mrv = 0 ; /* 26 Dec 2012 */
7452
7453 }
7454 #endif /* PROC_MAX */
7455
7456 if( proc_numjob == 1 && !option_data->quiet ){
7457 MEM_MESSAGE ;
7458 INFO_message("Calculations starting; elapsed time=%.3f",COX_clock_time()) ;
7459 }
7460
7461 /* show voxel loop when numjob > 1 17 Sep 2007 [rickr] */
7462 vstep = (ixyz_top - ixyz_bot) / 50 ;
7463 if( option_data->quiet ||
7464 option_data->fdisp >= 0.0 ||
7465 option_data->progress > 0 ||
7466 (proc_numjob > 1 && proc_ind != 0) ) vstep = 0 ;
7467
7468 if( vstep > 0 ) fprintf(stderr,"++ voxel loop:") ;
7469
7470 if( virtu_mrv && fname_mrv != NULL ){ /* 26 Dec 2012 */
7471 mfp = fopen(fname_mrv,"r") ;
7472 if( mfp == NULL ) ERROR_exit("Job #%d: can't re-open temp file %s",proc_ind,fname_mrv) ;
7473 if( ts_array == NULL ){
7474 ts_array = (float *) malloc (sizeof(float) * nt); MTEST (ts_array);
7475 }
7476 }
7477
7478 /*----- Loop over all voxels -----*/
7479 for (ixyz = ixyz_bot; ixyz < ixyz_top; ixyz++)
7480 {
7481
7482 if( vstep > 0 && ixyz%vstep==vstep-1 ) vstep_print() ;
7483
7484 /*----- Apply mask? -----*/
7485 if (mask_vol != NULL)
7486 if (mask_vol[ixyz] == 0) continue;
7487
7488 #ifdef USE_GET
7489 /*** race ahead and extract a bunch of voxel time series at once ***/
7490
7491 if( do_get && cget == nget ){
7492 if( imget != NULL ) DESTROY_IMARR(imget) ;
7493 iget[0] = ixyz ; nget = 1 ;
7494 for( jget=ixyz+1 ; jget < nxyz && nget < NGET ; jget++ ){
7495 if( mask_vol == NULL || mask_vol[jget] != 0 )
7496 iget[nget++] = jget ;
7497 }
7498 imget = THD_extract_many_series( nget, iget, dset ) ;
7499 cget = 0 ; /* the next one to take out of imget */
7500 }
7501 #endif
7502
7503 /*----- Extract Y-data for this voxel -----*/
7504 if (option_data->input1D_filename != NULL)
7505 ts_array = fmri_data;
7506 else {
7507 #ifdef USE_GET
7508 if( do_get ){
7509 ts_array = MRI_FLOAT_PTR(IMARR_SUBIM(imget,cget)); /* the GET way */
7510 cget++ ; /* take this one next time */
7511 } else if( mfp != NULL ){ /* Javier's way */
7512 int ijk = THD_vectim_ifind( ixyz , inset_mrv ) ;
7513 if( ijk >= 0 ) THD_vector_fromfile( nt , ijk , ts_array , mfp ) ;
7514 else memset( ts_array , 0 , sizeof(float)*nt ) ;
7515 } else {
7516 extract_ts_array (dset, ixyz, ts_array); /* the OLD way */
7517 }
7518 #else
7519 extract_ts_array (dset, ixyz, ts_array); /* the OLD way */
7520 #endif
7521 }
7522
7523 for (i = 0; i < N; i++)
7524 y.elts[i] = ts_array[good_list[i]];
7525
7526
7527 /*----- Perform the regression analysis for this voxel-----*/
7528 regression_analysis (N, p, q, num_stimts, min_lag, max_lag,
7529 x_full, xtxinv_full, xtxinvxt_full, x_base,
7530 xtxinvxt_base, x_rdcd, xtxinvxt_rdcd,
7531 y, rms_min, &mse, &coef, &scoef, &tcoef,
7532 fpart, rpart, &ffull, &rfull, &novar,
7533 fitts, errts);
7534
7535 if( voxel_base != NULL )
7536 voxel_base[ixyz] = baseline_mean( coef ) ; /* 31 Aug 2004 */
7537
7538
7539 /*----- Perform the general linear tests for this voxel -----*/
7540 if (num_glt > 0)
7541 glt_analysis (N, p, x_full, y, mse*(N-p), coef, novar, cxtxinvct,
7542 num_glt, glt_rows, glt_cmat, glt_amat,
7543 glt_coef, glt_tcoef, fglt, rglt);
7544
7545
7546 /*----- Save results for this voxel into arrays -----*/
7547 save_voxel (option_data, ixyz, coef, scoef, tcoef, fpart, rpart, mse,
7548 ffull, rfull, glt_coef, glt_tcoef, fglt, rglt,
7549 nt, ts_array, good_list, fitts, errts,
7550 coef_vol, scoef_vol, tcoef_vol, fpart_vol, rpart_vol,
7551 mse_vol, ffull_vol, rfull_vol, glt_coef_vol,
7552 glt_tcoef_vol, glt_fstat_vol, glt_rstat_vol,
7553 fitts_vol, errts_vol);
7554
7555
7556 /*----- Report results for this voxel -----*/
7557 if ( ((ffull > option_data->fdisp) && (option_data->fdisp >= 0.0))
7558 || ((option_data->progress > 0)
7559 && (ixyz % option_data->progress == 0))
7560 || (option_data->input1D_filename != NULL) )
7561 {
7562
7563 if( proc_ind == 0 ){
7564 printf ("\n\nResults for Voxel #%d: \n", ixyz);
7565 report_results (N, qp, q, p, polort, block_list, num_blocks,
7566 num_stimts, stim_label, baseline, min_lag, max_lag,
7567 coef, tcoef, fpart, rpart, ffull, rfull, mse,
7568 num_glt, glt_label, glt_rows, glt_coef,
7569 glt_tcoef, fglt, rglt, &label);
7570 printf ("%s \n", label); fflush(stdout);
7571 }
7572 }
7573
7574 } /*----- Loop over voxels -----*/
7575
7576 if( vstep > 0 ) fprintf(stderr,"\n") ;
7577
7578 #ifdef USE_GET
7579 if( do_get ){
7580 if( imget != NULL ) DESTROY_IMARR(imget) ;
7581 ts_array = NULL ;
7582 }
7583 #endif
7584
7585 if( mfp != NULL ) fclose(mfp) ; /* 26 Dec 2012 */
7586
7587 /*-- if this is a child process, we're done.
7588 if this is the parent process, wait for the children --*/
7589
7590 #ifdef PROC_MAX
7591 if( proc_numjob > 1 ){
7592 if( proc_ind > 0 ){ /* death of child */
7593 if( !option_data->quiet )
7594 INFO_message("Job #%d finished; elapsed time=%.3f",
7595 proc_ind,COX_clock_time()) ;
7596 _exit(0) ;
7597
7598 } else { /* parent waits for children */
7599 int pp ;
7600 if( !option_data->quiet )
7601 INFO_message("Job #0 waiting for children to finish; elapsed time=%.3f",
7602 COX_clock_time()) ;
7603 for( pp=1 ; pp < proc_numjob ; pp++ )
7604 waitpid( proc_pid[pp] , NULL , 0 ) ;
7605 if( !option_data->quiet )
7606 INFO_message("Job #0 now finishing up; elapsed time=%.3f",
7607 COX_clock_time()) ;
7608 }
7609
7610 /* when get to here, only parent process is left alive,
7611 and all the results are in the shared memory segment arrays */
7612
7613 if( inset_mrv != NULL ){
7614 VECTIM_destroy(inset_mrv) ; remove(fname_mrv) ;
7615 INFO_message("-virtvec: temp file %s has been removed",fname_mrv) ;
7616 free(fname_mrv) ; fname_mrv = NULL ; virtu_mrv = 0 ;
7617 }
7618 }
7619 #endif
7620 if( proc_numjob == 1 && !option_data->quiet )
7621 INFO_message("Calculations finished; elapsed time=%.3f",COX_clock_time()) ;
7622
7623 if( option_data->input1D_filename == NULL) /* don't need data anymore */
7624 DSET_unload(dset) ;
7625
7626 } /*----- NOT nodata -----*/
7627
7628
7629 /*----- Dispose of matrices and vectors -----*/
7630 vector_destroy (&y);
7631 vector_destroy (&tcoef);
7632 vector_destroy (&scoef);
7633 vector_destroy (&coef);
7634
7635 if (num_stimts > 0)
7636 {
7637 for (is = 0; is < num_stimts; is++)
7638 {
7639 matrix_destroy (&x_rdcd[is]);
7640 matrix_destroy (&xtxinvxt_rdcd[is]);
7641 }
7642 free (x_rdcd); x_rdcd = NULL;
7643 free (xtxinvxt_rdcd); xtxinvxt_rdcd = NULL;
7644 }
7645
7646 matrix_destroy (&xtxinvxt_base);
7647 matrix_destroy (&x_base);
7648 matrix_destroy (&xdata);
7649
7650 if (num_glt > 0)
7651 {
7652 for (iglt = 0; iglt < num_glt; iglt++)
7653 {
7654 matrix_destroy (&cxtxinvct[iglt]);
7655 matrix_destroy (&glt_amat[iglt]);
7656 vector_destroy (&glt_coef[iglt]);
7657 vector_destroy (&glt_tcoef[iglt]);
7658 }
7659 free (cxtxinvct); cxtxinvct = NULL;
7660 free (glt_amat); glt_amat = NULL;
7661 free (glt_coef); glt_coef = NULL;
7662 free (glt_tcoef); glt_tcoef = NULL;
7663 }
7664
7665
7666 if (fpart != NULL) { free (fpart); fpart = NULL; }
7667 if (rpart != NULL) { free (rpart); rpart = NULL; }
7668 if (fglt != NULL) { free (fglt); fglt = NULL; }
7669 if (rglt != NULL) { free (rglt); rglt = NULL; }
7670 if (ts_array != NULL) { free (ts_array); ts_array = NULL; }
7671 if (fitts != NULL) { free (fitts); fitts = NULL; }
7672 if (errts != NULL) { free (errts); errts = NULL; }
7673
7674 EXRETURN ;
7675 }
7676
7677 /*---------------------------------------------------------------------------*/
7678 /*
7679 Use cubic spline interpolation to time shift the estimated impulse response
7680 function, in order to correct for differences in slice acquisition times.
7681
7682 */
7683
cubic_spline(DC_options * option_data,int ts_length,float ** vol_array)7684 void cubic_spline
7685 (
7686 DC_options * option_data, /* deconvolution algorithm options */
7687 int ts_length, /* length of time series data */
7688 float ** vol_array /* output time series volume data */
7689 )
7690
7691 {
7692 THD_3dim_dataset * dset = NULL; /* input afni data set pointer */
7693 int nx, ny, nz, nxyz; /* dataset dimensions in voxels */
7694 int ixyz; /* voxel index */
7695 int isl; /* slice index */
7696 int i; /* data point index */
7697 float * yarray = NULL; /* impulse response function for a single voxel */
7698 float * sarray = NULL; /* second derivative of the cubic in each interval */
7699 matrix m, minv; /* matrices for cubic spline interpolation */
7700 vector v, sv; /* vectors for cubic spline interpolation */
7701 int n; /* number of intervals = ts_length-1 */
7702 float * a = NULL,
7703 * b = NULL,
7704 * c = NULL,
7705 * d = NULL; /* cubic spline interpolation polynomial coefs. */
7706 float tslice; /* slice acquisition time offset */
7707 float tdelta; /* time between same slice acquisitons */
7708 float frac; /* fraction of interval for slice acq. time offset */
7709 int k; /* interval to use for interpolation */
7710 float t; /* time in fractions of TR */
7711 float delt; /* time offset relative to interpolation interval */
7712 float y; /* interpolated value */
7713
7714
7715 /*----- Initialize matrices and vectors -----*/
7716 matrix_initialize (&m);
7717 matrix_initialize (&minv);
7718 vector_initialize (&v);
7719 vector_initialize (&sv);
7720
7721
7722 /*----- Initialize local variables -----*/
7723 dset = THD_open_dataset (option_data->input_filename);
7724 CHECK_OPEN_ERROR(dset,option_data->input_filename) ;
7725
7726 if( option_data->force_TR > 0.0 ) /* 18 Aug 2008 */
7727 EDIT_dset_items( dset ,
7728 ADN_ttdel , option_data->force_TR ,
7729 ADN_ntt , DSET_NVALS(dset) ,
7730 ADN_tunits, UNITS_SEC_TYPE ,
7731 ADN_none ) ;
7732
7733 n = ts_length - 1;
7734 tdelta = dset->taxis->ttdel;
7735 nx = dset->daxes->nxx; ny = dset->daxes->nyy; nz = dset->daxes->nzz;
7736 nxyz = nx * ny * nz;
7737 DSET_UNMSEC( dset ) ; /* 12 Aug 2005: surgery on the time units? */
7738
7739
7740 /*----- Allocate space for data and interpolation polynomials -----*/
7741 yarray = (float *) malloc (sizeof(float) * ts_length);
7742 sarray = (float *) malloc (sizeof(float) * (n+1));
7743 a = (float *) malloc (sizeof(float) * n);
7744 b = (float *) malloc (sizeof(float) * n);
7745 c = (float *) malloc (sizeof(float) * n);
7746 d = (float *) malloc (sizeof(float) * n);
7747
7748
7749 /*----- Calculate matrix for cubic spline interpolation -----*/
7750 matrix_create (n-1, n-1, &m);
7751 m.elts[0][0] = 4.0;
7752 m.elts[0][1] = 1.0;
7753 m.elts[n-2][n-3] = 1.0;
7754 m.elts[n-2][n-2] = 4.0;
7755 for (i = 1; i < n-2; i++)
7756 {
7757 m.elts[i][i] = 4.0;
7758 m.elts[i][i-1] = 1.0;
7759 m.elts[i][i+1] = 1.0;
7760 }
7761 matrix_inverse (m, &minv);
7762
7763
7764 vector_create (n-1, &v);
7765
7766
7767 /*----- Loop over all voxels -----*/
7768 for (ixyz = 0; ixyz < nxyz; ixyz++)
7769 {
7770
7771 /*----- Get time offset for this slice -----*/
7772 isl = ixyz / (nx*ny);
7773 tslice = THD_timeof_slice (0, isl, dset);
7774 frac = -((tslice/tdelta) - 0.5);
7775
7776 /*----- Get impulse response function for this voxel -----*/
7777 for (i = 0; i < ts_length; i++)
7778 yarray[i] = vol_array[i][ixyz];
7779
7780
7781 /*----- Calculate vector for cubic spline interpolation -----*/
7782 for (i = 1; i < n; i++)
7783 v.elts[i-1] = 6.0 * (yarray[i+1] - 2.0 * yarray[i] + yarray[i-1]);
7784 vector_multiply (minv, v, &sv);
7785
7786
7787 /*----- Set array of second derivatives -----*/
7788 for (i = 1; i < n; i++)
7789 {
7790 sarray[i] = sv.elts[i-1];
7791 }
7792 sarray[0] = 0.0;
7793 sarray[n] = 0.0;
7794
7795
7796 /*----- Calculate cubic spline polynomial coefficients -----*/
7797 for (i = 0; i < n; i++)
7798 {
7799 a[i] = (sarray[i+1] - sarray[i]) / 6.0;
7800 b[i] = sarray[i] / 2;
7801 c[i] = (yarray[i+1]-yarray[i]) - (2.0*sarray[i]+sarray[i+1]) / 6.0;
7802 d[i] = yarray[i];
7803 }
7804
7805
7806 /*----- Apply time shift to impulse response function -----*/
7807 for (i = 0; i < ts_length; i++)
7808 {
7809 t = i + frac;
7810
7811 if (frac < 0.0) k = i-1;
7812 else k = i;
7813
7814 if (k < 0) k = 0;
7815 if (k > n-1) k = n-1;
7816
7817 delt = t - k;
7818
7819 yarray[i] = a[k]*delt*delt*delt + b[k]*delt*delt + c[k]*delt + d[k];
7820 }
7821
7822
7823 /*----- Save interpolated impulse response function -----*/
7824 for (i = 0; i < ts_length; i++)
7825 vol_array[i][ixyz] = yarray[i];
7826
7827
7828
7829 } /* Loop over voxels */
7830
7831
7832 /*----- Deallocate memory -----*/
7833 THD_delete_3dim_dataset (dset, False); dset = NULL ;
7834
7835 matrix_destroy (&m);
7836 matrix_destroy (&minv);
7837 vector_destroy (&v);
7838 vector_destroy (&sv);
7839
7840 free (sarray); sarray = NULL;
7841 free (yarray); yarray = NULL;
7842 free (a); a = NULL;
7843 free (b); b = NULL;
7844 free (c); c = NULL;
7845 free (d); d = NULL;
7846 }
7847
7848
7849 /*---------------------------------------------------------------------------*/
7850 /*
7851 Routine to write one AFNI 3D+time data set.
7852 */
7853
7854
write_ts_array(int argc,char ** argv,DC_options * option_data,int ts_length,int nptr,int tshift,float ** vol_array,char * output_filename)7855 void write_ts_array
7856 (
7857 int argc, /* number of input arguments */
7858 char ** argv, /* array of input arguments */
7859 DC_options * option_data, /* deconvolution algorithm options */
7860 int ts_length, /* length of time series data */
7861 int nptr, /* number of time points per TR */
7862 int tshift, /* flag to set slice offset times to 0 */
7863 float ** vol_array, /* output time series volume data */
7864 char * output_filename /* output afni data set file name */
7865 )
7866
7867 {
7868 const float EPSILON = 1.0e-10;
7869
7870 THD_3dim_dataset * dset = NULL; /* input afni data set pointer */
7871 THD_3dim_dataset * new_dset = NULL; /* output afni data set pointer */
7872 int ib; /* sub-brick index */
7873 int ierror; /* number of errors in editing data */
7874 int nxyz; /* total number of voxels */
7875 float factor; /* factor is new scale factor for sub-brick #ib */
7876 char * input_filename; /* input afni data set file name */
7877 float * volume; /* pointer to volume of data */
7878 char label[THD_MAX_NAME]; /* label for output file */
7879 float newtr; /* new time step = TR/nptr */
7880 int dtype ;
7881
7882
7883 /*----- Initialize local variables -----*/
7884 input_filename = option_data->input_filename;
7885 dset = THD_open_dataset (input_filename);
7886 CHECK_OPEN_ERROR(dset,input_filename) ;
7887
7888 if( option_data->force_TR > 0.0 ) /* 18 Aug 2008 */
7889 EDIT_dset_items( dset ,
7890 ADN_ttdel , option_data->force_TR ,
7891 ADN_ntt , DSET_NVALS(dset) ,
7892 ADN_tunits, UNITS_SEC_TYPE ,
7893 ADN_none ) ;
7894
7895 nxyz = dset->daxes->nxx * dset->daxes->nyy * dset->daxes->nzz;
7896 DSET_UNMSEC(dset) ; /* 12 Aug 2005 */
7897 newtr = DSET_TIMESTEP(dset) / nptr;
7898
7899 /*----- allocate memory -----*/
7900
7901 dtype = (floatout) ? MRI_float : MRI_short ;
7902
7903 /*-- make an empty copy of the prototype dataset, for eventual output --*/
7904 new_dset = EDIT_empty_copy (dset);
7905
7906 /*----- Record history of dataset -----*/
7907 tross_Copy_History( dset , new_dset ) ;
7908
7909 sprintf (label, "Output prefix: %s", output_filename);
7910 if( commandline != NULL )
7911 tross_multi_Append_History( new_dset , commandline,label,NULL ) ;
7912 else
7913 tross_Append_History ( new_dset, label);
7914
7915 /*----- Delete prototype dataset -----*/
7916 THD_delete_3dim_dataset (dset, False); dset = NULL ;
7917
7918
7919 ierror = EDIT_dset_items (new_dset,
7920 ADN_prefix, output_filename,
7921 ADN_label1, output_filename,
7922 ADN_self_name, output_filename,
7923 ADN_malloc_type, DATABLOCK_MEM_MALLOC,
7924 ADN_datum_all, dtype ,
7925 ADN_nvals, ts_length,
7926 ADN_ntt, ts_length,
7927 ADN_ttdel, newtr,
7928 ADN_none);
7929
7930 if( ierror > 0 )
7931 ERROR_exit(
7932 "%d errors in attempting to create output dataset!", ierror ) ;
7933
7934 #ifndef FIX_CONFLICTS
7935 if( THD_is_file(new_dset->dblk->diskptr->header_name) )
7936 ERROR_exit(
7937 "Output dataset file %s already exists -- can't continue!",
7938 new_dset->dblk->diskptr->header_name ) ;
7939 #else
7940 if(!THD_ok_overwrite() && /* ZSS: Dec. 16 08 */
7941 THD_deconflict_prefix(new_dset) > 0 ) {
7942 WARNING_message("Filename conflict: changing '%s' to '%s'",
7943 output_filename,DSET_PREFIX(new_dset) ) ;
7944 }
7945 #endif
7946
7947
7948 /*----- Reset slice offset times to zero -----*/
7949 if (tshift)
7950 EDIT_dset_items (new_dset,
7951 ADN_nsl, 0, /* will have no offsets when done */
7952 ADN_ttorg, 0.0, /* in case not already set */
7953 ADN_ttdur, 0.0, /* in case not already set */
7954 ADN_none);
7955
7956 EDIT_dset_items( new_dset , ADN_brick_fac,NULL , ADN_none ) ;
7957
7958 /*----- attach bricks to new data set -----*/
7959 for (ib = 0; ib < ts_length; ib++)
7960 {
7961
7962 /*----- Set pointer to appropriate volume -----*/
7963 volume = vol_array[ib];
7964
7965 if( floatout ){ /* the new (float) way */
7966 float *fff ;
7967 EDIT_substitute_brick( new_dset , ib , MRI_float , NULL ) ;
7968 fff = DSET_ARRAY(new_dset,ib) ;
7969 memcpy( fff , volume , sizeof(float)*nxyz ) ;
7970
7971 } else { /* the old (short) way */
7972 short *bar ;
7973 EDIT_substitute_brick( new_dset , ib , MRI_short , NULL ) ;
7974 bar = DSET_ARRAY(new_dset,ib) ;
7975
7976 if( volume != NULL ){
7977 factor = EDIT_coerce_autoscale_new( nxyz, MRI_float, volume,
7978 MRI_short, bar);
7979 if (factor < EPSILON) factor = 0.0;
7980 else factor = 1.0 / factor;
7981 EDIT_BRICK_FACTOR( new_dset , ib , factor ) ;
7982
7983 EDIT_misfit_report( DSET_FILECODE(new_dset) , ib ,
7984 nxyz , factor , bar , volume ) ;
7985 }
7986 }
7987 }
7988
7989 /*----- write afni data set -----*/
7990
7991 THD_load_statistics (new_dset);
7992 THD_write_3dim_dataset (NULL, NULL, new_dset, True);
7993 if (! option_data->quiet)
7994 INFO_message("Wrote 3D+time dataset into %s",DSET_BRIKNAME(new_dset)) ;
7995
7996
7997 /*----- deallocate memory -----*/
7998 THD_delete_3dim_dataset (new_dset, False); new_dset = NULL ;
7999
8000 }
8001
8002
8003 /*---------------------------------------------------------------------------*/
8004 /*
8005 Attach one sub-brick to output bucket data set.
8006 */
8007
attach_sub_brick(THD_3dim_dataset * new_dset,int ibrick,float * volume,int nxyz,int brick_type,char * brick_label,float dof,float ndof,float ddof,void ** bar)8008 void attach_sub_brick
8009 (
8010 THD_3dim_dataset * new_dset, /* output bucket dataset */
8011 int ibrick, /* sub-brick indices */
8012 float * volume, /* volume of floating point data */
8013 int nxyz, /* total number of voxels */
8014 int brick_type, /* indicates statistical type of sub-brick */
8015 char * brick_label, /* character string label for sub-brick */
8016 float dof,
8017 float ndof,
8018 float ddof, /* degrees of freedom */
8019 void ** bar /* bar[ib] points to data for sub-brick #ib */
8020 )
8021
8022 {
8023 float factor=0.0f ; const float EPSILON = 1.0e-10;
8024
8025 ENTRY("attach_sub_brick") ;
8026
8027 /*----- allocate memory for output sub-brick -----*/
8028 if( floatout ){ /* the new (float) way */
8029 float *fff ;
8030 EDIT_substitute_brick( new_dset , ibrick , MRI_float , NULL ) ;
8031 fff = DSET_ARRAY(new_dset,ibrick) ;
8032 if( bar != NULL ) bar[ibrick] = (void *)fff ;
8033 memcpy( fff , volume , sizeof(float)*nxyz ) ;
8034
8035 } else { /* the old (short) way */
8036 short *sbr ;
8037 EDIT_substitute_brick( new_dset , ibrick , MRI_short , NULL ) ;
8038 sbr = DSET_ARRAY(new_dset,ibrick) ;
8039 if( bar != NULL ) bar[ibrick] = (void *)sbr ;
8040 factor = EDIT_coerce_autoscale_new(nxyz, MRI_float,volume, MRI_short,sbr);
8041 if (factor < EPSILON) factor = 0.0;
8042 else factor = 1.0 / factor;
8043
8044 EDIT_misfit_report( DSET_FILECODE(new_dset) , ibrick ,
8045 nxyz , factor , sbr , volume ) ;
8046 }
8047
8048 /*----- edit the sub-brick -----*/
8049 if( brick_label != NULL && *brick_label != '\0' )
8050 EDIT_BRICK_LABEL (new_dset, ibrick, brick_label);
8051
8052 EDIT_BRICK_FACTOR(new_dset, ibrick, factor);
8053
8054 switch( brick_type ){
8055 case FUNC_TT_TYPE: if( dof > 0 )
8056 EDIT_BRICK_TO_FITT(new_dset, ibrick, dof);
8057 break ;
8058 case FUNC_FT_TYPE: if( ndof > 0 && ddof > 0 )
8059 EDIT_BRICK_TO_FIFT(new_dset, ibrick, ndof, ddof);
8060 break ;
8061 case FUNC_BT_TYPE: if( ndof > 0 && ddof > 0 )
8062 EDIT_BRICK_TO_FIBT(new_dset, ibrick, ndof, ddof);
8063 break ;
8064 }
8065
8066 EXRETURN ;
8067 }
8068
8069 /*---------------------------------------------------------------------------*/
8070 /*
8071 Routine to write one bucket data set.
8072 */
8073
write_bucket_data(int argc,char ** argv,DC_options * option_data,float ** coef_vol,float ** tcoef_vol,float ** fpart_vol,float ** rpart_vol,float * mse_vol,float * ffull_vol,float * rfull_vol,float *** glt_coef_vol,float *** glt_tcoef_vol,float ** glt_fstat_vol,float ** glt_rstat_vol)8074 void write_bucket_data
8075 (
8076 int argc, /* number of input arguments */
8077 char ** argv, /* array of input arguments */
8078 DC_options * option_data, /* deconvolution algorithm options */
8079
8080 float ** coef_vol, /* array of volumes of signal model parameters */
8081 float ** tcoef_vol, /* array of volumes of signal model t-statistics */
8082 float ** fpart_vol, /* array of volumes of partial F-statistics */
8083 float ** rpart_vol, /* array of volumes of partial R^2 statistics */
8084 float * mse_vol, /* volume of full model mean square error */
8085 float * ffull_vol, /* volume of full model F-statistics */
8086 float * rfull_vol, /* volume of full model R^2 statistics */
8087 float *** glt_coef_vol, /* volumes for GLT linear combinations */
8088 float *** glt_tcoef_vol, /* volumes for GLT t-statistics */
8089 float ** glt_fstat_vol, /* volumes for GLT F-statistics */
8090 float ** glt_rstat_vol /* volumes for GLT R^2 statistics */
8091 )
8092
8093 {
8094 THD_3dim_dataset * old_dset = NULL; /* prototype dataset */
8095 THD_3dim_dataset * new_dset = NULL; /* output bucket dataset */
8096 char output_prefix[THD_MAX_NAME]; /* prefix name for bucket dataset */
8097 char output_session[THD_MAX_NAME]; /* directory for bucket dataset */
8098 int nbricks; /* number of sub-bricks in bucket dataset */
8099 void ** bar = NULL; /* bar[ib] points to data for sub-brick #ib */
8100
8101 int brick_type; /* indicates statistical type of sub-brick */
8102 int brick_coef; /* regression coefficient index for sub-brick */
8103 char brick_label[THD_MAX_NAME]; /* character string label for sub-brick */
8104
8105 int ierror; /* number of errors in editing data */
8106 float * volume; /* volume of floating point data */
8107
8108 int N; /* number of usable data points */
8109 int qp; /* number of poly. trend baseline parameters */
8110 int q; /* number of baseline model parameters */
8111 int p; /* number of full model parameters */
8112 int polort; /* degree of polynomial for baseline model */
8113 int num_stimts; /* number of stimulus time series */
8114 int istim; /* stimulus index */
8115 int nxyz; /* total number of voxels */
8116 int nt; /* number of images in input 3D+time dataset */
8117 int ilag; /* lag index */
8118 int icoef; /* coefficient index */
8119 int ibrick; /* sub-brick index */
8120 float dof, ndof, ddof; /* degrees of freedom */
8121 char label[THD_MAX_NAME]; /* general label for sub-bricks */
8122 char blab[THD_MAX_NAME] ; /* label for baseline funcs */
8123 int num_glt; /* number of general linear tests */
8124 int * glt_rows; /* number of linear constraints in glt */
8125 int iglt; /* general linear test index */
8126 int ilc; /* linear combination index */
8127
8128 THD_3dim_dataset *coef_dset = NULL ; /* coefficient bucket? */
8129 int cbuck , bout,cout , ibot,itop ;
8130
8131 /*----- read prototype dataset -----*/
8132 old_dset = THD_open_dataset (option_data->input_filename);
8133 CHECK_OPEN_ERROR(old_dset,option_data->input_filename);
8134
8135 if( option_data->force_TR > 0.0 ) /* 18 Aug 2008 */
8136 EDIT_dset_items( old_dset ,
8137 ADN_ttdel , option_data->force_TR ,
8138 ADN_ntt , DSET_NVALS(old_dset) ,
8139 ADN_tunits, UNITS_SEC_TYPE ,
8140 ADN_none ) ;
8141
8142 DSET_UNMSEC(old_dset) ; /* 12 Aug 2005 */
8143
8144 bout = !option_data->nobout ;
8145 cout = !option_data->nocout ;
8146
8147 /*----- Initialize local variables -----*/
8148 nxyz = old_dset->daxes->nxx * old_dset->daxes->nyy * old_dset->daxes->nzz;
8149 num_stimts = option_data->num_stimts;
8150 nt = DSET_NVALS(old_dset);
8151 num_glt = option_data->num_glt;
8152 glt_rows = option_data->glt_rows;
8153
8154 polort = option_data->polort;
8155 qp = option_data->qp;
8156 q = option_data->q;
8157 p = option_data->p;
8158 N = option_data->N;
8159 nbricks = option_data->nbricks;
8160
8161
8162 /*----- Prepare output file name -----*/
8163 strcpy (output_prefix, option_data->bucket_filename);
8164 strcpy (output_session, "./");
8165
8166
8167 /*----- allocate memory -----*/
8168 bar = (void **) malloc (sizeof(void *) * nbricks);
8169 MTEST (bar);
8170
8171
8172 /*-- make an empty copy of prototype dataset, for eventual output --*/
8173 new_dset = EDIT_empty_copy (old_dset);
8174
8175
8176 /*----- Record history of dataset -----*/
8177 tross_Copy_History( old_dset , new_dset ) ;
8178 tross_Make_History( PROGRAM_NAME , argc , argv , new_dset ) ;
8179 sprintf (label, "Output prefix: %s", output_prefix);
8180 tross_Append_History ( new_dset, label);
8181
8182 /*----- Modify some structural properties. Note that the nbricks
8183 just make empty sub-bricks, without any data attached. -----*/
8184 ierror = EDIT_dset_items (new_dset,
8185 ADN_prefix, output_prefix,
8186 ADN_type, HEAD_FUNC_TYPE,
8187 ADN_func_type, FUNC_BUCK_TYPE,
8188 ADN_datum_all, (floatout) ? MRI_float : MRI_short ,
8189 ADN_ntt, 0, /* no time axis */
8190 ADN_nvals, nbricks,
8191 ADN_malloc_type, DATABLOCK_MEM_MALLOC ,
8192 ADN_none ) ;
8193
8194 if( ierror > 0 )
8195 ERROR_exit("%d errors in attempting to create bucket dataset!",
8196 ierror);
8197
8198 if( strstr(output_prefix,"/") == NULL )
8199 (void) EDIT_dset_items (new_dset,
8200 ADN_directory_name, output_session,
8201 ADN_none ) ;
8202
8203 #ifndef FIX_CONFLICTS
8204 if( THD_is_file(DSET_HEADNAME(new_dset)) && strcmp(output_prefix,"Decon") != 0 )
8205 ERROR_exit(
8206 "Bucket dataset file %s already exists--cannot continue!",
8207 DSET_HEADNAME(new_dset));
8208 #else
8209 if( strcmp(output_prefix,"Decon") != 0 &&
8210 !THD_ok_overwrite() && /* ZSS: Dec. 16 08 */
8211 THD_deconflict_prefix(new_dset) > 0 ) {
8212 WARNING_message("Filename conflict: changing '%s' to '%s'",
8213 output_prefix,DSET_PREFIX(new_dset) ) ;
8214 }
8215 #endif
8216
8217 if( CoefFilename != NULL ){
8218 coef_dset = EDIT_empty_copy( new_dset ) ;
8219 tross_Copy_History( old_dset , coef_dset ) ;
8220 tross_Make_History( PROGRAM_NAME , argc , argv , coef_dset ) ;
8221 (void) EDIT_dset_items( coef_dset,
8222 ADN_prefix, CoefFilename ,
8223 ADN_type, HEAD_FUNC_TYPE,
8224 ADN_func_type, FUNC_BUCK_TYPE,
8225 ADN_datum_all, (floatout) ? MRI_float : MRI_short ,
8226 ADN_ntt, 0, /* no time axis */
8227 ADN_nvals, p ,
8228 ADN_malloc_type, DATABLOCK_MEM_MALLOC ,
8229 ADN_none ) ;
8230 if( strstr(CoefFilename,"/") == NULL )
8231 (void) EDIT_dset_items( coef_dset ,
8232 ADN_directory_name, output_session,
8233 ADN_none ) ;
8234 #ifndef FIX_CONFLICTS
8235 if( THD_is_file(DSET_HEADNAME(coef_dset)) )
8236 ERROR_exit(
8237 "Coefficient dataset file %s already exists--cannot continue!",
8238 DSET_HEADNAME(coef_dset));
8239 #else
8240 if( !THD_ok_overwrite() && /* ZSS: Dec. 16 08 */
8241 THD_deconflict_prefix(coef_dset) > 0 ) {
8242 WARNING_message("Filename conflict: changing '%s' to '%s'",
8243 CoefFilename,DSET_PREFIX(coef_dset) ) ;
8244 }
8245 #endif
8246 }
8247
8248 /*----- save names for future xsave-ing -----*/
8249 if( DSET_IS_TCAT(old_dset) )
8250 InputFilename = strdup(old_dset->tcat_list) ;
8251 else
8252 InputFilename = strdup(THD_trailname(DSET_HEADNAME(old_dset),0)) ;
8253
8254 BucketFilename = strdup(THD_trailname(DSET_HEADNAME(new_dset),0)) ;
8255
8256 if( coef_dset != NULL )
8257 CoefFilename = strdup(THD_trailname(DSET_HEADNAME(coef_dset),0)) ;
8258
8259 /*----- delete prototype dataset -----*/
8260 THD_delete_3dim_dataset( old_dset , False ); old_dset = NULL ;
8261
8262
8263 /*----- Attach individual sub-bricks to the bucket dataset -----*/
8264
8265
8266 /*----- User can choose to place full model stats first -----*/
8267 ibrick = -1;
8268 if (option_data->full_first)
8269 ibrick += option_data->vout + option_data->rout + option_data->do_fullf;
8270
8271 cbuck = -1 ;
8272
8273
8274 /*----- Include fit coefficients and associated statistics? -----*/
8275 if( cout || coef_dset != NULL )
8276 {
8277
8278 { int ii ;
8279 ParamStim = (int *) calloc(sizeof(int) ,nParam) ;
8280 ParamLabel = (char **)calloc(sizeof(char *),nParam) ;
8281 for( ii=0 ; ii < qp ; ii++ ) ParamLabel[ii] = strdup("ort") ;
8282 for( ; ii < nParam ; ii++ ) ParamLabel[ii] = strdup("coef") ;
8283 if( cout && bout )
8284 ParamIndex = (int *)calloc(sizeof(int) ,nParam) ;
8285 else
8286 ParamIndex = NULL ;
8287 }
8288
8289 /*----- Baseline statistics -----*/
8290 if( bout || coef_dset != NULL )
8291 {
8292 strcpy (label, "Base");
8293
8294 if( legendre_polort ) strcpy(blab,"P_") ; /* 25 Jul 2004: */
8295 else strcpy(blab,"t^") ; /* label for polynomials */
8296
8297 for (icoef = 0; icoef < qp; icoef++)
8298 {
8299 if (qp == polort+1)
8300 strcpy (label, "Base"); /* only 1 run */
8301 else
8302 sprintf (label, "Run#%d", icoef/(polort+1) + 1); /* multiple runs */
8303
8304 /*----- Baseline coefficient -----*/
8305 brick_type = FUNC_FIM_TYPE;
8306 #ifdef USE_OLD_LABELS
8307 sprintf (brick_label, "%s %s%d Coef", label,blab, icoef % (polort+1));
8308 #else
8309 sprintf( brick_label, "%s_Coef" , COLUMN_LABEL(icoef) ) ;
8310 #endif
8311 volume = coef_vol[icoef];
8312
8313 if( cout && bout )
8314 attach_sub_brick (new_dset, ++ibrick, volume, nxyz,
8315 brick_type, brick_label, 0, 0, 0, bar);
8316
8317 #ifdef USE_OLD_LABELS
8318 sprintf(brick_label,"%s:%s%d" , label,blab,icoef%(polort+1)) ;
8319 #else
8320 strcpy(brick_label,COLUMN_LABEL(icoef)) ; /* 12 Mar 2007 */
8321 #endif
8322
8323 if( ParamIndex != NULL ) ParamIndex[icoef] = ibrick ;
8324 ParamStim [icoef] = 0 ;
8325 ParamLabel[icoef] = strdup(brick_label) ;
8326
8327 if( coef_dset != NULL ){
8328 cbuck++ ;
8329 attach_sub_brick( coef_dset , cbuck , volume , nxyz ,
8330 brick_type, brick_label, 0, 0, 0, NULL);
8331 }
8332
8333 /*----- Baseline t-stat -----*/
8334 if ( cout && bout && option_data->tout)
8335 {
8336 ibrick++;
8337 brick_type = FUNC_TT_TYPE;
8338 dof = N - p;
8339 #ifdef USE_OLD_LABELS
8340 sprintf (brick_label, "%s %s%d t-st",
8341 label,blab, icoef % (polort+1));
8342 #else
8343 sprintf( brick_label, "%s_Tstat" , COLUMN_LABEL(icoef) ) ;
8344 #endif
8345 volume = tcoef_vol[icoef];
8346 attach_sub_brick (new_dset, ibrick, volume, nxyz,
8347 brick_type, brick_label, dof, 0, 0, bar);
8348 }
8349 }
8350 }
8351
8352
8353 /*----- Stimulus statistics -----*/
8354 icoef = qp;
8355 for (istim = 0; istim < num_stimts; istim++)
8356 {
8357 strcpy (label, option_data->stim_label[istim]);
8358
8359 if( basis_stim[istim] != NULL ){
8360 ibot = 0 ; itop = basis_stim[istim]->nparm-1 ;
8361 } else {
8362 ibot = option_data->stim_minlag[istim] ;
8363 itop = option_data->stim_maxlag[istim] ;
8364 }
8365
8366 /*----- Loop over stimulus time lags -----*/
8367 for( ilag=ibot ; ilag <= itop ; ilag++ )
8368 {
8369 if( !option_data->stim_base[istim] ||
8370 bout ||
8371 coef_dset != NULL )
8372 {
8373 /*----- Stimulus coefficient -----*/
8374 brick_type = FUNC_FIM_TYPE;
8375 #ifdef USE_OLD_LABELS
8376 sprintf (brick_label, "%s[%d] Coef", label, ilag);
8377 #else
8378 sprintf( brick_label, "%s_Coef" , COLUMN_LABEL(icoef) ) ;
8379 #endif
8380 volume = coef_vol[icoef];
8381 if( cout && (!option_data->stim_base[istim] || bout) )
8382 attach_sub_brick (new_dset, ++ibrick, volume, nxyz,
8383 brick_type, brick_label, 0, 0, 0, bar);
8384
8385 #ifdef USE_OLD_LABELS
8386 sprintf(brick_label,"%s:%d",label,ilag) ;
8387 #else
8388 strcpy(brick_label,COLUMN_LABEL(icoef)) ; /* 12 Mar 2007 */
8389 #endif
8390
8391 if( ParamIndex != NULL ) ParamIndex[icoef] = ibrick ;
8392 ParamStim [icoef] = option_data->stim_base[istim] ? 0
8393 : istim+1 ;
8394 ParamLabel[icoef] = strdup(brick_label) ;
8395
8396 if( coef_dset != NULL ){
8397 cbuck++ ;
8398 attach_sub_brick( coef_dset , cbuck , volume , nxyz ,
8399 brick_type, brick_label, 0, 0, 0, NULL);
8400 }
8401
8402 /*----- Stimulus t-stat -----*/
8403 if (cout && option_data->tout && (!option_data->stim_base[istim] || bout) )
8404 {
8405 ibrick++;
8406 brick_type = FUNC_TT_TYPE;
8407 dof = N - p;
8408 #ifdef USE_OLD_LABELS
8409 sprintf (brick_label, "%s[%d] t-st", label, ilag);
8410 #else
8411 sprintf( brick_label, "%s_Tstat" , COLUMN_LABEL(icoef) ) ;
8412 #endif
8413 volume = tcoef_vol[icoef];
8414 attach_sub_brick (new_dset, ibrick, volume, nxyz,
8415 brick_type, brick_label, dof, 0, 0, bar);
8416 }
8417 }
8418
8419 icoef++;
8420 }
8421
8422 /*----- Stimulus R^2 stat -----*/
8423 if( cout && option_data->rout
8424 && (!option_data->stim_base[istim] || bout) )
8425 {
8426 ibrick++;
8427 brick_type = FUNC_BT_TYPE;
8428 ndof = 0.5*(itop - ibot + 1) ;
8429 ddof = 0.5*(N - p);
8430 #ifdef USE_OLD_LABELS
8431 sprintf (brick_label, "%s R^2", label);
8432 #else
8433 sprintf( brick_label, "%s_R^2" , label ) ;
8434 #endif
8435 volume = rpart_vol[istim];
8436 attach_sub_brick (new_dset, ibrick, volume, nxyz,
8437 brick_type, brick_label, 0, ndof,ddof, bar);
8438 }
8439
8440 /*----- Stimulus F-stat -----*/
8441 if( cout && option_data->fout
8442 && (!option_data->stim_base[istim] || bout) )
8443 {
8444 ibrick++;
8445 brick_type = FUNC_FT_TYPE;
8446 ndof = itop - ibot + 1 ;
8447 ddof = N - p;
8448 #ifdef USE_OLD_LABELS
8449 sprintf (brick_label, "%s F-stat", label);
8450 #else
8451 sprintf( brick_label, "%s_Fstat" , label ) ;
8452 #endif
8453 volume = fpart_vol[istim];
8454 attach_sub_brick (new_dset, ibrick, volume, nxyz,
8455 brick_type, brick_label, 0, ndof, ddof, bar);
8456 }
8457
8458 } /* End loop over stim functions */
8459
8460 } /* if (! option_data->nocout) */
8461
8462 if( coef_dset != NULL ){
8463 DSET_write(coef_dset) ;
8464 if( !option_data->quiet )
8465 INFO_message("Wrote cbucket to %s",DSET_BRIKNAME(coef_dset)) ;
8466 DSET_delete(coef_dset) ; coef_dset = NULL ;
8467 }
8468
8469
8470 /*----- 25 Jul 2004: save matrix info (etc.) to dataset header -----*/
8471
8472 if( xsave ) XSAVE_output( DSET_PREFIX(new_dset) ) ;
8473
8474 /*----- General linear test statistics -----*/
8475 for (iglt = 0; iglt < num_glt; iglt++)
8476 {
8477 strcpy (label, option_data->glt_label[iglt]);
8478
8479 /*----- Loop over rows of GLT matrix -----*/
8480 for (ilc = 0; ilc < glt_rows[iglt]; ilc++)
8481 {
8482 /*----- GLT coefficient -----*/
8483 ibrick++;
8484 brick_type = FUNC_FIM_TYPE;
8485 #ifdef USE_OLD_LABELS
8486 sprintf (brick_label, "%s LC[%d] coef", label, ilc);
8487 #else
8488 sprintf (brick_label, "%s_GLT%c%d_Coef", label, EDIT_get_index_prefix() , ilc);
8489 #endif
8490 volume = glt_coef_vol[iglt][ilc];
8491 attach_sub_brick (new_dset, ibrick, volume, nxyz,
8492 brick_type, brick_label, 0, 0, 0, bar);
8493
8494 /*----- GLT t-stat -----*/
8495 if (option_data->tout)
8496 {
8497 ibrick++;
8498 brick_type = FUNC_TT_TYPE;
8499 dof = N - p;
8500 #ifdef USE_OLD_LABELS
8501 sprintf (brick_label, "%s LC[%d] t-st", label, ilc);
8502 #else
8503 sprintf (brick_label, "%s_GLT%c%d_Tstat", label, EDIT_get_index_prefix() , ilc);
8504 #endif
8505 volume = glt_tcoef_vol[iglt][ilc];
8506 attach_sub_brick (new_dset, ibrick, volume, nxyz,
8507 brick_type, brick_label, dof, 0, 0, bar);
8508 }
8509 }
8510
8511 /*----- GLT R^2 stat -----*/
8512 if (option_data->rout)
8513 {
8514 ibrick++;
8515 brick_type = FUNC_BT_TYPE;
8516 ndof = 0.5 * glt_rows[iglt];
8517 ddof = 0.5 * (N - p);
8518 #ifdef USE_OLD_LABELS
8519 sprintf (brick_label, "%s R^2", label);
8520 #else
8521 sprintf (brick_label, "%s_GLT_R^2", label);
8522 #endif
8523 volume = glt_rstat_vol[iglt];
8524 attach_sub_brick (new_dset, ibrick, volume, nxyz,
8525 brick_type, brick_label, 0, ndof,ddof, bar);
8526 }
8527
8528 /*----- GLT F-stat -----*/
8529 if (option_data->fout)
8530 {
8531 ibrick++;
8532 brick_type = FUNC_FT_TYPE;
8533 ndof = glt_rows[iglt];
8534 ddof = N - p;
8535 #ifdef USE_OLD_LABELS
8536 sprintf (brick_label, "%s F-stat", label);
8537 #else
8538 sprintf (brick_label, "%s_GLT_Fstat", label);
8539 #endif
8540 volume = glt_fstat_vol[iglt];
8541 attach_sub_brick (new_dset, ibrick, volume, nxyz,
8542 brick_type, brick_label, 0, ndof, ddof, bar);
8543 }
8544
8545 } /* End loop over general linear tests */
8546
8547
8548 /*----- Statistics for full model -----*/
8549 if (option_data->full_first) ibrick = -1;
8550
8551 /*----- Full model MSE -----*/
8552 if (option_data->vout)
8553 {
8554 ibrick++;
8555 brick_type = FUNC_FIM_TYPE;
8556 #ifdef USE_OLD_LABELS
8557 sprintf (brick_label, "Full MSE");
8558 #else
8559 sprintf (brick_label, "Full_MSE");
8560 #endif
8561 volume = mse_vol;
8562 attach_sub_brick (new_dset, ibrick, volume, nxyz,
8563 brick_type, brick_label, 0, 0, 0, bar);
8564 }
8565
8566 /*----- Full model R^2 -----*/
8567 if (option_data->rout)
8568 {
8569 ibrick++;
8570 brick_type = FUNC_BT_TYPE;
8571 ndof = 0.5*(p - q);
8572 ddof = 0.5*(N - p);
8573 #ifdef USE_OLD_LABELS
8574 sprintf (brick_label, "Full R^2");
8575 #else
8576 sprintf (brick_label, "Full_R^2");
8577 #endif
8578 volume = rfull_vol;
8579 attach_sub_brick (new_dset, ibrick, volume, nxyz,
8580 brick_type, brick_label, 0, ndof,ddof, bar);
8581 }
8582
8583 /*----- Full model F-stat -----*/
8584 if (option_data->do_fullf)
8585 {
8586 ibrick++;
8587 brick_type = FUNC_FT_TYPE;
8588 ndof = p - q;
8589 ddof = N - p;
8590 #ifdef USE_OLD_LABELS
8591 sprintf (brick_label, "Full F-stat");
8592 #else
8593 sprintf (brick_label, "Full_Fstat");
8594 #endif
8595 volume = ffull_vol;
8596 attach_sub_brick (new_dset, ibrick, volume, nxyz,
8597 brick_type, brick_label, 0, ndof, ddof, bar);
8598 }
8599
8600
8601 /*----- write bucket data set -----*/
8602
8603 if( do_FDR && !AFNI_noenv("AFNI_AUTOMATIC_FDR") )
8604 ibrick = THD_create_all_fdrcurves( new_dset ) ;
8605 else
8606 ibrick = 0 ;
8607
8608 THD_load_statistics (new_dset);
8609 THD_write_3dim_dataset( NULL,NULL , new_dset , True ) ;
8610 if (! option_data->quiet){
8611 INFO_message("Wrote bucket dataset into %s", DSET_BRIKNAME(new_dset));
8612 if( ibrick > 0 )
8613 ININFO_message("created %d FDR curves in bucket header",ibrick) ;
8614 }
8615
8616
8617 /*----- deallocate memory -----*/
8618 THD_delete_3dim_dataset( new_dset , False ) ; new_dset = NULL ;
8619
8620 }
8621
8622
8623 /*---------------------------------------------------------------------------*/
8624 /*
8625 Write one time series array to specified file.
8626 */
8627
write_one_ts(char * prefix,int ts_length,float ** vol_array)8628 void write_one_ts
8629 (
8630 char * prefix, /* output time series prefix name */
8631 int ts_length, /* length of time series data */
8632 float ** vol_array /* output time series volume data */
8633 )
8634
8635 {
8636 char filename[THD_MAX_NAME]; /* output time series file name */
8637 int it; /* time index */
8638 FILE * outfile = NULL; /* file pointer */
8639
8640 if( vol_array == NULL )
8641 ERROR_message("Can't output 1D file '%s' -- data array is NULL!",prefix);
8642
8643 /*----- Create output filename by appending ".1D" -----*/
8644
8645 if( strstr(prefix,"1D") == NULL )
8646 sprintf (filename, "%s.1D", prefix);
8647 else
8648 sprintf (filename, "%s" , prefix);
8649
8650 outfile = fopen (filename, "w");
8651
8652
8653 /*----- 'Volume' data consists of just one voxel -----*/
8654 for (it = 0; it < ts_length; it++)
8655 {
8656 fprintf (outfile, "%f \n",
8657 (vol_array[it] != NULL) ? vol_array[it][0] : 0.0 ) ;
8658 }
8659
8660
8661 fclose (outfile);
8662 }
8663
8664
8665 /*---------------------------------------------------------------------------*/
8666 /*
8667 Write out the user requested output files.
8668 */
8669
output_results(int argc,char ** argv,DC_options * option_data,float ** coef_vol,float ** scoef_vol,float ** tcoef_vol,float ** fpart_vol,float ** rpart_vol,float * mse_vol,float * ffull_vol,float * rfull_vol,float *** glt_coef_vol,float *** glt_tcoef_vol,float ** glt_fstat_vol,float ** glt_rstat_vol,float ** fitts_vol,float ** errts_vol)8670 void output_results
8671 (
8672 int argc, /* number of input arguments */
8673 char ** argv, /* array of input arguments */
8674 DC_options * option_data, /* deconvolution algorithm options */
8675
8676 float ** coef_vol, /* array of volumes of signal model parameters */
8677 float ** scoef_vol, /* array of volumes of parameter std. devs. */
8678 float ** tcoef_vol, /* array of volumes of parameter t-statistics */
8679 float ** fpart_vol, /* array of volumes of partial F-statistics */
8680 float ** rpart_vol, /* array of volumes of partial R^2 statistics */
8681 float * mse_vol, /* volume of full model mean square error */
8682 float * ffull_vol, /* volume of full model F-statistics */
8683 float * rfull_vol, /* volume of full model R^2 statistics */
8684 float *** glt_coef_vol, /* volumes for GLT linear combinations */
8685 float *** glt_tcoef_vol, /* volumes for GLT t-statistics */
8686 float ** glt_fstat_vol, /* volumes for GLT F-statistics */
8687 float ** glt_rstat_vol, /* volumes for GLT R^2 statistics */
8688 float ** fitts_vol, /* volumes for full model fit to input data */
8689 float ** errts_vol /* volumes for residual errors */
8690 )
8691
8692 {
8693 int qp; /* number of poly. trend baseline parameters */
8694 int q; /* number of baseline model parameters */
8695 int p; /* number of full model parameters */
8696 int polort; /* degree of polynomial for baseline model */
8697 int num_stimts; /* number of stimulus time series */
8698 int * min_lag; /* minimum time delay for impulse response */
8699 int * max_lag; /* maximum time delay for impulse response */
8700 int * nptr; /* number of stim fn. time points per TR */
8701 int ib; /* sub-brick index */
8702 int is; /* stimulus index */
8703 int ts_length; /* length of impulse reponse function */
8704 int nt; /* number of images in input 3D+time dataset */
8705 int nxyz; /* number of voxels */
8706
8707
8708 /*----- Initialize local variables -----*/
8709 polort = option_data->polort;
8710 qp = option_data->qp;
8711 q = option_data->q;
8712 p = option_data->p;
8713 num_stimts = option_data->num_stimts;
8714 min_lag = option_data->stim_minlag;
8715 max_lag = option_data->stim_maxlag;
8716 nptr = option_data->stim_nptr;
8717 nt = option_data->nt;
8718 nxyz = option_data->nxyz;
8719
8720
8721 /*----- Write the bucket dataset -----*/
8722 if (option_data->bucket_filename != NULL){
8723 if (nxyz > 1)
8724 write_bucket_data (argc, argv, option_data, coef_vol, tcoef_vol,
8725 fpart_vol, rpart_vol, mse_vol, ffull_vol, rfull_vol,
8726 glt_coef_vol, glt_tcoef_vol, glt_fstat_vol, glt_rstat_vol);
8727 else
8728 write_one_ts (option_data->bucket_filename, p, coef_vol);
8729 }
8730
8731 /*----- Write the impulse response function 3D+time dataset -----*/
8732 ib = qp;
8733 for (is = 0; is < num_stimts; is++)
8734 {
8735 if( basis_stim[is] != NULL ){ /* until later */
8736 if( option_data->iresp_filename[is] != NULL ) {
8737 if( option_data->input_filename )
8738 basis_write_iresp( argc , argv , option_data ,
8739 basis_stim[is] , basis_dtout ,
8740 coef_vol+ib ,
8741 option_data->iresp_filename[is] ) ;
8742 else if( option_data->input1D_filename )
8743 basis_write_iresp_1D( argc , argv , option_data ,
8744 basis_stim[is] , basis_dtout ,
8745 coef_vol+ib ,
8746 option_data->iresp_filename[is] ) ;
8747 }
8748 ib += basis_stim[is]->nparm ;
8749 continue ;
8750 }
8751
8752 /* old style iresp: each coefficent is a response */
8753
8754 ts_length = max_lag[is] - min_lag[is] + 1;
8755 if (option_data->iresp_filename[is] != NULL)
8756 {
8757 /*----- If requested, time shift the impulse response -----*/
8758 if ((option_data->tshift) && (nptr[is] == 1) && (nxyz > 1))
8759 cubic_spline (option_data, ts_length, coef_vol+ib);
8760
8761 if (nxyz > 1)
8762 write_ts_array (argc, argv, option_data, ts_length,
8763 nptr[is], option_data->tshift, coef_vol+ib,
8764 option_data->iresp_filename[is]);
8765 else
8766 write_one_ts (option_data->iresp_filename[is],
8767 ts_length, coef_vol+ib);
8768 }
8769 ib += ts_length;
8770 }
8771
8772
8773 /*----- Write the standard deviation 3D+time dataset -----*/
8774 ib = qp;
8775 for (is = 0; is < num_stimts; is++)
8776 {
8777 if( basis_stim[is] != NULL ){ /* until later */
8778 if( option_data->sresp_filename[is] != NULL ) {
8779 if( option_data->input_filename )
8780 basis_write_sresp( argc , argv , option_data ,
8781 basis_stim[is] , basis_dtout ,
8782 mse_vol , ib , XtXinv ,
8783 option_data->sresp_filename[is] ) ;
8784 /* 19 Aug 2011 [rickr] */
8785 else if( option_data->input1D_filename )
8786 basis_write_sresp_1D( argc , argv , option_data ,
8787 basis_stim[is] , basis_dtout ,
8788 mse_vol , ib , XtXinv ,
8789 option_data->sresp_filename[is] ) ;
8790 }
8791 ib += basis_stim[is]->nparm ;
8792 continue ;
8793 }
8794
8795 /* old style iresp: each coef is a response, so coef var is what we want */
8796
8797 ts_length = max_lag[is] - min_lag[is] + 1;
8798 if (option_data->sresp_filename[is] != NULL){
8799 if (nxyz > 1){
8800 write_ts_array (argc, argv, option_data, ts_length,
8801 nptr[is], 0, scoef_vol+ib,
8802 option_data->sresp_filename[is]);
8803 } else {
8804 write_one_ts (option_data->sresp_filename[is],
8805 ts_length, scoef_vol+ib);
8806 }
8807 }
8808 ib += ts_length;
8809 }
8810
8811
8812 /*----- Write the fitted (full model) 3D+time dataset -----*/
8813 if (option_data->fitts_filename != NULL && fitts_vol != NULL){
8814 if (nxyz > 1)
8815 write_ts_array (argc, argv, option_data, nt, 1, 0, fitts_vol,
8816 option_data->fitts_filename);
8817 else
8818 write_one_ts (option_data->fitts_filename, nt, fitts_vol);
8819 }
8820
8821
8822 /*----- Write the residual errors 3D+time dataset -----*/
8823 if (option_data->errts_filename != NULL && errts_vol != NULL){
8824 if (nxyz > 1)
8825 write_ts_array (argc, argv, option_data, nt, 1, 0, errts_vol,
8826 option_data->errts_filename);
8827 else
8828 write_one_ts (option_data->errts_filename, nt, errts_vol);
8829 }
8830
8831 }
8832
8833
8834 /*---------------------------------------------------------------------------*/
8835 #if 0
8836 void terminate_program
8837 (
8838 DC_options ** option_data, /* deconvolution algorithm options */
8839 float *** stimulus, /* stimulus time series arrays */
8840 matrix ** glt_cmat, /* general linear test matrices */
8841
8842 float *** coef_vol, /* array of volumes of signal model parameters */
8843 float *** scoef_vol, /* array of volumes of parameter std. devs. */
8844 float *** tcoef_vol, /* array of volumes of parameter t-statistics */
8845 float *** fpart_vol, /* array of volumes of partial F-statistics */
8846 float *** rpart_vol, /* array of volumes of partial R^2 statistics */
8847 float ** mse_vol, /* volume of full model mean square error */
8848 float ** ffull_vol, /* volume of full model F-statistics */
8849 float ** rfull_vol, /* volume of full model R^2 statistics */
8850
8851 float **** glt_coef_vol, /* volumes for GLT linear combinations */
8852 float **** glt_tcoef_vol, /* volumes for GLT t-statistics */
8853 float *** glt_fstat_vol, /* volumes for GLT F-statistics */
8854 float *** glt_rstat_vol, /* volumes for GLT R^2 statistics */
8855
8856 float *** fitts_vol, /* volumes for full model fit to input data */
8857 float *** errts_vol /* volumes for residual errors */
8858 )
8859
8860 {
8861 int p; /* number of parameters in full model */
8862 int num_stimts; /* number of stimulus time series */
8863 int ip; /* parameter index */
8864 int is; /* stimulus index */
8865 int num_glt; /* number of general linear tests */
8866 int iglt; /* general linear test index */
8867 int * glt_rows; /* number of linear constraints in glt */
8868 int ilc; /* linear combination index */
8869 int it; /* time index */
8870 int nt; /* number of images in input 3D+time dataset */
8871
8872
8873 /*----- Initialize local variables -----*/
8874 if (*option_data == NULL) return;
8875 p = (*option_data)->p;
8876 num_stimts = (*option_data)->num_stimts;
8877 num_glt = (*option_data)->num_glt;
8878 glt_rows = (*option_data)->glt_rows;
8879 nt = (*option_data)->nt;
8880
8881
8882 /*----- Deallocate memory for option data -----*/
8883 free (*option_data); *option_data = NULL;
8884
8885
8886 /*----- Deallocate memory for stimulus time series -----*/
8887 if (*stimulus != NULL)
8888 {
8889 for (is = 0; is < num_stimts; is++)
8890 if ((*stimulus)[is] != NULL)
8891 { free ((*stimulus)[is]); (*stimulus)[is] = NULL; }
8892 free (*stimulus); *stimulus = NULL;
8893 }
8894
8895
8896 /*----- Deallocate memory for general linear test matrices -----*/
8897 if (*glt_cmat != NULL)
8898 {
8899 for (iglt = 0; iglt < num_glt; iglt++)
8900 matrix_destroy (&((*glt_cmat)[iglt]));
8901 free (*glt_cmat); *glt_cmat = NULL;
8902 }
8903
8904
8905 /*----- Deallocate space for volume data -----*/
8906 if (*coef_vol != NULL)
8907 {
8908 for (ip = 0; ip < p; ip++)
8909 if ((*coef_vol)[ip] != NULL)
8910 { free ((*coef_vol)[ip]); (*coef_vol)[ip] = NULL; }
8911 free (*coef_vol); *coef_vol = NULL;
8912 }
8913
8914 if (*scoef_vol != NULL)
8915 {
8916 for (ip = 0; ip < p; ip++)
8917 if ((*scoef_vol)[ip] != NULL)
8918 { free ((*scoef_vol)[ip]); (*scoef_vol)[ip] = NULL; }
8919 free (*scoef_vol); *scoef_vol = NULL;
8920 }
8921
8922 if (*tcoef_vol != NULL)
8923 {
8924 for (ip = 0; ip < p; ip++)
8925 if ((*tcoef_vol)[ip] != NULL)
8926 { free ((*tcoef_vol)[ip]); (*tcoef_vol)[ip] = NULL; }
8927 free (*tcoef_vol); *tcoef_vol = NULL;
8928 }
8929
8930 if (*fpart_vol != NULL)
8931 {
8932 for (is = 0; is < num_stimts; is++)
8933 if ((*fpart_vol)[is] != NULL)
8934 { free ((*fpart_vol)[is]); (*fpart_vol)[is] = NULL; }
8935 free (*fpart_vol); *fpart_vol = NULL;
8936 }
8937
8938 if (*rpart_vol != NULL)
8939 {
8940 for (is = 0; is < num_stimts; is++)
8941 if ((*rpart_vol)[is] != NULL)
8942 { free ((*rpart_vol)[is]); (*rpart_vol)[is] = NULL; }
8943 free (*rpart_vol); *rpart_vol = NULL;
8944 }
8945
8946 if (*mse_vol != NULL) { free (*mse_vol); *mse_vol = NULL; }
8947 if (*ffull_vol != NULL) { free (*ffull_vol); *ffull_vol = NULL; }
8948 if (*rfull_vol != NULL) { free (*rfull_vol); *rfull_vol = NULL; }
8949
8950
8951 /*----- Deallocate space for general linear test results -----*/
8952 if (*glt_coef_vol != NULL)
8953 {
8954 for (iglt = 0; iglt < num_glt; iglt++)
8955 if ((*glt_coef_vol)[iglt] != NULL)
8956 {
8957 for (ilc = 0; ilc < glt_rows[iglt]; ilc++)
8958 if ((*glt_coef_vol)[iglt][ilc] != NULL)
8959 {
8960 free ((*glt_coef_vol)[iglt][ilc]);
8961 (*glt_coef_vol)[iglt][ilc] = NULL;
8962 }
8963 free ((*glt_coef_vol)[iglt]); (*glt_coef_vol)[iglt] = NULL;
8964 }
8965 free (*glt_coef_vol); *glt_coef_vol = NULL;
8966 }
8967
8968 if (*glt_tcoef_vol != NULL)
8969 {
8970 for (iglt = 0; iglt < num_glt; iglt++)
8971 if ((*glt_tcoef_vol)[iglt] != NULL)
8972 {
8973 for (ilc = 0; ilc < glt_rows[iglt]; ilc++)
8974 if ((*glt_tcoef_vol)[iglt][ilc] != NULL)
8975 {
8976 free ((*glt_tcoef_vol)[iglt][ilc]);
8977 (*glt_tcoef_vol)[iglt][ilc] = NULL;
8978 }
8979 free ((*glt_tcoef_vol)[iglt]); (*glt_tcoef_vol)[iglt] = NULL;
8980 }
8981 free (*glt_tcoef_vol); *glt_tcoef_vol = NULL;
8982 }
8983
8984 if (*glt_fstat_vol != NULL)
8985 {
8986 for (iglt = 0; iglt < num_glt; iglt++)
8987 if ((*glt_fstat_vol)[iglt] != NULL)
8988 { free ((*glt_fstat_vol)[iglt]); (*glt_fstat_vol)[iglt] = NULL; }
8989 free (*glt_fstat_vol); *glt_fstat_vol = NULL;
8990 }
8991
8992 if (*glt_rstat_vol != NULL)
8993 {
8994 for (iglt = 0; iglt < num_glt; iglt++)
8995 if ((*glt_rstat_vol)[iglt] != NULL)
8996 { free ((*glt_rstat_vol)[iglt]); (*glt_rstat_vol)[iglt] = NULL; }
8997 free (*glt_rstat_vol); *glt_rstat_vol = NULL;
8998 }
8999
9000
9001 /*----- Deallocate space for fitted time series and residual errors -----*/
9002 if (*fitts_vol != NULL)
9003 {
9004 for (it = 0; it < nt; it++)
9005 { free ((*fitts_vol)[it]); (*fitts_vol)[it] = NULL; }
9006 free (*fitts_vol); *fitts_vol = NULL;
9007 }
9008
9009 if (*errts_vol != NULL)
9010 {
9011 for (it = 0; it < nt; it++)
9012 { free ((*errts_vol)[it]); (*errts_vol)[it] = NULL; }
9013 free (*errts_vol); *errts_vol = NULL;
9014 }
9015
9016 }
9017 #endif
9018
9019
9020 /*---------------------------------------------------------------------------*/
9021 /*---------------------------------------------------------------------------*/
9022
main(int argc,char ** argv)9023 int main
9024 (
9025 int argc, /* number of input arguments */
9026 char ** argv /* array of input arguments */
9027 )
9028
9029 {
9030 DC_options * option_data; /* deconvolution algorithm options */
9031 THD_3dim_dataset * dset_time = NULL; /* input 3D+time data set */
9032 byte * mask_vol = NULL; /* mask volume */
9033 float * fmri_data = NULL; /* input fMRI time series data */
9034 int fmri_length; /* length of fMRI time series */
9035 float * censor_array = NULL; /* input censor time series array */
9036 int censor_length; /* length of censor time series */
9037 int * good_list = NULL; /* list of usable time points */
9038 int * block_list = NULL; /* list of block starting points */
9039 int num_blocks; /* number of blocks (runs) */
9040 float ** stimulus = NULL; /* stimulus time series arrays */
9041 int * stim_length = NULL; /* length of stimulus time series */
9042 matrix * glt_cmat = NULL; /* general linear test matrices */
9043
9044 float ** coef_vol = NULL; /* array of volumes for model parameters */
9045 float ** scoef_vol = NULL; /* array of volumes for parameter std. devs. */
9046 float ** tcoef_vol = NULL; /* array of volumes for parameter t-statistics */
9047 float ** fpart_vol = NULL; /* array of volumes of partial F-statistics */
9048 float ** rpart_vol = NULL; /* array of volumes of partial R^2 stats. */
9049
9050 float * mse_vol = NULL; /* volume of full model mean square error */
9051 float * ffull_vol = NULL; /* volume of full model F-statistics */
9052 float * rfull_vol = NULL; /* volume of full model R^2 stats. */
9053
9054 float *** glt_coef_vol = NULL; /* volumes for GLT linear combinations */
9055 float *** glt_tcoef_vol = NULL; /* volumes for GLT t-statistics */
9056 float ** glt_fstat_vol = NULL; /* volumes for GLT F-statistics */
9057 float ** glt_rstat_vol = NULL; /* volumes for GLT R^2 stats. */
9058
9059 float ** fitts_vol = NULL; /* volumes for full model fit to input data */
9060 float ** errts_vol = NULL; /* volumes for residual errors */
9061
9062
9063 #ifdef FLOATIZE
9064 /*----- force the user to acknowledge the riskiness of his behavior -----*/
9065 if( argc < 2 || strcmp(argv[1],"-OK") != 0 ){
9066 fprintf(stderr,"**\n"
9067 "** 3dDeconvolve_f is now disabled by default.\n"
9068 "** It is dangerous, due to roundoff problems.\n"
9069 "** Please use 3dDeconvolve from now on!\n"
9070 "**\n"
9071 "** HOWEVER, if you insist on using 3dDeconvolve_f, then:\n"
9072 "** + Use '-OK' as the first command line option.\n"
9073 "** + Check the matrix condition number;\n"
9074 "** if it is greater than 100, BEWARE!\n"
9075 "**\n"
9076 "** RWCox - July 2004\n"
9077 "**\n"
9078 ) ;
9079 exit(0) ;
9080 }
9081 #endif
9082
9083 #ifdef USING_MCW_MALLOC
9084 enable_mcw_malloc() ;
9085 #endif
9086 mainENTRY(PROGRAM_NAME " main") ; AFNI_process_environ(NULL) ; machdep() ;
9087 SET_message_file( PROGRAM_NAME ".err" ) ;
9088
9089 index_prefix = EDIT_get_index_prefix() ;
9090
9091 commandline = tross_commandline( PROGRAM_NAME , argc , argv ) ;
9092
9093 /*----- start the elapsed time counter -----*/
9094 (void) COX_clock_time() ;
9095
9096 /*----- Program initialization -----*/
9097 initialize_program (argc, argv, &option_data, &dset_time, &mask_vol,
9098 &fmri_data, &fmri_length, &censor_array, &censor_length, &good_list,
9099 &block_list, &num_blocks, &stimulus, &stim_length, &glt_cmat,
9100 &coef_vol, &scoef_vol, &tcoef_vol, &fpart_vol, &rpart_vol,
9101 &mse_vol, &ffull_vol, &rfull_vol, &glt_coef_vol, &glt_tcoef_vol,
9102 &glt_fstat_vol, &glt_rstat_vol, &fitts_vol, &errts_vol);
9103
9104 if( xrestore ){ /* 26 Jul 2004 - very special operations */
9105 do_xrestore_stuff( argc,argv , option_data ) ;
9106 exit(0) ;
9107 }
9108
9109
9110 /*----- Perform deconvolution -----*/
9111 calculate_results (option_data, dset_time, mask_vol, fmri_data, fmri_length,
9112 good_list, block_list, num_blocks, stimulus, stim_length,
9113 glt_cmat, coef_vol, scoef_vol, tcoef_vol, fpart_vol,
9114 rpart_vol, mse_vol, ffull_vol, rfull_vol, glt_coef_vol, glt_tcoef_vol,
9115 glt_fstat_vol, glt_rstat_vol, fitts_vol, errts_vol);
9116
9117
9118 /*----- Deallocate memory for input datasets -----*/
9119 if (dset_time != NULL)
9120 { THD_delete_3dim_dataset (dset_time, False); dset_time = NULL; }
9121 #if 0
9122 if (mask_vol != NULL){ free (mask_vol); mask_vol = NULL; }
9123 #endif
9124
9125
9126 /*----- Write requested output files -----*/
9127 if (!option_data->nodata)
9128 output_results (argc, argv, option_data, coef_vol, scoef_vol, tcoef_vol,
9129 fpart_vol, rpart_vol, mse_vol, ffull_vol, rfull_vol,
9130 glt_coef_vol, glt_tcoef_vol, glt_fstat_vol, glt_rstat_vol,
9131 fitts_vol, errts_vol);
9132
9133
9134 #if 0
9135 /*----- Terminate program -----*/
9136 terminate_program (&option_data, &stimulus, &glt_cmat, &coef_vol, &scoef_vol,
9137 &tcoef_vol, &fpart_vol, &rpart_vol, & mse_vol, &ffull_vol,
9138 &rfull_vol, &glt_coef_vol, &glt_tcoef_vol, &glt_fstat_vol,
9139 &glt_rstat_vol, &fitts_vol, &errts_vol);
9140 #endif
9141
9142 if( proc_use_jobs == 1 && verb ){ /* output requested - 2003.08.15 [rickr] */
9143 INFO_message("Program finished; elapsed time=%.3f",COX_clock_time());
9144 }
9145 #ifndef FLOATIZE
9146 if( proc_numjob == 1 && verb ){ /* 16 Jan 2004: print operation count */
9147 double fv=get_matrix_flops() , fd=get_matrix_dotlen() ;
9148 if( fv > 0.0 && fd > 0.0 )
9149 INFO_message("#Flops=%g Average Dot Product=%g",fv,fd) ;
9150 }
9151 #endif
9152
9153 exit(0);
9154 }
9155
9156 /*============================================================================*/
9157 /*--------- Grayplot X matrix columns to an image file [21 Jul 2004] ---------*/
9158 /*----------------------------------------------------------------------------*/
9159 #include "coxplot.h"
9160
9161 #define TSGRAY_SEPARATE_YSCALE (1<<0)
9162 #define TSGRAY_FLIP_XY (1<<1)
9163
9164 /*-----------------------------------------------------------------
9165 Plot some timeseries in grayscale
9166 npt = number of points in each series
9167 nts = number of series
9168 ymask = operation modifier:
9169 TSGRAY_SEPARATE_YSCALE
9170 TSGRAY_FLIP_XY
9171 y[j][i] = i-th point in j-th timeseries,
9172 for i=0..npt-1, j=0..nts-1
9173 -------------------------------------------------------------------*/
9174
PLOT_tsgray(int npt,int nts,int ymask,float ** y)9175 MEM_plotdata * PLOT_tsgray( int npt , int nts , int ymask , float **y )
9176 {
9177 MEM_plotdata *mp ;
9178 float ybot,ytop , yfac , dx,dy , val ;
9179 int ii,jj , flipxy ;
9180 char str[32] ;
9181 int sepscl ;
9182 float boxr=1.0,boxg=0.9,boxb=0.0 ;
9183 char *eee ;
9184 int dobox=1 ;
9185
9186 if( npt < 2 || nts < 1 || y == NULL ) return NULL ;
9187
9188 eee = my_getenv( "AFNI_XJPEG_COLOR" ) ;
9189 if( eee != NULL ){
9190 float rf=-1.0, gf=-1.0 , bf=-1.0 ;
9191 sscanf( eee , "rgbi:%f/%f/%f" , &rf,&gf,&bf ) ;
9192 if( rf >= 0.0 && rf <= 1.0 && gf >= 0.0 && gf <= 1.0 && bf >= 0.0 && bf <= 1.0 ){
9193 boxr = rf ; boxg = gf ; boxb = bf ;
9194 }
9195 if( NOISH(eee) ) dobox = 0 ; /* don't do boxes */
9196 }
9197
9198 /* find range of all the data */
9199
9200 ybot = ytop = y[0][0] ;
9201 for( jj=0 ; jj < nts ; jj++ ){
9202 for( ii=0 ; ii < npt ; ii++ ){
9203 val = y[jj][ii] ;
9204 if( ybot > val ) ybot = val ;
9205 else if( ytop < val ) ytop = val ;
9206 }
9207 }
9208 if( ybot >= ytop ) return NULL ; /* data is all the same? */
9209 yfac = 1.0/(ytop-ybot) ;
9210 dx = 0.9999/npt ;
9211 dy = 0.9999/nts ;
9212
9213 create_memplot_surely( "Gplot" , 1.0 ) ;
9214 set_color_memplot( 0.0 , 0.0 , 0.0 ) ;
9215 set_thick_memplot( 0.0 ) ;
9216 set_opacity_memplot( 1.0 ) ;
9217
9218 flipxy = (ymask & TSGRAY_FLIP_XY) != 0 ;
9219 sepscl = (ymask & TSGRAY_SEPARATE_YSCALE) != 0 ;
9220
9221 for( jj=0 ; jj < nts ; jj++ ){
9222
9223 if( sepscl ){
9224 ybot = ytop = y[jj][0] ; /* find range of data */
9225 for( ii=1 ; ii < npt ; ii++ ){
9226 val = y[jj][ii] ;
9227 if( ybot > val ) ybot = val ;
9228 else if( ytop < val ) ytop = val ;
9229 }
9230 if( ybot >= ytop ) yfac = 1.0 ;
9231 else yfac = 1.0/(ytop-ybot) ;
9232 }
9233
9234 for( ii=0 ; ii < npt ; ii++ ){
9235 val = yfac*(ytop-y[jj][ii]) ;
9236 set_color_memplot( val,val,val ) ;
9237 if( flipxy )
9238 plotrect_memplot( ii*dx,jj*dy , (ii+1)*dx,(jj+1)*dy ) ;
9239 else
9240 plotrect_memplot( jj*dy,1.0-ii*dx , (jj+1)*dy,1.0-(ii+1)*dy ) ;
9241 }
9242 }
9243
9244 if( dobox ){
9245 set_color_memplot( boxr, boxg, boxb ) ; /* lines between each column */
9246 set_opacity_memplot( 0.789 ) ;
9247 for( jj=0 ; jj <= nts ; jj++ ){
9248 if( flipxy ){
9249 plotline_memplot( 1.0,jj*dy , 0.0,jj*dy ) ;
9250 } else {
9251 plotline_memplot( jj*dy,1.0 , jj*dy,0.0 ) ;
9252 }
9253 }
9254 }
9255
9256 set_opacity_memplot( 1.0 ) ;
9257 set_color_memplot( 0.0 , 0.0 , 0.0 ) ;
9258 mp = get_active_memplot() ;
9259 return mp ;
9260 }
9261
9262 /*-----------------------------------------------------------------*/
9263
PLOT_matrix_gray(matrix X)9264 MRI_IMAGE * PLOT_matrix_gray( matrix X )
9265 {
9266 int nts=X.cols , npt=X.rows , ii,jj , nxim=2*768 , nyim=2*1024 ;
9267 MEM_plotdata *mp ;
9268 float **xar ;
9269 MRI_IMAGE *im ;
9270 char *eee ;
9271
9272 if( nts < 1 || npt < 2 ) return NULL ;
9273
9274 xar = (float **)malloc( sizeof(float *)*nts ) ;
9275 if( !xar ) {
9276 ERROR_message("PLOT_mg: failed to alloc %d float ptrs", nts);
9277 return NULL;
9278 }
9279 for( jj=0 ; jj < nts ; jj++ ){
9280 xar[jj] = (float *)malloc( sizeof(float)*npt ) ;
9281 if( !xar[jj] ) {
9282 ERROR_message("PLOT_mg: failed to alloc %d floats @jj=%d", npt, jj);
9283 return NULL;
9284 }
9285 for( ii=0 ; ii < npt ; ii++ ) xar[jj][ii] = X.elts[ii][jj] ;
9286 }
9287
9288 mp = PLOT_tsgray( npt , nts , TSGRAY_SEPARATE_YSCALE , xar ) ;
9289
9290 for( jj=0 ; jj < nts ; jj++ ) free((void *)xar[jj]) ;
9291 free((void *)xar) ;
9292
9293 if( mp == NULL ) return NULL ;
9294
9295 eee = my_getenv( "AFNI_XJPEG_IMXY") ;
9296 if( eee != NULL ){
9297 int a=-1, b=-1 ;
9298 sscanf( eee , "%dx%d" , &a,&b ) ;
9299 if( a > 99 && b > 99 ){ nxim = a ; nyim = b ; }
9300 if( a < -1 ) nxim = -a*nts ;
9301 if( b < 0 ) nyim = -b*npt ;
9302 }
9303
9304 im = mri_new( nxim , nyim , MRI_rgb ) ;
9305 memset( MRI_RGB_PTR(im) , 255 , 3*im->nvox ) ; /* whiten it */
9306 memplot_to_RGB_sef( im , mp , 0,0,1 ) ;
9307 delete_memplot( mp ) ;
9308 return im ;
9309 }
9310
9311 /*-----------------------------------------------------------------*/
9312
9313 #undef PLOT_MAX
9314 #define PLOT_MAX 3333
9315
JPEG_matrix_gray(matrix X,char * fname)9316 void JPEG_matrix_gray( matrix X , char *fname )
9317 {
9318 MRI_IMAGE *im ;
9319
9320 if( fname == NULL || *fname == '\0' ) return ;
9321
9322 if( X.cols > PLOT_MAX || X.rows > PLOT_MAX ){ /* 30 Apr 2015 */
9323 WARNING_message("Can't plot %s -- matrix size %dx%d exceeds max=%d",
9324 fname , X.rows , X.cols , PLOT_MAX ) ;
9325 return ;
9326 }
9327
9328 im = PLOT_matrix_gray( X ) ;
9329 if( im == NULL ){
9330 WARNING_message("Can't plot %s -- internal error!",fname) ;
9331 return ;
9332 }
9333
9334 mri_write_jpg( fname , im ) ;
9335
9336 if( verb ) INFO_message("Wrote matrix image to file %s",fname) ;
9337 mri_free(im) ; return ;
9338 }
9339
9340 /*----------------------------------------------------------------------------*/
9341 /*! Save matrix to a .1D text file */
9342
ONED_matrix_save(matrix X,char * fname,void * xd,int Ngl,int * gl,matrix * Xff,int nbl,int * bl,void * gs,void * ss)9343 void ONED_matrix_save( matrix X , char *fname , void *xd , int Ngl, int *gl,
9344 matrix *Xff , int nbl, int *bl , void *gs, void *ss )
9345 {
9346 int nx=X.rows , ny=X.cols , ii,jj,kk ;
9347 column_metadata *cd = (column_metadata *)xd ;
9348 matrix Xf ; int nxf=0,nyf ;
9349 glt_stuff *gst = (glt_stuff *) gs ;
9350 stimlabel_stuff *sst = (stimlabel_stuff *)ss ;
9351
9352 if( fname == NULL || *fname == '\0' ) return ;
9353
9354 if( Xff != NULL ){
9355 Xf = *Xff ; nxf = Xf.rows ; nyf = Xf.cols ;
9356 if( nyf != ny ){
9357 WARNING_message("X matrix save: ncol(X)=%d but ncol(Xf)=%d ?",ny,nyf) ;
9358 nxf = 0 ;
9359 }
9360 }
9361
9362 if( cd == NULL ){ /*---- standard save, plain text ----*/
9363
9364 MRI_IMAGE *xim = mri_new( nx , ny , MRI_float ) ;
9365 float *xar = MRI_FLOAT_PTR(xim) ;
9366
9367 for( jj=0 ; jj < ny ; jj++ )
9368 for( ii=0 ; ii < nx ; ii++ ) xar[ii+jj*nx] = X.elts[ii][jj] ;
9369 if( THD_is_file(fname) ) remove(fname) ; /* 09 Mar 2007 */
9370 mri_write_1D(fname,xim) ; mri_free(xim) ;
9371
9372 } else { /*---- save with NIML information ----*/
9373
9374 NI_element *nel ; NI_stream ns ; MTYPE *col ;
9375 char *lab=NULL,lll[128] ;
9376
9377 nel = NI_new_data_element( "matrix" , nx ) ;
9378 col = (MTYPE *)malloc(sizeof(MTYPE)*nx) ;
9379 for( jj=0 ; jj < ny ; jj++ ){
9380 for( ii=0 ; ii < nx ; ii++ ) col[ii] = X.elts[ii][jj] ;
9381 NI_add_column( nel , NI_MTYPE , col ) ;
9382 strcpy( lll , (jj < ncoldat) ? cd[jj].name : "cens" ) ;
9383 for( ii=0 ; lll[ii] != '\0' ; ii++ ) if( isspace(lll[ii]) ) lll[ii]='_';
9384 if( jj < ny-1 ) strcat(lll," ; ") ;
9385 lab = THD_zzprintf( lab , "%s" , lll ) ;
9386 }
9387 NI_set_attribute( nel , "ColumnLabels" , lab ) ;
9388 free((void *)col) ; free((void *)lab) ; lab = NULL ;
9389 #if 0
9390 for( jj=0 ; jj < ny ; jj++ ){
9391 sprintf(lll,"%u",cd[jj].mask) ; if( jj < ny-1 ) strcat(lll,";") ;
9392 lab = THD_zzprintf( lab , "%s" , lll ) ;
9393 }
9394 NI_set_attribute( nel,"ColumnMasks",lab ); free((void *)lab); lab = NULL;
9395 #endif
9396 #if 1
9397 { NI_int_array iar ;
9398 iar.num = ny ; iar.ar = (int *)malloc(sizeof(int)*ny) ;
9399 for( jj=0 ; jj < ny ; jj++ ) iar.ar[jj] = cd[jj].group ;
9400 lab = NI_encode_int_list( &iar , "," ) ;
9401 NI_set_attribute( nel,"ColumnGroups",lab ); NI_free((void *)lab); lab = NULL;
9402 }
9403 #endif
9404 #if 1
9405 lab = THD_zzprintf( lab , "%g" , basis_TR ) ;
9406 NI_set_attribute( nel, "RowTR", lab ); free((void *)lab); lab = NULL;
9407 #endif
9408 #if 1
9409 if( Ngl > 0 ){
9410 NI_int_array iar ;
9411 iar.num = Ngl ;
9412 if( gl != NULL ) iar.ar = gl ;
9413 else {
9414 iar.ar = (int *)malloc(sizeof(int)*Ngl) ;
9415 for( jj=0 ; jj < Ngl ; jj++ ) iar.ar[jj] = jj ;
9416 }
9417 lab = NI_encode_int_list( &iar , "," ) ;
9418 NI_set_attribute( nel, "GoodList", lab ); NI_free((void *)lab); lab = NULL;
9419 if( iar.ar != gl ) free((void *)iar.ar) ;
9420 }
9421 if( nxf > 0 ){
9422 sprintf(lll,"%d",nxf) ;
9423 NI_set_attribute( nel , "NRowFull" , lll ) ;
9424 }
9425 #endif
9426 #if 1
9427 if( nbl > 0 && bl != NULL ){ /* Bastille Day, 2008 */
9428 NI_int_array iar ;
9429 iar.num = nbl ;
9430 iar.ar = bl ;
9431 lab = NI_encode_int_list( &iar , "," ) ;
9432 NI_set_attribute( nel, "RunStart", lab ); NI_free((void *)lab); lab = NULL;
9433 }
9434 #endif
9435 #if 1
9436 if( sst != NULL && sst->nstim > 0 ){ /* 31 Jul 2008 */
9437 NI_int_array iar ;
9438 sprintf(lll,"%d",sst->nstim) ;
9439 NI_set_attribute( nel , "Nstim" , lll ) ;
9440 iar.num = sst->nstim ;
9441 iar.ar = sst->cbot ;
9442 lab = NI_encode_int_list( &iar , "," ) ;
9443 NI_set_attribute( nel, "StimBots", lab );NI_free((void *)lab); lab = NULL;
9444 iar.ar = sst->ctop ;
9445 lab = NI_encode_int_list( &iar , "," ) ;
9446 NI_set_attribute( nel, "StimTops", lab );NI_free((void *)lab); lab = NULL;
9447 for( jj=0 ; jj < sst->nstim ; jj++ ){
9448 strcpy(lll,sst->label[jj]) ;
9449 for( ii=0 ; lll[ii] != '\0' ; ii++ ) if( isspace(lll[ii]) ) lll[ii]='_';
9450 if( jj < sst->nstim-1 ) strcat(lll," ; ") ;
9451 lab = THD_zzprintf( lab , "%s" , lll ) ;
9452 }
9453 NI_set_attribute( nel, "StimLabels", lab ); free((void *)lab); lab = NULL;
9454 }
9455 #endif
9456 #if 1
9457 if( gst != NULL && gst->glt_num > 0 ){ /* 31 Jul 2008 */
9458 matrix gm ; NI_float_array far ; int nn,mm ;
9459 sprintf(lll,"%d",gst->glt_num) ;
9460 NI_set_attribute( nel , "Nglt" , lll ) ;
9461 for( kk=0 ; kk < gst->glt_num ; kk++ ){
9462 strcpy(lll,gst->glt_lab[kk]) ;
9463 for( ii=0 ; lll[ii] != '\0' ; ii++ ) if( isspace(lll[ii]) ) lll[ii]='_';
9464 if( kk < gst->glt_num-1 ) strcat(lll," ; ") ;
9465 lab = THD_zzprintf( lab , "%s" , lll ) ;
9466 }
9467 NI_set_attribute( nel, "GltLabels", lab ); free((void *)lab); lab = NULL;
9468 for( kk=0 ; kk < gst->glt_num ; kk++ ){
9469 gm = gst->glt_mat[kk] ;
9470 nn = gm.rows ;
9471 mm = gm.cols ;
9472 far.num = 2 + nn*mm ;
9473 far.ar = (float *)malloc(sizeof(float)*far.num) ;
9474 far.ar[0] = (float)nn ;
9475 far.ar[1] = (float)mm ;
9476 for( ii=0 ; ii < nn ; ii++ )
9477 for( jj=0 ; jj < mm ; jj++ )
9478 far.ar[jj+2+ii*mm] = (float)gm.elts[ii][jj] ;
9479 lab = NI_encode_float_list( &far , "," ) ;
9480 sprintf(lll,"GltMatrix_%06d",kk) ;
9481 NI_set_attribute( nel, lll, lab ); NI_free((void *)lab); lab = NULL;
9482 free((void *)far.ar) ;
9483 }
9484 }
9485 #endif
9486 #if 1
9487 if( basis_nused > 0 ){
9488 char qbuf[128] ;
9489 sprintf(lll,"%d",basis_nstim) ;
9490 NI_set_attribute( nel, "BasisNstim", lll ) ;
9491 for( kk=0 ; kk < basis_nstim ; kk++ ){
9492 if( basis_stim[kk] == NULL ) continue ;
9493 sprintf(lll,"BasisOption_%06d",kk+1) ;
9494 NI_set_attribute( nel, lll, basis_stim[kk]->option ) ;
9495 sprintf(lll,"BasisName_%06d",kk+1) ;
9496 NI_set_attribute( nel, lll, basis_stim[kk]->name ) ;
9497 sprintf(lll,"BasisFormula_%06d",kk+1) ;
9498 NI_set_attribute( nel, lll, basis_stim[kk]->symfun ) ;
9499 sprintf(lll,"BasisColumns_%06d",kk+1) ;
9500 sprintf(qbuf,"%d:%d",basis_stim[kk]->pbot,basis_stim[kk]->pbot+basis_stim[kk]->nparm-1) ;
9501 NI_set_attribute( nel , lll, qbuf ) ;
9502 }
9503 }
9504 #endif
9505 #if 1
9506 if( commandline != NULL ){
9507 NI_set_attribute( nel , "CommandLine" , commandline ) ;
9508 }
9509 #endif
9510
9511 NI_write_element_tofile( fname, nel, NI_HEADERSHARP_FLAG | NI_TEXT_MODE );
9512 NI_free_element( nel ) ;
9513 }
9514 if( verb ) INFO_message("Wrote matrix values to file %s",fname) ;
9515 return ;
9516 }
9517
9518 /*----------------------------------------------------------------------------*/
9519 /*--------- End of Grayplot addition ---------------------------------------*/
9520 /*============================================================================*/
9521
9522 /*============================================================================*/
9523 /*-- Save X, XtXinv, and XtXinvXt matrices in bucket file for later re-use. --*/
9524 /*----------------------------------------------------------------------------*/
9525
9526 #include "niml.h"
9527
9528 #if 0
9529 /*-----------------------------------------------------------------*/
9530 /*! Turn a NIML element into a string.
9531 -------------------------------------------------------------------*/
9532 /* SEE NI_write_element_tostring() */
9533 #endif
9534
9535 /*-----------------------------------------------------------------*/
9536 /*! Encode a matrix into a NIML element, which is returned;
9537 NI_free_element() this when done with it.
9538 ename is the name of the NIML element to create.
9539 -------------------------------------------------------------------*/
9540
matrix_to_niml(matrix a,char * ename)9541 NI_element * matrix_to_niml( matrix a , char *ename )
9542 {
9543 int m=a.rows , n=a.cols , ii,jj ;
9544 MTYPE **aar = a.elts ;
9545 NI_element *nel ;
9546 double *ecol ;
9547
9548 if( m < 1 || n < 1 || aar == NULL ) return NULL ; /* bad user, bad */
9549
9550 if( ename == NULL || *ename == '\0' ) ename = "matrix" ;
9551
9552 nel = NI_new_data_element( ename , m ) ;
9553 ecol = (double *) malloc(sizeof(double)*m) ;
9554
9555 for( jj=0 ; jj < n ; jj++ ){
9556 for( ii=0 ; ii < m ; ii++ ) ecol[ii] = aar[ii][jj] ;
9557 NI_add_column( nel , NI_DOUBLE , ecol ) ;
9558 }
9559
9560 free((void *)ecol) ;
9561 return nel ;
9562 }
9563
9564 /*-------------------------------------------------------------------*/
9565 /*! Decode an NIML element into a matrix.
9566 ---------------------------------------------------------------------*/
9567
niml_to_matrix(NI_element * nel,matrix * a)9568 void niml_to_matrix( NI_element *nel , matrix *a )
9569 {
9570 int m , n , ii , jj ;
9571 double *ecol ;
9572 MTYPE **aar ;
9573 char *ename ;
9574
9575 if( nel == NULL || a == NULL ) return ;
9576
9577 m = nel->vec_len ; /* number of rows */
9578 n = nel->vec_num ; /* number of cols */
9579
9580 if( m < 1 || n < 1 ) return ;
9581 for( jj=0 ; jj < n ; jj++ )
9582 if( nel->vec_typ[jj] != NI_DOUBLE ) return ;
9583
9584 matrix_create( m , n , a ) ;
9585 aar = a->elts ;
9586
9587 for( jj=0 ; jj < n ; jj++ ){
9588 ecol = (double *)nel->vec[jj] ;
9589 for( ii=0 ; ii < m ; ii++ ) aar[ii][jj] = (MTYPE)ecol[ii] ;;
9590 }
9591
9592 return ;
9593 }
9594
9595 /*-----------------------------------------------------------------*/
9596 /*! Encode an integer list into a NIML element.
9597 NI_free_element() this when done with it.
9598 ename is the name of the NIML element to create.
9599 -------------------------------------------------------------------*/
9600
intvec_to_niml(int nvec,int * vec,char * ename)9601 NI_element * intvec_to_niml( int nvec , int *vec , char *ename )
9602 {
9603 NI_element *nel ;
9604
9605 if( nvec < 1 || vec == NULL ) return NULL ; /* bad user, bad */
9606
9607 if( ename == NULL || *ename == '\0' ) ename = "intvec" ;
9608
9609 nel = NI_new_data_element( ename , nvec ) ;
9610 NI_add_column( nel , NI_INT , vec ) ;
9611 return nel ;
9612 }
9613
9614 /*-------------------------------------------------------------------*/
9615
niml_to_intvec(NI_element * nel,int * nvec,int ** vec)9616 void niml_to_intvec( NI_element *nel , int *nvec , int **vec )
9617 {
9618 if( nel == NULL || nvec == NULL || vec == NULL ) return ;
9619
9620 if( nel->vec_len < 1 || nel->vec_num < 1 ) return ;
9621 if( nel->vec_typ[0] != NI_INT ) return ;
9622
9623 *nvec = nel->vec_len ;
9624 *vec = (int *)malloc(*nvec*sizeof(int)) ;
9625 memcpy(*vec,nel->vec[0],*nvec*sizeof(int)) ;
9626 return ;
9627 }
9628
9629 /*-------------------------------------------------------------------*/
9630
stringvec_to_niml(int nstr,char ** str,char * ename)9631 NI_element * stringvec_to_niml( int nstr , char **str , char *ename )
9632 {
9633 NI_element *nel ;
9634
9635 if( nstr < 1 || str == NULL ) return NULL ; /* bad user, bad */
9636
9637 if( ename == NULL || *ename == '\0' ) ename = "stringvec" ;
9638
9639 nel = NI_new_data_element( ename , nstr ) ;
9640 NI_add_column( nel , NI_STRING , str ) ;
9641 return nel ;
9642 }
9643
9644 /*-------------------------------------------------------------------*/
9645
niml_to_stringvec(NI_element * nel,int * nstr,char *** str)9646 void niml_to_stringvec( NI_element *nel , int *nstr , char ***str )
9647 {
9648 int ii ;
9649 char **sv ;
9650
9651 if( nel == NULL || nstr == NULL || str == NULL ) return ;
9652
9653 if( nel->vec_len < 1 || nel->vec_num < 1 ) return ;
9654 if( nel->vec_typ[0] != NI_STRING ) return ;
9655 sv = (char **) nel->vec[0] ;
9656
9657 *nstr = nel->vec_len ;
9658 *str = (char **)calloc(sizeof(char *),*nstr) ;
9659 for( ii=0 ; ii < *nstr ; ii++ ) (*str)[ii] = strdup(sv[ii]) ;
9660 return ;
9661 }
9662
9663 /*-------------------------------------------------------------------*/
9664
symvec_to_niml(int ns,SYM_irange * sv,char * ename)9665 NI_element * symvec_to_niml( int ns , SYM_irange *sv , char *ename )
9666 {
9667 NI_element *nel ;
9668 int ii , *bc,*tc,*gc ; char **sc ;
9669
9670 if( ns < 1 || sv == NULL ) return NULL ; /* bad user, bad */
9671
9672 if( ename == NULL || *ename == '\0' ) ename = "symvec" ;
9673
9674 nel = NI_new_data_element( ename , ns ) ;
9675
9676 bc = (int *) malloc(sizeof(int) *ns) ;
9677 tc = (int *) malloc(sizeof(int) *ns) ;
9678 gc = (int *) malloc(sizeof(int) *ns) ;
9679 sc = (char **)malloc(sizeof(char *)*ns) ;
9680
9681 for( ii=0 ; ii < ns ; ii++ ){
9682 bc[ii] = sv[ii].nbot ; tc[ii] = sv[ii].ntop ;
9683 gc[ii] = sv[ii].gbot ; sc[ii] = sv[ii].name ;
9684 }
9685
9686 NI_add_column( nel , NI_INT , bc ); free((void *)bc) ;
9687 NI_add_column( nel , NI_INT , tc ); free((void *)tc) ;
9688 NI_add_column( nel , NI_INT , gc ); free((void *)gc) ;
9689 NI_add_column( nel , NI_STRING , sc ); free((void *)sc) ;
9690
9691 return nel ;
9692 }
9693
9694 /*-------------------------------------------------------------------*/
9695
niml_to_symvec(NI_element * nel,int * ns,SYM_irange ** sv)9696 void niml_to_symvec( NI_element *nel , int *ns , SYM_irange **sv )
9697 {
9698 int ii , *bc,*tc,*gc ; char **sc ;
9699
9700 if( nel == NULL || ns == NULL || sv == NULL ) return ;
9701
9702 if( nel->vec_len < 1 || nel->vec_num < 4 ) return ;
9703 if( nel->vec_typ[0] != NI_INT ) return ; bc = (int *) nel->vec[0] ;
9704 if( nel->vec_typ[1] != NI_INT ) return ; tc = (int *) nel->vec[1] ;
9705 if( nel->vec_typ[2] != NI_INT ) return ; gc = (int *) nel->vec[2] ;
9706 if( nel->vec_typ[3] != NI_STRING ) return ; sc = (char **)nel->vec[3] ;
9707
9708 *ns = nel->vec_len ;
9709 *sv = (SYM_irange *)calloc(sizeof(SYM_irange),*ns) ;
9710 for( ii=0 ; ii < *ns ; ii++ ){
9711 (*sv)[ii].nbot = bc[ii] ;
9712 (*sv)[ii].ntop = tc[ii] ;
9713 (*sv)[ii].gbot = gc[ii] ;
9714 NI_strncpy( (*sv)[ii].name , sc[ii] , 64 ) ;
9715 }
9716 return ;
9717 }
9718
9719 /*-------------------------------------------------------------------*/
9720
XSAVE_output(char * prefix)9721 void XSAVE_output( char *prefix )
9722 {
9723 char *fname , *cpt ;
9724 NI_stream ns ;
9725 NI_element *nel ;
9726 int nimode = NI_BINARY_MODE ;
9727
9728 if( !xsave ) return ;
9729
9730 if( AFNI_yesenv("AFNI_XSAVE_TEXT") ) nimode = NI_TEXT_MODE ;
9731
9732 /*-- open output stream --*/
9733
9734 if( prefix == NULL || *prefix == '\0' ) prefix = "X" ;
9735
9736 fname = malloc( sizeof(char) * (strlen(prefix)+32) ) ;
9737 strcpy(fname,"file:") ; strcat(fname,prefix) ; strcat(fname,".xsave") ;
9738 if( THD_is_ondisk(fname+5) && verb )
9739 WARNING_message(
9740 "-xsave output file %s will be overwritten!",fname+5) ;
9741 ns = NI_stream_open( fname , "w" ) ;
9742 if( ns == (NI_stream)NULL ){
9743 ERROR_message(
9744 "-xsave output file %s can't be opened!",fname+5) ;
9745 free((void *)fname) ;
9746 return ;
9747 }
9748
9749 /*-- write a header element --*/
9750
9751 nel = NI_new_data_element( "XSAVE", 0 ) ;
9752 if( InputFilename != NULL )
9753 NI_set_attribute( nel , "InputFilename" , InputFilename ) ;
9754 if( BucketFilename != NULL )
9755 NI_set_attribute( nel , "BucketFilename" , BucketFilename ) ;
9756 if( CoefFilename != NULL )
9757 NI_set_attribute( nel , "CoefFilename" , CoefFilename ) ;
9758
9759 sprintf(fname,"%d",X.rows) ;
9760 NI_set_attribute( nel , "NumTimePoints" , fname ) ;
9761 sprintf(fname,"%d",X.cols) ;
9762 NI_set_attribute( nel , "NumRegressors" , fname ) ;
9763
9764 NI_set_attribute( nel , "Deconvolveries" , XSAVE_version ) ;
9765
9766 cpt = tross_datetime() ;
9767 NI_set_attribute( nel , "DateTime" , cpt ) ;
9768 free((void *)cpt) ;
9769 cpt = tross_hostname() ;
9770 NI_set_attribute( nel , "Hostname" , cpt ) ;
9771 free((void *)cpt) ;
9772 cpt = tross_username() ;
9773 NI_set_attribute( nel , "Username" , cpt ) ;
9774 free((void *)cpt) ;
9775
9776 (void) NI_write_element( ns , nel , nimode ) ;
9777 NI_free_element( nel ) ;
9778
9779 /*-- write the matrices --*/
9780
9781 nel = matrix_to_niml( X , "matrix" ) ;
9782 NI_set_attribute( nel , "Xname" , "X" ) ;
9783 (void) NI_write_element( ns , nel , nimode ) ;
9784 NI_free_element( nel ) ;
9785
9786 nel = matrix_to_niml( XtXinv , "matrix" ) ;
9787 NI_set_attribute( nel , "Xname" , "XtXinv" ) ;
9788 (void) NI_write_element( ns , nel , nimode ) ;
9789 NI_free_element( nel ) ;
9790
9791 nel = matrix_to_niml( XtXinvXt , "matrix" ) ;
9792 NI_set_attribute( nel , "Xname" , "XtXinvXt" ) ;
9793 (void) NI_write_element( ns , nel , nimode ) ;
9794 NI_free_element( nel ) ;
9795
9796 /*-- list of good time points --*/
9797
9798 nel = intvec_to_niml( nGoodList , GoodList , "intvec" ) ;
9799 NI_set_attribute( nel , "Xname" , "GoodList" ) ;
9800 (void) NI_write_element( ns , nel , nimode ) ;
9801 NI_free_element( nel ) ;
9802
9803 /*-- list of bucket indices with estimated parameters --*/
9804
9805 if( ParamIndex != NULL ){
9806 nel = intvec_to_niml( nParam, ParamIndex , "intvec" ) ;
9807 NI_set_attribute( nel , "Xname" , "ParamIndex" ) ;
9808 (void) NI_write_element( ns , nel , nimode ) ;
9809 NI_free_element( nel ) ;
9810 }
9811
9812 /*-- which stimlus input file, for each parameter --*/
9813
9814 nel = intvec_to_niml( nParam, ParamStim , "intvec" ) ;
9815 NI_set_attribute( nel , "Xname" , "ParamStim" ) ;
9816 (void) NI_write_element( ns , nel , nimode ) ;
9817 NI_free_element( nel ) ;
9818
9819 /*-- stimulus label, for each parameter --*/
9820
9821 nel = stringvec_to_niml( nParam , ParamLabel , "stringvec" ) ;
9822 NI_set_attribute( nel , "Xname" , "ParamLabel" ) ;
9823 (void) NI_write_element( ns , nel , nimode ) ;
9824 NI_free_element( nel ) ;
9825
9826 /*-- stimulus symbols [29 Jul 2004] --*/
9827
9828 if( nSymStim > 0 ){
9829 nel = symvec_to_niml( nSymStim , SymStim , "symvec" ) ;
9830 NI_set_attribute( nel , "Xname" , "SymStim" ) ;
9831 (void) NI_write_element( ns , nel , nimode ) ;
9832 NI_free_element( nel ) ;
9833 }
9834
9835 /*-- done, finito, ciao babee --*/
9836
9837 NI_stream_close(ns) ; free((void *)fname) ; return ;
9838 }
9839
9840 /*-------------------------------------------------------------------*/
9841
9842 #define DPR(s) fprintf(stderr,"%s\n",(s))
9843
XSAVE_input(char * xname)9844 void XSAVE_input( char *xname )
9845 {
9846 char *fname , *cpt ;
9847 NI_stream ns ;
9848 NI_element *nel ;
9849
9850 if( xname == NULL || *xname == '\0' ) return ;
9851
9852 /*-- open input file --*/
9853
9854 fname = malloc( sizeof(char) * (strlen(xname)+32) ) ;
9855 strcpy(fname,"file:") ; strcat(fname,xname) ;
9856 ns = NI_stream_open( fname , "r" ) ;
9857 free((void *)fname) ;
9858 if( ns == (NI_stream)NULL ){
9859 ERROR_message("can't open file %s for -xrestore!",xname) ;
9860 return ;
9861 }
9862
9863 /*-- read and decode header element --*/
9864
9865 nel = NI_read_element( ns , 1 ) ;
9866 if( nel == NULL ){
9867 ERROR_message("can't read header in file %s for -xrestore!",xname) ;
9868 NI_stream_close( ns ) ; return ;
9869 }
9870
9871 /* extract filenames */
9872
9873 cpt = NI_get_attribute( nel , "InputFilename" ) ;
9874 if( cpt != NULL ) InputFilename = strdup(cpt) ;
9875 cpt = NI_get_attribute( nel , "BucketFilename" ) ;
9876 if( cpt != NULL ) BucketFilename = strdup(cpt) ;
9877 cpt = NI_get_attribute( nel , "CoefFilename" ) ;
9878 if( cpt != NULL ) CoefFilename = strdup(cpt) ;
9879
9880 /* extract other stuff (not used, yet) */
9881
9882 cpt = NI_get_attribute( nel , "NumTimePoints" ) ;
9883 if( cpt != NULL ) NumTimePoints = strtol(cpt,NULL,10) ;
9884 cpt = NI_get_attribute( nel , "NumRegressors" ) ;
9885 if( cpt != NULL ) NumRegressors = strtol(cpt,NULL,10) ;
9886
9887 NI_free_element( nel ) ;
9888
9889 /*-- read succeeding elements, decode and store them --*/
9890
9891 while(1){
9892
9893 nel = NI_read_element( ns , 1 ) ;
9894 if( nel == NULL ) break ; /* end of input */
9895
9896 cpt = NI_get_attribute( nel , "Xname" ) ; /*- name of variable to save -*/
9897 if( cpt == NULL ){
9898 NI_free_element( nel ) ; continue ; /*- unnamed ==> skip this! -*/
9899 }
9900
9901 if( strcmp(nel->name,"matrix") == 0 ){ /*- matrix elements -*/
9902
9903 if( strcmp(cpt,"X" )==0 ) niml_to_matrix( nel , &X );
9904 else if( strcmp(cpt,"XtXinv" )==0 ) niml_to_matrix( nel , &XtXinv );
9905 else if( strcmp(cpt,"XtXinvXt")==0 ) niml_to_matrix( nel , &XtXinvXt );
9906
9907 } else if( strcmp(nel->name,"intvec") == 0 ){ /*- intvec elements -*/
9908
9909 if( strcmp(cpt,"GoodList") == 0 )
9910 niml_to_intvec( nel , &nGoodList, &GoodList );
9911 else if( strcmp(cpt,"ParamIndex") == 0 )
9912 niml_to_intvec( nel , &nParam , &ParamIndex );
9913 else if( strcmp(cpt,"ParamStim" ) == 0 )
9914 niml_to_intvec( nel , &nParam , &ParamStim );
9915
9916 } else if( strcmp(nel->name,"stringvec") == 0 ){ /*- stringvec elements -*/
9917
9918 if( strcmp(cpt,"ParamLabel") == 0 )
9919 niml_to_stringvec( nel , &nParam , &ParamLabel );
9920
9921 } else if( strcmp(nel->name,"symvec") == 0 ){ /*- symvec elements -*/
9922
9923 if( strcmp(cpt,"SymStim") == 0 )
9924 niml_to_symvec( nel , &nSymStim , &SymStim );
9925
9926 } else { /*- other elements? -*/
9927 /*- silently skip them -*/
9928 }
9929
9930 NI_free_element( nel ) ; /* toss the trash (or recycle it) */
9931
9932 } /*-- end of loop over elements in file --*/
9933
9934 NI_stream_close( ns ) ; return ;
9935 }
9936
9937 /*============================================================================*/
9938 /*------ xrestore operations: 26 Jul 2004 ------------------------------------*/
9939 /*----------------------------------------------------------------------------*/
9940
check_xrestore_data(void)9941 void check_xrestore_data(void)
9942 {
9943 int nerr = 0 ;
9944
9945 if( X.rows < 1 || X.cols < 1 ){
9946 ERROR_message(
9947 "-xrestore %s has bad X matrix",xrestore_filename) ;
9948 nerr++ ;
9949 }
9950 if( XtXinv.rows < 1 || XtXinv.cols < 1 ){
9951 ERROR_message(
9952 "-xrestore %s has bad XtXinv matrix",xrestore_filename) ;
9953 nerr++ ;
9954 }
9955 if( XtXinvXt.rows < 1 || XtXinvXt.cols < 1 ){
9956 ERROR_message(
9957 "-xrestore %s has bad XtXinvXt matrix",xrestore_filename) ;
9958 nerr++ ;
9959 }
9960 if( nParam > 0 && X.cols != nParam ){
9961 ERROR_message(
9962 "-xrestore %s X matrix cols mismatch: %d != %d",
9963 xrestore_filename, X.cols , nParam ) ;
9964 nerr++ ;
9965 }
9966 if( GoodList == NULL ){
9967 ERROR_message(
9968 "-xrestore %s missing GoodList field",xrestore_filename) ;
9969 nerr++ ;
9970 } else if( nGoodList != X.rows ){
9971 ERROR_message(
9972 "-xrestore %s X matrix rows mismatch: %d != %d",
9973 xrestore_filename, X.cols , nGoodList ) ;
9974 nerr++ ;
9975 }
9976 #if 0
9977 if( ParamStim == NULL ){
9978 ERROR_message(
9979 "-xrestore %s missing ParamStim field",xrestore_filename) ;
9980 nerr++ ;
9981 }
9982 if( ParamLabel == NULL ){
9983 ERROR_message(
9984 "-xrestore %s missing ParamLabel field",xrestore_filename) ;
9985 nerr++ ;
9986 }
9987 #endif
9988 if( InputFilename == NULL ){
9989 ERROR_message(
9990 "-xrestore %s missing InputFilename field",xrestore_filename) ;
9991 nerr++ ;
9992 }
9993
9994 if( nerr > 0 ) exit(1) ; /** bad bad bad **/
9995 return ;
9996 }
9997
9998 /*-------------------------------------------------------------------*/
9999
do_xrestore_stuff(int argc,char ** argv,DC_options * option_data)10000 void do_xrestore_stuff( int argc , char **argv , DC_options *option_data )
10001 {
10002 THD_3dim_dataset *dset_time , *dset_coef, *dset_buck ;
10003 int nt , np , ii, nxyz, tout,rout,fout, ixyz,novar,view ;
10004 char *buck_prefix , *buck_name ;
10005 char brick_label[THD_MAX_NAME] ;
10006
10007 float *ts_array = NULL; /* array of measured data for one voxel */
10008 #undef NGET
10009 #define NGET 32 /* number to get at one time */
10010 int nget=0 , /* number of time series current gotten */
10011 cget=0 , /* index of next timeseries in iget & imget */
10012 jget , /* loop index for iget */
10013 iget[NGET] ; /* voxel index of timeseries */
10014 MRI_IMARR *imget=NULL ; /* array of timeseries */
10015
10016 int num_glt , iglt , ilc,nlc ;
10017 matrix *glt_cmat , *glt_amat , *cxtxinvct ;
10018 vector *glt_coef , *glt_tcoef, y , coef ;
10019 float *fglt , *rglt ;
10020 char **glt_label ;
10021 int *glt_rows ;
10022 float ***glt_coef_vol ,
10023 ***glt_tcoef_vol=NULL ,
10024 ** glt_fstat_vol=NULL ,
10025 ** glt_rstat_vol=NULL ;
10026 float *cdar=NULL , ssef=0.0f , *volume ;
10027 int ivol , nvol , nbuck , vstep ;
10028
10029 /*----- Check for GLT options -----*/
10030
10031 num_glt = option_data->num_glt ;
10032 glt_label = option_data->glt_label ;
10033 glt_rows = option_data->glt_rows ;
10034
10035 tout = option_data->tout ;
10036 rout = option_data->rout ;
10037 fout = option_data->fout ;
10038
10039 if( num_glt < 1 )
10040 ERROR_exit("-xrestore with no new GLTs???") ;
10041
10042 /*----- initialize values to be read from xsave file -----*/
10043
10044 matrix_initialize( &X ) ;
10045 matrix_initialize( &XtXinv ) ;
10046 matrix_initialize( &XtXinvXt ) ;
10047 nGoodList = 0 ; GoodList = NULL ;
10048 nParam = 0 ; ParamIndex = NULL ; ParamStim = NULL ; ParamLabel = NULL ;
10049
10050 /*----- read xsave file -----*/
10051
10052 if( verb ) INFO_message("Starting -xrestore %s",xrestore_filename) ;
10053
10054 XSAVE_input( xrestore_filename ) ;
10055 check_xrestore_data() ;
10056
10057 nt = X.rows ; np = X.cols ; /* number of time points and parameters */
10058
10059 /*----- read input time series dataset -----*/
10060
10061 if( verb ) INFO_message("loading time series dataset '%s'\n",InputFilename);
10062 dset_time = THD_open_dataset( InputFilename ) ;
10063 if( dset_time == NULL )
10064 ERROR_exit(
10065 "-xrestore can't open time series dataset '%s'" ,
10066 InputFilename ) ;
10067
10068 DSET_load( dset_time ) ;
10069 if( !DSET_LOADED(dset_time) )
10070 ERROR_exit(
10071 "-xrestore can't load time series dataset '%s'" ,
10072 InputFilename ) ;
10073
10074 nxyz = DSET_NVOX(dset_time) ; /* number of voxels */
10075 view = dset_time->view_type ; /* +orig, +acpc, +tlrc ? */
10076
10077 /*----- read coefficient dataset (if possible) -----*/
10078
10079 dset_coef = NULL ;
10080 if( CoefFilename != NULL ){
10081 if( verb) INFO_message("loading coefficient dataset %s\n",CoefFilename);
10082 dset_coef = THD_open_dataset( CoefFilename ) ;
10083 if( dset_coef == NULL ){
10084 WARNING_message(
10085 "-xrestore can't open coefficient dataset %s",
10086 CoefFilename);
10087 } else {
10088 DSET_load(dset_coef) ;
10089 if( !DSET_LOADED(dset_coef) ){
10090 WARNING_message(
10091 "-xrestore can't load coefficient dataset %s",
10092 CoefFilename);
10093 DSET_delete(dset_coef) ; dset_coef = NULL ;
10094 }
10095 }
10096 if( dset_coef != NULL && DSET_NVALS(dset_coef) < np ){
10097 WARNING_message(
10098 "-xrestore coefficient dataset %s too short",
10099 CoefFilename);
10100 DSET_delete(dset_coef) ; dset_coef = NULL ;
10101 }
10102 if( dset_coef != NULL ){
10103 if( ParamIndex != NULL ) free((void *)ParamIndex) ;
10104 ParamIndex = (int *)malloc(sizeof(int)*np) ;
10105 for( ii=0 ; ii < np ; ii++ ) ParamIndex[ii] = ii ;
10106 }
10107 }
10108
10109 /*----- if above failed, try the old bucket dataset -----*/
10110
10111 if( dset_coef == NULL && BucketFilename != NULL && ParamIndex != NULL ){
10112 if( verb ) INFO_message("loading original bucket dataset %s\n",BucketFilename) ;
10113 dset_coef = THD_open_dataset( BucketFilename ) ;
10114 if( dset_coef == NULL ){
10115 WARNING_message(
10116 "-xrestore can't open old bucket dataset %s",
10117 BucketFilename);
10118 } else {
10119 DSET_load(dset_coef) ;
10120 if( !DSET_LOADED(dset_coef) ){
10121 WARNING_message(
10122 "-xrestore can't load old bucket dataset %s",
10123 BucketFilename);
10124 DSET_delete(dset_coef) ; dset_coef = NULL ;
10125 }
10126 }
10127 if( dset_coef != NULL && DSET_NVALS(dset_coef) < ParamIndex[np-1] ){
10128 WARNING_message(
10129 "-xrestore old bucket dataset %s too short",
10130 BucketFilename);
10131 DSET_delete(dset_coef) ; dset_coef = NULL ;
10132 }
10133 }
10134
10135 if( ISVALID_DSET(dset_coef) && DSET_NVOX(dset_coef) != nxyz )
10136 ERROR_exit("dataset mismatch between time series and coef!") ;
10137
10138 /*----- neither worked ==> must recompute from input data time series -----*/
10139
10140 if( dset_coef == NULL && verb )
10141 INFO_message("-xrestore recomputing coefficients from time series");
10142
10143 /*----- read new GLT matrices -----*/
10144
10145 glt_cmat = (matrix *) malloc( sizeof(matrix) * num_glt ) ;
10146
10147 for( iglt=0; iglt < num_glt ; iglt++){
10148 matrix_initialize( glt_cmat + iglt ) ;
10149 #if 1
10150 read_glt_matrix( option_data->glt_filename[iglt] ,
10151 option_data->glt_rows + iglt ,
10152 np , glt_cmat + iglt ) ;
10153 #else
10154 matrix_file_read ( option_data->glt_filename[iglt] ,
10155 option_data->glt_rows[iglt] ,
10156 np , glt_cmat+iglt , 1 ) ;
10157 if( glt_cmat[iglt].elts == NULL )
10158 ERROR_exit( "Can't read GLT matrix from file %s",
10159 option_data->glt_filename[iglt] ) ;
10160 #endif
10161 }
10162
10163 /*----- initialize new GLT calculations:
10164 - setup space for matrices and vectors
10165 - calculate matrices
10166 - malloc space for output bricks -----*/
10167
10168 cxtxinvct = (matrix *) malloc( sizeof(matrix) * num_glt ) ;
10169 glt_amat = (matrix *) malloc( sizeof(matrix) * num_glt ) ;
10170 glt_coef = (vector *) malloc( sizeof(vector) * num_glt ) ;
10171 glt_tcoef = (vector *) malloc( sizeof(vector) * num_glt ) ;
10172
10173 for( iglt=0 ; iglt < num_glt ; iglt++ ){
10174 matrix_initialize( cxtxinvct+iglt ) ; /* will be loaded in */
10175 matrix_initialize( glt_amat +iglt ) ; /* init_glt_analysis() */
10176 vector_initialize( glt_coef +iglt ) ;
10177 vector_initialize( glt_tcoef+iglt ) ;
10178 }
10179
10180 fglt = (float *) malloc( sizeof(float) * num_glt ) ;
10181 rglt = (float *) malloc( sizeof(float) * num_glt ) ;
10182
10183 vector_initialize( &y ) ; vector_create( nt, &y ); /* time series */
10184 vector_initialize( &coef ); vector_create( np, &coef ); /* parameters */
10185
10186 if( dset_coef != NULL )
10187 cdar = (float *)malloc( sizeof(float) * DSET_NVALS(dset_coef) ) ;
10188
10189 init_glt_analysis( XtXinv , num_glt , glt_cmat , glt_amat , cxtxinvct ) ;
10190
10191 /*-- malloc output bricks --*/
10192
10193 glt_coef_vol = (float ***) malloc( sizeof(float **) * num_glt ) ;
10194 if( tout )
10195 glt_tcoef_vol = (float ***) malloc( sizeof(float **) * num_glt ) ;
10196 if( fout )
10197 glt_fstat_vol = (float **) malloc( sizeof(float *) * num_glt ) ;
10198 if( rout )
10199 glt_rstat_vol = (float **) malloc( sizeof(float *) * num_glt ) ;
10200
10201 nvol = 0 ;
10202 for( iglt=0 ; iglt < num_glt ; iglt++ ){
10203 nlc = glt_rows[iglt];
10204 glt_coef_vol[iglt] = (float **) malloc( sizeof(float *) * nlc ) ;
10205 if( tout )
10206 glt_tcoef_vol[iglt] = (float **) malloc( sizeof(float *) * nlc ) ;
10207 for( ilc=0 ; ilc < nlc ; ilc++ ){
10208 glt_coef_vol[iglt][ilc] = (float *)calloc(sizeof(float),nxyz); nvol++;
10209 if( tout ){
10210 glt_tcoef_vol[iglt][ilc] = (float *)calloc(sizeof(float),nxyz); nvol++;
10211 }
10212 }
10213 if( fout ){
10214 glt_fstat_vol[iglt] = (float *)calloc( sizeof(float), nxyz ); nvol++;
10215 }
10216 if( rout ){
10217 glt_rstat_vol[iglt] = (float *)calloc( sizeof(float), nxyz ); nvol++;
10218 }
10219 }
10220
10221 /*----- loop over voxels:
10222 - fetch coefficients (check for all zero), or recompute them
10223 - fetch time series
10224 - compute SSE of full model
10225 - compute and store new GLT results in arrays -----*/
10226
10227 vstep = nxyz / 50 ; if( !verb ) vstep = 0 ;
10228 if( vstep > 0 ) fprintf(stderr,"++ voxel loop:") ;
10229 for( ixyz=0 ; ixyz < nxyz ; ixyz++ ){
10230
10231 if( vstep > 0 && ixyz%vstep == vstep-1 ) vstep_print() ;
10232
10233 /*** race ahead and extract a bunch of voxel time series at once ***/
10234
10235 if( cget == nget ){
10236 if( imget != NULL ) DESTROY_IMARR(imget) ;
10237 iget[0] = ixyz ; nget = 1 ;
10238 for( jget=ixyz+1 ; jget < nxyz && nget < NGET ; jget++ )
10239 iget[nget++] = jget ;
10240 imget = THD_extract_many_series( nget, iget, dset_time ) ;
10241 cget = 0 ; /* the next one to take out of imget */
10242 }
10243
10244 /*** Extract Y-data for this voxel ***/
10245
10246 ts_array = MRI_FLOAT_PTR(IMARR_SUBIM(imget,cget)) ; cget++ ;
10247 for( ii=0 ; ii < nt ; ii++ ) y.elts[ii] = ts_array[GoodList[ii]];
10248
10249 /*** Extract or recompute coefficients for this voxel ***/
10250
10251 if( dset_coef != NULL ){
10252 (void) THD_extract_array( ixyz , dset_coef , 0 , cdar ) ;
10253 for( ii=0 ; ii < np ; ii++ ) coef.elts[ii] = cdar[ParamIndex[ii]] ;
10254 } else {
10255 vector_multiply( XtXinvXt , y , &coef ) ;
10256 }
10257
10258 /*** if coef is all zero, skip this voxel ***/
10259
10260 for( ii=0 ; ii < np ; ii++ ) if( coef.elts[ii] != 0.0 ) break ;
10261 novar = (ii==np) ;
10262
10263 if( !novar ) ssef = calc_sse( X , coef , y ) ;
10264
10265 /************************************/
10266 /*** Do the work we came here for ***/
10267 /************************************/
10268
10269 glt_analysis( nt , np ,
10270 X , y , ssef , coef , novar ,
10271 cxtxinvct , num_glt , glt_rows , glt_cmat , glt_amat ,
10272 glt_coef , glt_tcoef , fglt , rglt ) ;
10273
10274 /*** save results into output bricks ***/
10275
10276 if (glt_coef_vol != NULL)
10277 for (iglt = 0; iglt < num_glt; iglt++)
10278 if (glt_coef_vol[iglt] != NULL)
10279 for (ilc = 0; ilc < glt_rows[iglt]; ilc++)
10280 glt_coef_vol[iglt][ilc][ixyz] = glt_coef[iglt].elts[ilc];
10281
10282 if (glt_tcoef_vol != NULL)
10283 for (iglt = 0; iglt < num_glt; iglt++)
10284 if (glt_tcoef_vol[iglt] != NULL)
10285 for (ilc = 0; ilc < glt_rows[iglt]; ilc++)
10286 glt_tcoef_vol[iglt][ilc][ixyz] = glt_tcoef[iglt].elts[ilc];
10287
10288 if (glt_fstat_vol != NULL)
10289 for (iglt = 0; iglt < num_glt; iglt++)
10290 if (glt_fstat_vol[iglt] != NULL)
10291 glt_fstat_vol[iglt][ixyz] = fglt[iglt];
10292
10293 if (glt_rstat_vol != NULL)
10294 for (iglt = 0; iglt < num_glt; iglt++)
10295 if (glt_rstat_vol[iglt] != NULL)
10296 glt_rstat_vol[iglt][ixyz] = rglt[iglt];
10297
10298 } /*** end of loop over voxels */
10299
10300 if( vstep > 0 ) fprintf(stderr,"\n") ; /* end of progress meter */
10301
10302 /*** unload input datasets to save memory ***/
10303
10304 DSET_unload( dset_time ) ;
10305 if( dset_coef != NULL ) DSET_delete( dset_coef ) ;
10306
10307 /*----- open old dataset for output if
10308 (a) -bucket was given for an existing dataset, or
10309 (b) no -bucket option was given;
10310 otherwise, open a new dataset for output of the GLT results -----*/
10311
10312 if( option_data->bucket_filename != NULL ){
10313 buck_prefix = strdup(option_data->bucket_filename) ;
10314 } else if( BucketFilename != NULL ){
10315 buck_prefix = (char *)malloc(strlen(BucketFilename)+4) ;
10316 FILENAME_TO_PREFIX( BucketFilename , buck_prefix ) ;
10317 } else {
10318 buck_prefix = strdup("X") ; /* bad user, bad bad bad */
10319 }
10320
10321 /*** try to open dataset as an old one **/
10322
10323 buck_name = (char *)malloc(strlen(buck_prefix)+32) ;
10324 strcpy(buck_name,buck_prefix) ;
10325 strcat(buck_name,"+") ; strcat(buck_name,VIEW_codestr[view]) ;
10326
10327 dset_buck = THD_open_dataset( buck_name ) ;
10328
10329 if( dset_buck != NULL ){
10330
10331 if( verb) INFO_message("-xrestore appending to dataset %s",buck_name) ;
10332 DSET_mallocize( dset_buck ) ;
10333 if( DSET_NVOX(dset_buck) != nxyz )
10334 ERROR_exit(
10335 "dataset %s mismatch with time series '%s'" ,
10336 buck_name , DSET_HEADNAME(dset_time) );
10337
10338 DSET_load( dset_buck ) ;
10339 if( !DSET_LOADED(dset_buck) )
10340 ERROR_exit( "can't load dataset %s from disk" , buck_name ) ;
10341
10342 /* add nvol empty bricks at the end */
10343
10344 ivol = DSET_NVALS(dset_buck) ; /* where to save first new brick */
10345
10346 EDIT_add_bricklist( dset_buck , nvol, NULL, NULL, NULL ) ;
10347
10348 } else { /*** create a new dataset ***/
10349
10350 if( verb ) INFO_message("xrestore creating new dataset %s",buck_name) ;
10351
10352 dset_buck = EDIT_empty_copy( dset_time ) ;
10353 (void) EDIT_dset_items( dset_buck ,
10354 ADN_prefix, buck_prefix ,
10355 ADN_type, HEAD_FUNC_TYPE,
10356 ADN_func_type, FUNC_BUCK_TYPE,
10357 ADN_datum_all, (floatout)?MRI_float:MRI_short,
10358 ADN_ntt, 0, /* no time axis */
10359 ADN_nvals, nvol ,
10360 ADN_malloc_type, DATABLOCK_MEM_MALLOC ,
10361 ADN_none ) ;
10362 ivol = 0 ;
10363 }
10364
10365 tross_Make_History( PROGRAM_NAME , argc , argv , dset_buck ) ;
10366
10367 nbuck = DSET_NVALS(dset_buck) ;
10368
10369 /*** attach sub-bricks to output ***/
10370
10371 for( iglt=0 ; iglt < num_glt ; iglt++ ){
10372
10373 for( ilc=0 ; ilc < glt_rows[iglt] ; ilc++ ){
10374 #ifdef USE_OLD_LABELS
10375 sprintf( brick_label , "%s LC[%d] coef" , glt_label[iglt], ilc ) ;
10376 #else
10377 sprintf (brick_label, "%s_GLT%c%d_Coef", glt_label[iglt], EDIT_get_index_prefix(), ilc);
10378 #endif
10379 volume = glt_coef_vol[iglt][ilc];
10380 attach_sub_brick( dset_buck, ivol, volume, nxyz,
10381 FUNC_FIM_TYPE, brick_label, 0, 0, 0, NULL);
10382 free((void *)volume) ; ivol++ ;
10383
10384 if( tout ){
10385 #ifdef USE_OLD_LABELS
10386 sprintf( brick_label , "%s LC[%d] t-st" , glt_label[iglt], ilc ) ;
10387 #else
10388 sprintf (brick_label, "%s_GLT%c%d_Tstat", glt_label[iglt], EDIT_get_index_prefix(),ilc);
10389 #endif
10390 volume = glt_tcoef_vol[iglt][ilc];
10391 attach_sub_brick( dset_buck, ivol, volume, nxyz,
10392 FUNC_TT_TYPE, brick_label, nt-np, 0, 0, NULL);
10393 free((void *)volume) ; ivol++ ;
10394 }
10395 }
10396
10397 if( rout ){
10398 float a,b ;
10399 #ifdef USE_OLD_LABELS
10400 sprintf( brick_label , "%s R^2" , glt_label[iglt] ) ;
10401 #else
10402 sprintf( brick_label , "%s_GLT_R^2" , glt_label[iglt] ) ;
10403 #endif
10404 volume = glt_rstat_vol[iglt];
10405 a = 0.5*glt_rows[iglt] ; b = 0.5*(nt-np) ;
10406 attach_sub_brick( dset_buck, ivol, volume, nxyz,
10407 FUNC_BT_TYPE, brick_label, 0, a, b, NULL);
10408 free((void *)volume) ; ivol++ ;
10409 }
10410
10411 if( fout ){
10412 #ifdef USE_OLD_LABELS
10413 sprintf( brick_label , "%s F-stat" , glt_label[iglt] ) ;
10414 #else
10415 sprintf( brick_label , "%s_GLT_Fstat" , glt_label[iglt] ) ;
10416 #endif
10417 volume = glt_fstat_vol[iglt];
10418 attach_sub_brick( dset_buck, ivol, volume, nxyz,
10419 FUNC_FT_TYPE, brick_label, 0, glt_rows[iglt], nt-np, NULL);
10420 free((void *)volume) ; ivol++ ;
10421 }
10422 } /** End loop over general linear tests **/
10423
10424 /*----- Write dataset out! -----*/
10425
10426 putenv("AFNI_DECONFLICT=OVERWRITE") ; /* overwrite output dataset */
10427
10428 DSET_write( dset_buck ) ;
10429 return ;
10430 }
10431
10432 /*---------------------------------------------------------------------------*/
10433 /* New code to read one GLT matrix: the old way and the new way [29 Jul 2004]
10434 -----------------------------------------------------------------------------*/
10435
10436 #define GLT_ERR ERROR_exit("Can't read GLT matrix from file %s",fname)
10437
read_glt_matrix(char * fname,int * nrows,int ncol,matrix * cmat)10438 void read_glt_matrix( char *fname, int *nrows, int ncol, matrix *cmat )
10439 {
10440 int ii,jj ;
10441
10442 ENTRY("read_glt_matrix") ;
10443
10444 if( *nrows > 0 ){ /* standard read of numbers from a file*/
10445
10446 matrix_file_read( fname , *nrows , ncol , cmat , 1 ) ; /* mri_read_1D */
10447 if( cmat->elts == NULL ) GLT_ERR ;
10448
10449 } else { /* symbolic read of stim_labels */
10450 floatvecvec *fvv ;
10451 float **far=NULL ;
10452 int nr=0 , iv ;
10453 char *str_echo=NULL ; /* 26 Jan 2007 */
10454
10455 if( nSymStim < 1 )
10456 ERROR_exit("use of -gltsym without SymStim being defined");
10457
10458 if( strncmp(fname,"SYM:",4) == 0 ){ /* read directly from fname string */
10459 char *fdup=strdup(fname+4) , *fpt , *buf ;
10460 int ss , ns ;
10461 buf = fdup ;
10462 while(1){
10463 fpt = strchr(buf,'\\'); /* find end of 'line' */
10464 if( fpt == NULL ) fpt = strchr(buf,'|') ;
10465 if( fpt != NULL ) *fpt = '\0' ;
10466 fvv = SYM_expand_ranges( ncol-1 , nSymStim,SymStim , buf ) ;
10467 if( fvv == NULL || fvv->nvec < 1 ) {
10468 /* skip any empty row, else fail 17 Oct 2013 [rickr] */
10469 if( fpt ) WARNING_message("skipping empty SYM row at posn %d of %s",
10470 (int)(fpt-fdup)+4, fname);
10471 else ERROR_exit("failing on empty SYM");
10472 buf = fpt+1;
10473 continue ;
10474 }
10475 far = (float **)realloc((void *)far , sizeof(float *)*(nr+fvv->nvec)) ;
10476 for( iv=0 ; iv < fvv->nvec ; iv++ ) far[nr++] = fvv->fvar[iv].ar ;
10477 free((void *)fvv->fvar) ; free((void *)fvv) ;
10478 if( fpt == NULL ) break ; /* reached end of string? */
10479 buf = fpt+1 ; /* no, so loop back for next 'line' */
10480 }
10481 free((void *)fdup) ;
10482
10483 } else { /* read from file */
10484 char buf[8192] , *cpt ;
10485 FILE *fp = fopen( fname , "r" ) ;
10486 if( fp == NULL ) GLT_ERR ;
10487 while(1){
10488 cpt = afni_fgets( buf , 8192 , fp ) ; /* read next line */
10489 if( cpt == NULL ) break ; /* end of input? */
10490 str_echo = THD_zzprintf(str_echo," : %s",cpt) ;
10491 fvv = SYM_expand_ranges( ncol-1 , nSymStim,SymStim , buf ) ;
10492 if( fvv == NULL || fvv->nvec < 1 ) continue ;
10493 far = (float **)realloc((void *)far , sizeof(float *)*(nr+fvv->nvec)) ;
10494 for( iv=0 ; iv < fvv->nvec ; iv++ ) far[nr++] = fvv->fvar[iv].ar ;
10495 free((void *)fvv->fvar) ; free((void *)fvv) ;
10496 }
10497 fclose(fp) ;
10498 }
10499 if( nr == 0 ) GLT_ERR ;
10500 *nrows = nr ;
10501 array_to_matrix( nr , ncol , far , cmat ) ;
10502
10503 for( ii=0 ; ii < nr ; ii++ ) free((void *)far[ii]) ;
10504 free((void *)far) ;
10505
10506 if( !AFNI_noenv("AFNI_GLTSYM_PRINT") ){
10507 printf("------------------------------------------------------------\n");
10508 printf("GLT matrix from '%s':\n",fname) ;
10509 if( str_echo != NULL ){ printf("%s",str_echo); free(str_echo); }
10510 matrix_print( *cmat ) ;
10511 }
10512 }
10513
10514 /** check for all zero rows, which will cause trouble later **/
10515
10516 for( ii=0 ; ii < *nrows ; ii++ ){
10517 for( jj=0 ; jj < ncol && cmat->elts[ii][jj] == 0.0 ; jj++ ) ; /* nada */
10518 if( jj == ncol )
10519 ERROR_message("row #%d of matrix '%s' is all zero!", ii+1 , fname ) ;
10520 }
10521 EXRETURN ;
10522 }
10523
10524 /*---------------------------------------------------------------------------*/
10525
vstep_print(void)10526 static void vstep_print(void)
10527 {
10528 static int nn=0 ;
10529 static char xx[10] = "0123456789" ;
10530 fprintf(stderr , "%c" , xx[nn%10] ) ;
10531 if( nn%10 == 9) fprintf(stderr,".") ;
10532 nn++ ;
10533 }
10534
10535 /***************************************************************************/
10536 /** Functions for basis function expansion of impulse response function. **/
10537 /***************************************************************************/
10538
10539 /*--------------------------------------------------------------------------*/
10540 /*! Evaluate a basis expansion, given the weights for each function
10541 in wt[] and the point of evaluation.
10542 ----------------------------------------------------------------------------*/
10543
basis_evaluation(basis_expansion * be,float * wt,float x)10544 float basis_evaluation( basis_expansion *be , float *wt , float x )
10545 {
10546 float sum=0.0 ;
10547 int ii ;
10548
10549 if( x >= be->tbot && x <= be->ttop ){
10550 for( ii=0 ; ii < be->nfunc ; ii++ )
10551 sum += wt[ii] * basis_funceval( be->bfunc[ii] , x ) ;
10552 }
10553
10554 return sum ;
10555 }
10556
10557 /*--------------------------------------------------------------------------*/
10558 /*! Tent basis function:
10559 - 0 for x outside bot..top range
10560 - piecewise linear and equal to 1 at x=mid
10561 ----------------------------------------------------------------------------*/
10562
basis_tent(float x,float bot,float mid,float top,void * q)10563 static float basis_tent( float x, float bot, float mid, float top, void *q )
10564 {
10565 float val ;
10566 if( x <= bot || x >= top ) val = 0.0f ;
10567 else if( x <= mid ) val = (x-bot)/(mid-bot) ;
10568 else val = (top-x)/(top-mid) ;
10569 #if 0
10570 ININFO_message("basis_tent(x=%g,bot=%g,mid=%g,top=%g)=%g",x,bot,mid,top,val) ;
10571 #endif
10572 return val ;
10573 }
10574
10575 /*--------------------------------------------------------------------------*/
10576 #undef CA
10577 #define CA 0.5f /* negative of slope at x=1 */
hh_csplin(float y)10578 static float hh_csplin( float y ) /* for CSPLIN */
10579 {
10580 float yy = fabsf(y) ;
10581 if( yy >= 2.0f ) return 0.0f ;
10582 if( yy >= 1.0f ) return -CA*(-4.0f+yy*(8.0f+yy*(-5.0f+yy))) ;
10583 return 1.0f+yy*yy*((2.0f-CA)*yy-(3.0f-CA)) ;
10584 }
10585 #undef CA
10586 /*--------------------------------------------------------------------------*/
10587 /*! CSPLIN: Cardinal spline basis function: [15 Mar 2007]
10588 ----------------------------------------------------------------------------*/
10589
basis_csplin(float x,float a,float dx,float flag,void * q)10590 static float basis_csplin( float x, float a, float dx, float flag, void *q )
10591 {
10592 float y=(x-a)/dx , bot=-2.0f , top=2.0f , val ; int gg=(int)flag ;
10593 switch(gg){
10594 case -2: bot = 0.0f ; break ; /* at left edge */
10595 case -1: bot = -1.0f ; break ; /* 1 in from left edge */
10596 case 1: top = 1.0f ; break ; /* 1 in from right edge */
10597 case 2: top = 0.0f ; break ; /* at right edge */
10598 }
10599 bot -= 0.0009f ; top += 0.0009f ;
10600 if( y < bot || y > top ) val = 0.0f ;
10601 else val = hh_csplin(y) ;
10602 #if 0
10603 ININFO_message("basis_csplin(x=%g,a=%g,dx=%g,flag=%d)=%g [bot=%g top=%g y=%g]",
10604 x,a,dx,gg,val , bot,top,y ) ;
10605 #endif
10606 return val ;
10607 }
10608
10609 /*--------------------------------------------------------------------------*/
10610 /* Basis function that is 1 inside the bot..top interval, 0 outside of it.
10611 ----------------------------------------------------------------------------*/
10612
basis_one(float x,float bot,float top,float junk,void * q)10613 static float basis_one( float x, float bot, float top, float junk, void *q )
10614 {
10615 float eps=0.0009f ;
10616 if( x < bot-eps || x > top+eps ) return 0.0f ;
10617 return 1.0f ;
10618 }
10619
10620 /*--------------------------------------------------------------------------*/
10621 /* Cosine basis function:
10622 - 0 for x outside bot..top range
10623 - cos(freq*(x-bot)) otherwise.
10624 ----------------------------------------------------------------------------*/
10625
basis_cos(float x,float bot,float top,float freq,void * q)10626 static float basis_cos( float x, float bot, float top, float freq, void *q )
10627 {
10628 float eps=0.0009f ;
10629 if( x < bot-eps || x > top+eps ) return 0.0f ;
10630 return (float)cosf(freq*(x-bot)) ;
10631 }
10632
10633 /*--------------------------------------------------------------------------*/
10634 /* Sine basis function:
10635 - 0 for x outside bot..top range
10636 - sin(freq*(x-bot)) otherwise.
10637 ----------------------------------------------------------------------------*/
10638
basis_sin(float x,float bot,float top,float freq,void * q)10639 static float basis_sin( float x, float bot, float top, float freq, void *q )
10640 {
10641 if( x <= bot || x >= top ) return 0.0f ;
10642 return (float)sinf(freq*(x-bot)) ;
10643 }
10644
10645 /*--------------------------------------------------------------------------*/
10646 /* Gamma variate basis function
10647 - 0 for x outside range 0..top
10648 - x^b * exp(-x/c), scaled to peak value=1, otherwise
10649 ----------------------------------------------------------------------------*/
10650
basis_gam(float x,float b,float c,float top,void * q)10651 static float basis_gam( float x, float b, float c, float top, void *q )
10652 {
10653 if( x <= 0.0f || x > top ) return 0.0f ;
10654 return (float)(pow(x/(b*c),b)*exp(b-x/c)) ;
10655 }
10656
10657 /*---------- TWOGAM function; c is ignored [06 Jan 2018] ----------*/
10658
basis_twogam(float x,float b,float c,float top,void * q)10659 static float basis_twogam( float x , float b , float c , float top , void *q )
10660 {
10661 float *fq = (float *)q ;
10662 float p1,p2 , rr , q1,q2 , g1,g2 ;
10663 if( x <= 0.0f || x > top || q == NULL ) return 0.0f ;
10664 p1 = fq[0] ; q1=fq[1] ; rr = fq[2] ; p2 = fq[3] ; q2 = fq[4] ;
10665 g1 = basis_gam( x , p1,q1 , top , NULL ) ;
10666 g2 = basis_gam( x , p2,q2 , top , NULL ) ;
10667 return b*(g1-rr*g2) ; /* b is scale factor */
10668 }
10669
10670 /*---------- convert peak and width to p and q for GAM [06 Jan 2018] ----------*/
10671
gam_peak_fwhm_convert(float peak,float fwhm)10672 static float_pair gam_peak_fwhm_convert( float peak , float fwhm )
10673 {
10674 float_pair result = {0.0f,0.0f} ;
10675 double_pair pq ;
10676 float p , q ;
10677
10678 if( peak <= 0.0f || fwhm <= 0.0f ) return result ;
10679
10680 #if 1
10681 pq = gam_find_pq( (double)peak , (double)fwhm ) ; /* cs_gamfit.c */
10682 p = pq.a ; q = pq.b ;
10683 #else
10684 p = (2.35f*peak/fwhm) ; p = p*p ; q = peak/p ;
10685 #endif
10686
10687 INFO_message("GAM conversion: peak=%g fwhm=%g -> p=%g q=%g",peak,fwhm,p,q) ;
10688 if( p <= 0.0f || q <= 0.0f )
10689 ERROR_exit("GAM conversion from peak+fwhm to p,q parameters fails :(") ;
10690
10691 result.a = p ; result.b = q ; return result ;
10692 }
10693
10694 /*--------------------------------------------------------------------------*/
10695 /* MION basis function [12 Jul 2010] */
10696
basis_mion(float x,float b,float c,float top,void * q)10697 static float basis_mion( float x, float b, float c, float top, void *q )
10698 {
10699 if( x <= 0.0f || x > 60.0f ) return 0.0f ;
10700
10701 return 16.4486f * ( -0.184f/ 1.5f * expf(-x/ 1.5f)
10702 +0.330f/ 4.5f * expf(-x/ 4.5f)
10703 +0.670f/13.5f * expf(-x/13.5f) ) ;
10704 }
10705
10706 /*--------------------------------------------------------------------------*/
10707 /* MIONN basis function [02 Apr 2012] */
10708
basis_mionn(float x,float b,float c,float top,void * q)10709 static float basis_mionn( float x, float b, float c, float top, void *q )
10710 {
10711 if( x <= 0.0f || x > 60.0f ) return 0.0f ;
10712
10713 return -16.4486f * ( -0.184f/ 1.5f * expf(-x/ 1.5f)
10714 +0.330f/ 4.5f * expf(-x/ 4.5f)
10715 +0.670f/13.5f * expf(-x/13.5f) ) ;
10716 }
10717
10718 /*--------------------------------------------------------------------------*/
10719 /* SPMG basis functions (corrected 29 May 2007, I hope) */
10720
10721 #undef SPM_A1
10722 #undef SPM_A2
10723 #undef SPM_P1
10724 #undef SPM_P2
10725
10726 #define SPM_A1 0.0083333333 /* A * exp(-x) * x^P */
10727 #define SPM_P1 5.0 /* not 4.0 -- 29 May 2007 ! */
10728 #define SPM_A2 1.274527e-13
10729 #define SPM_P2 15.0
10730
basis_spmg1(float x,float a,float b,float c,void * q)10731 static float basis_spmg1( float x, float a, float b, float c, void *q )
10732 {
10733 if( x <= 0.0f || x >= 25.0f ) return 0.0f ;
10734 return (float)(exp(-x)*( SPM_A1*pow(x,SPM_P1)
10735 -SPM_A2*pow(x,SPM_P2) )) ;
10736 }
10737
10738 /*--------------------------- d/dx of the above ----------------------------*/
10739
basis_spmg2(float x,float a,float b,float c,void * q)10740 static float basis_spmg2( float x, float a, float b, float c, void *q )
10741 {
10742 if( x <= 0.0f || x >= 25.0f ) return 0.0f ;
10743 return (float)(exp(-x)*( SPM_A1*pow(x,SPM_P1-1.0)*(SPM_P1-x)
10744 -SPM_A2*pow(x,SPM_P2-1.0)*(SPM_P2-x) )) ;
10745 }
10746
10747 /*--------------------------------------------------------------------------*/
10748
10749 #undef SPM_A3
10750 #undef SPM_P3
10751 #define SPM_A3 0.00869011 /* SPMG3 added 27 Jul 2007 -- per Gang Chen */
10752 #define SPM_P3 4.94057
10753
basis_spmg3(float x,float a,float b,float c,void * q)10754 static float basis_spmg3( float x, float a, float b, float c, void *q )
10755 {
10756 float d0 , cc ;
10757 if( x <= 0.0f || x >= 25.0f ) return 0.0f ;
10758 d0 = SPM_A3 * pow(x,SPM_P3) * exp(-x/1.01)
10759 - SPM_A2 * pow(x,SPM_P2) * exp(-x) ;
10760 cc = basis_spmg1( x,a,b,c,q ) ;
10761 return (100.0f*(cc-d0)) ;
10762 }
10763
10764 /*--------------------------------------------------------------------------*/
10765
waveform_SPMG1(float t)10766 static float waveform_SPMG1( float t ){ return basis_spmg1(t,0.0f,0.0f,0.0f,NULL); }
waveform_SPMG2(float t)10767 static float waveform_SPMG2( float t ){ return basis_spmg2(t,0.0f,0.0f,0.0f,NULL); }
waveform_SPMG3(float t)10768 static float waveform_SPMG3( float t ){ return basis_spmg3(t,0.0f,0.0f,0.0f,NULL); }
waveform_MION(float t)10769 static float waveform_MION ( float t ){ return basis_mion (t,0.0f,0.0f,0.0f,NULL); }
waveform_MIONN(float t)10770 static float waveform_MIONN( float t ){ return basis_mionn(t,0.0f,0.0f,0.0f,NULL); }
10771
10772 static float GAM_p , GAM_q , GAM_top ;
waveform_GAM(float t)10773 static float waveform_GAM( float t ){ return basis_gam(t,GAM_p,GAM_q,GAM_top,NULL); }
10774
10775 static float TWOGAM_parm[6] , TWOGAM_top ;
waveform_TWOGAM(float t)10776 static float waveform_TWOGAM( float t )
10777 {
10778 return basis_twogam( t , 1.0f , 0.0f , TWOGAM_top , TWOGAM_parm ) ;
10779 }
10780
10781 /*--------------------------------------------------------------------------*/
10782 /* f(t,T) = int( h(t-s) , s=0..min(t,T) )
10783 where h(t) = t^4 * exp(-t) /(4^4*exp(-4))
10784 Code generated by Maple.
10785 ----------------------------------------------------------------------------*/
10786
10787 #undef TPEAK4
10788 #define TPEAK4(TT) ((TT)/(1.0-exp(-0.25*(TT))))
10789
basis_block_hrf4(float tt,float TT)10790 static float basis_block_hrf4( float tt , float TT )
10791 {
10792 register double t26, t2, t4, t1, t42, t12, t34, t35, t16, t46, t,L ;
10793 double w ;
10794
10795 if( tt <= 0.0f || tt >= (TT+15.0f) ) return 0.0f ;
10796
10797 t = tt ; L = TT ; t4 = exp(0.4e1 - t);
10798 if( t < L ){ L = t ; t16 = 54.5982 ; }
10799 else { t16 = exp(4.0-t+L) ; }
10800
10801 t1 = t * t;
10802 t2 = t1 * t1;
10803 t4 = exp(4.0 - t);
10804 t12 = t1 * t;
10805 t26 = t16 * L;
10806 t34 = L * L;
10807 t35 = t16 * t34;
10808 t42 = t16 * t34 * L;
10809 t46 = t34 * t34;
10810
10811 w = -t2 * t4 / 0.256e3 - 0.3e1 / 0.32e2 * t4 - 0.3e1 / 0.32e2 * t4 * t
10812 - 0.3e1 / 0.64e2 * t4 * t1 - t4 * t12 / 0.64e2 + t16 * t2 / 0.256e3
10813 + 0.3e1 / 0.32e2 * t16 + 0.3e1 / 0.32e2 * t16 * t
10814 + 0.3e1 / 0.64e2 * t1 * t16 + t16 * t12 / 0.64e2 - 0.3e1 / 0.32e2 * t26
10815 - 0.3e1 / 0.32e2 * t26 * t - 0.3e1 / 0.64e2 * t1 * t26
10816 - t26 * t12 / 0.64e2 + 0.3e1 / 0.64e2 * t35 + 0.3e1 / 0.64e2 * t35 * t
10817 + 0.3e1 / 0.128e3 * t1 * t35 - t42 / 0.64e2 - t42 * t / 0.64e2
10818 + t16 * t46 / 0.256e3 ;
10819 return (float)w ;
10820 }
10821
10822 /*----------------------------------------------------------------------------*/
10823 /* for BLOCK4, dmBLOCK4, and dmUBLOCK4:
10824 t = time of evaluation
10825 T = duration
10826 peak = if( peak > 0 ) ==> arrange so peak amplitude of curve is 'peak'
10827 else if( peak == 0 ) ==> let amplitude come from duration, and
10828 amplitude(duration=big) = 1
10829 else if( peak < 0 ) ==> let amplitude come from duration, with
10830 amplitude(duration=-peak) = 1
10831 *//*--------------------------------------------------------------------------*/
10832
basis_block4_NEW(float t,float T,float peak,float junk,void * q)10833 static float basis_block4_NEW( float t, float T, float peak, float junk, void *q )
10834 {
10835 float w , tp , pp , TT ;
10836
10837 w = basis_block_hrf4(t,T) ; /* function value, but need to alter amplitude */
10838
10839 if( w > 0.0f ){
10840 if( peak > 0.0f ){ TT = T ; }
10841 else if( peak == 0.0f ){ TT = 99.9f ; peak = 1.0f ; }
10842 else { TT = -peak ; peak = 1.0f ; }
10843 tp = TPEAK4(TT) ; pp = basis_block_hrf4(tp,TT) ;
10844 if( pp > 0.0f ) w *= peak / pp ;
10845 }
10846
10847 return w ;
10848 }
10849
basis_block4_OLD(float t,float T,float peak,float junk,void * q)10850 static float basis_block4_OLD( float t, float T, float peak, float junk, void *q )
10851 {
10852 float w , tp , pp ;
10853
10854 w = basis_block_hrf4(t,T) ;
10855
10856 if( w > 0.0f && peak > 0.0f ){
10857 tp = TPEAK4(T) ; pp = basis_block_hrf4(tp,T) ;
10858 if( pp > 0.0f ) w *= peak / pp ;
10859 }
10860
10861 return w ;
10862 }
10863
10864 /*--------------------------------------------------------------------------*/
10865 /* f(t,T) = int( h(t-s) , s=0..min(t,T) )
10866 where h(t) = t^5 * exp(-t) /(5^5*exp(-5))
10867 Code generated by Maple.
10868 ----------------------------------------------------------------------------*/
10869
10870 #undef TPEAK5
10871 #define TPEAK5(TT) ((TT)/(1.0-exp(-0.2*(TT))))
10872
basis_block_hrf5(float tt,float TT)10873 static float basis_block_hrf5( float tt, float TT )
10874 {
10875 register double t , T ;
10876 register double t2,t3,t4,t5,t6,t7,t9,t10,t11,t14,t20,t25,t28,t37,t57 ;
10877 double w ;
10878
10879 if( tt <= 0.0f || tt >= (TT+15.0f) ) return 0.0f ;
10880
10881 t = tt ; T = TT ;
10882
10883 #if 1
10884 t2 = exp(-t) ;
10885 if( t <= T ){ t3 = t ; t4 = 1.0/t2 ; }
10886 else { t3 = T ; t4 = exp(T) ; }
10887 t2 *= 148.413 ; /* 148.413 = exp(5) */
10888 #else
10889 t2 = exp(0.5e1 - t);
10890 t3 = (t <= T ? t : T);
10891 t4 = exp(t3);
10892 #endif
10893 t5 = t * t;
10894 t6 = t5 * t5;
10895 t7 = t6 * t;
10896 t9 = t3 * t3;
10897 t10 = t9 * t9;
10898 t11 = t4 * t10;
10899 t14 = t4 * t9 * t3;
10900 t20 = t4 * t3;
10901 t25 = t4 * t9;
10902 t28 = t5 * t;
10903 t37 = -0.120e3 + t4 * t7 + 0.5e1 * t11 - 0.20e2 * t14 - t4 * t10 * t3
10904 - 0.10e2 * t14 * t5 - 0.120e3 * t20 * t - 0.20e2 * t14 * t
10905 + 0.30e2 * t25 * t5 + 0.10e2 * t25 * t28 + 0.5e1 * t11 * t
10906 + 0.20e2 * t4 * t28 + 0.60e2 * t25 * t;
10907 t57 = -0.5e1 * t20 * t6 - 0.20e2 * t20 * t28 - 0.60e2 * t20 * t5
10908 - 0.5e1 * t6 - 0.20e2 * t28 + 0.120e3 * t4 - 0.120e3 * t
10909 - 0.120e3 * t20 + 0.60e2 * t25 - t7 - 0.60e2 * t5 + 0.120e3 * t4 * t
10910 + 0.60e2 * t4 * t5 + 0.5e1 * t4 * t6;
10911 w = t2 * (t37 + t57) / 0.3125e4;
10912
10913 return (float)w ;
10914 }
10915
10916 /*--------------------------------------------------------------------------*/
10917
10918
basis_block5_NEW(float t,float T,float peak,float junk,void * q)10919 static float basis_block5_NEW( float t, float T, float peak, float junk, void *q )
10920 {
10921 float w , tp , pp , TT ;
10922
10923 w = basis_block_hrf5(t,T) ;
10924
10925 if( w > 0.0f ){
10926 if( peak > 0.0f ){ TT = T ; }
10927 else if( peak == 0.0f ){ TT = 99.9f ; peak = 1.0f ; }
10928 else { TT = -peak ; peak = 1.0f ; }
10929 tp = TPEAK5(TT) ; pp = basis_block_hrf5(tp,TT) ;
10930 if( pp > 0.0f ) w *= peak / pp ;
10931 }
10932
10933 return w ;
10934 }
10935
basis_block5_OLD(float t,float T,float peak,float junk,void * q)10936 static float basis_block5_OLD( float t, float T, float peak, float junk, void *q )
10937 {
10938 float w , tp , pp ;
10939
10940 w = basis_block_hrf5(t,T) ;
10941
10942 if( w > 0.0f && peak > 0.0f ){
10943 tp = TPEAK5(T) ; pp = basis_block_hrf5(tp,T) ;
10944 if( pp > 0.0f ) w *= peak / pp ;
10945 }
10946
10947 return w ;
10948 }
10949
10950 /*--------------------------------------------------------------------------*/
10951 /* Legendre polynomial basis function
10952 - 0 for x outside range bot..top
10953 - P_n(x), x scaled to be -1..1 over range bot..top (for integer n >= 0)
10954 ----------------------------------------------------------------------------*/
10955
basis_legendre(float x,float bot,float top,float n,void * q)10956 static float basis_legendre( float x, float bot, float top, float n, void *q )
10957 {
10958 float xq ; int m ;
10959
10960 x = 2.0f*(x-bot)/(top-bot) - 1.0f ; /* now in range -1..1 */
10961
10962 if( x < -1.000001f || x > 1.000001f ) return 0.0f ;
10963
10964 xq = x*x ; m = (int)n ; if( m < 0 ) return 0.0f ;
10965
10966 switch( m ){
10967 case 0: return 1.0f ;
10968 case 1: return x ;
10969 case 2: return (3.0f*xq-1.0f)/2.0f ;
10970 case 3: return (5.0f*xq-3.0f)*x/2.0f ;
10971 case 4: return ((35.0f*xq-30.0f)*xq+3.0f)/8.0f ;
10972 case 5: return ((63.0f*xq-70.0f)*xq+15.0f)*x/8.0f ;
10973 case 6: return (((231.0f*xq-315.0f)*xq+105.0f)*xq-5.0f)/16.0f ;
10974 case 7: return (((429.0f*xq-693.0f)*xq+315.0f)*xq-35.0f)*x/16.0f ;
10975
10976 case 8: return ((((6435.0f*xq-12012.0f)*xq+6930.0f)*xq-1260.0f)*xq+35.0f)
10977 /128.0f;
10978
10979 case 9: return ((((12155.0f*xq-25740.0f)*xq+18018.0f)*xq-4620.0f)*xq+315.0f)
10980 *x/128.0f ;
10981
10982 /** orders above 9 added 14 Aug 2007 **/
10983
10984 case 10:
10985 return -0.24609375e0 + (0.1353515625e2 + (-0.1173046875e3 +
10986 (0.3519140625e3 + (-0.42732421875e3 + 0.18042578125e3 * xq)
10987 * xq) * xq) * xq) * xq;
10988
10989 case 11:
10990 return (-0.270703125e1 + (0.5865234375e2 + (-0.3519140625e3 +
10991 (0.8546484375e3 + (-0.90212890625e3 + 0.34444921875e3 * xq)
10992 * xq) * xq) * xq) * xq) * x;
10993
10994 case 12:
10995 return 0.2255859375e0 + (-0.17595703125e2 + (0.2199462890625e3 +
10996 (-0.99708984375e3 + (0.20297900390625e4 + (-0.1894470703125e4
10997 + 0.6601943359375e3 * xq) * xq) * xq) * xq) * xq)
10998 * xq;
10999
11000 case 13:
11001 return (0.29326171875e1 + (-0.87978515625e2 + (0.7478173828125e3 +
11002 (-0.270638671875e4 + (0.47361767578125e4 + (-0.3961166015625e4
11003 + 0.12696044921875e4 * xq) * xq) * xq) * xq) * xq)
11004 * xq) * x;
11005
11006 case 14:
11007 return -0.20947265625e0 + (0.2199462890625e2 + (-0.37390869140625e3 +
11008 (0.2368088378906250e4 + (-0.710426513671875e4 +
11009 (0.1089320654296875e5 + (-0.825242919921875e4 +
11010 0.244852294921875e4 * xq) * xq) * xq) * xq) * xq)
11011 * xq) * xq;
11012
11013 case 15:
11014 return (-0.314208984375e1 + (0.12463623046875e3 + (-0.142085302734375e4
11015 + (0.7104265136718750e4 + (-0.1815534423828125e5 +
11016 (0.2475728759765625e5 + (-0.1713966064453125e5 +
11017 0.473381103515625e4 * xq) * xq) * xq) * xq)
11018 * xq) * xq) * xq) * x;
11019
11020 case 16:
11021 return 0.196380615234375e0 + (-0.26707763671875e2 + (0.5920220947265625e3
11022 + (-0.4972985595703125e4 + (0.2042476226806641e5 +
11023 (-0.4538836059570312e5 + (0.5570389709472656e5 +
11024 (-0.3550358276367188e5 + 0.9171758880615234e4 * xq) * xq)
11025 * xq) * xq) * xq) * xq) * xq) * xq;
11026
11027 case 17:
11028 return (0.3338470458984375e1 + (-0.1691491699218750e3 +
11029 (0.2486492797851562e4 + (-0.1633980981445312e5 +
11030 (0.5673545074462891e5 + (-0.1114077941894531e6 +
11031 (0.1242625396728516e6 + (-0.7337407104492188e5 +
11032 0.1780400253295898e5 * xq) * xq) * xq) * xq)
11033 * xq) * xq) * xq) * xq) * x;
11034
11035 case 18:
11036 return -0.1854705810546875e0 + (0.3171546936035156e2 +
11037 (-0.8880331420898438e3 + (0.9531555725097656e4 +
11038 (-0.5106190567016602e5 + (0.1531857170104980e6 +
11039 (-0.2692355026245117e6 + (0.2751527664184570e6 +
11040 (-0.1513340215301514e6 + 0.3461889381408691e5 * xq) * xq)
11041 * xq) * xq) * xq) * xq) * xq) * xq) * xq;
11042
11043 case 19:
11044 return (-0.3523941040039062e1 + (0.2220082855224609e3 +
11045 (-0.4084952453613281e4 + (0.3404127044677734e5 +
11046 (-0.1531857170104980e6 + (0.4038532539367676e6 +
11047 (-0.6420231216430664e6 + (0.6053360861206055e6 +
11048 (-0.3115700443267822e6 + 0.6741574058532715e5 * xq) * xq)
11049 * xq) * xq) * xq) * xq) * xq) * xq) * xq) * x;
11050
11051 case 20:
11052 return 0.1761970520019531e0 + (-0.3700138092041016e2 +
11053 (0.1276547641754150e4 + (-0.1702063522338867e5 +
11054 (0.1148892877578735e6 + (-0.4442385793304443e6 +
11055 (0.1043287572669983e7 + (-0.1513340215301514e7 +
11056 (0.1324172688388824e7 + (-0.6404495355606079e6 +
11057 0.1314606941413879e6 * xq) * xq) * xq) * xq) * xq)
11058 * xq) * xq) * xq) * xq) * xq;
11059
11060 } /* end of switch on m */
11061
11062 /** if here, m > 20 ==> use recurrence relation **/
11063
11064 { float pk=0, pkm1, pkm2 ; int k ;
11065 pkm2 = basis_legendre( x , -1.0f , 1.0f , 19.0f , NULL ) ;
11066 pkm1 = basis_legendre( x , -1.0f , 1.0f , 20.0f , NULL ) ;
11067 for( k=21 ; k <= m ; k++ , pkm2=pkm1 , pkm1=pk )
11068 pk = ((2.0f*k-1.0f)*x*pkm1 - (k-1.0f)*pkm2)/k ;
11069 return pk ;
11070 }
11071 }
11072
11073 #undef POLY_MAX
11074 #define POLY_MAX 20 /* max order allowed in function above */
11075
11076 /*--------------------------------------------------------------------------*/
11077 #define ITT 19 /* index for symbol 't' */
11078 #define IXX 23 /* 'x' */
11079 #define IZZ 25 /* 'z' */
11080 /*------------------------------------------------------*/
11081 /*! Basis function given by a user-supplied expression. */
11082
basis_expr(float x,float bot,float top,float dtinv,void * q)11083 static float basis_expr( float x, float bot, float top, float dtinv, void *q )
11084 {
11085 PARSER_code *pc = (PARSER_code *)q ;
11086 double atoz[26] , val ; float eps=0.0009f ;
11087
11088 if( x < bot-eps || x > top+eps ) return 0.0f ;
11089 memset(atoz,0,sizeof(double)*26) ; /* set to 0 [24 Mar 2009] */
11090 atoz[ITT] = x ; /* t = true time from stim */
11091 atoz[IXX] = (x-bot)*dtinv ; /* x = scaled to [0,1] */
11092 atoz[IZZ] = 2.0*atoz[IXX] - 1.0 ; /* z = scaled to [-1,1] */
11093 val = PARSER_evaluate_one( pc , atoz ) ;
11094 return (float)val ;
11095 }
11096
11097 /*==========================================================================*/
11098 /**---------- Implementation of the Cox WAV function from waver.c ---------**/
11099 /*==========================================================================*/
11100
11101 /*----------------------------------------------------------------*/
11102
11103 static float WAV_rise_start, WAV_fall_start ,
11104 WAV_fall_end , WAV_restore_end ;
11105
11106 static float WAV_delay_time = 2.0f ,
11107 WAV_rise_time = 4.0f ,
11108 WAV_fall_time = 6.0f ,
11109 WAV_undershoot = 0.2f ,
11110 WAV_restore_time = 2.0f ;
11111
11112 /*----------------------------------------------------------------*/
11113
setup_WAV_constants(void)11114 static void setup_WAV_constants(void)
11115 {
11116 WAV_rise_start = WAV_delay_time ;
11117 WAV_fall_start = WAV_rise_start + WAV_rise_time ;
11118 WAV_fall_end = WAV_fall_start + WAV_fall_time ;
11119 WAV_restore_end = WAV_fall_end + WAV_restore_time ;
11120 return ;
11121 }
11122
11123 /*----------------------------------------------------------------
11124 Function that transitions from 0 to 1 over input x in [0,1].
11125 ------------------------------------------------------------------*/
11126
11127 #define ZT_FAC 0.50212657f
11128 #define ZT_ADD 0.99576486f
11129
ztone(float x)11130 static INLINE float ztone( float x )
11131 {
11132 register double y ;
11133
11134 if( x <= 0.0f ) return 0.0f ; else if( x >= 1.0f ) return 1.0f ;
11135
11136 y = (0.5*PI) * ( 1.6 * x - 0.8 ) ;
11137 return (float)(ZT_FAC * ( tanh(tan(y)) + ZT_ADD )) ;
11138 }
11139
11140 /*----------------------------------------------------------------*/
11141 /*! Basic WAV waveform at time lag t */
11142
waveform_WAV(float t)11143 static float waveform_WAV( float t )
11144 {
11145 if( t < WAV_rise_start )
11146 return 0.0f ;
11147
11148 if( t < WAV_fall_start )
11149 return ztone( (t-WAV_rise_start)/WAV_rise_time ) ;
11150
11151 if( t < WAV_fall_end )
11152 return (1.0f+WAV_undershoot) * ztone( (WAV_fall_end-t)/WAV_fall_time )
11153 - WAV_undershoot ;
11154
11155 if( t < WAV_restore_end )
11156 return -WAV_undershoot * ztone( (WAV_restore_end-t)/WAV_restore_time ) ;
11157
11158 return 0.0f ;
11159 }
11160
11161 /*----------------------------------------------------------------*/
11162 /* WFUN convolution for various basis functions with durations. */
11163
11164 #define WTYPE_SPMG1 1
11165 #define WTYPE_SPMG2 2
11166 #define WTYPE_SPMG3 3
11167
11168 #define WTYPE_GAM 7
11169 #define WTYPE_MION 8
11170 #define WTYPE_WAV 9
11171 #define WTYPE_MIONN 10
11172
11173 #define WTYPE_TWOGAM 17
11174
11175 typedef struct {
11176 int wtype , nfun ;
11177 float dur , parm[9] ;
11178 float *fun ;
11179 } WFUN_storage ;
11180
11181 #undef WFUN_equals
11182 #define WFUN_equals(wa,wb) ( (wa).wtype == (wb).wtype && \
11183 (wa).dur == (wb).dur && \
11184 (wa).parm[0] == (wb).parm[0] && \
11185 (wa).parm[1] == (wb).parm[1] && \
11186 (wa).parm[2] == (wb).parm[2] && \
11187 (wa).parm[3] == (wb).parm[3] && \
11188 (wa).parm[4] == (wb).parm[4] && \
11189 (wa).parm[5] == (wb).parm[5] && \
11190 (wa).parm[6] == (wb).parm[6] && \
11191 (wa).parm[7] == (wb).parm[7] && \
11192 (wa).parm[8] == (wb).parm[8] )
11193
11194 static int nWFUNS = 0 ;
11195 static WFUN_storage *WFUNS = NULL ;
11196
11197 /* "micro time" resolution for this convolution */
11198 #undef WFUNDT
11199 #define WFUNDT 0.01f
11200
11201 /*----------------------------------------------------------------*/
11202 /* Return value is index in WFUNS of the function value struct. */
11203
setup_WFUN_function(int wtyp,float dur,float * parm)11204 static int setup_WFUN_function( int wtyp , float dur , float *parm )
11205 {
11206 float val,tt,vmax,vthr,aval ;
11207 int nlag , ii,jj,have_nz ;
11208 WFUN_storage ws ;
11209 float *hhrf=NULL ; int nhrf, ahrf;
11210 float (*wavfun)(float) = NULL ;
11211 char msg[222] ;
11212
11213 ENTRY("setup_WFUN_function") ;
11214
11215 if( dur < 0.0f ) dur = 0.0f ;
11216 ws.wtype = wtyp ; ws.dur = dur ;
11217 ws.parm[0] = ws.parm[1] = ws.parm[2] = ws.parm[3] =
11218 ws.parm[4] = ws.parm[5] = ws.parm[6] =
11219 ws.parm[7] = ws.parm[8] = 0.0f ;
11220
11221 switch( wtyp ){
11222
11223 default: RETURN(-1) ; /* bad input */
11224
11225 case WTYPE_WAV:
11226 if( parm != NULL ){
11227 WAV_delay_time = MAX(0.0f,parm[0]) ; /* input params */
11228 WAV_rise_time = MAX(0.1f,parm[1]) ;
11229 WAV_fall_time = MAX(0.1f,parm[2]) ;
11230 WAV_undershoot = MAX(0.0f,parm[3]) ;
11231 WAV_restore_time = MAX(0.1f,parm[4]) ;
11232 } else {
11233 WAV_delay_time = 2.0f ; /* default params */
11234 WAV_rise_time = 4.0f ;
11235 WAV_fall_time = 6.0f ;
11236 WAV_undershoot = 0.2f ;
11237 WAV_restore_time = 2.0f ;
11238 }
11239 setup_WAV_constants() ;
11240 ws.parm[0] = WAV_rise_start ;
11241 ws.parm[1] = WAV_fall_start ;
11242 ws.parm[2] = WAV_fall_end ;
11243 ws.parm[3] = WAV_restore_end ;
11244 wavfun = waveform_WAV ; /* func to be integrated */
11245
11246 sprintf(msg,
11247 "waveform setup: WAV(dur=%g,delay=%g,rise=%g,fall=%g,undershoot=%g,restore=%g)" ,
11248 dur,WAV_delay_time,WAV_rise_time,
11249 WAV_fall_time,WAV_undershoot,WAV_restore_time) ;
11250
11251 break ;
11252
11253 case WTYPE_SPMG1:
11254 wavfun = waveform_SPMG1 ;
11255 sprintf(msg,"waveform setup: SPMG1(dur=%g)",dur) ;
11256 break ; /* no params */
11257
11258 case WTYPE_SPMG2:
11259 wavfun = waveform_SPMG2 ;
11260 sprintf(msg,"waveform setup: SPMG2(dur=%g)",dur) ;
11261 break ;
11262
11263 case WTYPE_SPMG3:
11264 wavfun = waveform_SPMG3 ;
11265 sprintf(msg,"waveform setup: SPMG3(dur=%g)",dur) ;
11266 break ;
11267
11268 case WTYPE_MION:
11269 wavfun = waveform_MION ;
11270 sprintf(msg,"waveform setup: MION(dur=%g)",dur) ;
11271 break ;
11272
11273 case WTYPE_MIONN:
11274 wavfun = waveform_MIONN ;
11275 sprintf(msg,"waveform setup: MIONN(dur=%g)",dur) ;
11276 break ;
11277
11278 case WTYPE_GAM:
11279 wavfun = waveform_GAM ;
11280 ws.parm[0] = GAM_p = parm[0] ;
11281 ws.parm[1] = GAM_q = parm[1] ;
11282 GAM_top = GAM_p*GAM_q + 5.0f*sqrtf(GAM_p)*GAM_q ;
11283 sprintf(msg,"waveform setup: GAM(p=%g,q=%g,dur=%g)",GAM_p,GAM_q,dur) ;
11284 break ;
11285
11286 case WTYPE_TWOGAM: /* 06 Jan 2018 */
11287 wavfun = waveform_TWOGAM ;
11288 ws.parm[0] = TWOGAM_parm[0] = parm[0] ;
11289 ws.parm[1] = TWOGAM_parm[1] = parm[1] ;
11290 ws.parm[2] = TWOGAM_parm[2] = parm[2] ;
11291 ws.parm[3] = TWOGAM_parm[3] = parm[3] ;
11292 ws.parm[4] = TWOGAM_parm[4] = parm[4] ;
11293 ws.parm[5] = TWOGAM_parm[5] = parm[5] ;
11294 ws.parm[6] = TWOGAM_top = parm[6] ;
11295 sprintf(msg,"waveform setup: TWOGAM()") ;
11296 break ;
11297 }
11298
11299 /* check if we have a duplicate of an existing WFUN function */
11300
11301 for( ii=0 ; ii < nWFUNS ; ii++ )
11302 if( WFUN_equals(ws,WFUNS[ii]) ) RETURN(ii) ; /* found a match */
11303
11304 /**** must create a new WFUN function: ****/
11305
11306 INFO_message(msg) ;
11307
11308 /* create array of basic waveformm, convolved with a square wave */
11309
11310 nlag = 1 + (int)rint(dur/WFUNDT) ; /* number of convolution lags */
11311
11312 ahrf = 1024 ; nhrf = 0 ;
11313 hhrf = (float *)malloc(sizeof(float)*ahrf) ;
11314
11315 /* loop until we get nonzero values, then decline back to zero */
11316
11317 vmax = vthr = 0.001f ;
11318 for( have_nz=ii=0 ; ; ii++ ){
11319 tt = ii*WFUNDT ; /* ii-th output time */
11320
11321 for( val=0.0f,jj=0 ; jj < nlag && tt >= 0.0f ; jj++,tt-=WFUNDT )
11322 val += wavfun(tt) ; /* convolution */
11323
11324 aval = fabsf(val) ;
11325 if( aval != 0.0f ){
11326 have_nz++ ;
11327 if( aval > vmax ){ vmax = aval ; vthr = 0.0001f*vmax ; }
11328 } else if( ii > 99 && have_nz > 1 &&
11329 fabsf(hhrf[ii-1]) <= vthr && fabsf(hhrf[ii-2]) <= vthr &&
11330 fabsf(hhrf[ii-3]) <= vthr && fabsf(hhrf[ii-4]) <= vthr ){
11331 break ;
11332 }
11333
11334 if( ii >= ahrf ){
11335 ahrf += 1024 ; hhrf = (float *)realloc(hhrf,sizeof(float)*ahrf) ;
11336 }
11337 hhrf[ii] = val ;
11338 }
11339 nhrf = ii-3 ;
11340 hhrf = (float *)realloc(hhrf,sizeof(float)*nhrf) ;
11341
11342 ws.nfun = nhrf ; /* store array in struct */
11343 ws.fun = hhrf ;
11344
11345 /* scale array to have max abs value 1 */
11346
11347 vmax = 1.0f / vmax ;
11348 for( ii=0 ; ii < nhrf ; ii++ ) hhrf[ii] *= vmax ;
11349
11350 /* add struct to permanent storage */
11351
11352 WFUNS = (WFUN_storage *)realloc(WFUNS,sizeof(WFUN_storage)*(nWFUNS+1)) ;
11353 memcpy( WFUNS+nWFUNS , &ws , sizeof(WFUN_storage) ) ;
11354 nWFUNS++ ;
11355
11356 RETURN(nWFUNS-1) ; /* index of new struct */
11357 }
11358
11359 /*----------------------------------------------------------------*/
11360
basis_WFUN(float t,float fwav,float junk1,float junk2,void * q)11361 static float basis_WFUN( float t, float fwav, float junk1, float junk2, void *q )
11362 {
11363 int iwav = (int)fwav , ii ;
11364 int nhrf ;
11365 float *hhrf , xx ;
11366
11367 if( t < 0.0f || iwav < 0 || iwav >= nWFUNS ) return 0.0f ;
11368
11369 nhrf = WFUNS[iwav].nfun ;
11370 hhrf = WFUNS[iwav].fun ;
11371
11372 xx = t/WFUNDT ; ii = (int)xx ; xx = xx - ii ;
11373 if( ii >= nhrf ) return 0.0f ;
11374 if( ii == nhrf-1 ) return (1.0f-xx)*hhrf[ii] ;
11375 return ( xx*hhrf[ii+1] + (1.0f-xx)*hhrf[ii] ) ;
11376 }
11377
11378 /*==========================================================================*/
11379 /*------------------------ End of WAV function stuff -----------------------*/
11380 /*==========================================================================*/
11381
11382 /*--------------------------------------------------------------------------*/
11383 /* Take a string and generate a basis expansion structure from it.
11384 ----------------------------------------------------------------------------*/
11385
basis_parser(char * sym)11386 basis_expansion * basis_parser( char *sym )
11387 {
11388 basis_expansion *be ;
11389 char *cpt , *scp ;
11390 float bot=0.0f, top=0.0f ;
11391 int nn , nord=0 ;
11392
11393 ENTRY("basis_parser") ;
11394
11395 if( sym == NULL ) RETURN(NULL);
11396
11397 scp = strdup(sym) ; /* duplicate, for editing */
11398 cpt = strchr(scp,'(') ; /* find opening '(' */
11399 if( cpt != NULL ){ *cpt = '\0' ; cpt++ ; } /* cut string there */
11400
11401 be = (basis_expansion *)malloc(sizeof(basis_expansion)) ;
11402 be->name = NULL ; /* will be fixed later */
11403 be->symfun = strdup(sym) ; /* 06 Mar 2007 */
11404 be->modsub = NULL ; /* 12 Jul 2012 */
11405
11406 be->vmod = be->vfun = 0 ; /* 05 Dec 2008 */
11407
11408 be->no_iresp = 0 ; /* 07 Nov 2011 */
11409
11410 /*--- GAM(b,c) ---*/
11411
11412 if( strcmp(scp,"GAM") == 0 || strcmp(scp,"GAMpw") == 0 ){
11413
11414 int do_pq = (strcmp(scp,"GAMpw") == 0) ;
11415
11416 be->nfunc = 1 ;
11417 be->bfunc = (basis_func *)calloc(sizeof(basis_func),be->nfunc) ;
11418 if( cpt == NULL ){
11419 be->bfunc[0].a = 8.6f ; /* Mark Cohen's parameters */
11420 be->bfunc[0].b = 0.547f ; /* t_peak=4.7 FWHM=3.7 */
11421 be->bfunc[0].c = 11.1f ; /* return to zero-ish */
11422 be->bfunc[0].f = basis_gam ;
11423 be->tbot = 0.0f ; be->ttop = be->bfunc[0].c ;
11424 } else {
11425 float dur=-1.0f ;
11426 sscanf(cpt,"%f,%f,%f",&bot,&top,&dur) ;
11427 if( dur < 0.0f && (bot <= 0.0f || top <= 0.0f) ){
11428 ERROR_message("'GAM(%s' is illegal",cpt) ;
11429 ERROR_message(
11430 " Correct format: 'GAM(b,c)' with b > 0 and c > 0.");
11431 free((void *)be->bfunc); free((void *)be); free(scp); RETURN(NULL);
11432 }
11433 if( do_pq ){ /* 06 Jan 2018 */
11434 float_pair pq = gam_peak_fwhm_convert(bot,top) ;
11435 if( pq.a <= 0.0f || pq.b <= 0.0f ){
11436 ERROR_message("'GAMpw(%s' is illegal",cpt) ;
11437 free((void *)be->bfunc); free((void *)be); free(scp); RETURN(NULL);
11438 }
11439 bot = pq.a ; top = pq.b ;
11440 }
11441 if( dur < 0.0f ){ /* the olden way: no duration given */
11442 be->bfunc[0].a = bot ; /* t_peak = bot*top */
11443 be->bfunc[0].b = top ; /* FWHM = 2.35*sqrt(bot)*top */
11444 be->bfunc[0].c = bot*top + 9.9f*sqrtf(bot)*top ; /* long enough */
11445 be->bfunc[0].f = basis_gam ;
11446 be->tbot = 0.0f ; be->ttop = be->bfunc[0].c ;
11447 } else { /* duration given ==> integrate it */
11448 int iwav ; float parm[2] ;
11449 if( bot <= 0.0f ) bot = 8.6f ;
11450 if( top <= 0.0f ) top = 0.547f ;
11451 if( dur == 0.0f ) dur = 0.01f ;
11452 parm[0] = bot ; parm[1] = top ;
11453 iwav = setup_WFUN_function( WTYPE_GAM , dur , parm ) ;
11454 if( iwav < 0 ){
11455 ERROR_message("Can't setup GAM(%f,%f,%f) for some reason?!",bot,top,dur) ;
11456 free((void *)be); free(scp); RETURN(NULL);
11457 }
11458 be->tbot = 0.0f ; be->ttop = WFUNDT * WFUNS[iwav].nfun ;
11459 be->bfunc[0].f = basis_WFUN ;
11460 be->bfunc[0].a = (float)iwav ;
11461 be->bfunc[0].b = 0.0f ;
11462 be->bfunc[0].c = 0.0f ;
11463 }
11464 }
11465
11466 /*--- TWOGAM(p1,q1,r,p2,q2[,dur]) [06 Jan 2018] ---*/
11467
11468 } else if( strcmp(scp,"TWOGAM") == 0 || strcmp(scp,"TWOGAMpw") == 0 ){
11469 float dur=0.0f,p1=0.0f,q1=0.0f,rr=0.0f,p2=0.0f,q2=0.0f , b1,b2 ;
11470 float *fq=NULL ;
11471 int do_pq = (strcmp(scp,"TWOGAMpw") == 0) ;
11472
11473 be->nfunc = 1 ;
11474 be->bfunc = (basis_func *)calloc(sizeof(basis_func),be->nfunc) ;
11475 if( cpt == NULL ){
11476 ERROR_message("TWOGAM format is incorrect") ;
11477 free((void *)be->bfunc); free((void *)be); free(scp); RETURN(NULL);
11478 }
11479 sscanf(cpt,"%f,%f,%f,%f,%f,%f",&p1,&q1,&rr,&p2,&q2,&dur) ;
11480 if( p1 <= 0.0f || q1 <= 0.0f || p2 <= 0.0f || q2 <= 0.0f || dur < 0.0f || fabsf(rr) > 1.0f ){
11481 ERROR_message("'TWOGAM(%s' is illegal",cpt) ;
11482 free((void *)be->bfunc); free((void *)be); free(scp); RETURN(NULL);
11483 }
11484 if( do_pq ){
11485 float_pair pq1 = gam_peak_fwhm_convert(p1,q1) ;
11486 float_pair pq2 = gam_peak_fwhm_convert(p2,q2) ;
11487 if( pq1.a <= 0.0f || pq1.b <= 0.0f || pq2.a <= 0.0f || pq2.b <= 0.0f ){
11488 ERROR_message("'TWOGAMpw(%s' is illegal",cpt) ;
11489 free((void *)be->bfunc); free((void *)be); free(scp); RETURN(NULL);
11490 }
11491 p1 = pq1.a ; q1 = pq1.b ; p2 = pq2.a ; q2 = pq2.b ;
11492 }
11493 fq = (float *)malloc(sizeof(float)*7) ;
11494 fq[0] = p1 ; fq[1] = q1 ; fq[2] = rr ;
11495 fq[3] = p2 ; fq[4] = q2 ; fq[5] = dur ;
11496 b1 = p1*q1+9.9f*sqrtf(p1)*q1 ;
11497 b2 = p2*q2+9.9f*sqrtf(p2)*q2 ; fq[6] = MAX(b1,b2) ;
11498 if( dur == 0.0f ){
11499 float mx=0.0f , tt,vv ;
11500 be->bfunc[0].a = 1.0f ; /* scale factor */
11501 be->bfunc[0].b = 0.0f ; /* ignored */
11502 be->bfunc[0].c = fq[6] ; /* impulse duration */
11503 be->bfunc[0].f = basis_twogam ;
11504 be->bfunc[0].q = (void *)fq ; /* all params */
11505 be->tbot = 0.0f ; be->ttop = be->bfunc[0].c ;
11506 /* find max value, to get scale factor */
11507 for( tt=WFUNDT ; tt < be->ttop ; tt+=WFUNDT ){
11508 vv = basis_twogam( tt , 1.0f , 0.0f , be->ttop , (void *)fq ) ;
11509 vv = fabsf(vv) ; if( mx < vv ) mx = vv ;
11510 }
11511 be->bfunc[0].a = 1.0f / mx ;
11512 } else { /* duration given ==> integrate it */
11513 int iwav ;
11514 iwav = setup_WFUN_function( WTYPE_TWOGAM , dur , fq ) ;
11515 if( iwav < 0 ){
11516 ERROR_message("Can't setup TWOGAM(%s for some reason?!",cpt) ;
11517 free((void *)be); free(scp); RETURN(NULL);
11518 }
11519 be->tbot = 0.0f ; be->ttop = WFUNDT * WFUNS[iwav].nfun ;
11520 be->bfunc[0].f = basis_WFUN ;
11521 be->bfunc[0].a = (float)iwav ;
11522 be->bfunc[0].b = 0.0f ;
11523 be->bfunc[0].c = 0.0f ;
11524 }
11525
11526 /*--- TENT(bot,top,order) ---*/ /*-- add TENTzero 23 Jul 2010 --*/
11527
11528 } else if( strcmp(scp,"TENT") == 0 ||
11529 strcmp(scp,"TENTzero") == 0 ){
11530 float dx ; int zzz = (strstr(scp,"zero") != NULL) , bb ;
11531
11532 if( cpt == NULL ){
11533 ERROR_message("'%s' by itself is illegal",scp) ;
11534 ERROR_message(
11535 " Correct format: '%s(bot,top,n)' with bot < top and n > %d.",
11536 scp , (zzz) ? 2 : 1 ) ;
11537 free((void *)be); free(scp); RETURN(NULL);
11538 }
11539 sscanf(cpt,"%f,%f,%d",&bot,&top,&nord) ;
11540 if( bot >= top || nord < 2 || (nord < 3 && zzz) ){
11541 ERROR_message("'%s(%s' is illegal",scp,cpt) ;
11542 ERROR_message(
11543 " Correct format: '%s(bot,top,n)' with bot < top and n > %d.",
11544 scp , (zzz) ? 2 : 1 ) ;
11545 free((void *)be); free(scp); RETURN(NULL);
11546 }
11547 be->nfunc = (zzz) ? nord-2 : nord ;
11548 be->tbot = bot ; be->ttop = top ;
11549 be->bfunc = (basis_func *)calloc(sizeof(basis_func),be->nfunc) ;
11550 dx = (top-bot) / (nord-1) ;
11551
11552 bb = 0 ;
11553 if( !zzz ){
11554 be->bfunc[bb].f = basis_tent ;
11555 be->bfunc[bb].a = bot-0.00111f*dx ;
11556 be->bfunc[bb].b = bot ;
11557 be->bfunc[bb].c = bot+dx ;
11558 bb++ ;
11559 }
11560 for( nn=1 ; nn < nord-1 ; nn++,bb++ ){
11561 be->bfunc[bb].f = basis_tent ;
11562 be->bfunc[bb].a = bot + (nn-1)*dx ;
11563 be->bfunc[bb].b = bot + nn *dx ;
11564 be->bfunc[bb].c = bot + (nn+1)*dx ;
11565 }
11566 if( !zzz ){
11567 be->bfunc[bb].f = basis_tent ;
11568 be->bfunc[bb].a = bot + (nord-2)*dx ;
11569 be->bfunc[bb].b = top ;
11570 be->bfunc[bb].c = top + 0.00111f*dx ;
11571 }
11572
11573 /*--- CSPLIN(bot,top,order) ---*/ /*-- add CSPLINzero 23 Jul 2010 --*/
11574
11575 } else if( strcmp(scp,"CSPLIN") == 0 || /* 15 Mar 2007 */
11576 strcmp(scp,"CSPLINzero") == 0 ){
11577 float dx ; int zzz = (strstr(scp,"zero") != NULL) , bb , nbot,ntop ;
11578
11579 if( cpt == NULL ){
11580 ERROR_message("'%s' by itself is illegal",scp) ;
11581 ERROR_message(
11582 " Correct format: '%s(bot,top,n)' with bot < top and n > 3.",scp) ;
11583 free((void *)be); free(scp); RETURN(NULL);
11584 }
11585 sscanf(cpt,"%f,%f,%d",&bot,&top,&nord) ;
11586 if( bot >= top || nord < 4 ){
11587 ERROR_message("'%s(%s' is illegal",scp,cpt) ;
11588 ERROR_message(
11589 " Correct format: '%s(bot,top,n)' with bot < top and n > 3.",scp) ;
11590 free((void *)be); free(scp); RETURN(NULL);
11591 }
11592 be->nfunc = (zzz) ? (nord-2) : nord ;
11593 be->tbot = bot ; be->ttop = top ;
11594 be->bfunc = (basis_func *)calloc(sizeof(basis_func),be->nfunc) ;
11595 dx = (top-bot) / (nord-1) ;
11596
11597 if( zzz ){ nbot = 1 ; ntop = nord-2 ; }
11598 else { nbot = 0 ; ntop = nord-1 ; }
11599 for( bb=0,nn=nbot ; nn <= ntop ; nn++,bb++ ){
11600 be->bfunc[bb].f = basis_csplin ;
11601 be->bfunc[bb].a = bot + nn*dx ;
11602 be->bfunc[bb].b = dx ;
11603 be->bfunc[bb].c = 0.0f ;
11604 }
11605 if( zzz ){
11606 be->bfunc[0].c = -1.0f ; /* edge markers */
11607 be->bfunc[nord-3].c = 1.0f ;
11608 } else {
11609 be->bfunc[0].c = -2.0f ;
11610 be->bfunc[1].c = -1.0f ;
11611 be->bfunc[nord-2].c = 1.0f ;
11612 be->bfunc[nord-1].c = 2.0f ;
11613 }
11614
11615 /*--- TRIG(bot,top,order) ---*/
11616
11617 } else if( strcmp(scp,"TRIG") == 0 ){
11618
11619 if( cpt == NULL ){
11620 ERROR_message("'TRIG' by itself is illegal") ;
11621 ERROR_message(
11622 " Correct format: 'TRIG(bot,top,n)' with bot < top and n > 2.") ;
11623 free((void *)be); free(scp); RETURN(NULL);
11624 }
11625 sscanf(cpt,"%f,%f,%d",&bot,&top,&nord) ;
11626 if( bot >= top || nord < 3 ){
11627 ERROR_message("'TRIG(%s' is illegal",cpt) ;
11628 ERROR_message(
11629 " Correct format: 'TRIG(bot,top,n)' with bot < top and n > 2.") ;
11630 free((void *)be); free(scp); RETURN(NULL);
11631 }
11632 be->nfunc = nord ;
11633 be->tbot = bot ; be->ttop = top ;
11634 be->bfunc = (basis_func *)calloc(sizeof(basis_func),be->nfunc) ;
11635
11636 be->bfunc[0].f = basis_one ;
11637 be->bfunc[0].a = bot ;
11638 be->bfunc[0].b = top ;
11639 be->bfunc[0].c = 0.0f ;
11640 for( nn=1 ; nn < nord ; nn++ ){
11641 be->bfunc[nn].f = basis_cos ;
11642 be->bfunc[nn].a = bot ;
11643 be->bfunc[nn].b = top ;
11644 be->bfunc[nn].c = (2.0*PI)*((nn+1)/2)/(top-bot) ;
11645 nn++ ; if( nn >= nord ) break ;
11646 be->bfunc[nn].f = basis_sin ;
11647 be->bfunc[nn].a = bot ;
11648 be->bfunc[nn].b = top ;
11649 be->bfunc[nn].c = (2.0*PI)*((nn+1)/2)/(top-bot) ;
11650 }
11651
11652 /*--- SIN(bot,top,order) ---*/
11653
11654 } else if( strcmp(scp,"SIN") == 0 ){
11655
11656 if( cpt == NULL ){
11657 ERROR_message("'SIN' by itself is illegal") ;
11658 ERROR_message(
11659 " Correct format: 'SIN(bot,top,n)' with bot < top and n > 0.") ;
11660 free((void *)be); free(scp); RETURN(NULL);
11661 }
11662 sscanf(cpt,"%f,%f,%d",&bot,&top,&nord) ;
11663 if( bot >= top || nord < 1 ){
11664 ERROR_message("'SIN(%s' is illegal",cpt) ;
11665 ERROR_message(
11666 " Correct format: 'SIN(bot,top,n)' with bot < top and n > 0.") ;
11667 free((void *)be); free(scp); RETURN(NULL);
11668 }
11669 be->nfunc = nord ;
11670 be->tbot = bot ; be->ttop = top ;
11671 be->bfunc = (basis_func *)calloc(sizeof(basis_func),be->nfunc) ;
11672
11673 for( nn=0 ; nn < nord ; nn++ ){
11674 be->bfunc[nn].f = basis_sin ;
11675 be->bfunc[nn].a = bot ;
11676 be->bfunc[nn].b = top ;
11677 be->bfunc[nn].c = PI*(nn+1)/(top-bot) ;
11678 }
11679
11680 /*--- POLY(bot,top,order) ---*/
11681
11682 } else if( strcmp(scp,"POLY") == 0 ){
11683
11684 if( cpt == NULL ){
11685 ERROR_message("'POLY' by itself is illegal") ;
11686 ERROR_message(
11687 " Correct format: 'POLY(bot,top,n)' with bot<top and n>0 and n<%d",
11688 POLY_MAX+1) ;
11689 free((void *)be); free(scp); RETURN(NULL);
11690 }
11691 sscanf(cpt,"%f,%f,%d",&bot,&top,&nord) ;
11692 if( bot >= top || nord < 1 || nord > POLY_MAX ){
11693 ERROR_message("'POLY(%s' is illegal",cpt) ;
11694 ERROR_message(
11695 " Correct format: 'POLY(bot,top,n)' with bot<top and n>0 and n<%d",
11696 POLY_MAX+1) ;
11697 free((void *)be); free(scp); RETURN(NULL);
11698 }
11699 be->nfunc = nord ;
11700 be->tbot = bot ; be->ttop = top ;
11701 be->bfunc = (basis_func *)calloc(sizeof(basis_func),be->nfunc) ;
11702 be->bfunc[0].f = basis_one ;
11703 be->bfunc[0].a = bot ;
11704 be->bfunc[0].b = top ;
11705 be->bfunc[0].c = 0.0f ;
11706 for( nn=1 ; nn < nord ; nn++ ){
11707 be->bfunc[nn].f = basis_legendre ;
11708 be->bfunc[nn].a = bot ;
11709 be->bfunc[nn].b = top ;
11710 be->bfunc[nn].c = (float)nn ;
11711 }
11712
11713 /*--- SPMG ---*/ /*--- or SPMG3 [27 Jul 2007] ---*/
11714
11715 } else if( strncmp(scp,"SPMG",4) == 0 ){
11716 int nb ; /* number of basis funcs */
11717 float dur=-1.0f ; /* 28 Apr 2009: duration param */
11718
11719 switch( scp[4] ){ /* 08 Mar 2009: */
11720 default:
11721 WARNING_message("unknown '%s' defaults to 'SPMG2'",scp) ; /*fallthru*/
11722 case '\0':
11723 case '2': nb = 2 ; break ; /* now allow nb=1..3 */
11724 case '3': nb = 3 ; break ;
11725 case '1': nb = 1 ; break ;
11726 }
11727
11728 if( cpt != NULL ) sscanf(cpt,"%f",&dur) ; /* 28 Apr 2009: get duration param */
11729
11730 if( dur < 0.0f ){ /** the olden way, with dur not given **/
11731 be->nfunc = nb ; /* no longer fixed at 2 */
11732 be->tbot = 0.0f ; be->ttop = 25.0f ;
11733 be->bfunc = (basis_func *)calloc(sizeof(basis_func),be->nfunc) ;
11734 be->bfunc[0].f = basis_spmg1 ;
11735 be->bfunc[0].a = 0.0f ; /* parameters aren't used */
11736 be->bfunc[0].b = 0.0f ;
11737 be->bfunc[0].c = 0.0f ;
11738 if( nb >= 2 ){ /* 08 Mar 2009 */
11739 be->bfunc[1].f = basis_spmg2 ;
11740 be->bfunc[1].a = 0.0f ;
11741 be->bfunc[1].b = 0.0f ;
11742 be->bfunc[1].c = 0.0f ;
11743 }
11744 if( nb >= 3 ){ /* 27 Jul 2007 */
11745 be->bfunc[2].f = basis_spmg3 ;
11746 be->bfunc[2].a = 0.0f ;
11747 be->bfunc[2].b = 0.0f ;
11748 be->bfunc[2].c = 0.0f ;
11749 }
11750
11751 } else { /** the new way: dur given **/
11752 int iwav ;
11753
11754 be->nfunc = nb ;
11755 be->bfunc = (basis_func *)calloc(sizeof(basis_func),be->nfunc) ;
11756
11757 /* setup function #1 in WFUNS[iwav] and then into be */
11758
11759 iwav = setup_WFUN_function( WTYPE_SPMG1 , dur , NULL ) ;
11760 if( iwav < 0 ){
11761 ERROR_message("Can't setup SPMG1(%f) for some reason?!",dur) ;
11762 free((void *)be); free(scp); RETURN(NULL);
11763 }
11764
11765 be->tbot = 0.0f ; be->ttop = WFUNDT * WFUNS[iwav].nfun ;
11766
11767 be->bfunc[0].f = basis_WFUN ;
11768 be->bfunc[0].a = (float)iwav ;
11769 be->bfunc[0].b = 0.0f ;
11770 be->bfunc[0].c = 0.0f ;
11771
11772 if( nb >= 2 ){
11773 iwav = setup_WFUN_function( WTYPE_SPMG2 , dur , NULL ) ;
11774 if( iwav < 0 ){
11775 ERROR_message("Can't setup SPMG2(%f) for some reason?!",dur) ;
11776 free((void *)be); free(scp); RETURN(NULL);
11777 }
11778 be->bfunc[1].f = basis_WFUN ;
11779 be->bfunc[1].a = (float)iwav ;
11780 be->bfunc[1].b = 0.0f ;
11781 be->bfunc[1].c = 0.0f ;
11782 }
11783
11784 if( nb >= 3 ){
11785 iwav = setup_WFUN_function( WTYPE_SPMG3 , dur , NULL ) ;
11786 if( iwav < 0 ){
11787 ERROR_message("Can't setup SPMG3(%f) for some reason?!",dur) ;
11788 free((void *)be); free(scp); RETURN(NULL);
11789 }
11790 be->bfunc[2].f = basis_WFUN ;
11791 be->bfunc[2].a = (float)iwav ;
11792 be->bfunc[2].b = 0.0f ;
11793 be->bfunc[2].c = 0.0f ;
11794 }
11795 }
11796
11797 /*--- dmBLOCKn for n=4 or 5 ; the first 'vfun' function [08 Dec 2008] ---*/
11798
11799 } else if( strncmp(scp,"dmBLOCK",7) == 0 ){
11800 int nb=4 ; float peak=0.0f ; /* 03 Apr 2012: alter default peak from 1 to 0 */
11801
11802 if( scp[7] != '\0' ){
11803 nb = strtol( scp+7 , NULL , 10 ) ;
11804 if( nb != 4 && nb != 5 ){
11805 ERROR_message("'%s' has illegal power: only 4 or 5 allowed",scp) ;
11806 free((void *)be); free(scp); RETURN(NULL);
11807 }
11808 }
11809
11810 if( cpt != NULL ) sscanf(cpt,"%f",&peak) ; /* 30 Sep 2009: get peak param */
11811
11812 be->nfunc = 1 ;
11813 be->tbot = 0.0f ; be->ttop = BASIS_MAX_DURATION+15.0f ;
11814 be->bfunc = (basis_func *)calloc(sizeof(basis_func),be->nfunc) ;
11815 be->bfunc[0].f = (nb==5) ? basis_block5_OLD : basis_block4_OLD ;
11816 be->bfunc[0].a = 1.0f; /* duration: will actually come from timing file */
11817 be->bfunc[0].b = peak ;
11818 be->bfunc[0].c = 0.0f ;
11819 be->vfun = 1 ; /* needs 1 param from timing file */
11820 be->no_iresp = 1 ; /* 07 Nov 2011 */
11821
11822 /*--- dmUBLOCKn for n=4 or 5 ; the first 'vfun' function [08 Dec 2008] ---*/
11823
11824 } else if( strncmp(scp,"dmUBLOCK",8) == 0 ){
11825 int nb=4 ; float peak=0.0f ; /* 03 Apr 2012: alter default peak from 1 to 0 */
11826
11827 if( scp[8] != '\0' ){
11828 nb = strtol( scp+8 , NULL , 10 ) ;
11829 if( nb != 4 && nb != 5 ){
11830 ERROR_message("'%s' has illegal power: only 4 or 5 allowed",scp) ;
11831 free((void *)be); free(scp); RETURN(NULL);
11832 }
11833 }
11834
11835 if( cpt != NULL ) sscanf(cpt,"%f",&peak) ; /* 30 Sep 2009: get peak param */
11836
11837 be->nfunc = 1 ;
11838 be->tbot = 0.0f ; be->ttop = BASIS_MAX_DURATION+15.0f ;
11839 be->bfunc = (basis_func *)calloc(sizeof(basis_func),be->nfunc) ;
11840 be->bfunc[0].f = (nb==5) ? basis_block5_NEW : basis_block4_NEW ;
11841 be->bfunc[0].a = 1.0f; /* duration: will actually come from timing file */
11842 be->bfunc[0].b = peak ;
11843 be->bfunc[0].c = 0.0f ;
11844 be->vfun = 1 ; /* needs 1 param from timing file */
11845 be->no_iresp = 1 ; /* 07 Nov 2011 */
11846
11847 /*--- BLOCKn(duration,peak) for n=4 or 5 ---*/
11848
11849 } else if( strncmp(scp,"BLOCK",5) == 0 || strncmp(scp,"IGFUN",5) == 0 ){
11850 int nb=4 ;
11851
11852 if( scp[5] != '\0' ){
11853 nb = strtol( scp+5 , NULL , 10 ) ;
11854 if( nb != 4 && nb != 5 ){
11855 ERROR_message("'%s' has illegal power: only 4 or 5 allowed",scp) ;
11856 free((void *)be); free(scp); RETURN(NULL);
11857 }
11858 }
11859
11860 if( cpt == NULL ){
11861 ERROR_message("'%s' by itself is illegal",scp) ;
11862 ERROR_message(
11863 " Correct format: 'BLOCKn(dur)' with dur > 0, n=4 or 5\n"
11864 " *OR* 'BLOCKn(dur,peak)' with peak > 0 too.") ;
11865 free((void *)be); free(scp); RETURN(NULL);
11866 }
11867 sscanf(cpt,"%f,%f",&top,&bot) ; /* top = duration, bot = peak */
11868 if( top <= 0.0f ){
11869 ERROR_message("'%s(%s' is illegal",scp,cpt) ;
11870 ERROR_message(
11871 " Correct format: 'BLOCKn(dur)' with dur > 0, n=4 or 4\n"
11872 " or: 'BLOCKn(dur,peak)' with peak > 0 too.") ;
11873 free((void *)be); free(scp); RETURN(NULL);
11874 }
11875 if( bot < 0.0f ) bot = 0.0f ;
11876
11877 be->nfunc = 1 ;
11878 be->tbot = 0.0f ; be->ttop = top+15.0f ;
11879 be->bfunc = (basis_func *)calloc(sizeof(basis_func),be->nfunc) ;
11880 be->bfunc[0].f = (nb==5) ? basis_block5_OLD : basis_block4_OLD ;
11881 be->bfunc[0].a = top ;
11882 be->bfunc[0].b = bot ;
11883 be->bfunc[0].c = 0.0f ;
11884
11885 /* 04 May 2007: check for consistency in BLOCK-izing */
11886
11887 { static float first_block_peakval = 0.0f ;
11888 static char *first_block_peaksym = NULL ;
11889 static int num_block = 0 ;
11890 static float first_len_pkzero = 0.0f ;
11891 static char *first_sym_pkzero = NULL ;
11892
11893 if( num_block == 0 ){
11894 first_block_peakval = bot ;
11895 first_block_peaksym = strdup(sym) ;
11896 } else if( FLDIF(bot,first_block_peakval) > 0.002f ){
11897 WARNING_message(
11898 "%s has different peak value than first %s\n"
11899 " We hope you know what you are doing!" ,
11900 sym , first_block_peaksym ) ;
11901 }
11902
11903 if( bot == 0.0f ){
11904 if( first_len_pkzero == 0.0f ){
11905 first_len_pkzero = top ;
11906 first_sym_pkzero = strdup(sym) ;
11907 } else if( FLDIF(top,first_len_pkzero) > 0.002f ){
11908 WARNING_message(
11909 "%s has different duration than first %s\n"
11910 " ==> Amplitudes will differ. We hope you know what you are doing!" ,
11911 sym , first_sym_pkzero ) ;
11912 }
11913 }
11914
11915 num_block++ ;
11916 }
11917
11918 /*--- UBLOCKn(duration,peak) for n=4 or 5 ---*/
11919
11920 } else if( strncmp(scp,"UBLOCK",6) == 0 ){
11921 int nb=4 ;
11922
11923 if( scp[6] != '\0' ){
11924 nb = strtol( scp+6 , NULL , 10 ) ;
11925 if( nb != 4 && nb != 5 ){
11926 ERROR_message("'%s' has illegal power: only 4 or 5 allowed",scp) ;
11927 free((void *)be); free(scp); RETURN(NULL);
11928 }
11929 }
11930
11931 if( cpt == NULL ){
11932 ERROR_message("'%s' by itself is illegal",scp) ;
11933 ERROR_message(
11934 " Correct format: 'UBLOCKn(dur)' with dur > 0, n=4 or 5\n"
11935 " *OR* 'UBLOCKn(dur,peak)' with peak > 0 too.") ;
11936 free((void *)be); free(scp); RETURN(NULL);
11937 }
11938 sscanf(cpt,"%f,%f",&top,&bot) ; /* top = duration, bot = peak */
11939 if( top <= 0.0f ){
11940 ERROR_message("'%s(%s' is illegal",scp,cpt) ;
11941 ERROR_message(
11942 " Correct format: 'UBLOCKn(dur)' with dur > 0, n=4 or 4\n"
11943 " or: 'UBLOCKn(dur,peak)' with peak > 0 too.") ;
11944 free((void *)be); free(scp); RETURN(NULL);
11945 }
11946 if( bot < 0.0f ) bot = 0.0f ;
11947
11948 be->nfunc = 1 ;
11949 be->tbot = 0.0f ; be->ttop = top+15.0f ;
11950 be->bfunc = (basis_func *)calloc(sizeof(basis_func),be->nfunc) ;
11951 be->bfunc[0].f = (nb==5) ? basis_block5_NEW : basis_block4_NEW ;
11952 be->bfunc[0].a = top ;
11953 be->bfunc[0].b = bot ;
11954 be->bfunc[0].c = 0.0f ;
11955
11956 /* 04 May 2007: check for consistency in UBLOCK-izing */
11957
11958 { static float first_block_peakval = 0.0f ;
11959 static char *first_block_peaksym = NULL ;
11960 static int num_block = 0 ;
11961 static float first_len_pkzero = 0.0f ;
11962 static char *first_sym_pkzero = NULL ;
11963
11964 if( num_block == 0 ){
11965 first_block_peakval = bot ;
11966 first_block_peaksym = strdup(sym) ;
11967 } else if( FLDIF(bot,first_block_peakval) > 0.002f ){
11968 WARNING_message(
11969 "%s has different peak value than first %s\n"
11970 " We hope you know what you are doing!" ,
11971 sym , first_block_peaksym ) ;
11972 }
11973
11974 if( bot == 0.0f ){
11975 if( first_len_pkzero == 0.0f ){
11976 first_len_pkzero = top ;
11977 first_sym_pkzero = strdup(sym) ;
11978 } else if( FLDIF(top,first_len_pkzero) > 0.002f ){
11979 WARNING_message(
11980 "%s has different duration than first %s\n"
11981 " ==> Amplitudes will differ. We hope you know what you are doing!" ,
11982 sym , first_sym_pkzero ) ;
11983 }
11984 }
11985
11986 num_block++ ;
11987 }
11988
11989 /*--- macro to scan for a float number and assign to a value ---*/
11990
11991 #undef WSCAN
11992 #define WSCAN(vv) \
11993 do{ if( dpt != NULL && *dpt != '\0' ){ \
11994 if( isdigit(*dpt) ){ \
11995 (vv) = (float)strtod(dpt,&ept) ; \
11996 dpt = ept ; if( *dpt != '\0' ) dpt++ ; \
11997 } else if( *dpt == '-' ){ \
11998 ERROR_message("Can't give negative arguments to 'WAV'"); \
11999 free((void *)be); free(scp); RETURN(NULL); \
12000 } else { \
12001 dpt++ ; \
12002 } \
12003 } \
12004 } while(0)
12005
12006 /*--- WAV(dur,delaytime,risetime,falltime.undershoot,restoretime) ---*/
12007
12008 } else if( strcmp(scp,"WAV") == 0 ){ /* 06 Mar 2009 */
12009 float parm[5] = { 2.0f , 4.0f , 6.0f , 0.2f , 2.0f } ;
12010 float dur = 0.0f ; char *dpt=cpt , *ept ; int iwav ;
12011
12012 /* scan for up to 6 parameters */
12013
12014 WSCAN(dur ) ; WSCAN(parm[0]) ; WSCAN(parm[1]) ;
12015 WSCAN(parm[2]) ; WSCAN(parm[3]) ; WSCAN(parm[4]) ;
12016
12017 /* setup the function in WFUNS[iwav] */
12018
12019 iwav = setup_WFUN_function( WTYPE_WAV , dur , parm ) ;
12020 if( iwav < 0 ){
12021 ERROR_message("Can't setup WAV for some reason?!") ;
12022 free((void *)be); free(scp); RETURN(NULL);
12023 }
12024
12025 be->nfunc = 1 ;
12026 be->tbot = 0.0f ; be->ttop = WFUNDT * WFUNS[iwav].nfun ;
12027 be->bfunc = (basis_func *)calloc(sizeof(basis_func),be->nfunc) ;
12028 be->bfunc[0].f = basis_WFUN ;
12029 be->bfunc[0].a = (float)iwav ;
12030 be->bfunc[0].b = 0.0f ;
12031 be->bfunc[0].c = 0.0f ;
12032
12033 /*--- EXPR(bot,top) exp1 exp2 ... ---*/
12034
12035 } else if( strcmp(scp,"EXPR") == 0 ){ /* 28 Aug 2004 */
12036 char *ept ;
12037 NI_str_array *sar ;
12038 int nexpr , ie ;
12039 PARSER_code *pc ;
12040
12041 if( cpt == NULL ){
12042 ERROR_message("'EXPR' by itself is illegal") ;
12043 free((void *)be); free(scp); RETURN(NULL);
12044 }
12045 sscanf(cpt,"%f,%f",&bot,&top) ;
12046 if( top <= bot ){
12047 ERROR_message("'EXPR(%f,%f)' has illegal time range",bot,top) ;
12048 free((void *)be); free(scp); RETURN(NULL);
12049 }
12050 ept = strchr( cpt , ')' ) ;
12051 if( ept == NULL ){
12052 ERROR_message("'EXPR(%f,%f)' has no expressions!?",bot,top);
12053 free((void *)be); free(scp); RETURN(NULL);
12054 }
12055 sar = NI_decode_string_list( ept+1 , "~" ) ;
12056 if( sar == NULL || sar->num == 0 ){
12057 ERROR_message("'EXPR(%f,%f)' has no expressions after '('!?",bot,top);
12058 free((void *)be); free(scp); RETURN(NULL);
12059 }
12060 be->nfunc = nexpr = sar->num ;
12061 be->tbot = bot ; be->ttop = top ;
12062 be->bfunc = (basis_func *)calloc(sizeof(basis_func),be->nfunc) ;
12063 PARSER_set_printout(1) ;
12064 for( ie=0 ; ie < nexpr ; ie++ ){
12065 pc = PARSER_generate_code( sar->str[ie] ) ;
12066 if( pc == NULL ){
12067 ERROR_message("unparsable EXPRession '%s'",sar->str[ie]) ;
12068 free((void *)be); free(scp); RETURN(NULL);
12069 }
12070 if( strcmp(sar->str[ie],"1") != 0 && /* must either be "1" */
12071 !PARSER_has_symbol("t",pc) && /* or contain symbol */
12072 !PARSER_has_symbol("x",pc) && /* 't', 'x', or 'z' */
12073 !PARSER_has_symbol("z",pc) ){
12074 ERROR_message(
12075 "illegal EXPRession '%s' lacks symbol t, x, or z",
12076 sar->str[ie]) ;
12077 free((void *)be); free(scp); RETURN(NULL);
12078 }
12079 be->bfunc[ie].f = basis_expr ;
12080 be->bfunc[ie].a = bot ;
12081 be->bfunc[ie].b = top ;
12082 be->bfunc[ie].c = 1.0f/(top-bot) ; /* for ease of scaling */
12083 be->bfunc[ie].q = (void *)pc ;
12084 }
12085 PARSER_set_printout(0) ;
12086
12087 NI_delete_str_array(sar) ;
12088
12089 /*--- MION ---*/
12090
12091 } else if( strcmp(scp,"MION") == 0 ){
12092 float dur=-1.0f ; int iwav ;
12093
12094 if( cpt != NULL ) sscanf(cpt,"%f",&dur) ; /* 28 Apr 2009: get duration param */
12095
12096 be->nfunc = 1 ;
12097 be->bfunc = (basis_func *)calloc(sizeof(basis_func),be->nfunc) ;
12098
12099 if( dur < 0.0f ){ /* impulse response */
12100 be->bfunc[0].f = basis_mion ;
12101 be->bfunc[0].a = 0.0f ; /* no parameters */
12102 be->bfunc[0].b = 0.0f ;
12103 be->bfunc[0].c = 0.0f ;
12104 be->tbot = 0.0f ; be->ttop = 60.0f ;
12105 } else { /* convolve with square wave */
12106 iwav = setup_WFUN_function( WTYPE_MION , dur , NULL ) ;
12107 if( iwav < 0 ){
12108 ERROR_message("Can't setup MION(%f) for some reason?!",dur) ;
12109 free((void *)be); free(scp); RETURN(NULL);
12110 }
12111 be->bfunc[0].f = basis_WFUN ;
12112 be->bfunc[0].a = (float)iwav ;
12113 be->bfunc[0].b = 0.0f ;
12114 be->bfunc[0].c = 0.0f ;
12115 be->tbot = 0.0f ; be->ttop = WFUNDT * WFUNS[iwav].nfun ;
12116 }
12117
12118 /*--- MIONN ---*/
12119
12120 } else if( strcmp(scp,"MIONN") == 0 ){
12121 float dur=-1.0f ; int iwav ;
12122
12123 if( cpt != NULL ) sscanf(cpt,"%f",&dur) ; /* 28 Apr 2009: get duration param */
12124
12125 be->nfunc = 1 ;
12126 be->bfunc = (basis_func *)calloc(sizeof(basis_func),be->nfunc) ;
12127
12128 if( dur < 0.0f ){ /* impulse response */
12129 be->bfunc[0].f = basis_mionn ;
12130 be->bfunc[0].a = 0.0f ; /* no parameters */
12131 be->bfunc[0].b = 0.0f ;
12132 be->bfunc[0].c = 0.0f ;
12133 be->tbot = 0.0f ; be->ttop = 60.0f ;
12134 } else { /* convolve with square wave */
12135 iwav = setup_WFUN_function( WTYPE_MIONN , dur , NULL ) ;
12136 if( iwav < 0 ){
12137 ERROR_message("Can't setup MION(%f) for some reason?!",dur) ;
12138 free((void *)be); free(scp); RETURN(NULL);
12139 }
12140 be->bfunc[0].f = basis_WFUN ;
12141 be->bfunc[0].a = (float)iwav ;
12142 be->bfunc[0].b = 0.0f ;
12143 be->bfunc[0].c = 0.0f ;
12144 be->tbot = 0.0f ; be->ttop = WFUNDT * WFUNS[iwav].nfun ;
12145 }
12146
12147
12148 /*--- NO MORE BASIS FUNCTION CHOICES ---*/
12149
12150 } else {
12151 ERROR_message("'%s' is unknown response function type",scp) ;
12152 free((void *)be); free(scp); RETURN(NULL);
12153 }
12154
12155 /* 28 Apr 2005: set scaling factors */
12156
12157 for( nn=0 ; nn < be->nfunc ; nn++ ) /* initialize factors to 1.0 */
12158 be->bfunc[nn].ffac = 1.0 ;
12159
12160 /* for each basis function, find its peak value, then
12161 set ffac so that the peak value becomes basis_normall */
12162
12163 #undef BNSUB
12164 #define BNSUB 1999
12165 if( basis_normall > 0.0f ){
12166 int jj , jtop=BNSUB ; float dt , ftop , val ;
12167 bot = be->tbot ; top = be->ttop ; dt = (top-bot)/BNSUB ;
12168 if( dt < 0.01f * basis_TR ){ /* should be rare */
12169 dt = 0.01f * basis_TR ; jtop = 1 + (int)((top-bot)/dt) ;
12170 } else if( dt > 0.1f * basis_TR ){ /* should not happen */
12171 dt = 0.10f * basis_TR ; jtop = 1 + (int)((top-bot)/dt) ;
12172 }
12173 for( nn=0 ; nn < be->nfunc ; nn++ ){
12174 ftop = 0.0f ;
12175 for( jj=0 ; jj <= jtop ; jj++ ){
12176 val = basis_funceval( be->bfunc[nn] , bot+jj*dt ) ;
12177 val = fabs(val) ; if( val > ftop ) ftop = val ;
12178 }
12179 if( ftop > 0.0f ) be->bfunc[nn].ffac = basis_normall / ftop ;
12180 }
12181 }
12182
12183 free(scp); RETURN(be);
12184 }
12185
12186 /*----------------------------------------------------------------------*/
12187 /*! For IRFs defined by -stim_times basis function expansion, write out
12188 a 3D+time dataset with time spacing dt.
12189 ------------------------------------------------------------------------*/
12190
basis_write_iresp(int argc,char * argv[],DC_options * option_data,basis_expansion * be,float dt,float ** wtar,char * output_filename)12191 void basis_write_iresp( int argc , char *argv[] ,
12192 DC_options *option_data ,
12193 basis_expansion *be , float dt ,
12194 float **wtar , char *output_filename )
12195 {
12196 int nvox, ii, nf, allz, ts_length ;
12197 register int pp, ib ;
12198 float *wt , *tt , **hout , factor , **bb ;
12199 short *bar ;
12200 THD_3dim_dataset *in_dset = NULL;
12201 THD_3dim_dataset *out_dset = NULL;
12202 char label[512] ;
12203 const float EPSILON = 1.0e-10 ;
12204
12205 /* open input 3D+time dataset to get some parameters */
12206
12207 if( be->no_iresp ){ /* 07 Nov 2011 */
12208 ERROR_message("Can't use -iresp for %s %s (%s)",be->option,be->symfun,be->name) ;
12209 return ;
12210 }
12211
12212 in_dset = THD_open_dataset(option_data->input_filename);
12213 CHECK_OPEN_ERROR(in_dset,option_data->input_filename);
12214
12215 if( option_data->force_TR > 0.0 ) /* 18 Aug 2008 */
12216 EDIT_dset_items( in_dset ,
12217 ADN_ttdel , option_data->force_TR ,
12218 ADN_ntt , DSET_NVALS(in_dset) ,
12219 ADN_tunits, UNITS_SEC_TYPE ,
12220 ADN_none ) ;
12221
12222 nvox = in_dset->daxes->nxx * in_dset->daxes->nyy * in_dset->daxes->nzz;
12223 DSET_UNMSEC(in_dset) ; /* 12 Aug 2005 */
12224
12225 if( dt <= 0.0f ) dt = DSET_TR(in_dset) ;
12226 if( dt <= 0.0f ) dt = 1.0f ;
12227
12228 /* create output dataset on the input as a model, then close the input */
12229
12230 out_dset = EDIT_empty_copy( in_dset ) ;
12231 tross_Copy_History( in_dset , out_dset ) ;
12232 DSET_delete( in_dset ) ;
12233
12234 /* historicize the output */
12235
12236 sprintf( label , "Impulse response: %s" , output_filename ) ;
12237 if( commandline != NULL )
12238 tross_multi_Append_History( out_dset , commandline,label,NULL ) ;
12239 else
12240 tross_Append_History ( out_dset, label);
12241
12242 ts_length = 1 + (int)myceil( (be->ttop - be->tbot)/dt ) ; /* 13 Apr 2005: +1 */
12243
12244 /* modify the output dataset appropriately */
12245
12246 (void ) EDIT_dset_items( out_dset,
12247 ADN_prefix, output_filename,
12248 ADN_label1, output_filename,
12249 ADN_self_name, output_filename,
12250 ADN_malloc_type, DATABLOCK_MEM_MALLOC,
12251 ADN_datum_all, (floatout)?MRI_float:MRI_short,
12252 ADN_nvals, ts_length,
12253 ADN_ntt, ts_length,
12254 ADN_ttdel, dt ,
12255 ADN_ttorg, be->tbot,
12256 ADN_none ) ;
12257
12258 #ifndef FIX_CONFLICTS
12259 if( THD_is_file(out_dset->dblk->diskptr->header_name) ){
12260 ERROR_message(
12261 "Output dataset file %s already exists - won't overwrite",
12262 out_dset->dblk->diskptr->header_name ) ;
12263 DSET_delete(out_dset) ; return ;
12264 }
12265 #else
12266 if( !THD_ok_overwrite() && /* ZSS: Dec. 16 08 */
12267 THD_deconflict_prefix(out_dset) > 0 ) {
12268 WARNING_message("Filename conflict: changing '%s' to '%s'",
12269 output_filename, DSET_PREFIX(out_dset) ) ;
12270 }
12271 #endif
12272
12273 /* create output bricks (float for now, will scale to shorts later) */
12274
12275 hout = (float **) malloc( sizeof(float *) * ts_length ) ;
12276 for( ib=0 ; ib < ts_length ; ib++ )
12277 hout[ib] = (float *)calloc(sizeof(float),nvox) ;
12278
12279 /* create basis vectors for the expansion on the dt time grid */
12280
12281 nf = be->nfunc ;
12282 wt = (float *) malloc( sizeof(float) * nf ) ;
12283 tt = (float *) malloc( sizeof(float) * ts_length ) ;
12284
12285 for( ib=0 ; ib < ts_length ; ib++ ) /* output time grid */
12286 tt[ib] = be->tbot + ib*dt ;
12287
12288 bb = (float **) malloc( sizeof(float *) * nf ) ;
12289 for( pp=0 ; pp < nf ; pp++ ){
12290 bb[pp] = (float *) malloc( sizeof(float) * ts_length ) ;
12291 for( ib=0 ; ib < ts_length ; ib++ )
12292 bb[pp][ib] = basis_funceval( be->bfunc[pp] , tt[ib] ) ;
12293 }
12294
12295 /* loop over voxels:
12296 extract coefficient (weights) for each basis function into wt
12297 sum up basis vectors times wt to get result, save into output arrays */
12298
12299 for( ii=0 ; ii < nvox ; ii++ ){
12300 allz = 1 ;
12301 for( pp=0 ; pp < nf ; pp++ ){
12302 wt[pp] = wtar[pp][ii] ; allz = ( allz && (wt[pp] == 0.0f) );
12303 }
12304
12305 if( allz ){
12306 for( ib=0 ; ib < ts_length ; ib++ ) hout[ib][ii] = 0.0f ;
12307 } else {
12308 register float sum ;
12309 for( ib=0 ; ib < ts_length ; ib++ ){
12310 sum = 0.0f ;
12311 for( pp=0 ; pp < nf ; pp++ ) sum += wt[pp] * bb[pp][ib] ;
12312 hout[ib][ii] = sum ;
12313 }
12314 }
12315 }
12316
12317 /* toss some trash */
12318
12319 for( pp=0 ; pp < nf ; pp++ ) free((void *)bb[pp]) ;
12320 free((void *)bb) ; free((void *)tt) ; free((void *)wt) ;
12321
12322 /* scale floating point bricks to shorts and insert into output dataset */
12323
12324 for( ib=0 ; ib < ts_length ; ib++ ){
12325 if( floatout ){
12326 EDIT_substitute_brick( out_dset , ib , MRI_float , hout[ib] ) ;
12327 factor = 0.0f ;
12328 } else {
12329 bar = (short *) malloc( sizeof(short) * nvox ) ;
12330 factor = EDIT_coerce_autoscale_new(nvox, MRI_float,hout[ib], MRI_short,bar) ;
12331 if( factor < EPSILON ) factor = 0.0f ; /* if brick is all zero */
12332 else factor = 1.0f / factor ;
12333 EDIT_substitute_brick( out_dset , ib , MRI_short , bar ) ;
12334
12335 EDIT_misfit_report( DSET_FILECODE(out_dset) , ib ,
12336 nvox , factor , bar , hout[ib] ) ;
12337
12338 free((void *)hout[ib]) ;
12339 }
12340 EDIT_BRICK_FACTOR( out_dset , ib , factor ) ;
12341 }
12342 free((void *)hout) ;
12343
12344 /* and save the results to disk! */
12345
12346 DSET_write( out_dset ) ;
12347 if( verb )
12348 INFO_message("Wrote iresp 3D+time dataset into %s\n",DSET_BRIKNAME(out_dset)) ;
12349
12350 DSET_delete( out_dset ) ;
12351 return ;
12352 }
12353
12354 /*----------------------------------------------------------------------*/
12355 /*! For IRFs defined by -stim_times basis function expansion, write out
12356 a 1D dataset with time spacing dt.
12357 ------------------------------------------------------------------------*/
12358
basis_write_iresp_1D(int argc,char * argv[],DC_options * option_data,basis_expansion * be,float dt,float ** wtar,char * output_filename)12359 void basis_write_iresp_1D( int argc , char *argv[] ,
12360 DC_options *option_data ,
12361 basis_expansion *be , float dt ,
12362 float **wtar , char *output_filename )
12363 {
12364 int nvox, ii, nf, allz, ts_length ;
12365 register int pp, ib ;
12366 float *wt , *tt , **hout , factor , **bb ;
12367 short *bar ;
12368 char label[512] ;
12369 const float EPSILON = 1.0e-10 ;
12370
12371 if( be->no_iresp ){ /* 07 Nov 2011 */
12372 ERROR_message("Can't use -iresp for %s %s (%s)",be->option,be->symfun,be->name) ;
12373 return ;
12374 }
12375
12376 nvox = 1 ; /* from basis_write_iresp(), but use 1 voxel */
12377
12378 if( dt <= 0.0f ) dt = 1.0f ;
12379
12380 ts_length = 1 + (int)myceil( (be->ttop - be->tbot)/dt ) ; /* 13 Apr 2005: +1 */
12381
12382 /* create output bricks */
12383
12384 hout = (float **) malloc( sizeof(float *) * ts_length ) ;
12385 for( ib=0 ; ib < ts_length ; ib++ )
12386 hout[ib] = (float *)calloc(sizeof(float),nvox) ;
12387
12388 /* create basis vectors for the expansion on the dt time grid */
12389
12390 nf = be->nfunc ;
12391 wt = (float *) malloc( sizeof(float) * nf ) ;
12392 tt = (float *) malloc( sizeof(float) * ts_length ) ;
12393
12394 for( ib=0 ; ib < ts_length ; ib++ ) /* output time grid */
12395 tt[ib] = be->tbot + ib*dt ;
12396
12397 bb = (float **) malloc( sizeof(float *) * nf ) ;
12398 for( pp=0 ; pp < nf ; pp++ ){
12399 bb[pp] = (float *) malloc( sizeof(float) * ts_length ) ;
12400 for( ib=0 ; ib < ts_length ; ib++ )
12401 bb[pp][ib] = basis_funceval( be->bfunc[pp] , tt[ib] ) ;
12402 }
12403
12404 /* loop over voxels:
12405 extract coefficient (weights) for each basis function into wt
12406 sum up basis vectors times wt to get result, save into output arrays */
12407
12408 for( ii=0 ; ii < nvox ; ii++ ){
12409 allz = 1 ;
12410 for( pp=0 ; pp < nf ; pp++ ){
12411 wt[pp] = wtar[pp][ii] ; allz = ( allz && (wt[pp] == 0.0f) );
12412 }
12413
12414 if( allz ){
12415 for( ib=0 ; ib < ts_length ; ib++ ) hout[ib][ii] = 0.0f ;
12416 } else {
12417 register float sum ;
12418 for( ib=0 ; ib < ts_length ; ib++ ){
12419 sum = 0.0f ;
12420 for( pp=0 ; pp < nf ; pp++ ) sum += wt[pp] * bb[pp][ib] ;
12421 hout[ib][ii] = sum ;
12422 }
12423 }
12424 }
12425
12426 /* toss some trash */
12427
12428 for( pp=0 ; pp < nf ; pp++ ) free((void *)bb[pp]) ;
12429 free((void *)bb) ; free((void *)tt) ; free((void *)wt) ;
12430
12431 /* write output */
12432 write_one_ts( output_filename , ts_length , hout ) ;
12433
12434 /* and free results */
12435 for( ib=0 ; ib < ts_length ; ib++ )
12436 free((void *)hout[ib]) ;
12437 free((void *)hout) ;
12438
12439 if( verb )
12440 INFO_message("Wrote iresp 1D dataset into %s\n",output_filename) ;
12441
12442 return ;
12443 }
12444
12445 /*----------------------------------------------------------------------*/
12446
basis_write_sresp(int argc,char * argv[],struct DC_options * option_data,basis_expansion * be,float dt,float * mse,int pbot,matrix cvar,char * output_filename)12447 void basis_write_sresp( int argc , char *argv[] ,
12448 struct DC_options *option_data ,
12449 basis_expansion *be , float dt ,
12450 float *mse ,
12451 int pbot, matrix cvar, char *output_filename )
12452 {
12453 int nvox, ii, nf, allz, ts_length ;
12454 register int pp,qq, ib ;
12455 register float sum ;
12456 float *vv , *tt , **hout , factor , **bb ;
12457 short *bar ;
12458 THD_3dim_dataset *in_dset = NULL;
12459 THD_3dim_dataset *out_dset = NULL;
12460 char label[512] ;
12461 const float EPSILON = 1.0e-10 ;
12462
12463 /* open input 3D+time dataset to get some parameters */
12464
12465 if( be->no_iresp ){ /* 07 Nov 2011 */
12466 ERROR_message("Can't use -sresp for %s %s (%s)",be->option,be->symfun,be->name) ;
12467 return ;
12468 }
12469
12470 in_dset = THD_open_dataset(option_data->input_filename);
12471 CHECK_OPEN_ERROR(in_dset,option_data->input_filename);
12472
12473 if( option_data->force_TR > 0.0 ) /* 18 Aug 2008 */
12474 EDIT_dset_items( in_dset ,
12475 ADN_ttdel , option_data->force_TR ,
12476 ADN_ntt , DSET_NVALS(in_dset) ,
12477 ADN_tunits, UNITS_SEC_TYPE ,
12478 ADN_none ) ;
12479
12480 nvox = in_dset->daxes->nxx * in_dset->daxes->nyy * in_dset->daxes->nzz;
12481 DSET_UNMSEC(in_dset) ; /* 12 Aug 2005 */
12482
12483 if( dt <= 0.0f ) dt = DSET_TR(in_dset) ;
12484 if( dt <= 0.0f ) dt = 1.0f ;
12485
12486 /* create output dataset on the input as a model, then close the input */
12487
12488 out_dset = EDIT_empty_copy( in_dset ) ;
12489 tross_Copy_History( in_dset , out_dset ) ;
12490 DSET_delete( in_dset ) ;
12491
12492 /* historicize the output */
12493
12494 sprintf( label , "Sigma response: %s" , output_filename ) ;
12495 if( commandline != NULL )
12496 tross_multi_Append_History( out_dset , commandline,label,NULL ) ;
12497 else
12498 tross_Append_History ( out_dset, label);
12499
12500 ts_length = 1 + (int)myceil( (be->ttop - be->tbot)/dt ) ;
12501
12502 /* modify the output dataset appropriately */
12503
12504 (void ) EDIT_dset_items( out_dset,
12505 ADN_prefix, output_filename,
12506 ADN_label1, output_filename,
12507 ADN_self_name, output_filename,
12508 ADN_malloc_type, DATABLOCK_MEM_MALLOC,
12509 ADN_datum_all, (floatout)?MRI_float:MRI_short,
12510 ADN_nvals, ts_length,
12511 ADN_ntt, ts_length,
12512 ADN_ttdel, dt ,
12513 ADN_ttorg, be->tbot,
12514 ADN_none ) ;
12515
12516 #ifndef FIX_CONFLICTS
12517 if( THD_is_file(out_dset->dblk->diskptr->header_name) ){
12518 ERROR_message(
12519 "Output dataset file %s already exists - won't overwrite",
12520 out_dset->dblk->diskptr->header_name ) ;
12521 DSET_delete(out_dset) ; return ;
12522 }
12523 #else
12524 if( !THD_ok_overwrite() && /* ZSS: Dec. 16 08 */
12525 THD_deconflict_prefix(out_dset) > 0 ) {
12526 WARNING_message("Filename conflict: changing '%s' to '%s'",
12527 output_filename,DSET_PREFIX(out_dset) ) ;
12528 }
12529 #endif
12530
12531 /* create output bricks (float for now, will scale to shorts later) */
12532
12533 hout = (float **) malloc( sizeof(float *) * ts_length ) ;
12534 for( ib=0 ; ib < ts_length ; ib++ )
12535 hout[ib] = (float *)calloc(sizeof(float),nvox) ;
12536
12537 nf = be->nfunc ;
12538 tt = (float *) malloc( sizeof(float) * ts_length ) ;
12539
12540 for( ib=0 ; ib < ts_length ; ib++ ) /* output time grid */
12541 tt[ib] = be->tbot + ib*dt ;
12542
12543 /* evaluate basis vectors for output on dt time grid */
12544
12545 bb = (float **) malloc( sizeof(float *) * nf ) ;
12546 for( pp=0 ; pp < nf ; pp++ ){
12547 bb[pp] = (float *) malloc( sizeof(float) * ts_length ) ;
12548 for( ib=0 ; ib < ts_length ; ib++ )
12549 bb[pp][ib] = basis_funceval( be->bfunc[pp] , tt[ib] ) ;
12550 }
12551 free((void *)tt) ;
12552
12553 /* evaluate unscaled variance on dt time grid */
12554
12555 vv = (float *) malloc( sizeof(float) * ts_length ) ;
12556 for( ib=0 ; ib < ts_length ; ib++ ){
12557 sum = 0.0f ;
12558 for( pp=0 ; pp < nf ; pp++ ){
12559 for( qq=0 ; qq < nf ; qq++ )
12560 sum += cvar.elts[pbot+pp][pbot+qq] * bb[pp][ib] * bb[qq][ib] ;
12561 }
12562 vv[ib] = (sum >= 0.0f) ? sum : 0.0f ;
12563 }
12564 for( pp=0 ; pp < nf ; pp++ ) free((void *)bb[pp]) ;
12565 free((void *)bb) ;
12566
12567 /* loop over voxels, scale by mse to get variance */
12568
12569 for( ii=0 ; ii < nvox ; ii++ ){
12570 for( ib=0 ; ib < ts_length ; ib++ )
12571 hout[ib][ii] = sqrt( vv[ib] * mse[ii] ) ;
12572 }
12573 free((void *)vv) ;
12574
12575 /* scale floating point bricks to shorts and insert into output dataset */
12576
12577 for( ib=0 ; ib < ts_length ; ib++ ){
12578 if( floatout ){
12579 EDIT_substitute_brick( out_dset , ib , MRI_float , hout[ib] ) ;
12580 factor = 0.0f ;
12581 } else {
12582 bar = (short *) malloc( sizeof(short) * nvox ) ;
12583 factor = EDIT_coerce_autoscale_new(nvox, MRI_float,hout[ib], MRI_short,bar) ;
12584 if( factor < EPSILON ) factor = 0.0f ; /* if brick is all zero */
12585 else factor = 1.0f / factor ;
12586 EDIT_substitute_brick( out_dset , ib , MRI_short , bar ) ;
12587
12588 EDIT_misfit_report( DSET_FILECODE(out_dset) , ib ,
12589 nvox , factor , bar , hout[ib] ) ;
12590
12591 free((void *)hout[ib]) ;
12592 }
12593 EDIT_BRICK_FACTOR( out_dset , ib , factor ) ;
12594 }
12595 free((void *)hout) ;
12596
12597 /* and save the results to disk! */
12598
12599 DSET_write( out_dset ) ;
12600 if( verb )
12601 INFO_message("Wrote sresp 3D+time dataset into %s\n",DSET_BRIKNAME(out_dset)) ;
12602
12603 DSET_delete( out_dset ) ;
12604 return ;
12605 }
12606
12607 /*----------------------------------------------------------------------*/
12608 /* similarly, make 1D version of write_sresp 19 Aug 2011 [rickr] */
basis_write_sresp_1D(int argc,char * argv[],struct DC_options * option_data,basis_expansion * be,float dt,float * mse,int pbot,matrix cvar,char * output_filename)12609 void basis_write_sresp_1D( int argc , char *argv[] ,
12610 struct DC_options *option_data ,
12611 basis_expansion *be , float dt ,
12612 float *mse ,
12613 int pbot, matrix cvar, char *output_filename )
12614 {
12615 int nvox, ii, nf, allz, ts_length ;
12616 register int pp,qq, ib ;
12617 register float sum ;
12618 float *vv , *tt , **hout , factor , **bb ;
12619 short *bar ;
12620 char label[512] ;
12621 const float EPSILON = 1.0e-10 ;
12622
12623 if( be->no_iresp ){ /* 07 Nov 2011 */
12624 ERROR_message("Can't use -sresp for %s %s (%s)",be->option,be->symfun,be->name) ;
12625 return ;
12626 }
12627
12628 nvox = 1 ; /* from basis_write_sresp(), but use 1 voxel */
12629
12630 if( option_data->force_TR > 0.0 ) dt = 1.0f ;
12631 if( dt <= 0.0f ) dt = 1.0f ;
12632
12633 ts_length = 1 + (int)myceil( (be->ttop - be->tbot)/dt ) ;
12634
12635 /* create output bricks */
12636
12637 hout = (float **) malloc( sizeof(float *) * ts_length ) ;
12638 for( ib=0 ; ib < ts_length ; ib++ )
12639 hout[ib] = (float *)calloc(sizeof(float),nvox) ;
12640
12641 nf = be->nfunc ;
12642 tt = (float *) malloc( sizeof(float) * ts_length ) ;
12643
12644 for( ib=0 ; ib < ts_length ; ib++ ) /* output time grid */
12645 tt[ib] = be->tbot + ib*dt ;
12646
12647 /* evaluate basis vectors for output on dt time grid */
12648
12649 bb = (float **) malloc( sizeof(float *) * nf ) ;
12650 for( pp=0 ; pp < nf ; pp++ ){
12651 bb[pp] = (float *) malloc( sizeof(float) * ts_length ) ;
12652 for( ib=0 ; ib < ts_length ; ib++ )
12653 bb[pp][ib] = basis_funceval( be->bfunc[pp] , tt[ib] ) ;
12654 }
12655 free((void *)tt) ;
12656
12657 /* evaluate unscaled variance on dt time grid */
12658
12659 vv = (float *) malloc( sizeof(float) * ts_length ) ;
12660 for( ib=0 ; ib < ts_length ; ib++ ){
12661 sum = 0.0f ;
12662 for( pp=0 ; pp < nf ; pp++ ){
12663 for( qq=0 ; qq < nf ; qq++ )
12664 sum += cvar.elts[pbot+pp][pbot+qq] * bb[pp][ib] * bb[qq][ib] ;
12665 }
12666 vv[ib] = (sum >= 0.0f) ? sum : 0.0f ;
12667 }
12668 for( pp=0 ; pp < nf ; pp++ ) free((void *)bb[pp]) ;
12669 free((void *)bb) ;
12670
12671 /* loop over voxels, scale by mse to get variance */
12672
12673 for( ii=0 ; ii < nvox ; ii++ ){
12674 for( ib=0 ; ib < ts_length ; ib++ )
12675 hout[ib][ii] = sqrt( vv[ib] * mse[ii] ) ;
12676 }
12677 free((void *)vv) ;
12678
12679 /* write output */
12680 write_one_ts( output_filename , ts_length , hout ) ;
12681
12682 /* and free results */
12683 for( ib=0 ; ib < ts_length ; ib++ )
12684 free((void *)hout[ib]) ;
12685 free((void *)hout) ;
12686
12687 if( verb )
12688 INFO_message("Wrote sresp 1D dataset into %s\n",output_filename) ;
12689
12690 return ;
12691 }
12692
12693 /*----------------------------------------------------------------------*/
12694
baseline_mean(vector coef)12695 float baseline_mean( vector coef ) /* 31 Aug 2004 */
12696 {
12697 register int jj ;
12698 register double sum ;
12699
12700 sum = 0.0 ;
12701 for( jj=0 ; jj < nParam ; jj++ )
12702 if( Xcol_inbase[jj] == 2 ) sum += coef.elts[jj] * Xcol_mean[jj] ;
12703
12704 return (float)sum ;
12705 }
12706
12707 /*----------------------------------------------------------------------*/
12708
12709 #if 0
12710 typedef struct { /** structure to hold one -IRC_times stuff **/
12711 int npar , pbot ;
12712 float *ww ; /* [npar] */
12713 float scale_fac ; /* fixed multiplier */
12714 int denom_flag ; /* what to put in denominator? */
12715 char *name ;
12716 } basis_irc ;
12717 #endif
12718
evaluate_irc(basis_irc * birc,vector coef,float base,float mse,matrix cvar)12719 float_pair evaluate_irc( basis_irc *birc , vector coef ,
12720 float base , float mse , matrix cvar )
12721 {
12722 float_pair vt={0.0f,0.0f} ;
12723 int ii,jj, np, pb ;
12724 double asum , bsum ;
12725 float *ww ;
12726
12727 np = birc->npar ;
12728 pb = birc->pbot ;
12729 ww = birc->ww ;
12730
12731 asum = 0.0 ;
12732 for( ii=0 ; ii < np ; ii++ )
12733 asum += coef.elts[pb+ii] * ww[ii] ;
12734
12735 bsum = 0.0 ;
12736 for( ii=0 ; ii < np ; ii++ )
12737 for( jj=0 ; jj < np ; jj++ )
12738 bsum += cvar.elts[pb+ii][pb+jj] * ww[ii] * ww[jj] ;
12739
12740 bsum *= mse ; /* variance estimate */
12741
12742 if( bsum > 0.0 ) vt.b = asum / sqrt(bsum) ; /* t statistic */
12743
12744 vt.a = (float)(asum * birc->scale_fac) ;
12745 if( birc->denom_flag && denom_BASELINE ){
12746 if( base == 0.0f ) vt.a = 0.0f ;
12747 else vt.a /= base ;
12748 }
12749 return vt ;
12750 }
12751
12752 /*---------------------------------------------------------------------------*/
12753 /*! Check matrix condition number. Return value is the
12754 number of bad things that were detected. [07 Mar 2007]
12755 -----------------------------------------------------------------------------*/
12756
check_matrix_condition(matrix xdata,char * xname)12757 static int check_matrix_condition( matrix xdata , char *xname )
12758 {
12759 double *ev, ebot,emin,emax ;
12760 int i,nsmall=0, ssing=show_singvals, bad=0 ;
12761
12762 #undef PSINV_EPS
12763 #ifdef FLOATIZE
12764 # define PSINV_EPS 1.e-8
12765 # define CN_VERYGOOD 10.0
12766 # define CN_GOOD 40.0
12767 # define CN_OK 160.0
12768 # define CN_BEWARE 666.0
12769 #else
12770 # define PSINV_EPS 1.e-14
12771 # define CN_VERYGOOD 20.0
12772 # define CN_GOOD 400.0
12773 # define CN_OK 8000.0
12774 # define CN_BEWARE 160000.0
12775 #endif
12776
12777 ev = matrix_singvals( xdata ) ;
12778 emax = ev[0] ;
12779 for( i=1 ; i < xdata.cols ; i++ ) if( ev[i] > emax ) emax = ev[i] ;
12780 ebot = sqrt(PSINV_EPS)*emax ; emin = 1.e+38 ;
12781 for( i=0 ; i < xdata.cols ; i++ ){
12782 if( ev[i] >= ebot && ev[i] < emin ) emin = ev[i] ;
12783 if( ev[i] < ebot ) nsmall++ ;
12784 }
12785
12786 if( ssing ) fprintf(stderr,"\n") ;
12787
12788 if( emin <= 0.0 || emax <= 0.0 ){
12789 ERROR_message("----- !! %s matrix condition: UNDEFINED ** VERY BAD **\n" ,
12790 xname ) ;
12791 ssing = 1 ; bad++ ;
12792 } else {
12793 double cond=sqrt(emax/emin) ; char *rating ;
12794 if( !use_psinv ) cond = cond*cond ; /* Gaussian elim is twice as bad */
12795 if( cond < CN_VERYGOOD ) rating = "++ VERY GOOD ++" ;
12796 else if( cond < CN_GOOD ) rating = "++ GOOD ++" ;
12797 else if( cond < CN_OK ) rating = "++ OK ++" ;
12798 else if( cond < CN_BEWARE ) rating = "++ A LITTLE BIG ++" ;
12799 else { rating = "** BEWARE **" ; bad++; ssing = 1; }
12800 if( strstr(rating,"*") == NULL )
12801 INFO_message("----- %s matrix condition [%s] (%dx%d): %g %s\n",
12802 xname, (use_psinv) ? "X" : "XtX",
12803 xdata.rows,xdata.cols , cond , rating ) ;
12804 else
12805 WARNING_message("----- !! %s matrix condition [%s] (%dx%d): %g %s\n",
12806 xname, (use_psinv) ? "X" : "XtX",
12807 xdata.rows,xdata.cols , cond , rating ) ;
12808 }
12809
12810 if( nsmall > 0 ){
12811 WARNING_message(
12812 "!! in %s matrix:\n"
12813 " * Largest singular value=%g\n"
12814 " * %d singular value%s less than cutoff=%g\n"
12815 " * Implies strong collinearity in the matrix columns! \n",
12816 xname , emax , nsmall , (nsmall==1)?" is":"s are" , ebot ) ;
12817 ssing = 1 ; bad++ ;
12818 }
12819
12820 if( ssing ){
12821 INFO_message("%s matrix singular values:\n",xname) ;
12822 for( i=0; i < xdata.cols ; i++ ){
12823 fprintf(stderr," %13g",ev[i]) ;
12824 if( i < xdata.cols-1 && i%5 == 4 ) fprintf(stderr,"\n") ;
12825 }
12826 fprintf(stderr,"\n") ;
12827 }
12828
12829 free((void *)ev) ; return bad ;
12830 }
12831
12832 /*----------------------------------------------------------------------------*/
12833 /* Function to convert FSL style stim times image of 3 columns
12834 to -stim_times_AM1 style of vector image.
12835 Note that the input (and output) are row major. In the input,
12836 each row is one stimulus time; unlike FSL, the file can specify times
12837 for more than one run -- runs are separated by a row of '*'.
12838 In the output, each row is one run, and each entry has 3 values
12839 (vdim==3): time,amplitude,duration.
12840 *//*--------------------------------------------------------------------------*/
12841
convert_FSL_to_fvect(MRI_IMAGE * fslim,int do_amp1)12842 MRI_IMAGE * convert_FSL_to_fvect( MRI_IMAGE *fslim , int do_amp1 )
12843 {
12844 int ncol , nrun , qq,qf,qd , nfx,nfy , irun,itim ;
12845 MRI_IMAGE *nbt ;
12846 float *far , *nbar , stim,sdur,samp ;
12847
12848 if( fslim == NULL || fslim->vdim > 0 ) return NULL ;
12849
12850 nfx = fslim->nx ; /* number of values per row, should be 3 */
12851 nfy = fslim->ny ; /* number of rows in input file */
12852
12853 far = MRI_FLOAT_PTR(fslim) ;
12854
12855 /* count number of runs (separated by rows of * = bigger than big_time) */
12856
12857 for( ncol=nrun=qq=qf=0 ; qq < nfy ; qq++ ){
12858 if( far[qq*nfx] > big_time ){
12859 nrun++ ; qd = qq-qf ; ncol = MAX(qd,ncol) ; qf = qq+1 ;
12860 }
12861 }
12862 nrun++ ; qd = nfy-qf ; ncol = MAX(qd,ncol) ;
12863
12864 #undef NBP
12865 #define NBP(ir,ic) (nbar + 3*((ir)*ncol+(ic)) )
12866
12867 nbt = mri_new_fvectim( ncol , nrun , 1 , 3 ) ;
12868 nbar = (float *)nbt->im ;
12869 for( qq=0 ; qq < 3*ncol*nrun ; qq++ ) nbar[qq] = basis_filler ;
12870
12871 for( irun=qq=0,qf=-1 ; qq < nfy ; qq++ ){
12872 stim = far[qq*nfx] ;
12873 if( stim > big_time ){ irun++ ; qf = qq ; continue ; }
12874 sdur = (nfx < 2) ? 0.1f : far[qq*nfx+1] ;
12875 samp = (nfx < 3 || do_amp1) ? 1.0f : far[qq*nfx+2] ;
12876 NBP(irun,qq-qf-1)[0] = stim ;
12877 NBP(irun,qq-qf-1)[1] = samp ;
12878 NBP(irun,qq-qf-1)[2] = sdur ;
12879 }
12880
12881 return nbt ;
12882 }
12883
12884 /******************************************************************************/
12885 /******************************************************************************/
12886 #if 0
12887 /*--- The shell script below is for testing this ARMA/REML implementation. ---*/
12888
12889 #!/bin/tcsh
12890
12891 ### Script to test REML GLSQ vs OLSQ regression
12892
12893 # B = signal amplitude for all repetitions
12894 # P = signal period (TRs)
12895 # nstim = number of signals (IM regression)
12896 # numvox = number of voxels to simulate
12897 # so there is a total of $nstim * $numvox stimuli being simulated
12898
12899 set B = 2
12900 set P = 12
12901 set nstim = 20
12902 set numvox = 400
12903
12904 # ARMA(1,1) parameters for this test/simulation
12905
12906 set AA = 0.8
12907 set LAM = 0.5
12908
12909 # D = number of time points (TR=1)
12910
12911 @ D = $P * $nstim
12912
12913 # create stimulus timing
12914
12915 1deval -num $nstim -expr "i*${P}" > stim.1D
12916
12917 # create the voxel time series = simulated data
12918
12919 1deval -num $D -expr "${B}*sin(PI*t/${P})^2" > signal.1D
12920 foreach ii ( `count -dig 4 1 $numvox` )
12921 1dgenARMA11 -num $D -a $AA -lam $LAM > noise.1D
12922 1deval -a noise.1D -b signal.1D -expr 'a+b' > data${ii}.1D
12923 end
12924
12925 # glue them together into one file
12926
12927 1dcat data0*.1D > data.1D
12928 \rm -f data0*.1D noise.1D signal.1D
12929
12930 # create the regression matrix
12931
12932 3dDeconvolve -num_stimts 1 \
12933 -stim_times_IM 1 stim.1D "EXPR(0,${P}) sin(PI*t/${P})^2" \
12934 -stim_label 1 'sinsq' \
12935 -nodata $D 1 -x1D_stop -polort 2 -x1D test.xmat.1D
12936
12937 # analyses
12938
12939 3dREMLfit -matrix test.xmat.1D \
12940 -input data.1D\' \
12941 -Rvar test.Rvar.1D \
12942 -Rbeta test.Rbeta.1D \
12943 -Obeta test.Obeta.1D \
12944 -nobout -Grid 5 -MAXa 0.9 -MAXb 0.9 -NEGcor
12945
12946 # extract the betas for each voxel into one long single column 1D file
12947 # instead of the multi-column file output by 3dREMLfit
12948
12949 @ ns1 = $nstim - 1
12950 if( -f test.Rbeta.all.1D ) \rm test.Rbeta.all.1D
12951 if( -f test.Obeta.all.1D ) \rm test.Obeta.all.1D
12952 foreach ii ( `count -dig 1 0 $ns1` )
12953 1dcat test.Rbeta.1D"[$ii]" >> test.Rbeta.all.1D
12954 1dcat test.Obeta.1D"[$ii]" >> test.Obeta.all.1D
12955 end
12956
12957 # compute the mean and stdev of the GLSQ and OLSQ betas
12958 # (means should be about B, or something weird happened)
12959
12960 3dTstat -mean -stdev -prefix test.Rbeta.stat.1D test.Rbeta.all.1D\'
12961 3dTstat -mean -stdev -prefix test.Obeta.stat.1D test.Obeta.all.1D\'
12962
12963 # compute the ratio of the stdevs
12964 # srat > 1 means OLSQ stdev was bigger than GLSQ (what we expect)
12965
12966 set Rsig = `1dcat test.Rbeta.stat.1D'[1]'`
12967 set Osig = `1dcat test.Obeta.stat.1D'[1]'`
12968 set srat = `ccalc "$Osig/$Rsig"`
12969
12970 # print out these results
12971
12972 echo "======================="
12973 echo "a = $AA lam = $LAM"
12974 echo "REML mean stdev = " `1dcat test.Rbeta.stat.1D`
12975 echo "OLSQ mean stdev = " `1dcat test.Obeta.stat.1D`
12976 echo "Osig/Rsig = $srat"
12977 echo "======================="
12978
12979 time ; exit 0
12980 #endif
12981 /******************************************************************************/
12982 /******************************************************************************/
12983