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 (6 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

# User Rev Content
1 greg 2.9 #ifndef lint
2 rschregle 2.18 static const char RCSid[] = "$Id: pmapcontrib.c,v 2.17 2018/03/20 19:55:33 rschregle 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.18 $Id: pmapcontrib.c,v 2.17 2018/03/20 19:55:33 rschregle 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 rschregle 2.15 #include <sys/wait.h>
29 rschregle 2.14 #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 rschregle 2.15
64     #ifdef PMAP_PRIMARYDIR
65 rschregle 2.12 /* 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 rschregle 2.15 #endif
71 rschregle 2.12 #ifdef PMAP_PRIMARYPOS
72     VCOPY(pmap -> lastPrimary.pos, primRay -> rop);
73     #endif
74     }
75    
76     return pmap -> numPrimary;
77     }
78    
79 greg 2.1
80    
81 rschregle 2.14 #ifdef DEBUG_PMAP
82 rschregle 2.12 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 greg 2.1
91 rschregle 2.12 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 greg 2.1 error(WARNING, errmsg);
111 rschregle 2.12 }
112 greg 2.1 }
113    
114 rschregle 2.12 return 0;
115     }
116     #endif
117    
118    
119    
120     static PhotonPrimaryIdx buildPrimaries (PhotonMap *pmap, FILE **primaryHeap,
121 rschregle 2.14 char **primaryHeapFname,
122 rschregle 2.12 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 greg 2.1
131 rschregle 2.12 if (!pmap || !primaryHeap || !primaryOfs || !numHeaps)
132     return 0;
133 greg 2.1
134 rschregle 2.12 pmap -> numPrimary = 0;
135    
136     for (heap = 0; heap < numHeaps; heap++) {
137     primaryOfs [heap] = pmap -> numPrimary;
138    
139 rschregle 2.14 if (fseek(primaryHeap [heap], 0, SEEK_END) < 0)
140 rschregle 2.12 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 greg 2.1
155 rschregle 2.14 fclose(primaryHeap [heap]);
156     unlink(primaryHeapFname [heap]);
157 rschregle 2.12 }
158    
159     return pmap -> numPrimary;
160     }
161 greg 2.6
162    
163 greg 2.7
164 rschregle 2.12 /* Defs for photon emission counter array passed by sub-processes to parent
165     * via shared memory */
166     typedef unsigned long PhotonContribCnt;
167 greg 2.7
168 rschregle 2.12 /* 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 greg 2.1
173    
174    
175 rschregle 2.16
176    
177    
178 rschregle 2.12 void distribPhotonContrib (PhotonMap* pm, unsigned numProc)
179 greg 2.1 {
180 rschregle 2.12 EmissionMap emap;
181 rschregle 2.14 char errmsg2 [128], shmFname [PMAP_TMPFNLEN];
182 rschregle 2.12 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 rschregle 2.14 unsigned photonCntSize = sizeof(PhotonContribCnt) *
188 rschregle 2.12 PHOTONCNT_NUMEMIT(nsources);
189 rschregle 2.14 FILE **primaryHeap = NULL;
190     char **primaryHeapFname = NULL;
191     PhotonPrimaryIdx *primaryOfs = NULL;
192 rschregle 2.12
193 greg 2.1 if (!pm)
194 rschregle 2.12 error(USER, "no photon map defined in distribPhotonContrib");
195 greg 2.1
196     if (!nsources)
197 rschregle 2.12 error(USER, "no light sources in distribPhotonContrib");
198    
199     if (nsources > MAXMODLIST)
200     error(USER, "too many light sources in distribPhotonContrib");
201    
202 greg 2.1 /* 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 rschregle 2.12 error(SYSTEM, "can't allocate source flux in distribPhotonContrib");
209 greg 2.1
210 rschregle 2.12 /* ===================================================================
211     * INITIALISATION - Set up emission and scattering funcs
212     * =================================================================== */
213 greg 2.1 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 rschregle 2.12 error(USER, "can't allocate source partitions in distribPhotonContrib");
219 greg 2.1
220 rschregle 2.12 /* Initialise contrib photon map */
221 greg 2.1 initPhotonMap(pm, PMAP_TYPE_CONTRIB);
222 rschregle 2.12 initPhotonHeap(pm);
223 greg 2.1 initPhotonEmissionFuncs();
224     initPhotonScatterFuncs();
225    
226 rschregle 2.12 /* Per-subprocess / per-source target counts */
227     pm -> distribTarget /= numProc;
228 rschregle 2.14 srcDistribTarget = nsources ? (double)pm -> distribTarget / nsources : 0;
229    
230     if (!pm -> distribTarget)
231     error(INTERNAL, "no photons to distribute in distribPhotonContrib");
232 rschregle 2.12
233 rschregle 2.17 /* Get photon ports from modifier list */
234     getPhotonPorts(photonPortList);
235 greg 2.1
236     /* Get photon sensor modifiers */
237     getPhotonSensors(photonSensorList);
238 rschregle 2.14
239     #if NIX
240 rschregle 2.12 /* Set up shared mem for photon counters (zeroed by ftruncate) */
241 rschregle 2.14 strcpy(shmFname, PMAP_TMPFNAME);
242 rschregle 2.12 shmFile = mkstemp(shmFname);
243    
244     if (shmFile < 0 || ftruncate(shmFile, photonCntSize) < 0)
245     error(SYSTEM, "failed shared mem init in distribPhotonContrib");
246 greg 2.1
247 rschregle 2.12 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 rschregle 2.14 #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 rschregle 2.12
273     /* =============================================================
274 rschregle 2.14 * FLUX INTEGRATION - Get total flux emitted from sources/ports
275 rschregle 2.12 * ============================================================= */
276 greg 2.1 for (srcIdx = 0; srcIdx < nsources; srcIdx++) {
277 rschregle 2.14 unsigned portCnt = 0;
278 rschregle 2.12 srcFlux [srcIdx] = 0;
279 greg 2.1 emap.src = source + srcIdx;
280    
281 rschregle 2.12 do { /* Need at least one iteration if no ports! */
282     emap.port = emap.src -> sflags & SDISTANT ? photonPorts + portCnt
283     : NULL;
284 greg 2.1 photonPartition [emap.src -> so -> otype] (&emap);
285 rschregle 2.14
286     if (verbose) {
287     sprintf(errmsg, "\tIntegrating flux from source %s ",
288     source [srcIdx].so -> oname);
289    
290 greg 2.1 if (emap.port) {
291     sprintf(errmsg2, "via port %s ",
292     photonPorts [portCnt].so -> oname);
293     strcat(errmsg, errmsg2);
294     }
295 rschregle 2.14
296     sprintf(errmsg2, "(%lu partitions)\n", emap.numPartitions);
297 greg 2.1 strcat(errmsg, errmsg2);
298     eputs(errmsg);
299 rschregle 2.14 #if NIX
300 greg 2.1 fflush(stderr);
301 rschregle 2.14 #endif
302     }
303 greg 2.1
304 rschregle 2.12 for (emap.partitionCnt = 0; emap.partitionCnt < emap.numPartitions;
305 greg 2.1 emap.partitionCnt++) {
306     initPhotonEmission(&emap, pdfSamples);
307     srcFlux [srcIdx] += colorAvg(emap.partFlux);
308     }
309    
310     portCnt++;
311 rschregle 2.12 } while (portCnt < numPhotonPorts);
312    
313 greg 2.1 if (srcFlux [srcIdx] < FTINY) {
314     sprintf(errmsg, "source %s has zero emission",
315     source [srcIdx].so -> oname);
316     error(WARNING, errmsg);
317     }
318 rschregle 2.12 }
319 rschregle 2.14
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 rschregle 2.12
340 rschregle 2.14 /* Record start time for progress reports */
341     repStartTime = time(NULL);
342 rschregle 2.12
343 rschregle 2.14 if (verbose) {
344     sprintf(errmsg, "\nPhoton distribution @ %d procs\n", numProc);
345     eputs(errmsg);
346     }
347 rschregle 2.12
348     /* MAIN LOOP */
349     for (proc = 0; proc < numProc; proc++) {
350 rschregle 2.14 #if NIX
351 rschregle 2.12 if (!(pid = fork())) {
352 rschregle 2.14 /* SUBPROCESS ENTERS HERE; opened and mmapped files inherited */
353     #else
354     if (1) {
355     /* No subprocess under Windoze */
356     #endif
357 rschregle 2.12 /* Local photon counters for this subprocess */
358     unsigned long lastNumPhotons = 0, localNumEmitted = 0;
359 rschregle 2.14 double photonFluxSum = 0; /* Accum. photon flux */
360 rschregle 2.12
361     /* Seed RNGs from PID for decorellated photon distribution */
362     pmapSeed(randSeed + proc, partState);
363 rschregle 2.16 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 rschregle 2.18 #ifdef PMAP_SIGUSR
396 rschregle 2.16 signal(SIGUSR1, sigUsrDiags);
397     #endif
398 rschregle 2.18
399     #ifdef DEBUG_PMAP
400 rschregle 2.16 /* Output child process PID after random delay to prevent corrupted
401     * console output due to race condition */
402     usleep(1e6 * pmapRandom(rouletteState));
403 rschregle 2.18 fprintf(stderr, "Proc %d: PID = %d "
404     "(waiting 10 sec to attach debugger...)\n",
405     proc, getpid());
406 rschregle 2.16 /* Allow time for debugger to attach to child process */
407     sleep(10);
408 rschregle 2.18 #endif
409 rschregle 2.16
410 rschregle 2.12 /* =============================================================
411 greg 2.1 * 2-PASS PHOTON DISTRIBUTION
412     * Pass 1 (pre): emit fraction of target photon count
413 rschregle 2.12 * Pass 2 (main): based on outcome of pass 1, estimate remaining
414     * number of photons to emit to approximate target
415     * count
416 rschregle 2.18 * ============================================================= */
417 rschregle 2.12 for (srcIdx = 0; srcIdx < nsources; srcIdx++) {
418 rschregle 2.16 #ifndef PMAP_SIGUSR
419 rschregle 2.12 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 rschregle 2.16 #else
424     passCnt = prePassCnt = 0;
425     srcPreDistrib = preDistrib;
426     srcNumEmit = 0; /* # to emit from source */
427     srcNumDistrib = pm -> numPhotons; /* # stored */
428     #endif
429 rschregle 2.12
430     if (srcFlux [srcIdx] < FTINY)
431     continue;
432    
433     while (passCnt < 2) {
434     if (!passCnt) {
435     /* INIT PASS 1 */
436 rschregle 2.16 if (++prePassCnt > maxPreDistrib) {
437 rschregle 2.12 /* Warn if no photons contributed after sufficient
438 rschregle 2.14 * iterations; only output from subprocess 0 to reduce
439     * console clutter */
440 rschregle 2.16 if (!proc) {
441     sprintf(errmsg,
442     "source %s: too many prepasses, skipped",
443     source [srcIdx].so -> oname);
444     error(WARNING, errmsg);
445     }
446    
447 rschregle 2.12 break;
448     }
449    
450     /* Num to emit is fraction of target count */
451     srcNumEmit = srcPreDistrib * srcDistribTarget;
452 greg 2.1 }
453 rschregle 2.12 else {
454     /* INIT PASS 2 */
455 rschregle 2.16 #ifndef PMAP_SIGUSR
456 rschregle 2.12 double srcPhotonFlux, avgPhotonFlux;
457 rschregle 2.16 #endif
458 rschregle 2.12
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 greg 2.1
476 rschregle 2.12 srcPhotonFlux = srcFlux [srcIdx] / srcNumEmit;
477     avgPhotonFlux = photonFluxSum / (srcIdx + 1);
478    
479 rschregle 2.16 if (avgPhotonFlux > FTINY &&
480 rschregle 2.12 srcPhotonFlux / avgPhotonFlux < FTINY) {
481     /* Skip source if its photon flux is grossly below the
482 rschregle 2.14 * running average, indicating negligible contributions
483     * at the expense of excessive distribution time; only
484     * output from subproc 0 to reduce console clutter */
485 rschregle 2.16 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 greg 2.1 }
494 rschregle 2.12
495     /* Update sum of photon flux per light source */
496     photonFluxSum += srcPhotonFlux;
497 greg 2.1 }
498 rschregle 2.14
499 rschregle 2.12 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 rschregle 2.14
506     if (verbose && !proc) {
507     /* Output from subproc 0 only to avoid race condition
508     * on console I/O */
509 rschregle 2.12 if (!passCnt)
510 rschregle 2.14 sprintf(errmsg, "\tPREPASS %d on source %s ",
511     prePassCnt, source [srcIdx].so -> oname);
512 rschregle 2.12 else
513 rschregle 2.14 sprintf(errmsg, "\tMAIN PASS on source %s ",
514     source [srcIdx].so -> oname);
515    
516 rschregle 2.12 if (emap.port) {
517     sprintf(errmsg2, "via port %s ",
518     photonPorts [portCnt].so -> oname);
519     strcat(errmsg, errmsg2);
520     }
521 rschregle 2.14
522 rschregle 2.12 sprintf(errmsg2, "(%lu partitions)\n",
523     emap.numPartitions);
524 rschregle 2.14 strcat(errmsg, errmsg2);
525 rschregle 2.12 eputs(errmsg);
526 rschregle 2.14 #if NIX
527 rschregle 2.12 fflush(stderr);
528 rschregle 2.14 #endif
529     }
530 greg 2.1
531 rschregle 2.12 for (emap.partitionCnt = 0; emap.partitionCnt < emap.numPartitions;
532     emap.partitionCnt++) {
533 rschregle 2.16 #ifndef PMAP_SIGUSR
534 rschregle 2.12 double partNumEmit;
535     unsigned long partEmitCnt;
536 rschregle 2.16 #endif
537 greg 2.1
538 rschregle 2.12 /* 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 rschregle 2.14 photonCnt [PHOTONCNT_NUMEMIT(srcIdx)] += partEmitCnt;
556 rschregle 2.12 localNumEmitted += partEmitCnt;
557    
558 rschregle 2.14 /* Integer counter avoids FP rounding errors during
559     * iteration */
560 rschregle 2.12 while (partEmitCnt--) {
561     RAY photonRay;
562 greg 2.1
563 rschregle 2.12 /* 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 rschregle 2.14 #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 rschregle 2.12 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 greg 2.1
585 rschregle 2.12 /* Update shared global photon count */
586     photonCnt [PHOTONCNT_NUMPHOT] += pm -> numPhotons -
587     lastNumPhotons;
588     lastNumPhotons = pm -> numPhotons;
589 rschregle 2.14 #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 greg 2.1 }
604 rschregle 2.12
605     portCnt++;
606     } while (portCnt < numPhotonPorts);
607    
608 rschregle 2.14 if (pm -> numPhotons == srcNumDistrib) {
609 rschregle 2.12 /* Double predistrib factor in case no photons were stored
610     * for this source and redo pass 1 */
611     srcPreDistrib *= 2;
612 rschregle 2.14 }
613 rschregle 2.12 else {
614     /* Now do pass 2 */
615     passCnt++;
616 greg 2.1 }
617     }
618 rschregle 2.12 }
619    
620     /* Flush heap buffa one final time to prevent data corruption */
621 rschregle 2.14 flushPhotonHeap(pm);
622 rschregle 2.12 /* Flush final photon primary to primary heap file */
623     newPhotonPrimary(pm, NULL, primaryHeap [proc]);
624 rschregle 2.14 /* Heap files closed automatically on exit
625     fclose(pm -> heap);
626     fclose(primaryHeap [proc]); */
627 rschregle 2.12
628     #ifdef DEBUG_PMAP
629 rschregle 2.14 sprintf(errmsg, "Proc %d total %ld photons\n", proc,
630 rschregle 2.12 pm -> numPhotons);
631     eputs(errmsg);
632 rschregle 2.14 fflush(stderr);
633 rschregle 2.12 #endif
634    
635 rschregle 2.16 #ifdef PMAP_SIGUSR
636     signal(SIGUSR1, SIG_DFL);
637     #endif
638    
639 rschregle 2.14 #if NIX
640     /* Terminate subprocess */
641 rschregle 2.12 exit(0);
642 rschregle 2.14 #endif
643 greg 2.1 }
644 rschregle 2.12 else if (pid < 0)
645     error(SYSTEM, "failed to fork subprocess in distribPhotonContrib");
646     }
647    
648 rschregle 2.14 #if NIX
649 rschregle 2.12 /* PARENT PROCESS CONTINUES HERE */
650     #ifdef SIGCONT
651 rschregle 2.14 /* Enable progress report signal handler */
652 rschregle 2.12 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 rschregle 2.14
668     /* Asynchronous progress report from shared subprocess counters */
669     repComplete = pm -> distribTarget * numProc;
670     repProgress = photonCnt [PHOTONCNT_NUMPHOT];
671 rschregle 2.12
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 greg 2.1 }
684 rschregle 2.14 #endif /* NIX */
685 greg 2.1
686     /* ================================================================
687     * POST-DISTRIBUTION - Set photon flux and build kd-tree, etc.
688     * ================================================================ */
689 rschregle 2.12 #ifdef SIGCONT
690 rschregle 2.14 /* Reset signal handler */
691 rschregle 2.12 signal(SIGCONT, SIG_DFL);
692     #endif
693 greg 2.1 free(emap.samples);
694    
695 rschregle 2.12 if (!pm -> numPhotons)
696 rschregle 2.14 error(USER, "empty contribution photon map");
697 greg 2.1
698 rschregle 2.12 /* Load per-subprocess primary rays into pm -> primary array */
699 rschregle 2.14 /* Dumb compilers apparently need the char** cast */
700     pm -> numPrimary = buildPrimaries(pm, primaryHeap,
701     (char**)primaryHeapFname,
702     primaryOfs, numProc);
703 rschregle 2.12 if (!pm -> numPrimary)
704 greg 2.1 error(INTERNAL, "no primary rays in contribution photon map");
705 rschregle 2.12
706     /* Set photon flux per source */
707     for (srcIdx = 0; srcIdx < nsources; srcIdx++)
708     srcFlux [srcIdx] /= photonCnt [PHOTONCNT_NUMEMIT(srcIdx)];
709 rschregle 2.14 #if NIX
710 rschregle 2.12 /* Photon counters no longer needed, unmap shared memory */
711     munmap(photonCnt, sizeof(*photonCnt));
712     close(shmFile);
713 rschregle 2.14 unlink(shmFname);
714 rschregle 2.12 #else
715 rschregle 2.14 free(photonCnt);
716 rschregle 2.12 #endif
717 greg 2.1
718 rschregle 2.14 if (verbose) {
719     eputs("\nBuilding contribution photon map...\n");
720     #if NIX
721 greg 2.1 fflush(stderr);
722 rschregle 2.14 #endif
723 greg 2.1 }
724 rschregle 2.12
725     /* Build underlying data structure; heap is destroyed */
726 rschregle 2.14 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 rschregle 2.12 }