1 #include "mrilib.h"
2
3 static int tcat_open_verb = 0;
4
5 static NI_str_array * NI_get_wildcard_list(char * pattern);
6 static char * update_sar_with_selectors(NI_str_array * sar, char * sel);
7
8 /*---------------------------------------------------------------------------*/
9 /*! Open a dataset that is an impromptu catenation of multiple dataset. */
10 /*---------------------------------------------------------------------------*/
11
THD_open_tcat(char * dlist)12 THD_3dim_dataset * THD_open_tcat( char *dlist )
13 {
14 THD_3dim_dataset *dset_out , **dset_in ;
15 int ndset_in , dd , nerr , new_nvals, sb=0 , ivout;
16 NI_str_array *sar ;
17 double angle=0.0;
18 char *dp, *dlocal = dlist; /* local dlist, in case it is altered */
19 char *sel=NULL;
20
21 ENTRY("THD_open_tcat") ;
22
23 if( dlocal == NULL || *dlocal == '\0' ) RETURN(NULL) ;
24
25 /* allow file list to be read from a file 23 Jul 2012 [rickr] */
26 if( ! strncmp(dlocal, "filelist:", 9) ) {
27 dlocal = AFNI_suck_file(dlocal+9) ;
28 if ( ! dlocal ) {
29 ERROR_message("THD_open_tcat: failed to open '%s' as filelist",
30 dlocal+9);
31 RETURN(NULL) ;
32 }
33 /* make it look more like expected */
34 for( dd=0, dp=dlocal; dd < strlen(dlocal); dd++, dp++ )
35 if( *dp == '\n' || *dp == '\r' ) *dp = ' ';
36 }
37
38 if( strchr(dlocal,' ') == NULL && ! HAS_WILDCARD(dlocal) ) {
39 dset_out = THD_open_dataset(dlocal) ; RETURN(dset_out) ;
40 }
41
42 /* save selectors, akin to wildcard selection 4 Apr 2016 [rickr] */
43 /* (use by default; consider future vals: FOR_COMPOSITE and FOR_INDIVID) */
44 tcat_open_verb = AFNI_numenv_def("AFNI_TCAT_SELECTORS_VERB", 0);
45 if( tcat_open_verb > 1 )
46 INFO_message("THD_open_tcat: processing wildcards in '%s'\n", dlocal);
47 if( ! AFNI_noenv("AFNI_TCAT_SELECTORS") ) {
48 for( dd=0; dd < strlen(dlocal); dd++ ) {
49 if( dlocal[dd] == '[' || dlocal[dd] == '<' || dlocal[dd] == '{' ) {
50 char * cp = strchr(dlocal+dd, ' ');
51 int dcp;
52 if( cp ) {
53 /* whitespace follows selector...
54 If something besides white space follows, then this is
55 not considered to be a general selector.
56 */
57 for( dcp=1; cp[dcp] && isspace(cp[dcp]); dcp++ )
58 ;
59
60 /* if non-nul do not use global tcat selector. */
61 if( cp[dcp] ) {
62 if( tcat_open_verb )
63 INFO_message("THD_open_tcat: skip general tcat selector\n");
64 break;
65 }
66 }
67
68 /* we have selectors! */
69 sel = strdup(dlocal+dd);
70
71 /* altering string, so be sure it is a local, modifiable one */
72 if( dlocal == dlist ) dlocal = strdup(dlocal);
73 dlocal[dd] = '\0'; /* terminate */
74
75 if( tcat_open_verb )
76 INFO_message("THD_open_tcat, have tcat selector %s\n", sel);
77
78 break;
79 }
80 }
81 }
82
83 /* check for failure here 14 Jul 2016 [rickr] */
84 if( strchr(dlocal,' ') ) {
85 sar = NI_decode_string_list( dlocal , "~" ) ;
86
87 if( ! sar ) {
88 if( tcat_open_verb )
89 WARNING_message("THD_open_tcat: no space list from '%s'", dlocal);
90 RETURN(NULL);
91 }
92 } else if( HAS_WILDCARD(dlocal) ) {
93 sar = NI_get_wildcard_list( dlocal );
94
95 if( ! sar ) {
96 if( tcat_open_verb )
97 WARNING_message("THD_open_tcat: no wildcard match for '%s'",dlocal);
98 RETURN(NULL);
99 }
100 } else {
101 WARNING_message("THD_open_tcat: should find wildcard or space in %s",
102 dlocal);
103 RETURN(NULL) ;
104 }
105
106 /* if selectors and/or WILDCARD, append to sar elements and create new */
107 /* 'dlocal' string 5 Apr 2016 [rickr] */
108 if( sel || HAS_WILDCARD(dlocal) ) {
109 if( dlocal != dlist ) free(dlocal); /* free if locally allocated */
110 dlocal = update_sar_with_selectors(sar, sel);
111 if(tcat_open_verb>1) INFO_message("THD_open_tcat: new dlocal %s",dlocal);
112
113 /* free selectors (if they exist) 18 Apr 2016 [rickr] */
114 if( sel ) { free(sel); sel = NULL; }
115 }
116
117 /* open all of the input datasets, possibly with selectors */
118 ndset_in = sar->num ;
119 dset_in = (THD_3dim_dataset **)malloc(sizeof(THD_3dim_dataset *)*sar->num) ;
120 for( nerr=dd=0 ; dd < ndset_in ; dd++ ){
121 if( tcat_open_verb > 1 )
122 INFO_message("THD_open_tcat: opening dset %s ...", sar->str[dd]);
123 dset_in[dd] = THD_open_dataset( sar->str[dd] );
124
125 if( dset_in[dd] == NULL ){
126 WARNING_message("THD_open_tcat: can't open dataset %s\n", sar->str[dd]);
127 nerr++ ;
128 }
129 }
130 if( nerr > 0 ){
131 for( dd=0 ; dd < ndset_in ; dd++ )
132 if( dset_in[dd] != NULL ) DSET_delete(dset_in[dd]) ;
133 free((void *)dset_in) ;
134 NI_delete_str_array(sar) ;
135 RETURN(NULL) ;
136 }
137 if( ndset_in == 1 ){
138 dset_out = dset_in[0] ;
139 free((void *)dset_in) ;
140 NI_delete_str_array(sar) ;
141 RETURN(dset_out) ;
142 }
143
144 (void)THD_check_for_duplicates( sar->num , sar->str , 1 ) ; /* 31 May 2007 */
145
146 for( nerr=0,dd=1 ; dd < ndset_in ; dd++ ){
147 if( DSET_NX(dset_in[0]) != DSET_NX(dset_in[dd]) ||
148 DSET_NY(dset_in[0]) != DSET_NY(dset_in[dd]) ||
149 DSET_NZ(dset_in[0]) != DSET_NZ(dset_in[dd]) ){
150 ERROR_message(
151 "THD_open_tcat: %s [%dx%dx%d] doesn't match %s [%dx%dx%d]\n",
152 sar->str[0] ,DSET_NX(dset_in[0]) ,
153 DSET_NY(dset_in[0]) ,DSET_NZ(dset_in[0]) ,
154 sar->str[dd],DSET_NX(dset_in[dd]),
155 DSET_NY(dset_in[dd]),DSET_NZ(dset_in[dd]) ) ;
156 nerr++ ;
157 } else {
158 if( !EQUIV_DATAXES(dset_in[dd]->daxes,dset_in[0]->daxes) ){
159 WARNING_message(
160 "THD_open_tcat: %s grid mismatch with %s\n",
161 sar->str[0] , sar->str[dd] ) ; /* don't increment nerr! */
162 }
163 /* allow for small differences 22 May 2015 [rickr] */
164 angle = dset_obliquity_angle_diff(dset_in[dd], dset_in[0],
165 OBLIQ_ANGLE_THRESH);
166 if (angle > 0.0) {
167 WARNING_message(
168 "dataset %s has an obliquity difference of %f degress with %s\n",
169 dset_in[dd] ,
170 angle, dset_in[0] );
171 }
172 }
173 }
174 if( nerr > 0 ){
175 for( dd=0 ; dd < ndset_in ; dd++ )
176 if( dset_in[dd] != NULL ) DSET_delete(dset_in[dd]) ;
177 free((void *)dset_in) ;
178 NI_delete_str_array(sar) ;
179 RETURN(NULL) ;
180 }
181
182 /*-- Check for type problems ZSS: Aug 27 2012 --*/
183 for (nerr=0,dd=0; dd < ndset_in ; dd++) {
184 for (sb=0; sb < DSET_NVALS(dset_in[dd]); ++sb) {
185 if ( DSET_BRICK_TYPE(dset_in[0],0) !=
186 DSET_BRICK_TYPE(dset_in[dd],sb) ) {
187 ++nerr;
188 }
189 }
190 }
191 if (nerr > 0) { /* don't die, just complain */
192 WARNING_message(
193 "Command-line catenated dataset has %d sub-bricks that differ \n"
194 " in data type from the first sub-brick of the first set.\n"
195 " Mme Irma sees potential for grief if you go down that path. \n"
196 " Use 3dinfo -datum on each input to understand why this is happening.\n"
197 " You can use 3dcalc's -datum option to rewrite the dataset with \n"
198 " all sub-bricks set to the same type then start over.\n\n",
199 nerr);
200 nerr=0;
201 }
202
203 /*-- OK, start making new dataset --*/
204
205 new_nvals = 0 ;
206 for( dd=0 ; dd < ndset_in ; dd++ )
207 new_nvals += DSET_NVALS(dset_in[dd]) ;
208
209 for( dd=0 ; dd < ndset_in ; dd++ )
210 if( DSET_TIMESTEP(dset_in[dd]) > 0.0 ) break ; /* 1st 3D+time */
211 if( dd == ndset_in ) dd = 0 ;
212
213 dset_out = EDIT_empty_copy( dset_in[dd] ) ;
214
215 /* since this is basically an input dataset, set the storage_mode
216 * to match 27 Jul 2010 [rickr] */
217 if( DSET_ONDISK(dset_out) && IS_VALID_NON_AFNI_DSET(dset_in[dd]) )
218 THD_set_storage_mode(dset_out, dset_in[dd]->dblk->diskptr->storage_mode);
219
220 EDIT_dset_items( dset_out ,
221 ADN_prefix , "tcat" ,
222 ADN_func_type , ISANAT(dset_in[dd]) ? ANAT_EPI_TYPE
223 : FUNC_FIM_TYPE ,
224 ADN_ntt , new_nvals ,
225 ADN_nvals , new_nvals ,
226 ADN_none ) ;
227 DSET_mallocize( dset_out ) ;
228
229 /* get factors and labels here, not at load time 4 Apr 2016 [rickr] */
230 ivout = 0;
231 for( dd=0 ; dd < ndset_in ; dd++ ) {
232 for (sb=0; sb < DSET_NVALS(dset_in[dd]); ++sb) {
233 EDIT_BRICK_FACTOR(dset_out, ivout, DSET_BRICK_FACTOR(dset_in[dd],sb));
234 EDIT_BRICK_LABEL (dset_out, ivout, DSET_BRICK_LABEL (dset_in[dd],sb));
235 ivout++;
236 }
237 }
238
239 /* check if we have a valid time axis; if not, make one up */
240
241 if( DSET_TIMESTEP(dset_out) <= 0.0f ){
242 float TR=1.0f , torg=0.0f , tdur=0.0f ;
243 int tunits=UNITS_SEC_TYPE ;
244 EDIT_dset_items( dset_out ,
245 ADN_tunits , tunits ,
246 ADN_ttdel , TR ,
247 ADN_ttorg , torg ,
248 ADN_ttdur , tdur ,
249 ADN_none ) ;
250 }
251
252 /* if dlocal is not new memory, must copy, else steal */
253 if( dlocal == dlist ) dset_out->tcat_list = strdup( dlocal ) ;
254 else dset_out->tcat_list = dlocal;
255
256 if( tcat_open_verb > 2 )
257 INFO_message("setting tcat_list[%d] = %s", ndset_in, dlocal);
258
259 dset_out->tcat_num = ndset_in ;
260 dset_out->tcat_len = (int *)malloc(sizeof(int)*ndset_in) ;
261 for( dd=0 ; dd < ndset_in ; dd++ ){
262 dset_out->tcat_len[dd] = DSET_NVALS(dset_in[dd]) ;
263 DSET_delete(dset_in[dd]) ;
264 if( tcat_open_verb > 2 )
265 INFO_message(" tcat: including %d volumes", dset_out->tcat_len[dd]);
266 }
267 free((void *)dset_in) ;
268 NI_delete_str_array(sar) ;
269
270 #if 0
271 fprintf(stderr,"THD_open_tcat('%s'):",dset_out->tcat_list);
272 for(dd=0;dd<ndset_in;dd++)fprintf(stderr," %d",dset_out->tcat_len[dd]);
273 fprintf(stderr,"\n");
274 #endif
275
276 RETURN(dset_out) ;
277 }
278
279 /*---------------------------------------------------------------------------*/
280 /*! append selectors to elements of a NI_str_array list */
281 /* - return a catenated string (space delimited) 7 Apr 2016 [rickr] */
282 /*---------------------------------------------------------------------------*/
update_sar_with_selectors(NI_str_array * sar,char * sel)283 static char * update_sar_with_selectors(NI_str_array * sar, char * sel)
284 {
285 char * lptr, * dlist;
286 int dd, len, fulllen, nsel=0;
287
288 if( ! sar ) return NULL;
289 if( sel ) nsel = strlen(sel);
290
291 /* first allocate for catenation string with repeated selectors */
292 fulllen = 1; /* for trailing nul */
293 for( dd=0 ; dd < sar->num ; dd++ )
294 /* extra +1 is for separation spaces */
295 fulllen += strlen(sar->str[dd]) + nsel + 1;
296 dlist = (char *)malloc(fulllen * sizeof(char));
297
298 /* empty dlist and fill with updated sar names and separation spaces */
299 dlist[0] = '\0';
300 lptr = dlist;
301 for( dd=0 ; dd < sar->num ; dd++ ) {
302 len = strlen(sar->str[dd]) + nsel;
303 sar->str[dd] = NI_realloc(sar->str[dd], char, (len+1)*sizeof(char));
304 if( sel ) strcat(sar->str[dd], sel);
305
306 /* and append to new dlist string */
307 strcpy(lptr, sar->str[dd]);
308 strcat(lptr, " ");
309 lptr += len+1;
310 }
311
312 return dlist;
313 }
314
315
316 /*---------------------------------------------------------------------------*/
317 /*! Expand the wildcard selection and populate a NI_str_array struct. */
318 /* - a wildcard version of NI_decode_string_list 7 Apr 2016 [rickr] */
319 /*---------------------------------------------------------------------------*/
NI_get_wildcard_list(char * pattern)320 static NI_str_array * NI_get_wildcard_list(char * pattern)
321 {
322 NI_str_array * sar=NULL;
323 int nexp=0, ind;
324 char ** fexp=NULL;
325
326 ENTRY("NI_get_wildcard_list");
327
328 MCW_file_expand(1, &pattern, &nexp, &fexp);
329 if( nexp == 0 ) RETURN(NULL);
330
331 sar = NI_malloc(NI_str_array, sizeof(NI_str_array));
332 sar->num = nexp;
333 sar->str = NI_malloc(char *, nexp*sizeof(char *));
334
335 for( ind=0; ind<nexp; ind++ )
336 sar->str[ind] = NI_strdup(fexp[ind]);
337
338 MCW_free_expand(nexp, fexp);
339
340 RETURN(sar);
341 }
342
343 /*---------------------------------------------------------------------------*/
344 /*! Load from disk the impromptu catenation. */
345 /*---------------------------------------------------------------------------*/
346
THD_load_tcat(THD_datablock * dblk)347 void THD_load_tcat( THD_datablock *dblk )
348 {
349 int ivout , dd , iv ;
350 THD_3dim_dataset *dset_in , *dset_out ;
351 NI_str_array *sar ;
352
353 ENTRY("THD_load_tcat") ;
354
355 if( !ISVALID_DBLK(dblk) ) EXRETURN ;
356 dset_out = (THD_3dim_dataset *)dblk->parent ;
357 if( !ISVALID_DSET(dset_out) ) EXRETURN ;
358 sar = NI_decode_string_list( dset_out->tcat_list , "~" ) ;
359 if( sar == NULL ) EXRETURN ;
360 if( sar->num != dset_out->tcat_num ){ NI_delete_str_array(sar); EXRETURN; }
361
362 ivout = 0 ;
363 for( dd=0 ; dd < sar->num ; dd++ ){
364 dset_in = THD_open_dataset( sar->str[dd] ) ;
365 if( dset_in == NULL ){
366 if( tcat_open_verb )
367 INFO_message("THD_load_tcat: failed for dset %s", sar->str[dd]);
368 NI_delete_str_array(sar) ; DSET_unload(dset_out) ;
369 EXRETURN ;
370 }
371 DSET_mallocize(dset_in) ; DSET_load(dset_in) ;
372 if( !DSET_LOADED(dset_in) ){
373 NI_delete_str_array(sar) ; DSET_unload(dset_out) ; DSET_delete(dset_in) ;
374 EXRETURN ;
375 }
376
377 for( iv=0 ; iv < DSET_NVALS(dset_in) ; iv++ ){
378 EDIT_substitute_brick( dset_out , ivout ,
379 DSET_BRICK_TYPE(dset_in,iv), DSET_ARRAY(dset_in,iv) );
380 mri_fix_data_pointer( NULL , DSET_BRICK(dset_in,iv) ) ;
381 ivout++ ;
382 }
383 DSET_delete(dset_in) ;
384 }
385
386 NI_delete_str_array(sar) ; EXRETURN ;
387 }
388