ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/rt/pmap.c
Revision: 2.12
Committed: Mon Sep 26 20:19:30 2016 UTC (8 years, 7 months ago) by greg
Content type: text/plain
Branch: MAIN
Changes since 2.11: +2 -230 lines
Log Message:
Pulled pmap routines needed during rendering from pmap.c into pmutil.c

File Contents

# User Rev Content
1 greg 2.9 #ifndef lint
2 greg 2.12 static const char RCSid[] = "$Id: pmap.c,v 2.11 2016/05/17 17:39:47 rschregle Exp $";
3 greg 2.9 #endif
4 rschregle 2.11
5 greg 2.1 /*
6 rschregle 2.11 ======================================================================
7 greg 2.1 Photon map main module
8    
9     Roland Schregle (roland.schregle@{hslu.ch, gmail.com})
10     (c) Fraunhofer Institute for Solar Energy Systems,
11 rschregle 2.4 (c) Lucerne University of Applied Sciences and Arts,
12 rschregle 2.11 supported by the Swiss National Science Foundation (SNSF, #147053)
13     ======================================================================
14 greg 2.1
15 greg 2.12 $Id: pmap.c,v 2.11 2016/05/17 17:39:47 rschregle Exp $
16 greg 2.1 */
17    
18    
19    
20     #include "pmap.h"
21     #include "pmapmat.h"
22     #include "pmapsrc.h"
23     #include "pmaprand.h"
24     #include "pmapio.h"
25     #include "pmapbias.h"
26     #include "pmapdiag.h"
27     #include "otypes.h"
28     #include <time.h>
29     #include <sys/stat.h>
30 rschregle 2.11 #include <sys/mman.h>
31     #include <sys/wait.h>
32 greg 2.1
33    
34    
35     void savePmaps (const PhotonMap **pmaps, int argc, char **argv)
36     {
37     unsigned t;
38    
39     for (t = 0; t < NUM_PMAP_TYPES; t++) {
40     if (pmaps [t])
41 greg 2.7 savePhotonMap(pmaps [t], pmaps [t] -> fileName, argc, argv);
42 greg 2.1 }
43     }
44    
45    
46    
47     static int photonParticipate (RAY *ray)
48     /* Trace photon through participating medium. Returns 1 if passed through,
49     or 0 if absorbed and $*%&ed. Analogon to rayparticipate(). */
50     {
51     int i;
52     RREAL cosTheta, cosPhi, du, dv;
53     const float cext = colorAvg(ray -> cext),
54     albedo = colorAvg(ray -> albedo);
55     FVECT u, v;
56     COLOR cvext;
57    
58     /* Mean free distance until interaction with medium */
59     ray -> rmax = -log(pmapRandom(mediumState)) / cext;
60    
61     while (!localhit(ray, &thescene)) {
62     setcolor(cvext, exp(-ray -> rmax * ray -> cext [0]),
63     exp(-ray -> rmax * ray -> cext [1]),
64     exp(-ray -> rmax * ray -> cext [2]));
65    
66     /* Modify ray color and normalise */
67     multcolor(ray -> rcol, cvext);
68     colorNorm(ray -> rcol);
69     VCOPY(ray -> rorg, ray -> rop);
70    
71 rschregle 2.11 if (albedo > FTINY && ray -> rlvl > 0)
72 greg 2.1 /* Add to volume photon map */
73 rschregle 2.11 newPhoton(volumePmap, ray);
74 greg 2.1
75     /* Absorbed? */
76 rschregle 2.11 if (pmapRandom(rouletteState) > albedo)
77     return 0;
78 greg 2.1
79     /* Colour bleeding without attenuation (?) */
80     multcolor(ray -> rcol, ray -> albedo);
81     scalecolor(ray -> rcol, 1 / albedo);
82    
83     /* Scatter photon */
84     cosTheta = ray -> gecc <= FTINY ? 2 * pmapRandom(scatterState) - 1
85     : 1 / (2 * ray -> gecc) *
86     (1 + ray -> gecc * ray -> gecc -
87     (1 - ray -> gecc * ray -> gecc) /
88     (1 - ray -> gecc + 2 * ray -> gecc *
89     pmapRandom(scatterState)));
90    
91     cosPhi = cos(2 * PI * pmapRandom(scatterState));
92     du = dv = sqrt(1 - cosTheta * cosTheta); /* sin(theta) */
93     du *= cosPhi;
94     dv *= sqrt(1 - cosPhi * cosPhi); /* sin(phi) */
95    
96     /* Get axes u & v perpendicular to photon direction */
97     i = 0;
98     do {
99     v [0] = v [1] = v [2] = 0;
100     v [i++] = 1;
101     fcross(u, v, ray -> rdir);
102     } while (normalize(u) < FTINY);
103     fcross(v, ray -> rdir, u);
104    
105     for (i = 0; i < 3; i++)
106     ray -> rdir [i] = du * u [i] + dv * v [i] +
107     cosTheta * ray -> rdir [i];
108     ray -> rlvl++;
109     ray -> rmax = -log(pmapRandom(mediumState)) / cext;
110     }
111    
112     setcolor(cvext, exp(-ray -> rot * ray -> cext [0]),
113     exp(-ray -> rot * ray -> cext [1]),
114     exp(-ray -> rot * ray -> cext [2]));
115    
116     /* Modify ray color and normalise */
117     multcolor(ray -> rcol, cvext);
118     colorNorm(ray -> rcol);
119    
120     /* Passed through medium */
121     return 1;
122     }
123    
124    
125    
126     void tracePhoton (RAY *ray)
127     /* Follow photon as it bounces around... */
128     {
129     long mod;
130     OBJREC* mat;
131    
132     if (ray -> rlvl > photonMaxBounce) {
133 rschregle 2.5 #ifdef PMAP_RUNAWAY_WARN
134 greg 2.1 error(WARNING, "runaway photon!");
135 rschregle 2.5 #endif
136 greg 2.1 return;
137     }
138 rschregle 2.5
139 greg 2.1 if (colorAvg(ray -> cext) > FTINY && !photonParticipate(ray))
140     return;
141    
142     if (localhit(ray, &thescene)) {
143     mod = ray -> ro -> omod;
144    
145     if ((ray -> clipset && inset(ray -> clipset, mod)) || mod == OVOID) {
146     /* Transfer ray if modifier is VOID or clipped within antimatta */
147     RAY tray;
148     photonRay(ray, &tray, PMAP_XFER, NULL);
149     tracePhoton(&tray);
150     }
151     else {
152     /* Scatter for modifier material */
153     mat = objptr(mod);
154     photonScatter [mat -> otype] (mat, ray);
155     }
156     }
157     }
158    
159    
160    
161     static void preComputeGlobal (PhotonMap *pmap)
162 rschregle 2.11 /* Precompute irradiance from global photons for final gathering for
163     a random subset of finalGather * pmap -> numPhotons photons, and builds
164     the photon map, discarding the original photons. */
165     /* !!! NOTE: PRECOMPUTATION WITH OOC CURRENTLY WITHOUT CACHE !!! */
166     {
167     unsigned long i, numPreComp;
168     unsigned j;
169     PhotonIdx pIdx;
170     Photon photon;
171     RAY ray;
172     PhotonMap nuPmap;
173 greg 2.1
174 rschregle 2.11 repComplete = numPreComp = finalGather * pmap -> numPhotons;
175 greg 2.1
176     if (photonRepTime) {
177 rschregle 2.11 sprintf(errmsg, "Precomputing irradiance for %ld global photons...\n",
178     numPreComp);
179 greg 2.1 eputs(errmsg);
180     fflush(stderr);
181     }
182    
183 rschregle 2.11 /* Copy photon map for precomputed photons */
184     memcpy(&nuPmap, pmap, sizeof(PhotonMap));
185    
186     /* Zero counters, init new heap and extents */
187     nuPmap.numPhotons = 0;
188     initPhotonHeap(&nuPmap);
189    
190     for (j = 0; j < 3; j++) {
191     nuPmap.minPos [j] = FHUGE;
192     nuPmap.maxPos [j] = -FHUGE;
193 greg 2.1 }
194 rschregle 2.11
195 greg 2.1 /* Record start time, baby */
196     repStartTime = time(NULL);
197 rschregle 2.11 #ifdef SIGCONT
198     signal(SIGCONT, pmapPreCompReport);
199     #endif
200 greg 2.1 repProgress = 0;
201    
202 rschregle 2.11 photonRay(NULL, &ray, PRIMARY, NULL);
203     ray.ro = NULL;
204    
205     for (i = 0; i < numPreComp; i++) {
206     /* Get random photon from stratified distribution in source heap to
207     * avoid duplicates and clutering */
208     pIdx = firstPhoton(pmap) +
209     (unsigned long)((i + pmapRandom(pmap -> randState)) /
210     finalGather);
211     getPhoton(pmap, pIdx, &photon);
212    
213     /* Init dummy photon ray with intersection at photon position */
214     VCOPY(ray.rop, photon.pos);
215     for (j = 0; j < 3; j++)
216     ray.ron [j] = photon.norm [j] / 127.0;
217    
218     /* Get density estimate at photon position */
219     photonDensity(pmap, &ray, ray.rcol);
220    
221     /* Append photon to new heap from ray */
222     newPhoton(&nuPmap, &ray);
223 greg 2.1
224 rschregle 2.11 /* Update progress */
225 greg 2.1 repProgress++;
226    
227     if (photonRepTime > 0 && time(NULL) >= repLastTime + photonRepTime)
228     pmapPreCompReport();
229 rschregle 2.11 #ifdef SIGCONT
230     else signal(SIGCONT, pmapPreCompReport);
231     #endif
232 greg 2.1 }
233    
234 rschregle 2.11 /* Flush heap */
235     flushPhotonHeap(&nuPmap);
236    
237     #ifdef SIGCONT
238     signal(SIGCONT, SIG_DFL);
239     #endif
240    
241     /* Trash original pmap, replace with precomputed one */
242     deletePhotons(pmap);
243     memcpy(pmap, &nuPmap, sizeof(PhotonMap));
244 greg 2.1
245     if (photonRepTime) {
246 rschregle 2.11 eputs("Rebuilding precomputed photon map...\n");
247 greg 2.1 fflush(stderr);
248     }
249 rschregle 2.11
250     /* Rebuild underlying data structure, destroying heap */
251     buildPhotonMap(pmap, NULL, NULL, 1);
252 greg 2.1 }
253    
254    
255    
256 rschregle 2.11 typedef struct {
257     unsigned long numPhotons [NUM_PMAP_TYPES],
258     numEmitted, numComplete;
259     } PhotonCnt;
260    
261    
262    
263     void distribPhotons (PhotonMap **pmaps, unsigned numProc)
264     {
265     EmissionMap emap;
266     char errmsg2 [128], shmFname [255];
267     unsigned t, srcIdx, proc;
268     double totalFlux = 0;
269     int shmFile, stat, pid;
270     PhotonMap *pm;
271     PhotonCnt *photonCnt;
272 greg 2.1
273 rschregle 2.8 for (t = 0; t < NUM_PMAP_TYPES && !pmaps [t]; t++);
274 rschregle 2.11
275 greg 2.1 if (t >= NUM_PMAP_TYPES)
276 rschregle 2.11 error(USER, "no photon maps defined in distribPhotons");
277 greg 2.1
278     if (!nsources)
279 rschregle 2.11 error(USER, "no light sources in distribPhotons");
280 greg 2.1
281     /* ===================================================================
282     * INITIALISATION - Set up emission and scattering funcs
283     * =================================================================== */
284     emap.samples = NULL;
285     emap.maxPartitions = MAXSPART;
286     emap.partitions = (unsigned char*)malloc(emap.maxPartitions >> 1);
287     if (!emap.partitions)
288 rschregle 2.11 error(INTERNAL, "can't allocate source partitions in distribPhotons");
289 greg 2.1
290     /* Initialise all defined photon maps */
291     for (t = 0; t < NUM_PMAP_TYPES; t++)
292 rschregle 2.11 if (pmaps [t]) {
293     initPhotonMap(pmaps [t], t);
294     /* Open photon heapfile */
295     initPhotonHeap(pmaps [t]);
296     /* Per-subprocess target count */
297     pmaps [t] -> distribTarget /= numProc;
298     }
299 greg 2.1
300     initPhotonEmissionFuncs();
301     initPhotonScatterFuncs();
302    
303     /* Get photon ports if specified */
304     if (ambincl == 1)
305     getPhotonPorts();
306    
307     /* Get photon sensor modifiers */
308     getPhotonSensors(photonSensorList);
309    
310 rschregle 2.11 /* Set up shared mem for photon counters (zeroed by ftruncate) */
311     #if 0
312     snprintf(shmFname, 255, PMAP_SHMFNAME, getpid());
313     shmFile = shm_open(shmFname, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR);
314     #else
315     strcpy(shmFname, PMAP_SHMFNAME);
316     shmFile = mkstemp(shmFname);
317     #endif
318    
319     if (shmFile < 0)
320     error(SYSTEM, "failed opening shared memory file in distribPhotons");
321    
322     if (ftruncate(shmFile, sizeof(*photonCnt)) < 0)
323     error(SYSTEM, "failed setting shared memory size in distribPhotons");
324    
325     photonCnt = mmap(NULL, sizeof(*photonCnt), PROT_READ | PROT_WRITE,
326     MAP_SHARED, shmFile, 0);
327    
328     if (photonCnt == MAP_FAILED)
329     error(SYSTEM, "failed mapping shared memory in distribPhotons");
330    
331 greg 2.1 if (photonRepTime)
332     eputs("\n");
333    
334     /* ===================================================================
335     * FLUX INTEGRATION - Get total photon flux from light sources
336     * =================================================================== */
337 rschregle 2.11 for (srcIdx = 0; srcIdx < nsources; srcIdx++) {
338 greg 2.1 unsigned portCnt = 0;
339     emap.src = source + srcIdx;
340    
341 rschregle 2.11 do { /* Need at least one iteration if no ports! */
342 greg 2.1 emap.port = emap.src -> sflags & SDISTANT ? photonPorts + portCnt
343     : NULL;
344     photonPartition [emap.src -> so -> otype] (&emap);
345    
346     if (photonRepTime) {
347     sprintf(errmsg, "Integrating flux from source %s ",
348     source [srcIdx].so -> oname);
349    
350     if (emap.port) {
351     sprintf(errmsg2, "via port %s ",
352     photonPorts [portCnt].so -> oname);
353     strcat(errmsg, errmsg2);
354     }
355    
356     sprintf(errmsg2, "(%lu partitions)...\n", emap.numPartitions);
357     strcat(errmsg, errmsg2);
358     eputs(errmsg);
359     fflush(stderr);
360     }
361    
362     for (emap.partitionCnt = 0; emap.partitionCnt < emap.numPartitions;
363     emap.partitionCnt++) {
364     initPhotonEmission(&emap, pdfSamples);
365     totalFlux += colorAvg(emap.partFlux);
366     }
367    
368     portCnt++;
369     } while (portCnt < numPhotonPorts);
370     }
371    
372     if (totalFlux < FTINY)
373     error(USER, "zero flux from light sources");
374    
375 rschregle 2.11 /* MAIN LOOP */
376     for (proc = 0; proc < numProc; proc++) {
377     if (!(pid = fork())) {
378     /* SUBPROCESS ENTERS HERE.
379     All opened and memory mapped files are inherited */
380     unsigned passCnt = 0, prePassCnt = 0;
381     unsigned long lastNumPhotons [NUM_PMAP_TYPES];
382     unsigned long localNumEmitted = 0; /* Num photons emitted by this
383     subprocess alone */
384 greg 2.1
385 rschregle 2.11 /* Seed RNGs from PID for decorellated photon distribution */
386     pmapSeed(randSeed + proc, partState);
387     pmapSeed(randSeed + proc, emitState);
388     pmapSeed(randSeed + proc, cntState);
389     pmapSeed(randSeed + proc, mediumState);
390     pmapSeed(randSeed + proc, scatterState);
391     pmapSeed(randSeed + proc, rouletteState);
392 greg 2.1
393     for (t = 0; t < NUM_PMAP_TYPES; t++)
394 rschregle 2.11 lastNumPhotons [t] = 0;
395    
396     /* =============================================================
397     * 2-PASS PHOTON DISTRIBUTION
398     * Pass 1 (pre): emit fraction of target photon count
399     * Pass 2 (main): based on outcome of pass 1, estimate remaining
400     * number of photons to emit to approximate target
401     * count
402     * ============================================================= */
403 greg 2.1 do {
404 rschregle 2.11 double numEmit;
405 greg 2.1
406 rschregle 2.11 if (!passCnt) {
407     /* INIT PASS 1 */
408     /* Skip if no photons contributed after sufficient
409     * iterations; make it clear to user which photon maps are
410     * missing so (s)he can check geometry and materials */
411     if (++prePassCnt > maxPreDistrib) {
412     sprintf(errmsg,
413     "proc %d, source %s: too many prepasses",
414     proc, source [srcIdx].so -> oname);
415    
416     for (t = 0; t < NUM_PMAP_TYPES; t++)
417     if (pmaps [t] && !pmaps [t] -> numPhotons) {
418     sprintf(errmsg2, ", no %s photons stored",
419     pmapName [t]);
420     strcat(errmsg, errmsg2);
421     }
422    
423     error(USER, errmsg);
424     break;
425 greg 2.1 }
426 rschregle 2.11
427     /* Num to emit is fraction of minimum target count */
428     numEmit = FHUGE;
429 greg 2.1
430 rschregle 2.11 for (t = 0; t < NUM_PMAP_TYPES; t++)
431     if (pmaps [t])
432     numEmit = min(pmaps [t] -> distribTarget, numEmit);
433    
434     numEmit *= preDistrib;
435 greg 2.1 }
436 rschregle 2.11 else {
437     /* INIT PASS 2 */
438     /* Based on the outcome of the predistribution we can now
439     * estimate how many more photons we have to emit for each
440     * photon map to meet its respective target count. This
441     * value is clamped to 0 in case the target has already been
442     * exceeded in the pass 1. */
443     double maxDistribRatio = 0;
444    
445     /* Set the distribution ratio for each map; this indicates
446     * how many photons of each respective type are stored per
447     * emitted photon, and is used as probability for storing a
448     * photon by newPhoton(). Since this biases the photon
449     * density, newPhoton() promotes the flux of stored photons
450     * to compensate. */
451     for (t = 0; t < NUM_PMAP_TYPES; t++)
452     if ((pm = pmaps [t])) {
453     pm -> distribRatio = (double)pm -> distribTarget /
454     pm -> numPhotons - 1;
455    
456     /* Check if photon map "overflowed", i.e. exceeded its
457     * target count in the prepass; correcting the photon
458     * flux via the distribution ratio is no longer
459     * possible, as no more photons of this type will be
460     * stored, so notify the user rather than deliver
461     * incorrect results. In future we should handle this
462     * more intelligently by using the photonFlux in each
463     * photon map to individually correct the flux after
464     * distribution. */
465     if (pm -> distribRatio <= FTINY) {
466     sprintf(errmsg, "%s photon map overflow in "
467     "prepass, reduce -apD", pmapName [t]);
468     error(INTERNAL, errmsg);
469     }
470    
471     maxDistribRatio = max(pm -> distribRatio,
472     maxDistribRatio);
473     }
474 greg 2.1
475 rschregle 2.11 /* Normalise distribution ratios and calculate number of
476     * photons to emit in main pass */
477     for (t = 0; t < NUM_PMAP_TYPES; t++)
478     if ((pm = pmaps [t]))
479     pm -> distribRatio /= maxDistribRatio;
480    
481     if ((numEmit = localNumEmitted * maxDistribRatio) < FTINY)
482     /* No photons left to distribute in main pass */
483     break;
484     }
485    
486     /* Update shared completion counter for prog.report by parent */
487     photonCnt -> numComplete += numEmit;
488    
489     /* PHOTON DISTRIBUTION LOOP */
490     for (srcIdx = 0; srcIdx < nsources; srcIdx++) {
491     unsigned portCnt = 0;
492     emap.src = source + srcIdx;
493    
494     do { /* Need at least one iteration if no ports! */
495     emap.port = emap.src -> sflags & SDISTANT
496     ? photonPorts + portCnt : NULL;
497     photonPartition [emap.src -> so -> otype] (&emap);
498    
499     if (photonRepTime && !proc) {
500     if (!passCnt)
501     sprintf(errmsg, "PREPASS %d on source %s ",
502     prePassCnt, source [srcIdx].so -> oname);
503     else
504     sprintf(errmsg, "MAIN PASS on source %s ",
505     source [srcIdx].so -> oname);
506    
507     if (emap.port) {
508     sprintf(errmsg2, "via port %s ",
509     photonPorts [portCnt].so -> oname);
510     strcat(errmsg, errmsg2);
511     }
512    
513     sprintf(errmsg2, "(%lu partitions)\n",
514     emap.numPartitions);
515     strcat(errmsg, errmsg2);
516     eputs(errmsg);
517     fflush(stderr);
518     }
519 greg 2.1
520 rschregle 2.11 for (emap.partitionCnt = 0; emap.partitionCnt < emap.numPartitions;
521     emap.partitionCnt++) {
522     double partNumEmit;
523     unsigned long partEmitCnt;
524    
525     /* Get photon origin within current source partishunn
526     * and build emission map */
527     photonOrigin [emap.src -> so -> otype] (&emap);
528     initPhotonEmission(&emap, pdfSamples);
529    
530     /* Number of photons to emit from ziss partishunn --
531     * proportional to flux; photon ray weight and scalar
532     * flux are uniform (the latter only varying in RGB).
533     * */
534     partNumEmit = numEmit * colorAvg(emap.partFlux) /
535     totalFlux;
536     partEmitCnt = (unsigned long)partNumEmit;
537    
538     /* Probabilistically account for fractional photons */
539     if (pmapRandom(cntState) < partNumEmit - partEmitCnt)
540     partEmitCnt++;
541    
542     /* Update local and shared (global) emission counter */
543     photonCnt -> numEmitted += partEmitCnt;
544     localNumEmitted += partEmitCnt;
545    
546     /* Integer counter avoids FP rounding errors during
547     * iteration */
548     while (partEmitCnt--) {
549     RAY photonRay;
550    
551     /* Emit photon based on PDF and trace through scene
552     * until absorbed/leaked */
553     emitPhoton(&emap, &photonRay);
554     tracePhoton(&photonRay);
555     }
556    
557     /* Update shared global photon count for each pmap */
558     for (t = 0; t < NUM_PMAP_TYPES; t++)
559     if (pmaps [t]) {
560     photonCnt -> numPhotons [t] +=
561     pmaps [t] -> numPhotons - lastNumPhotons [t];
562     lastNumPhotons [t] = pmaps [t] -> numPhotons;
563     }
564     }
565 greg 2.1
566 rschregle 2.11 portCnt++;
567     } while (portCnt < numPhotonPorts);
568     }
569    
570     for (t = 0; t < NUM_PMAP_TYPES; t++)
571     if (pmaps [t] && !pmaps [t] -> numPhotons) {
572     /* Double preDistrib in case a photon map is empty and
573     * redo pass 1 --> possibility of infinite loop for
574     * pathological scenes (e.g. absorbing materials) */
575     preDistrib *= 2;
576     break;
577 greg 2.1 }
578 rschregle 2.11
579     if (t >= NUM_PMAP_TYPES) {
580     /* No empty photon maps found; now do pass 2 */
581     passCnt++;
582     #if 0
583     if (photonRepTime)
584     eputs("\n");
585     #endif
586 greg 2.1 }
587 rschregle 2.11 } while (passCnt < 2);
588    
589     /* Unmap shared photon counters */
590     #if 0
591     munmap(photonCnt, sizeof(*photonCnt));
592     close(shmFile);
593     #endif
594    
595     /* Flush heap buffa for every pmap one final time; this is required
596     * to prevent data corruption! */
597     for (t = 0; t < NUM_PMAP_TYPES; t++)
598     if (pmaps [t]) {
599     #if 0
600     eputs("Final flush\n");
601     #endif
602     flushPhotonHeap(pmaps [t]);
603     fclose(pmaps [t] -> heap);
604     #ifdef DEBUG_PMAP
605     sprintf(errmsg, "Proc %d: total %ld photons\n", getpid(),
606     pmaps [t] -> numPhotons);
607     eputs(errmsg);
608     #endif
609     }
610    
611     exit(0);
612 greg 2.1 }
613 rschregle 2.11 else if (pid < 0)
614     error(SYSTEM, "failed to fork subprocess in distribPhotons");
615     }
616    
617     /* PARENT PROCESS CONTINUES HERE */
618     /* Record start time and enable progress report signal handler */
619     repStartTime = time(NULL);
620     #ifdef SIGCONT
621     signal(SIGCONT, pmapDistribReport);
622     #endif
623    
624     if (photonRepTime)
625     eputs("\n");
626    
627     /* Wait for subprocesses to complete while reporting progress */
628     proc = numProc;
629     while (proc) {
630     while (waitpid(-1, &stat, WNOHANG) > 0) {
631     /* Subprocess exited; check status */
632     if (!WIFEXITED(stat) || WEXITSTATUS(stat))
633     error(USER, "failed photon distribution");
634    
635     --proc;
636     }
637    
638     /* Nod off for a bit and update progress */
639     sleep(1);
640     /* Update progress report from shared subprocess counters */
641     repEmitted = repProgress = photonCnt -> numEmitted;
642     repComplete = photonCnt -> numComplete;
643    
644 greg 2.1 for (t = 0; t < NUM_PMAP_TYPES; t++)
645 rschregle 2.11 if ((pm = pmaps [t])) {
646     #if 0
647     /* Get photon count from heapfile size for progress update */
648     fseek(pm -> heap, 0, SEEK_END);
649     pm -> numPhotons = ftell(pm -> heap) / sizeof(Photon); */
650     #else
651     /* Get global photon count from shmem updated by subprocs */
652     pm -> numPhotons = photonCnt -> numPhotons [t];
653     #endif
654 greg 2.1 }
655 rschregle 2.11
656     if (photonRepTime > 0 && time(NULL) >= repLastTime + photonRepTime)
657     pmapDistribReport();
658     #ifdef SIGCONT
659     else signal(SIGCONT, pmapDistribReport);
660     #endif
661     }
662 greg 2.1
663     /* ===================================================================
664 rschregle 2.11 * POST-DISTRIBUTION - Set photon flux and build data struct for photon
665     * storage, etc.
666 greg 2.1 * =================================================================== */
667 rschregle 2.11 #ifdef SIGCONT
668     signal(SIGCONT, SIG_DFL);
669     #endif
670 greg 2.1 free(emap.samples);
671    
672     /* Set photon flux (repProgress is total num emitted) */
673 rschregle 2.11 totalFlux /= photonCnt -> numEmitted;
674    
675     /* Photon counters no longer needed, unmap shared memory */
676     munmap(photonCnt, sizeof(*photonCnt));
677     close(shmFile);
678     #if 0
679     shm_unlink(shmFname);
680     #else
681     unlink(shmFname);
682     #endif
683 greg 2.1
684     for (t = 0; t < NUM_PMAP_TYPES; t++)
685 rschregle 2.8 if (pmaps [t]) {
686 greg 2.1 if (photonRepTime) {
687     sprintf(errmsg, "\nBuilding %s photon map...\n", pmapName [t]);
688     eputs(errmsg);
689     fflush(stderr);
690     }
691 rschregle 2.11
692     /* Build underlying data structure; heap is destroyed */
693     buildPhotonMap(pmaps [t], &totalFlux, NULL, numProc);
694 greg 2.1 }
695 rschregle 2.11
696 greg 2.1 /* Precompute photon irradiance if necessary */
697     if (preCompPmap)
698     preComputeGlobal(preCompPmap);
699     }