1 /*----------------------------------------------------------------------------*/
2 /**** TO DO (someday, maybe):
3         -matini
4 ****/
5 
6 /****** N.B.: What used to be 'target' is now 'source' to users,
7               but remains as 'target' in the code and comments.  ******/
8 
9 /****** N.B.: See the note about coordinates at the end of this file! ******/
10 
11 /*
12   [PT: Nov 5, 2018] Don't know why this is only happening *now*, but
13   am moving the lpa/lpc cost functions into the main list under '-cost
14   ccc' in the help; they are no longer classified as "experimental"
15  */
16 
17 /*----------------------------------------------------------------------------*/
18 #include "mrilib.h"
19 #include "r_new_resam_dset.h"
20 #include <time.h>
21 #include <sys/types.h>
22 #include <unistd.h>
23 
24 /*** OpenMP specialized header includes & defines go here ***/
25 
26 #ifdef USE_OMP
27 #include <omp.h>
28 # if 0
29 #  ifdef USING_MCW_MALLOC
30 #   include "mcw_malloc.c"
31 #  endif
32 #endif
33 #endif
34 
35 #undef USE_OLD_BLOK_DEFAULTS  /* 21 Jul 2021 */
36 
37 #define MAXPAR   999    /* max number of parameters to optimize */
38 #define PARC_FIX 1
39 #define PARC_INI 2
40 #define PARC_RAN 3
41 typedef struct { int np,code; float vb,vt ; } param_opt ;
42 
43 /* codes for the 4 types of transformations,
44    each of which add 3 parameters to the mix */
45 
46 #define WARP_SHIFT    1   /* shift only */
47 #define WARP_ROTATE   2   /* shift + rotate */
48 #define WARP_SCALE    3   /* + xyz scaling */
49 #define WARP_AFFINE   4   /* + shears */
50 
51 /* for -1Dapply options */
52 
53 #define APPLY_PARAM   1   /* 23 Jul 2007 */
54 #define APPLY_AFF12   2
55 
56 /****************************************************************************/
57 /******* All the -nwarp stuff is inside ALLOW_NWARP #ifdef-s.
58          The goal is to make it easier to see and later remove this code ****/
59 #ifdef ALLOW_NWARP /*********************************************************/
60 /*** parameter counts for the obsolescent -nwarp option ***/
61 
62 #define NPBIL          39 /* plus 4 */
63 #define WARP_BILINEAR 661
64 #define APPLY_BILIN     3
65 
66 #define NPCUB          60 /* 3*(1+3+6+10) */
67 #define WARP_CUBIC    663
68 #define APPLY_CUBIC     4
69 
70 #define NPQUINT       168 /* 3*(1+3+6+10+15+21) */
71 #define WARP_QUINT    664
72 #define APPLY_QUINT     5
73 
74 #define NPHEPT        360 /* 3*(1+3+6+10+15+21+28+36) */
75 #define WARP_HEPT     665
76 #define APPLY_HEPT      6
77 
78 #define NPNONI        660 /* 3*(1+3+6+10+15+21+28+36+45+55) */
79 #define WARP_NONI     666
80 #define APPLY_NONI      7
81 
82 #define NONLINEAR_IS_POLY(aa) ( (aa) >= WARP_CUBIC && (aa) <= WARP_NONI )
83 
84 #define NONLINEAR_APPLY(aa) ( (aa) >= APPLY_BILIN )
85 
86 #endif /* ALLOW_NWARP */ /**************************************************/
87 
88 /****/
89 
90 /* -twobest defaults */
91 
92 #define DEFAULT_TBEST           5
93 #define DEFAULT_TBEST_LPA      17   /* 27 May 2021 */
94 
95 /* fractions for the lpc+ and lpa+ addons */
96 
97 #define DEFAULT_MICHO_LPC_MI  0.2
98 #define DEFAULT_MICHO_LPC_NMI 0.2
99 #define DEFAULT_MICHO_LPC_CRA 0.4
100 #define DEFAULT_MICHO_LPC_HEL 0.4
101 #define DEFAULT_MICHO_LPC_OV  0.4
102 
103 #define DEFAULT_MICHO_LPA_MI  0.0   /* 27 May 2021 */
104 #define DEFAULT_MICHO_LPA_NMI 0.2
105 #define DEFAULT_MICHO_LPA_CRA 0.4
106 #define DEFAULT_MICHO_LPA_HEL 0.4
107 #define DEFAULT_MICHO_LPA_OV  0.4   /* 28 Sep 2021: bring this back */
108 
109 // [PT: 28 Sep 2021] lpb == lpa, but lpb+ does NOT contain ov
110 // + leaving off doing more with this, at the moment
111 #define DEFAULT_MICHO_LPB_MI  0.0
112 #define DEFAULT_MICHO_LPB_NMI 0.2
113 #define DEFAULT_MICHO_LPB_CRA 0.4
114 #define DEFAULT_MICHO_LPB_HEL 0.4
115 #define DEFAULT_MICHO_LPB_OV  0.0
116 
117 /****/
118 
119 /* making the weight volume from the base dataset */
120 
121 static float wt_medsmooth = 2.25f ;   /* for mri_weightize() */
122 static float wt_gausmooth = 4.50f ;
123 MRI_IMAGE * mri_weightize( MRI_IMAGE *, int, int, float,float ); /* prototype */
124 
125 static int  doing_2D = 0 ; /* 28 Apr 2020: 2D registration */
126 static int  verb     = 1 ; /* somewhat on by default */
127 
128 /* for checking how far 2 sets of parameters are apart from each other */
129 
130 float param_dist( GA_setup *stp , float *aa , float *bb ) ;      /* prototype */
131 
132 void AL_setup_warp_coords( int,int,int,int ,
133                            int *, float *, mat44,
134                            int *, float *, mat44 ) ;             /* prototype */
135 
136 MRI_IMAGE * mri_identity_params(void);                           /* prototype */
137 
138 /* since I no longer like mcw_malloc, MEMORY_CHECK is down the memory hole */
139 
140 #undef MEMORY_CHECK
141 #ifdef USING_MCW_MALLOC
142 # define MEMORY_CHECK(mm)                                               \
143    do{ if( verb > 5 ) mcw_malloc_dump() ;                               \
144        if( verb > 1 ){                                                  \
145          long long nb = mcw_malloc_total() ;                            \
146          if( nb > 0 ) INFO_message("Memory usage now = %s (%s): %s" ,   \
147                       commaized_integer_string(nb) ,                    \
148                       approximate_number_string((double)nb) , (mm) ) ;  \
149        }                                                                \
150    } while(0)
151 #else
152 # define MEMORY_CHECK(mm) /*nada*/
153 #endif
154 
155 #define ALLOW_METH_CHECK   /* for the -check option: 03 Apr 2008 */
156 
157 /*----------------------------------------------------------------------------*/
158 /*** Stuff that defines the method codes and name ***/
159 
160 #undef  NMETH
161 #define NMETH GA_MATCH_METHNUM_SCALAR  /* cf. mrilib.h */
162 
163 static int meth_visible[NMETH] =       /* 1 = show in -help; 0 = don't show */
164   { 1 , 0 , 1 , 1 , 1 , 0 , 1 , 1 , 1 , 0 , 1 , 1 , 1  , 1 } ;
165 /* ls  sp  mi  crM nmi je  hel crA crU lss lpc lpa lpc+ lpa+ */
166 
167 static int meth_noweight[NMETH] =      /* 1 = don't allow weights, just masks */
168   { 0 , 1 , 1 , 0 , 1 , 1 , 1 , 0 , 0 , 0 , 0 , 0 , 0  , 0 } ;
169 /* ls  sp  mi  crM nmi je  hel crA crU lss lpc lpa lpc+ lpa+ */
170 
171 static int visible_noweights ;
172 
173 static char *meth_shortname[NMETH] =   /* short names for terse cryptic users */
174   { "ls" , "sp" , "mi" , "crM", "nmi", "je"   , "hel",
175     "crA", "crU", "lss", "lpc", "lpa", "lpc+" , "lpa+" } ;
176 
177 static char *meth_longname[NMETH] =    /* long names for prolix users */
178   { "leastsq"         , "spearman"     ,
179     "mutualinfo"      , "corratio_mul" ,
180     "norm_mutualinfo" , "jointentropy" ,
181     "hellinger"       ,
182     "corratio_add"    , "corratio_uns" , "signedPcor" ,
183     "localPcorSigned" , "localPcorAbs" , "localPcor+Others" ,
184     "localPcorAbs+Others" } ;
185 
186 static char *meth_username[NMETH] =    /* descriptive names */
187   { "Least Squares [Pearson Correlation]"   ,
188     "Spearman [rank] Correlation"           ,  /* hidden */
189     "Mutual Information [H(b)+H(s)-H(b,s)]" ,
190     "Correlation Ratio (Symmetrized*)"      ,
191     "Normalized MI [H(b,s)/(H(b)+H(s))]"    ,
192     "Joint Entropy [H(b,s)]"                ,  /* hidden */
193     "Hellinger metric"                      ,
194     "Correlation Ratio (Symmetrized+)"      ,
195     "Correlation Ratio (Unsym)"             ,
196     "Signed Pearson Correlation"            ,  /* hidden */
197     "Local Pearson Correlation Signed"      ,  /* hidden */
198     "Local Pearson Correlation Abs"         ,  /* hidden */
199     "Local Pearson Signed + Others"         ,  /* hidden */
200     "Local Pearson Abs + Others"          } ;  /* hidden */
201 
202 static char *meth_costfunctional[NMETH] =  /* describe cost functional */
203   { "1 - abs(Pearson correlation coefficient)"                 ,
204     "1 - abs(Spearman correlation coefficient)"                ,
205     "- Mutual Information = H(base,source)-H(base)-H(source)"  ,
206     "1 - abs[ CR(base,source) * CR(source,base) ]"             ,
207     "1/Normalized MI = H(base,source)/[H(base)+H(source)]"     ,
208     "H(base,source) = joint entropy of image pair"             ,
209     "- Hellinger distance(base,source)"                        ,
210     "1 - abs[ CR(base,source) + CR(source,base) ]"             ,
211     "CR(source,base) = Var(source|base) / Var(source)"         ,
212     "Pearson correlation coefficient between image pair"       ,
213     "nonlinear average of Pearson cc over local neighborhoods" ,
214     "1 - abs(lpc)"                                             ,
215     "lpc + hel + mi + nmi + crA + overlap"                     ,
216     "lpa + hel +      nmi + crA + overlap"
217   } ;
218 
219 /* check if method code implies use of BLOKs */
220 
221 #undef  METH_USES_BLOKS
222 #define METH_USES_BLOKS(mmm) ( mmm == GA_MATCH_PEARSON_LOCALS   || \
223                                mmm == GA_MATCH_LPC_MICHO_SCALAR || \
224                                mmm == GA_MATCH_LPA_MICHO_SCALAR || \
225                                mmm == GA_MATCH_PEARSON_LOCALA       )
226 
227 #undef  METH_IS_LPA
228 #define METH_IS_LPA(mmm)     ( mmm == GA_MATCH_LPA_MICHO_SCALAR || \
229                                mmm == GA_MATCH_PEARSON_LOCALA       )
230 
231 #undef  METH_IS_LPC
232 #define METH_IS_LPC(mmm)     ( mmm == GA_MATCH_LPC_MICHO_SCALAR || \
233                                mmm == GA_MATCH_PEARSON_LOCALS       )
234 
235 /* shortcut for the k-th output parameter in the alignment struct */
236 
237 #define OUTVAL(k) stup.wfunc_param[k].val_out
238 
239 /* In the stuff below,
240     stup.wfunc_param[i].fixed == 2  means parameter [i] cannot be unfixed
241     stup.wfunc_param[i].fixed == 1  means it is 'temporarily fixed'
242     stup.wfunc_param[i].fixed == 0  means it is 'free' -- to be optimized */
243 
244 #ifdef ALLOW_NWARP /*********************************************************/
245 /*---------------------------------------------------------------------------*/
246 /* For the bilinear warp method -- this is obsolete IMHO [RWC] */
247 
248 #define SETUP_BILINEAR_PARAMS                                                \
249  do{ char str[16] ;                                                          \
250      stup.wfunc_numpar = NPBIL+4 ;                                           \
251      stup.wfunc        = mri_genalign_bilinear ;                             \
252      stup.wfunc_param  = (GA_param *)realloc( (void *)stup.wfunc_param,      \
253                                               (NPBIL+4)*sizeof(GA_param) ) ; \
254      for( jj=12 ; jj < NPBIL ; jj++ ){                                       \
255        sprintf(str,"blin%02d",jj+1) ;                                        \
256        DEFPAR( jj,str, -nwarp_parmax,nwarp_parmax , 0.0f,0.0f,0.0f ) ;       \
257        stup.wfunc_param[jj].fixed = 1 ;                                      \
258      }                                                                       \
259      DEFPAR(NPBIL  ,"xcen" ,-1.0e9,1.0e9 , 0.0f,0.0f,0.0f ) ;                \
260      DEFPAR(NPBIL+1,"ycen" ,-1.0e9,1.0e9 , 0.0f,0.0f,0.0f ) ;                \
261      DEFPAR(NPBIL+2,"zcen" ,-1.0e9,1.0e9 , 0.0f,0.0f,0.0f ) ;                \
262      DEFPAR(NPBIL+3,"ddfac", 0.0f ,1.0e9 , 1.0f,0.0f,0.0f ) ;                \
263      stup.wfunc_param[NPBIL  ].fixed = 2 ;                                   \
264      stup.wfunc_param[NPBIL+1].fixed = 2 ;                                   \
265      stup.wfunc_param[NPBIL+2].fixed = 2 ;                                   \
266      stup.wfunc_param[NPBIL+3].fixed = 2 ;                                   \
267  } while(0)
268 
269 /*---------------------------------------------------------------------------*/
270 
BILINEAR_diag_norm(GA_setup stup)271 static float BILINEAR_diag_norm(GA_setup stup)
272 {
273    float sum ;
274    sum  = fabsf(OUTVAL(12))+fabsf(OUTVAL(13))+fabsf(OUTVAL(14)) ;
275    sum += fabsf(OUTVAL(24))+fabsf(OUTVAL(25))+fabsf(OUTVAL(26)) ;
276    sum += fabsf(OUTVAL(36))+fabsf(OUTVAL(37))+fabsf(OUTVAL(38)) ;
277    return (sum/9.0f) ;
278 }
279 
BILINEAR_offdiag_norm(GA_setup stup)280 static float BILINEAR_offdiag_norm(GA_setup stup)
281 {
282    float dmag ;
283    dmag  = fabsf(OUTVAL(15))+fabsf(OUTVAL(16))+fabsf(OUTVAL(17)) ;
284    dmag += fabsf(OUTVAL(18))+fabsf(OUTVAL(19))+fabsf(OUTVAL(20)) ;
285    dmag += fabsf(OUTVAL(21))+fabsf(OUTVAL(22))+fabsf(OUTVAL(23)) ;
286    dmag += fabsf(OUTVAL(27))+fabsf(OUTVAL(28))+fabsf(OUTVAL(29)) ;
287    dmag += fabsf(OUTVAL(30))+fabsf(OUTVAL(31))+fabsf(OUTVAL(32)) ;
288    dmag += fabsf(OUTVAL(33))+fabsf(OUTVAL(34))+fabsf(OUTVAL(35)) ;
289    return (dmag/18.0f) ;
290 }
291 
292 /*---------------------------------------------------------------------------*/
293 /* for the polynomial warp setup - also obsolete [RWC] */
294 
295 #define SETUP_POLYNO_PARAMS(nnl,ran,nam)                                     \
296  do{ char str[32] , *spt , xyz[3] = { 'x', 'y', 'z' } ;                     \
297      stup.wfunc_numpar = 16+(nnl) ;                                          \
298      stup.wfunc        = NULL ;                                              \
299      stup.wfunc_param  = (GA_param *)realloc( (void *)stup.wfunc_param,      \
300                                               (16+(nnl))*sizeof(GA_param) ); \
301      for( jj=12 ; jj < 12+(nnl) ; jj++ ){                                    \
302        spt = GA_polywarp_funcname( (jj-12)/3 ) ;                             \
303        if( spt != NULL ) sprintf(str,"%s:%s:%c"  ,(nam),spt ,xyz[jj%3]) ;    \
304        else              sprintf(str,"%s:%03d:%c",(nam),jj+1,xyz[jj%3]) ;    \
305        DEFPAR( jj,str, -(ran),(ran) , 0.0f,0.0f,0.0f ) ;                     \
306        stup.wfunc_param[jj].fixed = 1 ;                                      \
307      }                                                                       \
308      DEFPAR(12+(nnl),"xcen" ,-1.0e9,1.0e9 , 0.0f,0.0f,0.0f ) ;               \
309      DEFPAR(13+(nnl),"ycen" ,-1.0e9,1.0e9 , 0.0f,0.0f,0.0f ) ;               \
310      DEFPAR(14+(nnl),"zcen" ,-1.0e9,1.0e9 , 0.0f,0.0f,0.0f ) ;               \
311      DEFPAR(15+(nnl),"xxfac", 0.0f ,1.0e9 , 1.0f,0.0f,0.0f ) ;               \
312      stup.wfunc_param[12+(nnl)].fixed = 2 ;                                  \
313      stup.wfunc_param[13+(nnl)].fixed = 2 ;                                  \
314      stup.wfunc_param[14+(nnl)].fixed = 2 ;                                  \
315      stup.wfunc_param[15+(nnl)].fixed = 2 ;                                  \
316  } while(0)
317 
318 #define SETUP_CUBIC_PARAMS do{ SETUP_POLYNO_PARAMS(48,nwarp_parmax,"cubic");  \
319                                stup.wfunc = mri_genalign_cubic ; } while(0)
320 
321 #define SETUP_QUINT_PARAMS do{ SETUP_POLYNO_PARAMS(156,nwarp_parmax,"quint"); \
322                                stup.wfunc = mri_genalign_quintic ; } while(0)
323 
324 #define SETUP_HEPT_PARAMS do{ SETUP_POLYNO_PARAMS(348,nwarp_parmax,"heptic"); \
325                               stup.wfunc = mri_genalign_heptic ; } while(0)
326 
327 #define SETUP_NONI_PARAMS do{ SETUP_POLYNO_PARAMS(648,nwarp_parmax,"nonic");  \
328                               stup.wfunc = mri_genalign_nonic ; } while(0)
329 
330 /*---------- Macros for freezing motions in particular directions ----------*/
331 
332 /* cc = 1,2,3 for x,y,z directions:
333    permanently freeze parameters that cause motion in that direction */
334 
335 #define FREEZE_POLYNO_PARAMS_MOT(cc)                           \
336   do{ int pp ;                                                 \
337       for( pp=12 ; pp < stup.wfunc_numpar ; pp++ ){            \
338         if( 1+pp%3 == (cc) ) stup.wfunc_param[pp].fixed = 2 ;  \
339       }                                                        \
340   } while(0)
341 /* cc = 1,2,3 for x,y,z directions:
342    freeze parameters whose basis funcs are dependent on that coordinate */
343 
344 #define FREEZE_POLYNO_PARAMS_DEP(cc)                           \
345   do{ int pp , qq , cm=(1 << ((cc)-1)) ;                       \
346       for( pp=12 ; pp < stup.wfunc_numpar ; pp++ ){            \
347         qq = GA_polywarp_coordcode( (pp-12)/3 ) ;              \
348         if( qq & cm ) stup.wfunc_param[pp].fixed = 2 ;         \
349       }                                                        \
350   } while(0)
351 
352 /* overall parameter freeze box, based on user options */
353 
354 #define FREEZE_POLYNO_PARAMS                                   \
355  do{ if( nwarp_fixmotX ) FREEZE_POLYNO_PARAMS_MOT(1) ;         \
356      if( nwarp_fixmotY ) FREEZE_POLYNO_PARAMS_MOT(2) ;         \
357      if( nwarp_fixmotZ ) FREEZE_POLYNO_PARAMS_MOT(3) ;         \
358      if( nwarp_fixdepX ) FREEZE_POLYNO_PARAMS_DEP(1) ;         \
359      if( nwarp_fixdepY ) FREEZE_POLYNO_PARAMS_DEP(2) ;         \
360      if( nwarp_fixdepZ ) FREEZE_POLYNO_PARAMS_DEP(3) ; } while(0)
361 
362 #endif /* ALLOW_NWARP */ /**************************************************/
363 
364 /*----------- count free params into variable 'nf' -----------*/
365 
366 #define COUNT_FREE_PARAMS(nf)                                  \
367  do{ int jj ;                                                  \
368      if( verb > 4 ) fprintf(stderr,"++ Free params:") ;        \
369      for( (nf)=jj=0 ; jj < stup.wfunc_numpar ; jj++ ){         \
370        if( !stup.wfunc_param[jj].fixed ){                      \
371          (nf)++ ; if( verb > 4 ) fprintf(stderr," %d",jj) ;    \
372        }                                                       \
373      }                                                         \
374      if( verb > 4 ) fprintf(stderr,"\n") ;                     \
375  } while(0)
376 
377 /*--------- Macro to save Pearson map (for use in main) [27 Jan 2021] --------*/
378 
379 #define SAVE_PEARSON_MAP(sprefix,val_xxx)                                        \
380   do{ MRI_IMAGE *pim ;                                                           \
381       PAR_CPY(val_xxx) ;           /* copy output parameters to allpar[] */      \
382       pim = mri_genalign_map_pearson_local(&stup,allpar) ; /* get 3D map */      \
383       if( pim != NULL ){                                                         \
384         THD_3dim_dataset *pset ;                                                 \
385         pset = THD_volume_to_dataset( dset_base , pim , /* convert to dataset */ \
386                                       (sprefix) ,   pad_xm,pad_xp,               \
387                                       pad_ym,pad_yp,pad_zm,pad_zp ) ;            \
388         mri_free(pim) ;                                                          \
389         if( pset != NULL ){  /* save dataset */                                  \
390           DSET_write(pset) ; WROTE_DSET(pset) ; DSET_delete(pset) ;              \
391         } else {                                                                 \
392           ERROR_message("Failed to create -PearSave dataset %s :(",(sprefix)) ;  \
393         }                                                                        \
394       } else {                                                                   \
395           ERROR_message("Failed to create -PearSave volume %s :(",(sprefix)) ;   \
396       }                                                                          \
397   } while(0)
398 
399 /*---------------------------------------------------------------------------*/
400 /* Given a string, find the cost functional method code that goes with it. */
401 
meth_name_to_code(char * nam)402 int meth_name_to_code( char *nam )  /* 15 Dec 2010 */
403 {
404    int ii ;
405    if( nam == NULL || *nam == '\0' ) return 0 ;
406    for( ii=0 ; ii < NMETH ; ii++ ){
407      if( strcasecmp (nam,meth_shortname[ii])  == 0 ) return (ii+1) ;
408      if( strncasecmp(nam,meth_longname[ii],7) == 0 ) return (ii+1) ;
409    }
410    return 0 ;
411 }
412 
413 /*---------------------------------------------------------------------------*/
414 /* Given an interpolation code, find the name that goes with it. */
415 
INTERP_methname(int iii)416 char * INTERP_methname( int iii )
417 {
418    switch( iii ){
419      default:          return "UNKNOWN" ;
420      case MRI_NN:      return "NN"      ;
421      case MRI_LINEAR:  return "linear"  ;
422      case MRI_CUBIC:   return "cubic"   ;
423      case MRI_QUINTIC: return "quintic" ;
424      case MRI_HEPTIC:  return "heptic"  ;
425      case MRI_WSINC5:  return "wsinc5"  ;
426    }
427    return "MYSTERIOUS" ; /* unreachable */
428 }
429 
430 /*---------------------------- And vice-versa ------------------------------*/
431 
INTERP_code(char * name)432 int INTERP_code( char *name )
433 {
434    if( name == NULL ) return -1 ;
435    if( strcmp(name,"NN") == 0 || strncmp(name,"nearest",5) == 0 )
436      return MRI_NN ;
437    else
438    if( strncmp(name,"linear",3) == 0 || strncmp(name,"trilinear",5) == 0 )
439      return MRI_LINEAR ;
440    else
441    if( strncmp(name,"cubic",3) == 0 || strncmp(name,"tricubic",5) == 0 )
442      return MRI_CUBIC ;
443    else
444    if( strncmp(name,"quintic",3)==0 || strncmp(name,"triquintic",5)==0 )
445      return MRI_QUINTIC ;
446    else
447    if( strncasecmp(name,"WSINC",5)==0 )
448      return MRI_WSINC5 ;
449 
450    return -1 ;
451 }
452 
453 /*---------------------------------------------------------------------------*/
454 
Allin_Help(void)455 void Allin_Help(void)  /* moved here 15 Mar 2021 */
456 {
457    int ii ;
458 
459      visible_noweights = 0 ;
460      for( ii=0 ; ii < NMETH ; ii++ )
461        if( meth_visible[ii] && meth_noweight[ii] ) visible_noweights++ ;
462 
463      printf("\n"
464      "Usage: 3dAllineate [options] sourcedataset\n"
465      "\n"
466      "--------------------------------------------------------------------------\n"
467      "      Program to align one dataset (the 'source') to a 'base'\n"
468      "      dataset, using an affine (matrix) transformation of space.\n"
469      "--------------------------------------------------------------------------\n"
470      "\n"
471      "--------------------------------------------------------------------------\n"
472      "    ***** Please check your results visually, or at some point  *****\n"
473      "    ***** in time you will have bad results and not know it :-( *****\n"
474      "    *****                                                       *****\n"
475      "    ***** No method for 3D image alignment, however tested it   *****\n"
476      "    ***** was, can be relied upon 100%% of the time, and anyone  *****\n"
477      "    ***** who tells you otherwise is a madman or is a liar!!!!  *****\n"
478      "    *****                                                       *****\n"
479      "    ***** In particular, if you are aligning two datasets with  *****\n"
480      "    ***** significantly different spatial coverage (e.g.,       *****\n"
481      "    ***** -source = whole head T1w and -base = MNI template),   *****\n"
482      "    ***** the be careful to check the results. In such a case,  *****\n"
483      "    ***** using '-twobest MAX' should increase the chance of    *****\n"
484      "    ***** getting a good alignment (at the cost of CPU time).   *****\n"
485      "    *****                                                       *****\n"
486      "    ***** Furthermore, don't EVER think that \"I have so much    *****\n"
487      "    ***** data that a few errors will not matter\"!!!!           *****\n"
488      "--------------------------------------------------------------------------\n"
489      "\n"
490      "* Options (lots of them!) are available to control:\n"
491      " ++ How the matching between the source and the base is computed\n"
492      "    (i.e., the 'cost functional' measuring image mismatch).\n"
493      " ++ How the resliced source is interpolated to the base space.\n"
494      " ++ The complexity of the spatial transformation ('warp') used.\n"
495      " ++ And many many technical options to control the process in detail,\n"
496      "    if you know what you are doing (or just like to fool around).\n"
497      "\n"
498      "* This program is a generalization of and improvement on the older\n"
499      "    software 3dWarpDrive.\n"
500      "\n"
501      "* For nonlinear transformations, see progam 3dQwarp.\n"
502      "\n"
503      "* 3dAllineate can also be used to apply a pre-computed matrix to a dataset\n"
504      "  to produce the transformed output. In this mode of operation, it just\n"
505      "  skips the alignment process, whose function is to compute the matrix,\n"
506      "  and instead it reads the matrix in, computes the output dataset,\n"
507      "  writes it out, and stops.\n"
508      "\n"
509      "* If you are curious about the stepwise process used, see the section below\n"
510      "  titled 'SUMMARY of the Default Allineation Process'.\n"
511      "\n"
512      "=====----------------------------------------------------------------------\n"
513      "NOTES: For most 3D image registration purposes, we now recommend that you\n"
514      "=====  use Daniel Glen's script align_epi_anat.py (which, despite its name,\n"
515      "       can do many more registration problems than EPI-to-T1-weighted).\n"
516      "  -->> In particular, using 3dAllineate with the 'lpc' cost functional\n"
517      "       (to align EPI and T1-weighted volumes) requires using a '-weight'\n"
518      "       volume to get good results, and the align_epi_anat.py script will\n"
519      "       automagically generate such a weight dataset that works well for\n"
520      "       EPI-to-structural alignment.\n"
521      "  -->> This script can also be used for other alignment purposes, such\n"
522      "       as T1-weighted alignment between field strengths using the\n"
523      "       '-lpa' cost functional.  Investigate align_epi_anat.py to\n"
524      "       see if it will do what you need -- you might make your life\n"
525      "       a little easier and nicer and happier and more tranquil.\n"
526      "  -->> Also, if/when you ask for registration help on the AFNI\n"
527      "       message board, we'll probably start by recommending that you\n"
528      "       try align_epi_anat.py if you haven't already done so.\n"
529      "  -->> For aligning EPI and T1-weighted volumes, we have found that\n"
530      "       using a flip angle of 50-60 degrees for the EPI works better than\n"
531      "       a flip angle of 90 degrees.  The reason is that there is more\n"
532      "       internal contrast in the EPI data when the flip angle is smaller,\n"
533      "       so the registration has some image structure to work with.  With\n"
534      "       the 90 degree flip angle, there is so little internal contrast in\n"
535      "       the EPI dataset that the alignment process ends up being just\n"
536      "       trying to match brain outlines -- which doesn't always give accurate\n"
537      "       results: see http://dx.doi.org/10.1016/j.neuroimage.2008.09.037\n"
538      "  -->> Although the total MRI signal is reduced at a smaller flip angle,\n"
539      "       there is little or no loss in FMRI/BOLD information, since the bulk\n"
540      "       of the time series 'noise' is from physiological fluctuation signals,\n"
541      "       which are also reduced by the lower flip angle -- for more details,\n"
542      "       see http://dx.doi.org/10.1016/j.neuroimage.2010.11.020\n"
543      "---------------------------------------------------------------------------\n"
544      "  **** New (Summer 2013) program 3dQwarp is available to do nonlinear  ****\n"
545      "  ***  alignment between a base and source dataset, including the use   ***\n"
546      "  **   of 3dAllineate for the preliminary affine alignment.  If you are  **\n"
547      "  *    interested, see the output of '3dQwarp -help' for the details.     *\n"
548      "---------------------------------------------------------------------------\n"
549      "\n"
550      "COMMAND LINE OPTIONS:\n"
551      "====================\n"
552      " -base bbb   = Set the base dataset to be the #0 sub-brick of 'bbb'.\n"
553      "               If no -base option is given, then the base volume is\n"
554      "               taken to be the #0 sub-brick of the source dataset.\n"
555      "               (Base must be stored as floats, shorts, or bytes.)\n"
556      "            ** -base is not needed if you are just applying a given\n"
557      "               transformation to the -source dataset to produce\n"
558      "               the output, using -1Dmatrix_apply or -1Dparam_apply\n"
559      "            ** Unless you use the -master option, the aligned\n"
560      "               output dataset will be stored on the same 3D grid\n"
561      "               as the -base dataset.\n"
562      "\n"
563      " -source ttt = Read the source dataset from 'ttt'.  If no -source\n"
564      "   *OR*        (or -input) option is given, then the source dataset\n"
565      " -input ttt    is the last argument on the command line.\n"
566      "               (Source must be stored as floats, shorts, or bytes.)\n"
567      "            ** This is the dataset to be transformed, to match the\n"
568      "               -base dataset, or directly with one of the options\n"
569      "               -1Dmatrix_apply or -1Dparam_apply\n"
570      "            ** 3dAllineate can register 2D datasets (single slice),\n"
571      "               but both the base and source must be 2D -- you cannot\n"
572      "               use this program to register a 2D slice into a 3D volume!\n"
573      "               -- However, the 'lpc' and 'lpa' cost functionals do not\n"
574      "                  work properly with 2D images, as they are designed\n"
575      "                  around local 3D neighborhoods and that code has not\n"
576      "                  been patched to work with 2D neighborhoods :(\n"
577      "               -- You can input .jpg files as 2D 'datasets', register\n"
578      "                  them with 3dAllineate, and write the result back out\n"
579      "                  using a prefix that ends in '.jpg'; HOWEVER, the color\n"
580      "                  information will not be used in the registration, as\n"
581      "                  this program was written to deal with monochrome medical\n"
582      "                  datasets. At the end, if the source was RGB (color), then\n"
583      "                  the output will be also be RGB, and then a color .jpg\n"
584      "                  can be output.\n"
585      "               -- The above remarks also apply to aligning 3D RGB datasets:\n"
586      "                  it will be done using only the 3D volumes converted to\n"
587      "                  grayscale, but the final output will be the source\n"
588      "                  RGB dataset transformed to the (hopefully) aligned grid.\n"
589      "                 * However, I've never tested aligning 3D color datasets;\n"
590      "                   you can be the first one ever!\n"
591      "            ** See the script @2dwarper.Allin for an example of using\n"
592      "               3dAllineate to do slice-by-slice nonlinear warping to\n"
593      "               align 3D volumes distorted by time-dependent magnetic\n"
594      "               field inhomogeneities.\n"
595      "\n"
596      " ** NOTA BENE: The base and source dataset do NOT have to be defined **\n"
597      " ** [that's]   on the same 3D grids; the alignment process uses the  **\n"
598      " ** [Latin ]   coordinate systems defined in the dataset headers to  **\n"
599      " ** [  for ]   make the match between spatial locations, rather than **\n"
600      " ** [ NOTE ]   matching the 2 datasets on a voxel-by-voxel basis     **\n"
601      " ** [ WELL ]   (as 3dvolreg and 3dWarpDrive do).                     **\n"
602      " **       -->> However, this coordinate-based matching requires that **\n"
603      " **            image volumes be defined on roughly the same patch of **\n"
604      " **            of (x,y,z) space, in order to find a decent starting  **\n"
605      " **            point for the transformation.  You might need to use  **\n"
606      " **            the script @Align_Centers to do this, if the 3D       **\n"
607      " **            spaces occupied by the images do not overlap much.    **\n"
608      " **       -->> Or the '-cmass' option to this program might be       **\n"
609      " **            sufficient to solve this problem, maybe, with luck.   **\n"
610      " **            (Another reason why you should use align_epi_anat.py) **\n"
611      " **       -->> If the coordinate system in the dataset headers is    **\n"
612      " **            WRONG, then 3dAllineate will probably not work well!  **\n"
613      " **            And I say this because we have seen this in several   **\n"
614      " **            datasets downloaded from online archives.             **\n"
615      "\n"
616      " -prefix ppp = Output the resulting dataset to file 'ppp'.  If this\n"
617      "   *OR*        option is NOT given, no dataset will be output!  The\n"
618      " -out ppp      transformation matrix to align the source to the base will\n"
619      "               be estimated, but not applied.  You can save the matrix\n"
620      "               for later use using the '-1Dmatrix_save' option.\n"
621      "        *N.B.: By default, the new dataset is computed on the grid of the\n"
622      "                base dataset; see the '-master' and/or the '-mast_dxyz'\n"
623      "                options to change this grid.\n"
624      "        *N.B.: If 'ppp' is 'NULL', then no output dataset will be produced.\n"
625      "                This option is for compatibility with 3dvolreg.\n"
626      "\n"
627      " -floatize   = Write result dataset as floats.  Internal calculations\n"
628      " -float        are all done on float copies of the input datasets.\n"
629      "               [Default=convert output dataset to data format of  ]\n"
630      "               [        source dataset; if the source dataset was ]\n"
631      "               [        shorts with a scale factor, then the new  ]\n"
632      "               [        dataset will get a scale factor as well;  ]\n"
633      "               [        if the source dataset was shorts with no  ]\n"
634      "               [        scale factor, the result will be unscaled.]\n"
635      "\n"
636      " -1Dparam_save ff   = Save the warp parameters in ASCII (.1D) format into\n"
637      "                      file 'ff' (1 row per sub-brick in source).\n"
638      "                    * A historical synonym for this option is '-1Dfile'.\n"
639      "                    * At the top of the saved 1D file is a #comment line\n"
640      "                      listing the names of the parameters; those parameters\n"
641      "                      that are fixed (e.g., via '-parfix') will be marked\n"
642      "                      by having their symbolic names end in the '$' character.\n"
643      "                      You can use '1dcat -nonfixed' to remove these columns\n"
644      "                      from the 1D file if you just want to further process the\n"
645      "                      varying parameters somehow (e.g., 1dsvd).\n"
646      "                    * However, the '-1Dparam_apply' option requires the\n"
647      "                      full list of parameters, including those that were\n"
648      "                      fixed, in order to work properly!\n"
649      "\n"
650      " -1Dparam_apply aa  = Read warp parameters from file 'aa', apply them to \n"
651      "                      the source dataset, and produce a new dataset.\n"
652      "                      (Must also use the '-prefix' option for this to work!  )\n"
653      "                      (In this mode of operation, there is no optimization of)\n"
654      "                      (the cost functional by changing the warp parameters;  )\n"
655      "                      (previously computed parameters are applied directly.  )\n"
656 /** "               *N.B.: A historical synonym for this is '-1Dapply'.\n" **/
657      "               *N.B.: If you use -1Dparam_apply, you may also want to use\n"
658      "                       -master to control the grid on which the new\n"
659      "                       dataset is written -- the base dataset from the\n"
660      "                       original 3dAllineate run would be a good possibility.\n"
661      "                       Otherwise, the new dataset will be written out on the\n"
662      "                       3D grid coverage of the source dataset, and this\n"
663      "                       might result in clipping off part of the image.\n"
664      "               *N.B.: Each row in the 'aa' file contains the parameters for\n"
665      "                       transforming one sub-brick in the source dataset.\n"
666      "                       If there are more sub-bricks in the source dataset\n"
667      "                       than there are rows in the 'aa' file, then the last\n"
668      "                       row is used repeatedly.\n"
669      "               *N.B.: A trick to use 3dAllineate to resample a dataset to\n"
670      "                       a finer grid spacing:\n"
671      "                         3dAllineate -input dataset+orig         \\\n"
672      "                                     -master template+orig       \\\n"
673      "                                     -prefix newdataset          \\\n"
674      "                                     -final wsinc5               \\\n"
675      "                                     -1Dparam_apply '1D: 12@0'\\'  \n"
676      "                       Here, the identity transformation is specified\n"
677      "                       by giving all 12 affine parameters as 0 (note\n"
678      "                       the extra \\' at the end of the '1D: 12@0' input!).\n"
679      "                     ** You can also use the word 'IDENTITY' in place of\n"
680      "                        '1D: 12@0'\\' (to indicate the identity transformation).\n"
681      "              **N.B.: Some expert options for modifying how the wsinc5\n"
682      "                       method works are described far below, if you use\n"
683      "                       '-HELP' instead of '-help'.\n"
684      "            ****N.B.: The interpolation method used to produce a dataset\n"
685      "                       is always given via the '-final' option, NOT via\n"
686      "                       '-interp'.  If you forget this and use '-interp'\n"
687      "                       along with one of the 'apply' options, this program\n"
688      "                       will chastise you (gently) and change '-final'\n"
689      "                       to match what the '-interp' input.\n"
690      "\n"
691      " -1Dmatrix_save ff  = Save the transformation matrix for each sub-brick into\n"
692      "                      file 'ff' (1 row per sub-brick in the source dataset).\n"
693      "                      If 'ff' does NOT end in '.1D', then the program will\n"
694      "                      append '.aff12.1D' to 'ff' to make the output filename.\n"
695      "               *N.B.: This matrix is the coordinate transformation from base\n"
696      "                       to source DICOM coordinates. In other terms:\n"
697      "                          Xin = Xsource = M Xout = M Xbase\n"
698      "                                   or\n"
699      "                          Xout = Xbase = inv(M) Xin = inv(M) Xsource\n"
700      "                       where Xin or Xsource is the 4x1 coordinates of a\n"
701      "                       location in the input volume. Xout is the \n"
702      "                       coordinate of that same location in the output volume.\n"
703      "                       Xbase is the coordinate of the corresponding location\n"
704      "                       in the base dataset. M is ff augmented by a 4th row of\n"
705      "                       [0 0 0 1], X. is an augmented column vector [x,y,z,1]'\n"
706      "                       To get the inverse matrix inv(M)\n"
707      "                       (source to base), use the cat_matvec program, as in\n"
708      "                         cat_matvec fred.aff12.1D -I\n"
709      "\n"
710      " -1Dmatrix_apply aa = Use the matrices in file 'aa' to define the spatial\n"
711      "                      transformations to be applied.  Also see program\n"
712      "                      cat_matvec for ways to manipulate these matrix files.\n"
713      "               *N.B.: You probably want to use either -base or -master\n"
714      "                      with either *_apply option, so that the coordinate\n"
715      "                      system that the matrix refers to is correctly loaded.\n"
716      "                     ** You can also use the word 'IDENTITY' in place of a\n"
717      "                        filename to indicate the identity transformation --\n"
718      "                        presumably for the purpose of resampling the source\n"
719      "                        dataset to a new grid.\n"
720      "\n"
721      "  * The -1Dmatrix_* options can be used to save and re-use the transformation *\n"
722      "  * matrices.  In combination with the program cat_matvec, which can multiply *\n"
723      "  * saved transformation matrices, you can also adjust these matrices to      *\n"
724      "  * other alignments. These matrices can also be combined with nonlinear      *\n"
725      "  * warps (from 3dQwarp) using programs 3dNwarpApply or 3dNwarpCat.           *\n"
726      "\n"
727      "  * The script 'align_epi_anat.py' uses 3dAllineate and 3dvolreg to align EPI *\n"
728      "  * datasets to T1-weighted anatomical datasets, using saved matrices between *\n"
729      "  * the two programs.  This script is our currently recommended method for    *\n"
730      "  * doing such intra-subject alignments.                                      *\n"
731      "\n"
732      " -cost ccc   = Defines the 'cost' function that defines the matching\n"
733      "               between the source and the base; 'ccc' is one of\n"
734       ) ;
735 
736       for( ii=0 ; ii < NMETH ; ii++ )
737         if( meth_visible[ii] )
738           printf( "                %-4s *OR*  %-16s= %s\n" ,
739                   meth_shortname[ii] , meth_longname[ii] , meth_username[ii] ) ;
740 
741       printf(
742      "               You can also specify the cost functional using an option\n"
743      "               of the form '-mi' rather than '-cost mi', if you like\n"
744      "               to keep things terse and cryptic (as I do).\n"
745      "               [Default == '-hel' (for no good reason, but it sounds nice).]\n"
746      "               **NB** See more below about lpa and lpc, which are typically\n"
747      "                      what we would recommend as first-choice cost functions\n"
748      "                      now:\n"
749      "                        lpa if you have similar contrast vols to align;\n"
750      "                        lpc if you have *non*similar contrast vols to align!\n"
751      "\n"
752      " -interp iii = Defines interpolation method to use during matching\n"
753      "               process, where 'iii' is one of\n"
754      "                 NN      *OR* nearestneighbour *OR nearestneighbor\n"
755      "                 linear  *OR* trilinear\n"
756      "                 cubic   *OR* tricubic\n"
757      "                 quintic *OR* triquintic\n"
758      "               Using '-NN' instead of '-interp NN' is allowed (e.g.).\n"
759      "               Note that using cubic or quintic interpolation during\n"
760      "               the matching process will slow the program down a lot.\n"
761      "               Use '-final' to affect the interpolation method used\n"
762      "               to produce the output dataset, once the final registration\n"
763      "               parameters are determined.  [Default method == 'linear'.]\n"
764      "            ** N.B.: Linear interpolation is used during the coarse\n"
765      "                     alignment pass; the selection here only affects\n"
766      "                     the interpolation method used during the second\n"
767      "                     (fine) alignment pass.\n"
768      "            ** N.B.: '-interp' does NOT define the final method used\n"
769      "                     to produce the output dataset as warped from the\n"
770      "                     input dataset.  If you want to do that, use '-final'.\n"
771      "\n"
772      " -final iii  = Defines the interpolation mode used to create the\n"
773      "               output dataset.  [Default == 'cubic']\n"
774      "            ** N.B.: If you are applying a transformation to an\n"
775      "                       integer-valued dataset (such as an atlas),\n"
776      "                       then you should use '-final NN' to avoid\n"
777      "                       interpolation of the integer labels.\n"
778      "            ** N.B.: For '-final' ONLY, you can use 'wsinc5' to specify\n"
779      "                       that the final interpolation be done using a\n"
780      "                       weighted sinc interpolation method.  This method\n"
781      "                       is so SLOW that you aren't allowed to use it for\n"
782      "                       the registration itself.\n"
783      "                  ++ wsinc5 interpolation is highly accurate and should\n"
784      "                       reduce the smoothing artifacts from lower\n"
785      "                       order interpolation methods (which are most\n"
786      "                       visible if you interpolate an EPI time series\n"
787      "                       to high resolution and then make an image of\n"
788      "                       the voxel-wise variance).\n"
789      "                  ++ On my Intel-based Mac, it takes about 2.5 s to do\n"
790      "                       wsinc5 interpolation, per 1 million voxels output.\n"
791      "                       For comparison, quintic interpolation takes about\n"
792      "                       0.3 s per 1 million voxels: 8 times faster than wsinc5.\n"
793      "                  ++ The '5' refers to the width of the sinc interpolation\n"
794      "                       weights: plus/minus 5 grid points in each direction;\n"
795      "                       this is a tensor product interpolation, for speed.\n"
796      "\n"
797      "TECHNICAL OPTIONS (used for fine control of the program):\n"
798      "=================\n"
799      " -nmatch nnn = Use at most 'nnn' scattered points to match the\n"
800      "               datasets.  The smaller nnn is, the faster the matching\n"
801      "               algorithm will run; however, accuracy may be bad if\n"
802      "               nnn is too small.  If you end the 'nnn' value with the\n"
803      "               '%%' character, then that percentage of the base's\n"
804      "               voxels will be used.\n"
805      "               [Default == 47%% of voxels in the weight mask]\n"
806      "\n"
807      " -nopad      = Do not use zero-padding on the base image.\n"
808      "               (I cannot think of a good reason to use this option.)\n"
809      "               [Default == zero-pad, if needed; -verb shows how much]\n"
810      "\n"
811      " -zclip      = Replace negative values in the input datasets (source & base)\n"
812      " -noneg        with zero.  The intent is to clip off a small set of negative\n"
813      "               values that may arise when using 3dresample (say) with\n"
814      "               cubic interpolation.\n"
815      "\n"
816      " -conv mmm   = Convergence test is set to 'mmm' millimeters.\n"
817      "               This doesn't mean that the results will be accurate\n"
818      "               to 'mmm' millimeters!  It just means that the program\n"
819      "               stops trying to improve the alignment when the optimizer\n"
820      "               (NEWUOA) reports it has narrowed the search radius\n"
821      "               down to this level.\n"
822      "               * To set this value to the smallest allowable, use '-conv 0'.\n"
823      "               * A coarser value for 'quick-and-dirty' alignment is 0.05.\n"
824      "\n"
825      " -verb       = Print out verbose progress reports.\n"
826      "               [Using '-VERB' will give even more prolix reports :]\n"
827      " -quiet      = Don't print out verbose stuff. (But WHY?)\n"
828      "\n"
829      " -usetemp    = Write intermediate stuff to disk, to economize on RAM.\n"
830      "               Using this will slow the program down, but may make it\n"
831      "               possible to register datasets that need lots of space.\n"
832      "       **N.B.: Temporary files are written to the directory given\n"
833      "               in environment variable TMPDIR, or in /tmp, or in ./\n"
834      "               (preference in that order).  If the program crashes,\n"
835      "               these files are named TIM_somethingrandom, and you\n"
836      "               may have to delete them manually. (TIM=Temporary IMage)\n"
837      "       **N.B.: If the program fails with a 'malloc failure' type of\n"
838      "               message, then try '-usetemp' (malloc=memory allocator).\n"
839      "             * If the program just stops with a message 'killed', that\n"
840      "               means the operating system (Unix/Linux) stopped the\n"
841      "               program, which almost always is due to the system running\n"
842      "               low on memory -- so it starts killing programs to save itself.\n"
843 #ifdef USING_MCW_MALLOC
844      "       **N.B.: If you use '-verb', then memory usage is printed out\n"
845      "               at various points along the way.\n"
846 #endif
847      "\n"
848      " -nousetemp  = Don't use temporary workspace on disk [the default].\n"
849      "\n"
850 #ifdef ALLOW_METH_CHECK
851      " -check hhh  = After cost functional optimization is done, start at the\n"
852      "               final parameters and RE-optimize using the new cost\n"
853      "               function 'hhh'.  If the results are too different, a\n"
854      "               warning message will be printed.  However, the final\n"
855      "               parameters from the original optimization will be\n"
856      "               used to create the output dataset. Using '-check'\n"
857      "               increases the CPU time, but can help you feel sure\n"
858      "               that the alignment process did not go wild and crazy.\n"
859      "               [Default == no check == don't worry, be happy!]\n"
860      "       **N.B.: You can put more than one function after '-check', as in\n"
861      "                 -nmi -check mi hel crU crM\n"
862      "               to register with Normalized Mutual Information, and\n"
863      "               then check the results against 4 other cost functionals.\n"
864      "       **N.B.: On the other hand, some cost functionals give better\n"
865      "               results than others for specific problems, and so\n"
866      "               a warning that 'mi' was significantly different than\n"
867      "               'hel' might not actually mean anything useful (e.g.).\n"
868 #if 0
869      "       **N.B.: If you use '-CHECK' instead of '-check', AND there are\n"
870      "               at least two extra check functions specified (in addition\n"
871      "               to the primary cost functional), then the output parameter\n"
872      "               set will be the median of all the final parameter sets\n"
873      "               generated at this stage (including the primary set).\n"
874      "                 **** '-CHECK' is experimental and CPU intensive ****\n"
875 #endif
876 #endif
877      "\n"
878      " ** PARAMETERS THAT AFFECT THE COST OPTIMIZATION STRATEGY **\n"
879      "\n"
880      " -onepass    = Use only the refining pass -- do not try a coarse\n"
881      "               resolution pass first.  Useful if you know that only\n"
882      "               SMALL amounts of image alignment are needed.\n"
883      "               [The default is to use both passes.]\n"
884      "\n"
885      " -twopass    = Use a two pass alignment strategy, first searching for\n"
886      "               a large rotation+shift and then refining the alignment.\n"
887      "               [Two passes are used by default for the first sub-brick]\n"
888      "               [in the source dataset, and then one pass for the others.]\n"
889      "               ['-twopass' will do two passes for ALL source sub-bricks.]\n"
890      "            *** The first (coarse) pass is relatively slow, as it tries\n"
891      "                 to search a large volume of parameter (rotations+shifts)\n"
892      "                 space for initial guesses at the alignment transformation.\n"
893      "              * A lot of these initial guesses are kept and checked to\n"
894      "                 see which ones lead to good starting points for the\n"
895      "                 further refinement.\n"
896      "              * The winners of this competition are then passed to the\n"
897      "                 '-twobest' (infra) successive optimization passes.\n"
898      "              * The ultimate winner of THAT stage is what starts\n"
899      "                 the second (fine) pass alignment. Usually, this starting\n"
900      "                 point is so good that the fine pass optimization does\n"
901      "                 not provide a lot of improvement; that is, most of the\n"
902      "                 run time ends up in coarse pass with its multiple stages.\n"
903      "              * All of these stages are intended to help the program avoid\n"
904      "                 stopping at a 'false' minimum in the cost functional.\n"
905      "                 They were added to the software as we gathered experience\n"
906      "                 with difficult 3D alignment problems. The combination of\n"
907      "                 multiple stages of partial optimization of multiple\n"
908      "                 parameter candidates makes the coarse pass slow, but also\n"
909      "                 makes it (usually) work well.\n"
910      "\n"
911      " -twoblur rr = Set the blurring radius for the first pass to 'rr'\n"
912      "               millimeters.  [Default == 11 mm]\n"
913      "       **N.B.: You may want to change this from the default if\n"
914      "               your voxels are unusually small or unusually large\n"
915      "               (e.g., outside the range 1-4 mm along each axis).\n"
916      "\n"
917      " -twofirst   = Use -twopass on the first image to be registered, and\n"
918      "               then on all subsequent images from the source dataset,\n"
919      "               use results from the first image's coarse pass to start\n"
920      "               the fine pass.\n"
921      "               (Useful when there may be large motions between the   )\n"
922      "               (source and the base, but only small motions within   )\n"
923      "               (the source dataset itself; since the coarse pass can )\n"
924      "               (be slow, doing it only once makes sense in this case.)\n"
925      "       **N.B.: [-twofirst is on by default; '-twopass' turns it off.]\n"
926      "\n"
927      " -twobest bb = In the coarse pass, use the best 'bb' set of initial\n"
928      "               points to search for the starting point for the fine\n"
929      "               pass.  If bb==0, then no search is made for the best\n"
930      "               starting point, and the identity transformation is\n"
931      "               used as the starting point.  [Default=%d; min=0 max=%d]\n"
932      "       **N.B.: Setting bb=0 will make things run faster, but less reliably.\n"
933      "               Setting bb = 'MAX' will make it be the max allowed value.\n"
934      "\n"
935      " -fineblur x = Set the blurring radius to use in the fine resolution\n"
936      "               pass to 'x' mm.  A small amount (1-2 mm?) of blurring at\n"
937      "               the fine step may help with convergence, if there is\n"
938      "               some problem, especially if the base volume is very noisy.\n"
939      "               [Default == 0 mm = no blurring at the final alignment pass]\n"
940      "\n"
941      "   **NOTES ON\n"
942      "   **STRATEGY: * If you expect only small-ish (< 2 voxels?) image movement,\n"
943      "                 then using '-onepass' or '-twobest 0' makes sense.\n"
944      "               * If you expect large-ish image movements, then do not\n"
945      "                 use '-onepass' or '-twobest 0'; the purpose of the\n"
946      "                 '-twobest' parameter is to search for large initial\n"
947      "                 rotations/shifts with which to start the coarse\n"
948      "                 optimization round.\n"
949      "               * If you have multiple sub-bricks in the source dataset,\n"
950      "                 then the default '-twofirst' makes sense if you don't expect\n"
951      "                 large movements WITHIN the source, but expect large motions\n"
952      "                 between the source and base.\n"
953      "               * '-twopass' re-starts the alignment process for each sub-brick\n"
954      "                 in the source dataset -- this option can be time consuming,\n"
955      "                 and is really intended to be used when you might expect large\n"
956      "                 movements between sub-bricks; for example, when the different\n"
957      "                 volumes are gathered on different days.  For most purposes,\n"
958      "                 '-twofirst' (the default process) will be adequate and faster,\n"
959      "                 when operating on multi-volume source datasets.\n"
960 
961        , DEFAULT_TBEST , PARAM_MAXTRIAL  /* for -twobest */
962       ) ;
963 
964       printf(
965      "\n"
966      " -cmass        = Use the center-of-mass calculation to determin an initial shift\n"
967      "                   [This option is OFF by default]\n"
968      "                 can be given as cmass+a, cmass+xy, cmass+yz, cmass+xz\n"
969      "                 where +a means to try determine automatically in which\n"
970      "                 direction the data is partial by looking for a too large shift\n"
971      "                 If given in the form '-cmass+xy' (for example), means to\n"
972      "                 do the CoM calculation in the x- and y-directions, but\n"
973      "                 not the z-direction.\n"
974      "               * MY OPINION: This option is REALLY useful in most cases.\n"
975      "                             However, if you only have partial coverage in\n"
976      "                             the -source dataset, you will need to use\n"
977      "                             one of the '+' additions to restrict the\n"
978      "                             use of the CoM limits.\n"
979      "\n"
980      " -nocmass      = Don't use the center-of-mass calculation. [The default]\n"
981      "                  (You would not want to use the C-o-M calculation if the  )\n"
982      "                  (source sub-bricks have very different spatial locations,)\n"
983      "                  (since the source C-o-M is calculated from all sub-bricks)\n"
984      "\n"
985      " **EXAMPLE: You have a limited coverage set of axial EPI slices you want to\n"
986      "            register into a larger head volume (after 3dSkullStrip, of course).\n"
987      "            In this case, '-cmass+xy' makes sense, allowing CoM adjustment\n"
988      "            along the x = R-L and y = A-P directions, but not along the\n"
989      "            z = I-S direction, since the EPI doesn't cover the whole brain\n"
990      "            along that axis.\n"
991       ) ;
992 
993       printf(
994      "\n"
995      " -autoweight = Compute a weight function using the 3dAutomask\n"
996      "               algorithm plus some blurring of the base image.\n"
997      "       **N.B.: '-autoweight+100' means to zero out all voxels\n"
998      "                 with values below 100 before computing the weight.\n"
999      "               '-autoweight**1.5' means to compute the autoweight\n"
1000      "                 and then raise it to the 1.5-th power (e.g., to\n"
1001      "                 increase the weight of high-intensity regions).\n"
1002      "               These two processing steps can be combined, as in\n"
1003      "                 '-autoweight+100**1.5'\n"
1004      "               ** Note that '**' must be enclosed in quotes;\n"
1005      "                  otherwise, the shell will treat it as a wildcard\n"
1006      "                  and you will get an error message before 3dAllineate\n"
1007      "                  even starts!!\n"
1008      "               ** UPDATE: one can now use '^' for power notation, to \n"
1009      "                  avoid needing to enclose the string in quotes.\n"
1010       ) ;
1011       if( visible_noweights ){
1012          printf(
1013      "       **N.B.: Some cost functionals do not allow -autoweight, and\n"
1014      "               will use -automask instead.  A warning message\n"
1015      "               will be printed if you run into this situation.\n"
1016      "               If a clip level '+xxx' is appended to '-autoweight',\n"
1017      "               then the conversion into '-automask' will NOT happen.\n"
1018      "               Thus, using a small positive '+xxx' can be used trick\n"
1019      "               -autoweight into working on any cost functional.\n"
1020          ) ;
1021       }
1022       printf(
1023      "\n"
1024      " -automask   = Compute a mask function, which is like -autoweight,\n"
1025      "               but the weight for a voxel is set to either 0 or 1.\n"
1026      "       **N.B.: '-automask+3' means to compute the mask function, and\n"
1027      "               then dilate it outwards by 3 voxels (e.g.).\n"
1028      "               ** Note that '+' means something very different\n"
1029      "                  for '-automask' and '-autoweight'!!\n"
1030      "\n"
1031      " -autobox    = Expand the -automask function to enclose a rectangular\n"
1032      "               box that holds the irregular mask.\n"
1033      "       **N.B.: This is the default mode of operation!\n"
1034      "               For intra-modality registration, '-autoweight' may be better!\n"
1035      "             * If the cost functional is 'ls', then '-autoweight' will be\n"
1036      "               the default, instead of '-autobox'.\n"
1037      "\n"
1038      " -nomask     = Don't compute the autoweight/mask; if -weight is not\n"
1039      "               also used, then every voxel will be counted equally.\n"
1040      "\n"
1041      " -weight www = Set the weighting for each voxel in the base dataset;\n"
1042      "               larger weights mean that voxel counts more in the cost\n"
1043      "               function.\n"
1044      "       **N.B.: The weight dataset must be defined on the same grid as\n"
1045      "               the base dataset.\n"
1046      "       **N.B.: Even if a method does not allow -autoweight, you CAN\n"
1047      "               use a weight dataset that is not 0/1 valued.  The\n"
1048      "               risk is yours, of course (!*! as always in AFNI !*!).\n"
1049      "\n"
1050      " -wtprefix p = Write the weight volume to disk as a dataset with\n"
1051      "               prefix name 'p'.  Used with '-autoweight/mask', this option\n"
1052      "               lets you see what voxels were important in the algorithm.\n"
1053      "\n"
1054      " -emask ee   = This option lets you specify a mask of voxels to EXCLUDE from\n"
1055      "               the analysis. The voxels where the dataset 'ee' is nonzero\n"
1056      "               will not be included (i.e., their weights will be set to zero).\n"
1057      "             * Like all the weight options, it applies in the base image\n"
1058      "               coordinate system.\n"
1059      "            ** Like all the weight options, it means nothing if you are using\n"
1060      "               one of the 'apply' options.\n"
1061       ) ;
1062 
1063       if( visible_noweights > 0 ){
1064         printf("\n"
1065                "    Method  Allows -autoweight\n"
1066                "    ------  ------------------\n") ;
1067         for( ii=0 ; ii < NMETH ; ii++ )
1068           if( meth_visible[ii] )
1069             printf("     %-4s   %s\n", meth_shortname[ii] ,
1070                                        meth_noweight[ii] ? "NO" : "YES" ) ;
1071       }
1072 
1073       printf(
1074        "\n"
1075        " -source_mask sss = Mask the source (input) dataset, using 'sss'.\n"
1076        " -source_automask = Automatically mask the source dataset.\n"
1077        "                      [By default, all voxels in the source]\n"
1078        "                      [dataset are used in the matching.   ]\n"
1079        "            **N.B.: You can also use '-source_automask+3' to dilate\n"
1080        "                    the default source automask outward by 3 voxels.\n"
1081       ) ;
1082 
1083       printf(
1084        "\n"
1085        " -warp xxx   = Set the warp type to 'xxx', which is one of\n"
1086        "                 shift_only         *OR* sho =  3 parameters\n"
1087        "                 shift_rotate       *OR* shr =  6 parameters\n"
1088        "                 shift_rotate_scale *OR* srs =  9 parameters\n"
1089        "                 affine_general     *OR* aff = 12 parameters\n"
1090        "               [Default = affine_general, which includes image]\n"
1091        "               [      shifts, rotations, scaling, and shearing]\n"
1092        "             * MY OPINION: Shearing is usually unimportant, so\n"
1093        "                            you can omit it if you want: '-warp srs'.\n"
1094        "                           But it doesn't hurt to keep shearing,\n"
1095        "                            except for a little extra CPU time.\n"
1096        "                           On the other hand, scaling is often\n"
1097        "                            important, so should not be omitted.\n"
1098        "\n"
1099        " -warpfreeze = Freeze the non-rigid body parameters (those past #6)\n"
1100        "               after doing the first sub-brick.  Subsequent volumes\n"
1101        "               will have the same spatial distortions as sub-brick #0,\n"
1102        "               plus rigid body motions only.\n"
1103        "             * MY OPINION: This option is almost useless.\n"
1104        "\n"
1105        " -replacebase   = If the source has more than one sub-brick, and this\n"
1106        "                  option is turned on, then after the #0 sub-brick is\n"
1107        "                  aligned to the base, the aligned #0 sub-brick is used\n"
1108        "                  as the base image for subsequent source sub-bricks.\n"
1109        "                * MY OPINION: This option is almost useless.\n"
1110        "\n"
1111        " -replacemeth m = After sub-brick #0 is aligned, switch to method 'm'\n"
1112        "                  for later sub-bricks.  For use with '-replacebase'.\n"
1113        "                * MY OPINION: This option is almost useless.\n"
1114        "\n"
1115        " -EPI        = Treat the source dataset as being composed of warped\n"
1116        "               EPI slices, and the base as comprising anatomically\n"
1117        "               'true' images.  Only phase-encoding direction image\n"
1118        "               shearing and scaling will be allowed with this option.\n"
1119        "       **N.B.: For most people, the base dataset will be a 3dSkullStrip-ed\n"
1120        "               T1-weighted anatomy (MPRAGE or SPGR).  If you don't remove\n"
1121        "               the skull first, the EPI images (which have little skull\n"
1122        "               visible due to fat-suppression) might expand to fit EPI\n"
1123        "               brain over T1-weighted skull.\n"
1124        "       **N.B.: Usually, EPI datasets don't have as complete slice coverage\n"
1125        "               of the brain as do T1-weighted datasets.  If you don't use\n"
1126        "               some option (like '-EPI') to suppress scaling in the slice-\n"
1127        "               direction, the EPI dataset is likely to stretch the slice\n"
1128        "               thickness to better 'match' the T1-weighted brain coverage.\n"
1129 #if 0
1130        "       **N.B.: '-EPI' turns on '-warpfreeze -replacebase -replacemeth ls'.\n"
1131        "               To disable '-replacemeth ls', use '-replacemeth 0' after '-EPI'.\n"
1132 #else
1133        "       **N.B.: '-EPI' turns on '-warpfreeze -replacebase'.\n"
1134 #endif
1135        "               You can use '-nowarpfreeze' and/or '-noreplacebase' AFTER the\n"
1136        "               '-EPI' on the command line if you do not want these options used.\n"
1137        "\n"
1138        "  ** OPTIONS to change search ranges for alignment parameters **\n"
1139        "\n"
1140        " -smallrange   = Set all the parameter ranges to be smaller (about half) than\n"
1141        "                 the default ranges, which are rather large for many purposes.\n"
1142        "                * Default angle range    is plus/minus 30 degrees\n"
1143        "                * Default shift range    is plus/minus 32%% of grid size\n"
1144        "                * Default scaling range  is plus/minus 20%% of grid size\n"
1145        "                * Default shearing range is plus/minus 0.1111\n"
1146        "\n"
1147        " -parfix n v   = Fix parameter #n to be exactly at value 'v'.\n"
1148      "\n"
1149        " -parang n b t = Allow parameter #n to range only between 'b' and 't'.\n"
1150        "                 If not given, default ranges are used.\n"
1151      "\n"
1152        " -parini n v   = Initialize parameter #n to value 'v', but then\n"
1153        "                 allow the algorithm to adjust it.\n"
1154        "         **N.B.: Multiple '-par...' options can be used, to constrain\n"
1155        "                 multiple parameters.\n"
1156        "         **N.B.: -parini has no effect if -twopass is used, since\n"
1157        "                 the -twopass algorithm carries out its own search\n"
1158        "                 for initial parameters.\n"
1159        "\n"
1160        " -maxrot dd    = Allow maximum rotation of 'dd' degrees.  Equivalent\n"
1161        "                 to '-parang 4 -dd dd -parang 5 -dd dd -parang 6 -dd dd'\n"
1162        "                 [Default=30 degrees]\n"
1163      "\n"
1164        " -maxshf dd    = Allow maximum shift of 'dd' millimeters.  Equivalent\n"
1165        "                 to '-parang 1 -dd dd -parang 2 -dd dd -parang 3 -dd dd'\n"
1166        "                 [Default=32%% of the size of the base image]\n"
1167        "         **N.B.: This max shift setting is relative to the center-of-mass\n"
1168        "                 shift, if the '-cmass' option is used.\n"
1169      "\n"
1170        " -maxscl dd    = Allow maximum scaling factor to be 'dd'.  Equivalent\n"
1171        "                 to '-parang 7 1/dd dd -parang 8 1/dd dd -paran2 9 1/dd dd'\n"
1172        "                 [Default=1.4=image can go up or down 40%% in size]\n"
1173      "\n"
1174        " -maxshr dd    = Allow maximum shearing factor to be 'dd'. Equivalent\n"
1175        "                 to '-parang 10 -dd dd -parang 11 -dd dd -parang 12 -dd dd'\n"
1176        "                 [Default=0.1111 for no good reason]\n"
1177        "\n"
1178        " NOTE: If the datasets being registered have only 1 slice, 3dAllineate\n"
1179        "       will automatically fix the 6 out-of-plane motion parameters to\n"
1180        "       their 'do nothing' values, so you don't have to specify '-parfix'.\n"
1181 #if 0
1182        "\n"
1183        " -matini mmm   = Initialize 3x4 affine transformation matrix to 'mmm',\n"
1184        "                 which is either a .1D file or an expression in the\n"
1185        "                 syntax of program 1dmatcalc.  Using this option is\n"
1186        "                 like using '-parini' on all affine matrix parameters.\n"
1187 #endif
1188        "\n"
1189        " -master mmm = Write the output dataset on the same grid as dataset\n"
1190        "               'mmm'.  If this option is NOT given, the base dataset\n"
1191        "               is the master.\n"
1192        "       **N.B.: 3dAllineate transforms the source dataset to be 'similar'\n"
1193        "               to the base image.  Therefore, the coordinate system\n"
1194        "               of the master dataset is interpreted as being in the\n"
1195        "               reference system of the base image.  It is thus vital\n"
1196        "               that these finite 3D volumes overlap, or you will lose data!\n"
1197        "       **N.B.: If 'mmm' is the string 'SOURCE', then the source dataset\n"
1198        "               is used as the master for the output dataset grid.\n"
1199        "               You can also use 'BASE', which is of course the default.\n"
1200        "\n"
1201        " -mast_dxyz del = Write the output dataset using grid spacings of\n"
1202        "  *OR*            'del' mm.  If this option is NOT given, then the\n"
1203        " -newgrid del     grid spacings in the master dataset will be used.\n"
1204        "                  This option is useful when registering low resolution\n"
1205        "                  data (e.g., EPI time series) to high resolution\n"
1206        "                  datasets (e.g., MPRAGE) where you don't want to\n"
1207        "                  consume vast amounts of disk space interpolating\n"
1208        "                  the low resolution data to some artificially fine\n"
1209        "                  (and meaningless) spatial grid.\n"
1210      ) ;
1211 
1212      printf(
1213       "\n"
1214       "----------------------------------------------\n"
1215       "DEFINITION OF AFFINE TRANSFORMATION PARAMETERS\n"
1216       "----------------------------------------------\n"
1217       "The 3x3 spatial transformation matrix is calculated as [S][D][U],\n"
1218       "where [S] is the shear matrix,\n"
1219       "      [D] is the scaling matrix, and\n"
1220       "      [U] is the rotation (proper orthogonal) matrix.\n"
1221       "Thes matrices are specified in DICOM-ordered (x=-R+L,y=-A+P,z=-I+S)\n"
1222       "coordinates as:\n"
1223       "\n"
1224       "  [U] = [Rotate_y(param#6)] [Rotate_x(param#5)] [Rotate_z(param #4)]\n"
1225       "        (angles are in degrees)\n"
1226       "\n"
1227       "  [D] = diag( param#7 , param#8 , param#9 )\n"
1228       "\n"
1229       "        [    1        0     0 ]        [ 1 param#10 param#11 ]\n"
1230       "  [S] = [ param#10    1     0 ]   OR   [ 0    1     param#12 ]\n"
1231       "        [ param#11 param#12 1 ]        [ 0    0        1     ]\n"
1232       "\n"
1233       "The shift vector comprises parameters #1, #2, and #3.\n"
1234       "\n"
1235       "The goal of the program is to find the warp parameters such that\n"
1236       "   I([x]_warped) 'is similar to' J([x]_in)\n"
1237       "as closely as possible in some sense of 'similar', where J(x) is the\n"
1238       "base image, and I(x) is the source image.\n"
1239       "\n"
1240       "Using '-parfix', you can specify that some of these parameters\n"
1241       "are fixed.  For example, '-shift_rotate_scale' is equivalent\n"
1242       "'-affine_general -parfix 10 0 -parfix 11 0 -parfix 12 0'.\n"
1243       "Don't even think of using the '-parfix' option unless you grok\n"
1244       "this example!\n"
1245       "\n"
1246       "----------- Special Note for the '-EPI' Option's Coordinates -----------\n"
1247       "In this case, the parameters above are with reference to coordinates\n"
1248       "  x = frequency encoding direction (by default, first axis of dataset)\n"
1249       "  y = phase encoding direction     (by default, second axis of dataset)\n"
1250       "  z = slice encoding direction     (by default, third axis of dataset)\n"
1251       "This option lets you freeze some of the warping parameters in ways that\n"
1252       "make physical sense, considering how echo-planar images are acquired.\n"
1253       "The x- and z-scaling parameters are disabled, and shears will only affect\n"
1254       "the y-axis.  Thus, there will be only 9 free parameters when '-EPI' is\n"
1255       "used.  If desired, you can use a '-parang' option to allow the scaling\n"
1256       "fixed parameters to vary (put these after the '-EPI' option):\n"
1257       "  -parang 7 0.833 1.20     to allow x-scaling\n"
1258       "  -parang 9 0.833 1.20     to allow z-scaling\n"
1259       "You could also fix some of the other parameters, if that makes sense\n"
1260       "in your situation; for example, to disable out-of-slice rotations:\n"
1261       "  -parfix 5 0  -parfix 6 0\n"
1262       "and to disable out of slice translation:\n"
1263       "  -parfix 3 0\n"
1264       "NOTE WELL: If you use '-EPI', then the output warp parameters (e.g., in\n"
1265       "           '-1Dparam_save') apply to the (freq,phase,slice) xyz coordinates,\n"
1266       "           NOT to the DICOM xyz coordinates, so equivalent transformations\n"
1267       "           will be expressed with different sets of parameters entirely\n"
1268       "           than if you don't use '-EPI'!  This comment does NOT apply\n"
1269       "           to the output of '-1Dmatrix_save', since that matrix is\n"
1270       "           defined relative to the RAI (DICOM) spatial coordinates.\n"
1271      ) ;
1272 
1273      printf(
1274       "\n"
1275       "*********** CHANGING THE ORDER OF MATRIX APPLICATION ***********\n"
1276       "   {{{ There is no good reason to ever use these options! }}}\n"
1277       "\n"
1278       "  -SDU or -SUD }= Set the order of the matrix multiplication\n"
1279       "  -DSU or -DUS }= for the affine transformations:\n"
1280       "  -USD or -UDS }=   S = triangular shear (params #10-12)\n"
1281       "                    D = diagonal scaling matrix (params #7-9)\n"
1282       "                    U = rotation matrix (params #4-6)\n"
1283       "                  Default order is '-SDU', which means that\n"
1284       "                  the U matrix is applied first, then the\n"
1285       "                  D matrix, then the S matrix.\n"
1286       "\n"
1287       "  -Supper      }= Set the S matrix to be upper or lower\n"
1288       "  -Slower      }= triangular [Default=lower triangular]\n"
1289       "                  NOTE: There is no '-Lunch' option.\n"
1290       "                        There is no '-Faster' option.\n"
1291       "\n"
1292       "  -ashift OR   }= Apply the shift parameters (#1-3) after OR\n"
1293       "  -bshift      }= before the matrix transformation. [Default=after]\n"
1294      ) ;
1295 
1296      printf(
1297       "\n"
1298       "            ==================================================\n"
1299       "        ===== RWCox - September 2006 - Live Long and Prosper =====\n"
1300       "            ==================================================\n"
1301       "\n"
1302       "         ********************************************************\n"
1303       "        *** From Webster's Dictionary: Allineate == 'to align' ***\n"
1304       "         ********************************************************\n"
1305      ) ;
1306 
1307      /*......................................................................*/
1308 
1309      if( 1 ){   /* this used to be only for "-HELP" */
1310        printf(
1311         "\n"
1312         "===========================================================================\n"
1313         "                       FORMERLY SECRET HIDDEN OPTIONS\n"
1314         "---------------------------------------------------------------------------\n"
1315         "        ** N.B.: Most of these are experimental! [permanent beta] **\n"
1316         "===========================================================================\n"
1317         "\n"
1318         " -num_rtb n  = At the beginning of the fine pass, the best set of results\n"
1319         "               from the coarse pass are 'refined' a little by further\n"
1320         "               optimization, before the single best one is chosen for\n"
1321         "               for the final fine optimization.\n"
1322         "              * This option sets the maximum number of cost functional\n"
1323         "                evaluations to be used (for each set of parameters)\n"
1324         "                in this step.\n"
1325         "              * The default is 99; a larger value will take more CPU\n"
1326         "                time but may give more robust results.\n"
1327         "              * If you want to skip this step entirely, use '-num_rtb 0'.\n"
1328         "                then, the best of the coarse pass results is taken\n"
1329         "                straight to the final optimization passes.\n"
1330         "       **N.B.: If you use '-VERB', you will see that one extra case\n"
1331         "               is involved in this initial fine refinement step; that\n"
1332         "               case is starting with the identity transformation, which\n"
1333         "               helps insure against the chance that the coarse pass\n"
1334         "               optimizations ran totally amok.\n"
1335         "             * MY OPINION: This option is mostly useless - but not always!\n"
1336         "                         * Every step in the multi-step alignment process\n"
1337         "                            was added at some point to solve a difficult\n"
1338         "                            alignment problem.\n"
1339         "                         * Since you usually don't know if YOUR problem\n"
1340         "                            is difficult, you should not reduce the default\n"
1341         "                            process without good reason.\n"
1342         "\n"
1343         " -nocast     = By default, parameter vectors that are too close to the\n"
1344         "               best one are cast out at the end of the coarse pass\n"
1345         "               refinement process. Use this option if you want to keep\n"
1346         "               them all for the fine resolution pass.\n"
1347         "             * MY OPINION: This option is nearly useless.\n"
1348         "\n"
1349         " -norefinal  = Do NOT re-start the fine iteration step after it\n"
1350         "               has converged.  The default is to re-start it, which\n"
1351         "               usually results in a small improvement to the result\n"
1352         "               (at the cost of CPU time).  This re-start step is an\n"
1353         "               an attempt to avoid a local minimum trap.  It is usually\n"
1354         "               not necessary, but sometimes helps.\n"
1355         "\n"
1356         " -realaxes   = Use the 'real' axes stored in the dataset headers, if they\n"
1357         "               conflict with the default axes.  [For Jedi AFNI Masters only!]\n"
1358         "\n"
1359         " -savehist sss = Save start and final 2D histograms as PGM\n"
1360         "                 files, with prefix 'sss' (cost: cr mi nmi hel).\n"
1361         "                * if filename contains 'FF', floats is written\n"
1362         "                * these are the weighted histograms!\n"
1363         "                * -savehist will also save histogram files when\n"
1364         "                  the -allcost evaluations takes place\n"
1365         "                * this option is mostly useless unless '-histbin' is\n"
1366         "                  also used\n"
1367         "               * MY OPINION: This option is mostly for debugging.\n"
1368 #if 0
1369         " -seed iii     = Set random number seed (for coarse startup search)\n"
1370         "                 to 'iii'.\n"
1371         "                 [Default==7654321; if iii==0, a unique value is used]\n"
1372 #endif
1373         " -median       = Smooth with median filter instead of Gaussian blur.\n"
1374         "                 (Somewhat slower, and not obviously useful.)\n"
1375         "               * MY OPINION: This option is nearly useless.\n"
1376         "\n"
1377         " -powell m a   = Set the Powell NEWUOA dimensional parameters to\n"
1378         "                 'm' and 'a' (cf. source code in powell_int.c).\n"
1379         "                 The number of points used for approximating the\n"
1380         "                 cost functional is m*N+a, where N is the number\n"
1381         "                 of parameters being optimized.  The default values\n"
1382         "                 are m=2 and a=3.  Larger values will probably slow\n"
1383         "                 the program down for no good reason.  The smallest\n"
1384         "                 allowed values are 1.\n"
1385         "               * MY OPINION: This option is nearly useless.\n"
1386         "\n"
1387         " -target ttt   = Same as '-source ttt'.  In the earliest versions,\n"
1388         "                 what I now call the 'source' dataset was called the\n"
1389         "                 'target' dataset:\n"
1390         "                    Try to remember the kind of September (2006)\n"
1391         "                    When life was slow and oh so mellow\n"
1392         "                    Try to remember the kind of September\n"
1393         "                    When grass was green and source was target.\n"
1394 #if 0
1395         " -targijk      = Align source xyz axes with ijk indexes, rather than\n"
1396         "                 using coordinates in target header.\n"
1397 #endif
1398         " -Xwarp       =} Change the warp/matrix setup so that only the x-, y-, or z-\n"
1399         " -Ywarp       =} axis is stretched & sheared.  Useful for EPI, where 'X',\n"
1400         " -Zwarp       =} 'Y', or 'Z' corresponds to the phase encoding direction.\n"
1401         " -FPS fps      = Generalizes -EPI to arbitrary permutation of directions.\n"
1402         "\n"
1403         " -histpow pp   = By default, the number of bins in the histogram used\n"
1404         "                 for calculating the Hellinger, Mutual Information, and\n"
1405         "                 Correlation Ratio statistics is n^(1/3), where n is\n"
1406         "                 the number of data points.  You can change that exponent\n"
1407         "                 to 'pp' with this option.\n"
1408         " -histbin nn   = Or you can just set the number of bins directly to 'nn'.\n"
1409         " -eqbin   nn   = Use equalized marginal histograms with 'nn' bins.\n"
1410         " -clbin   nn   = Use 'nn' equal-spaced bins except for the bot and top,\n"
1411         "                 which will be clipped (thus the 'cl').  If nn is 0, the\n"
1412         "                 program will pick the number of bins for you.\n"
1413         "                 **N.B.: '-clbin 0' is now the default [25 Jul 2007];\n"
1414         "                         if you want the old all-equal-spaced bins, use\n"
1415         "                         '-histbin 0'.\n"
1416         "                 **N.B.: '-clbin' only works when the datasets are\n"
1417         "                         non-negative; any negative voxels in either\n"
1418         "                         the input or source volumes will force a switch\n"
1419         "                         to all equal-spaced bins.\n"
1420         "               * MY OPINION: The above histogram-altering options are useless.\n"
1421         "\n"
1422         " -wtmrad  mm   = Set autoweight/mask median filter radius to 'mm' voxels.\n"
1423         " -wtgrad  gg   = Set autoweight/mask Gaussian filter radius to 'gg' voxels.\n"
1424         " -nmsetup nn   = Use 'nn' points for the setup matching [default=98756]\n"
1425         " -ignout       = Ignore voxels outside the warped source dataset.\n"
1426         "\n"
1427         " -blok bbb     = Blok definition for the 'lp?' (Local Pearson) cost\n"
1428         "                 functions: 'bbb' is one of\n"
1429         "                   'BALL(r)' or 'CUBE(r)' or 'RHDD(r)' or 'TOHD(r)'\n"
1430         "                 corresponding to\n"
1431         "                   spheres or cubes or rhombic dodecahedra or\n"
1432         "                   truncated octahedra\n"
1433         "                 where 'r' is the size parameter in mm.\n"
1434 #ifdef USE_OLD_BLOK_DEFAULTS
1435         "                 [Default is 'RHDD(6.54321)' (rhombic dodecahedron)]\n"
1436         "               * Changing the 'blok' definition/radius should only be\n"
1437         "                 needed if the resolution of the base dataset is\n"
1438         "                 radically different from the common 1 mm.\n"
1439 #else
1440         "                 [Default is 'TOHD(r)' = truncated octahedron]\n"
1441         "                 [with 'radius' r chosen to include about 500]\n"
1442         "                 [voxels in the base dataset 3D grid.        ]\n"
1443         "               * Changing the 'blok' definition/radius should only be\n"
1444         "                 needed in unusual situations, as when you are trying\n"
1445         "                 to have fun fun fun.\n"
1446         "               * You can change the blok shape but leave the program\n"
1447         "                 to set the radius, using (say) 'RHDD(0)'.\n"
1448         "               * The old default blok shape/size was 'RHDD(6.54321)',\n"
1449         "                 so if you want to maintain backward compatibility,\n"
1450         "                 you should use option '-blok \"RHDD(6.54321)\"'\n"
1451 #endif
1452         "                 * Only voxels in the weight mask will be used\n"
1453         "                   inside a blok.\n"
1454         "               * HISTORICAL NOTES:\n"
1455         "                 * CUBE, RHDD, and TOHD are space filling polyhedra.\n"
1456         "                   That is, they are shapes that fit together without\n"
1457         "                   overlaps or gaps to fill up 3D space.\n"
1458         "                 * To even approximately fill space, BALLs must overlap,\n"
1459         "                   unlike the other blok shapes. Which means that BALL\n"
1460         "                   bloks will use some voxels more than once.\n"
1461         "                 * Kepler discovered/invented the RHDD (honeybees also did).\n"
1462         "                 * The TOHD is the 'most compact' or 'most ball-like'\n"
1463         "                   of the known convex space filling polyhedra.\n"
1464 #ifndef USE_OLD_BLOK_DEFAULTS
1465         "                   [Which is why TOHD is the default blok shape.]\n"
1466 #endif
1467         "\n"
1468         " -PearSave sss = Save the final local Pearson correlations into a dataset\n"
1469         "   *OR*          with prefix 'sss'. These are the correlations from\n"
1470         " -SavePear sss   which the lpc and lpa cost functionals are calculated.\n"
1471         "                * The values will be between -1 and 1 in each blok.\n"
1472         "                   See the 'Too Much Detail' section below for how\n"
1473         "                   these correlations are used to compute lpc and lpa.\n"
1474         "                * Locations not used in the matching will get 0.\n"
1475         "               ** Unless you use '-nmatch 100%%', there will be holes\n"
1476         "                   of 0s in the bloks, as not all voxels are used in\n"
1477         "                   the matching algorithm (speedup attempt).\n"
1478         "                * All the matching points in a given blok will get\n"
1479         "                   the same value, which makes the resulting dataset\n"
1480         "                   look jauntily blocky, especially in color.\n"
1481         "                * This saved dataset will be on the grid of the base\n"
1482         "                   dataset, and may be zero padded if the program\n"
1483         "                   chose to do so in it wisdom. This padding means\n"
1484         "                   that the voxels in this output dataset may not\n"
1485         "                   match one-to-one with the voxels in the base\n"
1486         "                   dataset; however, AFNI displays things using\n"
1487         "                   coordinates, so overlaying this dataset on the\n"
1488         "                   base dataset (say) should work OK.\n"
1489         "                * If you really want this saved dataset to be on the\n"
1490         "                   grid as the base dataset, you'll have use\n"
1491         "                     3dZeropad -master {Base Dataset} ....\n"
1492         "                * Option '-PearSave' works even if you don't use the\n"
1493         "                   'lpc' or 'lpa' cost functionals.\n"
1494         "                * If you use this option combined with '-allcostX', then\n"
1495         "                   the local correlations will be saved from the INITIAL\n"
1496         "                   alignment parameters, rather than from the FINAL\n"
1497         "                   optimized parameters.\n"
1498         "                   (Of course, with '-allcostX', there IS no final result.)\n"
1499         "                * This option does NOT work with '-allcost' or '-allcostX1D'.\n"
1500         "\n"
1501         " -allcost        = Compute ALL available cost functionals and print them\n"
1502         "                   at various points in the optimization progress.\n"
1503         " -allcostX       = Compute and print ALL available cost functionals for the\n"
1504         "                   un-warped inputs, and then quit.\n"
1505         "                  * This option is for testing purposes (AKA 'fun').\n"
1506         " -allcostX1D p q = Compute ALL available cost functionals for the set of\n"
1507         "                   parameters given in the 1D file 'p' (12 values per row),\n"
1508         "                   write them to the 1D file 'q', then exit. (For you, Zman)\n"
1509         "                  * N.B.: If -fineblur is used, that amount of smoothing\n"
1510         "                          will be applied prior to the -allcostX evaluations.\n"
1511         "                          The parameters are the rotation, shift, scale,\n"
1512         "                          and shear values, not the affine transformation\n"
1513         "                          matrix. An identity matrix could be provided as\n"
1514         "                          \"0 0 0  0 0 0  1 1 1  0 0 0\" for instance or by\n"
1515         "                          using the word \"IDENTITY\"\n"
1516         "                  * This option is for testing purposes (even more 'fun').\n"
1517        ) ;
1518 
1519        printf("\n"
1520         "===========================================================================\n" );
1521        printf("\n"
1522         "Too Much Detail -- How Local Pearson Correlations Are Computed and Used\n"
1523         "-----------------------------------------------------------------------\n"
1524         " * The automask region of the base dataset is divided into a discrete\n"
1525         "    set of 'bloks'. Usually there are several thousand bloks.\n"
1526         " * In each blok, the voxel values from the base and the source (after\n"
1527         "    the alignment transformation is applied) are extracted and the\n"
1528         "    correlation coefficient is computed -- either weighted or unweighted,\n"
1529         "    depending on the options used in 3dAllineate (usually weighted).\n"
1530         " * Let p[i] = correlation coefficient in blok #i,\n"
1531         "       w[i] = sum of weights used in blok #i, or = 1 if unweighted.\n"
1532         "** The values of p[i] are what get output via the '-PearSave' option.\n"
1533         " * Define pc[i] = arctanh(p[i]) = 0.5 * log( (1+p[i]) / (1-p[i]) )\n"
1534         "     This expression is designed to 'stretch' out larger correlations,\n"
1535         "     giving them more emphasis in psum below. The same reasoning\n"
1536         "     is why pc[i]*abs(pc[i]) is used below, to make bigger correlations\n"
1537         "     have a bigger impact in the final result.\n"
1538         " * psum = SUM_OVER_i { w[i]*pc[i]*abs(pc[i]) }\n"
1539         "   wsum = SUM_OVER_i { w[i] }\n"
1540         "   lpc  = psum / wsum   ==> negative correlations are good (smaller lpc)\n"
1541         "   lpa  = 1 - abs(lpc)  ==> positive correlations are good (smaller lpa)\n"
1542        ) ;
1543 
1544        printf("\n"
1545         "===========================================================================\n" );
1546        printf("\n"
1547         "Modifying '-final wsinc5' -- for the truly crazy people out there\n"
1548         "-----------------------------------------------------------------\n"
1549         " * The windowed (tapered) sinc function interpolation can be modified\n"
1550         "     by several environment variables.  This is expert-level stuff, and\n"
1551         "     you should understand what you are doing if you use these options.\n"
1552         "     The simplest way to use these would be on the command line, as in\n"
1553         "       -DAFNI_WSINC5_RADIUS=9 -DAFNI_WSINC5_TAPERFUN=Hamming\n"
1554         "\n"
1555         " * AFNI_WSINC5_TAPERFUN lets you choose the taper function.\n"
1556         "     The default taper function is the minimum sidelobe 3-term cosine:\n"
1557         "       0.4243801 + 0.4973406*cos(PI*x) + 0.0782793*cos(2*PI*x)\n"
1558         "     If you set this environment variable to 'Hamming', then the\n"
1559         "     minimum sidelobe 2-term cosine will be used instead:\n"
1560         "       0.53836 + 0.46164*cos(PI*x)\n"
1561         "     Here, 'x' is between 0 and 1, where x=0 is the center of the\n"
1562         "     interpolation mask and x=1 is the outer edge.\n"
1563         " ++  Unfortunately, the 3-term cosine doesn't have a catchy name; you can\n"
1564         "       find it (and many other) taper functions described in the paper\n"
1565         "         AH Nuttall, Some Windows with Very Good Sidelobe Behavior.\n"
1566         "         IEEE Trans. ASSP, 29:84-91 (1981).\n"
1567         "       In particular, see Fig.14 and Eq.36 in this paper.\n"
1568         "\n"
1569         " * AFNI_WSINC5_TAPERCUT lets you choose the start 'x' point for tapering:\n"
1570         "     This value should be between 0 and 0.8; for example, 0 means to taper\n"
1571         "     all the way from x=0 to x=1 (maximum tapering).  The default value\n"
1572         "     is 0.  Setting TAPERCUT to 0.5 (say) means only to taper from x=0.5\n"
1573         "     to x=1; thus, a larger value means that fewer points are tapered\n"
1574         "     inside the interpolation mask.\n"
1575         "\n"
1576         " * AFNI_WSINC5_RADIUS lets you choose the radius of the tapering window\n"
1577         "     (i.e., the interpolation mask region).  This value is an integer\n"
1578         "     between 3 and 21.  The default value is 5 (which used to be the\n"
1579         "     ONLY value, thus 'wsinc5').  RADIUS is measured in voxels, not mm.\n"
1580         "\n"
1581         " * AFNI_WSINC5_SPHERICAL lets you choose the shape of the mask region.\n"
1582         "     If you set this value to 'Yes', then the interpolation mask will be\n"
1583         "     spherical; otherwise, it defaults to cubical.\n"
1584         "\n"
1585         " * The Hamming taper function is a little faster than the 3-term function,\n"
1586         "     but will have a little more Gibbs phenomenon.\n"
1587         " * A larger TAPERCUT will give a little more Gibbs phenomenon; compute\n"
1588         "     speed won't change much with this parameter.\n"
1589         " * Compute time goes up with (at least) the 3rd power of the RADIUS; setting\n"
1590         "     RADIUS to 21 will be VERY slow.\n"
1591         " * Visually, RADIUS=3 is similar to quintic interpolation.  Increasing\n"
1592         "     RADIUS makes the interpolated images look sharper and more well-\n"
1593         "     defined.  However, values of RADIUS greater than or equal to 7 appear\n"
1594         "     (to Zhark's eagle eye) to be almost identical.  If you really care,\n"
1595         "     you'll have to experiment with this parameter yourself.\n"
1596         " * A spherical mask is also VERY slow, since the cubical mask allows\n"
1597         "     evaluation as a tensor product.  There is really no good reason\n"
1598         "     to use a spherical mask; I only put it in for fun/experimental purposes.\n"
1599         "** For most users, there is NO reason to ever use these environment variables\n"
1600         "     to modify wsinc5.  You should only do this kind of thing if you have a\n"
1601         "     good and articulable reason!  (Or if you really like to screw around.)\n"
1602         "** The wsinc5 interpolation function is parallelized using OpenMP, which\n"
1603         "     makes its usage moderately tolerable.\n"
1604 #ifndef USE_OMP
1605         "   ++ However, this binary copy of AFNI is NOT compiled with OpenMP support.\n"
1606         "        You should consider getting such binaries, as several AFNI program\n"
1607         "        (including this one) will become significantly faster.\n"
1608 #endif
1609        ) ;
1610 
1611        printf("\n"
1612         "===========================================================================\n" );
1613        printf("\n"
1614               "Hidden experimental cost functionals:\n"
1615               "-------------------------------------\n" ) ;
1616        for( ii=0 ; ii < NMETH ; ii++ )
1617         if( !meth_visible[ii] )
1618           printf( "   %-4s *OR*  %-16s= %s\n" ,
1619                   meth_shortname[ii] , meth_longname[ii] , meth_username[ii] );
1620 
1621        printf("\n"
1622               "Notes for the new [Feb 2010] lpc+ cost functional:\n"
1623               "--------------------------------------------------\n"
1624               " * The cost functional named 'lpc+' is a combination of several others:\n"
1625               "     lpc + hel*%.1f + crA*%.1f + nmi*%.1f + mi*%.1f + ov*%.1f\n"
1626               "   ++ 'hel', 'crA', 'nmi', and 'mi' are the histogram-based cost\n"
1627               "      functionals also available as standalone options.\n"
1628               "   ++ 'ov' is a measure of the overlap of the automasks of the base and\n"
1629               "      source volumes; ov is not available as a standalone option.\n"
1630               "\n"
1631               " * The purpose of lpc+ is to avoid situations where the pure lpc cost\n"
1632               "   goes wild; this especially happens if '-source_automask' isn't used.\n"
1633               "   ++ Even with lpc+, you should use '-source_automask+2' (say) to be safe.\n"
1634               "\n"
1635               " * You can alter the weighting of the extra functionals by giving the\n"
1636               "   option in the form (for example)\n"
1637               "     '-lpc+hel*0.5+nmi*0+mi*0+crA*1.0+ov*0.5'\n"
1638               "\n"
1639               " * The quotes are needed to prevent the shell from wild-card expanding\n"
1640               "   the '*' character.\n"
1641               "   --> You can now use ':' in place of '*' to avoid this wildcard problem:\n"
1642               "         -lpc+hel:0.5+nmi:0+mi:0+crA:1+ov:0.5+ZZ\n"
1643               "\n"
1644               " * Notice the weight factors FOLLOW the name of the extra functionals.\n"
1645               "   ++ If you want a weight to be 0 or 1, you have to provide for that\n"
1646               "      explicitly -- if you leave a weight off, then it will get its\n"
1647               "      default value!\n"
1648               "   ++ The order of the weight factor names is unimportant here:\n"
1649               "        '-lpc+hel*0.5+nmi*0.8' == '-lpc+nmi*0.8+hel*0.5'\n"
1650               "\n"
1651               " * Only the 5 functionals listed (hel,crA,nmi,mi,ov) can be used in '-lpc+'.\n"
1652               "\n"
1653               " * In addition, if you want the initial alignments to be with '-lpc+' and\n"
1654               "   then finish the Final alignment with pure '-lpc', you can indicate this\n"
1655               "   by putting 'ZZ' somewhere in the option string, as in '-lpc+ZZ'.\n"
1656               " ***** '-cost lpc+ZZ' is very useful for aligning EPI to T1w volumes *****\n"
1657               "\n"
1658               " * [28 Nov 2018]\n"
1659               "   All of the above now applies to the 'lpa+' cost functional,\n"
1660               "   which can be used as a robust method for like-to-like alignment.\n"
1661               "   For example, aligning 3T and 7T T1-weighted datasets from the same person.\n"
1662               " * [28 Sep 2021]\n"
1663               "   However, the default multiplier constants for cost 'lpa+' are now\n"
1664               "   different from the 'lpc+' multipliers -- to make 'lpa+' more\n"
1665               "   robust. The new default for 'lpa+' is\n"
1666               "     lpa + hel*%.1f + crA*%.1f + nmi*%.1f + mi*%.1f + ov*%.1f\n"
1667               " ***** '-cost lpa+ZZ' is very useful for T1w to T1w volumes (or any     *****\n"
1668               " ***** similar-contrast datasets).                                      *****\n"
1669               "\n"
1670               " *** Note that in trial runs, we have found that lpc+ZZ and lpa+ZZ are    ***\n"
1671               " *** more robust than lpc+ and lpa+ -- which is why the '+ZZ' amendment   ***\n"
1672               " *** was created.                                                         ***\n"
1673              , DEFAULT_MICHO_LPC_HEL, DEFAULT_MICHO_LPC_CRA, DEFAULT_MICHO_LPC_NMI, DEFAULT_MICHO_LPC_MI, DEFAULT_MICHO_LPC_OV
1674              , DEFAULT_MICHO_LPA_HEL, DEFAULT_MICHO_LPA_CRA, DEFAULT_MICHO_LPA_NMI, DEFAULT_MICHO_LPA_MI, DEFAULT_MICHO_LPA_OV
1675              ) ;
1676 
1677        printf("\n"
1678               "Cost functional descriptions (for use with -allcost output):\n"
1679               "------------------------------------------------------------\n"
1680              ) ;
1681        for( ii=0 ; ii < NMETH ; ii++ )
1682          printf("   %-4s:: %s\n",
1683                 meth_shortname[ii] , meth_costfunctional[ii] ) ;
1684 
1685        printf("\n") ;
1686        printf(" * N.B.: Some cost functional values (as printed out above)\n"
1687               "   are negated from their theoretical descriptions (e.g., 'hel')\n"
1688               "   so that the best image alignment will be found when the cost\n"
1689               "   is minimized.  See the descriptions above and the references\n"
1690               "   below for more details for each functional.\n");
1691        printf("\n") ;
1692        printf(" * MY OPINIONS:\n"
1693               "   * Some of these cost functionals were implemented only for\n"
1694               "      the purposes of fun and/or comparison and/or experimentation\n"
1695               "      and/or special circumstances. These are\n"
1696               "        sp je lss crM crA crM hel mi nmi\n"
1697               "   * For many purposes, lpc+ZZ and lpa+ZZ are the most robust\n"
1698               "      cost functionals, but usually the slowest to evaluate.\n"
1699               "   * HOWEVER, just because some method is best MOST of the\n"
1700               "      time does not mean it is best ALL of the time.\n"
1701               "      Please check your results visually, or at some point\n"
1702               "      in time you will have bad results and not know it!\n"
1703               "   * For speed and for 'like-to-like' alignment, '-cost ls'\n"
1704               "      can work well.\n") ;
1705        printf("\n") ;
1706        printf(" * For more information about the 'lpc' functional, see\n"
1707               "     ZS Saad, DR Glen, G Chen, MS Beauchamp, R Desai, RW Cox.\n"
1708               "       A new method for improving functional-to-structural\n"
1709               "       MRI alignment using local Pearson correlation.\n"
1710               "       NeuroImage 44: 839-848, 2009.\n"
1711               "     http://dx.doi.org/10.1016/j.neuroimage.2008.09.037\n"
1712               "     https://pubmed.ncbi.nlm.nih.gov/18976717\n"
1713               "   The '-blok' option can be used to control the regions\n"
1714               "   (size and shape) used to compute the local correlations.\n");
1715        printf(" *** Using the 'lpc' functional wisely requires the use of\n"
1716               "     a proper weight volume.  We HIGHLY recommend you use\n"
1717               "     the align_epi_anat.py script if you want to use this\n"
1718               "     cost functional!  Otherwise, you are likely to get\n"
1719               "     less than optimal results (and then swear at us unjustly).\n") ;
1720        printf("\n") ;
1721        printf(" * For more information about the 'cr' functionals, see\n"
1722               "     http://en.wikipedia.org/wiki/Correlation_ratio\n"
1723               "   Note that CR(x,y) is not the same as CR(y,x), which\n"
1724               "   is why there are symmetrized versions of it available.\n") ;
1725        printf("\n") ;
1726        printf(" * For more information about the 'mi', 'nmi', and 'je'\n"
1727               "   cost functionals, see\n"
1728               "     http://en.wikipedia.org/wiki/Mutual_information\n"
1729               "     http://en.wikipedia.org/wiki/Joint_entropy\n"
1730               "     http://www.cs.jhu.edu/~cis/cista/746/papers/mutual_info_survey.pdf\n");
1731        printf("\n") ;
1732        printf(" * For more information about the 'hel' functional, see\n"
1733               "     http://en.wikipedia.org/wiki/Hellinger_distance\n"     ) ;
1734        printf("\n") ;
1735        printf(" * Some cost functionals (e.g., 'mi', 'cr', 'hel') are\n"
1736               "   computed by creating a 2D joint histogram of the\n"
1737               "   base and source image pair.  Various options above\n"
1738               "   (e.g., '-histbin', etc.) can be used to control the\n"
1739               "   number of bins used in the histogram on each axis.\n"
1740               "   (If you care to control the program in such detail!)\n"  ) ;
1741        printf("\n") ;
1742        printf(" * Minimization of the chosen cost functional is done via\n"
1743               "   the NEWUOA software, described in detail in\n"
1744               "     MJD Powell. 'The NEWUOA software for unconstrained\n"
1745               "       optimization without derivatives.' In: GD Pillo,\n"
1746               "       M Roma (Eds), Large-Scale Nonlinear Optimization.\n"
1747               "       Springer, 2006.\n"
1748               "     http://www.damtp.cam.ac.uk/user/na/NA_papers/NA2004_08.pdf\n");
1749 
1750        printf("\n"
1751         "===========================================================================\n"
1752         "\n"
1753         "SUMMARY of the Default Allineation Process\n"
1754         "------------------------------------------\n"
1755         "As mentioned earlier, each of these steps was added to deal with a problem\n"
1756         " that came up over the years. The resulting process is reasonably robust :),\n"
1757         " but then tends to be slow :(. If you use the '-verb' or '-VERB' option, you\n"
1758         " will get a lot of fun fun fun progress messages that show the results from\n"
1759         " this sequence of steps.\n"
1760         "\n"
1761         "Below, I refer to different scales of effort in the optimizations at each\n"
1762         " step. Easier/faster optimization is done using: matching with fewer points\n"
1763         " from the datasets; more smoothing of the base and source datasets; and by\n"
1764         " putting a smaller upper limit on the number of trials the optimizer is\n"
1765         " allowed to take. The Coarse phase starts with the easiest optimization,\n"
1766         " and increases the difficulty a little at each refinement. The Fine phase\n"
1767         " starts with the most difficult optimization setup: the most points for\n"
1768         " matching, little or no smoothing, and a large limit on the number of\n"
1769         " optimizer trials.\n"
1770         "\n"
1771         " 0. Preliminary Setup [Goal: create the basis for the following steps]\n"
1772         "  a. Create the automask and/or autoweight from the '-base' dataset.\n"
1773         "     The cost functional will only be computed from voxels inside the\n"
1774         "     automask, and only a fraction of those voxels will actually be used\n"
1775         "     for evaluating the cost functional (unless '-nmatch 100%%' is used).\n"
1776         "  b. If the automask is 'too close' to the outside of the base 3D volume,\n"
1777         "     zeropad the base dataset to avoid edge effects.\n"
1778         "  c. Determine the 3D (x,y,z) shifts for the '-cmass' center-of-mass\n"
1779         "     crude alignment, if ordered by the user.\n"
1780         "  d. Set ranges of transformation parameters and which parameters are to\n"
1781         "     be frozen at fixed values.\n"
1782         "\n"
1783         " 1. Coarse Phase [Goal: explore the vastness of 6-12D parameter space]\n"
1784         "  a. The first step uses only the first 6 parameters (shifts + rotations),\n"
1785         "     and evaluates thousands of potential starting points -- selected from\n"
1786         "     a 6D grid in parameter space and also from random points in 6D\n"
1787         "     parameter space. This step is fairly slow. The best 45 parameter\n"
1788         "     sets (in the sense of the cost functional) are kept for the next step.\n"
1789         "  b. Still using only the first 6 parameters, the best 45 sets of parameters\n"
1790         "     undergo a little optimization. The best 6 parameter sets after this\n"
1791         "     refinement are kept for the next step. (The number of sets chosen\n"
1792         "     to go on to the next step can be set by the '-twobest' option.)\n"
1793         "     The optimizations in this step use the blurring radius that is\n"
1794         "     given by option '-twoblur', which defaults to 7.77 mm, and use\n"
1795         "     relatively few points in each dataset for computing the cost functional.\n"
1796         "  c. These 6 best parameter sets undergo further, more costly, optimization,\n"
1797         "     now using all 12 parameters. This optimization runs in 3 passes, each\n"
1798         "     more costly (less smoothing, more matching points) than the previous.\n"
1799         "     (If 2 sets get too close in parameter space, 1 of them will be cast out\n"
1800         "     -- this does not happen often.) Output parameter sets from the 3rd pass\n"
1801         "     of successive refinement are inputs to the fine refinement phase.\n"
1802         "\n"
1803         " 2. Fine Phase [Goal: use more expensive optimization on good starting points]\n"
1804         "  a. The 6 outputs from step 1c have the null parameter set (all 0, except\n"
1805         "     for the '-cmass' shifts) appended. Then a small amount of optimization\n"
1806         "     is applied to each of these 7 parameter sets ('-num_rtb'). The null\n"
1807         "     parameter set is added here to insure against the possibility that the\n"
1808         "     coarse optimizations 'ran away' to some unpleasant locations in the 12D\n"
1809         "     parameter space. These optimizations use the full set of points specified\n"
1810         "     by '-nmatch', and the smoothing specified by '-fineblur' (default = 0),\n"
1811         "     but the number of functional evaluations is small, to make this step fast.\n"
1812         "  b. The best (smallest cost) set from step 2a is chosen for the final\n"
1813         "     optimization, which is run until the '-conv' limit is reached.\n"
1814         "     These are the 'Finalish' parameters (shown using '-verb').\n"
1815         "  c. The set of parameters from step 2b is used as the starting point\n"
1816         "     for a new optimization, in an attempt to avoid a false minimum.\n"
1817         "     The results of this optimization are the final parameter set.\n"
1818         "\n"
1819         " 3. The final set of parameters is used to produce the output volume,\n"
1820         "    using the '-final' interpolation method.\n"
1821         "\n"
1822         "In practice, the output from the Coarse phase successive refinements is\n"
1823         "usually so good that the Fine phase runs quickly and makes only small\n"
1824         "adjustments. The quality resulting from the Coarse phase steps is mostly\n"
1825         "due, in my opinion, to the large number of initial trials (1ab), followed by\n"
1826         "by the successive refinements of several parameter sets (1c) to help usher\n"
1827         "'good' candidates to the starting line for the Fine phase.\n"
1828         "\n"
1829         "For some 'easy' registration problems -- such as T1w-to-T1w alignment, high\n"
1830         "quality images, a lot of overlap to start with -- the process can be sped\n"
1831         "up by reducing the number of steps. For example, '-num_rtb 0 -twobest 0'\n"
1832         "would eliminate step 2a and speed up step 1c. Even more extreme, '-onepass'\n"
1833         "could be used to skip all of the Coarse phase. But be careful out there!\n"
1834         "\n"
1835         "For 'hard' registration problems, cleverness is usually needed. Choice\n"
1836         "of cost functional matters. Preprocessing the datasets may be necessary.\n"
1837         "Using '-twobest %d' could help by providing more candidates for the\n"
1838         "Fine phase -- at the cost of CPU time. If you run into trouble -- which\n"
1839         "happens sooner or later -- try the AFNI Message Board -- and please\n"
1840         "give details, including the exact command line(s) you used.\n"
1841        , PARAM_MAXTRIAL
1842        ) ;
1843 
1844 #if 0               /* No longer show help for -nwarp [29 Jan 2021] */
1845        printf("\n"
1846         "===========================================================================\n"
1847         "\n"
1848         " -nwarp type = Experimental nonlinear warping:\n"
1849         "\n"
1850         "              ***** Note that these '-nwarp' options are superseded   *****\n"
1851         "              ***** by the AFNI program 3dQwarp,  which does a more   *****\n"
1852         "              ***** accurate and more better job of nonlinear warping *****\n"
1853         "            ********* I strongly recommend against using -nwarp!!!  *********\n"
1854         "            ********* [And I will not support or help you with it.] *********\n"
1855         "            ******* ------ Zhark the Warper ------ July 2013 -------- *******\n"
1856         "\n"
1857         "              * At present, the only 'type' is 'bilinear',\n"
1858         "                as in 3dWarpDrive, with 39 parameters.\n"
1859         "              * I plan to implement more complicated nonlinear\n"
1860         "                warps in the future, someday .... [HAH!]\n"
1861         "              * -nwarp can only be applied to a source dataset\n"
1862         "                that has a single sub-brick!\n"
1863         "              * -1Dparam_save and -1Dparam_apply work with\n"
1864         "                bilinear warps; see the Notes for more information.\n"
1865         "        ==>>*** Nov 2010: I have now added the following polynomial\n"
1866         "                warps: 'cubic', 'quintic', 'heptic', 'nonic' (using\n"
1867         "                3rd, 5th, 7th, and 9th order Legendre polynomials); e.g.,\n"
1868         "                   -nwarp heptic\n"
1869         "              * These are the nonlinear warps that I now am supporting.\n"
1870         "              * Or you can call them 'poly3', 'poly5', 'poly7', and 'poly9',\n"
1871         "                  for simplicity and non-Hellenistic clarity.\n"
1872         "              * These names are not case sensitive: 'nonic' == 'Nonic', etc.\n"
1873         "              * Higher and higher order polynomials will take longer and longer\n"
1874         "                to run!\n"
1875         "              * If you wish to apply a nonlinear warp, you have to supply\n"
1876         "                a parameter file with -1Dparam_apply and also specify the\n"
1877         "                warp type with -nwarp.  The number of parameters in the\n"
1878         "                file (per line) must match the warp type:\n"
1879         "                   bilinear =  43   [for all nonlinear warps, the final]\n"
1880         "                   cubic    =  64   [4 'parameters' are fixed values to]\n"
1881         "                   quintic  = 172   [normalize the coordinates to -1..1]\n"
1882         "                   heptic   = 364   [for the nonlinear warp functions. ]\n"
1883         "                   nonic    = 664\n"
1884         "                In all these cases, the first 12 parameters are the\n"
1885         "                affine parameters (shifts, rotations, etc.), and the\n"
1886         "                remaining parameters define the nonlinear part of the warp\n"
1887         "                (polynomial coefficients); thus, the number of nonlinear\n"
1888         "                parameters over which the optimization takes place is\n"
1889         "                the number in the table above minus 16.\n"
1890         "               * The actual polynomial functions used are products of\n"
1891         "                 Legendre polynomials, but the symbolic names used in\n"
1892         "                 the header line in the '-1Dparam_save' output just\n"
1893         "                 express the polynomial degree involved; for example,\n"
1894         "                      quint:x^2*z^3:z\n"
1895         "                 is the name given to the polynomial warp basis function\n"
1896         "                 whose highest power of x is 2, is independent of y, and\n"
1897         "                 whose highest power of z is 3; the 'quint' indicates that\n"
1898         "                 this was used in '-nwarp quintic'; the final ':z' signifies\n"
1899         "                 that this function was for deformations in the (DICOM)\n"
1900         "                 z-direction (+z == Superior).\n"
1901         "        ==>>*** You can further control the form of the polynomial warps\n"
1902         "                (but not the bilinear warp!) by restricting their degrees\n"
1903         "                of freedom in 2 different ways.\n"
1904         "                ++ You can remove the freedom to have the nonlinear\n"
1905         "                   deformation move along the DICOM x, y, and/or z axes.\n"
1906         "                ++ You can remove the dependence of the nonlinear\n"
1907         "                   deformation on the DICOM x, y, and/or z coordinates.\n"
1908         "                ++ To illustrate with the six second order polynomials:\n"
1909         "                      p2_xx(x,y,z) = x*x  p2_xy(x,y,z) = x*y\n"
1910         "                      p2_xz(x,y,z) = x*z  p2_yy(x,y,z) = y*y\n"
1911         "                      p2_yz(x,y,z) = y*z  p2_zz(x,y,z) = z*z\n"
1912         "                   Unrestricted, there are 18 parameters associated with\n"
1913         "                   these polynomials, one for each direction of motion (x,y,z)\n"
1914         "                   * If you remove the freedom of the nonlinear warp to move\n"
1915         "                     data in the z-direction (say), then there would be 12\n"
1916         "                     parameters left.\n"
1917         "                   * If you instead remove the freedom of the nonlinear warp\n"
1918         "                     to depend on the z-coordinate, you would be left with\n"
1919         "                     3 basis functions (p2_xz, p2_yz, and p2_zz would be\n"
1920         "                     eliminated), each of which would have x-motion, y-motion,\n"
1921         "                     and z-motion parameters, so there would be 9 parameters.\n"
1922         "                ++ To fix motion along the x-direction, use the option\n"
1923         "                   '-nwarp_fixmotX' (and '-nwarp_fixmotY' and '-nwarp_fixmotZ).\n"
1924         "                ++ To fix dependence of the polynomial warp on the x-coordinate,\n"
1925         "                   use the option '-nwarp_fixdepX' (et cetera).\n"
1926         "                ++ These coordinate labels in the options (X Y Z) refer to the\n"
1927         "                   DICOM directions (X=R-L, Y=A-P, Z=I-S).  If you would rather\n"
1928         "                   fix things along the dataset storage axes, you can use\n"
1929         "                   the symbols I J K to indicate the fastest to slowest varying\n"
1930         "                   array dimensions (e.g., '-nwarp_fixdepK').\n"
1931         "                   * Mixing up the X Y Z and I J K forms of parameter freezing\n"
1932         "                     (e.g., '-nwarp_fixmotX -nwarp_fixmotJ') may cause trouble!\n"
1933         "                ++ If you input a 2D dataset (a single slice) to be registered\n"
1934         "                   with '-nwarp', the program automatically assumes '-nwarp_fixmotK'\n"
1935         "                   and '-nwarp_fixdepK' so there are no out-of-plane parameters\n"
1936         "                   or dependence.  The number of nonlinear parameters is then:\n"
1937         "                     2D: cubic = 14 ; quintic =  36 ; heptic =  66 ; nonic = 104.\n"
1938         "                     3D: cubic = 48 ; quintic = 156 ; heptic = 348 ; nonic = 648.\n"
1939         "                     [ n-th order: 2D = (n+4)*(n-1) ; 3D = (n*n+7*n+18)*(n-1)/2 ]\n"
1940         "                ++ Note that these '-nwarp_fix' options have no effect on the\n"
1941         "                   affine part of the warp -- if you want to constrain that as\n"
1942         "                   well, you'll have to use the '-parfix' option.\n"
1943         "                   * However, for 2D images, the affine part will automatically\n"
1944         "                     be restricted to in-plane (6 parameter) 'motions'.\n"
1945         "                ++ If you save the warp parameters (with '-1Dparam_save') when\n"
1946         "                   doing 2D registration, all the parameters will be saved, even\n"
1947         "                   the large number of them that are fixed to zero. You can use\n"
1948         "                   '1dcat -nonfixed' to remove these columns from the 1D file if\n"
1949         "                   you want to further process the varying parameters (e.g., 1dsvd).\n"
1950         "              **++ The mapping from I J K to X Y Z (DICOM coordinates), where the\n"
1951         "                   '-nwarp_fix' constraints are actually applied, is very simple:\n"
1952         "                   given the command to fix K (say), the coordinate X, or Y, or Z\n"
1953         "                   whose direction most closely aligns with the dataset K grid\n"
1954         "                   direction is chosen.  Thus, for coronal images, K is in the A-P\n"
1955         "                   direction, so '-nwarp_fixmotK' is translated to '-nwarp_fixmotY'.\n"
1956         "                   * This simplicity means that using the '-nwarp_fix' commands on\n"
1957         "                     oblique datasets is problematic.  Perhaps it would work in\n"
1958         "                     combination with the '-EPI' option, but that has not been tested.\n"
1959         "\n"
1960         "-nwarp NOTES:\n"
1961         "-------------\n"
1962         "* -nwarp is slow - reeeaaallll slow - use it with OpenMP!\n"
1963         "* Check the results to make sure the optimizer didn't run amok!\n"
1964         "   (You should ALWAYS do this with any registration software.)\n"
1965         "* For the nonlinear warps, the largest coefficient allowed is\n"
1966         "   set to 0.10 by default.  If you wish to change this, use an\n"
1967         "   option like '-nwarp_parmax 0.05' (to make the allowable amount\n"
1968         "   of nonlinear deformation half the default).\n"
1969         "  ++ N.B.: Increasing the maximum past 0.10 may give very bad results!!\n"
1970         "* If you use -1Dparam_save, then you can apply the nonlinear\n"
1971         "   warp to another dataset using -1Dparam_apply in a later\n"
1972         "   3dAllineate run. To do so, use '-nwarp xxx' in both runs\n"
1973         "   , so that the program knows what the extra parameters in\n"
1974         "   the file are to be used for.\n"
1975         "  ++ Bilinear: 43 values are saved in 1 row of the param file.\n"
1976         "  ++ The first 12 are the affine parameters\n"
1977         "  ++ The next 27 are the D1,D2,D3 matrix parameters (cf. infra).\n"
1978         "  ++ The final 'extra' 4 values are used to specify\n"
1979         "      the center of coordinates (vector Xc below), and a\n"
1980         "      pre-computed scaling factor applied to parameters #13..39.\n"
1981         "  ++ For polynomial warps, a similar format is used (mutatis mutandis).\n"
1982         "* The option '-nwarp_save sss' lets you save a 3D dataset of the\n"
1983         "  the displacement field used to create the output dataset.  This\n"
1984         "  dataset can be used in program 3dNwarpApply to warp other datasets.\n"
1985         "  ++ If the warp is symbolized by x -> w(x) [here, x is a DICOM 3-vector],\n"
1986         "     then the '-nwarp_save' dataset contains w(x)-x; that is, it contains\n"
1987         "     the warp displacement of each grid point from its grid location.\n"
1988         "\n"
1989         "* Bilinear warp formula:\n"
1990         "   Xout = inv[ I + {D1 (Xin-Xc) | D2 (Xin-Xc) | D3 (Xin-Xc)} ] [ A Xin ]\n"
1991         "  where Xin  = input vector  (base dataset coordinates)\n"
1992         "        Xout = output vector (source dataset coordinates)\n"
1993         "        Xc   = center of coordinates used for nonlinearity\n"
1994         "               (will be the center of the base dataset volume)\n"
1995         "        A    = matrix representing affine transformation (12 params)\n"
1996         "        I    = 3x3 identity matrix\n"
1997         "    D1,D2,D3 = three 3x3 matrices (the 27 'new' parameters)\n"
1998         "               * when all 27 parameters == 0, warp is purely affine\n"
1999         "     {P|Q|R} = 3x3 matrix formed by adjoining the 3-vectors P,Q,R\n"
2000         "    inv[...] = inverse 3x3 matrix of stuff inside '[...]'\n"
2001         "* The inverse of a bilinear transformation is another bilinear\n"
2002         "   transformation.  Someday, I may write a program that will let\n"
2003         "   you compute that inverse transformation, so you can use it for\n"
2004         "   some cunning and devious purpose.\n"
2005         "* If you expand the inv[...] part of the above formula in a 1st\n"
2006         "   order Taylor series, you'll see that a bilinear warp is basically\n"
2007         "   a quadratic warp, with the additional feature that its inverse\n"
2008         "   is directly computable (unlike a pure quadratic warp).\n"
2009         "* 'bilinearD' means the matrices D1, D2, and D3 with be constrained\n"
2010         "  to be diagonal (a total of 9 nonzero values), rather than full\n"
2011         "  (a total of 27 nonzero values).  This option is much faster.\n"
2012         "* Is '-nwarp bilinear' useful?  Try it and tell me!\n"
2013         "* Unlike a bilinear warp, the polynomial warps cannot be exactly\n"
2014         "  inverted.  At some point, I'll write a program to compute an\n"
2015         "  approximate inverse, if there is enough clamor for such a toy.\n"
2016         "\n"
2017         "===========================================================================\n"
2018        ) ;
2019 #endif
2020 
2021      } else {  /* now unreachable */
2022 
2023        printf(
2024         "\n"
2025         " [[[ To see a plethora of advanced/experimental options, use '-HELP'. ]]]\n");
2026 
2027      }
2028 
2029      PRINT_AFNI_OMP_USAGE("3dAllineate",
2030        "* OpenMP may or may not speed up the program significantly.  Limited\n"
2031        "   tests show that it provides some benefit, particularly when using\n"
2032        "   the more complicated interpolation methods (e.g., '-cubic' and/or\n"
2033        "   '-final wsinc5'), for up to 3-4 CPU threads.\n"
2034        "* But the speedup is definitely not linear in the number of threads, alas.\n"
2035        "   Probably because my parallelization efforts were pretty limited.\n"
2036       ) ;
2037 
2038      PRINT_COMPILE_DATE ; exit(0);
2039 }
2040 
2041 /*---------------------------------------------------------------------------*/
2042 /*============================ Ye Olde Main Programme =======================*/
2043 /* Note the GA_setup struct 'stup' below.
2044    This struct contains all the alignment setup information,
2045    and is passed to functions in mri_genalign.c to do lots of things,
2046    like evaluate the cost functional, optimize the cost, and so forth. */
2047 /*---------------------------------------------------------------------------*/
2048 
main(int argc,char * argv[])2049 int main( int argc , char *argv[] )
2050 {
2051    GA_setup stup ;                   /* holds all the setup info */
2052    THD_3dim_dataset *dset_out=NULL ;
2053    MRI_IMAGE *im_base, *im_targ, *im_weig=NULL, *im_mask=NULL, *qim ;
2054    MRI_IMAGE *im_bset, *im_wset, *im_tmask=NULL ;
2055    int iarg , ii,jj,kk , nmask=0 , nfunc , rr , ntask , ntmask=0 , nnz ;
2056    int   nx_base,ny_base,nz_base , nx_targ,ny_targ,nz_targ , nxy_base ;
2057    float dx_base,dy_base,dz_base , dx_targ,dy_targ,dz_targ , dxyz_top ;
2058    int   nxyz_base[3] , nxyz_targ[3] , nxyz_dout[3] ;
2059    float dxyz_base[3] , dxyz_targ[3] , dxyz_dout[3] ;
2060    int nvox_base ;
2061    float v1,v2 , xxx_p,yyy_p,zzz_p,siz , xxx_m,yyy_m,zzz_m , xxx,yyy,zzz , xc,yc,zc ;
2062    float xxc,yyc,zzc ; int CMbad=0 ; /* 26 Feb 2020 */
2063    int pad_xm=0,pad_xp=0 , pad_ym=0,pad_yp=0 , pad_zm=0,pad_zp=0 ;
2064    int tfdone=0;  /* stuff for -twofirst */
2065    float tfparm[PARAM_MAXTRIAL+2][MAXPAR];  /* +2 for some extra cases */
2066    float ffparm[PARAM_MAXTRIAL+2][MAXPAR];  /* not really used yet */
2067    float tfcost[PARAM_MAXTRIAL+2] ;
2068    int   tfindx[PARAM_MAXTRIAL+2] ;
2069    int   tfiorg[PARAM_MAXTRIAL+2] , ffiorg[PARAM_MAXTRIAL+2] ; /* 24 Jun 2021 */
2070    int   tfi2bs[PARAM_MAXTRIAL+2] , ffi2bs[PARAM_MAXTRIAL+2] ;
2071    int skip_first=0 , didtwo , targ_kind, skipped=0 , nptwo=6 ;
2072    int targ_was_vector=0, targ_vector_kind=-1 ; MRI_IMAGE *im_targ_vector=NULL ;
2073    double ctim=0.0,dtim , rad , conv_rad ;
2074    float **parsave=NULL ;
2075    mat44 *matsave=NULL ;
2076    mat44 targ_cmat,base_cmat,base_cmat_inv,targ_cmat_inv,mast_cmat,mast_cmat_inv,
2077          qmat,wmat ;
2078    MRI_IMAGE *apply_im = NULL ;
2079    float *apply_far    = NULL ;
2080    int apply_nx=0, apply_ny=0, apply_mode=0, nparam_free , diffblur=1 ;
2081    float cost, cost_ini ;
2082    mat44 cmat_bout , cmat_tout , aff12_xyz ;
2083    int   nxout=0,nyout=0,nzout=0 ;
2084    float dxout,dyout,dzout ;
2085    floatvec *allcost ;   /* 19 Sep 2007 */
2086    float     allpar[MAXPAR] ;
2087    float xsize , ysize , zsize ;  /* 06 May 2008: box size */
2088    float bfac ;                   /* 14 Oct 2008: brick factor */
2089    int twodim_code=0 , xx_code=0 , yy_code=0 , zz_code=0 ;
2090 
2091    /*----- input parameters, to be filled in from the options -----*/
2092 
2093    THD_3dim_dataset *dset_base = NULL ;
2094    THD_3dim_dataset *dset_targ = NULL ;         /* target == source */
2095    THD_3dim_dataset *dset_mast = NULL ;
2096    THD_3dim_dataset *dset_weig = NULL ;
2097    int tb_mast                 = 0 ;            /* for -master SOURCE/BASE */
2098    int auto_weight             = 3 ;            /* -autobbox == default */
2099    float auto_wclip            = 0.0f ;         /* 31 Jul 2007 */
2100    float auto_wpow             = 1.0f ;         /* 10 Sep 2007 */
2101    char *auto_string           = "-autobox" ;
2102    int auto_dilation           = 0 ;            /* for -automask+N */
2103    int wtspecified             = 0 ;            /* 10 Sep 2007 (was weight specified?) */
2104    double dxyz_mast            = 0.0  ;         /* implemented 24 Jul 2007 */
2105    int meth_code               = GA_MATCH_HELLINGER_SCALAR ;
2106    int sm_code                 = GA_SMOOTH_GAUSSIAN ;
2107    float sm_rad                = 0.0f ;
2108    float fine_rad              = 0.0f ;
2109    int floatize                = 0 ;            /* off by default */
2110    int twopass                 = 1 ;            /* on by default */
2111    int twofirst                = 1 ;            /* on by default */
2112    int zeropad                 = 1 ;            /* on by default */
2113    char *prefix                = NULL ;         /* off by default */
2114    char *wtprefix              = NULL ;         /* off by default */
2115    char *param_save_1D         = NULL ;         /* off by default */
2116    char *matrix_save_1D        = NULL ;         /* 23 Jul 2007 */
2117    char *apply_1D              = NULL ;         /* off by default */
2118    int interp_code             = MRI_LINEAR ;
2119    int got_interp              = 0 ;
2120    int npt_match               = -47 ;          /* 47%, that is */
2121    int final_interp            = MRI_CUBIC ;
2122    int got_final               = 0 ;
2123    int warp_code               = WARP_AFFINE ;
2124    char warp_code_string[64]   = "\0" ;         /* 22 Feb 2010 */
2125    int warp_freeze             = 0 ;            /* off by default */
2126    int do_small                = 0 ;            /* 12 May 2020 */
2127    int nparopt                 = 0 ;
2128    MRI_IMAGE *matini           = NULL ;
2129    int tbest                   = DEFAULT_TBEST; /* default=try best 5 */
2130    int num_rtb                 = 99 ;           /* 28 Aug 2008 */
2131    int nocast                  = 0 ;            /* 29 Aug 2008 */
2132    param_opt paropt[MAXPAR] ;
2133    float powell_mm             = 0.0f ;
2134    float powell_aa             = 0.0f ;
2135    float conv_mm               = 0.001f ;       /* millimeters */
2136    float nmask_frac            = -1.0;          /* use default for voxel fraction */
2137    int matorder                = MATORDER_SDU ; /* matrix mult order */
2138    int smat                    = SMAT_LOWER ;   /* shear matrix triangle */
2139    int dcode                   = DELTA_AFTER ;  /* shift after */
2140    int meth_check_count        = 0 ;            /* don't do it */
2141    int meth_check[NMETH+1] ;
2142    int meth_median_replace     = 0 ;            /* don't do it */
2143    char *save_hist             = NULL ;         /* don't save it */
2144    long seed                   = 7654321 ;      /* random? */
2145    int XYZ_warp                = 0 ;            /* off by default */
2146    double hist_pow             = 0.0 ;
2147    int hist_nbin               = 0 ;
2148    int epi_fe                  = -1 ;           /* off by default */
2149    int epi_pe                  = -1 ;
2150    int epi_se                  = -1 ;
2151    int epi_targ                = -1 ;
2152    int replace_base            = 0 ;            /* off by default */
2153    int replace_meth            = 0 ;            /* off by default */
2154    int usetemp                 = 0 ;            /* off by default */
2155    int nmatch_setup            = 98765 ;
2156    int ignout                  = 0 ;            /* 28 Feb 2007 */
2157    int    hist_mode            = 0 ;            /* 08 May 2007 */
2158    float  hist_param           = 0.0f ;
2159    int    hist_setbyuser       = 0 ;
2160    int    do_cmass             = 0 ;            /* 30 Jul 2007 */
2161    int    big_cmass            = 0 ;            /* 29 May 2021 */
2162    int    do_refinal           = 1 ;            /* 14 Nov 2007 */
2163    int    use_realaxes         = 0 ;            /* 10 Oct 2014 */
2164 
2165    int auto_tdilation          = 0 ;            /* for -source_automask+N */
2166    int auto_tmask              = 0 ;
2167    char *auto_tstring          = NULL ;
2168    int fill_source_mask        = 0 ;
2169 
2170 #ifdef USE_OLD_BLOK_DEFAULTS
2171    int bloktype                = GA_BLOK_RHDD ; /* 20 Aug 2007 */
2172    float blokrad               = 6.54321f ;
2173 #else
2174    int bloktype                = GA_BLOK_TOHD ; /* 21 Jul 2021 */
2175    float blokrad               = -1.0f ;
2176 #endif
2177    int blokmin                 = 0 ;
2178 
2179    int do_allcost              = 0 ;            /* 19 Sep 2007 */
2180    int do_save_pearson_map     = 0 ;            /* 25 Jan 2021 */
2181    char *save_pearson_prefix   = NULL ;
2182 
2183    MRI_IMAGE *allcostX1D       = NULL ;         /* 02 Sep 2008 */
2184    char *allcostX1D_outname    = NULL ;
2185 
2186 #ifdef ALLOW_NWARP /*********************************************************/
2187    int   nwarp_pass            = 0 ;
2188    int   nwarp_type            = WARP_CUBIC ;
2189    float nwarp_parmax          = 0.10f ;         /* 05 Jan 2011 */
2190    int   nwarp_flags           = 0 ;             /* 29 Oct 2010 */
2191    int   nwarp_itemax          = 0 ;
2192    int   nwarp_fixaff          = 0 ;             /* 26 Nov 2010 */
2193    int   nwarp_fixmotX         = 0 ;             /* 07 Dec 2010 */
2194    int   nwarp_fixdepX         = 0 ;
2195    int   nwarp_fixmotY         = 0 ;
2196    int   nwarp_fixdepY         = 0 ;
2197    int   nwarp_fixmotZ         = 0 ;
2198    int   nwarp_fixdepZ         = 0 ;
2199    int   nwarp_fixmotI         = 0 ;
2200    int   nwarp_fixdepI         = 0 ;
2201    int   nwarp_fixmotJ         = 0 ;
2202    int   nwarp_fixdepJ         = 0 ;
2203    int   nwarp_fixmotK         = 0 ;
2204    int   nwarp_fixdepK         = 0 ;
2205    char *nwarp_save_prefix     = NULL ;          /* 10 Dec 2010 */
2206    int   nwarp_meth_code       = 0 ;             /* 15 Dec 2010 */
2207 #else
2208 #  define nwarp_pass             0    /* just in case it escapes somewhere */
2209 #endif /* ALLOW_NWARP */ /**************************************************/
2210 
2211    int    micho_zfinal         = 0 ;                      /* 24 Feb 2010 */
2212    double micho_mi             = DEFAULT_MICHO_LPC_MI  ;  /* -lpc+ stuff */
2213    double micho_nmi            = DEFAULT_MICHO_LPC_NMI ;
2214    double micho_crA            = DEFAULT_MICHO_LPC_CRA ;
2215    double micho_hel            = DEFAULT_MICHO_LPC_HEL ;
2216    double micho_ov             = DEFAULT_MICHO_LPC_OV  ;  /* 02 Mar 2010 */
2217    int    micho_fallthru       = 0 ;                      /* 19 Nov 2016 */
2218 
2219    int do_zclip                = 0 ;             /* 29 Oct 2010 */
2220 
2221    bytevec *emask              = NULL ;          /* 14 Feb 2013 */
2222 
2223    int do_xflip_bset           = 0 ;             /* 18 Jun 2019 */
2224 
2225 #undef ALLOW_UNIFIZE   /* I decided this was a bad idea */
2226 #ifdef ALLOW_UNIFIZE
2227    int do_unifize_base         = 0 ;             /* 23 Dec 2016 */
2228    int do_unifize_targ         = 0 ;             /* not implemented */
2229    MRI_IMAGE *im_ubase         = NULL ;
2230    MRI_IMAGE *im_utarg         = NULL ;
2231 #endif
2232 
2233 #define APPLYING ( apply_1D != NULL || apply_mode != 0 )  /* 13 Mar 2017 */
2234 
2235    /**----------------------------------------------------------------------*/
2236    /**----------------- Help the pitifully ignorant user? -----------------**/
2237 
2238    AFNI_SETUP_OMP(0) ;  /* 24 Jun 2013 */
2239 
2240    /*---- A couple thousand lines of help used to be here for some reason ----*/
2241 
2242    if( argc < 2 || strcmp(argv[1],"-help")==0 ||
2243                    strcmp(argv[1],"-HELP")==0 || strcmp(argv[1],"-POMOC")==0 ){
2244 
2245      Allin_Help() ; exit(0) ;
2246    }
2247 
2248    /**-------------------------------------------------------------------**/
2249    /**-------------------- bookkeeping and marketing --------------------**/
2250    /**-------------------------------------------------------------------**/
2251 
2252 #if defined(USING_MCW_MALLOC) && !defined(USE_OMP)
2253    enable_mcw_malloc() ;
2254 #else
2255 # if 0
2256    if( AFNI_yesenv("ALLIN_DEBUG") ) enable_mcw_malloc() ;
2257 # endif
2258 #endif
2259 
2260    mainENTRY("3dAllineate"); machdep();
2261    AFNI_logger("3dAllineate",argc,argv);
2262    PRINT_VERSION("3dAllineate"); AUTHOR("Zhark the Registrator");
2263    THD_check_AFNI_version("3dAllineate"); /* no longer does anything */
2264    (void)COX_clock_time() ;
2265 
2266    /*-- initialize -final interp from environment? [25 Nov 2018] --*/
2267 
2268    ii = INTERP_code(my_getenv("AFNI_3dAllineate_final")) ;
2269    if( ii >= 0 ){ final_interp = ii ; got_final = 1 ; }
2270 
2271    /*********************************************************************/
2272    /**--- process command line options (1000+ lines of boring code) ---**/
2273    /*********************************************************************/
2274 
2275    iarg = 1 ;
2276    while( iarg < argc && argv[iarg][0] == '-' ){
2277 
2278      /*------*/
2279 
2280 #ifdef ALLOW_UNIFIZE
2281      if( strcmp(argv[iarg],"-unifize_base") == 0 ){    /* 23 Dec 2016 */
2282        do_unifize_base++ ; iarg++ ; continue ;
2283      }
2284 # if 0
2285      if( strcmp(argv[iarg],"-unifize_source") == 0 ){  /* 23 Dec 2016 */
2286        do_unifize_targ++ ; iarg++ ; continue ;
2287      }
2288 # endif
2289 #endif
2290 
2291      /*------*/
2292 
2293      if( strcmp(argv[iarg],"-smallrange") == 0 ){ /* 12 May 2020 */
2294        do_small++ ; iarg++ ; continue ;
2295      }
2296 
2297      /*------*/
2298 
2299      if( strcmp(argv[iarg],"-realaxes") == 0 ){  /* 10 Oct 2014 */
2300        use_realaxes++ ; iarg++ ; continue ;
2301      }
2302 
2303      /*------*/
2304 
2305      if( strcmp(argv[iarg],"-xflipbase") == 0 ){  /* 18 Jun 2019 [SECRET] */
2306        do_xflip_bset = 1 ; iarg++ ; continue ;
2307      }
2308 
2309      /*-----*/
2310 
2311      if( strcmp(argv[iarg],"-zclip") == 0 || strcmp(argv[iarg],"-noneg") == 0 ){     /* 29 Oct 2010 */
2312        do_zclip++ ; iarg++ ; continue ;
2313      }
2314 
2315      /*-----*/
2316 
2317 #ifdef ALLOW_NWARP /*********************************************************/
2318      if( strncmp(argv[iarg],"-nwarp_save",11) == 0 ){  /* 10 Dec 2010 = SECRET */
2319        if( ++iarg >= argc ) ERROR_exit("no argument after '%s' :-(",argv[iarg-1]) ;
2320        if( !THD_filename_ok(argv[iarg]) )
2321          ERROR_exit("badly formed filename: '%s' '%s' :-(",argv[iarg-1],argv[iarg]) ;
2322        if( strcmp(argv[iarg],"NULL") == 0 ) nwarp_save_prefix = NULL ;
2323        else                                 nwarp_save_prefix = argv[iarg] ;
2324        iarg++ ; continue ;
2325      }
2326 
2327      /*-----*/
2328 
2329      if( strcmp(argv[iarg],"-nwarp_parmax") == 0 ){    /* 05 Jan 2011 = SECRET */
2330        if( ++iarg >= argc ) ERROR_exit("no argument after '%s' :-(",argv[iarg-1]) ;
2331        nwarp_parmax = (float)strtod(argv[iarg],NULL) ;
2332        if( nwarp_parmax <= 0.0f || nwarp_parmax > 1.0f )
2333          ERROR_exit("Illegal value (%g) after '%s' :-(",nwarp_parmax,argv[iarg-1]) ;
2334        iarg++ ; continue ;
2335      }
2336 
2337      /*-----*/
2338 
2339      if( strncmp(argv[iarg],"-nwarp_fix",10) == 0 ){  /* 07 Dec 2010 = SECRET */
2340        char *aaa = argv[iarg]+10 , dcod ;
2341        if( strlen(aaa) < 4 ) ERROR_exit("don't understand option %s",argv[iarg]) ;
2342        dcod = toupper(aaa[3]) ;
2343        if( strncmp(aaa,"mot",3) == 0 ){            /* -nwarp_fixmot */
2344          switch( dcod ){
2345            case 'X': nwarp_fixmotX = 1 ; break ;
2346            case 'Y': nwarp_fixmotY = 1 ; break ;
2347            case 'Z': nwarp_fixmotZ = 1 ; break ;
2348            case 'I': nwarp_fixmotI = 1 ; break ;
2349            case 'J': nwarp_fixmotJ = 1 ; break ;
2350            case 'K': nwarp_fixmotK = 1 ; break ;
2351            default:  ERROR_exit("can't decode option %s",argv[iarg]) ;
2352          }
2353        } else if( strncmp(aaa,"dep",3) == 0 ){     /* -nwarp_fixdep */
2354          switch( dcod ){
2355            case 'X': nwarp_fixdepX = 1 ; break ;
2356            case 'Y': nwarp_fixdepY = 1 ; break ;
2357            case 'Z': nwarp_fixdepZ = 1 ; break ;
2358            case 'I': nwarp_fixdepI = 1 ; break ;
2359            case 'J': nwarp_fixdepJ = 1 ; break ;
2360            case 'K': nwarp_fixdepK = 1 ; break ;
2361            default:  ERROR_exit("can't decode option %s",argv[iarg]) ;
2362          }
2363        } else {
2364          ERROR_exit("don't know option %s",argv[iarg]) ;
2365        }
2366        iarg++ ; continue ;
2367      }
2368 
2369      /*-----*/
2370 
2371      if( strcasecmp(argv[iarg],"-nwarp_HERMITE") == 0 ){  /** 28 Mar 2013: SUPER-SECRET **/
2372        GA_setup_polywarp(GA_HERMITE) ; nwarp_parmax = 0.0444f ;
2373        iarg++ ; continue ;
2374      }
2375 
2376      /*-----*/
2377 
2378      if( strcmp(argv[iarg],"-nwarp") == 0 ){     /* 03 Apr 2008 = SECRET */
2379        nwarp_pass = 1 ; iarg++ ;
2380 
2381        WARNING_message(" !! Use program 3dQwarp instead of 3dAllineate -nwarp !!" ) ;
2382        WARNING_message(" !! 3dAllineate -nwarp is obsolete and inferior :(    !!" ) ;
2383        WARNING_message(" (( YOU HAVE BEEN WARNED -- here lurketh the dragons  ))" ) ;
2384 
2385        if( iarg >= argc ){
2386          ERROR_exit("need a warp type after '-nwarp' :-(") ;
2387        } else if( strncasecmp(argv[iarg],"bil",3) == 0 ){
2388          nwarp_type = WARP_BILINEAR ;
2389          if( strstr(argv[iarg],"D") != NULL ) nwarp_flags = 1 ; /* 29 Oct 2010 */
2390        } else if( strncasecmp(argv[iarg],"cub",3)   == 0 ||
2391                   strncasecmp(argv[iarg],"poly3",5) == 0   ){   /* 13 Nov 2010 */
2392          nwarp_type = WARP_CUBIC ;
2393        } else if( strncasecmp(argv[iarg],"qui",3)   == 0 ||
2394                   strncasecmp(argv[iarg],"poly5",5) == 0   ){   /* 15 Nov 2010 */
2395          nwarp_type = WARP_QUINT ;
2396        } else if( strncasecmp(argv[iarg],"hep",3)   == 0 ||
2397                   strncasecmp(argv[iarg],"poly7",5) == 0   ){   /* 15 Nov 2010 */
2398          nwarp_type = WARP_HEPT ;
2399        } else if( strncasecmp(argv[iarg],"non",3)   == 0 ||
2400                   strncasecmp(argv[iarg],"poly9",5) == 0   ){   /* 17 Nov 2010 */
2401          nwarp_type = WARP_NONI ;
2402        } else {
2403          ERROR_exit("unknown -nwarp type '%s' :-(",argv[iarg]) ;
2404        }
2405        nwarp_fixaff = ( strstr(argv[iarg],"FA") != NULL ) ;
2406        warp_code = WARP_AFFINE ; iarg++ ;
2407 
2408        if( iarg < argc && isdigit(argv[iarg][0]) ){      /** really secret **/
2409          nwarp_itemax = (int)strtod(argv[iarg],NULL) ;
2410          iarg++ ;
2411        }
2412 
2413        if( iarg < argc && isalpha(argv[iarg][0]) ){
2414          nwarp_meth_code = meth_name_to_code(argv[iarg]) ;
2415          if( nwarp_meth_code > 0 ) iarg++ ;
2416        }
2417 
2418        /* change some other parameters from their defaults */
2419 
2420        do_refinal = 0 ;
2421        continue ;
2422      }
2423 #endif /* ALLOW_NWARP */ /**************************************************/
2424 
2425      /*-----*/
2426 
2427      if( strcmp(argv[iarg],"-norefinal") == 0 ){ /* 14 Nov 2007 */
2428        do_refinal = 0 ; iarg++ ; continue ;      /* SECRET OPTION */
2429      }
2430 
2431      /*-----*/
2432 
2433      if( strcmp(argv[iarg],"-allcost") == 0 ){   /* 19 Sep 2007 */
2434        do_allcost = 1 ; iarg++ ; continue ;      /* SECRET OPTIONS */
2435      }
2436      if( strcmp(argv[iarg],"-allcostX") == 0 ){
2437        do_allcost = -1 ; iarg++ ; continue ;
2438      }
2439      if( strcmp(argv[iarg],"-allcostX1D") == 0 ){ /* 02 Sep 2008 */
2440        MRI_IMAGE *qim ;
2441        do_allcost = -2 ;
2442        if(strcmp(argv[++iarg],"IDENTITY") == 0)
2443             allcostX1D = mri_identity_params();
2444        else {
2445           qim = mri_read_1D( argv[iarg] ) ;
2446           if( qim == NULL )
2447             ERROR_exit("Can't read -allcostX1D '%s' :-(",argv[iarg]) ;
2448           allcostX1D = mri_transpose(qim) ; mri_free(qim) ;
2449        }
2450        if( allcostX1D->nx < 12 )
2451          ERROR_exit("-allcostX1D '%s' has only %d values per row :-(" ,
2452                     argv[iarg] , allcostX1D->nx ) ;
2453        allcostX1D_outname = strdup(argv[++iarg]) ;
2454        ++iarg ; continue ;
2455      }
2456 
2457      /*-----*/
2458 
2459      if( strcasecmp(argv[iarg],"-PearSave") == 0 ||
2460          strcasecmp(argv[iarg],"-SavePear") == 0   ){  /* 25 Jan 2021 */
2461        static char *pppname = "PearSave.nii.gz" ;
2462        do_save_pearson_map = 1 ; iarg++ ;
2463        if( !THD_filename_ok(argv[iarg]) ){
2464          WARNING_message("Option '%s' has illegal prefix '%s' - replacing with '%s'",
2465                          argv[iarg-1] , argv[iarg] , pppname ) ;
2466          save_pearson_prefix = strdup(pppname) ;
2467        } else {
2468          save_pearson_prefix = strdup(argv[iarg]) ;
2469        }
2470        ++iarg ; continue ;
2471      }
2472 
2473      /*-----*/
2474 
2475      if( strncmp(argv[iarg],"-cmass",6) == 0 ){
2476        if( argv[iarg][6] == '+' ){
2477          if (strchr(argv[iarg]+6,'a')) {
2478             do_cmass = -1; /* ZSS -- automatic determination */
2479          } else {
2480             do_cmass =    (strchr(argv[iarg]+6,'x') != NULL)   /* does string */
2481                       + 2*(strchr(argv[iarg]+6,'y') != NULL)   /* contain x, */
2482                       + 4*(strchr(argv[iarg]+6,'z') != NULL) ; /* y, or z?  */
2483          }
2484          if( do_cmass == 0 )
2485            ERROR_exit("Don't understand coordinates in '%s :-(",argv[iarg]) ;
2486        } else {
2487          do_cmass = 7 ;  /* all coords */
2488        }
2489        if( verb ){
2490          char cstr[16]="undefined" ;
2491               if( do_cmass <  0 ) strcpy(cstr,"auto") ;
2492          else if( do_cmass == 0 ) strcpy(cstr,"none") ;
2493          else {
2494            strcpy(cstr,"+") ;
2495            if( do_cmass & 1 ) strcat(cstr,"x") ;
2496            if( do_cmass & 2 ) strcat(cstr,"y") ;
2497            if( do_cmass & 3 ) strcat(cstr,"z") ;
2498          }
2499          INFO_message("Option '%s' enables center-of-mass code = %d = %s",argv[iarg],do_cmass,cstr) ;
2500        }
2501        iarg++ ; continue ;
2502      }
2503 
2504      if( strcmp(argv[iarg],"-nocmass") == 0 ){
2505        if( verb ) INFO_message("Option '%s' disables center-of-mass usage",argv[iarg]) ;
2506        do_cmass = 0 ; iarg++ ; continue ;
2507      }
2508 
2509      /*-----*/
2510 
2511      if( strcmp(argv[iarg],"-ignout") == 0 ){               /* SECRET OPTION */
2512        GA_set_outval(1.e+33); ignout = 1; iarg++; continue; /* 28 Feb 2007  */
2513      }
2514 
2515      /*-----*/
2516 
2517      if( strcmp(argv[iarg],"-matini") == 0 ){
2518        if( matini != NULL ) ERROR_exit("Can't have multiple %s options :-(",argv[iarg]) ;
2519        if( ++iarg >= argc ) ERROR_exit("no argument after '%s' :-(",argv[iarg-1]) ;
2520        if( strncmp(argv[iarg],"1D:",3) == 0 ||
2521            (strchr(argv[iarg],' ') == NULL && argv[iarg][0] != '&') ){
2522          matini = mri_read_1D( argv[iarg] ) ;
2523          if( matini == NULL ) ERROR_exit("Can't read -matini file '%s' :-(",argv[iarg]);
2524        } else {
2525          matini = mri_matrix_evalrpn( argv[iarg] ) ;
2526          if( matini == NULL ) ERROR_exit("Can't evaluate -matini expression :-(");
2527        }
2528        if( matini->nx < 3 || matini->ny < 3 )
2529          ERROR_exit("-matini matrix has nx=%d and ny=%d (should be at least 3) :-(",
2530                     matini->nx,matini->ny) ;
2531        else if( matini->nx > 3 || matini->ny > 4 )
2532          WARNING_message("-matini matrix has nx=%d and ny=%d (should be 3x4) :-(",
2533                     matini->nx,matini->ny) ;
2534 
2535        WARNING_message("-matini is not yet implemented! :-(") ;
2536        iarg++ ; continue ;
2537      }
2538 
2539      /*-----*/
2540 
2541      if( strcmp(argv[iarg],"-mast_dxyz") == 0 ||
2542          strcmp(argv[iarg],"-dxyz_mast") == 0 ||
2543          strcmp(argv[iarg],"-newgrid"  ) == 0   ){
2544 
2545        if( ++iarg >= argc ) ERROR_exit("no argument after '%s' :-(",argv[iarg-1]) ;
2546        dxyz_mast = strtod(argv[iarg],NULL) ;
2547        if( dxyz_mast <= 0.0 )
2548          ERROR_exit("Illegal value '%s' after -mast_dxyz :-(",argv[iarg]) ;
2549        if( dxyz_mast <= 0.5 )
2550          WARNING_message("Small value %g after -mast_dxyz :-(",dxyz_mast) ;
2551        iarg++ ; continue ;
2552      }
2553 
2554      /*-----*/
2555 
2556      if( strcmp(argv[iarg],"-nmsetup") == 0 ){
2557        if( ++iarg >= argc ) ERROR_exit("no argument after '%s' :-(",argv[iarg-1]) ;
2558        nmatch_setup = (int)strtod(argv[iarg],NULL) ;
2559        if( nmatch_setup < 9999 ) nmatch_setup = 23456 ;
2560        iarg++ ; continue ;
2561      }
2562 
2563      /*-----*/
2564 
2565      if( strncmp(argv[iarg],"-master",6) == 0 ){
2566        if( dset_mast != NULL || tb_mast )
2567          ERROR_exit("Can't have multiple %s options :-(",argv[iarg]) ;
2568        if( ++iarg >= argc ) ERROR_exit("no argument after '%s' :-(",argv[iarg-1]) ;
2569        if( strcmp(argv[iarg],"SOURCE") == 0 ){  /* 19 Jul 2007 */
2570          tb_mast = 1 ;
2571        } else if( strcmp(argv[iarg],"BASE") == 0 ){
2572          tb_mast = 2 ;
2573        } else {
2574          dset_mast = THD_open_dataset( argv[iarg] ) ;
2575          if( dset_mast == NULL )
2576            ERROR_exit("can't open -master dataset '%s' :-(",argv[iarg]);
2577        }
2578        iarg++ ; continue ;
2579      }
2580 
2581      /*-----*/
2582 
2583      if( strcmp(argv[iarg],"-seed") == 0 ){   /* SECRET OPTION */
2584        if( ++iarg >= argc ) ERROR_exit("no argument after '%s' :-(",argv[iarg-1]) ;
2585        seed = (long)strtod(argv[iarg],NULL) ; iarg++ ; continue ;
2586      }
2587 
2588      /*-----*/
2589 
2590      if( strcmp(argv[iarg],"-powell") == 0 ){  /* SECRET OPTION */
2591        if( ++iarg >= argc-1 ) ERROR_exit("no arguments after '%s' :-(",argv[iarg-1]) ;
2592        powell_mm = (float)strtod(argv[iarg++],NULL) ;
2593        powell_aa = (float)strtod(argv[iarg++],NULL) ;
2594        if( powell_mm < 1.0f ) powell_mm = 1.0f ;
2595        if( powell_aa < 1.0f ) powell_aa = 1.0f ;
2596        if( verb ) INFO_message("Set Powell iteration factors to m=%.1f a=%.1f",powell_mm,powell_aa) ;
2597        continue ;
2598      }
2599 
2600      /*-----*/
2601 
2602      if( strncmp(argv[iarg],"-weight_frac",11) == 0 ){
2603        if( ++iarg >= argc ) ERROR_exit("no argument after '%s' :-(",argv[iarg-1]) ;
2604        nmask_frac = atof( argv[iarg] ) ;
2605        if( nmask_frac < 0.0f || nmask_frac > 1.0f )
2606          ERROR_exit("-weight_frac must be between 0.0 and 1.0 (have '%s') :-(",argv[iarg]);
2607        wtspecified = 1 ; iarg++ ; continue ;
2608      }
2609 
2610      /*-----*/
2611 
2612      if( strncmp(argv[iarg],"-weight",6) == 0 ){
2613        auto_weight = 0 ;
2614        if( dset_weig != NULL ) ERROR_exit("Can't have multiple %s options :-(",argv[iarg]) ;
2615        if( ++iarg >= argc ) ERROR_exit("no argument after '%s' :-(",argv[iarg-1]) ;
2616        dset_weig = THD_open_dataset( argv[iarg] ) ;
2617        if( dset_weig == NULL ) ERROR_exit("can't open -weight dataset '%s' :-(",argv[iarg]);
2618        wtspecified = 1 ; iarg++ ; continue ;
2619      }
2620 
2621      /*-----*/
2622 
2623      if( strncmp(argv[iarg],"-autoweight",11) == 0 ){
2624        char *cpt ;
2625        int   cpt_offset = 2; /* offset for exponent str [rickr 23 Apr 2019] */
2626                              /* allow ** or ^ (to avoid shell protection)   */
2627        if( dset_weig != NULL ) ERROR_exit("Can't use -autoweight AND -weight :-(") ;
2628        auto_weight = 1 ; auto_string = argv[iarg] ;
2629        cpt = strstr(auto_string,"+") ;
2630        if( cpt != NULL && *(cpt+1) != '\0' )      /* 31 Jul 2007 */
2631          auto_wclip = (float)strtod(cpt+1,NULL) ;
2632        cpt = strstr(auto_string,"**") ;
2633        if( cpt == NULL ) {
2634           /* allow ** or ^ (to avoid shell protection) [rickr 23 Apr 2019] */
2635           cpt = strstr(auto_string,"^") ;
2636           cpt_offset = 1;
2637        }
2638        if( cpt != NULL && *(cpt+cpt_offset) != '\0' )      /* 10 Sep 2007 */
2639          auto_wpow = (float)strtod(cpt+cpt_offset,NULL) ;
2640        wtspecified = 1 ; iarg++ ; continue ;
2641      }
2642 
2643      if( strncmp(argv[iarg],"-automask",9) == 0 ){
2644        if( dset_weig != NULL ) ERROR_exit("Can't use -automask AND -weight :-(") ;
2645        auto_weight = 2 ; auto_string = argv[iarg] ;
2646        if( auto_string[9] == '+' && auto_string[10] != '\0' )
2647          auto_dilation = (int)strtod(auto_string+10,NULL) ;
2648        wtspecified = 1 ; iarg++ ; continue ;
2649      }
2650 
2651      if( strncmp(argv[iarg],"-noauto",6) == 0 ||
2652          strncmp(argv[iarg],"-nomask",6) == 0   ){
2653        wtspecified = 1 ; auto_weight = 0 ; iarg++ ; continue ;
2654      }
2655 
2656      if( strcmp(argv[iarg],"-autobox") == 0 ){
2657        wtspecified = 1 ; auto_weight = 3 ; auto_string = "-autobox" ;
2658        iarg++ ; continue ;
2659      }
2660 
2661      /*-----*/
2662 
2663      if( strcmp(argv[iarg],"-source_mask") == 0 ){  /* 07 Aug 2007 */
2664        byte *mmm ; THD_3dim_dataset *dset_tmask ;
2665        if( im_tmask != NULL )
2666          ERROR_exit("Can't use -source_mask twice :-(") ;
2667        if( auto_tmask )
2668          ERROR_exit("Can't use -source_mask AND -source_automask :-(") ;
2669        if( ++iarg >= argc ) ERROR_exit("no argument after '%s' :-(",argv[iarg-1]) ;
2670        dset_tmask = THD_open_dataset( argv[iarg] ) ;
2671        if( dset_tmask == NULL )
2672          ERROR_exit("can't open -source_mask dataset '%s' :-(",argv[iarg]);
2673        mmm = THD_makemask( dset_tmask , 0 , 1.0f,-1.0f ) ;
2674        if( mmm == NULL )
2675          ERROR_exit("Can't use -source_mask '%s' for some reason :-(",argv[iarg]) ;
2676        im_tmask = mri_new_vol_empty(
2677                    DSET_NX(dset_tmask),DSET_NY(dset_tmask),DSET_NZ(dset_tmask) ,
2678                    MRI_byte ) ;
2679        DSET_delete(dset_tmask) ; /* ZSS: Moved here cause that's
2680                                     right and proper*/
2681        mri_fix_data_pointer( mmm , im_tmask ) ;
2682        ntmask = THD_countmask( im_tmask->nvox , mmm ) ;
2683        if( ntmask < 666 )
2684          ERROR_exit("Too few (%d) voxels in -source_mask :-(",ntmask) ;
2685        if( verb > 1 ) INFO_message("%d voxels in -source_mask",ntmask) ;
2686        iarg++ ; fill_source_mask = 1 ; continue ;
2687      }
2688 
2689      if( strncmp(argv[iarg],"-source_automask",16) == 0 ){  /* 07 Aug 2007 */
2690        if( im_tmask != NULL )
2691          ERROR_exit("Can't use -source_automask AND -source_mask :-(") ;
2692        auto_tmask = 1 ; auto_tstring = argv[iarg] ;
2693        if( auto_tstring[16] == '+' && auto_string[17] != '\0' )
2694          auto_tdilation = (int)strtod(auto_tstring+17,NULL) ;
2695        iarg++ ; fill_source_mask = 1 ; continue ;
2696      }
2697 
2698      /*-----*/
2699 
2700      if( strncmp(argv[iarg],"-wtprefix",6) == 0 ){
2701        if( ++iarg >= argc ) ERROR_exit("no argument after '%s' :-(",argv[iarg-1]) ;
2702        if( !THD_filename_ok(argv[iarg]) )
2703          ERROR_exit("badly formed filename: '%s' '%s' :-(",argv[iarg-1],argv[iarg]) ;
2704        wtprefix = argv[iarg] ; iarg++ ; continue ;
2705      }
2706 
2707      /*-----*/
2708 
2709      if( strcmp(argv[iarg],"-savehist") == 0 ){  /* SECRET OPTION */
2710        if( ++iarg >= argc ) ERROR_exit("no argument after '%s' :-(",argv[iarg-1]) ;
2711        if( !THD_filename_ok(argv[iarg]) )
2712          ERROR_exit("badly formed filename: '%s' '%s' :-(",argv[iarg-1],argv[iarg]) ;
2713        save_hist = argv[iarg] ; iarg++ ; continue ;
2714      }
2715 
2716      /*-----*/
2717 
2718      if( strcmp(argv[iarg],"-histpow") == 0 ){   /* SECRET OPTION */
2719        if( ++iarg >= argc ) ERROR_exit("no argument after '%s' :-(",argv[iarg-1]) ;
2720        hist_pow = strtod(argv[iarg],NULL) ;
2721        set_2Dhist_hpower(hist_pow) ;
2722        iarg++ ; continue ;
2723      }
2724 
2725      if( strcmp(argv[iarg],"-histbin") == 0 ){   /* SECRET OPTION */
2726        if( ++iarg >= argc ) ERROR_exit("no argument after '%s' :-(",argv[iarg-1]) ;
2727        hist_nbin = (int)strtod(argv[iarg],NULL) ;
2728        hist_mode = 0 ; hist_param = 0.0f ; hist_setbyuser = 1 ;
2729        set_2Dhist_hbin( hist_nbin ) ;
2730        iarg++ ; continue ;
2731      }
2732 
2733      if( strcmp(argv[iarg],"-clbin") == 0 ){   /* SECRET OPTION - 08 May 2007 */
2734        if( ++iarg >= argc ) ERROR_exit("no argument after '%s' :-(",argv[iarg-1]) ;
2735        hist_mode  = GA_HIST_CLEQWD ;
2736        hist_param = (float)strtod(argv[iarg],NULL) ; hist_setbyuser = 1 ;
2737        iarg++ ; continue ;
2738      }
2739 
2740 #if 0
2741      if( strcmp(argv[iarg],"-izz") == 0 ){    /* EXPERIMENTAL!! */
2742        THD_correlate_ignore_zerozero(1) ; iarg++ ; continue ;
2743      }
2744 #endif
2745 
2746      if( strcmp(argv[iarg],"-eqbin") == 0 ){   /* SECRET OPTION - 08 May 2007 */
2747        if( ++iarg >= argc ) ERROR_exit("no argument after '%s' :-(",argv[iarg-1]) ;
2748        hist_mode  = GA_HIST_EQHIGH ;
2749        hist_param = (float)strtod(argv[iarg],NULL) ; hist_setbyuser = 1 ;
2750        if( hist_param < 3.0f || hist_param > 255.0f ){
2751          WARNING_message("'-eqbin %f' is illegal -- ignoring :-(",hist_param) ;
2752          hist_mode = 0 ; hist_param = 0.0f ; hist_setbyuser = 0 ;
2753        }
2754        iarg++ ; continue ;
2755      }
2756 
2757      if( strcmp(argv[iarg],"-wtmrad") == 0 ){   /* SECRET OPTION */
2758        if( ++iarg >= argc ) ERROR_exit("no argument after '%s' :-(",argv[iarg-1]) ;
2759        wt_medsmooth = (float)strtod(argv[iarg],NULL) ;
2760        iarg++ ; continue ;
2761      }
2762 
2763      if( strcmp(argv[iarg],"-wtgrad") == 0 ){   /* SECRET OPTION */
2764        if( ++iarg >= argc ) ERROR_exit("no argument after '%s' :-(",argv[iarg-1]) ;
2765        wt_gausmooth = (float)strtod(argv[iarg],NULL) ;
2766        iarg++ ; continue ;
2767      }
2768 
2769      /*-----*/
2770 
2771      if( strcmp(argv[iarg],"-verb") == 0 ){
2772        verb++ ; iarg++ ; continue ;
2773      }
2774      if( strcmp(argv[iarg],"-VERB") == 0 ){
2775        verb+=2 ; iarg++ ; continue ;
2776      }
2777      if( strcmp(argv[iarg],"-quiet") == 0 ){  /* 10 Oct 2006 */
2778        verb=0 ; iarg++ ; continue ;
2779      }
2780 
2781      if( strcmp(argv[iarg],"-round") == 0 ){  /* 04 Jun 2021 [HIDDEN] */
2782        mri_genalign_round(1) ; iarg++ ; continue ;
2783      }
2784      if( strcmp(argv[iarg],"-noround") == 0 ){
2785        mri_genalign_round(0) ; iarg++ ; continue ;
2786      }
2787 
2788      if( strcmp(argv[iarg],"-usetemp") == 0 ){  /* 20 Dec 2006 */
2789        usetemp = 1 ; iarg++ ; continue ;
2790      }
2791      if( strcmp(argv[iarg],"-nousetemp") == 0 ){
2792        usetemp = 0 ; iarg++ ; continue ;
2793      }
2794 
2795      /*-----*/
2796 
2797      if( strncmp(argv[iarg],"-floatize",6) == 0 ){
2798        floatize++ ; iarg++ ; continue ;
2799      }
2800 
2801      /*-----*/
2802 
2803      if( strncmp(argv[iarg],"-nopad",5) == 0 ){
2804        zeropad = 0 ; iarg++ ; continue ;
2805      }
2806 
2807      /*----- Check the various cost options -----*/
2808 
2809      jj = meth_name_to_code( argv[iarg]+1 ) ; /* check for match after the '-' */
2810      if( jj > 0 ){
2811        meth_code = jj ; iarg++ ; continue ;   /* there was a match */
2812      }
2813 
2814      /** -cost shortname  *OR*  -cost longname **/
2815 
2816      if( strcmp(argv[iarg],"-cost") == 0 || strcmp(argv[iarg],"-meth") == 0 ){
2817        if( ++iarg >= argc ) ERROR_exit("no argument after '-cost' :-(") ;
2818 
2819        jj = meth_name_to_code( argv[iarg] ) ;
2820        if( jj > 0 ){ meth_code = jj ; iarg++ ; continue ; }
2821 
2822        /* fail here, UNLESS the method is 'lpc+something' */
2823 
2824        if( ! (strlen(argv[iarg]) > 5 &&
2825                (   strncasecmp(argv[iarg],"lpc+",4) == 0
2826                 || strncasecmp(argv[iarg],"lpa+",4) == 0 ) ) )
2827          ERROR_exit("Unknown code '%s' after -cost :-(",argv[iarg]) ;
2828 
2829        /* fall through to lpc+ code */
2830 
2831        micho_fallthru = 1 ;
2832      }
2833 
2834      /* 24 Feb 2010: special option for -lpc+stuff or -lpa+stuff */
2835 
2836      if( micho_fallthru ||
2837          (strlen(argv[iarg]) > 6 &&
2838            (   strncasecmp(argv[iarg],"-lpc+",5) == 0
2839             || strncasecmp(argv[iarg],"-lpa+",5) == 0 ) ) ){
2840        char *cpt ;
2841        if( strcasestr(argv[iarg],"lpc") != NULL ){
2842          meth_code = GA_MATCH_LPC_MICHO_SCALAR ;
2843          micho_mi  = DEFAULT_MICHO_LPC_MI  ;
2844          micho_nmi = DEFAULT_MICHO_LPC_NMI ;
2845          micho_crA = DEFAULT_MICHO_LPC_CRA ;
2846          micho_hel = DEFAULT_MICHO_LPC_HEL ;
2847          micho_ov  = DEFAULT_MICHO_LPC_OV  ;
2848        } else if( strcasestr(argv[iarg],"lpa") != NULL ){
2849          int do_old = ( strcasestr(argv[iarg],"+OLD") != NULL ) ;
2850          meth_code = GA_MATCH_LPA_MICHO_SCALAR ;
2851          micho_mi  = (do_old) ? DEFAULT_MICHO_LPC_MI  : DEFAULT_MICHO_LPA_MI  ;   /* 27 May 2021 */
2852          micho_nmi = (do_old) ? DEFAULT_MICHO_LPC_NMI : DEFAULT_MICHO_LPA_NMI ;
2853          micho_crA = (do_old) ? DEFAULT_MICHO_LPC_CRA : DEFAULT_MICHO_LPA_CRA ;
2854          micho_hel = (do_old) ? DEFAULT_MICHO_LPC_HEL : DEFAULT_MICHO_LPA_HEL ;
2855          micho_ov  = (do_old) ? DEFAULT_MICHO_LPC_OV  : DEFAULT_MICHO_LPA_OV  ;
2856        } else {
2857          WARNING_message("How did this happen? argv[%d] = %s",iarg,argv[iarg]) ;
2858          meth_code = GA_MATCH_LPC_MICHO_SCALAR ;
2859        }
2860        micho_fallthru = 0 ;
2861        cpt = strcasestr(argv[iarg],"+hel*"); if( cpt != NULL ) micho_hel = strtod(cpt+5,NULL);
2862        cpt = strcasestr(argv[iarg],"+hel:"); if( cpt != NULL ) micho_hel = strtod(cpt+5,NULL);
2863        cpt = strcasestr(argv[iarg],"+mi*" ); if( cpt != NULL ) micho_mi  = strtod(cpt+4,NULL);
2864        cpt = strcasestr(argv[iarg],"+mi:" ); if( cpt != NULL ) micho_mi  = strtod(cpt+4,NULL);
2865        cpt = strcasestr(argv[iarg],"+nmi*"); if( cpt != NULL ) micho_nmi = strtod(cpt+5,NULL);
2866        cpt = strcasestr(argv[iarg],"+nmi:"); if( cpt != NULL ) micho_nmi = strtod(cpt+5,NULL);
2867        cpt = strcasestr(argv[iarg],"+crA*"); if( cpt != NULL ) micho_crA = strtod(cpt+5,NULL);
2868        cpt = strcasestr(argv[iarg],"+crA:"); if( cpt != NULL ) micho_crA = strtod(cpt+5,NULL);
2869        cpt = strcasestr(argv[iarg],"+ov*" ); if( cpt != NULL ) micho_ov  = strtod(cpt+4,NULL);
2870        cpt = strcasestr(argv[iarg],"+ov:" ); if( cpt != NULL ) micho_ov  = strtod(cpt+4,NULL);
2871        cpt = strcasestr(argv[iarg],"ZZ")   ; micho_zfinal = (cpt != NULL) ;
2872 
2873        INFO_message("%s parameters: hel=%.2f mi=%.2f nmi=%.2f crA=%.2f ov=%.2f %s",
2874                     meth_shortname[meth_code-1] ,
2875                     micho_hel , micho_mi , micho_nmi , micho_crA , micho_ov ,
2876                     micho_zfinal ? "[to be zeroed at Final iteration]" : "\0" ) ;
2877        iarg++ ; continue ;
2878      }
2879 
2880 #ifdef ALLOW_METH_CHECK
2881      /*----- -check costname -----*/
2882 
2883      if( strncasecmp(argv[iarg],"-check",5) == 0 ){
2884 #if 0
2885        if( strncmp(argv[iarg],"-CHECK",5) == 0 ) meth_median_replace = 1 ; /* not good */
2886 #endif
2887        if( ++iarg >= argc ) ERROR_exit("no argument after '%s' :-(",argv[iarg-1]) ;
2888 
2889        for( ; iarg < argc && argv[iarg][0] != '-' ; iarg++ ){
2890          if( meth_check_count == NMETH ) continue ; /* malicious user? */
2891          jj = meth_name_to_code(argv[iarg]) ;
2892          if( jj > 0 ){ meth_check[meth_check_count++] = jj; continue; }
2893          WARNING_message("Unknown code '%s' after -check :-(",argv[iarg]) ;
2894        }
2895        continue ;
2896      }
2897 #else
2898      if( strncasecmp(argv[iarg],"-check",5) == 0 ){
2899        WARNING_message("option '%s' is no longer available",argv[iarg]) ;
2900        for( ; iarg < argc && argv[iarg][0] != '-' ; iarg++ ) ; /*nada*/
2901        continue ;
2902      }
2903 #endif
2904 
2905      /*-----*/
2906 
2907      if( strcmp(argv[iarg],"-emask") == 0 ){                   /* 14 Feb 2013 */
2908        if( emask != NULL ) ERROR_exit("Can't have multiple %s options :-(",argv[iarg]) ;
2909        if( ++iarg >= argc ) ERROR_exit("no argument after '-emask' :-(") ;
2910        emask = THD_create_mask_from_string( argv[iarg] ) ;
2911        if( emask == NULL ) ERROR_exit("Can't create emask from '%s'",argv[iarg]) ;
2912        iarg++ ; continue ;
2913      }
2914 
2915      /*-----*/
2916 
2917      if( strcmp(argv[iarg],"-base") == 0 ){
2918        if( dset_base != NULL ) ERROR_exit("Can't have multiple %s options :-(",argv[iarg]) ;
2919        if( ++iarg >= argc ) ERROR_exit("no argument after '-base' :-(") ;
2920        dset_base = THD_open_dataset( argv[iarg] ) ;
2921        if( dset_base == NULL ) ERROR_exit("can't open -base dataset '%s' :-(",argv[iarg]);
2922        ii = (int)DSET_BRICK_TYPE(dset_base,0) ;
2923        if( ii != MRI_float && ii != MRI_short && ii != MRI_byte )
2924 #if 0
2925          ERROR_exit("base dataset %s has non-scalar data type '%s' :-(",
2926                     DSET_BRIKNAME(dset_base) , MRI_TYPE_name[ii] ) ;
2927 #else
2928          WARNING_message("base dataset %s has non-scalar data type '%s' :-(",
2929                     DSET_BRIKNAME(dset_base) , MRI_TYPE_name[ii] ) ;
2930 #endif
2931        iarg++ ; continue ;
2932      }
2933 
2934      /*-----*/
2935 
2936      if( strncmp(argv[iarg],"-source",6) == 0 ||
2937          strncmp(argv[iarg],"-input" ,5) == 0 ||
2938          strncmp(argv[iarg],"-target",7) == 0 ||
2939          strncmp(argv[iarg],"-src"   ,4) == 0   ){
2940        if( dset_targ != NULL ) ERROR_exit("Can't have multiple %s options :-(",argv[iarg]) ;
2941        if( ++iarg >= argc ) ERROR_exit("no argument after '%s' :-(",argv[iarg-1]) ;
2942        dset_targ = THD_open_dataset( argv[iarg] ) ;
2943        if( dset_targ == NULL )
2944          ERROR_exit("can't open -%s dataset '%s' :-(",argv[iarg-1],argv[iarg]);
2945        iarg++ ; continue ;
2946      }
2947 
2948      /*-----*/
2949 
2950      if( strncmp(argv[iarg],"-median",5) == 0 ){        /* SECRET OPTION */
2951        sm_code = GA_SMOOTH_MEDIAN ; iarg++ ; continue ;
2952      }
2953 
2954      /*-----*/
2955 
2956      if( strncmp(argv[iarg],"-twoblur",7) == 0 ){
2957        if( ++iarg >= argc ) ERROR_exit("no argument after '%s' :-(",argv[iarg-1]) ;
2958        sm_rad = (float)strtod(argv[iarg],NULL) ; twopass = 1 ;
2959        if( sm_rad < 0.0f ) sm_rad = 0.0f ;
2960        iarg++ ; continue ;
2961      }
2962 
2963      if( strncmp(argv[iarg],"-fineblur",8) == 0 ){
2964        if( ++iarg >= argc ) ERROR_exit("no argument after '%s' :-(",argv[iarg-1]) ;
2965        fine_rad = (float)strtod(argv[iarg],NULL) ; iarg++ ; continue ;
2966      }
2967 
2968      /*-----*/
2969 
2970      if( strncmp(argv[iarg],"-twobest",7) == 0 ){
2971        static int first=1 ; int tbold=tbest ;
2972        if( ++iarg >= argc ) ERROR_exit("no argument after '%s' :-(",argv[iarg-1]) ;
2973        tbest = (int)strtod(argv[iarg],NULL) ; twopass = 1 ;
2974        if( tbest < 0 ){
2975          WARNING_message("-twobest %d is illegal: replacing with 0",tbest) ;
2976          tbest = 0 ;
2977        } else if( strncasecmp(argv[iarg],"MAX",3) == 0 ){  /* 28 May 2021 */
2978          tbest = PARAM_MAXTRIAL ;
2979          if( verb > 1 )
2980            INFO_message("-twobest MAX ==> %d",PARAM_MAXTRIAL) ;
2981        } else if( tbest > PARAM_MAXTRIAL ){
2982          INFO_message("-twobest %d is too big: replaced with %d",tbest,PARAM_MAXTRIAL) ;
2983          tbest = PARAM_MAXTRIAL ;
2984        } else if( !first && tbold > tbest ){
2985          INFO_message("keeping older/larger -twobest value of %d",tbold) ;
2986          tbest = tbold ;
2987        }
2988        first = 0 ; iarg++ ; continue ;
2989      }
2990 
2991      if( strncmp(argv[iarg],"-num_rtb",7) == 0 ){
2992        if( ++iarg >= argc ) ERROR_exit("no argument after '%s' :-(",argv[iarg-1]) ;
2993        num_rtb = (int)strtod(argv[iarg],NULL) ; twopass = 1 ;
2994             if( num_rtb <= 0   ) num_rtb = 0 ;
2995        else if( num_rtb <  66  ) num_rtb = 66 ;
2996        else if( num_rtb >  666 ) num_rtb = 666 ;
2997        iarg++ ; continue ;
2998      }
2999 
3000      if( strncmp(argv[iarg],"-nocast",6) == 0 ){
3001        nocast = 1 ; iarg++ ; continue ;
3002      }
3003 
3004      /*-----*/
3005 
3006      if( strncmp(argv[iarg],"-onepass",6) == 0 ){
3007        twopass = twofirst = 0 ; iarg++ ; continue ;
3008      }
3009      if( strncmp(argv[iarg],"-twopass",6) == 0 ){
3010        twopass = 1 ; twofirst = 0 ; iarg++ ; continue ;
3011      }
3012      if( strncmp(argv[iarg],"-twofirst",6) == 0 ){
3013        twofirst = twopass = 1 ; iarg++ ; continue ;
3014      }
3015 
3016      /*-----*/
3017 
3018      if( strncmp(argv[iarg],"-output",5) == 0 || strncmp(argv[iarg],"-prefix",5) == 0 ){
3019        if( prefix != NULL ) ERROR_exit("Can't have multiple %s options :-(",argv[iarg]) ;
3020        if( ++iarg >= argc ) ERROR_exit("no argument after '%s' :-(",argv[iarg-1]) ;
3021        if( !THD_filename_ok(argv[iarg]) )
3022          ERROR_exit("badly formed filename: '%s' '%s' :-(",argv[iarg-1],argv[iarg]) ;
3023        if( strcmp(argv[iarg],"NULL") == 0 ) prefix = NULL ;
3024        else                                 prefix = argv[iarg] ;
3025        iarg++ ; continue ;
3026      }
3027 
3028      /*-----*/
3029 
3030      if( strncmp(argv[iarg],"-1Dfile",5) == 0 || strncmp(argv[iarg],"-1Dparam_save",12) == 0 ){
3031        if( param_save_1D != NULL ) ERROR_exit("Can't have multiple %s options :-(",argv[iarg]);
3032        if( ++iarg >= argc ) ERROR_exit("no argument after '%s' :-(",argv[iarg-1]) ;
3033        if( !THD_filename_ok(argv[iarg]) )
3034          ERROR_exit("badly formed filename: %s '%s' :-(",argv[iarg-1],argv[iarg]) ;
3035        if( STRING_HAS_SUFFIX(argv[iarg],".1D") ){
3036          param_save_1D = argv[iarg] ;
3037        } else {
3038          param_save_1D = calloc(sizeof(char*),strlen(argv[iarg])+16) ;
3039          strcpy(param_save_1D,argv[iarg]) ; strcat(param_save_1D,".param.1D") ;
3040        }
3041        iarg++ ; continue ;
3042      }
3043 
3044      /*-----*/
3045 
3046      if( strncmp(argv[iarg],"-1Dmatrix_save",13) == 0 ){
3047        if( matrix_save_1D != NULL ) ERROR_exit("Can't have multiple %s options :-(",argv[iarg]);
3048        if( ++iarg >= argc ) ERROR_exit("no argument after '%s' :-(",argv[iarg-1]) ;
3049        if( !THD_filename_ok(argv[iarg]) )
3050          ERROR_exit("badly formed filename: %s '%s' :-(",argv[iarg-1],argv[iarg]) ;
3051        if( STRING_HAS_SUFFIX(argv[iarg],".1D") ){
3052          matrix_save_1D = argv[iarg] ;
3053        } else {
3054          matrix_save_1D = calloc(sizeof(char*),strlen(argv[iarg])+16) ;
3055          strcpy(matrix_save_1D,argv[iarg]) ; strcat(matrix_save_1D,".aff12.1D") ;
3056        }
3057        iarg++ ; continue ;
3058      }
3059 
3060      /*-----*/
3061 
3062 #undef  APL
3063 #define APL(i,j) apply_far[(i)+(j)*apply_nx] /* i=param index, j=row index */
3064 
3065      if( strncmp(argv[iarg],"-1Dapply",5)        == 0 ||
3066          strncmp(argv[iarg],"-1Dparam_apply",13) == 0   ){
3067        char *fname ;
3068 
3069        if( APPLYING )
3070          ERROR_exit("Can't have multiple 'apply' options :-(") ;
3071        if( ++iarg >= argc ) ERROR_exit("no argument after '%s' :-(",argv[iarg-1]) ;
3072 #if 0
3073        if( strncmp(argv[iarg],"1D:",3) != 0 && !THD_filename_ok(argv[iarg]) )
3074          ERROR_exit("badly formed filename: %s '%s' :-(",argv[iarg-1],argv[iarg]) ;
3075 #endif
3076        fname = argv[iarg] ;
3077        if( strcasecmp(fname,"IDENTITY")==0 ) fname = "1D: 12@0'" ;
3078        apply_1D = fname ; qim = mri_read_1D(apply_1D) ;
3079        if( qim == NULL ) ERROR_exit("Can't read %s '%s' :-(",argv[iarg-1],apply_1D) ;
3080        apply_im  = mri_transpose(qim); mri_free(qim);
3081        apply_far = MRI_FLOAT_PTR(apply_im) ;
3082        apply_nx  = apply_im->nx ;  /* # of values per row */
3083        apply_ny  = apply_im->ny ;  /* number of rows */
3084        apply_mode = APPLY_PARAM ;
3085        iarg++ ; continue ;
3086      }
3087 
3088      /*-----*/
3089 
3090      if( strncmp(argv[iarg],"-1Dmatrix_apply",13) == 0 ){
3091        char *fname ;
3092        if( APPLYING )
3093          ERROR_exit("Can't have multiple 'apply' options :-(") ;
3094        if( ++iarg >= argc ) ERROR_exit("no argument after '%s' :-(",argv[iarg-1]) ;
3095 #if 0
3096        if( !THD_filename_ok(argv[iarg]) )
3097          ERROR_exit("badly formed filename: %s '%s' :-(",argv[iarg-1],argv[iarg]) ;
3098 #endif
3099        fname = argv[iarg] ;
3100        if( strcasecmp(fname,"IDENTITY")==0 )
3101          fname = "1D: 1 0 0 0   0 1 0 0   0 0 1 0" ;
3102        apply_1D = fname ; qim = mri_read_1D(apply_1D) ;
3103        if( qim == NULL ) ERROR_exit("Can't read -1Dmatrix_apply '%s' :-(",apply_1D) ;
3104        apply_im  = mri_transpose(qim); mri_free(qim);
3105        apply_far = MRI_FLOAT_PTR(apply_im) ;
3106        apply_nx  = apply_im->nx ;  /* # of values per row */
3107        apply_ny  = apply_im->ny ;  /* number of rows */
3108        apply_mode = APPLY_AFF12 ;
3109        if( apply_nx < 12 && apply_im->nvox == 12 ){  /* special case of a 3x4 array */
3110          apply_nx = 12 ; apply_ny = 1 ;
3111          INFO_message("-1Dmatrix_apply: converting input 3x4 array to 1 row of 12 numbers") ;
3112        }
3113        if( apply_nx < 12 )
3114          ERROR_exit("%d = Less than 12 numbers per row in -1Dmatrix_apply '%s' :-(" ,apply_nx,apply_1D) ;
3115        else if( apply_nx > 12 )
3116          WARNING_message("%d = More than 12 numbers per row in -1Dmatrix_apply '%s'",apply_ny,apply_1D) ;
3117        iarg++ ; continue ;
3118      }
3119 
3120      /*-----*/
3121 
3122      if( strcmp(argv[iarg],"-NN") == 0 || strncmp(argv[iarg],"-nearest",6) == 0 ){
3123        interp_code = MRI_NN ; iarg++ ; got_interp = 1 ;continue ;
3124      }
3125      if( strncmp(argv[iarg],"-linear",4)==0 || strncmp(argv[iarg],"-trilinear",6)==0 ){
3126        interp_code = MRI_LINEAR ; iarg++ ; got_interp = 1 ;continue ;
3127      }
3128      if( strncmp(argv[iarg],"-cubic",4)==0 || strncmp(argv[iarg],"-tricubic",6)==0 ){
3129        interp_code = MRI_CUBIC ; iarg++ ; got_interp = 1 ;continue ;
3130      }
3131      if( strncmp(argv[iarg],"-quintic",4)==0 || strncmp(argv[iarg],"-triquintic",6)==0 ){
3132        interp_code = MRI_QUINTIC ; iarg++ ; got_interp = 1 ;continue ;
3133      }
3134 #if 0
3135      if( strncasecmp(argv[iarg],"-WSINC") == 0 ){
3136        interp_code = MRI_WSINC5 ; iarg++ ; got_interp = 1 ;continue ;
3137      }
3138 #endif
3139      if( strncmp(argv[iarg],"-interp",5)==0 ){
3140        if( ++iarg >= argc ) ERROR_exit("no argument after '%s' :-(",argv[iarg-1]) ;
3141        if( strcmp(argv[iarg],"NN")==0 || strncmp(argv[iarg],"nearest",5)==0 )
3142          interp_code = MRI_NN ;
3143        else
3144        if( strncmp(argv[iarg],"linear",3)==0 || strncmp(argv[iarg],"trilinear",5)==0 )
3145          interp_code = MRI_LINEAR ;
3146        else
3147        if( strncmp(argv[iarg],"cubic",3)==0 || strncmp(argv[iarg],"tricubic",5)==0 )
3148          interp_code = MRI_CUBIC ;
3149        else
3150        if( strncmp(argv[iarg],"quintic",3)==0 || strncmp(argv[iarg],"triquintic",5)==0 )
3151          interp_code = MRI_QUINTIC ;
3152 #if 0
3153        else
3154        if( strncasecmp(argv[iarg],"WSINC",5)==0 )
3155          interp_code = MRI_WSINC5 ;
3156 #endif
3157        else
3158          ERROR_exit("Unknown code '%s' after '%s' :-(",argv[iarg],argv[iarg-1]) ;
3159        iarg++ ; got_interp = 1 ;continue ;
3160      }
3161 
3162      if( strncmp(argv[iarg],"-final",5) == 0 ){
3163        if( ++iarg >= argc ) ERROR_exit("no argument after '%s' :-(",argv[iarg-1]) ;
3164        if( strcmp(argv[iarg],"NN") == 0 || strncmp(argv[iarg],"nearest",5) == 0 )
3165          final_interp = MRI_NN ;
3166        else
3167        if( strncmp(argv[iarg],"linear",3) == 0 || strncmp(argv[iarg],"trilinear",5) == 0 )
3168          final_interp = MRI_LINEAR ;
3169        else
3170        if( strncmp(argv[iarg],"cubic",3) == 0 || strncmp(argv[iarg],"tricubic",5) == 0 )
3171          final_interp = MRI_CUBIC ;
3172        else
3173        if( strncmp(argv[iarg],"quintic",3)==0 || strncmp(argv[iarg],"triquintic",5)==0 )
3174          final_interp = MRI_QUINTIC ;
3175        else
3176        if( strncasecmp(argv[iarg],"WSINC",5)==0 )
3177          final_interp = MRI_WSINC5 ;
3178        else
3179          ERROR_exit("Unknown code '%s' after '%s' :-(",argv[iarg],argv[iarg-1]) ;
3180        iarg++ ; got_final = 1 ;continue ;
3181      }
3182 
3183      /*-----*/
3184 
3185      if( strncmp(argv[iarg],"-converge",5) == 0 ){
3186        float vv ;
3187        if( ++iarg >= argc ) ERROR_exit("no argument after '%s' :-(",argv[iarg-1]) ;
3188        vv = (float)strtod(argv[iarg],NULL) ;
3189             if( vv < 0.0001f ){ vv = 0.0001f; WARNING_message("%s: limited %s to 0.0001",argv[iarg-1],argv[iarg]); }
3190        else if( vv > 6.666f  ){ vv = 6.666f ; WARNING_message("%s: limited %s to 6.666" ,argv[iarg-1],argv[iarg]); }
3191        conv_mm = vv ; iarg++ ; continue ;
3192      }
3193 
3194      /*-----*/
3195 
3196      if( strncmp(argv[iarg],"-nmatch",5) == 0 ){
3197        char *cpt ;
3198        if( ++iarg >= argc ) ERROR_exit("no argument after '%s' :-(",argv[iarg-1]) ;
3199        npt_match = (int)strtod(argv[iarg],&cpt) ;
3200        if( npt_match <= 0 )
3201          ERROR_exit("Illegal value '%s' after '%s' :-(",argv[iarg],argv[iarg-1]) ;
3202        if( *cpt == '%' || npt_match <= 100 )
3203          npt_match = -npt_match ;  /* signal for % */
3204        iarg++ ; continue ;
3205      }
3206 
3207      /*-----*/
3208 
3209      if( strcmp(argv[iarg],"-warp") == 0 ){
3210       if( ++iarg >= argc ) ERROR_exit("no argument after '%s' :-(",argv[iarg-1]) ;
3211       if( strcmp(argv[iarg],"sho")     ==0 || strcmp(argv[iarg],"shift_only")        ==0 )
3212         warp_code = WARP_SHIFT ;
3213       else if( strcmp(argv[iarg],"shr")==0 || strcmp(argv[iarg],"shift_rotate")      ==0 )
3214         warp_code = WARP_ROTATE ;
3215       else if( strcmp(argv[iarg],"srs")==0 || strcmp(argv[iarg],"shift_rotate_scale")==0 )
3216         warp_code = WARP_SCALE ;
3217       else if( strcmp(argv[iarg],"aff")==0 || strcmp(argv[iarg],"affine_general")    ==0 )
3218         warp_code = WARP_AFFINE ;
3219       else
3220         ERROR_exit("Unknown code '%s' after '%s' :-(",argv[iarg],argv[iarg-1]) ;
3221       iarg++ ; continue ;
3222      }
3223      if( strcmp(argv[iarg],"-dof") == 0 ){
3224        if( ++iarg >= argc ) ERROR_exit("no argument after '%s' :-(",argv[iarg-1]) ;
3225        ii = (int)strtod(argv[iarg],NULL) ;
3226        switch(ii){
3227          case  3: warp_code = WARP_SHIFT  ; break ;
3228          case  6: warp_code = WARP_ROTATE ; break ;
3229          case  9: warp_code = WARP_SCALE  ; break ;
3230          case 12: warp_code = WARP_AFFINE ; break ;
3231          default:
3232            ERROR_exit("Unknown value '%s' after '%s' :-(",argv[iarg],argv[iarg-1]) ;
3233        }
3234        iarg++ ; continue ;
3235      }
3236 
3237      /*-----*/
3238 
3239      if( strcmp(argv[iarg],"-parfix") == 0 ){
3240        if( ++iarg >= argc-1 ) ERROR_exit("need 2 arguments after '%s' :-(",argv[iarg-1]) ;
3241        if( nparopt >= MAXPAR ) ERROR_exit("too many -par... options :-(") ;
3242        ii = (int)strtod(argv[iarg],NULL) ;
3243        if( ii <= 0 ) ERROR_exit("-parfix '%s' is illegal :-(",argv[iarg]) ;
3244        v1 = (float)strtod(argv[++iarg],NULL) ;
3245        paropt[nparopt].np   = ii-1 ;
3246        paropt[nparopt].code = PARC_FIX ;
3247        paropt[nparopt].vb   = v1 ;
3248        nparopt++ ; iarg++ ; continue ;
3249      }
3250 
3251      /*-----*/
3252 
3253      if( strcmp(argv[iarg],"-parang") == 0 ){
3254        if( ++iarg >= argc-2 ) ERROR_exit("need 3 arguments after '%s' :-(",argv[iarg-1]) ;
3255        if( nparopt >= MAXPAR ) ERROR_exit("too many -par... options :-(") ;
3256        ii = (int)strtod(argv[iarg],NULL) ;
3257        if( ii <= 0 ) ERROR_exit("-parang '%s' is illegal :-(",argv[iarg]) ;
3258        v1 = (float)strtod(argv[++iarg],NULL) ;
3259        v2 = (float)strtod(argv[++iarg],NULL) ;
3260        if( v1 > v2 ) ERROR_exit("-parang %d '%s' '%s' is illegal :-(",
3261                      ii,argv[iarg-1],argv[iarg] ) ;
3262        paropt[nparopt].np   = ii-1 ;
3263        paropt[nparopt].code = PARC_RAN ;
3264        paropt[nparopt].vb   = v1 ;
3265        paropt[nparopt].vt   = v2 ;
3266        nparopt++ ; iarg++ ; continue ;
3267      }
3268 
3269      /*-----*/
3270 
3271      if( strcmp(argv[iarg],"-maxrot") == 0 ){
3272        float vv ;
3273        if( ++iarg >= argc ) ERROR_exit("no argument after '%s' :-(",argv[iarg-1]) ;
3274        if( nparopt+2 >= MAXPAR ) ERROR_exit("too many -par... options :-(") ;
3275        vv = (float)strtod(argv[iarg],NULL) ;
3276        if( vv <= 0.0f || vv > 90.0f ) ERROR_exit("-maxrot %f is illegal :-(",vv) ;
3277        paropt[nparopt].np   = 3 ;
3278        paropt[nparopt].code = PARC_RAN ;
3279        paropt[nparopt].vb   = -vv ;
3280        paropt[nparopt].vt   =  vv ; nparopt++ ;
3281        paropt[nparopt].np   = 4 ;
3282        paropt[nparopt].code = PARC_RAN ;
3283        paropt[nparopt].vb   = -vv ;
3284        paropt[nparopt].vt   =  vv ; nparopt++ ;
3285        paropt[nparopt].np   = 5 ;
3286        paropt[nparopt].code = PARC_RAN ;
3287        paropt[nparopt].vb   = -vv ;
3288        paropt[nparopt].vt   =  vv ; nparopt++ ; iarg++ ; continue ;
3289      }
3290 
3291      /*-----*/
3292 
3293      if( strcmp(argv[iarg],"-maxscl") == 0 ){
3294        float vv , vvi ; char *cpt ;
3295        if( ++iarg >= argc ) ERROR_exit("no argument after '%s' :-(",argv[iarg-1]) ;
3296        if( nparopt+2 >= MAXPAR ) ERROR_exit("too many -par... options :-(") ;
3297        vv = (float)strtod(argv[iarg],&cpt) ;
3298        if( *cpt == '%' ) vv = 1.0f + 0.01*vv ;
3299        if( vv == 1.0f || vv > 2.5f || vv < 0.4f )
3300          ERROR_exit("-maxscl %f is illegal :-(",vv) ;
3301        if( vv > 1.0f ){ vvi = 1.0f/vv; }
3302        else           { vvi = vv ; vv = 1.0f/vvi ; }
3303        paropt[nparopt].np   = 6 ;
3304        paropt[nparopt].code = PARC_RAN ;
3305        paropt[nparopt].vb   = vvi ;
3306        paropt[nparopt].vt   =  vv ; nparopt++ ;
3307        paropt[nparopt].np   = 7 ;
3308        paropt[nparopt].code = PARC_RAN ;
3309        paropt[nparopt].vb   = vvi ;
3310        paropt[nparopt].vt   =  vv ; nparopt++ ;
3311        paropt[nparopt].np   = 8 ;
3312        paropt[nparopt].code = PARC_RAN ;
3313        paropt[nparopt].vb   = vvi ;
3314        paropt[nparopt].vt   =  vv ; nparopt++ ; iarg++ ; continue ;
3315      }
3316 
3317      /*-----*/
3318 
3319      if( strcmp(argv[iarg],"-maxshr") == 0 ){  /* 03 Dec 2010 */
3320        float vv ;
3321        if( ++iarg >= argc ) ERROR_exit("no argument after '%s' :-(",argv[iarg-1]) ;
3322        if( nparopt+2 >= MAXPAR ) ERROR_exit("too many -par... options :-(") ;
3323        vv = (float)strtod(argv[iarg],NULL) ;
3324        if( vv <= 0.0f || vv > 1.0f ) ERROR_exit("-maxshr %f is illegal :-(",vv) ;
3325        paropt[nparopt].np   = 9 ;
3326        paropt[nparopt].code = PARC_RAN ;
3327        paropt[nparopt].vb   = -vv ;
3328        paropt[nparopt].vt   =  vv ; nparopt++ ;
3329        paropt[nparopt].np   = 10 ;
3330        paropt[nparopt].code = PARC_RAN ;
3331        paropt[nparopt].vb   = -vv ;
3332        paropt[nparopt].vt   =  vv ; nparopt++ ;
3333        paropt[nparopt].np   = 11 ;
3334        paropt[nparopt].code = PARC_RAN ;
3335        paropt[nparopt].vb   = -vv ;
3336        paropt[nparopt].vt   =  vv ; nparopt++ ; iarg++ ; continue ;
3337      }
3338 
3339      /*-----*/
3340 
3341      if( strcmp(argv[iarg],"-maxshf") == 0 ){
3342        float vv ;
3343        if( ++iarg >= argc ) ERROR_exit("no argument after '%s' :-(",argv[iarg-1]) ;
3344        if( nparopt+2 >= MAXPAR ) ERROR_exit("too many -par... options :-(") ;
3345        vv = (float)strtod(argv[iarg],NULL) ;
3346        if( vv <= 0.0f ) ERROR_exit("-maxshf %f is illegal :-(",vv) ;
3347        paropt[nparopt].np   = 0 ;
3348        paropt[nparopt].code = PARC_RAN ;
3349        paropt[nparopt].vb   = -vv ;
3350        paropt[nparopt].vt   =  vv ; nparopt++ ;
3351        paropt[nparopt].np   = 1 ;
3352        paropt[nparopt].code = PARC_RAN ;
3353        paropt[nparopt].vb   = -vv ;
3354        paropt[nparopt].vt   =  vv ; nparopt++ ;
3355        paropt[nparopt].np   = 2 ;
3356        paropt[nparopt].code = PARC_RAN ;
3357        paropt[nparopt].vb   = -vv ;
3358        paropt[nparopt].vt   =  vv ; nparopt++ ; iarg++ ; continue ;
3359      }
3360 
3361      /*-----*/
3362 
3363      if( strcmp(argv[iarg],"-parini") == 0 ){
3364        if( ++iarg >= argc-1 ) ERROR_exit("need 2 arguments after '%s' :-(",argv[iarg-1]) ;
3365        if( nparopt >= MAXPAR ) ERROR_exit("too many -par... options :-(") ;
3366        ii = (int)strtod(argv[iarg],NULL) ;
3367        if( ii <= 0 ) ERROR_exit("-parini '%s' is illegal :-(",argv[iarg]) ;
3368        v1 = (float)strtod(argv[++iarg],NULL) ;
3369        paropt[nparopt].np   = ii-1 ;
3370        paropt[nparopt].code = PARC_INI ;
3371        paropt[nparopt].vb   = v1 ;
3372        nparopt++ ; iarg++ ; continue ;
3373      }
3374 
3375      /*-----*/
3376 
3377      if( strncmp(argv[iarg],"-FPS",4)==0 || strncmp(argv[iarg],"-EPI",4)==0 ){
3378        int fe=-1 , pe=-1 , se=-1 ; char *fps , *aaa=argv[iarg] ;
3379 
3380        if( epi_targ >= 0 )
3381          ERROR_exit("Can't have multiple '%4.4s' options :-(",aaa) ;
3382 
3383        /* is the EPI dataset the target (default) or base? */
3384 
3385        epi_targ = (aaa[4] != '\0' && toupper(aaa[4]) == 'B') ? 0 : 1 ;
3386 
3387        if( aaa[1] == 'F' ){   /* -FPS code */
3388          if( ++iarg >= argc )  ERROR_exit("no argument after '%s' :-(",argv[iarg-1]);
3389          fps = argv[iarg] ;
3390          if( strlen(fps) < 3 ) ERROR_exit("Too short %4.4s codes '%s' :-(",aaa,fps);
3391        } else {
3392          fps = "123" ;        /* -EPI */
3393        }
3394 
3395        /* decode the FPS directions, so that
3396             epi_fe = freq encode direction = 0 or 1 or 2
3397             epi_pe = phase encode direction
3398             epi_se = slice encode direction */
3399 
3400        switch( fps[0] ){
3401          default: ERROR_exit("Illegal %4.4s f code '%c' :-(" , aaa,fps[0] );
3402          case 'i': case 'I': case 'x': case 'X': case '1':  fe = 1; break;
3403          case 'j': case 'J': case 'y': case 'Y': case '2':  fe = 2; break;
3404          case 'k': case 'K': case 'z': case 'Z': case '3':  fe = 3; break;
3405        }
3406        switch( fps[1] ){
3407          default: ERROR_exit("Illegal %4.4s p code '%c' :-(" , aaa,fps[1] );
3408          case 'i': case 'I': case 'x': case 'X': case '1':  pe = 1; break;
3409          case 'j': case 'J': case 'y': case 'Y': case '2':  pe = 2; break;
3410          case 'k': case 'K': case 'z': case 'Z': case '3':  pe = 3; break;
3411        }
3412        switch( fps[2] ){
3413          default: ERROR_exit("Illegal %4.4s s code '%c' :-(" , aaa,fps[2] );
3414          case 'i': case 'I': case 'x': case 'X': case '1':  se = 1; break;
3415          case 'j': case 'J': case 'y': case 'Y': case '2':  se = 2; break;
3416          case 'k': case 'K': case 'z': case 'Z': case '3':  se = 3; break;
3417        }
3418        if( fe+pe+se != 6 ) ERROR_exit("Illegal %4.4s combination '%s' :-(",aaa,fps);
3419 
3420        epi_fe = fe-1 ; epi_pe = pe-1 ; epi_se = se-1 ;  /* process later */
3421 
3422        if( verb > 1 )
3423          INFO_message("EPI parameters: targ=%d  fe=%d pe=%d se=%d",
3424                       epi_targ,epi_fe,epi_pe,epi_se ) ;
3425 
3426        /* restrict some transformation parameters */
3427 
3428        smat = SMAT_YYY ;               /* shear only in y (PE) direction */
3429        warp_freeze = 1 ;               /* 10 Oct 2006 */
3430 
3431        /* matrix order depends on if we are restricting transformation
3432           parameters in the base image or in the target image coordinates */
3433 
3434        matorder = (epi_targ) ? MATORDER_SDU : MATORDER_USD ;
3435 
3436        paropt[nparopt].np   = 6 ;      /* fix x-scale to 1 */
3437        paropt[nparopt].code = PARC_FIX ;
3438        paropt[nparopt].vb   = 1.0 ; nparopt++ ;
3439 
3440        paropt[nparopt].np   = 8 ;      /* fix z-scale to 1 */
3441        paropt[nparopt].code = PARC_FIX ;
3442        paropt[nparopt].vb   = 1.0 ; nparopt++ ;
3443 
3444        paropt[nparopt].np   = 11 ;      /* fix last shear to 0 */
3445        paropt[nparopt].code = PARC_FIX ;
3446        paropt[nparopt].vb   = 0.0 ; nparopt++ ;
3447 
3448        twofirst = 1; replace_base = 1;
3449 #if 0
3450        replace_meth = GA_MATCH_PEARSON_SCALAR;
3451 #endif
3452        iarg++ ; continue ;
3453      }
3454 
3455      /*-----*/
3456 
3457      if( strcmp(argv[iarg],"-replacebase") == 0 ){  /* 18 Oct 2006 */
3458        twofirst = replace_base = 1 ; iarg++ ; continue ;
3459      }
3460      if( strcmp(argv[iarg],"-warpfreeze") == 0 ){  /* 18 Oct 2006 */
3461        warp_freeze = 1 ; iarg++ ; continue ;
3462      }
3463 
3464      if( strcmp(argv[iarg],"-nowarpfreeze") == 0 ){  /* 01 Feb 2007 */
3465        warp_freeze = 0 ; iarg++ ; continue ;
3466      }
3467      if( strcmp(argv[iarg],"-noreplacebase") == 0 ){  /* 01 Feb 2007 */
3468        replace_base = 0 ; iarg++ ; continue ;
3469      }
3470 
3471      /*-----*/
3472 
3473      if( strcmp(argv[iarg],"-replacemeth") == 0 ){  /* 18 Oct 2006 */
3474        if( ++iarg >= argc ) ERROR_exit("no argument after '-replacemeth' :-(") ;
3475 
3476        if( strcmp(argv[iarg],"0") == 0 ){
3477          replace_meth = 0 ; iarg++ ; continue ;  /* special case */
3478        }
3479 
3480        jj = meth_name_to_code(argv[iarg]) ;
3481        if( jj > 0 ){ replace_meth = jj ; iarg++ ; continue ; }
3482 
3483        ERROR_exit("Unknown code '%s' after -replacemeth :-(",argv[iarg]) ;
3484        iarg++ ; continue ;
3485      }
3486 
3487      /*-----*/
3488 
3489      if( strcmp(argv[iarg],"-Xwarp") == 0 ){  /* 02 Oct 2006 */
3490        if( XYZ_warp > 0 ) ERROR_exit("only one use of -[XYZ]warp is allowed :-(");
3491        matorder = MATORDER_USD ;       /* rotation after shear and scale */
3492 
3493        paropt[nparopt].np   = 7 ;      /* fix y-scale to 1 */
3494        paropt[nparopt].code = PARC_FIX ;
3495        paropt[nparopt].vb   = 1.0 ; nparopt++ ;
3496 
3497        paropt[nparopt].np   = 8 ;      /* fix z-scale to 1 */
3498        paropt[nparopt].code = PARC_FIX ;
3499        paropt[nparopt].vb   = 1.0 ; nparopt++ ;
3500 
3501        paropt[nparopt].np   = 11 ;      /* fix last shear to 0 */
3502        paropt[nparopt].code = PARC_FIX ;
3503        paropt[nparopt].vb   = 0.0 ; nparopt++ ;
3504 
3505        smat = SMAT_XXX ;                /* fix shear matrix to x-only */
3506        XYZ_warp = 1 ;iarg++ ; continue ;
3507      }
3508 
3509      if( strcmp(argv[iarg],"-Ywarp") == 0 ){  /* 02 Oct 2006 */
3510        if( XYZ_warp > 0 ) ERROR_exit("only one use of -[XYZ]warp is allowed :-(");
3511        matorder = MATORDER_USD ;       /* rotation after shear and scale */
3512 
3513        paropt[nparopt].np   = 6 ;      /* fix x-scale to 1 */
3514        paropt[nparopt].code = PARC_FIX ;
3515        paropt[nparopt].vb   = 1.0 ; nparopt++ ;
3516 
3517        paropt[nparopt].np   = 8 ;      /* fix z-scale to 1 */
3518        paropt[nparopt].code = PARC_FIX ;
3519        paropt[nparopt].vb   = 1.0 ; nparopt++ ;
3520 
3521        paropt[nparopt].np   = 11 ;      /* fix last shear to 0 */
3522        paropt[nparopt].code = PARC_FIX ;
3523        paropt[nparopt].vb   = 0.0 ; nparopt++ ;
3524 
3525        smat = SMAT_YYY ;                /* fix shear matrix to y-only */
3526        XYZ_warp = 2 ; iarg++ ; continue ;
3527      }
3528 
3529      if( strcmp(argv[iarg],"-Zwarp") == 0 ){  /* 02 Oct 2006 */
3530        if( XYZ_warp > 0 ) ERROR_exit("only one use of -[XYZ]warp is allowed :-(");
3531        matorder = MATORDER_USD ;       /* rotation after shear and scale */
3532 
3533        paropt[nparopt].np   = 6 ;      /* fix x-scale to 1 */
3534        paropt[nparopt].code = PARC_FIX ;
3535        paropt[nparopt].vb   = 1.0 ; nparopt++ ;
3536 
3537        paropt[nparopt].np   = 7 ;      /* fix y-scale to 1 */
3538        paropt[nparopt].code = PARC_FIX ;
3539        paropt[nparopt].vb   = 1.0 ; nparopt++ ;
3540 
3541        paropt[nparopt].np   = 11 ;      /* fix last shear to 0 */
3542        paropt[nparopt].code = PARC_FIX ;
3543        paropt[nparopt].vb   = 0.0 ; nparopt++ ;
3544 
3545        smat = SMAT_ZZZ ;                /* fix shear matrix to x-only */
3546        XYZ_warp = 3 ; iarg++ ; continue ;
3547      }
3548 
3549      /*-----*/
3550 
3551      if( strcmp(argv[iarg],"-SDU") == 0 ){
3552        matorder = MATORDER_SDU ; iarg++ ; continue ;
3553      }
3554      if( strcmp(argv[iarg],"-SUD") == 0 ){
3555        matorder = MATORDER_SUD ; iarg++ ; continue ;
3556      }
3557      if( strcmp(argv[iarg],"-DSU") == 0 ){
3558        matorder = MATORDER_DSU ; iarg++ ; continue ;
3559      }
3560      if( strcmp(argv[iarg],"-DUS") == 0 ){
3561        matorder = MATORDER_DUS ; iarg++ ; continue ;
3562      }
3563      if( strcmp(argv[iarg],"-USD") == 0 ){
3564        matorder = MATORDER_USD ; iarg++ ; continue ;
3565      }
3566      if( strcmp(argv[iarg],"-UDS") == 0 ){
3567        matorder = MATORDER_UDS ; iarg++ ; continue ;
3568      }
3569      if( strcmp(argv[iarg],"-ashift") == 0 ){
3570        dcode = DELTA_AFTER     ; iarg++ ; continue ;
3571      }
3572      if( strcmp(argv[iarg],"-bshift") == 0 ){
3573        dcode = DELTA_BEFORE    ; iarg++ ; continue ;
3574      }
3575      if( strcmp(argv[iarg],"-Slower") == 0 ){
3576        smat  = SMAT_LOWER      ; iarg++ ; continue ;
3577      }
3578      if( strcmp(argv[iarg],"-Supper") == 0 ){
3579        smat  = SMAT_UPPER      ; iarg++ ; continue ;
3580      }
3581 
3582      /*-----*/
3583 
3584      if( strcasecmp(argv[iarg],"-Lunch") == 0 ){  /* 23 Sep 2020 */
3585        WARNING_message("There is no free '%s' with AFNI :(",argv[iarg]) ;
3586        iarg++ ; continue ;
3587      }
3588      if( strcasecmp(argv[iarg],"-Faster") == 0 ){
3589        WARNING_message("You want '%s'? We already use OpenMP! Give me a break.",argv[iarg]) ;
3590        iarg++ ; continue ;
3591      }
3592 
3593      /*-----*/
3594 
3595      if( strcmp(argv[iarg],"-blok") == 0 ){
3596        int ia=0 ;
3597        if( ++iarg >= argc ) ERROR_exit("Need argument after -blok :-(") ;
3598        if( strncmp(argv[iarg],"SPHERE(",7) == 0 ){
3599          ia = 7 ; bloktype = GA_BLOK_BALL ;
3600        } else if( strncmp(argv[iarg],"BALL(",5) == 0 ){
3601          ia = 5 ; bloktype = GA_BLOK_BALL ;
3602        } else if( strncmp(argv[iarg],"RECT(",5) == 0 ){
3603          ia = 5 ; bloktype = GA_BLOK_CUBE ;
3604        } else if( strncmp(argv[iarg],"CUBE(",5) == 0 ){
3605          ia = 5 ; bloktype = GA_BLOK_CUBE ;
3606        } else if( strncmp(argv[iarg],"RHDD(",5) == 0 ){
3607          ia = 5 ; bloktype = GA_BLOK_RHDD ;
3608        } else if( strncmp(argv[iarg],"TOHD(",5) == 0 ){
3609          ia = 5 ; bloktype = GA_BLOK_TOHD ;
3610        } else {
3611          ERROR_exit("Illegal argument after -blok :-(") ;
3612        }
3613        blokrad = (float)strtod(argv[iarg]+ia,NULL) ;
3614        iarg++ ; continue ;
3615      }
3616 
3617      /*-----*/
3618 
3619      ERROR_message("Unknown and Illegal option '%s' :-( :-( :-(",argv[iarg]) ;
3620      suggest_best_prog_option(argv[0], argv[iarg]);
3621      exit(1);
3622 
3623    } /*----------------- end of loop over command line args -----------------*/
3624 
3625    if( iarg < argc )  /* oopsie [should never happen, I hope] */
3626      WARNING_message("Processing command line options stopped at '%s'",argv[iarg]);
3627 
3628    /*---------------------------------------------------------------*/
3629    /*--- check inputs for validity, consistency, and moral fibre ---*/
3630    /*---------------------------------------------------------------*/
3631 
3632    /** open target/source from last argument, if not already open **/
3633 
3634    if( dset_targ == NULL ){
3635      if( iarg >= argc )
3636        ERROR_exit("no source datset on command line!?") ;
3637      dset_targ = THD_open_dataset( argv[iarg] ) ;
3638      if( dset_targ == NULL )
3639        ERROR_exit("Can't open source dataset '%s'",argv[iarg]) ;
3640    }
3641 
3642    /* speak to the user? */
3643 
3644    if( verb ){
3645      INFO_message("Source dataset: %s",DSET_HEADNAME(dset_targ)) ;
3646      INFO_message("Base dataset:   %s",
3647                   (dset_base != NULL) ? DSET_HEADNAME(dset_base) : "(not given)" ) ;
3648    }
3649 
3650    /* set random seed, if not set already */
3651    if( seed == 0 ) seed = (long)time(NULL)+(long)getpid() ;
3652    srand48(seed) ;
3653 
3654    /* ls/lpc/lpa: turn -autoweight on unless it was forced off. */
3655    /* [changed from pure warning to current status 23 Jan 2017] */
3656 
3657    if( !wtspecified &&
3658        ( meth_code == GA_MATCH_PEARSON_SCALAR   ||
3659          meth_code == GA_MATCH_PEARSON_LOCALS   ||
3660          meth_code == GA_MATCH_PEARSON_LOCALA   ||
3661          meth_code == GA_MATCH_LPC_MICHO_SCALAR ||
3662          meth_code == GA_MATCH_LPA_MICHO_SCALAR   ) ){
3663      wtspecified = auto_weight = 1 ;
3664      WARNING_message(
3665        "Cost 'ls' or 'lpc' or 'lpa' ==> turning '-autoweight' on\n"
3666        "          If you DO NOT want this to happen, then use one\n"
3667        "          of '-autobox' or '-automask' or '-noauto'.\n"     ) ;
3668    }
3669 
3670    if( im_tmask == NULL && !auto_tmask &&
3671        ( meth_code == GA_MATCH_PEARSON_LOCALS   ||
3672          meth_code == GA_MATCH_PEARSON_LOCALA   ||
3673          meth_code == GA_MATCH_LPC_MICHO_SCALAR ||
3674          meth_code == GA_MATCH_LPA_MICHO_SCALAR   ) ){
3675        WARNING_message(
3676         "'-source_automask' is strongly recommended when using -lpc or -lpa") ;
3677    }
3678 
3679    if( doing_2D &&
3680        ( meth_code == GA_MATCH_PEARSON_LOCALS   ||
3681          meth_code == GA_MATCH_PEARSON_LOCALA   ||
3682          meth_code == GA_MATCH_LPC_MICHO_SCALAR ||
3683          meth_code == GA_MATCH_LPA_MICHO_SCALAR   ) ){
3684      WARNING_message(
3685       "-lpc or -lpa cost functionals do NOT work well with 2D images :(") ;
3686    }
3687 
3688    /*--- set histogram mode (for computing -hel, -mi, -cr, etc) ---*/
3689 
3690    if( !hist_setbyuser ){   /* 25 Jul 2007 */
3691      switch( meth_code ){
3692        case GA_MATCH_PEARSON_LOCALS:
3693        case GA_MATCH_PEARSON_LOCALA:
3694        case GA_MATCH_SPEARMAN_SCALAR:
3695        case GA_MATCH_PEARSON_SCALAR:
3696          hist_mode = (do_allcost || meth_check_count) ? GA_HIST_CLEQWD : 0 ;
3697        break ;
3698 
3699        default:
3700          hist_mode  = GA_HIST_CLEQWD ;
3701        break ;
3702      }
3703    }
3704 
3705    /*--- if the user wants to see all cost functional values ---*/
3706 
3707    if( do_allcost < 0 && prefix != NULL ){  /* 19 Sep 2007 */
3708      prefix = NULL ;
3709      WARNING_message("-allcostX means -prefix is ignored :-(") ;
3710    }
3711    if( do_allcost < 0 && param_save_1D != NULL ){
3712      param_save_1D = NULL ;
3713      WARNING_message("-allcostX means -1Dparam_save is ignored :-(") ;
3714    }
3715    if( do_allcost < 0 && matrix_save_1D != NULL ){
3716      matrix_save_1D = NULL ;
3717      WARNING_message("-allcostX means -1Dmatrix_save is ignored :-(") ;
3718    }
3719 
3720    /*--- I don't think anyone has every used this option ---*/
3721 
3722    if( warp_freeze ) twofirst = 1 ;  /* 10 Oct 2006 */
3723 
3724 #ifdef ALLOW_NWARP /*********************************************************/
3725    /* applying an input transformation from -nwarp: obsolescent code */
3726 
3727    if( apply_mode > 0 && nwarp_pass ){
3728      switch( nwarp_type ){
3729        default: ERROR_exit("Can't apply that nonlinear warp :-(  [%d]",nwarp_type) ;
3730 
3731        case WARP_BILINEAR:{
3732          if( apply_nx == NPBIL+4 ){
3733            apply_mode = APPLY_BILIN ;
3734            INFO_message(
3735             "found %d param/row in param file '%s'; applying bilinear warp",
3736             apply_nx , apply_1D) ;
3737          } else {
3738            ERROR_exit(
3739             "found %d param/row in param file '%s'; not right for bilinear warp",
3740             apply_nx , apply_1D) ;
3741          }
3742        }
3743        break ;
3744 
3745        case WARP_CUBIC:{
3746          if( apply_nx == NPCUB+4 ){
3747            apply_mode = APPLY_CUBIC ;
3748            INFO_message(
3749             "found %d param/row in param file '%s'; applying cubic/poly3 warp",
3750             apply_nx , apply_1D) ;
3751          } else {
3752            ERROR_exit(
3753             "found %d param/row in param file '%s'; not right for cubic/poly3 warp",
3754             apply_nx , apply_1D) ;
3755          }
3756        }
3757        break ;
3758 
3759        case WARP_QUINT:{
3760          if( apply_nx == NPQUINT+4 ){
3761            apply_mode = APPLY_QUINT ;
3762            INFO_message(
3763             "found %d param/row in param file '%s'; applying quintic/poly5 warp",
3764             apply_nx , apply_1D) ;
3765          } else {
3766            ERROR_exit(
3767             "found %d param/row in param file '%s'; not right for quintic/poly5 warp",
3768             apply_nx , apply_1D) ;
3769          }
3770        }
3771        break ;
3772 
3773        case WARP_HEPT:{
3774          if( apply_nx == NPHEPT+4 ){
3775            apply_mode = APPLY_HEPT ;
3776            INFO_message(
3777             "found %d param/row in param file '%s'; applying heptic/poly7 warp",
3778             apply_nx , apply_1D) ;
3779          } else {
3780            ERROR_exit(
3781             "found %d param/row in param file '%s'; not right for heptic/poly7 warp",
3782             apply_nx , apply_1D) ;
3783          }
3784        }
3785        break ;
3786 
3787        case WARP_NONI:{
3788          if( apply_nx == NPNONI+4 ){
3789            apply_mode = APPLY_NONI ;
3790            INFO_message(
3791             "found %d param/row in param file '%s'; applying nonic/poly9 warp",
3792             apply_nx , apply_1D) ;
3793          } else {
3794            ERROR_exit(
3795             "found %d param/row in param file '%s'; not right for nonic/poly9 warp",
3796             apply_nx , apply_1D) ;
3797          }
3798        }
3799        break ;
3800      } /* end of switch on nwarp_type */
3801    }
3802 
3803    if( nwarp_pass && meth_check_count > 0 ){  /* 15 Dec 2010 */
3804      meth_check_count = 0 ;
3805      if( verb ) WARNING_message("-check disabled because of -nwarp") ;
3806    }
3807 
3808    if( nwarp_pass && DSET_NVALS(dset_targ) > 1 )
3809      ERROR_exit("Can't use -nwarp on more than 1 sub-brick :-(") ;
3810 
3811    if( nwarp_save_prefix != NULL && !nwarp_pass ){
3812      WARNING_message("Can't use -nwarp_save without -nwarp! :-(") ;
3813      nwarp_save_prefix = NULL ;
3814    }
3815 #endif /* ALLOW_NWARP */ /**************************************************/
3816 
3817    /*--- tb_mast is set by -master SOURCE or -master BASE ---*/
3818 
3819    switch( tb_mast ){                        /* 19 Jul 2007 */
3820      case 1: dset_mast = dset_targ ; break ;
3821      case 2: dset_mast = dset_base ; break ;
3822    }
3823 
3824    /*--- I don't think this is ever used, either ---*/
3825 
3826    if( replace_base && DSET_NVALS(dset_targ) == 1 ) replace_base = 0 ;
3827 
3828    /**--- check target dataset type ---**/
3829 
3830    targ_kind = (int)DSET_BRICK_TYPE(dset_targ,0) ;
3831    if( targ_kind != MRI_float && targ_kind != MRI_short && targ_kind != MRI_byte ){
3832      INFO_message("source dataset %s has non-scalar data type '%s'",
3833                   DSET_BRIKNAME(dset_targ) , MRI_TYPE_name[targ_kind] ) ;
3834      targ_kind = MRI_float ; /* for allineation purposes */
3835      /* The only vector type likely to be included is MRI_RGB;     */
3836      /* this code will let the base image be aligned by its float  */
3837      /* 'intensity' value, and then the final output be made by    */
3838      /* applying the warp parameters to each component separately. */
3839      /* see mri_genalign_scalar_warpone() in mri_genalign.c;       */
3840      /* and see mrilib.h for ISVECTIM() macro                      */
3841      targ_was_vector = !floatize && ISVECTIM(DSET_BRICK(dset_targ,0)) ;
3842      if( targ_was_vector ) targ_vector_kind = (int)DSET_BRICK_TYPE(dset_targ,0) ;
3843    }
3844    if( !DSET_datum_constant(dset_targ) )
3845      WARNING_message("source dataset %s does not have constant data type :-(",
3846                      DSET_BRIKNAME(dset_targ)) ;
3847 
3848    /*--- if applying a set of parameters, some options are contradictory ---*/
3849 
3850    if( apply_1D != NULL ){
3851      if( prefix == NULL ) ERROR_exit("-1D*_apply also needs -prefix :-(") ;
3852      if( param_save_1D  != NULL ) WARNING_message("-1D*_apply: Can't do -1Dparam_save") ;
3853      if( matrix_save_1D != NULL ) WARNING_message("-1D*_apply: Can't do -1Dmatrix_save") ;
3854      wtprefix = param_save_1D = matrix_save_1D = NULL ;
3855      zeropad = 0 ; auto_weight = auto_tmask = 0 ;
3856      if( dset_weig != NULL ){
3857        INFO_message("-1D*_apply: Ignoring weight dataset") ;
3858        DSET_delete(dset_weig) ; dset_weig=NULL ;
3859      }
3860      if( im_tmask != NULL ){
3861        INFO_message("-1D*_apply: Ignoring -source_mask") ;
3862        mri_free(im_tmask) ; im_tmask = NULL ;
3863      }
3864      if( dset_mast == NULL && dxyz_mast == 0.0 )
3865        INFO_message("You might want to use '-master' when using '-1D*_apply'") ;
3866      if( do_allcost ){  /* 19 Sep 2007 */
3867        do_allcost = 0 ;
3868        INFO_message("-allcost option illegal with -1D*_apply") ;
3869      }
3870    }
3871 
3872    /**--- if no base input, target should have more than 1 sub-brick ---**/
3873    /**    (I don't think anyone every uses this ability)                **/
3874 
3875    if( dset_base == NULL && apply_1D == NULL ){
3876      if( DSET_NVALS(dset_targ) == 1 )
3877        ERROR_exit("No base dataset AND source dataset has only 1 sub-brick") ;
3878 
3879      WARNING_message("No -base dataset: using sub-brick #0 of source") ;
3880      skip_first = 1 ;  /* don't register sub-brick #0 of targ to itself! */
3881    }
3882 
3883    /**-- check on interpolation codes --**/
3884 
3885    if( final_interp < 0 ) final_interp = interp_code ;  /* not used */
3886 
3887    if( got_interp && !got_final && apply_mode > 0 ){
3888      WARNING_message("you are applying a warp, AND you gave a -interp code;\n"
3889                      "            BUT for applying a warp to produce a dataset, it is\n"
3890                      "            always -final that matters ==> setting -final to %s" ,
3891                      INTERP_methname(interp_code) ) ;
3892      final_interp = interp_code ;
3893    }
3894 
3895    /* check for inconsistency between the interp_code for computing optimal
3896       parameters, and the final_interp for computing the output dataset    */
3897 
3898    if( (interp_code == MRI_NN       && final_interp != MRI_NN)       ||
3899        ( MRI_HIGHORDER(interp_code) && !MRI_HIGHORDER(final_interp) )  )
3900      WARNING_message("-interp is %s but -final is %s -- are you sure?",
3901                      INTERP_methname(interp_code) , INTERP_methname(final_interp) ) ;
3902 
3903    /*-- check if saving Pearson map is practicable [25 Jan 2021] --*/
3904 
3905    if( do_save_pearson_map && dset_base == NULL ){
3906      WARNING_message(
3907            "-PearSave option disabled -- you did not input a base dataset :(") ;
3908      do_save_pearson_map = 0 ;
3909    }
3910 
3911    /*--- load input datasets ---*/
3912 
3913    if( verb ) INFO_message("Loading datasets into memory") ;
3914 
3915    /*- target MUST be present -*/
3916 
3917    DSET_load(dset_targ) ; CHECK_LOAD_ERROR(dset_targ) ;
3918    nx_targ = DSET_NX(dset_targ) ; dx_targ = fabsf(DSET_DX(dset_targ)) ;
3919    ny_targ = DSET_NY(dset_targ) ; dy_targ = fabsf(DSET_DY(dset_targ)) ;
3920    nz_targ = DSET_NZ(dset_targ) ; dz_targ = fabsf(DSET_DZ(dset_targ)) ;
3921 
3922    nxyz_targ[0] = nx_targ; nxyz_targ[1] = ny_targ; nxyz_targ[2] = nz_targ;
3923    dxyz_targ[0] = dx_targ; dxyz_targ[1] = dy_targ; dxyz_targ[2] = dz_targ;
3924 
3925    if( nx_targ < 2 || ny_targ < 2 )
3926      ERROR_exit("Source dataset has nx=%d ny=%d ???",nx_targ,ny_targ) ;
3927 
3928    /*-- 07 Aug 2007: make target automask? --*/
3929 
3930    if( im_tmask == NULL && apply_1D == NULL ){  /* 01 Mar 2010: (almost) always make this mask */
3931 
3932      byte *mmm ; int ndil=auto_tdilation ;
3933      mmm = THD_automask( dset_targ ) ;  /* output = just a byte array */
3934      if( mmm == NULL )
3935        ERROR_exit("Can't make -source_automask for some reason :-(") ;
3936      im_tmask = mri_new_vol_empty( nx_targ,ny_targ,nz_targ , MRI_byte ) ;
3937      mri_fix_data_pointer( mmm , im_tmask ) ; /* attach byte array to MRI_IMAGE struct */
3938      if( ndil > 0 ){
3939        for( ii=0 ; ii < ndil ; ii++ ){
3940          THD_mask_dilate     ( nx_targ,ny_targ,nz_targ , mmm , 3, 2 ) ;
3941          THD_mask_fillin_once( nx_targ,ny_targ,nz_targ , mmm , 2 ) ;
3942        }
3943      }
3944      if( auto_tstring == NULL ){
3945        auto_tstring = (char *)malloc(sizeof(char)*32) ;
3946        sprintf(auto_tstring,"source_automask+%d",ndil) ;
3947      }
3948      ntmask = THD_countmask( im_tmask->nvox , mmm ) ;
3949      if( ntmask < 666 && auto_tmask )
3950        ERROR_exit("Too few (%d) voxels in %s :-(",ntmask,auto_tstring) ;
3951      if( verb > 1 )
3952        INFO_message("%d voxels in %s",ntmask,auto_tstring) ;
3953 
3954    } else if( im_tmask != NULL ){  /*-- check -source_mask vs. target --*/
3955 
3956      if( im_tmask->nx != nx_targ ||
3957          im_tmask->ny != ny_targ || im_tmask->nz != nz_targ )
3958        ERROR_exit("-source_mask and -source datasets "
3959                   "have different dimensions! :-(\n"
3960                   "Have: %d %d %d versus %d %d %d\n",
3961                   im_tmask->nx, im_tmask->ny , im_tmask->nz,
3962                   nx_targ, ny_targ, nz_targ) ;
3963    }
3964 
3965    /*-- load base dataset if defined --*/
3966 
3967    if( dset_base != NULL ){
3968 
3969      DSET_load(dset_base) ; CHECK_LOAD_ERROR(dset_base) ;
3970      im_base = mri_scale_to_float( DSET_BRICK_FACTOR(dset_base,0) ,
3971                                    DSET_BRICK(dset_base,0)         ) ;
3972      if( im_base == NULL )
3973        ERROR_exit("Cannot extract float image from base dataset :(") ;
3974 
3975      DSET_unload(dset_base) ;
3976      dx_base = fabsf(DSET_DX(dset_base)) ;
3977      dy_base = fabsf(DSET_DY(dset_base)) ;
3978      dz_base = fabsf(DSET_DZ(dset_base)) ;
3979      if( im_base->nx < 2 || im_base->ny < 2 )
3980        ERROR_exit("Base dataset has nx=%d ny=%d ???",im_base->nx,im_base->ny) ;
3981 
3982    } else {  /* no -base, so use target[0] as the base image */
3983 
3984      if( apply_mode == 0 )
3985        INFO_message("no -base option ==> base is #0 sub-brick of source") ;
3986      im_base = mri_scale_to_float( DSET_BRICK_FACTOR(dset_targ,0) ,
3987                                    DSET_BRICK(dset_targ,0)         ) ;
3988      if( im_base == NULL ) /* should not be possible */
3989        ERROR_exit("Cannot extract float image from source dataset :(") ;
3990      dx_base = dx_targ; dy_base = dy_targ; dz_base = dz_targ;
3991      if( do_cmass && apply_mode == 0 ){   /* 30 Jul 2007 */
3992        INFO_message("no base dataset ==> -cmass is disabled"); do_cmass = 0;
3993      }
3994 
3995    }
3996    nx_base = im_base->nx ;
3997    ny_base = im_base->ny ; nxy_base  = nx_base *ny_base ;
3998    nz_base = im_base->nz ; nvox_base = nxy_base*nz_base ;
3999 
4000    /*--- check base dimensions for reasonability ---*/
4001 
4002    if( nx_base < 9 || ny_base < 9 )
4003      ERROR_exit("Base volume i- and/or j-axis dimension < 9") ;
4004 
4005    /*-- check if there is some substance to the base image --*/
4006 
4007    if( !APPLYING ){                     /* 13 Mar 2017 */
4008      nnz = mri_nonzero_count(im_base) ;
4009      if( nnz < 100 )
4010        ERROR_exit("3dAllineate fails :: base image has only %d nonzero voxel%s (< 100)",
4011                   nnz , (nnz==1) ? "\0" : "s" ) ;
4012    }
4013 
4014    /*-- check if 3D volume of source is significantly bigger than
4015         volume of base; if so, use the max number of -twbest trials --*/
4016 
4017    if( twopass && tbest < PARAM_MAXTRIAL ){  /* 29 May 2021 */
4018      float vol_targ , vol_base ;
4019      vol_targ = (nx_targ*dx_targ)*(ny_targ*dy_targ)*(nz_targ*dz_targ) ;
4020      vol_base = (nx_base*dx_base)*(ny_base*dy_base)*(nz_base*dz_base) ;
4021      if( vol_targ > 1.3f*vol_base || big_cmass ){
4022        tbest = PARAM_MAXTRIAL ;
4023        if( verb > 1 )
4024          INFO_message("largeness ==> set -twobest %d",PARAM_MAXTRIAL) ;
4025      }
4026    }
4027 
4028    /*-- is this 2D image registration? --*/
4029 
4030    doing_2D = (nz_base == 1) ;          /* 28 Apr 2020 */
4031 
4032    /*--- Check emask for OK-ness [14 Feb 2013] ---*/
4033 
4034    if( apply_mode != 0 && emask != NULL ){
4035      INFO_message("-emask is ignored in apply mode") ;
4036      KILL_bytevec(emask) ;
4037    }
4038    if( emask != NULL && emask->nar != nvox_base )
4039      ERROR_exit("-emask doesn't match base dataset dimensions :-(") ;
4040 
4041    /*-- largest grid spacing in either dataset --*/
4042 
4043    dxyz_top = dx_base ;
4044    dxyz_top = MAX(dxyz_top,dy_base) ; dxyz_top = MAX(dxyz_top,dz_base) ;
4045    dxyz_top = MAX(dxyz_top,dx_targ) ;
4046    dxyz_top = MAX(dxyz_top,dy_targ) ; dxyz_top = MAX(dxyz_top,dz_targ) ;
4047 
4048    /*-- crop off negative voxels in the base? --*/
4049 
4050    if( do_zclip ){
4051      float *bar = MRI_FLOAT_PTR(im_base) ;
4052      for( ii=0 ; ii < nvox_base ; ii++ ) if( bar[ii] < 0.0f ) bar[ii] = 0.0f ;
4053    }
4054 
4055    /*-- x flip base for mirror check? [18 Jun 2019] --*/
4056 
4057    if( do_xflip_bset ){
4058       int nbx=im_base->nx, nby=im_base->ny, nbz=im_base->nz, nbyz = nby*nbz, ii,kk,koff,knnn ;
4059       float *bimar = MRI_FLOAT_PTR(im_base) , *tar ;
4060       tar = (float *)malloc(sizeof(float)*nbx) ;
4061       for( kk=0 ; kk < nbyz ; kk++ ){
4062         koff = kk*nbx ; knnn = koff+nbx-1 ;
4063         for( ii=0 ; ii < nbx ; ii++ ) tar[ii] = bimar[ii+koff] ; /* get row */
4064         for( ii=0 ; ii < nbx ; ii++ ) bimar[knnn-ii] = tar[ii] ; /* flip it */
4065       }
4066       free(tar) ;
4067       INFO_message("3dAllineate: x-flipped base dataset") ;
4068    }
4069 
4070    /*----- find the autobbox, and setup zero-padding -----*/
4071 
4072 #undef  MPAD
4073 #define MPAD 8
4074    if( zeropad ){
4075      float cv , *qar  ; int xpad,ypad,zpad,mpad ;
4076      cv = 0.33f * THD_cliplevel(im_base,0.33f) ;       /* set threshold */
4077      qim = mri_copy(im_base); qar = MRI_FLOAT_PTR(qim);
4078      for( ii=0 ; ii < qim->nvox ; ii++ ) if( qar[ii] < cv ) qar[ii] = 0.0f ;
4079 
4080      /* make padding depend on dataset size [22 May 2019] */
4081 
4082      xpad = nx_base/8; ypad = ny_base/8; zpad = nz_base/8; mpad = MPAD;
4083      if( mpad < xpad ) mpad = xpad ;
4084      if( mpad < ypad ) mpad = ypad ;
4085      if( mpad < zpad ) mpad = zpad ;
4086 
4087      /* find edges of box that contain supra-threshold contents */
4088 
4089      MRI_autobbox( qim, &pad_xm,&pad_xp, &pad_ym,&pad_yp, &pad_zm,&pad_zp ) ;
4090      mri_free(qim) ;
4091 #if 0
4092      if( verb > 1 ){
4093        INFO_message("bbox: xbot=%3d xtop=%3d nx=%3d",pad_xm,pad_xp,nx_base);
4094        INFO_message("    : ybot=%3d ytop=%3d ny=%3d",pad_ym,pad_yp,ny_base);
4095       if( nz_base > 1 )
4096        INFO_message("    : zbot=%3d ztop=%3d nz=%3d",pad_zm,pad_zp,nz_base);
4097      }
4098 #endif
4099 
4100      /* compute padding so that at least mpad all-zero slices on each face */
4101 
4102      pad_xm = mpad - pad_xm               ; if( pad_xm < 0 ) pad_xm = 0 ;
4103      pad_ym = mpad - pad_ym               ; if( pad_ym < 0 ) pad_ym = 0 ;
4104      pad_zm = mpad - pad_zm               ; if( pad_zm < 0 ) pad_zm = 0 ;
4105      pad_xp = mpad - (nx_base-1 - pad_xp) ; if( pad_xp < 0 ) pad_xp = 0 ;
4106      pad_yp = mpad - (ny_base-1 - pad_yp) ; if( pad_yp < 0 ) pad_yp = 0 ;
4107      pad_zp = mpad - (nz_base-1 - pad_zp) ; if( pad_zp < 0 ) pad_zp = 0 ;
4108      if( doing_2D ){ pad_zm = pad_zp = 0 ; }  /* don't z-pad 2D image! */
4109 
4110      zeropad = (pad_xm > 0 || pad_xp > 0 ||
4111                 pad_ym > 0 || pad_yp > 0 || pad_zm > 0 || pad_zp > 0) ;
4112 
4113      if( verb > 1 && apply_mode == 0 ){
4114        if( zeropad ){
4115          if( pad_xm > 0 || pad_xp > 0 )
4116            INFO_message("Zero-pad: xbot=%d xtop=%d",pad_xm,pad_xp) ;
4117          if( pad_ym > 0 || pad_yp > 0 )
4118            INFO_message("Zero-pad: ybot=%d ytop=%d",pad_ym,pad_yp) ;
4119          if( pad_zm > 0 || pad_zp > 0 )
4120            INFO_message("Zero-pad: zbot=%d ztop=%d",pad_zm,pad_zp) ;
4121        } else {
4122          INFO_message("Zero-pad: not needed (plenty of internal padding)") ;
4123        }
4124      }
4125 
4126      /* zeropad the base image at this point in spacetime? */
4127 
4128      if( zeropad ){
4129        int nxold=nx_base , nyold=ny_base , nzold=nz_base ;
4130        qim = mri_zeropad_3D( pad_xm,pad_xp , pad_ym,pad_yp ,
4131                                              pad_zm,pad_zp , im_base ) ;
4132        mri_free(im_base) ; im_base = qim ;
4133        nx_base = im_base->nx ;
4134        ny_base = im_base->ny ; nxy_base  = nx_base *ny_base ;
4135        nz_base = im_base->nz ; nvox_base = nxy_base*nz_base ;
4136 
4137        if( emask != NULL ){             /* also zeropad emask [14 Feb 2013] */
4138          byte *ezp = (byte *)EDIT_volpad( pad_xm,pad_xp ,
4139                                           pad_ym,pad_yp ,
4140                                           pad_zm,pad_zp ,
4141                                           nxold,nyold,nzold ,
4142                                           MRI_byte , emask->ar ) ;
4143          if( ezp == NULL )
4144            ERROR_exit("zeropad of emask fails !?!") ;  /* should not happen */
4145          free(emask->ar) ; emask->ar = ezp ; emask->nar = nvox_base ;
4146        }
4147 
4148      }
4149    }
4150 
4151    /*--- dimensions of the (possibly padded) base image ---*/
4152 
4153    nxyz_base[0] = nx_base; nxyz_base[1] = ny_base; nxyz_base[2] = nz_base;
4154    dxyz_base[0] = dx_base; dxyz_base[1] = dy_base; dxyz_base[2] = dz_base;
4155 
4156    /*-- orientation code for base --*/
4157 
4158    { THD_3dim_dataset *qset = (dset_base != NULL) ? dset_base : dset_targ ;
4159      xx_code = ORIENT_xyzint[ qset->daxes->xxorient ] ;
4160      yy_code = ORIENT_xyzint[ qset->daxes->yyorient ] ;
4161      zz_code = ORIENT_xyzint[ qset->daxes->zzorient ] ;
4162    }
4163 
4164    /*-- some 2D stuff --*/
4165 
4166    if( doing_2D ){  /* 2D input image */
4167      char *tnam ;
4168      twodim_code = zz_code ;
4169      tnam = (twodim_code == 1) ? "sagittal"         /* twodim_code = slice direction */
4170            :(twodim_code == 2) ? "coronal"
4171            :(twodim_code == 3) ? "axial"
4172            :                     "UNKNOWABLE" ;
4173      if( twodim_code < 1 || twodim_code > 3 )
4174        ERROR_exit("2D image: orientation is %s",tnam) ;
4175      else if( verb )
4176        ININFO_message("2D image registration: orientation is %s",tnam) ;
4177 
4178 #ifdef ALLOW_NWARP /*********************************************************/
4179      if( nwarp_pass ){ nwarp_fixaff = nwarp_fixmotK = nwarp_fixdepK = 1 ; }
4180 #endif /* ALLOW_NWARP */ /**************************************************/
4181    }
4182 
4183 #ifdef ALLOW_NWARP /*********************************************************/
4184    /* set parameter freeze directions for -nwarp_fix* now [07 Dec 2010] */
4185 
4186    if( nwarp_pass ){
4187      if( twodim_code ){ nwarp_fixmotK = nwarp_fixdepK = 1 ; }  /* 2D images: no out-of-plane stuff */
4188      if( nwarp_fixmotI ){
4189        switch( xx_code ){
4190          case 1: nwarp_fixmotX=1;break; case 2: nwarp_fixmotY=1;break; case 3: nwarp_fixmotZ=1;break;
4191        }
4192      }
4193      if( nwarp_fixmotJ ){
4194        switch( yy_code ){
4195          case 1: nwarp_fixmotX=1;break; case 2: nwarp_fixmotY=1;break; case 3: nwarp_fixmotZ=1;break;
4196        }
4197      }
4198      if( nwarp_fixmotK ){
4199        switch( zz_code ){
4200          case 1: nwarp_fixmotX=1;break; case 2: nwarp_fixmotY=1;break; case 3: nwarp_fixmotZ=1;break;
4201        }
4202      }
4203      if( nwarp_fixdepI ){
4204        switch( xx_code ){
4205          case 1: nwarp_fixdepX=1;break; case 2: nwarp_fixdepY=1;break; case 3: nwarp_fixdepZ=1;break;
4206        }
4207      }
4208      if( nwarp_fixdepJ ){
4209        switch( yy_code ){
4210          case 1: nwarp_fixdepX=1;break; case 2: nwarp_fixdepY=1;break; case 3: nwarp_fixdepZ=1;break;
4211        }
4212      }
4213      if( nwarp_fixdepK ){
4214        switch( zz_code ){
4215          case 1: nwarp_fixdepX=1;break; case 2: nwarp_fixdepY=1;break; case 3: nwarp_fixdepZ=1;break;
4216        }
4217      }
4218 
4219      if( nwarp_fixmotX && nwarp_fixmotY && nwarp_fixmotZ )
4220        ERROR_exit("-nwarp_fixmot has frozen all nonlinear warping parameters :-(") ;
4221 
4222      if( nwarp_fixdepX && nwarp_fixdepY && nwarp_fixdepZ )
4223        ERROR_exit("-nwarp_fixdep has frozen all nonlinear warping parameters :-(") ;
4224 
4225      if( (nwarp_fixmotX || nwarp_fixmotY || nwarp_fixmotZ ||
4226           nwarp_fixdepX || nwarp_fixdepY || nwarp_fixdepZ   ) &&
4227         !NONLINEAR_IS_POLY(nwarp_type)                           )
4228        ERROR_exit("-nwarp_fix... cannot be used with non-polynomial -nwarp types") ;
4229 
4230      if( verb ){
4231        if( nwarp_fixmotX ) ININFO_message("-nwarp: X motions are frozen") ;
4232        if( nwarp_fixmotY ) ININFO_message("-nwarp: Y motions are frozen") ;
4233        if( nwarp_fixmotZ ) ININFO_message("-nwarp: Z motions are frozen") ;
4234        if( nwarp_fixdepX ) ININFO_message("-nwarp: X dependencies are frozen") ;
4235        if( nwarp_fixdepY ) ININFO_message("-nwarp: Y dependencies are frozen") ;
4236        if( nwarp_fixdepZ ) ININFO_message("-nwarp: Z dependencies are frozen") ;
4237      }
4238    }
4239 #endif /* ALLOW_NWARP */ /**************************************************/
4240 
4241    /*----- check for base:target dimensionality mismatch -----*/
4242 
4243    if( !doing_2D && nz_targ == 1 )
4244      ERROR_exit("Can't register 2D source into 3D base :-(") ;
4245 
4246    if(  doing_2D && nz_targ >  1 )
4247      ERROR_exit("Can't register 3D source onto 2D base :-(") ;
4248 
4249 #ifdef ALLOW_NWARP /*********************************************************/
4250    if( doing_2D && nwarp_pass && !NONLINEAR_IS_POLY(nwarp_type) )
4251      ERROR_exit("Can't use non-polynomial -nwarp on 2D images :: see 3dQwarp") ;
4252 #endif /* ALLOW_NWARP */ /**************************************************/
4253 
4254    /*----- load user-supplied weight dataset if defined -----*/
4255 
4256    if( dset_weig != NULL ){
4257 
4258 STATUS("load weight dataset") ;
4259      DSET_load(dset_weig) ; CHECK_LOAD_ERROR(dset_weig) ;
4260      im_weig = mri_scale_to_float( DSET_BRICK_FACTOR(dset_weig,0) ,
4261                                    DSET_BRICK(dset_weig,0)         ) ;
4262      DSET_unload(dset_weig) ;
4263      if( im_weig == NULL )
4264        ERROR_exit("Cannot extract float image from weight dataset :(") ;
4265 
4266      /* zeropad weight to match base? */
4267 
4268      if( zeropad ){
4269 STATUS("zeropad weight dataset") ;
4270        qim = mri_zeropad_3D( pad_xm,pad_xp , pad_ym,pad_yp ,
4271                                              pad_zm,pad_zp , im_weig ) ;
4272        mri_free(im_weig) ; im_weig = qim ;
4273      }
4274      if( im_weig->nx != nx_base ||
4275          im_weig->ny != ny_base || im_weig->nz != nz_base )
4276        ERROR_exit("-weight and base volumes don't match in 3D grid dimensions :-(") ;
4277 
4278      /*-- convert to 0..1 range [23 Mar 2017] --*/
4279      { float clip=0.0f, *wf=MRI_FLOAT_PTR(im_weig); int ii,nxyz=im_weig->nvox;
4280        for( ii=0 ; ii < nxyz ; ii++ ) if( wf[ii] > clip ) clip = wf[ii] ;
4281        if( clip == 0.0f )
4282          ERROR_exit("Input -weight is never positive!") ;
4283        clip = 1.0f / clip ;
4284        for( ii=0 ; ii < nxyz ; ii++ ) wf[ii] *= clip ;
4285      }
4286                              /*-----------------------------------------------*/
4287    } else if( auto_weight ){ /* manufacture weight from base = the USUAL case */
4288 
4289      if( meth_noweight[meth_code-1] && auto_weight == 1 && auto_wclip == 0.0f ){
4290        WARNING_message("Cost function '%s' ('%s') uses -automask NOT -autoweight",
4291                        meth_longname[meth_code-1] , meth_shortname[meth_code-1] ) ;
4292        auto_weight = 2 ;
4293      } else if( verb > 1 ){
4294        INFO_message("Computing %s",auto_string) ;
4295      }
4296      if( verb > 1 ) ctim = COX_cpu_time() ;
4297      /*-- here is where the default weight volume is created --*/
4298      im_weig = mri_weightize(im_base,auto_weight,auto_dilation,auto_wclip,auto_wpow) ;
4299      if( verb > 1 ) INFO_message("%s net CPU time = %.1f s" ,
4300                                  auto_string , COX_cpu_time()-ctim ) ;
4301    }
4302 
4303    /*--- Apply the emask to the weight volume [14 Feb 2013] ---*/
4304 
4305    if( emask != NULL ){
4306      float *war ; byte *ear=emask->ar ; int near=0 ;
4307 
4308      if( im_weig == NULL ){  /* no weight volume ==> make one up */
4309        im_weig = mri_new_conforming(im_base,MRI_float) ;  /* all zero */
4310        war = MRI_FLOAT_PTR(im_weig) ;
4311        for( ii=0 ; ii < nvox_base ; ii++ ){
4312          if( ear[ii] == 0 ) war[ii] = 1.0f ; else near++ ;
4313        }
4314 
4315      } else {                /* edit existing weight volume */
4316        war = MRI_FLOAT_PTR(im_weig) ;
4317        for( ii=0 ; ii < nvox_base ; ii++ ){
4318          if( ear[ii] != 0 && war[ii] != 0.0f ){ war[ii] = 0.0f ; near++ ; }
4319        }
4320 
4321      }
4322      if( verb ) INFO_message("-emask excludes %d voxels from weight/mask",near) ;
4323      KILL_bytevec(emask) ;
4324    }
4325 
4326    /*-- also, make a binary mask from the weight (not used much, if at all) --*/
4327 
4328    if( im_weig != NULL ){
4329      float *wf = MRI_FLOAT_PTR(im_weig) ;
4330      byte  *mf ;
4331      im_mask = mri_new_conforming(im_weig,MRI_byte) ;
4332      mf = MRI_BYTE_PTR(im_mask) ;
4333      for( ii=0 ; ii < im_mask->nvox ; ii++ ) mf[ii] = (wf[ii] > 0.0f) ;
4334      nmask = THD_countmask(im_mask->nvox,mf) ;
4335      if( verb > 1 ) INFO_message("%d voxels [%.1f%%] in weight mask",
4336                                  nmask, 100.0*nmask/(float)im_mask->nvox ) ;
4337      if( !APPLYING && nmask < 100 )
4338        ERROR_exit("3dAllineate fails: not enough voxels in weight mask") ;
4339 
4340    } else {
4341      nmask = nvox_base ;  /* the universal 'mask' */
4342    }
4343    if( usetemp ) mri_purge(im_mask) ;
4344 
4345    /*--- save weight into a dataset? [mostly for "fun"] ---*/
4346 
4347    if( wtprefix != NULL && im_weig != NULL ){
4348      THD_3dim_dataset *wset ;
4349      wset = EDIT_empty_copy( (dset_base!=NULL) ? dset_base : dset_targ ) ;
4350      EDIT_dset_items( wset ,
4351                         ADN_prefix    , wtprefix ,
4352                         ADN_nvals     , 1 ,
4353                         ADN_ntt       , 0 ,
4354                         ADN_datum_all , MRI_float ,
4355                       ADN_none ) ;
4356      EDIT_BRICK_FACTOR(wset,0,0.0);
4357      if( zeropad ) qim = mri_zeropad_3D( -pad_xm,-pad_xp , -pad_ym,-pad_yp ,
4358                                          -pad_zm,-pad_zp , im_weig ) ;
4359      else          qim = mri_copy(im_weig) ;
4360      EDIT_substitute_brick( wset, 00, MRI_float, MRI_FLOAT_PTR(qim) );
4361      mri_clear_data_pointer(qim) ; mri_free(qim) ;
4362      DSET_write(wset); if( verb ) WROTE_DSET(wset);
4363      DSET_delete(wset) ;
4364    }
4365 
4366    /*--- initialize ntask, regardless     26 Aug 2008 [rickr] ---*/
4367    ntask = DSET_NVOX(dset_targ) ;
4368    ntask = (ntask < nmask) ? (int)sqrt(ntask*(double)nmask) : nmask ;
4369 
4370    /*--- number of points to use for matching base to target ---*/
4371 
4372    if( nmask_frac < 0 ){
4373       if( npt_match < 0     ) npt_match = (int)(-0.01f*npt_match*ntask) ;
4374       if( npt_match < 9999  ) npt_match = 9999 ;
4375       if( npt_match > ntask ) npt_match = ntask ;
4376    } else {
4377       npt_match = (int)(nmask_frac*(double)nmask);
4378    }
4379    if( verb > 1 && apply_mode == 0 )
4380      INFO_message("Number of points for matching = %d",npt_match) ;
4381 
4382    /*----------------------------------------------------------*/
4383    /*---------- setup alignment structure parameters ----------*/
4384    /*- the stup struct controls much of the alignment process -*/
4385    /*-- see mrilib.h for definition of this masterful struct --*/
4386    /*----------------------------------------------------------*/
4387 
4388    memset(&stup,0,sizeof(GA_setup)) ;  /* NULL out */
4389 
4390    stup.match_code = meth_code ;
4391    stup.usetemp    = usetemp ;     /* 20 Dec 2006 */
4392 
4393    stup.hist_mode  = hist_mode ;   /* 08 May 2007 */
4394    stup.hist_param = hist_param ;
4395 
4396    /*-- spatial coordinates: 'cmat' transforms from ijk to xyz --*/
4397    /*--                      'c' means coordinates are output  --*/
4398 
4399    if( !ISVALID_MAT44(dset_targ->daxes->ijk_to_dicom) )
4400      THD_daxes_to_mat44(dset_targ->daxes) ;
4401    stup.targ_cmat = DSET_CMAT(dset_targ,use_realaxes) ; /* source dset */
4402 
4403    /*-- base coordinates are drawn from it's header, or are same as target --*/
4404 
4405    if( dset_base != NULL ){                        /* base dset coords */
4406 
4407      float bdet , tdet ;
4408 
4409      if( !ISVALID_MAT44(dset_base->daxes->ijk_to_dicom) )
4410        THD_daxes_to_mat44(dset_base->daxes) ;
4411      stup.base_cmat = DSET_CMAT(dset_base,use_realaxes) ;
4412 
4413      /** check if handedness of source and base are the same; **/
4414      /** this check is purely advisory -- it is not a problem **/
4415 
4416      bdet = MAT44_DET(stup.base_cmat) ; /* sign of determinant */
4417      tdet = MAT44_DET(stup.targ_cmat) ; /* determines handedness */
4418      if( bdet * tdet < 0.0f ){          /* AHA - opposite signs! */
4419        INFO_message("NOTE: base and source coordinate systems have different handedness") ;
4420        ININFO_message(
4421          "      Orientations: base=%s handed (%c%c%c); source=%s handed (%c%c%c)" ,
4422          (bdet < 0.0f) ? "Left" : "Right" ,
4423            ORIENT_typestr[dset_base->daxes->xxorient][0] ,
4424            ORIENT_typestr[dset_base->daxes->yyorient][0] ,
4425            ORIENT_typestr[dset_base->daxes->zzorient][0] ,
4426          (tdet < 0.0f) ? "Left" : "Right" ,
4427            ORIENT_typestr[dset_targ->daxes->xxorient][0] ,
4428            ORIENT_typestr[dset_targ->daxes->yyorient][0] ,
4429            ORIENT_typestr[dset_targ->daxes->zzorient][0]  ) ;
4430        ININFO_message(
4431          "    - It is nothing to worry about: 3dAllineate aligns based on coordinates." ) ;
4432        ININFO_message(
4433          "    - But it is always important to check the alignment visually to be sure." ) ;
4434      }
4435 
4436    } else {
4437      stup.base_cmat = stup.targ_cmat ;  /* base coords == source coords */
4438    }
4439 
4440    /*----- for the local correlation methods:
4441            set the blok type (RHDD, etc), and the blok radius -----*/
4442 
4443    stup.blokset = NULL ;
4444    if( METH_USES_BLOKS(meth_code) || do_allcost || do_save_pearson_map ){
4445 #ifdef USE_OLD_BLOK_DEFAULTS
4446      float mr = 1.23f * ( MAT44_COLNORM(stup.base_cmat,0)
4447                          +MAT44_COLNORM(stup.base_cmat,1)
4448                          +MAT44_COLNORM(stup.base_cmat,2) ) ;
4449      if( blokrad < mr ) blokrad = mr ;
4450 #else
4451      float idel = MAT44_COLNORM(stup.base_cmat,0) ; /* length of step in i */
4452      float jdel = MAT44_COLNORM(stup.base_cmat,1) ; /* length of step in j */
4453      float kdel = MAT44_COLNORM(stup.base_cmat,2) ; /* length of step in k */
4454      float vvv  = idel*jdel*kdel ;                  /* volume of base voxel */
4455      /** compute blokrad so that 555 base voxels are contained in one blok **/
4456      blokrad = cbrtf( 555.0f * vvv / GA_BLOK_VOLFAC(bloktype) ) ;
4457 #endif
4458      stup.bloktype = bloktype ; stup.blokrad = blokrad ; stup.blokmin = 0 ;
4459      if( verb ) INFO_message("Local correlation: blok type = '%s(%g)'",
4460                              GA_BLOK_STRING(bloktype) , blokrad        ) ;
4461    }
4462 
4463    /*-- setup for a matching functional that combines multiple methods --*/
4464 
4465    if( meth_code == GA_MATCH_LPC_MICHO_SCALAR ||
4466        meth_code == GA_MATCH_LPA_MICHO_SCALAR   ){
4467      if( verb )
4468        INFO_message("%s parameters: hel=%.2f mi=%.2f nmi=%.2f crA=%.2f ov=%.2f %s",
4469                     meth_shortname[meth_code-1] ,
4470                     micho_hel , micho_mi , micho_nmi , micho_crA , micho_ov ,
4471                     micho_zfinal ? "[to be zeroed at Final iteration]" : "\0" ) ;
4472      GA_setup_micho( micho_hel , micho_mi , micho_nmi , micho_crA , micho_ov ) ;
4473      if( micho_zfinal ) do_refinal = 1 ;  /* this must be turned on for +ZZ */
4474    }
4475 
4476    /*-- modify base_cmat to allow for zeropad? --*/
4477 
4478    if( pad_xm > 0 || pad_ym > 0 || pad_zm > 0 )
4479      MAT44_EXTEND_IJK( stup.base_cmat , pad_xm,pad_ym,pad_zm ) ;
4480 
4481    /*-- compute inverse of cmats (cmat = index-to-coord)
4482         which will give the coord-to-index transformations --*/
4483 
4484    targ_cmat = stup.targ_cmat; targ_cmat_inv = MAT44_INV(targ_cmat); /* 23 Jul 2007 */
4485    base_cmat = stup.base_cmat; base_cmat_inv = MAT44_INV(base_cmat);
4486 
4487    /*---------- define warp 'before' and 'after' matrices ----------*/
4488 
4489    AL_setup_warp_coords( epi_targ,epi_fe,epi_pe,epi_se,
4490                          nxyz_base, dxyz_base, stup.base_cmat,
4491                          nxyz_targ, dxyz_targ, stup.targ_cmat ) ;
4492 
4493    /*----------- define warp parameters and function -----------*/
4494    /* that is, the mapping from parameters to the matrix itself */
4495 
4496    mri_genalign_affine_setup( matorder , dcode , smat ) ;
4497 
4498    stup.wfunc       = mri_genalign_affine ;  /* warping function in mri_genalign.c */
4499    stup.wfunc_param = (GA_param *)calloc(12,sizeof(GA_param)) ;
4500 
4501 #ifdef ALLOW_NWARP /*********************************************************/
4502    if( nwarp_pass && warp_code != WARP_AFFINE ){
4503      WARNING_message("Use of -nwarp ==> must allow all 12 affine parameters") ;
4504      warp_code = WARP_AFFINE ;
4505    }
4506 #endif /* ALLOW_NWARP */ /**************************************************/
4507 
4508    /*--- how many parameters will be used for affine transformation (3D) ---*/
4509 
4510    switch( warp_code ){
4511      case WARP_SHIFT:  stup.wfunc_numpar =  3; strcpy(warp_code_string,"shift_only")        ; break;
4512      case WARP_ROTATE: stup.wfunc_numpar =  6; strcpy(warp_code_string,"shift_rotate")      ; break;
4513      case WARP_SCALE:  stup.wfunc_numpar =  9; strcpy(warp_code_string,"shift_rotate_scale"); break;
4514      case WARP_AFFINE: stup.wfunc_numpar = 12; strcpy(warp_code_string,"affine_general")    ; break;
4515    }
4516 
4517    /*-- check if -1Dapply_param is giving us enough parameters for this warp --*/
4518 
4519    if( apply_1D != NULL ){
4520      if( apply_mode == APPLY_PARAM && apply_nx < stup.wfunc_numpar )
4521        ERROR_exit(
4522          "-1Dparam_apply '%s': %d isn't enough parameters per row for desired warp",
4523          apply_1D,apply_nx);
4524 
4525      if( apply_ny < DSET_NVALS(dset_targ) )
4526        WARNING_message(
4527         "-1D*_apply '%s': %d isn't enough rows for source dataset -- last row will repeat",
4528         apply_1D,apply_ny);
4529    }
4530 
4531    /*------------------------------------------------------------------------*/
4532    /*--------- macro to set up control values for a given parameter ---------*/
4533 
4534 #define DEFPAR(p,nm,bb,tt,id,dd,ll)               \
4535  do{ stup.wfunc_param[p].min      = (bb) ;        \
4536      stup.wfunc_param[p].max      = (tt) ;        \
4537      stup.wfunc_param[p].delta    = (dd) ;        \
4538      stup.wfunc_param[p].toler    = (ll) ;        \
4539      stup.wfunc_param[p].ident    = (id) ;        \
4540      stup.wfunc_param[p].val_init = (id) ;        \
4541      stup.wfunc_param[p].val_pinit= (id) ;        \
4542      stup.wfunc_param[p].val_fixed= (id) ;        \
4543      stup.wfunc_param[p].val_out  = (id) ;        \
4544      strcpy( stup.wfunc_param[p].name , (nm) ) ;  \
4545      stup.wfunc_param[p].fixed  = 0 ;             \
4546  } while(0)
4547 
4548    /*-- compute range of shifts allowed --*/
4549 
4550    xxx = 0.321f * (nx_base-1) ; /* about 1/3 of base */
4551    yyy = 0.321f * (ny_base-1) ;
4552    zzz = 0.321f * (nz_base-1) ; xxx_m = yyy_m = zzz_m = 0.01f ;
4553    /* transform 8 corners of a cube from index space to DICOM */
4554    /* space, and then find largest coordinates that happen */
4555    for( ii=-1 ; ii <= 1 ; ii+=2 ){
4556     for( jj=-1 ; jj <= 1 ; jj+=2 ){
4557       for( kk=-1 ; kk <= 1 ; kk+=2 ){
4558         MAT33_VEC( base_cmat , (ii*xxx),(jj*yyy),(kk*zzz) ,
4559                    xxx_p,yyy_p,zzz_p ) ;
4560         xxx_p = fabsf(xxx_p); yyy_p = fabsf(yyy_p); zzz_p = fabsf(zzz_p);
4561         xxx_m = MAX(xxx_m,xxx_p);
4562         yyy_m = MAX(yyy_m,yyy_p); zzz_m = MAX(zzz_m,zzz_p);
4563    }}}
4564    xxx = xxx_m ; yyy = yyy_m ; zzz = zzz_m ;  /* largest coords seen */
4565 
4566    /*-- 30 Jul 2007: center-of-mass sets range of shifts --*/
4567    /*-- 26 Feb 2020: always compute, maybe not use       --*/
4568 
4569    if( 1 || do_cmass ){
4570      float xtarg,ytarg,ztarg , xbase,ybase,zbase ;
4571 
4572      mri_get_cmass_3D( im_base , &xc,&yc,&zc ) ;  /* cmass in indexes */
4573      MAT44_VEC( base_cmat , xc,yc,zc , xbase,ybase,zbase ) ;
4574      if( verb > 1 )
4575        INFO_message("base center of mass = %.3f %.3f %.3f (index)",xc,yc,zc) ;
4576      im_targ = THD_median_brick( dset_targ ) ; /* if more than 1 source volume */
4577      mri_get_cmass_3D( im_targ , &xc,&yc,&zc ) ; mri_free(im_targ) ;
4578      if( verb > 1 )
4579        ININFO_message("source center of mass = %.3f %.3f %.3f (index)",xc,yc,zc) ;
4580      MAT44_VEC( targ_cmat , xc,yc,zc , xtarg,ytarg,ztarg ) ;
4581      /* center of mass shifts */
4582      xxc = xc = xtarg-xbase ; yyc = yc = ytarg-ybase ; zzc = zc = ztarg-zbase ;
4583      if( verb > 1 )
4584        ININFO_message("source-target CM = %.3f %.3f %.3f (xyz)",xc,yc,zc) ;
4585      if (do_cmass < 0) {
4586          /* try to figure what is OK, for partial coverage */
4587          if (fabs(xc) >= fabs(yc) && fabs(xc) >= fabs(zc)) {
4588             if (     fabs(xc) > 4.0          /* more than 4 voxels */
4589                   && fabs(xc) > 2.0*fabs(yc) /* more than twice the 2nd */
4590                   && fabs(xc) > 2.0*fabs(zc) /* more than twice the 3rd */) {
4591                xc = 0.0f;
4592                if( verb > 1 ) ININFO_message("  automatic -cmass disables x-shift") ;
4593             }
4594          } else if (fabs(yc) >= fabs(xc) && fabs(yc) >= fabs(zc)) {
4595             if (     fabs(yc) > 4.0          /* more than 4 voxels */
4596                   && fabs(yc) > 2.0*fabs(xc) /* more than twice the 2nd */
4597                   && fabs(yc) > 2.0*fabs(zc) /* more than twice the 3rd */) {
4598                yc = 0.0f;
4599                if( verb > 1 ) ININFO_message("  automatic -cmass disables y-shift") ;
4600             }
4601          } else if (fabs(zc) >= fabs(xc) && fabs(zc) >= fabs(yc)) {
4602             if (     fabs(zc) > 4.0          /* more than 4 voxels */
4603                   && fabs(zc) > 2.0*fabs(xc) /* more than twice the 2nd */
4604                   && fabs(zc) > 2.0*fabs(yc) /* more than twice the 3rd */) {
4605                zc = 0.0f;
4606                if( verb > 1 ) ININFO_message("  automatic -cmass disables z-shift") ;
4607             }
4608          }
4609      } else {  /* check do_cmass as a binary mask for which coords to use */
4610         if( (do_cmass & 1) == 0 ) xc = 0.0f ;
4611         if( (do_cmass & 2) == 0 ) yc = 0.0f ;
4612         if( (do_cmass & 4) == 0 ) zc = 0.0f ;
4613      }
4614      if( do_cmass && verb > 1 && apply_mode == 0 ){
4615        ININFO_message("estimated center of mass shifts = %.3f %.3f %.3f",xc,yc,zc) ;
4616      }
4617    } else {
4618      xc = yc = zc = 0.0f ; /* this code is currently unreachable */
4619    }
4620 
4621    /* WARNING message if unused cmass shifts are large compared to search range */
4622    /*         large = 20-49%  terribly large = 50+%                             */
4623 
4624    if( 1 ){                 /* 29 May 2021 */
4625      float rrr ;
4626      rrr = fabsf(xxc)/xxx ; CMbad += (rrr < 0.20f) ? 0 : (rrr < 0.5f) ? 1 : 100 ;
4627      rrr = fabsf(yyc)/yyy ; CMbad += (rrr < 0.20f) ? 0 : (rrr < 0.5f) ? 1 : 100 ;
4628      rrr = fabsf(zzc)/zzz ; CMbad += (rrr < 0.20f) ? 0 : (rrr < 0.5f) ? 1 : 100 ;
4629      big_cmass = (CMbad > 2) ;
4630    }
4631 
4632    if( !do_cmass ){         /* 26 Feb 2020 */
4633      if( CMbad > 0 && CMbad < 100 ){
4634        WARNING_message("center of mass shifts (-cmass) are turned off, but would be large") ;
4635        WARNING_message("  - at least one is more than 20%% of search range") ;
4636      } else if( CMbad >= 100 ){
4637        WARNING_message("center of mass shifts (-cmass) are turned off, but would be TERRIBLY large!") ;
4638        WARNING_message("  - at least one is more than 50%% of search range") ;
4639      }
4640 
4641      ININFO_message("       -cmass x y z shifts = %8.3f %8.3f %8.3f",xxc,yyc,zzc) ;
4642      ININFO_message(" shift search range is +/- = %8.3f %8.3f %8.3f",xxx,yyy,zzz) ;
4643      if( CMbad > 0 ){
4644        ININFO_message("                             %7.1f%% %7.1f%% %7.1f%%",
4645                       100.0f*fabsf(xxc)/xxx, 100.0f*fabsf(yyc)/yyy,100.0f*fabsf(zzc)/zzz  ) ;
4646      }
4647 
4648      xc = yc = zc = 0.0f ; /* pleonastic, to be safe */
4649    }
4650 
4651    /*-- use a smaller than normal range for parameter search? --*/
4652 
4653    if( do_small ){ xxx *= 0.5f ; yyy *= 0.5f ; zzz *= 0.5f ; }
4654    xxx_p = xc + xxx ; xxx_m = xc - xxx ;
4655    yyy_p = yc + yyy ; yyy_m = yc - yyy ;
4656    zzz_p = zc + zzz ; zzz_m = zc - zzz ;
4657 
4658    if( do_cmass && verb > 1 && apply_mode == 0 )
4659      INFO_message("shift param auto-range: %.1f..%.1f %.1f..%.1f %.1f..%.1f",
4660                   xxx_m,xxx_p , yyy_m,yyy_p , zzz_m,zzz_p ) ;
4661 
4662    /*-- now define all 12 affine parameters in stup; not all may be used --*/
4663 
4664    /* shifts = the first 3 */
4665 
4666    DEFPAR( 0, "x-shift" , xxx_m , xxx_p , 0.0 , 0.0 , 0.0 ) ;    /* mm */
4667    DEFPAR( 1, "y-shift" , yyy_m , yyy_p , 0.0 , 0.0 , 0.0 ) ;
4668    DEFPAR( 2, "z-shift" , zzz_m , zzz_p , 0.0 , 0.0 , 0.0 ) ;
4669    if( do_cmass ){                                            /* 31 Jul 2007 */
4670      if( nx_base > 1 ) stup.wfunc_param[0].val_pinit = xc ;
4671      if( ny_base > 1 ) stup.wfunc_param[1].val_pinit = yc ;
4672      if( nz_base > 1 ) stup.wfunc_param[2].val_pinit = zc ;
4673    }
4674 
4675    /*-- now the other 9 affine parameters --*/
4676 
4677    { float rval,sval ;
4678 
4679      /*-- angles = the next 3 --*/
4680 
4681      rval = (do_small) ? 15.0f : 30.0 ;
4682      DEFPAR( 3, "z-angle" , -rval , rval , 0.0 , 0.0 , 0.0 ) ;  /* degrees */
4683      DEFPAR( 4, "x-angle" , -rval , rval , 0.0 , 0.0 , 0.0 ) ;
4684      DEFPAR( 5, "y-angle" , -rval , rval , 0.0 , 0.0 , 0.0 ) ;
4685 
4686      /*-- scales = the next 3 --*/
4687 
4688      rval = (do_small) ? 0.85f : 0.711f ; sval = 1.0f / rval ;
4689      DEFPAR( 6, "x-scale" , rval , sval , 1.0 , 0.0 , 0.0 ) ;  /* identity */
4690      DEFPAR( 7, "y-scale" , rval , sval , 1.0 , 0.0 , 0.0 ) ;  /*  == 1.0 */
4691      DEFPAR( 8, "z-scale" , rval , sval , 1.0 , 0.0 , 0.0 ) ;
4692 
4693      /* shears = the final 3:
4694         The code below (for shear params) was modified 16 Jul 2014, to
4695         correct the labels (per user Mingbo) for the various EPI/FPS cases;
4696         see the usage of the 'a', 'b', 'c' parameters in defining the shear
4697         matrix 'ss' in function GA_setup_affine() in file mri_genalign.c.  */
4698 
4699      { char *alab , *blab , *clab ;
4700        switch( smat ){
4701          default:       alab = "y/x-shear" ; blab = "z/x-shear" ; clab = "z/y-shear" ; break ;
4702          case SMAT_XXX: alab = "y/x-shear" ; blab = "z/x-shear" ; clab = "unused"    ; break ;
4703          case SMAT_YYY: alab = "y/x-shear" ; blab = "z/y-shear" ; clab = "unused"    ; break ;
4704          case SMAT_ZZZ: alab = "z/x-shear" ; blab = "z/y-shear" ; clab = "unused"    ; break ;
4705        }
4706        rval = (do_small) ? 0.0555f : 0.1111f ;
4707        DEFPAR(  9, alab , -rval , rval , 0.0 , 0.0 , 0.0 ) ;
4708        DEFPAR( 10, blab , -rval , rval , 0.0 , 0.0 , 0.0 ) ;
4709        DEFPAR( 11, clab , -rval , rval , 0.0 , 0.0 , 0.0 ) ;
4710      }
4711    }
4712 
4713    /*-- adjustments for 2D images --*/
4714 
4715    if( twodim_code > 0 ){               /* 03 Dec 2010 */
4716      int i1=0,i2=0,i3=0,i4=0,i5=0,i6=0 ;
4717      switch( twodim_code ){             /* 2D images: freeze some parameters */
4718        case 3:                               /* axial slice == k-axis is I-S */
4719          i1=3 ; i2=5 ; i3=6 ; i4=9 ; i5=11 ; i6=12 ; break ;
4720        case 2:                             /* coronal slice == k-axis is A-P */
4721          i1=2 ; i2=4 ; i3=5 ; i4=8 ; i5=10 ; i6=12 ; break ;
4722        case 1:                            /* sagittal slice == k-axis is L-R */
4723          i1=1 ; i2=4 ; i3=6 ; i4=7 ; i5=10 ; i6=11 ; break ;
4724      }
4725      if( i1 > 0 ){
4726        stup.wfunc_param[i1-1].fixed = 2 ; /* fixed==2 means cannot be unfixed */
4727        stup.wfunc_param[i2-1].fixed = 2 ; /* fixed==1 is 'temporarily fixed'  */
4728        stup.wfunc_param[i3-1].fixed = 2 ;
4729        stup.wfunc_param[i4-1].fixed = 2 ;
4730        stup.wfunc_param[i5-1].fixed = 2 ;
4731        stup.wfunc_param[i6-1].fixed = 2 ;
4732        if( verb && apply_mode == 0 )
4733          INFO_message("base dataset is 2D ==> froze out-of-plane affine parameters") ;
4734      }
4735    }
4736 
4737    /*-- apply any parameter-altering user commands --*/
4738 
4739    for( ii=0 ; ii < nparopt ; ii++ ){  /* loop over parameter-altering opts */
4740 
4741      jj = paropt[ii].np ;              /* which parameter? */
4742 
4743      if( jj < stup.wfunc_numpar ){
4744 
4745        if( stup.wfunc_param[jj].fixed && verb )
4746          ININFO_message("Altering fixed param#%d [%s]" ,
4747                         jj+1 , stup.wfunc_param[jj].name ) ;
4748 
4749        switch( paropt[ii].code ){      /* which option was given? */
4750 
4751          case PARC_FIX: stup.wfunc_param[jj].fixed     = 2 ; /* permanent fix */
4752                         stup.wfunc_param[jj].val_fixed = paropt[ii].vb;
4753          if( verb > 1 )
4754            ININFO_message("Fix param#%d [%s] = %f",
4755                           jj+1 , stup.wfunc_param[jj].name ,
4756                                  stup.wfunc_param[jj].val_fixed ) ;
4757          break;
4758 
4759          case PARC_INI: stup.wfunc_param[jj].fixed     = 0 ;  /* initial val */
4760                         stup.wfunc_param[jj].val_fixed =
4761                         stup.wfunc_param[jj].val_init  =
4762                         stup.wfunc_param[jj].val_pinit = paropt[ii].vb;
4763          if( verb > 1 )
4764            ININFO_message("Init param#%d [%s] = %f",
4765                           jj+1 , stup.wfunc_param[jj].name ,
4766                                  stup.wfunc_param[jj].val_pinit ) ;
4767          break;
4768 
4769          case PARC_RAN:{                   /* parameter search range to allow */
4770            float vb = paropt[ii].vb , vt = paropt[ii].vt ;
4771            if( do_cmass ){  /* 06 Aug 2007 */
4772              switch(jj){
4773                case 0: vb += xc ; vt += xc ; break ;
4774                case 1: vb += yc ; vt += yc ; break ;
4775                case 2: vb += zc ; vt += zc ; break ;
4776              }
4777            }
4778            /** stup.wfunc_param[jj].fixed = 0 ; **/
4779            stup.wfunc_param[jj].min   = vb;
4780            stup.wfunc_param[jj].max   = vt;
4781            if( verb > 1 )
4782              ININFO_message("Range param#%d [%s] = %f .. %f  center = %f",
4783                             jj+1 , stup.wfunc_param[jj].name ,
4784                                    stup.wfunc_param[jj].min  ,
4785                                    stup.wfunc_param[jj].max  ,
4786                     0.5f*(stup.wfunc_param[jj].min+stup.wfunc_param[jj].max) );
4787          }
4788          break;
4789 
4790        }
4791 
4792      } else {  /* this means the user is a doofus or a wizard */
4793        WARNING_message("Can't alter parameter #%d: out of range :-(",jj+1) ;
4794      }
4795 
4796    } /* end of loop over parameter-altering options */
4797 
4798    /*-- check to see if we have free parameters so we can actually do something --*/
4799 
4800    for( ii=jj=0 ; jj < stup.wfunc_numpar ; jj++ )  /* count free params */
4801      if( !stup.wfunc_param[jj].fixed ) ii++ ;
4802    if( ii == 0 ) ERROR_exit("No free parameters for aligning datasets?! :-(") ;
4803    nparam_free = ii ;
4804    if( verb > 1 && apply_mode == 0 ) ININFO_message("%d free parameters",ii) ;
4805 
4806    /*-- should have some free parameters in the first 6 if using twopass --*/
4807    /*----- [This situation has never arisen in all recorded history!] -----*/
4808 
4809    if( twopass ){
4810      for( ii=jj=0 ; jj < stup.wfunc_numpar && jj < 6 ; jj++ )
4811        if( !stup.wfunc_param[jj].fixed ) ii++ ;
4812      if( ii == 0 ){
4813        WARNING_message("Disabling twopass because no free parameters in first 6!?");
4814        twopass = 0 ;
4815      }
4816    }
4817 
4818    /*---- set normalized convergence radius for parameter search ----*/
4819 
4820    /* get size of box we are dealing with */
4821    if( im_weig == NULL ){
4822      xsize = xxx = 0.5f * (nx_base-1) * dx_base ;  /* no weight means all  */
4823      ysize = yyy = 0.5f * (ny_base-1) * dy_base ;  /* voxels are available */
4824      zsize = zzz = 0.5f * (nz_base-1) * dz_base ;  /* for use in alignment */
4825    } else {
4826      int xm,xp , ym,yp , zm,zp ; /* otherwise, get size of the weight mask */
4827      MRI_autobbox_clust(0) ;
4828      MRI_autobbox( im_weig , &xm,&xp , &ym,&yp , &zm,&zp ) ;
4829      MRI_autobbox_clust(1) ;
4830      xsize = xxx = 0.5f * (xp-xm) * dx_base ;
4831      ysize = yyy = 0.5f * (yp-ym) * dy_base ;
4832      zsize = zzz = 0.5f * (zp-zm) * dz_base ;
4833    }
4834    /* convert box size to a single size */
4835    xxx = (nz_base > 1) ? cbrt(xxx*yyy*zzz) : sqrt(xxx*yyy) ;
4836    zzz = 0.01f ;  /* smallest normalized value */
4837    for( jj=0 ; jj < 9 && jj < stup.wfunc_numpar ; jj++ ){ /* loop over params */
4838      if( stup.wfunc_param[jj].fixed ) continue ;             /* except shears */
4839      siz = stup.wfunc_param[jj].max - stup.wfunc_param[jj].min ; /* par range */
4840      if( siz <= 0.0f ) continue ;                      /* skip this parameter */
4841 
4842         /* normalization = conv_mm scaled by mm size of the param range since */
4843         /*     optimization is done on unitless params scaled to [0..1] range */
4844         /* mm size of param range is                                          */
4845         /*     shift is in mm already, siz is in mm,                          */
4846         /*                             so conv_mm/siz is ratio of convergence */
4847         /*                             criterion to parameter range, which    */
4848         /*                             in turn is the range of the unitless   */
4849         /*                             [0..1] parameter -- got that?          */
4850         /*     angle is in degrees, so siz/57.3 is in radians                 */
4851         /*                          so xxx*siz/57.3 is in mm,                 */
4852         /*                          so conv_mm/(xx*siz/57.3) is ratio         */
4853         /*     scale is unitless, so siz*xxx is in mm                         */
4854           if( jj < 3 ) yyy = conv_mm / siz ;                   /* shift param */
4855      else if( jj < 6 ) yyy = 57.3f * conv_mm / (xxx*siz) ;     /* angle param */
4856      else              yyy = conv_mm / (xxx*siz) ;             /* scale param */
4857      zzz = MIN(zzz,yyy) ;               /* smallest scaled value found so far */
4858    }
4859    conv_rad = MIN(zzz,0.001f); conv_rad = MAX(conv_rad,0.000005f);  /* limits */
4860    if( verb > 1 && apply_mode == 0 )
4861      INFO_message("Normalized (unitless) convergence radius = %.7f",conv_rad) ;
4862 
4863    /*---- print parameter search ranges [10 Mar 2020] ----*/
4864 
4865    if( verb > 1 ){
4866      INFO_message("Final parameter search ranges:") ;
4867      for( jj=0 ; jj < stup.wfunc_numpar ; jj++ ){
4868        if( !stup.wfunc_param[jj].fixed )
4869          ININFO_message(" %12s = %8.3f .. %8.3f",
4870                         stup.wfunc_param[jj].name ,
4871                         stup.wfunc_param[jj].min  ,
4872                         stup.wfunc_param[jj].max   ) ;
4873      }
4874    }
4875 
4876 #ifdef ALLOW_NWARP /*********************************************************/
4877    /*-- special case: 04 Apr 2008 --*/
4878 
4879    switch( apply_mode ){  /* all this is for -nwarp inputs (obsolescent) */
4880      default:                                  break ;
4881      case APPLY_BILIN: SETUP_BILINEAR_PARAMS ; break ;
4882      case APPLY_CUBIC: SETUP_CUBIC_PARAMS    ; break ;
4883      case APPLY_QUINT: SETUP_QUINT_PARAMS    ; break ;
4884      case APPLY_HEPT : SETUP_HEPT_PARAMS     ; break ;
4885      case APPLY_NONI : SETUP_NONI_PARAMS     ; break ;
4886    }
4887 #endif /* ALLOW_NWARP */ /**************************************************/
4888 
4889    /*----------------------------------------------------*/
4890    /***--- creeping up on actually doing something! ---***/
4891    /*****------ create shell of output dataset ------*****/
4892 
4893    if( prefix == NULL ){
4894      WARNING_message("No output dataset will be calculated") ;
4895      if( dxyz_mast > 0.0 )
4896        WARNING_message("-mast_dxyz %g option was meaningless :-(",dxyz_mast) ;
4897    } else {
4898      if( dset_mast == NULL ){ /* pick a master dataset to control output grid */
4899        if( dset_base != NULL ){
4900          if( verb ) INFO_message("master dataset for output = base") ;
4901          dset_mast = dset_base ;
4902        } else {
4903          if( verb ) INFO_message("master dataset for output = source") ;
4904          dset_mast = dset_targ ;
4905        }
4906      }
4907      if( dxyz_mast > 0.0 ){   /* 24 Jul 2007 -- alter grid size */
4908        THD_3dim_dataset *qset ;
4909        qset = r_new_resam_dset( dset_mast , NULL ,
4910                                 dxyz_mast,dxyz_mast,dxyz_mast ,
4911                                 NULL , RESAM_NN_TYPE , NULL , 0 , 0) ;
4912        if( qset != NULL ){
4913          dset_mast = qset ;
4914          THD_daxes_to_mat44(dset_mast->daxes) ;
4915          if( verb )
4916            INFO_message("changing output grid spacing to %.4f mm",dxyz_mast) ;
4917        }
4918      }
4919      if( !ISVALID_MAT44(dset_mast->daxes->ijk_to_dicom) ) /* make sure have */
4920        THD_daxes_to_mat44(dset_mast->daxes) ;      /* index-to-DICOM matrix */
4921      mast_cmat     = DSET_CMAT(dset_mast,use_realaxes) ;
4922      mast_cmat_inv = MAT44_INV(mast_cmat) ;
4923 
4924      dset_out = EDIT_empty_copy( dset_mast ) ;  /* create the output dataset! */
4925      EDIT_dset_items( dset_out ,                /* and patch it up */
4926                         ADN_prefix    , prefix ,
4927                         ADN_nvals     , DSET_NVALS(dset_targ) ,
4928                         ADN_datum_all , MRI_float ,
4929                       ADN_none ) ;
4930      /* do not let time info from master confuse things, we'll go back */
4931      /* to ntt > 1 later, if approprate             [1 Jun 2020 rickr] */
4932      if( DSET_NUM_TIMES(dset_out) > 1 )
4933          EDIT_dset_items( dset_out ,   ADN_ntt , 1 , ADN_none ) ;
4934 
4935        if( DSET_NUM_TIMES(dset_targ) > 1 )
4936          EDIT_dset_items( dset_out ,
4937                             ADN_ntt   , DSET_NVALS(dset_targ) ,
4938                             ADN_ttdel , DSET_TR(dset_targ) ,
4939                             ADN_tunits, UNITS_SEC_TYPE ,
4940                             ADN_nsl   , 0 ,
4941                           ADN_none ) ;
4942        else
4943          EDIT_dset_items( dset_out ,
4944                             ADN_func_type , ISANAT(dset_out) ? ANAT_BUCK_TYPE
4945                                                              : FUNC_BUCK_TYPE ,
4946                           ADN_none ) ;
4947 
4948      /* copy brick info into output */
4949 
4950      THD_copy_datablock_auxdata( dset_targ->dblk , dset_out->dblk ) ;
4951      if (!THD_copy_labeltable_atr( dset_out->dblk,  dset_targ->dblk)) {
4952       WARNING_message("Failed trying to preserve labeltables");
4953      }
4954      for( kk=0 ; kk < DSET_NVALS(dset_out) ; kk++ )
4955        EDIT_BRICK_FACTOR(dset_out,kk,0.0);
4956 
4957      tross_Copy_History( dset_targ , dset_out ) ;        /* historic records */
4958      tross_Make_History( "3dAllineate" , argc,argv , dset_out ) ;
4959 
4960      memset(&cmat_tout,0,sizeof(mat44)) ;
4961      memset(&cmat_bout,0,sizeof(mat44)) ;
4962      THD_daxes_to_mat44(dset_out->daxes) ;          /* save coord transforms */
4963      cmat_tout = DSET_CMAT(dset_targ,use_realaxes) ;
4964      cmat_bout = DSET_CMAT(dset_out ,use_realaxes) ;
4965      nxout = DSET_NX(dset_out) ; dxout = fabsf(DSET_DX(dset_out)) ;
4966      nyout = DSET_NY(dset_out) ; dyout = fabsf(DSET_DY(dset_out)) ;
4967      nzout = DSET_NZ(dset_out) ; dzout = fabsf(DSET_DZ(dset_out)) ;
4968      nxyz_dout[0] = nxout; nxyz_dout[1] = nyout; nxyz_dout[2] = nzout;
4969      dxyz_dout[0] = dxout; dxyz_dout[1] = dyout; dxyz_dout[2] = dzout;
4970    }
4971 
4972 #ifdef ALLOW_NWARP /*********************************************************/
4973    /*-- check if have dataset prefix for saving the 3D warp --*/
4974 
4975    if( dset_out == NULL && nwarp_save_prefix != NULL ){
4976      WARNING_message("Can't use -nwarp_save without -prefix! :-(") ;
4977      nwarp_save_prefix = NULL ;
4978    }
4979 #endif /* ALLOW_NWARP */ /**************************************************/
4980 
4981    /***~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~***/
4982    /***---------------------- start alignment process ----------------------***/
4983    /***~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~***/
4984 
4985 #ifdef USE_OMP
4986 #pragma omp parallel
4987  {
4988   if( verb && omp_get_thread_num() == 0 )
4989     INFO_message("OpenMP thread count = %d",omp_get_num_threads()) ;
4990  }
4991 #endif
4992 
4993 /*------- macros useful for verbosity -------*/
4994 
4995 /* print all parameters from stup, on one line, with a string ss */
4996 
4997 #undef  PARDUMP  /* xxx = field name in param */
4998 #define PARDUMP(ss,xxx)                                     \
4999   do{ fprintf(stderr," + %s Parameters =",ss) ;             \
5000       for( jj=0 ; jj < stup.wfunc_numpar ; jj++ ){          \
5001         if( jj == 12 ) fprintf(stderr," |") ;               \
5002         fprintf(stderr," %.4f",stup.wfunc_param[jj].xxx) ;  \
5003       }                                                     \
5004       fprintf(stderr,"\n") ;                                \
5005   } while(0)
5006 
5007 /* print the output parameters */
5008 
5009 #undef  PAROUT
5010 #define PAROUT(ss) PARDUMP(ss,val_out)
5011 
5012 /* print the input parameters */
5013 
5014 #undef  PARINI
5015 #define PARINI(ss) PARDUMP(ss,val_init)
5016 
5017 /* print a parameter vector, not from stup */
5018 
5019 #undef  PARVEC
5020 #define PARVEC(ss,vv)                              \
5021   do{ fprintf(stderr," + %s Parameters =",ss) ;    \
5022       for( jj=0 ; jj < stup.wfunc_numpar ; jj++ )  \
5023         fprintf(stderr," %.4f",vv[jj]) ;           \
5024       fprintf(stderr,"\n") ;                       \
5025   } while(0)
5026 
5027 /* copy parameter set 'xxx' from stup to the
5028    allpar array, for ease of use in calling other functions */
5029 
5030 #undef  PAR_CPY
5031 #define PAR_CPY(xxx)                              \
5032   do{ for( jj=0 ; jj < stup.wfunc_numpar ; jj++ ) \
5033         allpar[jj] = stup.wfunc_param[jj].xxx ;   \
5034   } while(0)
5035 
5036 /*----- for the beautiful final output of parameters, with commentary -----*/
5037 
5038 #undef  PARLIST
5039 #define PARLIST(ss,xxx)                                     \
5040   do{ fprintf(stderr," + %s Parameters:\n    ",ss) ;        \
5041       for( jj=0 ; jj < stup.wfunc_numpar ; jj++ ){          \
5042         if( jj > 0 && jj%3 == 0 ) fprintf(stderr,"\n    "); \
5043         fprintf(stderr," %9s=%8.4f",                        \
5044      stup.wfunc_param[jj].name,stup.wfunc_param[jj].xxx) ;  \
5045         if( jj == 2 )                                              \
5046          fprintf(stderr,"  ...  enorm=%8.4f mm",                   \
5047           sqrt( stup.wfunc_param[0].xxx*stup.wfunc_param[0].xxx    \
5048                +stup.wfunc_param[1].xxx*stup.wfunc_param[1].xxx    \
5049                +stup.wfunc_param[2].xxx*stup.wfunc_param[2].xxx)); \
5050         else if( jj == 5 )                                  \
5051          fprintf(stderr,"  ...  total=%8.4f deg",           \
5052           total_rotation_degrees(stup.wfunc_param[3].xxx,   \
5053                                  stup.wfunc_param[4].xxx,   \
5054                                  stup.wfunc_param[5].xxx)); \
5055         else if( jj == 8 ){                                 \
5056          float fff = stup.wfunc_param[6].xxx                \
5057                     *stup.wfunc_param[7].xxx                \
5058                     *stup.wfunc_param[8].xxx ;              \
5059          fprintf(stderr,"  ...  vol3D=%8.4f=(%.4f)^3 %s",   \
5060            fff , cbrt(fff) ,                                \
5061            (fff < 0.97f )                                   \
5062             ? "[base bigger than source]"                   \
5063           :(fff > 1.03f )                                   \
5064             ? "[base smaller than source]"                  \
5065             : "[base about same as source]" ) ;             \
5066         }                                                   \
5067       }                                                     \
5068       fprintf(stderr,"\n") ;                                \
5069   } while(0)
5070 
5071 #undef  PARNOUT
5072 #define PARNOUT(ss) PARLIST(ss,val_out)   /* 30 Aug 2013 */
5073 
5074    /*--------------------------- the Annunciation ---------------------------*/
5075 
5076    if( do_allcost >= 0 && verb ){
5077      if( apply_1D == NULL )
5078        INFO_message("======= Allineation of %d sub-bricks using %s =======",
5079                     DSET_NVALS(dset_targ) , meth_username[meth_code-1] ) ;
5080      else
5081        INFO_message("========== Applying transformation to %d sub-bricks ==========",
5082                     DSET_NVALS(dset_targ) ) ;
5083    }
5084 
5085    if( verb > 1 ) mri_genalign_verbose(verb-1) ; /* verbosity in mri_genalign.c */
5086 
5087    /*-- array in which to save parameters for later waterboarding --*/
5088 
5089    if( param_save_1D != NULL || apply_mode != APPLY_AFF12 )
5090      parsave = (float **)calloc(sizeof(float *),DSET_NVALS(dset_targ)) ;
5091 
5092 #ifdef ALLOW_NWARP /*********************************************************/
5093    if( !NONLINEAR_APPLY(apply_mode) ){                                  /* 04 Apr 2008 */
5094     if( matrix_save_1D != NULL || apply_mode != APPLY_AFF12  )
5095       matsave = (mat44 * )calloc(sizeof(mat44),DSET_NVALS(dset_targ)) ; /* 23 Jul 2007 */
5096    }
5097 #else
5098     if( matrix_save_1D != NULL || apply_mode != APPLY_AFF12  )
5099       matsave = (mat44 * )calloc(sizeof(mat44),DSET_NVALS(dset_targ)) ; /* 23 Jul 2007 */
5100 #endif /* ALLOW_NWARP */ /**************************************************/
5101 
5102 /*--- as you might guess, this is for saving joint histogram to a file ---*/
5103 /*--- which is only done by the excessively inquisitive type of users  ---*/
5104 #undef  SAVEHIST
5105 #define SAVEHIST(nnn,docc)                                                 \
5106  do{ int nbin ; float *xyc ;                                               \
5107      if( docc ) (void)mri_genalign_scalar_cost( &stup , NULL ) ;           \
5108      nbin = retrieve_2Dhist( &xyc ) ;                                      \
5109      if( nbin > 0 && xyc != NULL ){                                        \
5110        char fname[256] ; MRI_IMAGE *fim ; double ftop ;                    \
5111        fim = mri_new(nbin,nbin,MRI_float); mri_fix_data_pointer(xyc,fim);  \
5112        if( strstr(save_hist,"FF") == NULL ){                               \
5113          ftop = mri_max(fim) ; qim = mri_to_byte_scl(255.4/ftop,0.0,fim) ; \
5114          mri_clear_data_pointer(fim); mri_free(fim);                       \
5115          fim = mri_flippo(MRI_ROT_90,0,qim); mri_free(qim);                \
5116          sprintf(fname,"%s_%s_%04d.pgm",save_hist,nnn,kk) ;                \
5117          mri_write_pnm(fname,fim); mri_free(fim);                          \
5118        } else {                                                            \
5119          qim = mri_flippo(MRI_ROT_90,0,fim);                               \
5120          mri_clear_data_pointer(fim); mri_free(fim);                       \
5121          sprintf(fname,"%s_%s_%04d.mri",save_hist,nnn,kk) ;                \
5122          mri_write(fname,qim); mri_free(qim);                              \
5123        }                                                                   \
5124        if( verb ) ININFO_message("- Saved histogram to %s",fname) ;        \
5125      }                                                                     \
5126  } while(0)
5127 
5128    /***==================== loop over target sub-bricks ====================***/
5129 
5130    im_bset = im_base ;  /* base image for first loop */
5131    im_wset = im_weig ;
5132 
5133    /** 3dUnifize the base image? [23 Dec 2016] **/
5134 
5135 #ifdef ALLOW_UNIFIZE
5136    if( do_unifize_base && dset_base != NULL && nz_base > 5 && apply_1D == NULL ){
5137      THD_3dim_dataset *qset, *uset ;
5138      char *uuu, bname[32], uname[32] , cmd[1024] ;
5139      float *bar , urad ;
5140 
5141      uuu = UNIQ_idcode_11() ;
5142      sprintf(uname,"UU.%s.nii",uuu) ;
5143      sprintf(bname,"BB.%s.nii",uuu) ;
5144 
5145      qset = THD_image_to_dset(im_bset,bname) ;
5146      qset->dblk->diskptr->storage_mode = STORAGE_BY_NIFTI ;
5147      DSET_write(qset) ;
5148 
5149      urad = 18.3f / cbrtf(dx_base*dy_base*dz_base) ;
5150           if( urad < 5.01f ) urad = 5.01f ;
5151      else if( urad > 23.3f ) urad = 23.3f ;
5152      sprintf(cmd,
5153              "3dUnifize -input %s -prefix %s -T2 -Urad %.2f -clfrac 0.333",
5154              bname , uname , urad ) ;
5155      INFO_message("About to do -unifize_base:\n  %s",cmd) ;
5156      system(cmd) ;
5157      THD_delete_3dim_dataset(qset,True) ;
5158 
5159      uset = THD_open_dataset(uname) ;
5160      if( uset == NULL ){
5161        WARNING_message("-unifize_base failed :(") ;
5162      } else {
5163        DSET_load(uset) ;
5164        if( !DSET_LOADED(uset) ){
5165          WARNING_message("-unifize_base did something weird :((") ;
5166        } else {
5167          im_bset = im_ubase = mri_copy(DSET_BRICK(uset,0)) ;
5168        }
5169        THD_delete_3dim_dataset(uset,True) ;
5170      }
5171    } /* end of -unifize_base */
5172 #endif  /* ALLOW_UNIFIZE */
5173 
5174    /*--- for filling the outside of the target mask with random crap ---*/
5175 
5176    stup.ajmask_ranfill = 0 ;                          /* 02 Mar 2010: oops */
5177    if( im_tmask != NULL ){
5178      mri_genalign_set_targmask( im_tmask , &stup ) ;  /* 07 Aug 2007 */
5179      mri_free(im_tmask) ; im_tmask = NULL ;           /* is copied inside */
5180      if( fill_source_mask ) stup.ajmask_ranfill = 1 ; /* 01 Mar 2010 */
5181    }
5182 
5183    /*--- for the overlap portion of lpc+ and lpa+ [latter no longer applies] ---*/
5184 
5185    if( !APPLYING && micho_ov != 0.0 ){
5186      byte *mmm ; int ndil=auto_tdilation ; MRI_IMAGE *bsm ;
5187      mmm = mri_automask_image(im_base) ;
5188      if( mmm != NULL ){
5189        bsm = mri_new_vol_empty( nx_base,ny_base,nz_base , MRI_byte ) ;
5190        mri_fix_data_pointer( mmm , bsm ) ;
5191        if( ndil > 0 ){
5192          for( ii=0 ; ii < ndil ; ii++ ){
5193            THD_mask_dilate     ( nx_base,ny_base,nz_base , mmm , 3, 2 ) ;
5194            THD_mask_fillin_once( nx_base,ny_base,nz_base , mmm , 2 ) ;
5195          }
5196        }
5197        mri_genalign_set_basemask( bsm , &stup ) ;
5198        mri_free(bsm) ;
5199      }
5200    }
5201 
5202    MEMORY_CHECK("about to start alignment loop") ;
5203 
5204    /*-- blurring in coarse pass must not be 0 if using BLOKs --*/
5205 
5206    if( sm_rad == 0.0f &&
5207        ( meth_code == GA_MATCH_PEARSON_LOCALS   ||
5208          meth_code == GA_MATCH_LPC_MICHO_SCALAR ||
5209          meth_code == GA_MATCH_LPA_MICHO_SCALAR ||
5210          meth_code == GA_MATCH_PEARSON_LOCALA     ) ) sm_rad = MAX(2.222f,dxyz_top) ;
5211 
5212    /*-- lpa method gets more twobest checks [27 May 2021] --*/
5213 
5214    if( METH_IS_LPA(meth_code) && tbest < DEFAULT_TBEST_LPA )
5215      tbest = DEFAULT_TBEST_LPA ;
5216 
5217    /*----------- process the target dataset volumes, one at a time -----------*/
5218 
5219    for( kk=0 ; kk < DSET_NVALS(dset_targ) ; kk++ ){  /** the sub-brick loop **/
5220 
5221      stup.match_code = meth_code ;  /* the cost functional code */
5222 
5223      ZERO_MAT44(aff12_xyz) ; /* 23 Jul 2007: invalidate the matrix */
5224 
5225      bfac = DSET_BRICK_FACTOR(dset_targ,kk) ;  /* sub-brick scale factor [14 Oct 2008] */
5226 
5227      skipped = 0 ;
5228      if( kk == 0 && skip_first ){  /* skip first image since it == im_base */
5229 
5230        if( verb )
5231          INFO_message("========= Skipping sub-brick #0: it's also base image =========");
5232        DSET_unload_one(dset_targ,0) ;
5233 
5234        /*-- load parameters with identity transform --*/
5235 
5236        for( jj=0 ; jj < stup.wfunc_numpar ; jj++ )   /* for -1Dfile output */
5237          stup.wfunc_param[jj].val_out = stup.wfunc_param[jj].ident ;
5238 
5239        /*-- load aff12_xyz matrix with identity transform [23 Jul 2007] --*/
5240 
5241        LOAD_DIAG_MAT44(aff12_xyz,1.0f,1.0f,1.0f) ;
5242        skipped = 1 ; goto WRAP_IT_UP_BABY ; /* where params/matrix will be used */
5243 
5244      } /* end of skipping first volume */
5245 
5246      /*-- show if verbose, else use light output     7 Jul 2017 [rickr] -- */
5247      if( verb > 1 )
5248        INFO_message("========== sub-brick #%d ========== [total CPU to here=%.1f s]",
5249                     kk , COX_cpu_time() ) ;
5250      else if ( verb && DSET_NVALS(dset_targ) > 1 ) {
5251        if( kk == 0 ) fprintf(stderr,"volume 0");
5252        else          fprintf(stderr,"..%d", kk);
5253        if( kk == DSET_NVALS(dset_targ)-1 ) fputc('\n', stderr);
5254      }
5255 
5256 
5257      /*-- make copy of target brick, and process that --*/
5258 
5259      im_targ = mri_scale_to_float( bfac , DSET_BRICK(dset_targ,kk) ) ;
5260      if( im_targ == NULL )  /* this is bad news, but also very improbable */
5261        ERROR_exit("Cannot extract float image from source dataset :(") ;
5262 
5263      if( targ_was_vector ){  /* 12 May 2020 (for RGB images) */
5264        if( im_targ_vector != NULL ) mri_free(im_targ_vector) ;
5265        im_targ_vector = mri_copy( DSET_BRICK(dset_targ,kk) ) ;  /* for use at end */
5266      }
5267      DSET_unload_one(dset_targ,kk) ; /* it's been copied in, so can unload it now */
5268 
5269      /*-- clip off negative values from the target? --*/
5270 
5271      if( do_zclip ){
5272        float *bar = MRI_FLOAT_PTR(im_targ) ;
5273        for( ii=0 ; ii < im_targ->nvox ; ii++ ) if( bar[ii] < 0.0f ) bar[ii] = 0.0f ;
5274      }
5275 
5276      /*-- check for empty-ish volume --*/
5277 
5278      nnz = mri_nonzero_count(im_targ) ;
5279      if( nnz < 66 )
5280        WARNING_message("3dAllineate :: source image #%d has only %d nonzero voxel%s (< 66)",
5281                        kk , nnz , (nnz==1) ? "\0" : "s" ) ;
5282 
5283      /*** if we are just applying input parameters, set up for that now ***/
5284      /*** we set output params as if they had been found by optimizing  ***/
5285 
5286      if( apply_1D != NULL ){ /* apply_1D = filename of params/matrix to apply */
5287        int rr=kk ;
5288        if( rr >= apply_ny ){  /* 19 Jul 2007 */
5289          rr = apply_ny-1 ;
5290          WARNING_message("Re-using final row of -1D*_apply '%s' for sub-brick #%d",
5291                          apply_1D , kk ) ;
5292        }
5293        stup.interp_code = final_interp ;  /* this IS the final operation */
5294        stup.smooth_code = 0 ;
5295        stup.npt_match   = 11 ;   /* this is just some small positive number */
5296        mri_genalign_scalar_setup( im_bset , NULL , im_targ , &stup ) ;
5297        im_bset = NULL ;  /* after setting base, don't need to set it again */
5298        mri_free(im_targ) ; im_targ = NULL ;
5299 
5300        /* store the parameters to apply OR the matrix to apply,
5301           then jump down to the end of the optimization phases,
5302           where these values will be used for something useful */
5303 
5304        switch( apply_mode ){   /* 23 Jul 2007 */
5305          default:
5306 #ifdef ALLOW_NWARP /*********************************************************/
5307          case APPLY_BILIN:
5308 #endif /* ALLOW_NWARP */ /**************************************************/
5309          case APPLY_PARAM:     /* load parameters from file into structure */
5310            if( verb > 1 ) INFO_message("using -1Dparam_apply") ;
5311            for( jj=0 ; jj < stup.wfunc_numpar ; jj++ )
5312              stup.wfunc_param[jj].val_out = APL(jj,rr) ;
5313          break ;
5314 
5315          case APPLY_AFF12:     /* load matrix from file into aff12_xyz */
5316            if( verb > 1 ) INFO_message("using -1Dmatrix_apply") ;
5317            LOAD_MAT44_AR( aff12_xyz , &APL(0,rr) ) ;    /* DICOM coord matrix */
5318          break ;
5319        }
5320        goto WRAP_IT_UP_BABY ;  /* all roads lead to WRAP_IT_UP_BABY */
5321      }
5322 
5323      /*--- at this point, am actually going to do optimization!! ---*/
5324 
5325      /*-- initialize parameters (for the -onepass case) --*/
5326 
5327      for( jj=0 ; jj < stup.wfunc_numpar ; jj++ )
5328        stup.wfunc_param[jj].val_init = stup.wfunc_param[jj].val_pinit ;
5329 
5330      /* initialize coordinate systems */
5331 
5332      AL_setup_warp_coords( epi_targ,epi_fe,epi_pe,epi_se,
5333                            nxyz_base, dxyz_base, stup.base_cmat,
5334                            nxyz_targ, dxyz_targ, stup.targ_cmat ) ;
5335 
5336      /*--- print all cost functionals, for fun? ---*/
5337 
5338      if( do_allcost != 0 ){
5339 
5340        stup.interp_code = MRI_LINEAR ;
5341        stup.npt_match   = npt_match ;
5342        if( do_allcost < 0 && fine_rad > 0.0f ){
5343          stup.smooth_code        = sm_code ;
5344          stup.smooth_radius_base = stup.smooth_radius_targ = fine_rad ;
5345        }
5346 
5347        mri_genalign_scalar_setup( im_bset , im_wset , im_targ , &stup ) ;
5348 
5349        if( allcostX1D == NULL ){ /* just do init parameters == the old way */
5350 
5351          PAR_CPY(val_init) ;   /* copy init parameters into the allpar arrary */
5352          allcost = mri_genalign_scalar_allcosts( &stup , allpar ) ;
5353          PARINI("initial") ;
5354          INFO_message("allcost output: init #%d",kk) ;
5355          for( jj=0 ; jj < GA_MATCH_METHNUM_SCALAR ; jj++ )
5356            fprintf(stderr,"   %-4s = %g\n",meth_shortname[jj],allcost->ar[jj]) ;
5357          KILL_floatvec(allcost) ;
5358 
5359          if( do_allcost == -1 ){
5360            SAVE_PEARSON_MAP(save_pearson_prefix,val_init) ;
5361            do_save_pearson_map = 0 ;
5362          }
5363 
5364          if( save_hist != NULL ) SAVEHIST("allcost_init",0) ;
5365          if( do_allcost == -1 ) continue ;  /* skip to next sub-brick */
5366 
5367        } else {  /* 02 Sep 2008: do a bunch of parameter vectors [for Ziad] */
5368 
5369          float *av=MRI_FLOAT_PTR(allcostX1D); int nxp=allcostX1D->nx; FILE *fp;
5370 
5371          if( strcmp(allcostX1D_outname,"-")      == 0 ||
5372              strcmp(allcostX1D_outname,"stdout") == 0   ){
5373            fp = stdout ;
5374          } else {
5375            fp = fopen( allcostX1D_outname , "w" ) ;
5376            if( fp == NULL )
5377              ERROR_exit("Can't open file '%s' for -allcostX1D output :-(" ,
5378                         allcostX1D_outname ) ;
5379          }
5380          INFO_message("Writing -allcostX1D results to '%s'",allcostX1D_outname) ;
5381          fprintf( fp , "# 3dAllineate -allcostX1D results:\n" ) ;
5382          fprintf( fp , "#" ) ;
5383          for( jj=0 ; jj < GA_MATCH_METHNUM_SCALAR ; jj++ )
5384            fprintf( fp , "  ___ %-4s ___",meth_shortname[jj]) ;
5385          fprintf( fp , "\n") ;
5386          for( ii=0 ; ii < allcostX1D->ny ; ii++ ){
5387            allcost = mri_genalign_scalar_allcosts( &stup , av + ii*nxp ) ;
5388            fprintf( fp , " " ) ;
5389            for( jj=0 ; jj < GA_MATCH_METHNUM_SCALAR ; jj++ )
5390              fprintf( fp , " %12.6f" , allcost->ar[jj] ) ;
5391            fprintf( fp , "\n") ;
5392            KILL_floatvec(allcost) ;
5393            if( save_hist != NULL ){
5394              char fn[32] ; sprintf(fn,"allcost%06d",ii) ; SAVEHIST(fn,0) ;
5395            }
5396          }
5397          if( fp != stdout ) fclose(fp) ;
5398          INFO_message("-allcostX1D finished") ; exit(0) ;
5399        }
5400 
5401      } /* end of -allcost stuff at the startup of optimization */
5402 
5403      /*-------- do coarse resolution pass? --------*/
5404 
5405      didtwo = 0 ;
5406      if( twopass && (!twofirst || !tfdone) ){
5407 
5408        int tb , ib , ccode , nrand ; char *eee ;
5409 
5410        if( verb ) INFO_message("*** Coarse pass begins ***") ;
5411        /* used to do NN in the coarse pass, but found that Linear worked better; */
5412        /* we still keep NN if ordered by user with -interp option, which would   */
5413        /* be done if trying to use 3dAllineate to align ROI masks (e.g.) - weird */
5414 
5415        ccode            = (interp_code == MRI_NN) ? MRI_NN : MRI_LINEAR ;
5416        stup.interp_code = ccode ;
5417        stup.npt_match   = ntask / 15 ;  /* small number of matching points */
5418        if( stup.npt_match < nmatch_setup ) stup.npt_match = nmatch_setup;
5419 
5420        /*- smoothing to use for coarse pass -*/
5421 
5422        stup.smooth_code        = sm_code ;
5423        stup.smooth_radius_base =
5424         stup.smooth_radius_targ = (sm_rad == 0.0f) ? 7.777f : sm_rad ;
5425 
5426        /*- setup the parameters for evaluation and optimization -*/
5427 
5428        mri_genalign_scalar_setup( im_bset , im_wset , im_targ , &stup ) ;
5429        im_bset = NULL; im_wset = NULL;  /* after being set, needn't set again */
5430        if( usetemp ){
5431          mri_purge(im_targ); mri_purge(im_base); mri_purge(im_weig);
5432        }
5433 
5434        if( save_hist != NULL ) SAVEHIST("start",1) ; /* for weird users */
5435 
5436        /*-- search for coarse start parameters, then optimize them? --*/
5437 
5438        if( tbest > 0 ){  /* tbest = result of -twobest option */
5439          int nrefine ;
5440 
5441          if( verb > 1 ) ININFO_message("- Search for coarse starting parameters") ;
5442 
5443          /*- startup search only allows up to 6 parameters, so freeze excess; -*/
5444          /*- all this complication below was for testing alternate strategies -*/
5445          /*- but those proved to be fairly fruitless (as I recall)            -*/
5446 
5447          eee = my_getenv("AFNI_TWOPASS_NUM") ;  /* normally, eee is NULL */
5448          if( eee == NULL || *eee != ':' ){      /* so this branch is taken */
5449            if( eee != NULL ) sscanf( eee , "%d" , &nptwo ) ;
5450            if( nptwo < 1 || nptwo > 6 ) nptwo = 6 ;   /* default = use 6 params */
5451            if( nparam_free > nptwo ){  /* old way: just free first nptwo params */
5452              for( ii=jj=0 ; jj < stup.wfunc_numpar ; jj++ ){
5453                if( !stup.wfunc_param[jj].fixed ){
5454                  ii++ ;  /* number free so far */
5455                  if( ii > nptwo ) stup.wfunc_param[jj].fixed = 1 ;  /* temp freeze */
5456                }
5457              }
5458            }
5459          } else {                      /* the new way: free from a list */
5460            int npk[6]={-1,-1,-1,-1,-1,-1} ;
5461            sscanf( eee , ":%d:%d:%d:%d:%d:%d" ,
5462                    npk+0 , npk+1 , npk+2 , npk+3 , npk+4 , npk+5 ) ;
5463            for( jj=0 ; jj < stup.wfunc_numpar ; jj++ ){
5464              if( !stup.wfunc_param[jj].fixed ) stup.wfunc_param[jj].fixed = 1 ;
5465            }
5466            for( ii=0 ; ii < 6 ; ii++ ){
5467              jj = npk[ii] ;
5468              if( jj >= 0 && jj < stup.wfunc_numpar && stup.wfunc_param[jj].fixed == 1 )
5469                stup.wfunc_param[jj].fixed = 0 ;
5470            }
5471          }
5472 
5473          /*-- do the startup parameter search:
5474                 saves best param set in val_init (and val_out),
5475                 plus a few more good sets in val_trial for refinement --*/
5476 
5477          if( verb > 1 ) ctim = COX_cpu_time() ;
5478 
5479          powell_set_mfac( 1.0f , 3.0f ) ;  /* 07 Jun 2011 - for some speedup */
5480 
5481          /* number of random trials depends on number to
5482             be optimized further (-twobest ==> tbest value) */
5483 
5484          nrand = 17 + 4*tbest ;
5485          if( METH_USES_BLOKS(meth_code) ) nrand += 2*tbest ;  /* 27 May 2021 */
5486          nrand = MAX(nrand,31) ; /* num random param setups to try */
5487 
5488          /***** Carryout the initial 'random' search for parameters *****/
5489 
5490          mri_genalign_scalar_ransetup( &stup , nrand ) ;
5491 
5492          if( verb > 1 )
5493            ININFO_message("- Coarse startup search net CPU time = %.1f s",COX_cpu_time()-ctim);
5494 
5495          /*-- unfreeze those parameters that were temporarily frozen above --*/
5496 
5497          for( jj=0 ; jj < stup.wfunc_numpar ; jj++ )
5498            if( stup.wfunc_param[jj].fixed == 1 ) stup.wfunc_param[jj].fixed = 0 ;
5499 
5500          /*---- now refine the tbest values saved already (from val_trial) ----*/
5501 
5502          tb = MIN(tbest,stup.wfunc_ntrial) ; nfunc=0 ;
5503          if( verb > 1 ) ctim = COX_cpu_time() ;
5504 
5505          /*- copy the trial parameters out into tfparm -*/
5506 
5507          for( ib=0 ; ib < tb ; ib++ ){
5508            for( jj=0 ; jj < stup.wfunc_numpar ; jj++ ){
5509              tfparm[ib][jj] = stup.wfunc_param[jj].val_trial[ib] ;
5510            }
5511            tfiorg[ib] = stup.wfunc_param[0].idx_trial[ib] ;  /* 24 Jun 2021 */
5512            tfi2bs[ib] = ib ;
5513          }
5514 
5515          /*- add identity transform to set, for comparisons (and insurance) -*/
5516 
5517          for( jj=0 ; jj < stup.wfunc_numpar ; jj++ )
5518            tfparm[tb][jj] = stup.wfunc_param[jj].val_pinit ;
5519          tfiorg[tb] = -1 ;
5520          tfi2bs[tb] = -1 ;
5521 
5522          tfdone = tb+1 ;  /* number of parameter sets now saved in tfparm */
5523 
5524          /*- number of refinement stages (default = max = 3) -*/
5525 
5526          nrefine = (int)AFNI_numenv("AFNI_TWOPASS_REFINE") ;
5527          if( nrefine <= 0 || nrefine >= 3 ) nrefine = 3 ;  /* number of refinement passes */
5528          rad = 0.0555 ;  /* initial search radius in parameter space */
5529                          /* recall that each scaled parameter search range is 0..1 */
5530                          /* see powell_int.c for details on how this is implemented */
5531 
5532          /*- loop over refinement passes: try to make each trial parameter set better -*/
5533 
5534          for( rr=0 ; rr < nrefine ; rr++ , rad*=0.6789 ){ /* refine with less smoothing */
5535 
5536            if( verb > 1 )
5537              INFO_message("Start refinement #%d on %d coarse parameter sets",rr+1,tfdone);
5538 
5539            powell_set_mfac( 1.0f , 5.0f+2.0f*rr ) ;  /* 07 Jun 2011 */
5540 
5541            stup.smooth_radius_base *= 0.7777 ;  /* less smoothing at each refinement */
5542            stup.smooth_radius_targ *= 0.7777 ;
5543            stup.smooth_radius_base = MAX(stup.smooth_radius_base,fine_rad) ;
5544            stup.smooth_radius_targ = MAX(stup.smooth_radius_targ,fine_rad) ;
5545 
5546            stup.npt_match          *= 1.5 ;     /* more voxels for matching at each refinement */
5547 
5548            /* re-set up the optimization, as the above stup parameters have changed */
5549 
5550            mri_genalign_scalar_setup( NULL,NULL,NULL , &stup ) ;
5551 
5552            for( ib=0 ; ib < tfdone ; ib++ ){              /* loop over param sets */
5553              for( jj=0 ; jj < stup.wfunc_numpar ; jj++ )  /* load initial parameters */
5554                stup.wfunc_param[jj].val_init = tfparm[ib][jj] ;       /* from tfparm */
5555 
5556              /* optimize a little */
5557 
5558              nfunc += mri_genalign_scalar_optim( &stup, rad, 0.01*rad, 99+11*rr ) ;
5559 
5560              for( jj=0 ; jj < stup.wfunc_numpar ; jj++ )  /* save optimized params */
5561                tfparm[ib][jj] = stup.wfunc_param[jj].val_out ; /* back into tfparm */
5562 
5563              tfcost[ib] = stup.vbest ; tfindx[ib] = ib ;  /* save cost */
5564              if( verb > 1 )
5565                ININFO_message("- param set #%d has cost=%f [o=%d t=%d]",ib+1,stup.vbest,tfiorg[ib],tfi2bs[ib]) ;
5566              if( verb > 2 ) PAROUT("--") ;
5567            }
5568 
5569            /* 29 Aug 2008: sort tfparm by cost, then cast out the close ones */
5570 
5571            if( !nocast && tfdone > 2 ){
5572              int jb,ncast=0 ; float pdist ;
5573 
5574              if( verb > 1 ) ININFO_message("- sorting parameter sets by cost") ;
5575              for( ib=0 ; ib < tfdone ; ib++ ){      /* copy tfparm into ffparm */
5576                memcpy( ffparm[ib], tfparm[ib], sizeof(float)*stup.wfunc_numpar );
5577                ffiorg[ib] = tfiorg[ib] ;                        /* 24 Jun 2021 */
5578                ffi2bs[ib] = tfi2bs[ib] ;
5579              }
5580              qsort_floatint( tfdone , tfcost , tfindx ) ;      /* sort by cost */
5581              for( ib=0 ; ib < tfdone ; ib++ ){        /* copy back into tfparm */
5582                jb = tfindx[ib] ;      /* jb = index in unsorted copy in ffparm */
5583                memcpy( tfparm[ib], ffparm[jb], sizeof(float)*stup.wfunc_numpar );
5584                tfiorg[ib] = ffiorg[jb] ;
5585                tfi2bs[ib] = ffi2bs[jb] ;
5586              }
5587 
5588              /* now cast out parameter sets that are very close to the best one */
5589 
5590 #undef  CTHRESH
5591 #define CTHRESH 0.02f
5592              if( verb > 1 ) ININFO_message("- scanning for distances from #1") ;
5593              for( ib=1 ; ib < tfdone ; ib++ ){
5594                pdist = param_dist( &stup , tfparm[0] , tfparm[ib] ) ;
5595                if( verb > 2 ) ININFO_message("--- dist(#%d,#1) = %.3g %s" ,
5596                                              ib+1, pdist, (pdist<CTHRESH)?"XXX":"" ) ;
5597                if( tfdone > 2 && pdist < CTHRESH ){
5598                  for( jb=ib+1 ; jb < tfdone ; jb++ ){  /* copy those above down */
5599                    memcpy( tfparm[jb-1], tfparm[jb], sizeof(float)*stup.wfunc_numpar );
5600                    tfiorg[jb-1] = tfiorg[jb] ;
5601                    tfi2bs[jb-1] = tfi2bs[jb] ;
5602                  }
5603                  ncast++ ; tfdone-- ;
5604                }
5605              }
5606              if( ncast > 0 && verb > 1 )
5607                ININFO_message(
5608                  "- cast out %d parameter set%s for being too close to best set" ,
5609                  ncast , (ncast==1)?"":"s" ) ;
5610            }
5611 
5612          } /* end of refinement loop (rr) */
5613 
5614          if( verb > 1 )
5615            ININFO_message("- Total coarse refinement net CPU time = %.1f s; %d funcs",
5616                           COX_cpu_time()-ctim,nfunc ) ;
5617 
5618          /* end of '-twobest x' for x > 0 */
5619 
5620        } else {  /*- if stoopid user did '-twobest 0' -*/
5621                  /*- just optimize coarse setup from default parameters -*/
5622                  /*- mimicking the 3 loop passes above --*/
5623 
5624          if( verb     ) ININFO_message("- Start coarse optimization with -twobest 0") ;
5625          if( verb > 1 ) ctim = COX_cpu_time() ;
5626          powell_set_mfac( 2.0f , 1.0f ) ;  /* 07 Jun 2011 */
5627          /* optimize pass 1 */
5628          nfunc = mri_genalign_scalar_optim( &stup , 0.05 , 0.001 , 444 ) ;
5629          if( verb > 2 ) PAROUT("--(a)") ;
5630          /* optimize pass 2 */
5631          stup.npt_match = ntask / 7 ;
5632          if( stup.npt_match < nmatch_setup  ) stup.npt_match = nmatch_setup ;
5633          stup.smooth_radius_base *= 0.456 ;
5634          stup.smooth_radius_targ *= 0.456 ;
5635          mri_genalign_scalar_setup( NULL,NULL,NULL , &stup ) ;
5636          nfunc += mri_genalign_scalar_optim( &stup , 0.0333 , 0.001 , 444 ) ;
5637          if( verb > 2 ) PAROUT("--(b)") ;
5638          /* optimize pass 2 */
5639          stup.smooth_radius_base *= 0.456 ;
5640          stup.smooth_radius_targ *= 0.456 ;
5641          mri_genalign_scalar_setup( NULL,NULL,NULL , &stup ) ;
5642          nfunc += mri_genalign_scalar_optim( &stup , 0.0166 , 0.001 , 444 ) ;
5643          if( verb > 2 ) PAROUT("--(c)") ;
5644          if( verb > 1 ) ININFO_message("- Coarse net CPU time = %.1f s; %d funcs",
5645                                        COX_cpu_time()-ctim,nfunc) ;
5646          if( verb     ) ININFO_message("- Coarse optimization:  best cost=%f",
5647                                        stup.vbest) ;
5648 
5649          for( jj=0 ; jj < stup.wfunc_numpar ; jj++ )  /* save best params */
5650            tfparm[0][jj] = stup.wfunc_param[jj].val_out ;
5651 
5652          tfiorg[0] = 0 ;
5653          tfi2bs[0] = 0 ;
5654          tfdone = 1 ;  /* number of parameter sets saved in tfparm */
5655 
5656        } /* end of '-twobest 0' */
5657 
5658        /*-- 22 Sep 2006: add default init params to the tfparm list --*/
5659        /*--              (so there will be at least 2 sets there)   --*/
5660 
5661        for( jj=0 ; jj < stup.wfunc_numpar ; jj++ )
5662          tfparm[tfdone][jj] = stup.wfunc_param[jj].val_pinit ;
5663        tfiorg[tfdone] = -2 ;
5664        tfi2bs[tfdone] = -2 ;
5665        tfdone++ ;
5666 
5667        didtwo = 1 ;   /* mark that we did the first pass */
5668 
5669      } /*------------- end of the coarse pass --------------------------------*/
5670 
5671      /*-----------------------------------------------------------------------*/
5672      /*----------------------- do final resolution pass ----------------------*/
5673      /*-------- which has less smoothing and more voxels for matching --------*/
5674      /*-----------------------------------------------------------------------*/
5675 
5676      if( verb > 1 || (verb && kk == 0) ) /* 7 Jan 2019 [rickr] */
5677         INFO_message("*** Fine pass begins ***") ;
5678      ctim = COX_cpu_time() ;
5679 
5680      stup.interp_code = interp_code ;  /* set interpolation   */
5681      stup.smooth_code = sm_code ;      /* and smoothing codes */
5682 
5683      /*-- setup smoothing --*/
5684 
5685      if( fine_rad > 0.0f ){  /* if ordered by user */
5686        stup.smooth_radius_base = stup.smooth_radius_targ = fine_rad ;
5687      } else if( diffblur ){  /* if base finer resolution than target */
5688        float br,tr ;
5689        if( nz_base > 1 ){
5690          br = cbrt(dx_base*dy_base*dz_base) ;  /* base voxel size */
5691          tr = cbrt(dx_targ*dy_targ*dz_targ) ;  /* targ voxel size */
5692        } else {
5693          br = sqrt(dx_base*dy_base) ;
5694          tr = sqrt(dx_targ*dy_targ) ;
5695        }
5696        stup.smooth_radius_targ = 0.0f ;
5697        stup.smooth_radius_base = (tr <= 1.1f*br) ? 0.0f
5698                                                  : sqrt(tr*tr-br*br) ;
5699      }
5700 
5701      /*-- setup the optimization --*/
5702 
5703      stup.npt_match = npt_match ;
5704      if( didtwo ){                                 /* did first pass already: */
5705        mri_genalign_scalar_setup( NULL,NULL,NULL, &stup ); /* simple re-setup */
5706 
5707      } else {                      /* have to setup which images are involved */
5708        mri_genalign_scalar_setup( im_bset , im_wset , im_targ , &stup ) ;
5709        im_bset = NULL; im_wset = NULL;  /* after being set, needn't set again */
5710        if( usetemp ) mri_purge( im_targ ) ;
5711      }
5712 
5713      /*-- set initial param radius for optimizer --*/
5714 
5715      switch( tfdone ){
5716         case 0: rad = 0.0666 ; break ;  /* this is size of initial trust region */
5717         case 1:                         /* -- in the unitless [-1..1] space */
5718         case 2: rad = 0.0444 ; break ;
5719        default: rad = 0.0333 ; break ;
5720      }
5721      if( rad < 44.4*conv_rad ) rad = 44.4*conv_rad ;  /* unlikely */
5722      if( rad > 0.111         ) rad = 0.111 ;          /* very unlikely */
5723 
5724      /*-- choose initial parameters, based on interp_code cost functional --*/
5725 
5726      powell_set_mfac( powell_mm , powell_aa ) ;  /* 07 Jun 2011 */
5727 
5728      /*-- find the best param set in tfparm array (if populated),
5729           using the cost functional evaluation setup for this fine pass --*/
5730 
5731      if( tfdone ){
5732        int kb=0 , ib ; float cbest=1.e+33 ;
5733 
5734        if( verb > 1 )
5735          INFO_message("Picking best parameter set out of %d cases",tfdone) ;
5736        for( ib=0 ; ib < tfdone ; ib++ ){
5737          cost = mri_genalign_scalar_cost( &stup , tfparm[ib] ) ;
5738          if( verb > 1 ) ININFO_message("- cost(#%d)=%f %c [o=%d t=%d]",
5739                                        ib+1,cost,(cost<cbest)?'*':' ',tfiorg[ib],tfi2bs[ib]);
5740          if( verb > 2 ) PARVEC("--",tfparm[ib]) ;
5741          if( cost < cbest ){ cbest=cost ; kb=ib ; }  /* save best case */
5742        }
5743 
5744        if( num_rtb == 0 ){  /*-- 27 Aug 2008: this was the old way,  --*/
5745                             /*-- to just pick the best at this point --*/
5746          if( verb > 1 )
5747            ININFO_message("-num_rtb 0 ==> pick best of the %d cases (#%d)",tfdone,kb+1);
5748          for( jj=0 ; jj < stup.wfunc_numpar ; jj++ )        /* copy best set */
5749            stup.wfunc_param[jj].val_init = tfparm[kb][jj] ; /* for fine work */
5750 
5751          for( ib=0 ; ib < tfdone ; ib++ )  /* save all cases into ffparm */
5752            memcpy( ffparm[ib], tfparm[ib], sizeof(float)*stup.wfunc_numpar ) ;
5753 
5754        } else {         /*-- now: try to make these a little better instead --*/
5755                         /*--      and THEN choose the best one at that point -*/
5756          if( verb > 1 )
5757            ININFO_message("-num_rtb %d ==> refine all %d cases",num_rtb,tfdone);
5758          cbest = 1.e+33 ;
5759          for( ib=0 ; ib < tfdone ; ib++ ){
5760            for( jj=0 ; jj < stup.wfunc_numpar ; jj++ )  /* load init params */
5761              stup.wfunc_param[jj].val_init = tfparm[ib][jj] ;
5762            nfunc = mri_genalign_scalar_optim( &stup, rad, 0.01*rad, /* improvement */
5763                                               (ib==tfdone-1) ? 2*num_rtb : num_rtb );
5764            for( jj=0 ; jj < stup.wfunc_numpar ; jj++ )       /* save refined */
5765              ffparm[ib][jj] = stup.wfunc_param[jj].val_out ; /* parameters */
5766            cost = stup.vbest ;
5767            if( verb > 1 ) ININFO_message("- cost(#%d)=%f %c [o=%d t=%d]",
5768                                          ib+1,cost,(cost<cbest)?'*':' ',tfiorg[ib],tfi2bs[ib] );
5769            if( verb > 2 ) PAROUT("--") ;
5770            if( cost < cbest ){ cbest=cost ; kb=ib ; }  /* save best case */
5771          }
5772          if( verb > 1 ) ININFO_message("- case #%d [o=%d t=%d] is now the best",kb+1,tfiorg[kb],tfi2bs[kb]) ;
5773          for( jj=0 ; jj < stup.wfunc_numpar ; jj++ )
5774            stup.wfunc_param[jj].val_init = ffparm[kb][jj] ;
5775        }
5776        cost_ini = cbest ;
5777 
5778      } else {  /*-- did not do first pass, so we start at default params --*/
5779                /*-- this situation is '-onepass' = fast and less reliable -*/
5780 
5781        cost_ini = mri_genalign_scalar_cost( &stup , NULL ) ;
5782 
5783      }
5784 
5785      /*-- BUT .. before we start the fine alignment ....... --*/
5786 
5787      if( do_allcost != 0 ){  /*-- print out all cost functionals, for fun --*/
5788        PAR_CPY(val_init) ;   /* copy init parameters into allpar[] */
5789        allcost = mri_genalign_scalar_allcosts( &stup , allpar ) ;
5790        INFO_message("allcost output: start fine #%d",kk) ;
5791        for( jj=0 ; jj < GA_MATCH_METHNUM_SCALAR ; jj++ )
5792          fprintf(stderr,"   %-4s = %g\n",meth_shortname[jj],allcost->ar[jj]) ;
5793        KILL_floatvec(allcost) ;
5794        if( save_hist != NULL ) SAVEHIST("allcost_finestart",0) ;
5795      }
5796 
5797      if( verb > 1 ){
5798        ININFO_message("- Initial  cost = %f",cost_ini) ;
5799        PARINI("- Initial fine") ;
5800      }
5801 
5802      powell_set_mfac( powell_mm , powell_aa ) ;  /* 07 Jun 2011 */
5803      nfunc = 0 ;
5804 
5805      /*-- start with some optimization with linear interp, for speed? --*/
5806      /*-- (that is, if no refinement was done above already)          --*/
5807 
5808      if( num_rtb == 0 &&
5809          (MRI_HIGHORDER(interp_code) || npt_match > 999999) ){
5810 
5811        float pini[MAXPAR] ;
5812        stup.interp_code = MRI_LINEAR ;  /* set interpolation to LINEAR */
5813        stup.npt_match   = MIN(499999,npt_match) ;  /* and fewer points */
5814        mri_genalign_scalar_setup( NULL,NULL,NULL, &stup ) ;
5815        if( verb > 1 ) ININFO_message("- start Intermediate optimization") ;
5816        /*** if( verb > 2 ) GA_do_params(1) ; ***/  /* was for debugging */
5817 
5818        nfunc = mri_genalign_scalar_optim( &stup, rad, 0.01*rad, 333 );
5819 
5820        for( jj=0 ; jj < stup.wfunc_numpar ; jj++ ){
5821          pini[jj] = stup.wfunc_param[jj].val_init ;
5822          stup.wfunc_param[jj].val_init = stup.wfunc_param[jj].val_out ;
5823        }
5824 
5825        stup.interp_code = interp_code ;  /* check cost of result with  */
5826        stup.npt_match   = npt_match ;    /* actual final interp method */
5827        mri_genalign_scalar_setup( NULL,NULL,NULL, &stup ) ;
5828        cost = mri_genalign_scalar_cost( &stup , NULL ) ; /* interp_code, not LINEAR */
5829        if( cost > cost_ini ){   /* should not happen, but it could since  */
5830          if( verb > 1 )         /* LINEAR cost optimized above isn't same */
5831            ININFO_message("- Intrmed  cost = %f > Initial cost = %f :-(",cost,cost_ini);
5832          for( jj=0 ; jj < stup.wfunc_numpar ; jj++ )
5833            stup.wfunc_param[jj].val_init = pini[jj] ;
5834        } else {
5835          if( verb > 1 ){
5836            PARINI("- Intrmed fine") ;
5837            ININFO_message("- Intrmed  cost = %f ; %d funcs",cost,nfunc) ;
5838          }
5839          if( nfunc < 333 ){
5840            rad *= 0.456 ; if( rad < 9.99*conv_rad ) rad = 9.99*conv_rad ;
5841          }
5842        }
5843 
5844        if( do_allcost != 0 ){  /*-- all cost functionals for fun again --*/
5845          PAR_CPY(val_init) ;   /* copy init parameters into allpar[] */
5846          allcost = mri_genalign_scalar_allcosts( &stup , allpar ) ;
5847          INFO_message("allcost output: intermed fine #%d",kk) ;
5848          for( jj=0 ; jj < GA_MATCH_METHNUM_SCALAR ; jj++ )
5849            fprintf(stderr,"   %-4s = %g\n",meth_shortname[jj],allcost->ar[jj]) ;
5850          KILL_floatvec(allcost) ;
5851          if( save_hist != NULL ) SAVEHIST("allcost_fineintermed",0) ;
5852        }
5853 
5854      }  /* end of the 'Intermediate' alignment prologue to the Final work */
5855 
5856      /*-- now do final final optimization, with the correct interp mode --*/
5857      /*-- note we now allow a lot of function evaluations, as we are    --*/
5858      /*-- telling NEWUOA to evaluate down to a fine convergence radius  --*/
5859 
5860      nfunc = mri_genalign_scalar_optim( &stup , rad, conv_rad,6666 );
5861 
5862      /*-- 14 Nov 2007: a final final final optimization? [default] --*/
5863 
5864      if( do_refinal ){   /* and here is where +ZZ is implemented */
5865        if( verb > 1 )
5866          ININFO_message("- Finalish cost = %f ; %d funcs",stup.vbest,nfunc) ;
5867        for( jj=0 ; jj < stup.wfunc_numpar ; jj++ )
5868          stup.wfunc_param[jj].val_init = stup.wfunc_param[jj].val_out;
5869        if( verb > 1 ) PARINI("- ini Finalish") ;
5870        stup.need_hist_setup = 1 ;
5871        if( (meth_code == GA_MATCH_LPC_MICHO_SCALAR ||
5872             meth_code == GA_MATCH_LPA_MICHO_SCALAR   ) && micho_zfinal ){
5873          GA_setup_micho( 0.0 , 0.0 , 0.0 , 0.0 , 0.0 ) ;  /* do +ZZ stuff */
5874          if( verb > 1 )
5875            ININFO_message(" - Set %s parameters back to purity before Final iterations",
5876                           meth_shortname[meth_code-1] ) ;
5877        }
5878        rad = 0.0666 ;  /* start with a moderately wide trust region */
5879        if( powell_mm == 0.0f ) powell_set_mfac( 4.0f , 4.0f ) ;  /* 07 Jun 2011 */
5880        nfunc = mri_genalign_scalar_optim( &stup , rad, conv_rad,6666 );
5881        powell_set_mfac( powell_mm , powell_aa ) ;                /* 07 Jun 2011 */
5882      }
5883 
5884      /*** if( powell_mm > 0.0f ) powell_set_mfac( 0.0f , 0.0f ) ; ***/
5885      /*** if( verb > 2 ) GA_do_params(0) ; ***/
5886 
5887      /*** Optimzation is done, so do some cleanup and some output ***/
5888 
5889      if( verb > 1 ) ININFO_message("- Final    cost = %f ; %d funcs",stup.vbest,nfunc) ;
5890      if( verb > 1 || (verb==1 && kk==0) ) PARNOUT("Final fine fit") ; /* 30 Aug 2013 */
5891 
5892      /* Check if some parameter is near the edge of the allowable [27 May 2021] */
5893 
5894      { float pmin , pmax , pdif , pval ;
5895        for( jj=0 ; jj < 12 ; jj++ ){
5896          if( stup.wfunc_param[jj].fixed ) continue ;  /* not change-able */
5897          pmin = stup.wfunc_param[jj].min ;
5898          pmax = stup.wfunc_param[jj].max ;
5899          pdif = 0.0101f * fabsf(pmax-pmin) ; if( pdif <= 0.0f ) continue ;
5900          pval = stup.wfunc_param[jj].val_out ;
5901          if( fabsf(pval-pmin) <= pdif || fabsf(pval-pmax) <= pdif ){  /* within 1% of edge */
5902            WARNING_message("Parameter %s = %9.5f is close to edge of its search range %9.5f .. %9.5f" ,
5903                            stup.wfunc_param[jj].name , pval , pmin , pmax ) ;
5904          }
5905        }
5906      }
5907 
5908      /* some more cleanup */
5909 
5910      if( verb > 1 ) ININFO_message("- Fine net CPU time = %.1f s",COX_cpu_time()-ctim) ;
5911 
5912      if( save_hist != NULL ) SAVEHIST("final",1) ;
5913 
5914      if( (meth_code == GA_MATCH_LPC_MICHO_SCALAR ||
5915           meth_code == GA_MATCH_LPA_MICHO_SCALAR   ) && micho_zfinal )  /* set them back */
5916        GA_setup_micho( micho_hel , micho_mi , micho_nmi , micho_crA , micho_ov ) ;
5917 
5918      /* some random outputs for the most random of users */
5919 
5920      if( do_allcost != 0 ){  /*-- all costs at final affine solution? --*/
5921        PAR_CPY(val_out) ;    /* copy output parameters into allpar[] */
5922        allcost = mri_genalign_scalar_allcosts( &stup , allpar ) ;
5923        INFO_message("allcost output: final fine #%d",kk) ;
5924        for( jj=0 ; jj < GA_MATCH_METHNUM_SCALAR ; jj++ )
5925          fprintf(stderr,"   %-4s = %g\n",meth_shortname[jj],allcost->ar[jj]) ;
5926        KILL_floatvec(allcost) ;
5927        if( save_hist != NULL ) SAVEHIST("allcost_finefinal",0) ;
5928      }
5929 
5930      if( do_save_pearson_map ){  /*-- Save Pearson map [25 Jan 2021] --*/
5931        SAVE_PEARSON_MAP(save_pearson_prefix,val_out) ;
5932        do_save_pearson_map = 0 ;
5933      }
5934 
5935 #if 0  /* I don't recall why this is here -- debugging, I guess? */
5936      for( jj=0 ; jj < stup.wfunc_numpar ; jj++ )
5937        stup.wfunc_param[jj].val_init = stup.wfunc_param[jj].val_out ;
5938      mri_genalign_verbose(9) ;
5939      cost = mri_genalign_scalar_cost( &stup , NULL ) ;
5940      INFO_message("Recomputed final cost = %g",cost) ;
5941      if( verb > 1 ) mri_genalign_verbose(verb-1) ;
5942 #endif
5943 
5944      /** Next up: about 400 lines of code that proved not to be very useful **/
5945 #ifdef ALLOW_NWARP /*********************************************************/
5946      /*----------------------------------------------------------------------*/
5947      /*------------ Nonlinear warp improvement to the above results? --------*/
5948      /*----------- Someday soon (?), this code will be expunged! ------------*/
5949 
5950 /* macro to (re)setup some parameters in the work below */
5951 
5952 #define PARAM_SETUP(pp,ff,vv)                                                          \
5953  do{ if( ff ){ stup.wfunc_param[pp].fixed = ff; stup.wfunc_param[pp].val_fixed = vv; } \
5954      else    { stup.wfunc_param[pp].fixed = 0; }                                       \
5955      stup.wfunc_param[pp].val_init = vv;                                               \
5956  } while(0)
5957 
5958      if( nwarp_pass ){
5959 
5960        /* 15 Dec 2010: change cost functional here? */
5961 
5962        if( nwarp_meth_code > 0 ){
5963          if( verb ) INFO_message( "-nwarp setup: switch method to '%s' from '%s'",
5964                                   meth_shortname[nwarp_meth_code-1] ,
5965                                   meth_shortname[stup.match_code-1]  ) ;
5966          stup.match_code = nwarp_meth_code ;
5967        }
5968 
5969        /*--- different blocks of code for the different types of warps ---*/
5970 
5971        if( nwarp_type == WARP_BILINEAR ){  /*------ special case [old] ------*/
5972 
5973          float rr , xcen,ycen,zcen , brad,crad ; int nbf , nite ;
5974 
5975          rr = MAX(xsize,ysize) ; rr = MAX(zsize,rr) ; rr = 1.2f / rr ;
5976 
5977          SETUP_BILINEAR_PARAMS ;  /* nonlinear params */
5978 
5979          /* nonlinear transformation is centered at middle of base volume
5980             indexes (xcen,ycen,zcen) and is scaled by reciprocal of size (rr) */
5981 
5982          MAT44_VEC( stup.base_cmat,
5983                     0.5f*nx_base, 0.5f*ny_base, 0.5f*nz_base,
5984                     xcen        , ycen        , zcen         ) ;
5985          stup.wfunc_param[NPBIL  ].val_fixed = stup.wfunc_param[NPBIL  ].val_init = xcen;
5986          stup.wfunc_param[NPBIL+1].val_fixed = stup.wfunc_param[NPBIL+1].val_init = ycen;
5987          stup.wfunc_param[NPBIL+2].val_fixed = stup.wfunc_param[NPBIL+2].val_init = zcen;
5988          stup.wfunc_param[NPBIL+3].val_fixed = stup.wfunc_param[NPBIL+3].val_init = rr  ;
5989 
5990          /* affine part is copied from results of work thus far */
5991 
5992          for( jj=0 ; jj < 12 ; jj++ )
5993            stup.wfunc_param[jj].val_init = stup.wfunc_param[jj].val_out;
5994 
5995          stup.need_hist_setup = 1 ;
5996          mri_genalign_scalar_setup( NULL,NULL,NULL, &stup );
5997 
5998          /* do the first pass of the bilinear optimization */
5999 
6000          if( verb > 0 ) INFO_message("Start bilinear warping") ;
6001          if( verb > 1 ) PARINI("- Bilinear initial") ;
6002          for( jj=12 ; jj <= 14 ; jj++ ){
6003            stup.wfunc_param[jj   ].fixed = 0 ;  /* just free up diagonal */
6004            stup.wfunc_param[jj+12].fixed = 0 ;  /* elements of B tensor */
6005            stup.wfunc_param[jj+24].fixed = 0 ;
6006          }
6007          if( verb ) ctim = COX_cpu_time() ;
6008          brad = MAX(conv_rad,0.001f) ;
6009               if( rad > 55.5f*brad ) rad = 55.5f*brad ;
6010          else if( rad < 22.2f*brad ) rad = 22.2f*brad ;
6011          crad = ( (nwarp_flags&1) == 0 ) ? (11.1f*brad) : (2.22f*brad) ;
6012          nite = MAX(555,nwarp_itemax) ;
6013          nbf  = mri_genalign_scalar_optim( &stup , rad, crad, nite );
6014          if( verb ){
6015            dtim = COX_cpu_time() ;
6016            ININFO_message("- Bilinear#1 cost = %f ; %d funcs ; net CPU = %.1f s",
6017                           stup.vbest,nbf,dtim-ctim) ;
6018            ctim = dtim ;
6019          }
6020 
6021          /* do the second pass, with more parameters varying */
6022 
6023          if( (nwarp_flags&1) == 0 ){
6024            float dnor , onor ;
6025 
6026            for( jj=0  ; jj < NPBIL ; jj++ )
6027              stup.wfunc_param[jj].val_init = stup.wfunc_param[jj].val_out;
6028 #if 1
6029            for( jj=0 ; jj < 12 ; jj++ ){      /* fix affine params */
6030              stup.wfunc_param[jj].val_fixed = stup.wfunc_param[jj].val_out ;
6031              stup.wfunc_param[jj].fixed = 1 ;
6032            }
6033 #endif
6034            for( jj=12 ; jj < NPBIL ; jj++ )   /* now free up all B elements */
6035              stup.wfunc_param[jj].fixed = 0 ;
6036            nite = MAX(1111,nwarp_itemax) ;
6037            nbf  = mri_genalign_scalar_optim( &stup, 33.3f*brad, 2.22f*brad,nite );
6038            if( verb ){
6039              dtim = COX_cpu_time() ;
6040              ININFO_message("- Bilinear#2 cost = %f ; %d funcs ; net CPU = %.1f s",
6041                             stup.vbest,nbf,dtim-ctim) ;
6042              ctim = dtim ;
6043            }
6044 
6045            /* run it again to see if it improves any more? */
6046 
6047            dnor = BILINEAR_diag_norm   (stup) ;
6048            onor = BILINEAR_offdiag_norm(stup) ;
6049            if( onor > 0.0333f * dnor ){
6050              for( jj=0  ; jj < NPBIL ; jj++ )
6051                stup.wfunc_param[jj].val_init = stup.wfunc_param[jj].val_out;
6052              nbf = mri_genalign_scalar_optim( &stup, 4.44f*brad, brad, 222 );
6053              if( verb ){
6054                dtim = COX_cpu_time() ;
6055                ININFO_message("- Bilinear#3 cost = %f ; %d funcs ; net CPU = %.1f s",
6056                               stup.vbest,nbf,dtim-ctim) ;
6057                ctim = dtim ;
6058              }
6059            }
6060          }
6061          /** if( verb > 1 ) PAROUT("- Bilinear final") ; **/
6062 
6063          strcpy(warp_code_string,"bilinear") ;
6064 
6065        } else if( nwarp_type == WARP_CUBIC ){  /*------ special case ------------*/
6066 
6067          float rr , xcen,ycen,zcen , brad,crad ; int nbf , nite ;
6068 
6069          rr = MAX(xsize,ysize) ; rr = MAX(zsize,rr) ; rr = 1.2f / rr ;
6070 
6071          SETUP_CUBIC_PARAMS ;  /* nonlinear params */
6072 
6073          /* nonlinear transformation is centered at middle of base volume
6074             indexes (xcen,ycen,zcen) and is scaled by reciprocal of size (rr) */
6075 
6076          MAT44_VEC( stup.base_cmat,
6077                     0.5f*nx_base, 0.5f*ny_base, 0.5f*nz_base,
6078                     xcen        , ycen        , zcen         ) ;
6079          stup.wfunc_param[NPCUB  ].val_fixed = stup.wfunc_param[NPCUB  ].val_init = xcen;
6080          stup.wfunc_param[NPCUB+1].val_fixed = stup.wfunc_param[NPCUB+1].val_init = ycen;
6081          stup.wfunc_param[NPCUB+2].val_fixed = stup.wfunc_param[NPCUB+2].val_init = zcen;
6082          stup.wfunc_param[NPCUB+3].val_fixed = stup.wfunc_param[NPCUB+3].val_init = rr  ;
6083 
6084          /* affine part is copied from results of work thus far */
6085 
6086          for( jj=0 ; jj < 12 ; jj++ ){
6087            nbf = (stup.wfunc_param[jj].fixed) ? stup.wfunc_param[jj].fixed : nwarp_fixaff ;
6088            PARAM_SETUP( jj , nbf , stup.wfunc_param[jj].val_out ) ;
6089          }
6090 
6091          stup.need_hist_setup = 1 ;
6092          mri_genalign_scalar_setup( NULL,NULL,NULL, &stup );
6093 
6094          /* do the optimization */
6095 
6096          /** if( verb > 1 ) PARINI("- Cubic/Poly3 initial") ; **/
6097          for( jj=12 ; jj < NPCUB  ; jj++ ) stup.wfunc_param[jj].fixed = 0 ;
6098          FREEZE_POLYNO_PARAMS ; /* 07 Dec 2010 */
6099 
6100          COUNT_FREE_PARAMS(nbf) ;
6101          if( verb > 0 )
6102            INFO_message("Start Cubic/Poly3 warping: %d free parameters",nbf) ;
6103 
6104          if( verb ) ctim = COX_cpu_time() ;
6105          rad  = 0.01f ; crad = 0.003f ;
6106          nite = MAX(2222,nwarp_itemax) ;
6107          nbf  = mri_genalign_scalar_optim( &stup , rad, crad, nite );
6108          if( verb ){
6109            dtim = COX_cpu_time() ;
6110            ININFO_message("- Cubic/Poly3 cost = %f ; %d funcs ; net CPU = %.1f s",
6111                           stup.vbest,nbf,dtim-ctim) ;
6112            ctim = dtim ;
6113          }
6114 
6115          /** if( verb > 1 ) PAROUT("- Cubic/Poly3 final") ; **/
6116          strcpy(warp_code_string,"cubic") ;
6117 
6118        } else if( nwarp_type == WARP_QUINT ){  /*------ special case ------------*/
6119 
6120          float rr , xcen,ycen,zcen , brad,crad ; int nbf , nite ;
6121 
6122          rr = MAX(xsize,ysize) ; rr = MAX(zsize,rr) ; rr = 1.2f / rr ;
6123 
6124          SETUP_QUINT_PARAMS ;  /* nonlinear params */
6125 
6126          /* nonlinear transformation is centered at middle of base volume
6127             indexes (xcen,ycen,zcen) and is scaled by reciprocal of size (rr) */
6128 
6129          MAT44_VEC( stup.base_cmat,
6130                     0.5f*nx_base, 0.5f*ny_base, 0.5f*nz_base,
6131                     xcen        , ycen        , zcen         ) ;
6132          PARAM_SETUP( NPQUINT   , 2 , xcen ) ;
6133          PARAM_SETUP( NPQUINT+1 , 2 , ycen ) ;
6134          PARAM_SETUP( NPQUINT+2 , 2 , zcen ) ;
6135          PARAM_SETUP( NPQUINT+3 , 2 , rr   ) ;
6136 
6137          /* affine part is copied from results of work thus far */
6138 
6139          for( jj=0 ; jj < 12 ; jj++ ){
6140            nbf = (stup.wfunc_param[jj].fixed) ? stup.wfunc_param[jj].fixed : nwarp_fixaff ;
6141            PARAM_SETUP( jj , nbf , stup.wfunc_param[jj].val_out ) ;
6142          }
6143 
6144          stup.need_hist_setup = 1 ;
6145          mri_genalign_scalar_setup( NULL,NULL,NULL, &stup );
6146          GA_set_nperval(0) ;
6147 
6148          /* do the optimization */
6149 
6150          for( jj=12 ; jj < NPQUINT ; jj++ ) stup.wfunc_param[jj].fixed = 0 ;
6151          FREEZE_POLYNO_PARAMS ; /* 07 Dec 2010 */
6152 
6153          COUNT_FREE_PARAMS(nbf) ;
6154          if( verb > 0 )
6155            INFO_message("Start Quintic/Poly5 warping: %d free parameters",nbf) ;
6156 
6157          if( verb ) ctim = COX_cpu_time() ;
6158          rad  = 0.01f ; crad = 0.003f ;
6159          nite = MAX(3333,nwarp_itemax) ;
6160          nbf  = mri_genalign_scalar_optim( &stup , rad, crad, nite );
6161          if( verb ){
6162            dtim = COX_cpu_time() ;
6163            ININFO_message("- Quintic/Poly5 cost = %f ; %d funcs ; net CPU = %.1f s",
6164                           stup.vbest,nbf,dtim-ctim) ;
6165            ctim = dtim ;
6166          }
6167 
6168          /** if( verb > 1 ) PAROUT("- Quintic/Poly5 final") ; **/
6169          strcpy(warp_code_string,"quintic") ;
6170 
6171        } else if( nwarp_type == WARP_HEPT ){  /*------ special case ------------*/
6172 
6173          float rr , xcen,ycen,zcen , brad,crad ; int nbf , nite ;
6174 
6175          rr = MAX(xsize,ysize) ; rr = MAX(zsize,rr) ; rr = 1.2f / rr ;
6176 
6177          SETUP_HEPT_PARAMS ;  /* nonlinear params */
6178 
6179          /* nonlinear transformation is centered at middle of base volume
6180             indexes (xcen,ycen,zcen) and is scaled by reciprocal of size (rr) */
6181 
6182          MAT44_VEC( stup.base_cmat,
6183                     0.5f*nx_base, 0.5f*ny_base, 0.5f*nz_base,
6184                     xcen        , ycen        , zcen         ) ;
6185          PARAM_SETUP( NPHEPT   , 2 , xcen ) ;
6186          PARAM_SETUP( NPHEPT+1 , 2 , ycen ) ;
6187          PARAM_SETUP( NPHEPT+2 , 2 , zcen ) ;
6188          PARAM_SETUP( NPHEPT+3 , 2 , rr   ) ;
6189 
6190          /* affine part is copied from results of work thus far */
6191 
6192          for( jj=0 ; jj < 12 ; jj++ ){
6193            nbf = (stup.wfunc_param[jj].fixed) ? stup.wfunc_param[jj].fixed : nwarp_fixaff ;
6194            PARAM_SETUP( jj , nbf , stup.wfunc_param[jj].val_out ) ;
6195          }
6196 
6197          stup.need_hist_setup = 1 ;
6198          mri_genalign_scalar_setup( NULL,NULL,NULL, &stup );
6199          GA_set_nperval(0) ;
6200 
6201          /* do the optimization */
6202 
6203          for( jj=12 ; jj < NPHEPT ; jj++ ) stup.wfunc_param[jj].fixed = 0 ;
6204          FREEZE_POLYNO_PARAMS ; /* 07 Dec 2010 */
6205 
6206          COUNT_FREE_PARAMS(nbf) ;
6207          if( verb > 0 )
6208            INFO_message("Start Heptic/Poly7 warping: %d free parameters",nbf) ;
6209 
6210          if( verb ) ctim = COX_cpu_time() ;
6211          rad  = 0.01f ; crad = 0.003f ;
6212          nite = MAX(4444,nwarp_itemax) ;
6213          nbf  = mri_genalign_scalar_optim( &stup , rad, crad, nite );
6214          if( verb ){
6215            dtim = COX_cpu_time() ;
6216            ININFO_message("- Heptic/Poly7 cost = %f ; %d funcs ; net CPU = %.1f s",
6217                           stup.vbest,nbf,dtim-ctim) ;
6218            ctim = dtim ;
6219          }
6220 
6221          /** if( verb > 1 ) PAROUT("- Heptic/Poly7 final") ; **/
6222          strcpy(warp_code_string,"heptic") ;
6223 
6224        } else if( nwarp_type == WARP_NONI ){  /*------ special case ------------*/
6225 
6226          float rr , xcen,ycen,zcen , brad,crad ; int nbf , nite ;
6227 
6228          rr = MAX(xsize,ysize) ; rr = MAX(zsize,rr) ; rr = 1.2f / rr ;
6229 
6230          SETUP_NONI_PARAMS ;  /* nonlinear params */
6231 
6232          /* nonlinear transformation is centered at middle of base volume
6233             indexes (xcen,ycen,zcen) and is scaled by reciprocal of size (rr) */
6234 
6235          MAT44_VEC( stup.base_cmat,
6236                     0.5f*nx_base, 0.5f*ny_base, 0.5f*nz_base,
6237                     xcen        , ycen        , zcen         ) ;
6238          PARAM_SETUP( NPNONI   , 2 , xcen ) ;
6239          PARAM_SETUP( NPNONI+1 , 2 , ycen ) ;
6240          PARAM_SETUP( NPNONI+2 , 2 , zcen ) ;
6241          PARAM_SETUP( NPNONI+3 , 2 , rr   ) ;
6242 
6243          /* affine part is copied from results of work thus far */
6244 
6245          for( jj=0 ; jj < 12 ; jj++ ){
6246            nbf = (stup.wfunc_param[jj].fixed) ? stup.wfunc_param[jj].fixed : nwarp_fixaff ;
6247            PARAM_SETUP( jj , nbf , stup.wfunc_param[jj].val_out ) ;
6248          }
6249 
6250          stup.need_hist_setup = 1 ;
6251          mri_genalign_scalar_setup( NULL,NULL,NULL, &stup );
6252          GA_set_nperval(0) ;
6253 
6254          /* do the optimization */
6255 
6256          powell_set_mfac( 1.2f , 5.0f ) ;
6257 
6258          if( AFNI_noenv("AFNI_NONIC_GRADUAL") ){  /* old way: all params at once */
6259            for( jj=12 ; jj < NPNONI ; jj++ ) stup.wfunc_param[jj].fixed = 0 ;
6260            FREEZE_POLYNO_PARAMS ; /* 07 Dec 2010 */
6261            COUNT_FREE_PARAMS(nbf) ;
6262            if( verb > 0 )
6263              INFO_message("Start Nonic/Poly9 warping: %d free parameters",nbf) ;
6264 
6265            if( verb ) ctim = COX_cpu_time() ;
6266            rad  = 0.03f ; crad = 0.003f ;
6267            nite = MAX(7777,nwarp_itemax) ;
6268            nbf  = mri_genalign_scalar_optim( &stup , rad, crad, nite );
6269            if( verb ){
6270              dtim = COX_cpu_time() ;
6271              ININFO_message("- Nonic/Poly9 cost = %f ; %d funcs ; net CPU = %.1f s",
6272                             stup.vbest,nbf,dtim-ctim) ;
6273              ctim = dtim ;
6274            }
6275          } else { /* the new way: cubic, then quintic, then heptic, then nonic */
6276 #undef  NPOL
6277 #define NPOL(k) (((k)+1)*((k)+2)*((k)+3)/6-4)
6278            static int fst[8] = { 12+3*NPOL(3) , 12+3*NPOL(4) , 12+3*NPOL(5) ,
6279                                  12+3*NPOL(6) , 12+3*NPOL(7) , 12+3*NPOL(8) ,
6280                                  12+3*NPOL(9)  } ;
6281            int pq , ngite=2 , ig ; char *eee ; float gfac ;
6282            eee = my_getenv("AFNI_NONIC_GRADUAL") ;
6283            if( eee != NULL && isdigit(*eee) ) ngite = (int)strtod(eee,NULL) ;
6284            for( ig=0 ; ig < ngite ; ig++ ){
6285              if( verb > 0 )
6286                INFO_message("Start iteration #%d/%d of Nonic/Poly9 gradual warp",ig+1,ngite) ;
6287              for( pq=0 ; pq < 7 ; pq++ ){
6288                for( jj=12 ; jj < NPNONI ; jj++ ) stup.wfunc_param[jj].fixed = 0 ;
6289                FREEZE_POLYNO_PARAMS ;
6290                for( jj=fst[pq] ; jj < NPNONI ; jj++ )
6291                  if( stup.wfunc_param[jj].fixed == 0 ) stup.wfunc_param[jj].fixed = 1 ;
6292                COUNT_FREE_PARAMS(nbf) ;
6293                if( verb > 0 )
6294                  ININFO_message("Level %d of Nonic/Poly9 warping: %d free parameters",pq+3,nbf) ;
6295                if( nbf == 0 ) continue ;
6296                if( pq > 0 || ig > 0 ){
6297                  for( jj=0 ; jj < fst[pq] ; jj++ ){
6298                    if( stup.wfunc_param[jj].fixed == 0 )
6299                      stup.wfunc_param[jj].val_init = stup.wfunc_param[jj].val_out ;
6300                  }
6301                }
6302                if( verb ) ctim = COX_cpu_time() ;
6303                gfac = 1.0f / sqrtf(ig+1.0f) ;
6304                rad  = 0.05f*gfac ; crad = 0.003f*gfac ;
6305                nite = MAX(19*nbf,nwarp_itemax) ;
6306                nbf  = mri_genalign_scalar_optim( &stup , rad, crad, nite );
6307                for( jj=0 ; jj < NPNONI ; jj++ ){        /* for fixers next time thru */
6308                  if( stup.wfunc_param[jj].fixed == 0 )
6309                    stup.wfunc_param[jj].val_fixed = stup.wfunc_param[jj].val_out ;
6310                }
6311                if( verb ){
6312                  dtim = COX_cpu_time() ;
6313                  ININFO_message("- Nonic/Poly9 cost = %f ; %d funcs ; net CPU = %.1f s",
6314                                 stup.vbest,nbf,dtim-ctim) ;
6315                  ctim = dtim ;
6316                }
6317              } /* end of pq loop */
6318            } /* end of ig loop */
6319          } /* end of GRADUAL-osity */
6320 
6321          /** if( verb > 1 ) PAROUT("- Nonic/Poly9 final") ; **/
6322          strcpy(warp_code_string,"nonic") ;
6323 
6324        } else {   /*-------- unimplemented ----------*/
6325 
6326          ERROR_message("Unknown nonlinear warp type!") ;
6327 
6328        } /* end of Warpfield */
6329 
6330      } /* end of nonlinear warp */
6331 #endif /* ALLOW_NWARP */ /**************************************************/
6332 
6333      /*-------- FINALLY HAVE FINISHED (hah!) ----------------------*/
6334 
6335      mri_free(im_targ) ; im_targ = NULL ;
6336 
6337 #ifdef ALLOW_METH_CHECK
6338      /*--- 27 Sep 2006: check if results are stable when
6339                         we optimize a different cost functional ---*/
6340 
6341      if( meth_check_count > 0 ){
6342        float pval[MAXPAR] , pdist , dmax ; int jmax,jtop ;
6343        float **aval = NULL ;
6344        int mm , mc ;
6345 
6346        if( meth_check_count > 1 ){   /* save for median-izing at end */
6347          aval = (float **)malloc(sizeof(float *)*stup.wfunc_numpar) ;
6348          for( jj=0 ; jj < stup.wfunc_numpar ; jj++ ){
6349            aval[jj] = (float *)malloc(sizeof(float)*(meth_check_count+1)) ;
6350            aval[jj][0] = stup.wfunc_param[jj].val_out ;
6351          }
6352        }
6353 
6354        PAROUT("Final fit") ;
6355        INFO_message("Checking %s (%s) vs other costs",
6356                     meth_longname[meth_code-1] , meth_shortname[meth_code-1] ) ;
6357        for( mm=0 ; mm < meth_check_count ; mm++ ){
6358          mc = meth_check[mm] ; if( mc <= 0 ) continue ;
6359          if( verb > 1 ){
6360            ININFO_message("- checking vs cost %s (%s)",
6361                           meth_longname[mc-1],meth_shortname[mc-1]) ;
6362            ctim = COX_cpu_time() ;
6363          }
6364          for( jj=0 ; jj < stup.wfunc_numpar ; jj++ ) /* save output params */
6365            stup.wfunc_param[jj].val_init = pval[jj] = stup.wfunc_param[jj].val_out;
6366 
6367          stup.match_code = mc ;
6368          nfunc = mri_genalign_scalar_optim( &stup, 33.3*conv_rad, conv_rad,666 );
6369          stup.match_code = meth_code ;
6370 
6371          if( aval != NULL ){
6372            for( jj=0 ; jj < stup.wfunc_numpar ; jj++ )
6373              aval[jj][mm+1] = stup.wfunc_param[jj].val_out ;
6374          }
6375 
6376          /* compute max fractional distance between 2 output parameter sets */
6377 
6378          jtop = MIN( 9 , stup.wfunc_numpar ) ; jmax = 0 ;
6379          for( dmax=0.0f,jj=0 ; jj < jtop ; jj++ ){
6380            if( !stup.wfunc_param[jj].fixed ){
6381              pdist = fabsf( stup.wfunc_param[jj].val_out - pval[jj] )
6382                     /(stup.wfunc_param[jj].max-stup.wfunc_param[jj].min) ;
6383              if( pdist > dmax ){ dmax = pdist ; jmax = jj ; }
6384            }
6385          }
6386 
6387 #define CHECK_TOL 99.0
6388 
6389          if( dmax > CHECK_TOL*conv_rad )
6390            WARNING_message(
6391              "Check vs %s (%s): max parameter discrepancy=%.4f%%! tolerance=%.4f%%",
6392              meth_longname[mc-1] , meth_shortname[mc-1] , 100.0*dmax , 100.0*CHECK_TOL*conv_rad ) ;
6393          else
6394            ININFO_message(
6395              "INFO:   Check vs %s (%s): max parameter discrepancy=%.4f%% tolerance=%.4f%%",
6396              meth_longname[mc-1] , meth_shortname[mc-1] , 100.0*dmax , 100.0*CHECK_TOL*conv_rad ) ;
6397          PAROUT("Check fit") ;
6398          if( verb > 2 )
6399            ININFO_message("- Check net CPU time=%.1f s; funcs=%d; dmax=%f jmax=%d",
6400                           COX_cpu_time()-ctim , nfunc , dmax , jmax ) ;
6401          if( do_allcost != 0 ){
6402            PAR_CPY(val_out) ;  /* copy output parameters into allpar */
6403            allcost = mri_genalign_scalar_allcosts( &stup , allpar ) ;
6404            ININFO_message("allcost output: check %s",meth_shortname[mc-1]) ;
6405            for( jj=0 ; jj < GA_MATCH_METHNUM_SCALAR ; jj++ )
6406              fprintf(stderr,"   %-4s = %g\n",meth_shortname[jj],allcost->ar[jj]) ;
6407            KILL_floatvec(allcost) ;
6408            if( save_hist != NULL ){
6409              char fn[64] ; sprintf(fn,"allcost_check_%s",meth_shortname[mc-1]);
6410              SAVEHIST(fn,0);
6411            }
6412          }
6413 
6414          for( jj=0 ; jj < stup.wfunc_numpar ; jj++ )
6415            stup.wfunc_param[jj].val_out = pval[jj] ;  /* restore previous param */
6416        } /* end of loop over check methods */
6417 
6418        if( aval != NULL ){  /* median-ize the parameter sets */
6419          for( jj=0 ; jj < stup.wfunc_numpar ; jj++ ){
6420            pval[jj] = qmed_float( meth_check_count+1 , aval[jj] ) ;
6421            free((void *)aval[jj]) ;
6422          }
6423          free((void *)aval) ;
6424          fprintf(stderr," + Median of Parameters =") ;
6425          for( jj=0 ; jj < stup.wfunc_numpar ; jj++ ) fprintf(stderr," %.6f",pval[jj]) ;
6426          fprintf(stderr,"\n") ;
6427          if( meth_median_replace ){  /* replace final results with median! NOT GOOD */
6428            ININFO_message("Replacing Final parameters with Median") ;
6429            for( jj=0 ; jj < stup.wfunc_numpar ; jj++ )
6430              stup.wfunc_param[jj].val_out = pval[jj] ;
6431          }
6432        }
6433 
6434      } /* end of checking */
6435 #endif
6436 
6437      /*-- freeze warp-ing parameters (those after #0..5) for later rounds? --*/
6438      /*-- (count this among the almost never used options)                 --*/
6439 
6440      if( warp_freeze && DSET_NVALS(dset_targ) > 1 ){  /* 10 Oct 2006 */
6441        for( jj=6 ; jj < stup.wfunc_numpar ; jj++ ){
6442          if( !stup.wfunc_param[jj].fixed ){
6443            if( verb > 1 ) INFO_message("Freezing parameter #%d [%s] = %.6f",
6444                                        jj+1 , stup.wfunc_param[jj].name ,
6445                                               stup.wfunc_param[jj].val_out ) ;
6446            stup.wfunc_param[jj].fixed = 2 ;
6447            stup.wfunc_param[jj].val_fixed = stup.wfunc_param[jj].val_out ;
6448          }
6449        }
6450      }
6451 
6452      /*--- do we replace the base image with warped first target image? ---*/
6453      /*--- (count this among the almost never used options)             ---*/
6454 
6455      if( replace_base ){
6456        float pp[MAXPAR] ; MRI_IMAGE *aim ;
6457        for( jj=0 ; jj < stup.wfunc_numpar ; jj++ )
6458          pp[jj] = stup.wfunc_param[jj].val_out ;
6459        mri_free(im_base) ;
6460        if( verb > 1 ) INFO_message("Computing replacement base image") ;
6461        aim = (stup.ajimor != NULL) ? stup.ajimor : stup.ajim ;
6462        im_base =
6463         im_bset = mri_genalign_scalar_warpone(
6464                              stup.wfunc_numpar , pp , stup.wfunc ,
6465                              aim, nx_base,ny_base,nz_base, final_interp );
6466 #if 0
6467        im_wset = im_weig ;  /* not needed, since stup 'remembers' the weight */
6468 #endif
6469        replace_base = 0 ; diffblur = 0 ;
6470      }
6471 
6472      /*-- an another almost never used option --*/
6473 
6474      if( replace_meth ){
6475        if( verb > 1 ) INFO_message("Replacing meth='%s' with '%s'",
6476                                    meth_shortname[meth_code] ,
6477                                    meth_shortname[replace_meth] ) ;
6478        meth_code = replace_meth; replace_meth = 0;
6479      }
6480 
6481      /*---- get final DICOM coord transformation matrix [23 Jul 2007] ----*/
6482 
6483      { float par[MAXPAR] ;
6484        for( jj=0 ; jj < stup.wfunc_numpar ; jj++ )
6485          par[jj] = stup.wfunc_param[jj].val_out ;
6486 #if 0
6487 mri_genalign_set_pgmat(1) ;
6488 #endif
6489        mri_genalign_affine( stup.wfunc_numpar , par , 0,NULL,NULL,NULL , NULL,NULL,NULL ) ;
6490        mri_genalign_affine_get_gammaijk( &qmat ) ;
6491        wmat = MAT44_MUL(targ_cmat,qmat) ;    /* matrix multiplies to undo the befafter stuff */
6492        aff12_xyz = MAT44_MUL(wmat,base_cmat_inv) ;  /* DICOM coord matrix */
6493      }
6494 
6495 #if 0                               /* lots of debugging output */
6496 DUMP_MAT44("targ_cmat",targ_cmat) ;
6497 DUMP_MAT44("targ_cmat_inv",targ_cmat_inv) ;
6498 DUMP_MAT44("base_cmat",base_cmat) ;
6499 DUMP_MAT44("base_cmat_inv",base_cmat_inv) ;
6500 DUMP_MAT44("aff12_xyz",aff12_xyz) ;
6501 DUMP_MAT44("aff12_ijk",qmat) ;
6502 #endif
6503 
6504      /*-----------------------------------------------------------------------*/
6505      /*--------- at this point, val_out contains alignment parameters --------*/
6506      /*--------- for source/target sub-brick under consideration [kk] --------*/
6507      /*-----------------------------------------------------------------------*/
6508 
6509    WRAP_IT_UP_BABY: /***** goto target !!!!! *****/
6510 
6511      /* save parameters for the historical record */
6512 
6513      if( parsave != NULL ){
6514        parsave[kk] = (float *)malloc(sizeof(float)*stup.wfunc_numpar) ;
6515        for( jj=0 ; jj < stup.wfunc_numpar ; jj++ )
6516          parsave[kk][jj] = stup.wfunc_param[jj].val_out ;
6517      }
6518 
6519      /* save matrix for the hysterical record [23 Jul 2007] */
6520 
6521      if( matsave != NULL ){
6522        if( ISVALID_MAT44(aff12_xyz) )
6523          matsave[kk] = aff12_xyz ;
6524        else
6525          LOAD_DIAG_MAT44(matsave[kk],1.0f,1.0f,1.0f) ;
6526      }
6527 
6528      /**-- store warped volume into the output dataset --**/
6529 
6530      if( dset_out != NULL ){
6531        MRI_IMAGE *aim = (stup.ajimor != NULL) ? stup.ajimor : stup.ajim ;
6532        /* lose obliquity if using 3dWarp for any transformation */
6533        /* recompute Tc (Cardinal transformation matrix for new grid output */
6534        THD_make_cardinal(dset_out);    /* needed for oblique NIFTI datasets - 07/03/14 drg */
6535 
6536        if( verb > 1 ) INFO_message("Computing output image") ;
6537 #if 0
6538 mri_genalign_set_pgmat(1) ;
6539 #endif
6540 
6541        switch( apply_mode ){  /* are we applying a matrix or parameter set? */
6542 
6543          default:             /* applying parameter set */
6544 
6545            AL_setup_warp_coords( epi_targ,epi_fe,epi_pe,epi_se,
6546                                  nxyz_dout, dxyz_dout, cmat_bout,
6547                                  nxyz_targ, dxyz_targ, cmat_tout ) ;
6548 
6549            if( im_targ_vector == NULL ){
6550              im_targ = mri_genalign_scalar_warpone(
6551                                    stup.wfunc_numpar , parsave[kk] , stup.wfunc ,
6552                                    aim , nxout,nyout,nzout, final_interp ) ;
6553            } else { /* RGB image [12 May 2020] */
6554              im_targ = mri_genalign_scalar_warpone(
6555                                    stup.wfunc_numpar , parsave[kk] , stup.wfunc ,
6556                                    im_targ_vector , nxout,nyout,nzout, final_interp ) ;
6557              mri_free(im_targ_vector) ; im_targ_vector = NULL ;
6558            }
6559 
6560 #ifdef ALLOW_NWARP /*********************************************************/
6561            if( nwarp_save_prefix != NULL ){  /* 10 Dec 2010: save map of warp itself */
6562              THD_3dim_dataset *wset; MRI_IMARR *wimar;
6563              MRI_IMAGE *xim,*yim,*zim,*vim=NULL; int iv=0,nw;
6564              wimar = mri_genalign_scalar_xyzwarp(
6565                                  stup.wfunc_numpar , parsave[kk] , stup.wfunc ,
6566                                  nxout , nyout , nzout ) ;
6567              nw = IMARR_COUNT(wimar) ;
6568              wset = EDIT_empty_copy(dset_out) ;
6569              EDIT_dset_items( wset ,
6570                                 ADN_prefix    , nwarp_save_prefix ,
6571                                 ADN_nvals     , (twodim_code) ? nw-1 : nw ,
6572                                 ADN_ntt       , 0 ,
6573                                 ADN_datum_all , MRI_float ,
6574                               ADN_none ) ;
6575              xim = IMARR_SUBIM(wimar,0); yim = IMARR_SUBIM(wimar,1);
6576              zim = IMARR_SUBIM(wimar,2); if( nw == 4 ) vim = IMARR_SUBIM(wimar,3) ;
6577              FREE_IMARR(wimar) ;
6578              if( twodim_code != 1 ){
6579                EDIT_BRICK_LABEL( wset , iv , "x_delta" ) ;
6580                EDIT_substitute_brick(wset,iv,MRI_float,MRI_FLOAT_PTR(xim)) ;
6581                mri_clear_data_pointer(xim) ; iv++ ;
6582              }
6583              if( twodim_code != 2 ){
6584                EDIT_BRICK_LABEL( wset , iv , "y_delta" ) ;
6585                EDIT_substitute_brick(wset,iv,MRI_float,MRI_FLOAT_PTR(yim)) ;
6586                mri_clear_data_pointer(yim) ; iv++ ;
6587              }
6588              if( twodim_code != 3 ){
6589                EDIT_BRICK_LABEL( wset , iv , "z_delta" ) ;
6590                EDIT_substitute_brick(wset,iv,MRI_float,MRI_FLOAT_PTR(zim)) ;
6591                mri_clear_data_pointer(zim) ; iv++ ;
6592              }
6593              if( vim != NULL ){
6594                EDIT_BRICK_LABEL( wset , iv , "hexvol" ) ;
6595                EDIT_substitute_brick(wset,iv,MRI_float,MRI_FLOAT_PTR(vim)) ;
6596                mri_clear_data_pointer(vim) ; mri_free(vim) ; iv++ ;
6597              }
6598              mri_free(xim) ; mri_free(yim) ; mri_free(zim) ;
6599              DSET_write(wset) ; WROTE_DSET(wset) ; DSET_delete(wset) ;
6600            } /* end of nwarp_save */
6601 #endif /* ALLOW_NWARP */ /**************************************************/
6602 
6603          break ;  /* end of default case */
6604 
6605          case APPLY_AFF12:{   /* applying a matrix */
6606            float ap[12] ;
6607            wmat = MAT44_MUL(aff12_xyz,mast_cmat) ;
6608            qmat = MAT44_MUL(targ_cmat_inv,wmat) ;  /* index transform matrix */
6609            UNLOAD_MAT44_AR(qmat,ap) ;
6610            if( im_targ_vector == NULL ){
6611              im_targ = mri_genalign_scalar_warpone(
6612                                    12 , ap , mri_genalign_mat44 ,
6613                                    aim , nxout,nyout,nzout, final_interp ) ;
6614            } else { /* RGB image [12 May 2020] - transform components */
6615              im_targ = mri_genalign_scalar_warpone(
6616                                    12 , ap , mri_genalign_mat44 ,
6617                                    im_targ_vector , nxout,nyout,nzout, final_interp ) ;
6618              mri_free(im_targ_vector) ; im_targ_vector = NULL ;
6619            }
6620          }
6621          break ;
6622 
6623        } /* end of switch on apply_mode */
6624 
6625        /*--- 04 Apr 2007: save matrix into dataset header ---*/
6626 
6627        { static mat44 gam , gami ; char anam[64] ; float matar[12] , *psav ;
6628 
6629          if( matsave != NULL )
6630            gam = matsave[kk] ;
6631          else if( ISVALID_MAT44(aff12_xyz) )
6632            gam = aff12_xyz ;
6633          else
6634            mri_genalign_affine_get_gammaxyz( &gam ) ;  /* should not happen */
6635 
6636          /* set the header attribute */
6637 
6638          if( ISVALID_MAT44(gam) ){
6639            sprintf(anam,"ALLINEATE_MATVEC_B2S_%06d",kk) ;
6640            UNLOAD_MAT44_AR(gam,matar) ;
6641            THD_set_float_atr( dset_out->dblk , anam , 12 , matar ) ;
6642            gami = MAT44_INV(gam) ;
6643            sprintf(anam,"ALLINEATE_MATVEC_S2B_%06d",kk) ;
6644            UNLOAD_MAT44_AR(gami,matar) ;
6645            THD_set_float_atr( dset_out->dblk , anam , 12 , matar ) ;
6646          }
6647 
6648          /* 22 Feb 2010: save the parameters as well */
6649 
6650          if( kk == 0 && *warp_code_string != '\0' )
6651            THD_set_string_atr( dset_out->dblk , "ALLINEATE_WARP_TYPE" , warp_code_string ) ;
6652 
6653          psav = (float *)malloc(sizeof(float)*stup.wfunc_numpar) ;
6654          for( jj=0 ; jj < stup.wfunc_numpar ; jj++ )
6655            psav[jj] = stup.wfunc_param[jj].val_out ;
6656          sprintf(anam,"ALLINEATE_PARAMS_%06d",kk) ;
6657          THD_set_float_atr( dset_out->dblk , anam , stup.wfunc_numpar , psav ) ;
6658          free(psav) ;
6659 
6660        }
6661 
6662        /*--- save sub-brick without scaling factor ---*/
6663 
6664        if( targ_was_vector ){                  /* RGB image [12 May 2020] */
6665          EDIT_substitute_brick( dset_out ,kk ,
6666                                 im_targ->kind , mri_data_pointer(im_targ) ) ;
6667          mri_clear_data_pointer(im_targ) ;
6668        } else if( floatize || targ_kind == MRI_float ){
6669          EDIT_substitute_brick( dset_out,kk,MRI_float, MRI_FLOAT_PTR(im_targ) );
6670          mri_clear_data_pointer(im_targ) ;  /* data in im_targ saved directly */
6671        } else {
6672          EDIT_substscale_brick( dset_out,kk,MRI_float, MRI_FLOAT_PTR(im_targ),
6673                                 targ_kind ,
6674                                 (bfac == 0.0f) ? 1.0f : 0.0f ) ;
6675        }
6676        mri_free(im_targ) ; im_targ = NULL ;
6677 
6678        if( usetemp && DSET_NVALS(dset_out) > 1 )   /* 31 Jan 2007 */
6679          mri_purge( DSET_BRICK(dset_out,kk) ) ;
6680      }
6681 
6682      MEMORY_CHECK("end of sub-brick alignment") ;
6683 
6684    } /***------------- end of loop over target sub-bricks ------------------***/
6685 
6686    /*--------------- unload stuff we no longer need --------------------------*/
6687 
6688    if( verb > 1 ) INFO_message("Unloading unneeded data") ;
6689 
6690    DSET_unload(dset_targ) ;
6691    mri_free(im_base); mri_free(im_weig); mri_free(im_mask);
6692 #ifdef ALLOW_UNIFIZE
6693    mri_free(im_ubase);
6694 #endif
6695 
6696    MRI_FREE(stup.bsim); MRI_FREE(stup.bsims);
6697    MRI_FREE(stup.ajim); MRI_FREE(stup.ajims); MRI_FREE(stup.bwght);
6698    MRI_FREE(stup.ajimor);
6699 
6700    /***--- write output dataset to disk? ---***/
6701 
6702    MEMORY_CHECK("end of sub-brick loop (after cleanup)") ;
6703 
6704    if( dset_out != NULL ){
6705      DSET_write(dset_out); WROTE_DSET(dset_out); DSET_unload(dset_out);
6706      MEMORY_CHECK("after writing output dataset") ;
6707    }
6708 
6709    /*--- save parameters to a file, if desired ---*/
6710 
6711    if( param_save_1D != NULL && parsave != NULL ){
6712      FILE *fp ;
6713      fp = (strcmp(param_save_1D,"-") == 0) ? stdout
6714                                            : fopen(param_save_1D,"w") ;
6715      if( fp == NULL ) ERROR_exit("Can't open -1Dparam_save %s for output!?",param_save_1D);
6716      fprintf(fp,"# 3dAllineate parameters:\n") ;
6717      fprintf(fp,"#") ;
6718      for( jj=0 ; jj < stup.wfunc_numpar ; jj++ )         /* 04 Dec 2010 */
6719        fprintf(fp," %s%c" , stup.wfunc_param[jj].name ,  /* add '$' for frozen */
6720                 (stup.wfunc_param[jj].fixed == 2) ? '$' : ' ' ) ;
6721      fprintf(fp,"\n") ;
6722      for( kk=0 ; kk < DSET_NVALS(dset_targ) ; kk++ ){
6723        for( jj=0 ; jj < stup.wfunc_numpar ; jj++ )
6724          fprintf(fp," %.6f",parsave[kk][jj]) ;
6725        fprintf(fp,"\n") ;                           /* oops */
6726      }
6727      if( fp != stdout ){
6728        fclose(fp) ; if( verb ) INFO_message("Wrote -1Dparam_save %s",param_save_1D) ;
6729      }
6730    }
6731 
6732    /*--- save matrices to disk, if so ordered by the omniscient user ---*/
6733 
6734    if( matrix_save_1D != NULL && matsave != NULL ){
6735      FILE *fp ;
6736      float a11,a12,a13,a14,a21,a22,a23,a24,a31,a32,a33,a34 ;
6737      fp = (strcmp(matrix_save_1D,"-") == 0) ? stdout
6738                                             : fopen(matrix_save_1D,"w") ;
6739      if( fp == NULL ) ERROR_exit("Can't open -1Dmatrix_save %s for output!?",matrix_save_1D);
6740      fprintf(fp,"# 3dAllineate matrices (DICOM-to-DICOM, row-by-row):\n") ;
6741      for( kk=0 ; kk < DSET_NVALS(dset_targ) ; kk++ ){
6742        UNLOAD_MAT44(matsave[kk],a11,a12,a13,a14,a21,a22,a23,a24,a31,a32,a33,a34) ;
6743        fprintf(fp,
6744                " %13.6g %13.6g %13.6g %13.6g %13.6g %13.6g %13.6g %13.6g %13.6g %13.6g %13.6g %13.6g\n",
6745                a11,a12,a13,a14,a21,a22,a23,a24,a31,a32,a33,a34 ) ;
6746      }
6747      if( fp != stdout ){
6748        fclose(fp) ; if( verb ) INFO_message("Wrote -1Dmatrix_save %s",matrix_save_1D) ;
6749      }
6750    }
6751 
6752    /*--------------- FREE AT LAST, FREE AT LAST (almost) ------------------*/
6753 
6754    FREE_GA_setup(&stup) ;
6755    if( parsave != NULL ){
6756      for( kk=0 ; kk < DSET_NVALS(dset_targ) ; kk++ )
6757        if( parsave[kk] != NULL ) free((void *)parsave[kk]) ;
6758      free((void *)parsave) ;
6759    }
6760    if( matsave != NULL ) free((void *)matsave) ;
6761 
6762    if( 1 || verb )
6763      INFO_message("3dAllineate: total CPU time = %.1f sec  Elapsed = %.1f\n",
6764                   COX_cpu_time() , COX_clock_time() ) ;
6765    MEMORY_CHECK("end of program (after final cleanup)") ;
6766    if( verb && apply_1D == NULL && prefix != NULL ){
6767     INFO_message(  "###########################################################");
6768     INFO_message(  "#   PLEASE check results VISUALLY for alignment quality   #");
6769 
6770     if( (meth_code == GA_MATCH_PEARSON_LOCALS   ||
6771          meth_code == GA_MATCH_PEARSON_LOCALA   ||
6772          meth_code == GA_MATCH_LPC_MICHO_SCALAR ||
6773          meth_code == GA_MATCH_LPA_MICHO_SCALAR   ) &&
6774         (!wtspecified)                                 ){
6775       INFO_message("###########################################################");
6776       INFO_message("#     '-autoweight' or some other voxelwise weighting     #");
6777       INFO_message("#     method is recommended when using -lpc or -lpa       #");
6778       INFO_message("#     If your results are not good, please try again.     #");
6779      }
6780    }
6781    if( verb ){
6782       INFO_message("###########################################################");
6783    }
6784    if( !do_cmass && CMbad > 0 ){ /* 26 Feb 2020 */
6785      ININFO_message (" ") ;
6786      INFO_message   ("***********************************************************") ;
6787      WARNING_message("-cmass was turned off, but might have been needed :("       ) ;
6788      ININFO_message ("          Please check your results - PLEASE PLEASE PLEASE" ) ;
6789      INFO_message   ("***********************************************************") ;
6790    }
6791 
6792    exit(0) ;
6793 }
6794 
6795 /*---------------------------------------------------------------------------*/
6796 /*! Turn an input image into a weighting factor (for -autoweight).
6797     If acod == 2, then make a binary mask at the end.
6798     If acod == 3, then make a boxed binary mask at the end.
6799 -----------------------------------------------------------------------------*/
6800 
mri_weightize(MRI_IMAGE * im,int acod,int ndil,float aclip,float apow)6801 MRI_IMAGE * mri_weightize( MRI_IMAGE *im, int acod, int ndil, float aclip, float apow )
6802 {
6803    float *wf,clip,clip2 ;
6804    int xfade,yfade,zfade , nx,ny,nz,nxy,nxyz , ii,jj,kk,ff ;
6805    byte *mmm ;
6806    MRI_IMAGE *qim , *wim ;
6807 
6808    /*-- copy input image --*/
6809 
6810    qim = mri_to_float(im) ; wf = MRI_FLOAT_PTR(qim) ;
6811    nx = qim->nx; ny = qim->ny; nz = qim->nz; nxy = nx*ny; nxyz = nxy*nz;
6812    for( ii=0 ; ii < nxyz ; ii++ ) wf[ii] = fabsf(wf[ii]) ;
6813 
6814    /*-- zero out along the edges --*/
6815 #undef  WW
6816 #define WW(i,j,k) wf[(i)+(j)*nx+(k)*nxy]
6817 
6818    xfade = (int)(0.05*qim->nx+3.0) ;                 /* number of points */
6819    yfade = (int)(0.05*qim->ny+3.0) ;                 /* along each face */
6820    zfade = (int)(0.05*qim->nz+3.0) ;                 /* to set to zero */
6821    if( 5*xfade >= qim->nx ) xfade = (qim->nx-1)/5 ;
6822    if( 5*yfade >= qim->ny ) yfade = (qim->ny-1)/5 ;
6823    if( 5*zfade >= qim->nz ) zfade = (qim->nz-1)/5 ;
6824    if( verb > 1 )
6825      ININFO_message("Weightize: xfade=%d yfade=%d zfade=%d",xfade,yfade,zfade);
6826    for( jj=0 ; jj < ny ; jj++ )
6827     for( ii=0 ; ii < nx ; ii++ )
6828      for( ff=0 ; ff < zfade ; ff++ ) WW(ii,jj,ff) = WW(ii,jj,nz-1-ff) = 0.0f;
6829    for( kk=0 ; kk < nz ; kk++ )
6830     for( jj=0 ; jj < ny ; jj++ )
6831      for( ff=0 ; ff < xfade ; ff++ ) WW(ff,jj,kk) = WW(nx-1-ff,jj,kk) = 0.0f;
6832    for( kk=0 ; kk < nz ; kk++ )
6833     for( ii=0 ; ii < nx ; ii++ )
6834      for( ff=0 ; ff < yfade ; ff++ ) WW(ii,ff,kk) = WW(ii,ny-1-ff,kk) = 0.0f;
6835 
6836    if( aclip > 0.0f ){  /* 31 Jul 2007 */
6837      int nleft , nclip ;
6838      for( nclip=nleft=ii=0 ; ii < nxyz ; ii++ ){
6839        if( wf[ii] > 0.0f ){
6840          if( wf[ii] < aclip ){ nclip++; wf[ii] = 0.0f; } else nleft++ ;
6841        }
6842      }
6843      if( verb > 1 ) ININFO_message("Weightize: user clip=%g #clipped=%d #left=%d",
6844                                    aclip,nclip,nleft) ;
6845    }
6846 
6847    /*-- squash super-large values down to reasonability --*/
6848 
6849    clip = 3.0f * THD_cliplevel(qim,0.5f) ;
6850    if( verb > 1 ) ININFO_message("Weightize: (unblurred) top clip=%g",clip) ;
6851    for( ii=0 ; ii < nxyz ; ii++ ) if( wf[ii] > clip ) wf[ii] = clip ;
6852 
6853    /*-- blur a little: median then Gaussian;
6854           the idea is that the median filter smashes localized spikes,
6855           then the Gaussian filter does a litte extra general smoothing. --*/
6856 
6857    mmm = (byte *)malloc( sizeof(byte)*nxyz ) ;
6858    for( ii=0 ; ii < nxyz ; ii++ ) mmm[ii] = (wf[ii] > 0.0f) ; /* mask */
6859    if( wt_medsmooth > 0.0f ){
6860      wim = mri_medianfilter( qim , wt_medsmooth , mmm , 0 ) ; mri_free(qim) ;
6861    } else {
6862      wim = qim ;
6863    }
6864    wf = MRI_FLOAT_PTR(wim) ;
6865    if( wt_gausmooth > 0.0f )
6866      FIR_blur_volume_3d( wim->nx , wim->ny , wim->nz ,
6867                          1.0f , 1.0f , 1.0f ,  wf ,
6868                          wt_gausmooth , wt_gausmooth , wt_gausmooth ) ;
6869 
6870    /*-- clip off small values, and
6871         keep only the largest cluster of supra threshold voxels --*/
6872 
6873    clip  = 0.05f * mri_max(wim) ;
6874    clip2 = 0.33f * THD_cliplevel(wim,0.33f) ;
6875    clip  = MAX(clip,clip2) ;
6876    if( verb > 1 ) ININFO_message("Weightize: (blurred) bot clip=%g",clip) ;
6877    for( jj=ii=0 ; ii < nxyz ; ii++ ){
6878      if( wf[ii] >= clip ){ jj++ ; mmm[ii] = 1 ; }
6879      else                {        mmm[ii] = 0 ; }
6880    }
6881    if( verb > 1 ) ININFO_message("Weightize: %d voxels survive clip",jj) ;
6882    if( ! doing_2D ){                          /* 28 Apr 2020 */
6883      THD_mask_clust( nx,ny,nz, mmm ) ;
6884      THD_mask_erode( nx,ny,nz, mmm, 1, 2 ) ;  /* cf. thd_automask.c NN2 */
6885      THD_mask_clust( nx,ny,nz, mmm ) ;
6886    } else {
6887      THD_mask_remove_isolas( nx,ny,nz , mmm ) ;
6888    }
6889    for( jj=nxyz,ii=0 ; ii < nxyz ; ii++ ){
6890      if( !mmm[ii] ){ wf[ii] = 0.0f ; jj-- ; }
6891    }
6892    free((void *)mmm) ;
6893    if( verb > 1 ) ININFO_message("Weightize: %d voxels survive clusterize",jj) ;
6894 
6895    /*-- convert to 0..1 range [10 Sep 2007] --*/
6896 
6897    clip = 0.0f ;
6898    for( ii=0 ; ii < nxyz ; ii++ ) if( wf[ii] > clip ) clip = wf[ii] ;
6899    if( clip == 0.0f )
6900      ERROR_exit("Can't compute autoweight: max value seen as 0") ;
6901    clip = 1.0f / clip ;
6902    for( ii=0 ; ii < nxyz ; ii++ ) wf[ii] *= clip ;
6903 
6904    /*-- power? --*/
6905 
6906    if( apow > 0.0f && apow != 1.0f ){
6907      if( verb > 1 ) ININFO_message("Weightize: raising to %g power",apow) ;
6908      for( ii=0 ; ii < nxyz ; ii++ )
6909        if( wf[ii] > 0.0f ) wf[ii] = powf( wf[ii] , apow ) ;
6910    }
6911 
6912    /*-- binarize (acod==2)?  boxize (acod==3)? --*/
6913 
6914 #undef  BPAD
6915 #define BPAD 4
6916    if( acod == 2 || acod == 3 ){  /* binary weight: mask=2 or maskbox=3 */
6917      if( verb > 1 ) ININFO_message("Weightize: binarizing") ;
6918      for( ii=0 ; ii < nxyz ; ii++ ) if( wf[ii] != 0.0f ) wf[ii] = 1.0f ;
6919      if( ndil > 0 ){  /* 01 Mar 2007: dilation */
6920        byte *mmm = (byte *)malloc(sizeof(byte)*nxyz) ;
6921        if( verb > 1 ) ININFO_message("Weightize: dilating") ;
6922        for( ii=0 ; ii < nxyz ; ii++ ) mmm[ii] = (wf[ii] != 0.0f) ;
6923        for( ii=0 ; ii < ndil ; ii++ ){
6924          THD_mask_dilate     ( nx,ny,nz , mmm , 3, 2 ) ;
6925          THD_mask_fillin_once( nx,ny,nz , mmm , 2 ) ;
6926        }
6927        for( ii=0 ; ii < nxyz ; ii++ ) wf[ii] = (float)mmm[ii] ;
6928        free(mmm) ;
6929      }
6930      if( acod == 3 ){  /* boxize */
6931        int xm,xp , ym,yp , zm,zp ;
6932        MRI_autobbox_clust(0) ;
6933        MRI_autobbox( wim , &xm,&xp , &ym,&yp , &zm,&zp ) ;
6934        xm -= BPAD ; if( xm < 1    ) xm = 1 ;
6935        ym -= BPAD ; if( ym < 1    ) ym = 1 ;
6936        zm -= BPAD ; if( zm < 1    ) zm = 1 ;
6937        xp += BPAD ; if( xp > nx-2 ) xp = nx-2 ;
6938        yp += BPAD ; if( yp > ny-2 ) yp = ny-2 ;
6939        zp += BPAD ; if( zp > nz-2 ) zp = nz-2 ;
6940        if( verb > 1 )
6941          ININFO_message("Weightize: box=%d..%d X %d..%d X %d..%d = %d voxels",
6942                         xm,xp , ym,yp , zm,zp , (xp-xm+1)*(yp-ym+1)*(zp-zm+1) ) ;
6943        for( kk=zm ; kk <= zp ; kk++ )
6944         for( jj=ym ; jj <= yp ; jj++ )
6945          for( ii=xm ; ii <= xp ; ii++ ) WW(ii,jj,kk) = 1.0f ;
6946      }
6947    }
6948 
6949    return wim ;
6950 }
6951 
6952 /*---------------------------------------------------------------------------*/
6953 /*! Return the L_infinity distance between two parameter vectors. */
6954 
param_dist(GA_setup * stp,float * aa,float * bb)6955 float param_dist( GA_setup *stp , float *aa , float *bb )
6956 {
6957    int jj ; float ap, bp, pdist, dmax ;
6958 
6959    if( stp == NULL || aa == NULL || bb == NULL ) return 1.0f ;
6960 
6961    dmax = 0.0f ;
6962    for( jj=0 ; jj < stp->wfunc_numpar ; jj++ ){
6963      if( !stp->wfunc_param[jj].fixed ){
6964        ap = aa[jj] ; bp = bb[jj] ;
6965        pdist = fabsf(ap-bp)
6966               / (stp->wfunc_param[jj].max - stp->wfunc_param[jj].min) ;
6967        if( pdist > dmax ) dmax = pdist ;
6968      }
6969    }
6970    return dmax ;
6971 }
6972 
6973 /*---------------------------------------------------------------------------*/
6974 /*! Setup before and after index-to-coordinate matrices in the warp func.
6975     See the notes at the end of this file for the gruesome details.
6976 -----------------------------------------------------------------------------*/
6977 
AL_setup_warp_coords(int epi_targ,int epi_fe,int epi_pe,int epi_se,int * nxyz_base,float * dxyz_base,mat44 base_cmat,int * nxyz_targ,float * dxyz_targ,mat44 targ_cmat)6978 void AL_setup_warp_coords( int epi_targ , int epi_fe, int epi_pe, int epi_se,
6979                            int *nxyz_base, float *dxyz_base, mat44 base_cmat,
6980                            int *nxyz_targ, float *dxyz_targ, mat44 targ_cmat )
6981 {
6982    mat44 cmat_before , imat_after , gmat,tmat,qmat ;
6983    float *dijk ; int *nijk ;
6984 
6985    if( epi_targ < 0 ){            /*---------- no EPI info given ----------*/
6986 
6987      /* [it] = inv[Ct] [S] [D] [U] [Cb]     [ib]
6988                ------- ----------- --------
6989                [after] [transform] [before]      */
6990 
6991      imat_after  = MAT44_INV(targ_cmat) ;  /* xyz -> ijk for target */
6992      cmat_before = base_cmat ;             /* ijk -> xyz for base */
6993 
6994    } else if( epi_targ == 1 ){  /*---------- target is EPI --------------*/
6995 
6996      dijk = dxyz_targ ; nijk = nxyz_targ ;
6997 
6998      /* -FPS kij should have           [ 0  0  dk -mk ]
6999                               [gmat] = [ di 0  0  -mi ]
7000                                        [ 0  dj 0  -mj ]
7001                                        [ 0  0  0   1  ]
7002         In this example, epi_fe=2, epi_pe=0, epi_se=1   */
7003 
7004      ZERO_MAT44(gmat) ;
7005      gmat.m[0][epi_fe] = dijk[epi_fe] ;
7006      gmat.m[1][epi_pe] = dijk[epi_pe] ;
7007      gmat.m[2][epi_se] = dijk[epi_se] ;
7008      gmat.m[0][3]      = -0.5f * dijk[epi_fe] * (nijk[epi_fe]-1) ;
7009      gmat.m[1][3]      = -0.5f * dijk[epi_pe] * (nijk[epi_pe]-1) ;
7010      gmat.m[2][3]      = -0.5f * dijk[epi_se] * (nijk[epi_se]-1) ;
7011 
7012      /* [it] = inv[Gt] [S] [D] [U] inv[Rt] [Cb] [ib]
7013                ------- ----------- ------------
7014                [after] [transform] [before]        where [Ct] = [Rt] [Gt] */
7015 
7016      imat_after  = MAT44_INV(gmat) ;
7017      tmat        = MAT44_INV(targ_cmat) ;       /* inv[Ct] */
7018      qmat        = MAT44_MUL(tmat,base_cmat) ;  /* inv[Ct] [Cb] */
7019      cmat_before = MAT44_MUL(gmat,qmat) ;       /* [G] inv[Ct] [Cb] */
7020 
7021    } else {                     /*---------- base is EPI ----------------*/
7022 
7023      dijk = dxyz_base ; nijk = nxyz_base ;
7024 
7025      ZERO_MAT44(gmat) ;
7026      gmat.m[0][epi_fe] = dijk[epi_fe] ;
7027      gmat.m[1][epi_pe] = dijk[epi_pe] ;
7028      gmat.m[2][epi_se] = dijk[epi_se] ;
7029      gmat.m[0][3]      = -0.5f * dijk[epi_fe] * (nijk[epi_fe]-1) ;
7030      gmat.m[1][3]      = -0.5f * dijk[epi_pe] * (nijk[epi_pe]-1) ;
7031      gmat.m[2][3]      = -0.5f * dijk[epi_se] * (nijk[epi_se]-1) ;
7032 
7033      /*  [it] = inv[Ct] [Rb] [U] [S] [D] [Gb]     [ib]
7034                 ------------ ----------- --------
7035                 [after]      [transform] [before]  where [Cb] = [Rb] [Gb] */
7036 
7037      cmat_before = gmat ;                       /* [Gb] */
7038      qmat        = MAT44_INV(gmat) ;            /* inv[Gb] */
7039      qmat        = MAT44_MUL(base_cmat,qmat) ;  /* [Cb] inv[Gb] = [Rb] */
7040      tmat        = MAT44_INV(targ_cmat) ;       /* inv[Ct] */
7041      imat_after  = MAT44_MUL(tmat,qmat) ;       /* inv[Ct] [Rb] */
7042    }
7043 
7044    /*-- actually let the warping function 'know' about these matrices --*/
7045 
7046    mri_genalign_affine_set_befafter( &cmat_before , &imat_after ) ;
7047 
7048    return ;
7049 }
7050 
7051 /* create MRI_IMAGE Identity parameters (not affine matrix) */
mri_identity_params(void)7052 MRI_IMAGE * mri_identity_params(void)
7053 {
7054 
7055    MRI_IMAGE *om;
7056    float id[] = {0,0,0, 0,0,0, 1,1,1, 0,0,0};
7057    float *oar;
7058    int ii;
7059 
7060    om  = mri_new( 12 , 1 , MRI_float ) ;
7061    oar = MRI_FLOAT_PTR(om) ;
7062 
7063    for( ii=0 ; ii < 12 ; ii++ )
7064          oar[ii] = id[ii] ;
7065 
7066    RETURN(om) ;
7067 }
7068 
7069 #ifdef USE_OMP
7070 #include "mri_genalign_util.c"
7071 #include "mri_genalign.c"
7072 #include "thd_correlate.c"
7073 #endif
7074 
7075 /*----------------------------------------------------------------------------*/
7076 #if 0
7077 #undef  MMM
7078 #define MMM(i,j,k) mmm[(i)+(j)*nx+(k)*nxy]
7079 
7080 int * mri_edgesize( MRI_IMAGE *im )  /* 13 Aug 2007 */
7081 {
7082    byte *mmm ;
7083    int ii,jj,kk , nx,ny,nz , nxy ;
7084    static int eijk[6] ;
7085 
7086 ENTRY("mri_edgesize") ;
7087 
7088    if( im == NULL ) RETURN( NULL );
7089 
7090    nx = im->nx ; ny = im->ny ; nz = im->nz ; nxy = nx*ny ;
7091 
7092    STATUS("automask-ing on the cheap") ;
7093 
7094    THD_automask_set_cheapo(1) ;
7095    mmm = mri_automask_image( im ) ;
7096    if( mmm == NULL ) RETURN( NULL );
7097 
7098    /* check i-direction */
7099 
7100    STATUS("check i-direction") ;
7101 
7102    for( ii=0 ; ii < nx ; ii++ ){
7103      for( kk=0 ; kk < nz ; kk++ ){
7104        for( jj=0 ; jj < ny ; jj++ ) if( MMM(ii,jj,kk) ) goto I1 ;
7105    }}
7106  I1: eijk[0] = ii ;
7107    for( ii=nx-1 ; ii >= 0 ; ii-- ){
7108      for( kk=0 ; kk < nz ; kk++ ){
7109        for( jj=0 ; jj < ny ; jj++ ) if( MMM(ii,jj,kk) ) goto I2 ;
7110    }}
7111  I2: eijk[1] = nx-1-ii ;
7112 
7113    /* check j-direction */
7114 
7115    STATUS("check j-direction") ;
7116 
7117    for( jj=0 ; jj < ny ; jj++ ){
7118      for( kk=0 ; kk < nz ; kk++ ){
7119        for( ii=0 ; ii < nx ; ii++ ) if( MMM(ii,jj,kk) ) goto J1 ;
7120    }}
7121  J1: eijk[2] = jj ;
7122      for( jj=ny-1 ; jj >= 0 ; jj-- ){
7123        for( kk=0 ; kk < nz ; kk++ ){
7124          for( ii=0 ; ii < nx ; ii++ ) if( MMM(ii,jj,kk) ) goto J2 ;
7125      }}
7126  J2: eijk[3] = ny-1-jj ;
7127 
7128    /* check k-direction */
7129 
7130    STATUS("check k-direction") ;
7131 
7132    for( kk=0 ; kk < nz ; kk++ ){
7133      for( jj=0 ; jj < ny ; jj++ ){
7134        for( ii=0 ; ii < nx ; ii++ ) if( MMM(ii,jj,kk) ) goto K1 ;
7135    }}
7136  K1: eijk[4] = kk ;
7137    for( kk=nz-1 ; kk >= 0 ; kk-- ){
7138      for( jj=0 ; jj < ny ; jj++ ){
7139        for( ii=0 ; ii < nx ; ii++ ) if( MMM(ii,jj,kk) ) goto K2 ;
7140    }}
7141  K2: eijk[5] = nz-1-kk ;
7142 
7143    free(mmm) ; RETURN( eijk );
7144 }
7145 #endif
7146 
7147 /******************************************************************************
7148 *******************************************************************************
7149 
7150        ==============================================================
7151      ===== Notes on Coordinates and Indexes - RWCox - 05 Oct 2006 =====
7152        ==============================================================
7153 
7154 The base and target datasets each have their own coordinate systems and
7155 indexes.  We use 4x4 matrices to represent affine transformations, and
7156 4-vectors to represent coordinates and indexes.  (The last row of a 4x4
7157 matrix is [0 0 0 1] and the last element of a 4-vector is always 1.)
7158 The index-to-coordinate transformations for base and target are given by
7159 
7160   [xb] = [Cb] [ib]
7161   [xt] = [Ct] [it]
7162 
7163 where [Cb] and [Ct] are the dset->daxes->ijk_to_dicom matrices in the
7164 datasets' header.
7165 
7166 The 4x4 affine transformation matrix is not directly parametrized by its 12
7167 non-trivial elements.  To give control over and meaning to the parameters,
7168 the matrix is instead modeled as
7169 
7170   [T] = [S] [D] [U]
7171 
7172 where [S] is a shear matrix, [D] is a diagonal scaling matrix, and [U] is
7173 a proper orthogonal matrix.  If we wish to restrict the transformation [T]
7174 to rigid body movement, for example, then we can fix the [S] and [D]
7175 matrices to be the identity.
7176 
7177 N.B.: The shift matrix [H] can be inserted before or after the [S][D][U]
7178 product, as desired, so we'd really have [H][S][D][U] for dcode==DELTA_AFTER
7179 and [S][D][U][H] for dcode==DELTA_BEFORE.  [H] must be a matrix of the form
7180    [ 1 0 0 a ]
7181    [ 0 1 0 b ]
7182    [ 0 0 1 c ]
7183    [ 0 0 0 1 ]
7184 where {a,b,c} are the shifts.  I will ignore [H] in what follows.  Also,
7185 the order [S][D][U] can be altered by the user, which I'll pretty much
7186 ignore below, as well.
7187 
7188 For EPI data, we may want to restrict the transformation parameters so as
7189 to treat the phase-encoding direction differently than the frequency- and
7190 slice-encoding directions.  However, the matrices as described above mean
7191 that the [T] matrix components apply to DICOM coordinates, which may not
7192 be aligned with the FPS directions in the image.  In such a case, putting
7193 restrictions on the [T] parameters will not translate in a simple way into
7194 FPS coordinates.
7195 
7196 The solution is to break the transformation from indexes to spatial
7197 coordinates into two pieces.  Let [C] = [R] [G], where [C] is an index-to
7198 DICOM space matrix, [G] is a matrix that transforms indexes to FPS coordinates,
7199 and [R] is "what's left" (should be a rotation matrix, possibly with
7200 det[R]=-1).  A sample [G] is
7201 
7202         [ 0  0  dk -mk ]
7203   [G] = [ di 0  0  -mi ]
7204         [ 0  dj 0  -mj ]
7205         [ 0  0  0   1  ]
7206 
7207 where the dataset is stored with '-FPS kij':
7208   i=P (phase-encoding), j=S (slice-encoding), and k=F (frequency-encoding);
7209   d{i,j,k} is the grid spacing along the respective dimensions; and
7210   m{i,j,k} is the coordinate at the volume center: e.g., mi=0.5*di*(ni-1).
7211 (Here, 'i' refers to the first index in the dataset, etc.)
7212 
7213 If we break up [Ct] this way, then the transformation is
7214 
7215   [xt] = [S] [D] [U] [xb], or
7216   [xb] = inv[U] inv[D] inv[S] [xt]
7217        = inv[U] inv[D] inv[S] [Rt] [Gt] [it]
7218 
7219 and inv[T] is applied to the DICOM ordered coordinates in [Rt] [Gt] [it].
7220 If we want to apply inv[T] to the FPS ordered coordinates, then we change
7221 the last equation above to
7222 
7223   [xb] = [Rt] inv[U] inv[D] inv[S] [Gt] [it]
7224 
7225 where inv[T] is now applied to coordinates where xyz=FPS.  Now, restricting
7226 the parameters in [T] applies directly to FPS coordinates (e.g., fix the
7227 scaling factor in [D] along the z-axis to 1, and then there will be no
7228 stretching/shrinking of the data along the slice-encoding direction).  The
7229 final multiplication by [Rt] rotates the inv[T]-transformed FPS coordinates
7230 to DICOM order.
7231 
7232 So, if the target dataset is the EPI dataset, then the transformation from
7233 [ib] to [it] is expressed at
7234 
7235   [it] = inv[Gt] [S] [D] [U] inv[Rt] [Cb] [ib]
7236          ------- ----------- ------------
7237          [after] [transform] [before]
7238 
7239 where the [transform] matrix is what the parameter searching is all about,
7240 and the [before] and [after] matrices are fixed.
7241 
7242 If the base dataset is the EPI dataset, on the other hand, then the index-
7243 to-index transformation (what is really needed, after all) is
7244 
7245   [it] = inv[Ct] [Rb] [U] [D] [S] [Gb]     [ib]
7246          ------------ ----------- --------
7247          [after]      [transform] [before]
7248 
7249 (N.B.: The SDU order has been inverted to UDS, on the presumption that
7250 we will control the scaling and shear in the FPS coordinate system given
7251 by [Gb][ib].) In the 'normal' case, where either (a) we are going to allow
7252 full transform generality, or (b) no particular distortions of the image are
7253 to be specially allowed for, then we simply have
7254 
7255   [it] = inv[Ct] [S] [D] [U] [Cb]     [ib]
7256          ------- ----------- --------
7257          [after] [transform] [before]
7258 
7259 All of these cases are possible.  They will be especially important if/when
7260 nonlinear warping is allowed in place of the simple [S][D][U] transformation,
7261 the user needs to restrict the warping to occur only in the P-direction, and
7262 the data slices are oblique.
7263 
7264 *******************************************************************************
7265 *******************************************************************************/
7266