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