void conv_model( float * gs , int ts_length , float ** x_array , float * ts_array ) { int ii, jj,jbot,jtop , kk , nid_top,nid_bot ; int cur_debug = 0; float top , val , max0, max1 ; static int iter = -1; /* iteration number */ static int do_scale = 0; /* scale the curves by 1/height */ static int nid = 0 ; /* number of pts in impulse */ static float * fid0 = NULL ; /* impulse response function */ static float * fid1 = NULL ; /* impulse response function */ /*----- check for env vars -----*/ iter++ ; if( iter == 0 ) { double dval = AFNI_numenv("AFNI_MODEL_DITER"); if( dval >= 1.0 ) g_diter = (int)dval; /* zero is failure */ dval = AFNI_numenv("AFNI_MODEL_DEBUG"); if( dval >= 1.0 ) g_debug = (int)dval; if(g_debug) fprintf(stderr,"\n+d TR = %f\n", x_array[1][1]-x_array[0][1]); do_scale = ! AFNI_noenv("AFNI_CONVDIFFGAM_DO_SCALE"); } /*** make sure there is a reference function to convolve with ***/ if( refnum <= 0 ) conv_set_ref( 0 , NULL ) ; /* to clean up, particularly as a parameter */ cur_debug = (iter == g_diter || (iter == 0 && g_debug > 1)); if( cur_debug ) disp_floats("+d params: ", gs, 8); /*** initialize the output ***/ for( ii=0 ; ii < ts_length ; ii++ ) ts_array[ii] = 0.0 ; /*** initialize the impulse response ***/ if( nid < ts_length ){ /* make some space for it */ if( fid0 ) free(fid0) ; if( fid1 ) free(fid1) ; nid = ts_length ; fid0 = (float *) malloc( sizeof(float) * nid ) ; fid1 = (float *) malloc( sizeof(float) * nid ) ; } /* compute first and second impulse functions */ gamma_model(gs, ts_length, x_array, fid0, do_scale, cur_debug); gamma_model(gs+4, ts_length, x_array, fid1, do_scale, cur_debug); max0 = test_n_truncate(fid0, ts_length, cur_debug); max1 = test_n_truncate(fid1, ts_length, cur_debug); /* find first and last nonzero value */ for( nid_bot=0 ; nid_bot < ts_length ; nid_bot++ ) if( fid0[nid_bot] != 0.0 || fid1[nid_bot] != 0.0 ) break ; for( nid_top=ts_length-1 ; nid_top > nid_bot ; nid_top-- ) if( fid0[nid_top] != 0.0 || fid1[nid_top] != 0.0 ) break ; /*** loop over each nonzero point in the reference ***/ for( ii=0 ; ii < refnz ; ii++ ){ kk = refin[ii] ; if( kk >= ts_length ) break ; val = refts[kk] ; /*** for each point in the impulse ***/ jtop = ts_length - kk ; if( jtop > nid_top ) jtop = nid_top+1 ; for( jj=nid_bot ; jj < jtop ; jj++ ) ts_array[kk+jj] += val * ( fid0[jj] - fid1[jj] ) ; } if( cur_debug ) disp_floats("+d conv : ", ts_array, ts_length); return ; }
MRI_IMAGE * mri_warp3D_align_one( MRI_warp3D_align_basis *bas, MRI_IMAGE *im ) { float *fit , *dfit , *qfit , *tol ; int iter , good,ngood , ii, pp , skip_first ; MRI_IMAGE *tim , *fim ; float *pmat=MRI_FLOAT_PTR(bas->imps) , /* pseudo inverse: n X m matrix */ *tar , tv , sfit ; int n=bas->imps->nx , /* = nfree+1 */ m=bas->imps->ny , /* = imap->nx = length of ima */ npar=bas->nparam , /* = number of warp parameters */ nfree=bas->nfree , /* = number of free warp parameters */ *ima=MRI_INT_PTR(bas->imap) , /* = indexes in fim of voxels to use */ *pma ; /* = map of free to total params */ int ctstart ; int do_twopass=(bas->imps_blur != NULL && bas->twoblur > 0.0f) , passnum=1 ; int blur_pass ; char *save_prefix ; static int save_index=0 ; #define AITMAX 3.33 #define NMEM 5 float *fitmem[NMEM] ; int mm , last_aitken , num_aitken=0 ; float sdif , fitdif[NMEM] ; /* 28 Sep 2005 */ int num_bad_diff ; float best_dif , best_par[999] ; /* 09 Jan 2006 */ int best_ite=0 ; ENTRY("mri_warp3D_align_one") ; ctstart = NI_clock_time() ; save_prefix = getenv("AFNI_WARPDRIVE_SAVER") ; /** pma[k] = external parameter index for the k-th free parameter **/ pma = (int *)malloc(sizeof(int) * nfree) ; for( pp=ii=0 ; ii < npar ; ii++ ) if( !bas->param[ii].fixed ) pma[pp++] = ii ; #if 0 fprintf(stderr,"pma=") ; for(pp=0;pp<nfree;pp++)fprintf(stderr," %d",pma[pp]); fprintf(stderr,"\n") ; #endif fit = (float *)malloc(sizeof(float) * npar ) ; dfit = (float *)malloc(sizeof(float) * npar ) ; qfit = (float *)malloc(sizeof(float) * nfree) ; tol = (float *)malloc(sizeof(float) * npar ) ; for( mm=0 ; mm < NMEM ; mm++ ) fitmem[mm] = NULL ; for( mm=0 ; mm < NMEM ; mm++ ) fitdif[mm] = 3.e+33 ; /*--- loop back point for two pass alignment ---*/ bas->num_iter = 0 ; mri_warp3D_set_womask( bas->imsk ) ; ReStart: best_dif = -666.0f ; /* 09 Jan 2006 */ blur_pass = (do_twopass && passnum==1) ; mri_warp3D_method( blur_pass ? MRI_LINEAR : bas->regmode ) ; /* load initial fit parameters; if they are all the identity transform value, then skip the first transformation of the fim volume */ if( passnum == 1 ){ skip_first = 1 ; for( pp=0 ; pp < npar ; pp++ ){ if( bas->param[pp].fixed ){ fit[pp] = bas->param[pp].val_fixed ; } else { fit[pp] = bas->param[pp].val_init ; } skip_first = skip_first && (fit[pp] == bas->param[pp].ident) ; } } else { skip_first = 0 ; /* and fit[] is unchanged */ } fitmem[0] = (float *)malloc(sizeof(float)*npar) ; memcpy( fitmem[0] , fit , sizeof(float)*npar ) ; for( pp=0 ; pp < npar ; pp++ ) tol[pp] = bas->param[pp].toler ; if( blur_pass ){ float fac = (1.0f+bas->twoblur) ; if( fac < 3.0f ) fac = 3.0f ; for( pp=0 ; pp < npar ; pp++ ) tol[pp] *= fac ; } if( bas->verb ) fprintf(stderr,"++ mri_warp3D_align_one: START PASS #%d\n",passnum) ; /* setup base image for registration into fim, and pseudo-inverse of base+derivative images into pmat */ if( blur_pass ){ /* first pass ==> registering blurred images */ float *far , blur=bas->twoblur ; int nx=im->nx , ny=im->ny , nz=im->nz ; fim = mri_to_float( im ) ; far = MRI_FLOAT_PTR(fim) ; EDIT_blur_volume_3d( nx,ny,nz , 1.0f,1.0f,1.0f , MRI_float , far, blur,blur,blur ) ; pmat = MRI_FLOAT_PTR(bas->imps_blur) ; } else { /* registering original image */ if( im->kind == MRI_float ) fim = im ; else fim = mri_to_float( im ) ; pmat = MRI_FLOAT_PTR(bas->imps) ; } /******** iterate fit ********/ iter = 0 ; good = 1 ; last_aitken = 3 ; num_bad_diff = 0 ; while( good ){ if( skip_first ){ tim = fim ; skip_first = 0 ; } else { bas->vwset( npar , fit ) ; /**************************/ tim = mri_warp3D( fim , 0,0,0 , bas->vwfor ) ; /* warp on current params */ } /**************************/ tar = MRI_FLOAT_PTR(tim) ; sdif = mri_scaled_diff( bas->imbase , tim , bas->imsk ) ; if( bas->verb ) fprintf(stderr,"++++++++++ Start iter=%d RMS_diff=%g\n",iter+1,sdif) ; if( best_dif < 0.0f || sdif < best_dif ){ /* 09 Jan 2006 */ best_dif = sdif ; best_ite = iter ; memcpy( best_par , fit , sizeof(float)*npar ) ; } /* find least squares fit of base + derivatives to warped image */ sfit = 0.0f ; for( pp=0 ; pp < npar ; pp++ ) dfit[pp] = 0.0f ; for( pp=0 ; pp < nfree ; pp++ ) qfit[pp] = 0.0f ; for( ii=0 ; ii < m ; ii++ ){ tv = tar[ima[ii]] ; sfit += P(nfree,ii) * tv ; for( pp=0 ; pp < nfree ; pp++ ) qfit[pp] += P(pp,ii) * tv ; } if( tim != fim ) mri_free( tim ) ; #if 0 fprintf(stderr,"qfit="); for(pp=0;pp<nfree;pp++)fprintf(stderr," %g",qfit[pp]); fprintf(stderr,"\n") ; #endif for( pp=0 ; pp < nfree ; pp++ ) dfit[pma[pp]] = qfit[pp] ; for( pp=0 ; pp < npar ; pp++ ){ fit[pp] += dfit[pp] ; if( fit[pp] > bas->param[pp].max ) fit[pp] = bas->param[pp].max ; else if( fit[pp] < bas->param[pp].min ) fit[pp] = bas->param[pp].min ; } if( bas->verb ){ fprintf(stderr,"+ Delta:") ; for( pp=0 ; pp < npar ; pp++ ) fprintf(stderr," %13.6g",dfit[pp]) ; fprintf(stderr,"\n") ; fprintf(stderr,"+ Total: scale factor=%g\n" "+ #%5d:",sfit,iter+1) ; for( pp=0 ; pp < npar ; pp++ ) fprintf(stderr," %13.6g", fit[pp]) ; fprintf(stderr,"\n") ; } /* save fit results for a while into the past, and then maybe do Aitken */ if( fitmem[NMEM-1] != NULL ) free((void *)fitmem[NMEM-1]) ; for( mm=NMEM-1 ; mm > 0 ; mm-- ) fitmem[mm] = fitmem[mm-1] ; fitmem[0] = (float *)malloc(sizeof(float)*npar) ; memcpy( fitmem[0] , fit , sizeof(float)*npar ) ; /* 28 Sep 2005: if RMS went up, back off the changes! */ for( mm=NMEM-1 ; mm > 0 ; mm-- ) fitdif[mm] = fitdif[mm-1] ; fitdif[0] = sdif ; if( iter > 1 && num_bad_diff < 2 && fitmem[1] != NULL && fitdif[0] > 1.0666f * fitdif[1] ){ for( pp=0 ; pp < npar ; pp++ ) fit[pp] = 0.5 * ( fitmem[0][pp] + fitmem[1][pp] ) ; memcpy( fitmem[0] , fit , sizeof(float)*npar ) ; last_aitken = iter+1 ; num_bad_diff++ ; if( bas->verb ) fprintf(stderr,"+++ RMS_diff changes too much! Shrinking!\n") ; } else { num_bad_diff = 0 ; } iter++ ; if( iter > last_aitken+NMEM && !AFNI_noenv("AFNI_WARPDRIVE_AITKEN") ){ double s0,s1,s2 , dd , de,df ; num_aitken = 0 ; for( pp=0 ; pp < npar ; pp++ ){ dd = fabs(fitmem[1][pp]-fit[pp]) ; if( dd <= tol[pp] ) continue ; /* done here */ de = dd ; for( mm=2 ; mm < NMEM ; mm++ ){ df = fabs(fitmem[mm][pp]-fitmem[mm-1][pp]) ; if( df <= de ) break ; de = df ; } if( mm == NMEM ){ /* do Aitken */ s2 = fit[pp] ; s1 = fitmem[1][pp] ; s0 = fitmem[2][pp] ; de = ( (s2-s1) - (s1-s0) ) ; if( de != 0.0 ){ de = -(s2-s1)*(s2-s1) / de ; dd *= AITMAX ; if( fabs(de) > dd ){ de = (de > 0.0) ? dd : -dd ; } fit[pp] += de ; if( fit[pp] > bas->param[pp].max ) fit[pp] = bas->param[pp].max ; else if( fit[pp] < bas->param[pp].min ) fit[pp] = bas->param[pp].min ; num_aitken++ ; } } } if( num_aitken > 0 ) last_aitken = iter ; if( bas->verb && num_aitken > 0 ){ fprintf(stderr,"+ Aitken on %d params:\n" "+________:",num_aitken) ; for( pp=0 ; pp < npar ; pp++ ){ if( fit[pp] != fitmem[0][pp] ){ fprintf(stderr," %13.6g", fit[pp]) ; fitmem[0][pp] = fit[pp] ; } else { fprintf(stderr," _____________") ; } } fprintf(stderr,"\n") ; } } /* save intermediate image? */ if( save_prefix != NULL ){ char sname[THD_MAX_NAME] ; FILE *fp ; mri_warp3D_set_womask( NULL ) ; /* must warp the whole thing */ bas->vwset( npar , fit ) ; tim = mri_warp3D( fim , 0,0,0 , bas->vwfor ) ; tar = MRI_FLOAT_PTR(tim) ; mri_warp3D_set_womask( bas->imsk ) ; sprintf(sname,"%s_%04d.mmm",save_prefix,save_index++) ; fprintf(stderr,"+ Saving intermediate image to binary file %s\n",sname) ; fp = fopen( sname , "w" ) ; if( fp != NULL ){ fwrite( tar, tim->pixel_size, tim->nvox, fp ) ; fclose(fp) ; } if( bas->vwdet != NULL ){ int i,j,k , nx=tim->nx,ny=tim->ny,nz=tim->nz ; for( k=0 ; k < nz ; k++ ){ for( j=0 ; j < ny ; j++ ){ for( i=0 ; i < nx ; i++ ){ tar[i+(j+k*ny)*nx] = bas->vwdet( (float)i,(float)j,(float)k ) ; }}} sprintf(sname,"%s_%04d.ddd",save_prefix,save_index-1) ; fprintf(stderr,"+ Saving determinant image to binary file %s\n",sname) ; fp = fopen( sname , "w" ) ; if( fp != NULL ){ fwrite( tar, tim->pixel_size, tim->nvox, fp ) ; fclose(fp) ; } } mri_free( tim ) ; } /* loop back for more iterations? */ if( last_aitken == iter ) continue ; /* don't test, just loop */ if( fitmem[2] == NULL ) continue ; ngood = 0 ; for( pp=0 ; pp < npar ; pp++ ) if( !bas->param[pp].fixed ) ngood += ( ( fabs(fitmem[1][pp]-fitmem[0][pp]) <= tol[pp] ) && ( fabs(fitmem[2][pp]-fitmem[1][pp]) <= tol[pp] ) ) ; good = (ngood < nfree) && (iter < bas->max_iter) ; } /******** end while loop for iteration of fitting procedure ********/ for( mm=0 ; mm < NMEM ; mm++ ) if( fitmem[mm] != NULL ){ free((void *)fitmem[mm]); fitmem[mm] = NULL; } /*--- 09 Jan 2006: if prior best fit was better than current, replace ---*/ if( best_dif > 0.0f && 1.0666f*best_dif < sdif ){ memcpy( fit , best_par , sizeof(float)*npar ) ; if( bas->verb ) fprintf(stderr,"+++++ Replacing final fit with iter #%d's fit +++++\n", best_ite+1) ; } /*--- do the second pass? ---*/ if( blur_pass ){ if( bas->verb ) fprintf(stderr,"+++++++++++++ Loop back for next pass +++++++++++++\n"); mri_free(fim) ; fim = NULL ; passnum++ ; goto ReStart ; } else { if( bas->verb ) fprintf(stderr,"+++++++++++++ Convergence test passed +++++++++++++\n"); } /*--- done! ---*/ bas->num_iter = iter ; for( pp=0 ; pp < npar ; pp++ ) bas->param[pp].val_out = fit[pp] ; /*-- do the actual realignment to get the output image --*/ if( bas->regfinal > 0 ) mri_warp3D_method( bas->regfinal ) ; mri_warp3D_set_womask( NULL ) ; bas->vwset( npar , fit ) ; tim = mri_warp3D( fim , 0,0,0 , bas->vwfor ) ; if( fim != im ) mri_free(fim) ; /* if it was a copy, junk it */ free((void *)dfit) ; free((void *)fit) ; free((void *)qfit) ; free((void *)pma) ; free((void *)tol) ; if( bas->verb ){ double st = (NI_clock_time()-ctstart) * 0.001 ; fprintf(stderr,"++ mri_warp3D_align_one EXIT: %.2f seconds elapsed\n",st) ; } RETURN( tim ) ; }
THD_session * THD_init_session( char *sessname ) { THD_session *sess ; XtPointer_array *dblk_arrarr ; THD_datablock_array *dblk_arr ; THD_3dim_dataset *dset=NULL , *temp_dset; THD_3dim_dataset_array *dset_arr ; int ibar , idset , iview , nds , qview=-666 ; ENTRY("THD_init_session") ; /*-- sanity check --*/ if( sessname == NULL || strlen(sessname) == 0 || !THD_is_directory(sessname) ) RETURN( NULL ) ; /*-- initialize session --*/ sess = myXtNew( THD_session ) ; sess->type = SESSION_TYPE ; sess->parent = NULL ; #ifdef DEBUG_SESSIONS fprintf(stderr, "blanking session\n"); #endif BLANK_SESSION(sess) ; /* null out all entries */ /* save directory name, with a trailing slash */ MCW_strncpy( sess->sessname , sessname , THD_MAX_NAME ) ; iview = strlen(sess->sessname) ; if( sess->sessname[iview-1] != '/' ) { /* tack trailing / onto sessname */ sess->sessname[iview] = '/' ; sess->sessname[iview+1] = '\0' ; } else { iview-- ; /* iview now points to last non-NUL character in string */ } /* save last name from sessname */ #if 1 { char *env = my_getenv( "AFNI_SESSTRAIL" ) ; int tt = 0 ; if( env != NULL ) tt = strtol(env,NULL,10) ; env = THD_trailname(sess->sessname,tt) ; tt = 1+strlen(env) - THD_MAX_NAME ; if( tt < 0 ) tt = 0 ; strcpy( sess->lastname , env+tt ) ; } #else for( iview-- ; iview >= 0 ; iview-- ) if( sess->sessname[iview] == '/' ) break ; MCW_strncpy( sess->lastname, &(sess->sessname[iview+1]), THD_MAX_NAME ) ; #endif /*-- override dataset 'view'?? [30 May 2013] --*/ { char *env = my_getenv("AFNI_OVERRIDE_VIEW") ; if( env != NULL ) { if( toupper(*env) == 'T' ) qview = VIEW_TALAIRACH_TYPE ; else if( toupper(*env) == 'O' ) qview = VIEW_ORIGINAL_TYPE ; else WARNING_message("AFNI_OVERRIDE_VIEW=%s is not understood",env) ; } } /*-- read all datablocks --*/ dblk_arrarr = THD_init_alldir_datablocks( sess->sessname ) ; /*-- for each datablock array ... --*/ for( ibar=0 ; ibar < dblk_arrarr->num ; ibar++ ) { /*-- get the current array of datablocks --*/ dblk_arr = (THD_datablock_array *) dblk_arrarr->ar[ibar] ; if( dblk_arr == NULL || dblk_arr->num <= 0 ) continue ; /* huh? */ /*-- convert it into an array of datasets --*/ dset_arr = THD_array_3dim_from_block( dblk_arr ) ; if( dset_arr == NULL || dset_arr->num <= 0 ) continue ; /*-- place it into the next row of the THD_session [28 Jul 2003] --*/ nds = sess->num_dsset ; if( nds >= THD_MAX_SESSION_SIZE ) { /* bad! */ fprintf(stderr, "\n*** Session %s table overflow with dataset %s ***\n", sessname , dset_arr->ar[0]->self_name) ; for( idset=0 ; idset < dset_arr->num ; idset++ ) THD_delete_3dim_dataset( dset_arr->ar[idset] , False ) ; FREE_3DARR(dset_arr) ; continue ; /* skip to next dblk_arr (ibar loop) */ } /*-- put each dataset into this row in its view place --*/ for( idset=0 ; idset < dset_arr->num ; idset++ ) { dset = dset_arr->ar[idset] ; iview = dset->view_type ; if( qview >= 0 ) iview = qview ; /* 30 May 2013 */ if( GET_SESSION_DSET(sess,nds,iview) != NULL ) { /* should never happen */ fprintf(stderr, "\n*** Session %s has duplicate dataset views of %s ***\n", sessname , dset->self_name) ; THD_delete_3dim_dataset( dset , False ) ; } else { #ifdef DEBUG_SESSIONS fprintf(stderr,"\nputting datasets into initial view \n"); #endif SET_SESSION_DSET(dset, sess, nds, iview); /* should always happen */ /* sess->dsset_xform_table[nds][iview] = dset ; */ /* should always happen */ } } sess->num_dsset ++ ; /* one more row */ FREE_3DARR(dset_arr) ; } /* end of loop over each datablock array (ibar) */ /*-- throw away the datablock arrays at this point --*/ STATUS("trashing dblk_arrarr") ; for( ibar=0 ; ibar < dblk_arrarr->num ; ibar++ ) { dblk_arr = (THD_datablock_array *) dblk_arrarr->ar[ibar] ; FREE_DBARR( dblk_arr ) ; } FREE_XTARR( dblk_arrarr ) ; /*-- 29 Oct 2001: try to read .mnc "datasets" --*/ if( !AFNI_noenv("AFNI_MINC_DATASETS") ) { char ename[THD_MAX_NAME] , **fn_minc , *eee ; int num_minc , ii ; STATUS("looking for MINC files") ; strcpy(ename,sess->sessname) ; strcat(ename,"*.mnc") ; eee = ename ; MCW_file_expand( 1,&eee , &num_minc,&fn_minc ) ; /* find files */ if( num_minc > 0 ) { /* got some! */ STATUS("opening MINC files") ; for( ii=0 ; ii < num_minc ; ii++ ) { /* loop over files */ dset = THD_open_minc( fn_minc[ii] ) ; /* try it on */ if( !ISVALID_DSET(dset) ) continue ; /* doesn't fit? */ nds = sess->num_dsset ; if( nds >= THD_MAX_SESSION_SIZE ) { fprintf(stderr, "\n*** Session %s table overflow with MINC dataset %s ***\n", sessname , fn_minc[ii] ) ; THD_delete_3dim_dataset( dset , False ) ; break ; /* out of for loop */ } iview = dset->view_type ; SET_SESSION_DSET(dset, sess, nds, iview); /* sess->dsset_xform_table[nds][iview] = dset ;*/ sess->num_dsset ++ ; } /* end of loop over files */ MCW_free_expand( num_minc , fn_minc ) ; } /* end of if we found MINC files */ } /*-- 06 Apr 2005: try to read NIfTI-1 files [KRH and RWC] --*/ if( !AFNI_noenv("AFNI_NIFTI_DATASETS") ) { char *ename[2] , **fn_nifti ; int num_nifti , ii ; STATUS("looking for NIFTI files") ; ename[0] = AFMALL(char, THD_MAX_NAME) ; ename[1] = AFMALL(char, THD_MAX_NAME) ; strcpy(ename[0],sess->sessname) ; strcat(ename[0],"*.nii") ; strcpy(ename[1],sess->sessname) ; strcat(ename[1],"*.nii.gz") ; MCW_file_expand( 2,ename , &num_nifti,&fn_nifti ) ; /* find files */ free(ename[0]) ; free(ename[1]) ; if( num_nifti > 0 ) { /* got some! */ STATUS("opening NIFTI files") ; for( ii=0 ; ii < num_nifti ; ii++ ) { /* loop over files */ dset = THD_open_nifti( fn_nifti[ii] ) ; /* try it on */ if( !ISVALID_DSET(dset) ) continue ; /* doesn't fit? */ nds = sess->num_dsset ; if( nds >= THD_MAX_SESSION_SIZE ) { fprintf(stderr, "\n*** Session %s table overflow with NIfTI dataset %s ***\n", sessname , fn_nifti[ii] ) ; THD_delete_3dim_dataset( dset , False ) ; break ; /* out of for loop */ } iview = dset->view_type ; SET_SESSION_DSET(dset, sess, nds, iview); /* sess->dsset_xform_table[nds][iview] = dset ;*/ sess->num_dsset ++ ; } /* end of loop over files */ MCW_free_expand( num_nifti , fn_nifti ) ; } /* end of if we found NIFTI files */ }
int main( int argc , char *argv[] ) { int nx,ny,nz , nxyz , ii,kk , num1,num2 , num_tt=0 , iv , piece , fim_offset; float dx,dy,dz , dxyz , num1_inv=0.0 , num2_inv , num1m1_inv=0.0 , num2m1_inv , dof , dd,tt,q1,q2 , f1,f2 , tt_max=0.0 ; THD_3dim_dataset *dset=NULL , *new_dset=NULL ; THD_3dim_dataset * base_dset; float *av1 , *av2 , *sd1 , *sd2 , *ffim , *gfim ; float *base_ary=NULL; void *vsp ; void *vdif ; /* output mean difference */ char cbuf[THD_MAX_NAME] ; float fbuf[MAX_STAT_AUX] , fimfac ; int output_datum ; float npiece , memuse ; float *dofbrik=NULL , *dofar=NULL ; THD_3dim_dataset *dof_dset=NULL ; /*-- read command line arguments --*/ if( argc < 2 || strncmp(argv[1],"-help",5) == 0 ) TT_syntax(NULL) ; /*-- 20 Apr 2001: addto the arglist, if user wants to [RWCox] --*/ mainENTRY("3dttest main"); machdep() ; PRINT_VERSION("3dttest") ; INFO_message("For most purposes, 3dttest++ should be used instead of 3dttest!") ; { int new_argc ; char ** new_argv ; addto_args( argc , argv , &new_argc , &new_argv ) ; if( new_argv != NULL ){ argc = new_argc ; argv = new_argv ; } } AFNI_logger("3dttest",argc,argv) ; TT_read_opts( argc , argv ) ; if( ! TT_be_quiet ) printf("3dttest: t-tests of 3D datasets, by RW Cox\n") ; /*-- read first dataset in set2 to get dimensions, etc. --*/ dset = THD_open_dataset( TT_set2->ar[0] ) ; /* 20 Dec 1999 BDW */ if( ! ISVALID_3DIM_DATASET(dset) ) ERROR_exit("Unable to open dataset file %s",TT_set2->ar[0]); nx = dset->daxes->nxx ; ny = dset->daxes->nyy ; nz = dset->daxes->nzz ; nxyz = nx * ny * nz ; dx = fabs(dset->daxes->xxdel) ; dy = fabs(dset->daxes->yydel) ; dz = fabs(dset->daxes->zzdel) ; dxyz = dx * dy * dz ; #ifdef TTDEBUG printf("*** nx=%d ny=%d nz=%d\n",nx,ny,nz) ; #endif /*-- make an empty copy of this dataset, for eventual output --*/ #ifdef TTDEBUG printf("*** making empty dataset\n") ; #endif new_dset = EDIT_empty_copy( dset ) ; tross_Make_History( "3dttest" , argc,argv , new_dset ) ; strcpy( cbuf , dset->self_name ) ; strcat( cbuf , "+TT" ) ; iv = DSET_PRINCIPAL_VALUE(dset) ; if( TT_datum >= 0 ){ output_datum = TT_datum ; } else { output_datum = DSET_BRICK_TYPE(dset,iv) ; if( output_datum == MRI_byte ) output_datum = MRI_short ; } #ifdef TTDEBUG printf(" ** datum = %s\n",MRI_TYPE_name[output_datum]) ; #endif iv = EDIT_dset_items( new_dset , ADN_prefix , TT_prefix , ADN_label1 , TT_prefix , ADN_directory_name , TT_session , ADN_self_name , cbuf , ADN_type , ISHEAD(dset) ? HEAD_FUNC_TYPE : GEN_FUNC_TYPE , ADN_func_type , FUNC_TT_TYPE , ADN_nvals , FUNC_nvals[FUNC_TT_TYPE] , ADN_ntt , 0 , /* 07 Jun 2007 */ ADN_datum_all , output_datum , ADN_none ) ; if( iv > 0 ) ERROR_exit("%d errors in attempting to create output dataset!",iv ) ; if( THD_deathcon() && THD_is_file(new_dset->dblk->diskptr->header_name) ) ERROR_exit( "Output dataset file %s already exists--cannot continue!\a", new_dset->dblk->diskptr->header_name ) ; #ifdef TTDEBUG printf("*** deleting exemplar dataset\n") ; #endif THD_delete_3dim_dataset( dset , False ) ; dset = NULL ; /** macro to test a malloc-ed pointer for validity **/ #define MTEST(ptr) \ if((ptr)==NULL) \ ( fprintf(stderr,"*** Cannot allocate memory for statistics!\n"), exit(0) ) /*-- make space for the t-test computations --*/ /* (allocate entire volumes) 13 Dec 2005 [rickr] */ npiece = 3.0 ; /* need at least this many */ if( TT_paired ) npiece += 1.0 ; else if( TT_set1 != NULL ) npiece += 2.0 ; npiece += mri_datum_size(output_datum) / (float) sizeof(float) ; npiece += mri_datum_size(output_datum) / (float) sizeof(float) ; #if 0 piece_size = TT_workmem * MEGA / ( npiece * sizeof(float) ) ; if( piece_size > nxyz ) piece_size = nxyz ; #ifdef TTDEBUG printf("*** malloc-ing space for statistics: %g float arrays of length %d\n", npiece,piece_size) ; #endif #endif av2 = (float *) malloc( sizeof(float) * nxyz ) ; MTEST(av2) ; sd2 = (float *) malloc( sizeof(float) * nxyz ) ; MTEST(sd2) ; ffim = (float *) malloc( sizeof(float) * nxyz ) ; MTEST(ffim) ; num2 = TT_set2->num ; if( TT_paired ){ av1 = sd1 = NULL ; gfim = (float *) malloc( sizeof(float) * nxyz ) ; MTEST(gfim) ; num1 = num2 ; } else if( TT_set1 != NULL ){ av1 = (float *) malloc( sizeof(float) * nxyz ) ; MTEST(av1) ; sd1 = (float *) malloc( sizeof(float) * nxyz ) ; MTEST(sd1) ; gfim = NULL ; num1 = TT_set1->num ; } else { av1 = sd1 = NULL ; gfim = NULL ; num1 = 0 ; } vdif = (void *) malloc( mri_datum_size(output_datum) * nxyz ) ; MTEST(vdif) ; vsp = (void *) malloc( mri_datum_size(output_datum) * nxyz ) ; MTEST(vsp) ; /* 27 Dec 2002: make DOF dataset (if prefix is given, and unpooled is on) */ if( TT_pooled == 0 && TT_dof_prefix[0] != '\0' ){ dofbrik = (float *) malloc( sizeof(float) * nxyz ) ; MTEST(dofbrik) ; dof_dset = EDIT_empty_copy( new_dset ) ; tross_Make_History( "3dttest" , argc,argv , dof_dset ) ; EDIT_dset_items( dof_dset , ADN_prefix , TT_dof_prefix , ADN_directory_name , TT_session , ADN_type , ISHEAD(dset) ? HEAD_FUNC_TYPE : GEN_FUNC_TYPE, ADN_func_type , FUNC_BUCK_TYPE , ADN_nvals , 1 , ADN_datum_all , MRI_float , ADN_none ) ; if( THD_is_file(dof_dset->dblk->diskptr->header_name) ) ERROR_exit( "-dof_prefix dataset file %s already exists--cannot continue!\a", dof_dset->dblk->diskptr->header_name ) ; EDIT_substitute_brick( dof_dset , 0 , MRI_float , dofbrik ) ; } /* print out memory usage to edify the user */ if( ! TT_be_quiet ){ memuse = sizeof(float) * nxyz * npiece + ( mri_datum_size(output_datum) + sizeof(short) ) * nxyz ; if( dofbrik != NULL ) memuse += sizeof(float) * nxyz ; /* 27 Dec 2002 */ printf("--- allocated %d Megabytes memory for internal use (%d volumes)\n", (int)(memuse/MEGA), (int)npiece) ; } mri_fix_data_pointer( vdif , DSET_BRICK(new_dset,0) ) ; /* attach bricks */ mri_fix_data_pointer( vsp , DSET_BRICK(new_dset,1) ) ; /* to new dataset */ /** only short and float are allowed for output **/ if( output_datum != MRI_short && output_datum != MRI_float ) ERROR_exit("Illegal output data type %d = %s", output_datum , MRI_TYPE_name[output_datum] ) ; num2_inv = 1.0 / num2 ; num2m1_inv = 1.0 / (num2-1) ; if( num1 > 0 ){ num1_inv = 1.0 / num1 ; num1m1_inv = 1.0 / (num1-1) ; } /*----- loop over pieces to process the input datasets with -----*/ /** macro to open a dataset and make it ready for processing **/ #define DOPEN(ds,name) \ do{ int pv ; (ds) = THD_open_dataset((name)) ; /* 16 Sep 1999 */ \ if( !ISVALID_3DIM_DATASET((ds)) ) \ ERROR_exit("Can't open dataset: %s",(name)) ; \ if( (ds)->daxes->nxx!=nx || (ds)->daxes->nyy!=ny || (ds)->daxes->nzz!=nz ) \ ERROR_exit("Axes size mismatch: %s",(name)) ; \ if( !EQUIV_GRIDS((ds),new_dset) ) \ WARNING_message("Grid mismatch: %s",(name)) ; \ if( DSET_NUM_TIMES((ds)) > 1 ) \ ERROR_exit("Can't use time-dependent data: %s",(name)) ; \ if( TT_use_editor ) EDIT_one_dataset( (ds), &TT_edopt ) ; \ else DSET_load((ds)) ; \ pv = DSET_PRINCIPAL_VALUE((ds)) ; \ if( DSET_ARRAY((ds),pv) == NULL ) \ ERROR_exit("Can't access data: %s",(name)) ; \ if( DSET_BRICK_TYPE((ds),pv) == MRI_complex ) \ ERROR_exit("Can't use complex data: %s",(name)) ; \ break ; } while (0) #if 0 /* can do it directly now (without offsets) 13 Dec 2005 [rickr] */ /** macro to return pointer to correct location in brick for current processing **/ #define SUB_POINTER(ds,vv,ind,ptr) \ do{ switch( DSET_BRICK_TYPE((ds),(vv)) ){ \ default: ERROR_exit("Illegal datum! ***"); \ case MRI_short:{ short * fim = (short *) DSET_ARRAY((ds),(vv)) ; \ (ptr) = (void *)( fim + (ind) ) ; \ } break ; \ case MRI_byte:{ byte * fim = (byte *) DSET_ARRAY((ds),(vv)) ; \ (ptr) = (void *)( fim + (ind) ) ; \ } break ; \ case MRI_float:{ float * fim = (float *) DSET_ARRAY((ds),(vv)) ; \ (ptr) = (void *)( fim + (ind) ) ; \ } break ; } break ; } while(0) #endif /** number of pieces to process **/ /* num_piece = (nxyz + piece_size - 1) / nxyz ; */ #if 0 nice(2) ; /** lower priority a little **/ #endif /* possibly open TT_base_dset now, and convert to floats */ if( TT_base_dname ) { DOPEN(base_dset, TT_base_dname) ; base_ary = (float *) malloc( sizeof(float) * nxyz ) ; MTEST(base_ary) ; EDIT_coerce_scale_type(nxyz , DSET_BRICK_FACTOR(base_dset,0) , DSET_BRICK_TYPE(base_dset,0),DSET_ARRAY(base_dset,0), /* input */ MRI_float ,base_ary ) ; /* output */ THD_delete_3dim_dataset( base_dset , False ) ; base_dset = NULL ; } /* only 1 'piece' now 13 Dec 2005 [rickr] */ for( piece=0 ; piece < 1 ; piece++ ){ fim_offset = 0 ; #ifdef TTDEBUG printf("*** start of piece %d: length=%d offset=%d\n",piece,nxyz,fim_offset) ; #else if( ! TT_be_quiet ){ printf("--- starting piece %d/%d (%d voxels) ",piece+1,1,nxyz) ; fflush(stdout) ; } #endif /** process set2 (and set1, if paired) **/ for( ii=0 ; ii < nxyz ; ii++ ) av2[ii] = 0.0 ; for( ii=0 ; ii < nxyz ; ii++ ) sd2[ii] = 0.0 ; for( kk=0 ; kk < num2 ; kk++ ){ /** read in the data **/ DOPEN(dset,TT_set2->ar[kk]) ; iv = DSET_PRINCIPAL_VALUE(dset) ; #ifndef TTDEBUG if( ! TT_be_quiet ){ printf(".") ; fflush(stdout) ; } /* progress */ #else printf(" ** opened dataset file %s\n",TT_set2->ar[kk]); #endif #if 0 /* fimfac will be compute when the results are ready */ if( piece == 0 && kk == 0 ){ fimfac = DSET_BRICK_FACTOR(dset,iv) ; if( fimfac == 0.0 ) fimfac = 1.0 ; fimfacinv = 1.0 / fimfac ; #ifdef TTDEBUG printf(" ** set fimfac = %g\n",fimfac) ; #endif } #endif /** convert it to floats (in ffim) **/ EDIT_coerce_scale_type(nxyz , DSET_BRICK_FACTOR(dset,iv) , DSET_BRICK_TYPE(dset,iv),DSET_ARRAY(dset,iv), /* input */ MRI_float ,ffim ) ; /* output */ THD_delete_3dim_dataset( dset , False ) ; dset = NULL ; /** get the paired dataset, if present **/ if( TT_paired ){ DOPEN(dset,TT_set1->ar[kk]) ; iv = DSET_PRINCIPAL_VALUE(dset) ; #ifndef TTDEBUG if( ! TT_be_quiet ){ printf(".") ; fflush(stdout) ; } /* progress */ #else printf(" ** opened dataset file %s\n",TT_set1->ar[kk]); #endif EDIT_coerce_scale_type( nxyz , DSET_BRICK_FACTOR(dset,iv) , DSET_BRICK_TYPE(dset,iv),DSET_ARRAY(dset,iv), /* input */ MRI_float ,gfim ) ; /* output */ THD_delete_3dim_dataset( dset , False ) ; dset = NULL ; if( TT_voxel >= 0 ) fprintf(stderr,"-- paired values #%02d: %f, %f\n", kk,ffim[TT_voxel],gfim[TT_voxel]) ; for( ii=0 ; ii < nxyz ; ii++ ) ffim[ii] -= gfim[ii] ; } else if( TT_voxel >= 0 ) fprintf(stderr,"-- set2 value #%02d: %f\n",kk,ffim[TT_voxel]); #ifdef TTDEBUG printf(" * adding into av2 and sd2\n") ; #endif /* accumulate into av2 and sd2 */ for( ii=0 ; ii < nxyz ; ii++ ){ dd = ffim[ii] ; av2[ii] += dd ; sd2[ii] += dd * dd ; } } /* end of loop over set2 datasets */ /** form the mean and stdev of set2 **/ #ifdef TTDEBUG printf(" ** forming mean and sigma of set2\n") ; #endif for( ii=0 ; ii < nxyz ; ii++ ){ av2[ii] *= num2_inv ; dd = (sd2[ii] - num2*av2[ii]*av2[ii]) ; sd2[ii] = (dd > 0.0) ? sqrt( num2m1_inv * dd ) : 0.0 ; } if( TT_voxel >= 0 ) fprintf(stderr,"-- s2 mean = %g, sd = %g\n", av2[TT_voxel],sd2[TT_voxel]) ; /** if set1 exists but is not paired with set2, process it now **/ if( ! TT_paired && TT_set1 != NULL ){ for( ii=0 ; ii < nxyz ; ii++ ) av1[ii] = 0.0 ; for( ii=0 ; ii < nxyz ; ii++ ) sd1[ii] = 0.0 ; for( kk=0 ; kk < num1 ; kk++ ){ DOPEN(dset,TT_set1->ar[kk]) ; iv = DSET_PRINCIPAL_VALUE(dset) ; #ifndef TTDEBUG if( ! TT_be_quiet ){ printf(".") ; fflush(stdout) ; } /* progress */ #else printf(" ** opened dataset file %s\n",TT_set1->ar[kk]); #endif EDIT_coerce_scale_type( nxyz , DSET_BRICK_FACTOR(dset,iv) , DSET_BRICK_TYPE(dset,iv),DSET_ARRAY(dset,iv), /* input */ MRI_float ,ffim ) ; /* output */ THD_delete_3dim_dataset( dset , False ) ; dset = NULL ; #ifdef TTDEBUG printf(" * adding into av1 and sd1\n") ; #endif for( ii=0 ; ii < nxyz ; ii++ ){ dd = ffim[ii] ; av1[ii] += dd ; sd1[ii] += dd * dd ; } if( TT_voxel >= 0 ) fprintf(stderr,"-- set1 value #%02d: %g\n",kk,ffim[TT_voxel]) ; } /* end of loop over set1 datasets */ /** form the mean and stdev of set1 **/ #ifdef TTDEBUG printf(" ** forming mean and sigma of set1\n") ; #endif for( ii=0 ; ii < nxyz ; ii++ ){ av1[ii] *= num1_inv ; dd = (sd1[ii] - num1*av1[ii]*av1[ii]) ; sd1[ii] = (dd > 0.0) ? sqrt( num1m1_inv * dd ) : 0.0 ; } if( TT_voxel >= 0 ) fprintf(stderr,"-- s1 mean = %g, sd = %g\n", av1[TT_voxel], sd1[TT_voxel]) ; } /* end of processing set1 by itself */ /***** now form difference and t-statistic *****/ #ifndef TTDEBUG if( ! TT_be_quiet ){ printf("+") ; fflush(stdout) ; } /* progress */ #else printf(" ** computing t-tests next\n") ; #endif #if 0 /* will do at end using EDIT_convert_dtype 13 Dec 2005 [rickr] */ /** macro to assign difference value to correct type of array **/ #define DIFASS switch( output_datum ){ \ case MRI_short: sdar[ii] = (short) (fimfacinv*dd) ; break ; \ case MRI_float: fdar[ii] = (float) dd ; break ; } #define TOP_SS 32700 #define TOP_TT (32700.0/FUNC_TT_SCALE_SHORT) #endif if( TT_paired || TT_use_bval == 1 ){ /** case 1: paired estimate or 1-sample **/ if( TT_paired || TT_n1 == 0 ){ /* the olde waye: 1 sample test */ f2 = 1.0 / sqrt( (double) num2 ) ; for( ii=0 ; ii < nxyz ; ii++ ){ av2[ii] -= (base_ary ? base_ary[ii] : TT_bval) ; /* final mean */ if( sd2[ii] > 0.0 ){ num_tt++ ; tt = av2[ii] / (f2 * sd2[ii]) ; sd2[ii] = tt; /* final t-stat */ tt = fabs(tt) ; if( tt > tt_max ) tt_max = tt ; } else { sd2[ii] = 0.0; } } if( TT_voxel >= 0 ) fprintf(stderr,"-- paired/bval mean = %g, t = %g\n", av2[TT_voxel], sd2[TT_voxel]) ; } else { /* 10 Oct 2007: -sdn1 was used with -base1: 'two' sample test */ f1 = (TT_n1-1.0) * (1.0/TT_n1 + 1.0/num2) / (TT_n1+num2-2.0) ; f2 = (num2 -1.0) * (1.0/TT_n1 + 1.0/num2) / (TT_n1+num2-2.0) ; for( ii=0 ; ii < nxyz ; ii++ ){ av2[ii] -= (base_ary ? base_ary[ii] : TT_bval) ; /* final mean */ q1 = f1 * TT_sd1*TT_sd1 + f2 * sd2[ii]*sd2[ii] ; if( q1 > 0.0 ){ num_tt++ ; tt = av2[ii] / sqrt(q1) ; sd2[ii] = tt ; /* final t-stat */ tt = fabs(tt) ; if( tt > tt_max ) tt_max = tt ; } else { sd2[ii] = 0.0 ; } } } /* end of -sdn1 special case */ #ifdef TTDEBUG printf(" ** paired or bval test: num_tt = %d\n",num_tt) ; #endif } else if( TT_pooled ){ /** case 2: unpaired 2-sample, pooled variance **/ f1 = (num1-1.0) * (1.0/num1 + 1.0/num2) / (num1+num2-2.0) ; f2 = (num2-1.0) * (1.0/num1 + 1.0/num2) / (num1+num2-2.0) ; for( ii=0 ; ii < nxyz ; ii++ ){ av2[ii] -= av1[ii] ; /* final mean */ q1 = f1 * sd1[ii]*sd1[ii] + f2 * sd2[ii]*sd2[ii] ; if( q1 > 0.0 ){ num_tt++ ; tt = av2[ii] / sqrt(q1) ; sd2[ii] = tt ; /* final t-stat */ tt = fabs(tt) ; if( tt > tt_max ) tt_max = tt ; } else { sd2[ii] = 0.0 ; } } if( TT_voxel >= 0 ) fprintf(stderr,"-- unpaired, pooled mean = %g, t = %g\n", av2[TT_voxel], sd2[TT_voxel]) ; #ifdef TTDEBUG printf(" ** pooled test: num_tt = %d\n",num_tt) ; #endif } else { /** case 3: unpaired 2-sample, unpooled variance **/ /** 27 Dec 2002: modified to save DOF into dofar **/ if( dofbrik != NULL ) dofar = dofbrik + fim_offset ; /* 27 Dec 2002 */ for( ii=0 ; ii < nxyz ; ii++ ){ av2[ii] -= av1[ii] ; q1 = num1_inv * sd1[ii]*sd1[ii] ; q2 = num2_inv * sd2[ii]*sd2[ii] ; if( q1>0.0 && q2>0.0 ){ /* have positive variances? */ num_tt++ ; tt = av2[ii] / sqrt(q1+q2) ; sd2[ii] = tt ; /* final t-stat */ tt = fabs(tt) ; if( tt > tt_max ) tt_max = tt ; if( dofar != NULL ) /* 27 Dec 2002 */ dofar[ii] = (q1+q2)*(q1+q2) / (num1m1_inv*q1*q1 + num2m1_inv*q2*q2) ; } else { sd2[ii] = 0.0 ; if( dofar != NULL ) dofar[ii] = 1.0 ; /* 27 Dec 2002 */ } } if( TT_voxel >= 0 ) fprintf(stderr,"-- unpaired, unpooled mean = %g, t = %g\n", av2[TT_voxel], sd2[TT_voxel]) ; #ifdef TTDEBUG printf(" ** unpooled test: num_tt = %d\n",num_tt) ; #endif } #ifndef TTDEBUG if( ! TT_be_quiet ){ printf("\n") ; fflush(stdout) ; } #endif } /* end of loop over pieces of the input */ if( TT_paired ){ printf("--- Number of degrees of freedom = %d (paired test)\n",num2-1) ; dof = num2 - 1 ; } else if( TT_use_bval == 1 ){ if( TT_n1 == 0 ){ printf("--- Number of degrees of freedom = %d (1-sample test)\n",num2-1) ; dof = num2 - 1 ; } else { dof = TT_n1+num2-2 ; printf("--- Number of degrees of freedom = %d (-sdn1 2-sample test)\n",(int)dof) ; } } else { printf("--- Number of degrees of freedom = %d (2-sample test)\n",num1+num2-2) ; dof = num1+num2-2 ; if( ! TT_pooled ) printf(" (For unpooled variance estimate, this is only approximate!)\n") ; } printf("--- Number of t-tests performed = %d out of %d voxels\n",num_tt,nxyz) ; printf("--- Largest |t| value found = %g\n",tt_max) ; kk = sizeof(ptable) / sizeof(float) ; for( ii=0 ; ii < kk ; ii++ ){ tt = student_p2t( ptable[ii] , dof ) ; printf("--- Double sided tail p = %8f at t = %8f\n" , ptable[ii] , tt ) ; } /**----------------------------------------------------------------------**/ /** now convert data to output format 13 Dec 2005 [rickr] **/ /* first set mean */ fimfac = EDIT_convert_dtype(nxyz , MRI_float,av2 , output_datum,vdif , 0.0) ; DSET_BRICK_FACTOR(new_dset, 0) = (fimfac != 0.0) ? 1.0/fimfac : 0.0 ; dd = fimfac; /* save for debug output */ /* if output is of type short, limit t-stat magnitude to 32.7 */ if( output_datum == MRI_short ){ for( ii=0 ; ii < nxyz ; ii++ ){ if ( sd2[ii] > 32.7 ) sd2[ii] = 32.7 ; else if( sd2[ii] < -32.7 ) sd2[ii] = -32.7 ; } } fimfac = EDIT_convert_dtype(nxyz , MRI_float,sd2 , output_datum,vsp , 0.0) ; DSET_BRICK_FACTOR(new_dset, 1) = (fimfac != 0.0) ? 1.0/fimfac : 0.0 ; #ifdef TTDEBUG printf(" ** fimfac for mean, t-stat = %g, %g\n",dd, fimfac) ; #endif /**----------------------------------------------------------------------**/ INFO_message("Writing combined dataset into %s\n", DSET_BRIKNAME(new_dset) ) ; fbuf[0] = dof ; for( ii=1 ; ii < MAX_STAT_AUX ; ii++ ) fbuf[ii] = 0.0 ; (void) EDIT_dset_items( new_dset , ADN_stat_aux , fbuf , ADN_none ) ; #if 0 /* factors already set */ fbuf[0] = (output_datum == MRI_short && fimfac != 1.0 ) ? fimfac : 0.0 ; fbuf[1] = (output_datum == MRI_short ) ? 1.0 / FUNC_TT_SCALE_SHORT : 0.0 ; (void) EDIT_dset_items( new_dset , ADN_brick_fac , fbuf , ADN_none ) ; #endif if( !AFNI_noenv("AFNI_AUTOMATIC_FDR") ) ii = THD_create_all_fdrcurves(new_dset) ; else ii = 0 ; THD_load_statistics( new_dset ) ; THD_write_3dim_dataset( NULL,NULL , new_dset , True ) ; if( ii > 0 ) ININFO_message("created %d FDR curves in header",ii) ; if( dof_dset != NULL ){ /* 27 Dec 2002 */ DSET_write( dof_dset ) ; WROTE_DSET( dof_dset ) ; } exit(0) ; }
int AFNI_process_environ( char *fname ) { int nbuf , nused , ii ; char *fbuf , *fptr ; char str[NSBUF] , left[NSBUF] , middle[NSBUF] , right[NSBUF], fname_str[NSBUF] = {"not_set"}; int nenv=0 , senv=0 ; static int first=1 ; /* 13 Mar 2008 */ ENTRY("AFNI_process_environ") ; bloced = 1 ; if( fname != NULL ){ strcpy(str,fname) ; } else { char *home ; if( afni_env_done ) RETURN(nenv) ; home = getenv("HOME") ; if( home != NULL ){ strcpy(str,home) ; strcat(str,"/.afnirc") ; } else { strcpy(str,".afnirc") ; } if( !THD_is_file(str) ){ /* 19 Sep 2007 */ if( home != NULL ){ strcpy(str,home) ; strcat(str,"/AFNI.afnirc") ; } else { strcpy(str,"AFNI.afnirc") ; } } afni_env_done = 1 ; } strcpy(fname_str,str) ; /* ZSS: Nov. 25 08 */ fbuf = AFNI_suck_file( str ) ; if( fbuf == NULL ){ bloced=0; if(fname==NULL)afni_env_done=0; RETURN(nenv); } nbuf = strlen(fbuf) ; if( nbuf == 0 ){ bloced=0; if(fname==NULL)afni_env_done=0; RETURN(nenv); } fptr = fbuf ; nused = 0 ; /** scan for section strings, which start with "***" **/ str[0] = '\0' ; /* initialize string */ while( nused < nbuf ){ /**----------------------------------------**/ /**-- skip ahead to next section keyword --**/ SkipSection: while( ! ISTARRED(str) ){ GETSTR; } /*- 04 Jun 1999 -*/ if( strcmp(str,"***END") == 0 ) break ; /* exit main loop */ if( strcmp(str,"***ENVIRONMENT") != 0 ){ GETSTR ; goto SkipSection ; } /**---------------------------------------**/ /**-- ENVIRONMENT section [04 Jun 1999] --**/ if( strcmp(str,"***ENVIRONMENT") == 0 ){ /* loop: find environment eqns */ char *enveqn , *eee; int nl , nr , allow_reset ; senv = 1 ; eee = getenv("AFNI_ENVIRON_RESET") ; allow_reset = YESSISH(eee) ; while(1){ /* loop, looking for 'name = value' */ GETEQN ; if( !THD_filename_pure(left) ) continue ; nl = strlen(left) ; nr = strlen(right) ; enveqn = (char *) malloc(nl+nr+4) ; strcpy(enveqn,left) ; strcat(enveqn,"=") ; strcat(enveqn,right) ; if( !(eee = getenv(left)) || allow_reset ){ /* ZSS Nov 25 2008 */ putenv(enveqn) ; } else if( !AFNI_noenv("AFNI_ENVIRON_WARNINGS") && strcmp(right, eee)){ INFO_message( "Environment variable %s already set to '%s'. " "Value of '%s' from %s is ignored. \n" "To kill such warnings Set AFNI_ENVIRON_WARNINGS to NO", left, eee, right, fname_str); } nenv++ ; } continue ; /* to end of outer while */ } /* end of ENVIRONMENT */ } /* end of while loop */ Done: if( fname == NULL && first ){ if( senv == 0 ) WARNING_message("didn't find '***ENVIRONMENT' line in ~/.afnirc") ; else if( nenv == 0 ) WARNING_message("didn't find any environment equations in ~/.afnirc") ; } first = 0 ; free(fbuf) ; bloced = 0 ; RETURN(nenv) ; }
void AFNI_start_fetching_url( char *urlstring ) { pid_t child_pid ; #ifdef CYGWIN /* 18 Dec 2002 */ FAIL_MESSAGE("not possible under Cygwin") ; return ; #else /*-- decide if we are to do anything --*/ if( AFNI_noenv("AFNI_VERSION_CHECK") ){ /* never check */ FAIL_MESSAGE("AFNI_VERSION_CHECK forbids") ; return ; } #undef VDELAY #define VDELAY 1234567 /* about 2 weeks */ /* check if we did this in the last VDELAY seconds */ /* also, update global motd_old */ if( vc_check_too_soon() ) { disabled = 1 ; return ; } /*-- OK, start the child process --*/ child_pid = fork() ; if( child_pid == (pid_t)(-1) ){ /* bad */ FAIL_MESSAGE("can't fork") ; return ; } /*---------------------------------------------------------*/ if( child_pid > 0 ){ /* I'm the parent */ /*-- save PID of child for later use --*/ vc_child_pid = child_pid ; /*-- open an IOCHAN to talk to child --*/ vc_ioc = iochan_init( STR_CHILD , "accept" ) ; if( vc_ioc == NULL ){ kill(child_pid,SIGTERM) ; /* cf. Abraham and Isaac */ vc_child_pid = (pid_t)(-1) ; FAIL_MESSAGE("can't open connection to child") ; } else { atexit( vc_exit ) ; /* 12 Dec 2002 */ } return ; /*---------------------------------------------------------*/ } else { /* I'm the child */ /* (never returns) */ int nbuf=0 , jj ; char *vbuf=NULL ; IOCHAN *ioc ; struct utsname ubuf ; char ua[512] ; iochan_enable_perror(0) ; /* don't print TCP/IP error messages */ signal( SIGTERM , vexit ) ; /* if parent kills us, call vexit() */ /*-- get information from the AFNI server --*/ #define USE_HTTP_10 #ifdef USE_HTTP_10 # undef PCLAB # ifdef SHOWOFF # undef SHSH # undef SHSHSH # define SHSH(x) #x # define SHSHSH(x) SHSH(x) # define PCLAB SHSHSH(SHOWOFF) # else # define PCLAB "Unknown" # endif #endif /** 25 Mar 2005: send more info in the request header **/ #ifdef USE_HTTP_10 ubuf.nodename[0] = ubuf.sysname[0] = ubuf.machine[0] = '\0' ; jj = uname( &ubuf ) ; if( jj >= 0 && ubuf.nodename[0] != '\0' ) sprintf( ua , "afni (avers='%s'; prec='%s' node='%s'; sys='%s'; mach='%s')" , AVERZHN, PCLAB, ubuf.nodename, ubuf.sysname, ubuf.machine ) ; else sprintf( ua , "afni (avers='%s'; prec='%s')" , AVERZHN , PCLAB ) ; set_HTTP_10( 1 ) ; set_HTTP_user_agent( ua ) ; #else set_HTTP_10( 0 ) ; #endif /* send the request */ THD_death_setup( 34567 ) ; /* die if 34.567 seconds passes away */ nbuf = read_URL( urlstring , &vbuf ) ; /* may take a while */ set_HTTP_10( 0 ) ; /*-- if this failed, quit --*/ if( nbuf <= 0 || vbuf == NULL || vbuf[0] == '\0' ) { /* block recheck until a new DELAY has passed 22 Mar 2016 [rickr] */ /* - also so server is not flooded when there are issues */ AFNI_update_vctime(NULL, NULL); vexit(1); } /*-- talk to parent process thru IOCHAN --*/ ioc = iochan_init( STR_CHILD , "create" ) ; if( ioc == NULL ) vexit(2); /*-- wait until ioc is ready for writing --*/ jj = iochan_writecheck(ioc,-1) ; if( jj < 0 ) vexit(3); /*-- send the info in vbuf --*/ iochan_sendall( ioc , vbuf , nbuf ) ; while( ! iochan_clearcheck(ioc,10) ) /* loop until cleared */ AFNI_sleep(10) ; /* by parent process */ AFNI_sleep(10); /* a little extra napping, then death */ _exit(0); } #endif /* not CYGWIN */ }
THD_3dim_dataset * THD_open_nifti( char *pathname ) { THD_3dim_dataset *dset=NULL ; nifti_image *nim ; int ntt , nbuc , nvals ; int use_qform = 0 , use_sform = 0, form_code = 0 ; int statcode = 0 , datum , iview , ibr ; int scale_data = 0 ; /* flag based on scl_slope and inter 20 Jun 2008 */ int xform_data = 0; THD_ivec3 orixyz , nxyz ; THD_fvec3 dxyz , orgxyz ; THD_mat33 R ; mat44 ijk_to_dicom44 ; char *ppp , prefix[THD_MAX_PREFIX] ; char form_priority = 'S' ; /* 23 Mar 2006 */ static int n_xform_warn=0; ENTRY("THD_open_nifti") ; /*-- open input file --*/ { /* set the nifti_io debug level 8 Apr 2005 [rickr] */ char * ept = my_getenv("AFNI_NIFTI_DEBUG"); if( ept != NULL ) nifti_set_debug_level(atoi(ept)); } nifti_set_alter_cifti(1) ; /* if CIFTI, shift dims 23 Jul 2015 [rickr] */ nim = nifti_image_read( pathname, 0 ) ; if( nim == NULL || nim->nifti_type == 0 ) RETURN(NULL) ; /*-- extract some useful AFNI-ish information from the nim struct --*/ /* we must have at least 2 spatial dimensions */ /* this should be okay 11 Jun 2007 */ /* if( nim->nx < 2 || nim->ny < 2 ) RETURN(NULL) ; */ /* 4th dimension = time; 5th dimension = bucket: these are mutually exclusive in AFNI at present */ ntt = nim->nt ; nbuc = nim->nu ; /* nt and nu might be 0 now (see irritating niftilib 1.17 update) */ /* so ensure that ntt and nbuc are positive 02 Mar 2006 [rickr] */ if( ntt <= 0 ) ntt = 1; if( nbuc <= 0 ) nbuc = 1; if( nim->nz <= 0 ) nim->nz = 1 ; /* 03 Mar 2006: RWCox */ if( ntt > 1 && nbuc > 1 ){ fprintf(stderr, "** AFNI can't deal with 5 dimensional NIfTI(%s)\n", pathname ) ; RETURN(NULL) ; } nvals = MAX(ntt,nbuc) ; /* collapse higher-dimensional datasets 23 Jul 2015 [rickr] */ /* (this includes CIFTI) */ if( nim->nv > 1 ) nvals *= nim->nv; if( nim->nw > 1 ) nvals *= nim->nw; if( ntt > 1 ) ntt = nvals; else nbuc = nvals; /* determine type of dataset values: if we are scaling, or if the data type in the NIfTI file is something AFNI can't handle, then the result will be floats */ /* do not scale if slope is 0 or if slope is 1 and inter is 0 */ if( !isfinite(nim->scl_slope) || !isfinite(nim->scl_inter) ){ fprintf(stderr,"** bad scl_slope and inter = %f, %f, ignoring...\n", nim->scl_slope, nim->scl_inter); } else { scale_data = nim->scl_slope != 0.0 && (nim->scl_slope != 1.0 || nim->scl_inter != 0.0) ; } { char *eee = getenv("AFNI_NIFTI_SCALE") ; if( eee != NULL && toupper(*eee) == 'N' ) scale_data = 0 ; } switch( nim->datatype ){ default: fprintf(stderr, "** AFNI can't handle NIFTI datatype=%d (%s) in file %s\n", nim->datatype, nifti_datatype_string(nim->datatype), pathname ); RETURN(NULL) ; break ; case DT_UINT8: datum = scale_data ? MRI_float : MRI_byte ; xform_data = scale_data; break ; case DT_INT16: datum = scale_data ? MRI_float : MRI_short ; xform_data = scale_data; break ; case DT_FLOAT32: datum = MRI_float ; break ; case DT_COMPLEX64: datum = MRI_complex ; break ; case DT_RGB24: datum = MRI_rgb ; break ; case DT_INT8: /* NIfTI-1 data types that AFNI can't handle directly */ case DT_UINT16: case DT_INT32: case DT_UINT32: case DT_FLOAT64: datum = MRI_float ; xform_data = 1 ; break ; #if 0 case DT_COMPLEX128: /* this case would be too much like real work */ fprintf(stderr, "** AFNI convert NIFTI_datatype=%d (%s) in file %s to COMPLEX64\n", nim->datatype, nifti_datatype_string(nim->datatype), pathname ); datum = MRI_complex ; break ; #endif } if( xform_data && !AFNI_noenv("AFNI_NIFTI_TYPE_WARN")) { if (!n_xform_warn || AFNI_yesenv("AFNI_NIFTI_TYPE_WARN")) {/* ZSS 04/11 */ fprintf(stderr, "** AFNI converts NIFTI_datatype=%d (%s) in file %s to FLOAT32\n", nim->datatype, nifti_datatype_string(nim->datatype), pathname ); if (!AFNI_yesenv("AFNI_NIFTI_TYPE_WARN")) { fprintf(stderr, " Warnings of this type will be muted for this session.\n" " Set AFNI_NIFTI_TYPE_WARN to YES to see them all, NO to see none.\n"); } } ++n_xform_warn; } /* check for statistics code */ if( nim->intent_code >= NIFTI_FIRST_STATCODE && nim->intent_code <= NIFTI_LAST_STATCODE ){ if( nim->intent_code > FUNC_PT_TYPE ){ fprintf(stderr, "** AFNI doesn't understand NIFTI statistic type %d (%s) in file %s\n", nim->intent_code , nifti_intent_string(nim->intent_code) , pathname ) ; } else { statcode = nim->intent_code ; if( nbuc > 1 ){ fprintf(stderr, "** AFNI doesn't support NIFTI voxel-dependent statistic parameters" " in file %s\n" , pathname ) ; statcode = 0 ; } } } /* 23 Mar 2006: set qform or sform as having priority -- RWCox */ ppp = my_getenv("NIFTI_FORM_PRIORITY") ; if( ppp == NULL ) ppp = getenv("AFNI_FORM_PRIORITY") ; if( ppp == NULL ) ppp = getenv("AFNI_NIFTI_PRIORITY") ; if( ppp == NULL ) ppp = getenv("AFNI_NIFTI_FORM") ; if( ppp == NULL ) ppp = getenv("AFNI_NIFTI_FORM_PRIORITY") ; if( ppp != NULL ){ char fp = toupper(*ppp) ; if( fp == 'S' || fp == 'Q' ) form_priority = fp ; else WARNING_message("Illegal NIFTI_FORM_PRIORITY='%s'",ppp) ; } /** 24 Mar 2006: check determs of qform and sform, if have both **/ if( nim->qform_code > 0 && nim->sform_code > 0 ){ float qdet , sdet ; LOAD_MAT(R, nim->qto_xyz.m[0][0] , nim->qto_xyz.m[0][1] , nim->qto_xyz.m[0][2] , nim->qto_xyz.m[1][0] , nim->qto_xyz.m[1][1] , nim->qto_xyz.m[1][2] , nim->qto_xyz.m[2][0] , nim->qto_xyz.m[2][1] , nim->qto_xyz.m[2][2] ) ; qdet = MAT_DET(R) ; LOAD_MAT(R, nim->sto_xyz.m[0][0] , nim->sto_xyz.m[0][1] , nim->sto_xyz.m[0][2] , nim->sto_xyz.m[1][0] , nim->sto_xyz.m[1][1] , nim->sto_xyz.m[1][2] , nim->sto_xyz.m[2][0] , nim->sto_xyz.m[2][1] , nim->sto_xyz.m[2][2] ) ; sdet = MAT_DET(R) ; if( qdet*sdet < 0.0f ) WARNING_message("NIfTI('%s'): Qform/Sform handedness differ; %c wins!", pathname , form_priority ) ; } /* KRH 07/11/05 -- adding ability to choose spatial transform from the options of qform, sform, bothform, or noform. If qform is present, it will be used. If qform is absent, but sform present, then the sform will be modified to be an orthogonal rotation and used. If both qform and sform are absent, then we will have an error. Previously assumed qform present. */ /* 23 Mar 2006: use form_priority to choose between them */ if ((nim->qform_code > 0) && (nim->sform_code > 0) ) { if( form_priority == 'Q' ) { use_qform = 1 ; use_sform = 0 ; } else { use_qform = 0 ; use_sform = 1 ; } } else if (nim->qform_code > 0){ use_qform = 1 ; use_sform = 0 ; } else if (nim->sform_code > 0){ use_qform = 0 ; use_sform = 1 ; } else { use_qform = 0 ; use_sform = 0 ; WARNING_message( "NO spatial transform (neither qform nor sform), in NIfTI file '%s'" , pathname ) ; } /** now take NIfTI-1.1 coords and transform to AFNI codes **/ if (use_qform) { float orgx, orgy, orgz ; form_code = nim->qform_code; /* determine orientation from the qto_xyz matrix, which transforms (i,j,k) voxel indexes to (x,y,z) LPI coordinates */ LOAD_MAT(R, -nim->qto_xyz.m[0][0] , /* negate x and y */ -nim->qto_xyz.m[0][1] , /* coefficients, */ -nim->qto_xyz.m[0][2] , /* since AFNI works */ -nim->qto_xyz.m[1][0] , /* with RAI coords, */ -nim->qto_xyz.m[1][1] , /* but NIFTI uses */ -nim->qto_xyz.m[1][2] , /* LPI coordinates. */ nim->qto_xyz.m[2][0] , /* [Which is my own] */ nim->qto_xyz.m[2][1] , /* [damn fault!!!!!] */ nim->qto_xyz.m[2][2] ) ; LOAD_MAT44(ijk_to_dicom44, -nim->qto_xyz.m[0][0] , /* negate x and y */ -nim->qto_xyz.m[0][1] , /* coefficients, */ -nim->qto_xyz.m[0][2] , /* since AFNI works */ -nim->qto_xyz.m[0][3] , -nim->qto_xyz.m[1][0] , /* with RAI coords, */ -nim->qto_xyz.m[1][1] , /* but NIFTI uses */ -nim->qto_xyz.m[1][2] , /* LPI coordinates. */ -nim->qto_xyz.m[1][3] , nim->qto_xyz.m[2][0] , /* [Which is my own] */ nim->qto_xyz.m[2][1] , /* [damn fault!!!!!] */ nim->qto_xyz.m[2][2] , nim->qto_xyz.m[2][3] ) ; orixyz = THD_matrix_to_orientation( R ) ; /* compute orientation codes */ iview = NIFTI_code_to_view(nim->qform_code); /* load the offsets and the grid spacings */ if (ORIENT_xyz[orixyz.ijk[0]] == 'z' ) { orgx = nim->qto_xyz.m[ORIENT_xyzint[orixyz.ijk[0]] - 1][3] ; } else { orgx = - nim->qto_xyz.m[ORIENT_xyzint[orixyz.ijk[0]] - 1][3] ; } if (ORIENT_xyz[orixyz.ijk[1]] == 'z' ) { orgy = nim->qto_xyz.m[ORIENT_xyzint[orixyz.ijk[1]] - 1][3] ; } else { orgy = - nim->qto_xyz.m[ORIENT_xyzint[orixyz.ijk[1]] - 1][3] ; } if (ORIENT_xyz[orixyz.ijk[2]] == 'z' ) { orgz = nim->qto_xyz.m[ORIENT_xyzint[orixyz.ijk[2]] - 1][3] ; } else { orgz = - nim->qto_xyz.m[ORIENT_xyzint[orixyz.ijk[2]] - 1][3] ; } LOAD_FVEC3( orgxyz , orgx , orgy , orgz ) ; #if 0 LOAD_FVEC3( orgxyz , -nim->qto_xyz.m[0][3] , /* again, negate */ -nim->qto_xyz.m[1][3] , /* x and y coords */ nim->qto_xyz.m[2][3] ) ; #endif /* AFNI space units are always mm */ if( nim->xyz_units == NIFTI_UNITS_METER ){ nim->dx *= 1000.0 ; nim->dy *= 1000.0 ; nim->dz *= 1000.0 ; } else if( nim->xyz_units == NIFTI_UNITS_MICRON ){ nim->dx *= 0.001 ; nim->dy *= 0.001 ; nim->dz *= 0.001 ; } LOAD_FVEC3( dxyz , (ORIENT_sign[orixyz.ijk[0]]=='+') ? nim->dx : -nim->dx , (ORIENT_sign[orixyz.ijk[1]]=='+') ? nim->dy : -nim->dy , (ORIENT_sign[orixyz.ijk[2]]=='+') ? nim->dz : -nim->dz ) ; } else if (use_sform) { int orimap[7] = { 6 , 1 , 0 , 2 , 3 , 4 , 5 } ; int oritmp[3] ; float dxtmp, dytmp, dztmp ; float xmax, ymax, zmax ; float orgx, orgy, orgz ; float fig_merit, ang_merit ; form_code = nim->sform_code; /* convert sform to nifti orientation codes */ /* n2 10 Jul, 2015 [rickr] */ nifti_dmat44_to_orientation(nim->sto_xyz, &oritmp[0], &oritmp[1], &oritmp[2] ) ; /* convert nifti orientation codes to AFNI codes and store in vector */ LOAD_IVEC3( orixyz , orimap[oritmp[0]] , orimap[oritmp[1]] , orimap[oritmp[2]] ) ; /* assume original view if there's no talairach id present */ iview = NIFTI_code_to_view(nim->sform_code); /* load the offsets and the grid spacings */ if (ORIENT_xyz[orixyz.ijk[0]] == 'z' ) { orgx = nim->sto_xyz.m[ORIENT_xyzint[orixyz.ijk[0]] - 1][3] ; } else { orgx = - nim->sto_xyz.m[ORIENT_xyzint[orixyz.ijk[0]] - 1][3] ; } if (ORIENT_xyz[orixyz.ijk[1]] == 'z' ) { orgy = nim->sto_xyz.m[ORIENT_xyzint[orixyz.ijk[1]] - 1][3] ; } else { orgy = - nim->sto_xyz.m[ORIENT_xyzint[orixyz.ijk[1]] - 1][3] ; } if (ORIENT_xyz[orixyz.ijk[2]] == 'z' ) { orgz = nim->sto_xyz.m[ORIENT_xyzint[orixyz.ijk[2]] - 1][3] ; } else { orgz = - nim->sto_xyz.m[ORIENT_xyzint[orixyz.ijk[2]] - 1][3] ; } LOAD_FVEC3( orgxyz , orgx , orgy , orgz ) ; #if 0 LOAD_FVEC3( orgxyz , -nim->sto_xyz.m[0][3] , /* again, negate */ -nim->sto_xyz.m[1][3] , /* x and y coords */ nim->sto_xyz.m[2][3] ) ; #endif #define MAXNUM(a,b) ( (a) > (b) ? (a):(b)) #define MAX3(a,b,c) ( (MAXNUM(a,b)) > (MAXNUM(a,c)) ? (MAXNUM(a,b)):(MAXNUM(a,c))) #define MINNUM(a,b) ( (a) < (b) ? (a):(b)) #define MIN3(a,b,c) ( (MINNUM(a,b)) < (MINNUM(a,c)) ? (MINNUM(a,b)):(MINNUM(a,c))) dxtmp = sqrt ( nim->sto_xyz.m[0][0] * nim->sto_xyz.m[0][0] + nim->sto_xyz.m[1][0] * nim->sto_xyz.m[1][0] + nim->sto_xyz.m[2][0] * nim->sto_xyz.m[2][0] ) ; xmax = MAX3(fabs(nim->sto_xyz.m[0][0]),fabs(nim->sto_xyz.m[1][0]),fabs(nim->sto_xyz.m[2][0])) / dxtmp ; dytmp = sqrt ( nim->sto_xyz.m[0][1] * nim->sto_xyz.m[0][1] + nim->sto_xyz.m[1][1] * nim->sto_xyz.m[1][1] + nim->sto_xyz.m[2][1] * nim->sto_xyz.m[2][1] ) ; ymax = MAX3(fabs(nim->sto_xyz.m[0][1]),fabs(nim->sto_xyz.m[1][1]),fabs(nim->sto_xyz.m[2][1])) / dytmp ; dztmp = sqrt ( nim->sto_xyz.m[0][2] * nim->sto_xyz.m[0][2] + nim->sto_xyz.m[1][2] * nim->sto_xyz.m[1][2] + nim->sto_xyz.m[2][2] * nim->sto_xyz.m[2][2] ) ; zmax = MAX3(fabs(nim->sto_xyz.m[0][2]),fabs(nim->sto_xyz.m[1][2]),fabs(nim->sto_xyz.m[2][2])) / dztmp ; fig_merit = MIN3(xmax,ymax,zmax) ; ang_merit = acos (fig_merit) * 180.0 / 3.141592653 ; #if 0 if (fabs(ang_merit) > .01) { WARNING_message ( "qform not present in:\n" " '%s'\n" " oblique sform used, and the worst axis is\n" " %f degrees from plumb.\n" " If you are performing spatial transformations on this dset, \n" " or viewing/combining it with volumes of differing obliquity,\n" " you should consider running: \n" " 3dWarp -deoblique \n" " on this and other oblique datasets in the same session.\n" ,pathname, ang_merit ) ; } #endif if( nim->xyz_units == NIFTI_UNITS_METER ){ dxtmp *= 1000.0 ; dytmp *= 1000.0 ; dztmp *= 1000.0 ; } else if( nim->xyz_units == NIFTI_UNITS_MICRON ){ dxtmp *= 0.001 ; dytmp *= 0.001 ; dztmp *= 0.001 ; } LOAD_FVEC3( dxyz , (ORIENT_sign[orixyz.ijk[0]]=='+') ? dxtmp : -dxtmp , (ORIENT_sign[orixyz.ijk[1]]=='+') ? dytmp : -dytmp , (ORIENT_sign[orixyz.ijk[2]]=='+') ? dztmp : -dztmp ) ; LOAD_MAT44(ijk_to_dicom44, -nim->sto_xyz.m[0][0] , /* negate x and y */ -nim->sto_xyz.m[0][1] , /* coefficients, */ -nim->sto_xyz.m[0][2] , /* since AFNI works */ -nim->sto_xyz.m[0][3] , -nim->sto_xyz.m[1][0] , /* with RAI coords, */ -nim->sto_xyz.m[1][1] , /* but NIFTI uses */ -nim->sto_xyz.m[1][2] , /* LPI coordinates. */ -nim->sto_xyz.m[1][3] , nim->sto_xyz.m[2][0] , /* [Which is my own] */ nim->sto_xyz.m[2][1] , /* [damn fault!!!!!] */ nim->sto_xyz.m[2][2] , nim->sto_xyz.m[2][3] ) ; } else { /* NO SPATIAL XFORM. BAD BAD BAD BAD BAD BAD. */ float dxtmp, dytmp, dztmp ; /* if pixdim data are present, use them in order to set pixel dimensions. otherwise, set the dimensions to 1 unit. */ dxtmp = ((nim->pixdim[1] > 0) ? nim->pixdim[1] : 1) ; dytmp = ((nim->pixdim[2] > 0) ? nim->pixdim[2] : 1) ; dztmp = ((nim->pixdim[3] > 0) ? nim->pixdim[3] : 1) ; if( nim->xyz_units == NIFTI_UNITS_METER ){ dxtmp *= 1000.0 ; dytmp *= 1000.0 ; dztmp *= 1000.0 ; } else if( nim->xyz_units == NIFTI_UNITS_MICRON ){ dxtmp *= 0.001 ; dytmp *= 0.001 ; dztmp *= 0.001 ; } /* set orientation to LPI by default */ LOAD_IVEC3( orixyz , 1 , 2 , 4 ) ; LOAD_FVEC3( dxyz , (ORIENT_sign[orixyz.ijk[0]]=='+') ? dxtmp : -dxtmp , (ORIENT_sign[orixyz.ijk[1]]=='+') ? dytmp : -dytmp , (ORIENT_sign[orixyz.ijk[2]]=='+') ? dztmp : -dztmp ) ; iview = NIFTI_default_view(); /* set origin to 0,0,0 */ LOAD_FVEC3( orgxyz , 0 , 0 , 0 ) ; /* put scaled identity matrix by default */ LOAD_MAT44(ijk_to_dicom44, dxtmp, 0.0, 0.0, 0.0, 0.0, dytmp, 0.0, 0.0, 0.0, 0.0, dztmp, 0.0 ); } /*-- make an AFNI dataset! --*/ dset = EDIT_empty_copy(NULL) ; ppp = THD_trailname(pathname,0) ; /* strip directory */ MCW_strncpy( prefix , ppp , THD_MAX_PREFIX ) ; /* to make prefix */ /* You need to set the path too before, if you loaded ~/tmp/joe.nii the path appeared to be ./joe.nii, troubling in multiple instances. ZSS Dec 2011 */ THD_init_diskptr_names( dset->dblk->diskptr , THD_filepath(pathname) , NULL , prefix , dset->view_type , True ); nxyz.ijk[0] = nim->nx ; /* grid dimensions */ nxyz.ijk[1] = nim->ny ; nxyz.ijk[2] = nim->nz ; dset->idcode.str[0] = 'N' ; /* overwrite 1st 3 bytes with something special */ dset->idcode.str[1] = 'I' ; dset->idcode.str[2] = 'I' ; MCW_hash_idcode( pathname , dset ) ; /* 06 May 2005 */ EDIT_dset_items( dset , ADN_prefix , prefix , ADN_datum_all , datum , ADN_nxyz , nxyz , ADN_xyzdel , dxyz , ADN_xyzorg , orgxyz , ADN_xyzorient , orixyz , ADN_malloc_type , DATABLOCK_MEM_MALLOC , ADN_view_type , iview , ADN_type , (statcode != 0) ? HEAD_FUNC_TYPE : HEAD_ANAT_TYPE , ADN_none ) ; /* copy transformation matrix to dataset structure */ /* moved after setting grid 4 Apr 2014 [rickr,drg] */ dset->daxes->ijk_to_dicom_real = ijk_to_dicom44; /* not a time dependent dataset */ if( ntt < 2 ){ EDIT_dset_items( dset , ADN_nvals , nbuc , ADN_datum_all , datum , ADN_func_type , (statcode != 0) ? FUNC_BUCK_TYPE : ANAT_BUCK_TYPE , ADN_none ) ; } else { /* is a time dependent dataset */ if( nim->time_units == NIFTI_UNITS_MSEC ){ nim->dt *= 0.001 ; nim->toffset *= 0.001 ; } else if( nim->time_units == NIFTI_UNITS_USEC ){ nim->dt *= 1.e-6 ; nim->toffset *= 1.e-6 ; } EDIT_dset_items( dset , ADN_nvals , ntt , ADN_ntt , ntt , ADN_datum_all , datum , ADN_ttorg , nim->toffset , /* 12 Oct 2007 [rickr] */ ADN_ttdel , nim->dt , ADN_ttdur , 0.0 , ADN_tunits , UNITS_SEC_TYPE , ADN_func_type , (statcode != 0) ? FUNC_FIM_TYPE : ANAT_EPI_TYPE , ADN_none ) ; /* if present, add stuff about the slice-timing offsets */ if( nim->slice_dim == 3 && /* AFNI can only deal with */ nim->slice_code > 0 && /* slice timing offsets */ nim->slice_duration > 0.0 && /* along the k-axis of */ nim->slice_start >= 0 && /* the dataset volume */ nim->slice_start < nim->nz && nim->slice_end > nim->slice_start && nim->slice_end < nim->nz ){ float *toff=(float *)calloc(sizeof(float),nim->nz) , tsl ; int kk ; if( nim->time_units == NIFTI_UNITS_MSEC ) nim->slice_duration *= 0.001; else if( nim->time_units == NIFTI_UNITS_USEC ) nim->slice_duration *= 1.e-6; /* set up slice time offsets in the divers orders */ switch( nim->slice_code ){ case NIFTI_SLICE_SEQ_INC: tsl = 0.0 ; for( kk=nim->slice_start ; kk <= nim->slice_end ; kk++ ){ toff[kk] = tsl ; tsl += nim->slice_duration ; } break ; case NIFTI_SLICE_SEQ_DEC: tsl = 0.0 ; for( kk=nim->slice_end ; kk >= nim->slice_end ; kk-- ){ toff[kk] = tsl ; tsl += nim->slice_duration ; } break ; case NIFTI_SLICE_ALT_INC: tsl = 0.0 ; for( kk=nim->slice_start ; kk <= nim->slice_end ; kk+=2 ){ toff[kk] = tsl ; tsl += nim->slice_duration ; } for( kk=nim->slice_start+1 ; kk <= nim->slice_end ; kk+=2 ){ toff[kk] = tsl ; tsl += nim->slice_duration ; } break ; case NIFTI_SLICE_ALT_INC2: tsl = 0.0 ; for( kk=nim->slice_start+1 ; kk <= nim->slice_end ; kk+=2 ){ toff[kk] = tsl ; tsl += nim->slice_duration ; } for( kk=nim->slice_start ; kk <= nim->slice_end ; kk+=2 ){ toff[kk] = tsl ; tsl += nim->slice_duration ; } break ; case NIFTI_SLICE_ALT_DEC: tsl = 0.0 ; for( kk=nim->slice_end ; kk >= nim->slice_start ; kk-=2 ){ toff[kk] = tsl ; tsl += nim->slice_duration ; } for( kk=nim->slice_end-1 ; kk >= nim->slice_start ; kk-=2 ){ toff[kk] = tsl ; tsl += nim->slice_duration ; } break ; case NIFTI_SLICE_ALT_DEC2: tsl = 0.0 ; for( kk=nim->slice_end-1 ; kk >= nim->slice_start ; kk-=2 ){ toff[kk] = tsl ; tsl += nim->slice_duration ; } for( kk=nim->slice_end ; kk >= nim->slice_start ; kk-=2 ){ toff[kk] = tsl ; tsl += nim->slice_duration ; } break ; } EDIT_dset_items( dset , ADN_nsl , nim->nz , ADN_zorg_sl , orgxyz.xyz[2] , ADN_dz_sl , dxyz.xyz[2] , ADN_toff_sl , toff , ADN_none ) ; free(toff) ; } /* end of slice timing stuff */ } /* end of 3D+time dataset stuff */ /* set atlas space based on NIFTI s/qform code */ NIFTI_code_to_space(form_code,dset); /* add statistics, if present */ if( statcode != 0 ){ for( ibr=0 ; ibr < nvals ; ibr++ ) EDIT_STATAUX4(dset,ibr,statcode,nim->intent_p1,nim->intent_p2,nim->intent_p3,0) ; } /*-- flag to read data from disk using NIFTI functions --*/ dset->dblk->diskptr->storage_mode = STORAGE_BY_NIFTI ; strcpy( dset->dblk->diskptr->brick_name , pathname ) ; dset->dblk->diskptr->byte_order = nim->byteorder ; #if 0 for( ibr=0 ; ibr < nvals ; ibr++ ){ /* make sub-brick labels */ sprintf(prefix,"%s[%d]",tname,ibr) ; EDIT_BRICK_LABEL( dset , ibr , prefix ) ; } #endif /** 10 May 2005: see if there is an AFNI extension; if so, load attributes from it and then edit the dataset appropriately **/ { int ee ; /* extension index */ /* scan extension list to find the first AFNI extension */ for( ee=0 ; ee < nim->num_ext ; ee++ ) if( nim->ext_list[ee].ecode == NIFTI_ECODE_AFNI && nim->ext_list[ee].esize > 32 && nim->ext_list[ee].edata != NULL ) break ; /* if found an AFNI extension ... */ if( ee < nim->num_ext ){ char *buf = nim->ext_list[ee].edata , *rhs , *cpt ; int nbuf = nim->ext_list[ee].esize - 8 ; NI_stream ns ; void *nini ; NI_group *ngr , *nngr ; /* if have data, it's long enough, and starts properly, then ... */ if( buf != NULL && nbuf > 32 && strncmp(buf,"<?xml",5)==0 ){ if( buf[nbuf-1] != '\0' ) buf[nbuf-1] = '\0' ; /* for safety */ cpt = strstr(buf,"?>") ; /* find XML prolog close */ if( cpt != NULL ){ /* if found it, then ... */ ns = NI_stream_open( "str:" , "r" ) ; NI_stream_setbuf( ns , cpt+2 ) ; /* start just after prolog */ nini = NI_read_element(ns,1) ; /* get root element */ NI_stream_close(ns) ; if( NI_element_type(nini) == NI_GROUP_TYPE ){ /* must be a group */ ngr = (NI_group *)nini ; if( strcmp(ngr->name,"AFNI_attributes") == 0 ){ /* root is OK */ nngr = ngr ; } else { /* search in group for proper element */ int nn ; void **nnini ; nn = NI_search_group_deep( ngr , "AFNI_attributes" , &nnini ) ; if( nn <= 0 ) nngr = NULL ; else { nngr = (NI_group *)nnini[0]; NI_free(nnini); } } if( NI_element_type(nngr) == NI_GROUP_TYPE ){ /* have good name */ rhs = NI_get_attribute( nngr , "self_idcode" ) ; if( rhs == NULL ) rhs = NI_get_attribute( nngr , "AFNI_idcode" ) ; if( rhs != NULL ) /* set dataset ID code from XML attribute */ MCW_strncpy( dset->idcode.str , rhs , MCW_IDSIZE ) ; rhs = NI_get_attribute( nngr , "NIfTI_nums" ) ; /* check if */ if( rhs != NULL ){ /* dataset dimensions */ char buf[128] ; /* were altered */ sprintf(buf,"%ld,%ld,%ld,%ld,%ld,%d" , /* 12 May 2005 */ nim->nx, nim->ny, nim->nz, nim->nt, nim->nu, nim->datatype ); if( strcmp(buf,rhs) != 0 ){ static int nnn=0 ; if(nnn==0){fprintf(stderr,"\n"); nnn=1;} fprintf(stderr, "** WARNING: NIfTI file %s dimensions altered since " "AFNI extension was added\n",pathname ) ; } } THD_dblkatr_from_niml( nngr , dset->dblk ); /* load attributes */ THD_datablock_apply_atr( dset ) ; /* apply to dataset struct */ } NI_free_element( ngr ) ; /* get rid of the root element */ } /* end of if found a group element at the root */ } /* end of if extension data array had an XML prolog close */ } /* end of if had a good extension data array */ } /* end of if had an AFNI extension */ } /* end of processing extensions */ /* return unpopulated dataset */ nifti_image_free(nim) ; RETURN(dset) ; }
static char * DELAY_main( PLUGIN_interface * plint ) { hilbert_data_V2 uda,*ud; MRI_IMAGE * tsim; MCW_idcode * idc ; /* input dataset idcode */ THD_3dim_dataset * old_dset , * new_dset ; /* input and output datasets */ char *tmpstr , * str , *nprfxstr; /* strings from user */ int ntime, nvec ,nprfx, i; float * vec , fs , T ; /* Allocate as much character space as Bob specifies in afni.h + a bit more */ tmpstr = (char *) calloc (PLUGIN_MAX_STRING_RANGE+10,sizeof(char)); nprfxstr = (char *) calloc (PLUGIN_MAX_STRING_RANGE+10,sizeof(char)); if (tmpstr == NULL || nprfxstr == NULL) return "********************\n" "Could not Allocate\n" "a teeni weeni bit of\n" "Memory ! \n" "********************\n"; ud = &uda; /* ud now points to an allocated space */ ud->errcode = 0; /*reset error flag */ /*--------------------------------------------------------------------*/ /*----- Check inputs from AFNI to see if they are reasonable-ish -----*/ /*--------- go to first input line ---------*/ PLUTO_next_option(plint) ; idc = PLUTO_get_idcode(plint) ; /* get dataset item */ old_dset = PLUTO_find_dset(idc) ; /* get ptr to dataset */ if( old_dset == NULL ) return "*************************\n" "Cannot find Input Dataset\n" "*************************" ; ud->dsetname = DSET_FILECODE (old_dset); ud->nsamp = DSET_NUM_TIMES (old_dset); ud->Navg = 1 ; /* Navg does not play a role for the p value, averaging increases sensitivity */ ud->Nort = PLUTO_get_number(plint) ; /* Should be two by default, for mean and linear trend */ ud->Nfit = 2 ; /* Always 2 for phase and amplitude for this plugin */ /*--------- go to 2nd input line, input time series ---------*/ PLUTO_next_option(plint) ; tsim = PLUTO_get_timeseries(plint); if (tsim == NULL) return "No Timeseries Input"; ud->ln = (int)tsim -> nx; /* number of points in each vector */ nvec = tsim -> ny; /* number of vectors */ ud->rvec = (float *) MRI_FLOAT_PTR(tsim); /* vec[i+j*nx] = ith point of jth vector */ /* for i=0 .. ntime-1 and j=0 .. nvec-1 */ if (is_vect_null (ud->rvec,ud->ln) == 1) /* check if ref vect is all zeroes */ { return "Reference vector is all zeros"; } ud->refname = tsim->name; ud->ignore = PLUTO_get_number(plint) ; /* get number item */ str = PLUTO_get_string(plint) ; ud->Dsamp = (int)PLUTO_string_index( str , NUM_YN_STRINGS , yn_strings ) ; /*--------- go to 3rd input line, sampling frequency, and stimulus period ---------*/ PLUTO_next_option(plint) ; ud->fs = PLUTO_get_number(plint) ; /* get number item */ ud->T = PLUTO_get_number(plint) ; /* get number item */ ud->co = PLUTO_get_number(plint) ; /* get number item */ str = PLUTO_get_string(plint) ; ud->biasrem = (int)PLUTO_string_index( str , NUM_YN_STRINGS , yn_strings ) ; /*--------- go to 4th input line, delay units and wrp option---------*/ PLUTO_next_option(plint) ; ud->Nseg = (int)PLUTO_get_number(plint) ; /* get number item */ ud->Pover = (int)PLUTO_get_number(plint) ; /* get number item */ str = PLUTO_get_string(plint) ; /* get string item (the method) */ ud->unt = (int)PLUTO_string_index( str , /* find it in list it is from */ NUM_METHOD_STRINGS , method_strings ) ; str = PLUTO_get_string(plint) ; ud->wrp = (int)PLUTO_string_index( str , NUM_YN_STRINGS , yn_strings ) ; /*--------- go to 5th input line Output prefix ---------*/ PLUTO_next_option(plint) ; ud->new_prefix = PLUTO_get_string(plint) ; /* get string item (the output prefix) */ /* check to see if the field is empty */ if (ud->new_prefix == NULL) nprfx = 0; else nprfx = 1; /* check if the size is larger than 0. I did not want to check for this unless it's allocated */ if (nprfx == 1 && (int)strlen (ud->new_prefix) == 0) nprfx = 0; if (nprfx == 0) /* now create the new name and make new_prefix point to it */ { sprintf (nprfxstr,"%s.DEL",DSET_PREFIX (old_dset)); ud->new_prefix = nprfxstr; /*printf ("New prefix is set to be : %s\n\a",ud->new_prefix);*/ } if( ! PLUTO_prefix_ok(ud->new_prefix) ) /* check if it is OK */ return "************************\n" "Output Prefix is illegal\n" "************************" ; str = PLUTO_get_string(plint) ; /* write delays to file ? */ ud->out = (int)PLUTO_string_index( str , NUM_YN_STRINGS , yn_strings ); ud->strout = PLUTO_get_string(plint) ; /* strout is for the outiflename, which will be used after the debugging section */ if (ud->strout == NULL) /* if no output name is given, use the new_prefix */ {ud->strout = ud->new_prefix;} else { if((int)strlen (ud->strout) == 0) ud->strout = ud->new_prefix; } str = PLUTO_get_string(plint) ; ud->outts = (int)PLUTO_string_index( str , NUM_YN_STRINGS , yn_strings ); /* ------------------Done with user parameters ---------------------------- */ ud->nxx = (int)old_dset->daxes->nxx; /* get data set dimensions */ ud->nyy = (int)old_dset->daxes->nyy; ud->nzz = (int)old_dset->daxes->nzz; /* No need for users to set these options ...*/ ud->dtrnd = 0; if (ud->ln != (ud->nsamp - ud->ignore)) { ud->errcode = ERROR_BADLENGTH; return "***************************\n" "Bad time series length \n" "Check reference time series\n" " or the ignore parameter \n" "***************************\n"; } if ((ud->unt < 0) || (ud->unt > 2)) /* unt error Check */ { ud->errcode = ERROR_WRONGUNIT; return "***********************\n" " internal error: (ziad)\n" "unt values out of bound\n" "***********************\n"; /*unt must be between 0 and 2 */ } if ((ud->wrp < 0) || (ud->wrp > 1)) /* wrp error Check */ { ud->errcode = ERROR_WARPVALUES; return "***********************\n" " internal error: (ziad)\n" "wrp values out of bound\n" "***********************\n"; /* wrp must be between 0 and 1*/ } if (ud->fs < 0.0) { /* fs error Check */ ud->errcode = ERROR_FSVALUES; return "***********************\n" " internal error: (ziad)\n" "fs value is negative !\n" "***********************\n"; /* fs must be >= 0*/ } if (ud->T < 0.0) { /* T error Check */ ud->errcode = ERROR_TVALUES; return "***********************\n" " internal error: (ziad)\n" "T value is negative !\n" "***********************\n"; /*T must be >= 0 */ } if ((ud->T == 0.0) && (ud->unt > 0)) /* unt error Check */ { ud->errcode = ERROR_TaUNITVALUES; return "***********************\n" " internal error: (ziad)\n" "T and unt val. mismatch\n" "***********************\n"; /*T must be specified, and > 0 in order to use polar units*/ } if ((ud->wrp == 1) && (ud->T == 0.0)) /* wrp error Check */ { ud->errcode = ERROR_TaWRAPVALUES; return "***********************\n" " internal error: (ziad)\n" "wrp and T val. mismatch\n" "***********************\n"; /*T must be specified, and > 0 in order to use polar warp*/ } if ((ud->out == NOPE) && (ud->outts == YUP)) { ud->errcode = ERROR_OUTCONFLICT; return"***********************\n" "error: \n" "Write flag must be on\n" "to use Write ts\n" "***********************\n"; } /* Open the logfile, regardless of the ascii output files */ sprintf ( tmpstr , "%s.log" , ud->strout); ud->outlogfile = fopen (tmpstr,"w"); if (ud->out == YUP) /* open outfile */ { ud->outwrite = fopen (ud->strout,"w"); if (ud->outts == YUP) { sprintf ( tmpstr , "%s.ts" , ud->strout); ud->outwritets = fopen (tmpstr,"w"); } if ((ud->outwrite == NULL) || (ud->outlogfile == NULL) ||\ (ud->outwritets == NULL && ud->outts == YUP) ) { ud->errcode = ERROR_FILEOPEN; return "***********************\n" "Could Not Write Outfile\n" "***********************\n"; } } /* Write out user variables to Logfile */ write_ud (ud); /* writes user data to a file */ /*show_ud (ud,0); */ /* For some debugging */ /*------------- ready to compute new dataset -----------*/ new_dset = MAKER_4D_to_typed_fbuc ( old_dset , /* input dataset */ ud->new_prefix , /* output prefix */ -1, /* negative value indicating data type is like original brick */ ud->ignore , /* ignore count */ 1 , /* detrend = ON Let BOB do it*/ NBUCKETS, /*Number of values at each voxel*/ DELAY_tsfuncV2 , /* timeseries processor (bucket version)*/ (void *)ud, /* data for tsfunc */ NULL, 0 ) ; /* Setup the label, keywords and types of subbricks */ i = 0; while (i < NBUCKETS) { switch (i) { case DELINDX: /* delay value in results vector */ EDIT_BRICK_LABEL (new_dset,i,"Delay"); EDIT_BRICK_ADDKEY (new_dset,i,"D"); ++i; break; case COVINDX: /* covariance value in results vector */ EDIT_BRICK_LABEL (new_dset,i,"Covariance"); EDIT_BRICK_ADDKEY (new_dset,i,"I"); ++i; break; case COFINDX: /* cross correlation coefficient value in results vector */ EDIT_BRICK_LABEL (new_dset,i,"Corr. Coef."); EDIT_BRICK_ADDKEY (new_dset,i,"r"); /* Here you must modify either ud->Nfit or ud->Nort or most likely ud->nsamp based on ud->Navg */ EDIT_BRICK_TO_FICO (new_dset,i,ud->nsamp - ud->ignore,ud->Nfit,ud->Nort); ++i; break; case VARINDX: /* FMRI time course variance value in results vector */ EDIT_BRICK_LABEL (new_dset,i,"Variance"); EDIT_BRICK_ADDKEY (new_dset,i,"S2"); ++i; break; default : return "*********************\n" "Internal Error (ziad)\n" " Bad i value \n" "*********************\n"; break; } } if (!AFNI_noenv("AFNI_AUTOMATIC_FDR")) { THD_create_all_fdrcurves( new_dset ); } PLUTO_add_dset( plint , new_dset , DSET_ACTION_MAKE_CURRENT ) ; if (ud->out == YUP) /* close outfile and outlogfile*/ { fclose (ud->outlogfile); fclose (ud->outwrite); if (ud->outts == YUP) fclose (ud->outwritets); } else { if (ud->outlogfile != NULL) fclose (ud->outlogfile); /* close outlogfile */ } free (tmpstr); free (nprfxstr); return NULL ; /* null string returned means all was OK */ }