ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/rt/pmapcontrib.c
Revision: 2.19
Committed: Thu Nov 8 00:54:07 2018 UTC (5 years, 6 months ago) by greg
Content type: text/plain
Branch: MAIN
CVS Tags: rad5R3
Changes since 2.18: +3 -2 lines
Log Message:
Moved findmaterial() from source.c to initotypes.c

File Contents

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