Links

Content Skeleton

This Page

Surface Debug : lacking hits due to surface/volume model mismatch

FIXED long ago

Not getting any SURFACE_DETECT despite photons obviously traversing PMTs because the requisite boundaries have no associated surfaces.

Surface flags:

SURFACE_DETECT
SURFACE_ABSORB
SURFACE_DREFLECT
SURFACE_SREFLECT

generate.cu:

281
282         command = propagate_to_boundary( p, s, rng );
283         if(command == BREAK)    break ;           // BULK_ABSORB
284         if(command == CONTINUE) continue ;        // BULK_REEMIT/BULK_SCATTER
285         // PASS : survivors will go on to pick up one of the below flags,
286
287
288         if(s.optical.x > 0 )       // x/y/z/w:index/type/finish/value
289         {
290             command = propagate_at_surface(p, s, rng);
291             if(command == BREAK)    break ;       // SURFACE_DETECT/SURFACE_ABSORB
292             if(command == CONTINUE) continue ;    // SURFACE_DREFLECT/SURFACE_SREFLECT
293         }
294         else
295         {
296             propagate_at_boundary(p, s, rng);     // BOUNDARY_RELECT/BOUNDARY_TRANSMIT
297             // tacit CONTINUE
298         }

state.h:

19 __device__ void fill_state( State& s, int boundary, int sensor, float wavelength )
20 {
21     // boundary : 1 based code, signed by cos_theta of photon direction to outward geometric normal
22     // >0 outward going photon
23     // <0 inward going photon
24
25     int line = boundary > 0 ? (boundary - 1)*6 : (-boundary - 1)*6  ;
26
27     // pick relevant lines depening on boundary sign, ie photon direction relative to normal
28     //
29     int m1_line = boundary > 0 ? line + 0 : line + 1 ;   // inner-material / outer-material
30     int m2_line = boundary > 0 ? line + 1 : line + 0 ;   // outer-material / inner-material
31     int su_line = boundary > 0 ? line + 2 : line + 3 ;   // inner-surface  / outer-surface
32
33     s.material1 = wavelength_lookup( wavelength, m1_line );
34     s.material2 = wavelength_lookup( wavelength, m2_line ) ;
35     s.surface   = wavelength_lookup( wavelength, su_line );
36
37     s.optical = optical_buffer[su_line] ;   // index/type/finish/value
38
39     s.index.x = optical_buffer[m1_line].x ;
40     s.index.y = optical_buffer[m2_line].x ;
41     s.index.z = optical_buffer[su_line].x ;
42     s.index.w = sensor  ;
43
44 }

Chroma Solution to same issue

Addressed this with G4DAEChroma by adding “fake” surfaces

delta:env blyth$ hg shortlog | grep sensitive
ef4ab750f29e | 2014-10-10 20:15:22 +0800 | simoncblyth: debug the tranlation of sensitive materials into surfaces for G4 to Chroma model translation
4b938256ea50 | 2014-10-10 14:02:43 +0800 | simoncblyth: add extra SkinSurface and OpticalSurface objects to DAE level geometry in order to be transformed into sensitive surfaces needed for chroma SURFACE_DETECT
d41b1d971f68 | 2014-10-09 21:02:37 +0800 | simoncblyth: working out how to reconcile the G4 and Chroma models regards sensitive detectors, in order to get Chroma to come up with photon hit data
b192e176d992 | 2009-06-23 18:31:51 +0800 | simoncblyth: tg-quickstart 1st checkin of OfflineDB project ... untouched other than exclusions of sensitive {{{.ini}}} files
3b26e5c356f4 | 2008-08-21 13:00:42 +0800 | simoncblyth: improved access control to sensitive variables
101ef1dc0491 | 2007-12-24 08:16:45 +0800 | thho: sensitive skin opacity setting
b04e2e8719ab | 2007-07-27 12:00:47 +0800 | simoncblyth: sensitive skin testing
delta:env blyth$
395     @classmethod
396     def add_sensitive_surfaces(cls, matid='__dd__Materials__Bialkali', qeprop='EFFICIENCY'):
397         """
398         Chroma expects sensitive detectors to have an Optical Surface
399         with channel_id associated.
400         Whereas Geant4 just has sensitive LV.
401
402         This attempts to bridge from Geant4 to Chroma model
403         by creation of "fake" chroma skinsurfaces.
404
405         Effectively sensitive materials are translated
406         into sensitive surfaces
407
408         ::
409
410             In [57]: DAENode.orig.materials['__dd__Materials__Bialkali0xc2f2428'].extra
411             Out[57]: <MaterialProperties keys=['RINDEX', 'EFFICIENCY', 'ABSLENGTH'] >
412
413
414         #. Different efficiency for different cathodes ?
415
416         """
417         log.info("add_sensitive_surfaces matid %s qeprop %s " % (matid, qeprop))
418         sensitive_material = cls.materialsearch(matid)
419         assert sensitive_material
420
421         if sensitive_material.extra is None:
422             log.warn("sensitive_material.extra not available cannot sensitize ")
423             return
424
425         efficiency = sensitive_material.extra.properties[qeprop]
426         assert not efficiency is None
427
428         cls.sensitize(matid=matid)
429
430         # follow convention used in G4DAE exports of using same names for
431         # the SkinSurface and the OpticalSurface it refers too
432
433         for node in cls.sensitive_nodes:
434             ssid = cls.sensitive_surface_id(node)
435             volumeref = node.lv.id
436
437             surf = OpticalSurface.sensitive(name=ssid, properties={qeprop:efficiency})
438             cls.add_extra_opticalsurface(surf)
439
440             skin = SkinSurface.sensitive(name=ssid, surfaceproperty=surf, volumeref=volumeref )
441             cls.add_extra_skinsurface(skin)
442         pass

