ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/rt/pmapcontrib.c
Revision: 2.18
Committed: Thu Jun 7 19:26:04 2018 UTC (5 years, 11 months ago) by rschregle
Content type: text/plain
Branch: MAIN
CVS Tags: rad5R2
Changes since 2.17: +10 -6 lines
Log Message:
Added photon distrib PID output to attach debugger

File Contents

# Content
1 #ifndef lint
2 static const char RCSid[] = "$Id: pmapcontrib.c,v 2.17 2018/03/20 19:55:33 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.17 2018/03/20 19:55:33 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 #ifdef PMAP_SIGUSR
396 signal(SIGUSR1, sigUsrDiags);
397 #endif
398
399 #ifdef DEBUG_PMAP
400 /* Output child process PID after random delay to prevent corrupted
401 * console output due to race condition */
402 usleep(1e6 * pmapRandom(rouletteState));
403 fprintf(stderr, "Proc %d: PID = %d "
404 "(waiting 10 sec to attach debugger...)\n",
405 proc, getpid());
406 /* Allow time for debugger to attach to child process */
407 sleep(10);
408 #endif
409
410 /* =============================================================
411 * 2-PASS PHOTON DISTRIBUTION
412 * Pass 1 (pre): emit fraction of target photon count
413 * Pass 2 (main): based on outcome of pass 1, estimate remaining
414 * number of photons to emit to approximate target
415 * count
416 * ============================================================= */
417 for (srcIdx = 0; srcIdx < nsources; srcIdx++) {
418 #ifndef PMAP_SIGUSR
419 unsigned portCnt, passCnt = 0, prePassCnt = 0;
420 float srcPreDistrib = preDistrib;
421 double srcNumEmit = 0; /* # to emit from source */
422 unsigned long srcNumDistrib = pm -> numPhotons; /* # stored */
423 #else
424 passCnt = prePassCnt = 0;
425 srcPreDistrib = preDistrib;
426 srcNumEmit = 0; /* # to emit from source */
427 srcNumDistrib = pm -> numPhotons; /* # stored */
428 #endif
429
430 if (srcFlux [srcIdx] < FTINY)
431 continue;
432
433 while (passCnt < 2) {
434 if (!passCnt) {
435 /* INIT PASS 1 */
436 if (++prePassCnt > maxPreDistrib) {
437 /* Warn if no photons contributed after sufficient
438 * iterations; only output from subprocess 0 to reduce
439 * console clutter */
440 if (!proc) {
441 sprintf(errmsg,
442 "source %s: too many prepasses, skipped",
443 source [srcIdx].so -> oname);
444 error(WARNING, errmsg);
445 }
446
447 break;
448 }
449
450 /* Num to emit is fraction of target count */
451 srcNumEmit = srcPreDistrib * srcDistribTarget;
452 }
453 else {
454 /* INIT PASS 2 */
455 #ifndef PMAP_SIGUSR
456 double srcPhotonFlux, avgPhotonFlux;
457 #endif
458
459 /* Based on the outcome of the predistribution we can now
460 * figure out how many more photons we have to emit from
461 * the current source to meet the target count,
462 * srcDistribTarget. This value is clamped to 0 in case
463 * the target has already been exceeded in pass 1.
464 * srcNumEmit and srcNumDistrib is the number of photons
465 * emitted and distributed (stored) from the current
466 * source in pass 1, respectively. */
467 srcNumDistrib = pm -> numPhotons - srcNumDistrib;
468 srcNumEmit *= srcNumDistrib
469 ? max(srcDistribTarget/srcNumDistrib, 1) - 1
470 : 0;
471
472 if (!srcNumEmit)
473 /* No photons left to distribute in main pass */
474 break;
475
476 srcPhotonFlux = srcFlux [srcIdx] / srcNumEmit;
477 avgPhotonFlux = photonFluxSum / (srcIdx + 1);
478
479 if (avgPhotonFlux > FTINY &&
480 srcPhotonFlux / avgPhotonFlux < FTINY) {
481 /* Skip source if its photon flux is grossly below the
482 * running average, indicating negligible contributions
483 * at the expense of excessive distribution time; only
484 * output from subproc 0 to reduce console clutter */
485 if (!proc) {
486 sprintf(errmsg,
487 "source %s: itsy bitsy photon flux, skipped",
488 source [srcIdx].so -> oname);
489 error(WARNING, errmsg);
490 }
491
492 srcNumEmit = 0; /* Or just break??? */
493 }
494
495 /* Update sum of photon flux per light source */
496 photonFluxSum += srcPhotonFlux;
497 }
498
499 portCnt = 0;
500 do { /* Need at least one iteration if no ports! */
501 emap.src = source + srcIdx;
502 emap.port = emap.src -> sflags & SDISTANT
503 ? photonPorts + portCnt : NULL;
504 photonPartition [emap.src -> so -> otype] (&emap);
505
506 if (verbose && !proc) {
507 /* Output from subproc 0 only to avoid race condition
508 * on console I/O */
509 if (!passCnt)
510 sprintf(errmsg, "\tPREPASS %d on source %s ",
511 prePassCnt, source [srcIdx].so -> oname);
512 else
513 sprintf(errmsg, "\tMAIN PASS on source %s ",
514 source [srcIdx].so -> oname);
515
516 if (emap.port) {
517 sprintf(errmsg2, "via port %s ",
518 photonPorts [portCnt].so -> oname);
519 strcat(errmsg, errmsg2);
520 }
521
522 sprintf(errmsg2, "(%lu partitions)\n",
523 emap.numPartitions);
524 strcat(errmsg, errmsg2);
525 eputs(errmsg);
526 #if NIX
527 fflush(stderr);
528 #endif
529 }
530
531 for (emap.partitionCnt = 0; emap.partitionCnt < emap.numPartitions;
532 emap.partitionCnt++) {
533 #ifndef PMAP_SIGUSR
534 double partNumEmit;
535 unsigned long partEmitCnt;
536 #endif
537
538 /* Get photon origin within current source partishunn
539 * and build emission map */
540 photonOrigin [emap.src -> so -> otype] (&emap);
541 initPhotonEmission(&emap, pdfSamples);
542
543 /* Number of photons to emit from ziss partishunn;
544 * scale according to its normalised contribushunn to
545 * the emitted source flux */
546 partNumEmit = srcNumEmit * colorAvg(emap.partFlux) /
547 srcFlux [srcIdx];
548 partEmitCnt = (unsigned long)partNumEmit;
549
550 /* Probabilistically account for fractional photons */
551 if (pmapRandom(cntState) < partNumEmit - partEmitCnt)
552 partEmitCnt++;
553
554 /* Update local and shared global emission counter */
555 photonCnt [PHOTONCNT_NUMEMIT(srcIdx)] += partEmitCnt;
556 localNumEmitted += partEmitCnt;
557
558 /* Integer counter avoids FP rounding errors during
559 * iteration */
560 while (partEmitCnt--) {
561 RAY photonRay;
562
563 /* Emit photon according to PDF (if any), allocate
564 * associated primary ray, and trace through scene
565 * until absorbed/leaked; emitPhoton() sets the
566 * emitting light source index in photonRay */
567 emitPhoton(&emap, &photonRay);
568 #if 1
569 if (emap.port)
570 /* !!! PHOTON PORT REJECTION SAMPLING HACK: set
571 * !!! photon port as fake hit object for
572 * !!! primary ray to check for intersection in
573 * !!! tracePhoton() */
574 photonRay.ro = emap.port -> so;
575 #endif
576 newPhotonPrimary(pm, &photonRay, primaryHeap[proc]);
577 /* Set subprocess index in photonRay for post-
578 * distrib primary index linearisation; this is
579 * propagated with the primary index in photonRay
580 * and set for photon hits by newPhoton() */
581 PMAP_SETRAYPROC(&photonRay, proc);
582 tracePhoton(&photonRay);
583 }
584
585 /* Update shared global photon count */
586 photonCnt [PHOTONCNT_NUMPHOT] += pm -> numPhotons -
587 lastNumPhotons;
588 lastNumPhotons = pm -> numPhotons;
589 #if !NIX
590 /* Synchronous progress report on Windoze */
591 if (!proc && photonRepTime > 0 &&
592 time(NULL) >= repLastTime + photonRepTime) {
593 unsigned s;
594 repComplete = pm -> distribTarget * numProc;
595 repProgress = photonCnt [PHOTONCNT_NUMPHOT];
596
597 for (repEmitted = 0, s = 0; s < nsources; s++)
598 repEmitted += photonCnt [PHOTONCNT_NUMEMIT(s)];
599
600 pmapDistribReport();
601 }
602 #endif
603 }
604
605 portCnt++;
606 } while (portCnt < numPhotonPorts);
607
608 if (pm -> numPhotons == srcNumDistrib) {
609 /* Double predistrib factor in case no photons were stored
610 * for this source and redo pass 1 */
611 srcPreDistrib *= 2;
612 }
613 else {
614 /* Now do pass 2 */
615 passCnt++;
616 }
617 }
618 }
619
620 /* Flush heap buffa one final time to prevent data corruption */
621 flushPhotonHeap(pm);
622 /* Flush final photon primary to primary heap file */
623 newPhotonPrimary(pm, NULL, primaryHeap [proc]);
624 /* Heap files closed automatically on exit
625 fclose(pm -> heap);
626 fclose(primaryHeap [proc]); */
627
628 #ifdef DEBUG_PMAP
629 sprintf(errmsg, "Proc %d total %ld photons\n", proc,
630 pm -> numPhotons);
631 eputs(errmsg);
632 fflush(stderr);
633 #endif
634
635 #ifdef PMAP_SIGUSR
636 signal(SIGUSR1, SIG_DFL);
637 #endif
638
639 #if NIX
640 /* Terminate subprocess */
641 exit(0);
642 #endif
643 }
644 else if (pid < 0)
645 error(SYSTEM, "failed to fork subprocess in distribPhotonContrib");
646 }
647
648 #if NIX
649 /* PARENT PROCESS CONTINUES HERE */
650 #ifdef SIGCONT
651 /* Enable progress report signal handler */
652 signal(SIGCONT, pmapDistribReport);
653 #endif
654 /* Wait for subprocesses to complete while reporting progress */
655 proc = numProc;
656 while (proc) {
657 while (waitpid(-1, &stat, WNOHANG) > 0) {
658 /* Subprocess exited; check status */
659 if (!WIFEXITED(stat) || WEXITSTATUS(stat))
660 error(USER, "failed photon distribution");
661
662 --proc;
663 }
664
665 /* Nod off for a bit and update progress */
666 sleep(1);
667
668 /* Asynchronous progress report from shared subprocess counters */
669 repComplete = pm -> distribTarget * numProc;
670 repProgress = photonCnt [PHOTONCNT_NUMPHOT];
671
672 for (repEmitted = 0, srcIdx = 0; srcIdx < nsources; srcIdx++)
673 repEmitted += photonCnt [PHOTONCNT_NUMEMIT(srcIdx)];
674
675 /* Get global photon count from shmem updated by subprocs */
676 pm -> numPhotons = photonCnt [PHOTONCNT_NUMPHOT];
677
678 if (photonRepTime > 0 && time(NULL) >= repLastTime + photonRepTime)
679 pmapDistribReport();
680 #ifdef SIGCONT
681 else signal(SIGCONT, pmapDistribReport);
682 #endif
683 }
684 #endif /* NIX */
685
686 /* ================================================================
687 * POST-DISTRIBUTION - Set photon flux and build kd-tree, etc.
688 * ================================================================ */
689 #ifdef SIGCONT
690 /* Reset signal handler */
691 signal(SIGCONT, SIG_DFL);
692 #endif
693 free(emap.samples);
694
695 if (!pm -> numPhotons)
696 error(USER, "empty contribution photon map");
697
698 /* Load per-subprocess primary rays into pm -> primary array */
699 /* Dumb compilers apparently need the char** cast */
700 pm -> numPrimary = buildPrimaries(pm, primaryHeap,
701 (char**)primaryHeapFname,
702 primaryOfs, numProc);
703 if (!pm -> numPrimary)
704 error(INTERNAL, "no primary rays in contribution photon map");
705
706 /* Set photon flux per source */
707 for (srcIdx = 0; srcIdx < nsources; srcIdx++)
708 srcFlux [srcIdx] /= photonCnt [PHOTONCNT_NUMEMIT(srcIdx)];
709 #if NIX
710 /* Photon counters no longer needed, unmap shared memory */
711 munmap(photonCnt, sizeof(*photonCnt));
712 close(shmFile);
713 unlink(shmFname);
714 #else
715 free(photonCnt);
716 #endif
717
718 if (verbose) {
719 eputs("\nBuilding contribution photon map...\n");
720 #if NIX
721 fflush(stderr);
722 #endif
723 }
724
725 /* Build underlying data structure; heap is destroyed */
726 buildPhotonMap(pm, srcFlux, primaryOfs, numProc);
727
728 /* Free per-subprocess primary heap files */
729 for (proc = 0; proc < numProc; proc++)
730 free(primaryHeapFname [proc]);
731
732 free(primaryHeapFname);
733 free(primaryHeap);
734 free(primaryOfs);
735
736 if (verbose)
737 eputs("\n");
738 }