1 /*****************************************************************************
2    Major portions of this software are copyrighted by the Medical College
3    of Wisconsin, 1994-2000, and are released under the Gnu General Public
4    License, Version 2.  See the file README.Copyright for details.
5 ******************************************************************************/
6 
7 #include "afni.h"
8 
9 #ifndef ALLOW_PLUGINS
10 #  error "Plugins not properly set up -- see machdep.h"
11 #endif
12 
13 /***********************************************************************
14   Plugin to compute voxelwise mean, slope, or sigma of a 3D+time dataset.
15 ************************************************************************/
16 
17 /*--------------------- string to 'help' the user --------------------*/
18 
19 static char helpstring[] =
20   "Purpose: Compute mean, slope, or sigma of a 3D+time dataset.\n"
21   "Input items are:\n"
22   "   3d+time = 3D+time dataset to analyze\n"
23   "   Method  = Mean, Slope, or Sigma = type of analysis to do\n"
24   "   Ignore  = How many points to ignore at start\n"
25   "\n"
26   "Output: Prefix = Filename prefix for new dataset"
27 ;
28 
29 /*--------------------- strings for output format --------------------*/
30 
31 static char * method_strings[] = { "Mean" , "Slope" , "Sigma" , "CVar" } ;
32 
33 #define NUM_METHOD_STRINGS (sizeof(method_strings)/sizeof(char *))
34 
35 #define METH_MEAN  0
36 #define METH_SLOPE 1
37 #define METH_SIGMA 2
38 #define METH_CVAR  3
39 
40 /*----------------- prototypes for internal routines -----------------*/
41 
42 char * STATS_main( PLUGIN_interface * ) ;  /* the entry point */
43 
44 void STATS_tsfunc( double tzero , double tdelta ,
45                    int npts , float ts[] , double ts_mean , double ts_slope ,
46                    void * ud , float * val ) ;
47 
48 /*---------------------------- global data ---------------------------*/
49 
50 static PLUGIN_interface * global_plint = NULL ;
51 
52 /***********************************************************************
53    Set up the interface to the user:
54     1) Create a new interface using "PLUTO_new_interface";
55 
56     2) For each line of inputs, create the line with "PLUTO_add_option"
57          (this line of inputs can be optional or mandatory);
58 
59     3) For each item on the line, create the item with
60         "PLUTO_add_dataset" for a dataset chooser,
61         "PLUTO_add_string"  for a string chooser,
62         "PLUTO_add_number"  for a number chooser.
63 ************************************************************************/
64 
65 
66 DEFINE_PLUGIN_PROTOTYPE
67 
PLUGIN_init(int ncall)68 PLUGIN_interface * PLUGIN_init( int ncall )
69 {
70    PLUGIN_interface * plint ;     /* will be the output of this routine */
71 
72    if( ncall > 0 ) return NULL ;  /* only one interface */
73 
74    CHECK_IF_ALLOWED("3DSTATISTIC","3D+t Statistic") ;  /* 30 Sep 2016 */
75 
76    /*---------------- set titles and call point ----------------*/
77 
78    plint = PLUTO_new_interface( "3D+t Statistic" ,
79                                 "Voxel Statistics of 3D+time Dataset" ,
80                                 helpstring ,
81                                 PLUGIN_CALL_VIA_MENU , STATS_main  ) ;
82 
83    PLUTO_add_hint( plint , "Voxel Statistics of 3D+time Dataset" ) ;
84 
85    PLUTO_set_sequence( plint , "A:newdset:statistics" ) ;
86 
87    global_plint = plint ;  /* make global copy */
88 
89    /*--------- 1st line: Input dataset ---------*/
90 
91    PLUTO_add_option( plint ,
92                      "Input" ,  /* label at left of input line */
93                      "Input" ,  /* tag to return to plugin */
94                      TRUE       /* is this mandatory? */
95                    ) ;
96 
97    PLUTO_add_dataset(  plint ,
98                        "3D+time" ,        /* label next to button   */
99                        ANAT_ALL_MASK ,    /* take any anat datasets */
100                        FUNC_FIM_MASK ,    /* only allow fim funcs   */
101                        DIMEN_4D_MASK |    /* need 3D+time datasets  */
102                        BRICK_ALLREAL_MASK /* need real-valued datasets */
103                     ) ;
104 
105    PLUTO_add_hint( plint , "Choose input dataset" ) ;
106 
107    /*---------- 2nd line: other inputs ----------*/
108 
109    PLUTO_add_option( plint ,
110                      "Input" ,  /* label at left of input line */
111                      "Input" ,  /* tag to return to plugin */
112                      TRUE       /* is this mandatory? */
113                    ) ;
114 
115    PLUTO_add_hint( plint , "Control parameters" ) ;
116 
117    PLUTO_add_string( plint ,
118                      "Method" ,           /* label next to chooser button */
119                      NUM_METHOD_STRINGS , /* number of strings to choose among */
120                      method_strings ,     /* list of strings to choose among */
121                      0                    /* index of default string */
122                    ) ;
123 
124    PLUTO_add_hint( plint , "Choose statistic to compute" ) ;
125 
126    PLUTO_add_number( plint ,
127                      "Ignore" ,  /* label next to chooser */
128                      0 ,         /* smallest possible value */
129                      20 ,        /* largest possible value */
130                      0 ,         /* decimal shift (none in this case) */
131                      3 ,         /* default value */
132                      FALSE       /* allow user to edit value? */
133                    ) ;
134 
135    PLUTO_add_hint( plint , "Number of points to ignore at start of time series" ) ;
136 
137    /*---------- 3rd line: Output dataset ----------*/
138 
139    PLUTO_add_option( plint ,
140                      "Output" ,  /* label at left of input line */
141                      "Output" ,  /* tag to return to plugin */
142                      TRUE        /* is this mandatory? */
143                    ) ;
144 
145    PLUTO_add_string( plint ,
146                      "Prefix" ,  /* label next to textfield */
147                      0,NULL ,    /* no fixed strings to choose among */
148                      19          /* 19 spaces for typing in value */
149                    ) ;
150 
151    PLUTO_add_hint( plint , "Name of output dataset" ) ;
152 
153    /*--------- done with interface setup ---------*/
154 
155    return plint ;
156 }
157 
158 /***************************************************************************
159   Main routine for this plugin (will be called from AFNI).
160   If the return string is not NULL, some error transpired, and
161   AFNI will popup the return string in a message box.
162 ****************************************************************************/
163 
STATS_main(PLUGIN_interface * plint)164 char * STATS_main( PLUGIN_interface * plint )
165 {
166    MCW_idcode * idc ;                          /* input dataset idcode */
167    THD_3dim_dataset * old_dset , * new_dset ;  /* input and output datasets */
168    char * new_prefix , * str ;                 /* strings from user */
169    int meth , ignore ;
170 
171    /*--------------------------------------------------------------------*/
172    /*----- Check inputs from AFNI to see if they are reasonable-ish -----*/
173 
174    /*--------- go to first input line ---------*/
175 
176    PLUTO_next_option(plint) ;
177 
178    idc      = PLUTO_get_idcode(plint) ;   /* get dataset item */
179    old_dset = PLUTO_find_dset(idc) ;      /* get ptr to dataset */
180    if( old_dset == NULL )
181       return "*************************\n"
182              "Cannot find Input Dataset\n"
183              "*************************"  ;
184 
185    /*--------- go to next input line ---------*/
186 
187    PLUTO_next_option(plint) ;
188 
189    str  = PLUTO_get_string(plint) ;      /* get string item (the method) */
190    meth = PLUTO_string_index( str ,      /* find it in list it is from */
191                               NUM_METHOD_STRINGS ,
192                               method_strings ) ;
193 
194    ignore = PLUTO_get_number(plint) ;    /* get number item */
195 
196    /*--------- go to next input line ---------*/
197 
198    PLUTO_next_option(plint) ;
199 
200    new_prefix = PLUTO_get_string(plint) ;   /* get string item (the output prefix) */
201    if( ! PLUTO_prefix_ok(new_prefix) )      /* check if it is OK */
202       return "************************\n"
203              "Output Prefix is illegal\n"
204              "************************"  ;
205 
206    /*------------- ready to compute new dataset -----------*/
207 
208    new_dset = PLUTO_4D_to_fim( old_dset ,             /* input dataset */
209                                new_prefix ,           /* output prefix */
210                                ignore ,               /* ignore count */
211                                1 ,                    /* detrend = ON */
212                                STATS_tsfunc ,         /* timeseries processor */
213                                ITOP(meth)             /* data for tsfunc */
214                              ) ;
215 
216    PLUTO_add_dset( plint , new_dset , DSET_ACTION_MAKE_CURRENT ) ;
217 
218    return NULL ;  /* null string returned means all was OK */
219 }
220 
221 /**********************************************************************
222    Function that does the real work
223 ***********************************************************************/
224 
STATS_tsfunc(double tzero,double tdelta,int npts,float ts[],double ts_mean,double ts_slope,void * ud,float * val)225 void STATS_tsfunc( double tzero , double tdelta ,
226                    int npts , float ts[] , double ts_mean , double ts_slope ,
227                    void * ud , float * val )
228 {
229    int meth = PTOI(ud) ;
230    static int nvox , ncall ;
231 
232    /** is this a "notification"? **/
233 
234    if( val == NULL ){
235 
236       if( npts > 0 ){  /* the "start notification" */
237 
238          PLUTO_popup_meter( global_plint ) ;  /* progress meter  */
239          nvox  = npts ;                       /* keep track of   */
240          ncall = 0 ;                          /* number of calls */
241 
242       } else {  /* the "end notification" */
243 
244          PLUTO_set_meter( global_plint , 100 ) ; /* set meter to 100% */
245 
246       }
247       return ;
248    }
249 
250    /** OK, actually do some work **/
251 
252    switch( meth ){
253 
254       default:
255       case METH_MEAN:  *val = ts_mean  ; break ;
256 
257       case METH_SLOPE: *val = ts_slope ; break ;
258 
259       case METH_CVAR:
260       case METH_SIGMA:{
261          register int ii ;
262          register double sum ;
263 
264          sum = 0.0 ;
265          for( ii=0 ; ii < npts ; ii++ ) sum += ts[ii] * ts[ii] ;
266 
267          sum = sqrt( sum/(npts-1) ) ;
268 
269          if( meth == METH_SIGMA )  *val = sum ;
270          else if( ts_mean != 0.0 ) *val = sum / fabs(ts_mean) ;
271          else                      *val = 0.0 ;
272       }
273    }
274 
275    /** set the progress meter to the % of completion **/
276 
277    ncall++ ;
278    PLUTO_set_meter( global_plint , (100*ncall)/nvox ) ;
279    return ;
280 }
281