/* * for each input dataset name * open (check dims, etc.) * dilate (zeropad, make binary, dilate, unpad, apply) * fill list of bytemask datasets * * also, count total volumes */ int process_input_dsets(param_t * params) { THD_3dim_dataset * dset, * dfirst=NULL; int iset, nxyz; ENTRY("process_input_dsets"); if( !params ) ERROR_exit("NULL inputs to PID"); if( params->ndsets <= 0 ) { ERROR_message("process_input_dsets: no input datasets"); RETURN(1); } /* allocate space for dsets array */ params->dsets = (THD_3dim_dataset **)malloc(params->ndsets* sizeof(THD_3dim_dataset*)); if( !params->dsets ) ERROR_exit("failed to allocate dset pointers"); if( params->verb ) INFO_message("processing %d input datasets...", params->ndsets); /* warn user of dilations */ if(params->verb && params->ndsets) { int pad = needed_padding(¶ms->IND); INFO_message("padding all datasets by %d (for dilations)", pad); } /* process the datasets */ nxyz = 0; for( iset=0; iset < params->ndsets; iset++ ) { /* open and verify dataset */ dset = THD_open_dataset(params->inputs[iset]); if( !dset ) ERROR_exit("failed to open mask dataset '%s'", params->inputs[iset]); DSET_load(dset); CHECK_LOAD_ERROR(dset); if( params->verb>1 ) INFO_message("loaded dset %s, with %d volumes", DSET_PREFIX(dset), DSET_NVALS(dset)); if( nxyz == 0 ) { /* make an empty copy of the first dataset */ nxyz = DSET_NVOX(dset); dfirst = EDIT_empty_copy(dset); } /* check for consistency in voxels and grid */ if( DSET_NVOX(dset) != nxyz ) ERROR_exit("nvoxel mis-match"); if( ! EQUIV_GRIDS(dset, dfirst) ) WARNING_message("grid from dset %s does not match that of dset %s", DSET_PREFIX(dset), DSET_PREFIX(dfirst)); /* apply dilations to all volumes, returning bytemask datasets */ params->dsets[iset] = apply_dilations(dset, ¶ms->IND,1,params->verb); if( ! params->dsets[iset] ) RETURN(1); } DSET_delete(dfirst); /* and nuke */ RETURN(0); }
int main (int argc,char *argv[]) {/* Main */ static char FuncName[]={"3dBRAIN_VOYAGERtoAFNI"}; SUMA_GENERIC_PROG_OPTIONS_STRUCT *Opt; SUMA_GENERIC_ARGV_PARSE *ps=NULL; SUMA_OPEN_DX_STRUCT **dx = NULL; THD_3dim_dataset *dset=NULL; char *sto3d = NULL; SUMA_Boolean LocalHead = NOPE; SUMA_STANDALONE_INIT; SUMA_mainENTRY; /* Allocate space for DO structure */ SUMAg_DOv = SUMA_Alloc_DisplayObject_Struct (SUMA_MAX_DISPLAYABLE_OBJECTS); ps = SUMA_Parse_IO_Args(argc, argv, ""); if (argc < 2) { usage_3dBRAIN_VOYAGERtoAFNI(ps); exit (1); } Opt = SUMA_3dBRAIN_VOYAGERtoAFNI_ParseInput (argv, argc, ps); if (Opt->debug > 2) LocalHead = YUP; dset = EDIT_empty_copy( NULL ) ; tross_Make_History( "3dBRAIN_VOYAGERtoAFNI" , argc,argv , dset) ; if (!(sto3d = SUMA_BrainVoyager_Read_vmr(Opt->in_name, dset, 1, Opt->b2, Opt->b1, Opt->Icold, Opt->out_prefix))) { if (Opt->debug) SUMA_SL_Err("Failed in SUMA_BrainVoyager_Read_vmr"); exit(1); } SUMA_LHv("Old command would be %s\n", sto3d); if (dset) { SUMA_LH("Writing Dset"); DSET_write(dset) ; if (LocalHead) { fprintf(SUMA_STDERR,"%s: Can use the following command to create dset with to3d:\n%s\n", FuncName,sto3d); } } else { /* the olde way */ if (system(sto3d)) { fprintf(SUMA_STDERR, "Error %s: Failed while executing shell command:\n%s\n" "Check to3d's error messages, and disk writing permissions.\n", FuncName, sto3d); } } if (sto3d) SUMA_free(sto3d); sto3d = NULL; if (dset) { DSET_delete(dset); dset = NULL; } if (Opt) Opt = SUMA_Free_Generic_Prog_Options_Struct(Opt); if (!SUMA_Free_CommonFields(SUMAg_CF)) SUMA_error_message(FuncName,"SUMAg_CF Cleanup Failed!",1); exit(0); }
THD_3dim_dataset * GRINCOR_extract_dataset( MRI_shindss *shd, int ids, char *pref ) { MRI_vectim *mv ; THD_3dim_dataset *dset ; char prefix[THD_MAX_NAME] ; int iv , nvals=shd->nvals[ids] ; static int nds=0 ; ENTRY("GRINCOR_extract_dataset") ; STATUS("extract vectim") ; mv = GRINCOR_extract_vectim( shd , ids ) ; STATUS("create empty copy of template") ; dset = EDIT_empty_copy( shd->tdset ) ; STATUS("edit prefix") ; prefix[0] = '\0' ; if( pref != NULL && *pref != '\0' ){ strcpy(prefix,pref) ; strcat(prefix,"_") ; } if( shd->dslab != NULL && shd->dslab[ids] != NULL ){ strcat(prefix,shd->dslab[ids]) ; } else { nds++ ; sprintf(prefix+strlen(prefix),"%03d",nds) ; } STATUS("edit empty copy header") ; EDIT_dset_items( dset , ADN_prefix , prefix , ADN_nvals , nvals , ADN_ntt , nvals , ADN_ttdel , 1.0 , ADN_tunits , UNITS_SEC_TYPE , ADN_brick_fac , NULL , ADN_type , HEAD_FUNC_TYPE , ADN_func_type , FUNC_FIM_TYPE , ADN_none ) ; STATUS("create empty float bricks") ; for( iv=0 ; iv < nvals ; iv++ ) EDIT_substitute_brick( dset , iv , MRI_float , NULL ) ; STATUS("copy index vector") ; if( shd->ivec != NULL ){ memcpy( mv->ivec , shd->ivec , sizeof(int)*shd->nvec ) ; } else { for( iv=0 ; iv < shd->nvec ; iv++ ) mv->ivec[iv] = iv ; } STATUS("convert vectim to dset") ; THD_vectim_to_dset( mv , dset ) ; STATUS("destroy vectim") ; VECTIM_destroy( mv ) ; RETURN(dset) ; }
void check_one_output_file ( THD_3dim_dataset * dset_time, /* input 3d+time data set */ char * filename /* name of output file */ ) { char message[THD_MAX_NAME]; /* error message */ THD_3dim_dataset * new_dset=NULL; /* output afni data set pointer */ int ierror; /* number of errors in editing data */ ENTRY("check_one_output_file") ; /*----- make an empty copy of input dataset -----*/ new_dset = EDIT_empty_copy( dset_time ) ; ierror = EDIT_dset_items( new_dset , ADN_prefix , filename , ADN_label1 , filename , ADN_self_name , filename , ADN_type , ISHEAD(dset_time) ? HEAD_FUNC_TYPE : GEN_FUNC_TYPE , ADN_none ) ; if( ierror > 0 ) { sprintf (message, "*** %d errors in attempting to create output dataset!\n", ierror); FDR_error (message); } if( THD_is_file(new_dset->dblk->diskptr->header_name) ) { sprintf (message, "Output dataset file %s already exists " " -- cannot continue! ", new_dset->dblk->diskptr->header_name); FDR_error (message); } /*----- deallocate memory -----*/ THD_delete_3dim_dataset( new_dset , False ) ; new_dset = NULL ; EXRETURN ; }
int main( int argc , char * argv[] ) { int kk , nvox , ii ; THD_3dim_dataset * oset ; float * far ; /*-- read command line arguments --*/ if( argc < 2 || strncmp(argv[1],"-help",5) == 0 ) UC_syntax(NULL) ; (void) my_getenv("junk") ; UC_read_opts( argc , argv ) ; set_unusuality_tail( UC_ptail ) ; oset = EDIT_empty_copy( UC_dset ) ; EDIT_dset_items( oset , ADN_prefix , UC_prefix , ADN_ntt , 0 , ADN_nvals , 1 , ADN_datum_all , MRI_float , ADN_malloc_type , DATABLOCK_MEM_MALLOC , ADN_none ) ; nvox = DSET_NVOX(oset) ; far = (float *) malloc( sizeof(float) * nvox ) ; for( kk=0 ; kk < nvox ; kk++ ) far[kk] = 0.0 ; EDIT_substitute_brick( oset , 0 , MRI_float , far ) ; if( !UC_be_quiet ){ printf("--- computing u") ; fflush(stdout) ; } for( kk=0 ; kk < UC_nvec ; kk++ ){ ii = (UC_iv == NULL) ? kk : UC_iv[kk] ; far[ii] = UC_unusuality( UC_vdim, UC_vec[kk] , UC_nvec, UC_vec ) ; if( !UC_be_quiet && kk%1000==999 ){ printf(".");fflush(stdout); } } if( !UC_be_quiet ) printf("\n--- writing output\n") ; DSET_write(oset) ; exit(0) ; }
THD_3dim_dataset * GRINCOR_extract_dataset( MRI_shindss *shd, int ids, char *pref ) { MRI_vectim *mv ; THD_3dim_dataset *dset ; char prefix[THD_MAX_NAME] ; int iv , nvals=shd->nvals[ids] ; mv = GRINCOR_extract_vectim( shd , ids ) ; dset = EDIT_empty_copy( shd->tdset ) ; prefix[0] = '\0' ; if( pref != NULL && *pref != '\0' ){ strcpy(prefix,pref) ; strcat(prefix,"_") ; } strcat(prefix,shd->dslab[ids]) ; EDIT_dset_items( dset , ADN_prefix , prefix , ADN_nvals , nvals , ADN_ntt , nvals , ADN_ttdel , 1.0 , ADN_tunits , UNITS_SEC_TYPE , ADN_brick_fac , NULL , ADN_type , HEAD_FUNC_TYPE , ADN_func_type , FUNC_FIM_TYPE , ADN_none ) ; for( iv=0 ; iv < nvals ; iv++ ) EDIT_substitute_brick( dset , iv , MRI_float , NULL ) ; if( shd->ivec != NULL ){ memcpy( mv->ivec , shd->ivec , sizeof(int)*shd->nvec ) ; } else { for( iv=0 ; iv < shd->nvec ; iv++ ) mv->ivec[iv] = iv ; } THD_vectim_to_dset( mv , dset ) ; VECTIM_destroy( mv ) ; return dset ; }
THD_3dim_dataset * THD_despike9_dataset( THD_3dim_dataset *inset , byte *mask ) { THD_3dim_dataset *outset ; MRI_vectim *mrv ; int ii ; ENTRY("THD_despike9_dataset") ; if( !ISVALID_DSET(inset) || DSET_NVALS(inset) < 9 ) RETURN(NULL) ; mrv = THD_dset_to_vectim(inset,mask,0) ; DSET_unload(inset) ; if( mrv == NULL ) RETURN(NULL) ; (void)THD_vectim_despike9(mrv) ; outset = EDIT_empty_copy(inset) ; for( ii=0 ; ii < DSET_NVALS(outset) ; ii++ ) EDIT_substitute_brick(outset,ii,MRI_float,NULL) ; THD_vectim_to_dset(mrv,outset) ; VECTIM_destroy(mrv) ; RETURN(outset) ; }
THD_3dim_dataset * THD_detrend_dataset( THD_3dim_dataset *dset , int nref , float **ref , int meth , int scl , byte *mask , MRI_IMARR **imar ) { MRI_IMARR *qmar ; int ii,jj,kk , nvals,nvox , iv ; float *var ; THD_3dim_dataset *newset ; ENTRY("THD_detrend_dataset") ; if( !ISVALID_DSET(dset) ) RETURN(NULL) ; nvals = DSET_NVALS(dset) ; nvox = DSET_NVOX(dset) ; qmar = THD_time_fit_dataset( dset , nref,ref , meth , mask ) ; if( qmar == NULL ) RETURN(NULL) ; newset = EDIT_empty_copy(dset) ; for( iv=0 ; iv < nvals ; iv++ ){ EDIT_substitute_brick( newset , iv , MRI_float , NULL ) ; EDIT_BRICK_FACTOR( newset , iv , 0.0f ) ; /* 04 Jun 2007 */ } var = (float *)malloc(sizeof(float)*nvals) ; for( ii=0 ; ii < nvox ; ii++ ){ if( mask == NULL || mask[ii] ) THD_extract_detrended_array( dset , nref,ref , qmar , ii,scl , var ) ; else memset(var,0,sizeof(float)*nvals) ; THD_insert_series( ii , newset , nvals , MRI_float , var , 0 ) ; } free(var) ; if( imar != NULL ) *imar = qmar ; else DESTROY_IMARR(qmar) ; RETURN(newset) ; }
THD_3dim_dataset * THD_open_tcat( char *dlist ) { THD_3dim_dataset *dset_out , **dset_in ; int ndset_in , dd , nerr , new_nvals, sb=0 ; NI_str_array *sar ; double angle=0.0; char *dp, *dlocal = dlist; /* local dlist, in case it is altered */ ENTRY("THD_open_tcat") ; if( dlocal == NULL || *dlocal == '\0' ) RETURN(NULL) ; /* allow file list to be read from a file 23 Jul 2012 [rickr] */ if( ! strncmp(dlocal, "filelist:", 9) ) { dlocal = AFNI_suck_file(dlocal+9) ; if ( ! dlocal ) { ERROR_message("THD_open_tcat: failed to open '%s' as filelist", dlocal+9); RETURN(NULL) ; } /* make it look more like expected */ for( dd=0, dp=dlocal; dd < strlen(dlocal); dd++, dp++ ) if( *dp == '\n' || *dp == '\r' ) *dp = ' '; } if( strchr(dlocal,' ') == NULL ){ dset_out = THD_open_dataset(dlocal) ; RETURN(dset_out) ; } sar = NI_decode_string_list( dlocal , "~" ) ; if( sar == NULL ) RETURN(NULL) ; ndset_in = sar->num ; dset_in = (THD_3dim_dataset **)malloc(sizeof(THD_3dim_dataset *)*sar->num) ; for( nerr=dd=0 ; dd < ndset_in ; dd++ ){ dset_in[dd] = THD_open_dataset( sar->str[dd] ) ; if( dset_in[dd] == NULL ){ fprintf(stderr,"** THD_open_tcat: can't open dataset %s\n",sar->str[dd]) ; nerr++ ; } } if( nerr > 0 ){ for( dd=0 ; dd < ndset_in ; dd++ ) if( dset_in[dd] != NULL ) DSET_delete(dset_in[dd]) ; free((void *)dset_in) ; NI_delete_str_array(sar) ; RETURN(NULL) ; } if( ndset_in == 1 ){ dset_out = dset_in[0] ; free((void *)dset_in) ; NI_delete_str_array(sar) ; RETURN(dset_out) ; } (void)THD_check_for_duplicates( sar->num , sar->str , 1 ) ; /* 31 May 2007 */ for( nerr=0,dd=1 ; dd < ndset_in ; dd++ ){ if( DSET_NX(dset_in[0]) != DSET_NX(dset_in[dd]) || DSET_NY(dset_in[0]) != DSET_NY(dset_in[dd]) || DSET_NZ(dset_in[0]) != DSET_NZ(dset_in[dd]) ){ ERROR_message( "THD_open_tcat: %s [%dx%dx%d] doesn't match %s [%dx%dx%d]\n", sar->str[0] ,DSET_NX(dset_in[0]) , DSET_NY(dset_in[0]) ,DSET_NZ(dset_in[0]) , sar->str[dd],DSET_NX(dset_in[dd]), DSET_NY(dset_in[dd]),DSET_NZ(dset_in[dd]) ) ; nerr++ ; } else { if( !EQUIV_DATAXES(dset_in[dd]->daxes,dset_in[0]->daxes) ){ WARNING_message( "THD_open_tcat: %s grid mismatch with %s\n", sar->str[0] , sar->str[dd] ) ; /* don't increment nerr! */ } angle = dset_obliquity_angle_diff(dset_in[dd], dset_in[0], -1.0); if (angle > 0.0) { WARNING_message( "dataset %s has an obliquity difference of %f degress with %s\n", dset_in[dd] , angle, dset_in[0] ); } } } if( nerr > 0 ){ for( dd=0 ; dd < ndset_in ; dd++ ) if( dset_in[dd] != NULL ) DSET_delete(dset_in[dd]) ; free((void *)dset_in) ; NI_delete_str_array(sar) ; RETURN(NULL) ; } /*-- Check for type problems ZSS: Aug 27 2012 --*/ for (nerr=0,dd=0; dd < ndset_in ; dd++) { for (sb=0; sb < DSET_NVALS(dset_in[dd]); ++sb) { if ( DSET_BRICK_TYPE(dset_in[0],0) != DSET_BRICK_TYPE(dset_in[dd],sb) ) { ++nerr; } } } if (nerr > 0) { /* don't die, just complain */ WARNING_message( "Command-line catenated dataset has %d sub-bricks that differ \n" " in data type from the first sub-brick of the first set.\n" " Mme Irma sees potential for grief if you go down that path. \n" " Use 3dinfo -datum on each input to understand why this is happening.\n" " You can use 3dcalc's -datum option to rewrite the dataset with \n" " all sub-bricks set to the same type then start over.\n\n", nerr); nerr=0; } /*-- OK, start making new dataset --*/ new_nvals = 0 ; for( dd=0 ; dd < ndset_in ; dd++ ) new_nvals += DSET_NVALS(dset_in[dd]) ; for( dd=0 ; dd < ndset_in ; dd++ ) if( DSET_TIMESTEP(dset_in[dd]) > 0.0 ) break ; /* 1st 3D+time */ if( dd == ndset_in ) dd = 0 ; dset_out = EDIT_empty_copy( dset_in[dd] ) ; /* since this is basically an input dataset, set the storage_mode * to match 27 Jul 2010 [rickr] */ if( DSET_ONDISK(dset_out) && IS_VALID_NON_AFNI_DSET(dset_in[dd]) ) THD_set_storage_mode(dset_out, dset_in[dd]->dblk->diskptr->storage_mode); EDIT_dset_items( dset_out , ADN_prefix , "tcat" , ADN_func_type , ISANAT(dset_in[dd]) ? ANAT_EPI_TYPE : FUNC_FIM_TYPE , ADN_ntt , new_nvals , ADN_nvals , new_nvals , ADN_none ) ; DSET_mallocize( dset_out ) ; /* check if we have a valid time axis; if not, make one up */ if( DSET_TIMESTEP(dset_out) <= 0.0f ){ float TR=1.0f , torg=0.0f , tdur=0.0f ; int tunits=UNITS_SEC_TYPE ; EDIT_dset_items( dset_out , ADN_tunits , tunits , ADN_ttdel , TR , ADN_ttorg , torg , ADN_ttdur , tdur , ADN_none ) ; } dset_out->tcat_list = strdup( dlocal ) ; dset_out->tcat_num = ndset_in ; dset_out->tcat_len = (int *)malloc(sizeof(int)*ndset_in) ; for( dd=0 ; dd < ndset_in ; dd++ ){ dset_out->tcat_len[dd] = DSET_NVALS(dset_in[dd]) ; DSET_delete(dset_in[dd]) ; } free((void *)dset_in) ; NI_delete_str_array(sar) ; #if 0 fprintf(stderr,"THD_open_tcat('%s'):",dset_out->tcat_list); for(dd=0;dd<ndset_in;dd++)fprintf(stderr," %d",dset_out->tcat_len[dd]); fprintf(stderr,"\n"); #endif RETURN(dset_out) ; }
char * POWER_main( PLUGIN_interface * plint ) { MCW_idcode * idc ; /* input dataset idcode */ THD_3dim_dataset * old_dset , * new_dsetD3 , * new_dsetA3, * new_dsetavgD3 ; /* input and output datasets */ char * new_prefix , * str , * namestr, * filename; /* strings from user */ int new_datum , ignore , nfft , ninp , /* control parameters */ old_datum , nuse , ntaper , ktbot, image_type, scale,OutputFlag ,numT,flip; float avFac; byte ** bptr = NULL ; /* one of these will be the array of */ short ** sptr = NULL ; /* pointers to input dataset sub-bricks */ float ** fptr = NULL ; /* (depending on input datum type) */ float * this = NULL ; /* array loaded from input dataset */ float ** foutD3 = NULL ; /* will be array of output floats */ float ** foutA3 = NULL ; /* will be array of output floats */ float ** foutavgD3 = NULL ; /* will be array of output floats */ float * tarD3 = NULL ; /* will be array of taper coefficients */ float * tarA3 = NULL ; /* will be array of taper coefficients */ float * taravgD3 = NULL ; /* will be array of taper coefficients */ /*float * flip;*/ float * numAv; float dfreq , pfact , phi , xr,xi , yr,yi ; float x0,x1 , y0,y1 , d0fac,d1fac ; int nfreq , nvox , perc , new_units ; int istr , ii,iip , ibot,itop , kk , icx ; /* temp variables */ new_prefix = (char *)calloc(100, sizeof(char)); filename = (char *)calloc(100, sizeof(char)); str = (char *)calloc(100, sizeof(char)); namestr = (char *)calloc(100, sizeof(char)); OutputFlag=0; /*--------------------------------------------------------------------*/ /*----- 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 */ namestr = DSET_PREFIX(old_dset) ; if( old_dset == NULL ) return "*************************\n" "Cannot find Input Dataset\n" "*************************" ; /*--------- go to second input line ---------*/ PLUTO_next_option(plint) ; filename = PLUTO_get_string(plint) ; /* get string item (the output prefix) */ sprintf(new_prefix,"%s%s",filename,"_D3"); if (strcmp(new_prefix,"_D3")==0){ OutputFlag=1; sprintf(new_prefix,"%s%s",namestr,"_D3"); } if (! PLUTO_prefix_ok(new_prefix) ){ PLUTO_popup_transient(plint,new_prefix); return "*************************\n" "Output filename already exists\n" "*************************" ; } PLUTO_popup_transient(plint,"Output file tags set automatically"); str = PLUTO_get_string(plint) ; /* get string item (the datum type) */ istr = PLUTO_string_index( str , /* find it in the list it came from */ NUM_TYPE_STRINGS , type_strings ) ; switch( istr ){ default: case 0: new_datum = MRI_float ; break ; break ; case 1: new_datum = MRI_byte ; break ; /* assign type of user's choice */ case 2: new_datum = MRI_short ; break ; case 3: new_datum = DSET_BRICK_TYPE( old_dset , 0 ) ; /* use old dataset type */ } /*--------- go to next input lines ---------*/ PLUTO_next_option(plint) ; /* skip to next line */ ignore = PLUTO_get_number(plint) ; /* get number item (ignore) */ ninp = DSET_NUM_TIMES(old_dset) ; /* number of values in input */ nuse = ninp; /* number of values to actually use */ nfreq=nuse; nfft=nuse; str = PLUTO_get_string(plint) ; /* get string item (the datum type) */ istr = PLUTO_string_index( str , /* find it in the list it came from */ NUM_TYPE_STRINGSX , type_stringsx ) ; switch( istr ){ default: case 0: image_type = 0; break; } PLUTO_next_option(plint) ; /* skip to next line */ scale = PLUTO_get_number(plint) ; /* get number item (scale) */ /*------------------------------------------------------*/ /*---------- At this point, the inputs are OK ----------*/ PLUTO_popup_meter( plint ) ; /* popup a progress meter */ /*--------- set up pointers to each sub-brick in the input dataset ---------*/ DSET_load( old_dset ) ; /* must be in memory before we get pointers to it */ old_datum = DSET_BRICK_TYPE( old_dset , 0 ) ; /* get old dataset datum type */ switch( old_datum ){ /* pointer type depends on input datum type */ default: return "******************************\n" "Illegal datum in Input Dataset\n" "******************************" ; /** create array of pointers into old dataset sub-bricks **/ /** Note that we skip the first 'ignore' sub-bricks here **/ /*--------- input is bytes ----------*/ /* voxel #i at time #k is bptr[k][i] */ /* for i=0..nvox-1 and k=0..nuse-1. */ case MRI_byte: bptr = (byte **) malloc( sizeof(byte *) * nuse ) ; if( bptr == NULL ) return "Malloc\nFailure!\n [bptr]" ; for( kk=0 ; kk < nuse ; kk++ ) bptr[kk] = (byte *) DSET_ARRAY(old_dset,kk) ; break ; /*--------- input is shorts ---------*/ /* voxel #i at time #k is sptr[k][i] */ /* for i=0..nvox-1 and k=0..nuse-1. */ case MRI_short: sptr = (short **) malloc( sizeof(short *) * nuse ) ; if( sptr == NULL ) return "Malloc\nFailure!\n [sptr]" ; for( kk=0 ; kk < nuse ; kk++ ) sptr[kk] = (short *) DSET_ARRAY(old_dset,kk) ; break ; /*--------- input is floats ---------*/ /* voxel #i at time #k is fptr[k][i] */ /* for i=0..nvox-1 and k=0..nuse-1. */ case MRI_float: fptr = (float **) malloc( sizeof(float *) * nuse ) ; if( fptr == NULL ) return "Malloc\nFailure!\n [fptr]" ; for( kk=0 ; kk < nuse ; kk++ ) fptr[kk] = (float *) DSET_ARRAY(old_dset,kk) ; break ; } /* end of switch on input type */ /*---- allocate space for 2 voxel timeseries and 1 FFT ----*/ this = (float *) malloc( sizeof(float) * nuse ) ; /* input */ tarD3 = (float *) malloc( sizeof(float) * MAX(nuse,nfreq) ) ; tarA3 = (float *) malloc( sizeof(float) * MAX(nuse,nfreq) ) ; taravgD3 = (float *) malloc( sizeof(float) * MAX(nuse,nfreq) ) ; /*flip = (float *)malloc( sizeof(float) * 1);*/ numAv = (float *)malloc( sizeof(float) * 1); numT=nuse-ignore; if (OutputFlag==1) sprintf(new_prefix,"%s%s",namestr,"_D3"); else sprintf(new_prefix,"%s%s",filename,"_D3"); new_dsetD3 = EDIT_empty_copy( old_dset ); { char * his = PLUTO_commandstring(plint) ; tross_Copy_History( old_dset , new_dsetD3 ) ; tross_Append_History( new_dsetD3 , his ) ; free(his) ; } /*-- edit some of its internal parameters --*/ ii = EDIT_dset_items( new_dsetD3 , ADN_prefix , new_prefix , /* filename prefix */ ADN_malloc_type , DATABLOCK_MEM_MALLOC , /* store in memory */ ADN_datum_all , new_datum , /* atomic datum */ ADN_nvals , numT , ADN_ntt ,numT, ADN_none ) ; if (OutputFlag==1) sprintf(new_prefix,"%s%s",namestr,"_A3"); else sprintf(new_prefix,"%s%s",filename,"_A3"); numT=nuse-ignore; new_dsetA3 = EDIT_empty_copy( old_dset ); { char * his = PLUTO_commandstring(plint) ; tross_Copy_History( old_dset , new_dsetA3 ) ; tross_Append_History( new_dsetA3 , his ) ; free(his) ; } /*-- edit some of its internal parameters --*/ ii = EDIT_dset_items( new_dsetA3 , ADN_prefix , new_prefix , /* filename prefix */ ADN_malloc_type , DATABLOCK_MEM_MALLOC , /* store in memory */ ADN_datum_all , new_datum , /* atomic datum */ ADN_nvals , numT, ADN_ntt ,numT, ADN_none ) ; if (OutputFlag==1) sprintf(new_prefix,"%s%s",namestr,"_avgD3"); else sprintf(new_prefix,"%s%s",filename,"_avgD3"); new_dsetavgD3 = EDIT_empty_copy( old_dset ); { char * his = PLUTO_commandstring(plint) ; tross_Copy_History( old_dset , new_dsetavgD3 ) ; tross_Append_History( new_dsetavgD3 , his ) ; free(his) ; } /*-- edit some of its internal parameters --*/ ii = EDIT_dset_items( new_dsetavgD3 , ADN_prefix , new_prefix , /* filename prefix */ ADN_malloc_type , DATABLOCK_MEM_MALLOC , /* store in memory */ ADN_datum_all , new_datum , /* atomic datum */ ADN_nvals , 1, ADN_ntt ,1, ADN_none ) ; /*---------------------- make a new dataset ----------------------*/ /*-------------------making a new dataset------------------------------------*/ /*------ make floating point output sub-bricks (only at the end will scale to byte or shorts) Output #ii at freq #kk will go into fout[kk][ii], for kk=0..nfreq-1, and for ii=0..nvox-1. ------*/ nvox = old_dset->daxes->nxx * old_dset->daxes->nyy * old_dset->daxes->nzz ; foutD3 = (float **) malloc( sizeof(float *) * nuse ) ; /* ptrs to sub-bricks */ foutA3 = (float **) malloc( sizeof(float *) * nuse ) ; /* ptrs to sub-bricks */ foutavgD3 = (float **) malloc( sizeof(float *) * 1 ) ; /* ptrs to sub-bricks */ if( foutD3 == NULL | foutA3 == NULL | foutavgD3 == NULL){ THD_delete_3dim_dataset( new_dsetD3 , False ) ; THD_delete_3dim_dataset( new_dsetA3 , False ) ; THD_delete_3dim_dataset( new_dsetavgD3 , False ) ; FREE_WORKSPACE ; return "Malloc\nFailure!\n [fout]" ; } for( kk=0 ; kk < nfreq ; kk++ ){ foutD3[kk] = (float *) malloc( sizeof(float) * nvox ) ; /* sub-brick # kk */ foutA3[kk] = (float *) malloc( sizeof(float) * nvox ) ; /* sub-brick # kk */ foutavgD3[0] = (float *) malloc( sizeof(float) * nvox ) ; /* sub-brick # kk */ if( foutD3[kk] == NULL ) break ; if( foutA3[kk] == NULL ) break ; if( foutavgD3[0] == NULL ) break ; } if( kk < nfreq ){ for( ; kk >= 0 ; kk-- ){ FREEUP(foutD3[kk]) ; FREEUP(foutA3[kk]) ; FREEUP(foutavgD3[0]) ; }/* free all we did get */ THD_delete_3dim_dataset( new_dsetD3 , False ) ; THD_delete_3dim_dataset( new_dsetA3 , False ) ; THD_delete_3dim_dataset( new_dsetavgD3 , False ) ; FREE_WORKSPACE ; return "Malloc\nFailure!\n [arrays]" ; } { char buf[128] ; ii = (nfreq * nvox * sizeof(float)) / (1024*1024) ; sprintf( buf , " \n" "*** 3D+time ASL a3/d3:\n" "*** Using %d MBytes of workspace,\n " "*** with # time points = %d\n" , ii,numT ) ; PLUTO_popup_transient( plint , buf ) ; } /*----------------------------------------------------*/ /*----- Setup has ended. Now do some real work. -----*/ /***** loop over voxels *****/ /* *(flip)=scale; */ *(numAv)= nuse-ignore; for( ii=0 ; ii < nvox ; ii ++ ){ /* time series */ switch( old_datum ){ case MRI_byte: for( kk=0 ; kk < nuse ; kk++ ){ this[kk] = bptr[kk][ii] ; } break ; case MRI_short: for( kk=0 ; kk < nuse ; kk++ ){ this[kk] = sptr[kk][ii] ; } break ; case MRI_float: for( kk=0 ; kk < nuse ; kk++ ){ this[kk] = fptr[kk][ii] ; } break ; } flip=scale*pow(-1,ignore+1); for( kk=0 ; kk < nuse-ignore ; kk++ ){ if (kk==nuse-1-ignore){ *(*(foutD3+kk)+ii)= flip*( *(this+kk+ignore-1)-*(this+kk+ignore) ); *(*(foutA3+kk)+ii)= 2*(*(this+kk+ignore-1)+*(this+kk+ignore)); } else if (kk==0){ /*D3 tag - control*/ *(*(foutD3+kk)+ii)= flip*( *(this+kk+ignore)-*(this+kk+ignore+1) ); *(*(foutA3+kk)+ii)= 2*(*(this+kk+ignore)+*(this+kk+ignore+1)); } else{ *(*(foutD3+kk)+ii)= flip*( 1*(*(this+kk+ignore-1))+-2*(*(this+kk+ignore))+1*(*(this+kk+ignore+1)) ); *(*(foutA3+kk)+ii)= ((*(this+kk+ignore-1))+2*(*(this+kk+ignore))+(*(this+kk+ignore+1))); flip=-1*flip; } } for( kk=0 ; kk < nuse-ignore ; kk++ ) *(*(foutavgD3)+ii)= *(*(foutavgD3)+ii)+(*(*(foutD3+kk)+ii)); *(*(foutavgD3)+ii)=*(*(foutavgD3)+ii) / (*(numAv)); } DSET_unload( old_dset ) ; /* don't need this no more */ switch( new_datum ){ /*** output is floats is the simplest: we just have to attach the fout bricks to the dataset ***/ case MRI_float: for( kk=0 ; kk < nuse-ignore ; kk++ ) EDIT_substitute_brick( new_dsetD3 , kk , MRI_float , foutD3[kk] ) ; break ; /*** output is shorts: we have to create a scaled sub-brick from fout ***/ case MRI_short:{ short * boutD3 ; float facD3 ; for( kk=0 ; kk < nuse-ignore ; kk++ ){ /* loop over sub-bricks */ /*-- get output sub-brick --*/ boutD3 = (short *) malloc( sizeof(short) * nvox ) ; if( boutD3 == NULL ){ fprintf(stderr,"\nFinal malloc error in plug_power!\n\a") ; EXIT(1) ; } /*-- find scaling and then scale --*/ facD3 = MCW_vol_amax( nvox,1,1 , MRI_float , foutD3[kk] ) ; if( facD3 > 0.0 ){ facD3 = 32767.0 / facD3 ; EDIT_coerce_scale_type( nvox,facD3 , MRI_float,foutD3[kk] , MRI_short,boutD3 ) ; facD3 = 1.0 / facD3 ; } free( foutD3[kk] ) ; /* don't need this anymore */ /*-- put output brick into dataset, and store scale factor --*/ EDIT_substitute_brick( new_dsetD3 , kk , MRI_short , boutD3 ) ; tarD3 [kk] = facD3 ; } /*-- save scale factor array into dataset --*/ EDIT_dset_items( new_dsetD3 , ADN_brick_fac , tarD3 , ADN_none ) ; } break ; /*** output is bytes (byte = unsigned char) we have to create a scaled sub-brick from fout ***/ case MRI_byte:{ byte * boutD3 ; float facD3 ; for( kk=0 ; kk < nuse-ignore ; kk++ ){ /* loop over sub-bricks */ /*-- get output sub-brick --*/ boutD3 = (byte *) malloc( sizeof(byte) * nvox ) ; if( boutD3 == NULL ){ fprintf(stderr,"\nFinal malloc error in plug_power!\n\a") ; EXIT(1) ; } /*-- find scaling and then scale --*/ facD3 = MCW_vol_amax( nvox,1,1 , MRI_float , foutD3[kk] ) ; if( facD3 > 0.0 ){ facD3 = 255.0 / facD3 ; EDIT_coerce_scale_type( nvox,facD3 , MRI_float,foutD3[kk] , MRI_byte,boutD3 ) ; facD3 = 1.0 / facD3 ; } free( foutD3[kk] ) ; /* don't need this anymore */ /*-- put output brick into dataset, and store scale factor --*/ EDIT_substitute_brick( new_dsetD3 , kk , MRI_byte , boutD3 ) ; tarD3 [kk] = facD3 ; } /*-- save scale factor array into dataset --*/ EDIT_dset_items( new_dsetD3 , ADN_brick_fac , tarD3 , ADN_none ) ; } break ; } /* end of switch on output data type */ switch( new_datum ){ /*** output is floats is the simplest: we just have to attach the fout bricks to the dataset ***/ case MRI_float: for( kk=0 ; kk < nuse-ignore ; kk++ ) EDIT_substitute_brick( new_dsetA3 , kk , MRI_float , foutA3[kk] ) ; break ; /*** output is shorts: we have to create a scaled sub-brick from fout ***/ case MRI_short:{ short * boutA3 ; float facA3 ; for( kk=0 ; kk < nuse-ignore ; kk++ ){ /* loop over sub-bricks */ /*-- get output sub-brick --*/ boutA3 = (short *) malloc( sizeof(short) * nvox ) ; if( boutA3 == NULL ){ fprintf(stderr,"\nFinal malloc error in plug_power!\n\a") ; EXIT(1) ; } /*-- find scaling and then scale --*/ facA3 = MCW_vol_amax( nvox,1,1 , MRI_float , foutA3[kk] ) ; if( facA3 > 0.0 ){ facA3 = 32767.0 / facA3 ; EDIT_coerce_scale_type( nvox,facA3 , MRI_float,foutA3[kk] , MRI_short,boutA3 ) ; facA3 = 1.0 / facA3 ; } free( foutA3[kk] ) ; /* don't need this anymore */ /*-- put output brick into dataset, and store scale factor --*/ EDIT_substitute_brick( new_dsetA3 , kk , MRI_short , boutA3 ) ; tarA3[kk] = facA3 ; } /*-- save scale factor array into dataset --*/ EDIT_dset_items( new_dsetA3 , ADN_brick_fac , tarA3 , ADN_none ) ; } break ; /*** output is bytes (byte = unsigned char) we have to create a scaled sub-brick from fout ***/ case MRI_byte:{ byte * boutA3 ; float facA3 ; for( kk=0 ; kk < nuse-ignore ; kk++ ){ /* loop over sub-bricks */ /*-- get output sub-brick --*/ boutA3 = (byte *) malloc( sizeof(byte) * nvox ) ; if( boutA3 == NULL ){ fprintf(stderr,"\nFinal malloc error in plug_power!\n\a") ; EXIT(1) ; } /*-- find scaling and then scale --*/ facA3 = MCW_vol_amax( nvox,1,1 , MRI_float , foutA3[kk] ) ; if( facA3 > 0.0 ){ facA3 = 255.0 / facA3 ; EDIT_coerce_scale_type( nvox,facA3 , MRI_float,foutA3[kk] , MRI_byte,boutA3 ) ; facA3 = 1.0 / facA3 ; } free( foutA3[kk] ) ; /* don't need this anymore */ /*-- put output brick into dataset, and store scale factor --*/ EDIT_substitute_brick( new_dsetA3 , kk , MRI_byte , boutA3 ) ; tarA3[kk]= facA3 ; } /*-- save scale factor array into dataset --*/ EDIT_dset_items( new_dsetA3 , ADN_brick_fac , tarA3 , ADN_none ) ; } break ; } /* end of switch on output data type */ switch( new_datum ){ case MRI_float:{ EDIT_substitute_brick( new_dsetavgD3 , 0 , MRI_float , foutavgD3[0] ) ; } break ; case MRI_short:{ short * boutavgD3 ; float facavgD3 ; boutavgD3 = (short *) malloc( sizeof(short) * nvox ) ; if( boutavgD3 == NULL ){ fprintf(stderr,"\nFinal malloc error in plug_power!\n\a") ; EXIT(1) ; } facavgD3 = MCW_vol_amax( nvox,1,1 , MRI_float , foutavgD3[0] ) ; if( facavgD3 > 0.0 ){ facavgD3 = 32767.0 / facavgD3 ; EDIT_coerce_scale_type( nvox,facavgD3 , MRI_float,foutavgD3[0] , MRI_short,boutavgD3 ) ; facavgD3 = 1.0 / facavgD3 ; } EDIT_substitute_brick( new_dsetavgD3 , 0 , MRI_short , boutavgD3 ) ; taravgD3[0] = facavgD3 ; EDIT_dset_items( new_dsetavgD3 , ADN_brick_fac , taravgD3 , ADN_none ) ; } break ; case MRI_byte:{ byte * boutavgD3 ; float facavgD3 ; boutavgD3 = (byte *) malloc( sizeof(byte) * nvox ) ; if( boutavgD3 == NULL ){ fprintf(stderr,"\nFinal malloc error in plug_power!\n\a") ; EXIT(1) ; } facavgD3 = MCW_vol_amax( nvox,1,1 , MRI_float , foutavgD3[0] ) ; if( facavgD3 > 0.0 ){ facavgD3 = 255.0 / facavgD3 ; EDIT_coerce_scale_type( nvox,facavgD3 , MRI_float,foutavgD3[0] , MRI_byte,boutavgD3 ) ; facavgD3 = 1.0 / facavgD3 ; } EDIT_substitute_brick( new_dsetavgD3 , 0 , MRI_byte , boutavgD3 ) ; taravgD3[0]= facavgD3 ; EDIT_dset_items( new_dsetavgD3 , ADN_brick_fac , taravgD3 , ADN_none ) ; } break ; } /* endasda of switch on output data type */ /*-------------- Cleanup and go home ----------------*/ PLUTO_add_dset( plint , new_dsetD3 , DSET_ACTION_NONE ) ; PLUTO_add_dset( plint , new_dsetA3 , DSET_ACTION_NONE ) ; PLUTO_add_dset( plint , new_dsetavgD3 , DSET_ACTION_NONE ) ; FREE_WORKSPACE ; free(numAv); return NULL ; /* null string returned means all was OK */ }
THD_3dim_dataset * THD_localhistog( int nsar , THD_3dim_dataset **insar , int numval , int *rlist , MCW_cluster *nbhd , int do_prob , int verb ) { THD_3dim_dataset *outset=NULL , *inset ; int nvox=DSET_NVOX(insar[0]) ; int ids, iv, bb, nnpt=nbhd->num_pt ; MRI_IMAGE *bbim ; int btyp ; float **outar , **listar ; ENTRY("THD_localhistog") ; /*---- create output dataset ----*/ outset = EDIT_empty_copy(insar[0]) ; EDIT_dset_items( outset , ADN_nvals , numval , ADN_datum_all , MRI_float , ADN_nsl , 0 , ADN_brick_fac , NULL , ADN_none ) ; outar = (float **)malloc(sizeof(float *)*numval) ; for( bb=0 ; bb < numval ; bb++ ){ EDIT_substitute_brick( outset , bb , MRI_float , NULL ) ; outar[bb] = DSET_BRICK_ARRAY(outset,bb) ; } /*---- make mapping between values and arrays to get those values ----*/ listar = (float **)malloc(sizeof(float *)*TWO16) ; for( bb=0 ; bb < TWO16 ; bb++ ) listar[bb] = outar[0] ; for( bb=1 ; bb < numval ; bb++ ){ listar[ rlist[bb] + TWO15 ] = outar[bb] ; } /*----------- loop over datasets, add in counts for all voxels -----------*/ for( ids=0 ; ids < nsar ; ids++ ){ /* dataset loop */ inset = insar[ids] ; DSET_load(inset) ; for( iv=0 ; iv < DSET_NVALS(inset) ; iv++ ){ /* sub-brick loop */ if( verb ) fprintf(stderr,".") ; bbim = DSET_BRICK(inset,iv) ; btyp = bbim->kind ; if( nnpt == 1 ){ /* only 1 voxel in nbhd */ int qq,ii,jj,kk,ib,nb ; switch( bbim->kind ){ case MRI_short:{ short *sar = MRI_SHORT_PTR(bbim) ; for( qq=0 ; qq < nvox ; qq++ ) listar[sar[qq]+TWO15][qq]++ ; } break ; case MRI_byte:{ byte *bar = MRI_BYTE_PTR(bbim) ; for( qq=0 ; qq < nvox ; qq++ ) listar[bar[qq]+TWO15][qq]++ ; } break ; case MRI_float:{ float *far = MRI_FLOAT_PTR(bbim) ; short ss ; for( qq=0 ; qq < nvox ; qq++ ){ ss = SHORTIZE(far[qq]); listar[ss+TWO15][qq]++; } } break ; } } else { /* multiple voxels in nbhd */ AFNI_OMP_START ; #pragma omp parallel { int qq,ii,jj,kk,ib,nb ; void *nar ; short *sar,ss ; byte *bar ; float *far ; nar = malloc(sizeof(float)*nnpt) ; sar = (short *)nar ; bar = (byte *)nar ; far = (float *)nar ; #pragma omp for for( qq=0 ; qq < nvox ; qq++ ){ /* qq=voxel index */ ii = DSET_index_to_ix(inset,qq) ; jj = DSET_index_to_jy(inset,qq) ; kk = DSET_index_to_kz(inset,qq) ; nb = mri_get_nbhd_array( bbim , NULL , ii,jj,kk , nbhd , nar ) ; if( nb == 0 ) continue ; switch( btyp ){ case MRI_short: for( ib=0 ; ib < nb ; ib++ ) listar[sar[ib]+TWO15][qq]++ ; break ; case MRI_byte: for( ib=0 ; ib < nb ; ib++ ) listar[bar[ib]+TWO15][qq]++ ; break ; case MRI_float: for( ib=0 ; ib < nb ; ib++ ){ ss = SHORTIZE(far[ib]); listar[ss+TWO15][qq]++; } break ; } } /* end of voxel loop */ free(nar) ; } /* end of OpenMP */ AFNI_OMP_END ; } } /* end of sub-brick loop */ DSET_unload(inset) ; } /* end of dataset loop */ if( verb ) fprintf(stderr,"\n") ; free(listar) ; /*---- post-process output ---*/ if( do_prob ){ byte **bbar ; int pp ; if( verb ) INFO_message("Conversion to probabilities") ; AFNI_OMP_START ; #pragma omp parallel { int qq , ib ; float pfac , val ; byte **bbar ; #pragma omp for for( qq=0 ; qq < nvox ; qq++ ){ pfac = 0.0001f ; for( ib=0 ; ib < numval ; ib++ ) pfac += outar[ib][qq] ; pfac = 250.0f / pfac ; for( ib=0 ; ib < numval ; ib++ ){ val = outar[ib][qq]*pfac ; outar[ib][qq] = BYTEIZE(val) ; } } } /* end OpenMP */ AFNI_OMP_END ; bbar = (byte **)malloc(sizeof(byte *)*numval) ; for( bb=0 ; bb < numval ; bb++ ){ bbar[bb] = (byte *)malloc(sizeof(byte)*nvox) ; for( pp=0 ; pp < nvox ; pp++ ) bbar[bb][pp] = (byte)outar[bb][pp] ; EDIT_substitute_brick(outset,bb,MRI_byte,bbar[bb]) ; EDIT_BRICK_FACTOR(outset,bb,0.004f) ; } free(bbar) ; } /* end of do_prob */ free(outar) ; RETURN(outset) ; }
int main(int argc, char *argv[]) { int i,j,k,m,n,aa,ii,jj,kk,mm,rr; int iarg; int nmask1=0; int nmask2=0; THD_3dim_dataset *insetFA = NULL, *insetV1 = NULL, *insetMD = NULL, *insetL1 = NULL; THD_3dim_dataset *insetEXTRA=NULL; THD_3dim_dataset *mset2=NULL; THD_3dim_dataset *mset1=NULL; THD_3dim_dataset *outsetMAP=NULL, *outsetMASK=NULL; char *prefix="tracky"; int LOG_TYPE=0; char in_FA[300]; char in_V1[300]; char in_MD[300]; char in_L1[300]; int EXTRAFILE=0; // switch for whether other file is input as WM map char OUT_bin[300]; char OUT_tracstat[300]; char prefix_mask[300]; char prefix_map[300]; // FACT algopts FILE *fout0; float MinFA=0.2,MaxAngDeg=45,MinL=20.0; float MaxAng; int SeedPerV[3]={2,2,2}; int ArrMax=0; float tempvmagn; int Nvox=-1; // tot number vox int Dim[3]={0,0,0}; // dim in each dir int Nseed=0,M=30,bval=1000; int DimSeed[3]; // number of seeds there will be float Ledge[3]; // voxel edge lengths int *ROI1, *ROI2; short int *temp_arr; char *temp_byte; int **Tforw, **Tback; int **Ttot; float **flTforw, **flTback; float ****coorded; int ****INDEX; int len_forw, len_back; // int count of num of squares through float phys_forw[1], phys_back[1]; int idx; float ave_tract_len, ave_tract_len_phys; int inroi1, inroi2, KEEPIT; // switches for detecting int in[3]; // to pass to trackit float physin[3]; // also for trackit, physical loc, int totlen; float totlen_phys; int Numtract; int READS_in; float READS_fl; int end[2][3]; int test_ind[2][3]; int roi3_ct=0, id=0; float roi3_mu_MD = 0.,roi3_mu_RD = 0.,roi3_mu_L1 = 0.,roi3_mu_FA = 0.; float roi3_sd_MD = 0.,roi3_sd_RD = 0.,roi3_sd_L1 = 0.,roi3_sd_FA = 0.; float tempMD,tempFA,tempRD,tempL1; char dset_or[4] = "RAI"; THD_3dim_dataset *dsetn; int TV_switch[3] = {0,0,0}; TAYLOR_BUNDLE *tb=NULL; TAYLOR_TRACT *tt=NULL; char *mode = "NI_fast_binary"; NI_element *nel=NULL; int dump_opts=0; tv_io_header header1 = {.id_string = "TRACK\0", .origin = {0,0,0}, .n_scalars = 3, .scal_n[0] = "FA", .scal_n[1] = "MD", .scal_n[2] = "L1", .n_properties = 0, .vox_to_ras = {{0.,0.,0.,0.},{0.,0.,0.,0.}, {0.,0.,0.,0.},{0.,0.,0.,0.}}, // reset this later based on actual data set .voxel_order = "RAI\0", .invert_x = 0, .invert_y = 0, .invert_z = 0, .swap_xy = 0, .swap_yz = 0, .swap_zx = 0, .n_count = 0, .version = 2, .hdr_size = 1000}; // for testing names... char *postfix[4]={"+orig.HEAD\0",".nii.gz\0",".nii\0","+tlrc.HEAD\0"}; int FOUND =-1; int RECORD_ORIG = 0; float Orig[3] = {0.0,0.0,0.0}; mainENTRY("3dTrackID"); machdep(); // **************************************************************** // **************************************************************** // load AFNI stuff // **************************************************************** // **************************************************************** INFO_message("version: MU"); /** scan args **/ if (argc == 1) { usage_TrackID(1); exit(0); } iarg = 1; while( iarg < argc && argv[iarg][0] == '-' ){ if( strcmp(argv[iarg],"-help") == 0 || strcmp(argv[iarg],"-h") == 0 ) { usage_TrackID(strlen(argv[iarg])>3 ? 2:1); exit(0); } if( strcmp(argv[iarg],"-verb") == 0) { if( ++iarg >= argc ) ERROR_exit("Need argument after '-verb'") ; set_tract_verb(atoi(argv[iarg])); iarg++ ; continue ; } if( strcmp(argv[iarg],"-write_opts") == 0) { dump_opts=1; iarg++ ; continue ; } if( strcmp(argv[iarg],"-rec_orig") == 0) { RECORD_ORIG=1; iarg++ ; continue ; } if( strcmp(argv[iarg],"-tract_out_mode") == 0) { if( ++iarg >= argc ) ERROR_exit("Need argument after '-tract_out_mode'") ; if (strcmp(argv[iarg], "NI_fast_binary") && strcmp(argv[iarg], "NI_fast_text") && strcmp(argv[iarg], "NI_slow_binary") && strcmp(argv[iarg], "NI_slow_text") ) { ERROR_message("Bad value (%s) for -tract_out_mode",argv[iarg]); exit(1); } mode = argv[iarg]; iarg++ ; continue ; } if( strcmp(argv[iarg],"-mask1") == 0 ){ if( ++iarg >= argc ) ERROR_exit("Need argument after '-mask1'") ; mset1 = THD_open_dataset( argv[iarg] ) ; if( mset1 == NULL ) ERROR_exit("Can't open mask1 dataset '%s'", argv[iarg]) ; DSET_load(mset1) ; CHECK_LOAD_ERROR(mset1) ; nmask1 = DSET_NVOX(mset1) ; iarg++ ; continue ; } if( strcmp(argv[iarg],"-mask2") == 0 ){ if( ++iarg >= argc ) ERROR_exit("Need argument after '-mask2'") ; mset2 = THD_open_dataset( argv[iarg] ) ; if( mset2 == NULL ) ERROR_exit("Can't open mask2 dataset '%s'", argv[iarg]) ; DSET_load(mset2) ; CHECK_LOAD_ERROR(mset2) ; nmask2 = DSET_NVOX(mset2) ; iarg++ ; continue ; } if( strcmp(argv[iarg],"-prefix") == 0 ){ iarg++ ; if( iarg >= argc ) ERROR_exit("Need argument after '-prefix'"); prefix = strdup(argv[iarg]) ; if( !THD_filename_ok(prefix) ) ERROR_exit("Illegal name after '-prefix'"); iarg++ ; continue ; } if( strcmp(argv[iarg],"-input") == 0 ){ iarg++ ; if( iarg >= argc ) ERROR_exit("Need argument after '-input'"); for( i=0 ; i<4 ; i++) { sprintf(in_FA,"%s_FA%s", argv[iarg],postfix[i]); if(THD_is_ondisk(in_FA)) { FOUND = i; break; } } insetFA = THD_open_dataset(in_FA) ; if( (insetFA == NULL ) || (FOUND==-1)) ERROR_exit("Can't open dataset '%s': for FA.",in_FA); DSET_load(insetFA) ; CHECK_LOAD_ERROR(insetFA) ; Nvox = DSET_NVOX(insetFA) ; Dim[0] = DSET_NX(insetFA); Dim[1] = DSET_NY(insetFA); Dim[2] = DSET_NZ(insetFA); Ledge[0] = fabs(DSET_DX(insetFA)); Ledge[1] = fabs(DSET_DY(insetFA)); Ledge[2] = fabs(DSET_DZ(insetFA)); Orig[0] = DSET_XORG(insetFA); Orig[1] = DSET_YORG(insetFA); Orig[2] = DSET_ZORG(insetFA); // check tot num vox match (as proxy for dims...) if( (Nvox != nmask1) || (Nvox != nmask2) ) ERROR_exit("Input dataset does not match both mask volumes!"); // this stores the original data file orientation for later use, // as well since we convert everything to RAI temporarily, as // described below header1.voxel_order[0]=ORIENT_typestr[insetFA->daxes->xxorient][0]; header1.voxel_order[1]=ORIENT_typestr[insetFA->daxes->yyorient][0]; header1.voxel_order[2]=ORIENT_typestr[insetFA->daxes->zzorient][0]; for( i=0 ; i<3 ; i++) { header1.dim[i] = Dim[i]; header1.voxel_size[i] = Ledge[i]; // will want this when outputting file later for TrackVis. TV_switch[i] = !(dset_or[i]==header1.voxel_order[i]); } dset_or[3]='\0'; FOUND = -1; for( i=0 ; i<4 ; i++) { sprintf(in_V1,"%s_V1%s", argv[iarg],postfix[i]); if(THD_is_ondisk(in_V1)) { FOUND = i; break; } } insetV1 = THD_open_dataset(in_V1); if( insetV1 == NULL ) ERROR_exit("Can't open dataset '%s':V1",in_V1); DSET_load(insetV1) ; CHECK_LOAD_ERROR(insetV1) ; FOUND = -1; for( i=0 ; i<4 ; i++) { sprintf(in_L1,"%s_L1%s", argv[iarg],postfix[i]); if(THD_is_ondisk(in_L1)) { FOUND = i; break; } } insetL1 = THD_open_dataset(in_L1); if( insetL1 == NULL ) ERROR_exit("Can't open dataset '%s':L1",in_L1); DSET_load(insetL1) ; CHECK_LOAD_ERROR(insetL1) ; FOUND = -1; for( i=0 ; i<4 ; i++) { sprintf(in_MD,"%s_MD%s", argv[iarg],postfix[i]); if(THD_is_ondisk(in_MD)) { FOUND = i; break; } } insetMD = THD_open_dataset(in_MD); if( insetMD == NULL ) ERROR_exit("Can't open dataset '%s':MD",in_MD); DSET_load(insetMD) ; CHECK_LOAD_ERROR(insetMD) ; iarg++ ; continue ; } if( strcmp(argv[iarg],"-algopt") == 0 ){ iarg++ ; if( iarg >= argc ) ERROR_exit("Need argument after '-algopt'"); if (!(nel = ReadTractAlgOpts(argv[iarg]))) { ERROR_message("Failed to read options in %s\n", argv[iarg]); exit(19); } if (NI_getTractAlgOpts(nel, &MinFA, &MaxAngDeg, &MinL, SeedPerV, &M, &bval)) { ERROR_message("Failed to get options"); exit(1); } NI_free_element(nel); nel=NULL; iarg++ ; continue ; } if( strcmp(argv[iarg],"-logic") == 0 ){ iarg++ ; if( iarg >= argc ) ERROR_exit("Need argument after '-logic'"); INFO_message("ROI logic type is: %s",argv[iarg]); if( strcmp(argv[iarg],"AND") == 0 ) LOG_TYPE = 1; else if( strcmp(argv[iarg],"OR") == 0 ) LOG_TYPE = 0; else if( strcmp(argv[iarg],"ALL") == 0 ) LOG_TYPE = -1; else ERROR_exit("Illegal after '-logic': need 'OR' or 'AND'"); iarg++ ; continue ; } //@@ if( strcmp(argv[iarg],"-extra_set") == 0) { if( ++iarg >= argc ) ERROR_exit("Need argument after '-extra_set'"); EXTRAFILE = 1; // switch on insetEXTRA = THD_open_dataset(argv[iarg]); if( (insetEXTRA == NULL ) ) ERROR_exit("Can't open dataset '%s': for extra set.",argv[iarg]); DSET_load(insetEXTRA) ; CHECK_LOAD_ERROR(insetEXTRA) ; if( !((Dim[0] == DSET_NX(insetEXTRA)) && (Dim[1] == DSET_NY(insetEXTRA)) && (Dim[2] == DSET_NZ(insetEXTRA)))) ERROR_exit("Dimensions of extra set '%s' don't match those of the DTI prop ones ('%s', etc.).",argv[iarg], in_FA); iarg++ ; continue ; } ERROR_message("Bad option '%s'\n",argv[iarg]) ; suggest_best_prog_option(argv[0], argv[iarg]); exit(1); } if (iarg < 4) { ERROR_message("Too few options. Try -help for details.\n"); exit(1); } if (dump_opts) { nel = NI_setTractAlgOpts(NULL, &MinFA, &MaxAngDeg, &MinL, SeedPerV, &M, &bval); WriteTractAlgOpts(prefix, nel); NI_free_element(nel); nel=NULL; } // Process the options a little for( i=0 ; i<3 ; i++) DimSeed[i] = Dim[i]*SeedPerV[i]; Nseed = Nvox*SeedPerV[0]*SeedPerV[1]*SeedPerV[2]; // convert to cos of rad value for comparisons, instead of using acos() MaxAng = cos(CONV*MaxAngDeg); // switch to add header-- option for now, added Sept. 2012 // for use with map_TrackID to map tracks to different space if(RECORD_ORIG) { for( i=0 ; i<3 ; i++) header1.origin[i] = Orig[i]; } // at some point, we will have to convert indices into // pseudo-locations; being forced into this choice means that // different data set orientations would be represented differently // and incorrectly in some instances... so, for now, we'll resample // everything to RAI, and then resample back later. guess this will // just slow things down slightly. // have all be RAI for processing here if(TV_switch[0] || TV_switch[1] || TV_switch[2]) { dsetn = r_new_resam_dset(insetFA, NULL, 0.0, 0.0, 0.0, dset_or, RESAM_NN_TYPE, NULL, 1, 0); DSET_delete(insetFA); insetFA=dsetn; dsetn=NULL; dsetn = r_new_resam_dset(insetMD, NULL, 0.0, 0.0, 0.0, dset_or, RESAM_NN_TYPE, NULL, 1, 0); DSET_delete(insetMD); insetMD=dsetn; dsetn=NULL; dsetn = r_new_resam_dset(insetV1, NULL, 0.0, 0.0, 0.0, dset_or, RESAM_NN_TYPE, NULL, 1, 0); DSET_delete(insetV1); insetV1=dsetn; dsetn=NULL; dsetn = r_new_resam_dset(insetL1, NULL, 0.0, 0.0, 0.0, dset_or, RESAM_NN_TYPE, NULL, 1, 0); DSET_delete(insetL1); insetL1=dsetn; dsetn=NULL; dsetn = r_new_resam_dset(mset1, NULL, 0.0, 0.0, 0.0, dset_or, RESAM_NN_TYPE, NULL, 1, 0); DSET_delete(mset1); mset1=dsetn; dsetn=NULL; dsetn = r_new_resam_dset(mset2, NULL, 0.0, 0.0, 0.0, dset_or, RESAM_NN_TYPE, NULL, 1, 0); DSET_delete(mset2); mset2=dsetn; dsetn=NULL; if(EXTRAFILE) { dsetn = r_new_resam_dset(insetEXTRA, NULL, 0.0, 0.0, 0.0, dset_or, RESAM_NN_TYPE, NULL, 1, 0); DSET_delete(insetEXTRA); insetEXTRA=dsetn; dsetn=NULL; } } // **************************************************************** // **************************************************************** // make arrays for tracking // **************************************************************** // **************************************************************** // for temp storage array, just a multiple of longest dimension! if(Dim[0] > Dim[1]) ArrMax = Dim[0] * 4; else ArrMax = Dim[1] * 4; if(4*Dim[2] > ArrMax) ArrMax = Dim[2] * 4; ROI1 = (int *)calloc(Nvox, sizeof(int)); ROI2 = (int *)calloc(Nvox, sizeof(int)); temp_arr = (short int *)calloc(Nvox, sizeof(short int)); temp_byte = (char *)calloc(Nvox, sizeof(char)); // temp storage whilst tracking Tforw = calloc(ArrMax, sizeof(Tforw)); for(i=0 ; i<ArrMax ; i++) Tforw[i] = calloc(3, sizeof(int)); Ttot = calloc(2*ArrMax , sizeof(Ttot)); for(i=0 ; i<2*ArrMax ; i++) Ttot[i] = calloc(3, sizeof(int)); Tback = calloc(ArrMax, sizeof(Tback)); for(i=0 ; i<ArrMax ; i++) Tback[i] = calloc(3, sizeof(int)); // temp storage whilst tracking, physical loc flTforw = calloc(ArrMax, sizeof(flTforw)); for(i=0 ; i<ArrMax ; i++) flTforw[i] = calloc(3, sizeof(int)); flTback = calloc(ArrMax,sizeof(flTback)); for(i=0 ; i<ArrMax ; i++) flTback[i] = calloc(3, sizeof(int)); if( (ROI1 == NULL) || (ROI2 == NULL) || (temp_arr == NULL) || (Tforw == NULL) || (Tback == NULL) || (flTforw == NULL) || (flTback == NULL) || (Ttot == NULL)) { fprintf(stderr, "\n\n MemAlloc failure.\n\n"); exit(12); } coorded = (float ****) calloc( Dim[0], sizeof(float ***) ); for ( i = 0 ; i < Dim[0] ; i++ ) coorded[i] = (float ***) calloc( Dim[1], sizeof(float **) ); for ( i = 0 ; i < Dim[0] ; i++ ) for ( j = 0 ; j < Dim[1] ; j++ ) coorded[i][j] = (float **) calloc( Dim[2], sizeof(float *) ); for ( i=0 ; i<Dim[0] ; i++ ) for ( j=0 ; j<Dim[1] ; j++ ) for ( k= 0 ; k<Dim[2] ; k++ ) //3 comp of V1 and FA coorded[i][j][k] = (float *) calloc( 4, sizeof(float) ); INDEX = (int ****) calloc( Dim[0], sizeof(int ***) ); for ( i = 0 ; i < Dim[0] ; i++ ) INDEX[i] = (int ***) calloc( Dim[1], sizeof(int **) ); for ( i = 0 ; i < Dim[0] ; i++ ) for ( j = 0 ; j < Dim[1] ; j++ ) INDEX[i][j] = (int **) calloc( Dim[2], sizeof(int *) ); for ( i=0 ; i<Dim[0] ; i++ ) for ( j=0 ; j<Dim[1] ; j++ ) for ( k= 0 ; k<Dim[2] ; k++ ) INDEX[i][j][k] = (int *) calloc( 4, sizeof(int) ); // this statement will never be executed if allocation fails above if( (INDEX == NULL) || (coorded == NULL) ) { fprintf(stderr, "\n\n MemAlloc failure.\n\n"); exit(122); } for(i=0 ; i<Nvox ; i++) { if(THD_get_voxel( mset1, i, 0) >0.5){ ROI1[i] = 1; } if(THD_get_voxel( mset2, i, 0) >0.5) ROI2[i] = 1; } // set up eigvecs in 3D coord sys, // mark off where ROIs are and keep index handy idx=0; for( k=0 ; k<Dim[2] ; k++ ) for( j=0 ; j<Dim[1] ; j++ ) for( i=0 ; i<Dim[0] ; i++ ) { for( m=0 ; m<3 ; m++ ) coorded[i][j][k][m] = THD_get_voxel(insetV1, idx, m); if(EXTRAFILE) coorded[i][j][k][3] = THD_get_voxel(insetEXTRA, idx, 0); else coorded[i][j][k][3] = THD_get_voxel(insetFA, idx, 0); // make sure that |V1| == 1 for all eigenvects, otherwise it's /// a problem in the tractography; currently, some from // 3dDWItoDT do not have this property... tempvmagn = sqrt(coorded[i][j][k][0]*coorded[i][j][k][0]+ coorded[i][j][k][1]*coorded[i][j][k][1]+ coorded[i][j][k][2]*coorded[i][j][k][2]); if( tempvmagn<0.99 ) for( m=0 ; m<3 ; m++ ) coorded[i][j][k][m]/= tempvmagn; INDEX[i][j][k][0] =idx; // first value is the index itself if( ROI1[idx]==1 ) INDEX[i][j][k][1]=1; // second value identifies ROI1 mask else INDEX[i][j][k][1]=0; if( ROI2[idx]==1 ) INDEX[i][j][k][2]=1; // third value identifies ROI2 mask else INDEX[i][j][k][2]=0; // fourth value will be counter for number of kept tracks // passing through INDEX[i][j][k][3] = 0; idx+= 1; } // ************************************************************* // ************************************************************* // Beginning of main loop // ************************************************************* // ************************************************************* Numtract = 0; ave_tract_len = 0.; ave_tract_len_phys = 0.; sprintf(OUT_bin,"%s.trk",prefix); if( (fout0 = fopen(OUT_bin, "w")) == NULL) { fprintf(stderr, "Error opening file %s.",OUT_bin); exit(16); } fwrite(&header1,sizeof(tv_io_header),1,fout0); if (get_tract_verb()) { INFO_message("Begin tracking..."); } tb = AppCreateBundle(NULL, 0, NULL, insetFA); // start bundle id = 0; for( k=0 ; k<Dim[2] ; k++ ) for( j=0 ; j<Dim[1] ; j++ ) for( i=0 ; i<Dim[0] ; i++ ) if(coorded[i][j][k][3] >= MinFA) { for( ii=0 ; ii<SeedPerV[0] ; ii++ ) for( jj=0 ; jj<SeedPerV[1] ; jj++ ) for( kk=0 ; kk<SeedPerV[2] ; kk++ ) { in[0] = i; in[1] = j; in[2] = k; physin[0] = ((float) in[0] + (0.5 + (float) ii)/SeedPerV[0])*Ledge[0]; physin[1] = ((float) in[1] + (0.5 + (float) jj)/SeedPerV[1])*Ledge[1]; physin[2] = ((float) in[2] + (0.5 + (float) kk)/SeedPerV[2])*Ledge[2]; len_forw = TrackIt(coorded, in, physin, Ledge, Dim, MinFA, MaxAng, ArrMax, Tforw, flTforw, 1, phys_forw); // reset, because it's changed in TrackIt func in[0] = i; in[1] = j; in[2] = k; physin[0] = ((float) in[0] + (0.5 + (float) ii)/SeedPerV[0])*Ledge[0]; physin[1] = ((float) in[1] + (0.5 + (float) jj)/SeedPerV[1])*Ledge[1]; physin[2] = ((float) in[2] + (0.5 + (float) kk)/SeedPerV[2])*Ledge[2]; len_back = TrackIt(coorded, in, physin, Ledge, Dim, MinFA, MaxAng, ArrMax, Tback, flTback, -1, phys_back); KEEPIT = 0; // a simple switch totlen = len_forw+len_back-1; // NB: overlap of starts totlen_phys = phys_forw[0] + phys_back[0]; if( totlen_phys >= MinL ) { // glue together for simpler notation later for( n=0 ; n<len_back ; n++) { // all of this rr = len_back-n-1; // read in backward for(m=0;m<3;m++) Ttot[rr][m] = Tback[n][m]; } for( n=1 ; n<len_forw ; n++){// skip first->overlap rr = n+len_back-1; // put after for(m=0;m<3;m++) Ttot[rr][m] = Tforw[n][m]; } // <<So close and orthogonal condition>>: // test projecting ends, to see if they abut ROI. for(m=0;m<3;m++) { //actual projected ends end[1][m] = 2*Ttot[totlen-1][m]-Ttot[totlen-2][m]; end[0][m] = 2*Ttot[0][m]-Ttot[1][m]; // default choice, just retest known ends // as default test_ind[1][m] = test_ind[0][m] = Ttot[0][m]; } tt = Create_Tract(len_back, flTback, len_forw, flTforw, id, insetFA); ++id; if (LOG_TYPE == -1) { KEEPIT = 1; } else { inroi1 = 0; // check forw for( n=0 ; n<len_forw ; n++) { if(INDEX[Tforw[n][0]][Tforw[n][1]][Tforw[n][2]][1]==1){ inroi1 = 1; break; } else continue; } if( inroi1==0 ){// after 1st half, check 2nd half for( m=0 ; m<len_back ; m++) { if(INDEX[Tback[m][0]][Tback[m][1]][Tback[m][2]][1]==1){ inroi1 = 1; break; } else continue; } } // after 1st&2nd halves, check bound/neigh if( inroi1==0 ) { if(INDEX[test_ind[1][0]][test_ind[1][1]][test_ind[1][2]][1]==1) inroi1 = 1; if(INDEX[test_ind[0][0]][test_ind[0][1]][test_ind[0][2]][1]==1) inroi1 = 1; } if( ((LOG_TYPE ==0) && (inroi1 ==0)) || ((LOG_TYPE ==1) && (inroi1 ==1))) { // have to check in ROI2 inroi2 = 0; // check forw for( n=0 ; n<len_forw ; n++) { if(INDEX[Tforw[n][0]][Tforw[n][1]][Tforw[n][2]][2]==1){ inroi2 = 1; break; } else continue; } //after 1st half, check 2nd half if( inroi2==0 ) { for( m=0 ; m<len_back ; m++) { if(INDEX[Tback[m][0]][Tback[m][1]][Tback[m][2]][2]==1){ inroi2 = 1; break; } else continue; } } // after 1st&2nd halves, check bound/neigh if( inroi2==0 ) { if(INDEX[test_ind[1][0]][test_ind[1][1]][test_ind[1][2]][2]==1) inroi2 = 1; if(INDEX[test_ind[0][0]][test_ind[0][1]][test_ind[0][2]][2]==1) inroi2 = 1; } // for both cases, need to see it here to keep if( inroi2 ==1 ) KEEPIT = 1; // otherwise, it's gone } else if((LOG_TYPE ==0) && (inroi1 ==1)) KEEPIT = 1; } } // by now, we *know* if we're keeping this or not. if( KEEPIT == 1 ) { tb = AppCreateBundle(tb, 1, tt, NULL); tt = Free_Tracts(tt, 1); READS_in = totlen; fwrite(&READS_in,sizeof(READS_in),1,fout0); for( n=0 ; n<len_back ; n++) { //put this one in backwords, to make it connect m = len_back - 1 - n; for(aa=0 ; aa<3 ; aa++) { // recenter phys loc for trackvis, if nec... // just works this way (where they define // origin) READS_fl = flTback[m][aa]; if(!TV_switch[aa]) READS_fl = Ledge[aa]*Dim[aa]-READS_fl; fwrite(&READS_fl,sizeof(READS_fl),1,fout0); } mm = INDEX[Tback[m][0]][Tback[m][1]][Tback[m][2]][0]; READS_fl =THD_get_voxel(insetFA, mm, 0); // FA fwrite(&READS_fl,sizeof(READS_fl),1,fout0); READS_fl =THD_get_voxel(insetMD, mm, 0); // MD fwrite(&READS_fl,sizeof(READS_fl),1,fout0); READS_fl =THD_get_voxel(insetL1, mm, 0); // L1 fwrite(&READS_fl,sizeof(READS_fl),1,fout0); // count this voxel for having a tract INDEX[Tback[m][0]][Tback[m][1]][Tback[m][2]][3]+= 1; } for( m=1 ; m<len_forw ; m++) { for(aa=0 ; aa<3 ; aa++) { // recenter phys loc for trackvis, if nec... READS_fl = flTforw[m][aa]; if(!TV_switch[aa]) READS_fl = Ledge[aa]*Dim[aa]-READS_fl; fwrite(&READS_fl,sizeof(READS_fl),1,fout0); } mm = INDEX[Tforw[m][0]][Tforw[m][1]][Tforw[m][2]][0]; READS_fl =THD_get_voxel(insetFA, mm, 0); // FA fwrite(&READS_fl,sizeof(READS_fl),1,fout0); READS_fl =THD_get_voxel(insetMD, mm, 0); // MD fwrite(&READS_fl,sizeof(READS_fl),1,fout0); READS_fl =THD_get_voxel(insetL1, mm, 0); // L1 fwrite(&READS_fl,sizeof(READS_fl),1,fout0); // count this voxel for having a tract INDEX[Tforw[m][0]][Tforw[m][1]][Tforw[m][2]][3]+= 1; } ave_tract_len+= totlen; ave_tract_len_phys+= totlen_phys; Numtract+=1; } } } fclose(fout0); if (get_tract_verb()) { INFO_message("Done tracking, have %d tracks.", tb->N_tracts); Show_Taylor_Bundle(tb, NULL, 3); } if (!Write_Bundle(tb,prefix,mode)) { ERROR_message("Failed to write the bundle"); } // ************************************************************** // ************************************************************** // Some simple stats on ROIs and outputs // ************************************************************** // ************************************************************** for( k=0 ; k<Dim[2] ; k++ ) for( j=0 ; j<Dim[1] ; j++ ) for( i=0 ; i<Dim[0] ; i++ ) { if( INDEX[i][j][k][3]>=1 ) { tempMD = THD_get_voxel(insetMD,INDEX[i][j][k][0],0); tempFA = THD_get_voxel(insetFA,INDEX[i][j][k][0],0); tempL1 = THD_get_voxel(insetL1,INDEX[i][j][k][0],0); tempRD = 0.5*(3*tempMD-tempL1); roi3_mu_MD+= tempMD; roi3_mu_FA+= tempFA; roi3_mu_L1+= tempL1; roi3_mu_RD+= tempRD; roi3_sd_MD+= tempMD*tempMD; roi3_sd_FA+= tempFA*tempFA; roi3_sd_L1+= tempL1*tempL1; roi3_sd_RD+= tempRD*tempRD; roi3_ct+= 1; } } if(roi3_ct > 0 ) { // !!!! make into afni file roi3_mu_MD/= (float) roi3_ct; roi3_mu_FA/= (float) roi3_ct; roi3_mu_L1/= (float) roi3_ct; roi3_mu_RD/= (float) roi3_ct; roi3_sd_MD-= roi3_ct*roi3_mu_MD*roi3_mu_MD; roi3_sd_FA-= roi3_ct*roi3_mu_FA*roi3_mu_FA; roi3_sd_L1-= roi3_ct*roi3_mu_L1*roi3_mu_L1; roi3_sd_RD-= roi3_ct*roi3_mu_RD*roi3_mu_RD; roi3_sd_MD/= (float) roi3_ct-1; roi3_sd_FA/= (float) roi3_ct-1; roi3_sd_L1/= (float) roi3_ct-1; roi3_sd_RD/= (float) roi3_ct-1; roi3_sd_MD = sqrt(roi3_sd_MD); roi3_sd_FA = sqrt(roi3_sd_FA); roi3_sd_L1 = sqrt(roi3_sd_L1); roi3_sd_RD = sqrt(roi3_sd_RD); sprintf(OUT_tracstat,"%s.stats",prefix); if( (fout0 = fopen(OUT_tracstat, "w")) == NULL) { fprintf(stderr, "Error opening file %s.",OUT_tracstat); exit(19); } fprintf(fout0,"%d\t%d\n",Numtract,roi3_ct); fprintf(fout0,"%.3f\t%.3f\n",ave_tract_len/Numtract, ave_tract_len_phys/Numtract); // as usual, these next values would have to be divided by the // bval to get their actual value in standard phys units fprintf(fout0,"%.4f\t%.4f\n",roi3_mu_FA,roi3_sd_FA); fprintf(fout0,"%.4f\t%.4f\n",roi3_mu_MD,roi3_sd_MD); fprintf(fout0,"%.4f\t%.4f\n",roi3_mu_RD,roi3_sd_RD); fprintf(fout0,"%.4f\t%.4f\n",roi3_mu_L1,roi3_sd_L1); fclose(fout0); sprintf(prefix_map,"%s_MAP",prefix); sprintf(prefix_mask,"%s_MASK",prefix); outsetMAP = EDIT_empty_copy( mset1 ) ; EDIT_dset_items( outsetMAP , ADN_datum_all , MRI_short , ADN_prefix , prefix_map , ADN_none ) ; if( !THD_ok_overwrite() && THD_is_ondisk(DSET_HEADNAME(outsetMAP)) ) ERROR_exit("Can't overwrite existing dataset '%s'", DSET_HEADNAME(outsetMAP)); outsetMASK = EDIT_empty_copy( mset1 ) ; EDIT_dset_items( outsetMASK , ADN_datum_all , MRI_byte , ADN_prefix , prefix_mask , ADN_none ) ; if(!THD_ok_overwrite() && THD_is_ondisk(DSET_HEADNAME(outsetMASK)) ) ERROR_exit("Can't overwrite existing dataset '%s'", DSET_HEADNAME(outsetMASK)); m=0; for( k=0 ; k<Dim[2] ; k++ ) for( j=0 ; j<Dim[1] ; j++ ) for( i=0 ; i<Dim[0] ; i++ ) { temp_arr[m]=INDEX[i][j][k][3]; if(temp_arr[m]>0.5) temp_byte[m]=1; else temp_byte[m]=0; m++; } // re-orient the data as original inputs // (this function copies the pointer) EDIT_substitute_brick(outsetMAP, 0, MRI_short, temp_arr); temp_arr=NULL; if(TV_switch[0] || TV_switch[1] || TV_switch[2]) { dsetn = r_new_resam_dset(outsetMAP, NULL, 0.0, 0.0, 0.0, header1.voxel_order, RESAM_NN_TYPE, NULL, 1, 0); DSET_delete(outsetMAP); outsetMAP=dsetn; dsetn=NULL; } EDIT_dset_items( outsetMAP , ADN_prefix , prefix_map , ADN_none ) ; THD_load_statistics(outsetMAP ); if( !THD_ok_overwrite() && THD_is_ondisk(DSET_HEADNAME(outsetMAP)) ) ERROR_exit("Can't overwrite existing dataset '%s'", DSET_HEADNAME(outsetMAP)); tross_Make_History( "3dTrackID" , argc , argv , outsetMAP) ; THD_write_3dim_dataset(NULL, NULL, outsetMAP, True); // re-orient the data as original inputs EDIT_substitute_brick(outsetMASK, 0, MRI_byte, temp_byte); temp_byte=NULL; if(TV_switch[0] || TV_switch[1] || TV_switch[2]) { dsetn = r_new_resam_dset(outsetMASK, NULL, 0.0, 0.0, 0.0, header1.voxel_order, RESAM_NN_TYPE, NULL, 1, 0); DSET_delete(outsetMASK); outsetMASK=dsetn; dsetn=NULL; } EDIT_dset_items( outsetMASK , ADN_prefix , prefix_mask , ADN_none ) ; THD_load_statistics(outsetMASK); if(!THD_ok_overwrite() && THD_is_ondisk(DSET_HEADNAME(outsetMASK)) ) ERROR_exit("Can't overwrite existing dataset '%s'", DSET_HEADNAME(outsetMASK)); tross_Make_History( "3dTrackID" , argc , argv , outsetMASK) ; THD_write_3dim_dataset(NULL, NULL, outsetMASK, True); INFO_message("Number of tracts found = %d",Numtract) ; } else INFO_message("\n No Tracts Found!!!\n"); // ************************************************************ // ************************************************************ // Freeing // ************************************************************ // ************************************************************ // !!! need to free afni-sets? DSET_delete(insetFA); DSET_delete(insetMD); DSET_delete(insetL1); DSET_delete(insetV1); DSET_delete(insetEXTRA); //DSET_delete(outsetMAP); //DSET_delete(outsetMASK); DSET_delete(mset2); DSET_delete(mset1); free(prefix); free(insetV1); free(insetFA); free(mset1); free(mset2); free(insetEXTRA); free(ROI1); free(ROI2); free(temp_byte); for( i=0 ; i<ArrMax ; i++) { free(Tforw[i]); free(Tback[i]); free(flTforw[i]); free(flTback[i]); } free(Tforw); free(Tback); free(flTforw); free(flTback); for( i=0 ; i<Dim[0] ; i++) for( j=0 ; j<Dim[1] ; j++) for( k=0 ; k<Dim[2] ; k++) free(coorded[i][j][k]); for( i=0 ; i<Dim[0] ; i++) for( j=0 ; j<Dim[1] ; j++) free(coorded[i][j]); for( i=0 ; i<Dim[0] ; i++) free(coorded[i]); free(coorded); for( i=0 ; i<Dim[0] ; i++) for( j=0 ; j<Dim[1] ; j++) for( k=0 ; k<Dim[2] ; k++) free(INDEX[i][j][k]); for( i=0 ; i<Dim[0] ; i++) for( j=0 ; j<Dim[1] ; j++) free(INDEX[i][j]); for( i=0 ; i<Dim[0] ; i++) free(INDEX[i]); free(INDEX); free(temp_arr); // need to free for( i=0 ; i<2*ArrMax ; i++) free(Ttot[i]); free(Ttot); //free(mode); return 0; }
int main( int argc , char *argv[] ) { THD_3dim_dataset *xset , *cset, *mset=NULL ; int nopt=1 , method=PEARSON , do_autoclip=0 ; int nvox , nvals , ii, jj, kout, kin, polort=1 ; int ix1,jy1,kz1, ix2, jy2, kz2 ; char *prefix = "degree_centrality" ; byte *mask=NULL; int nmask , abuc=1 ; int all_source=0; /* output all source voxels 25 Jun 2010 [rickr] */ char str[32] , *cpt ; int *imap = NULL ; MRI_vectim *xvectim ; float (*corfun)(int,float *,float*) = NULL ; /* djc - add 1d file output for similarity matrix */ FILE *fout1D=NULL; /* CC - we will have two subbricks: binary and weighted centrality */ int nsubbriks = 2; int subbrik = 0; float * bodset; float * wodset; int nb_ctr = 0; /* CC - added flags for thresholding correlations */ double thresh = 0.0; double othresh = 0.0; int dothresh = 0; double sparsity = 0.0; int dosparsity = 0; /* variables for calculating degree centrality */ long * binaryDC = NULL; double * weightedDC = NULL; /* variables for histogram */ hist_node_head* histogram=NULL; hist_node* hptr=NULL; hist_node* pptr=NULL; int bottom_node_idx = 0; int totNumCor = 0; long totPosCor = 0; int ngoal = 0; int nretain = 0; float binwidth = 0.0; int nhistnodes = 50; /*----*/ AFNI_SETUP_OMP(0) ; /* 24 Jun 2013 */ if( argc < 2 || strcmp(argv[1],"-help") == 0 ){ printf( "Usage: 3dDegreeCentrality [options] dset\n" " Computes voxelwise weighted and binary degree centrality and\n" " stores the result in a new 3D bucket dataset as floats to\n" " preserve their values. Degree centrality reflects the strength and\n" " extent of the correlation of a voxel with every other voxel in\n" " the brain.\n\n" " Conceptually the process involves: \n" " 1. Calculating the correlation between voxel time series for\n" " every pair of voxels in the brain (as determined by masking)\n" " 2. Applying a threshold to the resulting correlations to exclude\n" " those that might have arisen by chance, or to sparsify the\n" " connectivity graph.\n" " 3. At each voxel, summarizing its correlation with other voxels\n" " in the brain, by either counting the number of voxels correlated\n" " with the seed voxel (binary) or by summing the correlation \n" " coefficients (weighted).\n" " Practically the algorithm is ordered differently to optimize for\n" " computational time and memory usage.\n\n" " The threshold can be supplied as a correlation coefficient, \n" " or a sparsity threshold. The sparsity threshold reflects the fraction\n" " of connections that should be retained after the threshold has been\n" " applied. To minimize resource consumption, using a sparsity threshold\n" " involves a two-step procedure. In the first step, a correlation\n" " coefficient threshold is applied to substantially reduce the number\n" " of correlations. Next, the remaining correlations are sorted and a\n" " threshold is calculated so that only the specified fraction of \n" " possible correlations are above threshold. Due to ties between\n" " correlations, the fraction of correlations that pass the sparsity\n" " threshold might be slightly more than the number specified.\n\n" " Regardless of the thresholding procedure employed, negative \n" " correlations are excluded from the calculations.\n" "\n" "Options:\n" " -pearson = Correlation is the normal Pearson (product moment)\n" " correlation coefficient [default].\n" #if 0 " -spearman = Correlation is the Spearman (rank) correlation\n" " coefficient.\n" " -quadrant = Correlation is the quadrant correlation coefficient.\n" #else " -spearman AND -quadrant are disabled at this time :-(\n" #endif "\n" " -thresh r = exclude correlations <= r from calculations\n" " -sparsity s = only use top s percent of correlations in calculations\n" " s should be an integer between 0 and 100. Uses an\n" " an adaptive thresholding procedure to reduce memory.\n" " The speed of determining the adaptive threshold can\n" " be improved by specifying an initial threshold with\n" " the -thresh flag.\n" "\n" " -polort m = Remove polynomical trend of order 'm', for m=-1..3.\n" " [default is m=1; removal is by least squares].\n" " Using m=-1 means no detrending; this is only useful\n" " for data/information that has been pre-processed.\n" "\n" " -autoclip = Clip off low-intensity regions in the dataset,\n" " -automask = so that the correlation is only computed between\n" " high-intensity (presumably brain) voxels. The\n" " mask is determined the same way that 3dAutomask works.\n" "\n" " -mask mmm = Mask to define 'in-brain' voxels. Reducing the number\n" " the number of voxels included in the calculation will\n" " significantly speedup the calculation. Consider using\n" " a mask to constrain the calculations to the grey matter\n" " rather than the whole brain. This is also preferrable\n" " to using -autoclip or -automask.\n" "\n" " -prefix p = Save output into dataset with prefix 'p', this file will\n" " contain bricks for both 'weighted' or 'degree' centrality\n" " [default prefix is 'deg_centrality'].\n" "\n" " -out1D f = Save information about the above threshold correlations to\n" " 1D file 'f'. Each row of this file will contain:\n" " Voxel1 Voxel2 i1 j1 k1 i2 j2 k2 Corr\n" " Where voxel1 and voxel2 are the 1D indices of the pair of\n" " voxels, i j k correspond to their 3D coordinates, and Corr\n" " is the value of the correlation between the voxel time courses.\n" "\n" "Notes:\n" " * The output dataset is a bucket type of floats.\n" " * The program prints out an estimate of its memory used\n" " when it ends. It also prints out a progress 'meter'\n" " to keep you pacified.\n" "\n" "-- RWCox - 31 Jan 2002 and 16 Jul 2010\n" "-- Cameron Craddock - 26 Sept 2015 \n" ) ; PRINT_AFNI_OMP_USAGE("3dDegreeCentrality",NULL) ; PRINT_COMPILE_DATE ; exit(0) ; } mainENTRY("3dDegreeCentrality main"); machdep(); PRINT_VERSION("3dDegreeCentrality"); AFNI_logger("3dDegreeCentrality",argc,argv); /*-- option processing --*/ while( nopt < argc && argv[nopt][0] == '-' ){ if( strcmp(argv[nopt],"-time") == 0 ){ abuc = 0 ; nopt++ ; continue ; } if( strcmp(argv[nopt],"-autoclip") == 0 || strcmp(argv[nopt],"-automask") == 0 ){ do_autoclip = 1 ; nopt++ ; continue ; } if( strcmp(argv[nopt],"-mask") == 0 ){ mset = THD_open_dataset(argv[++nopt]); CHECK_OPEN_ERROR(mset,argv[nopt]); nopt++ ; continue ; } if( strcmp(argv[nopt],"-pearson") == 0 ){ method = PEARSON ; nopt++ ; continue ; } #if 0 if( strcmp(argv[nopt],"-spearman") == 0 ){ method = SPEARMAN ; nopt++ ; continue ; } if( strcmp(argv[nopt],"-quadrant") == 0 ){ method = QUADRANT ; nopt++ ; continue ; } #endif if( strcmp(argv[nopt],"-eta2") == 0 ){ method = ETA2 ; nopt++ ; continue ; } if( strcmp(argv[nopt],"-prefix") == 0 ){ prefix = strdup(argv[++nopt]) ; if( !THD_filename_ok(prefix) ){ ERROR_exit("Illegal value after -prefix!") ; } nopt++ ; continue ; } if( strcmp(argv[nopt],"-thresh") == 0 ){ double val = (double)strtod(argv[++nopt],&cpt) ; if( *cpt != '\0' || val >= 1.0 || val < 0.0 ){ ERROR_exit("Illegal value (%f) after -thresh!", val) ; } dothresh = 1; thresh = val ; othresh = val ; nopt++ ; continue ; } if( strcmp(argv[nopt],"-sparsity") == 0 ){ double val = (double)strtod(argv[++nopt],&cpt) ; if( *cpt != '\0' || val > 100 || val <= 0 ){ ERROR_exit("Illegal value (%f) after -sparsity!", val) ; } if( val > 5.0 ) { WARNING_message("Sparsity %3.2f%% is large and will require alot of memory and time, consider using a smaller value. ", val); } dosparsity = 1 ; sparsity = val ; nopt++ ; continue ; } if( strcmp(argv[nopt],"-polort") == 0 ){ int val = (int)strtod(argv[++nopt],&cpt) ; if( *cpt != '\0' || val < -1 || val > 3 ){ ERROR_exit("Illegal value after -polort!") ; } polort = val ; nopt++ ; continue ; } if( strcmp(argv[nopt],"-mem_stat") == 0 ){ MEM_STAT = 1 ; nopt++ ; continue ; } if( strncmp(argv[nopt],"-mem_profile",8) == 0 ){ MEM_PROF = 1 ; nopt++ ; continue ; } /* check for 1d argument */ if ( strcmp(argv[nopt],"-out1D") == 0 ){ if (!(fout1D = fopen(argv[++nopt], "w"))) { ERROR_message("Failed to open %s for writing", argv[nopt]); exit(1); } nopt++ ; continue ; } ERROR_exit("Illegal option: %s",argv[nopt]) ; } /*-- open dataset, check for legality --*/ if( nopt >= argc ) ERROR_exit("Need a dataset on command line!?") ; xset = THD_open_dataset(argv[nopt]); CHECK_OPEN_ERROR(xset,argv[nopt]); if( DSET_NVALS(xset) < 3 ) ERROR_exit("Input dataset %s does not have 3 or more sub-bricks!",argv[nopt]) ; DSET_load(xset) ; CHECK_LOAD_ERROR(xset) ; /*-- compute mask array, if desired --*/ nvox = DSET_NVOX(xset) ; nvals = DSET_NVALS(xset) ; INC_MEM_STATS((nvox * nvals * sizeof(double)), "input dset"); PRINT_MEM_STATS("inset"); /* if a mask was specified make sure it is appropriate */ if( mset ){ if( DSET_NVOX(mset) != nvox ) ERROR_exit("Input and mask dataset differ in number of voxels!") ; mask = THD_makemask(mset, 0, 1.0, 0.0) ; /* update running memory statistics to reflect loading the image */ INC_MEM_STATS( mset->dblk->total_bytes, "mask dset" ); PRINT_MEM_STATS( "mset load" ); nmask = THD_countmask( nvox , mask ) ; INC_MEM_STATS( nmask * sizeof(byte), "mask array" ); PRINT_MEM_STATS( "mask" ); INFO_message("%d voxels in -mask dataset",nmask) ; if( nmask < 2 ) ERROR_exit("Only %d voxels in -mask, exiting...",nmask); /* update running memory statistics to reflect loading the image */ DEC_MEM_STATS( mset->dblk->total_bytes, "mask dset" ); DSET_unload(mset) ; PRINT_MEM_STATS( "mset unload" ); } /* if automasking is requested, handle that now */ else if( do_autoclip ){ mask = THD_automask( xset ) ; nmask = THD_countmask( nvox , mask ) ; INFO_message("%d voxels survive -autoclip",nmask) ; if( nmask < 2 ) ERROR_exit("Only %d voxels in -automask!",nmask); } /* otherwise we use all of the voxels in the image */ else { nmask = nvox ; INFO_message("computing for all %d voxels",nmask) ; } if( method == ETA2 && polort >= 0 ) WARNING_message("Polort for -eta2 should probably be -1..."); /* djc - 1d file out init */ if (fout1D != NULL) { /* define affine matrix */ mat44 affine_mat = xset->daxes->ijk_to_dicom; /* print command line statement */ fprintf(fout1D,"#Similarity matrix from command:\n#"); for(ii=0; ii<argc; ++ii) fprintf(fout1D,"%s ", argv[ii]); /* Print affine matrix */ fprintf(fout1D,"\n"); fprintf(fout1D,"#[ "); int mi, mj; for(mi = 0; mi < 4; mi++) { for(mj = 0; mj < 4; mj++) { fprintf(fout1D, "%.6f ", affine_mat.m[mi][mj]); } } fprintf(fout1D, "]\n"); /* Print image extents*/ THD_dataxes *xset_daxes = xset->daxes; fprintf(fout1D, "#Image dimensions:\n"); fprintf(fout1D, "#[%d, %d, %d]\n", xset_daxes->nxx, xset_daxes->nyy, xset_daxes->nzz); /* Similarity matrix headers */ fprintf(fout1D,"#Voxel1 Voxel2 i1 j1 k1 i2 j2 k2 Corr\n"); } /* CC calculate the total number of possible correlations, will be usefule down the road */ totPosCor = (.5*((float)nmask))*((float)(nmask-1)); /** For the case of Pearson correlation, we make sure the **/ /** data time series have their mean removed (polort >= 0) **/ /** and are normalized, so that correlation = dot product, **/ /** and we can use function zm_THD_pearson_corr for speed. **/ switch( method ){ default: case PEARSON: corfun = zm_THD_pearson_corr ; break ; case ETA2: corfun = my_THD_eta_squared ; break ; } /*-- create vectim from input dataset --*/ INFO_message("vectim-izing input dataset") ; /*-- CC added in mask to reduce the size of xvectim -- */ xvectim = THD_dset_to_vectim( xset , mask , 0 ) ; if( xvectim == NULL ) ERROR_exit("Can't create vectim?!") ; /*-- CC update our memory stats to reflect vectim -- */ INC_MEM_STATS((xvectim->nvec*sizeof(int)) + ((xvectim->nvec)*(xvectim->nvals))*sizeof(float) + sizeof(MRI_vectim), "vectim"); PRINT_MEM_STATS( "vectim" ); /*--- CC the vectim contains a mapping between voxel index and mask index, tap into that here to avoid duplicating memory usage ---*/ if( mask != NULL ) { imap = xvectim->ivec; /* --- CC free the mask */ DEC_MEM_STATS( nmask*sizeof(byte), "mask array" ); free(mask); mask=NULL; PRINT_MEM_STATS( "mask unload" ); } /* -- CC unloading the dataset to reduce memory usage ?? -- */ DEC_MEM_STATS((DSET_NVOX(xset) * DSET_NVALS(xset) * sizeof(double)), "input dset"); DSET_unload(xset) ; PRINT_MEM_STATS("inset unload"); /* -- CC configure detrending --*/ if( polort < 0 && method == PEARSON ){ polort = 0; WARNING_message("Pearson correlation always uses polort >= 0"); } if( polort >= 0 ){ for( ii=0 ; ii < xvectim->nvec ; ii++ ){ /* remove polynomial trend */ DETREND_polort(polort,nvals,VECTIM_PTR(xvectim,ii)) ; } } /* -- this procedure does not change time series that have zero variance -- */ if( method == PEARSON ) THD_vectim_normalize(xvectim) ; /* L2 norm = 1 */ /* -- CC create arrays to hold degree and weighted centrality while they are being calculated -- */ if( dosparsity == 0 ) { if( ( binaryDC = (long*)calloc( nmask, sizeof(long) )) == NULL ) { ERROR_message( "Could not allocate %d byte array for binary DC calculation\n", nmask*sizeof(long)); } /* -- update running memory estimate to reflect memory allocation */ INC_MEM_STATS( nmask*sizeof(long), "binary DC array" ); PRINT_MEM_STATS( "binaryDC" ); if( ( weightedDC = (double*)calloc( nmask, sizeof(double) )) == NULL ) { if (binaryDC){ free(binaryDC); binaryDC = NULL; } ERROR_message( "Could not allocate %d byte array for weighted DC calculation\n", nmask*sizeof(double)); } /* -- update running memory estimate to reflect memory allocation */ INC_MEM_STATS( nmask*sizeof(double), "weighted DC array" ); PRINT_MEM_STATS( "weightedDC" ); } /* -- CC if we are using a sparsity threshold, build a histogram to calculate the threshold */ if (dosparsity == 1) { /* make sure that there is a bin for correlation values that == 1.0 */ binwidth = (1.005-thresh)/nhistnodes; /* calculate the number of correlations we wish to retain */ ngoal = nretain = (int)(((double)totPosCor)*((double)sparsity) / 100.0); /* allocate memory for the histogram bins */ if(( histogram = (hist_node_head*)malloc(nhistnodes*sizeof(hist_node_head))) == NULL ) { /* if the allocation fails, free all memory and exit */ if (binaryDC){ free(binaryDC); binaryDC = NULL; } if (weightedDC){ free(weightedDC); weightedDC = NULL; } ERROR_message( "Could not allocate %d byte array for histogram\n", nhistnodes*sizeof(hist_node_head)); } else { /* -- update running memory estimate to reflect memory allocation */ INC_MEM_STATS( nhistnodes*sizeof(hist_node_head), "hist bins" ); PRINT_MEM_STATS( "hist1" ); } /* initialize history bins */ for( kout = 0; kout < nhistnodes; kout++ ) { histogram[ kout ].bin_low = thresh+kout*binwidth; histogram[ kout ].bin_high = histogram[ kout ].bin_low+binwidth; histogram[ kout ].nbin = 0; histogram[ kout ].nodes = NULL; /*INFO_message("Hist bin %d [%3.3f, %3.3f) [%d, %p]\n", kout, histogram[ kout ].bin_low, histogram[ kout ].bin_high, histogram[ kout ].nbin, histogram[ kout ].nodes );*/ } } /*-- tell the user what we are about to do --*/ if (dosparsity == 0 ) { INFO_message( "Calculating degree centrality with threshold = %f.\n", thresh); } else { INFO_message( "Calculating degree centrality with threshold = %f and sparsity = %3.2f%% (%d)\n", thresh, sparsity, nretain); } /*---------- loop over mask voxels, correlate ----------*/ AFNI_OMP_START ; #pragma omp parallel if( nmask > 999 ) { int lii,ljj,lin,lout,ithr,nthr,vstep,vii ; float *xsar , *ysar ; hist_node* new_node = NULL ; hist_node* tptr = NULL ; hist_node* rptr = NULL ; int new_node_idx = 0; double car = 0.0 ; /*-- get information about who we are --*/ #ifdef USE_OMP ithr = omp_get_thread_num() ; nthr = omp_get_num_threads() ; if( ithr == 0 ) INFO_message("%d OpenMP threads started",nthr) ; #else ithr = 0 ; nthr = 1 ; #endif /*-- For the progress tracker, we want to print out 50 numbers, figure out a number of loop iterations that will make this easy */ vstep = (int)( nmask / (nthr*50.0f) + 0.901f ) ; vii = 0 ; if((MEM_STAT==0) && (ithr == 0 )) fprintf(stderr,"Looping:") ; #pragma omp for schedule(static, 1) for( lout=0 ; lout < xvectim->nvec ; lout++ ){ /*----- outer voxel loop -----*/ if( ithr == 0 && vstep > 2 ) /* allow small dsets 16 Jun 2011 [rickr] */ { vii++ ; if( vii%vstep == vstep/2 && MEM_STAT == 0 ) vstep_print(); } /* get ref time series from this voxel */ xsar = VECTIM_PTR(xvectim,lout) ; /* try to make calculation more efficient by only calculating the unique correlations */ for( lin=(lout+1) ; lin < xvectim->nvec ; lin++ ){ /*----- inner loop over voxels -----*/ /* extract the voxel time series */ ysar = VECTIM_PTR(xvectim,lin) ; /* now correlate the time series */ car = (double)(corfun(nvals,xsar,ysar)) ; if ( car <= thresh ) { continue ; } /* update degree centrality values, hopefully the pragma will handle mutual exclusion */ #pragma omp critical(dataupdate) { /* if the correlation is less than threshold, ignore it */ if ( car > thresh ) { totNumCor += 1; if ( dosparsity == 0 ) { binaryDC[lout] += 1; binaryDC[lin] += 1; weightedDC[lout] += car; weightedDC[lin] += car; /* print correlation out to the 1D file */ if ( fout1D != NULL ) { /* determine the i,j,k coords */ ix1 = DSET_index_to_ix(xset,lii) ; jy1 = DSET_index_to_jy(xset,lii) ; kz1 = DSET_index_to_kz(xset,lii) ; ix2 = DSET_index_to_ix(xset,ljj) ; jy2 = DSET_index_to_jy(xset,ljj) ; kz2 = DSET_index_to_kz(xset,ljj) ; /* add source, dest, correlation to 1D file */ fprintf(fout1D, "%d %d %d %d %d %d %d %d %.6f\n", lii, ljj, ix1, jy1, kz1, ix2, jy2, kz2, car); } } else { /* determine the index in the histogram to add the node */ new_node_idx = (int)floor((double)(car-othresh)/(double)binwidth); if ((new_node_idx > nhistnodes) || (new_node_idx < bottom_node_idx)) { /* this error should indicate a programming error and should not happen */ WARNING_message("Node index %d is out of range [%d,%d)!",new_node_idx, bottom_node_idx, nhistnodes); } else { /* create a node to add to the histogram */ new_node = (hist_node*)calloc(1,sizeof(hist_node)); if( new_node == NULL ) { /* allocate memory for this node, rather than fiddling with error handling here, lets just move on */ WARNING_message("Could not allocate a new node!"); } else { /* populate histogram node */ new_node->i = lout; new_node->j = lin; new_node->corr = car; new_node->next = NULL; /* -- update running memory estimate to reflect memory allocation */ INC_MEM_STATS( sizeof(hist_node), "hist nodes" ); if ((totNumCor % (1024*1024)) == 0) PRINT_MEM_STATS( "hist nodes" ); /* populate histogram */ new_node->next = histogram[new_node_idx].nodes; histogram[new_node_idx].nodes = new_node; histogram[new_node_idx].nbin++; /* see if there are enough correlations in the histogram for the sparsity */ if ((totNumCor - histogram[bottom_node_idx].nbin) > nretain) { /* delete the list of nodes */ rptr = histogram[bottom_node_idx].nodes; while(rptr != NULL) { tptr = rptr; rptr = rptr->next; /* check that the ptr is not null before freeing it*/ if(tptr!= NULL) { DEC_MEM_STATS( sizeof(hist_node), "hist nodes" ); free(tptr); } } PRINT_MEM_STATS( "unloaded hist nodes - thresh increase" ); histogram[bottom_node_idx].nodes = NULL; totNumCor -= histogram[bottom_node_idx].nbin; histogram[bottom_node_idx].nbin=0; /* get the new threshold */ thresh = (double)histogram[++bottom_node_idx].bin_low; if(MEM_STAT == 1) INFO_message("Increasing threshold to %3.2f (%d)\n", thresh,bottom_node_idx); } } /* else, newptr != NULL */ } /* else, new_node_idx in range */ } /* else, do_sparsity == 1 */ } /* car > thresh */ } /* this is the end of the critical section */ } /* end of inner loop over voxels */ } /* end of outer loop over ref voxels */ if( ithr == 0 ) fprintf(stderr,".\n") ; } /* end OpenMP */ AFNI_OMP_END ; /* update the user so that they know what we are up to */ INFO_message ("AFNI_OMP finished\n"); INFO_message ("Found %d (%3.2f%%) correlations above threshold (%f)\n", totNumCor, 100.0*((float)totNumCor)/((float)totPosCor), thresh); /*---------- Finish up ---------*/ /*if( dosparsity == 1 ) { for( kout = 0; kout < nhistnodes; kout++ ) { INFO_message("Hist bin %d [%3.3f, %3.3f) [%d, %p]\n", kout, histogram[ kout ].bin_low, histogram[ kout ].bin_high, histogram[ kout ].nbin, histogram[ kout ].nodes ); } }*/ /*-- create output dataset --*/ cset = EDIT_empty_copy( xset ) ; /*-- configure the output dataset */ if( abuc ){ EDIT_dset_items( cset , ADN_prefix , prefix , ADN_nvals , nsubbriks , /* 2 subbricks, degree and weighted centrality */ ADN_ntt , 0 , /* no time axis */ ADN_type , HEAD_ANAT_TYPE , ADN_func_type , ANAT_BUCK_TYPE , ADN_datum_all , MRI_float , ADN_none ) ; } else { EDIT_dset_items( cset , ADN_prefix , prefix , ADN_nvals , nsubbriks , /* 2 subbricks, degree and weighted centrality */ ADN_ntt , nsubbriks , /* num times */ ADN_ttdel , 1.0 , /* fake TR */ ADN_nsl , 0 , /* no slice offsets */ ADN_type , HEAD_ANAT_TYPE , ADN_func_type , ANAT_EPI_TYPE , ADN_datum_all , MRI_float , ADN_none ) ; } /* add history information to the hearder */ tross_Make_History( "3dDegreeCentrality" , argc,argv , cset ) ; ININFO_message("creating output dataset in memory") ; /* -- Configure the subbriks: Binary Degree Centrality */ subbrik = 0; EDIT_BRICK_TO_NOSTAT(cset,subbrik) ; /* stat params */ /* CC this sets the subbrik scaling factor, which we will probably want to do again after we calculate the voxel values */ EDIT_BRICK_FACTOR(cset,subbrik,1.0) ; /* scale factor */ sprintf(str,"Binary Degree Centrality") ; EDIT_BRICK_LABEL(cset,subbrik,str) ; EDIT_substitute_brick(cset,subbrik,MRI_float,NULL) ; /* make array */ /* copy measure data into the subbrik */ bodset = DSET_ARRAY(cset,subbrik); /* -- Configure the subbriks: Weighted Degree Centrality */ subbrik = 1; EDIT_BRICK_TO_NOSTAT(cset,subbrik) ; /* stat params */ /* CC this sets the subbrik scaling factor, which we will probably want to do again after we calculate the voxel values */ EDIT_BRICK_FACTOR(cset,subbrik,1.0) ; /* scale factor */ sprintf(str,"Weighted Degree Centrality") ; EDIT_BRICK_LABEL(cset,subbrik,str) ; EDIT_substitute_brick(cset,subbrik,MRI_float,NULL) ; /* make array */ /* copy measure data into the subbrik */ wodset = DSET_ARRAY(cset,subbrik); /* increment memory stats */ INC_MEM_STATS( (DSET_NVOX(cset)*DSET_NVALS(cset)*sizeof(float)), "output dset"); PRINT_MEM_STATS( "outset" ); /* pull the values out of the histogram */ if( dosparsity == 0 ) { for( kout = 0; kout < nmask; kout++ ) { if ( imap != NULL ) { ii = imap[kout] ; /* ii= source voxel (we know that ii is in the mask) */ } else { ii = kout ; } if( ii >= DSET_NVOX(cset) ) { WARNING_message("Avoiding bodset, wodset overflow %d > %d (%s,%d)\n", ii,DSET_NVOX(cset),__FILE__,__LINE__ ); } else { bodset[ ii ] = (float)(binaryDC[kout]); wodset[ ii ] = (float)(weightedDC[kout]); } } /* we are done with this memory, and can kill it now*/ if(binaryDC) { free(binaryDC); binaryDC=NULL; /* -- update running memory estimate to reflect memory allocation */ DEC_MEM_STATS( nmask*sizeof(long), "binary DC array" ); PRINT_MEM_STATS( "binaryDC" ); } if(weightedDC) { free(weightedDC); weightedDC=NULL; /* -- update running memory estimate to reflect memory allocation */ DEC_MEM_STATS( nmask*sizeof(double), "weighted DC array" ); PRINT_MEM_STATS( "weightedDC" ); } } else { /* add in the values from the histogram, this is a two stage procedure: at first we add in values a whole bin at the time until we get to a point where we need to add in a partial bin, then we create a new histogram to sort the values in the bin and then add those bins at a time */ kout = nhistnodes - 1; while (( histogram[kout].nbin < nretain ) && ( kout >= 0 )) { hptr = pptr = histogram[kout].nodes; while( hptr != NULL ) { /* determine the indices corresponding to this node */ if ( imap != NULL ) { ii = imap[hptr->i] ; /* ii= source voxel (we know that ii is in the mask) */ } else { ii = hptr->i ; } if ( imap != NULL ) { jj = imap[hptr->j] ; /* ii= source voxel (we know that ii is in the mask) */ } else { jj = hptr->j ; } /* add in the values */ if(( ii >= DSET_NVOX(cset) ) || ( jj >= DSET_NVOX(cset))) { if( ii >= DSET_NVOX(cset)) { WARNING_message("Avoiding bodset, wodset overflow (ii) %d > %d\n (%s,%d)\n", ii,DSET_NVOX(cset),__FILE__,__LINE__ ); } if( jj >= DSET_NVOX(cset)) { WARNING_message("Avoiding bodset, wodset overflow (jj) %d > %d\n (%s,%d)\n", jj,DSET_NVOX(cset),__FILE__,__LINE__ ); } } else { bodset[ ii ] += 1.0 ; wodset[ ii ] += (float)(hptr->corr); bodset[ jj ] += 1.0 ; wodset[ jj ] += (float)(hptr->corr); } if( fout1D != NULL ) { /* add source, dest, correlation to 1D file */ ix1 = DSET_index_to_ix(cset,ii) ; jy1 = DSET_index_to_jy(cset,ii) ; kz1 = DSET_index_to_kz(cset,ii) ; ix2 = DSET_index_to_ix(cset,jj) ; jy2 = DSET_index_to_jy(cset,jj) ; kz2 = DSET_index_to_kz(cset,jj) ; fprintf(fout1D, "%d %d %d %d %d %d %d %d %.6f\n", ii, jj, ix1, jy1, kz1, ix2, jy2, kz2, (float)(hptr->corr)); } /* increment node pointers */ pptr = hptr; hptr = hptr->next; /* delete the node */ if(pptr) { /* -- update running memory estimate to reflect memory allocation */ DEC_MEM_STATS(sizeof( hist_node ), "hist nodes" ); /* free the mem */ free(pptr); pptr=NULL; } } /* decrement the number of correlations we wish to retain */ nretain -= histogram[kout].nbin; histogram[kout].nodes = NULL; /* go on to the next bin */ kout--; } PRINT_MEM_STATS( "hist1 bins free - inc into output" ); /* if we haven't used all of the correlations that are available, go through and add a subset of the voxels from the remaining bin */ if(( nretain > 0 ) && (kout >= 0)) { hist_node_head* histogram2 = NULL; hist_node_head* histogram2_save = NULL; int h2nbins = 100; float h2binwidth = 0.0; int h2ndx=0; h2binwidth = (((1.0+binwidth/((float)h2nbins))*histogram[kout].bin_high) - histogram[kout].bin_low) / ((float)h2nbins); /* allocate the bins */ if(( histogram2 = (hist_node_head*)malloc(h2nbins*sizeof(hist_node_head))) == NULL ) { if (binaryDC){ free(binaryDC); binaryDC = NULL; } if (weightedDC){ free(weightedDC); weightedDC = NULL; } if (histogram){ histogram = free_histogram(histogram, nhistnodes); } ERROR_message( "Could not allocate %d byte array for histogram2\n", h2nbins*sizeof(hist_node_head)); } else { /* -- update running memory estimate to reflect memory allocation */ histogram2_save = histogram2; INC_MEM_STATS(( h2nbins*sizeof(hist_node_head )), "hist bins"); PRINT_MEM_STATS( "hist2" ); } /* initiatize the bins */ for( kin = 0; kin < h2nbins; kin++ ) { histogram2[ kin ].bin_low = histogram[kout].bin_low + kin*h2binwidth; histogram2[ kin ].bin_high = histogram2[ kin ].bin_low + h2binwidth; histogram2[ kin ].nbin = 0; histogram2[ kin ].nodes = NULL; /*INFO_message("Hist2 bin %d [%3.3f, %3.3f) [%d, %p]\n", kin, histogram2[ kin ].bin_low, histogram2[ kin ].bin_high, histogram2[ kin ].nbin, histogram2[ kin ].nodes );*/ } /* move correlations from histogram to histgram2 */ INFO_message ("Adding %d nodes from histogram to histogram2",histogram[kout].nbin); while ( histogram[kout].nodes != NULL ) { hptr = histogram[kout].nodes; h2ndx = (int)floor((double)(hptr->corr - histogram[kout].bin_low)/(double)h2binwidth); if(( h2ndx < h2nbins ) && ( h2ndx >= 0 )) { histogram[kout].nodes = hptr->next; hptr->next = histogram2[h2ndx].nodes; histogram2[h2ndx].nodes = hptr; histogram2[h2ndx].nbin++; histogram[kout].nbin--; } else { WARNING_message("h2ndx %d is not in range [0,%d) :: %.10f,%.10f\n",h2ndx,h2nbins,hptr->corr, histogram[kout].bin_low); } } /* free the remainder of histogram */ { int nbins_rem = 0; for(ii = 0; ii < nhistnodes; ii++) nbins_rem+=histogram[ii].nbin; histogram = free_histogram(histogram, nhistnodes); PRINT_MEM_STATS( "free remainder of histogram1" ); } kin = h2nbins - 1; while (( nretain > 0 ) && ( kin >= 0 )) { hptr = pptr = histogram2[kin].nodes; while( hptr != NULL ) { /* determine the indices corresponding to this node */ if ( imap != NULL ) { ii = imap[hptr->i] ; } else { ii = hptr->i ; } if ( imap != NULL ) { jj = imap[hptr->j] ; } else { jj = hptr->j ; } /* add in the values */ if(( ii >= DSET_NVOX(cset) ) || ( jj >= DSET_NVOX(cset))) { if( ii >= DSET_NVOX(cset)) { WARNING_message("Avoiding bodset, wodset overflow (ii) %d > %d\n (%s,%d)\n", ii,DSET_NVOX(cset),__FILE__,__LINE__ ); } if( jj >= DSET_NVOX(cset)) { WARNING_message("Avoiding bodset, wodset overflow (jj) %d > %d\n (%s,%d)\n", jj,DSET_NVOX(cset),__FILE__,__LINE__ ); } } else { bodset[ ii ] += 1.0 ; wodset[ ii ] += (float)(hptr->corr); bodset[ jj ] += 1.0 ; wodset[ jj ] += (float)(hptr->corr); } if( fout1D != NULL ) { /* add source, dest, correlation to 1D file */ ix1 = DSET_index_to_ix(cset,ii) ; jy1 = DSET_index_to_jy(cset,ii) ; kz1 = DSET_index_to_kz(cset,ii) ; ix2 = DSET_index_to_ix(cset,jj) ; jy2 = DSET_index_to_jy(cset,jj) ; kz2 = DSET_index_to_kz(cset,jj) ; fprintf(fout1D, "%d %d %d %d %d %d %d %d %.6f\n", ii, jj, ix1, jy1, kz1, ix2, jy2, kz2, (float)(hptr->corr)); } /* increment node pointers */ pptr = hptr; hptr = hptr->next; /* delete the node */ if(pptr) { free(pptr); DEC_MEM_STATS(( sizeof(hist_node) ), "hist nodes"); pptr=NULL; } } /* decrement the number of correlations we wish to retain */ nretain -= histogram2[kin].nbin; histogram2[kin].nodes = NULL; /* go on to the next bin */ kin--; } PRINT_MEM_STATS("hist2 nodes free - incorporated into output"); /* we are finished with histogram2 */ { histogram2 = free_histogram(histogram2, h2nbins); /* -- update running memory estimate to reflect memory allocation */ PRINT_MEM_STATS( "free hist2" ); } if (nretain < 0 ) { WARNING_message( "Went over sparsity goal %d by %d, with a resolution of %f", ngoal, -1*nretain, h2binwidth); } } if (nretain > 0 ) { WARNING_message( "Was not able to meet goal of %d (%3.2f%%) correlations, %d (%3.2f%%) correlations passed the threshold of %3.2f, maybe you need to change the threshold or the desired sparsity?", ngoal, 100.0*((float)ngoal)/((float)totPosCor), totNumCor, 100.0*((float)totNumCor)/((float)totPosCor), thresh); } } INFO_message("Done..\n") ; /* update running memory statistics to reflect freeing the vectim */ DEC_MEM_STATS(((xvectim->nvec*sizeof(int)) + ((xvectim->nvec)*(xvectim->nvals))*sizeof(float) + sizeof(MRI_vectim)), "vectim"); /* toss some trash */ VECTIM_destroy(xvectim) ; DSET_delete(xset) ; if(fout1D!=NULL)fclose(fout1D); PRINT_MEM_STATS( "vectim unload" ); if (weightedDC) free(weightedDC) ; weightedDC = NULL; if (binaryDC) free(binaryDC) ; binaryDC = NULL; /* finito */ INFO_message("Writing output dataset to disk [%s bytes]", commaized_integer_string(cset->dblk->total_bytes)) ; /* write the dataset */ DSET_write(cset) ; WROTE_DSET(cset) ; /* increment our memory stats, since we are relying on the header for this information, we update the stats before actually freeing the memory */ DEC_MEM_STATS( (DSET_NVOX(cset)*DSET_NVALS(cset)*sizeof(float)), "output dset"); /* free up the output dataset memory */ DSET_unload(cset) ; DSET_delete(cset) ; /* force a print */ MEM_STAT = 1; PRINT_MEM_STATS( "Fin" ); exit(0) ; }
int main( int argc , char *argv[] ) { THD_3dim_dataset *inset=NULL , *outset=NULL ; MCW_cluster *nbhd=NULL ; byte *mask=NULL ; int mask_nx,mask_ny,mask_nz , automask=0 ; char *prefix="./LocalCormat" ; int iarg=1 , verb=1 , ntype=0 , kk,nx,ny,nz,nxy,nxyz,nt , xx,yy,zz, vstep ; float na,nb,nc , dx,dy,dz ; MRI_IMARR *imar=NULL ; MRI_IMAGE *pim=NULL ; int mmlag=10 , ii,jj , do_arma=0 , nvout ; MRI_IMAGE *concim=NULL ; float *concar=NULL ; if( argc < 2 || strcmp(argv[1],"-help") == 0 ){ printf( "Usage: 3dLocalCORMAT [options] inputdataset\n" "\n" "Compute the correlation matrix (in time) of the input dataset,\n" "up to lag given by -maxlag. The matrix is averaged over the\n" "neighborhood specified by the -nbhd option, and then the entries\n" "are output at each voxel in a new dataset.\n" "\n" "Normally, the input to this program would be the -errts output\n" "from 3dDeconvolve, or the equivalent residuals from some other\n" "analysis. If you input a non-residual time series file, you at\n" "least should use an appropriate -polort level for detrending!\n" "\n" "Options:\n" " -input inputdataset\n" " -prefix ppp\n" " -mask mset {these 2 options are}\n" " -automask {mutually exclusive.}\n" " -nbhd nnn [e.g., 'SPHERE(9)' for 9 mm radius]\n" " -polort ppp [default = 0, which is reasonable for -errts output]\n" " -concat ccc [as in 3dDeconvolve]\n" " -maxlag mmm [default = 10]\n" " -ARMA [estimate ARMA(1,1) parameters into last 2 sub-bricks]\n" "\n" "A quick hack for my own benignant purposes -- RWCox -- June 2008\n" ) ; PRINT_COMPILE_DATE ; exit(0) ; } /*---- official startup ---*/ PRINT_VERSION("3dLocalCormat"); mainENTRY("3dLocalCormat main"); machdep(); AFNI_logger("3dLocalCormat",argc,argv); AUTHOR("Zhark the Toeplitzer"); /*---- loop over options ----*/ while( iarg < argc && argv[iarg][0] == '-' ){ #if 0 fprintf(stderr,"argv[%d] = %s\n",iarg,argv[iarg]) ; #endif if( strcmp(argv[iarg],"-ARMA") == 0 ){ do_arma = 1 ; iarg++ ; continue ; } if( strcmp(argv[iarg],"-polort") == 0 ){ char *cpt ; if( ++iarg >= argc ) ERROR_exit("Need argument after option %s",argv[iarg-1]) ; pport = (int)strtod(argv[iarg],&cpt) ; if( *cpt != '\0' ) WARNING_message("Illegal non-numeric value after -polort") ; if( pport > 3 ){ pport = 3 ; WARNING_message("-polort set to 3 == max implemented") ; } else if( pport < 0 ){ pport = 0 ; WARNING_message("-polort set to 0 == min implemented") ; } iarg++ ; continue ; } if( strcmp(argv[iarg],"-input") == 0 ){ if( inset != NULL ) ERROR_exit("Can't have two -input options") ; if( ++iarg >= argc ) ERROR_exit("Need argument after '-input'") ; inset = THD_open_dataset( argv[iarg] ) ; CHECK_OPEN_ERROR(inset,argv[iarg]) ; iarg++ ; continue ; } if( strcmp(argv[iarg],"-prefix") == 0 ){ if( ++iarg >= argc ) ERROR_exit("Need argument after '-prefix'") ; prefix = strdup(argv[iarg]) ; iarg++ ; continue ; } if( strcmp(argv[iarg],"-mask") == 0 ){ THD_3dim_dataset *mset ; int mmm ; if( ++iarg >= argc ) ERROR_exit("Need argument after '-mask'") ; if( mask != NULL || automask ) ERROR_exit("Can't have two mask inputs") ; mset = THD_open_dataset( argv[iarg] ) ; CHECK_OPEN_ERROR(mset,argv[iarg]) ; DSET_load(mset) ; CHECK_LOAD_ERROR(mset) ; mask_nx = DSET_NX(mset); mask_ny = DSET_NY(mset); mask_nz = DSET_NZ(mset); mask = THD_makemask( mset , 0 , 0.5f, 0.0f ) ; DSET_delete(mset) ; if( mask == NULL ) ERROR_exit("Can't make mask from dataset '%s'",argv[iarg]) ; mmm = THD_countmask( mask_nx*mask_ny*mask_nz , mask ) ; INFO_message("Number of voxels in mask = %d",mmm) ; if( mmm < 2 ) ERROR_exit("Mask is too small to process") ; iarg++ ; continue ; } if( strcmp(argv[iarg],"-automask") == 0 ){ if( mask != NULL ) ERROR_exit("Can't have -automask and -mask") ; automask = 1 ; iarg++ ; continue ; } if( strcmp(argv[iarg],"-nbhd") == 0 ){ char *cpt ; if( ntype > 0 ) ERROR_exit("Can't have 2 '-nbhd' options") ; if( ++iarg >= argc ) ERROR_exit("Need argument after '-nbhd'") ; cpt = argv[iarg] ; if( strncasecmp(cpt,"SPHERE",6) == 0 ){ sscanf( cpt+7 , "%f" , &na ) ; if( na == 0.0f ) ERROR_exit("Can't have a SPHERE of radius 0") ; ntype = NTYPE_SPHERE ; } else if( strncasecmp(cpt,"RECT",4) == 0 ){ sscanf( cpt+5 , "%f,%f,%f" , &na,&nb,&nc ) ; if( na == 0.0f && nb == 0.0f && nc == 0.0f ) ERROR_exit("'RECT(0,0,0)' is not a legal neighborhood") ; ntype = NTYPE_RECT ; } else if( strncasecmp(cpt,"RHDD",4) == 0 ){ sscanf( cpt+5 , "%f" , &na ) ; if( na == 0.0f ) ERROR_exit("Can't have a RHDD of radius 0") ; ntype = NTYPE_RHDD ; } else { ERROR_exit("Unknown -nbhd shape: '%s'",cpt) ; } iarg++ ; continue ; } if( strcmp(argv[iarg],"-maxlag") == 0 ){ if( ++iarg >= argc ) ERROR_exit("Need argument after option %s",argv[iarg-1]) ; mmlag = (int)strtod(argv[iarg],NULL) ; iarg++ ; continue ; } if( strcmp(argv[iarg],"-concat") == 0 ){ if( concim != NULL ) ERROR_exit("Can't have two %s options!",argv[iarg]) ; if( ++iarg >= argc ) ERROR_exit("Need argument after option %s",argv[iarg-1]) ; concim = mri_read_1D( argv[iarg] ) ; if( concim == NULL ) ERROR_exit("Can't read -concat file '%s'",argv[iarg]) ; if( concim->nx < 2 ) ERROR_exit("-concat file '%s' must have at least 2 entries!", argv[iarg]) ; concar = MRI_FLOAT_PTR(concim) ; for( ii=1 ; ii < concim->nx ; ii++ ) if( (int)concar[ii-1] >= (int)concar[ii] ) ERROR_exit("-concat file '%s' is not ordered increasingly!", argv[iarg]) ; iarg++ ; continue ; } ERROR_exit("Unknown option '%s'",argv[iarg]) ; } /*--- end of loop over options ---*/ if( do_arma && mmlag > 0 && mmlag < 5 ) ERROR_exit("Can't do -ARMA with -maxlag %d",mmlag) ; /*---- deal with input dataset ----*/ if( inset == NULL ){ if( iarg >= argc ) ERROR_exit("No input dataset on command line?") ; inset = THD_open_dataset( argv[iarg] ) ; CHECK_OPEN_ERROR(inset,argv[iarg]) ; } ntime = DSET_NVALS(inset) ; if( ntime < 9 ) ERROR_exit("Must have at least 9 values per voxel") ; DSET_load(inset) ; CHECK_LOAD_ERROR(inset) ; if( mask != NULL ){ if( mask_nx != DSET_NX(inset) || mask_ny != DSET_NY(inset) || mask_nz != DSET_NZ(inset) ) ERROR_exit("-mask dataset grid doesn't match input dataset") ; } else if( automask ){ int mmm ; mask = THD_automask( inset ) ; if( mask == NULL ) ERROR_message("Can't create -automask from input dataset?") ; mmm = THD_countmask( DSET_NVOX(inset) , mask ) ; INFO_message("Number of voxels in automask = %d",mmm) ; if( mmm < 2 ) ERROR_exit("Automask is too small to process") ; } /*-- set up blocks of continuous time data --*/ if( DSET_IS_TCAT(inset) ){ if( concim != NULL ){ WARNING_message("Ignoring -concat, since dataset is auto-catenated") ; mri_free(concim) ; } concim = mri_new(inset->tcat_num,1,MRI_float) ; concar = MRI_FLOAT_PTR(concim) ; concar[0] = 0.0 ; for( ii=0 ; ii < inset->tcat_num-1 ; ii++ ) concar[ii+1] = concar[ii] + inset->tcat_len[ii] ; } else if( concim == NULL ){ concim = mri_new(1,1,MRI_float) ; concar = MRI_FLOAT_PTR(concim) ; concar[0] = 0 ; } nbk = concim->nx ; bk = (int *)malloc(sizeof(int)*(nbk+1)) ; for( ii=0 ; ii < nbk ; ii++ ) bk[ii] = (int)concar[ii] ; bk[nbk] = ntime ; mri_free(concim) ; mlag = DSET_NVALS(inset) ; for( ii=0 ; ii < nbk ; ii++ ){ jj = bk[ii+1]-bk[ii] ; if( jj < mlag ) mlag = jj ; if( bk[ii] < 0 || jj < 9 ) ERROR_exit("something is rotten in the dataset run lengths") ; } mlag-- ; if( mmlag > 0 && mlag > mmlag ) mlag = mmlag ; else INFO_message("Max lag set to %d",mlag) ; if( do_arma && mlag < 5 ) ERROR_exit("Can't do -ARMA with maxlag=%d",mlag) ; /*---- create neighborhood (as a cluster) -----*/ if( ntype <= 0 ){ /* default neighborhood */ ntype = NTYPE_SPHERE ; na = -1.01f ; INFO_message("Using default neighborhood = self + 6 neighbors") ; } switch( ntype ){ default: ERROR_exit("WTF? ntype=%d",ntype) ; case NTYPE_SPHERE:{ if( na < 0.0f ){ dx = dy = dz = 1.0f ; na = -na ; } else { dx = fabsf(DSET_DX(inset)) ; dy = fabsf(DSET_DY(inset)) ; dz = fabsf(DSET_DZ(inset)) ; } nbhd = MCW_spheremask( dx,dy,dz , na ) ; } break ; case NTYPE_RECT:{ if( na < 0.0f ){ dx = 1.0f; na = -na; } else dx = fabsf(DSET_DX(inset)); if( nb < 0.0f ){ dy = 1.0f; nb = -nb; } else dy = fabsf(DSET_DY(inset)); if( nc < 0.0f ){ dz = 1.0f; nc = -nc; } else dz = fabsf(DSET_DZ(inset)); nbhd = MCW_rectmask( dx,dy,dz , na,nb,nc ) ; } break ; case NTYPE_RHDD:{ if( na < 0.0f ){ dx = dy = dz = 1.0f ; na = -na ; } else { dx = fabsf(DSET_DX(inset)) ; dy = fabsf(DSET_DY(inset)) ; dz = fabsf(DSET_DZ(inset)) ; } nbhd = MCW_rhddmask( dx,dy,dz , na ) ; } break ; } MCW_radsort_cluster( nbhd , dx,dy,dz ) ; /* 26 Feb 2008 */ INFO_message("Neighborhood comprises %d voxels",nbhd->num_pt) ; /** create output dataset **/ outset = EDIT_empty_copy(inset) ; nvout = mlag ; if( do_arma ) nvout += 2 ; EDIT_dset_items( outset, ADN_prefix , prefix, ADN_brick_fac, NULL , ADN_nvals , nvout , ADN_ntt , nvout , ADN_none ); tross_Copy_History( inset , outset ) ; tross_Make_History( "3dLocalCormat" , argc,argv , outset ) ; for( kk=0 ; kk < nvout ; kk++ ) EDIT_substitute_brick( outset , kk , MRI_float , NULL ) ; nx = DSET_NX(outset) ; ny = DSET_NY(outset) ; nxy = nx*ny ; nz = DSET_NZ(outset) ; nxyz = nxy*nz ; vstep = (verb && nxyz > 999) ? nxyz/50 : 0 ; if( vstep ) fprintf(stderr,"++ voxel loop: ") ; /** actually do the long long slog through all voxels **/ for( kk=0 ; kk < nxyz ; kk++ ){ if( vstep && kk%vstep==vstep-1 ) vstep_print() ; if( !INMASK(kk) ) continue ; IJK_TO_THREE( kk , xx,yy,zz , nx,nxy ) ; imar = THD_get_dset_nbhd_array( inset , mask , xx,yy,zz , nbhd ) ; if( imar == NULL ) continue ; pim = mri_cormat_vector(imar) ; DESTROY_IMARR(imar) ; if( pim == NULL ) continue ; THD_insert_series( kk, outset, pim->nx, MRI_float, MRI_FLOAT_PTR(pim), 0 ) ; if( do_arma ){ /* estimate ARMA(1,1) params and store those, too */ float_pair ab ; float *aa=DSET_ARRAY(outset,mlag), *bb=DSET_ARRAY(outset,mlag+1) ; ab = estimate_arma11( pim->nx , MRI_FLOAT_PTR(pim) ) ; aa[kk] = ab.a ; bb[kk] = ab.b ; } mri_free(pim) ; } if( vstep ) fprintf(stderr,"\n") ; DSET_delete(inset) ; DSET_write(outset) ; WROTE_DSET(outset) ; exit(0) ; }
THD_3dim_dataset * MAKER_4D_to_typed_fim( THD_3dim_dataset * old_dset , char * new_prefix , int new_datum , int ignore , int detrend , generic_func * user_func , void * user_data ) { THD_3dim_dataset * new_dset ; /* output dataset */ byte ** bptr = NULL ; /* one of these will be the array of */ short ** sptr = NULL ; /* pointers to input dataset sub-bricks */ float ** fptr = NULL ; /* (depending on input datum type) */ complex ** cptr = NULL ; float * fxar = NULL ; /* array loaded from input dataset */ float * fac = NULL ; /* array of brick scaling factors */ float * fout = NULL ; /* will be array of output floats */ float * dtr = NULL ; /* will be array of detrending coeff */ float val , d0fac , d1fac , x0,x1; double tzero=0 , tdelta , ts_mean , ts_slope ; int ii , old_datum , nuse , use_fac , iz,izold, nxy,nvox , nbad ; register int kk ; void (*ufunc)(double,double,int,float *,double,double,void *,float *) = (void (*)(double,double,int,float *,double,double,void *,float *)) user_func ; /*----------------------------------------------------------*/ /*----- Check inputs to see if they are reasonable-ish -----*/ if( ! ISVALID_3DIM_DATASET(old_dset) ) return NULL ; if( new_datum >= 0 && new_datum != MRI_byte && new_datum != MRI_short && new_datum != MRI_float ) return NULL ; if( user_func == NULL ) return NULL ; if( ignore < 0 ) ignore = 0 ; /*--------- set up pointers to each sub-brick in the input dataset ---------*/ old_datum = DSET_BRICK_TYPE( old_dset , 0 ) ; /* get old dataset datum */ nuse = DSET_NUM_TIMES(old_dset) - ignore ; /* # of points on time axis */ if( nuse < 2 ) return NULL ; if( new_datum < 0 ) new_datum = old_datum ; /* output datum = input */ if( new_datum == MRI_complex ) return NULL ; /* but complex = bad news */ DSET_load( old_dset ) ; /* must be in memory before we get pointers to it */ kk = THD_count_databricks( old_dset->dblk ) ; /* check if it was */ if( kk < DSET_NVALS(old_dset) ){ /* loaded correctly */ DSET_unload( old_dset ) ; return NULL ; } switch( old_datum ){ /* pointer type depends on input datum type */ default: /** don't know what to do **/ DSET_unload( old_dset ) ; return NULL ; /** create array of pointers into old dataset sub-bricks **/ /*--------- input is bytes ----------*/ /* voxel #i at time #k is bptr[k][i] */ /* for i=0..nvox-1 and k=0..nuse-1. */ case MRI_byte: bptr = (byte **) malloc( sizeof(byte *) * nuse ) ; if( bptr == NULL ) return NULL ; for( kk=0 ; kk < nuse ; kk++ ) bptr[kk] = (byte *) DSET_ARRAY(old_dset,kk+ignore) ; break ; /*--------- input is shorts ---------*/ /* voxel #i at time #k is sptr[k][i] */ /* for i=0..nvox-1 and k=0..nuse-1. */ case MRI_short: sptr = (short **) malloc( sizeof(short *) * nuse ) ; if( sptr == NULL ) return NULL ; for( kk=0 ; kk < nuse ; kk++ ) sptr[kk] = (short *) DSET_ARRAY(old_dset,kk+ignore) ; break ; /*--------- input is floats ---------*/ /* voxel #i at time #k is fptr[k][i] */ /* for i=0..nvox-1 and k=0..nuse-1. */ case MRI_float: fptr = (float **) malloc( sizeof(float *) * nuse ) ; if( fptr == NULL ) return NULL ; for( kk=0 ; kk < nuse ; kk++ ) fptr[kk] = (float *) DSET_ARRAY(old_dset,kk+ignore) ; break ; /*--------- input is complex ---------*/ /* voxel #i at time #k is cptr[k][i] */ /* for i=0..nvox-1 and k=0..nuse-1. */ case MRI_complex: cptr = (complex **) malloc( sizeof(complex *) * nuse ) ; if( cptr == NULL ) return NULL ; for( kk=0 ; kk < nuse ; kk++ ) cptr[kk] = (complex *) DSET_ARRAY(old_dset,kk+ignore) ; break ; } /* end of switch on input type */ /*---- allocate space for 1 voxel timeseries ----*/ fxar = (float *) malloc( sizeof(float) * nuse ) ; /* voxel timeseries */ if( fxar == NULL ){ FREE_WORKSPACE ; return NULL ; } /*--- get scaling factors for sub-bricks ---*/ fac = (float *) malloc( sizeof(float) * nuse ) ; /* factors */ if( fac == NULL ){ FREE_WORKSPACE ; return NULL ; } use_fac = 0 ; for( kk=0 ; kk < nuse ; kk++ ){ fac[kk] = DSET_BRICK_FACTOR(old_dset,kk+ignore) ; if( fac[kk] != 0.0 ) use_fac++ ; else fac[kk] = 1.0 ; } if( !use_fac ) FREEUP(fac) ; /*--- setup for detrending ---*/ dtr = (float *) malloc( sizeof(float) * nuse ) ; if( dtr == NULL ){ FREE_WORKSPACE ; return NULL ; } d0fac = 1.0 / nuse ; d1fac = 12.0 / nuse / (nuse*nuse - 1.0) ; for( kk=0 ; kk < nuse ; kk++ ) dtr[kk] = kk - 0.5 * (nuse-1) ; /* linear trend, orthogonal to 1 */ /*---------------------- make a new dataset ----------------------*/ new_dset = EDIT_empty_copy( old_dset ) ; /* start with copy of old one */ /*-- edit some of its internal parameters --*/ ii = EDIT_dset_items( new_dset , ADN_prefix , new_prefix , /* filename prefix */ ADN_malloc_type , DATABLOCK_MEM_MALLOC , /* store in memory */ ADN_datum_all , new_datum , /* atomic datum */ ADN_nvals , 1 , /* # sub-bricks */ ADN_ntt , 0 , /* # time points */ ADN_type , ISHEAD(old_dset) /* dataset type */ ? HEAD_FUNC_TYPE : GEN_FUNC_TYPE , ADN_func_type , FUNC_FIM_TYPE , /* function type */ ADN_none ) ; if( ii != 0 ){ ERROR_message("Error creating dataset '%s'",new_prefix) ; THD_delete_3dim_dataset( new_dset , False ) ; /* some error above */ FREE_WORKSPACE ; return NULL ; } /*------ make floating point output brick (only at the end will scale to byte or shorts) ------*/ nvox = old_dset->daxes->nxx * old_dset->daxes->nyy * old_dset->daxes->nzz ; fout = (float *) malloc( sizeof(float) * nvox ) ; /* ptr to brick */ if( fout == NULL ){ THD_delete_3dim_dataset( new_dset , False ) ; FREE_WORKSPACE ; return NULL ; } /*----- set up to find time at each voxel -----*/ tdelta = old_dset->taxis->ttdel ; if( DSET_TIMEUNITS(old_dset) == UNITS_MSEC_TYPE ) tdelta *= 0.001 ; if( tdelta == 0.0 ) tdelta = 1.0 ; izold = -666 ; nxy = old_dset->daxes->nxx * old_dset->daxes->nyy ; /*----------------------------------------------------*/ /*----- Setup has ended. Now do some real work. -----*/ /* start notification */ #if 0 user_func( 0.0 , 0.0 , nvox , NULL,0.0,0.0 , user_data , NULL ) ; #else ufunc( 0.0 , 0.0 , nvox , NULL,0.0,0.0 , user_data , NULL ) ; #endif /***** loop over voxels *****/ for( ii=0 ; ii < nvox ; ii++ ){ /* 1 time series at a time */ /*** load data from input dataset, depending on type ***/ switch( old_datum ){ /*** input = bytes ***/ case MRI_byte: for( kk=0 ; kk < nuse ; kk++ ) fxar[kk] = bptr[kk][ii] ; break ; /*** input = shorts ***/ case MRI_short: for( kk=0 ; kk < nuse ; kk++ ) fxar[kk] = sptr[kk][ii] ; break ; /*** input = floats ***/ case MRI_float: for( kk=0 ; kk < nuse ; kk++ ) fxar[kk] = fptr[kk][ii] ; break ; /*** input = complex (note we use absolute value) ***/ case MRI_complex: for( kk=0 ; kk < nuse ; kk++ ) fxar[kk] = CABS(cptr[kk][ii]) ; break ; } /* end of switch over input type */ /*** scale? ***/ if( use_fac ) for( kk=0 ; kk < nuse ; kk++ ) fxar[kk] *= fac[kk] ; /** compute mean and slope **/ x0 = x1 = 0.0 ; for( kk=0 ; kk < nuse ; kk++ ){ x0 += fxar[kk] ; x1 += fxar[kk] * dtr[kk] ; } x0 *= d0fac ; x1 *= d1fac ; /* factors to remove mean and trend */ ts_mean = x0 ; ts_slope = x1 / tdelta ; /** detrend? **/ if( detrend ) for( kk=0 ; kk < nuse ; kk++ ) fxar[kk] -= (x0 + x1 * dtr[kk]) ; /** compute start time of this timeseries **/ iz = ii / nxy ; /* which slice am I in? */ if( iz != izold ){ /* in a new slice? */ tzero = THD_timeof( ignore , old_dset->daxes->zzorg + iz*old_dset->daxes->zzdel , old_dset->taxis ) ; izold = iz ; if( DSET_TIMEUNITS(old_dset) == UNITS_MSEC_TYPE ) tzero *= 0.001 ; } /*** compute output ***/ #if 0 user_func( tzero,tdelta , nuse,fxar,ts_mean,ts_slope , user_data , fout+ii ) ; #else ufunc( tzero,tdelta , nuse,fxar,ts_mean,ts_slope , user_data , fout+ii ) ; #endif } /* end of outer loop over 1 voxels at a time */ DSET_unload( old_dset ) ; /* don't need this no more */ /* end notification */ #if 0 user_func( 0.0 , 0.0 , 0 , NULL,0.0,0.0 , user_data , NULL ) ; #else ufunc( 0.0 , 0.0 , 0 , NULL,0.0,0.0 , user_data , NULL ) ; #endif nbad = thd_floatscan( nvox , fout ) ; /* 08 Aug 2000 */ if( nbad > 0 ) fprintf(stderr, "++ Warning: %d bad floats computed in MAKER_4D_to_typed_fim\n\a", nbad ) ; /*------------------------------------------------------------*/ /*------- The output is now in fout[ii], ii=0..nvox-1. We must now put this into the output dataset -------*/ switch( new_datum ){ /*** output is floats is the simplest: we just have to attach the fout brick to the dataset ***/ case MRI_float: EDIT_substitute_brick( new_dset , 0 , MRI_float , fout ) ; fout = NULL ; /* so it won't be freed later */ break ; /*** output is shorts: we have to create a scaled sub-brick from fout ***/ case MRI_short:{ short * bout ; float sfac ; /*-- get output sub-brick --*/ bout = (short *) malloc( sizeof(short) * nvox ) ; if( bout == NULL ){ fprintf(stderr, "\nFinal malloc error in MAKER_4D_to_fim - is memory exhausted?\n\a"); EXIT(1) ; } /*-- find scaling and then scale --*/ sfac = MCW_vol_amax( nvox,1,1 , MRI_float , fout ) ; if( sfac > 0.0 ){ sfac = 32767.0 / sfac ; EDIT_coerce_scale_type( nvox,sfac , MRI_float,fout , MRI_short,bout ) ; sfac = 1.0 / sfac ; } /*-- put output brick into dataset, and store scale factor --*/ EDIT_substitute_brick( new_dset , 0 , MRI_short , bout ) ; EDIT_dset_items( new_dset , ADN_brick_fac , &sfac , ADN_none ) ; } break ; /*** output is bytes (byte = unsigned char) we have to create a scaled sub-brick from fout ***/ case MRI_byte:{ byte * bout ; float sfac ; /*-- get output sub-brick --*/ bout = (byte *) malloc( sizeof(byte) * nvox ) ; if( bout == NULL ){ fprintf(stderr, "\nFinal malloc error in MAKER_4D_to_fim - is memory exhausted?\n\a"); EXIT(1) ; } /*-- find scaling and then scale --*/ sfac = MCW_vol_amax( nvox,1,1 , MRI_float , fout ) ; if( sfac > 0.0 ){ sfac = 255.0 / sfac ; EDIT_coerce_scale_type( nvox,sfac , MRI_float,fout , MRI_byte,bout ) ; sfac = 1.0 / sfac ; } /*-- put output brick into dataset, and store scale factor --*/ EDIT_substitute_brick( new_dset , 0 , MRI_byte , bout ) ; EDIT_dset_items( new_dset , ADN_brick_fac , &sfac , ADN_none ) ; } break ; } /* end of switch on output data type */ /*-------------- Cleanup and go home ----------------*/ FREE_WORKSPACE ; return new_dset ; }
int WB_netw_corr(int Do_r, int Do_Z, int HAVE_ROIS, char *prefix, int NIFTI_OUT, int *NROI_REF, int *Dim, double ***ROI_AVE_TS, int **ROI_LABELS_REF, THD_3dim_dataset *insetTIME, byte *mskd2, int Nmask, int argc, char *argv[]) { int i,j,k; float **AVE_TS_fl=NULL; // not great, but another format of TS char OUT_indiv0[300]; char OUT_indiv[300]; char OUT_indivZ[300]; MRI_IMAGE *mri=NULL; THD_3dim_dataset *OUT_CORR_MAP=NULL; THD_3dim_dataset *OUT_Z_MAP=NULL; float *zscores=NULL; int Nvox; Nvox = Dim[0]*Dim[1]*Dim[2]; // make average time series per voxel AVE_TS_fl = calloc( 1,sizeof(AVE_TS_fl)); for(i=0 ; i<1 ; i++) AVE_TS_fl[i] = calloc(Dim[3],sizeof(float)); if( (AVE_TS_fl == NULL) ) { fprintf(stderr, "\n\n MemAlloc failure (time series out).\n\n"); exit(123); } fprintf(stderr,"\nHAVE_ROIS=%d",HAVE_ROIS); for( k=0 ; k<HAVE_ROIS ; k++) { // each netw gets own file sprintf(OUT_indiv0,"%s_%03d_INDIV", prefix, k); mkdir(OUT_indiv0, 0777); for( i=0 ; i<NROI_REF[k] ; i++ ) { fprintf(stderr,"\nNROI_REF[%d]= %d",k,NROI_REF[k]); for( j=0 ; j<Dim[3] ; j++) AVE_TS_fl[0][j] = (float) ROI_AVE_TS[k][i][j]; if( NIFTI_OUT ) sprintf(OUT_indiv,"%s/WB_CORR_ROI_%03d.nii.gz", OUT_indiv0,ROI_LABELS_REF[k][i+1]); else sprintf(OUT_indiv,"%s/WB_CORR_ROI_%03d", OUT_indiv0,ROI_LABELS_REF[k][i+1]); mri = mri_float_arrays_to_image(AVE_TS_fl,Dim[3],1); OUT_CORR_MAP = THD_Tcorr1D(insetTIME, mskd2, Nmask, mri, "pearson", OUT_indiv); if(Do_r){ THD_load_statistics(OUT_CORR_MAP); tross_Copy_History( insetTIME , OUT_CORR_MAP ) ; tross_Make_History( "3dNetcorr", argc, argv, OUT_CORR_MAP ); if( !THD_ok_overwrite() && THD_is_ondisk(DSET_HEADNAME(OUT_CORR_MAP)) ) ERROR_exit("Can't overwrite existing dataset '%s'", DSET_HEADNAME(OUT_CORR_MAP)); THD_write_3dim_dataset(NULL, NULL, OUT_CORR_MAP, True); INFO_message("Wrote dataset: %s\n",DSET_BRIKNAME(OUT_CORR_MAP)); } if(Do_Z){ if( NIFTI_OUT ) sprintf(OUT_indivZ,"%s/WB_Z_ROI_%03d.nii.gz", OUT_indiv0,ROI_LABELS_REF[k][i+1]); else sprintf(OUT_indivZ,"%s/WB_Z_ROI_%03d", OUT_indiv0,ROI_LABELS_REF[k][i+1]); OUT_Z_MAP = EDIT_empty_copy(OUT_CORR_MAP); EDIT_dset_items( OUT_Z_MAP, ADN_nvals, 1, ADN_datum_all , MRI_float , ADN_prefix , OUT_indivZ, ADN_none ) ; if( !THD_ok_overwrite() && THD_is_ondisk(DSET_HEADNAME(OUT_Z_MAP)) ) ERROR_exit("Can't overwrite existing dataset '%s'", DSET_HEADNAME(OUT_Z_MAP)); zscores = (float *)calloc(Nvox,sizeof(float)); if( (zscores == NULL) ) { fprintf(stderr, "\n\n MemAlloc failure (zscores).\n\n"); exit(123); } for( j=0 ; j<Nvox ; j++ ) if( mskd2[j] ) // control for r ==1 BOBatanhf( THD_get_voxel(OUT_CORR_MAP, j, 0) ); /* if( THD_get_voxel(OUT_CORR_MAP, j, 0) > MAX_R ) zscores[j] = (float) atanh(MAX_R); else if ( THD_get_voxel(OUT_CORR_MAP, j, 0) < -MAX_R ) zscores[j] = (float) atanh(-MAX_R); else zscores[j] = (float) atanh(THD_get_voxel(OUT_CORR_MAP, j, 0));*/ EDIT_substitute_brick(OUT_Z_MAP, 0, MRI_float, zscores); zscores=NULL; THD_load_statistics(OUT_Z_MAP); tross_Copy_History(insetTIME, OUT_Z_MAP); tross_Make_History("3dNetcorr", argc, argv, OUT_Z_MAP); THD_write_3dim_dataset(NULL, NULL, OUT_Z_MAP, True); INFO_message("Wrote dataset: %s\n",DSET_BRIKNAME(OUT_Z_MAP)); DSET_delete(OUT_Z_MAP); free(OUT_Z_MAP); OUT_Z_MAP=NULL; } DSET_delete(OUT_CORR_MAP); free(OUT_CORR_MAP); OUT_CORR_MAP=NULL; } } free(zscores); mri_free(mri); for( i=0 ; i<1 ; i++) free(AVE_TS_fl[i]); free(AVE_TS_fl); RETURN(1); }
int main( int argc , char *argv[] ) { char *prefix = "Deghost" ; int iarg ; int fe=1 , pe=2 , se=3 , nvals ; THD_3dim_dataset *inset=NULL , *outset , *filset=NULL ; if( argc < 2 || strcmp(argv[1],"-help") == 0 ) { printf( "Usage: 3dDeghost [options] dataset\n" "\n" "* This program tries do remove N/2 (AKA Nyquist) ghosts from an EPI\n" " magnitude time series dataset.\n" "* If you apply it to some other kind of dataset (e.g., spiral), weird\n" " things will probably transpire.\n" "* The input EPI dataset should NOT be filtered, masked, cropped,\n" " registered, or pre-processed in any way!\n" "* This program will not work well if the input EPI dataset is heavily\n" " 'shaded' -- that is, its intensity varies dramatically inside the brain.\n" "* The output dataset is always stored in float format.\n" "* Only the Amitabha Buddha knows if this program is actually useful.\n" "\n" "========\n" "OPTIONS:\n" "========\n" " -input dataset = Another way to specify the input dataset\n" " -prefix pp = Use 'pp' for prefix of output dataset\n" " -FPS abc = Define the Frequency, Phase, and Slice\n" " directions in the dataset based on the\n" " axis orientations inside the dataset header\n" " (e.g., see the output of 3dinfo). The 'abc'\n" " code is a permutaton of the digits '123'.\n" " * The first digit 'a' specifies which dataset\n" " axis/index is the Frequency encoding direction.\n" " * The second digit 'b' specifies which dataset\n" " direction is the Phase encoding direction.\n" " * The third digit 'c' specifies which dataset\n" " direction is the Slice encoding direction.\n" " -->>** The default value for 'abc' is '123'; that is,\n" " the dataset is ordered so that the first index\n" " (x-axis) is frequency, the second index is phase,\n" " and the third index is slice. In most cases,\n" " this is how the reconstruction software will\n" " store the images. Only in unusual cases should\n" " you need the '-FPS' option!\n" " -filt N = Length of time series filter to apply when\n" " estimating ghosting parameters. Set N to 0 or 1\n" " to turn this feature off; otherwise, N should be an\n" " odd positive integer from 3 to 19 [default N=%d].\n" " * Longer filter lengths ARE allowed, but will be slow\n" " (cases with N <= 19 are hand coded for speed).\n" " * Datasets with fewer than 4 time points will not\n" " be filtered. For longer datasets, if the filter\n" " length is too big, it will be shortened ruthlessly.\n" "=======\n" "METHOD:\n" "=======\n" "Would you believe me if I said magic? Would you accept secret algorithms\n" "known only to the Olmecs? How about something so ad hoc that it cannot\n" "be described without embarrasment and shame?\n" "\n" "-- Feb 2014 - Zhark the Phantasmal\n" , orfilt_len ) ; PRINT_COMPILE_DATE ; exit(0) ; } mainENTRY("3dDeghost main"); machdep(); AFNI_logger("3dDeghost",argc,argv); PRINT_VERSION("3dDeghost") ; /*-- scan command line --*/ iarg = 1 ; while( iarg < argc && argv[iarg][0] == '-' ) { /*---*/ if( strcasecmp(argv[iarg],"-quiet") == 0 ) { verb = 0 ; iarg++ ; continue ; } if( strcasecmp(argv[iarg],"-verb") == 0 ) { verb++ ; iarg++ ; continue ; } /*---*/ if( strcasecmp(argv[iarg],"-filt") == 0 ) { if( ++iarg >= argc ) ERROR_exit("Need argument after option '%s'",argv[iarg-1]) ; orfilt_len = (int)strtod(argv[iarg],NULL) ; if( orfilt_len > 1 && orfilt_len%2 == 0 ) { orfilt_len++ ; INFO_message("-filt %d has been adjusted to %d (must be odd)" , orfilt_len-1 , orfilt_len) ; } if( orfilt_len > 19 ) WARNING_message("-filt %d is over the recommended limit of 19",orfilt_len) ; iarg++ ; continue ; } /*---*/ if( strcasecmp(argv[iarg],"-prefix") == 0 ) { if( ++iarg >= argc ) ERROR_exit("Need argument after option '%s'",argv[iarg-1]) ; prefix = argv[iarg] ; if( !THD_filename_ok(prefix) ) ERROR_exit("Illegal value after -prefix!\n"); iarg++ ; continue ; } /*---*/ if( strcasecmp(argv[iarg],"-input") == 0 || strcasecmp(argv[iarg],"-inset") == 0 ) { if( ++iarg >= argc ) ERROR_exit("Need argument after option '%s'",argv[iarg-1]) ; if( inset != NULL ) ERROR_exit("You can't give the input dataset twice!") ; inset = THD_open_dataset( argv[iarg] ) ; CHECK_OPEN_ERROR(inset,argv[iarg]) ; DSET_load(inset) ; CHECK_LOAD_ERROR(inset) ; iarg++ ; continue ; } /*---*/ if( strcasecmp(argv[iarg],"-FPS") == 0 ) { /* stolen from 3dAllineate.c */ char *fps ; if( ++iarg >= argc ) ERROR_exit("Need argument after option '%s'",argv[iarg-1]) ; fps = argv[iarg] ; if( strlen(fps) < 3 ) ERROR_exit("Code '%s' after '%s' is too short", fps , argv[iarg-1] ) ; switch( fps[0] ) { default: ERROR_exit("Illegal '%s' F code '%c' :-(" , argv[iarg-1],fps[0] ); case 'i': case 'I': case 'x': case 'X': case '1': fe = 1; break; case 'j': case 'J': case 'y': case 'Y': case '2': fe = 2; break; case 'k': case 'K': case 'z': case 'Z': case '3': fe = 3; break; } switch( fps[1] ) { default: ERROR_exit("Illegal '%s' P code '%c' :-(" , argv[iarg-1],fps[1] ); case 'i': case 'I': case 'x': case 'X': case '1': pe = 1; break; case 'j': case 'J': case 'y': case 'Y': case '2': pe = 2; break; case 'k': case 'K': case 'z': case 'Z': case '3': pe = 3; break; } switch( fps[2] ) { default: ERROR_exit("Illegal '%s' S code '%c' :-(" , argv[iarg-1],fps[2] ); case 'i': case 'I': case 'x': case 'X': case '1': se = 1; break; case 'j': case 'J': case 'y': case 'Y': case '2': se = 2; break; case 'k': case 'K': case 'z': case 'Z': case '3': se = 3; break; } if( fe+pe+se != 6 ) ERROR_exit("Code '%s' after '%s' is nonsensical", fps , argv[iarg-1] ) ; iarg++ ; continue ; } /*---*/ ERROR_exit("Unknown option: %s\n",argv[iarg]); } if( inset == NULL && iarg >= argc ) ERROR_exit("No dataset name on command line?\n"); /*-- read input if needed --*/ if( inset == NULL ) { inset = THD_open_dataset( argv[iarg] ) ; CHECK_OPEN_ERROR(inset,argv[iarg]) ; DSET_load( inset ) ; CHECK_LOAD_ERROR(inset) ; } /*-- filter input? --*/ nvals = DSET_NVALS(inset) ; if( orfilt_len > nvals/2 ) { orfilt_len = nvals/2 ; if( orfilt_len%2 == 0 ) orfilt_len++ ; } if( orfilt_len > 1 && nvals > 1 ) { MRI_vectim *invect ; int ii ; if( verb ) INFO_message("Filtering input dataset: filter length=%d",orfilt_len) ; invect = THD_dset_to_vectim(inset,NULL,0) ; THD_vectim_applyfunc( invect , orfilt_vector ) ; filset = EDIT_empty_copy( inset ) ; for( ii=0 ; ii < nvals ; ii++ ) EDIT_substitute_brick( filset , ii , MRI_float , NULL ) ; THD_vectim_to_dset( invect , filset ) ; VECTIM_destroy(invect) ; } else { if( verb ) INFO_message("Time series filtering is turned off") ; } /***** outsource the work *****/ outset = THD_deghoster( inset , (filset!=NULL)?filset:inset , pe,fe,se ) ; if( outset == NULL ) ERROR_exit("THD_deghoster fails :-(((") ; if( filset != NULL ) DSET_delete(filset) ; EDIT_dset_items( outset , ADN_prefix,prefix , ADN_none ) ; tross_Copy_History( inset , outset ) ; tross_Make_History( "3dDeghost" , argc,argv , outset ) ; DSET_write(outset) ; WROTE_DSET(outset) ; exit(0) ; }
THD_3dim_dataset * THD_deghoster( THD_3dim_dataset *inset , THD_3dim_dataset *filset, int pe , int fe , int se ) { MRI_IMAGE *medim=NULL , *tim=NULL , *oim=NULL ; float cval, *mar=NULL , *tar=NULL , *oar=NULL ; float *xzero_t=NULL , *thet1_t=NULL , *dparr_t=NULL , t1med,t1bmv; byte *bmask=NULL , *amask=NULL , sm ; int nvox , nx,ny,nz , dp=0,df=0,ds=0 , np=0,nf=0,ns=0,np2,nf2 ; int pp,ff,ss,nfp , ii , ppg , nsm,ism , vv,nv , iim , sskip ; THD_3dim_dataset *outset=NULL ; float iy,iyn ; float_pair mp ; /* create brain mask (bmask) */ medim = THD_median_brick(inset) ; bmask = DEG_automask_image(medim) ; /* brain mask (we hope) */ nx = medim->nx ; ny = medim->ny ; nz = medim->nz ; nvox = medim->nvox ; nv = DSET_NVALS(inset) ; /* estimate noise level from data outside the mask (crudely) */ mar = MRI_FLOAT_PTR(medim) ; cval = THD_cliplevel(medim,CLFRAC) ; for( noise_estimate=0.0f,iim=ii=0 ; ii < nvox ; ii++ ) { if( !bmask[ii] && mar[ii] < cval ) { noise_estimate += mar[ii] ; iim++ ; } } if( iim < 9 ) { FREEUP; /* should not happen */ return NULL; } noise_estimate /= iim ; /* initial estimate of noise level */ if( verb > 1 ) INFO_message("Global crude noise_estimate = %g",noise_estimate) ; /* chop out all sub-threshold voxels (amask) */ amask = (byte *)malloc(sizeof(byte)*nvox) ; /* clipped brain mask */ memcpy(amask,bmask,sizeof(byte)*nvox) ; for( ii=0 ; ii < nvox ; ii++ ) if( amask[ii] && mar[ii] < cval ) amask[ii] = 0 ; /* setting up slice coordinates f,p,s */ if( pe == 1 ) { dp = 1 ; np = nx ; } else if( pe == 2 ) { dp = nx ; np = ny ; } else if( pe == 3 ) { dp = nx*ny ; np = ns ; } if( fe == 1 ) { df = 1 ; nf = nx ; } else if( fe == 2 ) { df = nx ; nf = ny ; } else if( fe == 3 ) { df = nx*ny ; nf = nz ; } if( se == 1 ) { ds = 1 ; ns = nx ; } else if( se == 2 ) { ds = nx ; ns = ny ; } else if( se == 3 ) { ds = nx*ny ; ns = nz ; } #undef IJK #define IJK(f,p,s) ((f)*df+(p)*dp+(s)*ds) nvim = nfp = nf * np ; np2 = np / 2 ; nf2 = nf / 2 ; smask = (byte * )malloc(sizeof(byte) *nfp) ; bvec = (float *)malloc(sizeof(float)*nfp) ; gvec = (float *)malloc(sizeof(float)*nfp) ; xvec = (float *)malloc(sizeof(float)*nfp) ; yvec = (float *)malloc(sizeof(float)*nfp) ; ctvec = (float *)malloc(sizeof(float)*nfp) ; stvec = (float *)malloc(sizeof(float)*nfp) ; bvim = (float *)malloc(sizeof(float)*nvim) ; gvim = (float *)malloc(sizeof(float)*nvim) ; xvim = (float *)malloc(sizeof(float)*nvim) ; yvim = (float *)malloc(sizeof(float)*nvim) ; ctvim = (float *)malloc(sizeof(float)*nvim) ; stvim = (float *)malloc(sizeof(float)*nvim) ; xzero_t = (float *)malloc(sizeof(float)*nv) ; thet1_t = (float *)malloc(sizeof(float)*nv) ; dparr_t = (float *)malloc(sizeof(float)*nv) ; /* copy input to output (will be ghost edited later) */ outset = EDIT_empty_copy(inset) ; for( vv=0 ; vv < nv ; vv++ ) { oim = THD_extract_float_brick(vv,inset) ; oar = MRI_FLOAT_PTR(oim) ; EDIT_BRICK_FACTOR( outset , vv , 0.0f ) ; EDIT_substitute_brick( outset , vv , MRI_float , oar ) ; mri_clear_and_free(oim) ; } /* loop over slices */ for( ss=0 ; ss < ns ; ss++ ) { /* make copy of brain mask in this slice, then edit it down to voxels in the brain whose N/2 point is outside the brain (smask) */ for( iim=nsm=pp=0 ; pp < np ; pp++ ) { if( pp >= np2 ) ppg = pp-np2 ; else ppg = pp+np2 ; for( ff=0 ; ff < nf ; ff++,iim++ ) { smask[iim] = sm = amask[IJK(ff,pp,ss)] && !bmask[IJK(ff,ppg,ss)] ; xvim[iim] = ff-nf2 ; yvim[iim] = pp-np2 ; if( sm ) { xvec[nsm] = xvim[iim]; yvec[nsm] = yvim[iim]; nsm++; } } } if( nsm < nfp/20 ) { /* skip this slice */ if( verb ) INFO_message("deghost: skipping slice #%d -- too few points in smask",ss) ; continue ; } nvec = nsm ; if( verb ) INFO_message("deghost: processing slice #%d",ss) ; /* smask is now the mask of brain voxels whose Nyquist ghost locations are NOT in the brain mask */ /* loop over time points, estimate the ghost correction parameters */ for( vv=0 ; vv < nv ; vv++ ) { tim = THD_extract_float_brick(vv,filset) ; tar = MRI_FLOAT_PTR(tim) ; /* extract the vector of image values in smask, and the vector of image values at the ghost locations */ for( iim=ism=pp=0 ; pp < np ; pp++ ) { if( pp >= np2 ) ppg = pp-np2 ; else ppg = pp+np2 ; for( ff=0 ; ff < nf ; ff++,iim++ ) { bvim[iim] = tar[IJK(ff,pp,ss)] ; gvim[iim] = tar[IJK(ff,ppg,ss)] ; if( smask[iim] ) { bvec[ism] = bvim[iim]; gvec[ism++] = gvim[iim]; } } } /* fit the theta parameters from the smask region and save them */ optimize_theta() ; xzero_t[vv] = theta_par[0] ; thet1_t[vv] = theta_par[1] ; dparr_t[vv] = d_par ; mri_free(tim) ; tim = NULL ; } /* now check the slice parameters for reasonability */ sskip = 0 ; if( nv > 4 ) { orfilt_len = 3 ; orfilt_vector(nv,xzero_t) ; orfilt_vector(nv,thet1_t) ; orfilt_vector(nv,dparr_t) ; qmedmadbmv_float(nv,thet1_t,&t1med,NULL,&t1bmv) ; if( verb ) ININFO_message(" slice #%d -- median(theta1)=%g stdev=%g ratio=%g", ss,t1med,t1bmv,(t1bmv>0.0f)?t1med/t1bmv:0.0f) ; if( t1med == 0.0f || fabsf(t1med) <= 0.111f*t1bmv ) { sskip = 1 ; ININFO_message(" skipping slice #%d -- theta1 too small",ss) ; } } if( sskip ) continue ; /* skip processing this slice */ /* loop over time points, estimate the un-ghosted image */ for( vv=0 ; vv < nv ; vv++ ) { tim = THD_extract_float_brick(vv,inset) ; /* input data for slice */ tar = MRI_FLOAT_PTR(tim) ; oar = DSET_ARRAY(outset,vv) ; /* output data for volume */ /* compute theta at each voxel */ if( thet1_t[vv] == 0.0f ) continue ; /* ghost amplitude is 0 ==> skip this time point */ if( verb > 1 ) ININFO_message(" slice=%d index=%d theta = %g %g %g", ss,vv,xzero_t[vv],thet1_t[vv],dparr_t[vv]) ; theta_par[0] = xzero_t[vv]; theta_par[1] = thet1_t[vv]; d_par = dparr_t[vv]; compute_thvim() ; /* compute output values at each voxel: (a) inside the smask == voxel in brain, N/2 ghost isn't (b) not in the smask but in the bmask == voxel && N/2 ghost are in brain (c) otherwise == voxel is unimportant effluvium */ for( iim=pp=0 ; pp < np ; pp++ ) { if( pp >= np2 ) ppg = pp-np2 ; else ppg = pp+np2 ; for( ff=0 ; ff < nf ; ff++,iim++ ) { iy = tar[IJK(ff,pp,ss)] ; iyn = tar[IJK(ff,ppg,ss)] ; if( smask[iim] ) { oar[IJK(ff,pp,ss)] = find_mhat( iy,iyn , ctvim[iim],stvim[iim] , d_par ) ; oar[IJK(ff,ppg,ss)] = 0.0f ; } else if( bmask[IJK(ff,pp,ss)] && bmask[IJK(ff,ppg,ss)] ) { if( ppg > pp ) { mp = find_mpair( iy,iyn , ctvim[iim],stvim[iim] , d_par ) ; oar[IJK(ff,pp,ss)] = mp.a ; oar[IJK(ff,ppg,ss)] = mp.b ; } } else { /* nada: output is already a copy of input */ } } } } } /* end of loop over slices */ FREEUP ; return outset ; }
/*! Put some help like for function thd_polyfit */ int thd_Acluster ( THD_3dim_dataset *in_set, byte *mask, int nmask, THD_3dim_dataset **clust_set, THD_3dim_dataset **dist_set, OPT_KMEANS oc ) { int ii, nl, nc; double **D=NULL, **distmatrix=NULL; /* this double business is a waste of memory, at least for D..*/ int ncol = -1; float *dvec=NULL; int* clusterid = NULL; short *sc = NULL; ENTRY("thd_Acluster"); if (!clust_set || *clust_set) { fprintf(stderr, "ERROR: output volume pointer pointers must point to NULL\n"); RETURN(0); } if (!mask) nmask = DSET_NVOX(in_set); ncol = DSET_NVALS(in_set); if (ncol < DSET_NUM_TIMES(in_set)) ncol = DSET_NUM_TIMES(in_set); if (oc.verb) { ININFO_message("Have %d/%d voxels to process " "with %d dimensions per voxel.\n", nmask, DSET_NVOX(in_set), ncol); } /* Create data matrix */ D = (double **)calloc(sizeof(double*), nmask); for (ii=0;ii<(nmask);++ii) { if (!(D[ii] = (double *)calloc(sizeof(double), ncol))) { fprintf(stderr,"ERROR: Failed while allocating %dx%d double matrix\n", nmask, ncol); RETURN(0); } } dvec = (float * )malloc(sizeof(float)*ncol) ; /* array to hold series */ if (oc.verb) { ININFO_message("Filling D(%dx%d) (mask=%p).\n", nmask, ncol, mask); } ii = 0; for (nl=0; nl<DSET_NVOX(in_set); ++nl) { if (!mask || mask[nl]) { THD_extract_array( nl , in_set , 0 , dvec ) ; for (nc=0; nc<ncol; ++nc) D[ii][nc] = dvec[nc]; ++ii; } } /* allocate for answer arrays */ if (!(clusterid = (int *)calloc(sizeof(int), nmask))) { fprintf(stderr,"ERROR: Failed to allocate for clusterid\n"); RETURN(0); } /* now do the clustering (ANDREJ: I do not know why the counting skipped 1st row and 1st col....) */ if (oc.k > 0) { if (oc.verb) { ININFO_message("Going to cluster: k=%d, r=%d\n" "distmetric %c, jobname %s\n", oc.k, oc.r, oc.distmetric, oc.jobname); } example_kmeans( nmask, ncol, D, oc.k, oc.r, oc.distmetric, oc.jobname, clusterid); } else if (oc.kh > 0) { if (oc.verb) { ININFO_message("Going to h cluster: kh=%d\n" "jobname %s\n", oc.kh, oc.jobname); } if ((distmatrix = example_distance_gene(nmask, ncol, D))) { example_hierarchical( nmask, ncol, D, oc.jobname, oc.kh, distmatrix, clusterid); /* YOU SHOULD FREE distmatrix here ...*/ } else { ERROR_message("Failed to create distmatrix"); RETURN(0); } } else { ERROR_message("Bad option selection"); RETURN(0); } /* create output datasets, if required*/ *clust_set = EDIT_empty_copy(in_set) ; EDIT_dset_items( *clust_set , ADN_nvals , 1 , ADN_ntt , 1 , ADN_datum_all , MRI_short , ADN_brick_fac , NULL , ADN_prefix , "OML!" , ADN_none ) ; /* MRI_float */ if (oc.verb) { ININFO_message("loading results into %s\n", DSET_PREFIX(*clust_set)); } /* transfer ints in clusterid to shorts array */ sc = (short *)calloc(sizeof(short),DSET_NVOX(in_set)); ii = 0; for (nl=0; nl<DSET_NVOX(in_set); ++nl) { if (!mask || mask[nl]) { sc[nl] = (short)clusterid[ii]+1; ++ii; } } free(clusterid); clusterid = NULL; EDIT_substitute_brick( *clust_set , 0 , MRI_short , sc ) ; sc = NULL; /* array now in brick */ if (oc.verb) { ININFO_message("Freedom"); } if (dvec) free(dvec); dvec=NULL; // To free D for (ii=0;ii<nmask;++ii) { if (D[ii]) free(D[ii]); } free(D); D = NULL; RETURN(1); }
/*! \brief out_set = thd_polyfit( in_set, mask, polorder, prefix, verb); fits a polynomial model of order polorder to the time series of voxels in in_set \param in_set (THD_3dim_dataset* ) An AFNI dset pointer to input data \param mask (byte *) if mask is not NULL then voxel i will be processed if mask[i] != 0. if mask is NULL then all voxels are processed. \param polorder (int) polynomial order \param prefix (char *) prefix of output dset \param verb (int) verbosity flag \return out_set (THD_3dim_dataset* ) Dset containing polynomial fits. */ THD_3dim_dataset *thd_polyfit(THD_3dim_dataset *in_set, byte *mask, int polorder, char *prefix, int verb) { int i=0, j=0, nl=0, k=0, posi=0, posj=0, posk=0, nrow=0, ncol = 0; double xi=0.0, yi=0.0, yy=0.0, ei=0.0, sumsq=0.0, med=0.0; gsl_matrix *X=NULL, *cov=NULL; gsl_vector *y=NULL, *w=NULL, *c=NULL; MRI_IMAGE *im = NULL; THD_3dim_dataset *out_set=NULL; double *dar = NULL; float *cbuf=NULL; float *dvec = NULL; gsl_multifit_linear_workspace *work=NULL; ENTRY("thd_polyfit"); /* prepare output */ out_set = EDIT_empty_copy(in_set) ; EDIT_dset_items( out_set , ADN_nvals , polorder , ADN_ntt , polorder , ADN_datum_all , MRI_float , ADN_brick_fac , NULL , ADN_prefix , prefix ? prefix : "OMG!" , ADN_none ) ; for( j=0 ; j < polorder ; j++ ) /* create empty bricks to be filled below */ EDIT_substitute_brick( out_set , j , MRI_float , NULL ) ; /* do the fitting */ if (verb) fprintf (stderr,"Now fitting...\n"); ncol = DSET_NVALS(in_set); nrow = DSET_NVOX(in_set); X = gsl_matrix_alloc (ncol, polorder); y = gsl_vector_alloc (ncol); c = gsl_vector_alloc (polorder); cov = gsl_matrix_alloc (polorder, polorder); for (i = 0; i < ncol; i++) { xi = i+1; gsl_matrix_set (X, i, 0, 1.0); gsl_matrix_set (X, i, 1, xi); gsl_matrix_set (X, i, 2, xi*xi); gsl_matrix_set (X, i, 3, xi*xi*xi); gsl_matrix_set (X, i, 4, xi*xi*xi*xi); // printf ("%lg ",xi); } /*make header printf ("matrvola\n"); ZSS: By adding # to the text line, I made the output file be a .1D format */ if (verb > 1) fprintf(stdout, "#%s_0\t%s_1\t%s_2\t%s_3\t%s_4\n", DSET_PREFIX(in_set),DSET_PREFIX(in_set), DSET_PREFIX(in_set),DSET_PREFIX(in_set), DSET_PREFIX(in_set)); // go by lines - signatures /* pre-allocate, I think this should be just fine, there should be no need to reinitialize work all the time */ work = gsl_multifit_linear_alloc (ncol, polorder); dvec = (float * )malloc(sizeof(float)*ncol) ; /* array to hold signature */ cbuf = (float *)malloc(sizeof(float)*polorder) ; /* array to hold fit */ for (nl=0; nl<nrow; ++nl) { if (!mask || mask[nl]) { posi = -1; posj = -1; posk = -1; THD_extract_array( nl , in_set , 0 , dvec ) ; /*get signature from voxel */ for (k = 0; k < ncol; k++) { gsl_vector_set (y, k, dvec[k]); } gsl_multifit_linear (X, y, c, cov, &sumsq, work); /* printf ( "\n # best fit: Y = %g + %g X + %g X^2 +%g X^3 + %g X^4\n", C(0), C(1), C(2), C(3), C(4)); printf ("# sumsq = %g\n", sumsq); */ for (i=0;i<polorder;++i) cbuf[i] = (float)C(i); THD_insert_series( nl , out_set , polorder , MRI_float , cbuf , 1 ) ; /* stick result in output */ if (verb > 1) fprintf (stdout, "%11g\t%11g\t%11g\t%11g\t%11g\n", C(0), C(1), C(2), C(3), C(4)); /* printf ("# covariance matrix:\n"); printf ("[ %+.5e, %+.5e, %+.5e \n", COV(0,0), COV(0,1), COV(0,2)); printf (" %+.5e, %+.5e, %+.5e \n", COV(1,0), COV(1,1), COV(1,2)); printf (" %+.5e, %+.5e, %+.5e ]\n", COV(2,0), COV(2,1), COV(2,2)); printf ("# chisq = %g\n", chisq); */ } } gsl_multifit_linear_free (work); work = NULL; free(dvec); dvec = NULL; free(cbuf); cbuf = NULL; gsl_vector_free (y); gsl_vector_free (c); gsl_matrix_free (cov); gsl_matrix_free (X); //gsl_vector_free (w); free(dvec); dvec = NULL; RETURN(out_set); }
char * STAVG_main( PLUGIN_interface * plint ) { MCW_idcode * idc ; /* input dataset idcode */ THD_3dim_dataset * old_dset , * new_dset ; /* input and output datasets */ char * new_prefix , * str , * str2; /* strings from user */ int meth; /* chosen computation method */ int new_datum , /* control parameters */ old_datum , ntime ; int te, ne, tinc, kim, nia; int numepochs, minlength, maxlength, lastindex, navgpts; int nvox , perc , new_units, old_units ; int ii, ibot,itop , kk, jj; int no1, user_maxlength, delta; int *pEpochLength, *pTimeIndex; int nx, ny, nz, npix; float *pNumAvg; float old_dtime; MRI_IMAGE * stimim; MRI_IMARR *avgimar; byte ** bptr = NULL ; /* one of these will be the array of */ short ** sptr = NULL ; /* pointers to input dataset sub-bricks */ float ** fptr = NULL ; /* (depending on input datum type) */ float * fxar = NULL ; /* array loaded from input dataset */ float * stimar = NULL ; float ** fout = NULL ; /* will be array of output floats */ float * tar = NULL ; /* will be array of taper coefficients */ float * nstimar; /*--------------------------------------------------------------------*/ /*----- 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" "*************************" ; ntime = DSET_NUM_TIMES(old_dset) ; if( ntime < 2 ) return "*****************************\n" "Dataset has only 1 time point\n" "*****************************" ; ii = DSET_NVALS_PER_TIME(old_dset) ; if( ii > 1 ) return "************************************\n" "Dataset has > 1 value per time point\n" "************************************" ; old_datum = DSET_BRICK_TYPE( old_dset , 0 ) ; /* get old dataset datum type */ new_datum = old_datum; old_dtime = DSET_TIMESTEP(old_dset); old_units = DSET_TIMEUNITS(old_dset); nvox = old_dset->daxes->nxx * old_dset->daxes->nyy * old_dset->daxes->nzz; npix = old_dset->daxes->nxx * old_dset->daxes->nyy; nx = old_dset->daxes->nxx; new_prefix = PLUTO_get_string(plint) ; /* get string item (the output prefix) */ if( ! PLUTO_prefix_ok(new_prefix) ) /* check if it is OK */ return "************************\n" "Output Prefix is illegal\n" "************************" ; /*--------- go to next input line ---------*/ PLUTO_next_option(plint); stimim = PLUTO_get_timeseries(plint); if( stimim == NULL ) return "Please specify stimulus timing"; if( stimim->nx < ntime ){ return "**************************************\n" "Not enough pts in stimulus time-series\n" "**************************************"; } stimar = MRI_FLOAT_PTR(stimim); delta = PLUTO_get_number(plint); if( abs(delta) > ntime ){ return "************************\n" "Delta shift is too large\n" "************************"; } /*initialize variables if not user specified */ user_maxlength = ntime; no1 = 0; /*--------- go to next input line ---------*/ PLUTO_next_option(plint); str = PLUTO_get_string(plint) ; /* get string item (the method) */ meth = PLUTO_string_index( str , /* find it in list it is from */ _STAVG_NUM_METHODS , method_strings ) ; /*--------- see if the 4th option line is present --------*/ str = PLUTO_get_optiontag( plint ) ; if( str != NULL ){ user_maxlength = (int) PLUTO_get_number(plint) ; str2 = PLUTO_get_string(plint) ; /* get string item (the method) */ no1 = PLUTO_string_index( str2 , /* find it in list it is from */ 2 , yes_no_strings) ; } /*------------------------------------------------------*/ /*---------- At this point, the inputs are OK ----------*/ PLUTO_popup_meter( plint ) ; /* popup a progress meter */ /*________________[ Main Code ]_________________________*/ fout = avg_epochs( old_dset, stimar, user_maxlength, 1, meth, plint ); if( fout == NULL ) return " \nError in avg_epochs() function!\n " ; if( RMB_DEBUG ) fprintf(stderr, "Done with avg_epochs\n"); maxlength = M_maxlength; /*______________________________________________________*/ new_dset = EDIT_empty_copy( old_dset ) ; /* start with copy of old one */ { char * his = PLUTO_commandstring(plint) ; tross_Copy_History( old_dset , new_dset ) ; tross_Append_History( new_dset , his ) ; free( his ) ; } /*-- edit some of its internal parameters --*/ ii = EDIT_dset_items( new_dset , ADN_prefix , new_prefix , /* filename prefix */ ADN_malloc_type , DATABLOCK_MEM_MALLOC , /* store in memory */ ADN_datum_all , new_datum , /* atomic datum */ ADN_nvals , maxlength , /* # sub-bricks */ ADN_ntt , maxlength , /* # time points */ /* ADN_ttorg , old_dtime , */ /* time origin */ /* ADN_ttdel , old_dtime , */ /* time step */ /* ADN_ttdur , old_dtime , */ /* time duration */ /* ADN_nsl , 0 , */ /* z-axis time slicing */ /* ADN_tunits , old_units , */ /* time units */ ADN_none ) ; if( ii != 0 ){ THD_delete_3dim_dataset( new_dset , False ) ; FREE_WORKSPACE ; return "***********************************\n" "Error while creating output dataset\n" "***********************************" ; } /*------------------------------------------------------------*/ /*------- The output is now in fout[kk][ii], for kk=0..maxlength-1 , ii=0..nvox-1. We must now put this into the output dataset -------*/ switch( new_datum ){ /*** output is floats is the simplest: we just have to attach the fout bricks to the dataset ***/ case MRI_float: for( kk=0 ; kk < maxlength ; kk++ ) EDIT_substitute_brick( new_dset , kk , MRI_float , fout[kk] ) ; break ; /*** output is shorts: we have to create a scaled sub-brick from fout ***/ case MRI_short:{ short * bout ; float fac ; for( kk=0 ; kk < maxlength ; kk++ ){ /* loop over sub-bricks */ /*-- get output sub-brick --*/ bout = (short *) malloc( sizeof(short) * nvox ) ; if( bout == NULL ){ fprintf(stderr,"\nFinal malloc error in plug_stavg!\n\a") ; return("Final malloc error in plug_stavg!"); ; /* exit(1) ;*/ } /*-- find scaling and then scale --*/ /*fac = MCW_vol_amax( nvox,1,1 , MRI_float , fout[kk] ) ;*/ fac = 1.0; EDIT_coerce_scale_type( nvox,fac , MRI_float,fout[kk] , MRI_short,bout ) ; free( fout[kk] ) ; /* don't need this anymore */ /*-- put output brick into dataset, and store scale factor --*/ EDIT_substitute_brick( new_dset , kk , MRI_short , bout ) ; } } break ; /*** output is bytes (byte = unsigned char) we have to create a scaled sub-brick from fout ***/ case MRI_byte:{ byte * bout ; float fac ; for( kk=0 ; kk < maxlength ; kk++ ){ /* loop over sub-bricks */ /*-- get output sub-brick --*/ bout = (byte *) malloc( sizeof(byte) * nvox ) ; if( bout == NULL ){ fprintf(stderr,"\nFinal malloc error in plug_stavg!\n\a") ; return("Final malloc error in plug_stavg!"); ; /* exit(1) ;*/ } /*-- find scaling and then scale --*/ fac = 1.0; EDIT_coerce_scale_type( nvox,fac , MRI_float,fout[kk] , MRI_byte,bout ) ; free( fout[kk] ) ; /* don't need this anymore */ /*-- put output brick into dataset, and store scale factor --*/ EDIT_substitute_brick( new_dset , kk , MRI_byte , bout ) ; } } break ; } /* end of switch on output data type */ /*-------------- Cleanup and go home ----------------*/ PLUTO_set_meter( plint , 100 ) ; /* set progress meter to 100% */ PLUTO_add_dset( plint , new_dset , DSET_ACTION_MAKE_CURRENT ) ; FREE_WORKSPACE ; return NULL ; /* null string returned means all was OK */ }
int main( int argc , char * argv[] ) { int do_norm=0 , qdet=2 , have_freq=0 , do_automask=0 ; float dt=0.0f , fbot=0.0f,ftop=999999.9f , blur=0.0f ; MRI_IMARR *ortar=NULL ; MRI_IMAGE *ortim=NULL ; THD_3dim_dataset **ortset=NULL ; int nortset=0 ; THD_3dim_dataset *inset=NULL , *outset ; char *prefix="bandpass" ; byte *mask=NULL ; int mask_nx=0,mask_ny=0,mask_nz=0,nmask , verb=1 , nx,ny,nz,nvox , nfft=0 , kk ; float **vec , **ort=NULL ; int nort=0 , vv , nopt , ntime ; MRI_vectim *mrv ; float pvrad=0.0f ; int nosat=0 ; int do_despike=0 ; /*-- help? --*/ AFNI_SETUP_OMP(0) ; /* 24 Jun 2013 */ if( argc < 2 || strcmp(argv[1],"-help") == 0 ){ printf( "\n" "** NOTA BENE: For the purpose of preparing resting-state FMRI datasets **\n" "** for analysis (e.g., with 3dGroupInCorr), this program is now mostly **\n" "** superseded by the afni_proc.py script. See the 'afni_proc.py -help' **\n" "** section 'Resting state analysis (modern)' to get our current rs-FMRI **\n" "** pre-processing recommended sequence of steps. -- RW Cox, et alii. **\n" "\n" "Usage: 3dBandpass [options] fbot ftop dataset\n" "\n" "* One function of this program is to prepare datasets for input\n" " to 3dSetupGroupInCorr. Other uses are left to your imagination.\n" "\n" "* 'dataset' is a 3D+time sequence of volumes\n" " ++ This must be a single imaging run -- that is, no discontinuities\n" " in time from 3dTcat-ing multiple datasets together.\n" "\n" "* fbot = lowest frequency in the passband, in Hz\n" " ++ fbot can be 0 if you want to do a lowpass filter only;\n" " HOWEVER, the mean and Nyquist freq are always removed.\n" "\n" "* ftop = highest frequency in the passband (must be > fbot)\n" " ++ if ftop > Nyquist freq, then it's a highpass filter only.\n" "\n" "* Set fbot=0 and ftop=99999 to do an 'allpass' filter.\n" " ++ Except for removal of the 0 and Nyquist frequencies, that is.\n" "\n" "* You cannot construct a 'notch' filter with this program!\n" " ++ You could use 3dBandpass followed by 3dcalc to get the same effect.\n" " ++ If you are understand what you are doing, that is.\n" " ++ Of course, that is the AFNI way -- if you don't want to\n" " understand what you are doing, use Some other PrograM, and\n" " you can still get Fine StatisticaL maps.\n" "\n" "* 3dBandpass will fail if fbot and ftop are too close for comfort.\n" " ++ Which means closer than one frequency grid step df,\n" " where df = 1 / (nfft * dt) [of course]\n" "\n" "* The actual FFT length used will be printed, and may be larger\n" " than the input time series length for the sake of efficiency.\n" " ++ The program will use a power-of-2, possibly multiplied by\n" " a power of 3 and/or 5 (up to and including the 3rd power of\n" " each of these: 3, 9, 27, and 5, 25, 125).\n" "\n" "* Note that the results of combining 3dDetrend and 3dBandpass will\n" " depend on the order in which you run these programs. That's why\n" " 3dBandpass has the '-ort' and '-dsort' options, so that the\n" " time series filtering can be done properly, in one place.\n" "\n" "* The output dataset is stored in float format.\n" "\n" "* The order of processing steps is the following (most are optional):\n" " (0) Check time series for initial transients [does not alter data]\n" " (1) Despiking of each time series\n" " (2) Removal of a constant+linear+quadratic trend in each time series\n" " (3) Bandpass of data time series\n" " (4) Bandpass of -ort time series, then detrending of data\n" " with respect to the -ort time series\n" " (5) Bandpass and de-orting of the -dsort dataset,\n" " then detrending of the data with respect to -dsort\n" " (6) Blurring inside the mask [might be slow]\n" " (7) Local PV calculation [WILL be slow!]\n" " (8) L2 normalization [will be fast.]\n" "\n" "--------\n" "OPTIONS:\n" "--------\n" " -despike = Despike each time series before other processing.\n" " ++ Hopefully, you don't actually need to do this,\n" " which is why it is optional.\n" " -ort f.1D = Also orthogonalize input to columns in f.1D\n" " ++ Multiple '-ort' options are allowed.\n" " -dsort fset = Orthogonalize each voxel to the corresponding\n" " voxel time series in dataset 'fset', which must\n" " have the same spatial and temporal grid structure\n" " as the main input dataset.\n" " ++ At present, only one '-dsort' option is allowed.\n" " -nodetrend = Skip the quadratic detrending of the input that\n" " occurs before the FFT-based bandpassing.\n" " ++ You would only want to do this if the dataset\n" " had been detrended already in some other program.\n" " -dt dd = set time step to 'dd' sec [default=from dataset header]\n" " -nfft N = set the FFT length to 'N' [must be a legal value]\n" " -norm = Make all output time series have L2 norm = 1\n" " ++ i.e., sum of squares = 1\n" " -mask mset = Mask dataset\n" " -automask = Create a mask from the input dataset\n" " -blur fff = Blur (inside the mask only) with a filter\n" " width (FWHM) of 'fff' millimeters.\n" " -localPV rrr = Replace each vector by the local Principal Vector\n" " (AKA first singular vector) from a neighborhood\n" " of radius 'rrr' millimiters.\n" " ++ Note that the PV time series is L2 normalized.\n" " ++ This option is mostly for Bob Cox to have fun with.\n" "\n" " -input dataset = Alternative way to specify input dataset.\n" " -band fbot ftop = Alternative way to specify passband frequencies.\n" "\n" " -prefix ppp = Set prefix name of output dataset.\n" " -quiet = Turn off the fun and informative messages. (Why?)\n" "\n" " -notrans = Don't check for initial positive transients in the data:\n" " *OR* ++ The test is a little slow, so skipping it is OK,\n" " -nosat if you KNOW the data time series are transient-free.\n" " ++ Or set AFNI_SKIP_SATCHECK to YES.\n" " ++ Initial transients won't be handled well by the\n" " bandpassing algorithm, and in addition may seriously\n" " contaminate any further processing, such as inter-voxel\n" " correlations via InstaCorr.\n" " ++ No other tests are made [yet] for non-stationary behavior\n" " in the time series data.\n" ) ; PRINT_AFNI_OMP_USAGE( "3dBandpass" , "* At present, the only part of 3dBandpass that is parallelized is the\n" " '-blur' option, which processes each sub-brick independently.\n" ) ; PRINT_COMPILE_DATE ; exit(0) ; } /*-- startup --*/ mainENTRY("3dBandpass"); machdep(); AFNI_logger("3dBandpass",argc,argv); PRINT_VERSION("3dBandpass"); AUTHOR("RW Cox"); nosat = AFNI_yesenv("AFNI_SKIP_SATCHECK") ; nopt = 1 ; while( nopt < argc && argv[nopt][0] == '-' ){ if( strcmp(argv[nopt],"-despike") == 0 ){ /* 08 Oct 2010 */ do_despike++ ; nopt++ ; continue ; } if( strcmp(argv[nopt],"-nfft") == 0 ){ int nnup ; if( ++nopt >= argc ) ERROR_exit("need an argument after -nfft!") ; nfft = (int)strtod(argv[nopt],NULL) ; nnup = csfft_nextup_even(nfft) ; if( nfft < 16 || nfft != nnup ) ERROR_exit("value %d after -nfft is illegal! Next legal value = %d",nfft,nnup) ; nopt++ ; continue ; } if( strcmp(argv[nopt],"-blur") == 0 ){ if( ++nopt >= argc ) ERROR_exit("need an argument after -blur!") ; blur = strtod(argv[nopt],NULL) ; if( blur <= 0.0f ) WARNING_message("non-positive blur?!") ; nopt++ ; continue ; } if( strcmp(argv[nopt],"-localPV") == 0 ){ if( ++nopt >= argc ) ERROR_exit("need an argument after -localpv!") ; pvrad = strtod(argv[nopt],NULL) ; if( pvrad <= 0.0f ) WARNING_message("non-positive -localpv?!") ; nopt++ ; continue ; } if( strcmp(argv[nopt],"-prefix") == 0 ){ if( ++nopt >= argc ) ERROR_exit("need an argument after -prefix!") ; prefix = strdup(argv[nopt]) ; if( !THD_filename_ok(prefix) ) ERROR_exit("bad -prefix option!") ; nopt++ ; continue ; } if( strcmp(argv[nopt],"-automask") == 0 ){ if( mask != NULL ) ERROR_exit("Can't use -mask AND -automask!") ; do_automask = 1 ; nopt++ ; continue ; } if( strcmp(argv[nopt],"-mask") == 0 ){ THD_3dim_dataset *mset ; if( ++nopt >= argc ) ERROR_exit("Need argument after '-mask'") ; if( mask != NULL || do_automask ) ERROR_exit("Can't have two mask inputs") ; mset = THD_open_dataset( argv[nopt] ) ; CHECK_OPEN_ERROR(mset,argv[nopt]) ; DSET_load(mset) ; CHECK_LOAD_ERROR(mset) ; mask_nx = DSET_NX(mset); mask_ny = DSET_NY(mset); mask_nz = DSET_NZ(mset); mask = THD_makemask( mset , 0 , 0.5f, 0.0f ) ; DSET_delete(mset) ; if( mask == NULL ) ERROR_exit("Can't make mask from dataset '%s'",argv[nopt]) ; nmask = THD_countmask( mask_nx*mask_ny*mask_nz , mask ) ; if( verb ) INFO_message("Number of voxels in mask = %d",nmask) ; if( nmask < 1 ) ERROR_exit("Mask is too small to process") ; nopt++ ; continue ; } if( strcmp(argv[nopt],"-norm") == 0 ){ do_norm = 1 ; nopt++ ; continue ; } if( strcmp(argv[nopt],"-quiet") == 0 ){ verb = 0 ; nopt++ ; continue ; } if( strcmp(argv[nopt],"-notrans") == 0 || strcmp(argv[nopt],"-nosat") == 0 ){ nosat = 1 ; nopt++ ; continue ; } if( strcmp(argv[nopt],"-ort") == 0 ){ if( ++nopt >= argc ) ERROR_exit("need an argument after -ort!") ; if( ortar == NULL ) INIT_IMARR(ortar) ; ortim = mri_read_1D( argv[nopt] ) ; if( ortim == NULL ) ERROR_exit("can't read from -ort '%s'",argv[nopt]) ; mri_add_name(argv[nopt],ortim) ; ADDTO_IMARR(ortar,ortim) ; nopt++ ; continue ; } if( strcmp(argv[nopt],"-dsort") == 0 ){ THD_3dim_dataset *qset ; if( ++nopt >= argc ) ERROR_exit("need an argument after -dsort!") ; if( nortset > 0 ) ERROR_exit("only 1 -dsort option is allowed!") ; qset = THD_open_dataset(argv[nopt]) ; CHECK_OPEN_ERROR(qset,argv[nopt]) ; ortset = (THD_3dim_dataset **)realloc(ortset, sizeof(THD_3dim_dataset *)*(nortset+1)) ; ortset[nortset++] = qset ; nopt++ ; continue ; } if( strncmp(argv[nopt],"-nodetrend",6) == 0 ){ qdet = 0 ; nopt++ ; continue ; } if( strcmp(argv[nopt],"-dt") == 0 ){ if( ++nopt >= argc ) ERROR_exit("need an argument after -dt!") ; dt = (float)strtod(argv[nopt],NULL) ; if( dt <= 0.0f ) WARNING_message("value after -dt illegal!") ; nopt++ ; continue ; } if( strcmp(argv[nopt],"-input") == 0 ){ if( inset != NULL ) ERROR_exit("Can't have 2 -input options!") ; if( ++nopt >= argc ) ERROR_exit("need an argument after -input!") ; inset = THD_open_dataset(argv[nopt]) ; CHECK_OPEN_ERROR(inset,argv[nopt]) ; nopt++ ; continue ; } if( strncmp(argv[nopt],"-band",5) == 0 ){ if( ++nopt >= argc-1 ) ERROR_exit("need 2 arguments after -band!") ; if( have_freq ) WARNING_message("second -band option replaces first one!") ; fbot = strtod(argv[nopt++],NULL) ; ftop = strtod(argv[nopt++],NULL) ; have_freq = 1 ; continue ; } ERROR_exit("Unknown option: '%s'",argv[nopt]) ; } /** check inputs for reasonablositiness **/ if( !have_freq ){ if( nopt+1 >= argc ) ERROR_exit("Need frequencies on command line after options!") ; fbot = (float)strtod(argv[nopt++],NULL) ; ftop = (float)strtod(argv[nopt++],NULL) ; } if( inset == NULL ){ if( nopt >= argc ) ERROR_exit("Need input dataset name on command line after options!") ; inset = THD_open_dataset(argv[nopt]) ; CHECK_OPEN_ERROR(inset,argv[nopt]) ; nopt++ ; } DSET_UNMSEC(inset) ; if( fbot < 0.0f ) ERROR_exit("fbot value can't be negative!") ; if( ftop <= fbot ) ERROR_exit("ftop value %g must be greater than fbot value %g!",ftop,fbot) ; ntime = DSET_NVALS(inset) ; if( ntime < 9 ) ERROR_exit("Input dataset is too short!") ; if( nfft <= 0 ){ nfft = csfft_nextup_even(ntime) ; if( verb ) INFO_message("Data length = %d FFT length = %d",ntime,nfft) ; (void)THD_bandpass_set_nfft(nfft) ; } else if( nfft < ntime ){ ERROR_exit("-nfft %d is less than data length = %d",nfft,ntime) ; } else { kk = THD_bandpass_set_nfft(nfft) ; if( kk != nfft && verb ) INFO_message("Data length = %d FFT length = %d",ntime,kk) ; } if( dt <= 0.0f ){ dt = DSET_TR(inset) ; if( dt <= 0.0f ){ WARNING_message("Setting dt=1.0 since input dataset lacks a time axis!") ; dt = 1.0f ; } } if( !THD_bandpass_OK(ntime,dt,fbot,ftop,1) ) ERROR_exit("Can't continue!") ; nx = DSET_NX(inset); ny = DSET_NY(inset); nz = DSET_NZ(inset); nvox = nx*ny*nz; /* check mask, or create it */ if( verb ) INFO_message("Loading input dataset time series" ) ; DSET_load(inset) ; if( mask != NULL ){ if( mask_nx != nx || mask_ny != ny || mask_nz != nz ) ERROR_exit("-mask dataset grid doesn't match input dataset") ; } else if( do_automask ){ mask = THD_automask( inset ) ; if( mask == NULL ) ERROR_message("Can't create -automask from input dataset?") ; nmask = THD_countmask( DSET_NVOX(inset) , mask ) ; if( verb ) INFO_message("Number of voxels in automask = %d",nmask); if( nmask < 1 ) ERROR_exit("Automask is too small to process") ; } else { mask = (byte *)malloc(sizeof(byte)*nvox) ; nmask = nvox ; memset(mask,1,sizeof(byte)*nvox) ; if( verb ) INFO_message("No mask ==> processing all %d voxels",nvox); } /* A simple check of dataset quality [08 Feb 2010] */ if( !nosat ){ float val ; INFO_message( "Checking dataset for initial transients [use '-notrans' to skip this test]") ; val = THD_saturation_check(inset,mask,0,0) ; kk = (int)(val+0.54321f) ; if( kk > 0 ) ININFO_message( "Looks like there %s %d non-steady-state initial time point%s :-(" , ((kk==1) ? "is" : "are") , kk , ((kk==1) ? " " : "s") ) ; else if( val > 0.3210f ) /* don't ask where this threshold comes from! */ ININFO_message( "MAYBE there's an initial positive transient of 1 point, but it's hard to tell\n") ; else ININFO_message("No widespread initial positive transient detected :-)") ; } /* check -dsort inputs for match to inset */ for( kk=0 ; kk < nortset ; kk++ ){ if( DSET_NX(ortset[kk]) != nx || DSET_NY(ortset[kk]) != ny || DSET_NZ(ortset[kk]) != nz || DSET_NVALS(ortset[kk]) != ntime ) ERROR_exit("-dsort %s doesn't match input dataset grid" , DSET_BRIKNAME(ortset[kk]) ) ; } /* convert input dataset to a vectim, which is more fun */ mrv = THD_dset_to_vectim( inset , mask , 0 ) ; if( mrv == NULL ) ERROR_exit("Can't load time series data!?") ; DSET_unload(inset) ; /* similarly for the ort vectors */ if( ortar != NULL ){ for( kk=0 ; kk < IMARR_COUNT(ortar) ; kk++ ){ ortim = IMARR_SUBIM(ortar,kk) ; if( ortim->nx < ntime ) ERROR_exit("-ort file %s is shorter than input dataset time series", ortim->name ) ; ort = (float **)realloc( ort , sizeof(float *)*(nort+ortim->ny) ) ; for( vv=0 ; vv < ortim->ny ; vv++ ) ort[nort++] = MRI_FLOAT_PTR(ortim) + ortim->nx * vv ; } } /* check whether processing leaves any DoF remaining 18 Mar 2015 [rickr] */ { int nbprem = THD_bandpass_remain_dim(ntime, dt, fbot, ftop, 1); int bpused, nremain; int wlimit; /* warning limit */ bpused = ntime - nbprem; /* #dim lost in bandpass step */ nremain = nbprem - nort; /* #dim left in output */ if( nortset == 1 ) nremain--; nremain -= (qdet+1); if( verb ) INFO_message("%d dimensional data reduced to %d by:\n" " %d (bandpass), %d (-ort), %d (-dsort), %d (detrend)", ntime, nremain, bpused, nort, nortset?1:0, qdet+1); /* possibly warn (if 95% lost) user or fail */ wlimit = ntime/20; if( wlimit < 3 ) wlimit = 3; if( nremain < wlimit && nremain > 0 ) WARNING_message("dimensionality reduced from %d to %d, be careful!", ntime, nremain); if( nremain <= 0 ) /* FAILURE */ ERROR_exit("dimensionality reduced from %d to %d, failing!", ntime, nremain); } /* all the real work now */ if( do_despike ){ int_pair nsp ; if( verb ) INFO_message("Testing data time series for spikes") ; nsp = THD_vectim_despike9( mrv ) ; if( verb ) ININFO_message(" -- Squashed %d spikes from %d voxels",nsp.j,nsp.i) ; } if( verb ) INFO_message("Bandpassing data time series") ; (void)THD_bandpass_vectim( mrv , dt,fbot,ftop , qdet , nort,ort ) ; /* OK, maybe a little more work */ if( nortset == 1 ){ MRI_vectim *orv ; orv = THD_dset_to_vectim( ortset[0] , mask , 0 ) ; if( orv == NULL ){ ERROR_message("Can't load -dsort %s",DSET_BRIKNAME(ortset[0])) ; } else { float *dp , *mvv , *ovv , ff ; if( verb ) INFO_message("Orthogonalizing to bandpassed -dsort") ; (void)THD_bandpass_vectim( orv , dt,fbot,ftop , qdet , nort,ort ) ; THD_vectim_normalize( orv ) ; dp = malloc(sizeof(float)*mrv->nvec) ; THD_vectim_vectim_dot( mrv , orv , dp ) ; for( vv=0 ; vv < mrv->nvec ; vv++ ){ ff = dp[vv] ; if( ff != 0.0f ){ mvv = VECTIM_PTR(mrv,vv) ; ovv = VECTIM_PTR(orv,vv) ; for( kk=0 ; kk < ntime ; kk++ ) mvv[kk] -= ff*ovv[kk] ; } } VECTIM_destroy(orv) ; free(dp) ; } } if( blur > 0.0f ){ if( verb ) INFO_message("Blurring time series data spatially; FWHM=%.2f",blur) ; mri_blur3D_vectim( mrv , blur ) ; } if( pvrad > 0.0f ){ if( verb ) INFO_message("Local PV-ing time series data spatially; radius=%.2f",pvrad) ; THD_vectim_normalize( mrv ) ; THD_vectim_localpv( mrv , pvrad ) ; } if( do_norm && pvrad <= 0.0f ){ if( verb ) INFO_message("L2 normalizing time series data") ; THD_vectim_normalize( mrv ) ; } /* create output dataset, populate it, write it, then quit */ if( verb ) INFO_message("Creating output dataset in memory, then writing it") ; outset = EDIT_empty_copy(inset) ; /* do not copy scalars 11 Sep 2015 [rickr] */ EDIT_dset_items( outset , ADN_prefix,prefix , ADN_brick_fac,NULL , ADN_none ) ; tross_Copy_History( inset , outset ) ; tross_Make_History( "3dBandpass" , argc,argv , outset ) ; for( vv=0 ; vv < ntime ; vv++ ) EDIT_substitute_brick( outset , vv , MRI_float , NULL ) ; #if 1 THD_vectim_to_dset( mrv , outset ) ; #else AFNI_OMP_START ; #pragma omp parallel { float *far , *var ; int *ivec=mrv->ivec ; int vv,kk ; #pragma omp for for( vv=0 ; vv < ntime ; vv++ ){ far = DSET_BRICK_ARRAY(outset,vv) ; var = mrv->fvec + vv ; for( kk=0 ; kk < nmask ; kk++ ) far[ivec[kk]] = var[kk*ntime] ; } } AFNI_OMP_END ; #endif VECTIM_destroy(mrv) ; DSET_write(outset) ; if( verb ) WROTE_DSET(outset) ; exit(0) ; }
int main( int argc , char *argv[] ) { THD_3dim_dataset *dset_in=NULL , *dset_out ; int Lxx=-1 , Lyy=-1 , Lzz=-1 , Mode=FFT_ABS , Sign=-1 , do_alt=0 ; char *prefix = "FFTout" ; int iarg ; MRI_IMAGE *inim , *outim ; float fac ; int nx,ny,nz ; THD_ivec3 iv ; if( argc < 2 || strcasecmp(argv[1],"-help") == 0 ){ printf( "Usage: 3dFFT [options] dataset\n" "\n" "* Does the FFT of the input dataset in 3 directions (x,y,z) and\n" " produces the output dataset.\n" "\n" "* Why you'd want to do this is an interesting question.\n" "\n" "* Program 3dcalc can operate on complex-valued datasets, but\n" " only on one component at a time (cf. the '-cx2r' option).\n" "\n" "* Most other AFNI programs can only operate on real-valued\n" " datasets.\n" "\n" "* You could use 3dcalc (twice) to split a complex-valued dataset\n" " into two real-valued datasets, do your will on those with other\n" " AFNI programs, then merge the results back into a complex-valued\n" " dataset with 3dTwotoComplex.\n" "\n" "Options\n" "=======\n" " -abs = Outputs the magnitude of the FFT [default]\n" " -phase = Outputs the phase of the FFT (-PI..PI == no unwrapping!)\n" " -complex = Outputs the complex-valued FFT\n" " -inverse = Does the inverse FFT instead of the forward FFT\n" "\n" " -Lx xx = Use FFT of length 'xx' in the x-direction\n" " -Ly yy = Use FFT of length 'yy' in the y-direction\n" " -Lz zz = Use FFT of length 'zz' in the z-direction\n" " * Set a length to 0 to skip the FFT in that direction\n" "\n" " -altIN = Alternate signs of input data before FFT, to bring\n" " zero frequency from edge of FFT-space to center of grid\n" " for cosmetic purposes.\n" " -altOUT = Alternate signs of output data after FFT. If you\n" " use '-altI' on the forward transform, then you should\n" " use '-altO' an the inverse transform, to get the\n" " signs of the recovered image correct.\n" " **N.B.: You cannot use '-altIN' and '-altOUT' in the same run!\n" "\n" " -input dd = Read the input dataset from 'dd', instead of\n" " from the last argument on the command line.\n" "\n" " -prefix pp = Use 'pp' for the output dataset prefix.\n" "\n" "Notes\n" "=====\n" " * In the present avatar, only 1 sub-brick will be processed.\n" "\n" " * The program can only do FFT lengths that are factorable\n" " into a product of powers of 2, 3, and 5, and are even.\n" " + The largest power of 3 that is allowed is 3^3 = 27.\n" " + The largest power of 5 that is allowed is 5^3 = 125.\n" " + e.g., FFT of length 3*5*8=120 is possible.\n" " + e.g., FFT of length 4*31 =124 is not possible.\n" "\n" " * The 'x', 'y', and 'z' axes here refer to the order the\n" " data is stored, not DICOM coordinates; cf. 3dinfo.\n" "\n" " * If you force (via '-Lx' etc.) an FFT length that is not\n" " allowed, the program will stop with an error message.\n" "\n" " * If you force an FFT length that is shorter than an dataset\n" " axis dimension, the program will stop with an error message.\n" "\n" " * If you don't force an FFT length along a particular axis,\n" " the program will pick the smallest legal value that is\n" " greater than or equal to the corresponding dataset dimension.\n" " + e.g., 124 would be increased to 128.\n" "\n" " * If an FFT length is longer than an axis length, then the\n" " input data in that direction is zero-padded at the end.\n" "\n" " * For -abs and -phase, the output dataset is in float format.\n" "\n" " * If you do the forward and inverse FFT, then you should get back\n" " the original dataset, except for roundoff error and except that\n" " the new dataset axis dimensions may be longer than the original.\n" "\n" " * Forward FFT = sum_{k=0..N-1} [ exp(-2*PI*i*k/N) * data(k) ]\n" "\n" " * Inverse FFT = sum_{k=0..N-1} [ exp(+2*PI*i*k/N) * data(k) ] / N\n" "\n" " * Started a long time ago, but only finished in Aug 2009 at the\n" " request of John Butman, because he asked so nicely. (Now pay up!)\n" ) ; PRINT_COMPILE_DATE ; exit(0) ; } PRINT_VERSION("3dFFT") ; mainENTRY("3dFFT main") ; machdep() ; AUTHOR("RW Cox") ; AFNI_logger("3dFFT",argc,argv) ; /*--- scan args ---*/ iarg = 1 ; while( iarg < argc && argv[iarg][0] == '-' ){ if( strncasecmp(argv[iarg],"-altI",5) == 0 ){ do_alt = 1 ; iarg++ ; continue ; } if( strncasecmp(argv[iarg],"-altOUT",5) == 0 ){ do_alt = -1 ; iarg++ ; continue ; } if( strncasecmp(argv[iarg],"-inverse",4) == 0 ){ Sign = +1 ; iarg++ ; continue ; } if( strncasecmp(argv[iarg],"-abs",4) == 0 ){ Mode = FFT_ABS ; iarg++ ; continue ; } if( strncasecmp(argv[iarg],"-phase",4) == 0 ){ Mode = FFT_PHASE ; iarg++ ; continue ; } if( strncasecmp(argv[iarg],"-complex",4) == 0 ){ Mode = FFT_COMPLEX ; iarg++ ; continue ; } if( strlen(argv[iarg]) == 3 && strncmp(argv[iarg],"-L",2) == 0 ){ int lll=-1 , mmm ; char *ept ; iarg++ ; if( iarg >= argc ) ERROR_exit("need an argument after option %s",argv[iarg-1]) ; lll = strtol( argv[iarg] , &ept , 10 ) ; if( *ept != '\0' ) ERROR_exit("bad argument after option %s",argv[iarg-1]) ; if( lll > 0 && (mmm = csfft_nextup_even(lll)) != lll ) ERROR_exit( "'%s %d' is not a legal FFT length here: next largest legal value = %d" , argv[iarg-1] , lll , mmm ) ; switch( argv[iarg-1][2] ){ case 'x': case 'X': Lxx = lll ; break ; case 'y': case 'Y': Lyy = lll ; break ; case 'z': case 'Z': Lzz = lll ; break ; default: ERROR_exit("unknown option '%s'",argv[iarg-1]) ; } iarg++ ; continue ; } if( strncasecmp(argv[iarg],"-prefix",4) == 0 ){ iarg++ ; if( iarg >= argc ) ERROR_exit("need an argument after %s\n",argv[iarg-1]) ; prefix = strdup( argv[iarg] ) ; if( !THD_filename_ok(prefix) ) ERROR_exit("bad argument after %s\n",argv[iarg-1]) ; iarg++ ; continue ; } if( strncasecmp(argv[iarg],"-input",4) == 0 ){ iarg++ ; if( iarg >= argc ) ERROR_exit("need an argument after %s\n",argv[iarg-1]) ; dset_in = THD_open_dataset(argv[iarg]); CHECK_OPEN_ERROR(dset_in,argv[iarg]); iarg++ ; continue ; } ERROR_exit("unknown option '%s'\n",argv[iarg]) ; } /* check for simple errors */ if( Lxx == 0 && Lyy == 0 && Lzz == 0 ) ERROR_exit("-Lx, -Ly, -Lz all given as zero?!") ; /* open input dataset */ if( dset_in == NULL ){ if( iarg >= argc ) ERROR_exit("no input dataset on command line?!\n") ; dset_in = THD_open_dataset(argv[iarg]); CHECK_OPEN_ERROR(dset_in,argv[iarg]); } nx = DSET_NX(dset_in) ; ny = DSET_NY(dset_in) ; nz = DSET_NZ(dset_in) ; if( DSET_NVALS(dset_in) > 1 ) WARNING_message("only 3dFFT-ing sub-brick #0 of input dataset") ; /* establish actual FFT lengths now (0 ==> no FFT) */ if( nx == 1 ) Lxx = 0 ; /* can't FFT if dataset is shrimpy! */ if( ny == 1 ) Lyy = 0 ; if( nz == 1 ) Lzz = 0 ; if( Lxx < 0 ) Lxx = csfft_nextup_even(nx) ; /* get FFT length from */ if( Lyy < 0 ) Lyy = csfft_nextup_even(ny) ; /* dataset dimensions */ if( Lzz < 0 ) Lzz = csfft_nextup_even(nz) ; INFO_message("x-axis length=%d ; FFT length=%d %s",nx,Lxx,(Lxx==0)?"==> none":"\0") ; INFO_message("y-axis length=%d ; FFT length=%d %s",ny,Lyy,(Lyy==0)?"==> none":"\0") ; INFO_message("z-axis length=%d ; FFT length=%d %s",nz,Lzz,(Lzz==0)?"==> none":"\0") ; if( Lxx > 0 && Lxx < nx ) ERROR_exit("x-axis FFT length too short for data!") ; if( Lyy > 0 && Lyy < ny ) ERROR_exit("y-axis FFT length too short for data!") ; if( Lzz > 0 && Lzz < nz ) ERROR_exit("z-axis FFT length too short for data!") ; /* extract sub-brick #0 */ DSET_load(dset_in) ; CHECK_LOAD_ERROR(dset_in) ; inim = mri_to_complex( DSET_BRICK(dset_in,0) ) ; /* convert input to complex */ fac = DSET_BRICK_FACTOR(dset_in,0) ; if( fac > 0.0f && fac != 1.0f ){ /* scale it if needed */ int ii , nvox = nx*ny*nz ; complex *car = MRI_COMPLEX_PTR(inim) ; for( ii=0 ; ii < nvox ; ii++ ){ car[ii].r *= fac ; car[ii].i *= fac ; } } DSET_unload(dset_in) ; /* input data is all copied now */ /* FFT to get output image */ csfft_scale_inverse(1) ; /* scale by 1/N for inverse FFTs */ outim = mri_fft_3D( Sign , inim , Lxx,Lyy,Lzz , do_alt ) ; mri_free(inim) ; /* post-process output? */ switch( Mode ){ case FFT_ABS:{ MRI_IMAGE *qim = mri_complex_abs(outim) ; mri_free(outim) ; outim = qim ; } break ; case FFT_PHASE:{ MRI_IMAGE *qim = mri_complex_phase(outim) ; mri_free(outim) ; outim = qim ; } break ; } /* create and write output dataset */ dset_out = EDIT_empty_copy( dset_in ) ; tross_Copy_History( dset_in , dset_out ) ; tross_Make_History( "3dFFT" , argc,argv , dset_out ) ; LOAD_IVEC3( iv , outim->nx , outim->ny , outim->nz ) ; EDIT_dset_items( dset_out , ADN_prefix , prefix , ADN_nvals , 1 , ADN_ntt , 0 , ADN_nxyz , iv , /* change dimensions, possibly */ ADN_none ) ; EDIT_BRICK_FACTOR( dset_out , 0 , 0.0 ) ; EDIT_substitute_brick( dset_out , 0 , outim->kind , mri_data_pointer(outim) ) ; DSET_write(dset_out) ; WROTE_DSET(dset_out) ; DSET_unload(dset_out) ; exit(0) ; }
THD_3dim_dataset * EDIT_full_copy( THD_3dim_dataset *dset , char *new_prefix ) { THD_3dim_dataset *new_dset ; int ival , ityp , nbytes , nvals ; void *new_brick , *old_brick ; ENTRY("EDIT_full_copy") ; /*-- sanity check --*/ if( ! ISVALID_3DIM_DATASET(dset) ) RETURN(NULL) ; /*-- make the empty copy --*/ new_dset = EDIT_empty_copy( dset ) ; /* copy is set to MALLOC memory */ /*-- change its name? --*/ if( new_prefix != NULL ) EDIT_dset_items( new_dset , ADN_prefix , new_prefix , ADN_label1 , new_prefix , ADN_none ) ; /*-- make brick(s) for this dataset --*/ if( !DSET_LOADED(dset) ) DSET_load(dset) ; /* make sure is in memory */ nvals = DSET_NVALS(dset) ; for( ival=0 ; ival < nvals ; ival++ ){ ityp = DSET_BRICK_TYPE(new_dset,ival) ; /* type of data */ nbytes = DSET_BRICK_BYTES(new_dset,ival) ; /* how much data */ new_brick = malloc( nbytes ) ; /* make room */ if( new_brick == NULL ){ THD_delete_3dim_dataset( new_dset , False ) ; RETURN(NULL) ; } EDIT_substitute_brick( new_dset , ival , ityp , new_brick ) ; /*-- copy data from old brick to new brick --*/ old_brick = DSET_BRICK_ARRAY(dset,ival) ; if( old_brick == NULL ){ THD_delete_3dim_dataset( new_dset , False ) ; RETURN(NULL) ; } memcpy( new_brick , old_brick , nbytes ) ; } if (0) { /* For DG to activate */ THD_copy_labeltable_atr( new_dset->dblk, dset->dblk); } RETURN( new_dset ); }
/* * create empty count dataset * for each input dataset and each sub-volume * for each voxel, if set: increment * close datasets as they are processed */ int count_masks(THD_3dim_dataset * dsets[], int ndsets, int verb, /* inputs */ THD_3dim_dataset ** cset, int * nvol) /* outputs */ { THD_3dim_dataset * dset; short * counts = NULL; /* will become data for returned cset */ byte * bptr; /* always points to mask volumes */ int nxyz, iset, ivol, ixyz; ENTRY("count_masks"); if( !dsets || !cset || !nvol ) ERROR_exit("NULL inputs to count_masks"); if( ndsets <= 0 ) { ERROR_message("count_masks: no input datasets"); RETURN(1); } *nvol = 0; nxyz = DSET_NVOX(dsets[0]); /* allocate memory for the counts */ counts = (short *)calloc(nxyz, sizeof(short)); if( !counts ) ERROR_exit("failed to malloc %d shorts", nxyz); /* for each volume of each dataset, count set voxels */ for( iset=0; iset < ndsets; iset++ ) { dset = dsets[iset]; *nvol += DSET_NVALS(dset); /* accumulate num volumes */ /* for each volume in this dataset, count set voxels */ for( ivol=0; ivol < DSET_NVALS(dset); ivol++ ) { if( DSET_BRICK_TYPE(dset, ivol) != MRI_byte ) ERROR_exit("in count_masks with non-byte data (set %d, vol %d)", iset, ivol); bptr = DBLK_ARRAY(dset->dblk, ivol); for( ixyz = 0; ixyz < nxyz; ixyz++ ) if( bptr[ixyz] ) counts[ixyz]++; } if( iset > 0 ) DSET_delete(dset); /* close the first one at end */ } /* dataset */ if( verb > 1 ) { int maxval; for( maxval=counts[0], ixyz=1; ixyz < nxyz; ixyz++ ) if( counts[ixyz] > maxval ) maxval = counts[ixyz]; INFO_message("counted %d mask volumes in %d datasets (%d voxels)\n", *nvol, ndsets, nxyz); INFO_message(" (maximum overlap = %d)\n", maxval); } if( *nvol >= (1<<15) ) WARNING_message("too many volumes to count as shorts: %d", *nvol); /* create output dataset */ *cset = EDIT_empty_copy(dsets[0]); EDIT_dset_items(*cset, ADN_nvals, 1, ADN_ntt, 0, ADN_none); EDIT_substitute_brick(*cset, 0, MRI_short, counts); DSET_delete(dsets[0]); /* now finished with first dataset */ RETURN(0); }
int main( int argc , char *argv[] ) { MRI_IMAGE *imin, *imout , *imout_orig; THD_3dim_dataset *iset, *oset , *ooset; char *prefix = "SpatNorm", *bottom_cuts = NULL; int iarg , verb=0, OrigSpace = 0 , specie = HUMAN; float SpatNormDxyz= 0.0, iset_scaled=1.0; THD_ivec3 orixyz , nxyz ; THD_fvec3 dxyz , orgxyz, originRAIfv, fv2; mainENTRY("3dSpatNorm main") ; machdep() ; if (argc == 1) { usage_3dSpatNorm(1); exit(0); } /*--- options ---*/ iarg = 1 ; OrigSpace = 0; while( iarg < argc && argv[iarg][0] == '-' ){ if (strcmp(argv[iarg],"-h") == 0 || strcmp(argv[iarg],"-help") == 0 ) { usage_3dSpatNorm(strlen(argv[iarg]) > 3 ? 2:1); exit(0); } /* -prefix */ if( strcmp(argv[iarg],"-prefix") == 0 ){ if( ++iarg >= argc ){ fprintf(stderr,"**ERROR: -prefix requires another argument!\n") ; exit(1) ; } prefix = strdup(argv[iarg]) ; if( !THD_filename_ok(prefix) ){ fprintf(stderr,"**ERROR: -prefix value contains forbidden characters!\n") ; exit(1) ; } iarg++ ; continue ; } if( strcmp(argv[iarg],"-dxyz") == 0 ){ if( ++iarg >= argc ){ fprintf(stderr,"**ERROR: -dxyz requires another argument!\n") ; exit(1) ; } SpatNormDxyz = atof(argv[iarg]) ; iarg++ ; continue ; } if( strcmp(argv[iarg],"-bottom_cuts") == 0 ){ if( ++iarg >= argc ){ fprintf(stderr,"**ERROR: -bottom_cuts requires another argument!\n") ; exit(1) ; } bottom_cuts = argv[iarg] ; iarg++ ; continue ; } if( strncmp(argv[iarg],"-verb",5) == 0 ){ verb++ ; iarg++ ; continue ; } if( strncmp(argv[iarg],"-human",5) == 0 ){ specie = HUMAN ; iarg++ ; continue ; } if( strncmp(argv[iarg],"-monkey",5) == 0 ){ specie = MONKEY ; iarg++ ; continue ; } if( strncmp(argv[iarg],"-marmoset",5) == 0 ){ specie = MARMOSET ; iarg++ ; continue ; } if( strncmp(argv[iarg],"-rat",5) == 0 ){ specie = RAT ; iarg++ ; continue ; } if( strncmp(argv[iarg],"-orig_space",10) == 0 ){ OrigSpace = 1 ; iarg++ ; continue ; } fprintf(stderr,"**ERROR: %s is unknown option!\n",argv[iarg]) ; suggest_best_prog_option(argv[0], argv[iarg]); exit(1) ; } if( iarg >= argc ){ fprintf(stderr,"**ERROR: no input dataset name on command line?!\n") ; exit(1) ; } /*--- read dataset ---*/ iset = THD_open_dataset( argv[iarg] ) ; if( !ISVALID_DSET(iset) ){ fprintf(stderr,"**ERROR: can't open dataset %s\n",argv[iarg]) ; exit(1) ; } /*--- get median brick --*/ if( verb ) fprintf(stderr,"++3dSpatNorm: loading dataset\n") ; if (specie == MARMOSET) { iset_scaled = 2.5; THD_volDXYZscale(iset->daxes, iset_scaled, 0); specie = MONKEY; } imin = THD_median_brick( iset ) ; if( imin == NULL ){ fprintf(stderr,"**ERROR: can't load dataset %s\n",argv[iarg]) ; exit(1) ; } imin->dx = fabs(iset->daxes->xxdel) ; imin->dy = fabs(iset->daxes->yydel) ; imin->dz = fabs(iset->daxes->zzdel) ; mri_speciebusiness(specie); mri_brain_normalize_cuts(bottom_cuts); if (SpatNormDxyz) { if (verb) fprintf(stderr,"Overriding default resampling\n"); mri_brainormalize_initialize(SpatNormDxyz, SpatNormDxyz, SpatNormDxyz); } else { float xxdel, yydel, zzdel, minres; if (specie == MONKEY) minres = 0.5; else if (specie == MARMOSET) minres = 0.2; else if (specie == RAT) minres = 0.1; else minres = 0.5; /* don't allow for too low a resolution, please */ if (imin->dx < minres) xxdel = minres; else xxdel = imin->dx; if (imin->dy < minres) yydel = minres; else yydel = imin->dy; if (imin->dz < minres) zzdel = minres; else zzdel = imin->dz; if (verb) { fprintf(stderr, "%s:\n" " Original resolution %f, %f, %f\n" " SpatNorm resolution %f, %f, %f\n", "3dSpatnorm", imin->dx, imin->dy, imin->dz, xxdel, yydel, zzdel); } mri_brainormalize_initialize(xxdel, yydel, zzdel); } /* To get around the #define for voxel counts and dimensions */ mri_brainormalize_initialize(imin->dz, imin->dy, imin->dz); /* me needs the origin of this dset in RAI world */ LOAD_FVEC3( originRAIfv , iset->daxes->xxorg , iset->daxes->yyorg , iset->daxes->zzorg) ; originRAIfv = THD_3dmm_to_dicomm( iset , originRAIfv ) ; LOAD_FVEC3(fv2, iset->daxes->xxorg + (iset->daxes->nxx-1)*iset->daxes->xxdel , iset->daxes->yyorg + (iset->daxes->nyy-1)*iset->daxes->yydel , iset->daxes->zzorg + (iset->daxes->nzz-1)*iset->daxes->zzdel); fv2 = THD_3dmm_to_dicomm( iset , fv2 ) ; if( originRAIfv.xyz[0] > fv2.xyz[0] ) { float tf; tf = originRAIfv.xyz[0]; originRAIfv.xyz[0] = fv2.xyz[0]; fv2.xyz[0] = tf; } if( originRAIfv.xyz[1] > fv2.xyz[1] ) { float tf; tf = originRAIfv.xyz[1]; originRAIfv.xyz[1] = fv2.xyz[1]; fv2.xyz[1] = tf; } if( originRAIfv.xyz[2] > fv2.xyz[2] ) { float tf; tf = originRAIfv.xyz[2]; originRAIfv.xyz[2] = fv2.xyz[2]; fv2.xyz[2] = tf; } if (verb) { fprintf(stderr,"++3dSpatNorm (ZSS): RAI origin info: %f %f %f\n", originRAIfv.xyz[0], originRAIfv.xyz[1], originRAIfv.xyz[2]); } DSET_unload( iset ) ; /* don't need this data no more */ /*-- convert image to shorts, if appropriate --*/ if( DSET_BRICK_TYPE(iset,0) == MRI_short || DSET_BRICK_TYPE(iset,0) == MRI_byte ){ imout = mri_to_short(0.0,imin) ; /* ZSS Oct 2012: Let function set scaling*/ mri_free(imin) ; imin = imout ; } /*--- normalize image spatially ---*/ mri_brainormalize_verbose( verb ) ; if (OrigSpace) { imout = mri_brainormalize( imin , iset->daxes->xxorient, iset->daxes->yyorient, iset->daxes->zzorient , &imout_orig, NULL) ; } else { imout = mri_brainormalize( imin , iset->daxes->xxorient, iset->daxes->yyorient, iset->daxes->zzorient , NULL, NULL) ; } mri_free( imin ) ; if( imout == NULL ){ fprintf(stderr,"**ERROR: normalization fails!?\n"); exit(1); } if (OrigSpace) { if( verb ) fprintf(stderr,"++3dSpatNorm: Output in Orignal space\n") ; mri_free( imout ) ; imout = imout_orig; imout->xo = originRAIfv.xyz[0]; imout->yo = originRAIfv.xyz[1]; imout->zo = originRAIfv.xyz[2]; imout_orig = NULL; } else { if( verb ) fprintf(stderr,"++3dSpatNorm: Output in SpatNorm space\n") ; } #if 0 if( AFNI_yesenv("WATERSHED") ){ imin = mri_watershedize( imout , 0.10 ) ; if( imin != NULL ){ mri_free(imout); imout = imin; } } #endif /*--- create output dataset ---*/ if( verb ) fprintf(stderr,"++3dSpatNorm: Creating output dset\n") ; oset = EDIT_empty_copy( NULL ) ; tross_Copy_History( iset , oset ) ; tross_Make_History( "3dSpatNorm" , argc,argv , oset ) ; LOAD_IVEC3( nxyz , imout->nx , imout->ny , imout->nz ) ; LOAD_FVEC3( dxyz , imout->dx , imout->dy , imout->dz ) ; LOAD_FVEC3( orgxyz , imout->xo , imout->yo , imout->zo ) ; LOAD_IVEC3( orixyz , ORI_R2L_TYPE , ORI_A2P_TYPE , ORI_I2S_TYPE ) ; if( verb ) fprintf(stderr,"++3dSpatNorm: EDIT_dset_items\n") ; EDIT_dset_items( oset , ADN_prefix , prefix , ADN_datum_all , imout->kind , ADN_nxyz , nxyz , ADN_xyzdel , dxyz , ADN_xyzorg , orgxyz , ADN_xyzorient , orixyz , ADN_malloc_type , DATABLOCK_MEM_MALLOC , ADN_view_type , VIEW_ORIGINAL_TYPE , ADN_type , HEAD_ANAT_TYPE , ADN_func_type , ANAT_BUCK_TYPE , ADN_none ) ; if( verb ) fprintf(stderr,"++3dSpatNorm: EDIT_substitute_brick\n") ; EDIT_substitute_brick( oset , 0 , imout->kind , mri_data_pointer(imout) ) ; if (OrigSpace) { if( verb ) fprintf(stderr,"++3dSpatNorm: Changing orientation from RAI\n") ; ooset = r_new_resam_dset ( oset, iset, 0, 0, 0, NULL, MRI_NN, NULL, 1, 0); if (!ooset) { fprintf(stderr,"**ERROR: Failed to reslice!?\n"); exit(1); } /* put prefix back, r_new_resam_dset puts dummy prefix */ EDIT_dset_items( ooset , ADN_prefix , prefix, ADN_none ) ; DSET_delete(oset); oset = ooset; ooset = NULL; } if (iset_scaled != 1.0f) THD_volDXYZscale(oset->daxes, 1/iset_scaled, 0); DSET_write(oset) ; if( verb ) fprintf(stderr,"++3dSpatNorm: wrote dataset %s\n",DSET_BRIKNAME(oset)) ; exit(0) ; }
int main( int argc , char * argv[] ) { int do_norm=0 , qdet=2 , have_freq=0 , do_automask=0 ; float dt=0.0f , fbot=0.0f,ftop=999999.9f , blur=0.0f ; MRI_IMARR *ortar=NULL ; MRI_IMAGE *ortim=NULL ; THD_3dim_dataset **ortset=NULL ; int nortset=0 ; THD_3dim_dataset *inset=NULL , *outset=NULL; char *prefix="RSFC" ; byte *mask=NULL ; int mask_nx=0,mask_ny=0,mask_nz=0,nmask , verb=1 , nx,ny,nz,nvox , nfft=0 , kk ; float **vec , **ort=NULL ; int nort=0 , vv , nopt , ntime ; MRI_vectim *mrv ; float pvrad=0.0f ; int nosat=0 ; int do_despike=0 ; // @@ non-BP variables float fbotALL=0.0f, ftopALL=999999.9f; // do full range version int NumDen = 0; // switch for doing numerator or denom THD_3dim_dataset *outsetALL=NULL ; int m, mm; float delf; // harmonics int ind_low,ind_high,N_ny, ctr; float sqnt,nt_fac; gsl_fft_real_wavetable *real1, *real2; // GSL stuff gsl_fft_real_workspace *work; double *series1, *series2; double *xx1,*xx2; float numer,denom,val; float *alff=NULL,*malff=NULL,*falff=NULL, *rsfa=NULL,*mrsfa=NULL,*frsfa=NULL; // values float meanALFF=0.0f,meanRSFA=0.0f; // will be for mean in brain region THD_3dim_dataset *outsetALFF=NULL; THD_3dim_dataset *outsetmALFF=NULL; THD_3dim_dataset *outsetfALFF=NULL; THD_3dim_dataset *outsetRSFA=NULL; THD_3dim_dataset *outsetmRSFA=NULL; THD_3dim_dataset *outsetfRSFA=NULL; char out_lff[300]; char out_alff[300]; char out_malff[300]; char out_falff[300]; char out_rsfa[300]; char out_mrsfa[300]; char out_frsfa[300]; char out_unBP[300]; int SERIES_OUT = 1; int UNBP_OUT = 0; int DO_RSFA = 1; int BP_LAST = 0; // option for only doing filter to LFFs at very end of proc float de_rsfa=0.0f,nu_rsfa=0.0f; double pow1=0.0,pow2=0.0; /*-- help? --*/ if( argc < 2 || strcmp(argv[1],"-help") == 0 ){ printf( "\n Program to calculate common resting state functional connectivity (RSFC)\n" " parameters (ALFF, mALFF, fALFF, RSFA, etc.) for resting state time\n" " series. This program is **heavily** based on the existing\n" " 3dBandPass by RW Cox, with the amendments to calculate RSFC\n" " parameters written by PA Taylor (July, 2012).\n" " This program is part of FATCAT (Taylor & Saad, 2013) in AFNI. Importantly,\n" " its functionality can be included in the `afni_proc.py' processing-script \n" " generator; see that program's help file for an example including RSFC\n" " and spectral parameter calculation via the `-regress_RSFC' option.\n" "\n" "* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n" "\n" " All options of 3dBandPass may be used here (with a couple other\n" " parameter options, as well): essentially, the motivation of this\n" " program is to produce ALFF, etc. values of the actual RSFC time\n" " series that you calculate. Therefore, all the 3dBandPass processing\n" " you normally do en route to making your final `resting state time\n" " series' is done here to generate your LFFs, from which the\n" " amplitudes in the LFF band are calculated at the end. In order to\n" " calculate fALFF, the same initial time series are put through the\n" " same processing steps which you have chosen but *without* the\n" " bandpass part; the spectrum of this second time series is used to\n" " calculate the fALFF denominator.\n" " \n" " For more information about each RSFC parameter, see, e.g.: \n" " ALFF/mALFF -- Zang et al. (2007),\n" " fALFF -- Zou et al. (2008),\n" " RSFA -- Kannurpatti & Biswal (2008).\n" "\n" "* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n" "\n" " + USAGE: 3dRSFC [options] fbot ftop dataset\n" "\n" "* One function of this program is to prepare datasets for input\n" " to 3dSetupGroupInCorr. Other uses are left to your imagination.\n" "\n" "* 'dataset' is a 3D+time sequence of volumes\n" " ++ This must be a single imaging run -- that is, no discontinuities\n" " in time from 3dTcat-ing multiple datasets together.\n" "\n" "* fbot = lowest frequency in the passband, in Hz\n" " ++ fbot can be 0 if you want to do a lowpass filter only;\n" " HOWEVER, the mean and Nyquist freq are always removed.\n" "\n" "* ftop = highest frequency in the passband (must be > fbot)\n" " ++ if ftop > Nyquist freq, then it's a highpass filter only.\n" "\n" "* Set fbot=0 and ftop=99999 to do an 'allpass' filter.\n" " ++ Except for removal of the 0 and Nyquist frequencies, that is.\n" "\n" "* You cannot construct a 'notch' filter with this program!\n" " ++ You could use 3dRSFC followed by 3dcalc to get the same effect.\n" " ++ If you are understand what you are doing, that is.\n" " ++ Of course, that is the AFNI way -- if you don't want to\n" " understand what you are doing, use Some other PrograM, and\n" " you can still get Fine StatisticaL maps.\n" "\n" "* 3dRSFC will fail if fbot and ftop are too close for comfort.\n" " ++ Which means closer than one frequency grid step df,\n" " where df = 1 / (nfft * dt) [of course]\n" "\n" "* The actual FFT length used will be printed, and may be larger\n" " than the input time series length for the sake of efficiency.\n" " ++ The program will use a power-of-2, possibly multiplied by\n" " a power of 3 and/or 5 (up to and including the 3rd power of\n" " each of these: 3, 9, 27, and 5, 25, 125).\n" "\n" "* Note that the results of combining 3dDetrend and 3dRSFC will\n" " depend on the order in which you run these programs. That's why\n" " 3dRSFC has the '-ort' and '-dsort' options, so that the\n" " time series filtering can be done properly, in one place.\n" "\n" "* The output dataset is stored in float format.\n" "\n" "* The order of processing steps is the following (most are optional), and\n" " for the LFFs, the bandpass is done between the specified fbot and ftop,\n" " while for the `whole spectrum' (i.e., fALFF denominator) the bandpass is:\n" " done only to exclude the time series mean and the Nyquist frequency:\n" " (0) Check time series for initial transients [does not alter data]\n" " (1) Despiking of each time series\n" " (2) Removal of a constant+linear+quadratic trend in each time series\n" " (3) Bandpass of data time series\n" " (4) Bandpass of -ort time series, then detrending of data\n" " with respect to the -ort time series\n" " (5) Bandpass and de-orting of the -dsort dataset,\n" " then detrending of the data with respect to -dsort\n" " (6) Blurring inside the mask [might be slow]\n" " (7) Local PV calculation [WILL be slow!]\n" " (8) L2 normalization [will be fast.]\n" " (9) Calculate spectrum and amplitudes, for RSFC parameters.\n" "\n" "* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n" "--------\n" "OPTIONS:\n" "--------\n" " -despike = Despike each time series before other processing.\n" " ++ Hopefully, you don't actually need to do this,\n" " which is why it is optional.\n" " -ort f.1D = Also orthogonalize input to columns in f.1D\n" " ++ Multiple '-ort' options are allowed.\n" " -dsort fset = Orthogonalize each voxel to the corresponding\n" " voxel time series in dataset 'fset', which must\n" " have the same spatial and temporal grid structure\n" " as the main input dataset.\n" " ++ At present, only one '-dsort' option is allowed.\n" " -nodetrend = Skip the quadratic detrending of the input that\n" " occurs before the FFT-based bandpassing.\n" " ++ You would only want to do this if the dataset\n" " had been detrended already in some other program.\n" " -dt dd = set time step to 'dd' sec [default=from dataset header]\n" " -nfft N = set the FFT length to 'N' [must be a legal value]\n" " -norm = Make all output time series have L2 norm = 1\n" " ++ i.e., sum of squares = 1\n" " -mask mset = Mask dataset\n" " -automask = Create a mask from the input dataset\n" " -blur fff = Blur (inside the mask only) with a filter\n" " width (FWHM) of 'fff' millimeters.\n" " -localPV rrr = Replace each vector by the local Principal Vector\n" " (AKA first singular vector) from a neighborhood\n" " of radius 'rrr' millimiters.\n" " ++ Note that the PV time series is L2 normalized.\n" " ++ This option is mostly for Bob Cox to have fun with.\n" "\n" " -input dataset = Alternative way to specify input dataset.\n" " -band fbot ftop = Alternative way to specify passband frequencies.\n" "\n" " -prefix ppp = Set prefix name of output dataset. Name of filtered time\n" " series would be, e.g., ppp_LFF+orig.*, and the parameter\n" " outputs are named with obvious suffices.\n" " -quiet = Turn off the fun and informative messages. (Why?)\n" " -no_rs_out = Don't output processed time series-- just output\n" " parameters (not recommended, since the point of\n" " calculating RSFC params here is to have them be quite\n" " related to the time series themselves which are used for\n" " further analysis)." " -un_bp_out = Output the un-bandpassed series as well (default is not \n" " to). Name would be, e.g., ppp_unBP+orig.* .\n" " with suffix `_unBP'.\n" " -no_rsfa = If you don't want RSFA output (default is to do so).\n" " -bp_at_end = A (probably unnecessary) switch to have bandpassing be \n" " the very last processing step that is done in the\n" " sequence of steps listed above; at Step 3 above, only \n" " the time series mean and nyquist are BP'ed out, and then\n" " the LFF series is created only after Step 9. NB: this \n" " probably makes only very small changes for most\n" " processing sequences (but maybe not, depending usage).\n" "\n" " -notrans = Don't check for initial positive transients in the data:\n" " *OR* ++ The test is a little slow, so skipping it is OK,\n" " -nosat if you KNOW the data time series are transient-free.\n" " ++ Or set AFNI_SKIP_SATCHECK to YES.\n" " ++ Initial transients won't be handled well by the\n" " bandpassing algorithm, and in addition may seriously\n" " contaminate any further processing, such as inter-\n" " voxel correlations via InstaCorr.\n" " ++ No other tests are made [yet] for non-stationary \n" " behavior in the time series data.\n" "\n" "* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n" "\n" " If you use this program, please reference the introductory/description\n" " paper for the FATCAT toolbox:\n" " Taylor PA, Saad ZS (2013). FATCAT: (An Efficient) Functional\n" " And Tractographic Connectivity Analysis Toolbox. Brain \n" " Connectivity 3(5):523-535.\n" "____________________________________________________________________________\n" ); PRINT_AFNI_OMP_USAGE( " 3dRSFC" , " * At present, the only part of 3dRSFC that is parallelized is the\n" " '-blur' option, which processes each sub-brick independently.\n" ) ; PRINT_COMPILE_DATE ; exit(0) ; } /*-- startup --*/ mainENTRY("3dRSFC"); machdep(); AFNI_logger("3dRSFC",argc,argv); PRINT_VERSION("3dRSFC (from 3dBandpass by RW Cox): version THETA"); AUTHOR("PA Taylor"); nosat = AFNI_yesenv("AFNI_SKIP_SATCHECK") ; nopt = 1 ; while( nopt < argc && argv[nopt][0] == '-' ){ if( strcmp(argv[nopt],"-despike") == 0 ){ /* 08 Oct 2010 */ do_despike++ ; nopt++ ; continue ; } if( strcmp(argv[nopt],"-nfft") == 0 ){ int nnup ; if( ++nopt >= argc ) ERROR_exit("need an argument after -nfft!") ; nfft = (int)strtod(argv[nopt],NULL) ; nnup = csfft_nextup_even(nfft) ; if( nfft < 16 || nfft != nnup ) ERROR_exit("value %d after -nfft is illegal! Next legal value = %d",nfft,nnup) ; nopt++ ; continue ; } if( strcmp(argv[nopt],"-blur") == 0 ){ if( ++nopt >= argc ) ERROR_exit("need an argument after -blur!") ; blur = strtod(argv[nopt],NULL) ; if( blur <= 0.0f ) WARNING_message("non-positive blur?!") ; nopt++ ; continue ; } if( strcmp(argv[nopt],"-localPV") == 0 ){ if( ++nopt >= argc ) ERROR_exit("need an argument after -localpv!") ; pvrad = strtod(argv[nopt],NULL) ; if( pvrad <= 0.0f ) WARNING_message("non-positive -localpv?!") ; nopt++ ; continue ; } if( strcmp(argv[nopt],"-prefix") == 0 ){ if( ++nopt >= argc ) ERROR_exit("need an argument after -prefix!") ; prefix = strdup(argv[nopt]) ; if( !THD_filename_ok(prefix) ) ERROR_exit("bad -prefix option!") ; nopt++ ; continue ; } if( strcmp(argv[nopt],"-automask") == 0 ){ if( mask != NULL ) ERROR_exit("Can't use -mask AND -automask!") ; do_automask = 1 ; nopt++ ; continue ; } if( strcmp(argv[nopt],"-mask") == 0 ){ THD_3dim_dataset *mset ; if( ++nopt >= argc ) ERROR_exit("Need argument after '-mask'") ; if( mask != NULL || do_automask ) ERROR_exit("Can't have two mask inputs") ; mset = THD_open_dataset( argv[nopt] ) ; CHECK_OPEN_ERROR(mset,argv[nopt]) ; DSET_load(mset) ; CHECK_LOAD_ERROR(mset) ; mask_nx = DSET_NX(mset); mask_ny = DSET_NY(mset); mask_nz = DSET_NZ(mset); mask = THD_makemask( mset , 0 , 0.5f, 0.0f ) ; DSET_delete(mset) ; if( mask == NULL ) ERROR_exit("Can't make mask from dataset '%s'",argv[nopt]) ; nmask = THD_countmask( mask_nx*mask_ny*mask_nz , mask ) ; if( verb ) INFO_message("Number of voxels in mask = %d",nmask) ; if( nmask < 1 ) ERROR_exit("Mask is too small to process") ; nopt++ ; continue ; } if( strcmp(argv[nopt],"-norm") == 0 ){ do_norm = 1 ; nopt++ ; continue ; } if( strcmp(argv[nopt],"-quiet") == 0 ){ verb = 0 ; nopt++ ; continue ; } if( strcmp(argv[nopt],"-no_rs_out") == 0 ){ // @@ SERIES_OUT = 0 ; nopt++ ; continue ; } if( strcmp(argv[nopt],"-un_bp_out") == 0 ){ // @@ UNBP_OUT = 1 ; nopt++ ; continue ; } if( strcmp(argv[nopt],"-no_rsfa") == 0 ){ // @@ DO_RSFA = 0 ; nopt++ ; continue ; } if( strcmp(argv[nopt],"-bp_at_end") == 0 ){ // @@ BP_LAST = 1 ; nopt++ ; continue ; } if( strcmp(argv[nopt],"-notrans") == 0 || strcmp(argv[nopt],"-nosat") == 0 ){ nosat = 1 ; nopt++ ; continue ; } if( strcmp(argv[nopt],"-ort") == 0 ){ if( ++nopt >= argc ) ERROR_exit("need an argument after -ort!") ; if( ortar == NULL ) INIT_IMARR(ortar) ; ortim = mri_read_1D( argv[nopt] ) ; if( ortim == NULL ) ERROR_exit("can't read from -ort '%s'",argv[nopt]) ; mri_add_name(argv[nopt],ortim) ; ADDTO_IMARR(ortar,ortim) ; nopt++ ; continue ; } if( strcmp(argv[nopt],"-dsort") == 0 ){ THD_3dim_dataset *qset ; if( ++nopt >= argc ) ERROR_exit("need an argument after -dsort!") ; if( nortset > 0 ) ERROR_exit("only 1 -dsort option is allowed!") ; qset = THD_open_dataset(argv[nopt]) ; CHECK_OPEN_ERROR(qset,argv[nopt]) ; ortset = (THD_3dim_dataset **)realloc(ortset, sizeof(THD_3dim_dataset *)*(nortset+1)) ; ortset[nortset++] = qset ; nopt++ ; continue ; } if( strncmp(argv[nopt],"-nodetrend",6) == 0 ){ qdet = 0 ; nopt++ ; continue ; } if( strcmp(argv[nopt],"-dt") == 0 ){ if( ++nopt >= argc ) ERROR_exit("need an argument after -dt!") ; dt = (float)strtod(argv[nopt],NULL) ; if( dt <= 0.0f ) WARNING_message("value after -dt illegal!") ; nopt++ ; continue ; } if( strcmp(argv[nopt],"-input") == 0 ){ if( inset != NULL ) ERROR_exit("Can't have 2 -input options!") ; if( ++nopt >= argc ) ERROR_exit("need an argument after -input!") ; inset = THD_open_dataset(argv[nopt]) ; CHECK_OPEN_ERROR(inset,argv[nopt]) ; nopt++ ; continue ; } if( strncmp(argv[nopt],"-band",5) == 0 ){ if( ++nopt >= argc-1 ) ERROR_exit("need 2 arguments after -band!") ; if( have_freq ) WARNING_message("second -band option replaces first one!") ; fbot = strtod(argv[nopt++],NULL) ; ftop = strtod(argv[nopt++],NULL) ; have_freq = 1 ; continue ; } ERROR_exit("Unknown option: '%s'",argv[nopt]) ; } /** check inputs for reasonablositiness **/ if( !have_freq ){ if( nopt+1 >= argc ) ERROR_exit("Need frequencies on command line after options!") ; fbot = (float)strtod(argv[nopt++],NULL) ; ftop = (float)strtod(argv[nopt++],NULL) ; } if( inset == NULL ){ if( nopt >= argc ) ERROR_exit("Need input dataset name on command line after options!") ; inset = THD_open_dataset(argv[nopt]) ; CHECK_OPEN_ERROR(inset,argv[nopt]) ; nopt++ ; } DSET_UNMSEC(inset) ; if( fbot < 0.0f ) ERROR_exit("fbot value can't be negative!") ; if( ftop <= fbot ) ERROR_exit("ftop value %g must be greater than fbot value %g!",ftop,fbot) ; ntime = DSET_NVALS(inset) ; if( ntime < 9 ) ERROR_exit("Input dataset is too short!") ; if( nfft <= 0 ){ nfft = csfft_nextup_even(ntime) ; if( verb ) INFO_message("Data length = %d FFT length = %d",ntime,nfft) ; (void)THD_bandpass_set_nfft(nfft) ; } else if( nfft < ntime ){ ERROR_exit("-nfft %d is less than data length = %d",nfft,ntime) ; } else { kk = THD_bandpass_set_nfft(nfft) ; if( kk != nfft && verb ) INFO_message("Data length = %d FFT length = %d",ntime,kk) ; } if( dt <= 0.0f ){ dt = DSET_TR(inset) ; if( dt <= 0.0f ){ WARNING_message("Setting dt=1.0 since input dataset lacks a time axis!") ; dt = 1.0f ; } } ftopALL = 1./dt ;// Aug,2016: should solve problem of a too-large // value for THD_bandpass_vectors(), while still // being >f_{Nyquist} if( !THD_bandpass_OK(ntime,dt,fbot,ftop,1) ) ERROR_exit("Can't continue!") ; nx = DSET_NX(inset); ny = DSET_NY(inset); nz = DSET_NZ(inset); nvox = nx*ny*nz; /* check mask, or create it */ if( verb ) INFO_message("Loading input dataset time series" ) ; DSET_load(inset) ; if( mask != NULL ){ if( mask_nx != nx || mask_ny != ny || mask_nz != nz ) ERROR_exit("-mask dataset grid doesn't match input dataset") ; } else if( do_automask ){ mask = THD_automask( inset ) ; if( mask == NULL ) ERROR_message("Can't create -automask from input dataset?") ; nmask = THD_countmask( DSET_NVOX(inset) , mask ) ; if( verb ) INFO_message("Number of voxels in automask = %d",nmask); if( nmask < 1 ) ERROR_exit("Automask is too small to process") ; } else { mask = (byte *)malloc(sizeof(byte)*nvox) ; nmask = nvox ; memset(mask,1,sizeof(byte)*nvox) ; // if( verb ) // @@ alert if aaaalllllll vox are going to be analyzed! INFO_message("No mask ==> processing all %d voxels",nvox); } /* A simple check of dataset quality [08 Feb 2010] */ if( !nosat ){ float val ; INFO_message( "Checking dataset for initial transients [use '-notrans' to skip this test]") ; val = THD_saturation_check(inset,mask,0,0) ; kk = (int)(val+0.54321f) ; if( kk > 0 ) ININFO_message( "Looks like there %s %d non-steady-state initial time point%s :-(" , ((kk==1) ? "is" : "are") , kk , ((kk==1) ? " " : "s") ) ; else if( val > 0.3210f ) /* don't ask where this threshold comes from! */ ININFO_message( "MAYBE there's an initial positive transient of 1 point, but it's hard to tell\n") ; else ININFO_message("No widespread initial positive transient detected :-)") ; } /* check -dsort inputs for match to inset */ for( kk=0 ; kk < nortset ; kk++ ){ if( DSET_NX(ortset[kk]) != nx || DSET_NY(ortset[kk]) != ny || DSET_NZ(ortset[kk]) != nz || DSET_NVALS(ortset[kk]) != ntime ) ERROR_exit("-dsort %s doesn't match input dataset grid" , DSET_BRIKNAME(ortset[kk]) ) ; } /* convert input dataset to a vectim, which is more fun */ // @@ convert BP'ing ftop/bot into indices for the DFT (below) delf = 1.0/(ntime*dt); ind_low = (int) rint(fbot/delf); ind_high = (int) rint(ftop/delf); if( ntime % 2 ) // nyquist number N_ny = (ntime-1)/2; else N_ny = ntime/2; sqnt = sqrt(ntime); nt_fac = sqrt(ntime*(ntime-1)); // @@ if BP_LAST==0: // now we go through twice, doing LFF bandpass for NumDen==0 and // `full spectrum' processing for NumDen==1. // if BP_LAST==1: // now we go through once, doing only `full spectrum' processing for( NumDen=0 ; NumDen<2 ; NumDen++) { //if( NumDen==1 ){ // full spectrum // fbot = fbotALL; // ftop = ftopALL; //} // essentially, just doesn't BP here, and the perfect filtering at end // is used for both still; this makes the final output spectrum // contain only frequencies in range of 0.01-0.08 if( BP_LAST==1 ) INFO_message("Only doing filtering to LFFs at end!"); mrv = THD_dset_to_vectim( inset , mask , 0 ) ; if( mrv == NULL ) ERROR_exit("Can't load time series data!?") ; if( NumDen==1 ) DSET_unload(inset) ; // @@ only unload on 2nd pass /* similarly for the ort vectors */ if( ortar != NULL ){ for( kk=0 ; kk < IMARR_COUNT(ortar) ; kk++ ){ ortim = IMARR_SUBIM(ortar,kk) ; if( ortim->nx < ntime ) ERROR_exit("-ort file %s is shorter than input dataset time series", ortim->name ) ; ort = (float **)realloc( ort , sizeof(float *)*(nort+ortim->ny) ) ; for( vv=0 ; vv < ortim->ny ; vv++ ) ort[nort++] = MRI_FLOAT_PTR(ortim) + ortim->nx * vv ; } } /* all the real work now */ if( do_despike ){ int_pair nsp ; if( verb ) INFO_message("Testing data time series for spikes") ; nsp = THD_vectim_despike9( mrv ) ; if( verb ) ININFO_message(" -- Squashed %d spikes from %d voxels",nsp.j,nsp.i) ; } if( verb ) INFO_message("Bandpassing data time series") ; if( (BP_LAST==0) && (NumDen==0) ) (void)THD_bandpass_vectim( mrv , dt,fbot,ftop , qdet , nort,ort ) ; else (void)THD_bandpass_vectim( mrv , dt,fbotALL,ftopALL, qdet,nort,ort ) ; /* OK, maybe a little more work */ if( nortset == 1 ){ MRI_vectim *orv ; orv = THD_dset_to_vectim( ortset[0] , mask , 0 ) ; if( orv == NULL ){ ERROR_message("Can't load -dsort %s",DSET_BRIKNAME(ortset[0])) ; } else { float *dp , *mvv , *ovv , ff ; if( verb ) INFO_message("Orthogonalizing to bandpassed -dsort") ; //(void)THD_bandpass_vectim( orv , dt,fbot,ftop , qdet , nort,ort ) ; //@@ if( (BP_LAST==0) && (NumDen==0) ) (void)THD_bandpass_vectim(orv,dt,fbot,ftop,qdet,nort,ort); else (void)THD_bandpass_vectim(orv,dt,fbotALL,ftopALL,qdet,nort,ort); THD_vectim_normalize( orv ) ; dp = malloc(sizeof(float)*mrv->nvec) ; THD_vectim_vectim_dot( mrv , orv , dp ) ; for( vv=0 ; vv < mrv->nvec ; vv++ ){ ff = dp[vv] ; if( ff != 0.0f ){ mvv = VECTIM_PTR(mrv,vv) ; ovv = VECTIM_PTR(orv,vv) ; for( kk=0 ; kk < ntime ; kk++ ) mvv[kk] -= ff*ovv[kk] ; } } VECTIM_destroy(orv) ; free(dp) ; } } if( blur > 0.0f ){ if( verb ) INFO_message("Blurring time series data spatially; FWHM=%.2f",blur) ; mri_blur3D_vectim( mrv , blur ) ; } if( pvrad > 0.0f ){ if( verb ) INFO_message("Local PV-ing time series data spatially; radius=%.2f",pvrad) ; THD_vectim_normalize( mrv ) ; THD_vectim_localpv( mrv , pvrad ) ; } if( do_norm && pvrad <= 0.0f ){ if( verb ) INFO_message("L2 normalizing time series data") ; THD_vectim_normalize( mrv ) ; } /* create output dataset, populate it, write it, then quit */ if( (NumDen==0) ) { // @@ BP'ed version; will do filt if BP_LAST if(BP_LAST) // do bandpass here for BP_LAST (void)THD_bandpass_vectim(mrv,dt,fbot,ftop,qdet,0,NULL); if( verb ) INFO_message("Creating output dataset in memory, then writing it") ; outset = EDIT_empty_copy(inset) ; if(SERIES_OUT){ sprintf(out_lff,"%s_LFF",prefix); EDIT_dset_items( outset , ADN_prefix,out_lff , ADN_none ) ; tross_Copy_History( inset , outset ) ; tross_Make_History( "3dBandpass" , argc,argv , outset ) ; } for( vv=0 ; vv < ntime ; vv++ ) EDIT_substitute_brick( outset , vv , MRI_float , NULL ) ; #if 1 THD_vectim_to_dset( mrv , outset ) ; #else AFNI_OMP_START ; #pragma omp parallel { float *far , *var ; int *ivec=mrv->ivec ; int vv,kk ; #pragma omp for for( vv=0 ; vv < ntime ; vv++ ){ far = DSET_BRICK_ARRAY(outset,vv) ; var = mrv->fvec + vv ; for( kk=0 ; kk < nmask ; kk++ ) far[ivec[kk]] = var[kk*ntime] ; } } AFNI_OMP_END ; #endif VECTIM_destroy(mrv) ; if(SERIES_OUT){ // @@ DSET_write(outset) ; if( verb ) WROTE_DSET(outset) ; } } else{ // @@ non-BP'ed version if( verb ) INFO_message("Creating output dataset 2 in memory") ; // do this here because LFF version was also BP'ed at end. if(BP_LAST) // do bandpass here for BP_LAST (void)THD_bandpass_vectim(mrv,dt,fbotALL,ftopALL,qdet,0,NULL); outsetALL = EDIT_empty_copy(inset) ; if(UNBP_OUT){ sprintf(out_unBP,"%s_unBP",prefix); EDIT_dset_items( outsetALL, ADN_prefix, out_unBP, ADN_none ); tross_Copy_History( inset , outsetALL ) ; tross_Make_History( "3dRSFC" , argc,argv , outsetALL ) ; } for( vv=0 ; vv < ntime ; vv++ ) EDIT_substitute_brick( outsetALL , vv , MRI_float , NULL ) ; #if 1 THD_vectim_to_dset( mrv , outsetALL ) ; #else AFNI_OMP_START ; #pragma omp parallel { float *far , *var ; int *ivec=mrv->ivec ; int vv,kk ; #pragma omp for for( vv=0 ; vv < ntime ; vv++ ){ far = DSET_BRICK_ARRAY(outsetALL,vv) ; var = mrv->fvec + vv ; for( kk=0 ; kk < nmask ; kk++ ) far[ivec[kk]] = var[kk*ntime] ; } } AFNI_OMP_END ; #endif VECTIM_destroy(mrv) ; if(UNBP_OUT){ DSET_write(outsetALL) ; if( verb ) WROTE_DSET(outsetALL) ; } } }// end of NumDen loop // @@ INFO_message("Starting the (f)ALaFFel calcs") ; // allocations series1 = (double *)calloc(ntime,sizeof(double)); series2 = (double *)calloc(ntime,sizeof(double)); xx1 = (double *)calloc(2*ntime,sizeof(double)); xx2 = (double *)calloc(2*ntime,sizeof(double)); alff = (float *)calloc(nvox,sizeof(float)); malff = (float *)calloc(nvox,sizeof(float)); falff = (float *)calloc(nvox,sizeof(float)); if( (series1 == NULL) || (series2 == NULL) || (xx1 == NULL) || (xx2 == NULL) || (alff == NULL) || (malff == NULL) || (falff == NULL)) { fprintf(stderr, "\n\n MemAlloc failure.\n\n"); exit(122); } if(DO_RSFA) { rsfa = (float *)calloc(nvox,sizeof(float)); mrsfa = (float *)calloc(nvox,sizeof(float)); frsfa = (float *)calloc(nvox,sizeof(float)); if( (rsfa == NULL) || (mrsfa == NULL) || (frsfa == NULL)) { fprintf(stderr, "\n\n MemAlloc failure.\n\n"); exit(123); } } work = gsl_fft_real_workspace_alloc (ntime); real1 = gsl_fft_real_wavetable_alloc (ntime); real2 = gsl_fft_real_wavetable_alloc (ntime); gsl_complex_packed_array compl_freqs1 = xx1; gsl_complex_packed_array compl_freqs2 = xx2; // ********************************************************************* // ********************************************************************* // ************** Falafelling = ALFF/fALFF calcs ***************** // ********************************************************************* // ********************************************************************* // Be now have the BP'ed data set (outset) and the non-BP'ed one // (outsetALL). now we'll FFT both, get amplitudes in appropriate // ranges, and calculate: ALFF, mALFF, fALFF, ctr = 0; for( kk=0; kk<nvox ; kk++) { if(mask[kk]) { // BP one, and unBP one, either for BP_LAST or !BP_LAST for( m=0 ; m<ntime ; m++ ) { series1[m] = THD_get_voxel(outset,kk,m); series2[m] = THD_get_voxel(outsetALL,kk,m); } mm = gsl_fft_real_transform(series1, 1, ntime, real1, work); mm = gsl_fft_halfcomplex_unpack(series1, compl_freqs1, 1, ntime); mm = gsl_fft_real_transform(series2, 1, ntime, real2, work); mm = gsl_fft_halfcomplex_unpack(series2, compl_freqs2, 1, ntime); numer = 0.0f; denom = 0.0f; de_rsfa = 0.0f; nu_rsfa = 0.0f; for( m=1 ; m<N_ny ; m++ ) { mm = 2*m; pow2 = compl_freqs2[mm]*compl_freqs2[mm] + compl_freqs2[mm+1]*compl_freqs2[mm+1]; // power //pow2*=2;// factor of 2 since ampls are even funcs denom+= (float) sqrt(pow2); // amplitude de_rsfa+= (float) pow2; if( ( m>=ind_low ) && ( m<=ind_high ) ){ pow1 = compl_freqs1[mm]*compl_freqs1[mm]+ compl_freqs1[mm+1]*compl_freqs1[mm+1]; //pow1*=2; numer+= (float) sqrt(pow1); nu_rsfa+= (float) pow1; } } if( denom>0.000001 ) falff[kk] = numer/denom; else falff[kk] = 0.; alff[kk] = 2*numer/sqnt;// factor of 2 since ampl is even funct meanALFF+= alff[kk]; if(DO_RSFA){ nu_rsfa = sqrt(2*nu_rsfa); // factor of 2 since ampls de_rsfa = sqrt(2*de_rsfa); // are even funcs if( de_rsfa>0.000001 ) frsfa[kk] = nu_rsfa/de_rsfa; else frsfa[kk]=0.; rsfa[kk] = nu_rsfa/nt_fac; meanRSFA+= rsfa[kk]; } ctr+=1; } } meanALFF/= ctr; meanRSFA/= ctr; gsl_fft_real_wavetable_free(real1); gsl_fft_real_wavetable_free(real2); gsl_fft_real_workspace_free(work); // ALFFs divided by mean of brain value for( kk=0 ; kk<nvox ; kk++ ) if(mask[kk]){ malff[kk] = alff[kk]/meanALFF; if(DO_RSFA) mrsfa[kk] = rsfa[kk]/meanRSFA; } // ************************************************************** // ************************************************************** // Store and output // ************************************************************** // ************************************************************** outsetALFF = EDIT_empty_copy( inset ) ; sprintf(out_alff,"%s_ALFF",prefix); EDIT_dset_items( outsetALFF, ADN_nvals, 1, ADN_datum_all , MRI_float , ADN_prefix , out_alff, ADN_none ) ; if( !THD_ok_overwrite() && THD_is_ondisk(DSET_HEADNAME(outsetALFF)) ) ERROR_exit("Can't overwrite existing dataset '%s'", DSET_HEADNAME(outsetALFF)); EDIT_substitute_brick(outsetALFF, 0, MRI_float, alff); alff=NULL; THD_load_statistics(outsetALFF); tross_Make_History("3dRSFC", argc, argv, outsetALFF); THD_write_3dim_dataset(NULL, NULL, outsetALFF, True); outsetfALFF = EDIT_empty_copy( inset ) ; sprintf(out_falff,"%s_fALFF",prefix); EDIT_dset_items( outsetfALFF, ADN_nvals, 1, ADN_datum_all , MRI_float , ADN_prefix , out_falff, ADN_none ) ; if( !THD_ok_overwrite() && THD_is_ondisk(DSET_HEADNAME(outsetfALFF)) ) ERROR_exit("Can't overwrite existing dataset '%s'", DSET_HEADNAME(outsetfALFF)); EDIT_substitute_brick(outsetfALFF, 0, MRI_float, falff); falff=NULL; THD_load_statistics(outsetfALFF); tross_Make_History("3dRSFC", argc, argv, outsetfALFF); THD_write_3dim_dataset(NULL, NULL, outsetfALFF, True); outsetmALFF = EDIT_empty_copy( inset ) ; sprintf(out_malff,"%s_mALFF",prefix); EDIT_dset_items( outsetmALFF, ADN_nvals, 1, ADN_datum_all , MRI_float , ADN_prefix , out_malff, ADN_none ) ; if( !THD_ok_overwrite() && THD_is_ondisk(DSET_HEADNAME(outsetmALFF)) ) ERROR_exit("Can't overwrite existing dataset '%s'", DSET_HEADNAME(outsetmALFF)); EDIT_substitute_brick(outsetmALFF, 0, MRI_float, malff); malff=NULL; THD_load_statistics(outsetmALFF); tross_Make_History("3dRSFC", argc, argv, outsetmALFF); THD_write_3dim_dataset(NULL, NULL, outsetmALFF, True); if(DO_RSFA){ outsetRSFA = EDIT_empty_copy( inset ) ; sprintf(out_rsfa,"%s_RSFA",prefix); EDIT_dset_items( outsetRSFA, ADN_nvals, 1, ADN_datum_all , MRI_float , ADN_prefix , out_rsfa, ADN_none ) ; if( !THD_ok_overwrite() && THD_is_ondisk(DSET_HEADNAME(outsetRSFA)) ) ERROR_exit("Can't overwrite existing dataset '%s'", DSET_HEADNAME(outsetRSFA)); EDIT_substitute_brick(outsetRSFA, 0, MRI_float, rsfa); rsfa=NULL; THD_load_statistics(outsetRSFA); tross_Make_History("3dRSFC", argc, argv, outsetRSFA); THD_write_3dim_dataset(NULL, NULL, outsetRSFA, True); outsetfRSFA = EDIT_empty_copy( inset ) ; sprintf(out_frsfa,"%s_fRSFA",prefix); EDIT_dset_items( outsetfRSFA, ADN_nvals, 1, ADN_datum_all , MRI_float , ADN_prefix , out_frsfa, ADN_none ) ; if( !THD_ok_overwrite() && THD_is_ondisk(DSET_HEADNAME(outsetfRSFA)) ) ERROR_exit("Can't overwrite existing dataset '%s'", DSET_HEADNAME(outsetfRSFA)); EDIT_substitute_brick(outsetfRSFA, 0, MRI_float, frsfa); frsfa=NULL; THD_load_statistics(outsetfRSFA); tross_Make_History("3dRSFC", argc, argv, outsetfRSFA); THD_write_3dim_dataset(NULL, NULL, outsetfRSFA, True); outsetmRSFA = EDIT_empty_copy( inset ) ; sprintf(out_mrsfa,"%s_mRSFA",prefix); EDIT_dset_items( outsetmRSFA, ADN_nvals, 1, ADN_datum_all , MRI_float , ADN_prefix , out_mrsfa, ADN_none ) ; if( !THD_ok_overwrite() && THD_is_ondisk(DSET_HEADNAME(outsetmRSFA)) ) ERROR_exit("Can't overwrite existing dataset '%s'", DSET_HEADNAME(outsetmRSFA)); EDIT_substitute_brick(outsetmRSFA, 0, MRI_float, mrsfa); mrsfa=NULL; THD_load_statistics(outsetmRSFA); tross_Make_History("3dRSFC", argc, argv, outsetmRSFA); THD_write_3dim_dataset(NULL, NULL, outsetmRSFA, True); } // ************************************************************ // ************************************************************ // Freeing // ************************************************************ // ************************************************************ DSET_delete(inset); DSET_delete(outsetALL); DSET_delete(outset); DSET_delete(outsetALFF); DSET_delete(outsetmALFF); DSET_delete(outsetfALFF); DSET_delete(outsetRSFA); DSET_delete(outsetmRSFA); DSET_delete(outsetfRSFA); free(inset); free(outsetALL); free(outset); free(outsetALFF); free(outsetmALFF); free(outsetfALFF); free(outsetRSFA); free(outsetmRSFA); free(outsetfRSFA); free(rsfa); free(mrsfa); free(frsfa); free(alff); free(malff); free(falff); free(mask); free(series1); free(series2); free(xx1); free(xx2); exit(0) ; }
int main( int argc , char *argv[] ) { int vstep=0 , ii,nvox , ntin , ntout , do_one=0 , nup=-1 ; THD_3dim_dataset *inset=NULL , *outset ; char *prefix="Upsam", *dsetname=NULL ; int verb=0 , iarg=1, datum = MRI_float; float *ivec , *ovec , trin , trout, *fac=NULL, *ofac=NULL, top=0.0, maxtop=0.0; /*------- help the pitifully ignorant user? -------*/ if( argc < 2 || strcmp(argv[1],"-help") == 0 ){ printf( "Usage: 3dUpsample [options] n dataset\n" "\n" "* Upsamples a 3D+time dataset, in the time direction,\n" " by a factor of 'n'.\n" "* The value of 'n' must be between 2 and 320 (inclusive).\n" "* The output dataset is in float format by default.\n" "\n" "Options:\n" "--------\n" " -1 or -one = Use linear interpolation. Otherwise,\n" " or -linear 7th order polynomial interpolation is used.\n" "\n" " -prefix pp = Define the prefix name of the output dataset.\n" " [default prefix is 'Upsam']\n" "\n" " -verb = Be eloquently and mellifluosly verbose.\n" "\n" " -n n = An alternate way to specify n\n" " -input dataset = An alternate way to specify dataset\n" "\n" " -datum ddd = Use datatype ddd at output. Choose from\n" " float (default), short, byte.\n" "Example:\n" "--------\n" " 3dUpsample -prefix LongFred 5 Fred+orig\n" "\n" "Nota Bene:\n" "----------\n" "* You should not use this for files that were 3dTcat-ed across\n" " imaging run boundaries, since that will result in interpolating\n" " between non-contiguous time samples!\n" "* If the input has M time points, the output will have n*M time\n" " points. The last n-1 of them will be past the end of the original\n" " time series.\n" "* This program gobbles up memory and diskspace as a function of n.\n" " You can reduce output file size with -datum option.\n" "\n" "--- RW Cox - April 2008\n" ) ; PRINT_COMPILE_DATE ; exit(0) ; } mainENTRY("3dUpsample"); machdep(); PRINT_VERSION("3dUpsample"); AUTHOR("RWCox") ; AFNI_logger("3dUpsample",argc,argv); /*------- read command line args -------*/ datum = MRI_float; iarg = 1 ; while( iarg < argc && argv[iarg][0] == '-' ){ if( strncasecmp(argv[iarg],"-prefix",5) == 0 ){ if( ++iarg >= argc ) ERROR_exit("Need argument after '%s'",argv[iarg-1]); prefix = argv[iarg] ; if( !THD_filename_ok(prefix) ) ERROR_exit("Illegal string after -prefix: '%s'",prefix) ; iarg++ ; continue ; } if( strncasecmp(argv[iarg],"-one",4) == 0 || strcmp (argv[iarg],"-1" ) == 0 || strncasecmp(argv[iarg],"-lin",4) == 0 ){ do_one = 1 ; iarg++ ; continue ; } if( strncasecmp(argv[iarg],"-verb",3) == 0 ){ verb = 1 ; iarg++ ; continue ; } if( strcasecmp(argv[iarg],"-n") == 0 ){ if( ++iarg >= argc ) ERROR_exit("Need argument after '%s'",argv[iarg-1]); nup = (int)strtod(argv[iarg],NULL) ; if( nup < 2 || nup > 320 ) ERROR_exit("3dUpsample rate '%d' is outside range 2..320",nup) ; iarg++ ; continue ; } if( strcasecmp(argv[iarg],"-input") == 0 ){ if( ++iarg >= argc ) ERROR_exit("Need argument after '%s'",argv[iarg-1]); dsetname = argv[iarg]; iarg++ ; continue ; } if( strcasecmp(argv[iarg],"-datum") == 0 ){ if( ++iarg >= argc ) ERROR_exit("Need argument after '%s'",argv[iarg-1]); if( strcmp(argv[iarg],"short") == 0 ){ datum = MRI_short ; } else if( strcmp(argv[iarg],"float") == 0 ){ datum = MRI_float ; } else if( strcmp(argv[iarg],"byte") == 0 ){ datum = MRI_byte ; } else { ERROR_message("-datum of type '%s' not supported in 3dUpsample!\n", argv[iarg] ) ; exit(1) ; } iarg++ ; continue ; } ERROR_message("Unknown argument on command line: '%s'",argv[iarg]) ; suggest_best_prog_option(argv[0], argv[iarg]); exit (1); } /*------- check options for completeness and consistency -----*/ if (nup == -1) { if( iarg+1 >= argc ) ERROR_exit("need 'n' and 'dataset' on command line!") ; nup = (int)strtod(argv[iarg++],NULL) ; if( nup < 2 || nup > 320 ) ERROR_exit("3dUpsample rate '%d' is outside range 2..320",nup) ; } if (!dsetname) { if( iarg >= argc ) ERROR_exit("need 'dataset' on command line!") ; dsetname = argv[iarg]; } inset = THD_open_dataset(dsetname) ; if( !ISVALID_DSET(inset) ) ERROR_exit("3dUpsample can't open dataset '%s'", dsetname) ; ntin = DSET_NVALS(inset) ; trin = DSET_TR(inset) ; if( ntin < 2 ) ERROR_exit("dataset '%s' has only 1 value per voxel?!",dsetname) ; nvox = DSET_NVOX(inset) ; if( verb ) INFO_message("loading input dataset into memory") ; DSET_load(inset) ; CHECK_LOAD_ERROR(inset) ; /*------ create output dataset ------*/ ntout = ntin * nup ; trout = trin / nup ; /* scaling factor for output */ fac = NULL; maxtop = 0.0; if (MRI_IS_INT_TYPE(datum)) { fac = (float *)calloc(DSET_NVALS(inset), sizeof(float)); ofac = (float *)calloc(ntout, sizeof(float)); for (ii=0; ii<DSET_NVALS(inset); ++ii) { top = MCW_vol_amax( DSET_NVOX(inset),1,1 , DSET_BRICK_TYPE(inset,ii), DSET_BRICK_ARRAY(inset,ii) ) ; if (DSET_BRICK_FACTOR(inset, ii)) top = top * DSET_BRICK_FACTOR(inset,ii); fac[ii] = (top > MRI_TYPE_maxval[datum]) ? top/MRI_TYPE_maxval[datum] : 0.0 ; if (top > maxtop) maxtop = top; } if (storage_mode_from_filename(prefix) != STORAGE_BY_BRICK) { fac[0] = (maxtop > MRI_TYPE_maxval[datum]) ? maxtop/MRI_TYPE_maxval[datum] : 0.0 ; for (ii=0; ii<ntout; ++ii) ofac[ii] = fac[0]; if (verb) INFO_message("Forcing global scaling, Max = %f, fac = %f\n", maxtop, fac[0]); } else { if (verb) INFO_message("Reusing scaling factors of input dset\n"); upsample_1( nup, DSET_NVALS(inset), fac, ofac); } } free(fac); fac = NULL; outset = EDIT_empty_copy(inset) ; EDIT_dset_items( outset , ADN_nvals , ntout , ADN_ntt , DSET_NUM_TIMES(inset) > 1 ? ntout : 0 , ADN_datum_all , datum , ADN_brick_fac , ofac , ADN_prefix , prefix , ADN_none ) ; tross_Copy_History( inset , outset ) ; tross_Make_History( "3dUpsample" , argc,argv , outset ) ; free(ofac); ofac = NULL; if( outset->taxis != NULL ){ outset->taxis->ttdel /= nup ; outset->taxis->ttdur /= nup ; if( outset->taxis->toff_sl != NULL ){ for( ii=0 ; ii < outset->taxis->nsl ; ii++ ) outset->taxis->toff_sl[ii] /= nup ; } } for( ii=0 ; ii < ntout ; ii++ ){ /* create empty bricks to be filled below */ EDIT_substitute_brick( outset , ii , datum , NULL ) ; } /*------- loop over voxels and process them one at a time ---------*/ if( verb ) INFO_message("Upsampling time series from %d to %d: %s interpolation", ntin , ntout , (do_one) ? "linear" : "heptic" ) ; if( verb && nvox > 499 ) vstep = nvox / 50 ; if( vstep > 0 ) fprintf(stderr,"++ voxel loop: ") ; ivec = (float *)malloc(sizeof(float)*ntin) ; ovec = (float *)malloc(sizeof(float)*ntout) ; for( ii=0 ; ii < nvox ; ii++ ){ if( vstep > 0 && ii%vstep==vstep-1 ) vstep_print() ; THD_extract_array( ii , inset , 0 , ivec ) ; if( do_one ) upsample_1( nup , ntin , ivec , ovec ) ; else upsample_7( nup , ntin , ivec , ovec ) ; THD_insert_series( ii , outset , ntout , MRI_float , ovec , datum==MRI_float ? 1:0 ) ; } /* end of loop over voxels */ if( vstep > 0 ) fprintf(stderr," Done!\n") ; /*----- clean up and go away -----*/ DSET_write(outset) ; if( verb ) WROTE_DSET(outset) ; if( verb ) INFO_message("Total CPU time = %.1f s",COX_cpu_time()) ; exit(0); }
int main( int argc , char * argv[] ) { int iarg=1 , dcode=0 , maxgap=2 , nftot=0 ; char * prefix="zfillin" , * dstr=NULL; THD_3dim_dataset * inset , * outset ; MRI_IMAGE * brim ; int verb=0 ; if( argc < 2 || strcmp(argv[1],"-help") == 0 ){ printf("Usage: 3dZFillin [options] dataset\n" "Extracts 1D rows in the given direction from a 3D dataset,\n" "searches for zeros that are 'close' to nonzero values in the row,\n" "and replaces the zeros with the closest nonzero neighbor.\n" "\n" "OPTIONS:\n" " -maxstep N = set the maximum distance to a neighbor\n" " [default=2].\n" " -dir D = set the direction of fill to 'D', which can\n" " be one of the following:\n" " A-P, P-A, I-S, S-I, L-R, R-L, x, y, z\n" " The first 6 are anatomical directions;\n" " the last 3 are reference to the dataset\n" " internal axes [no default value].\n" " -prefix P = set the prefix to 'P' for the output dataset.\n" "\n" "N.B.: * If the input dataset has more than one sub-brick,\n" " only the first one will be processed.\n" " * At this time, 3dZFillin only works on byte-valued datasets\n" "\n" "This program's only purpose is to fill up the Talairach Daemon\n" "bricks obtained from the UT San Antonio database.\n" "\n" ) ; PRINT_COMPILE_DATE ; exit(0) ; } mainENTRY("3dZFillin main") ; machdep() ; AFNI_logger("3dZfillin",argc,argv) ; PRINT_VERSION(3dZFillin") ; /*-- scan args --*/ while( iarg < argc && argv[iarg][0] == '-' ){ if( strncmp(argv[iarg],"-verb",5) == 0 ){ verb++ ; iarg++ ; continue ; } if( strcmp(argv[iarg],"-prefix") == 0 ){ prefix = argv[++iarg] ; if( !THD_filename_ok(prefix) ){ fprintf(stderr,"*** Illegal string after -prefix!\n"); exit(1) ; } iarg++ ; continue ; } if( strcmp(argv[iarg],"-maxstep") == 0 ){ maxgap = strtol( argv[++iarg] , NULL , 10 ) ; if( maxgap < 1 ){ fprintf(stderr,"*** Illegal value after -maxgap!\n"); exit(1); } iarg++ ; continue ; } if( strcmp(argv[iarg],"-dir") == 0 ){ dstr = argv[++iarg] ; iarg++ ; continue ; } fprintf(stderr,"*** Illegal option: %s\n",argv[iarg]) ; exit(1) ; } if( dstr == NULL ){ fprintf(stderr,"*** No -dir option on command line!\n"); exit(1); } if( iarg >= argc ){ fprintf(stderr,"*** No input dataset on command line!\n"); exit(1); } inset = THD_open_dataset( argv[iarg] ) ; if( inset == NULL ){ fprintf(stderr,"*** Can't open dataset %s\n",argv[iarg]); exit(1); } outset = EDIT_empty_copy( inset ) ; EDIT_dset_items( outset , ADN_prefix , prefix , ADN_none ) ; if( THD_deathcon() && THD_is_file( DSET_HEADNAME(outset) ) ){ fprintf(stderr,"** Output file %s exists -- cannot overwrite!\n", DSET_HEADNAME(outset) ) ; exit(1) ; } tross_Copy_History( inset , outset ) ; tross_Make_History( "3dZFillin" , argc,argv , outset ) ; if( DSET_NVALS(inset) > 1 ){ fprintf(stderr,"++ WARNING: input dataset has more than one sub-brick!\n"); EDIT_dset_items( outset , ADN_ntt , 0 , ADN_nvals , 1 , ADN_none ) ; } if( DSET_BRICK_TYPE(outset,0) != MRI_byte ){ fprintf(stderr,"*** This program only works on byte datasets!\n"); exit(1) ; } switch( *dstr ){ case 'x': dcode = 1 ; break ; case 'y': dcode = 2 ; break ; case 'z': dcode = 3 ; break ; default: if( *dstr == ORIENT_tinystr[outset->daxes->xxorient][0] || *dstr == ORIENT_tinystr[outset->daxes->xxorient][1] ) dcode = 1 ; if( *dstr == ORIENT_tinystr[outset->daxes->yyorient][0] || *dstr == ORIENT_tinystr[outset->daxes->yyorient][1] ) dcode = 2 ; if( *dstr == ORIENT_tinystr[outset->daxes->zzorient][0] || *dstr == ORIENT_tinystr[outset->daxes->zzorient][1] ) dcode = 3 ; break ; } if( dcode == 0 ){ fprintf(stderr,"*** Illegal -dir direction!\n") ; exit(1) ; } if( verb ) fprintf(stderr,"++ Direction = axis %d in dataset\n",dcode) ; DSET_load(inset) ; CHECK_LOAD_ERROR(inset) ; brim = mri_copy( DSET_BRICK(inset,0) ) ; DSET_unload(inset) ; EDIT_substitute_brick( outset , 0 , brim->kind , mri_data_pointer(brim) ) ; nftot = THD_dataset_zfillin( outset , 0 , dcode , maxgap ) ; fprintf(stderr,"++ Number of voxels filled = %d\n",nftot) ; if (DSET_write(outset) != False) { fprintf(stderr,"++ output dataset: %s\n",DSET_BRIKNAME(outset)) ; exit(0) ; } else { fprintf(stderr, "** 3dZFillin: Failed to write output!\n" ) ; exit(1) ; } }
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) ; }