How to do this with GGeo ?

Which level to add the fake cathode surfaces at ?

  • AssimpGGeo::convertMaterials, creates and adds to GGeo instances of GOpticalSurface, GSkinSurface, GBorderSurface, GMaterial based on the properties that the assimp “materials” have
  • AssimpGGeo::convertStructureVisit pulls GBoundary into existance based on boundary identity combining imat/omat/isur/osur
603     GSolid* solid = new GSolid(nodeIndex, gtransform, mesh, NULL, NULL ); // boundary and sensor start NULL
604     solid->setLevelTransform(ltransform);
605
606     const char* lv   = node->getName(0);
607     const char* pv   = node->getName(1);
608     const char* pv_p   = pnode->getName(1);
609
610     gg->countMeshUsage(msi, nodeIndex, lv, pv);
611
612     GBorderSurface* obs = gg->findBorderSurface(pv_p, pv);  // outer surface (parent->self)
613     GBorderSurface* ibs = gg->findBorderSurface(pv, pv_p);  // inner surface (self->parent)
614     GSkinSurface*   sks = gg->findSkinSurface(lv);
615

Avoiding interference with this structure means would need to add the surfaces prior to AssimpGGeo::convertStructure

Approach using AssimpGGeo::convertSensors

2 sensor skin surfaces are added:

lvPmtHemiCathodeSensorSurface
lvHeadonPmtCathodeSensorSurface

But only one shows up in boundarylib (may be due to identity digest not including the name):

ggv --blib

boundary : index 21 x6 126 e554f1b518cd18fae063073e9147b70d Bialkali/Vacuum/-/lvPmtHemiCathodeSensorSurface

Running does not yet yield any SURFACE_DETECT, but getting lots of SURFACE_SREFLECT:

288         if(s.optical.x > 0 )       // x/y/z/w:index/type/finish/value
289         {
290             command = propagate_at_surface(p, s, rng);
291             if(command == BREAK)    break ;       // SURFACE_DETECT/SURFACE_ABSORB
292             if(command == CONTINUE) continue ;    // SURFACE_DREFLECT/SURFACE_SREFLECT
293         }


402 __device__ int
403 propagate_at_surface(Photon &p, State &s, curandState &rng)
404 {
405
406     float u = curand_uniform(&rng);
407
408     if( u < s.surface.y )   // absorb
409     {
410         s.flag = SURFACE_ABSORB ;
411         return BREAK ;
412     }
413     else if ( u < s.surface.y + s.surface.x )  // absorb + detect
414     {
415         s.flag = SURFACE_DETECT ;
416         return BREAK ;
417     }
418     else if (u  < s.surface.y + s.surface.x + s.surface.w )  // absorb + detect + reflect_diffuse
419     {
420         s.flag = SURFACE_DREFLECT ;
421         propagate_at_diffuse_reflector(p, s, rng);
422         return CONTINUE;
423     }
424     else
425     {
426         s.flag = SURFACE_SREFLECT ;
427         propagate_at_specular_reflector(p, s, rng );
428         return CONTINUE;
429     }
430 }

