--- ray/src/util/eplus_adduvf.c 2014/02/10 04:51:26 2.3 +++ ray/src/util/eplus_adduvf.c 2014/02/13 17:33:37 2.10 @@ -1,5 +1,5 @@ #ifndef lint -static const char RCSid[] = "$Id: eplus_adduvf.c,v 2.3 2014/02/10 04:51:26 greg Exp $"; +static const char RCSid[] = "$Id: eplus_adduvf.c,v 2.10 2014/02/13 17:33:37 greg Exp $"; #endif /* * Add User View Factors to EnergyPlus Input Data File @@ -16,47 +16,60 @@ static const char RCSid[] = "$Id: eplus_adduvf.c,v 2.3 #include "rtprocess.h" #ifndef NSAMPLES -#define NSAMPLES 100000 /* number of samples to use */ +#define NSAMPLES 80000 /* default number of samples */ #endif char *progname; /* global argv[0] */ -char temp_octree[128]; /* temporary octree */ +int nsamps = NSAMPLES; /* number of samples to use */ +char temp_octree[128]; /* temporary octree */ + const char UVF_PNAME[] = - "ZoneProperty:UserViewFactor:bySurfaceName"; + "ZoneProperty:UserViewFactors:bySurfaceName"; const char ADD_HEADER[] = - "!+++ User View Factors computed by Radiance +++!\n"; + "\n!+++ User View Factors computed by Radiance +++!\n\n"; #define NAME_FLD 1 /* name field always first? */ typedef struct { - const char *pname; /* parameter type name */ + const char *pname; /* object type name */ short zone_fld; /* zone field index */ short vert_fld; /* vertex field index */ } SURF_PTYPE; /* surface type we're interested in */ const SURF_PTYPE surf_type[] = { {"BuildingSurface:Detailed", 4, 10}, + {"Floor:Detailed", 3, 9}, + {"RoofCeiling:Detailed", 3, 9}, + {"Wall:Detailed", 3, 9}, {NULL} - }; + }; /* IDF surface types */ typedef struct s_zone { const char *zname; /* zone name */ struct s_zone *next; /* next zone in list */ int nsurf; /* surface count */ - IDF_PARAMETER *pfirst; /* first matching parameter */ - IDF_PARAMETER *plast; /* last matching parameter */ + IDF_OBJECT *pfirst; /* first matching object */ + IDF_OBJECT *plast; /* last matching object */ } ZONE; /* a list of collected zone surfaces */ ZONE *zone_list = NULL; /* our list of zones */ IDF_LOADED *our_idf = NULL; /* loaded/modified IDF */ +typedef struct { + FVECT sdir[3]; /* UVW unit sampling vectors */ + double poff; /* W-offset for plane of polygon */ + double area_left; /* area left to sample */ + int samp_left; /* remaining samples */ + int wd; /* output file descriptor */ +} POLYSAMP; /* structure for polygon sampling */ + /* Create a new zone and push to top of our list */ static ZONE * -new_zone(const char *zname, IDF_PARAMETER *param) +new_zone(const char *zname, IDF_OBJECT *param) { ZONE *znew = (ZONE *)malloc(sizeof(ZONE)); @@ -71,7 +84,7 @@ new_zone(const char *zname, IDF_PARAMETER *param) /* Add the detailed surface (polygon) to the named zone */ static ZONE * -add2zone(IDF_PARAMETER *param, const char *zname) +add2zone(IDF_OBJECT *param, const char *zname) { ZONE *zptr; @@ -81,16 +94,16 @@ add2zone(IDF_PARAMETER *param, const char *zname) if (zptr == NULL) return(new_zone(zname, param)); /* keep surfaces together */ - if (!idf_movparam(our_idf, param, zptr->plast)) + if (!idf_movobject(our_idf, param, zptr->plast)) return(NULL); zptr->plast = param; zptr->nsurf++; return(zptr); } -/* Return field for vertices in the given parameter */ +/* Return field for vertices in the given object */ static IDF_FIELD * -get_vlist(IDF_PARAMETER *param, const char *zname) +get_vlist(IDF_OBJECT *param, const char *zname) { int i = 0; IDF_FIELD *fptr; @@ -110,7 +123,7 @@ get_vlist(IDF_PARAMETER *param, const char *zname) /* Convert surface to Radiance with modifier based on unique name */ static int -rad_surface(IDF_PARAMETER *param, FILE *ofp) +rad_surface(IDF_OBJECT *param, FILE *ofp) { const char *sname = idf_getfield(param,NAME_FLD)->val; IDF_FIELD *fptr = get_vlist(param, NULL); @@ -143,14 +156,14 @@ rad_surface(IDF_PARAMETER *param, FILE *ofp) static int start_rcontrib(SUBPROC *pd, ZONE *zp) { -#define BASE_AC 3 +#define BASE_AC 5 static char *base_av[BASE_AC] = { - "rcontrib", "-ff", "-h" + "rcontrib", "-fff", "-h", "-x", "1" }; char cbuf[300]; char **av; FILE *ofp; - IDF_PARAMETER *pptr; + IDF_OBJECT *pptr; int i, n; /* start oconv command */ sprintf(cbuf, "oconv - > '%s'", temp_octree); @@ -165,14 +178,14 @@ start_rcontrib(SUBPROC *pd, ZONE *zp) return(0); for (i = 0; i < BASE_AC; i++) av[i] = base_av[i]; - sprintf(cbuf, "%d", NSAMPLES); + sprintf(cbuf, "%d", nsamps); av[i++] = "-c"; av[i++] = cbuf; /* add modifier arguments */ for (n = zp->nsurf, pptr = zp->pfirst; n--; pptr = pptr->dnext) { IDF_FIELD *fptr = idf_getfield(pptr,NAME_FLD); if (fptr == NULL || !fptr->val[0]) { fputs(progname, stderr); - fputs(": missing name for surface parameter\n", stderr); + fputs(": missing name for surface object\n", stderr); return(0); } if (!rad_surface(pptr, ofp)) /* add surface to octree */ @@ -187,7 +200,7 @@ start_rcontrib(SUBPROC *pd, ZONE *zp) } av[i++] = temp_octree; /* add final octree argument */ av[i] = NULL; - if (!open_process(pd, av)) { /* start process */ + if (open_process(pd, av) <= 0) { /* start process */ fputs(progname, stderr); fputs(": cannot start rcontrib process\n", stderr); return(0); @@ -197,14 +210,6 @@ start_rcontrib(SUBPROC *pd, ZONE *zp) #undef BASE_AC } -typedef struct { - FVECT sdir[3]; /* XYZ unit sampling vectors */ - double poff; /* Z-offset for plane of polygon */ - double area_left; /* area left to sample */ - int samp_left; /* remaining samples */ - int wd; /* output file descriptor */ -} POLYSAMP; /* structure for polygon sampling */ - /* Initialize polygon sampling */ static Vert2_list * init_poly(POLYSAMP *ps, IDF_FIELD *f0, int nv) @@ -221,14 +226,15 @@ init_poly(POLYSAMP *ps, IDF_FIELD *f0, int nv) vl3 = (FVECT *)malloc(sizeof(FVECT)*nv); if (vl3 == NULL) return(NULL); - for (i = 0; i < nv; i++) + for (i = nv; i--; ) /* reverse vertex ordering */ for (j = 0; j < 3; j++) { if (fptr == NULL) { fputs(progname, stderr); - fputs(": bad vertex in init_poly()\n", stderr); + fputs(": missing vertex in init_poly()\n", stderr); return(NULL); } vl3[i][j] = atof(fptr->val); + fptr = fptr->next; } /* compute area and normal */ ps->sdir[2][0] = ps->sdir[2][1] = ps->sdir[2][2] = 0; @@ -252,7 +258,7 @@ init_poly(POLYSAMP *ps, IDF_FIELD *f0, int nv) normalize(ps->sdir[0]); fcross(ps->sdir[1], ps->sdir[2], ps->sdir[0]); /* compute plane offset */ - ps->poff = DOT(vl3[0], ps->sdir[2]) + FTINY; + ps->poff = DOT(vl3[0], ps->sdir[2]); /* assign 2-D vertices */ for (i = 0; i < nv; i++) { vl2->v[i].mX = DOT(vl3[i], ps->sdir[0]); @@ -276,7 +282,7 @@ sample_triangle(const Vert2_list *vl2, int a, int b, i for (i = 3; i--; ) { orig[i] = vl2->v[a].mX*ps->sdir[0][i] + vl2->v[a].mY*ps->sdir[1][i] + - ps->poff*ps->sdir[2][i]; + (ps->poff+.001)*ps->sdir[2][i]; ab[i] = (vl2->v[b].mX - vl2->v[a].mX)*ps->sdir[0][i] + (vl2->v[b].mY - vl2->v[a].mY)*ps->sdir[1][i]; ac[i] = (vl2->v[c].mX - vl2->v[a].mX)*ps->sdir[0][i] + @@ -305,18 +311,23 @@ sample_triangle(const Vert2_list *vl2, int a, int b, i samp = (float *)malloc(sizeof(float)*6*ns); if (samp == NULL) return(0); - for (i = ns; i--; ) { + for (i = ns; i--; ) { /* stratified Monte Carlo sampling */ double sv[4]; + FVECT dv; multisamp(sv, 4, (i+frandom())/(double)ns); sv[0] *= sv[1] = sqrt(sv[1]); sv[1] = 1. - sv[1]; for (j = 3; j--; ) - samp[ns*6 + j] = orig[j] + sv[0]*ab[j] + sv[1]*ac[j]; - sv[3] = sqrt(sv[3]); - sv[4] *= 2.*PI; - samp[ns*6 + 3] = tcos(sv[4]) * sv[3]; - samp[ns*6 + 4] = tsin(sv[4]) * sv[3]; - samp[ns*6 + 5] = sqrt(1. - sv[3]*sv[3]); + samp[i*6 + j] = orig[j] + sv[0]*ab[j] + sv[1]*ac[j]; + sv[2] = sqrt(sv[2]); + sv[3] *= 2.*PI; + dv[0] = tcos(sv[3]) * sv[2]; + dv[1] = tsin(sv[3]) * sv[2]; + dv[2] = sqrt(1. - sv[2]*sv[2]); + for (j = 3; j--; ) + samp[i*6 + 3 + j] = dv[0]*ps->sdir[0][j] + + dv[1]*ps->sdir[1][j] + + dv[2]*ps->sdir[2][j] ; } /* send to our process */ writebuf(ps->wd, (char *)samp, sizeof(float)*6*ns); @@ -326,23 +337,21 @@ sample_triangle(const Vert2_list *vl2, int a, int b, i /* Sample the given surface */ static int -sample_surface(IDF_PARAMETER *param, int wd) +sample_surface(IDF_OBJECT *param, int wd) { IDF_FIELD *fptr = get_vlist(param, NULL); POLYSAMP psamp; int nv; Vert2_list *vlist2; /* set up our polygon sampler */ - if (fptr == NULL || (nv = atoi(fptr->val)) < 3) { - fprintf(stderr, "%s: error in %s '%s'\n", + if (fptr == NULL || (nv = atoi(fptr->val)) < 3 || + (vlist2 = init_poly(&psamp, fptr->next, nv)) == NULL) { + fprintf(stderr, "%s: bad polygon %s '%s'\n", progname, param->pname, idf_getfield(param,NAME_FLD)->val); return(0); } - vlist2 = init_poly(&psamp, fptr->next, nv); - if (vlist2 == NULL) - return(0); - psamp.samp_left = NSAMPLES; /* assign samples & destination */ + psamp.samp_left = nsamps; /* assign samples & destination */ psamp.wd = wd; /* sample each subtriangle */ if (!polyTriangulate(vlist2, &sample_triangle)) @@ -355,16 +364,16 @@ sample_surface(IDF_PARAMETER *param, int wd) static int compute_uvfs(SUBPROC *pd, ZONE *zp) { - IDF_PARAMETER *pptr, *pout, *pptr1; + IDF_OBJECT *pptr, *pout, *pptr1; float *uvfa; char uvfbuf[24]; int n, m; - /* create output parameter */ - pout = idf_newparam(our_idf, UVF_PNAME, + /* create output object */ + pout = idf_newobject(our_idf, UVF_PNAME, " ! computed by Radiance\n ", zp->plast); if (pout == NULL) { fputs(progname, stderr); - fputs(": cannot create new IDF parameter\n", stderr); + fputs(": cannot create new IDF object\n", stderr); return(0); } if (!idf_addfield(pout, zp->zname, @@ -379,6 +388,7 @@ compute_uvfs(SUBPROC *pd, ZONE *zp) return(0); /* UVFs from each surface */ for (n = zp->nsurf, pptr = zp->pfirst; n--; pptr = pptr->dnext) { + double vfsum = 0; /* send samples to rcontrib */ if (!sample_surface(pptr, pd->w)) return(0); @@ -392,15 +402,16 @@ compute_uvfs(SUBPROC *pd, ZONE *zp) /* append UVF fields */ for (m = 0, pptr1 = zp->pfirst; m < zp->nsurf; m++, pptr1 = pptr1->dnext) { + vfsum += uvfa[3*m + 1]; if (pptr1 == pptr) { if (uvfa[3*m + 1] > .001) fprintf(stderr, - "%s: warning - non-zero self-VF (%.3e) for surface '%s'\n", - progname, uvfa[3*m + 1], + "%s: warning - non-zero self-VF (%.1f%%) for surface '%s'\n", + progname, 100.*uvfa[3*m + 1], idf_getfield(pptr,NAME_FLD)->val); continue; /* don't record self-factor */ } - sprintf(uvfbuf, "%.6f", uvfa[3*m + 1]); + sprintf(uvfbuf, "%.4f", uvfa[3*m + 1]); if (!idf_addfield(pout, idf_getfield(pptr,NAME_FLD)->val, NULL) || !idf_addfield(pout, @@ -413,6 +424,11 @@ compute_uvfs(SUBPROC *pd, ZONE *zp) return(0); } } + if (vfsum < 0.95) + fprintf(stderr, + "%s: warning - missing %.1f%% of energy from surface '%s'\n", + progname, 100.*(1.-vfsum), + idf_getfield(pptr,NAME_FLD)->val); } free(uvfa); /* clean up and return */ return(1); @@ -424,11 +440,7 @@ compute_zones(void) { ZONE *zptr; /* temporary octree name */ - if (temp_filename(temp_octree, sizeof(temp_octree), TEMPLATE) == NULL) { - fputs(progname, stderr); - fputs(": cannot create temporary octree\n", stderr); - return(0); - } + mktemp(strcpy(temp_octree, TEMPLATE)); /* compute each zone */ for (zptr = zone_list; zptr != NULL; zptr = zptr->next) { SUBPROC rcproc; @@ -454,22 +466,31 @@ main(int argc, char *argv[]) { int incl_comments = 1; char *origIDF, *revIDF; - IDF_PARAMETER *pptr; + IDF_OBJECT *pptr; int i; - progname = argv[0]; - if (argc > 2 && !strcmp(argv[1], "-c")) { - incl_comments = -1; /* output header only */ - ++argv; --argc; - } - if ((argc < 2) | (argc > 3)) { - fputs("Usage: ", stderr); - fputs(progname, stderr); - fputs(" [-c] Model.idf [Revised.idf]\n", stderr); - return(1); - } - origIDF = argv[1]; - revIDF = (argc == 2) ? argv[1] : argv[2]; + progname = *argv++; argc--; /* get options if any */ + while (argc > 1 && argv[0][0] == '-') + switch (argv[0][1]) { + case 'c': /* elide comments */ + incl_comments = -1; /* header only */ + argv++; argc--; + continue; + case 's': /* samples */ + nsamps = 1000*atoi(*++argv); + argv++; argc -= 2; + continue; + default: + fputs(progname, stderr); + fputs(": unknown option '", stderr); + fputs(argv[0], stderr); + fputs("'\n", stderr); + goto userr; + } + if ((argc < 1) | (argc > 2)) + goto userr; + origIDF = argv[0]; + revIDF = (argc == 1) ? argv[0] : argv[1]; /* load Input Data File */ our_idf = idf_load(origIDF); if (our_idf == NULL) { @@ -480,13 +501,13 @@ main(int argc, char *argv[]) return(1); } /* remove existing UVFs */ - if ((pptr = idf_getparam(our_idf, UVF_PNAME)) != NULL) { - IDF_PARAMETER *pnext; + if ((pptr = idf_getobject(our_idf, UVF_PNAME)) != NULL) { + IDF_OBJECT *pnext; fputs(progname, stderr); fputs(": removing previous User View Factors\n", stderr); do { pnext = pptr->pnext; - idf_delparam(our_idf, pptr); + idf_delobject(our_idf, pptr); } while (pnext != NULL); } /* add to header */ @@ -496,7 +517,7 @@ main(int argc, char *argv[]) idf_add2hdr(our_idf, ADD_HEADER); /* gather zone surfaces */ for (i = 0; surf_type[i].pname != NULL; i++) - for (pptr = idf_getparam(our_idf, surf_type[i].pname); + for (pptr = idf_getobject(our_idf, surf_type[i].pname); pptr != NULL; pptr = pptr->pnext) { IDF_FIELD *fptr = idf_getfield(pptr, surf_type[i].zone_fld); @@ -520,4 +541,9 @@ main(int argc, char *argv[]) return(1); } return(0); /* finito! */ +userr: + fputs("Usage: ", stderr); + fputs(progname, stderr); + fputs(" [-c][-s Ksamps] Model.idf [Revised.idf]\n", stderr); + return(1); }