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