Hmm setting efficiency to 1.0 still getting nothing other than SURFACE_SREFLECT

delta:env blyth$ ggv --blib 126 127 128 129 130 131
[2015-10-06 13:22:01.832171] [0x000007fff7448031] [warning] GBoundaryLib::setWavelengthBuffer didnt see 54, numBoundary: 57

boundary : index  0 x6   0 019d50af046b6733287e43af2e8f7fa2 Vacuum/Vacuum/-/-
...
boundary : index 21 x6 126 31ec4ad900fe9b40be261fa11af380b7 Bialkali/Vacuum/-/lvPmtHemiCathodeSensorSurface
GBoundaryLib.dumpWavelengthBuffer 126
GBoundaryLib::dumpWavelengthBuffer wline 126 numSub 57 domainLength 39 numQuad 6

 126 |  21/  0 __dd__Materials__Bialkali0xc2f2428
           1.458           1.458           1.458           1.458           1.458           1.458           1.458           1.458
        1000.000        1000.000        1000.000        1077.339        1736.682        1393.428         821.650         529.476
     1000000.000     1000000.000     1000000.000     1000000.000     1000000.000     1000000.000     1000000.000     1000000.000
           0.000           0.000           0.000           0.000           0.000           0.000           0.000           0.000

GBoundaryLib.dumpWavelengthBuffer 127
GBoundaryLib::dumpWavelengthBuffer wline 127 numSub 57 domainLength 39 numQuad 6

 127 |  21/  1 __dd__Materials__Vacuum0xbf9fcc0
           1.000           1.000           1.000           1.000           1.000           1.000           1.000           1.000
    10000000.000    10000000.000    10000000.000    10000000.000    10000000.000    10000000.000    10000000.000    10000000.000
     1000000.000     1000000.000     1000000.000     1000000.000     1000000.000     1000000.000     1000000.000     1000000.000
           0.000           0.000           0.000           0.000           0.000           0.000           0.000           0.000

GBoundaryLib.dumpWavelengthBuffer 128
GBoundaryLib::dumpWavelengthBuffer wline 128 numSub 57 domainLength 39 numQuad 6

 128 |  21/  2 -
          -1.000          -1.000          -1.000          -1.000          -1.000          -1.000          -1.000          -1.000
          -1.000          -1.000          -1.000          -1.000          -1.000          -1.000          -1.000          -1.000
          -1.000          -1.000          -1.000          -1.000          -1.000          -1.000          -1.000          -1.000
          -1.000          -1.000          -1.000          -1.000          -1.000          -1.000          -1.000          -1.000

GBoundaryLib.dumpWavelengthBuffer 129
GBoundaryLib::dumpWavelengthBuffer wline 129 numSub 57 domainLength 39 numQuad 6

 129 |  21/  3 __dd__Geometry__PMT__lvPmtHemiCathodeSensorSurface
           1.000           1.000           1.000           1.000           1.000           1.000           1.000           1.000
          -1.000          -1.000          -1.000          -1.000          -1.000          -1.000          -1.000          -1.000
          -1.000          -1.000          -1.000          -1.000          -1.000          -1.000          -1.000          -1.000
          -1.000          -1.000          -1.000          -1.000          -1.000          -1.000          -1.000          -1.000

GBoundaryLib.dumpWavelengthBuffer 130
GBoundaryLib::dumpWavelengthBuffer wline 130 numSub 57 domainLength 39 numQuad 6

 130 |  21/  4 -
          -1.000          -1.000          -1.000          -1.000          -1.000          -1.000          -1.000          -1.000
          -1.000          -1.000          -1.000          -1.000          -1.000          -1.000          -1.000          -1.000
          -1.000          -1.000          -1.000          -1.000          -1.000          -1.000          -1.000          -1.000
          -1.000          -1.000          -1.000          -1.000          -1.000          -1.000          -1.000          -1.000

GBoundaryLib.dumpWavelengthBuffer 131
GBoundaryLib::dumpWavelengthBuffer wline 131 numSub 57 domainLength 39 numQuad 6

 131 |  21/  5 -
          -1.000          -1.000          -1.000          -1.000          -1.000          -1.000          -1.000          -1.000
          -1.000          -1.000          -1.000          -1.000          -1.000          -1.000          -1.000          -1.000
          -1.000          -1.000          -1.000          -1.000          -1.000          -1.000          -1.000          -1.000
          -1.000          -1.000          -1.000          -1.000          -1.000          -1.000          -1.000          -1.000
