ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/rt/pmapcontrib.c
(Generate patch)

Comparing ray/src/rt/pmapcontrib.c (file contents):
Revision 2.13 by greg, Thu Sep 29 21:51:58 2016 UTC vs.
Revision 2.14 by rschregle, Mon Aug 14 21:12:10 2017 UTC

# Line 4 | Line 4 | static const char RCSid[] = "$Id$";
4  
5   /*
6     ======================================================================
7 <   Photon map support for building light source contributions
7 >   Photon map for light source contributions
8  
9     Roland Schregle (roland.schregle@{hslu.ch, gmail.com})
10     (c) Lucerne University of Applied Sciences and Arts,
# Line 23 | Line 23 | static const char RCSid[] = "$Id$";
23   #include "pmapdiag.h"
24   #include "rcontrib.h"
25   #include "otypes.h"
26 < #include <sys/mman.h>
27 < #include <sys/wait.h>
26 > #if NIX
27 >   #include <sys/mman.h>
28 >   #include <sys/wait.h>
29 > #endif
30  
31  
30
32   static PhotonPrimaryIdx newPhotonPrimary (PhotonMap *pmap,
33                                            const RAY *primRay,
34                                            FILE *primHeap)
# Line 42 | Line 43 | static PhotonPrimaryIdx newPhotonPrimary (PhotonMap *p
43        return 0;
44        
45     /* Check if last primary ray has spawned photons (srcIdx >= 0, see
46 <    * newPhoton()), in which case we write it to the primary heap file
47 <    * before overwriting it */
46 >    * newPhoton()), in which case we save it to the primary heap file
47 >    * before clobbering it */
48     if (pmap -> lastPrimary.srcIdx >= 0) {
49        if (!fwrite(&pmap -> lastPrimary, sizeof(PhotonPrimary), 1, primHeap))
50           error(SYSTEM, "failed writing photon primary in newPhotonPrimary");
# Line 75 | Line 76 | static PhotonPrimaryIdx newPhotonPrimary (PhotonMap *p
76  
77  
78  
79 < #ifdef DEBUG_PMAP_CONTRIB
79 > #ifdef DEBUG_PMAP
80   static int checkPrimaryHeap (FILE *file)
81   /* Check heap for ordered primaries */
82   {
# Line 115 | Line 116 | static int checkPrimaryHeap (FILE *file)
116  
117  
118   static PhotonPrimaryIdx buildPrimaries (PhotonMap *pmap, FILE **primaryHeap,
119 +                                        char **primaryHeapFname,
120                                          PhotonPrimaryIdx *primaryOfs,
121                                          unsigned numHeaps)
122   /* Consolidate per-subprocess photon primary heaps into the primary array
# Line 132 | Line 134 | static PhotonPrimaryIdx buildPrimaries (PhotonMap *pma
134     for (heap = 0; heap < numHeaps; heap++) {
135        primaryOfs [heap] = pmap -> numPrimary;
136        
137 <      if (fseek(primaryHeap [heap], 0, SEEK_END))
137 >      if (fseek(primaryHeap [heap], 0, SEEK_END) < 0)
138           error(SYSTEM, "failed photon primary seek in buildPrimaries");
139        pmap -> numPrimary += heapLen = ftell(primaryHeap [heap]) /
140                                        sizeof(PhotonPrimary);      
# Line 148 | Line 150 | static PhotonPrimaryIdx buildPrimaries (PhotonMap *pma
150                  heapLen, primaryHeap [heap]) != heapLen)
151           error(SYSTEM, "failed reading photon primaries in buildPrimaries");
152        
153 <      fclose(primaryHeap [heap]);      
153 >      fclose(primaryHeap [heap]);
154 >      unlink(primaryHeapFname [heap]);
155     }
156    
157     return pmap -> numPrimary;
# Line 170 | Line 173 | typedef  unsigned long  PhotonContribCnt;
173   void distribPhotonContrib (PhotonMap* pm, unsigned numProc)
174   {
175     EmissionMap       emap;
176 <   char              errmsg2 [128], shmFname [255];
176 >   char              errmsg2 [128], shmFname [PMAP_TMPFNLEN];
177     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 <   const unsigned    photonCntSize = sizeof(PhotonContribCnt) *
182 >   unsigned          photonCntSize = sizeof(PhotonContribCnt) *
183                                       PHOTONCNT_NUMEMIT(nsources);
184 <   FILE              *primaryHeap [numProc];
185 <   PhotonPrimaryIdx  primaryOfs [numProc];
184 >   FILE              **primaryHeap = NULL;
185 >   char              **primaryHeapFname = NULL;
186 >   PhotonPrimaryIdx  *primaryOfs = NULL;
187                                      
188     if (!pm)
189        error(USER, "no photon map defined in distribPhotonContrib");
# Line 216 | Line 220 | void distribPhotonContrib (PhotonMap* pm, unsigned num
220    
221     /* Per-subprocess / per-source target counts */
222     pm -> distribTarget /= numProc;
223 <   srcDistribTarget = nsources ? (double)pm -> distribTarget / nsources : 0;
223 >   srcDistribTarget = nsources ? (double)pm -> distribTarget / nsources : 0;  
224    
225 +   if (!pm -> distribTarget)
226 +      error(INTERNAL, "no photons to distribute in distribPhotonContrib");
227 +  
228     /* Get photon ports if specified */
229     if (ambincl == 1)
230        getPhotonPorts();
231        
232     /* Get photon sensor modifiers */
233     getPhotonSensors(photonSensorList);      
234 <  
234 >
235 > #if NIX  
236     /* Set up shared mem for photon counters (zeroed by ftruncate) */
237 < #if 0  
230 <   snprintf(shmFname, 255, PMAP_SHMFNAME, getpid());
231 <   shmFile = shm_open(shmFname, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR);
232 < #else
233 <   strcpy(shmFname, PMAP_SHMFNAME);
237 >   strcpy(shmFname, PMAP_TMPFNAME);
238     shmFile = mkstemp(shmFname);
235 #endif        
239    
240     if (shmFile < 0 || ftruncate(shmFile, photonCntSize) < 0)
241        error(SYSTEM, "failed shared mem init in distribPhotonContrib");
# Line 242 | Line 245 | void distribPhotonContrib (PhotonMap* pm, unsigned num
245                      
246     if (photonCnt == MAP_FAILED)
247        error(SYSTEM, "failed shared mem mapping in distribPhotonContrib");
248 + #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 +
269     /* =============================================================
270 <    * FLUX INTEGRATION - Get total flux emitted from light source
270 >    * FLUX INTEGRATION - Get total flux emitted from sources/ports
271      * ============================================================= */  
272     for (srcIdx = 0; srcIdx < nsources; srcIdx++) {
273 <      unsigned portCnt = 0;
251 <      
273 >      unsigned portCnt = 0;      
274        srcFlux [srcIdx] = 0;
275        emap.src = source + srcIdx;
276        
255      if (photonRepTime)
256         eputs("\n");
257
277        do {  /* Need at least one iteration if no ports! */      
278           emap.port = emap.src -> sflags & SDISTANT ? photonPorts + portCnt
279                                                     : NULL;
280           photonPartition [emap.src -> so -> otype] (&emap);
281 <        
282 <         if (photonRepTime) {
283 <            sprintf(errmsg, "Integrating flux from source %s (mod %s) ",
284 <                    source [srcIdx].so -> oname,
285 <                    objptr(source [srcIdx].so -> omod) -> oname);
267 <                    
281 >
282 >         if (verbose) {
283 >            sprintf(errmsg, "\tIntegrating flux from source %s ",
284 >                    source [srcIdx].so -> oname);
285 >
286              if (emap.port) {
287                 sprintf(errmsg2, "via port %s ",
288                         photonPorts [portCnt].so -> oname);
289                 strcat(errmsg, errmsg2);
290              }
291 <            
292 <            sprintf(errmsg2, "(%lu partitions)...\n", emap.numPartitions);
291 >
292 >            sprintf(errmsg2, "(%lu partitions)\n", emap.numPartitions);
293              strcat(errmsg, errmsg2);
294              eputs(errmsg);
295 + #if NIX            
296              fflush(stderr);
297 <         }
297 > #endif            
298 >         }                    
299          
300           for (emap.partitionCnt = 0; emap.partitionCnt < emap.numPartitions;
301                emap.partitionCnt++) {
# Line 292 | Line 312 | void distribPhotonContrib (PhotonMap* pm, unsigned num
312           error(WARNING, errmsg);
313        }
314     }  
315 <
316 <   if (photonRepTime)
317 <      eputs("\n");
318 <
319 <   /* Init per-subprocess primary heap files */
320 <   for (proc = 0; proc < numProc; proc++)
321 <      if (!(primaryHeap [proc] = tmpfile()))
315 >  
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 +
336 +   /* Record start time for progress reports */
337 +   repStartTime = time(NULL);
338 +
339 +   if (verbose) {
340 +      sprintf(errmsg, "\nPhoton distribution @ %d procs\n", numProc);
341 +      eputs(errmsg);
342 +   }
343                
344     /* MAIN LOOP */
345     for (proc = 0; proc < numProc; proc++) {
346 + #if NIX          
347        if (!(pid = fork())) {
348 <         /* SUBPROCESS ENTERS HERE;
349 <          * all opened and memory mapped files are inherited */
350 <          
348 >         /* SUBPROCESS ENTERS HERE; opened and mmapped files inherited */
349 > #else
350 >      if (1) {
351 >         /* No subprocess under Windoze */
352 > #endif  
353           /* Local photon counters for this subprocess */
354           unsigned long  lastNumPhotons = 0, localNumEmitted = 0;
355 <         double         photonFluxSum = 0;   /* Running photon flux sum */
355 >         double         photonFluxSum = 0;   /* Accum. photon flux */
356  
357           /* Seed RNGs from PID for decorellated photon distribution */
358           pmapSeed(randSeed + proc, partState);
# Line 339 | Line 381 | void distribPhotonContrib (PhotonMap* pm, unsigned num
381              while (passCnt < 2) {
382                 if (!passCnt) {  
383                    /* INIT PASS 1 */
384 <                  if (++prePassCnt > maxPreDistrib) {
384 >                  if (++prePassCnt > maxPreDistrib && !proc) {
385                       /* Warn if no photons contributed after sufficient
386 <                      * iterations */
387 <                     sprintf(errmsg, "proc %d, source %s: "
388 <                             "too many prepasses, skipped",
389 <                             proc, source [srcIdx].so -> oname);
386 >                      * 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                       error(WARNING, errmsg);
392                       break;
393                    }
# Line 379 | Line 422 | void distribPhotonContrib (PhotonMap* pm, unsigned num
422                    if (avgPhotonFlux > 0 &&
423                        srcPhotonFlux / avgPhotonFlux < FTINY) {
424                       /* Skip source if its photon flux is grossly below the
425 <                      * running average, indicating negligible contribs at
426 <                      * the expense of excessive distribution time */
427 <                     sprintf(errmsg, "proc %d, source %s: "
428 <                             "itsy bitsy photon flux, skipped",
429 <                             proc, source [srcIdx].so -> oname);
425 >                      * 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                       error(WARNING, errmsg);
432                       srcNumEmit = 0;
433                    }
# Line 391 | Line 435 | void distribPhotonContrib (PhotonMap* pm, unsigned num
435                    /* Update sum of photon flux per light source */
436                    photonFluxSum += srcPhotonFlux;
437                 }
438 <              
438 >                              
439                 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 <                  
446 <                  if (photonRepTime && !proc) {
445 >
446 >                  if (verbose && !proc) {
447 >                     /* Output from subproc 0 only to avoid race condition
448 >                      * on console I/O */
449                       if (!passCnt)
450 <                        sprintf(errmsg, "PREPASS %d on source %s (mod %s) ",
451 <                                prePassCnt, source [srcIdx].so -> oname,
406 <                                objptr(source[srcIdx].so->omod) -> oname);
450 >                        sprintf(errmsg, "\tPREPASS %d on source %s ",
451 >                                prePassCnt, source [srcIdx].so -> oname);
452                       else
453 <                        sprintf(errmsg, "MAIN PASS on source %s (mod %s) ",
454 <                                source [srcIdx].so -> oname,
455 <                                objptr(source[srcIdx].so->omod) -> oname);
411 <                            
453 >                        sprintf(errmsg, "\tMAIN PASS on source %s ",
454 >                                source [srcIdx].so -> oname);
455 >
456                       if (emap.port) {
457                          sprintf(errmsg2, "via port %s ",
458                                  photonPorts [portCnt].so -> oname);
459                          strcat(errmsg, errmsg2);
460                       }
461 <                    
461 >
462                       sprintf(errmsg2, "(%lu partitions)\n",
463                               emap.numPartitions);
464 <                     strcat(errmsg, errmsg2);
464 >                     strcat(errmsg, errmsg2);                    
465                       eputs(errmsg);
466 + #if NIX                    
467                       fflush(stderr);
468 <                  }
468 > #endif                    
469 >                  }                
470                    
471                    for (emap.partitionCnt = 0; emap.partitionCnt < emap.numPartitions;
472                         emap.partitionCnt++) {
# Line 444 | Line 490 | void distribPhotonContrib (PhotonMap* pm, unsigned num
490                          partEmitCnt++;
491                          
492                       /* Update local and shared global emission counter */
447                     localNumEmitted += partEmitCnt;                                    
493                       photonCnt [PHOTONCNT_NUMEMIT(srcIdx)] += partEmitCnt;
494 +                     localNumEmitted += partEmitCnt;                                    
495                      
496 <                     /* Integer counter avoids FP rounding errors */
496 >                     /* Integer counter avoids FP rounding errors during
497 >                      * iteration */
498                       while (partEmitCnt--) {
499                          RAY photonRay;
500                      
# Line 456 | Line 503 | void distribPhotonContrib (PhotonMap* pm, unsigned num
503                           * until absorbed/leaked; emitPhoton() sets the
504                           * emitting light source index in photonRay */
505                          emitPhoton(&emap, &photonRay);
506 + #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                          newPhotonPrimary(pm, &photonRay, primaryHeap[proc]);
515                          /* Set subprocess index in photonRay for post-
516                           * distrib primary index linearisation; this is
# Line 469 | Line 524 | void distribPhotonContrib (PhotonMap* pm, unsigned num
524                       photonCnt [PHOTONCNT_NUMPHOT] += pm -> numPhotons -
525                                                        lastNumPhotons;
526                       lastNumPhotons = pm -> numPhotons;
527 + #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                    }
542  
543                    portCnt++;
544                 } while (portCnt < numPhotonPorts);                  
545  
546 <               if (pm -> numPhotons == srcNumDistrib)
546 >               if (pm -> numPhotons == srcNumDistrib) {
547                    /* Double predistrib factor in case no photons were stored
548                     * for this source and redo pass 1 */
549                    srcPreDistrib *= 2;
550 +               }
551                 else {
552                    /* Now do pass 2 */
553                    passCnt++;
484 /*                if (photonRepTime)
485                     eputs("\n"); */
554                 }
555              }
556           }
557                          
558           /* Flush heap buffa one final time to prevent data corruption */
559 <         flushPhotonHeap(pm);
492 <         fclose(pm -> heap);
493 <        
559 >         flushPhotonHeap(pm);        
560           /* Flush final photon primary to primary heap file */
561           newPhotonPrimary(pm, NULL, primaryHeap [proc]);
562 <         fclose(primaryHeap [proc]);
562 >         /* Heap files closed automatically on exit
563 >            fclose(pm -> heap);
564 >            fclose(primaryHeap [proc]); */
565                    
566   #ifdef DEBUG_PMAP
567 <         sprintf(errmsg, "Proc %d exited with total %ld photons\n", proc,
567 >         sprintf(errmsg, "Proc %d total %ld photons\n", proc,
568                   pm -> numPhotons);
569           eputs(errmsg);
570 +         fflush(stderr);
571   #endif
572  
573 + #if NIX
574 +         /* Terminate subprocess */
575           exit(0);
576 + #endif
577        }
578        else if (pid < 0)
579           error(SYSTEM, "failed to fork subprocess in distribPhotonContrib");
580     }
581  
582 + #if NIX
583     /* PARENT PROCESS CONTINUES HERE */
511   /* Record start time and enable progress report signal handler */
512   repStartTime = time(NULL);
584   #ifdef SIGCONT
585 +   /* Enable progress report signal handler */
586     signal(SIGCONT, pmapDistribReport);
587   #endif
516 /*
517   if (photonRepTime)
518      eputs("\n"); */
519  
588     /* Wait for subprocesses to complete while reporting progress */
589     proc = numProc;
590     while (proc) {
# Line 530 | Line 598 | void distribPhotonContrib (PhotonMap* pm, unsigned num
598        
599        /* Nod off for a bit and update progress  */
600        sleep(1);
601 <      
602 <      /* Update progress report from shared subprocess counters */
601 >
602 >      /* Asynchronous progress report from shared subprocess counters */      
603        repComplete = pm -> distribTarget * numProc;
604 <      repProgress = photonCnt [PHOTONCNT_NUMPHOT];
604 >      repProgress = photonCnt [PHOTONCNT_NUMPHOT];      
605 >      
606        for (repEmitted = 0, srcIdx = 0; srcIdx < nsources; srcIdx++)
607           repEmitted += photonCnt [PHOTONCNT_NUMEMIT(srcIdx)];
608  
# Line 546 | Line 615 | void distribPhotonContrib (PhotonMap* pm, unsigned num
615        else signal(SIGCONT, pmapDistribReport);
616   #endif
617     }
618 + #endif /* NIX */
619  
620     /* ================================================================
621      * POST-DISTRIBUTION - Set photon flux and build kd-tree, etc.
622      * ================================================================ */
623   #ifdef SIGCONT    
624 +   /* Reset signal handler */
625     signal(SIGCONT, SIG_DFL);
626   #endif  
627     free(emap.samples);
628  
629     if (!pm -> numPhotons)
630 <      error(USER, "empty photon map");
630 >      error(USER, "empty contribution photon map");
631  
632     /* Load per-subprocess primary rays into pm -> primary array */
633 <   pm -> numPrimary = buildPrimaries(pm, primaryHeap, primaryOfs, numProc);
633 >   /* Dumb compilers apparently need the char** cast */
634 >   pm -> numPrimary = buildPrimaries(pm, primaryHeap,
635 >                                     (char**)primaryHeapFname,
636 >                                     primaryOfs, numProc);
637     if (!pm -> numPrimary)
638        error(INTERNAL, "no primary rays in contribution photon map");
639    
640     /* Set photon flux per source */
641     for (srcIdx = 0; srcIdx < nsources; srcIdx++)
642        srcFlux [srcIdx] /= photonCnt [PHOTONCNT_NUMEMIT(srcIdx)];
643 <
643 > #if NIX
644     /* Photon counters no longer needed, unmap shared memory */
645     munmap(photonCnt, sizeof(*photonCnt));
646     close(shmFile);
573 #if 0  
574   shm_unlink(shmFname);
575 #else
647     unlink(shmFname);
648 + #else
649 +   free(photonCnt);  
650   #endif      
651    
652 <   if (photonRepTime) {
653 <      eputs("\nBuilding contrib photon map...\n");
652 >   if (verbose) {
653 >      eputs("\nBuilding contribution photon map...\n");
654 > #if NIX      
655        fflush(stderr);
656 + #endif      
657     }
658    
659     /* Build underlying data structure; heap is destroyed */
660 <   buildPhotonMap(pm, srcFlux, primaryOfs, numProc);  
660 >   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   }

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines