ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/util/eplus_adduvf.c
Revision: 2.21
Committed: Mon Jan 20 17:53:40 2020 UTC (4 years, 2 months ago) by greg
Content type: text/plain
Branch: MAIN
Changes since 2.20: +6 -5 lines
Log Message:
Updated eplus_adduvf to work with version 9.x

File Contents

# Content
1 #ifndef lint
2 static const char RCSid[] = "$Id: eplus_adduvf.c,v 2.20 2020/01/17 17:33:48 greg Exp $";
3 #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 #include <ctype.h>
12 #include "platform.h"
13 #include "rtio.h"
14 #include "rtmath.h"
15 #include "random.h"
16 #include "eplus_idf.h"
17 #include "triangulate.h"
18 #include "rtprocess.h"
19
20 #ifndef NSAMPLES
21 #define NSAMPLES 80000 /* default number of samples */
22 #endif
23
24 #define SURF_EPS 0.0005 /* surface testing epsilon */
25
26 char *progname; /* global argv[0] */
27
28 int nsamps = NSAMPLES; /* number of samples to use */
29
30 char temp_octree[128]; /* temporary octree */
31
32 const char UVF_PNAME[] =
33 "ZoneProperty:UserViewFactors:bySurfaceName";
34
35 const char SUBSURF_PNAME[] =
36 "FenestrationSurface:Detailed";
37
38 const char ADD_HEADER[] =
39 "\n!+++ User View Factors computed by Radiance +++!\n\n";
40
41 #define NAME_FLD 1 /* name field always first? */
42
43 #define SS_BASE_FLD 4 /* subsurface base surface */
44 #define SS_VERT_FLD 9 /* subsurface vertex count */
45
46 typedef struct {
47 const char *pname; /* object type name */
48 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 {"Floor:Detailed", 3, 9},
55 {"RoofCeiling:Detailed", 3, 9},
56 {"Wall:Detailed", 3, 9},
57 {NULL}
58 }; /* IDF surface types */
59
60 typedef struct s_zone {
61 const char *zname; /* zone name */
62 struct s_zone *next; /* next zone in list */
63 int nsurf; /* surface count */
64 int ntotal; /* surfaces+subsurfaces */
65 IDF_OBJECT *pfirst; /* first matching object */
66 IDF_OBJECT *plast; /* last before subsurfaces */
67 float *area_redu; /* subsurface area per surf. */
68 } ZONE; /* a list of collected zone surfaces */
69
70 ZONE *zone_list = NULL; /* our list of zones */
71
72 LUTAB zonesurf_lut = /* zone surface lookup table */
73 LU_SINIT(NULL,NULL);
74
75 IDF_LOADED *our_idf = NULL; /* loaded/modified IDF */
76
77 typedef struct {
78 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 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 /* Create a new zone and push to top of our list */
93 static ZONE *
94 new_zone(const char *zname, IDF_OBJECT *param)
95 {
96 ZONE *znew = (ZONE *)malloc(sizeof(ZONE));
97
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 znew->ntotal = znew->nsurf = 1;
104 znew->area_redu = NULL;
105 return(zone_list = znew);
106 }
107
108 /* Add the detailed surface (polygon) to the named zone */
109 static ZONE *
110 add2zone(IDF_OBJECT *param, const char *zname)
111 {
112 IDF_FIELD *nfp = idf_getfield(param, NAME_FLD);
113 ZONE *zptr;
114 LUENT *lep;
115
116 if (nfp == NULL) {
117 fputs(progname, stderr);
118 fputs(": surface missing name field!\n", stderr);
119 return(NULL);
120 }
121 for (zptr = zone_list; zptr != NULL; zptr = zptr->next)
122 if (!strcmp(zptr->zname, zname))
123 break;
124 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 if (!idf_movobject(our_idf, param, zptr->plast))
172 return(NULL);
173 zptr->ntotal++;
174 return(zptr);
175 }
176
177 /* Return field for vertices in the given object */
178 static IDF_FIELD *
179 get_vlist(IDF_OBJECT *param, const char *zname)
180 {
181 #define itm_len (sizeof(IDF_FIELD)+6)
182 static char fld_buf[4*itm_len];
183 static char *next_fbp = fld_buf;
184 int i;
185 IDF_FIELD *res;
186 /* 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 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 }
208 if (!res->val[0] || tolower(res->val[0]) == 'a') { /* autocalculate */
209 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 return(NULL);
217 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 }
223 return(res);
224 #undef itm_len
225 }
226
227 /* 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 /* Convert surface to Radiance with modifier based on unique name */
284 static int
285 rad_surface(IDF_OBJECT *param, FILE *ofp)
286 {
287 const char *sname = idf_getfield(param,NAME_FLD)->val;
288 IDF_FIELD *fptr = get_vlist(param, NULL);
289 const char **fargs;
290 int nvert, i, j;
291
292 if (fptr == NULL || (nvert = atoi(fptr->val)) < 3) {
293 fprintf(stderr, "%s: bad surface '%s'\n", progname, sname);
294 return(0);
295 }
296 fargs = (const char **)malloc(sizeof(const char *)*3*nvert);
297 if (fargs == NULL)
298 return(0);
299 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 for (j = nvert; j--; ) { /* get arguments in reverse */
302 for (i = 0; i < 3; i++) {
303 fptr = fptr->next;
304 if (fptr == NULL || !isflt(fptr->val)) {
305 fprintf(stderr,
306 "%s: missing/bad vertex for %s '%s'\n",
307 progname, param->pname, sname);
308 return(0);
309 }
310 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 fputc('\t', ofp);
316 fputs(fargs[3*j + i], ofp);
317 }
318 fputc('\n', ofp);
319 }
320 free(fargs);
321 return(!ferror(ofp));
322 }
323
324 /* Convert subsurface to Radiance with modifier based on unique name */
325 static double
326 rad_subsurface(IDF_OBJECT *param, FILE *ofp)
327 {
328 const char *sname = idf_getfield(param,NAME_FLD)->val;
329 SURFACE *surf = get_surface(get_vlist(param, NULL));
330 double area;
331 int i;
332
333 if (surf == NULL) {
334 fprintf(stderr, "%s: bad subsurface '%s'\n", progname, sname);
335 return(-1.);
336 }
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 area = surf->area;
346 free(surf);
347 if (ferror(ofp))
348 return(-1.);
349 return(area);
350 }
351
352 /* Start rcontrib process */
353 static int
354 start_rcontrib(SUBPROC *pd, ZONE *zp)
355 {
356 #define BASE_AC 6
357 static char *base_av[BASE_AC] = {
358 "rcontrib", "-V+", "-fff", "-h", "-x", "1"
359 };
360 char cbuf[300];
361 char **av;
362 FILE *ofp;
363 IDF_OBJECT *pptr;
364 IDF_FIELD *fptr;
365 int i, j, n;
366 /* start oconv command */
367 sprintf(cbuf, "oconv - > \"%s\"", temp_octree);
368 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 av = (char **)malloc(sizeof(char *)*(BASE_AC+4+2*(zp->ntotal)));
375 if (av == NULL)
376 return(0);
377 for (i = 0; i < BASE_AC; i++)
378 av[i] = base_av[i];
379 sprintf(cbuf, "%d", nsamps);
380 av[i++] = "-c";
381 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 if (fptr == NULL || !fptr->val[0]) {
385 fputs(progname, stderr);
386 fputs(": missing name for surface object\n", stderr);
387 return(0);
388 }
389 if (!rad_surface(pptr, ofp)) /* add surface to octree */
390 return(0);
391 av[i++] = "-m";
392 av[i++] = fptr->val;
393 }
394 /* now subsurfaces */
395 if (zp->ntotal > zp->nsurf) {
396 if (zp->area_redu != NULL)
397 memset(zp->area_redu, 0, sizeof(float)*zp->ntotal);
398 else if ((zp->area_redu = (float *)calloc(zp->ntotal,
399 sizeof(float))) == NULL)
400 return(0);
401 }
402 for ( ; n < zp->ntotal; n++, pptr = pptr->dnext) {
403 double ssarea;
404 const char *bname;
405 IDF_OBJECT *pptr1;
406 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 /* add subsurface to octree */
413 if ((ssarea = rad_subsurface(pptr, ofp)) < 0)
414 return(0);
415 /* 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 av[i++] = "-m";
424 av[i++] = fptr->val;
425 }
426 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 if (open_process(pd, av) <= 0) { /* start process */
434 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 /* Initialize polygon sampling */
444 static Vert2_list *
445 init_poly(POLYSAMP *ps, IDF_FIELD *f0)
446 {
447 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 if (vl2 == NULL)
455 return(NULL);
456 /* 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 return(NULL);
461 fcross(ps->sdir[1], ps->sdir[2], ps->sdir[0]);
462 /* compute plane offset */
463 ps->poff = DOT(surf->vl[0], ps->sdir[2]);
464 /* assign 2-D vertices */
465 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 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 (ps->poff+SURF_EPS)*ps->sdir[2][i];
490 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 for (i = ns; i--; ) { /* stratified Monte Carlo sampling */
519 double sv[4];
520 FVECT dv;
521 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 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 }
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 static double
544 sample_surface(IDF_OBJECT *param, int wd)
545 {
546 POLYSAMP psamp;
547 double area;
548 int nv;
549 Vert2_list *vlist2;
550 /* set up our polygon sampler */
551 if ((vlist2 = init_poly(&psamp, get_vlist(param, NULL))) == NULL) {
552 fprintf(stderr, "%s: bad polygon %s '%s'\n",
553 progname, param->pname,
554 idf_getfield(param,NAME_FLD)->val);
555 return(-1.);
556 }
557 psamp.samp_left = nsamps; /* assign samples & destination */
558 psamp.wd = wd;
559 /* hack for subsurface sampling */
560 psamp.poff += 2.*SURF_EPS * !strcmp(param->pname, SUBSURF_PNAME);
561
562 area = psamp.area_left; /* remember starting surface area */
563 /* sample each subtriangle */
564 if (!polyTriangulate(vlist2, &sample_triangle))
565 return(-1.);
566 polyFree(vlist2); /* clean up and return */
567 return(area);
568 }
569
570 /* Compute User View Factors using open rcontrib process */
571 static int
572 compute_uvfs(SUBPROC *pd, ZONE *zp)
573 {
574 IDF_OBJECT *pptr, *pout, *pptr1;
575 float *uvfa;
576 char uvfbuf[24];
577 int n, m;
578 /* create output object */
579 pout = idf_newobject(our_idf, UVF_PNAME,
580 " ! computed by Radiance\n ", our_idf->plast);
581 if (pout == NULL) {
582 fputs(progname, stderr);
583 fputs(": cannot create new IDF object\n", stderr);
584 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 uvfa = (float *)malloc(sizeof(float)*3*zp->ntotal);
594 if (uvfa == NULL)
595 return(0);
596 /* UVFs from each surface */
597 for (n = 0, pptr = zp->pfirst; n < zp->ntotal; n++, pptr = pptr->dnext) {
598 double vfsum = 0;
599 double adj_factor;
600 /* send samples to rcontrib */
601 if ((adj_factor = sample_surface(pptr, pd->w)) < 0)
602 return(0);
603 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 /* read results */
608 if (readbuf(pd->r, (char *)uvfa, sizeof(float)*3*zp->ntotal) !=
609 sizeof(float)*3*zp->ntotal) {
610 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 m < zp->ntotal; m++, pptr1 = pptr1->dnext) {
617 const double uvf = uvfa[3*m + 1] * adj_factor;
618 vfsum += uvf;
619 if (pptr1 == pptr && uvf > .001)
620 fprintf(stderr,
621 "%s: warning - non-zero self-VF (%.1f%%) for surface '%s'\n",
622 progname, 100.*uvf,
623 idf_getfield(pptr,NAME_FLD)->val);
624 sprintf(uvfbuf, "%.4f", uvf);
625 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 (n+m < 2*zp->ntotal-2) ?
631 "\n " : "\n\n")) {
632 fputs(progname, stderr);
633 fputs(": error adding UVF fields\n", stderr);
634 return(0);
635 }
636 }
637 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 }
643 free(uvfa); /* clean up and return */
644 return(1);
645 }
646
647 /* Compute zone User View Factors */
648 static int
649 compute_zones(void)
650 {
651 ZONE *zptr;
652 /* temporary octree name */
653 mktemp(strcpy(temp_octree, TEMPLATE));
654 /* compute each zone */
655 for (zptr = zone_list; zptr != NULL; zptr = zptr->next) {
656 SUBPROC rcproc;
657 /* start rcontrib process */
658 if (!start_rcontrib(&rcproc, zptr))
659 return(0);
660 /* compute+add view factors */
661 if (!compute_uvfs(&rcproc, zptr))
662 return(0);
663 if (close_process(&rcproc) != 0) {
664 fputs(progname, stderr);
665 fputs(": bad return status from rcontrib\n", stderr);
666 return(0);
667 }
668 }
669 unlink(temp_octree); /* remove octree file */
670 return(1);
671 }
672
673 /* Load IDF and compute User View Factors */
674 int
675 main(int argc, char *argv[])
676 {
677 int incl_comments = 1;
678 char *origIDF, *revIDF;
679 IDF_OBJECT *pptr;
680 int i;
681
682 progname = *argv++; argc--; /* get options if any */
683 while (argc > 1 && argv[0][0] == '-')
684 switch (argv[0][1]) {
685 case 'c': /* elide comments */
686 incl_comments = -1; /* header only */
687 argv++; argc--;
688 continue;
689 case 's': /* samples */
690 nsamps = 1000*atoi(*++argv);
691 argv++; argc -= 2;
692 continue;
693 default:
694 fputs(progname, stderr);
695 fputs(": unknown option '", stderr);
696 fputs(argv[0], stderr);
697 fputs("'\n", stderr);
698 goto userr;
699 }
700 if ((argc < 1) | (argc > 2))
701 goto userr;
702 origIDF = argv[0];
703 revIDF = (argc == 1) ? argv[0] : argv[1];
704 /* load Input Data File */
705 our_idf = idf_load(origIDF);
706 if (our_idf == NULL) {
707 fputs(progname, stderr);
708 fputs(": cannot load IDF '", stderr);
709 fputs(origIDF, stderr);
710 fputs("'\n", stderr);
711 return(1);
712 }
713 /* check version (warning) */
714 if ((pptr = idf_getobject(our_idf, "Version")) != NULL &&
715 pptr->flist != NULL && pptr->flist->val[0] != '9') {
716 fputs(progname, stderr);
717 fputs(": warning - written for IDF version 9.x, not ",
718 stderr);
719 fputs(pptr->flist->val, stderr);
720 fputc('\n', stderr);
721 }
722 /* remove existing UVFs */
723 if ((pptr = idf_getobject(our_idf, UVF_PNAME)) != NULL) {
724 IDF_OBJECT *pnext;
725 fputs(progname, stderr);
726 fputs(": removing previous User View Factors\n", stderr);
727 do {
728 pnext = pptr->pnext;
729 idf_delobject(our_idf, pptr);
730 } while ((pptr = pnext) != NULL);
731 }
732 /* add to header */
733 if (our_idf->hrem == NULL ||
734 (i = strlen(our_idf->hrem)-strlen(ADD_HEADER)) < 0 ||
735 strcmp(our_idf->hrem+i, ADD_HEADER))
736 idf_add2hdr(our_idf, ADD_HEADER);
737 /* gather zone surfaces */
738 for (i = 0; surf_type[i].pname != NULL; i++)
739 for (pptr = idf_getobject(our_idf, surf_type[i].pname);
740 pptr != NULL; pptr = pptr->pnext) {
741 IDF_FIELD *fptr = idf_getfield(pptr,
742 surf_type[i].zone_fld);
743 if (fptr == NULL) {
744 fputs(progname, stderr);
745 fputs(": warning - missing zone field\n", stderr);
746 continue;
747 }
748 if (add2zone(pptr, fptr->val) == NULL)
749 return(1);
750 }
751 /* add subsurfaces */
752 for (pptr = idf_getobject(our_idf, SUBSURF_PNAME);
753 pptr != NULL; pptr = pptr->pnext)
754 if (add_subsurf(pptr) == NULL)
755 return(1);
756 /* run rcontrib on each zone */
757 if (!compute_zones())
758 return(1);
759 /* write out modified IDF */
760 if (!idf_write(our_idf, revIDF, incl_comments)) {
761 fputs(progname, stderr);
762 fputs(": error writing IDF '", stderr);
763 fputs(revIDF, stderr);
764 fputs("'\n", stderr);
765 return(1);
766 }
767 return(0); /* finito! */
768 userr:
769 fputs("Usage: ", stderr);
770 fputs(progname, stderr);
771 fputs(" [-c][-s Ksamps] Model.idf [Revised.idf]\n", stderr);
772 return(1);
773 }