ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/rt/pmapcontrib.c
Revision: 2.14
Committed: Mon Aug 14 21:12:10 2017 UTC (6 years, 9 months ago) by rschregle
Content type: text/plain
Branch: MAIN
CVS Tags: rad5R1
Changes since 2.13: +186 -100 lines
Log Message:
Updated photon map code for Windows; no multproc or ooC for now

File Contents

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