ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/rt/rxcmain.cpp
Revision: 2.5
Committed: Wed Oct 30 19:53:37 2024 UTC (6 months ago) by greg
Branch: MAIN
Changes since 2.4: +2 -2 lines
Log Message:
fix(rxcontrib): error-check on ComputRecord() return was off

File Contents

# Content
1 #ifndef lint
2 static const char RCSid[] = "$Id: rxcmain.cpp,v 2.4 2024/10/30 17:26:13 greg Exp $";
3 #endif
4 /*
5 * rxcmain.c - main for rxcontrib ray contribution tracer
6 */
7
8 #include "copyright.h"
9
10 #include <signal.h>
11 #include <time.h>
12 #include <ctype.h>
13 #include "RcontribSimulManager.h"
14 #include "platform.h"
15 #include "func.h"
16
17 const char *sigerr[NSIG]; /* signal error messages */
18
19 int nproc = 1; /* number of processes requested */
20
21 int inpfmt = 'a'; /* input format */
22 int outfmt = 'f'; /* output format */
23
24 int report_intvl = 0; /* reporting interval (seconds) */
25
26 extern char * progname; // global argv[0]
27
28 RcontribSimulManager myRCmanager; // global rcontrib simulation manager
29
30 #define RCONTRIB_FEATURES "Multiprocessing\n" \
31 "Accumulation\nRecovery\n" \
32 "ImmediateIrradiance\n" \
33 "ProgressReporting\nDistanceLimiting\n" \
34 "InputFormats=a,f,d\nOutputFormats=f,d,c\n" \
35 "Outputs=V,W\n" \
36 "OutputCS=RGB,spec\n"
37
38 static void rxcontrib(const int rstart = 0);
39
40 static void
41 printdefaults(void) /* print default values to stdout */
42 {
43 printf("-c %-5d\t\t\t# accumulated rays per record\n", myRCmanager.accum);
44 printf("-V%c\t\t\t\t# output %s\n", contrib ? '+' : '-',
45 contrib ? "contributions" : "coefficients");
46 if (myRCmanager.HasFlag(RTimmIrrad))
47 printf("-I+\t\t\t\t# immediate irradiance on\n");
48 printf("-n %-2d\t\t\t\t# number of rendering processes\n", nproc);
49 if (xres > 0)
50 printf("-x %-9d\t\t\t# x resolution\n", xres);
51 printf("-y %-9d\t\t\t# y resolution\n", yres);
52 printf(myRCmanager.HasFlag(RTlimDist) ?
53 "-ld+\t\t\t\t# limit distance on\n" :
54 "-ld-\t\t\t\t# limit distance off\n");
55 printf("-f%c%c\t\t\t\t# format input/output = %s/%s\n",
56 inpfmt, outfmt, formstr(inpfmt), formstr(outfmt));
57 if (report_intvl > 0)
58 printf("-t %-9d\t\t\t# time between reports\n", report_intvl);
59 printf(erract[WARNING].pf != NULL ?
60 "-w+\t\t\t\t# warning messages on\n" :
61 "-w-\t\t\t\t# warning messages off\n");
62 print_rdefaults();
63 }
64
65
66 static void
67 onsig( /* fatal signal */
68 int signo
69 )
70 {
71 static int gotsig = 0;
72
73 if (gotsig++) /* two signals and we're gone! */
74 _exit(signo);
75
76 #ifdef SIGALRM
77 alarm(180); /* allow 3 minutes to clean up */
78 signal(SIGALRM, SIG_DFL); /* make certain we do die */
79 #endif
80 eputs("signal - ");
81 eputs(sigerr[signo]);
82 eputs("\n");
83 quit(3);
84 }
85
86
87 static void
88 sigdie( /* set fatal signal */
89 int signo,
90 const char *msg
91 )
92 {
93 if (signal(signo, onsig) == SIG_IGN)
94 signal(signo, SIG_IGN);
95 sigerr[signo] = msg;
96 }
97
98 const char *
99 formstr(int f) // return format identifier
100 {
101 switch (f) {
102 case 'a': return("ascii");
103 case 'f': return("float");
104 case 'd': return("double");
105 case 'c': return(NCSAMP==3 ? COLRFMT : SPECFMT);
106 }
107 return("unknown");
108 }
109
110 /* set input/output format */
111 static void
112 setformat(const char *fmt)
113 {
114 switch (fmt[0]) {
115 case 'f':
116 case 'd':
117 SET_FILE_BINARY(stdin);
118 /* fall through */
119 case 'a':
120 inpfmt = fmt[0];
121 break;
122 default:
123 goto fmterr;
124 }
125 switch (fmt[1]) {
126 case '\0':
127 if (inpfmt == 'a')
128 goto fmterr;
129 outfmt = inpfmt;
130 return;
131 case 'f':
132 case 'd':
133 case 'c':
134 outfmt = fmt[1];
135 break;
136 default:
137 goto fmterr;
138 }
139 if (!fmt[2])
140 return;
141 fmterr:
142 sprintf(errmsg, "Unsupported i/o format: -f%s", fmt);
143 error(USER, errmsg);
144 }
145
146
147 /* Set overriding options */
148 static void
149 override_options(void)
150 {
151 shadthresh = 0;
152 ambssamp = 0;
153 ambacc = 0;
154 }
155
156
157 int
158 main(int argc, char *argv[])
159 {
160 #define check(ol,al) if (argv[i][ol] || \
161 badarg(argc-i-1,argv+i+1,al)) \
162 goto badopt
163 #define check_bool(olen,var) switch (argv[i][olen]) { \
164 case '\0': var = !var; break; \
165 case 'y': case 'Y': case 't': case 'T': \
166 case '+': case '1': var = 1; break; \
167 case 'n': case 'N': case 'f': case 'F': \
168 case '-': case '0': var = 0; break; \
169 default: goto badopt; }
170 int force_open = 0;
171 int recover = 0;
172 char *curout = NULL;
173 char *prms = NULL;
174 char *binval = NULL;
175 int bincnt = 0;
176 int rval;
177 int i;
178 /* global program name */
179 progname = argv[0];
180 /* feature check only? */
181 strcat(RFeatureList, RCONTRIB_FEATURES);
182 if (argc > 1 && !strcmp(argv[1], "-features"))
183 return feature_status(argc-2, argv+2);
184 /* initialize calcomp routines early */
185 initfunc();
186 calcontext(RCCONTEXT);
187 /* option city */
188 for (i = 1; i < argc; i++) {
189 /* expand arguments */
190 while ((rval = expandarg(&argc, &argv, i)) > 0)
191 ;
192 if (rval < 0) {
193 sprintf(errmsg, "cannot expand '%s'", argv[i]);
194 error(SYSTEM, errmsg);
195 }
196 if (argv[i] == NULL || argv[i][0] != '-')
197 break; /* break from options */
198 if (!strcmp(argv[i], "-version")) {
199 puts(VersionID);
200 quit(0);
201 }
202 if (!strcmp(argv[i], "-defaults") ||
203 !strcmp(argv[i], "-help")) {
204 override_options();
205 printdefaults();
206 quit(0);
207 }
208 rval = getrenderopt(argc-i, argv+i);
209 if (rval >= 0) {
210 i += rval;
211 continue;
212 }
213 switch (argv[i][1]) {
214 case 'n': /* number of processes */
215 check(2,"i");
216 nproc = atoi(argv[++i]);
217 if (nproc < 0 && (nproc += RadSimulManager::GetNCores()) <= 0)
218 nproc = 1;
219 break;
220 case 'V': /* output contributions? */
221 check_bool(2,contrib);
222 break;
223 case 'x': /* x resolution */
224 check(2,"i");
225 xres = atoi(argv[++i]);
226 break;
227 case 'y': /* y resolution */
228 check(2,"i");
229 yres = atoi(argv[++i]);
230 break;
231 case 'w': /* warnings on/off */
232 rval = (erract[WARNING].pf != NULL);
233 check_bool(2,rval);
234 if (rval) erract[WARNING].pf = wputs;
235 else erract[WARNING].pf = NULL;
236 break;
237 case 'e': /* .cal expression */
238 check(2,"s");
239 scompile(argv[++i], NULL, 0);
240 break;
241 case 'l': /* limit distance */
242 if (argv[i][2] != 'd')
243 goto badopt;
244 rval = myRCmanager.HasFlag(RTlimDist);
245 check_bool(3,rval);
246 myRCmanager.SetFlag(RTlimDist, rval);
247 break;
248 case 'I': /* immed. irradiance */
249 rval = myRCmanager.HasFlag(RTimmIrrad);
250 check_bool(2,rval);
251 myRCmanager.SetFlag(RTimmIrrad, rval);
252 break;
253 case 'f': /* .cal file or force or format */
254 if (!argv[i][2]) {
255 check(2,"s");
256 loadfunc(argv[++i]);
257 break;
258 }
259 if (argv[i][2] == 'o') {
260 check_bool(3,force_open);
261 break;
262 }
263 setformat(argv[i]+2);
264 myRCmanager.SetDataFormat(outfmt);
265 break;
266 case 'o': /* output file */
267 check(2,"s");
268 curout = argv[++i];
269 break;
270 case 'r': /* recover output */
271 check_bool(2,recover);
272 break;
273 case 'p': /* parameter setting(s) */
274 check(2,"s");
275 set_eparams(prms = argv[++i]);
276 break;
277 case 'c': /* sample count */
278 check(2,"i");
279 myRCmanager.accum = atoi(argv[++i]);
280 break;
281 case 'b': /* bin expression/count */
282 if (argv[i][2] == 'n') {
283 check(3,"s");
284 bincnt = (int)(eval(argv[++i]) + .5);
285 break;
286 }
287 check(2,"s");
288 binval = argv[++i];
289 break;
290 case 'm': /* modifier name */
291 check(2,"s");
292 myRCmanager.AddModifier(argv[++i], curout, prms, binval, bincnt);
293 break;
294 case 'M': /* file of modifier names */
295 check(2,"s");
296 myRCmanager.AddModFile(argv[++i], curout, prms, binval, bincnt);
297 break;
298 case 't': /* reporting interval */
299 check(2,"i");
300 report_intvl = atoi(argv[++i]);
301 break;
302 default:
303 goto badopt;
304 }
305 }
306 if (i != argc-1)
307 error(USER, "expected single octree argument");
308
309 override_options(); /* override some option settings */
310
311 if (!myRCmanager.GetOutput()) // check that we have work to do
312 error(USER, "missing required modifier argument");
313 // get ready to rock...
314 if (setspectrsamp(CNDX, WLPART) < 0)
315 error(USER, "unsupported spectral sampling");
316 /* set up signal handling */
317 sigdie(SIGINT, "Interrupt");
318 #ifdef SIGHUP
319 sigdie(SIGHUP, "Hangup");
320 #endif
321 sigdie(SIGTERM, "Terminate");
322 #ifdef SIGPIPE
323 sigdie(SIGPIPE, "Broken pipe");
324 #endif
325 #ifdef SIGALRM
326 sigdie(SIGALRM, "Alarm clock");
327 #endif
328 #ifdef SIGXCPU
329 sigdie(SIGXCPU, "CPU limit exceeded");
330 sigdie(SIGXFSZ, "File size exceeded");
331 #endif
332 #ifdef NICE
333 nice(NICE); /* lower priority */
334 #endif
335 // load octree
336 myRCmanager.LoadOctree(argv[argc-1]);
337 // add to header
338 myRCmanager.AddHeader(argc-1, argv);
339 // prepare output files
340 if (recover)
341 myRCmanager.outOp = RCOrecover;
342 else if (force_open)
343 myRCmanager.outOp = RCOforce;
344 else
345 myRCmanager.outOp = RCOnew;
346 // rval = # rows recovered
347 rval = myRCmanager.PrepOutput();
348 // check if recovered everything
349 if (recover && rval >= myRCmanager.GetRowMax()) {
350 error(WARNING, "nothing left to compute");
351 quit(0);
352 } // add processes as requested
353 myRCmanager.SetThreadCount(nproc);
354
355 rxcontrib(rval); /* trace ray contributions (loop) */
356
357 quit(0); /* exit clean */
358
359 badopt:
360 fprintf(stderr,
361 "Usage: %s [-V][-c count][-r][-e expr][-f source][-o ospec][-p p1=V1,p2=V2][-b binv][-bn N] {-m mod | -M file} [rtrace options] octree\n",
362 progname);
363 sprintf(errmsg, "command line error at '%s'", argv[i]);
364 error(USER, errmsg);
365 return(1); /* pro forma return */
366
367 #undef check
368 #undef check_bool
369 }
370
371
372 // skip specified number of bytes, return false if EOF
373 static bool
374 skipBytes(int n2skip)
375 {
376 while (n2skip-- > 0)
377 if (getchar() == EOF)
378 return false;
379 return true;
380 }
381
382
383 // skip specified number of whitespace-separated words, return false if EOF
384 static bool
385 skipWords(int n2skip)
386 {
387 int c;
388
389 while (n2skip-- > 0) {
390 do {
391 c = getchar();
392 } while (isspace(c));
393 do {
394 if (c == EOF) return false;
395 c = getchar();
396 } while (!isspace(c));
397 }
398 return true;
399 }
400
401
402 // read a bundle of myRCmanager.accum ray origins and directions
403 static bool
404 getRayBundle(FVECT *orig_dir = NULL)
405 {
406 int n2go = myRCmanager.accum;
407
408 switch (inpfmt) {
409 case 'a': // ASCII input
410 if (!orig_dir)
411 return skipWords(6*n2go);
412 while (n2go-- > 0) {
413 if (scanf(FVFORMAT, &orig_dir[0][0],
414 &orig_dir[0][1], &orig_dir[0][2]) != 3)
415 return false;
416 if (scanf(FVFORMAT, &orig_dir[1][0],
417 &orig_dir[1][1], &orig_dir[1][2]) != 3)
418 return false;
419 orig_dir += 2;
420 }
421 break;
422 case 'f': // float input
423 if (!orig_dir)
424 return skipBytes(6*sizeof(float)*n2go);
425 #ifdef SMLFLT
426 if (getbinary(orig_dir, sizeof(FVECT), 2*n2go, stdin) != 2*n2go)
427 return false;
428 #else
429 while (n2go-- > 0) {
430 float fvecs[6];
431 if (getbinary(fvecs, sizeof(fvecs), 1, stdin) != 1)
432 return false;
433 for (int i = 6; i--; )
434 orig_dir[0][i] = fvecs[i];
435 orig_dir += 2;
436 }
437 #endif
438 break;
439 case 'd': // double input
440 if (!orig_dir)
441 return skipBytes(6*sizeof(double)*n2go);
442 #ifndef SMLFLT
443 if (getbinary(orig_dir, sizeof(FVECT), 2*n2go, stdin) != 2*n2go)
444 return false;
445 #else
446 while (n2go-- > 0) {
447 double dvecs[6];
448 if (getbinary(dvecs, sizeof(dvecs), 1, stdin) != 1)
449 return false;
450 for (int i = 6; i--; )
451 orig_dir[0][i] = dvecs[i];
452 orig_dir += 2;
453 }
454 #endif
455 break;
456 default:
457 error(INTERNAL, "unsupported format in getRayBundle()");
458 return false;
459 }
460 int warned = 0; // normalize directions
461 n2go = myRCmanager.accum;
462 while (n2go-- > 0) {
463 orig_dir -= 2;
464 if (normalize(orig_dir[1]) == 0)
465 if (!warned++)
466 error(WARNING, "zero ray direction on input");
467 }
468 return true;
469 }
470
471
472 // Run loop to load data, report progress, etc.
473 void
474 rxcontrib(const int rstart)
475 {
476 const int totRows = myRCmanager.GetRowMax();
477 FVECT * odarr = (FVECT *)emalloc(sizeof(FVECT)*2*myRCmanager.accum);
478 time_t tstart, last_report;
479 int r = 0;
480
481 while (r < rstart) { // skip input rays already done
482 if (!getRayBundle())
483 goto readerr;
484 r++;
485 }
486 if (report_intvl > 0) { // set up reporting
487 if (r > 0) {
488 sprintf(errmsg, "recovered %.2f%% of total\n",
489 100.*r/totRows);
490 eputs(errmsg);
491 }
492 last_report = tstart = time(0);
493 }
494 while (r < totRows) { // getting to work...
495 time_t tnow;
496 if (!getRayBundle(odarr))
497 goto readerr;
498 if (myRCmanager.ComputeRecord(odarr) <= 0)
499 return; // error reported, hopefully...
500 r++;
501 if (report_intvl <= 0)
502 continue;
503 if ((r < totRows) & ((tnow = time(0)) < last_report+report_intvl))
504 continue;
505 sprintf(errmsg, "%.2f%% done after %.3f hours\n",
506 100.*r/totRows, (1./3600.)*(tnow - tstart));
507 eputs(errmsg);
508 last_report = tnow;
509 }
510 efree(odarr);
511 return;
512 readerr:
513 sprintf(errmsg, "unexpected EOF on standard input (record %d of %d)",
514 r, totRows);
515 error(USER, errmsg);
516 }
517
518
519 void
520 wputs( /* warning output function */
521 const char *s
522 )
523 {
524 if (!erract[WARNING].pf) return;
525 int lasterrno = errno;
526 eputs(s);
527 errno = lasterrno;
528 }
529
530
531 void
532 eputs( /* put string to stderr */
533 const char *s
534 )
535 {
536 static int midline = 0;
537
538 if (!*s)
539 return;
540 if (!midline++) {
541 fputs(progname, stderr);
542 fputs(": ", stderr);
543 }
544 fputs(s, stderr);
545 if (s[strlen(s)-1] == '\n') {
546 fflush(stderr);
547 midline = 0;
548 }
549 }
550
551
552 /* Exit program */
553 void
554 quit(
555 int code
556 )
557 {
558 if (!code && myRCmanager.Ready()) // clean up on normal exit
559 code = myRCmanager.Cleanup();
560
561 exit(code);
562 }