ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/util/eplus_adduvf.c
Revision: 2.22
Committed: Fri Feb 28 05:18:49 2020 UTC (4 years, 1 month ago) by greg
Content type: text/plain
Branch: MAIN
CVS Tags: rad5R4, rad5R3, HEAD
Changes since 2.21: +2 -1 lines
Log Message:
Added filtering capabilities to Unix version of open_process()

File Contents

# User Rev Content
1 greg 2.1 #ifndef lint
2 greg 2.22 static const char RCSid[] = "$Id: eplus_adduvf.c,v 2.21 2020/01/20 17:53:40 greg Exp $";
3 greg 2.1 #endif
4     /*
5     * Add User View Factors to EnergyPlus Input Data File
6     *
7     * G.Ward for LBNL
8     */
9    
10     #include <stdlib.h>
11 greg 2.21 #include <ctype.h>
12 schorsch 2.18 #include "platform.h"
13 greg 2.3 #include "rtio.h"
14     #include "rtmath.h"
15     #include "random.h"
16 greg 2.1 #include "eplus_idf.h"
17     #include "triangulate.h"
18 greg 2.2 #include "rtprocess.h"
19 greg 2.1
20     #ifndef NSAMPLES
21 greg 2.7 #define NSAMPLES 80000 /* default number of samples */
22 greg 2.1 #endif
23    
24 greg 2.11 #define SURF_EPS 0.0005 /* surface testing epsilon */
25    
26 greg 2.2 char *progname; /* global argv[0] */
27    
28 greg 2.7 int nsamps = NSAMPLES; /* number of samples to use */
29    
30 greg 2.5 char temp_octree[128]; /* temporary octree */
31 greg 2.2
32     const char UVF_PNAME[] =
33 greg 2.10 "ZoneProperty:UserViewFactors:bySurfaceName";
34 greg 2.1
35 greg 2.11 const char SUBSURF_PNAME[] =
36     "FenestrationSurface:Detailed";
37    
38 greg 2.1 const char ADD_HEADER[] =
39 greg 2.5 "\n!+++ User View Factors computed by Radiance +++!\n\n";
40 greg 2.1
41     #define NAME_FLD 1 /* name field always first? */
42    
43 greg 2.11 #define SS_BASE_FLD 4 /* subsurface base surface */
44 greg 2.21 #define SS_VERT_FLD 9 /* subsurface vertex count */
45 greg 2.11
46 greg 2.1 typedef struct {
47 greg 2.9 const char *pname; /* object type name */
48 greg 2.1 short zone_fld; /* zone field index */
49     short vert_fld; /* vertex field index */
50     } SURF_PTYPE; /* surface type we're interested in */
51    
52     const SURF_PTYPE surf_type[] = {
53     {"BuildingSurface:Detailed", 4, 10},
54 greg 2.5 {"Floor:Detailed", 3, 9},
55     {"RoofCeiling:Detailed", 3, 9},
56     {"Wall:Detailed", 3, 9},
57 greg 2.1 {NULL}
58 greg 2.7 }; /* IDF surface types */
59 greg 2.1
60 greg 2.2 typedef struct s_zone {
61 greg 2.1 const char *zname; /* zone name */
62     struct s_zone *next; /* next zone in list */
63 greg 2.2 int nsurf; /* surface count */
64 greg 2.11 int ntotal; /* surfaces+subsurfaces */
65 greg 2.9 IDF_OBJECT *pfirst; /* first matching object */
66 greg 2.11 IDF_OBJECT *plast; /* last before subsurfaces */
67 greg 2.12 float *area_redu; /* subsurface area per surf. */
68 greg 2.2 } ZONE; /* a list of collected zone surfaces */
69    
70     ZONE *zone_list = NULL; /* our list of zones */
71 greg 2.1
72 greg 2.11 LUTAB zonesurf_lut = /* zone surface lookup table */
73     LU_SINIT(NULL,NULL);
74    
75 greg 2.1 IDF_LOADED *our_idf = NULL; /* loaded/modified IDF */
76    
77 greg 2.7 typedef struct {
78 greg 2.11 FVECT norm; /* surface normal */
79     double area; /* surface area */
80     int nv; /* number of vertices */
81     FVECT vl[3]; /* vertex list (extends struct) */
82     } SURFACE; /* a polygonal surface */
83    
84     typedef struct {
85 greg 2.7 FVECT sdir[3]; /* UVW unit sampling vectors */
86     double poff; /* W-offset for plane of polygon */
87     double area_left; /* area left to sample */
88     int samp_left; /* remaining samples */
89     int wd; /* output file descriptor */
90     } POLYSAMP; /* structure for polygon sampling */
91    
92 greg 2.1 /* Create a new zone and push to top of our list */
93 greg 2.2 static ZONE *
94 greg 2.9 new_zone(const char *zname, IDF_OBJECT *param)
95 greg 2.1 {
96 greg 2.2 ZONE *znew = (ZONE *)malloc(sizeof(ZONE));
97 greg 2.1
98     if (znew == NULL)
99     return(NULL);
100     znew->zname = zname; /* assumes static */
101     znew->next = zone_list;
102     znew->pfirst = znew->plast = param;
103 greg 2.11 znew->ntotal = znew->nsurf = 1;
104 greg 2.12 znew->area_redu = NULL;
105 greg 2.1 return(zone_list = znew);
106     }
107    
108     /* Add the detailed surface (polygon) to the named zone */
109 greg 2.2 static ZONE *
110 greg 2.9 add2zone(IDF_OBJECT *param, const char *zname)
111 greg 2.1 {
112 greg 2.11 IDF_FIELD *nfp = idf_getfield(param, NAME_FLD);
113     ZONE *zptr;
114     LUENT *lep;
115 greg 2.1
116 greg 2.11 if (nfp == NULL) {
117     fputs(progname, stderr);
118     fputs(": surface missing name field!\n", stderr);
119     return(NULL);
120     }
121 greg 2.1 for (zptr = zone_list; zptr != NULL; zptr = zptr->next)
122     if (!strcmp(zptr->zname, zname))
123     break;
124 greg 2.11 if (zptr == NULL) {
125     zptr = new_zone(zname, param);
126     } else { /* keep surfaces together */
127     if (!idf_movobject(our_idf, param, zptr->plast))
128     return(NULL);
129     zptr->plast = param;
130     zptr->nsurf++;
131     zptr->ntotal++;
132     }
133     /* add to lookup table */
134     lep = lu_find(&zonesurf_lut, nfp->val);
135     if (lep == NULL)
136     return(NULL);
137     if (lep->data != NULL) {
138     fputs(progname, stderr);
139     fputs(": duplicate surface name '", stderr);
140     fputs(nfp->val, stderr);
141     fputs("'\n", stderr);
142     return(NULL);
143     }
144     lep->key = nfp->val;
145     lep->data = (char *)zptr;
146     return(zptr);
147     }
148    
149     /* Add a subsurface by finding its base surface and the corresponding zone */
150     static ZONE *
151     add_subsurf(IDF_OBJECT *param)
152     {
153     IDF_FIELD *bfp = idf_getfield(param, SS_BASE_FLD);
154     ZONE *zptr;
155     LUENT *lep;
156    
157     if (bfp == NULL) {
158     fputs(progname, stderr);
159     fputs(": missing base field name in subsurface!\n", stderr);
160     return(NULL);
161     }
162     lep = lu_find(&zonesurf_lut, bfp->val); /* find base zone */
163     if (lep == NULL || lep->data == NULL) {
164     fputs(progname, stderr);
165     fputs(": cannot find referenced base surface '", stderr);
166     fputs(bfp->val, stderr);
167     fputs("'\n", stderr);
168     return(NULL);
169     }
170     zptr = (ZONE *)lep->data; /* add this subsurface */
171 greg 2.9 if (!idf_movobject(our_idf, param, zptr->plast))
172 greg 2.1 return(NULL);
173 greg 2.11 zptr->ntotal++;
174 greg 2.1 return(zptr);
175     }
176    
177 greg 2.9 /* Return field for vertices in the given object */
178 greg 2.3 static IDF_FIELD *
179 greg 2.9 get_vlist(IDF_OBJECT *param, const char *zname)
180 greg 2.2 {
181 greg 2.15 #define itm_len (sizeof(IDF_FIELD)+6)
182 greg 2.14 static char fld_buf[4*itm_len];
183     static char *next_fbp = fld_buf;
184     int i;
185     IDF_FIELD *res;
186 greg 2.11 /* check if subsurface */
187     if (!strcmp(param->pname, SUBSURF_PNAME)) {
188     if (zname != NULL) {
189     LUENT *lep = lu_find(&zonesurf_lut,
190     idf_getfield(param,SS_BASE_FLD)->val);
191     if (strcmp((*(ZONE *)lep->data).zname, zname))
192     return(NULL);
193     }
194 greg 2.13 res = idf_getfield(param, SS_VERT_FLD);
195     } else {
196     i = 0; /* check for surface type */
197     while (strcmp(surf_type[i].pname, param->pname))
198     if (surf_type[++i].pname == NULL)
199     return(NULL);
200    
201     if (zname != NULL) { /* matches specified zone? */
202     IDF_FIELD *fptr = idf_getfield(param, surf_type[i].zone_fld);
203     if (fptr == NULL || strcmp(fptr->val, zname))
204     return(NULL);
205     }
206     res = idf_getfield(param, surf_type[i].vert_fld);
207 greg 2.11 }
208 greg 2.21 if (!res->val[0] || tolower(res->val[0]) == 'a') { /* autocalculate */
209 greg 2.13 IDF_FIELD *fptr;
210     if (next_fbp >= fld_buf+sizeof(fld_buf))
211     next_fbp = fld_buf;
212     i = 0; /* count vertices */
213     for (fptr = res->next; fptr != NULL; fptr = fptr->next)
214     ++i;
215     if (i % 3)
216 greg 2.3 return(NULL);
217 greg 2.13 fptr = res->next;
218     res = (IDF_FIELD *)next_fbp; next_fbp += itm_len;
219     res->next = fptr;
220     res->rem = "";
221     sprintf(res->val, "%d", i/3);
222 greg 2.3 }
223 greg 2.13 return(res);
224 greg 2.15 #undef itm_len
225 greg 2.2 }
226    
227 greg 2.11 /* Get/allocate surface polygon */
228     static SURFACE *
229     get_surface(IDF_FIELD *fptr)
230     {
231     SURFACE *surf;
232     int nv;
233     FVECT e1, e2, vc;
234     int i, j;
235     /* get number of vertices */
236     if (fptr == NULL || (nv = atoi(fptr->val)) < 3) {
237     fputs(progname, stderr);
238     fputs(": bad vertex count for surface!\n", stderr);
239     return(NULL);
240     }
241     surf = (SURFACE *)malloc(sizeof(SURFACE)+sizeof(FVECT)*(nv-3));
242     if (surf == NULL)
243     return(NULL);
244     surf->nv = nv;
245     for (i = nv; i--; ) /* reverse vertex order/orientation */
246     for (j = 0; j < 3; j++) {
247     fptr = fptr->next;
248     if (fptr == NULL) {
249     fputs(progname, stderr);
250     fputs(": missing vertex in get_surface()\n", stderr);
251     free(surf);
252     return(NULL);
253     }
254     if ((surf->vl[i][j] = atof(fptr->val)) == 0 &&
255     !isflt(fptr->val)) {
256     fputs(progname, stderr);
257     fputs(": bad vertex in get_surface()\n", stderr);
258     free(surf);
259     return(NULL);
260     }
261     }
262     /* compute area and normal */
263     surf->norm[0] = surf->norm[1] = surf->norm[2] = 0;
264     VSUB(e1, surf->vl[1], surf->vl[0]);
265     for (i = 2; i < nv; i++) {
266     VSUB(e2, surf->vl[i], surf->vl[0]);
267     fcross(vc, e1, e2);
268     surf->norm[0] += vc[0];
269     surf->norm[1] += vc[1];
270     surf->norm[2] += vc[2];
271     VCOPY(e1, e2);
272     }
273     surf->area = .5 * normalize(surf->norm);
274     if (surf->area == 0) {
275     fputs(progname, stderr);
276     fputs(": degenerate polygon in get_surface()\n", stderr);
277     free(surf);
278     return(NULL);
279     }
280     return(surf);
281     }
282    
283 greg 2.2 /* Convert surface to Radiance with modifier based on unique name */
284     static int
285 greg 2.9 rad_surface(IDF_OBJECT *param, FILE *ofp)
286 greg 2.2 {
287 greg 2.3 const char *sname = idf_getfield(param,NAME_FLD)->val;
288     IDF_FIELD *fptr = get_vlist(param, NULL);
289 greg 2.11 const char **fargs;
290     int nvert, i, j;
291 greg 2.2
292 greg 2.3 if (fptr == NULL || (nvert = atoi(fptr->val)) < 3) {
293 greg 2.2 fprintf(stderr, "%s: bad surface '%s'\n", progname, sname);
294     return(0);
295     }
296 greg 2.11 fargs = (const char **)malloc(sizeof(const char *)*3*nvert);
297     if (fargs == NULL)
298     return(0);
299 greg 2.2 fprintf(ofp, "\nvoid glow '%s'\n0\n0\n4 1 1 1 0\n", sname);
300     fprintf(ofp, "\n'%s' polygon 's_%s'\n0\n0\n%d\n", sname, sname, 3*nvert);
301 greg 2.11 for (j = nvert; j--; ) { /* get arguments in reverse */
302     for (i = 0; i < 3; i++) {
303 greg 2.2 fptr = fptr->next;
304 greg 2.3 if (fptr == NULL || !isflt(fptr->val)) {
305 greg 2.2 fprintf(stderr,
306 greg 2.3 "%s: missing/bad vertex for %s '%s'\n",
307     progname, param->pname, sname);
308 greg 2.2 return(0);
309     }
310 greg 2.11 fargs[3*j + i] = fptr->val;
311     }
312     }
313     for (j = 0; j < nvert; j++) { /* output reversed verts */
314     for (i = 0; i < 3; i++) {
315 greg 2.2 fputc('\t', ofp);
316 greg 2.11 fputs(fargs[3*j + i], ofp);
317 greg 2.2 }
318     fputc('\n', ofp);
319     }
320 greg 2.11 free(fargs);
321     return(!ferror(ofp));
322     }
323    
324     /* Convert subsurface to Radiance with modifier based on unique name */
325 greg 2.12 static double
326 greg 2.11 rad_subsurface(IDF_OBJECT *param, FILE *ofp)
327     {
328     const char *sname = idf_getfield(param,NAME_FLD)->val;
329 greg 2.14 SURFACE *surf = get_surface(get_vlist(param, NULL));
330 greg 2.12 double area;
331 greg 2.11 int i;
332    
333     if (surf == NULL) {
334     fprintf(stderr, "%s: bad subsurface '%s'\n", progname, sname);
335 greg 2.12 return(-1.);
336 greg 2.11 }
337     fprintf(ofp, "\nvoid glow '%s'\n0\n0\n4 1 1 1 0\n", sname);
338     fprintf(ofp, "\n'%s' polygon 'ss_%s'\n0\n0\n%d\n",
339     sname, sname, 3*surf->nv);
340     for (i = 0; i < surf->nv; i++) { /* offset vertices */
341     FVECT vert;
342     VSUM(vert, surf->vl[i], surf->norm, 2.*SURF_EPS);
343     fprintf(ofp, "\t%.12f %.12f %.12f\n", vert[0], vert[1], vert[2]);
344     }
345 greg 2.12 area = surf->area;
346 greg 2.11 free(surf);
347 greg 2.12 if (ferror(ofp))
348     return(-1.);
349     return(area);
350 greg 2.2 }
351    
352 greg 2.3 /* Start rcontrib process */
353 greg 2.2 static int
354     start_rcontrib(SUBPROC *pd, ZONE *zp)
355     {
356 greg 2.11 #define BASE_AC 6
357 greg 2.2 static char *base_av[BASE_AC] = {
358 greg 2.11 "rcontrib", "-V+", "-fff", "-h", "-x", "1"
359 greg 2.2 };
360     char cbuf[300];
361     char **av;
362     FILE *ofp;
363 greg 2.9 IDF_OBJECT *pptr;
364 greg 2.11 IDF_FIELD *fptr;
365 greg 2.12 int i, j, n;
366 greg 2.2 /* start oconv command */
367 greg 2.16 sprintf(cbuf, "oconv - > \"%s\"", temp_octree);
368 greg 2.2 if ((ofp = popen(cbuf, "w")) == NULL) {
369     fputs(progname, stderr);
370     fputs(": cannot open oconv process\n", stderr);
371     return(0);
372     }
373     /* allocate argument list */
374 greg 2.11 av = (char **)malloc(sizeof(char *)*(BASE_AC+4+2*(zp->ntotal)));
375 greg 2.2 if (av == NULL)
376     return(0);
377     for (i = 0; i < BASE_AC; i++)
378     av[i] = base_av[i];
379 greg 2.7 sprintf(cbuf, "%d", nsamps);
380 greg 2.2 av[i++] = "-c";
381 greg 2.11 av[i++] = cbuf; /* add modifiers & surfaces */
382     for (n = 0, pptr = zp->pfirst; n < zp->nsurf; n++, pptr = pptr->dnext) {
383     fptr = idf_getfield(pptr,NAME_FLD);
384 greg 2.3 if (fptr == NULL || !fptr->val[0]) {
385 greg 2.2 fputs(progname, stderr);
386 greg 2.9 fputs(": missing name for surface object\n", stderr);
387 greg 2.2 return(0);
388     }
389 greg 2.3 if (!rad_surface(pptr, ofp)) /* add surface to octree */
390     return(0);
391 greg 2.2 av[i++] = "-m";
392 greg 2.3 av[i++] = fptr->val;
393 greg 2.2 }
394 greg 2.11 /* now subsurfaces */
395 greg 2.12 if (zp->ntotal > zp->nsurf) {
396     if (zp->area_redu != NULL)
397 greg 2.17 memset(zp->area_redu, 0, sizeof(float)*zp->ntotal);
398     else if ((zp->area_redu = (float *)calloc(zp->ntotal,
399 greg 2.12 sizeof(float))) == NULL)
400     return(0);
401     }
402 greg 2.11 for ( ; n < zp->ntotal; n++, pptr = pptr->dnext) {
403 greg 2.12 double ssarea;
404     const char *bname;
405     IDF_OBJECT *pptr1;
406 greg 2.11 fptr = idf_getfield(pptr,NAME_FLD);
407     if (fptr == NULL || !fptr->val[0]) {
408     fputs(progname, stderr);
409     fputs(": missing name for subsurface object\n", stderr);
410     return(0);
411     }
412 greg 2.12 /* add subsurface to octree */
413     if ((ssarea = rad_subsurface(pptr, ofp)) < 0)
414 greg 2.11 return(0);
415 greg 2.12 /* mark area for subtraction */
416     bname = idf_getfield(pptr,SS_BASE_FLD)->val;
417     for (j = 0, pptr1 = zp->pfirst;
418     j < zp->nsurf; j++, pptr1 = pptr1->dnext)
419     if (!strcmp(idf_getfield(pptr1,NAME_FLD)->val, bname)) {
420     zp->area_redu[j] += ssarea;
421     break;
422     }
423 greg 2.11 av[i++] = "-m";
424     av[i++] = fptr->val;
425     }
426 greg 2.2 if (pclose(ofp) != 0) { /* finish oconv */
427     fputs(progname, stderr);
428     fputs(": error running oconv process\n", stderr);
429     return(0);
430     }
431     av[i++] = temp_octree; /* add final octree argument */
432     av[i] = NULL;
433 greg 2.8 if (open_process(pd, av) <= 0) { /* start process */
434 greg 2.2 fputs(progname, stderr);
435     fputs(": cannot start rcontrib process\n", stderr);
436     return(0);
437     }
438     free(av); /* all done -- clean up */
439     return(1);
440     #undef BASE_AC
441     }
442    
443 greg 2.3 /* Initialize polygon sampling */
444     static Vert2_list *
445 greg 2.11 init_poly(POLYSAMP *ps, IDF_FIELD *f0)
446 greg 2.3 {
447 greg 2.11 SURFACE *surf;
448     Vert2_list *vl2;
449     int i;
450     /* get 3-D polygon vertices */
451     if ((surf = get_surface(f0)) == NULL)
452     return(NULL);
453     vl2 = polyAlloc(surf->nv);
454 greg 2.3 if (vl2 == NULL)
455     return(NULL);
456 greg 2.11 /* create X & Y axes */
457     VCOPY(ps->sdir[2], surf->norm);
458     VSUB(ps->sdir[0], surf->vl[1], surf->vl[0]);
459     if (normalize(ps->sdir[0]) == 0)
460 greg 2.3 return(NULL);
461     fcross(ps->sdir[1], ps->sdir[2], ps->sdir[0]);
462     /* compute plane offset */
463 greg 2.11 ps->poff = DOT(surf->vl[0], ps->sdir[2]);
464 greg 2.3 /* assign 2-D vertices */
465 greg 2.11 for (i = 0; i < surf->nv; i++) {
466     vl2->v[i].mX = DOT(surf->vl[i], ps->sdir[0]);
467     vl2->v[i].mY = DOT(surf->vl[i], ps->sdir[1]);
468     }
469     ps->area_left = surf->area;
470     free(surf); /* it's ready! */
471     vl2->p = (void *)ps;
472 greg 2.3 return(vl2);
473     }
474    
475     /* Generate samples on 2-D triangle */
476     static int
477     sample_triangle(const Vert2_list *vl2, int a, int b, int c)
478     {
479     POLYSAMP *ps = (POLYSAMP *)vl2->p;
480     float *samp;
481     FVECT orig;
482     FVECT ab, ac;
483     double area;
484     int i, j, ns;
485     /* compute sampling axes */
486     for (i = 3; i--; ) {
487     orig[i] = vl2->v[a].mX*ps->sdir[0][i] +
488     vl2->v[a].mY*ps->sdir[1][i] +
489 greg 2.11 (ps->poff+SURF_EPS)*ps->sdir[2][i];
490 greg 2.3 ab[i] = (vl2->v[b].mX - vl2->v[a].mX)*ps->sdir[0][i] +
491     (vl2->v[b].mY - vl2->v[a].mY)*ps->sdir[1][i];
492     ac[i] = (vl2->v[c].mX - vl2->v[a].mX)*ps->sdir[0][i] +
493     (vl2->v[c].mY - vl2->v[a].mY)*ps->sdir[1][i];
494     }
495     /* compute number of samples to take */
496     area = .5*(vl2->v[a].mX*vl2->v[b].mY - vl2->v[b].mX*vl2->v[a].mY +
497     vl2->v[b].mX*vl2->v[c].mY - vl2->v[c].mX*vl2->v[b].mY +
498     vl2->v[c].mX*vl2->v[a].mY - vl2->v[a].mX*vl2->v[c].mY);
499     if (area < .0) {
500     fputs(progname, stderr);
501     fputs(": negative triangle area in sample_triangle()\n", stderr);
502     return(0);
503     }
504     if (area >= ps->area_left) {
505     ns = ps->samp_left;
506     ps->area_left = 0;
507     } else {
508     ns = (ps->samp_left*area/ps->area_left + .5);
509     ps->samp_left -= ns;
510     ps->area_left -= area;
511     }
512     if (ns <= 0) /* XXX should be error? */
513     return(1);
514     /* buffer sample rays */
515     samp = (float *)malloc(sizeof(float)*6*ns);
516     if (samp == NULL)
517     return(0);
518 greg 2.4 for (i = ns; i--; ) { /* stratified Monte Carlo sampling */
519 greg 2.3 double sv[4];
520 greg 2.5 FVECT dv;
521 greg 2.3 multisamp(sv, 4, (i+frandom())/(double)ns);
522     sv[0] *= sv[1] = sqrt(sv[1]);
523     sv[1] = 1. - sv[1];
524     for (j = 3; j--; )
525 greg 2.5 samp[i*6 + j] = orig[j] + sv[0]*ab[j] + sv[1]*ac[j];
526     sv[2] = sqrt(sv[2]);
527     sv[3] *= 2.*PI;
528     dv[0] = tcos(sv[3]) * sv[2];
529     dv[1] = tsin(sv[3]) * sv[2];
530     dv[2] = sqrt(1. - sv[2]*sv[2]);
531     for (j = 3; j--; )
532     samp[i*6 + 3 + j] = dv[0]*ps->sdir[0][j] +
533     dv[1]*ps->sdir[1][j] +
534     dv[2]*ps->sdir[2][j] ;
535 greg 2.3 }
536     /* send to our process */
537     writebuf(ps->wd, (char *)samp, sizeof(float)*6*ns);
538     free(samp); /* that's it! */
539     return(1);
540     }
541    
542     /* Sample the given surface */
543 greg 2.12 static double
544 greg 2.9 sample_surface(IDF_OBJECT *param, int wd)
545 greg 2.3 {
546     POLYSAMP psamp;
547 greg 2.12 double area;
548 greg 2.3 int nv;
549     Vert2_list *vlist2;
550     /* set up our polygon sampler */
551 greg 2.11 if ((vlist2 = init_poly(&psamp, get_vlist(param, NULL))) == NULL) {
552 greg 2.5 fprintf(stderr, "%s: bad polygon %s '%s'\n",
553 greg 2.3 progname, param->pname,
554     idf_getfield(param,NAME_FLD)->val);
555 greg 2.12 return(-1.);
556 greg 2.3 }
557 greg 2.7 psamp.samp_left = nsamps; /* assign samples & destination */
558 greg 2.3 psamp.wd = wd;
559 greg 2.11 /* hack for subsurface sampling */
560     psamp.poff += 2.*SURF_EPS * !strcmp(param->pname, SUBSURF_PNAME);
561 greg 2.12
562     area = psamp.area_left; /* remember starting surface area */
563 greg 2.3 /* sample each subtriangle */
564     if (!polyTriangulate(vlist2, &sample_triangle))
565 greg 2.12 return(-1.);
566 greg 2.3 polyFree(vlist2); /* clean up and return */
567 greg 2.12 return(area);
568 greg 2.3 }
569    
570 greg 2.2 /* Compute User View Factors using open rcontrib process */
571     static int
572 greg 2.3 compute_uvfs(SUBPROC *pd, ZONE *zp)
573 greg 2.2 {
574 greg 2.9 IDF_OBJECT *pptr, *pout, *pptr1;
575 greg 2.3 float *uvfa;
576     char uvfbuf[24];
577     int n, m;
578 greg 2.9 /* create output object */
579     pout = idf_newobject(our_idf, UVF_PNAME,
580 greg 2.11 " ! computed by Radiance\n ", our_idf->plast);
581 greg 2.3 if (pout == NULL) {
582     fputs(progname, stderr);
583 greg 2.9 fputs(": cannot create new IDF object\n", stderr);
584 greg 2.3 return(0);
585     }
586     if (!idf_addfield(pout, zp->zname,
587     " !- Zone Name\n ")) {
588     fputs(progname, stderr);
589     fputs(": cannot add zone name field\n", stderr);
590     return(0);
591     }
592     /* allocate read buffer */
593 greg 2.11 uvfa = (float *)malloc(sizeof(float)*3*zp->ntotal);
594 greg 2.3 if (uvfa == NULL)
595     return(0);
596     /* UVFs from each surface */
597 greg 2.11 for (n = 0, pptr = zp->pfirst; n < zp->ntotal; n++, pptr = pptr->dnext) {
598 greg 2.4 double vfsum = 0;
599 greg 2.12 double adj_factor;
600 greg 2.3 /* send samples to rcontrib */
601 greg 2.12 if ((adj_factor = sample_surface(pptr, pd->w)) < 0)
602 greg 2.3 return(0);
603 greg 2.12 if (zp->area_redu == NULL)
604     adj_factor = 1.;
605     else /* comp. for subsurface area */
606     adj_factor /= adj_factor - zp->area_redu[n];
607 greg 2.3 /* read results */
608 greg 2.11 if (readbuf(pd->r, (char *)uvfa, sizeof(float)*3*zp->ntotal) !=
609     sizeof(float)*3*zp->ntotal) {
610 greg 2.3 fputs(progname, stderr);
611     fputs(": read error from rcontrib process\n", stderr);
612     return(0);
613     }
614     /* append UVF fields */
615     for (m = 0, pptr1 = zp->pfirst;
616 greg 2.11 m < zp->ntotal; m++, pptr1 = pptr1->dnext) {
617 greg 2.12 const double uvf = uvfa[3*m + 1] * adj_factor;
618     vfsum += uvf;
619     if (pptr1 == pptr && uvf > .001)
620 greg 2.11 fprintf(stderr,
621 greg 2.5 "%s: warning - non-zero self-VF (%.1f%%) for surface '%s'\n",
622 greg 2.12 progname, 100.*uvf,
623 greg 2.3 idf_getfield(pptr,NAME_FLD)->val);
624 greg 2.12 sprintf(uvfbuf, "%.4f", uvf);
625 greg 2.3 if (!idf_addfield(pout,
626     idf_getfield(pptr,NAME_FLD)->val, NULL) ||
627     !idf_addfield(pout,
628     idf_getfield(pptr1,NAME_FLD)->val, NULL) ||
629     !idf_addfield(pout, uvfbuf,
630 greg 2.11 (n+m < 2*zp->ntotal-2) ?
631     "\n " : "\n\n")) {
632 greg 2.3 fputs(progname, stderr);
633     fputs(": error adding UVF fields\n", stderr);
634     return(0);
635     }
636     }
637 greg 2.4 if (vfsum < 0.95)
638     fprintf(stderr,
639     "%s: warning - missing %.1f%% of energy from surface '%s'\n",
640     progname, 100.*(1.-vfsum),
641     idf_getfield(pptr,NAME_FLD)->val);
642 greg 2.3 }
643     free(uvfa); /* clean up and return */
644     return(1);
645 greg 2.2 }
646    
647 greg 2.1 /* Compute zone User View Factors */
648     static int
649     compute_zones(void)
650     {
651 greg 2.2 ZONE *zptr;
652     /* temporary octree name */
653 greg 2.5 mktemp(strcpy(temp_octree, TEMPLATE));
654 greg 2.2 /* compute each zone */
655     for (zptr = zone_list; zptr != NULL; zptr = zptr->next) {
656     SUBPROC rcproc;
657     /* start rcontrib process */
658 greg 2.22 rcproc = sp_inactive;
659 greg 2.2 if (!start_rcontrib(&rcproc, zptr))
660     return(0);
661     /* compute+add view factors */
662     if (!compute_uvfs(&rcproc, zptr))
663     return(0);
664     if (close_process(&rcproc) != 0) {
665     fputs(progname, stderr);
666     fputs(": bad return status from rcontrib\n", stderr);
667     return(0);
668     }
669     }
670     unlink(temp_octree); /* remove octree file */
671     return(1);
672 greg 2.1 }
673    
674     /* Load IDF and compute User View Factors */
675     int
676     main(int argc, char *argv[])
677     {
678 greg 2.2 int incl_comments = 1;
679 greg 2.1 char *origIDF, *revIDF;
680 greg 2.9 IDF_OBJECT *pptr;
681 greg 2.1 int i;
682    
683 greg 2.7 progname = *argv++; argc--; /* get options if any */
684     while (argc > 1 && argv[0][0] == '-')
685     switch (argv[0][1]) {
686     case 'c': /* elide comments */
687     incl_comments = -1; /* header only */
688     argv++; argc--;
689     continue;
690     case 's': /* samples */
691     nsamps = 1000*atoi(*++argv);
692     argv++; argc -= 2;
693     continue;
694     default:
695     fputs(progname, stderr);
696     fputs(": unknown option '", stderr);
697     fputs(argv[0], stderr);
698     fputs("'\n", stderr);
699     goto userr;
700     }
701     if ((argc < 1) | (argc > 2))
702     goto userr;
703     origIDF = argv[0];
704     revIDF = (argc == 1) ? argv[0] : argv[1];
705 greg 2.1 /* load Input Data File */
706     our_idf = idf_load(origIDF);
707     if (our_idf == NULL) {
708 greg 2.2 fputs(progname, stderr);
709 greg 2.1 fputs(": cannot load IDF '", stderr);
710     fputs(origIDF, stderr);
711     fputs("'\n", stderr);
712     return(1);
713     }
714 greg 2.20 /* check version (warning) */
715     if ((pptr = idf_getobject(our_idf, "Version")) != NULL &&
716 greg 2.21 pptr->flist != NULL && pptr->flist->val[0] != '9') {
717 greg 2.20 fputs(progname, stderr);
718 greg 2.21 fputs(": warning - written for IDF version 9.x, not ",
719 greg 2.20 stderr);
720     fputs(pptr->flist->val, stderr);
721     fputc('\n', stderr);
722     }
723 greg 2.1 /* remove existing UVFs */
724 greg 2.9 if ((pptr = idf_getobject(our_idf, UVF_PNAME)) != NULL) {
725     IDF_OBJECT *pnext;
726 greg 2.2 fputs(progname, stderr);
727 greg 2.1 fputs(": removing previous User View Factors\n", stderr);
728     do {
729     pnext = pptr->pnext;
730 greg 2.9 idf_delobject(our_idf, pptr);
731 greg 2.19 } while ((pptr = pnext) != NULL);
732 greg 2.1 }
733     /* add to header */
734     if (our_idf->hrem == NULL ||
735     (i = strlen(our_idf->hrem)-strlen(ADD_HEADER)) < 0 ||
736     strcmp(our_idf->hrem+i, ADD_HEADER))
737     idf_add2hdr(our_idf, ADD_HEADER);
738     /* gather zone surfaces */
739     for (i = 0; surf_type[i].pname != NULL; i++)
740 greg 2.9 for (pptr = idf_getobject(our_idf, surf_type[i].pname);
741 greg 2.1 pptr != NULL; pptr = pptr->pnext) {
742     IDF_FIELD *fptr = idf_getfield(pptr,
743     surf_type[i].zone_fld);
744     if (fptr == NULL) {
745 greg 2.2 fputs(progname, stderr);
746     fputs(": warning - missing zone field\n", stderr);
747 greg 2.1 continue;
748     }
749 greg 2.3 if (add2zone(pptr, fptr->val) == NULL)
750 greg 2.1 return(1);
751     }
752 greg 2.11 /* add subsurfaces */
753     for (pptr = idf_getobject(our_idf, SUBSURF_PNAME);
754     pptr != NULL; pptr = pptr->pnext)
755     if (add_subsurf(pptr) == NULL)
756     return(1);
757 greg 2.1 /* run rcontrib on each zone */
758     if (!compute_zones())
759     return(1);
760     /* write out modified IDF */
761 greg 2.2 if (!idf_write(our_idf, revIDF, incl_comments)) {
762     fputs(progname, stderr);
763 greg 2.1 fputs(": error writing IDF '", stderr);
764     fputs(revIDF, stderr);
765     fputs("'\n", stderr);
766     return(1);
767     }
768     return(0); /* finito! */
769 greg 2.7 userr:
770     fputs("Usage: ", stderr);
771     fputs(progname, stderr);
772     fputs(" [-c][-s Ksamps] Model.idf [Revised.idf]\n", stderr);
773     return(1);
774 greg 2.1 }