- Cerenkov energy sampling via ICDF lookups ?
- workaround poor float/double matching with rejection sampling
- ICDF lookup working on CPU, good enough chi2 match to rejection
- TODO: bring over to 2d GPU float texture
- Opticks updates for Geant4 11 API changes, G4 bugs
- Unclear how many more API changes coming, ongoing work
- 2D planar ray tracing to create cross-section views from intersects
- Useful technique to investigate geometry issues
- possible CSG bug found : A-(B-C) yielding spurious intersects
- TODO: confirm with simpler solids (elim. tree balancing)
- specific case fixable by simpler modelling, general fix unclear
Cerenkov Photons Energy Distrib
New approach : Cerenkov ICDF sampling ?
Sampling : generate (x0,x1,x2,... ) that follow distribution f(x)
Rejection Sampling (used by current G4Cerenkov)
Inverse Transform (ICDF) Sampling
Cerenkov radiation is electromagnetic equivalent of sonic boom in air or bow waves in water
BetaInverse^2 N_photon/369.81 = Integral ( 1 - ----------------- ) dE where BetaInverse < ri[E] ri(E)^2 = Integral [ 1 ] dE - BetaInverse^2 * Integral[ 1./(ri[E]*ri[E]) ] dE
G4Cerenkov::BuildThePhysicsTable -> CerenkovAngleIntegrals (misnomer)
Problems with G4Cerenkov::GetAverageNumberOfPhotons integration
636 G4double CAImax = CerenkovAngleIntegrals->GetMaxValue(); 637 638 G4double dp, ge; 642 if (nMax < BetaInverse) // ... no photons 649 else if (nMin > BetaInverse) { 650 dp = Pmax - Pmin; 651 ge = CAImax; 660 } else { 661 Pmin = Rindex->GetEnergy(BetaInverse); 662 dp = Pmax - Pmin; 667 G4double CAImin = CerenkovAngleIntegrals->GetValue(Pmin, isOutRange); 668 ge = CAImax - CAImin; 674 } 677 G4double NumPhotons = Rfact * charge/eplus * charge/eplus * (dp - ge * BetaInverse*BetaInverse);
Trapezoidal s2 Integration
s2(E) : from RINDEX(E) values and BetaInverse
BetaInverse*BetaInverse Integral [ 1. - ----------------------- ] (for BetaInverse < RINDEX) RINDEX * RINDEX Integral [ 1. - cos^2 theta ] Integral [ sin^2 theta ] Integral [ s2 ] ( s2 > 0 )
Do not split the integral, do "s2" integral in one pass. Advantages:
G4double G4Cerenkov_modified::GetAverageNumberOfPhotons_s2( const G4double charge, const G4double beta, const G4Material*, G4MaterialPropertyVector* Rindex) const { G4double BetaInverse = 1./beta; G4double s2integral(0.) ; for(unsigned i=0 ; i < Rindex->GetVectorLength()-1 ; i++) { G4double en_0 = Rindex->Energy(i) ; G4double en_1 = Rindex->Energy(i+1) ; G4double ri_0 = (*Rindex)[i] ; G4double ri_1 = (*Rindex)[i+1] ; G4double ct_0 = BetaInverse/ri_0 ; G4double ct_1 = BetaInverse/ri_1 ; G4double s2_0 = (1.-ct_0)*(1.+ct_0) ; G4double s2_1 = (1.-ct_1)*(1.+ct_1) ; G4bool cross = s2_0*s2_1 < 0. ; G4double en_cross = cross ? en_0 + (BetaInverse - ri_0)*(en_1 - en_0)/(ri_1 - ri_0) : -1. ; // linear crossing more precision than s2 zeros if( s2_0 <= 0. and s2_1 <= 0. ) // no CK { // noop } else if( s2_0 < 0. and s2_1 > 0. ) // s2 becomes +ve within the bin left edge triangle { s2integral += (en_1 - en_cross)*s2_1*0.5 ; } else if( s2_0 >= 0. and s2_1 >= 0. ) // s2 +ve across full bin trapezoid { s2integral += (en_1 - en_0)*(s2_0 + s2_1)*0.5 ; } else if( s2_0 > 0. and s2_1 < 0. ) // s2 becomes -ve within the bin right edge triangle { s2integral += (en_cross - en_0)*s2_0*0.5 ; } } const G4double Rfact = 369.81/(eV * cm); return Rfact * charge/eplus * charge/eplus * s2integral ; }
Created with:
cd ~/opticks/qudarap QCerenkovIntegralTest # create ICDF lookups for many BetaInverse QCKTest # load ICDF, create lookup+rejection samples ipython -i tests/QCKTest.py # chi2 comparisons on energy distribs
Plots show:
Note: ICDF becomes flat in disallowed energy regions
chi2 comparison
bi : BetaInverse of particle
c2p : chi2 per degree of freedom
emn/emx : photon energy range (eV)
avp : average number of photons per mm
Most discrepancy from edge regions
bi | c2sum | ndf | c2p | emn | emx | avp |
---|---|---|---|---|---|---|
1.0000 | 82.0388 | 99.0000 | 0.8287 | 1.5500 | 15.5000 | 293.2454 |
1.0500 | 91.5019 | 99.0000 | 0.9243 | 1.5500 | 15.5000 | 270.4207 |
1.1000 | 92.9688 | 99.0000 | 0.9391 | 1.5500 | 15.5000 | 246.4823 |
1.1500 | 79.5928 | 99.0000 | 0.8040 | 1.5500 | 15.5000 | 221.4304 |
1.2000 | 100.4855 | 99.0000 | 1.0150 | 1.5500 | 15.5000 | 195.2648 |
1.2500 | 116.2938 | 99.0000 | 1.1747 | 1.5500 | 15.5000 | 167.9857 |
1.3000 | 110.0716 | 99.0000 | 1.1118 | 1.5500 | 15.5000 | 139.5929 |
1.3500 | 84.7895 | 99.0000 | 0.8565 | 1.5500 | 15.5000 | 110.0865 |
1.4000 | 90.6946 | 99.0000 | 0.9161 | 1.5500 | 15.5000 | 79.4666 |
1.4500 | 374.1477 | 99.0000 | 3.7793 | 1.5500 | 15.5000 | 47.7330 |
1.5000 | 147.4192 | 99.0000 | 1.4891 | 3.1136 | 9.9651 | 28.7508 |
1.5500 | 222.8197 | 92.0000 | 2.4220 | 4.6647 | 9.5725 | 16.5258 |
1.6000 | 254.6680 | 78.0000 | 3.2650 | 5.7872 | 9.2549 | 9.1571 |
1.6500 | 156.4206 | 99.0000 | 1.5800 | 7.4768 | 8.9444 | 5.3764 |
1.7000 | 209.5865 | 100.0000 | 2.0959 | 7.5724 | 8.6780 | 2.8470 |
1.7500 | 401.4795 | 101.0000 | 3.9750 | 7.6680 | 8.4288 | 0.9762 |
1.7920 | 54036.1523 | 101.0000 | 535.0114 | 7.7485 | 7.7895 | 0.0007 |
Aiming to include Opticks example in Geant4 11 Distribution
Geant4 Fermilab Group (Hans Wentzel, Soon Yung Jun) working on this
My role : Opticks updates to cope with API changes
Geant4 11 API+behavior changes causing problems
From last tarball tried : all tests passing BUT notable slowdown, suspect G4VSolid::CalculateExtent
1042 : all pass, no slow
1100, Soon 2nd tarball geant4.master100721.tar:
SLOW: tests taking longer that 15 seconds 3 /45 Test #3 : CFG4Test.CTestDetectorTest Passed 35.47 5 /45 Test #5 : CFG4Test.CGDMLDetectorTest Passed 35.54 7 /45 Test #7 : CFG4Test.CGeometryTest Passed 35.34 27 /45 Test #27 : CFG4Test.CInterpolationTest Passed 37.76 FAILS: 0 / 501 : Sat Oct 9 04:57:42 2021 (base) [simon@localhost opticks]$
CTraverser::AncestorTraverse finding extents of 300k solids
Fasteners : performance+validity
NEW: 2D geometry cross-section technique
qudarap/QEvent.cc/QEvent::MakeCenterExtentGensteps
Transform local frame photon source positions (eg XZ plane, XYZ grid) into global frame using instance transforms of any piece of geometry.
671 template <typename T> inline QSIM_METHOD void qsim<T>::generate_photon_torch(quad4& p, curandStateXORWOW& rng, const quad6& gs)
672 {
673 p.q0.f = gs.q1.f ; // start with local frame position, eg (0,0,0)
674
675 float u = curand_uniform(&rng);
676 float sinPhi, cosPhi;
677 sincosf(2.f*M_PIf*u,&sinPhi,&cosPhi);
678
679 // local frame XZ plane directions
680 p.q1.f.x = cosPhi ; p.q1.f.y = 0.f ; p.q1.f.z = sinPhi ; p.q1.f.w = 0.f ;
681
682 qat4 qt(gs) ; // copy 4x4 transform from last 4 quads of genstep
683 qt.right_multiply_inplace( p.q0.f, 1.f ); // position transform local->global
684 qt.right_multiply_inplace( p.q1.f, 0.f ); // direction
685 }
CSGOptiX/cxs.sh
CSGOptiX/tests/CSGOptiXSimulateTest.cc
CSGOptiX/tests/CSGOptiXSimulateTest.py
##!/bin/bash -l cxs=${CXS:-20} # collect sets of config underneath CXS if [ "$cxs" == "1" ]; then moi=Hama ##cegs=16:0:9:1000:18700:0:0:100 cegs=16:0:9:500 gridscale=0.05 elif [ "$cxs" == "2" ]; then moi=uni_acrylic3 cegs=16:0:9:100 ##cegs=0:0:0:1000 ##cegs=16:4:9:100 gridscale=0.05 elif [ "$cxs" == "20" ]; then note="very tight grid to get into close corners" moi=uni_acrylic3 cegs=16:0:9:100 gridscale=0.025 fi export MOI=${MOI:-$moi} export CEGS=${CEGS:-$cegs} export GRIDSCALE=${GRIDSCALE:-$gridscale} export CXS=${CXS:-$cxs} export TOPLINE="cxs.sh CSGOptiXSimulateTest CXS $CXS MOI $MOI CEGS $CEGS GRIDSCALE $GRIDSCALE ISEL $ISEL ZZ $ZZ" export BOTLINE="ZOOM $ZOOM LOOK $LOOK" if [ "$1" == "py" ]; then ipython --pdb -i tests/CSGOptiXSimulateTest.py else CSGOptiXSimulateTest fi
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; 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); 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; 135 }
Start from Polycone (thin cylinder+large cone) and subtract:
JUST the Polycone should work fine : and give same results
Pipe Cylinder with inner removed
G4Tubs with rmin > 0
Opticks implements as CSG subtraction:
BUT WHEN SUBTRACT AGAIN: A - (B - C)
solidAddition_down (GPolycone) Z: 5.7, 0.0, -140.0
solidAddition_up (G4Sphere)
solidAddition_up1 (G4Tubs) rmin/rmax 120/208 hz 15.2
uni_acrylic1 - solidAddition_up1 [ Z : -20 ]
solidAddition_up2 (G4Tubs) rmin/rmax 0/14 hz 52.5
uni_acrylic2 - solidAddition_up2 [ Z : -87.5 ]
Mind the gap:
Geometry Modelling Experience
Geant4: Each volume is created by describing its shape and its physical characteristics, and then placing it inside a containing volume.
DO NOT subtract CSG holes for daughters:
If gap between acrylic cone and steel rods is important
Model with hierarchy of 3 volumes:
NB NO CSG subtraction for the water cylinders or steel rods
If gap between acrylic cone and steel rods is not important
Model with hierarchy of 2 volumes:
NB NO CSG subtraction for the steel rods
Multiple non-interfering CSG subtractions work fine
CSG Subtraction of a "pipe" cylinder (with inner rmin>0) : gives spurious inner intersects
Problem Arises from inherent CSG fragility regarding coincident faces
Positive form CSG Trees
Apply deMorgan pushing negations down tree
End with only UNION, INTERSECT operators, and some complemented leaves.
COMMUTATIVE -> easily rearranged
1st step to allow balancing : Positivize : remove CSG difference di operators
... ... un cy un cy un cy un cy un cy di cy cy cy
... ... un cy un cy un cy un cy un cy in cy cy !cy