ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/rt/pmapcontrib.c
Revision: 2.17
Committed: Tue Mar 20 19:55:33 2018 UTC (6 years, 2 months ago) by rschregle
Content type: text/plain
Branch: MAIN
Changes since 2.16: +4 -5 lines
Log Message:
Added -ae/-ai ambient exclude options to mkpmap, cleaned up opt parsing.

File Contents

# Content
1 #ifndef lint
2 static const char RCSid[] = "$Id: pmapcontrib.c,v 2.16 2018/03/16 21:00:09 rschregle Exp $";
3 #endif
4
5 /*
6 ======================================================================
7 Photon map for light source contributions
8
9 Roland Schregle (roland.schregle@{hslu.ch, gmail.com})
10 (c) Lucerne University of Applied Sciences and Arts,
11 supported by the Swiss National Science Foundation (SNSF, #147053)
12 ======================================================================
13
14 $Id: pmapcontrib.c,v 2.16 2018/03/16 21:00:09 rschregle Exp $
15 */
16
17
18 #include "pmapcontrib.h"
19 #include "pmapmat.h"
20 #include "pmapsrc.h"
21 #include "pmaprand.h"
22 #include "pmapio.h"
23 #include "pmapdiag.h"
24 #include "rcontrib.h"
25 #include "otypes.h"
26 #if NIX
27 #include <sys/mman.h>
28 #include <sys/wait.h>
29 #endif
30
31
32 static PhotonPrimaryIdx newPhotonPrimary (PhotonMap *pmap,
33 const RAY *primRay,
34 FILE *primHeap)
35 /* Add primary ray for emitted photon and save light source index, origin on
36 * source, and emitted direction; used by contrib photons. The current
37 * primary is stored in pmap -> lastPrimary. If the previous primary
38 * contributed photons (has srcIdx >= 0), it's appended to primHeap. If
39 * primRay == NULL, the current primary is still flushed, but no new primary
40 * is set. Returns updated primary counter pmap -> numPrimary. */
41 {
42 if (!pmap || !primHeap)
43 return 0;
44
45 /* Check if last primary ray has spawned photons (srcIdx >= 0, see
46 * newPhoton()), in which case we save it to the primary heap file
47 * before clobbering it */
48 if (pmap -> lastPrimary.srcIdx >= 0) {
49 if (!fwrite(&pmap -> lastPrimary, sizeof(PhotonPrimary), 1, primHeap))
50 error(SYSTEM, "failed writing photon primary in newPhotonPrimary");
51
52 pmap -> numPrimary++;
53 if (pmap -> numPrimary > PMAP_MAXPRIMARY)
54 error(INTERNAL, "photon primary overflow in newPhotonPrimary");
55 }
56
57 /* Mark unused with negative source index until path spawns a photon (see
58 * newPhoton()) */
59 pmap -> lastPrimary.srcIdx = -1;
60
61 if (primRay) {
62 FVECT dvec;
63
64 #ifdef PMAP_PRIMARYDIR
65 /* Reverse incident direction to point to light source */
66 dvec [0] = -primRay -> rdir [0];
67 dvec [1] = -primRay -> rdir [1];
68 dvec [2] = -primRay -> rdir [2];
69 pmap -> lastPrimary.dir = encodedir(dvec);
70 #endif
71 #ifdef PMAP_PRIMARYPOS
72 VCOPY(pmap -> lastPrimary.pos, primRay -> rop);
73 #endif
74 }
75
76 return pmap -> numPrimary;
77 }
78
79
80
81 #ifdef DEBUG_PMAP
82 static int checkPrimaryHeap (FILE *file)
83 /* Check heap for ordered primaries */
84 {
85 Photon p, lastp;
86 int i, dup;
87
88 rewind(file);
89 memset(&lastp, 0, sizeof(lastp));
90
91 while (fread(&p, sizeof(p), 1, file)) {
92 dup = 1;
93
94 for (i = 0; i <= 2; i++) {
95 if (p.pos [i] < thescene.cuorg [i] ||
96 p.pos [i] > thescene.cuorg [i] + thescene.cusize) {
97
98 sprintf(errmsg, "corrupt photon in heap at [%f, %f, %f]\n",
99 p.pos [0], p.pos [1], p.pos [2]);
100 error(WARNING, errmsg);
101 }
102
103 dup &= p.pos [i] == lastp.pos [i];
104 }
105
106 if (dup) {
107 sprintf(errmsg,
108 "consecutive duplicate photon in heap at [%f, %f, %f]\n",
109 p.pos [0], p.pos [1], p.pos [2]);
110 error(WARNING, errmsg);
111 }
112 }
113
114 return 0;
115 }
116 #endif
117
118
119
120 static PhotonPrimaryIdx buildPrimaries (PhotonMap *pmap, FILE **primaryHeap,
121 char **primaryHeapFname,
122 PhotonPrimaryIdx *primaryOfs,
123 unsigned numHeaps)
124 /* Consolidate per-subprocess photon primary heaps into the primary array
125 * pmap -> primaries. Returns offset for primary index linearisation in
126 * numPrimary. The heap files in primaryHeap are closed on return. */
127 {
128 PhotonPrimaryIdx heapLen;
129 unsigned heap;
130
131 if (!pmap || !primaryHeap || !primaryOfs || !numHeaps)
132 return 0;
133
134 pmap -> numPrimary = 0;
135
136 for (heap = 0; heap < numHeaps; heap++) {
137 primaryOfs [heap] = pmap -> numPrimary;
138
139 if (fseek(primaryHeap [heap], 0, SEEK_END) < 0)
140 error(SYSTEM, "failed photon primary seek in buildPrimaries");
141 pmap -> numPrimary += heapLen = ftell(primaryHeap [heap]) /
142 sizeof(PhotonPrimary);
143
144 pmap -> primaries = realloc(pmap -> primaries,
145 pmap -> numPrimary *
146 sizeof(PhotonPrimary));
147 if (!pmap -> primaries)
148 error(SYSTEM, "failed photon primary alloc in buildPrimaries");
149
150 rewind(primaryHeap [heap]);
151 if (fread(pmap -> primaries + primaryOfs [heap], sizeof(PhotonPrimary),
152 heapLen, primaryHeap [heap]) != heapLen)
153 error(SYSTEM, "failed reading photon primaries in buildPrimaries");
154
155 fclose(primaryHeap [heap]);
156 unlink(primaryHeapFname [heap]);
157 }
158
159 return pmap -> numPrimary;
160 }
161
162
163
164 /* Defs for photon emission counter array passed by sub-processes to parent
165 * via shared memory */
166 typedef unsigned long PhotonContribCnt;
167
168 /* Indices for photon emission counter array: num photons stored and num
169 * emitted per source */
170 #define PHOTONCNT_NUMPHOT 0
171 #define PHOTONCNT_NUMEMIT(n) (1 + n)
172
173
174
175
176
177
178 void distribPhotonContrib (PhotonMap* pm, unsigned numProc)
179 {
180 EmissionMap emap;
181 char errmsg2 [128], shmFname [PMAP_TMPFNLEN];
182 unsigned srcIdx, proc;
183 int shmFile, stat, pid;
184 double *srcFlux, /* Emitted flux per light source */
185 srcDistribTarget; /* Target photon count per source */
186 PhotonContribCnt *photonCnt; /* Photon emission counter array */
187 unsigned photonCntSize = sizeof(PhotonContribCnt) *
188 PHOTONCNT_NUMEMIT(nsources);
189 FILE **primaryHeap = NULL;
190 char **primaryHeapFname = NULL;
191 PhotonPrimaryIdx *primaryOfs = NULL;
192
193 if (!pm)
194 error(USER, "no photon map defined in distribPhotonContrib");
195
196 if (!nsources)
197 error(USER, "no light sources in distribPhotonContrib");
198
199 if (nsources > MAXMODLIST)
200 error(USER, "too many light sources in distribPhotonContrib");
201
202 /* Allocate photon flux per light source; this differs for every
203 * source as all sources contribute the same number of distributed
204 * photons (srcDistribTarget), hence the number of photons emitted per
205 * source does not correlate with its emitted flux. The resulting flux
206 * per photon is therefore adjusted individually for each source. */
207 if (!(srcFlux = calloc(nsources, sizeof(double))))
208 error(SYSTEM, "can't allocate source flux in distribPhotonContrib");
209
210 /* ===================================================================
211 * INITIALISATION - Set up emission and scattering funcs
212 * =================================================================== */
213 emap.samples = NULL;
214 emap.src = NULL;
215 emap.maxPartitions = MAXSPART;
216 emap.partitions = (unsigned char*)malloc(emap.maxPartitions >> 1);
217 if (!emap.partitions)
218 error(USER, "can't allocate source partitions in distribPhotonContrib");
219
220 /* Initialise contrib photon map */
221 initPhotonMap(pm, PMAP_TYPE_CONTRIB);
222 initPhotonHeap(pm);
223 initPhotonEmissionFuncs();
224 initPhotonScatterFuncs();
225
226 /* Per-subprocess / per-source target counts */
227 pm -> distribTarget /= numProc;
228 srcDistribTarget = nsources ? (double)pm -> distribTarget / nsources : 0;
229
230 if (!pm -> distribTarget)
231 error(INTERNAL, "no photons to distribute in distribPhotonContrib");
232
233 /* Get photon ports from modifier list */
234 getPhotonPorts(photonPortList);
235
236 /* Get photon sensor modifiers */
237 getPhotonSensors(photonSensorList);
238
239 #if NIX
240 /* Set up shared mem for photon counters (zeroed by ftruncate) */
241 strcpy(shmFname, PMAP_TMPFNAME);
242 shmFile = mkstemp(shmFname);
243
244 if (shmFile < 0 || ftruncate(shmFile, photonCntSize) < 0)
245 error(SYSTEM, "failed shared mem init in distribPhotonContrib");
246
247 photonCnt = mmap(NULL, photonCntSize, PROT_READ | PROT_WRITE,
248 MAP_SHARED, shmFile, 0);
249
250 if (photonCnt == MAP_FAILED)
251 error(SYSTEM, "failed shared mem mapping in distribPhotonContrib");
252 #else
253 /* Allocate photon counters statically on Windoze */
254 if (!(photonCnt = malloc(photonCntSize)))
255 error(SYSTEM, "failed trivial malloc in distribPhotonContrib");
256
257 for (srcIdx = 0; srcIdx < PHOTONCNT_NUMEMIT(nsources); srcIdx++)
258 photonCnt [srcIdx] = 0;
259 #endif /* NIX */
260
261 if (verbose) {
262 sprintf(errmsg, "\nIntegrating flux from %d sources", nsources);
263
264 if (photonPorts) {
265 sprintf(errmsg2, " via %d ports", numPhotonPorts);
266 strcat(errmsg, errmsg2);
267 }
268
269 strcat(errmsg, "\n");
270 eputs(errmsg);
271 }
272
273 /* =============================================================
274 * FLUX INTEGRATION - Get total flux emitted from sources/ports
275 * ============================================================= */
276 for (srcIdx = 0; srcIdx < nsources; srcIdx++) {
277 unsigned portCnt = 0;
278 srcFlux [srcIdx] = 0;
279 emap.src = source + srcIdx;
280
281 do { /* Need at least one iteration if no ports! */
282 emap.port = emap.src -> sflags & SDISTANT ? photonPorts + portCnt
283 : NULL;
284 photonPartition [emap.src -> so -> otype] (&emap);
285
286 if (verbose) {
287 sprintf(errmsg, "\tIntegrating flux from source %s ",
288 source [srcIdx].so -> oname);
289
290 if (emap.port) {
291 sprintf(errmsg2, "via port %s ",
292 photonPorts [portCnt].so -> oname);
293 strcat(errmsg, errmsg2);
294 }
295
296 sprintf(errmsg2, "(%lu partitions)\n", emap.numPartitions);
297 strcat(errmsg, errmsg2);
298 eputs(errmsg);
299 #if NIX
300 fflush(stderr);
301 #endif
302 }
303
304 for (emap.partitionCnt = 0; emap.partitionCnt < emap.numPartitions;
305 emap.partitionCnt++) {
306 initPhotonEmission(&emap, pdfSamples);
307 srcFlux [srcIdx] += colorAvg(emap.partFlux);
308 }
309
310 portCnt++;
311 } while (portCnt < numPhotonPorts);
312
313 if (srcFlux [srcIdx] < FTINY) {
314 sprintf(errmsg, "source %s has zero emission",
315 source [srcIdx].so -> oname);
316 error(WARNING, errmsg);
317 }
318 }
319
320 /* Allocate & init per-subprocess primary heap files */
321 primaryHeap = calloc(numProc, sizeof(FILE*));
322 primaryHeapFname = calloc(numProc, sizeof(char*));
323 primaryOfs = calloc(numProc, sizeof(PhotonPrimaryIdx));
324 if (!primaryHeap || !primaryHeapFname || !primaryOfs)
325 error(SYSTEM, "failed primary heap allocation in "
326 "distribPhotonContrib");
327
328 for (proc = 0; proc < numProc; proc++) {
329 primaryHeapFname [proc] = malloc(PMAP_TMPFNLEN);
330 if (!primaryHeapFname [proc])
331 error(SYSTEM, "failed primary heap file allocation in "
332 "distribPhotonContrib");
333
334 mktemp(strcpy(primaryHeapFname [proc], PMAP_TMPFNAME));
335 if (!(primaryHeap [proc] = fopen(primaryHeapFname [proc], "w+b")))
336 error(SYSTEM, "failed opening primary heap file in "
337 "distribPhotonContrib");
338 }
339
340 /* Record start time for progress reports */
341 repStartTime = time(NULL);
342
343 if (verbose) {
344 sprintf(errmsg, "\nPhoton distribution @ %d procs\n", numProc);
345 eputs(errmsg);
346 }
347
348 /* MAIN LOOP */
349 for (proc = 0; proc < numProc; proc++) {
350 #if NIX
351 if (!(pid = fork())) {
352 /* SUBPROCESS ENTERS HERE; opened and mmapped files inherited */
353 #else
354 if (1) {
355 /* No subprocess under Windoze */
356 #endif
357 /* Local photon counters for this subprocess */
358 unsigned long lastNumPhotons = 0, localNumEmitted = 0;
359 double photonFluxSum = 0; /* Accum. photon flux */
360
361 /* Seed RNGs from PID for decorellated photon distribution */
362 pmapSeed(randSeed + proc, partState);
363 pmapSeed(randSeed + (proc + 1) % numProc, emitState);
364 pmapSeed(randSeed + (proc + 2) % numProc, cntState);
365 pmapSeed(randSeed + (proc + 3) % numProc, mediumState);
366 pmapSeed(randSeed + (proc + 4) % numProc, scatterState);
367 pmapSeed(randSeed + (proc + 5) % numProc, rouletteState);
368
369 #ifdef PMAP_SIGUSR
370 double partNumEmit;
371 unsigned long partEmitCnt;
372 double srcPhotonFlux, avgPhotonFlux;
373 unsigned portCnt, passCnt, prePassCnt;
374 float srcPreDistrib;
375 double srcNumEmit; /* # to emit from source */
376 unsigned long srcNumDistrib; /* # stored */
377
378 void sigUsrDiags()
379 /* Loop diags via SIGUSR1 */
380 {
381 sprintf(errmsg,
382 "********************* Proc %d Diags *********************\n"
383 "srcIdx = %d (%s)\nportCnt = %d (%s)\npassCnt = %d\n"
384 "srcFlux = %f\nsrcPhotonFlux = %f\navgPhotonFlux = %f\n"
385 "partNumEmit = %f\npartEmitCnt = %lu\n\n",
386 proc, srcIdx, findmaterial(source [srcIdx].so) -> oname,
387 portCnt, photonPorts [portCnt].so -> oname,
388 passCnt, srcFlux [srcIdx], srcPhotonFlux, avgPhotonFlux,
389 partNumEmit, partEmitCnt);
390 eputs(errmsg);
391 fflush(stderr);
392 }
393 #endif
394
395 #if PMAP_SIGUSR
396 signal(SIGUSR1, sigUsrDiags);
397 #endif
398
399 /* Output child process PID after random delay to prevent corrupted
400 * console output due to race condition */
401 usleep(1e6 * pmapRandom(rouletteState));
402 fprintf(stderr, "Proc %d: PID = %d\n", proc, getpid());
403 /* Allow time for debugger to attach to child process */
404 sleep(10);
405
406 /* =============================================================
407 * 2-PASS PHOTON DISTRIBUTION
408 * Pass 1 (pre): emit fraction of target photon count
409 * Pass 2 (main): based on outcome of pass 1, estimate remaining
410 * number of photons to emit to approximate target
411 * count
412 * ============================================================= */
413 for (srcIdx = 0; srcIdx < nsources; srcIdx++) {
414 #ifndef PMAP_SIGUSR
415 unsigned portCnt, passCnt = 0, prePassCnt = 0;
416 float srcPreDistrib = preDistrib;
417 double srcNumEmit = 0; /* # to emit from source */
418 unsigned long srcNumDistrib = pm -> numPhotons; /* # stored */
419 #else
420 passCnt = prePassCnt = 0;
421 srcPreDistrib = preDistrib;
422 srcNumEmit = 0; /* # to emit from source */
423 srcNumDistrib = pm -> numPhotons; /* # stored */
424 #endif
425
426 if (srcFlux [srcIdx] < FTINY)
427 continue;
428
429 while (passCnt < 2) {
430 if (!passCnt) {
431 /* INIT PASS 1 */
432 if (++prePassCnt > maxPreDistrib) {
433 /* Warn if no photons contributed after sufficient
434 * iterations; only output from subprocess 0 to reduce
435 * console clutter */
436 if (!proc) {
437 sprintf(errmsg,
438 "source %s: too many prepasses, skipped",
439 source [srcIdx].so -> oname);
440 error(WARNING, errmsg);
441 }
442
443 break;
444 }
445
446 /* Num to emit is fraction of target count */
447 srcNumEmit = srcPreDistrib * srcDistribTarget;
448 }
449 else {
450 /* INIT PASS 2 */
451 #ifndef PMAP_SIGUSR
452 double srcPhotonFlux, avgPhotonFlux;
453 #endif
454
455 /* Based on the outcome of the predistribution we can now
456 * figure out how many more photons we have to emit from
457 * the current source to meet the target count,
458 * srcDistribTarget. This value is clamped to 0 in case
459 * the target has already been exceeded in pass 1.
460 * srcNumEmit and srcNumDistrib is the number of photons
461 * emitted and distributed (stored) from the current
462 * source in pass 1, respectively. */
463 srcNumDistrib = pm -> numPhotons - srcNumDistrib;
464 srcNumEmit *= srcNumDistrib
465 ? max(srcDistribTarget/srcNumDistrib, 1) - 1
466 : 0;
467
468 if (!srcNumEmit)
469 /* No photons left to distribute in main pass */
470 break;
471
472 srcPhotonFlux = srcFlux [srcIdx] / srcNumEmit;
473 avgPhotonFlux = photonFluxSum / (srcIdx + 1);
474
475 if (avgPhotonFlux > FTINY &&
476 srcPhotonFlux / avgPhotonFlux < FTINY) {
477 /* Skip source if its photon flux is grossly below the
478 * running average, indicating negligible contributions
479 * at the expense of excessive distribution time; only
480 * output from subproc 0 to reduce console clutter */
481 if (!proc) {
482 sprintf(errmsg,
483 "source %s: itsy bitsy photon flux, skipped",
484 source [srcIdx].so -> oname);
485 error(WARNING, errmsg);
486 }
487
488 srcNumEmit = 0; /* Or just break??? */
489 }
490
491 /* Update sum of photon flux per light source */
492 photonFluxSum += srcPhotonFlux;
493 }
494
495 portCnt = 0;
496 do { /* Need at least one iteration if no ports! */
497 emap.src = source + srcIdx;
498 emap.port = emap.src -> sflags & SDISTANT
499 ? photonPorts + portCnt : NULL;
500 photonPartition [emap.src -> so -> otype] (&emap);
501
502 if (verbose && !proc) {
503 /* Output from subproc 0 only to avoid race condition
504 * on console I/O */
505 if (!passCnt)
506 sprintf(errmsg, "\tPREPASS %d on source %s ",
507 prePassCnt, source [srcIdx].so -> oname);
508 else
509 sprintf(errmsg, "\tMAIN PASS on source %s ",
510 source [srcIdx].so -> oname);
511
512 if (emap.port) {
513 sprintf(errmsg2, "via port %s ",
514 photonPorts [portCnt].so -> oname);
515 strcat(errmsg, errmsg2);
516 }
517
518 sprintf(errmsg2, "(%lu partitions)\n",
519 emap.numPartitions);
520 strcat(errmsg, errmsg2);
521 eputs(errmsg);
522 #if NIX
523 fflush(stderr);
524 #endif
525 }
526
527 for (emap.partitionCnt = 0; emap.partitionCnt < emap.numPartitions;
528 emap.partitionCnt++) {
529 #ifndef PMAP_SIGUSR
530 double partNumEmit;
531 unsigned long partEmitCnt;
532 #endif
533
534 /* Get photon origin within current source partishunn
535 * and build emission map */
536 photonOrigin [emap.src -> so -> otype] (&emap);
537 initPhotonEmission(&emap, pdfSamples);
538
539 /* Number of photons to emit from ziss partishunn;
540 * scale according to its normalised contribushunn to
541 * the emitted source flux */
542 partNumEmit = srcNumEmit * colorAvg(emap.partFlux) /
543 srcFlux [srcIdx];
544 partEmitCnt = (unsigned long)partNumEmit;
545
546 /* Probabilistically account for fractional photons */
547 if (pmapRandom(cntState) < partNumEmit - partEmitCnt)
548 partEmitCnt++;
549
550 /* Update local and shared global emission counter */
551 photonCnt [PHOTONCNT_NUMEMIT(srcIdx)] += partEmitCnt;
552 localNumEmitted += partEmitCnt;
553
554 /* Integer counter avoids FP rounding errors during
555 * iteration */
556 while (partEmitCnt--) {
557 RAY photonRay;
558
559 /* Emit photon according to PDF (if any), allocate
560 * associated primary ray, and trace through scene
561 * until absorbed/leaked; emitPhoton() sets the
562 * emitting light source index in photonRay */
563 emitPhoton(&emap, &photonRay);
564 #if 1
565 if (emap.port)
566 /* !!! PHOTON PORT REJECTION SAMPLING HACK: set
567 * !!! photon port as fake hit object for
568 * !!! primary ray to check for intersection in
569 * !!! tracePhoton() */
570 photonRay.ro = emap.port -> so;
571 #endif
572 newPhotonPrimary(pm, &photonRay, primaryHeap[proc]);
573 /* Set subprocess index in photonRay for post-
574 * distrib primary index linearisation; this is
575 * propagated with the primary index in photonRay
576 * and set for photon hits by newPhoton() */
577 PMAP_SETRAYPROC(&photonRay, proc);
578 tracePhoton(&photonRay);
579 }
580
581 /* Update shared global photon count */
582 photonCnt [PHOTONCNT_NUMPHOT] += pm -> numPhotons -
583 lastNumPhotons;
584 lastNumPhotons = pm -> numPhotons;
585 #if !NIX
586 /* Synchronous progress report on Windoze */
587 if (!proc && photonRepTime > 0 &&
588 time(NULL) >= repLastTime + photonRepTime) {
589 unsigned s;
590 repComplete = pm -> distribTarget * numProc;
591 repProgress = photonCnt [PHOTONCNT_NUMPHOT];
592
593 for (repEmitted = 0, s = 0; s < nsources; s++)
594 repEmitted += photonCnt [PHOTONCNT_NUMEMIT(s)];
595
596 pmapDistribReport();
597 }
598 #endif
599 }
600
601 portCnt++;
602 } while (portCnt < numPhotonPorts);
603
604 if (pm -> numPhotons == srcNumDistrib) {
605 /* Double predistrib factor in case no photons were stored
606 * for this source and redo pass 1 */
607 srcPreDistrib *= 2;
608 }
609 else {
610 /* Now do pass 2 */
611 passCnt++;
612 }
613 }
614 }
615
616 /* Flush heap buffa one final time to prevent data corruption */
617 flushPhotonHeap(pm);
618 /* Flush final photon primary to primary heap file */
619 newPhotonPrimary(pm, NULL, primaryHeap [proc]);
620 /* Heap files closed automatically on exit
621 fclose(pm -> heap);
622 fclose(primaryHeap [proc]); */
623
624 #ifdef DEBUG_PMAP
625 sprintf(errmsg, "Proc %d total %ld photons\n", proc,
626 pm -> numPhotons);
627 eputs(errmsg);
628 fflush(stderr);
629 #endif
630
631 #ifdef PMAP_SIGUSR
632 signal(SIGUSR1, SIG_DFL);
633 #endif
634
635 #if NIX
636 /* Terminate subprocess */
637 exit(0);
638 #endif
639 }
640 else if (pid < 0)
641 error(SYSTEM, "failed to fork subprocess in distribPhotonContrib");
642 }
643
644 #if NIX
645 /* PARENT PROCESS CONTINUES HERE */
646 #ifdef SIGCONT
647 /* Enable progress report signal handler */
648 signal(SIGCONT, pmapDistribReport);
649 #endif
650 /* Wait for subprocesses to complete while reporting progress */
651 proc = numProc;
652 while (proc) {
653 while (waitpid(-1, &stat, WNOHANG) > 0) {
654 /* Subprocess exited; check status */
655 if (!WIFEXITED(stat) || WEXITSTATUS(stat))
656 error(USER, "failed photon distribution");
657
658 --proc;
659 }
660
661 /* Nod off for a bit and update progress */
662 sleep(1);
663
664 /* Asynchronous progress report from shared subprocess counters */
665 repComplete = pm -> distribTarget * numProc;
666 repProgress = photonCnt [PHOTONCNT_NUMPHOT];
667
668 for (repEmitted = 0, srcIdx = 0; srcIdx < nsources; srcIdx++)
669 repEmitted += photonCnt [PHOTONCNT_NUMEMIT(srcIdx)];
670
671 /* Get global photon count from shmem updated by subprocs */
672 pm -> numPhotons = photonCnt [PHOTONCNT_NUMPHOT];
673
674 if (photonRepTime > 0 && time(NULL) >= repLastTime + photonRepTime)
675 pmapDistribReport();
676 #ifdef SIGCONT
677 else signal(SIGCONT, pmapDistribReport);
678 #endif
679 }
680 #endif /* NIX */
681
682 /* ================================================================
683 * POST-DISTRIBUTION - Set photon flux and build kd-tree, etc.
684 * ================================================================ */
685 #ifdef SIGCONT
686 /* Reset signal handler */
687 signal(SIGCONT, SIG_DFL);
688 #endif
689 free(emap.samples);
690
691 if (!pm -> numPhotons)
692 error(USER, "empty contribution photon map");
693
694 /* Load per-subprocess primary rays into pm -> primary array */
695 /* Dumb compilers apparently need the char** cast */
696 pm -> numPrimary = buildPrimaries(pm, primaryHeap,
697 (char**)primaryHeapFname,
698 primaryOfs, numProc);
699 if (!pm -> numPrimary)
700 error(INTERNAL, "no primary rays in contribution photon map");
701
702 /* Set photon flux per source */
703 for (srcIdx = 0; srcIdx < nsources; srcIdx++)
704 srcFlux [srcIdx] /= photonCnt [PHOTONCNT_NUMEMIT(srcIdx)];
705 #if NIX
706 /* Photon counters no longer needed, unmap shared memory */
707 munmap(photonCnt, sizeof(*photonCnt));
708 close(shmFile);
709 unlink(shmFname);
710 #else
711 free(photonCnt);
712 #endif
713
714 if (verbose) {
715 eputs("\nBuilding contribution photon map...\n");
716 #if NIX
717 fflush(stderr);
718 #endif
719 }
720
721 /* Build underlying data structure; heap is destroyed */
722 buildPhotonMap(pm, srcFlux, primaryOfs, numProc);
723
724 /* Free per-subprocess primary heap files */
725 for (proc = 0; proc < numProc; proc++)
726 free(primaryHeapFname [proc]);
727
728 free(primaryHeapFname);
729 free(primaryHeap);
730 free(primaryOfs);
731
732 if (verbose)
733 eputs("\n");
734 }