1 #include "mrilib.h"
2 
3 /***** This file is intended to be #include-d into   *****/
4 /***** places such as 3dXClustSim.c and 3dClustSim.c *****/
5 
6 /***** Also see program 3dtoXdataset.c for creating such files *****/
7 
8 /*---------------------------------------------------------------------------*/
9 /* Stuff for reading z-statistic dataset stored as shorts inside a mask
10    -- Basically, a compressed file, since 10000+
11       realizations is pretty damn big when stored as 3D float bricks!
12    -- And reading them in that way is damn slow, too.
13 *//*-------------------------------------------------------------------------*/
14 
15 #define SFAC 0.0002f  /* scale factor to convert shorts to floats */
16                       /* 0.0002 * 32767 = 6.5534 = a pretty big z */
17 
18 /* struct that combines the 3D mask dataset and the arrays of shorts */
19 
20 typedef struct {
21   THD_3dim_dataset  *mask_dset ;                        /* mask dataset */
22   byte              *mask_vol ;                          /* mask volume */
23   int nvox, ngood ;
24   ind_t *ipmask, *jpmask, *kpmask ;             /* indexes in 3D and 1D */
25   int   *ijkmask ;                               /* for pts in the mask */
26   int   *ijk_to_vec ;    /* map from index in volume to pts in the mask */
27 
28   int    nsdat ;                               /* number of input files */
29   char **sname ;                                 /* name of input files */
30   int    *nvol , nvtot ;  /* length of each file (in volumes) and total */
31   short  **sdat ;           /* pointer to data from each file (mmap-ed) */
32   size_t *ssiz ;                         /* length of each file (bytes) */
33   size_t totsiz ;                        /* length of all files (bytes) */
34   int    is_mapped ;                        /* is it mapped? [Sep 2018] */
35 } Xdataset ;
36 
37 /*----------------------------------------------------------*/
38 /* create Xdataset struct from 2 files: mask and short data */
39 
open_Xdataset(char * mask_fname,int nsdat,char ** sdat_fname)40 Xdataset * open_Xdataset( char *mask_fname, int nsdat, char **sdat_fname )
41 {
42    Xdataset *xds ; int ids,fdes,nvtot,pp,qq ; int64_t fsiz ; int nbad=0 ;
43 
44    if( mask_fname == NULL || sdat_fname == NULL )
45      ERROR_exit("open_Xdataset: bad input filenames") ;
46 
47    xds = (Xdataset *)calloc(sizeof(Xdataset),1) ;
48 
49    /*--- create the mask ---*/
50 
51    xds->mask_dset = THD_open_dataset(mask_fname) ;
52    if( xds->mask_dset == NULL )
53      ERROR_exit("open_Xdataset: can't open mask dataset '%s'",mask_fname) ;
54 
55    DSET_load(xds->mask_dset) ; CHECK_LOAD_ERROR(xds->mask_dset) ;
56 
57    if( DSET_NX(xds->mask_dset) > 1u+MAX_IND ||
58        DSET_NY(xds->mask_dset) > 1u+MAX_IND ||
59        DSET_NZ(xds->mask_dset) > 1u+MAX_IND   )
60 #ifdef USE_UBYTE
61      ERROR_exit("open_Xdataset: dataset grid too big -- must recompile to use shorts as indexes :(") ;
62 #else
63      ERROR_exit("open_Xdataset: dataset grid too big -- what ARE you doing?") ; /* should never happen */
64  #endif
65 
66    xds->mask_vol = THD_makemask( xds->mask_dset , 0 , 1.0,0.0 ) ;
67    if( xds->mask_vol == NULL )
68      ERROR_exit("open_Xdataset: can't use -mask dataset '%s' -- it is empty",mask_fname) ;
69    DSET_unload(xds->mask_dset) ;
70 
71    xds->nvox  = DSET_NVOX(xds->mask_dset) ;
72    xds->ngood = THD_countmask( xds->nvox , xds->mask_vol ) ;
73 
74    /* check mask for finger licking goodness */
75 
76    if( xds->ngood < 2 )
77      ERROR_exit("open_Xdataset: mask count is only %d -- cannot continue",xds->ngood) ;
78 
79    xds->ijkmask = (int *)malloc(sizeof(int)*xds->nvox) ;
80    for( pp=qq=0 ; qq < xds->nvox ; qq++ ){
81      if( xds->mask_vol[qq] ) xds->ijkmask[pp++] = qq ;
82    }
83 
84    /*--- open data files with the short-ized and mask-ized data ---*/
85 
86    xds->nsdat = nsdat ;
87    xds->nvol  = (int *)   calloc(sizeof(int)    ,nsdat) ;
88    xds->sdat  = (short **)calloc(sizeof(short *),nsdat) ;
89    xds->ssiz  = (size_t *)calloc(sizeof(size_t) ,nsdat) ;
90    xds->sname = (char **) calloc(sizeof(char *) ,nsdat) ; /* 22 Aug 2017 */
91 
92    xds->totsiz = 0 ;                                      /* 22 Aug 2017 */
93    nvtot = 0 ;
94 
95    for( ids=0 ; ids < nsdat ; ids++ ){
96 
97      if( sdat_fname[ids] == NULL ){
98        ERROR_message("open_Xdataset: NULL .sdat filename [%d] :-(",ids) ; nbad++ ; continue ;
99      }
100 
101      xds->sname[ids] = strdup(sdat_fname[ids]) ;
102 
103      fsiz = (int64_t)THD_filesize(xds->sname[ids]) ;  /* in bytes */
104      if( fsiz <= 0 ){
105        ERROR_message("open_Xdataset: can't find ANY data in file '%s'",xds->sname[ids]) ; nbad++ ; continue ;
106      }
107 
108      xds->nvol[ids] = (int)( fsiz /(sizeof(short)*xds->ngood) ); /* num volumes */
109      if( xds->nvol[ids] == 0 ){                                  /* in file */
110        ERROR_exit("open_Xdataset: file '%s' isn't long enough - only %lld bytes in file but need 2*%d for mask %s",
111                   xds->sname[ids] , (long long)fsiz , xds->ngood , mask_fname ) ;
112        nbad++ ; continue ;
113      }
114      nvtot += xds->nvol[ids] ;
115 
116      fdes = open( xds->sname[ids] , O_RDONLY ) ; /* open, get file descriptor */
117      if( fdes < 0 ){
118        ERROR_message("open_Xdataset: can't open file '%s'",xds->sname[ids]) ; nbad++ ; continue ;
119      }
120 
121      /* memory map the data file */
122 
123      xds->ssiz[ids] = (size_t)fsiz ;
124      xds->totsiz   += xds->ssiz[ids] ;
125      xds->sdat[ids] = (short *)mmap( 0, (size_t)fsiz, PROT_READ, THD_MMAP_FLAG, fdes, 0 ) ;
126      close(fdes) ;
127      if( xds->sdat[ids] == (short *)(-1) ){
128        ERROR_message("open_Xdataset: can't mmap() data file '%s' -- memory space exhausted?",
129                      xds->sname[ids]) ;
130        nbad++ ; continue ;
131      }
132 
133      /* page fault the data into memory */
134 
135 #if 0
136      if( verb )
137        INFO_message("mapping %s into memory",xds->sname[ids]) ;
138 #endif
139 
140 #if 0
141      { int64_t ii,sum=0 ; char *bdat = (char *)xds->sdat[ids] ;
142        for( ii=0 ; ii < fsiz ; ii+=1024 ) sum += (int64_t)bdat[ii] ;
143        if( sin((double)sum)==666.0 )
144          INFO_message("sum=%g",(double)sum) ; /* never executed */
145      }
146 #endif
147    } /* end of loop over input .sdat files */
148 
149    if( nbad > 0 ){
150      ERROR_exit("Cannot continue after above error%s",(nbad==1)?"\0":"s") ;
151    }
152 
153    xds->nvtot = nvtot ;
154 
155    xds->is_mapped = 1 ;
156 
157    /* e finito */
158 
159    return xds ;
160 }
161 
162 /*---------------------------------------------------------------------------*/
163 
unmap_Xdataset(Xdataset * xds)164 void unmap_Xdataset( Xdataset *xds )
165 {
166    int jj ;
167 
168    if( xds == NULL || xds->is_mapped==0 ) return ;
169 
170    for( jj=0 ; jj < xds->nsdat ; jj++ )
171      munmap( xds->sdat[jj] , xds->ssiz[jj] ) ;
172 
173    xds->is_mapped = 0 ;
174    return ;
175 }
176 
177 /*---------------------------------------------------------------------------*/
178 
remap_Xdataset(Xdataset * xds)179 void remap_Xdataset( Xdataset *xds )  /* undo the unmap [22 Aug 2017] */
180 {
181    int ids,fdes ; int64_t fsiz ;
182 
183    if( xds == NULL || xds->is_mapped ) return ; /* duh */
184 
185    for( ids=0 ; ids < xds->nsdat ; ids++ ){
186 
187      fsiz = (int64_t)THD_filesize(xds->sname[ids]) ;  /* in bytes */
188      if( fsiz <= 0 )
189        ERROR_exit("remap_Xdataset: can't re-find any data in file '%s'",xds->sname[ids]) ;
190 
191      xds->nvol[ids] = (int)( fsiz /(sizeof(short)*xds->ngood) ); /* num volumes */
192      if( xds->nvol[ids] == 0 )                                   /* in file */
193        ERROR_exit("remap_Xdataset: re-data file '%s' isn't long enough",xds->sname[ids]) ;
194 
195      fdes = open( xds->sname[ids] , O_RDONLY ) ; /* open, get file descriptor */
196      if( fdes < 0 )
197        ERROR_exit("remap_Xdataset: can't re-open file '%s'",xds->sname[ids]) ;
198 
199      /* memory map the data file */
200 
201      xds->ssiz[ids] = (size_t)fsiz ;
202      xds->sdat[ids] = (short *)mmap( 0, (size_t)fsiz, PROT_READ, THD_MMAP_FLAG, fdes, 0 ) ;
203      close(fdes) ;
204      if( xds->sdat[ids] == (short *)(-1) )
205        ERROR_exit("remap_Xdataset: can't re-mmap() file '%s' -- memory space exhausted?",
206                   xds->sname[ids]) ;
207 
208    } /* end of loop over input .sdat files */
209 
210    xds->is_mapped = 1 ;
211    return ;
212 }
213 
214 /*---------------------------------------------------------------------------*/
215 /* load a 3D array from the masked file of shorts */
216 
load_from_Xdataset(Xdataset * xds,int ival,float * far)217 void load_from_Xdataset( Xdataset *xds , int ival , float *far )
218 {
219    int ii,jj,qval,qq ; short *spt ;
220 
221    if( ival < 0 || ival >= xds->nvtot )
222      ERROR_exit("load_from_Xdataset: ival=%d nvol=%d",ival,xds->nvtot) ;
223 
224    if( !xds->is_mapped )
225      ERROR_exit("load_from_Xdataset: not mapped!? :(") ;
226 
227    AAmemset( far , 0 , sizeof(float)*xds->nvox ) ;
228 
229    for( qval=ival,qq=0 ; qq < xds->nsdat ; qq++ ){ /* find which to use */
230      if( qval < xds->nvol[qq] ) break ;            /* got it! */
231      qval -= xds->nvol[qq] ;                       /* try next one */
232    }
233    if( qq == xds->nsdat )                     /* should not be possible */
234      ERROR_exit("load_from_Xdataset[%d] == array overflow :-(",ival) ;
235 
236    spt = xds->sdat[qq] + ((size_t)qval)*((size_t)xds->ngood) ;
237 
238    for( ii=0 ; ii < xds->ngood ; ii++ ){
239      jj = xds->ijkmask[ii] ;    /* if put this directly in the far[] */
240      far[jj] = SFAC * spt[ii] ; /* subscript, optimizer problems in icc */
241    }
242    return ;
243 }
244 
245 #undef SFAC
246