delta:env blyth$

Hmm is inner/outer surface swapped somewhere ? Dont think so.

Possibly a problem with PMT normals ?

Suspect issue with PMT front face normals. The Q normal view shows no normals coming out the front of PMTs

43 (v  482 f  960 )  (t    1 oe    0) : x    98.143 : n   672 : n*v 323904 :                         pmt-hemi-cathode : 3201,3207,3213,3219,3225,
44 (v  242 f  480 )  (t    1 oe    0) : x    98.143 : n   672 : n*v 162624 :                             pmt-hemi-bot : 3202,3208,3214,3220,3226,
45 (v   50 f   96 )  (t    1 oe    0) : x    83.000 : n   672 : n*v  33600 :                          pmt-hemi-dynode : 3203,3209,3215,3221,3227,
46 (v  338 f  672 )  (t    1 oe    0) : x   146.252 : n   672 : n*v 227136 :                             pmt-hemi-vac : 3200,3206,3212,3218,3224,
47 (v  362 f  720 )  (t    1 oe    0) : x   149.997 : n   672 : n*v 243264 :                                 pmt-hemi : 3199,3205,3211,3217,3223,

Wow 960 faces for the cathode ?

Add mdyb for checking pmt-hemi-cathode geometry, its a flikering mess and a cats cradle of normals:

ggv --mdyb -G --noinstanced

ggv --mdyb -O
udp.py --target 3201

ggv --mdyb --torchconfig="pos_target=3201;pos_offset=500,0,0"

ggv --mdyb --torchconfig "pos_target=3201;pos_offset=800,0,0;radius=100"

   # hmm dont see photons that miss

ggv --mdyb --torchconfig "pos_target=3201;pos_offset=0,1000,0;radius=100;direction=0,-1,0" --geocenter

   # targetting the beam is not easier as can only see the photons when they hit

ggv --mdyb --torchconfig "pos_target=3154;radius=3000;direction=0,0,-1"

   # added SST but do not see records that just get absorbed either
   # that means are propagating in a lump of Steel

ggv --mdyb --torchconfig "pos_target=3154;radius=3000;direction=0,0,-1" --save

   # export GGEOVIEW_QUERY="range:3201:3202,range:3153:3154"   # 2 volumes : first pmt-hemi-cathode and ADE
   # change envelope volume to ADE much better, as photons get somewhere in IwsWater/IwsWater


ggv --mdyb --torchconfig "frame=3201;source=0,0,1000;target=0,0,0;radius=300;" --save

   # head on beam strarting 1m out in front of PMT cathode
   #
   # using reworked the Torch configuration to be frame based with source and target positions
   # specified in the identified frame
   #
   # note effect of material inconsistency, photons destined to hit the cathode
   # think they are in a vacuum, hence they lead ahead of those destined to hit ADE envelope

Hmm would be easiest to target the PMT using its own frame, hmm view targetting did something similar ?

Detdesc dive

Looks like need to replace the cathode with something simpler ?

G5:/home/blyth/local/env/dyb/NuWa-trunk/dybgaudi/Detector/XmlDetDesc/DDDB/PMT/hemi-pmt.xml:

118   <!-- The Photo Cathode -->
119   <!-- use if limit photocathode to a face on diameter gt 167mm. -->
120   <logvol name="lvPmtHemiCathode" material="Bialkali" sensdet="DsPmtSensDet">
121     <union name="pmt-hemi-cathode">
122       <sphere name="pmt-hemi-cathode-face"
123           outerRadius="PmtHemiFaceROCvac"
124           innerRadius="PmtHemiFaceROCvac-PmtHemiCathodeThickness"
125           deltaThetaAngle="PmtHemiFaceCathodeAngle"/>
///
///                  PmtHemiFaceROC-PmtHemiGlassThickness : 131. - 3. = 128.
///                                                       128. - 0.05 = 127.95
///
126       <sphere name="pmt-hemi-cathode-belly"
127           outerRadius="PmtHemiBellyROCvac"
128           innerRadius="PmtHemiBellyROCvac-PmtHemiCathodeThickness"
129           startThetaAngle="PmtHemiBellyCathodeAngleStart"
130           deltaThetaAngle="PmtHemiBellyCathodeAngleDelta"/>
///
///
///
///
131       <posXYZ z="PmtHemiFaceOff-PmtHemiBellyOff"/>
///
///             56. - 17. = 39.
///
132     </union>
133   </logvol>

