ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/util/rttree_reduce.c
Revision: 2.14
Committed: Thu Mar 10 16:25:05 2016 UTC (8 years, 1 month ago) by greg
Content type: text/plain
Branch: MAIN
Changes since 2.13: +2 -3 lines
Log Message:
Fixed potential 64-bit bug pointed out by Schorsch

File Contents

# Content
1 #ifndef lint
2 static const char RCSid[] = "$Id: rttree_reduce.c,v 2.13 2016/03/06 01:13:18 schorsch Exp $";
3 #endif
4 /*
5 * A utility called by genBSDF.pl to reduce tensor tree samples and output
6 * in a standard format as required by XML specification for variable
7 * resolution BSDF data. We are not meant to be run by the user directly.
8 */
9
10 #include "rtio.h"
11 #include "rterror.h"
12 #include "platform.h"
13 #include <stdlib.h>
14 #include <math.h>
15
16 float *datarr; /* our loaded BSDF data array */
17 int ttrank = 4; /* tensor tree rank */
18 int log2g = 4; /* log2 of grid resolution */
19 int infmt = 'a'; /* input format ('a','f','d') */
20 double pctcull = 95.; /* target culling percentile */
21
22 #define dval3(ix,ox,oy) datarr[((((ix)<<log2g)+(ox))<<log2g)+(oy)]
23 #define dval4(ix,iy,ox,oy) datarr[((((((ix)<<log2g)+(iy))<<log2g)+(ox))<<log2g)+(oy)]
24
25 /* Tensor tree node */
26 typedef struct ttree_s {
27 float vmin, vmax; /* value extrema */
28 float vavg; /* average */
29 struct ttree_s *kid; /* 2^ttrank children */
30 } TNODE;
31
32 #define HISTLEN 300 /* histogram resolution */
33 #define HISTMAX 10. /* maximum recorded measure in histogram */
34
35 int histo[HISTLEN]; /* histogram freq. of variance measure */
36
37 double tthresh; /* acceptance threshold (TBD) */
38
39 #define var_measure(tp) ( ((tp)->vmax - (tp)->vmin) / \
40 (sqrt((tp)->vavg) + .03) )
41 #define above_threshold(tp) (var_measure(tp) > tthresh)
42
43 /* Allocate a new set of children for the given node (no checks) */
44 static void
45 new_kids(TNODE *pn)
46 {
47 pn->kid = (TNODE *)calloc((size_t)1<<ttrank, sizeof(TNODE));
48 if (pn->kid == NULL)
49 error(SYSTEM, "out of memory in new_kids");
50 }
51
52 /* Free children for this node */
53 static void
54 free_kids(TNODE *pn)
55 {
56 int i;
57
58 if (pn->kid == NULL)
59 return;
60 for (i = 1<<ttrank; i--; )
61 free_kids(pn->kid+i);
62 free(pn->kid);
63 pn->kid = NULL;
64 }
65
66 /* Build a tensor tree starting from the given hypercube */
67 static void
68 build_tree(TNODE *tp, const int bmin[], int l2s)
69 {
70 int bkmin[4];
71 int i, j;
72
73 tp->vmin = 1e20;
74 tp->vmax = 0;
75 tp->vavg = 0;
76 if (l2s <= 1) { /* reached upper leaves */
77 for (i = 1<<ttrank; i--; ) {
78 float val;
79 for (j = ttrank; j--; )
80 bkmin[j] = bmin[j] + (i>>j & 1);
81 val = (ttrank == 3) ? dval3(bkmin[0],bkmin[1],bkmin[2])
82 : dval4(bkmin[0],bkmin[1],bkmin[2],bkmin[3]);
83 if (val < tp->vmin)
84 tp->vmin = val;
85 if (val > tp->vmax)
86 tp->vmax = val;
87 tp->vavg += val;
88 }
89 tp->vavg /= (float)(1<<ttrank);
90 /* record stats */
91 i = (HISTLEN/HISTMAX) * var_measure(tp);
92 if (i >= HISTLEN) i = HISTLEN-1;
93 ++histo[i];
94 return;
95 }
96 --l2s; /* else still branching */
97 new_kids(tp); /* grow recursively */
98 for (i = 1<<ttrank; i--; ) {
99 for (j = ttrank; j--; )
100 bkmin[j] = bmin[j] + ((i>>j & 1)<<l2s);
101 build_tree(tp->kid+i, bkmin, l2s);
102 if (tp->kid[i].vmin < tp->vmin)
103 tp->vmin = tp->kid[i].vmin;
104 if (tp->kid[i].vmax > tp->vmax)
105 tp->vmax = tp->kid[i].vmax;
106 tp->vavg += tp->kid[i].vavg;
107 }
108 tp->vavg /= (float)(1<<ttrank);
109 }
110
111 /* Set our trimming threshold */
112 static void
113 set_threshold(void)
114 {
115 int hsum = 0;
116 int i;
117
118 for (i = HISTLEN; i--; )
119 hsum += histo[i];
120 hsum = pctcull*.01 * (double)hsum;
121 for (i = 0; hsum > 0; i++)
122 hsum -= histo[i];
123 tthresh = (HISTMAX/HISTLEN) * i;
124 }
125
126 /* Trim our tree according to the current threshold */
127 static void
128 trim_tree(TNODE *tp)
129 {
130 if (tp->kid == NULL)
131 return;
132 if (above_threshold(tp)) { /* keeping branches? */
133 int i = 1<<ttrank;
134 while (i--)
135 trim_tree(tp->kid+i);
136 return;
137 }
138 free_kids(tp); /* else trim at this point */
139 }
140
141 /* Print a tensor tree from the given hypercube */
142 static void
143 print_tree(const TNODE *tp, const int bmin[], int l2s)
144 {
145 int bkmin[4];
146 int i, j;
147
148 for (j = log2g-l2s; j--; ) /* indent based on branch level */
149 fputs(" ", stdout);
150 fputc('{', stdout); /* special case for upper leaves */
151 if (l2s <= 1 && above_threshold(tp)) {
152 for (i = 0; i < 1<<ttrank; i++) {
153 float val;
154 for (j = ttrank; j--; )
155 bkmin[j] = bmin[j] + (i>>(ttrank-1-j) & 1);
156 val = (ttrank == 3) ? dval3(bkmin[0],bkmin[1],bkmin[2])
157 : dval4(bkmin[0],bkmin[1],bkmin[2],bkmin[3]);
158 printf((0.001<=val)&(val<10.) ? " %.7f" : " %.3e", val);
159 }
160 fputs(" }\n", stdout);
161 return;
162 }
163 if (tp->kid == NULL) { /* trimmed limb */
164 printf(" %.6e }\n", tp->vavg);
165 return;
166 }
167 --l2s; /* else still branching */
168 fputc('\n', stdout);
169 for (i = 0; i < 1<<ttrank; i++) {
170 for (j = ttrank; j--; )
171 bkmin[j] = bmin[j] + ((i>>j & 1)<<l2s);
172 print_tree(tp->kid+i, bkmin, l2s);
173 }
174 ++l2s;
175 for (j = log2g-l2s; j--; )
176 fputs(" ", stdout);
177 fputs("}\n", stdout);
178 }
179
180 /* Read a row of data in ASCII */
181 static int
182 read_ascii(float *rowp, int n)
183 {
184 int n2go;
185
186 if ((rowp == NULL) | (n <= 0))
187 return(0);
188 for (n2go = n; n2go; n2go--)
189 if (scanf("%f", rowp++) != 1)
190 break;
191 if (n2go)
192 error(USER, "unexpected EOD on ascii input");
193 return(n-n2go);
194 }
195
196 /* Read a row of float data */
197 static int
198 read_float(float *rowp, int n)
199 {
200 int nread;
201
202 if ((rowp == NULL) | (n <= 0))
203 return(0);
204 nread = fread(rowp, sizeof(float), n, stdin);
205 if (nread != n)
206 error(USER, "unexpected EOF on float input");
207 return(nread);
208 }
209
210 /* Read a row of double data */
211 static int
212 read_double(float *rowp, int n)
213 {
214 static double *rowbuf = NULL;
215 static int rblen = 0;
216 int nread, i;
217
218 if ((rowp == NULL) | (n <= 0)) {
219 if (rblen) {
220 free(rowbuf);
221 rowbuf = NULL; rblen = 0;
222 }
223 return(0);
224 }
225 if (rblen < n) {
226 rowbuf = (double *)realloc(rowbuf, sizeof(double)*(rblen=n));
227 if (rowbuf == NULL)
228 error(SYSTEM, "out of memory in read_double");
229 }
230 nread = fread(rowbuf, sizeof(double), n, stdin);
231 if (nread != n)
232 error(USER, "unexpected EOF on double input");
233 for (i = 0; i < nread; i++)
234 *rowp++ = rowbuf[i];
235 return(nread);
236 }
237
238 /* Truncate any negative values to zero */
239 static void
240 noneg(float *varr, int n)
241 {
242 int nnan = 0;
243
244 while (n-- > 0) {
245 #ifdef isnan
246 if (isnan(*varr)) {
247 *varr = 0;
248 ++nnan;
249 } else
250 #endif
251 if (*varr < 0) *varr = 0;
252 ++varr;
253 }
254 if (nnan)
255 fprintf(stderr, "Warning: BSDF data contains %d NaN values\n",
256 nnan);
257 }
258
259 /* Load data array, filling zeroes for rank 3 demi-tensor */
260 static void
261 load_data(void)
262 {
263 int (*readf)(float *, int) = NULL;
264
265 switch (infmt) {
266 case 'a':
267 readf = &read_ascii;
268 break;
269 case 'f':
270 readf = &read_float;
271 break;
272 case 'd':
273 readf = &read_double;
274 break;
275 default:
276 error(COMMAND, "unsupported input format");
277 break;
278 }
279 /* XXX VC warns about 32 bit shift coerced to 64 bit */
280 datarr = (float *)calloc(1<<(log2g*ttrank), sizeof(float));
281 if (datarr == NULL)
282 error(SYSTEM, "out of memory in load_data");
283 if (ttrank == 3) {
284 int ix, ox;
285 for (ix = 0; ix < 1<<(log2g-1); ix++)
286 for (ox = 0; ox < 1<<log2g; ox++)
287 (*readf)(datarr+(((ix<<log2g)+ox)<<log2g),
288 1<<log2g);
289 } else /* ttrank == 4 */ {
290 int ix, iy, ox;
291 for (ix = 0; ix < 1<<log2g; ix++)
292 for (iy = 0; iy < 1<<log2g; iy++)
293 for (ox = 0; ox < 1<<log2g; ox++)
294 (*readf)(datarr +
295 (((((ix<<log2g)+iy)<<log2g)+ox)<<log2g),
296 1<<log2g);
297 }
298 (*readf)(NULL, 0); /* releases any buffers */
299 if (infmt == 'a') {
300 int c;
301 while ((c = getc(stdin)) != EOF) {
302 switch (c) {
303 case ' ':
304 case '\t':
305 case '\r':
306 case '\n':
307 continue;
308 }
309 error(WARNING, "data past end of expected input");
310 break;
311 }
312 } else if (getc(stdin) != EOF)
313 error(WARNING, "binary data past end of expected input");
314
315 noneg(datarr, 1<<(log2g*ttrank)); /* take precautions */
316 }
317
318 /* Enforce reciprocity by averaging data values */
319 static void
320 do_reciprocity(void)
321 {
322 const int siz = 1<<log2g;
323 float *v1p, *v2p;
324
325 if (ttrank == 3) {
326 int ix, ox, oy;
327 for (ix = 0; ix < siz>>1; ix++)
328 for (ox = 0; ox < siz; ox++)
329 for (oy = 0; oy < siz>>1; oy++) {
330 v1p = &dval3(ix,ox,oy);
331 v2p = &dval3(ix,ox,siz-1-oy);
332 *v1p = *v2p = .5f*( *v1p + *v2p );
333 }
334 } else /* ttrank == 4 */ {
335 int ix, iy, ox, oy;
336 for (ix = 1; ix < siz; ix++)
337 for (iy = 1; iy < siz; iy++)
338 for (ox = 0; ox < ix; ox++)
339 for (oy = 0; oy < iy; oy++) {
340 v1p = &dval4(siz-1-ix,siz-1-iy,ox,oy);
341 v2p = &dval4(siz-1-ox,siz-1-oy,ix,iy);
342 *v1p = *v2p = .5f*( *v1p + *v2p );
343 }
344 }
345 }
346
347 /* Load BSDF array, coalesce uniform regions and format as tensor tree */
348 int
349 main(int argc, char *argv[])
350 {
351 int doheader = 1;
352 int recipavg = 0;
353 int bmin[4];
354 TNODE gtree;
355 int i;
356 /* get options and parameters */
357 for (i = 1; i < argc && argv[i][0] == '-'; i++)
358 switch (argv[i][1]) {
359 case 'a':
360 recipavg = !recipavg;
361 break;
362 case 'h':
363 doheader = !doheader;
364 break;
365 case 'r':
366 ttrank = atoi(argv[++i]);
367 if (ttrank != 3 && ttrank != 4)
368 goto userr;
369 break;
370 case 'g':
371 log2g = atoi(argv[++i]);
372 if (log2g <= 1)
373 goto userr;
374 break;
375 case 't':
376 pctcull = atof(argv[++i]);
377 if ((pctcull < 0) | (pctcull >= 100.))
378 goto userr;
379 break;
380 case 'f':
381 infmt = argv[i][2];
382 if (!infmt || strchr("afd", infmt) == NULL)
383 goto userr;
384 break;
385 default:
386 goto userr;
387 }
388 if (i < argc-1)
389 goto userr;
390 /* load input data */
391 if (i == argc-1 && freopen(argv[i], "r", stdin) == NULL) {
392 sprintf(errmsg, "cannot open input file '%s'", argv[i]);
393 error(SYSTEM, errmsg);
394 }
395 if (infmt != 'a')
396 SET_FILE_BINARY(stdin);
397 #ifdef getc_unlocked /* avoid lock/unlock overhead */
398 flockfile(stdin);
399 #endif
400 load_data();
401 if (recipavg)
402 do_reciprocity();
403 if (doheader) {
404 for (i = 0; i < argc; i++) {
405 fputs(argv[i], stdout);
406 fputc(i < argc-1 ? ' ' : '\n', stdout);
407 }
408 fputc('\n', stdout);
409 }
410 gtree.kid = NULL; /* create our tree */
411 bmin[0] = bmin[1] = bmin[2] = bmin[3] = 0;
412 build_tree(&gtree, bmin, log2g);
413 /* compute threshold & trim tree */
414 set_threshold();
415 trim_tree(&gtree);
416 /* format to stdout */
417 print_tree(&gtree, bmin, log2g);
418 /* Clean up isn't necessary for main()...
419 free_kids(&gtree);
420 free(datarr);
421 */
422 return(0);
423 userr:
424 fprintf(stderr, "Usage: %s [-h][-a][-f{a|f|d}][-r {3|4}][-g log2grid][-t trim%%] [input]\n",
425 argv[0]);
426 return(1);
427 }