ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/rt/rc2.c
Revision: 2.27
Committed: Wed May 22 21:44:03 2024 UTC (2 weeks, 1 day ago) by greg
Content type: text/plain
Branch: MAIN
CVS Tags: HEAD
Changes since 2.26: +3 -1 lines
Log Message:
fix(rcontrib): Added output of wavelength splits for hyperspectral results

File Contents

# Content
1 #ifndef lint
2 static const char RCSid[] = "$Id: rc2.c,v 2.26 2023/11/15 18:02:53 greg Exp $";
3 #endif
4 /*
5 * Accumulate ray contributions for a set of materials
6 * File i/o and recovery
7 */
8
9 #include <ctype.h>
10 #include "platform.h"
11 #include "rcontrib.h"
12 #include "resolu.h"
13
14 /* Close output stream and free record */
15 static void
16 closestream(void *p)
17 {
18 STREAMOUT *sop = (STREAMOUT *)p;
19
20 if (sop->ofp != NULL) {
21 int status = 0;
22 if (sop->outpipe)
23 status = pclose(sop->ofp);
24 else if (sop->ofp != stdout)
25 status = fclose(sop->ofp);
26 if (status)
27 error(SYSTEM, "error closing output stream");
28 }
29 free(p);
30 }
31
32 LUTAB ofiletab = LU_SINIT(free,closestream); /* output file table */
33
34 #define OF_MODIFIER 01
35 #define OF_BIN 02
36
37 /************************** STREAM & FILE I/O ***************************/
38
39 /* Construct output file name and return flags whether modifier/bin present */
40 static int
41 ofname(char *oname, const char *ospec, const char *mname, int bn)
42 {
43 const char *mnp = NULL;
44 const char *bnp = NULL;
45 const char *cp;
46
47 if (ospec == NULL)
48 return(-1);
49 for (cp = ospec; *cp; cp++) /* check format position(s) */
50 if (*cp == '%') {
51 do
52 ++cp;
53 while (isdigit(*cp));
54 switch (*cp) {
55 case '%':
56 break;
57 case 's':
58 if (mnp != NULL)
59 return(-1);
60 mnp = cp;
61 break;
62 case 'd':
63 case 'i':
64 case 'o':
65 case 'x':
66 case 'X':
67 if (bnp != NULL)
68 return(-1);
69 bnp = cp;
70 break;
71 default:
72 return(-1);
73 }
74 }
75 if (mnp != NULL) { /* create file name */
76 if (bnp != NULL) {
77 if (bnp > mnp)
78 sprintf(oname, ospec, mname, bn);
79 else
80 sprintf(oname, ospec, bn, mname);
81 return(OF_MODIFIER|OF_BIN);
82 }
83 sprintf(oname, ospec, mname);
84 return(OF_MODIFIER);
85 }
86 if (bnp != NULL) {
87 sprintf(oname, ospec, bn);
88 return(OF_BIN);
89 }
90 strcpy(oname, ospec);
91 return(0);
92 }
93
94
95 /* Write header to the given output stream */
96 static void
97 printheader(FILE *fout, const char *info)
98 {
99 extern char VersionID[];
100 /* copy octree header */
101 if (octname[0] == '!') {
102 newheader("RADIANCE", fout);
103 fputs(octname+1, fout);
104 if (octname[strlen(octname)-1] != '\n')
105 fputc('\n', fout);
106 } else {
107 FILE *fin = fopen(octname, (outfmt=='a') ? "r" : "rb");
108 if (fin == NULL)
109 quit(1);
110 checkheader(fin, OCTFMT, fout);
111 fclose(fin);
112 }
113 printargs(gargc-1, gargv, fout); /* add our command */
114 fprintf(fout, "SOFTWARE= %s\n", VersionID);
115 fputnow(fout);
116 fputncomp(NCSAMP, fout);
117 if (NCSAMP > 3)
118 fputwlsplit(WLPART, fout);
119 if (info != NULL) /* add extra info if given */
120 fputs(info, fout);
121 if ((outfmt == 'f') | (outfmt == 'd'))
122 fputendian(fout);
123 fputformat(formstr(outfmt), fout);
124 fputc('\n', fout); /* empty line ends header */
125 }
126
127
128 /* Write resolution string to given output stream */
129 static void
130 printresolu(FILE *fout, int xr, int yr)
131 {
132 if ((xr > 0) & (yr > 0)) /* resolution string */
133 fprtresolu(xr, yr, fout);
134 }
135
136
137 /* Get output stream pointer (open and write header if new and noopen==0) */
138 STREAMOUT *
139 getostream(const char *ospec, const char *mname, int bn, int noopen)
140 {
141 static STREAMOUT stdos;
142 char info[1024];
143 int ofl;
144 char oname[1024];
145 LUENT *lep;
146 STREAMOUT *sop;
147 char *cp;
148
149 info[0] = '\0';
150 if (ospec == NULL) { /* use stdout? */
151 if (!noopen & !using_stdout) {
152 if (outfmt != 'a')
153 SET_FILE_BINARY(stdout);
154 #ifdef getc_unlocked
155 flockfile(stdout); /* avoid lock/unlock overhead */
156 #endif
157 if (header) {
158 cp = info;
159 if (yres > 0) {
160 sprintf(cp, "NROWS=%d\n", yres *
161 (xres + !xres) );
162 while (*cp) ++cp;
163 }
164 if ((xres <= 0) | (stdos.reclen > 1))
165 sprintf(cp, "NCOLS=%d\n", stdos.reclen);
166 printheader(stdout, info);
167 }
168 if (stdos.reclen == 1)
169 printresolu(stdout, xres, yres);
170 if (waitflush > 0)
171 fflush(stdout);
172 stdos.xr = xres; stdos.yr = yres;
173 using_stdout = 1;
174 }
175 stdos.ofp = stdout;
176 stdos.reclen += noopen;
177 return(&stdos);
178 }
179 ofl = ofname(oname, ospec, mname, bn); /* get output name */
180 if (ofl < 0) {
181 sprintf(errmsg, "bad output format '%s'", ospec);
182 error(USER, errmsg);
183 }
184 lep = lu_find(&ofiletab, oname); /* look it up */
185 if (lep->key == NULL) /* new entry */
186 lep->key = strcpy((char *)malloc(strlen(oname)+1), oname);
187 sop = (STREAMOUT *)lep->data;
188 if (sop == NULL) { /* allocate stream */
189 sop = (STREAMOUT *)malloc(sizeof(STREAMOUT));
190 if (sop == NULL)
191 error(SYSTEM, "out of memory in getostream");
192 sop->outpipe = (oname[0] == '!');
193 sop->reclen = 0;
194 sop->ofp = NULL; /* open iff noopen==0 */
195 sop->xr = xres; sop->yr = yres;
196 lep->data = (char *)sop;
197 if (!sop->outpipe & !force_open & !recover &&
198 access(oname, F_OK) == 0) {
199 errno = EEXIST; /* file exists */
200 goto openerr;
201 }
202 } else if (noopen && outfmt == 'c' && /* stream exists to picture? */
203 (sop->xr > 0) & (sop->yr > 0)) {
204 if (ofl & OF_BIN)
205 return(NULL); /* let caller offset bins */
206 sprintf(errmsg, "output '%s' not a valid picture", oname);
207 error(WARNING, errmsg);
208 }
209 if (!noopen && sop->ofp == NULL) { /* open output stream */
210 if (oname[0] == '!') /* output to command */
211 sop->ofp = popen(oname+1, "w");
212 else /* else open file */
213 sop->ofp = fopen(oname, "w");
214 if (sop->ofp == NULL)
215 goto openerr;
216 if (outfmt != 'a')
217 SET_FILE_BINARY(sop->ofp);
218 #ifdef getc_unlocked
219 flockfile(sop->ofp); /* avoid lock/unlock overhead */
220 #endif
221 if (accumulate > 0) { /* global resolution */
222 sop->xr = xres; sop->yr = yres;
223 }
224 if (header) {
225 cp = info;
226 if (ofl & OF_MODIFIER || sop->reclen == 1) {
227 sprintf(cp, "MODIFIER=%s\n", mname);
228 while (*cp) ++cp;
229 }
230 if (ofl & OF_BIN) {
231 sprintf(cp, "BIN=%d\n", bn);
232 while (*cp) ++cp;
233 }
234 if (sop->yr > 0) {
235 sprintf(cp, "NROWS=%d\n", sop->yr *
236 (sop->xr + !sop->xr) );
237 while (*cp) ++cp;
238 }
239 if ((sop->xr <= 0) | (sop->reclen > 1))
240 sprintf(cp, "NCOLS=%d\n", sop->reclen);
241 printheader(sop->ofp, info);
242 }
243 if (sop->reclen == 1)
244 printresolu(sop->ofp, sop->xr, sop->yr);
245 if (waitflush > 0)
246 fflush(sop->ofp);
247 }
248 sop->reclen += noopen; /* add to length if noopen */
249 return(sop); /* return output stream */
250 openerr:
251 sprintf(errmsg, "cannot open '%s' for writing", oname);
252 error(SYSTEM, errmsg);
253 return(NULL); /* pro forma return */
254 }
255
256
257 /* Get a vector from stdin */
258 int
259 getvec(FVECT vec)
260 {
261 float vf[3];
262 double vd[3];
263 char buf[32];
264 int i;
265
266 switch (inpfmt) {
267 case 'a': /* ascii */
268 for (i = 0; i < 3; i++) {
269 if (fgetword(buf, sizeof(buf), stdin) == NULL ||
270 !isflt(buf))
271 return(-1);
272 vec[i] = atof(buf);
273 }
274 break;
275 case 'f': /* binary float */
276 if (getbinary(vf, sizeof(float), 3, stdin) != 3)
277 return(-1);
278 VCOPY(vec, vf);
279 break;
280 case 'd': /* binary double */
281 if (getbinary(vd, sizeof(double), 3, stdin) != 3)
282 return(-1);
283 VCOPY(vec, vd);
284 break;
285 default:
286 error(CONSISTENCY, "botched input format");
287 }
288 return(0);
289 }
290
291
292 /* Put out ray contribution to file */
293 static void
294 put_contrib(const DCOLORV *cnt, FILE *fout)
295 {
296 double sf = 1;
297 SCOLOR fv;
298 SCOLR cv;
299 int i;
300
301 if (accumulate > 1)
302 sf = 1./(double)accumulate;
303 switch (outfmt) {
304 case 'a':
305 for (i = 0; i < NCSAMP; i++)
306 fprintf(fout, "%.6e\t", sf*cnt[i]);
307 break;
308 case 'f':
309 for (i = NCSAMP; i-- > 0; )
310 fv[i] = cnt[i];
311 if (accumulate > 1)
312 scalescolor(fv, sf);
313 putbinary(fv, sizeof(COLORV), NCSAMP, fout);
314 break;
315 case 'd':
316 if (accumulate > 1) {
317 DCOLORV dv[MAXCSAMP];
318 for (i = NCSAMP; i-- > 0; )
319 dv[i] = sf*cnt[i];
320 putbinary(dv, sizeof(DCOLORV), NCSAMP, fout);
321 } else
322 putbinary(cnt, sizeof(DCOLORV), NCSAMP, fout);
323 break;
324 case 'c':
325 for (i = NCSAMP; i-- > 0; )
326 fv[i] = cnt[i];
327 if (accumulate > 1)
328 scalescolor(fv, sf);
329 scolor_scolr(cv, fv);
330 putbinary(cv, 1, LSCOLR, fout);
331 break;
332 default:
333 error(INTERNAL, "botched output format");
334 }
335 }
336
337
338 /* Output modifier values to appropriate stream(s) */
339 void
340 mod_output(MODCONT *mp)
341 {
342 STREAMOUT *sop = getostream(mp->outspec, mp->modname, mp->bin0, 0);
343 int j;
344
345 put_contrib(mp->cbin, sop->ofp);
346 if (mp->nbins > 3 && /* minor optimization */
347 sop == getostream(mp->outspec, mp->modname, mp->bin0+1, 0)) {
348 for (j = 1; j < mp->nbins; j++)
349 put_contrib(mcbin(mp,j), sop->ofp);
350 } else {
351 for (j = 1; j < mp->nbins; j++) {
352 sop = getostream(mp->outspec, mp->modname, mp->bin0+j, 0);
353 put_contrib(mcbin(mp,j), sop->ofp);
354 }
355 }
356 }
357
358
359 /* callback to output newline to ASCII file and/or flush as requested */
360 static int
361 puteol(const LUENT *e, void *p)
362 {
363 STREAMOUT *sop = (STREAMOUT *)e->data;
364
365 if (outfmt == 'a')
366 putc('\n', sop->ofp);
367 if (!waitflush)
368 fflush(sop->ofp);
369 if (ferror(sop->ofp)) {
370 sprintf(errmsg, "write error on file '%s'", e->key);
371 error(SYSTEM, errmsg);
372 }
373 return(0);
374 }
375
376
377 /* Terminate record output and flush if time */
378 void
379 end_record()
380 {
381 --waitflush;
382 lu_doall(&ofiletab, &puteol, NULL);
383 if (using_stdout & (outfmt == 'a'))
384 putc('\n', stdout);
385 if (!waitflush) {
386 waitflush = (yres > 0) & (xres > 1) ? 0 : xres;
387 if (using_stdout)
388 fflush(stdout);
389 }
390 }
391
392 /************************** PARTIAL RESULTS RECOVERY ***********************/
393
394 /* Get ray contribution from previous file */
395 static int
396 get_contrib(DCOLORV *cnt, FILE *finp)
397 {
398 SCOLOR fv;
399 SCOLR cv;
400 int i;
401
402 switch (outfmt) {
403 case 'a':
404 for (i = 0; i < NCSAMP; i++)
405 if (fscanf(finp, "%lf", &cnt[i]) != 1)
406 return(0);
407 return(1);
408 case 'd':
409 return(getbinary(cnt, sizeof(DCOLORV), NCSAMP, finp) == NCSAMP);
410 case 'f':
411 if (getbinary(fv, sizeof(COLORV), NCSAMP, finp) != NCSAMP)
412 return(0);
413 break;
414 case 'c':
415 if (getbinary(cv, 1, LSCOLR, finp) != LSCOLR)
416 return(0);
417 scolr_scolor(fv, cv);
418 break;
419 default:
420 error(INTERNAL, "botched output format");
421 }
422 /* copy result from SCOLOR */
423 for (i = NCSAMP; i-- > 0; )
424 cnt[i] = fv[i];
425 return(1);
426 }
427
428
429 /* Close output file opened for input */
430 static int
431 myclose(const LUENT *e, void *p)
432 {
433 STREAMOUT *sop = (STREAMOUT *)e->data;
434
435 if (sop->ofp == NULL)
436 return(0);
437 fclose(sop->ofp);
438 sop->ofp = NULL;
439 return(0);
440 }
441
442
443 /* Load previously accumulated values */
444 void
445 reload_output()
446 {
447 int i, j;
448 MODCONT *mp;
449 int ofl;
450 char oname[1024];
451 char *fmode = "rb";
452 char *outvfmt;
453 LUENT *oent;
454 int xr, yr;
455 STREAMOUT *sop;
456 DCOLORV contr[MAXCSAMP];
457
458 if (outfmt == 'a')
459 fmode = "r";
460 outvfmt = (char *)formstr(outfmt);
461 /* reload modifier values */
462 for (i = 0; i < nmods; i++) {
463 mp = (MODCONT *)lu_find(&modconttab,modname[i])->data;
464 if (mp->outspec == NULL)
465 error(USER, "cannot reload from stdout");
466 if (mp->outspec[0] == '!')
467 error(USER, "cannot reload from command");
468 for (j = 0; j < mp->nbins; j++) { /* load each modifier bin */
469 ofl = ofname(oname, mp->outspec, mp->modname, mp->bin0+j);
470 if (ofl < 0)
471 error(USER, "bad output file specification");
472 oent = lu_find(&ofiletab, oname);
473 if (oent->data == NULL)
474 error(INTERNAL, "unallocated stream in reload_output()");
475 sop = (STREAMOUT *)oent->data;
476 if (sop->ofp == NULL) { /* open output as input */
477 sop->ofp = fopen(oname, fmode);
478 if (sop->ofp == NULL) {
479 sprintf(errmsg, "missing reload file '%s'",
480 oname);
481 error(WARNING, errmsg);
482 break;
483 }
484 #ifdef getc_unlocked
485 flockfile(sop->ofp);
486 #endif
487 if (header && checkheader(sop->ofp, outvfmt, NULL) != 1) {
488 sprintf(errmsg, "format mismatch for '%s'",
489 oname);
490 error(USER, errmsg);
491 }
492 if ((sop->reclen == 1) & (sop->xr > 0) & (sop->yr > 0) &&
493 (!fscnresolu(&xr, &yr, sop->ofp) ||
494 (xr != sop->xr) |
495 (yr != sop->yr))) {
496 sprintf(errmsg, "resolution mismatch for '%s'",
497 oname);
498 error(USER, errmsg);
499 }
500 }
501 /* read in spectral value */
502 if (!get_contrib(contr, sop->ofp)) {
503 if (!j) {
504 fclose(sop->ofp);
505 break; /* ignore empty file */
506 }
507 if (j < mp->nbins) {
508 sprintf(errmsg, "missing data in '%s'",
509 oname);
510 error(USER, errmsg);
511 }
512 break;
513 }
514 memcpy(mcbin(mp,j), contr, DCOLORSIZ);
515 }
516 }
517 lu_doall(&ofiletab, &myclose, NULL); /* close all files */
518 }
519
520
521 /* Seek on the given output file */
522 static int
523 myseeko(const LUENT *e, void *p)
524 {
525 STREAMOUT *sop = (STREAMOUT *)e->data;
526 off_t nbytes = *(off_t *)p;
527
528 if (sop->reclen > 1)
529 nbytes *= (off_t)sop->reclen;
530 if (fseeko(sop->ofp, nbytes, SEEK_CUR) < 0) {
531 sprintf(errmsg, "seek error on file '%s'", e->key);
532 error(SYSTEM, errmsg);
533 }
534 return(0);
535 }
536
537
538 /* Recover output if possible */
539 void
540 recover_output()
541 {
542 off_t lastout = -1;
543 int outvsiz, recsiz;
544 char *outvfmt;
545 int i, j;
546 MODCONT *mp;
547 int ofl;
548 char oname[1024];
549 LUENT *oent;
550 STREAMOUT *sop;
551 off_t nvals;
552 int xr, yr;
553
554 switch (outfmt) {
555 case 'a':
556 error(USER, "cannot recover ASCII output");
557 return;
558 case 'f':
559 outvsiz = sizeof(float)*NCSAMP;
560 break;
561 case 'd':
562 outvsiz = sizeof(double)*NCSAMP;
563 break;
564 case 'c':
565 outvsiz = LSCOLR;
566 break;
567 default:
568 error(INTERNAL, "botched output format");
569 return;
570 }
571 outvfmt = (char *)formstr(outfmt);
572 /* check modifier outputs */
573 for (i = 0; i < nmods; i++) {
574 mp = (MODCONT *)lu_find(&modconttab,modname[i])->data;
575 if (mp->outspec == NULL)
576 error(USER, "cannot recover from stdout");
577 if (mp->outspec[0] == '!')
578 error(USER, "cannot recover from command");
579 for (j = 0; j < mp->nbins; j++) { /* check each bin's file */
580 ofl = ofname(oname, mp->outspec, mp->modname, mp->bin0+j);
581 if (ofl < 0)
582 error(USER, "bad output file specification");
583 oent = lu_find(&ofiletab, oname);
584 if (oent->data == NULL)
585 error(INTERNAL, "unallocated stream in recover_output()");
586 sop = (STREAMOUT *)oent->data;
587 if (sop->ofp != NULL) { /* already open? */
588 if (ofl & OF_BIN)
589 continue;
590 break;
591 }
592 /* open output */
593 sop->ofp = fopen(oname, "rb+");
594 if (sop->ofp == NULL) {
595 sprintf(errmsg, "missing recover file '%s'",
596 oname);
597 error(WARNING, errmsg);
598 lastout = 0;
599 break;
600 }
601 nvals = lseek(fileno(sop->ofp), 0, SEEK_END);
602 if (nvals <= 0) {
603 lastout = 0; /* empty output, quit here */
604 fclose(sop->ofp);
605 break;
606 }
607 recsiz = outvsiz * sop->reclen;
608
609 lseek(fileno(sop->ofp), 0, SEEK_SET);
610 if (header && checkheader(sop->ofp, outvfmt, NULL) != 1) {
611 sprintf(errmsg, "format mismatch for '%s'",
612 oname);
613 error(USER, errmsg);
614 }
615 if ((sop->reclen == 1) & (sop->xr > 0) & (sop->yr > 0) &&
616 (!fscnresolu(&xr, &yr, sop->ofp) ||
617 (xr != sop->xr) |
618 (yr != sop->yr))) {
619 sprintf(errmsg, "resolution mismatch for '%s'",
620 oname);
621 error(USER, errmsg);
622 }
623 nvals = (nvals - (off_t)ftell(sop->ofp)) / recsiz;
624 if ((lastout < 0) | (nvals < lastout))
625 lastout = nvals;
626 if (!(ofl & OF_BIN))
627 break; /* no bin separation */
628 }
629 if (!lastout) { /* empty output */
630 error(WARNING, "no previous data to recover");
631 /* reclose all outputs */
632 lu_doall(&ofiletab, &myclose, NULL);
633 return;
634 }
635 }
636 if (lastout < 0) {
637 error(WARNING, "no output files to recover");
638 return;
639 }
640 if (raysleft && lastout >= raysleft/accumulate) {
641 error(WARNING, "output appears to be complete");
642 /* XXX should read & discard input? */
643 quit(0);
644 }
645 /* seek on all files */
646 nvals = lastout * outvsiz;
647 lu_doall(&ofiletab, &myseeko, &nvals);
648 /* skip repeated input */
649 lastout *= accumulate;
650 for (nvals = 0; nvals < lastout; nvals++) {
651 FVECT vdummy;
652 if (getvec(vdummy) < 0 || getvec(vdummy) < 0)
653 error(USER, "unexpected EOF on input");
654 }
655 lastray = lastdone = (RNUMBER)lastout;
656 if (raysleft)
657 raysleft -= lastray;
658 }