G5:/home/blyth/local/env/dyb/NuWa-trunk/dybgaudi/Detector/XmlDetDesc/DDDB/PMT/hemi-parameters.xml:

010 <!-- Radius of curvature of face of PMT, HM catalog -->
 11 <parameter name="PmtHemiFaceROC" value="131*mm"/>
 12
 13 <!-- Radius of curvature of top and bottom belly parts, average of Tak Pui's numbers -->
 14 <parameter name="PmtHemiBellyROC" value="102*mm"/>
 15
 16 <!-- Offset of face hemisphere -->
 17 <!-- <parameter name="PmtHemiFaceOff" value="60*mm"/> -->
 18 <!-- Shrink offset from Tak Pui's numbers to better fit G4dyb hitz vs. hity -->
 19 <parameter name="PmtHemiFaceOff" value="56*mm"/>
 20
 21 <!-- Offset of top/bottom belly hemispheres, average of Tak Pui's numbers -->
 22 <!-- <parameter name="PmtHemiBellyOff" value="17*mm"/> -->
 23 <!-- Shrink offset from Tak Pui's numbers to better fit G4dyb hitz vs. hity -->
 24 <parameter name="PmtHemiBellyOff" value="13*mm"/>
 25
 26 <!-- Radius of cylindrical glass base, HM catalog -->
 27 <parameter name="PmtHemiGlassBaseRadius" value="42.25*mm"/>
 28
 29 <!-- Radius of opaque "dynode" -->
 30 <parameter name="PmtHemiDynodeRadius" value="27.5*mm"/>

 44 <!-- Thickness of the glass, from GLG4sim numbers -->
 45 <parameter name="PmtHemiGlassThickness" value="3*mm"/>
 46
 47 <!-- Thickness of the photo cathode, this is a made up number -->
 48 <parameter name="PmtHemiCathodeThickness" value="0.05*mm"/>
 ..
 68
 69 <!-- Radius of curvature of vacuum side of face of PMT, HM catalog -->
 70 <parameter name="PmtHemiFaceROCvac" value="PmtHemiFaceROC-PmtHemiGlassThickness"/>
 //                                                 131. - 3. = 128.
 //
 72 <!-- Radius of curvature of vacuum side of top and bottom belly parts, average of Tak Pui's numbers -->
 73 <parameter name="PmtHemiBellyROCvac" value="PmtHemiBellyROC-PmtHemiGlassThickness"/>
 //                                                   102.-3. = 99.
 74
 75
 76 <!--
 77      a = PmtHemiFaceROCvac
 78      b = PmtHemiBellyROCvac
 79      d = (PmtHemiFaceOff-PmtHemiBellyOff)
 80
 81      y = PmtHemiFaceTopOff = distance from center of top belly hemi to
 82      z location of interface between top and face hemis.
 83
 84  -->
 85
 86 <parameter name="PmtHemiFaceTopOff" value="(PmtHemiFaceROCvac^2-PmtHemiBellyROCvac^2-(PmtHemiFaceOff-PmtHemiBellyOff)^2)/(2*(PmtHemiFaceOff-PmtHemiBellyOff))"/>
 //                                                (128.*128.- 99.*99. - (56.-13.)*(56.-13.))/(2.*(56.-13.))
 //
 //       In [1]: (128.*128.- 99.*99. - (56.-13.)*(56.-13.))/(2.*(56.-13.))
 //       Out[1]: 55.04651162790697
 //
 //
 //
 87
 88 <!-- Angular extent of photocathode on face
 89      acos((y+b)/a)
 90 -->
 91 <parameter name="PmtHemiFaceCathodeAngle" value="0.5*degree+radian*acos((PmtHemiFaceTopOff+(PmtHemiFaceOff-PmtHemiBellyOff))/PmtHemiFaceROCvac)"/>
 //
 //          math.acos((55.0465+(56.-13.))/128.)
 //
 // In [8]: 0.5+math.acos((55.0465+(56.-13.))/128.)*180./math.pi
 // Out[8]: 40.50500580674586
 //
 92
 93 <!-- Start angle for photocathode on belly
 94      acos(y/b)
 95 -->
 96 <parameter name="PmtHemiBellyCathodeAngleStart" value="-0.5*degree+radian*acos(PmtHemiFaceTopOff/PmtHemiBellyROCvac)"/>
 97
 98 <!-- Stop angle for photocathode on belly
 99      asin(PC diameter / 2 / a)
