ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/util/eplus_adduvf.c
Revision: 2.12
Committed: Fri Feb 21 13:17:45 2014 UTC (10 years, 1 month ago) by greg
Content type: text/plain
Branch: MAIN
Changes since 2.11: +49 -15 lines
Log Message:
Added adjustments for area reduction due to subsurfaces

File Contents

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