--- ray/src/util/rttree_reduce.c 2011/05/26 15:32:02 2.1 +++ ray/src/util/rttree_reduce.c 2020/05/11 20:26:12 2.19 @@ -1,5 +1,5 @@ #ifndef lint -static const char RCSid[] = "$Id: rttree_reduce.c,v 2.1 2011/05/26 15:32:02 greg Exp $"; +static const char RCSid[] = "$Id: rttree_reduce.c,v 2.19 2020/05/11 20:26:12 greg Exp $"; #endif /* * A utility called by genBSDF.pl to reduce tensor tree samples and output @@ -11,18 +11,17 @@ static const char RCSid[] = "$Id: rttree_reduce.c,v 2. #include "rterror.h" #include "platform.h" #include +#include float *datarr; /* our loaded BSDF data array */ int ttrank = 4; /* tensor tree rank */ int log2g = 4; /* log2 of grid resolution */ int infmt = 'a'; /* input format ('a','f','d') */ -double tthresh = .05; /* relative acceptance threshold */ +double pctcull = 95.; /* target culling percentile */ -#define dval3(ix,ox,oy) datarr[((((ix)<vmax - (tp)->vmin > 2.*tthresh*(tp)->vavg) - /* Tensor tree node */ typedef struct ttree_s { float vmin, vmax; /* value extrema */ @@ -30,11 +29,22 @@ typedef struct ttree_s { struct ttree_s *kid; /* 2^ttrank children */ } TNODE; +#define HISTLEN 300 /* histogram resolution */ +#define HISTMAX 4. /* maximum recorded measure in histogram */ + +int histo[HISTLEN]; /* histogram freq. of variance measure */ + +double tthresh; /* acceptance threshold (TBD) */ + +#define var_measure(tp) sqrt( ((tp)->vmax - (tp)->vmin) / \ + (sqrt((tp)->vavg) + .03) ) +#define above_threshold(tp) (var_measure(tp) > tthresh) + /* Allocate a new set of children for the given node (no checks) */ static void new_kids(TNODE *pn) { - pn->kid = (TNODE *)calloc(1<kid = (TNODE *)calloc((size_t)1<kid == NULL) error(SYSTEM, "out of memory in new_kids"); } @@ -77,6 +87,10 @@ build_tree(TNODE *tp, const int bmin[], int l2s) tp->vavg += val; } tp->vavg /= (float)(1<= HISTLEN) i = HISTLEN-1; + ++histo[i]; return; } --l2s; /* else still branching */ @@ -92,11 +106,38 @@ build_tree(TNODE *tp, const int bmin[], int l2s) tp->vavg += tp->kid[i].vavg; } tp->vavg /= (float)(1< 0; i++) + hsum -= histo[i]; + tthresh = (HISTMAX/HISTLEN) * i; +} + +/* Trim our tree according to the current threshold */ +static void +trim_tree(TNODE *tp) +{ + if (tp->kid == NULL) + return; + if (above_threshold(tp)) { /* keeping branches? */ + int i = 1<kid+i); + return; + } + free_kids(tp); /* else trim at this point */ +} + /* Print a tensor tree from the given hypercube */ static void print_tree(const TNODE *tp, const int bmin[], int l2s) @@ -111,10 +152,10 @@ print_tree(const TNODE *tp, const int bmin[], int l2s) for (i = 0; i < 1<>j & 1); + bkmin[j] = bmin[j] + (i>>(ttrank-1-j) & 1); val = (ttrank == 3) ? dval3(bkmin[0],bkmin[1],bkmin[2]) : dval4(bkmin[0],bkmin[1],bkmin[2],bkmin[3]); - printf(" %.4e", val); + printf((0.001<=val)&(val<10.) ? " %.7f" : " %.3e", val); } fputs(" }\n", stdout); return; @@ -160,7 +201,7 @@ read_float(float *rowp, int n) if ((rowp == NULL) | (n <= 0)) return(0); - nread = fread(rowp, sizeof(float), n, stdin); + nread = getbinary(rowp, sizeof(float), n, stdin); if (nread != n) error(USER, "unexpected EOF on float input"); return(nread); @@ -182,11 +223,12 @@ read_double(float *rowp, int n) return(0); } if (rblen < n) { - rowbuf = (double *)realloc(rowbuf, sizeof(double)*(rblen=n)); + if (rblen) free(rowbuf); + rowbuf = (double *)malloc(sizeof(double)*(rblen=n)); if (rowbuf == NULL) error(SYSTEM, "out of memory in read_double"); } - nread = fread(rowbuf, sizeof(double), n, stdin); + nread = getbinary(rowbuf, sizeof(double), n, stdin); if (nread != n) error(USER, "unexpected EOF on double input"); for (i = 0; i < nread; i++) @@ -194,9 +236,30 @@ read_double(float *rowp, int n) return(nread); } +/* Truncate any negative values to zero */ +static void +noneg(float *varr, int n) +{ + int nnan = 0; + + while (n-- > 0) { +#ifdef isnan + if (isnan(*varr)) { + *varr = 0; + ++nnan; + } else +#endif + if (*varr < 0) *varr = 0; + ++varr; + } + if (nnan) + fprintf(stderr, "Warning: BSDF data contains %d NaN values\n", + nnan); +} + /* Load data array, filling zeroes for rank 3 demi-tensor */ static void -load_data() +load_data(void) { int (*readf)(float *, int) = NULL; @@ -214,23 +277,20 @@ load_data() error(COMMAND, "unsupported input format"); break; } - datarr = (float *)calloc(1<<(log2g*ttrank), sizeof(float)); + datarr = (float *)calloc((size_t)1<<(log2g*ttrank), sizeof(float)); if (datarr == NULL) error(SYSTEM, "out of memory in load_data"); if (ttrank == 3) { int ix, ox; - for (ix = 0; ix < 1<>1; ix++) + for (ox = 0; ox < siz; ox++) + for (oy = 0; oy < siz>>1; oy++) { + v1p = &dval3(ix,ox,oy); + v2p = &dval3(ix,ox,siz-1-oy); + *v1p = *v2p = .5f*( *v1p + *v2p ); + } + } else /* ttrank == 4 */ { + int ix, iy, ox, oy; + for (ix = 0; ix < siz; ix++) + for (iy = 0; iy < siz; iy++) { + int cnt = ix*siz + iy; + for (ox = 0; cnt > 0; ox++) + for (oy = 0; oy < siz; oy++) { + v1p = &dval4(siz-1-ix,siz-1-iy,ox,oy); + v2p = &dval4(siz-1-ox,siz-1-oy,ix,iy); + *v1p = *v2p = .5f*( *v1p + *v2p ); + if (--cnt <= 0) + break; + } + } + } +} + /* Load BSDF array, coalesce uniform regions and format as tensor tree */ int main(int argc, char *argv[]) { int doheader = 1; + int recipavg = 0; int bmin[4]; TNODE gtree; int i; /* get options and parameters */ for (i = 1; i < argc && argv[i][0] == '-'; i++) switch (argv[i][1]) { + case 'a': + recipavg = !recipavg; + break; case 'h': doheader = !doheader; break; @@ -275,8 +374,8 @@ main(int argc, char *argv[]) goto userr; break; case 't': - tthresh = atof(argv[++i]); - if (tthresh <= 0) + pctcull = atof(argv[++i]); + if ((pctcull < 0) | (pctcull >= 100.)) goto userr; break; case 'f': @@ -290,13 +389,18 @@ main(int argc, char *argv[]) if (i < argc-1) goto userr; /* load input data */ - if (i == argc-1 && freopen(argv[i], "rb", stdin) == NULL) { + if (i == argc-1 && freopen(argv[i], "r", stdin) == NULL) { sprintf(errmsg, "cannot open input file '%s'", argv[i]); error(SYSTEM, errmsg); } if (infmt != 'a') SET_FILE_BINARY(stdin); +#ifdef getc_unlocked /* avoid lock/unlock overhead */ + flockfile(stdin); +#endif load_data(); + if (recipavg) + do_reciprocity(); if (doheader) { for (i = 0; i < argc; i++) { fputs(argv[i], stdout); @@ -307,6 +411,9 @@ main(int argc, char *argv[]) gtree.kid = NULL; /* create our tree */ bmin[0] = bmin[1] = bmin[2] = bmin[3] = 0; build_tree(>ree, bmin, log2g); + /* compute threshold & trim tree */ + set_threshold(); + trim_tree(>ree); /* format to stdout */ print_tree(>ree, bmin, log2g); /* Clean up isn't necessary for main()... @@ -315,7 +422,7 @@ main(int argc, char *argv[]) */ return(0); userr: - fprintf(stderr, "Usage: %s [-h][-f{a|f|d}][-r {3|4}][-g log2grid][-t thresh] [input]\n", + fprintf(stderr, "Usage: %s [-h][-a][-f{a|f|d}][-r {3|4}][-g log2grid][-t trim%%] [input]\n", argv[0]); return(1); }