100 -->
101 <!--
102 <parameter name="PmtHemiBellyCathodeAngleDelta" value="radian*asin(0.5*PmtHemiCathodeDiameter/PmtHemiBellyROCvac)-PmtHemiBellyCathodeAngleStart"/>
103  -->
104 <parameter name="PmtHemiBellyCathodeAngleDelta" value="PmtHemiBellyIntAngle-PmtHemiBellyCathodeAngleStart"/>
105
106 <!-- Angle where belly spheres intersect -->
107 <parameter name="PmtHemiBellyIntAngle" value="acos(PmtHemiBellyOff/PmtHemiBellyROCvac)*radian"/>
108

How to try some simple replacement cathode ?

  • adding analytic spheres to OptiX at the positions corresponding to front face of cathode : would allow a simple geometry check
OGeo::makeGeometryInstance(GMergedMesh* mergedmesh)

Five volumes within repeated PMT instance:

[2015-Oct-07 12:26:54.103163]:info: GGeo::dumpNodeInfo mmindex 1 solids 5
    720    362   3199   3155 lv            __dd__Geometry__PMT__lvPmtHemi0xc133740 pv __dd__Geometry__AD__lvOIL--pvAdPmtArray--pvAdPmtA.......--pvAdPmtUnit--pvAdPmt0xc2a6b40
    672    338   3200   3199 lv      __dd__Geometry__PMT__lvPmtHemiVacuum0xc2c7cc8 pv __dd__Geometry__PMT__lvPmtHemi--pvPmtHemiVacuum0xc1340e8
    960    482   3201   3200 lv     __dd__Geometry__PMT__lvPmtHemiCathode0xc2cdca0 pv __dd__Geometry__PMT__lvPmtHemiVacuum--pvPmtHemiCathode0xc02c380
    480    242   3202   3200 lv      __dd__Geometry__PMT__lvPmtHemiBottom0xc12ad60 pv __dd__Geometry__PMT__lvPmtHemiVacuum--pvPmtHemiBottom0xc21de78
     96     50   3203   3200 lv      __dd__Geometry__PMT__lvPmtHemiDynode0xc02b280 pv __dd__Geometry__PMT__lvPmtHemiVacuum--pvPmtHemiDynode0xc04ad28

Note identity relative transform for 1st three:

In [5]: n = np.load("nodeinfo.npy")

In [6]: n
Out[6]:
array([[ 720,  362, 3199, 3155],
       [ 672,  338, 3200, 3199],
       [ 960,  482, 3201, 3200],
       [ 480,  242, 3202, 3200],
       [  96,   50, 3203, 3200]], dtype=uint32)



In [1]: t = np.load("transforms.npy")

In [4]: t.reshape(-1,4,4)
Out[4]:
array([[[  1. ,   0. ,   0. ,   0. ],
        [  0. ,   1. ,   0. ,   0. ],
        [  0. ,   0. ,   1. ,   0. ],
        [  0. ,   0. ,   0. ,   1. ]],

       [[  1. ,   0. ,   0. ,   0. ],
        [  0. ,   1. ,   0. ,   0. ],
        [  0. ,   0. ,   1. ,   0. ],
        [  0. ,   0. ,   0. ,   1. ]],

       [[  1. ,   0. ,   0. ,   0. ],
        [  0. ,   1. ,   0. ,   0. ],
        [  0. ,   0. ,   1. ,   0. ],
        [  0. ,   0. ,   0. ,   1. ]],

       [[  1. ,   0. ,   0. ,   0. ],
        [  0. ,   1. ,   0. ,   0. ],
        [  0. ,   0. ,   1. ,   0. ],
        [  0. ,   0. ,  69. ,   1. ]],

       [[  1. ,   0. ,   0. ,   0. ],
        [  0. ,   1. ,   0. ,   0. ],
        [  0. ,   0. ,   1. ,   0. ],
        [  0. ,   0. , -81.5,   1. ]]], dtype=float32)

Analytic OptiX geometry

Per triangle buffers with boundaries, nodes and sensors are used by TriangleMesh to set attributes based on primIdx:

