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