ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/rt/pmapcontrib.c
Revision: 2.20
Committed: Tue Feb 16 20:06:06 2021 UTC (3 years, 2 months ago) by greg
Content type: text/plain
Branch: MAIN
CVS Tags: rad5R4, HEAD
Changes since 2.19: +2 -5 lines
Log Message:
feat: removed upper limit on number of modifiers in rcontrib

File Contents

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