In [1]: b = np.load("boundaries.npy")

In [2]: b
Out[2]:
array([[11],
       [11],
       [11],
       ...,
       [12],
       [12],
       [12]], dtype=int32)

In [3]: b.shape
Out[3]: (434816, 1)

In [4]: n = np.load("nodes.npy")

In [5]: n.shape
Out[5]: (434816, 1)

In [6]: n
Out[6]:
array([[ 3153],
       [ 3153],
       [ 3153],
       ...,
       [12220],
       [12220],
       [12220]], dtype=int32)

In [7]: s = np.load("sensors.npy")

In [8]: s.shape
Out[8]: (434816, 1)

In [9]: s
Out[9]:
array([[3154],
       [3154],
       [3154],
       ...,

Whats the equivalent for instanced analytic geometry ?

In the full analytic treatment might have 10-20 primitives per instance arranged into a CSG tree of boolean operations and transforms. Although there are only 5 volumes there are multiple primitives (spheres, cones, boxes) inside each.

On top of identifying the primitive also have the instance index.

So need an analytic index:

instance_index*numPrim + prim_index

Triangulated Case

OGeo.cc:

283     optix::Geometry geometry = m_context->createGeometry();
284     RayTraceConfig* cfg = RayTraceConfig::getInstance();
285     geometry->setIntersectionProgram(cfg->createProgram("TriangleMesh.cu.ptx", "mesh_intersect"));
286     geometry->setBoundingBoxProgram(cfg->createProgram("TriangleMesh.cu.ptx", "mesh_bounds"));
...
296     geometry->setPrimitiveCount(numFaces);

Gross structure of geometry communicated to OptiX by returning bounding boxes from the BoundingBoxProgram for each primIdx. The range of primIdx is specified by setPrimitiveCount

When a ray intersects with a bbox the associated primIdx is used to invoke the IntersectionProgram which reports the parametric t with rtPotentialIntersection(t)

cu/TriangleMesh.cu:

96 RT_PROGRAM void mesh_bounds (int primIdx, float result[6])
34 RT_PROGRAM void mesh_intersect(int primIdx)

With instanced geometry:

166 optix::Group OGeo::makeRepeatedGroup(GMergedMesh* mm, unsigned int limit)
167 {
168     GBuffer* tbuf = mm->getITransformsBuffer();
169     unsigned int numTransforms = limit > 0 ? std::min(tbuf->getNumItems(), limit) : tbuf->getNumItems() ;
170     assert(tbuf && numTransforms > 0);
171
172     LOG(info) << "OGeo::makeRepeatedGroup numTransforms " << numTransforms ;
173
174     float* tptr = (float*)tbuf->getPointer();
175
176     optix::Group group = m_context->createGroup();
177     group->setChildCount(numTransforms);
178
179     optix::GeometryInstance gi = makeGeometryInstance(mm);
180     optix::GeometryGroup repeated = m_context->createGeometryGroup();
181     repeated->addChild(gi);
182     repeated->setAcceleration( makeAcceleration() );
///
///   can an id be planted in GeometryGroup  ?
///   seems not but can with GeometryInstance according to docs,
///   so need to adjust to having a GeometryInstance for every xform
///   to plant an instance index
///
183
184     bool transpose = true ;
185     for(unsigned int i=0 ; i<numTransforms ; i++)
186     {
187         optix::Transform xform = m_context->createTransform();
188         group->setChild(i, xform);
189         xform->setChild(repeated);
190         const float* tdata = tptr + 16*i ;
191         optix::Matrix4x4 m(tdata) ;
192         xform->setMatrix(transpose, m.getData(), 0);
193         //dump("OGeo::makeRepeatedGroup", m.getData());
194     }
195     return group ;
196 }

Hmm how with instanced geometry to know which instance was landed on, because all the geometry info lives within the instance island ?

Is there an easy way to know withing the closest hit or any hit program which
object was hit? I'd prefer to use a single material for all but can encode the
information into the material. I do however wish to use the same hit program to
be flexible with the number of objects.


(Detlef Roettger)
This should be pretty easy, if there aren't any other circumstances involved.

- If you have exactly one Transform node per object,
  let your Material have a variable rtDeclareVariable(unsigned int, objectID, , );
- In your given node hierarchy you load the Geometry only once,
  but assign different Material parameters (=> objectID) per hierarchy path
  to each GeometryInstance (i.e. per Transform) to identify the Geometry as you wish.
- To report back to the ray generation program that you hit a specific object,
  add a member unsigned int objectID; to your custom PerRayData payload.
- Inside the closest-hit program write the objectID from the material
  into the objectID of the current ray payload.
- Inside the ray generation program add a switch-case which writes
  the other PerRayData results you generated into the output
  buffer you select with the PerRayData objectID.
In [1]: i = np.load("identity.npy")

In [2]: i
Out[2]:
array([[3199,   47,   19,    1],
       [3200,   46,   20,    2],
       [3201,   43,   21,    3],
       [3202,   44,    1,    4],
       [3203,   45,    1,    5]], dtype=uint32)

#  hmm those boundary 1 look wrong ? Rock inside the PMT ?  off-by-one problem ?


In [1]: n = np.load("nodeinfo.npy")

In [2]: n
Out[2]:
array([[ 720,  362, 3199, 3155],
       [ 672,  338, 3200, 3199],
       [ 960,  482, 3201, 3200],
       [ 480,  242, 3202, 3200],
       [  96,   50, 3203, 3200]], dtype=uint32)




boundary : index  0 x6   0 019d50af046b6733287e43af2e8f7fa2 Vacuum/Vacuum/-/-
boundary : index  1 x6   6 1c71e6371ce86dec9ed4f0e2395f1933 Rock/Vacuum/-/-
boundary : index 18 x6 108 77a84102a9c397d91eed17b2bc0988ce GdDopedLS/LiquidScintillator/-/-
boundary : index 19 x6 114 b609b4350dfeebd16df30bc7c0132459 Pyrex/MineralOil/-/-
boundary : index 20 x6 120 05fb49644888940aab8eb466d69d3693 Vacuum/Pyrex/-/-
boundary : index 21 x6 126 31ec4ad900fe9b40be261fa11af380b7 Bialkali/Vacuum/-/lvPmtHemiCathodeSensorSurface
boundary : index 22 x6 132 df883e53b3d96edda237a45ba82a0e94 UnstStainlessSteel/MineralOil/-/-

Does OpaqueVacuum have same properties as Rock ?:

[2015-Oct-07 16:35:33.313017]:info: AssimpGGeo::convertStructureVisit nodeIndex   3199 ( mti   68 mt 0x7fd03def9750 )                Pyrex ( mti_p   59 mt_p 0x7fd040460690 )           MineralOil ( msi   47 mesh 0x7fd03ded9840 ) pmt-hemi0xc0fed90
[2015-Oct-07 16:35:33.313442]:info: AssimpGGeo::convertStructureVisit nodeIndex   3200 ( mti   76 mt 0x7fd040453ff0 )               Vacuum ( mti_p   68 mt_p 0x7fd03def9750 )                Pyrex ( msi   46 mesh 0x7fd04044cbc0 ) pmt-hemi-vac0xc21e248
[2015-Oct-07 16:35:33.314093]:info: AssimpGGeo::convertStructureVisit nodeIndex   3201 ( mti   48 mt 0x7fd03874b5e0 )             Bialkali ( mti_p   76 mt_p 0x7fd040453ff0 )               Vacuum ( msi   43 mesh 0x7fd03dee03c0 ) pmt-hemi-cathode0xc2f1ce8
[2015-Oct-07 16:35:33.314487]:info: AssimpGGeo::convertStructureVisit nodeIndex   3202 ( mti   64 mt 0x7fd03dec5580 )         OpaqueVacuum ( mti_p   76 mt_p 0x7fd040453ff0 )               Vacuum ( msi   44 mesh 0x7fd0403e6940 ) pmt-hemi-bot0xc22a958
[2015-Oct-07 16:35:33.314863]:info: AssimpGGeo::convertStructureVisit nodeIndex   3203 ( mti   64 mt 0x7fd03dec5580 )         OpaqueVacuum ( mti_p   76 mt_p 0x7fd040453ff0 )               Vacuum ( msi   45 mesh 0x7fd03def9290 ) pmt-hemi-dynode0xc346c50

Now with simplified OptiX geometry

ggv --mdyb -G
ggv --mdyb --torchconfig "frame=3201;source=0,0,1000;target=0,0,0;radius=300;" --save --simplify


ggv --torchconfig "frame=3201;source=0,0,1000;target=0,0,0;radius=300;" --save