1 //============================================================================
2 //  Copyright (c) Kitware, Inc.
3 //  All rights reserved.
4 //  See LICENSE.txt for details.
5 //  This software is distributed WITHOUT ANY WARRANTY; without even
6 //  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
7 //  PURPOSE.  See the above copyright notice for more information.
8 //
9 //  Copyright 2015 National Technology & Engineering Solutions of Sandia, LLC (NTESS).
10 //  Copyright 2015 UT-Battelle, LLC.
11 //  Copyright 2015 Los Alamos National Security.
12 //
13 //  Under the terms of Contract DE-NA0003525 with NTESS,
14 //  the U.S. Government retains certain rights in this software.
15 //
16 //  Under the terms of Contract DE-AC52-06NA25396 with Los Alamos National
17 //  Laboratory (LANL), the U.S. Government retains certain rights in
18 //  this software.
19 //============================================================================
20 #include <vtkm/cont/DeviceAdapterAlgorithm.h>
21 #include <vtkm/cont/ErrorBadValue.h>
22 #include <vtkm/cont/Timer.h>
23 #include <vtkm/cont/TryExecute.h>
24 #include <vtkm/cont/internal/DeviceAdapterListHelpers.h>
25 
26 #include <vtkm/rendering/raytracing/Camera.h>
27 #include <vtkm/rendering/raytracing/CellIntersector.h>
28 #include <vtkm/rendering/raytracing/CellSampler.h>
29 #include <vtkm/rendering/raytracing/CellTables.h>
30 #include <vtkm/rendering/raytracing/MeshConnectivityBase.h>
31 #include <vtkm/rendering/raytracing/Ray.h>
32 #include <vtkm/rendering/raytracing/RayOperations.h>
33 #include <vtkm/rendering/raytracing/RayTracingTypeDefs.h>
34 #include <vtkm/rendering/raytracing/Worklets.h>
35 
36 #include <vtkm/worklet/DispatcherMapField.h>
37 #include <vtkm/worklet/DispatcherMapTopology.h>
38 #include <vtkm/worklet/WorkletMapField.h>
39 #include <vtkm/worklet/WorkletMapTopology.h>
40 
41 namespace vtkm
42 {
43 namespace rendering
44 {
45 namespace raytracing
46 {
47 namespace detail
48 {
49 template <typename FloatType>
50 template <typename Device>
Compact(vtkm::cont::ArrayHandle<FloatType> & compactedDistances,vtkm::cont::ArrayHandle<UInt8> & masks,Device)51 void RayTracking<FloatType>::Compact(vtkm::cont::ArrayHandle<FloatType>& compactedDistances,
52                                      vtkm::cont::ArrayHandle<UInt8>& masks,
53                                      Device)
54 {
55   //
56   // These distances are stored in the rays, and it has
57   // already been compacted.
58   //
59   CurrentDistance = compactedDistances;
60 
61   vtkm::cont::ArrayHandleCast<vtkm::Id, vtkm::cont::ArrayHandle<vtkm::UInt8>> castedMasks(masks);
62 
63   bool distance1IsEnter = EnterDist == &Distance1;
64 
65   vtkm::cont::ArrayHandle<FloatType> compactedDistance1;
66   vtkm::cont::DeviceAdapterAlgorithm<Device>::CopyIf(Distance1, masks, compactedDistance1);
67   Distance1 = compactedDistance1;
68 
69   vtkm::cont::ArrayHandle<FloatType> compactedDistance2;
70   vtkm::cont::DeviceAdapterAlgorithm<Device>::CopyIf(Distance2, masks, compactedDistance2);
71   Distance2 = compactedDistance2;
72 
73   vtkm::cont::ArrayHandle<vtkm::Int32> compactedExitFace;
74   vtkm::cont::DeviceAdapterAlgorithm<Device>::CopyIf(ExitFace, masks, compactedExitFace);
75   ExitFace = compactedExitFace;
76 
77   if (distance1IsEnter)
78   {
79     EnterDist = &Distance1;
80     ExitDist = &Distance2;
81   }
82   else
83   {
84     EnterDist = &Distance2;
85     ExitDist = &Distance1;
86   }
87 }
88 
89 template <typename FloatType>
90 template <typename Device>
Init(const vtkm::Id size,vtkm::cont::ArrayHandle<FloatType> & distances,Device)91 void RayTracking<FloatType>::Init(const vtkm::Id size,
92                                   vtkm::cont::ArrayHandle<FloatType>& distances,
93                                   Device)
94 {
95 
96   ExitFace.PrepareForOutput(size, Device());
97   Distance1.PrepareForOutput(size, Device());
98   Distance2.PrepareForOutput(size, Device());
99 
100   CurrentDistance = distances;
101   //
102   // Set the initial Distances
103   //
104   vtkm::worklet::DispatcherMapField<CopyAndOffset<FloatType>> resetDistancesDispatcher(
105     CopyAndOffset<FloatType>(0.0f));
106   resetDistancesDispatcher.SetDevice(Device());
107   resetDistancesDispatcher.Invoke(distances, *EnterDist);
108 
109   //
110   // Init the exit faces. This value is used to load the next cell
111   // base on the cell and face it left
112   //
113   vtkm::cont::ArrayHandleConstant<vtkm::Int32> negOne(-1, size);
114   vtkm::cont::Algorithm::Copy(Device(), negOne, ExitFace);
115 
116   vtkm::cont::ArrayHandleConstant<FloatType> negOnef(-1.f, size);
117   vtkm::cont::Algorithm::Copy(Device(), negOnef, *ExitDist);
118 }
119 
120 template <typename FloatType>
Swap()121 void RayTracking<FloatType>::Swap()
122 {
123   vtkm::cont::ArrayHandle<FloatType>* tmpPtr;
124   tmpPtr = EnterDist;
125   EnterDist = ExitDist;
126   ExitDist = tmpPtr;
127 }
128 } //namespace detail
129 
130 template <typename FloatType, typename Device>
PrintRayStatus(Ray<FloatType> & rays,Device)131 void ConnectivityTracer::PrintRayStatus(Ray<FloatType>& rays, Device)
132 {
133   vtkm::Id raysExited = RayOperations::GetStatusCount(rays, RAY_EXITED_MESH, Device());
134   vtkm::Id raysActive = RayOperations::GetStatusCount(rays, RAY_ACTIVE, Device());
135   vtkm::Id raysAbandoned = RayOperations::GetStatusCount(rays, RAY_ABANDONED, Device());
136   vtkm::Id raysExitedDom = RayOperations::GetStatusCount(rays, RAY_EXITED_DOMAIN, Device());
137   std::cout << "\r Ray Status " << std::setw(10) << std::left << " Lost " << std::setw(10)
138             << std::left << RaysLost << std::setw(10) << std::left << " Exited " << std::setw(10)
139             << std::left << raysExited << std::setw(10) << std::left << " Active " << std::setw(10)
140             << raysActive << std::setw(10) << std::left << " Abandoned " << std::setw(10)
141             << raysAbandoned << " Exited Domain " << std::setw(10) << std::left << raysExitedDom
142             << "\n";
143 }
144 
145 //
146 //  Advance Ray
147 //      After a ray leaves the mesh, we need to check to see
148 //      of the ray re-enters the mesh within this domain. This
149 //      function moves the ray forward some offset to prevent
150 //      "shadowing" and hitting the same exit point.
151 //
152 template <typename FloatType>
153 class AdvanceRay : public vtkm::worklet::WorkletMapField
154 {
155   FloatType Offset;
156 
157 public:
158   VTKM_CONT
AdvanceRay(const FloatType offset=0.00001)159   AdvanceRay(const FloatType offset = 0.00001)
160     : Offset(offset)
161   {
162   }
163   using ControlSignature = void(FieldIn<>, FieldInOut<>);
164   using ExecutionSignature = void(_1, _2);
165 
operator ()(const vtkm::UInt8 & status,FloatType & distance) const166   VTKM_EXEC inline void operator()(const vtkm::UInt8& status, FloatType& distance) const
167   {
168     if (status == RAY_EXITED_MESH)
169       distance += Offset;
170   }
171 }; //class AdvanceRay
172 
173 template <typename FloatType>
174 class LocateCell : public vtkm::worklet::WorkletMapField
175 {
176 private:
177   const MeshConnectivityBase* MeshConn;
178   CellIntersector<255> Intersector;
179 
180 public:
LocateCell(const MeshConnectivityBase * meshConn)181   LocateCell(const MeshConnectivityBase* meshConn)
182     : MeshConn(meshConn)
183   {
184   }
185 
186   using ControlSignature = void(FieldInOut<>,
187                                 WholeArrayIn<>,
188                                 FieldIn<>,
189                                 FieldInOut<>,
190                                 FieldInOut<>,
191                                 FieldInOut<>,
192                                 FieldInOut<>,
193                                 FieldIn<>);
194   using ExecutionSignature = void(_1, _2, _3, _4, _5, _6, _7, _8);
195 
196   template <typename PointPortalType>
operator ()(vtkm::Id & currentCell,PointPortalType & vertices,const vtkm::Vec<FloatType,3> & dir,FloatType & enterDistance,FloatType & exitDistance,vtkm::Int32 & enterFace,vtkm::UInt8 & rayStatus,const vtkm::Vec<FloatType,3> & origin) const197   VTKM_EXEC inline void operator()(vtkm::Id& currentCell,
198                                    PointPortalType& vertices,
199                                    const vtkm::Vec<FloatType, 3>& dir,
200                                    FloatType& enterDistance,
201                                    FloatType& exitDistance,
202                                    vtkm::Int32& enterFace,
203                                    vtkm::UInt8& rayStatus,
204                                    const vtkm::Vec<FloatType, 3>& origin) const
205   {
206     if (enterFace != -1 && rayStatus == RAY_ACTIVE)
207     {
208       currentCell = MeshConn->GetConnectingCell(currentCell, enterFace);
209       if (currentCell == -1)
210         rayStatus = RAY_EXITED_MESH;
211       enterFace = -1;
212     }
213     //This ray is dead or exited the mesh and needs re-entry
214     if (rayStatus != RAY_ACTIVE)
215     {
216       return;
217     }
218     FloatType xpoints[8];
219     FloatType ypoints[8];
220     FloatType zpoints[8];
221     vtkm::Id cellConn[8];
222     FloatType distances[6];
223 
224     const vtkm::Int32 numIndices = MeshConn->GetCellIndices(cellConn, currentCell);
225     //load local cell data
226     for (int i = 0; i < numIndices; ++i)
227     {
228       BOUNDS_CHECK(vertices, cellConn[i]);
229       vtkm::Vec<FloatType, 3> point = vtkm::Vec<FloatType, 3>(vertices.Get(cellConn[i]));
230       xpoints[i] = point[0];
231       ypoints[i] = point[1];
232       zpoints[i] = point[2];
233     }
234     const vtkm::UInt8 cellShape = MeshConn->GetCellShape(currentCell);
235     Intersector.IntersectCell(xpoints, ypoints, zpoints, dir, origin, distances, cellShape);
236 
237     CellTables tables;
238     const vtkm::Int32 numFaces = tables.FaceLookUp(tables.CellTypeLookUp(cellShape), 1);
239     //vtkm::Int32 minFace = 6;
240     vtkm::Int32 maxFace = -1;
241 
242     FloatType minDistance = static_cast<FloatType>(1e32);
243     FloatType maxDistance = static_cast<FloatType>(-1);
244     int hitCount = 0;
245     for (vtkm::Int32 i = 0; i < numFaces; ++i)
246     {
247       FloatType dist = distances[i];
248 
249       if (dist != -1)
250       {
251         hitCount++;
252         if (dist < minDistance)
253         {
254           minDistance = dist;
255           //minFace = i;
256         }
257         if (dist > maxDistance)
258         {
259           maxDistance = dist;
260           maxFace = i;
261         }
262       }
263     }
264 
265     if (maxDistance <= enterDistance || minDistance == maxDistance)
266     {
267       rayStatus = RAY_LOST;
268     }
269     else
270     {
271       enterDistance = minDistance;
272       exitDistance = maxDistance;
273       enterFace = maxFace;
274     }
275 
276   } //operator
277 };  //class LocateCell
278 
279 template <typename FloatType, typename Device>
280 class RayBumper : public vtkm::worklet::WorkletMapField
281 {
282 private:
283   using FloatTypeHandle = typename vtkm::cont::ArrayHandle<FloatType>;
284   using FloatTypePortal = typename FloatTypeHandle::template ExecutionTypes<Device>::Portal;
285   FloatTypePortal DirectionsX;
286   FloatTypePortal DirectionsY;
287   FloatTypePortal DirectionsZ;
288   const MeshConnectivityBase* MeshConn;
289   CellIntersector<255> Intersector;
290   const vtkm::UInt8 FailureStatus; // the status to assign ray if we fail to find the intersection
291 public:
RayBumper(FloatTypeHandle dirsx,FloatTypeHandle dirsy,FloatTypeHandle dirsz,const MeshConnectivityBase * meshConn,vtkm::UInt8 failureStatus=RAY_ABANDONED)292   RayBumper(FloatTypeHandle dirsx,
293             FloatTypeHandle dirsy,
294             FloatTypeHandle dirsz,
295             const MeshConnectivityBase* meshConn,
296             vtkm::UInt8 failureStatus = RAY_ABANDONED)
297     : DirectionsX(dirsx.PrepareForInPlace(Device()))
298     , DirectionsY(dirsy.PrepareForInPlace(Device()))
299     , DirectionsZ(dirsz.PrepareForInPlace(Device()))
300     , MeshConn(meshConn)
301     , FailureStatus(failureStatus)
302   {
303   }
304 
305 
306   using ControlSignature = void(FieldInOut<>,
307                                 WholeArrayIn<>,
308                                 FieldInOut<>,
309                                 FieldInOut<>,
310                                 FieldInOut<>,
311                                 FieldInOut<>,
312                                 FieldIn<>);
313   using ExecutionSignature = void(_1, _2, _3, _4, _5, WorkIndex, _6, _7);
314 
315   template <typename PointPortalType>
operator ()(vtkm::Id & currentCell,PointPortalType & vertices,FloatType & enterDistance,FloatType & exitDistance,vtkm::Int32 & enterFace,const vtkm::Id & pixelIndex,vtkm::UInt8 & rayStatus,const vtkm::Vec<FloatType,3> & origin) const316   VTKM_EXEC inline void operator()(vtkm::Id& currentCell,
317                                    PointPortalType& vertices,
318                                    FloatType& enterDistance,
319                                    FloatType& exitDistance,
320                                    vtkm::Int32& enterFace,
321                                    const vtkm::Id& pixelIndex,
322                                    vtkm::UInt8& rayStatus,
323                                    const vtkm::Vec<FloatType, 3>& origin) const
324   {
325     // We only process lost rays
326     if (rayStatus != RAY_LOST)
327     {
328       return;
329     }
330 
331     FloatType xpoints[8];
332     FloatType ypoints[8];
333     FloatType zpoints[8];
334     vtkm::Id cellConn[8];
335     FloatType distances[6];
336 
337     vtkm::Vec<FloatType, 3> centroid(0., 0., 0.);
338 
339     const vtkm::Int32 numIndices = MeshConn->GetCellIndices(cellConn, currentCell);
340     //load local cell data
341     for (int i = 0; i < numIndices; ++i)
342     {
343       BOUNDS_CHECK(vertices, cellConn[i]);
344       vtkm::Vec<FloatType, 3> point = vtkm::Vec<FloatType, 3>(vertices.Get(cellConn[i]));
345       centroid = centroid + point;
346       xpoints[i] = point[0];
347       ypoints[i] = point[1];
348       zpoints[i] = point[2];
349     }
350 
351     FloatType invNumIndices = static_cast<FloatType>(1.) / static_cast<FloatType>(numIndices);
352     centroid[0] = centroid[0] * invNumIndices;
353     centroid[1] = centroid[1] * invNumIndices;
354     centroid[2] = centroid[2] * invNumIndices;
355 
356     vtkm::Vec<FloatType, 3> toCentroid = centroid - origin;
357     vtkm::Normalize(toCentroid);
358 
359     vtkm::Vec<FloatType, 3> dir(
360       DirectionsX.Get(pixelIndex), DirectionsY.Get(pixelIndex), DirectionsZ.Get(pixelIndex));
361     vtkm::Vec<FloatType, 3> bump = toCentroid - dir;
362     dir = dir + RAY_TUG_EPSILON * bump;
363 
364     vtkm::Normalize(dir);
365 
366     DirectionsX.Set(pixelIndex, dir[0]);
367     DirectionsY.Set(pixelIndex, dir[1]);
368     DirectionsZ.Set(pixelIndex, dir[2]);
369 
370     const vtkm::UInt8 cellShape = MeshConn->GetCellShape(currentCell);
371     Intersector.IntersectCell(xpoints, ypoints, zpoints, dir, origin, distances, cellShape);
372 
373     CellTables tables;
374     const vtkm::Int32 numFaces = tables.FaceLookUp(tables.CellTypeLookUp(cellShape), 1);
375 
376     //vtkm::Int32 minFace = 6;
377     vtkm::Int32 maxFace = -1;
378     FloatType minDistance = static_cast<FloatType>(1e32);
379     FloatType maxDistance = static_cast<FloatType>(-1);
380     int hitCount = 0;
381     for (int i = 0; i < numFaces; ++i)
382     {
383       FloatType dist = distances[i];
384 
385       if (dist != -1)
386       {
387         hitCount++;
388         if (dist < minDistance)
389         {
390           minDistance = dist;
391           //minFace = i;
392         }
393         if (dist >= maxDistance)
394         {
395           maxDistance = dist;
396           maxFace = i;
397         }
398       }
399     }
400     if (minDistance >= maxDistance)
401     {
402       rayStatus = FailureStatus;
403     }
404     else
405     {
406       enterDistance = minDistance;
407       exitDistance = maxDistance;
408       enterFace = maxFace;
409       rayStatus = RAY_ACTIVE; //re-activate ray
410     }
411 
412   } //operator
413 };  //class RayBumper
414 
415 template <typename FloatType>
416 class AddPathLengths : public vtkm::worklet::WorkletMapField
417 {
418 public:
419   VTKM_CONT
AddPathLengths()420   AddPathLengths() {}
421 
422   using ControlSignature = void(FieldIn<RayStatusType>,            // ray status
423                                 FieldIn<ScalarRenderingTypes>,     // cell enter distance
424                                 FieldIn<ScalarRenderingTypes>,     // cell exit distance
425                                 FieldInOut<ScalarRenderingTypes>); // ray absorption data
426 
427   using ExecutionSignature = void(_1, _2, _3, _4);
428 
operator ()(const vtkm::UInt8 & rayStatus,const FloatType & enterDistance,const FloatType & exitDistance,FloatType & distance) const429   VTKM_EXEC inline void operator()(const vtkm::UInt8& rayStatus,
430                                    const FloatType& enterDistance,
431                                    const FloatType& exitDistance,
432                                    FloatType& distance) const
433   {
434     if (rayStatus != RAY_ACTIVE)
435     {
436       return;
437     }
438 
439     if (exitDistance <= enterDistance)
440     {
441       return;
442     }
443 
444     FloatType segmentLength = exitDistance - enterDistance;
445     distance += segmentLength;
446   }
447 };
448 
449 template <typename FloatType>
450 class Integrate : public vtkm::worklet::WorkletMapField
451 {
452 private:
453   const vtkm::Int32 NumBins;
454 
455 public:
456   VTKM_CONT
Integrate(const vtkm::Int32 numBins)457   Integrate(const vtkm::Int32 numBins)
458     : NumBins(numBins)
459   {
460   }
461 
462   using ControlSignature = void(FieldIn<RayStatusType>,                // ray status
463                                 FieldIn<ScalarRenderingTypes>,         // cell enter distance
464                                 FieldIn<ScalarRenderingTypes>,         // cell exit distance
465                                 FieldInOut<ScalarRenderingTypes>,      // current distance
466                                 WholeArrayIn<ScalarRenderingTypes>,    // cell absorption data array
467                                 WholeArrayInOut<ScalarRenderingTypes>, // ray absorption data
468                                 FieldIn<IdType>);                      // current cell
469 
470   using ExecutionSignature = void(_1, _2, _3, _4, _5, _6, _7, WorkIndex);
471 
472   template <typename CellDataPortalType, typename RayDataPortalType>
operator ()(const vtkm::UInt8 & rayStatus,const FloatType & enterDistance,const FloatType & exitDistance,FloatType & currentDistance,const CellDataPortalType & cellData,RayDataPortalType & energyBins,const vtkm::Id & currentCell,const vtkm::Id & rayIndex) const473   VTKM_EXEC inline void operator()(const vtkm::UInt8& rayStatus,
474                                    const FloatType& enterDistance,
475                                    const FloatType& exitDistance,
476                                    FloatType& currentDistance,
477                                    const CellDataPortalType& cellData,
478                                    RayDataPortalType& energyBins,
479                                    const vtkm::Id& currentCell,
480                                    const vtkm::Id& rayIndex) const
481   {
482     if (rayStatus != RAY_ACTIVE)
483     {
484       return;
485     }
486     if (exitDistance <= enterDistance)
487     {
488       return;
489     }
490 
491     FloatType segmentLength = exitDistance - enterDistance;
492 
493     vtkm::Id rayOffset = NumBins * rayIndex;
494     vtkm::Id cellOffset = NumBins * currentCell;
495     for (vtkm::Int32 i = 0; i < NumBins; ++i)
496     {
497       BOUNDS_CHECK(cellData, cellOffset + i);
498       FloatType absorb = static_cast<FloatType>(cellData.Get(cellOffset + i));
499 
500       absorb = vtkm::Exp(-absorb * segmentLength);
501       BOUNDS_CHECK(energyBins, rayOffset + i);
502       FloatType intensity = static_cast<FloatType>(energyBins.Get(rayOffset + i));
503       energyBins.Set(rayOffset + i, intensity * absorb);
504     }
505     currentDistance = exitDistance;
506   }
507 };
508 
509 template <typename FloatType>
510 class IntegrateEmission : public vtkm::worklet::WorkletMapField
511 {
512 private:
513   const vtkm::Int32 NumBins;
514   bool DivideEmisByAbsorb;
515 
516 public:
517   VTKM_CONT
IntegrateEmission(const vtkm::Int32 numBins,const bool divideEmisByAbsorb)518   IntegrateEmission(const vtkm::Int32 numBins, const bool divideEmisByAbsorb)
519     : NumBins(numBins)
520     , DivideEmisByAbsorb(divideEmisByAbsorb)
521   {
522   }
523 
524   using ControlSignature = void(FieldIn<>,                          // ray status
525                                 FieldIn<>,                          // cell enter distance
526                                 FieldIn<>,                          // cell exit distance
527                                 FieldInOut<>,                       // current distance
528                                 WholeArrayIn<ScalarRenderingTypes>, // cell absorption data array
529                                 WholeArrayIn<ScalarRenderingTypes>, // cell emission data array
530                                 WholeArrayInOut<>,                  // ray absorption data
531                                 WholeArrayInOut<>,                  // ray emission data
532                                 FieldIn<>);                         // current cell
533 
534   using ExecutionSignature = void(_1, _2, _3, _4, _5, _6, _7, _8, _9, WorkIndex);
535 
536   template <typename CellAbsPortalType, typename CellEmisPortalType, typename RayDataPortalType>
operator ()(const vtkm::UInt8 & rayStatus,const FloatType & enterDistance,const FloatType & exitDistance,FloatType & currentDistance,const CellAbsPortalType & absorptionData,const CellEmisPortalType & emissionData,RayDataPortalType & absorptionBins,RayDataPortalType & emissionBins,const vtkm::Id & currentCell,const vtkm::Id & rayIndex) const537   VTKM_EXEC inline void operator()(const vtkm::UInt8& rayStatus,
538                                    const FloatType& enterDistance,
539                                    const FloatType& exitDistance,
540                                    FloatType& currentDistance,
541                                    const CellAbsPortalType& absorptionData,
542                                    const CellEmisPortalType& emissionData,
543                                    RayDataPortalType& absorptionBins,
544                                    RayDataPortalType& emissionBins,
545                                    const vtkm::Id& currentCell,
546                                    const vtkm::Id& rayIndex) const
547   {
548     if (rayStatus != RAY_ACTIVE)
549     {
550       return;
551     }
552     if (exitDistance <= enterDistance)
553     {
554       return;
555     }
556 
557     FloatType segmentLength = exitDistance - enterDistance;
558 
559     vtkm::Id rayOffset = NumBins * rayIndex;
560     vtkm::Id cellOffset = NumBins * currentCell;
561     for (vtkm::Int32 i = 0; i < NumBins; ++i)
562     {
563       BOUNDS_CHECK(absorptionData, cellOffset + i);
564       FloatType absorb = static_cast<FloatType>(absorptionData.Get(cellOffset + i));
565       BOUNDS_CHECK(emissionData, cellOffset + i);
566       FloatType emission = static_cast<FloatType>(emissionData.Get(cellOffset + i));
567 
568       if (DivideEmisByAbsorb)
569       {
570         emission /= absorb;
571       }
572 
573       FloatType tmp = vtkm::Exp(-absorb * segmentLength);
574       BOUNDS_CHECK(absorptionBins, rayOffset + i);
575 
576       //
577       // Traditionally, we would only keep track of a single intensity value per ray
578       // per bin and we would integrate from the beginning to end of the ray. In a
579       // distributed memory setting, we would move cell data around so that the
580       // entire ray could be traced, but in situ, moving that much cell data around
581       // could blow memory. Here we are keeping track of two values. Total absorption
582       // through this contiguous segment of the mesh, and the amount of emitted energy
583       // that makes it out of this mesh segment. If this is really run on a single node,
584       // we can get the final energy value by multiplying the background intensity by
585       // the total absorption of the mesh segment and add in the amount of emitted
586       // energy that escapes.
587       //
588       FloatType absorbIntensity = static_cast<FloatType>(absorptionBins.Get(rayOffset + i));
589       FloatType emissionIntensity = static_cast<FloatType>(emissionBins.Get(rayOffset + i));
590 
591       absorptionBins.Set(rayOffset + i, absorbIntensity * tmp);
592 
593       emissionIntensity = emissionIntensity * tmp + emission * (1.f - tmp);
594 
595       BOUNDS_CHECK(emissionBins, rayOffset + i);
596       emissionBins.Set(rayOffset + i, emissionIntensity);
597     }
598     currentDistance = exitDistance;
599   }
600 };
601 //
602 //  IdentifyMissedRay is a debugging routine that detects
603 //  rays that fail to have any value because of a external
604 //  intersection and cell intersection mismatch
605 //
606 //
607 class IdentifyMissedRay : public vtkm::worklet::WorkletMapField
608 {
609 public:
610   vtkm::Id Width;
611   vtkm::Id Height;
612   vtkm::Vec<vtkm::Float32, 4> BGColor;
IdentifyMissedRay(const vtkm::Id width,const vtkm::Id height,vtkm::Vec<vtkm::Float32,4> bgcolor)613   IdentifyMissedRay(const vtkm::Id width,
614                     const vtkm::Id height,
615                     vtkm::Vec<vtkm::Float32, 4> bgcolor)
616     : Width(width)
617     , Height(height)
618     , BGColor(bgcolor)
619   {
620   }
621   using ControlSignature = void(FieldIn<>, WholeArrayIn<>);
622   using ExecutionSignature = void(_1, _2);
623 
624 
IsBGColor(const vtkm::Vec<vtkm::Float32,4> color) const625   VTKM_EXEC inline bool IsBGColor(const vtkm::Vec<vtkm::Float32, 4> color) const
626   {
627     bool isBG = false;
628 
629     if (color[0] == BGColor[0] && color[1] == BGColor[1] && color[2] == BGColor[2] &&
630         color[3] == BGColor[3])
631       isBG = true;
632     return isBG;
633   }
634 
635   template <typename ColorBufferType>
operator ()(const vtkm::Id & pixelId,ColorBufferType & buffer) const636   VTKM_EXEC inline void operator()(const vtkm::Id& pixelId, ColorBufferType& buffer) const
637   {
638     vtkm::Id x = pixelId % Width;
639     vtkm::Id y = pixelId / Width;
640 
641     // Conservative check, we only want to check pixels in the middle
642     if (x <= 0 || y <= 0)
643       return;
644     if (x >= Width - 1 || y >= Height - 1)
645       return;
646     vtkm::Vec<vtkm::Float32, 4> pixel;
647     pixel[0] = static_cast<vtkm::Float32>(buffer.Get(pixelId * 4 + 0));
648     pixel[1] = static_cast<vtkm::Float32>(buffer.Get(pixelId * 4 + 1));
649     pixel[2] = static_cast<vtkm::Float32>(buffer.Get(pixelId * 4 + 2));
650     pixel[3] = static_cast<vtkm::Float32>(buffer.Get(pixelId * 4 + 3));
651     if (!IsBGColor(pixel))
652       return;
653     vtkm::Id p0 = (y)*Width + (x + 1);
654     vtkm::Id p1 = (y)*Width + (x - 1);
655     vtkm::Id p2 = (y + 1) * Width + (x);
656     vtkm::Id p3 = (y - 1) * Width + (x);
657     pixel[0] = static_cast<vtkm::Float32>(buffer.Get(p0 * 4 + 0));
658     pixel[1] = static_cast<vtkm::Float32>(buffer.Get(p0 * 4 + 1));
659     pixel[2] = static_cast<vtkm::Float32>(buffer.Get(p0 * 4 + 2));
660     pixel[3] = static_cast<vtkm::Float32>(buffer.Get(p0 * 4 + 3));
661     if (IsBGColor(pixel))
662       return;
663     pixel[0] = static_cast<vtkm::Float32>(buffer.Get(p1 * 4 + 0));
664     pixel[1] = static_cast<vtkm::Float32>(buffer.Get(p1 * 4 + 1));
665     pixel[2] = static_cast<vtkm::Float32>(buffer.Get(p1 * 4 + 2));
666     pixel[3] = static_cast<vtkm::Float32>(buffer.Get(p1 * 4 + 3));
667     if (IsBGColor(pixel))
668       return;
669     pixel[0] = static_cast<vtkm::Float32>(buffer.Get(p2 * 4 + 0));
670     pixel[1] = static_cast<vtkm::Float32>(buffer.Get(p2 * 4 + 1));
671     pixel[2] = static_cast<vtkm::Float32>(buffer.Get(p2 * 4 + 2));
672     pixel[3] = static_cast<vtkm::Float32>(buffer.Get(p2 * 4 + 3));
673     if (IsBGColor(pixel))
674       return;
675     pixel[0] = static_cast<vtkm::Float32>(buffer.Get(p3 * 4 + 0));
676     pixel[1] = static_cast<vtkm::Float32>(buffer.Get(p3 * 4 + 1));
677     pixel[2] = static_cast<vtkm::Float32>(buffer.Get(p3 * 4 + 2));
678     pixel[3] = static_cast<vtkm::Float32>(buffer.Get(p3 * 4 + 3));
679     if (IsBGColor(pixel))
680       return;
681 
682     printf("Possible error ray missed ray %d\n", (int)pixelId);
683   }
684 };
685 
686 template <typename FloatType, typename Device>
687 class SampleCellAssocCells : public vtkm::worklet::WorkletMapField
688 {
689 private:
690   using ColorHandle = typename vtkm::cont::ArrayHandle<vtkm::Vec<vtkm::Float32, 4>>;
691   using ColorBuffer = typename vtkm::cont::ArrayHandle<FloatType>;
692   using ColorConstPortal = typename ColorHandle::ExecutionTypes<Device>::PortalConst;
693   using ColorPortal = typename ColorBuffer::template ExecutionTypes<Device>::Portal;
694 
695   CellSampler<255> Sampler;
696   FloatType SampleDistance;
697   FloatType MinScalar;
698   FloatType InvDeltaScalar;
699   ColorPortal FrameBuffer;
700   ColorConstPortal ColorMap;
701   const MeshConnectivityBase* MeshConn;
702   vtkm::Int32 ColorMapSize;
703 
704 public:
SampleCellAssocCells(const FloatType & sampleDistance,const FloatType & minScalar,const FloatType & maxScalar,ColorHandle & colorMap,ColorBuffer & frameBuffer,const MeshConnectivityBase * meshConn)705   SampleCellAssocCells(const FloatType& sampleDistance,
706                        const FloatType& minScalar,
707                        const FloatType& maxScalar,
708                        ColorHandle& colorMap,
709                        ColorBuffer& frameBuffer,
710                        const MeshConnectivityBase* meshConn)
711     : SampleDistance(sampleDistance)
712     , MinScalar(minScalar)
713     , ColorMap(colorMap.PrepareForInput(Device()))
714     , MeshConn(meshConn)
715   {
716     InvDeltaScalar = (minScalar == maxScalar) ? 1.f : 1.f / (maxScalar - minScalar);
717     ColorMapSize = static_cast<vtkm::Int32>(ColorMap.GetNumberOfValues());
718     this->FrameBuffer = frameBuffer.PrepareForOutput(frameBuffer.GetNumberOfValues(), Device());
719   }
720 
721 
722   using ControlSignature = void(FieldIn<>,
723                                 WholeArrayIn<ScalarRenderingTypes>,
724                                 FieldIn<>,
725                                 FieldIn<>,
726                                 FieldInOut<>,
727                                 FieldInOut<>);
728   using ExecutionSignature = void(_1, _2, _3, _4, _5, _6, WorkIndex);
729 
730   template <typename ScalarPortalType>
operator ()(const vtkm::Id & currentCell,ScalarPortalType & scalarPortal,const FloatType & enterDistance,const FloatType & exitDistance,FloatType & currentDistance,vtkm::UInt8 & rayStatus,const vtkm::Id & pixelIndex) const731   VTKM_EXEC inline void operator()(const vtkm::Id& currentCell,
732                                    ScalarPortalType& scalarPortal,
733                                    const FloatType& enterDistance,
734                                    const FloatType& exitDistance,
735                                    FloatType& currentDistance,
736                                    vtkm::UInt8& rayStatus,
737                                    const vtkm::Id& pixelIndex) const
738   {
739 
740     if (rayStatus != RAY_ACTIVE)
741       return;
742 
743     vtkm::Vec<vtkm::Float32, 4> color;
744     BOUNDS_CHECK(FrameBuffer, pixelIndex * 4 + 0);
745     color[0] = static_cast<vtkm::Float32>(FrameBuffer.Get(pixelIndex * 4 + 0));
746     BOUNDS_CHECK(FrameBuffer, pixelIndex * 4 + 1);
747     color[1] = static_cast<vtkm::Float32>(FrameBuffer.Get(pixelIndex * 4 + 1));
748     BOUNDS_CHECK(FrameBuffer, pixelIndex * 4 + 2);
749     color[2] = static_cast<vtkm::Float32>(FrameBuffer.Get(pixelIndex * 4 + 2));
750     BOUNDS_CHECK(FrameBuffer, pixelIndex * 4 + 3);
751     color[3] = static_cast<vtkm::Float32>(FrameBuffer.Get(pixelIndex * 4 + 3));
752 
753     vtkm::Float32 scalar;
754     BOUNDS_CHECK(scalarPortal, currentCell);
755     scalar = vtkm::Float32(scalarPortal.Get(currentCell));
756     //
757     // There can be mismatches in the initial enter distance and the current distance
758     // due to lost rays at cell borders. For now,
759     // we will just advance the current position to the enter distance, since otherwise,
760     // the pixel would never be sampled.
761     //
762     if (currentDistance < enterDistance)
763       currentDistance = enterDistance;
764 
765     vtkm::Float32 lerpedScalar;
766     lerpedScalar = static_cast<vtkm::Float32>((scalar - MinScalar) * InvDeltaScalar);
767     vtkm::Id colorIndex = vtkm::Id(lerpedScalar * vtkm::Float32(ColorMapSize));
768     if (colorIndex < 0)
769       colorIndex = 0;
770     if (colorIndex >= ColorMapSize)
771       colorIndex = ColorMapSize - 1;
772     BOUNDS_CHECK(ColorMap, colorIndex);
773     vtkm::Vec<vtkm::Float32, 4> sampleColor = ColorMap.Get(colorIndex);
774 
775     while (enterDistance <= currentDistance && currentDistance <= exitDistance)
776     {
777       //composite
778       vtkm::Float32 alpha = sampleColor[3] * (1.f - color[3]);
779       color[0] = color[0] + sampleColor[0] * alpha;
780       color[1] = color[1] + sampleColor[1] * alpha;
781       color[2] = color[2] + sampleColor[2] * alpha;
782       color[3] = alpha + color[3];
783 
784       if (color[3] > 1.)
785       {
786         rayStatus = RAY_TERMINATED;
787         break;
788       }
789       currentDistance += SampleDistance;
790     }
791 
792     BOUNDS_CHECK(FrameBuffer, pixelIndex * 4 + 0);
793     FrameBuffer.Set(pixelIndex * 4 + 0, color[0]);
794     BOUNDS_CHECK(FrameBuffer, pixelIndex * 4 + 1);
795     FrameBuffer.Set(pixelIndex * 4 + 1, color[1]);
796     BOUNDS_CHECK(FrameBuffer, pixelIndex * 4 + 2);
797     FrameBuffer.Set(pixelIndex * 4 + 2, color[2]);
798     BOUNDS_CHECK(FrameBuffer, pixelIndex * 4 + 3);
799     FrameBuffer.Set(pixelIndex * 4 + 3, color[3]);
800   }
801 }; //class Sample cell
802 
803 template <typename FloatType, typename Device>
804 class SampleCellAssocPoints : public vtkm::worklet::WorkletMapField
805 {
806 private:
807   using ColorHandle = typename vtkm::cont::ArrayHandle<vtkm::Vec<vtkm::Float32, 4>>;
808   using ColorBuffer = typename vtkm::cont::ArrayHandle<FloatType>;
809   using ColorConstPortal = typename ColorHandle::ExecutionTypes<Device>::PortalConst;
810   using ColorPortal = typename ColorBuffer::template ExecutionTypes<Device>::Portal;
811 
812   CellSampler<255> Sampler;
813   FloatType SampleDistance;
814   const MeshConnectivityBase* MeshConn;
815   FloatType MinScalar;
816   FloatType InvDeltaScalar;
817   ColorPortal FrameBuffer;
818   ColorConstPortal ColorMap;
819   vtkm::Id ColorMapSize;
820 
821 public:
SampleCellAssocPoints(const FloatType & sampleDistance,const FloatType & minScalar,const FloatType & maxScalar,ColorHandle & colorMap,ColorBuffer & frameBuffer,const MeshConnectivityBase * meshConn)822   SampleCellAssocPoints(const FloatType& sampleDistance,
823                         const FloatType& minScalar,
824                         const FloatType& maxScalar,
825                         ColorHandle& colorMap,
826                         ColorBuffer& frameBuffer,
827                         const MeshConnectivityBase* meshConn)
828     : SampleDistance(sampleDistance)
829     , MeshConn(meshConn)
830     , MinScalar(minScalar)
831     , ColorMap(colorMap.PrepareForInput(Device()))
832   {
833     InvDeltaScalar = (minScalar == maxScalar) ? 1.f : 1.f / (maxScalar - minScalar);
834     ColorMapSize = ColorMap.GetNumberOfValues();
835     this->FrameBuffer = frameBuffer.PrepareForOutput(frameBuffer.GetNumberOfValues(), Device());
836   }
837 
838 
839   using ControlSignature = void(FieldIn<>,
840                                 WholeArrayIn<Vec3>,
841                                 WholeArrayIn<ScalarRenderingTypes>,
842                                 FieldIn<>,
843                                 FieldIn<>,
844                                 FieldInOut<>,
845                                 FieldIn<>,
846                                 FieldInOut<>,
847                                 FieldIn<>);
848   using ExecutionSignature = void(_1, _2, _3, _4, _5, _6, _7, _8, WorkIndex, _9);
849 
850   template <typename PointPortalType, typename ScalarPortalType>
operator ()(const vtkm::Id & currentCell,PointPortalType & vertices,ScalarPortalType & scalarPortal,const FloatType & enterDistance,const FloatType & exitDistance,FloatType & currentDistance,const vtkm::Vec<vtkm::Float32,3> & dir,vtkm::UInt8 & rayStatus,const vtkm::Id & pixelIndex,const vtkm::Vec<FloatType,3> & origin) const851   VTKM_EXEC inline void operator()(const vtkm::Id& currentCell,
852                                    PointPortalType& vertices,
853                                    ScalarPortalType& scalarPortal,
854                                    const FloatType& enterDistance,
855                                    const FloatType& exitDistance,
856                                    FloatType& currentDistance,
857                                    const vtkm::Vec<vtkm::Float32, 3>& dir,
858                                    vtkm::UInt8& rayStatus,
859                                    const vtkm::Id& pixelIndex,
860                                    const vtkm::Vec<FloatType, 3>& origin) const
861   {
862 
863     if (rayStatus != RAY_ACTIVE)
864       return;
865 
866     vtkm::Vec<vtkm::Float32, 4> color;
867     BOUNDS_CHECK(FrameBuffer, pixelIndex * 4 + 0);
868     color[0] = static_cast<vtkm::Float32>(FrameBuffer.Get(pixelIndex * 4 + 0));
869     BOUNDS_CHECK(FrameBuffer, pixelIndex * 4 + 1);
870     color[1] = static_cast<vtkm::Float32>(FrameBuffer.Get(pixelIndex * 4 + 1));
871     BOUNDS_CHECK(FrameBuffer, pixelIndex * 4 + 2);
872     color[2] = static_cast<vtkm::Float32>(FrameBuffer.Get(pixelIndex * 4 + 2));
873     BOUNDS_CHECK(FrameBuffer, pixelIndex * 4 + 3);
874     color[3] = static_cast<vtkm::Float32>(FrameBuffer.Get(pixelIndex * 4 + 3));
875 
876     if (color[3] >= 1.f)
877     {
878       rayStatus = RAY_TERMINATED;
879       return;
880     }
881     vtkm::Vec<vtkm::Float32, 8> scalars;
882     vtkm::Vec<vtkm::Vec<FloatType, 3>, 8> points;
883     // silence "may" be uninitialized warning
884     for (vtkm::Int32 i = 0; i < 8; ++i)
885     {
886       scalars[i] = 0.f;
887       points[i] = vtkm::Vec<FloatType, 3>(0.f, 0.f, 0.f);
888     }
889     //load local scalar cell data
890     vtkm::Id cellConn[8];
891     const vtkm::Int32 numIndices = MeshConn->GetCellIndices(cellConn, currentCell);
892     for (int i = 0; i < numIndices; ++i)
893     {
894       BOUNDS_CHECK(scalarPortal, cellConn[i]);
895       scalars[i] = static_cast<vtkm::Float32>(scalarPortal.Get(cellConn[i]));
896       BOUNDS_CHECK(vertices, cellConn[i]);
897       points[i] = vtkm::Vec<FloatType, 3>(vertices.Get(cellConn[i]));
898     }
899     //
900     // There can be mismatches in the initial enter distance and the current distance
901     // due to lost rays at cell borders. For now,
902     // we will just advance the current position to the enter distance, since otherwise,
903     // the pixel would never be sampled.
904     //
905     if (currentDistance < enterDistance)
906     {
907       currentDistance = enterDistance;
908     }
909 
910     const vtkm::Int32 cellShape = MeshConn->GetCellShape(currentCell);
911     while (enterDistance <= currentDistance && currentDistance <= exitDistance)
912     {
913       vtkm::Vec<FloatType, 3> sampleLoc = origin + currentDistance * dir;
914       vtkm::Float32 lerpedScalar;
915       bool validSample =
916         Sampler.SampleCell(points, scalars, sampleLoc, lerpedScalar, *this, cellShape);
917       if (!validSample)
918       {
919         //
920         // There is a slight mismatch between intersections and parametric coordinates
921         // which results in a invalid sample very close to the cell edge. Just throw
922         // this sample away, and move to the next sample.
923         //
924 
925         //There should be a sample here, so offset and try again.
926 
927         currentDistance += 0.00001f;
928         continue;
929       }
930       lerpedScalar = static_cast<vtkm::Float32>((lerpedScalar - MinScalar) * InvDeltaScalar);
931       vtkm::Id colorIndex = vtkm::Id(lerpedScalar * vtkm::Float32(ColorMapSize));
932 
933       colorIndex = vtkm::Min(vtkm::Max(colorIndex, vtkm::Id(0)), ColorMapSize - 1);
934       BOUNDS_CHECK(ColorMap, colorIndex);
935       vtkm::Vec<vtkm::Float32, 4> sampleColor = ColorMap.Get(colorIndex);
936       //composite
937       sampleColor[3] *= (1.f - color[3]);
938       color[0] = color[0] + sampleColor[0] * sampleColor[3];
939       color[1] = color[1] + sampleColor[1] * sampleColor[3];
940       color[2] = color[2] + sampleColor[2] * sampleColor[3];
941       color[3] = sampleColor[3] + color[3];
942 
943       if (color[3] >= 1.0)
944       {
945         rayStatus = RAY_TERMINATED;
946         break;
947       }
948       currentDistance += SampleDistance;
949     }
950 
951     BOUNDS_CHECK(FrameBuffer, pixelIndex * 4 + 0);
952     FrameBuffer.Set(pixelIndex * 4 + 0, color[0]);
953     BOUNDS_CHECK(FrameBuffer, pixelIndex * 4 + 1);
954     FrameBuffer.Set(pixelIndex * 4 + 1, color[1]);
955     BOUNDS_CHECK(FrameBuffer, pixelIndex * 4 + 2);
956     FrameBuffer.Set(pixelIndex * 4 + 2, color[2]);
957     BOUNDS_CHECK(FrameBuffer, pixelIndex * 4 + 3);
958     FrameBuffer.Set(pixelIndex * 4 + 3, color[3]);
959   }
960 }; //class Sample cell
961 
962 template <typename FloatType, typename Device>
IntersectCell(Ray<FloatType> & rays,detail::RayTracking<FloatType> & tracker,const MeshConnectivityBase * meshConn,Device)963 void ConnectivityTracer::IntersectCell(Ray<FloatType>& rays,
964                                        detail::RayTracking<FloatType>& tracker,
965                                        const MeshConnectivityBase* meshConn,
966                                        Device)
967 {
968   using LocateC = LocateCell<FloatType>;
969   vtkm::cont::Timer<Device> timer;
970   vtkm::worklet::DispatcherMapField<LocateC> locateDispatch(meshConn);
971   locateDispatch.SetDevice(Device());
972   locateDispatch.Invoke(rays.HitIdx,
973                         this->Coords,
974                         rays.Dir,
975                         *(tracker.EnterDist),
976                         *(tracker.ExitDist),
977                         tracker.ExitFace,
978                         rays.Status,
979                         rays.Origin);
980 
981   if (this->CountRayStatus)
982     RaysLost = RayOperations::GetStatusCount(rays, RAY_LOST, Device());
983   this->IntersectTime += timer.GetElapsedTime();
984 }
985 
986 template <typename FloatType, typename Device>
AccumulatePathLengths(Ray<FloatType> & rays,detail::RayTracking<FloatType> & tracker,Device)987 void ConnectivityTracer::AccumulatePathLengths(Ray<FloatType>& rays,
988                                                detail::RayTracking<FloatType>& tracker,
989                                                Device)
990 {
991   vtkm::worklet::DispatcherMapField<AddPathLengths<FloatType>> dispatcher(
992     (AddPathLengths<FloatType>()));
993   dispatcher.SetDevice(Device());
994   dispatcher.Invoke(
995     rays.Status, *(tracker.EnterDist), *(tracker.ExitDist), rays.GetBuffer("path_lengths").Buffer);
996 }
997 
998 template <typename FloatType, typename Device>
FindLostRays(Ray<FloatType> & rays,detail::RayTracking<FloatType> & tracker,const MeshConnectivityBase * meshConn,Device)999 void ConnectivityTracer::FindLostRays(Ray<FloatType>& rays,
1000                                       detail::RayTracking<FloatType>& tracker,
1001                                       const MeshConnectivityBase* meshConn,
1002                                       Device)
1003 {
1004   using RayB = RayBumper<FloatType, Device>;
1005   vtkm::cont::Timer<Device> timer;
1006 
1007   vtkm::worklet::DispatcherMapField<RayB> bumpDispatch(
1008     RayB(rays.DirX, rays.DirY, rays.DirZ, meshConn));
1009   bumpDispatch.SetDevice(Device());
1010   bumpDispatch.Invoke(rays.HitIdx,
1011                       this->Coords,
1012                       *(tracker.EnterDist),
1013                       *(tracker.ExitDist),
1014                       tracker.ExitFace,
1015                       rays.Status,
1016                       rays.Origin);
1017 
1018   this->LostRayTime += timer.GetElapsedTime();
1019 }
1020 
1021 template <typename FloatType, typename Device>
SampleCells(Ray<FloatType> & rays,detail::RayTracking<FloatType> & tracker,const MeshConnectivityBase * meshConn,Device)1022 void ConnectivityTracer::SampleCells(Ray<FloatType>& rays,
1023                                      detail::RayTracking<FloatType>& tracker,
1024                                      const MeshConnectivityBase* meshConn,
1025                                      Device)
1026 {
1027   using SampleP = SampleCellAssocPoints<FloatType, Device>;
1028   using SampleC = SampleCellAssocCells<FloatType, Device>;
1029   vtkm::cont::Timer<Device> timer;
1030 
1031   VTKM_ASSERT(rays.Buffers.at(0).GetNumChannels() == 4);
1032 
1033   if (FieldAssocPoints)
1034   {
1035     vtkm::worklet::DispatcherMapField<SampleP> dispatcher(
1036       SampleP(this->SampleDistance,
1037               vtkm::Float32(this->ScalarBounds.Min),
1038               vtkm::Float32(this->ScalarBounds.Max),
1039               this->ColorMap,
1040               rays.Buffers.at(0).Buffer,
1041               meshConn));
1042     dispatcher.SetDevice(Device());
1043     dispatcher.Invoke(rays.HitIdx,
1044                       this->Coords,
1045                       this->ScalarField.GetData(),
1046                       *(tracker.EnterDist),
1047                       *(tracker.ExitDist),
1048                       tracker.CurrentDistance,
1049                       rays.Dir,
1050                       rays.Status,
1051                       rays.Origin);
1052   }
1053   else
1054   {
1055     vtkm::worklet::DispatcherMapField<SampleC> dispatcher(
1056       SampleC(this->SampleDistance,
1057               vtkm::Float32(this->ScalarBounds.Min),
1058               vtkm::Float32(this->ScalarBounds.Max),
1059               this->ColorMap,
1060               rays.Buffers.at(0).Buffer,
1061               meshConn));
1062     dispatcher.SetDevice(Device());
1063     dispatcher.Invoke(rays.HitIdx,
1064                       this->ScalarField.GetData(),
1065                       *(tracker.EnterDist),
1066                       *(tracker.ExitDist),
1067                       tracker.CurrentDistance,
1068                       rays.Status);
1069   }
1070 
1071   this->SampleTime += timer.GetElapsedTime();
1072 }
1073 
1074 template <typename FloatType, typename Device>
IntegrateCells(Ray<FloatType> & rays,detail::RayTracking<FloatType> & tracker,Device)1075 void ConnectivityTracer::IntegrateCells(Ray<FloatType>& rays,
1076                                         detail::RayTracking<FloatType>& tracker,
1077                                         Device)
1078 {
1079   vtkm::cont::Timer<Device> timer;
1080   if (HasEmission)
1081   {
1082     bool divideEmisByAbsorp = false;
1083     vtkm::cont::ArrayHandle<FloatType> absorp = rays.Buffers.at(0).Buffer;
1084     vtkm::cont::ArrayHandle<FloatType> emission = rays.GetBuffer("emission").Buffer;
1085     vtkm::worklet::DispatcherMapField<IntegrateEmission<FloatType>> dispatcher(
1086       IntegrateEmission<FloatType>(rays.Buffers.at(0).GetNumChannels(), divideEmisByAbsorp));
1087     dispatcher.SetDevice(Device());
1088     dispatcher.Invoke(rays.Status,
1089                       *(tracker.EnterDist),
1090                       *(tracker.ExitDist),
1091                       rays.Distance,
1092                       this->ScalarField.GetData(),
1093                       this->EmissionField.GetData(),
1094                       absorp,
1095                       emission,
1096                       rays.HitIdx);
1097   }
1098   else
1099   {
1100     vtkm::worklet::DispatcherMapField<Integrate<FloatType>> dispatcher(
1101       Integrate<FloatType>(rays.Buffers.at(0).GetNumChannels()));
1102     dispatcher.SetDevice(Device());
1103     dispatcher.Invoke(rays.Status,
1104                       *(tracker.EnterDist),
1105                       *(tracker.ExitDist),
1106                       rays.Distance,
1107                       this->ScalarField.GetData(),
1108                       rays.Buffers.at(0).Buffer,
1109                       rays.HitIdx);
1110   }
1111 
1112   IntegrateTime += timer.GetElapsedTime();
1113 }
1114 
1115 // template <vtkm::Int32 CellType>
1116 // template <typename FloatType>
1117 // void ConnectivityTracer<CellType>::PrintDebugRay(Ray<FloatType>& rays, vtkm::Id rayId)
1118 // {
1119 //   vtkm::Id index = -1;
1120 //   for (vtkm::Id i = 0; i < rays.NumRays; ++i)
1121 //   {
1122 //     if (rays.PixelIdx.GetPortalControl().Get(i) == rayId)
1123 //     {
1124 //       index = i;
1125 //       break;
1126 //     }
1127 //   }
1128 //   if (index == -1)
1129 //   {
1130 //     return;
1131 //   }
1132 
1133 //   std::cout << "++++++++RAY " << rayId << "++++++++\n";
1134 //   std::cout << "Status: " << (int)rays.Status.GetPortalControl().Get(index) << "\n";
1135 //   std::cout << "HitIndex: " << rays.HitIdx.GetPortalControl().Get(index) << "\n";
1136 //   std::cout << "Dist " << rays.Distance.GetPortalControl().Get(index) << "\n";
1137 //   std::cout << "MinDist " << rays.MinDistance.GetPortalControl().Get(index) << "\n";
1138 //   std::cout << "Origin " << rays.Origin.GetPortalConstControl().Get(index) << "\n";
1139 //   std::cout << "Dir " << rays.Dir.GetPortalConstControl().Get(index) << "\n";
1140 //   std::cout << "+++++++++++++++++++++++++\n";
1141 // }
1142 
1143 template <typename FloatType, typename Device>
OffsetMinDistances(Ray<FloatType> & rays,Device)1144 void ConnectivityTracer::OffsetMinDistances(Ray<FloatType>& rays, Device)
1145 {
1146   vtkm::worklet::DispatcherMapField<AdvanceRay<FloatType>> dispatcher(
1147     AdvanceRay<FloatType>(FloatType(0.001)));
1148   dispatcher.SetDevice(Device());
1149   dispatcher.Invoke(rays.Status, rays.MinDistance);
1150 }
1151 
1152 template <typename Device, typename FloatType>
RenderOnDevice(Ray<FloatType> & rays,Device)1153 void ConnectivityTracer::RenderOnDevice(Ray<FloatType>& rays, Device)
1154 {
1155   this->RaysLost = 0;
1156   Logger* logger = Logger::GetInstance();
1157   logger->OpenLogEntry("conn_tracer");
1158   logger->AddLogData("device", GetDeviceString(Device()));
1159   this->ResetTimers();
1160   vtkm::cont::Timer<Device> renderTimer;
1161 
1162   vtkm::cont::DeviceAdapterId devId = Device();
1163 
1164   const MeshConnectivityBase* meshConn = MeshContainer->Construct(devId);
1165 
1166   bool hasPathLengths = rays.HasBuffer("path_lengths");
1167 
1168   vtkm::cont::Timer<Device> timer;
1169   this->Init(); // sets sample distance
1170   //
1171   // All Rays begin as exited to force intersection
1172   //
1173   RayOperations::ResetStatus(rays, RAY_EXITED_MESH, Device());
1174 
1175   detail::RayTracking<FloatType> rayTracker;
1176 
1177   rayTracker.Init(rays.NumRays, rays.Distance, Device());
1178   vtkm::Float64 time = timer.GetElapsedTime();
1179   logger->AddLogData("init", time);
1180 
1181   //CountRayStatus = true;
1182   bool cullMissedRays = true;
1183   bool workRemaining = true;
1184   if (this->CountRayStatus)
1185   {
1186     this->PrintRayStatus(rays, Device());
1187   }
1188 
1189   do
1190   {
1191     {
1192       vtkm::cont::Timer<Device> entryTimer;
1193       //
1194       // if ray misses the external face it will be marked RAY_EXITED_MESH
1195       //
1196       MeshContainer->FindEntry(rays, devId);
1197       MeshEntryTime += entryTimer.GetElapsedTime();
1198     }
1199 
1200     if (this->CountRayStatus)
1201     {
1202       this->PrintRayStatus(rays, Device());
1203     }
1204     if (cullMissedRays)
1205     {
1206       //TODO: if we always call this after intersection, then
1207       //      we could make a specialized version that only compacts
1208       //      hitIdx distance and status, resizing everything else.
1209       vtkm::cont::ArrayHandle<UInt8> activeRays;
1210       activeRays = RayOperations::CompactActiveRays(rays, Device());
1211       rayTracker.Compact(rays.Distance, activeRays, Device());
1212       cullMissedRays = false;
1213     }
1214 
1215     if (this->CountRayStatus)
1216     {
1217       this->PrintRayStatus(rays, Device());
1218     }
1219     // TODO: we should compact out exited rays once below a threshold
1220     while (RayOperations::RaysInMesh(rays, Device()))
1221     {
1222       //
1223       // Rays the leave the mesh will be marked as RAYEXITED_MESH
1224       this->IntersectCell(rays, rayTracker, meshConn, Device());
1225       //
1226       // If the ray was lost due to precision issues, we find it.
1227       // If it is marked RAY_ABANDONED, then something went wrong.
1228       //
1229       this->FindLostRays(rays, rayTracker, meshConn, Device());
1230       //
1231       // integrate along the ray
1232       //
1233       if (this->Integrator == Volume)
1234         this->SampleCells(rays, rayTracker, meshConn, Device());
1235       else
1236         this->IntegrateCells(rays, rayTracker, Device());
1237 
1238       if (hasPathLengths)
1239       {
1240         this->AccumulatePathLengths(rays, rayTracker, Device());
1241       }
1242       //swap enter and exit distances
1243       rayTracker.Swap();
1244       if (this->CountRayStatus)
1245         this->PrintRayStatus(rays, Device());
1246     } //for
1247 
1248     workRemaining = RayOperations::RaysProcessed(rays, Device()) != rays.NumRays;
1249     //
1250     // Ensure that we move the current distance forward some
1251     // epsilon so we don't re-enter the cell we just left.
1252     //
1253     if (workRemaining)
1254     {
1255       RayOperations::CopyDistancesToMin(rays, Device());
1256       this->OffsetMinDistances(rays, Device());
1257     }
1258   } while (workRemaining);
1259 
1260   if (rays.DebugWidth != -1 && this->Integrator == Volume)
1261   {
1262 
1263     vtkm::cont::ArrayHandleCounting<vtkm::Id> pCounter(0, 1, rays.NumRays);
1264     vtkm::worklet::DispatcherMapField<IdentifyMissedRay> dispatcher(
1265       IdentifyMissedRay(rays.DebugWidth, rays.DebugHeight, this->BackgroundColor));
1266     dispatcher.SetDevice(Device());
1267     dispatcher.Invoke(pCounter, rays.Buffers.at(0).Buffer);
1268   }
1269   vtkm::Float64 renderTime = renderTimer.GetElapsedTime();
1270   this->LogTimers();
1271   logger->AddLogData("active_pixels", rays.NumRays);
1272   logger->CloseLogEntry(renderTime);
1273 } //Render
1274 }
1275 }
1276 } // namespace vtkm::rendering::raytracing
1277