Opticks replaces Geant4 optical photon simulation with an equivalent implementation that benefits from state-of-the-art GPU ray tracing from NVIDIA OptiX. All optically relevant aspects of Geant4 context must be translated+copied to GPU:
- geometry : solids, structure, material+surface properties
- generation : Cerenkov + Scintillation (using Gensteps from Geant4)
- propagation : Rayleigh scattering, absorption, reemission, boundary
Achieving+maintaining equivalence is time consuming, BUT:
- transformative performance benefits >1000x Geant4
Helpful addition of active users, BUT: JUNO-Opticks still needs many more active users
tut_detsim.py options:
Using GtOpticksTool GenTool to run from input photons : NumPy arrays (num_photons,4,4):
tut_detsim.py ... --opticks-mode 3 ... opticks --input-photon-path /path/to/input_photons.npy --input-photon-repeat 10000 ## repeat photons --input-photon-wavelength 360,380,400,420,440,460 ## override
G4OpticksRecorder/CManager/CRecorder/CWriter
~/opticks/ana/evt.py ab.py ... NumPy based analysis machinery
C+S Gensteps : Geant4 -> Opticks
Interface to Opticks CFG4 Package
G4OpticksRecorder/CManager/CRecorder/CWriter
34 struct G4OK_API G4OpticksRecorder 35 { ... 47 G4OpticksRecorder(); 48 virtual ~G4OpticksRecorder(); 49 50 void setGeometry(const GGeo* ggeo); 51 52 virtual void BeginOfRunAction(const G4Run*); 53 virtual void EndOfRunAction(const G4Run*); 54 55 virtual void BeginOfEventAction(const G4Event*); 56 virtual void EndOfEventAction(const G4Event*); 57 58 virtual void PreUserTrackingAction(const G4Track*); 59 virtual void PostUserTrackingAction(const G4Track*); 60 61 virtual void UserSteppingAction(const G4Step*); 62 63 void ProcessHits( const G4Step* step, bool efficiency_collect ); 64 65 static G4OpticksRecorder* fInstance; 66 67 private: 68 void TerminateEvent(); 69 70 };
200 G4VParticleChange* 201 DsG4Scintillation::PostStepDoIt(const G4Track& aTrack, const G4Step& aStep) ... 235 flagReemission= doReemission 236 && aTrack.GetTrackStatus() == fStopAndKill 237 && aStep.GetPostStepPoint()->GetStepStatus() != fGeomBoundary;
Geant4 WITH_G4OPTICKS photon_id
CRecorder/CWriter : REJOIN reemission secondary tracks with ancestors
epsilon:ana blyth$ tds3gun.sh 1 ## seqhis: 64bit uint : 16x4bit step flags for each photon
In [1]: ab.his[:20] ## OK:1 G4:-1 OK-G4 "c2" deviation
. n seqhis a b a-b (a-b)^2/(a+b) label ## optickscore/OpticksPhoton.h enum
## hexstring
0000 42 1822 1721 101 2.88 SI AB ## AB : BULK_ABSORB
0001 7ccc2 1446 1406 40 0.56 SI BT BT BT SD ## SD : SURFACE_DETECT
0002 7ccc62 672 666 6 0.03 SI SC BT BT BT SD ## SC : BULK_SCATTER
0003 8ccc2 649 597 52 2.17 SI BT BT BT SA ## BT : BOUNDARY_TRANSMIT
0004 8cc2 606 615 -9 0.07 SI BT BT SA ## SI : SCINTILLATION
0005 452 538 536 2 0.00 SI RE AB ## RE : BULK_REEMIT
0006 7ccc52 433 438 -5 0.03 SI RE BT BT BT SD
0007 462 397 405 -8 0.08 SI SC AB
0008 8ccc62 269 262 7 0.09 SI SC BT BT BT SA
0009 7ccc662 242 222 20 0.86 SI SC SC BT BT BT SD
0010 8cc62 217 212 5 0.06 SI SC BT BT SA
0011 7ccc652 211 205 6 0.09 SI RE SC BT BT BT SD
0012 8ccc52 200 201 -1 0.00 SI RE BT BT BT SA
0013 8cc52 158 192 -34 3.30 SI RE BT BT SA
0014 4552 181 165 16 0.74 SI RE RE AB
0015 41 164 145 19 1.17 CK AB ## CK : CERENKOV
0016 7ccc552 135 160 -25 2.12 SI RE RE BT BT BT SD
0017 4cc2 130 115 15 0.92 SI BT BT AB
0018 4652 120 117 3 0.04 SI RE SC AB
. TOTALS: 11684 11684 52.92 52.92/63 = 0.84 pvalue:P[C2>]:0.814 1-pvalue:P[C2<]:0.186
In [2]: ab.his.ss[ab.his.c2 > 2.7] ## largest chi-squared contributors -> next issue to look into
Out[2]:
array(['0000 42 1822 1721 101 2.88 SI AB',
'0013 8cc52 158 192 -34 3.30 SI RE BT BT SA',
'0020 8ccc662 75 108 -33 5.95 SI SC SC BT BT BT SA',
'0027 8cc552 49 70 -21 3.71 SI RE RE BT BT SA',
'0029 4562 39 66 -27 6.94 SI SC RE AB'],
In [7]: ab.a.seqhis_ana.table.compare(ab.b.seqhis_ana.table, ordering="sum") Out[7]: . cfo:sum 1:g4live:tds3gun -1:g4live:tds3gun . 11278 11278 1766.28/69 = 25.60 (pval:0.000 prob:1.000) 0000 42 1653 1665 -12 0.04 [2 ] SI AB 0001 7ccc2 1292 1230 62 1.52 [5 ] SI BT BT BT SD 0002 8ccc2 590 674 -84 5.58 [5 ] SI BT BT BT SA 0003 7ccc62 581 552 29 0.74 [6 ] SI SC BT BT BT SD 0004 452 422 534 -112 13.12 [3 ] SI RE AB 0005 7ccc52 380 397 -17 0.37 [6 ] SI RE BT BT BT SD 0006 462 392 367 25 0.82 [3 ] SI SC AB 0007 8ccc62 251 267 -16 0.49 [6 ] SI SC BT BT BT SA 0008 8cc2 0 464 -464 464.00 [4 ] SI BT BT SA ## LS->Acrylic->Water->SURFACE_ABSORB on Tyvek 0009 7ccc662 219 213 6 0.08 [7 ] SI SC SC BT BT BT SD 0010 4cc2 278 127 151 56.30 [4 ] SI BT BT AB 0011 8ccc52 154 188 -34 3.38 [6 ] SI RE BT BT BT SA 0012 7ccc652 157 159 -2 0.01 [7 ] SI RE SC BT BT BT SD 0013 41 142 144 -2 0.01 [2 ] CK AB 0014 4cc62 197 71 126 59.24 [5 ] SI SC BT BT AB 0015 4552 124 142 -18 1.22 [4 ] SI RE RE AB 0016 4662 137 121 16 0.99 [4 ] SI SC SC AB 0017 4652 121 112 9 0.35 [4 ] SI RE SC AB 0018 7ccc552 102 124 -22 2.14 [7 ] SI RE RE BT BT BT SD 0019 7cccc2 53 154 -101 49.28 [6 ] SI BT BT BT BT SD 0020 8cc62 0 186 -186 186.00 [5 ] SI SC BT BT SA 0021 8ccc662 69 107 -38 8.20 [7 ] SI SC SC BT BT BT SA
epsilon:ana blyth$ tds3gun.sh 1 # IPython session using Opticks NumPy based analysis machinery
In [1]: b.sel = "SI BT BT SA" # selecting G4 photons that go direct to Tyvek
In [2]: b.ox.shape # ox : final photons array honours the selection
Out[2]: (464, 4, 4)
In [3]: p = b.ox[0:1] ; p # first photon
Out[3]:
A([[[ 14210.083 , 5228.8896, -13142.859 , 110.41 ], # position, time
[ 0.7191, 0.2595, -0.6447, 1. ], # direction, weight
[ -0.4468, -0.538 , -0.7148, 415.3976], # polarization, wavelength
[ 0. , 0. , 0. , 0. ]]], # uint flags: not visible as float
dtype=float32)
In [4]: p[0,0,:3] -= p[0,1,:3]*2220. # back up the photon by 2220mm to position 10mm into the water
In [5]: np.save("/tmp/check_innerwater.npy", p ) # save photon array with 1 photon to .npy file
Perform both Geant4 and Opticks simulations with 100k repeats of the input photon
tut_detsim.py ... --opticks-mode 3 # enable Geant4 + Opticks simulations --opticks-anamgr # G4Track, G4Step --> G4OpticksRecorder opticks # GtOpticksTool input photon "GenTool" --input-photon-path /tmp/check_innerwater.npy --input-photon-repeat 100000
In [2]: ab.his # repr of opticks.ana.seq:SeqTable object Out[2]: ab.his . seqhis_ana cfo:sum 1:g4live:tds3gun -1:g4live:tds3gun c2 ab ba . 11142 11142 616.50/66 = 9.34 n iseq a b a-b c2 [ns] label 0000 42 1666 1621 45 0.62 [2 ] SI AB 0001 7ccc2 1264 1258 6 0.01 [5 ] SI BT BT BT SD 0002 8ccc2 581 766 -185 25.41 [5 ] SI BT BT BT SA 0003 7ccc62 579 543 36 1.16 [6 ] SI SC BT BT BT SD 0004 8cc2 570 496 74 5.14 [4 ] SI BT BT SA 0005 452 408 495 -87 8.38 [3 ] SI RE AB 0006 462 399 351 48 3.07 [3 ] SI SC AB 0007 7ccc52 360 385 -25 0.84 [6 ] SI RE BT BT BT SD 0008 8ccc62 239 258 -19 0.73 [6 ] SI SC BT BT BT SA 0009 7ccc662 218 195 23 1.28 [7 ] SI SC SC BT BT BT SD 0010 8cc62 195 180 15 0.60 [5 ] SI SC BT BT SA 0011 4cc2 268 104 164 72.30 [4 ] SI BT BT AB 0012 8ccc52 160 191 -31 2.74 [6 ] SI RE BT BT BT SA 0013 7ccc652 163 165 -2 0.01 [7 ] SI RE SC BT BT BT SD 0014 41 156 160 -4 0.05 [2 ] CK AB 0015 4552 118 152 -34 4.28 [4 ] SI RE RE AB 0016 8cc52 136 133 3 0.03 [5 ] SI RE BT BT SA 0017 4662 125 114 11 0.51 [4 ] SI SC SC AB 0018 4cc62 189 40 149 96.95 [5 ] SI SC BT BT AB . 11142 11142 616.50/66 = 9.34
In [3]: a.sel = "SI BT BT BT SA" ## select photons with this history In [15]: a.bn.reshape(-1,4).view(np.int8)[:20] ## signed boundary at up to 16 steps of the photon Out[15]: A([[ 18, 17, -23, -25, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [ 18, 17, -23, -27, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], ... [ 18, 17, -23, -27, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [ 18, 17, -24, -25, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]], dtype=int8) In [17]: print(a.blib.format(a.bn.reshape(-1,4).view(np.int8)[0])) ## 16*char(int8) packed into uint4 4*32bit 18 : Acrylic///LS ## boundary : outer-material/outer-surface/inner-surface/inner-material 17 : Water///Acrylic ## +ve boundary : photon direction is with the normal, exiting the shape -23 : Water///Pyrex ## -ve boundary : photon direction against the normal, entering the shape -25 : Pyrex/NNVTMCPPMT_photocathode_logsurf2/NNVTMCPPMT_photocathode_logsurf1/Vacuum In [18]: print(a.blib.format(a.bn.reshape(-1,4).view(np.int8)[1])) 18 : Acrylic///LS 17 : Water///Acrylic -23 : Water///Pyrex -27 : Pyrex/HamamatsuR12860_photocathode_logsurf2/HamamatsuR12860_photocathode_logsurf1/Vacuum In [19]: print(a.blib.format(a.bn.reshape(-1,4).view(np.int8)[19])) 18 : Acrylic///LS 17 : Water///Acrylic -24 : Pyrex///Pyrex ## expect Water///Pyrex --> GEOMETRY PROBLEM -25 : Pyrex/NNVTMCPPMT_photocathode_logsurf2/NNVTMCPPMT_photocathode_logsurf1/Vacuum
Possible approaches to handle degenerate geometry:
- fix source geometry removing the pointless Pyrex///Pyrex -0.001mm boundary
- seems to cause no problem for Geant4 : get "microStep" of ~0.001-0.002mm
- eg --dbgseqhis 0x7ccccd dumps Geant4 details for photons in category
- experience shows is time consuming to get agreement on geometry change
- runtime workaround trying to notice inconsistency by maintaining state of which material are in
- need very strong reasons to add complexity to GPU code, so disqualify this
- skip the near degenerate inner Pyrex solids in the translated GPU geometry
- easy, causing no problems because are removing a pointless Pyrex///Pyrex border
- BUT: requires suppression of Geant4 "microSteps" in CRecorder to facilitate history comparison
Currently using 3, with Opticks commandline option:
--skipsolidname NNVTMCPPMT_body_solid, HamamatsuR12860_body_solid_1_9, PMT_20inch_veto_body_solid_1_2
epsilon:ana blyth$ tds3ip.sh 1
In [1]: ab.his[:15]
Out[1]:
ab.his
. seqhis_ana cfo:sum 1:g4live:tds3ip -1:g4live:tds3ip
. 100000 100000 739.41/9 = 82.16 (pval:0.000 prob:1.000)
0000 8d 93766 92777 989 5.24 [2 ] TO SA
0001 4d 6031 5918 113 1.07 [2 ] TO AB
0002 7c6d 38 311 -273 213.55 [4 ] TO SC BT SD
0003 86d 33 236 -203 153.19 [3 ] TO SC SA
0004 4cc6d 10 212 -202 183.80 [5 ] TO SC BT BT AB
0005 8c6d 13 80 -67 48.27 [4 ] TO SC BT SA
0006 46d 20 63 -43 22.28 [3 ] TO SC AB
0007 8ccac6d 0 72 -72 72.00 [7 ] TO SC BT SR BT BT SA
0008 46cc6d 1 39 -38 36.10 [6 ] TO SC BT BT SC AB
0009 4c6d 10 21 -11 3.90 [4 ] TO SC BT AB
0010 7cc6d 2 27 -25 0.00 [5 ] TO SC BT BT SD
0011 ccacccac6d 0 26 -26 0.00 [10] TO SC BT SR BT BT BT SR BT BT
0012 4ccc6d 0 19 -19 0.00 [6 ] TO SC BT BT BT AB
0013 7ccccc6d 9 9 0 0.00 [8 ] TO SC BT BT BT BT BT SD
0014 466cc6d 1 17 -16 0.00 [7 ] TO SC BT BT SC SC AB
. 100000 100000 739.41/9 = 82.16 (pval:0.000 prob:1.000)
Opticks GPU equivalent
// optixrap/cu/scintillationstep.h 185 __device__ void 186 generate_scintillation_photon(Photon& p, ScintillationStep& ss, curandState& rng) 187 { ... 199 p.wavelength = reemission_lookup(curand_uniform(&rng)); 200 // optixrap/cu/reemission_lookup.h 025 static __device__ __inline__ float reemission_lookup(float u) 26 { 27 float ui = u/reemission_domain.z + 0.5f ; 28 return tex2D(reemission_texture, ui, 0.5f ); 29 }
200 G4VParticleChange* 201 DsG4Scintillation::PostStepDoIt( const G4Track& aTrack, const G4Step& aStep) 208 { ... 540 G4PhysicsOrderedFreeVector* ScintillationIntegral = NULL; 543 ScintillationIntegral = 544 (G4PhysicsOrderedFreeVector*) ((*theFastIntegralTable)(materialIndex)); ... 579 for(G4int i = 0 ; i < NumPhoton ; i++) { ... 583 G4double sampledEnergy; 586 G4double CIIvalue = G4UniformRand()* 587 ScintillationIntegral->GetMaxValue(); 588 sampledEnergy= 589 ScintillationIntegral->GetEnergy(CIIvalue); 096 G4double G4PhysicsOrderedFreeVector::GetEnergy(G4double aValue) 97 { 98 G4double e; ... 104 size_t closestBin = FindValueBinLocation(aValue); 105 e = LinearInterpolationOfEnergy(aValue, closestBin); 107 return e; 108 } 110 size_t G4PhysicsOrderedFreeVector::FindValueBinLocation(G4double aValue) 111 { 112 size_t bin = std::lower_bound(dataVector.begin(), dataVector.end(), aValue) 113 - dataVector.begin() - 1; 114 bin = std::min(bin, numberOfNodes-2); 115 return bin; 116 }
DsG4Scintillator compared with | chi2 | note |
---|---|---|
hd0_cudaFilterModePoint | 13.79 | "artifact" issue in tails, terrible chi2 |
hd0 | 1.00 | interpolation enabled, fixes chi2 |
hd20 | 0.88 | effectively x20 bins, improves chi2 |
hd20_cudaFilterModePoint | 1.29 | XHD "HD20" even OK without interpolation |
GPU texture lookup
float scint_wavelength_hd20(curandStateXORWOW& rng) { float u0 = curand_uniform(&rng); float wl ; constexpr float y0 = 0.5f/3.f ; constexpr float y1 = 1.5f/3.f ; constexpr float y2 = 2.5f/3.f ; if( u0 < 0.05f ) { wl = tex2D(scint_tex, u0*20.f , y1 ); } else if ( u0 > 0.95f ) { wl = tex2D (scint_tex, (u0 - 0.95f)*20.f , y2 ); } else { wl = tex2D (scint_tex, u0, y0 ); } return wl ; }
156 NPY<double>* X4Scintillation::CreateGeant4InterpolatedInverseCDF( 157 const G4PhysicsOrderedFreeVector* ScintillatorIntegral, 158 unsigned num_bins, unsigned hd_factor, .. 161 ) 164 double mx = ScintillatorIntegral->GetMaxValue() ; 166 NPY<double>* icdf = NPY<double>::make(3, num_bins, 1 ); 170 int nj = icdf->getShape(1); 180 double edge = 1./double(hd_factor) ; ... 202 for(int j=0 ; j < nj ; j++) 203 { 204 double u_all = double(j)/double(nj) ; 205 double u_lhs = double(j)/double(hd_factor*nj) ; 206 double u_rhs = 1. - edge + double(j)/double(hd_factor*nj) ; 207 208 double energy_all = ScintillatorIntegral->GetEnergy( u_all*mx ); 209 double energy_lhs = ScintillatorIntegral->GetEnergy( u_lhs*mx ); 210 double energy_rhs = ScintillatorIntegral->GetEnergy( u_rhs*mx ); 211 212 double wavelength_all = h_Planck*c_light/energy_all/nm ; 213 double wavelength_lhs = h_Planck*c_light/energy_lhs/nm ; 214 double wavelength_rhs = h_Planck*c_light/energy_rhs/nm ; 215 217 icdf->setValue(0, j, 0, 0, wavelength_all ); 218 icdf->setValue(1, j, 0, 0, wavelength_lhs ); 219 icdf->setValue(2, j, 0, 0, wavelength_rhs ); 220 } 221 return icdf ; 222 }
https://bitbucket.org/simoncblyth/opticks/src/master/extg4/X4Scintillation.cc
https://bitbucket.org/simoncblyth/opticks/src/master/qudarap/qctx.h
Č photon gen. : Spot the bug
continue-ing a do-while loop jumps to condition.
sampleRI < BetaInverse :
do-while looping continues naturally as always:
rand*maxSin2 > sin2Theta
168 G4VParticleChange* 169 G4Cerenkov_modified::PostStepDoIt( const G4Track& aTrack, const G4Step& aStep) ... 252 G4double Pmin = Rindex->GetMinLowEdgeEnergy(); 253 G4double Pmax = Rindex->GetMaxLowEdgeEnergy(); 254 G4double dp = Pmax - Pmin; ... 268 G4double maxCos = BetaInverse / nMax; 270 G4double maxSin2 = (1.0 - maxCos) * (1.0 + maxCos); ... 315 for (G4int i = 0; i < fNumPhotons; i++) { 317 318 G4double rand; 319 G4double sampledEnergy, sampledRI; 320 G4double cosTheta, sin2Theta; ... 324 do { 325 rand = G4UniformRand(); 326 sampledEnergy = Pmin + rand * dp; 327 sampledRI = Rindex->Value(sampledEnergy); 328 329 // check if n(E) > 1/beta 330 if (sampledRI < BetaInverse) { 331 continue; 332 } 333 334 cosTheta = BetaInverse / sampledRI; 341 342 sin2Theta = (1.0 - cosTheta)*(1.0 + cosTheta); 343 rand = G4UniformRand(); 344 346 } while (rand*maxSin2 > sin2Theta);
\ B / \ . | . / AC ct / n 1 i BetaInverse \ C | C / cos th = ---- = -------- = ------ = --- = ------------- \ . \ | / . / AB bct b n n sampledRI . \ bct / . \ | / BetaInverse \ | / ct maxCos = ----------------- \ |th/ ---- nMax \ | / n \|/ A Particle travels AB, light travels AC, ACB is right angle Only get Cerenkov radiation when cos th <= 1 , beta >= beta_min = 1/n BetaInverse <= BetaInverse_max = n At the small beta threshold AB = AC, beta = beta_min = 1/n eg for n = 1.333, beta_min = 0.75 cos th = 1, th = 0 light is in direction of the particle For ultra relativistic particle beta = 1, there is a maximum angle th = arccos( 1/n )
1.5/1.8 = .83, 1.5/1.62 = 0.92
FIRST LOOK, AFTER BUG FIX. Fixed BetaInverse = 1.50
In [1]: ri = np.load(os.path.join(kd, "GScintillatorLib/LS_ori/RINDEX.npy")) ; ri[:,0] *= 1e6 In [2]: ri_w = ri.copy() ; ri_w[:,0] = 1240./ri_w[:,0] ; In [2]: np.c_[ri, ri_w] Out[2]: array([[ 1.55 , 1.4781, 800. , 1.4781], [ 1.7951, 1.48 , 690.7886, 1.48 ], [ 2.105 , 1.4842, 589.0764, 1.4842], [ 2.2708, 1.4861, 546.0703, 1.4861], [ 2.5511, 1.4915, 486.0629, 1.4915], [ 2.845 , 1.4955, 435.8554, 1.4955], [ 3.0636, 1.4988, 404.7513, 1.4988], [ 4.1328, 1.5264, 300.038 , 1.5264], [ 6.2 , 1.6185, 200. , 1.6185], [ 6.526 , 1.6176, 190.0092, 1.6176], [ 6.889 , 1.527 , 179.9971, 1.527 ], [ 7.294 , 1.5545, 170.0027, 1.5545], [ 7.75 , 1.793 , 160. , 1.793 ], [ 8.267 , 1.7826, 149.994 , 1.7826], [ 8.857 , 1.6642, 140.0023, 1.6642], [ 9.538 , 1.5545, 130.0063, 1.5545], [ 10.33 , 1.4536, 120.0387, 1.4536], [ 15.5 , 1.4536, 80. , 1.4536]])
Expected Straightforward Updates
Uncertain Difficulty : JUNO Geometry Issues
Currently skipping LSExpDetectorConstruction::setupCD_Sticks to allow fair comparisons.
590 "uni_acrylic3" Fasteners : cost 65x more than all 45.6k PMTs
uni_acrylic3
092 AdditionAcrylicConstruction::makeAdditionLogical(){ ... 108 double ZNodes3[3]; 109 double RminNodes3[3]; 110 double RmaxNodes3[3]; 111 ZNodes3[0] = 5.7*mm; RminNodes3[0] = 0*mm; RmaxNodes3[0] = 450.*mm; 112 ZNodes3[1] = 0.0*mm; RminNodes3[1] = 0*mm; RmaxNodes3[1] = 450.*mm; 113 ZNodes3[2] = -140.0*mm; RminNodes3[2] = 0*mm; RmaxNodes3[2] = 200.*mm; 114 115 solidAddition_down = new G4Polycone("solidAddition_down",0.0*deg,360.0*deg,3,ZNodes3,RminNodes3,RmaxNodes3); ... 122 solidAddition_up = new G4Sphere("solidAddition_up",0*mm,17820*mm,0.0*deg,360.0*deg,0.0*deg,180.*deg); 123 124 uni_acrylic1 = new G4SubtractionSolid("uni_acrylic1",solidAddition_down,solidAddition_up,0,G4ThreeVector(0*mm,0*mm,+17820.0*mm)); 125 126 solidAddition_up1 = new G4Tubs("solidAddition_up1",120*mm,208*mm,15.2*mm,0.0*deg,360.0*deg); 127 uni_acrylic2 = new G4SubtractionSolid("uni_acrylic2",uni_acrylic1,solidAddition_up1,0,G4ThreeVector(0.*mm,0.*mm,-20*mm)); 128 solidAddition_up2 = new G4Tubs("solidAddition_up2",0,14*mm,52.5*mm,0.0*deg,360.0*deg); 129 130 for(int i=0;i<8;i++) 131 { 132 uni_acrylic3 = new G4SubtractionSolid("uni_acrylic3",uni_acrylic2,solidAddition_up2,0,G4ThreeVector(164.*cos(i*pi/4)*mm,164.*sin(i*pi/4)*mm,-87.5)); 133 uni_acrylic2 = uni_acrylic3; 134 135 } 136 137
Subtraction of huge sphere from small polycone
epsilon:ana blyth$ tds3gun.sh 1 ## seqhis: 64bit uint : 16x4bit step flags for each photon
In [1]: ab.his[:20] ## OK:1 G4:-1 OK-G4 "c2" deviation
. n seqhis a b a-b (a-b)^2/(a+b) label ## optickscore/OpticksPhoton.h enum
## hexstring
0000 42 1822 1721 101 2.88 SI AB ## AB : BULK_ABSORB
0001 7ccc2 1446 1406 40 0.56 SI BT BT BT SD ## SD : SURFACE_DETECT
0002 7ccc62 672 666 6 0.03 SI SC BT BT BT SD ## SC : BULK_SCATTER
0003 8ccc2 649 597 52 2.17 SI BT BT BT SA ## BT : BOUNDARY_TRANSMIT
0004 8cc2 606 615 -9 0.07 SI BT BT SA ## SI : SCINTILLATION
0005 452 538 536 2 0.00 SI RE AB ## RE : BULK_REEMIT
0006 7ccc52 433 438 -5 0.03 SI RE BT BT BT SD
0007 462 397 405 -8 0.08 SI SC AB
0008 8ccc62 269 262 7 0.09 SI SC BT BT BT SA
0009 7ccc662 242 222 20 0.86 SI SC SC BT BT BT SD
0010 8cc62 217 212 5 0.06 SI SC BT BT SA
0011 7ccc652 211 205 6 0.09 SI RE SC BT BT BT SD
0012 8ccc52 200 201 -1 0.00 SI RE BT BT BT SA
0013 8cc52 158 192 -34 3.30 SI RE BT BT SA
0014 4552 181 165 16 0.74 SI RE RE AB
0015 41 164 145 19 1.17 CK AB ## CK : CERENKOV
0016 7ccc552 135 160 -25 2.12 SI RE RE BT BT BT SD
0017 4cc2 130 115 15 0.92 SI BT BT AB
0018 4652 120 117 3 0.04 SI RE SC AB
. TOTALS: 11684 11684 52.92 52.92/63 = 0.84 pvalue:P[C2>]:0.814 1-pvalue:P[C2<]:0.186
LS absorption length (red)
Next Steps
Opticks : state-of-the-art GPU ray traced optical simulation integrated with Geant4. Match with JUNO-Geant4 is converging. More pioneer users welcome
- More JUNO-Opticks users essential to bring into production
https://bitbucket.org/simoncblyth/opticks | code repository |
https://github.com/simoncblyth/opticks/releases | .zip .tar.gz archives |
https://simoncblyth.bitbucket.io | presentations and videos |
https://groups.io/g/opticks | forum/mailing list archive |
email:opticks+subscribe@groups.io | subscribe to mailing list |
GPU Ray Tracing APIs Converged
NVIDIA OptiX 6->7 : drastically slimmed down
More control/flexibility over everything.
Demands much more developer effort than OptiX 6
IAS < Inst < Solid < Prim < Node
struct CSGFoundry { void upload(); // to GPU ... std::vector<CSGSolid> solid ; // compounds (eg PMT) std::vector<CSGPrim> prim ; std::vector<CSGNode> node ; // shapes, operators std::vector<float4> plan ; // planes std::vector<qat4> tran ; // CSG transforms std::vector<qat4> itra ; // inverse CSG transforms std::vector<qat4> inst ; // instance transforms // entire geometry in four GPU allocations CSGPrim* d_prim ; CSGNode* d_node ; float4* d_plan ; qat4* d_itra ; };
referencing by offset, count
Simple intersect headers, common CPU/GPU types
GAS : Geometry Acceleration Structure
IAS : Instance Acceleration Structure
CSG : Constructive Solid Geometry
1st JUNO Opticks OptiX 7 Ray-trace
Very New CSG "Foundry" CPU/GPU Geometry
Factorize ~300,000 vol -> 10 comp
"progeny digest" characterizes subtree of every volume-node
ridx | plc | prim | component | note |
---|---|---|---|---|
0 | 1 | 3084 | 3084:sWorld | non-repeated remainder |
1 | 25600 | 5 | 5:PMT_3inch_pmt_solid | 4 types of PMT |
2 | 12612 | 5 | 5:NNVTMCPPMTsMask | |
3 | 5000 | 5 | 5:HamamatsuR12860sMask | |
4 | 2400 | 5 | 5:mask_PMT_20inch_vetosMask | |
5 | 590 | 1 | 1:sStrutBallhead | 4 parts of same assembly, BUT not grouped as siblings (not parent-child) |
6 | 590 | 1 | 1:uni1 | |
7 | 590 | 1 | 1:base_steel | |
8 | 590 | 1 | 1:uni_acrylic3 | |
9 | 504 | 130 | 130:sPanel | repeated parts of TT |
Increasing instancing : reduces memory for geometry -> improved performance
Vary Geom. Compare Render Times
Fast render -> Fast simulation
Same viewpoint, vary GPU geometry
Very large range of times 1:600
Table identifies slow geometry to fix :
Good performance for ONLY PMTs :
idx | -e | time(s) | relative | enabled geometry description |
---|---|---|---|---|
0 | 9, | 0.0017 | 0.1702 | ONLY: 130:sPanel |
1 | 7, | 0.0017 | 0.1714 | ONLY: 1:base_steel |
2 | 6, | 0.0019 | 0.1923 | ONLY: 1:uni1 |
3 | 5, | 0.0027 | 0.2780 | ONLY: 1:sStrutBallhead |
4 | 4, | 0.0032 | 0.3268 | ONLY: 5:mask_PMT_20inch_vetosMask |
5 | 1, | 0.0032 | 0.3287 | ONLY: 5:PMT_3inch_pmt_solid |
6 | 2, | 0.0055 | 0.5669 | ONLY: 5:NNVTMCPPMTsMask |
7 | 3, | 0.0074 | 0.7582 | ONLY: 5:HamamatsuR12860sMask |
8 | 1,2,3,4 | 0.0097 | 1.0000 | ONLY PMT |
9 | t8,0 | 0.0099 | 1.0179 | EXCL: 1:uni_acrylic3 3084:sWorld |
10 | 0, | 0.1171 | 12.0293 | ONLY: 3084:sWorld |
11 | t8, | 0.1186 | 12.1769 | EXCL: 1:uni_acrylic3 |
12 | t0, | 0.5278 | 54.2066 | EXCL: 3084:sWorld |
13 | 8, | 0.5310 | 54.5298 | ONLY: 1:uni_acrylic3 |
14 | t3, | 0.6017 | 61.7954 | EXCL: 5:HamamatsuR12860sMask |
15 | t2, | 0.6043 | 62.0620 | EXCL: 5:NNVTMCPPMTsMask |
16 | t5, | 0.6171 | 63.3787 | EXCL: 1:sStrutBallhead |
17 | t6, | 0.6196 | 63.6301 | EXCL: 1:uni1 |
18 | t7, | 0.6226 | 63.9458 | EXCL: 1:base_steel |
19 | t0 | 0.6240 | 64.0879 | 3084:sWorld |
20 | t4, | 0.6243 | 64.1169 | EXCL: 5:mask_PMT_20inch_vetosMask |
21 | t9, | 0.6335 | 65.0636 | EXCL: 130:sPanel |
22 | t1, | 0.6391 | 65.6384 | EXCL: 5:PMT_3inch_pmt_solid |