MRI_IMARR * THD_medmad_bricks( THD_3dim_dataset *dset ) { int nvox , nvals , ii ; MRI_IMAGE *tsim , *madim, *medim ; float *madar, *medar ; MRI_IMARR *imar ; float *tsar ; ENTRY("THD_medmad_bricks") ; if( !ISVALID_DSET(dset) ) RETURN(NULL) ; nvals = DSET_NVALS(dset) ; if( nvals == 1 ) RETURN(NULL) ; DSET_load(dset) ; if( !DSET_LOADED(dset) ) RETURN(NULL) ; tsim = DSET_BRICK(dset,0) ; madim = mri_new_conforming( tsim , MRI_float ) ; madar = MRI_FLOAT_PTR(madim) ; medim = mri_new_conforming( tsim , MRI_float ) ; medar = MRI_FLOAT_PTR(medim) ; nvox = DSET_NVOX(dset) ; tsar = (float *) calloc( sizeof(float),nvals+1 ) ; for( ii=0 ; ii < nvox ; ii++ ){ THD_extract_array( ii , dset , 0 , tsar ) ; qmedmad_float( nvals , tsar , medar+ii , madar+ii ) ; } free(tsar) ; INIT_IMARR(imar) ; ADDTO_IMARR(imar,medim) ; ADDTO_IMARR(imar,madim) ; RETURN(imar) ; }
MRI_IMARR * IMARR_medmad_bricks( MRI_IMARR *dmar ) { int nvox , nvals , ii , kk ; MRI_IMAGE *tsim , *madim, *medim ; float *madar, *medar ; MRI_IMARR *imar ; float *tsar , **dar ; ENTRY("IMARR_medmad_bricks") ; if( dmar == NULL || IMARR_COUNT(dmar) < 2 ) RETURN(NULL) ; nvals = IMARR_COUNT(dmar) ; tsim = IMARR_SUBIM(dmar,0) ; madim = mri_new_conforming( tsim , MRI_float ) ; madar = MRI_FLOAT_PTR(madim) ; medim = mri_new_conforming( tsim , MRI_float ) ; medar = MRI_FLOAT_PTR(medim) ; nvox = tsim->nvox ; dar = (float **)malloc(sizeof(float *)*nvals) ; for( kk=0 ; kk < nvals ; kk++ ) dar[kk] = MRI_FLOAT_PTR( IMARR_SUBIM(dmar,kk) ) ; tsar = (float *) calloc( sizeof(float),nvals+1 ) ; for( ii=0 ; ii < nvox ; ii++ ){ for( kk=0 ; kk < nvals ; kk++ ) tsar[kk] = dar[kk][ii] ; qmedmad_float( nvals , tsar , medar+ii , madar+ii ) ; } free(tsar) ; free(dar) ; INIT_IMARR(imar) ; ADDTO_IMARR(imar,medim) ; ADDTO_IMARR(imar,madim) ; RETURN(imar) ; }
MRI_IMARR * mri_complex_to_pair( MRI_IMAGE * cim ) { MRI_IMARR * imarr ; MRI_IMAGE * rim , * iim ; register int ii , nvox ; register float * rar , * iar ; register complex * car ; ENTRY("mri_complex_to_pair") ; if( cim == NULL || cim->kind != MRI_complex ) RETURN( NULL ); rim = mri_new_conforming( cim , MRI_float ) ; rar = MRI_FLOAT_PTR(rim) ; iim = mri_new_conforming( cim , MRI_float ) ; iar = MRI_FLOAT_PTR(iim) ; car = MRI_COMPLEX_PTR(cim) ; nvox = cim->nvox ; for( ii=0 ; ii < nvox ; ii++ ){ rar[ii] = car[ii].r ; iar[ii] = car[ii].i ; } INIT_IMARR(imarr) ; ADDTO_IMARR(imarr,rim) ; ADDTO_IMARR(imarr,iim) ; RETURN( imarr ); }
MRI_IMARR * mri_rgb_to_3byte( MRI_IMAGE *oldim ) /* 15 Apr 1999 */ { MRI_IMARR *imar ; MRI_IMAGE *rim , *gim , *bim ; byte *rr , *gg , *bb , *rgb ; int ii , npix ; ENTRY("mri_rgb_to_3byte") ; if( oldim == NULL || oldim->kind != MRI_rgb ) RETURN( NULL ); rim = mri_new_conforming( oldim , MRI_byte ) ; rr = MRI_BYTE_PTR(rim) ; gim = mri_new_conforming( oldim , MRI_byte ) ; gg = MRI_BYTE_PTR(gim) ; bim = mri_new_conforming( oldim , MRI_byte ) ; bb = MRI_BYTE_PTR(bim) ; rgb= MRI_BYTE_PTR(oldim); npix = oldim->nvox ; for( ii=0 ; ii < npix ; ii++ ){ rr[ii] = rgb[3*ii ] ; gg[ii] = rgb[3*ii+1] ; bb[ii] = rgb[3*ii+2] ; } INIT_IMARR(imar) ; ADDTO_IMARR(imar,rim) ; ADDTO_IMARR(imar,gim) ; ADDTO_IMARR(imar,bim) ; RETURN( imar ); }
MRI_IMAGE * mri_bport( float dt, float fbot, float ftop, int nblock, int *ntim ) { MRI_IMAGE *tim ; MRI_IMARR *bimar ; int nrow , nbef , naft , tt ; ENTRY("mri_bport") ; if( nblock <= 0 || ntim == NULL ) RETURN(NULL) ; if( nblock == 1 ){ tim = mri_bport_contig( dt,fbot,ftop , ntim[0],0,0 ) ; RETURN(tim) ; } for( nrow=tt=0 ; tt < nblock ; tt++ ){ if( ntim[tt] < 9 ) RETURN(NULL) ; nrow += ntim[tt] ; } INIT_IMARR(bimar) ; nbef = 0 ; naft = nrow - ntim[0] ; for( tt=0 ; tt < nblock ; tt++ ){ tim = mri_bport_contig( dt,fbot,ftop , ntim[tt],nbef,naft ) ; if( tim == NULL ){ DESTROY_IMARR(bimar) ; RETURN(NULL) ; } ADDTO_IMARR(bimar,tim) ; if( tt < nblock-1 ){ nbef += ntim[tt]; naft -= ntim[tt+1]; } } tim = mri_catvol_1D( bimar , 2 ) ; DESTROY_IMARR(bimar) ; RETURN(tim) ; }
MRI_IMARR * LSS_mangle_matrix( MRI_IMAGE *ima, int jbot, int jtop ) { int ii , jj , jnew , jn , njj , nn,mm ; MRI_IMAGE *imb , *imc ; MRI_IMARR *imar ; float *aa , *bb , *cc , *acol , *bcol , *ccol ; ENTRY("LSS_mangle_matrix") ; if( ima == NULL || ima->kind != MRI_float ) RETURN(NULL) ; nn = ima->nx ; mm = ima->ny ; njj = jtop-jbot+1 ; if( njj <= 1 ) RETURN(NULL) ; if( jbot < 0 || jtop >= mm ) RETURN(NULL) ; imb = mri_new( nn , mm-njj+1 , MRI_float ) ; /* matrix without jbot..jtop */ imc = mri_new( nn , njj , MRI_float ) ; /* matrix with jbot..jtop */ aa = MRI_FLOAT_PTR(ima) ; bb = MRI_FLOAT_PTR(imb) ; cc = MRI_FLOAT_PTR(imc) ; /* copy non-excised columns into the new imb */ for( jn=jj=0 ; jj < mm ; jj++ ){ if( jj >= jbot && jj <= jtop ) continue ; acol = aa + jj*nn ; /* jj = old column index */ bcol = bb + jn*nn ; jn++ ; /* jn = new column index */ for( ii=0 ; ii < nn ; ii++ ) bcol[ii] = acol[ii] ; } /* copy excised columns into the new imc, and also add them up into the last column of imb */ bcol = bb + (mm-njj)*nn ; /* last col of imb */ for( jn=0,jj=jbot ; jj <= jtop ; jj++ ){ acol = aa + jj*nn ; ccol = cc + jn*nn ; jn++ ; for( ii=0 ; ii < nn ; ii++ ){ ccol[ii] = acol[ii] ; bcol[ii] += acol[ii] ; } } INIT_IMARR(imar) ; ADDTO_IMARR(imar,imb) ; ADDTO_IMARR(imar,imc) ; RETURN(imar) ; }
void PH_redraw(void) { MRI_IMAGE * imc , * im3 ; MRI_IMARR * imar ; float fgap = 0.0 ; if( P_ima == NULL || P_imb == NULL ) return ; #if 0 fprintf(stderr,"PH_redraw: A:nx=%d ny=%d B:nx=%d ny=%d\n", P_ima->nx,P_ima->ny , P_imb->nx,P_imb->ny ) ; fprintf(stderr,"PH_redraw: calling mri_scramble\n") ; #endif imc = mri_scramble( P_ima,P_imb , 1.0-P_alpha,1.0-P_beta ) ; #if 0 if(imc==NULL)fprintf(stderr," - returned NULL!\n") ; #endif INIT_IMARR(imar) ; ADDTO_IMARR(imar,P_ima); ADDTO_IMARR(imar,imc); ADDTO_IMARR(imar,P_imb); #if 0 fprintf(stderr,"PH_redraw: calling mri_cat2D\n") ; if(imc!=NULL)fprintf(stderr," C:nx=%d ny=%d\n", imc->nx,imc->ny ) ; #endif im3 = mri_cat2D( 3,1 , 3 , &fgap , imar ) ; FREE_IMARR(imar) ; mri_free(imc) ; #if 0 if(im3==NULL)fprintf(stderr," - returned NULL!\n") ; fprintf(stderr,"PH_redraw: calling PH_popup_image\n") ; #endif P_handle = PH_popup_image( P_handle , im3 ) ; mri_free(im3) ; return ; }
MRI_IMARR * mri_to_imarr( MRI_IMAGE *imin ) { MRI_IMARR *imar ; MRI_IMAGE *qim ; int nx,ny,nz , kk ; if( imin == NULL ) return NULL ; nx = imin->nx ; ny = imin->ny ; nz = imin->nz ; INIT_IMARR(imar) ; for( kk=0 ; kk < nz ; kk++ ){ qim = mri_cut_3D( imin , 0,nx-1 , 0,ny-1 , kk,kk ) ; ADDTO_IMARR(imar,qim) ; } return imar ; }
MRI_IMARR * THD_extract_many_series( int ns, int *ind, THD_3dim_dataset *dset ) { MRI_IMARR *imar ; /* output */ MRI_IMAGE *im ; int nv , ival , kk ; char *iar ; /* brick in the input */ float **far ; /* 27 Feb 2003: ptrs to output */ ENTRY("THD_extract_many_series") ; if( ns <= 0 || ind == NULL | dset == NULL ) RETURN( NULL ); /* try to load dataset */ nv = dset->dblk->nvals ; iar = DSET_ARRAY(dset,0) ; if( iar == NULL ){ /* if data needs to be loaded from disk */ (void) THD_load_datablock( dset->dblk ) ; iar = DSET_ARRAY(dset,0) ; if( iar == NULL ){ static int nerr=0 ; if( nerr < 2 ){ ERROR_message("Can't load dataset %s",DSET_HEADNAME(dset)); nerr++; } RETURN( NULL ); } } /* create output */ far = (float **) malloc(sizeof(float *)*ns) ; /* 27 Feb 2003 */ NULL_CHECK(far) ; INIT_IMARR(imar) ; for( kk=0 ; kk < ns ; kk++ ){ im = mri_new( nv , 1 , MRI_float ) ; /* N.B.: now does 0 fill */ far[kk] = MRI_FLOAT_PTR(im) ; /* ptr to kk-th output series */ ADDTO_IMARR(imar,im) ; } /* fill the output */ switch( DSET_BRICK_TYPE(dset,0) ){ default: /* don't know what to do --> return nada */ DESTROY_IMARR(imar) ; free(far) ; RETURN( NULL ); case MRI_byte:{ byte * bar ; for( ival=0 ; ival < nv ; ival++ ){ bar = (byte *) DSET_ARRAY(dset,ival) ; if( bar != NULL ){ for( kk=0 ; kk < ns ; kk++ ){ far[kk][ival] = (float)bar[ind[kk]] ; } } } } break ; case MRI_short:{ short * bar ; for( ival=0 ; ival < nv ; ival++ ){ bar = (short *) DSET_ARRAY(dset,ival) ; if( bar != NULL ){ for( kk=0 ; kk < ns ; kk++ ){ far[kk][ival] = (float)bar[ind[kk]] ; } } } } break ; case MRI_float:{ float * bar ; for( ival=0 ; ival < nv ; ival++ ){ bar = (float *) DSET_ARRAY(dset,ival) ; if( bar != NULL ){ for( kk=0 ; kk < ns ; kk++ ){ far[kk][ival] = bar[ind[kk]] ; } } } } break ; #if 0 case MRI_int:{ int * bar ; for( ival=0 ; ival < nv ; ival++ ){ bar = (int *) DSET_ARRAY(dset,ival) ; if( bar != NULL ){ for( kk=0 ; kk < ns ; kk++ ){ far[kk][ival] = bar[ind[kk]] ; } } } } break ; case MRI_double:{ double * bar ; for( ival=0 ; ival < nv ; ival++ ){ bar = (double *) DSET_ARRAY(dset,ival) ; if( bar != NULL ){ for( kk=0 ; kk < ns ; kk++ ){ far[kk][ival] = (float)bar[ind[kk]] ; } } } } break ; #endif case MRI_complex:{ complex * bar ; for( ival=0 ; ival < nv ; ival++ ){ bar = (complex *) DSET_ARRAY(dset,ival) ; if( bar != NULL ){ for( kk=0 ; kk < ns ; kk++ ){ far[kk][ival] = bar[ind[kk]].r ; } } } } break ; } /* scale outputs, if needed */ if( THD_need_brick_factor(dset) ){ MRI_IMAGE *qim ; for( kk=0 ; kk < ns ; kk++ ){ im = IMARR_SUBIMAGE(imar,kk) ; qim = mri_mult_to_float( dset->dblk->brick_fac , im ) ; mri_free(im) ; IMARR_SUBIMAGE(imar,kk) = qim ; } } #if 0 /* 27 Feb 2003 */ /* convert to floats, if needed */ if( IMARR_SUBIMAGE(imar,0)->kind != MRI_float ){ MRI_IMAGE * qim ; for( kk=0 ; kk < ns ; kk++ ){ im = IMARR_SUBIMAGE(imar,kk) ; qim = mri_to_float( im ) ; mri_free(im) ; IMARR_SUBIMAGE(imar,kk) = qim ; } } #endif /* add time axis stuff to output images, if present */ if( dset->taxis != NULL ){ float zz , tt ; int kz ; for( kk=0 ; kk < ns ; kk++ ){ kz = ind[kk] / ( dset->daxes->nxx * dset->daxes->nyy ) ; zz = dset->daxes->zzorg + kz * dset->daxes->zzdel ; tt = THD_timeof( 0 , zz , dset->taxis ) ; im = IMARR_SUBIMAGE(imar,kk) ; im->xo = tt ; im->dx = dset->taxis->ttdel ; /* origin and delta */ if( dset->taxis->units_type == UNITS_MSEC_TYPE ){ /* convert to sec */ im->xo *= 0.001 ; im->dx *= 0.001 ; } } } else { for( kk=0 ; kk < ns ; kk++ ){ im = IMARR_SUBIMAGE(imar,kk) ; im->xo = 0.0 ; im->dx = 1.0 ; } } free(far) ; RETURN(imar); }
int main( int argc , char *argv[] ) { THD_3dim_dataset *inset=NULL ; byte *mask=NULL ; int mask_nx=0,mask_ny=0,mask_nz=0 , automask=0 , masknum=0 ; int iarg=1 , verb=1 , ntype=0 , nev,kk,ii,nxyz,nt ; float na,nb,nc , dx,dy,dz ; MRI_IMARR *imar=NULL ; int *ivox ; MRI_IMAGE *pim ; int do_vmean=0 , do_vnorm=0 , sval_itop=0 ; int polort=-1 ; float *ev ; MRI_IMARR *ortar ; MRI_IMAGE *ortim ; int nyort=0 ; float bpass_L=0.0f , bpass_H=0.0f , dtime ; int do_bpass=0 ; if( argc < 2 || strcmp(argv[1],"-help") == 0 ){ printf( "Usage: 3dmaskSVD [options] inputdataset\n" "Author: Zhark the Gloriously Singular\n" "\n" "* Computes the principal singular vector of the time series\n" " vectors extracted from the input dataset over the input mask.\n" " ++ You can use the '-sval' option to change which singular\n" " vectors are output.\n" "* The sign of the output vector is chosen so that the average\n" " of arctanh(correlation coefficient) over all input data\n" " vectors (from the mask) is positive.\n" "* The output vector is normalized: the sum of its components\n" " squared is 1.\n" "* You probably want to use 3dDetrend (or something similar) first,\n" " to get rid of annoying artifacts, such as motion, breathing,\n" " dark matter interactions with the brain, etc.\n" " ++ If you are lazy scum like Zhark, you might be able to get\n" " away with using the '-polort' option.\n" " ++ In particular, if your data time series has a nonzero mean,\n" " then you probably want at least '-polort 0' to remove the\n" " mean, otherwise you'll pretty much just get a constant\n" " time series as the principal singular vector!\n" "* An alternative to this program would be 3dmaskdump followed\n" " by 1dsvd, which could give you all the singular vectors you\n" " could ever want, and much more -- enough to confuse you for days.\n" " ++ In particular, although you COULD input a 1D file into\n" " 3dmaskSVD, the 1dsvd program would make much more sense.\n" "* This program will be pretty slow if there are over about 2000\n" " voxels in the mask. It could be made more efficient for\n" " such cases, but you'll have to give Zhark some 'incentive'.\n" "* Result vector goes to stdout. Redirect per your pleasures and needs.\n" "* Also see program 3dLocalSVD if you want to compute the principal\n" " singular time series vector from a neighborhood of EACH voxel.\n" " ++ (Which is a pretty slow operation!)\n" "* http://en.wikipedia.org/wiki/Singular_value_decomposition\n" "\n" "-------\n" "Options:\n" "-------\n" " -vnorm = L2 normalize all time series before SVD [recommended!]\n" " -sval a = output singular vectors 0 .. a [default a=0 = first one only]\n" " -mask mset = define the mask [default is entire dataset == slow!]\n" " -automask = you'll have to guess what this option does\n" " -polort p = if you are lazy and didn't run 3dDetrend (like Zhark)\n" " -bpass L H = bandpass [mutually exclusive with -polort]\n" " -ort xx.1D = time series to remove from the data before SVD-ization\n" " ++ You can give more than 1 '-ort' option\n" " ++ 'xx.1D' can contain more than 1 column\n" " -input ddd = alternative way to give the input dataset name\n" "\n" "-------\n" "Example:\n" "-------\n" " You have a mask dataset with discrete values 1, 2, ... 77 indicating\n" " some ROIs; you want to get the SVD from each ROI's time series separately,\n" " and then put these into 1 big 77 column .1D file. You can do this using\n" " a csh shell script like the one below:\n" "\n" " # Compute the individual SVD vectors\n" " foreach mm ( `count 1 77` )\n" " 3dmaskSVD -vnorm -mask mymask+orig\"<${mm}..${mm}>\" epi+orig > qvec${mm}.1D\n" " end\n" " # Glue them together into 1 big file, then delete the individual files\n" " 1dcat qvec*.1D > allvec.1D\n" " /bin/rm -f qvec*.1D\n" " # Plot the results to a JPEG file, then compute their correlation matrix\n" " 1dplot -one -nopush -jpg allvec.jpg allvec.1D\n" " 1ddot -terse allvec.1D > allvec_COR.1D\n" "\n" " [[ If you use the bash shell, you'll have to figure out the syntax ]]\n" " [[ yourself. Zhark has no sympathy for you bash shell infidels, and ]]\n" " [[ considers you only slightly better than those lowly Emacs users. ]]\n" " [[ And do NOT ever even mention 'nedit' in Zhark's august presence! ]]\n" ) ; PRINT_COMPILE_DATE ; exit(0) ; } /*---- official startup ---*/ PRINT_VERSION("3dmaskSVD"); mainENTRY("3dmaskSVD main"); machdep(); AFNI_logger("3dmaskSVD",argc,argv); AUTHOR("Zhark the Singular"); /*---- loop over options ----*/ INIT_IMARR(ortar) ; mpv_sign_meth = AFNI_yesenv("AFNI_3dmaskSVD_meansign") ; while( iarg < argc && argv[iarg][0] == '-' ){ if( strcasecmp(argv[iarg],"-bpass") == 0 ){ if( iarg+2 >= argc ) ERROR_exit("need 2 args after -bpass") ; bpass_L = (float)strtod(argv[++iarg],NULL) ; bpass_H = (float)strtod(argv[++iarg],NULL) ; if( bpass_L < 0.0f || bpass_H <= bpass_L ) ERROR_exit("Illegal values after -bpass: %g %g",bpass_L,bpass_H) ; iarg++ ; continue ; } if( strcmp(argv[iarg],"-ort") == 0 ){ /* 01 Oct 2009 */ int nx,ny ; if( ++iarg >= argc ) ERROR_exit("Need argument after '-ort'") ; ortim = mri_read_1D( argv[iarg] ) ; if( ortim == NULL ) ERROR_exit("-ort '%s': Can't read 1D file",argv[iarg]) ; nx = ortim->nx ; ny = ortim->ny ; if( nx == 1 && ny > 1 ){ MRI_IMAGE *tim=mri_transpose(ortim); mri_free(ortim); ortim = tim; ny = 1; } mri_add_name(argv[iarg],ortim) ; ADDTO_IMARR(ortar,ortim) ; nyort += ny ; iarg++ ; continue ; } if( strcmp(argv[iarg],"-polort") == 0 ){ char *qpt ; if( ++iarg >= argc ) ERROR_exit("Need argument after '-polort'") ; polort = (int)strtod(argv[iarg],&qpt) ; if( *qpt != '\0' ) WARNING_message("Illegal non-numeric value after -polort") ; iarg++ ; continue ; } if( strcmp(argv[iarg],"-vnorm") == 0 ){ do_vnorm = 1 ; 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],"-sval") == 0 ){ if( ++iarg >= argc ) ERROR_exit("Need argument after '-sval'") ; sval_itop = (int)strtod(argv[iarg],NULL) ; if( sval_itop < 0 ){ sval_itop = 0 ; WARNING_message("'-sval' reset to 0") ; } 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]) ; masknum = 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 two mask inputs!") ; automask = 1 ; iarg++ ; continue ; } ERROR_exit("Unknown option '%s'",argv[iarg]) ; } /*--- end of loop over options ---*/ /*---- 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]) ; } nt = DSET_NVALS(inset) ; /* vector lengths */ if( nt < 9 ) ERROR_exit("Must have at least 9 values per voxel") ; if( polort+1 >= nt ) ERROR_exit("'-polort %d' too big for time series length = %d",polort,nt) ; DSET_load(inset) ; CHECK_LOAD_ERROR(inset) ; nxyz = DSET_NVOX(inset) ; DSET_UNMSEC(inset) ; dtime = DSET_TR(inset) ; if( dtime <= 0.0f ) dtime = 1.0f ; do_bpass = (bpass_L < bpass_H) ; if( do_bpass ){ kk = THD_bandpass_OK( nt , dtime , bpass_L , bpass_H , 1 ) ; if( kk <= 0 ) ERROR_exit("Can't continue since -bpass setup is illegal") ; polort = -1 ; } /*--- deal with the masking ---*/ 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?") ; masknum = mmm = THD_countmask( DSET_NVOX(inset) , mask ) ; INFO_message("Number of voxels in automask = %d",mmm) ; if( mmm < 9 ) ERROR_exit("Automask is too small to process") ; } else { mask = (byte *)malloc(sizeof(byte)*nxyz) ; masknum = nxyz ; memset( mask , 1 , sizeof(byte)*nxyz ) ; INFO_message("Using all %d voxels in dataset",nxyz) ; } nev = MIN(nt,masknum) ; /* max possible number of eigenvalues */ if( sval_itop >= nev ){ sval_itop = nev-1 ; WARNING_message("'-sval' reset to '%d'",sval_itop) ; } mri_principal_vector_params( 0 , do_vnorm , sval_itop ) ; mri_principal_setev(nev) ; /*-- get data vectors --*/ ivox = (int *)malloc(sizeof(int)*masknum) ; for( kk=ii=0 ; ii < nxyz ; ii++ ) if( mask[ii] ) ivox[kk++] = ii ; INFO_message("Extracting data vectors") ; imar = THD_extract_many_series( masknum, ivox, inset ) ; DSET_unload(inset) ; if( imar == NULL ) ERROR_exit("Can't get data vector?!") ; /*-- detrending --*/ if( polort >= 0 || nyort > 0 || do_bpass ){ float **polref=NULL ; float *tsar ; int nort=IMARR_COUNT(ortar) , nref=0 ; if( polort >= 0 ){ /* polynomials */ nref = polort+1 ; polref = THD_build_polyref(nref,nt) ; } if( nort > 0 ){ /* other orts */ float *oar , *par ; int nx,ny , qq,tt ; for( kk=0 ; kk < nort ; kk++ ){ /* loop over input -ort files */ ortim = IMARR_SUBIM(ortar,kk) ; nx = ortim->nx ; ny = ortim->ny ; if( nx < nt ) ERROR_exit("-ort '%s' length %d shorter than dataset length %d" , ortim->name , nx , nt ) ; polref = (float **)realloc(polref,(nref+ny)*sizeof(float *)) ; oar = MRI_FLOAT_PTR(ortim) ; for( qq=0 ; qq < ny ; qq++,oar+=nx ){ par = polref[nref+qq] = (float *)malloc(sizeof(float)*nt) ; for( tt=0 ; tt < nt ; tt++ ) par[tt] = oar[tt] ; if( polort == 0 ) THD_const_detrend (nt,par,NULL) ; else if( polort > 0 ) THD_linear_detrend(nt,par,NULL,NULL) ; } nref += ny ; } DESTROY_IMARR(ortar) ; } if( !do_bpass ){ /* old style ort-ification */ MRI_IMAGE *imq , *imp ; float *qar ; INFO_message("Detrending data vectors") ; #if 1 imq = mri_new( nt , nref , MRI_float) ; qar = MRI_FLOAT_PTR(imq) ; for( kk=0 ; kk < nref ; kk++ ) memcpy( qar+kk*nt , polref[kk] , sizeof(float)*nt ) ; imp = mri_matrix_psinv( imq , NULL , 1.e-8 ) ; for( kk=0 ; kk < IMARR_COUNT(imar) ; kk++ ){ mri_matrix_detrend( IMARR_SUBIM(imar,kk) , imq , imp ) ; } mri_free(imp) ; mri_free(imq) ; #else for( kk=0 ; kk < IMARR_COUNT(imar) ; kk++ ){ tsar = MRI_FLOAT_PTR(IMARR_SUBIM(imar,kk)) ; THD_generic_detrend_LSQ( nt , tsar , -1 , nref , polref , NULL ) ; } #endif } else { /* bandpass plus (maybe) orts */ float **vec = (float **)malloc(sizeof(float *)*IMARR_COUNT(imar)) ; INFO_message("Bandpassing data vectors") ; for( kk=0 ; kk < IMARR_COUNT(imar) ; kk++ ) vec[kk] = MRI_FLOAT_PTR(IMARR_SUBIM(imar,kk)) ; (void)THD_bandpass_vectors( nt , IMARR_COUNT(imar) , vec , dtime , bpass_L , bpass_H , 2 , nref , polref ) ; free(vec) ; } for( kk=0 ; kk < nref; kk++ ) free(polref[kk]) ; free(polref) ; } /* end of detrendization */ /*--- the actual work ---*/ INFO_message("Computing SVD") ; pim = mri_principal_vector( imar ) ; DESTROY_IMARR(imar) ; if( pim == NULL ) ERROR_exit("SVD failure!?!") ; ev = mri_principal_getev() ; switch(sval_itop+1){ case 1: INFO_message("First singular value: %g",ev[0]) ; break ; case 2: INFO_message("First 2 singular values: %g %g",ev[0],ev[1]) ; break ; case 3: INFO_message("First 3 singular values: %g %g %g",ev[0],ev[1],ev[2]) ; break ; case 4: INFO_message("First 4 singular values: %g %g %g %g",ev[0],ev[1],ev[2],ev[3]) ; break ; default: case 5: INFO_message("First 5 singular values: %g %g %g %g %g",ev[0],ev[1],ev[2],ev[3],ev[4]) ; break ; } mri_write_1D(NULL,pim) ; exit(0) ; }
MRI_IMARR * THD_time_fit_dataset( THD_3dim_dataset *dset , int nref , float **ref , int meth , byte *mask ) { int ii , nvox,nval , qq,tt ; float *far , *fit , *var , val ; MRI_IMARR *imar ; MRI_IMAGE *qim ; float **fitar ; ENTRY("THD_time_fit_dataset") ; if( !ISVALID_DSET(dset) || nref < 1 || nref >= DSET_NVALS(dset) || ref == NULL ) RETURN(NULL) ; DSET_load(dset) ; if( !DSET_LOADED(dset) ) RETURN(NULL) ; /* construct output images */ INIT_IMARR(imar) ; fitar = (float **)malloc(sizeof(float *)*nref) ; for( qq=0 ; qq < nref ; qq++ ){ qim = mri_new_conforming( DSET_BRICK(dset,0) , MRI_float ) ; fitar[qq] = MRI_FLOAT_PTR(qim) ; ADDTO_IMARR(imar,qim) ; } qim = mri_new_conforming( DSET_BRICK(dset,0) , MRI_float ) ; var = MRI_FLOAT_PTR(qim) ; ADDTO_IMARR(imar,qim) ; nvox = DSET_NVOX(dset) ; nval = DSET_NVALS(dset) ; far = (float *)malloc(sizeof(float)*nval) ; fit = (float *)malloc(sizeof(float)*nref) ; for( ii=0 ; ii < nvox ; ii++ ){ if( !INMASK(ii) ) continue ; qq = THD_extract_array( ii , dset , 0 , far ) ; /* get data */ if( qq == 0 ){ switch(meth){ /* get fit */ default: case 2: THD_generic_detrend_LSQ( nval, far, -1, nref,ref, fit ); break; case 1: THD_generic_detrend_L1 ( nval, far, -1, nref,ref, fit ); break; } for( qq=0 ; qq < nref ; qq++ ) fitar[qq][ii] = fit[qq] ; /* save fit */ /* at this point, far[] contains the residuals */ switch(meth){ /* get stdev or MAD */ default: case 2:{ float mm,vv ; for( mm=0.0,tt=0 ; tt < nval ; tt++ ) mm += far[tt] ; mm /= nval ; for( vv=0.0,tt=0 ; tt < nval ; tt++ ) vv += (far[tt]-mm)*(far[tt]-mm) ; var[ii] = sqrtf( vv/(nval-1.0) ) ; } break ; case 1:{ for( tt=0 ; tt < nval ; tt++ ) far[tt] = fabsf(far[tt]) ; var[ii] = qmed_float( nval , far ) ; } break ; } } } free(fit); free(far); free(fitar); RETURN(imar); }
/*------------------------------------------------------------------------- * read data into image array, based on mosaic (fill image and image array) * (from mri_read_dicom.c 22 Dec 2010 [rickr] * * - fp : open file pointer (input/output) * - im : current image (output) * - imar : mosaic image array (output) * - flip_slices: whether to reverse slice order (output) * - mi : mosaic info (input) * - datum : type for image array (input) * - bpp : bytes per pixel (input) * - kor : slice direction orientation (input) * - swap : whether to byte swap data (input) * - dx,y,z : slice dimensions (input) * - dt : TR, if > 0 (input) * * return 0 on success * 1 on error */ int read_mosaic_data( FILE *fp, MRI_IMAGE *im, MRI_IMARR *imar, int * flip_slices, Siemens_extra_info *mi, int datum, int bpp, int kor, int swap, float dx, float dy, float dz, float dt) { /*-- 28 Oct 2002: is a 2D mosaic --*******************/ char * dar=NULL, * iar ; int nvox, yy, xx, nxx, ii, jj, slice ; int mos_nx, mos_ny, mos_nz, mos_ix, mos_iy, mosaic_num; int verb = g_dicom_ctrl.verb; /* typing ease, default level is 1 */ ENTRY("read_mosaic_data"); if( !mi->good ) { if( verb ) fprintf(stderr,"** apply_z_orient but not mosaic"); RETURN(1); } /* determine if slices should be reversed */ *flip_slices = flip_slices_mosaic(mi, kor); /* just to make it a little easier to read */ mos_nx = mi->mos_nx; mos_ny = mi->mos_ny; mos_ix = mi->mos_ix; mos_iy = mi->mos_ix; /* always square */ mos_nz = mos_ix * mos_iy ; /* number of slices in mosaic */ if( verb > 1 ) fprintf(stderr, "-- read_mosaic_data flip_slices %d " "mos_nx,ny,nz = %d,%d,%d mos_ix = %d\n", *flip_slices,mos_nx,mos_ny,mos_nz, mos_ix); mosaic_num = mi->mosaic_num; nvox = mos_nx*mos_ny*mos_nz ; /* total number of voxels */ if( g_dicom_ctrl.read_data ) { dar = (char*)calloc(bpp,nvox) ; /* make space for super-image */ if(dar==NULL) { /* exit if can't allocate memory */ ERROR_message("Could not allocate memory for mosaic volume"); RETURN(1); } fread( dar , bpp , nvox , fp ) ; /* read data directly into it */ if( swap ){ /* swap bytes? */ switch( bpp ){ default: break ; case 2: swap_twobytes ( nvox, dar ) ; break ; /* short */ case 4: swap_fourbytes( nvox, dar ) ; break ; /* int, float */ case 8: swap_fourbytes( 2*nvox, dar ) ; break ; /* complex */ } } } /* load data from dar into images */ nxx = mos_nx * mos_ix ; /* # pixels per mosaic line */ for (ii=0;ii<mosaic_num;ii++) { /* find right slice - may be reading the series of slices backwards */ if(*flip_slices) slice = mosaic_num - ii -1; else slice = ii; xx = slice % mos_ix; /* xx,yy are indices for position in mosaic matrix */ yy = slice / mos_iy; /* im = mri_new( mos_nx , mos_ny , datum ) ; */ im = mri_new_7D_generic(mos_nx,mos_ny, 1,1,1,1,1, datum, g_dicom_ctrl.read_data); if( !im ) { fprintf(stderr,"** RMD: failed to allocate %d voxel image\n", mos_nx * mos_ny); RETURN(1); } /* if reading data, actually copy data into MRI image */ if( g_dicom_ctrl.read_data ) { iar = mri_data_pointer( im ) ; /* sub-image array */ for( jj=0 ; jj < mos_ny ; jj++ ) /* loop over rows inside sub-image */ memcpy( iar + jj*mos_nx*bpp , dar + xx*mos_nx*bpp + (jj+yy*mos_ny)*nxx*bpp , mos_nx*bpp ) ; } if( dx > 0.0 && dy > 0.0 && dz > 0.0 ){ im->dx = dx; im->dy = dy; im->dz = dz; im->dw = 1.0; } if( dt > 0.0 ) im->dt = dt ; if( swap ) im->was_swapped = 1 ; ADDTO_IMARR(imar,im) ; } /* end of ii sub-image loop */ if( dar ) free(dar); /* don't need no more; copied all data out of it now */ /* truncate zero images out of tail of mosaic */ if( mosaic_num < IMARR_COUNT(imar) ) TRUNCATE_IMARR(imar,mosaic_num) ; if( verb > 1 ) fprintf(stderr,"\nmri_read_dicom Mosaic: mos_nx=%d mos_ny=%d mos_ix=%d" " mos_iy=%d slices=%d\n", mos_nx,mos_ny,mos_ix,mos_iy,IMARR_COUNT(imar)) ; /* MCHECK ; */ RETURN(0); }
MRI_IMARR * THD_get_many_timeseries( THD_string_array * dlist ) { int id , ii , ndir ; MRI_IMARR * outar=NULL, * tmpar=NULL ; char * epath , * eee ; char efake[] = "./" ; THD_string_array *qlist ; /* 02 Feb 2002 */ ENTRY("THD_get_many_timeseries") ; /*----- sanity check and initialize -----*/ epath = my_getenv( "AFNI_TSPATH" ) ; if( epath == NULL ) epath = my_getenv( "AFNI_TS_PATH" ) ; /* 07 Oct 1996 */ if( epath == NULL ) epath = efake ; /* 07 Oct 1996 */ ndir = (dlist != NULL) ? dlist->num : 0 ; if( ndir == 0 && epath == NULL ) RETURN( outar ) ; INIT_IMARR( outar ) ; INIT_SARR( qlist ) ; /*----- for each input directory, find all *.1D files -----*/ for( id=0 ; id < ndir ; id++ ){ ADDTO_SARR(qlist,dlist->ar[id]) ; tmpar = THD_get_all_timeseries( dlist->ar[id] ) ; if( tmpar == NULL ) continue ; for( ii=0 ; ii < tmpar->num ; ii++ ) /* move images to output array */ ADDTO_IMARR( outar , tmpar->imarr[ii] ) ; FREE_IMARR(tmpar) ; /* don't need this no more */ } /*----- also do directories in environment path, if any -----*/ if( epath != NULL ){ int epos =0 , ll = strlen(epath) ; char * elocal ; char ename[THD_MAX_NAME] ; /* copy path list into local memory */ elocal = (char *) malloc( sizeof(char) * (ll+2) ) ; if( elocal == NULL ){ fprintf(stderr, "\n*** THD_get_many_timeseries malloc failure - is memory full? ***\n"); EXIT(1) ; } strcpy( elocal , epath ) ; elocal[ll] = ' ' ; elocal[ll+1] = '\0' ; /* replace colons with blanks */ for( ii=0 ; ii < ll ; ii++ ) if( elocal[ii] == ':' ) elocal[ii] = ' ' ; /* extract blank delimited strings, use as directory names to get timeseries files */ do{ ii = sscanf( elocal+epos , "%s%n" , ename , &id ) ; if( ii < 1 ) break ; /* no read --> end of work */ epos += id ; /* epos = char after last one scanned */ ii = strlen(ename) ; /* make sure name has */ if( ename[ii-1] != '/' ){ /* a trailing '/' on it */ ename[ii] = '/' ; ename[ii+1] = '\0' ; } if( !THD_is_directory(ename) ) continue ; /* 21 May 2002 - rcr */ /* 02 Feb 2002: check if scanned this directory before */ for( ii=0 ; ii < qlist->num ; ii++ ) if( THD_equiv_files(qlist->ar[ii],ename) ) break ; if( ii < qlist->num ) continue ; /* skip to end of do loop */ ADDTO_SARR(qlist,ename) ; tmpar = THD_get_all_timeseries( ename ) ; /* read this directory */ if( tmpar != NULL ){ for( ii=0 ; ii < tmpar->num ; ii++ ) /* move images to output array */ ADDTO_IMARR( outar , tmpar->imarr[ii] ) ; FREE_IMARR(tmpar) ; /* don't need this no more */ } } while( epos < ll ) ; /* scan until 'epos' is after end of epath */ free(elocal) ; } if( IMARR_COUNT(outar) == 0 ) DESTROY_IMARR(outar) ; DESTROY_SARR(qlist) ; RETURN( outar ) ; }
float * mri_lsqfit( MRI_IMAGE * fitim , MRI_IMARR * refim , MRI_IMAGE * wtim ) { float *fit = NULL ; /* will be the output */ MRI_IMAGE *ffitim , *tim , *wim ; /* local versions of inputs */ MRI_IMARR *frefim ; int ii , jj , npix,nref ; float **refar , *fitar , *war ; ENTRY("mri_lsqfit") ; /****---- check inputs, convert to float type if needed ----****/ if( fitim == NULL ){ ERROR_message("mri_lsqfit has NULL fitim"); RETURN(NULL); } if( fitim->kind == MRI_float ) ffitim = fitim ; else ffitim = mri_to_float( fitim ) ; npix = ffitim->nvox ; fitar = mri_data_pointer(ffitim) ; if( wtim == NULL ){ wim = NULL ; war = NULL ; } else if( wtim->kind == MRI_float ){ wim = wtim ; war = mri_data_pointer( wim ) ; if( wim->nvox != npix ){ ERROR_message("mri_lsqfit: MISMATCH wtim->nvox=%d npix=%d", wtim->nvox , npix ); RETURN(NULL); } } else { wim = mri_to_float( wtim ) ; war = mri_data_pointer( wim ) ; if( wim->nvox != npix ){ ERROR_message("mri_lsqfit: MISMATCH wtim->nvox=%d npix=%d", wtim->nvox , npix ); RETURN(NULL); } } if( refim == NULL || refim->num < 1 ){ ERROR_message("mri_lsqfit: NULL refim"); RETURN(NULL); } nref = refim->num ; INIT_IMARR(frefim) ; refar = (float **) malloc( sizeof(float *) * nref ) ; if( refar == NULL ){ fprintf(stderr,"** mri_lsqfit: malloc failure for refar"); RETURN(NULL); } for( ii=0 ; ii < nref ; ii++ ){ if( refim->imarr[ii] == NULL ){ ERROR_message("mri_lsqfit: NULL refim[%d]!",ii); RETURN(NULL); } if( refim->imarr[ii]->nvox != npix ){ ERROR_message("mri_lsqfit: MISMATCH refim[%d]!",ii); RETURN(NULL); } if( refim->imarr[ii]->kind == MRI_float ) tim = refim->imarr[ii] ; else tim = mri_to_float(refim->imarr[ii]) ; ADDTO_IMARR(frefim,tim) ; refar[ii] = mri_data_pointer(tim) ; } /****---- get coefficients ----****/ fit = lsqfit( npix , fitar , war , nref , refar ) ; /****---- clean up and exit ----****/ if( ffitim != fitim ) mri_free( ffitim ) ; if( wim != NULL && wim != wtim ) mri_free( wim ) ; for( ii=0 ; ii < nref ; ii++ ){ if( frefim->imarr[ii] != refim->imarr[ii] ) mri_free( frefim->imarr[ii] ) ; } FREE_IMARR(frefim) ; free(refar) ; RETURN(fit) ; }
/*-------------------------------------------------------*/ MRI_IMARR * dset_to_mri(THD_3dim_dataset * dset) /*--------------------------------------------------------*/ { int ii, kk, ntime, datum; int nvox, nx, ny, nz; int use_fac; MRI_IMARR * ims_in; MRI_IMAGE * im, *temp_im; 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 * fac = NULL ; /* array of brick scaling factors */ float * fout; ntime = DSET_NUM_TIMES(dset) ; nx = dset->daxes->nxx; ny = dset->daxes->nyy; nz = dset->daxes->nzz; nvox = dset->daxes->nxx * dset->daxes->nyy * dset->daxes->nzz ; datum = DSET_BRICK_TYPE( dset , 0 ) ; /* get dataset datum type */ switch( datum ){ /* pointer type depends on input datum type */ default: 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..ntime-1. */ case MRI_byte: bptr = (byte **) malloc( sizeof(byte *) * ntime ) ; if( bptr == NULL ) return NULL ; for( kk=0 ; kk < ntime ; kk++ ) bptr[kk] = (byte *) DSET_ARRAY(dset,kk) ; break ; /*--------- input is shorts ---------*/ /* voxel #i at time #k is sptr[k][i] */ /* for i=0..nvox-1 and k=0..ntime-1. */ case MRI_short: sptr = (short **) malloc( sizeof(short *) * ntime ) ; if( sptr == NULL ) return NULL ; for( kk=0 ; kk < ntime; kk++ ) sptr[kk] = (short *) DSET_ARRAY(dset,kk) ; break ; /*--------- input is floats ---------*/ /* voxel #i at time #k is fptr[k][i] */ /* for i=0..nvox-1 and k=0..ntime-1. */ case MRI_float: fptr = (float **) malloc( sizeof(float *) * ntime) ; if( fptr == NULL ) return NULL ; for( kk=0 ; kk < ntime; kk++ ) fptr[kk] = (float *) DSET_ARRAY(dset,kk) ; break ; } /* end of switch on input type */ INIT_IMARR(ims_in) ; for( kk=0 ; kk < ntime ; kk++ ){ im = mri_new_vol_empty( nx , ny , nz , datum ) ; ADDTO_IMARR(ims_in,im) ; } for( kk=0 ; kk < ntime ; kk++ ){ im = IMARR_SUBIMAGE(ims_in,kk) ; switch( datum ){ case MRI_byte: mri_fix_data_pointer( bptr[kk], im ) ; break ; case MRI_short: mri_fix_data_pointer( sptr[kk], im ) ; break ; case MRI_float: mri_fix_data_pointer( fptr[kk], im ) ; break ; } } return(ims_in); }
int main( int argc , char *argv[] ) { int iarg , ii,jj,kk,mm , nvec , nx=0,ny , ff , vlen=4 ; MRI_IMAGE *tim , *vsim=NULL ; MRI_IMARR *tar ; char **vecnam , *tnam ; float *far , **tvec , *vsig=NULL , xsig,ysig ; float_quad qcor ; float_pair pci ; float corst, cor025, cor500, cor975 ; char fmt[256] ; int cormeth=0 ; /* 0=Pearson, 1=Spearman, 2=Quadrant, 3=Kendall tau_b */ float (*corfun)(int,float *,float *) ; /*-- start the AFNI machinery --*/ mainENTRY("1dCorrelate main") ; machdep() ; /* check for options */ iarg = 1 ; nvec = 0 ; while( iarg < argc && argv[iarg][0] == '-' ){ /* I get by with a little help from my friends? */ if( strcmp(argv[iarg],"-help") == 0 || strcmp(argv[iarg],"-h") == 0){ usage_1dCorrelate(strlen(argv[iarg])>3 ? 2:1); exit(0) ; } /*--- methods ---*/ if( toupper(argv[iarg][1]) == 'P' ){ cormeth = 0 ; iarg++ ; continue ; } if( toupper(argv[iarg][1]) == 'S' ){ cormeth = 1 ; iarg++ ; continue ; } if( toupper(argv[iarg][1]) == 'Q' ){ cormeth = 2 ; iarg++ ; continue ; } if( toupper(argv[iarg][1]) == 'K' ){ cormeth = 3 ; iarg++ ; continue ; } if( toupper(argv[iarg][1]) == 'T' ){ cormeth = 4 ; iarg++ ; continue ; } if( toupper(argv[iarg][1]) == 'U' ){ cormeth = 5 ; iarg++ ; continue ; } /*--- set nboot ---*/ if( strcasecmp(argv[iarg],"-nboot") == 0 || strcasecmp(argv[iarg],"-num") == 0 ){ iarg++ ; if( iarg >= argc ) ERROR_exit("Need argument after '-nboot'") ; nboot = (int)strtod(argv[iarg],NULL) ; if( nboot < NBMIN ){ WARNING_message("Replacing -nboot %d with %d",nboot,NBMIN) ; nboot = NBMIN ; } iarg++ ; continue ; } /*--- set alpha ---*/ if( strcasecmp(argv[iarg],"-alpha") == 0 ){ iarg++ ; if( iarg >= argc ) ERROR_exit("Need argument after '-alpha'") ; alpha = (float)strtod(argv[iarg],NULL) ; if( alpha < 1.0f ){ WARNING_message("Replacing -alpha %.1f with 1",alpha) ; alpha = 0.01f ; } else if( alpha > 20.0f ){ WARNING_message("Replacing -alpha %.1f with 20",alpha) ; alpha = 0.20f ; } else { alpha *= 0.01f ; /* convert from percent to fraction */ } iarg++ ; continue ; } /*--- block resampling ---*/ if( strcasecmp(argv[iarg],"-blk") == 0 || strcasecmp(argv[iarg],"-block") == 0 ){ doblk = 1 ; iarg++ ; continue ; } if( strcasecmp(argv[iarg],"-vsig") == 0 ){ if( vsim != NULL ) ERROR_exit("Can't use -vsig twice!") ; if( ++iarg >= argc ) ERROR_exit("Need argument after -vsig") ; vsim = mri_read_1D(argv[iarg]) ; if( vsim == NULL ) ERROR_exit("Can't read -vsig file '%s'",argv[iarg]) ; iarg++ ; continue ; } /*--- user should be flogged ---*/ ERROR_message("Monstrously illegal option '%s'",argv[iarg]) ; suggest_best_prog_option(argv[0], argv[iarg]); exit(1); } /*--- user should be flogged twice ---*/ if( argc < 2 ){ usage_1dCorrelate(1) ; exit(0) ; } if( iarg == argc ) ERROR_exit("No 1D files on command line!?\n") ; /* the function to compute the correlation */ corfun = cor_func[cormeth] ; /* check and assemble list of input 1D files */ ff = iarg ; INIT_IMARR(tar) ; for( ; iarg < argc ; iarg++ ){ tim = mri_read_1D( argv[iarg] ) ; if( tim == NULL ) ERROR_exit("Can't read 1D file '%s'",argv[iarg]) ; if( nx == 0 ){ nx = tim->nx ; if( nx < 3 ) ERROR_exit("1D file '%.77s' length=%d is less than 3",argv[iarg],nx) ; else if( nx < 7 ) WARNING_message("1D file '%.77s' length=%d is less than 7",argv[iarg],nx) ; } else if( tim->nx != nx ){ ERROR_exit("Length of 1D file '%.77s' [%d] doesn't match first file [%d]", argv[iarg] , tim->nx , nx ); } nvec += tim->ny ; ADDTO_IMARR(tar,tim) ; } /* user is really an idiot -- flogging's too good for him */ if( nvec < 2 ) ERROR_exit("Must have at least 2 input columns!") ; if( nx < 20 && doblk ){ doblk = 0 ; WARNING_message("Column length %d < 20 ==> cannot use block resampling",nx) ; } if( vsim != NULL ){ if( vsim->nvox < nvec ) ERROR_exit("-vsig file only has %d entries, but needs at least %d",vsim->nvox,nvec) ; vsig = MRI_FLOAT_PTR(vsim) ; } /* create vectors from 1D files */ tvec = (float **)malloc( sizeof(float *)*nvec ) ; vecnam = (char **)malloc( sizeof(char *)*nvec ) ; for( jj=0 ; jj < nvec ; jj++ ){ tvec[jj] = (float *)malloc( sizeof(float)*nx ) ; vecnam[jj] = (char *)malloc(sizeof(char)*THD_MAX_NAME) ; } /* copy data into new space, create output labels, check for stoopiditees */ for( kk=mm=0 ; mm < IMARR_COUNT(tar) ; mm++ ){ tim = IMARR_SUBIM(tar,mm) ; far = MRI_FLOAT_PTR(tim) ; tnam = tim->name ; if( tnam == NULL ) tnam = "File" ; for( jj=0 ; jj < tim->ny ; jj++,kk++ ){ for( ii=0 ; ii < nx ; ii++ ) tvec[kk][ii] = far[ii+jj*nx] ; sprintf(vecnam[kk],"%s[%d]",THD_trailname(tnam,0),jj) ; /* vector name */ iarg = strlen(vecnam[kk]) ; vlen = MAX(vlen,iarg) ; if( THD_is_constant(nx,tvec[kk]) ) ERROR_exit("Column %s is constant!",vecnam[kk]) ; } } DESTROY_IMARR(tar) ; /*--- Print a beeyootiful header ---*/ printf("# %s correlation [n=%d #col=%d]\n",cor_name[cormeth],nx,nvec) ; sprintf(fmt,"# %%-%ds %%-%ds",vlen,vlen) ; printf(fmt,"Name","Name") ; printf(" Value BiasCorr %5.2f%% %5.2f%%",50.0f*alpha,100.0f-50.0f*alpha) ; if( cormeth == 0 ) /* Pearson */ printf(" N:%5.2f%% N:%5.2f%%",50.0f*alpha,100.0f-50.0f*alpha) ; printf("\n") ; printf("# ") ; for( ii=0 ; ii < vlen ; ii++ ) printf("-") ; printf(" ") ; for( ii=0 ; ii < vlen ; ii++ ) printf("-") ; printf(" ") ; printf(" --------") ; printf(" --------") ; printf(" --------") ; printf(" --------") ; if( cormeth == 0 ){ printf(" --------") ; printf(" --------") ; } printf("\n") ; if( cormeth != 0 ) /* non-Pearson */ sprintf(fmt," %%-%ds %%-%ds %%+8.5f %%+8.5f %%+8.5f %%+8.5f\n",vlen,vlen) ; else /* Pearson */ sprintf(fmt," %%-%ds %%-%ds %%+8.5f %%+8.5f %%+8.5f %%+8.5f %%+8.5f %%+8.5f\n",vlen,vlen) ; /*--- Do some actual work for a suprising change ---*/ for( jj=0 ; jj < nvec ; jj++ ){ /* loops over column pairs */ for( kk=jj+1 ; kk < nvec ; kk++ ){ if( vsig != NULL ){ xsig = vsig[jj]; ysig = vsig[kk]; } else { xsig = ysig = 0.0f; } qcor = Corrboot( nx, tvec[jj], tvec[kk], xsig, ysig, corfun ) ; /* outsourced */ corst = qcor.a ; cor025 = qcor.b ; cor500 = qcor.c ; cor975 = qcor.d ; if( cormeth == 0 ){ /* Pearson */ pci = PCorrCI( nx , corst , alpha ) ; printf(fmt, vecnam[jj], vecnam[kk], corst, cor500, cor025, cor975, pci.a,pci.b ) ; } else { /* all other methods */ printf(fmt, vecnam[jj], vecnam[kk], corst, cor500, cor025, cor975 ) ; } } } /* Finished -- go back to watching Star Trek reruns -- Tribbles ahoy, Cap'n! */ exit(0) ; }
char * IMREG_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 ; /* strings from user */ int base , ntime , datum , nx,ny,nz , ii,kk , npix ; float dx,dy,dz ; MRI_IMARR * ims_in , * ims_out ; MRI_IMAGE * im , * imbase ; byte ** bptr = NULL , ** bout = NULL ; short ** sptr = NULL , ** sout = NULL ; float ** fptr = NULL , ** fout = NULL ; float * dxar = NULL , * dyar = NULL , * phiar = NULL ; /*--------------------------------------------------------------------*/ /*----- 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" "************************************" ; nx = old_dset->daxes->nxx ; dx = old_dset->daxes->xxdel ; ny = old_dset->daxes->nyy ; dy = old_dset->daxes->yydel ; npix = nx*ny ; nz = old_dset->daxes->nzz ; dz = old_dset->daxes->zzdel ; if( nx != ny || fabs(dx) != fabs(dy) ) { #ifdef IMREG_DEBUG fprintf(stderr,"\nIMREG: nx=%d ny=%d nz=%d dx=%f dy=%f dz=%f\n", nx,ny,nz,dx,dy,dz ) ; #endif return "***********************************\n" "Dataset does not have square slices\n" "***********************************" ; } 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) ; base = PLUTO_get_number(plint) ; if( base >= ntime ) return "********************\n" "Base value too large\n" "********************" ; /*--------- see if the 3rd option line is present --------*/ str = PLUTO_get_optiontag( plint ) ; if( str != NULL ) { float fsig , fdxy , fdph ; fsig = PLUTO_get_number(plint) * 0.42466090 ; fdxy = PLUTO_get_number(plint) ; fdph = PLUTO_get_number(plint) ; mri_align_params( 0 , 0.0,0.0,0.0 , fsig,fdxy,fdph ) ; /* fprintf(stderr,"Set fine params = %f %f %f\n",fsig,fdxy,fdph) ; */ } /*------------- ready to compute new dataset -----------*/ #ifdef IMREG_DEBUG fprintf(stderr,"IMREG: loading dataset\n") ; #endif DSET_load( old_dset ) ; /*** 1) Copy the dataset in toto ***/ #ifdef IMREG_DEBUG fprintf(stderr,"IMREG: Copying dataset\n") ; #endif new_dset = PLUTO_copy_dset( old_dset , new_prefix ) ; if( new_dset == NULL ) return "****************************\n" "Failed to copy input dataset\n" "****************************" ; /*** 2) Make an array of empty images ***/ #ifdef IMREG_DEBUG fprintf(stderr,"IMREG: making empty images\n") ; #endif datum = DSET_BRICK_TYPE(new_dset,0) ; INIT_IMARR(ims_in) ; for( ii=0 ; ii < ntime ; ii++ ) { im = mri_new_vol_empty( nx , ny , 1 , datum ) ; ADDTO_IMARR(ims_in,im) ; } imbase = mri_new_vol_empty( nx , ny , 1 , datum ) ; dxar = (float *) malloc( sizeof(float) * ntime ) ; dyar = (float *) malloc( sizeof(float) * ntime ) ; phiar = (float *) malloc( sizeof(float) * ntime ) ; /*** 3) Get pointers to sub-bricks in old and new datasets ***/ #ifdef IMREG_DEBUG fprintf(stderr,"IMREG: getting input brick pointers\n") ; #endif switch( datum ) { /* pointer type depends on input datum type */ case MRI_byte: bptr = (byte **) malloc( sizeof(byte *) * ntime ) ; bout = (byte **) malloc( sizeof(byte *) * ntime ) ; for( ii=0 ; ii < ntime ; ii++ ) { bptr[ii] = (byte *) DSET_ARRAY(old_dset,ii) ; bout[ii] = (byte *) DSET_ARRAY(new_dset,ii) ; } break ; case MRI_short: sptr = (short **) malloc( sizeof(short *) * ntime ) ; sout = (short **) malloc( sizeof(short *) * ntime ) ; for( ii=0 ; ii < ntime ; ii++ ) { sptr[ii] = (short *) DSET_ARRAY(old_dset,ii) ; sout[ii] = (short *) DSET_ARRAY(new_dset,ii) ; } #ifdef IMREG_DEBUG fprintf(stderr,"IMREG: sptr[0] = %p sout[0] = %p\n",sptr[0],sout[0]) ; #endif break ; case MRI_float: fptr = (float **) malloc( sizeof(float *) * ntime ) ; fout = (float **) malloc( sizeof(float *) * ntime ) ; for( ii=0 ; ii < ntime ; ii++ ) { fptr[ii] = (float *) DSET_ARRAY(old_dset,ii) ; fout[ii] = (float *) DSET_ARRAY(new_dset,ii) ; } break ; } /*** 4) Loop over slices ***/ PLUTO_popup_meter(plint) ; for( kk=0 ; kk < nz ; kk++ ) { /*** 4a) Setup ims_in images to point to input slices ***/ #ifdef IMREG_DEBUG fprintf(stderr,"IMREG: slice %d -- setup input images\n",kk) ; #endif for( ii=0 ; ii < ntime ; ii++ ) { im = IMARR_SUBIMAGE(ims_in,ii) ; switch( datum ) { case MRI_byte: mri_fix_data_pointer( bptr[ii] + kk*npix, im ) ; break ; case MRI_short: mri_fix_data_pointer( sptr[ii] + kk*npix, im ) ; break ; case MRI_float: mri_fix_data_pointer( fptr[ii] + kk*npix, im ) ; break ; } } /*** 4b) Setup im to point to base image ***/ #ifdef IMREG_DEBUG fprintf(stderr,"IMREG: slice %d -- setup base image\n",kk) ; #endif switch( datum ) { case MRI_byte: mri_fix_data_pointer( bptr[base] + kk*npix, imbase ) ; break ; case MRI_short: mri_fix_data_pointer( sptr[base] + kk*npix, imbase ) ; break ; case MRI_float: mri_fix_data_pointer( fptr[base] + kk*npix, imbase ) ; break ; } /*** 4c) Register this slice at all times ***/ #ifdef IMREG_DEBUG fprintf(stderr,"IMREG: slice %d -- register\n",kk) ; #endif ims_out = mri_align_dfspace( imbase , NULL , ims_in , ALIGN_REGISTER_CODE , dxar,dyar,phiar ) ; if( ims_out == NULL ) fprintf(stderr,"IMREG: mri_align_dfspace return NULL\n") ; /*** 4d) Put the output back in on top of the input; note that the output is always in MRI_float format ***/ #ifdef IMREG_DEBUG fprintf(stderr,"IMREG: slice %d -- put output back into dataset\n",kk) ; #endif for( ii=0 ; ii < ntime ; ii++ ) { switch( datum ) { case MRI_byte: im = mri_to_mri( MRI_byte , IMARR_SUBIMAGE(ims_out,ii) ) ; memcpy( bout[ii] + kk*npix , MRI_BYTE_PTR(im) , sizeof(byte)*npix ) ; mri_free(im) ; break ; case MRI_short: #ifdef IMREG_DEBUG if( ii==0 )fprintf(stderr,"IMREG: conversion to short at ii=%d\n",ii) ; #endif im = mri_to_mri( MRI_short , IMARR_SUBIMAGE(ims_out,ii) ) ; #ifdef IMREG_DEBUG if( ii==0 )fprintf(stderr,"IMREG: copying to %p from %p\n",sout[ii] + kk*npix,MRI_SHORT_PTR(im)) ; #endif memcpy( sout[ii] + kk*npix , MRI_SHORT_PTR(im) , sizeof(short)*npix ) ; #ifdef IMREG_DEBUG if( ii==0 )fprintf(stderr,"IMREG: freeing\n") ; #endif mri_free(im) ; break ; case MRI_float: im = IMARR_SUBIMAGE(ims_out,ii) ; memcpy( fout[ii] + kk*npix , MRI_FLOAT_PTR(im) , sizeof(float)*npix ) ; break ; } } PLUTO_set_meter(plint, (100*(kk+1))/nz ) ; /*** 4e) Destroy the output images ***/ #ifdef IMREG_DEBUG fprintf(stderr,"IMREG: destroying aligned output\n") ; #endif DESTROY_IMARR( ims_out ) ; } /*** 5) Destroy the empty images and other workspaces ***/ #ifdef IMREG_DEBUG fprintf(stderr,"IMREG: destroy workspaces\n") ; #endif mri_clear_data_pointer(imbase) ; mri_free(imbase) ; for( ii=0 ; ii < ntime ; ii++ ) { im = IMARR_SUBIMAGE(ims_in,ii) ; mri_clear_data_pointer(im) ; } DESTROY_IMARR(ims_in) ; FREE_WORKSPACE ; /*------------- let AFNI know about the new dataset ------------*/ #ifdef IMREG_DEBUG fprintf(stderr,"IMREG: send result to AFNI\n") ; #endif PLUTO_add_dset( plint , new_dset , DSET_ACTION_MAKE_CURRENT ) ; 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[] ) { float mrad=0.0f , fwhm=0.0f ; int nrep=1 ; char *prefix = "Polyfit" ; char *resid = NULL ; char *cfnam = NULL ; int iarg , verb=0 , do_automask=0 , nord=3 , meth=2 , do_mclip=0 ; THD_3dim_dataset *inset ; MRI_IMAGE *imout , *imin ; byte *mask=NULL ; int nvmask=0 , nmask=0 , do_mone=0 , do_byslice=0 ; MRI_IMARR *exar=NULL ; floatvec *fvit=NULL ; /* 26 Feb 2019 */ if( argc < 2 || strcasecmp(argv[1],"-help") == 0 ){ printf("\n" "Usage: 3dPolyfit [options] dataset ~1~\n" "\n" "* Fits a polynomial in space to the input dataset and outputs that fitted dataset.\n" "\n" "* You can also add your own basis datasets to the fitting mix, using the\n" " '-base' option.\n" "\n" "* You can get the fit coefficients using the '-1Dcoef' option.\n" "\n" "--------\n" "Options: ~1~\n" "--------\n" "\n" " -nord n = Maximum polynomial order (0..9) [default order=3]\n" " [n=0 is the constant 1]\n" " [n=-1 means only use volumes from '-base']\n" "\n" " -blur f = Gaussian blur input dataset (inside mask) with FWHM='f' (mm)\n" "\n" " -mrad r = Radius (voxels) of preliminary median filter of input\n" " [default is no blurring of either type; you can]\n" " [do both types (Gaussian and median), but why??]\n" " [N.B.: median blur is slower than Gaussian]\n" "\n" " -prefix pp = Use 'pp' for prefix of output dataset (the fit).\n" " [default prefix is 'Polyfit'; use NULL to skip this output]\n" "\n" " -resid rr = Use 'rr' for the prefix of the residual dataset.\n" " [default is not to output residuals]\n" "\n" " -1Dcoef cc = Save coefficients of fit into text file cc.1D.\n" " [default is not to save these coefficients]\n" "\n" " -automask = Create a mask (a la 3dAutomask)\n" " -mask mset = Create a mask from nonzero voxels in 'mset'.\n" " [default is not to use a mask, which is probably a bad idea]\n" "\n" " -mone = Scale the mean value of the fit (inside the mask) to 1.\n" " [probably this option is not useful for anything]\n" "\n" " -mclip = Clip fit values outside the rectilinear box containing the\n" " mask to the edge of that box, to avoid weird artifacts.\n" "\n" " -meth mm = Set 'mm' to 2 for least squares fit;\n" " set it to 1 for L1 fit [default method=2]\n" " [Note that L1 fitting is slower than L2 fitting!]\n" "\n" " -base bb = In addition to the polynomial fit, also use\n" " the volumes in dataset 'bb' as extra basis functions.\n" " [If you use a base dataset, then you can set nord]\n" " [to -1, to skip using any spatial polynomial fit.]\n" "\n" " -verb = Print fun and useful progress reports :-)\n" "\n" "------\n" "Notes: ~1~\n" "------\n" "* Output dataset is always stored in float format.\n" "\n" "* If the input dataset has more than 1 sub-brick, only sub-brick #0\n" " is processed. To fit more than one volume, you'll have to use a script\n" " to loop over the input sub-bricks, and then glue (3dTcat) the results\n" " together to get a final result. A simple example:\n" " #!/bin/tcsh\n" " set base = model.nii\n" " set dset = errts.nii\n" " set nval = `3dnvals $dset`\n" " @ vtop = $nval - 1\n" " foreach vv ( `count 0 $vtop` )\n" " 3dPolyfit -base \"$base\" -nord 0 -mask \"$base\" -1Dcoef QQ.$vv -prefix QQ.$vv.nii $dset\"[$vv]\"\n" " end\n" " 3dTcat -prefix QQall.nii QQ.0*.nii\n" " 1dcat QQ.0*.1D > QQall.1D\n" " \rm QQ.0*\n" " exit 0\n" "\n" "* If the '-base' dataset has multiple sub-bricks, all of them are used.\n" "\n" "* You can use the '-base' option more than once, if desired or needed.\n" "\n" "* The original motivation for this program was to fit a spatial model\n" " to a field map MRI, but that didn't turn out to be useful. Nevertheless,\n" " I make this program available to someone who might find it beguiling.\n" "\n" "* If you really want, I could allow you to put sign constraints on the\n" " fit coefficients (e.g., say that the coefficient for a given base volume\n" " should be non-negative). But you'll have to beg for this.\n" "\n" "-- Emitted by RWCox\n" ) ; PRINT_COMPILE_DATE ; exit(0) ; } /*-- startup paperwork --*/ mainENTRY("3dPolyfit main"); machdep(); AFNI_logger("3dPolyfit",argc,argv); PRINT_VERSION("3dPolyfit") ; /*-- scan command line --*/ iarg = 1 ; while( iarg < argc && argv[iarg][0] == '-' ){ if( strcasecmp(argv[iarg],"-base") == 0 ){ THD_3dim_dataset *bset ; int kk ; MRI_IMAGE *bim ; if( ++iarg >= argc ) ERROR_exit("Need argument after '-base'") ; bset = THD_open_dataset(argv[iarg]) ; CHECK_OPEN_ERROR(bset,argv[iarg]) ; DSET_load(bset) ; CHECK_LOAD_ERROR(bset) ; if( exar == NULL ) INIT_IMARR(exar) ; for( kk=0 ; kk < DSET_NVALS(bset) ; kk++ ){ bim = THD_extract_float_brick(kk,bset) ; if( bim != NULL ) ADDTO_IMARR(exar,bim) ; DSET_unload_one(bset,kk) ; } DSET_delete(bset) ; iarg++ ; continue ; } if( strcasecmp(argv[iarg],"-verb") == 0 ){ verb++ ; iarg++ ; continue ; } if( strcasecmp(argv[iarg],"-hermite") == 0 ){ /* 25 Mar 2013 [New Year's Day] */ mri_polyfit_set_basis("hermite") ; /* HIDDEN */ iarg++ ; continue ; } if( strcasecmp(argv[iarg],"-byslice") == 0 ){ /* 25 Mar 2013 [New Year's Day] */ do_byslice++ ; iarg++ ; continue ; /* HIDDEN */ } if( strcasecmp(argv[iarg],"-mask") == 0 ){ THD_3dim_dataset *mset ; if( ++iarg >= 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[iarg]) ; CHECK_OPEN_ERROR(mset,argv[iarg]) ; DSET_load(mset) ; CHECK_LOAD_ERROR(mset) ; nvmask = DSET_NVOX(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]) ; nmask = THD_countmask( nvmask , mask ) ; if( nmask < 99 ) ERROR_exit("Too few voxels in mask (%d)",nmask) ; if( verb ) INFO_message("Number of voxels in mask = %d",nmask) ; iarg++ ; continue ; } if( strcasecmp(argv[iarg],"-nord") == 0 ){ nord = (int)strtol( argv[++iarg], NULL , 10 ) ; if( nord < -1 || nord > 9 ) ERROR_exit("Illegal value after -nord :(") ; iarg++ ; continue ; } if( strcasecmp(argv[iarg],"-meth") == 0 ){ meth = (int)strtol( argv[++iarg], NULL , 10 ) ; if( meth < 1 || meth > 2 ) ERROR_exit("Illegal value after -meth :(") ; iarg++ ; continue ; } if( strncmp(argv[iarg],"-automask",5) == 0 ){ if( mask != NULL ) ERROR_exit("Can't use -mask and -automask together!") ; do_automask++ ; iarg++ ; continue ; } if( strncmp(argv[iarg],"-mclip",5) == 0 ){ do_mclip++ ; iarg++ ; continue ; } if( strncmp(argv[iarg],"-mone",5) == 0 ){ do_mone++ ; iarg++ ; continue ; } if( strcasecmp(argv[iarg],"-mrad") == 0 ){ mrad = strtod( argv[++iarg] , NULL ) ; iarg++ ; continue ; } if( strcasecmp(argv[iarg],"-blur") == 0 ){ fwhm = strtod( argv[++iarg] , NULL ) ; iarg++ ; continue ; } if( strcasecmp(argv[iarg],"-prefix") == 0 ){ prefix = argv[++iarg] ; if( !THD_filename_ok(prefix) ) ERROR_exit("Illegal value after -prefix :("); if( strcasecmp(prefix,"NULL") == 0 ) prefix = NULL ; iarg++ ; continue ; } if( strcasecmp(argv[iarg],"-resid") == 0 ){ resid = argv[++iarg] ; if( !THD_filename_ok(resid) ) ERROR_exit("Illegal value after -resid :("); if( strcasecmp(resid,"NULL") == 0 ) resid = NULL ; iarg++ ; continue ; } if( strcasecmp(argv[iarg],"-1Dcoef") == 0 ){ /* 26 Feb 2019 */ cfnam = argv[++iarg] ; if( !THD_filename_ok(cfnam) ) ERROR_exit("Illegal value after -1Dcoef :("); if( strcasecmp(cfnam,"NULL") == 0 ) cfnam = NULL ; iarg++ ; continue ; } ERROR_exit("Unknown option: %s\n",argv[iarg]); } /*--- check for blatant errors ---*/ if( iarg >= argc ) ERROR_exit("No input dataset name on command line?"); if( prefix == NULL && resid == NULL && cfnam == NULL ) ERROR_exit("-prefix and -resid and -1Dcoef are all NULL?!") ; if( do_byslice && cfnam != NULL ){ WARNING_message("-byslice does not work with -1Dcoef option :(") ; cfnam = NULL ; } if( nord < 0 && exar == NULL ) ERROR_exit("no polynomial fit AND no -base option ==> nothing to compute :(") ; /*-- read input --*/ if( verb ) INFO_message("Load input dataset") ; inset = THD_open_dataset( argv[iarg] ) ; CHECK_OPEN_ERROR(inset,argv[iarg]) ; DSET_load(inset) ; CHECK_LOAD_ERROR(inset) ; if( DSET_NVALS(inset) > 1 ) WARNING_message( "Only processing sub-brick #0 (out of %d)" , DSET_NVALS(inset) ); /* check input mask or create automask */ if( mask != NULL ){ if( nvmask != DSET_NVOX(inset) ) ERROR_exit("-mask and input datasets don't match in voxel counts :-(") ; } else if( do_automask ){ THD_automask_verbose( (verb > 1) ) ; THD_automask_extclip( 1 ) ; mask = THD_automask( inset ) ; nvmask = DSET_NVOX(inset) ; nmask = THD_countmask( nvmask , mask ) ; if( nmask < 99 ) ERROR_exit("Too few voxels in automask (%d)",nmask) ; if( verb ) ININFO_message("Number of voxels in automask = %d",nmask) ; } else { WARNING_message("3dPolyfit is running without a mask") ; } #undef GOOD #define GOOD(i) (mask == NULL || mask[i]) /* check -base input datasets */ if( exar != NULL ){ int ii,kk , nvbad=0 , nvox=DSET_NVOX(inset),nm ; float *ex , exb ; for( kk=0 ; kk < IMARR_COUNT(exar) ; kk++ ){ if( nvox != IMARR_SUBIM(exar,kk)->nvox ){ if( IMARR_SUBIM(exar,kk)->nvox != nvbad ){ ERROR_message("-base volume (%d voxels) doesn't match input dataset grid size (%d voxels)", IMARR_SUBIM(exar,kk)->nvox , nvox ) ; nvbad = IMARR_SUBIM(exar,kk)->nvox ; } } } if( nvbad != 0 ) ERROR_exit("Cannot continue :-(") ; /* subtract mean from each base input, if is a constant polynomial in the fit */ if( nord >= 0 ){ if( verb ) INFO_message("subtracting spatial mean from '-base'") ; for( kk=0 ; kk < IMARR_COUNT(exar) ; kk++ ){ exb = 0.0f ; ex = MRI_FLOAT_PTR(IMARR_SUBIM(exar,kk)) ; for( nm=ii=0 ; ii < nvox ; ii++ ){ if( GOOD(ii) ){ exb += ex[ii]; nm++; } } exb /= nm ; for( ii=0 ; ii < nvox ; ii++ ) ex[ii] -= exb ; } } } /* if blurring, edit mask a little */ if( mask != NULL && (fwhm > 0.0f || mrad > 0.0f) ){ int ii ; ii = THD_mask_remove_isolas( DSET_NX(inset),DSET_NY(inset),DSET_NZ(inset),mask ) ; if( ii > 0 ){ nmask = THD_countmask( nvmask , mask ) ; if( verb ) ININFO_message("Removed %d isola%s from mask, leaving %d voxels" , ii,(ii==1)?"\0":"s" , nmask ) ; if( nmask < 99 ) ERROR_exit("Too few voxels left in mask after isola removal :-(") ; } } /* convert input to float, which is simpler to deal with */ imin = THD_extract_float_brick(0,inset) ; if( imin == NULL ) ERROR_exit("Can't extract input dataset brick?! :-(") ; DSET_unload(inset) ; if( verb ) INFO_message("Start fitting process") ; /* do the Gaussian blurring */ if( fwhm > 0.0f ){ if( verb ) ININFO_message("Gaussian blur: FWHM=%g mm",fwhm) ; imin->dx = fabsf(DSET_DX(inset)) ; imin->dy = fabsf(DSET_DY(inset)) ; imin->dz = fabsf(DSET_DZ(inset)) ; mri_blur3D_addfwhm( imin , mask , fwhm ) ; } /* do the fitting */ mri_polyfit_verb(verb) ; if( do_byslice ) imout = mri_polyfit_byslice( imin , nord , exar , mask , mrad , meth ) ; else imout = mri_polyfit ( imin , nord , exar , mask , mrad , meth ) ; /* WTF? */ if( imout == NULL ) ERROR_exit("Can't compute polynomial fit :-( !?") ; if( resid == NULL ) mri_free(imin) ; if( ! do_byslice ) fvit = mri_polyfit_get_fitvec() ; /* get coefficients of fit [26 Feb 2019] */ /* scale the fit dataset? */ if( do_mone ){ float sum=0.0f ; int nsum=0 , ii,nvox ; float *par=MRI_FLOAT_PTR(imout) ; nvox = imout->nvox ; for( ii=0 ; ii < nvox ; ii++ ){ if( mask != NULL && mask[ii] == 0 ) continue ; sum += par[ii] ; nsum++ ; } if( nsum > 0 && sum != 0.0f ){ sum = nsum / sum ; if( verb ) ININFO_message("-mone: scaling fit by %g",sum) ; for( ii=0 ; ii < nvox ; ii++ ) par[ii] *= sum ; } } /* if there's a mask, clip values outside of its box */ #undef PF #define PF(i,j,k) par[(i)+(j)*nx+(k)*nxy] if( mask != NULL && do_mclip ){ int xm,xp,ym,yp,zm,zp , ii,jj,kk , nx,ny,nz,nxy ; float *par ; MRI_IMAGE *bim = mri_empty_conforming( imout , MRI_byte ) ; mri_fix_data_pointer(mask,bim) ; if( verb ) ININFO_message("-mclip: polynomial fit to autobox of mask") ; MRI_autobbox( bim , &xm,&xp , &ym,&yp , &zm,&zp ) ; mri_clear_data_pointer(bim) ; mri_free(bim) ; nx = imout->nx ; ny = imout->ny ; nz = imout->nz ; nxy = nx*ny ; par = MRI_FLOAT_PTR(imout) ; for( ii=0 ; ii < xm ; ii++ ) for( kk=0 ; kk < nz ; kk++ ) for( jj=0 ; jj < ny ; jj++ ) PF(ii,jj,kk) = PF(xm,jj,kk) ; for( ii=xp+1 ; ii < nx ; ii++ ) for( kk=0 ; kk < nz ; kk++ ) for( jj=0 ; jj < ny ; jj++ ) PF(ii,jj,kk) = PF(xp,jj,kk) ; for( jj=0 ; jj < ym ; jj++ ) for( kk=0 ; kk < nz ; kk++ ) for( ii=0 ; ii < nx ; ii++ ) PF(ii,jj,kk) = PF(ii,ym,kk) ; for( jj=yp+1 ; jj < ny ; jj++ ) for( kk=0 ; kk < nz ; kk++ ) for( ii=0 ; ii < nx ; ii++ ) PF(ii,jj,kk) = PF(ii,yp,kk) ; for( kk=0 ; kk < zm ; kk++ ) for( jj=0 ; jj < ny ; jj++ ) for( ii=0 ; ii < nx ; ii++ ) PF(ii,jj,kk) = PF(ii,jj,zm) ; for( kk=zp+1 ; kk < nz ; kk++ ) for( jj=0 ; jj < ny ; jj++ ) for( ii=0 ; ii < nx ; ii++ ) PF(ii,jj,kk) = PF(ii,jj,zp) ; } if( mask != NULL ) free(mask) ; /* write outputs */ if( prefix != NULL ){ THD_3dim_dataset *outset = EDIT_empty_copy( inset ) ; EDIT_dset_items( outset , ADN_prefix , prefix , ADN_nvals , 1 , ADN_ntt , 0 , ADN_none ) ; EDIT_substitute_brick( outset , 0 , MRI_float , MRI_FLOAT_PTR(imout) ) ; tross_Copy_History( inset , outset ) ; tross_Make_History( "3dPolyfit" , argc,argv , outset ) ; DSET_write(outset) ; WROTE_DSET(outset) ; } if( resid != NULL ){ THD_3dim_dataset *outset = EDIT_empty_copy( inset ) ; float *inar=MRI_FLOAT_PTR(imin) , *outar=MRI_FLOAT_PTR(imout) ; int nx,ny,nz , nxyz , kk ; nx = imout->nx ; ny = imout->ny ; nz = imout->nz ; nxyz = nx*ny*nz ; for( kk=0 ; kk < nxyz ; kk++ ) outar[kk] = inar[kk] - outar[kk] ; mri_free(imin) ; EDIT_dset_items( outset , ADN_prefix , resid , ADN_nvals , 1 , ADN_ntt , 0 , ADN_none ) ; EDIT_substitute_brick( outset , 0 , MRI_float , MRI_FLOAT_PTR(imout) ) ; tross_Copy_History( inset , outset ) ; tross_Make_History( "3dPolyfit" , argc,argv , outset ) ; DSET_write(outset) ; WROTE_DSET(outset) ; } if( cfnam != NULL && fvit != NULL ){ /* won't work with '-byslice' */ char *qn ; qn = STRING_HAS_SUFFIX(cfnam,".1D") ? cfnam : modify_afni_prefix(cfnam,NULL,".1D") ; mri_write_floatvec( qn , fvit ) ; } exit(0) ; }
void DT_read_opts( int argc , char * argv[] ) { int nopt = 1 , nvals , ii , nvcheck , nerr=0 ; MRI_IMARR *slice_imar ; INIT_IMARR(DT_imar) ; INIT_IMARR(slice_imar) ; while( nopt < argc && argv[nopt][0] == '-' ){ /**** -polort p ****/ if( strncmp(argv[nopt],"-polort",6) == 0 ){ char *cpt ; nopt++ ; if( nopt >= argc ) ERROR_exit("Need argument after -polort") ; DT_polort = (int)strtod(argv[nopt],&cpt) ; if( *cpt != '\0' ) WARNING_message("Illegal non-numeric value after -polort") ; if( DT_polort < 0 ) WARNING_message("Ignoring negative value after -polort") ; nopt++ ; continue ; } /**** -prefix prefix ****/ if( strncmp(argv[nopt],"-prefix",6) == 0 ){ nopt++ ; if( nopt >= argc ) ERROR_exit("Need argument after -prefix") ; MCW_strncpy( DT_output_prefix , argv[nopt] , THD_MAX_PREFIX ) ; if( !THD_filename_ok(DT_output_prefix) ) ERROR_exit("bad name '%s' after -prefix",argv[nopt]) ; nopt++ ; continue ; } /**** -session directory ****/ if( strncmp(argv[nopt],"-session",6) == 0 ){ nopt++ ; if( nopt >= argc ) ERROR_exit("Need argument after -session") ; MCW_strncpy( DT_session , argv[nopt] , THD_MAX_NAME ) ; if( !THD_filename_ok(DT_session) ) ERROR_exit("bad name '%s' after -session",argv[nopt]) ; nopt++ ; continue ; } /**** -verb ****/ if( strncmp(argv[nopt],"-verb",5) == 0 ){ DT_verb++ ; nopt++ ; continue ; } /**** -replace ****/ if( strncmp(argv[nopt],"-replace",5) == 0 ){ DT_replace++ ; nopt++ ; continue ; } /**** -byslice [08 Dec 1999] ****/ if( strncmp(argv[nopt],"-byslice",5) == 0 ){ #ifdef ALLOW_BYSLICE if( IMARR_COUNT(slice_imar) > 0 ) ERROR_exit("can't mix -byslice and -slicevector") ; DT_byslice++ ; nopt++ ; continue ; #else ERROR_exit("-byslice is no longer suppported") ; #endif } /**** -normalize [23 Nov 1999] ****/ if( strncmp(argv[nopt],"-normalize",5) == 0 ){ DT_norm++ ; nopt++ ; continue ; } /**** -vector ****/ if( strncmp(argv[nopt],"-vector",4) == 0 ){ MRI_IMAGE * flim ; nopt++ ; if( nopt >= argc ) ERROR_exit("need argument after -vector") ; flim = mri_read_1D( argv[nopt++] ) ; if( flim == NULL ) ERROR_exit("can't read -vector '%s'",argv[nopt-1]) ; ADDTO_IMARR(DT_imar,flim) ; if( DT_verb ) INFO_message("Read file %s: rows=%d cols=%d", argv[nopt-1],flim->ny,flim->nx ) ; continue ; } /**** -slicevector ****/ if( strncmp(argv[nopt],"-slicevector",6) == 0 ){ MRI_IMAGE *flim ; nopt++ ; if( nopt >= argc ) ERROR_exit("need argument after -slicevector") ; #ifdef ALLOW_BYSLICE if( DT_byslice ) ERROR_exit("can't mix -slicevector and -byslice") ; #endif flim = mri_read_1D( argv[nopt++] ) ; if( flim == NULL ) ERROR_exit("can't read -slicevector '%s'",argv[nopt-1]) ; ADDTO_IMARR(slice_imar,flim) ; if( DT_verb ) INFO_message("Read file %s: rows=%d cols=%d", argv[nopt-1],flim->ny,flim->nx ) ; continue ; } /**** -del ****/ if( strncmp(argv[nopt],"-del",4) == 0 ){ nopt++ ; if( nopt >= argc ) ERROR_exit("need argument after -del") ; DT_current_del = strtod( argv[nopt++] , NULL ) ; if( DT_verb ) INFO_message("Set expression stepsize = %g\n",DT_current_del) ; continue ; } /**** -expr ****/ if( strncmp(argv[nopt],"-expr",4) == 0 ){ int nexp , qvar , kvar ; char sym[4] ; nopt++ ; if( nopt >= argc ) ERROR_exit("need argument after -expr") ; nexp = DT_exnum + 1 ; if( DT_exnum == 0 ){ /* initialize storage */ DT_expr = (char **) malloc( sizeof(char *) ) ; DT_excode = (PARSER_code **) malloc( sizeof(PARSER_code *) ) ; DT_exdel = (float *) malloc( sizeof(float) ) ; DT_exvar = (int *) malloc( sizeof(int) ) ; } else { DT_expr = (char **) realloc( DT_expr , sizeof(char *)*nexp ) ; DT_excode = (PARSER_code **) realloc( DT_excode , sizeof(PARSER_code *)*nexp ) ; DT_exdel = (float *) realloc( DT_exdel , sizeof(float)*nexp) ; DT_exvar = (int *) realloc( DT_exvar , sizeof(int)*nexp) ; } DT_expr[DT_exnum] = argv[nopt] ; /* string */ DT_exdel[DT_exnum] = DT_current_del ; /* delta */ DT_excode[DT_exnum] = PARSER_generate_code( argv[nopt] ) ; /* compile */ if( DT_excode[DT_exnum] == NULL ) ERROR_exit("Illegal expression: '%s'",argv[nopt]) ; qvar = 0 ; kvar = -1 ; /* find symbol */ for( ii=0 ; ii < 26 ; ii++ ){ sym[0] = 'A' + ii ; sym[1] = '\0' ; if( PARSER_has_symbol(sym,DT_excode[DT_exnum]) ){ qvar++ ; if( kvar < 0 ) kvar = ii ; if( DT_verb ) INFO_message("Found expression symbol %s\n",sym) ; } } if( qvar > 1 ) ERROR_exit("-expr '%s' has too many symbols",DT_expr[DT_exnum]) ; else if( qvar == 0 ) WARNING_message("-expr '%s' is constant",DT_expr[DT_exnum]) ; DT_exvar[DT_exnum] = kvar ; DT_exnum = nexp ; nopt++ ; continue ; } /**** ERROR ****/ ERROR_exit("Unknown option: %s\n",argv[nopt]) ; } /* end of scan over options */ /*-- check for errors --*/ if( nopt >= argc ) ERROR_exit("No input dataset?!") ; #ifdef ALLOW_BYSLICE if( IMARR_COUNT(slice_imar) > 0 && DT_byslice ) ERROR_exit("Illegal mixing of -slicevector and -byslice") ; #endif DT_nvector = IMARR_COUNT(DT_imar) ; if( DT_nvector + DT_exnum == 0 && DT_polort < 0 ) ERROR_exit("No detrending options ordered!") ; #ifdef ALLOW_BYSLICE if( DT_nvector == 0 && DT_byslice ) ERROR_exit("No -vector option supplied with -byslice!") ; #endif /*--- read input dataset ---*/ DT_dset = THD_open_dataset( argv[nopt] ) ; CHECK_OPEN_ERROR(DT_dset,argv[nopt]) ; if( DT_dset == NULL ) ERROR_exit("Can't open dataset %s\n",argv[nopt]) ; DT_current_del = DSET_TR(DT_dset) ; if( DT_current_del <= 0.0 ){ DT_current_del = 1.0 ; if( DT_verb ) WARNING_message("Input has no TR value; setting TR=1.0\n") ; } else if( DT_verb ){ INFO_message("Input has TR=%g\n",DT_current_del) ; } /*-- check vectors for good size --*/ nvcheck = nvals = DSET_NVALS(DT_dset) ; #ifdef ALLOW_BYSLICE if( DT_byslice ) nvcheck *= DSET_NZ(DT_dset) ; #endif for( ii=0 ; ii < DT_nvector ; ii++ ){ if( IMARR_SUBIMAGE(DT_imar,ii)->nx < nvcheck ){ ERROR_message("%d-th -vector is shorter (%d) than dataset (%d)", ii+1,IMARR_SUBIMAGE(DT_imar,ii)->nx,nvcheck) ; nerr++ ; } } if( nerr > 0 ) ERROR_exit("Cannot continue") ; /*--- create time series from expressions */ if( DT_exnum > 0 ){ double atoz[26] , del ; int kvar , jj ; MRI_IMAGE *flim ; float *flar ; for( jj=0 ; jj < DT_exnum ; jj++ ){ if( DT_verb ) INFO_message("Evaluating %d-th -expr\n",jj+1) ; kvar = DT_exvar[jj] ; del = DT_exdel[jj] ; if( del <= 0.0 ) del = DT_current_del ; flim = mri_new( nvals , 1 , MRI_float ) ; flar = MRI_FLOAT_PTR(flim) ; for( ii=0 ; ii < 26 ; ii++ ) atoz[ii] = 0.0 ; for( ii=0 ; ii < nvals ; ii++ ){ if( kvar >= 0 ) atoz[kvar] = ii * del ; flar[ii] = PARSER_evaluate_one( DT_excode[jj] , atoz ) ; } ADDTO_IMARR( DT_imar , flim ) ; } } /*--- from polort [10 Apr 2006] ---*/ if( DT_polort >= 0 ){ int kk ; MRI_IMAGE *flim ; float *flar ; double fac=2.0/(nvals-1.0) ; for( kk=0 ; kk <= DT_polort ; kk++ ){ flim = mri_new( nvals , 1 , MRI_float ) ; flar = MRI_FLOAT_PTR(flim) ; for( ii=0 ; ii < nvals ; ii++ ) flar[ii] = Plegendre(fac*ii-1.0,kk) ; ADDTO_IMARR( DT_imar , flim ) ; } } return ; }
int main( int argc , char *argv[] ) { THD_3dim_dataset *yset=NULL , *aset=NULL , *mset=NULL , *wset=NULL ; MRI_IMAGE *fim=NULL, *qim,*tim, *pfim=NULL , *vim , *wim=NULL ; float *flar , *qar,*tar, *par=NULL , *var , *war=NULL ; MRI_IMARR *fimar=NULL ; MRI_IMAGE *aim , *yim ; float *aar , *yar ; int nt=0 , nxyz=0 , nvox=0 , nparam=0 , nqbase , polort=0 , ii,jj,kk,bb ; byte *mask=NULL ; int nmask=0 , iarg ; char *fname_out="-" ; /** equiv to stdout **/ float alpha=0.0f ; int nfir =0 ; float firwt[5]={0.09f,0.25f,0.32f,0.25f,0.09f} ; int nmed =0 ; int nwt =0 ; #define METHOD_C 3 #define METHOD_K 11 int method = METHOD_C ; /**--- help the pitiful user? ---**/ if( argc < 2 || strcmp(argv[1],"-help") == 0 ){ printf( "Usage: 3dInvFMRI [options]\n" "Program to compute stimulus time series, given a 3D+time dataset\n" "and an activation map (the inverse of the usual FMRI analysis problem).\n" "-------------------------------------------------------------------\n" "OPTIONS:\n" "\n" " -data yyy =\n" " *OR* = Defines input 3D+time dataset [a non-optional option].\n" " -input yyy =\n" "\n" " -map aaa = Defines activation map; 'aaa' should be a bucket dataset,\n" " each sub-brick of which defines the beta weight map for\n" " an unknown stimulus time series [also non-optional].\n" "\n" " -mapwt www = Defines a weighting factor to use for each element of\n" " the map. The dataset 'www' can have either 1 sub-brick,\n" " or the same number as in the -map dataset. In the\n" " first case, in each voxel, each sub-brick of the map\n" " gets the same weight in the least squares equations.\n" " [default: all weights are 1]\n" "\n" " -mask mmm = Defines a mask dataset, to restrict input voxels from\n" " -data and -map. [default: all voxels are used]\n" "\n" " -base fff = Each column of the 1D file 'fff' defines a baseline time\n" " series; these columns should be the same length as\n" " number of time points in 'yyy'. Multiple -base options\n" " can be given.\n" " -polort pp = Adds polynomials of order 'pp' to the baseline collection.\n" " The default baseline model is '-polort 0' (constant).\n" " To specify no baseline model at all, use '-polort -1'.\n" "\n" " -out vvv = Name of 1D output file will be 'vvv'.\n" " [default = '-', which is stdout; probably not good]\n" "\n" " -method M = Determines the method to use. 'M' is a single letter:\n" " -method C = least squares fit to data matrix Y [default]\n" " -method K = least squares fit to activation matrix A\n" "\n" " -alpha aa = Set the 'alpha' factor to 'aa'; alpha is used to penalize\n" " large values of the output vectors. Default is 0.\n" " A large-ish value for alpha would be 0.1.\n" "\n" " -fir5 = Smooth the results with a 5 point lowpass FIR filter.\n" " -median5 = Smooth the results with a 5 point median filter.\n" " [default: no smoothing; only 1 of these can be used]\n" "-------------------------------------------------------------------\n" "METHODS:\n" " Formulate the problem as\n" " Y = V A' + F C' + errors\n" " where Y = data matrix (N x M) [from -data]\n" " V = stimulus (N x p) [to -out]\n" " A = map matrix (M x p) [from -map]\n" " F = baseline matrix (N x q) [from -base and -polort]\n" " C = baseline weights (M x q) [not computed]\n" " N = time series length = length of -data file\n" " M = number of voxels in mask\n" " p = number of stimulus time series to estimate\n" " = number of parameters in -map file\n" " q = number of baseline parameters\n" " and ' = matrix transpose operator\n" " Next, define matrix Z (Y detrended relative to columns of F) by\n" " -1\n" " Z = [I - F(F'F) F'] Y\n" "-------------------------------------------------------------------\n" " The method C solution is given by\n" " -1\n" " V0 = Z A [A'A]\n" "\n" " This solution minimizes the sum of squares over the N*M elements\n" " of the matrix Y - V A' + F C' (N.B.: A' means A-transpose).\n" "-------------------------------------------------------------------\n" " The method K solution is given by\n" " -1 -1\n" " W = [Z Z'] Z A and then V = W [W'W]\n" "\n" " This solution minimizes the sum of squares of the difference between\n" " the A(V) predicted from V and the input A, where A(V) is given by\n" " -1\n" " A(V) = Z' V [V'V] = Z'W\n" "-------------------------------------------------------------------\n" " Technically, the solution is unidentfiable up to an arbitrary\n" " multiple of the columns of F (i.e., V = V0 + F G, where G is\n" " an arbitrary q x p matrix); the solution above is the solution\n" " that is orthogonal to the columns of F.\n" "\n" "-- RWCox - March 2006 - purely for experimental purposes!\n" ) ; printf("\n" "===================== EXAMPLE USAGE =====================================\n" "** Step 1: From a training dataset, generate activation map.\n" " The input dataset has 4 runs, each 108 time points long. 3dDeconvolve\n" " is used on the first 3 runs (time points 0..323) to generate the\n" " activation map. There are two visual stimuli (Complex and Simple).\n" "\n" " 3dDeconvolve -x1D xout_short_two.1D -input rall_vr+orig'[0..323]' \\\n" " -num_stimts 2 \\\n" " -stim_file 1 hrf_complex.1D -stim_label 1 Complex \\\n" " -stim_file 2 hrf_simple.1D -stim_label 2 Simple \\\n" " -concat '1D:0,108,216' \\\n" " -full_first -fout -tout \\\n" " -bucket func_ht2_short_two -cbucket cbuc_ht2_short_two\n" "\n" " N.B.: You may want to de-spike, smooth, and register the 3D+time\n" " dataset prior to the analysis (as usual). These steps are not\n" " shown here -- I'm presuming you know how to use AFNI already.\n" "\n" "** Step 2: Create a mask of highly activated voxels.\n" " The F statistic threshold is set to 30, corresponding to a voxel-wise\n" " p = 1e-12 = very significant. The mask is also lightly clustered, and\n" " restricted to brain voxels.\n" "\n" " 3dAutomask -prefix Amask rall_vr+orig\n" " 3dcalc -a 'func_ht2_short+orig[0]' -b Amask+orig -datum byte \\\n" " -nscale -expr 'step(a-30)*b' -prefix STmask300\n" " 3dmerge -dxyz=1 -1clust 1.1 5 -prefix STmask300c STmask300+orig\n" "\n" "** Step 3: Run 3dInvFMRI to estimate the stimulus functions in run #4.\n" " Run #4 is time points 324..431 of the 3D+time dataset (the -data\n" " input below). The -map input is the beta weights extracted from\n" " the -cbucket output of 3dDeconvolve.\n" "\n" " 3dInvFMRI -mask STmask300c+orig \\\n" " -data rall_vr+orig'[324..431]' \\\n" " -map cbuc_ht2_short_two+orig'[6..7]' \\\n" " -polort 1 -alpha 0.01 -median5 -method K \\\n" " -out ii300K_short_two.1D\n" "\n" " 3dInvFMRI -mask STmask300c+orig \\\n" " -data rall_vr+orig'[324..431]' \\\n" " -map cbuc_ht2_short_two+orig'[6..7]' \\\n" " -polort 1 -alpha 0.01 -median5 -method C \\\n" " -out ii300C_short_two.1D\n" "\n" "** Step 4: Plot the results, and get confused.\n" "\n" " 1dplot -ynames VV KK CC -xlabel Run#4 -ylabel ComplexStim \\\n" " hrf_complex.1D'{324..432}' \\\n" " ii300K_short_two.1D'[0]' \\\n" " ii300C_short_two.1D'[0]'\n" "\n" " 1dplot -ynames VV KK CC -xlabel Run#4 -ylabel SimpleStim \\\n" " hrf_simple.1D'{324..432}' \\\n" " ii300K_short_two.1D'[1]' \\\n" " ii300C_short_two.1D'[1]'\n" "\n" " N.B.: I've found that method K works better if MORE voxels are\n" " included in the mask (lower threshold) and method C if\n" " FEWER voxels are included. The above threshold gave 945\n" " voxels being used to determine the 2 output time series.\n" "=========================================================================\n" ) ; PRINT_COMPILE_DATE ; exit(0) ; } /**--- bureaucracy ---**/ mainENTRY("3dInvFMRI main"); machdep(); PRINT_VERSION("3dInvFMRI"); AUTHOR("Zhark"); AFNI_logger("3dInvFMRI",argc,argv) ; /**--- scan command line ---**/ iarg = 1 ; while( iarg < argc ){ if( strcmp(argv[iarg],"-method") == 0 ){ switch( argv[++iarg][0] ){ default: WARNING_message("Ignoring illegal -method '%s'",argv[iarg]) ; break ; case 'C': method = METHOD_C ; break ; case 'K': method = METHOD_K ; break ; } iarg++ ; continue ; } if( strcmp(argv[iarg],"-fir5") == 0 ){ if( nmed > 0 ) WARNING_message("Ignoring -fir5 in favor of -median5") ; else nfir = 5 ; iarg++ ; continue ; } if( strcmp(argv[iarg],"-median5") == 0 ){ if( nfir > 0 ) WARNING_message("Ignoring -median5 in favor of -fir5") ; else nmed = 5 ; iarg++ ; continue ; } if( strcmp(argv[iarg],"-alpha") == 0 ){ alpha = (float)strtod(argv[++iarg],NULL) ; if( alpha <= 0.0f ){ alpha = 0.0f ; WARNING_message("-alpha '%s' ignored!",argv[iarg]) ; } iarg++ ; continue ; } if( strcmp(argv[iarg],"-data") == 0 || strcmp(argv[iarg],"-input") == 0 ){ if( yset != NULL ) ERROR_exit("Can't input 2 3D+time datasets") ; yset = THD_open_dataset(argv[++iarg]) ; CHECK_OPEN_ERROR(yset,argv[iarg]) ; nt = DSET_NVALS(yset) ; if( nt < 2 ) ERROR_exit("Only 1 sub-brick in dataset %s",argv[iarg]) ; nxyz = DSET_NVOX(yset) ; iarg++ ; continue ; } if( strcmp(argv[iarg],"-map") == 0 ){ if( aset != NULL ) ERROR_exit("Can't input 2 -map datasets") ; aset = THD_open_dataset(argv[++iarg]) ; CHECK_OPEN_ERROR(aset,argv[iarg]) ; nparam = DSET_NVALS(aset) ; iarg++ ; continue ; } if( strcmp(argv[iarg],"-mapwt") == 0 ){ if( wset != NULL ) ERROR_exit("Can't input 2 -mapwt datasets") ; wset = THD_open_dataset(argv[++iarg]) ; CHECK_OPEN_ERROR(wset,argv[iarg]) ; iarg++ ; continue ; } if( strcmp(argv[iarg],"-mask") == 0 ){ if( mset != NULL ) ERROR_exit("Can't input 2 -mask datasets") ; mset = THD_open_dataset(argv[++iarg]) ; CHECK_OPEN_ERROR(mset,argv[iarg]) ; iarg++ ; continue ; } if( strcmp(argv[iarg],"-polort") == 0 ){ char *cpt ; polort = (int)strtod(argv[++iarg],&cpt) ; if( *cpt != '\0' ) WARNING_message("Illegal non-numeric value after -polort") ; iarg++ ; continue ; } if( strcmp(argv[iarg],"-out") == 0 ){ fname_out = strdup(argv[++iarg]) ; if( !THD_filename_ok(fname_out) ) ERROR_exit("Bad -out filename '%s'",fname_out) ; iarg++ ; continue ; } if( strcmp(argv[iarg],"-base") == 0 ){ if( fimar == NULL ) INIT_IMARR(fimar) ; qim = mri_read_1D( argv[++iarg] ) ; if( qim == NULL ) ERROR_exit("Can't read 1D file %s",argv[iarg]) ; ADDTO_IMARR(fimar,qim) ; iarg++ ; continue ; } ERROR_exit("Unrecognized option '%s'",argv[iarg]) ; } /**--- finish up processing options ---**/ if( yset == NULL ) ERROR_exit("No input 3D+time dataset?!") ; if( aset == NULL ) ERROR_exit("No input FMRI -map dataset?!") ; if( DSET_NVOX(aset) != nxyz ) ERROR_exit("Grid mismatch between -data and -map") ; INFO_message("Loading dataset for Y") ; DSET_load(yset); CHECK_LOAD_ERROR(yset) ; INFO_message("Loading dataset for A") ; DSET_load(aset); CHECK_LOAD_ERROR(aset) ; if( wset != NULL ){ if( DSET_NVOX(wset) != nxyz ) ERROR_exit("Grid mismatch between -data and -mapwt") ; nwt = DSET_NVALS(wset) ; if( nwt > 1 && nwt != nparam ) ERROR_exit("Wrong number of values=%d in -mapwt; should be 1 or %d", nwt , nparam ) ; INFO_message("Loading dataset for mapwt") ; DSET_load(wset); CHECK_LOAD_ERROR(wset) ; } if( mset != NULL ){ if( DSET_NVOX(mset) != nxyz ) ERROR_exit("Grid mismatch between -data and -mask") ; INFO_message("Loading dataset for mask") ; DSET_load(mset); CHECK_LOAD_ERROR(mset) ; mask = THD_makemask( mset , 0 , 1.0f,-1.0f ); DSET_delete(mset); nmask = THD_countmask( nxyz , mask ) ; if( nmask < 3 ){ WARNING_message("Mask has %d voxels -- ignoring!",nmask) ; free(mask) ; mask = NULL ; nmask = 0 ; } } nvox = (nmask > 0) ? nmask : nxyz ; INFO_message("N = time series length = %d",nt ) ; INFO_message("M = number of voxels = %d",nvox ) ; INFO_message("p = number of params = %d",nparam) ; /**--- set up baseline funcs in one array ---*/ nqbase = (polort >= 0 ) ? polort+1 : 0 ; if( fimar != NULL ){ for( kk=0 ; kk < IMARR_COUNT(fimar) ; kk++ ){ qim = IMARR_SUBIMAGE(fimar,kk) ; if( qim != NULL && qim->nx != nt ) WARNING_message("-base #%d length=%d; data length=%d",kk+1,qim->nx,nt) ; nqbase += qim->ny ; } } INFO_message("q = number of baselines = %d",nqbase) ; #undef F #define F(i,j) flar[(i)+(j)*nt] /* nt X nqbase */ if( nqbase > 0 ){ fim = mri_new( nt , nqbase , MRI_float ) ; /* F matrix */ flar = MRI_FLOAT_PTR(fim) ; bb = 0 ; if( polort >= 0 ){ /** load polynomial baseline **/ double a = 2.0/(nt-1.0) ; for( jj=0 ; jj <= polort ; jj++ ){ for( ii=0 ; ii < nt ; ii++ ) F(ii,jj) = (float)Plegendre( a*ii-1.0 , jj ) ; } bb = polort+1 ; } #undef Q #define Q(i,j) qar[(i)+(j)*qim->nx] /* qim->nx X qim->ny */ if( fimar != NULL ){ /** load -base baseline columns **/ for( kk=0 ; kk < IMARR_COUNT(fimar) ; kk++ ){ qim = IMARR_SUBIMAGE(fimar,kk) ; qar = MRI_FLOAT_PTR(qim) ; for( jj=0 ; jj < qim->ny ; jj++ ){ for( ii=0 ; ii < nt ; ii++ ) F(ii,bb+jj) = (ii < qim->nx) ? Q(ii,jj) : 0.0f ; } bb += qim->ny ; } DESTROY_IMARR(fimar) ; fimar=NULL ; } /* remove mean from each column after first? */ if( polort >= 0 && nqbase > 1 ){ float sum ; for( jj=1 ; jj < nqbase ; jj++ ){ sum = 0.0f ; for( ii=0 ; ii < nt ; ii++ ) sum += F(ii,jj) ; sum /= nt ; for( ii=0 ; ii < nt ; ii++ ) F(ii,jj) -= sum ; } } /* compute pseudo-inverse of baseline matrix, so we can project it out from the data time series */ /* -1 */ /* (F'F) F' matrix */ INFO_message("Computing pseudo-inverse of baseline matrix F") ; pfim = mri_matrix_psinv(fim,NULL,0.0f) ; par = MRI_FLOAT_PTR(pfim) ; #undef P #define P(i,j) par[(i)+(j)*nqbase] /* nqbase X nt */ #if 0 qim = mri_matrix_transpose(pfim) ; /** save to disk? **/ mri_write_1D( "Fpsinv.1D" , qim ) ; mri_free(qim) ; #endif } /**--- set up map image into aim/aar = A matrix ---**/ #undef GOOD #define GOOD(i) (mask==NULL || mask[i]) #undef A #define A(i,j) aar[(i)+(j)*nvox] /* nvox X nparam */ INFO_message("Loading map matrix A") ; aim = mri_new( nvox , nparam , MRI_float ); aar = MRI_FLOAT_PTR(aim); for( jj=0 ; jj < nparam ; jj++ ){ for( ii=kk=0 ; ii < nxyz ; ii++ ){ if( GOOD(ii) ){ A(kk,jj) = THD_get_voxel(aset,ii,jj); kk++; } }} DSET_unload(aset) ; /**--- set up map weight into wim/war ---**/ #undef WT #define WT(i,j) war[(i)+(j)*nvox] /* nvox X nparam */ if( wset != NULL ){ int numneg=0 , numpos=0 ; float fac ; INFO_message("Loading map weight matrix") ; wim = mri_new( nvox , nwt , MRI_float ) ; war = MRI_FLOAT_PTR(wim) ; for( jj=0 ; jj < nwt ; jj++ ){ for( ii=kk=0 ; ii < nxyz ; ii++ ){ if( GOOD(ii) ){ WT(kk,jj) = THD_get_voxel(wset,ii,jj); if( WT(kk,jj) > 0.0f ){ numpos++; WT(kk,jj) = sqrt(WT(kk,jj)); } else if( WT(kk,jj) < 0.0f ){ numneg++; WT(kk,jj) = 0.0f; } kk++; } }} DSET_unload(wset) ; if( numpos <= nparam ) WARNING_message("Only %d positive weights found in -wtmap!",numpos) ; if( numneg > 0 ) WARNING_message("%d negative weights found in -wtmap!",numneg) ; for( jj=0 ; jj < nwt ; jj++ ){ fac = 0.0f ; for( kk=0 ; kk < nvox ; kk++ ) if( WT(kk,jj) > fac ) fac = WT(kk,jj) ; if( fac > 0.0f ){ fac = 1.0f / fac ; for( kk=0 ; kk < nvox ; kk++ ) WT(kk,jj) *= fac ; } } } /**--- set up data image into yim/yar = Y matrix ---**/ #undef Y #define Y(i,j) yar[(i)+(j)*nt] /* nt X nvox */ INFO_message("Loading data matrix Y") ; yim = mri_new( nt , nvox , MRI_float ); yar = MRI_FLOAT_PTR(yim); for( ii=0 ; ii < nt ; ii++ ){ for( jj=kk=0 ; jj < nxyz ; jj++ ){ if( GOOD(jj) ){ Y(ii,kk) = THD_get_voxel(yset,jj,ii); kk++; } }} DSET_unload(yset) ; /**--- project baseline out of data image = Z matrix ---**/ if( pfim != NULL ){ #undef T #define T(i,j) tar[(i)+(j)*nt] /* nt X nvox */ INFO_message("Projecting baseline out of Y") ; qim = mri_matrix_mult( pfim , yim ) ; /* nqbase X nvox */ tim = mri_matrix_mult( fim , qim ) ; /* nt X nvox */ tar = MRI_FLOAT_PTR(tim) ; /* Y projected onto baseline */ for( jj=0 ; jj < nvox ; jj++ ) for( ii=0 ; ii < nt ; ii++ ) Y(ii,jj) -= T(ii,jj) ; mri_free(tim); mri_free(qim); mri_free(pfim); mri_free(fim); } /***** At this point: matrix A is in aim, matrix Z is in yim. Solve for V into vim, using the chosen method *****/ switch( method ){ default: ERROR_exit("Illegal method code! WTF?") ; /* Huh? */ /*.....................................................................*/ case METHOD_C: /**--- compute pseudo-inverse of A map ---**/ INFO_message("Method C: Computing pseudo-inverse of A") ; if( wim != NULL ) WARNING_message("Ignoring -mapwt dataset") ; pfim = mri_matrix_psinv(aim,NULL,alpha) ; /* nparam X nvox */ if( pfim == NULL ) ERROR_exit("mri_matrix_psinv() fails") ; mri_free(aim) ; /**--- and apply to data to get results ---*/ INFO_message("Computing result V") ; vim = mri_matrix_multranB( yim , pfim ) ; /* nt x nparam */ mri_free(pfim) ; mri_free(yim) ; break ; /*.....................................................................*/ case METHOD_K: /**--- compute pseudo-inverse of transposed Z ---*/ INFO_message("Method K: Computing pseudo-inverse of Z'") ; if( nwt > 1 ){ WARNING_message("Ignoring -mapwt dataset: more than 1 sub-brick") ; nwt = 0 ; mri_free(wim) ; wim = NULL ; war = NULL ; } if( nwt == 1 ){ float fac ; for( kk=0 ; kk < nvox ; kk++ ){ fac = war[kk] ; for( ii=0 ; ii < nt ; ii++ ) Y(ii,kk) *= fac ; for( ii=0 ; ii < nparam ; ii++ ) A(kk,ii) *= fac ; } } tim = mri_matrix_transpose(yim) ; mri_free(yim) ; pfim = mri_matrix_psinv(tim,NULL,alpha) ; mri_free(tim) ; if( pfim == NULL ) ERROR_exit("mri_matrix_psinv() fails") ; INFO_message("Computing W") ; tim = mri_matrix_mult( pfim , aim ) ; mri_free(aim) ; mri_free(pfim) ; INFO_message("Computing result V") ; pfim = mri_matrix_psinv(tim,NULL,0.0f) ; mri_free(tim) ; vim = mri_matrix_transpose(pfim) ; mri_free(pfim); break ; } /* end of switch on method */ if( wim != NULL ) mri_free(wim) ; /**--- smooth? ---**/ if( nfir > 0 && vim->nx > nfir ){ INFO_message("FIR-5-ing result") ; var = MRI_FLOAT_PTR(vim) ; for( jj=0 ; jj < vim->ny ; jj++ ) linear_filter_reflect( nfir,firwt , vim->nx , var + (jj*vim->nx) ) ; } if( nmed > 0 && vim->nx > nmed ){ INFO_message("Median-5-ing result") ; var = MRI_FLOAT_PTR(vim) ; for( jj=0 ; jj < vim->ny ; jj++ ) median5_filter_reflect( vim->nx , var + (jj*vim->nx) ) ; } /**--- write results ---**/ INFO_message("Writing result to '%s'",fname_out) ; mri_write_1D( fname_out , vim ) ; exit(0) ; }
void EDIT_add_bricklist( THD_3dim_dataset *dset , int nbr, int *tbr, float *fbr , void *sbr[] ) { int ibr , typ , nx,ny,nz , nvals,new_nvals ; THD_datablock *dblk ; MRI_IMAGE *qim ; char str[32] ; ENTRY("EDIT_add_bricklist") ; /**-- Sanity Checks --**/ if( ! ISVALID_3DIM_DATASET(dset) || nbr <= 0 ) EXRETURN; /* error! */ if( dset->dblk->brick == NULL ) EXRETURN; /* error! */ if( dset->dblk->malloc_type != DATABLOCK_MEM_MALLOC )EXRETURN; /* error! */ dblk = dset->dblk ; nvals = dblk->nvals ; nx = dblk->diskptr->dimsizes[0] ; ny = dblk->diskptr->dimsizes[1] ; nz = dblk->diskptr->dimsizes[2] ; /**-- reallocate the brick control information --**/ new_nvals = nvals + nbr ; dblk->brick_bytes = (int64_t *) XtRealloc( (char *) dblk->brick_bytes , sizeof(int64_t) * new_nvals ) ; dblk->brick_fac = (float *) XtRealloc( (char *) dblk->brick_fac , sizeof(float) * new_nvals ) ; dblk->nvals = dblk->diskptr->nvals = new_nvals ; /** allocate new sub-brick images **/ for( ibr=0 ; ibr < nbr ; ibr++ ){ typ = (tbr != NULL ) ? tbr[ibr] : MRI_short ; qim = mri_new_vol_empty( nx,ny,nz , typ ) ; /* image with no data */ if( sbr != NULL && sbr[ibr] != NULL ) /* attach data to image */ mri_fix_data_pointer( sbr[ibr] , qim ) ; ADDTO_IMARR( dblk->brick , qim ) ; /* attach image to dset */ dblk->brick_fac[nvals+ibr] = (fbr != NULL) ? fbr[ibr] : 0.0 ; dblk->brick_bytes[nvals+ibr] = (int64_t)qim->pixel_size * (int64_t)qim->nvox ; dblk->total_bytes += dblk->brick_bytes[ibr] ; } /** allocate new sub-brick auxiliary data: labels **/ if( dblk->brick_lab == NULL ) THD_init_datablock_labels( dblk ) ; else dblk->brick_lab = (char **) XtRealloc( (char *) dblk->brick_lab , sizeof(char *) * new_nvals ) ; for( ibr=0 ; ibr < nbr ; ibr++ ){ sprintf( str , "#%d" , nvals+ibr ) ; dblk->brick_lab[nvals+ibr] = NULL ; THD_store_datablock_label( dblk , nvals+ibr , str ) ; } /** keywords **/ if( dblk->brick_keywords == NULL ) THD_init_datablock_keywords( dblk ) ; else dblk->brick_keywords = (char **) XtRealloc( (char *) dblk->brick_keywords , sizeof(char *) * new_nvals ) ; for( ibr=0 ; ibr < nbr ; ibr++ ){ dblk->brick_keywords[nvals+ibr] = NULL ; THD_store_datablock_keywords( dblk , nvals+ibr , NULL ) ; } /** stataux **/ if( dblk->brick_statcode != NULL ){ dblk->brick_statcode = (int *) XtRealloc( (char *) dblk->brick_statcode , sizeof(int) * new_nvals ) ; dblk->brick_stataux = (float **) XtRealloc( (char *) dblk->brick_stataux , sizeof(float *) * new_nvals ) ; for( ibr=0 ; ibr < nbr ; ibr++ ){ dblk->brick_statcode[nvals+ibr] = 0 ; dblk->brick_stataux[nvals+ibr] = NULL ; } } /** fdrcurve **/ if( dblk->brick_fdrcurve != NULL ){ dblk->brick_fdrcurve = (floatvec **) realloc( (void *)dblk->brick_fdrcurve , sizeof(floatvec *) * new_nvals ) ; for( ibr=0 ; ibr < nbr ; ibr++ ) dblk->brick_fdrcurve[nvals+ibr] = NULL ; } if( dblk->brick_mdfcurve != NULL ){ /* 22 Oct 2008 */ dblk->brick_mdfcurve = (floatvec **) realloc( (void *)dblk->brick_mdfcurve , sizeof(floatvec *) * new_nvals ) ; for( ibr=0 ; ibr < nbr ; ibr++ ) dblk->brick_mdfcurve[nvals+ibr] = NULL ; } EXRETURN; }
MRI_IMARR * THD_get_all_timeseries( char * dname ) { THD_string_array * flist , * rlist ; int ir , ll , ii ; char * fname , * tname ; float * far ; MRI_IMARR * outar ; MRI_IMAGE * outim , * flim ; #ifdef NEWWAY char * pat ; #endif unsigned long max_fsize ; /* 20 Jul 2004: max 1D file size to load */ max_fsize = (unsigned long) AFNI_numenv( "AFNI_MAX_1DSIZE" ) ; if( max_fsize == 0 ) max_fsize = 123*1024 ; /*----- sanity check and initialize -----*/ if( dname == NULL || strlen(dname) == 0 ) return NULL ; INIT_IMARR( outar ) ; /*----- find all *.1D files -----*/ #ifdef NEWWAY ii = strlen(dname) ; pat = (char *) malloc(sizeof(char)*(ii+8)) ; strcpy(pat,dname) ; if( pat[ii-1] != '/' ) strcat(pat,"/") ; strcat(pat,"*.1D*") ; flist = THD_get_wildcard_filenames( pat ) ; free(pat) ; #else flist = THD_get_all_filenames( dname ) ; #endif if( flist == NULL || flist->num <= 0 ){ DESTROY_SARR(flist) ; DESTROY_IMARR(outar) ; return NULL ; } rlist = THD_extract_regular_files( flist ) ; DESTROY_SARR(flist) ; if( rlist == NULL || rlist->num <= 0 ){ DESTROY_SARR(rlist) ; DESTROY_IMARR(outar) ; return NULL ; } for( ir=0 ; ir < rlist->num ; ir++ ){ fname = rlist->ar[ir] ; if( fname == NULL ) continue ; ll = strlen(fname) - 3 ; if( ll < 1 ) continue ; if( strcmp(fname+ll,".1D")==0 || strcmp(fname+ll,"1Dx")==0 || strcmp(fname+ll,"1Dv")==0 ){ if( THD_filesize(fname) > max_fsize ) continue ; /* 20 Jul 2004 */ flim = mri_read_1D( fname ) ; if( flim != NULL ){ far = MRI_FLOAT_PTR(flim) ; for( ii=0 ; ii < flim->nvox ; ii++ ) if( fabs(far[ii]) >= 33333.0 ) far[ii] = WAY_BIG ; tname = THD_trailname(fname,1) ; mri_add_name( tname , flim ) ; ADDTO_IMARR( outar , flim ) ; } } } DESTROY_SARR(rlist) ; if( IMARR_COUNT(outar) == 0 ) DESTROY_IMARR(outar) ; return outar ; }
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 iarg , ii,jj,kk,mm , nvec , do_one=0 , nx=0,ny , ff, doterse = 0 ; MRI_IMAGE *tim ; MRI_IMARR *tar ; double sum , *eval , *amat , **tvec , *bmat , *svec ; float *far ; int demean=0 , docov=0 ; char *matname ; int okzero = 0; mainENTRY("1ddot main"); machdep(); /* options */ iarg = 1 ; nvec = 0 ; while( iarg < argc && argv[iarg][0] == '-' ){ if (strcmp(argv[iarg],"-help") == 0 || strcmp(argv[iarg],"-h") == 0){ usage_1ddot(strlen(argv[iarg])>3 ? 2:1); exit(0); } if( strcmp(argv[iarg],"-one") == 0 ){ demean = 0 ; do_one = 1 ; iarg++ ; continue ; } if( strcmp(argv[iarg],"-okzero") == 0 ){ okzero = 1 ; iarg++ ; continue ; } if( strncmp(argv[iarg],"-dem",4) == 0 ){ demean = 1 ; do_one = 0 ; iarg++ ; continue ; } if( strncmp(argv[iarg],"-cov",4) == 0 ){ docov = 1 ; iarg++ ; continue ; } if( strncmp(argv[iarg],"-inn",4) == 0 ){ docov = 2 ; iarg++ ; continue ; } if( strcasecmp(argv[iarg],"-rank") == 0 || strcasecmp(argv[iarg],"-spearman") == 0 ){ do_one = 0; docov = 3; demean = 0; doterse = 1; iarg++; continue; } if( strncmp(argv[iarg],"-terse",4) == 0 ){ doterse = 1 ; iarg++ ; continue ; } fprintf(stderr,"** Unknown option: %s\n",argv[iarg]); suggest_best_prog_option(argv[0], argv[iarg]); exit(1); } if( argc < 2 ){ usage_1ddot(1); exit(0) ; } if( iarg == argc ) ERROR_exit("No 1D files on command line!?") ; /* input 1D files */ ff = iarg ; INIT_IMARR(tar) ; if( do_one ) nvec = 1 ; for( ; iarg < argc ; iarg++ ){ tim = mri_read_1D( argv[iarg] ) ; if( tim == NULL ){ fprintf(stderr,"** Can't read 1D file %s\n",argv[iarg]); exit(1); } if( nx == 0 ){ nx = tim->nx ; } else if( tim->nx != nx ){ fprintf(stderr,"** 1D file %s doesn't match first file in length!\n", argv[iarg]); exit(1); } nvec += tim->ny ; ADDTO_IMARR(tar,tim) ; } if (!doterse) { printf("\n") ; printf("++ 1ddot input vectors:\n") ; } jj = 0 ; if( do_one ){ if (!doterse) printf("00..00: all ones\n") ; jj = 1 ; } for( mm=0 ; mm < IMARR_COUNT(tar) ; mm++ ){ tim = IMARR_SUBIM(tar,mm) ; if (!doterse) printf("%02d..%02d: %s\n", jj,jj+tim->ny-1, argv[ff+mm] ) ; jj += tim->ny ; } /* create vectors from 1D files */ tvec = (double **) malloc( sizeof(double *)*nvec ) ; svec = (double * ) malloc( sizeof(double )*nvec ) ; for( jj=0 ; jj < nvec ; jj++ ) tvec[jj] = (double *) malloc( sizeof(double)*nx ) ; kk = 0 ; if( do_one ){ svec[0] = 1.0 / sqrt((double)nx) ; for( ii=0 ; ii < nx ; ii++ ) tvec[0][ii] = 1.0 ; kk = 1 ; } for( mm=0 ; mm < IMARR_COUNT(tar) ; mm++ ){ tim = IMARR_SUBIM(tar,mm) ; far = MRI_FLOAT_PTR(tim) ; for( jj=0 ; jj < tim->ny ; jj++,kk++ ){ for( ii=0 ; ii < nx ; ii++ ) tvec[kk][ii] = far[ii+jj*nx] ; if( demean ){ sum = 0.0 ; for( ii=0 ; ii < nx ; ii++ ) sum += tvec[kk][ii] ; sum /= nx ; for( ii=0 ; ii < nx ; ii++ ) tvec[kk][ii] -= sum ; } sum = 0.0 ; for( ii=0 ; ii < nx ; ii++ ) sum += tvec[kk][ii] * tvec[kk][ii] ; if( sum == 0.0 ) { if (okzero) svec[kk] = 0.0; else ERROR_exit("Input column %02d is all zero!",kk) ; } else { svec[kk] = 1.0 / sqrt(sum) ; } } } DESTROY_IMARR(tar) ; /* normalize vectors? (for ordinary correlation) */ if( !docov ){ for( kk=0 ; kk < nvec ; kk++ ){ sum = svec[kk] ; for( ii=0 ; ii < nx ; ii++ ) tvec[kk][ii] *= sum ; } } switch(docov){ default: case 3: matname = "Spearman" ; break ; case 2: matname = "InnerProduct" ; break ; case 1: matname = "Covariance" ; break ; case 0: matname = "Correlation" ; break ; } /* create matrix from dot product of vectors */ amat = (double *) calloc( sizeof(double) , nvec*nvec ) ; if( docov != 3 ){ for( kk=0 ; kk < nvec ; kk++ ){ for( jj=0 ; jj <= kk ; jj++ ){ sum = 0.0 ; for( ii=0 ; ii < nx ; ii++ ) sum += tvec[jj][ii] * tvec[kk][ii] ; amat[jj+nvec*kk] = sum ; if( jj < kk ) amat[kk+nvec*jj] = sum ; } } } else { /* Spearman */ for( kk=0 ; kk < nvec ; kk++ ){ for( jj=0 ; jj <= kk ; jj++ ){ amat[jj+nvec*kk] = THD_spearman_corr_dble( nx , tvec[jj] , tvec[kk] ) ; if( jj < kk ) amat[kk+nvec*jj] = amat[jj+nvec*kk] ; } } } /* normalize */ if (docov==1) { for( kk=0 ; kk < nvec ; kk++ ){ for( jj=0 ; jj <= kk ; jj++ ){ sum = amat[jj+nvec*kk] / (double) (nx-1); amat[jj+nvec*kk] = sum; if( jj < kk ) amat[kk+nvec*jj] = sum ; } } } /* print matrix out */ if (!doterse) { printf("\n" "++ %s Matrix:\n ",matname) ; for( jj=0 ; jj < nvec ; jj++ ) printf(" %02d ",jj) ; printf("\n ") ; for( jj=0 ; jj < nvec ; jj++ ) printf(" ---------") ; printf("\n") ; } for( kk=0 ; kk < nvec ; kk++ ){ if (!doterse) printf("%02d:",kk) ; for( jj=0 ; jj < nvec ; jj++ ) printf(" %9.5f",amat[jj+kk*nvec]) ; printf("\n") ; } if (doterse) exit(0) ; /* au revoir */ /* compute eigendecomposition */ eval = (double *) malloc( sizeof(double)*nvec ) ; symeig_double( nvec , amat , eval ) ; printf("\n" "++ Eigensolution of %s Matrix:\n " , matname ) ; for( jj=0 ; jj < nvec ; jj++ ) printf(" %9.5f",eval[jj]) ; printf("\n ") ; for( jj=0 ; jj < nvec ; jj++ ) printf(" ---------") ; printf("\n") ; for( kk=0 ; kk < nvec ; kk++ ){ printf("%02d:",kk) ; for( jj=0 ; jj < nvec ; jj++ ) printf(" %9.5f",amat[kk+jj*nvec]) ; printf("\n") ; } /* compute matrix inverse */ if ( eval[0]/eval[nvec-1] < 1.0e-10) { printf("\n" "-- WARNING: Matrix is near singular,\n" " rubbish likely for inverses ahead.\n"); } for( jj=0 ; jj < nvec ; jj++ ) eval[jj] = 1.0 / eval[jj] ; bmat = (double *) calloc( sizeof(double) , nvec*nvec ) ; for( ii=0 ; ii < nvec ; ii++ ){ for( jj=0 ; jj < nvec ; jj++ ){ sum = 0.0 ; for( kk=0 ; kk < nvec ; kk++ ) sum += amat[ii+kk*nvec] * amat[jj+kk*nvec] * eval[kk] ; bmat[ii+jj*nvec] = sum ; } } printf("\n") ; printf("++ %s Matrix Inverse:\n " , matname ) ; for( jj=0 ; jj < nvec ; jj++ ) printf(" %02d ",jj) ; printf("\n ") ; for( jj=0 ; jj < nvec ; jj++ ) printf(" ---------") ; printf("\n") ; for( kk=0 ; kk < nvec ; kk++ ){ printf("%02d:",kk) ; for( jj=0 ; jj < nvec ; jj++ ) printf(" %9.5f",bmat[jj+kk*nvec]) ; printf("\n") ; } /* square roots of diagonals of the above */ printf("\n") ; printf("++ %s sqrt(diagonal)\n ",matname) ; for( jj=0 ; jj < nvec ; jj++ ) printf(" %9.5f",sqrt(bmat[jj+jj*nvec])) ; printf("\n") ; /* normalize matrix inverse */ for( ii=0 ; ii < nvec ; ii++ ){ for( jj=0 ; jj < nvec ; jj++ ){ sum = bmat[ii+ii*nvec] * bmat[jj+jj*nvec] ; if( sum > 0.0 ) amat[ii+jj*nvec] = bmat[ii+jj*nvec] / sqrt(sum) ; else amat[ii+jj*nvec] = 0.0 ; } } printf("\n") ; printf("++ %s Matrix Inverse Normalized:\n " , matname ) ; for( jj=0 ; jj < nvec ; jj++ ) printf(" %02d ",jj) ; printf("\n ") ; for( jj=0 ; jj < nvec ; jj++ ) printf(" ---------") ; printf("\n") ; for( kk=0 ; kk < nvec ; kk++ ){ printf("%02d:",kk) ; for( jj=0 ; jj < nvec ; jj++ ) printf(" %9.5f",amat[jj+kk*nvec]) ; printf("\n") ; } /* done */ exit(0) ; }