File indexing completed on 2026-04-10 07:49:39
0001 #pragma once
0002
0003
0004
0005
0006
0007
0008 #if defined(__CUDACC__) || defined(__CUDABE__)
0009 #define QCERENKOV_METHOD __device__
0010 #else
0011 #define QCERENKOV_METHOD
0012 #endif
0013
0014 #include "scurand.h"
0015 #include "smath.h"
0016 #include "OpticksPhoton.h"
0017
0018 #include "qrng.h"
0019
0020
0021 struct scerenkov ;
0022 struct qbase ;
0023 struct qbnd ;
0024 struct quad6 ;
0025 template <typename T> struct qprop ;
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036
0037 struct qcerenkov
0038 {
0039 qbase* base ;
0040 qbnd* bnd ;
0041 qprop<float>* prop ;
0042
0043 #if defined(__CUDACC__) || defined(__CUDABE__) || defined(MOCK_CURAND) || defined(MOCK_CUDA)
0044 QCERENKOV_METHOD void generate( sphoton& p, RNG& rng, const quad6& gs, unsigned long long idx, int genstep_id ) const ;
0045
0046 template<typename T>
0047 QCERENKOV_METHOD void wavelength_sampled_enprop( float& wavelength, float& cosTheta, float& sin2Theta, RNG& rng, const scerenkov& gs, unsigned long long idx, int genstep_id ) const ;
0048 QCERENKOV_METHOD void wavelength_sampled_bndtex( float& wavelength, float& cosTheta, float& sin2Theta, RNG& rng, const scerenkov& gs, unsigned long long idx, int genstep_id ) const ;
0049
0050 QCERENKOV_METHOD void fraction_sampled(float& fraction, float& delta, RNG& rng, const scerenkov& gs, unsigned long long idx, int gsid ) const ;
0051 #endif
0052
0053 };
0054
0055 #if defined(__CUDACC__) || defined(__CUDABE__) || defined(MOCK_CURAND) || defined(MOCK_CUDA)
0056 inline QCERENKOV_METHOD void qcerenkov::generate( sphoton& p, RNG& rng, const quad6& _gs, unsigned long long idx, int gsid ) const
0057 {
0058
0059
0060 const scerenkov& gs = (const scerenkov&)_gs ;
0061 const float3 p0 = normalize(gs.DeltaPosition) ;
0062
0063 float wavelength ;
0064 float cosTheta ;
0065 float sin2Theta ;
0066
0067
0068
0069 wavelength_sampled_bndtex(wavelength, cosTheta, sin2Theta, rng, gs, idx, gsid) ;
0070
0071
0072
0073 float sinTheta = sqrtf(sin2Theta);
0074
0075
0076
0077
0078 float u0 = curand_uniform(&rng);
0079 float phi = 2.f*M_PIf*u0 ;
0080 float sinPhi = sin(phi);
0081 float cosPhi = cos(phi);
0082
0083
0084
0085
0086
0087 p.mom.x = sinTheta*cosPhi ;
0088 p.mom.y = sinTheta*sinPhi ;
0089 p.mom.z = cosTheta ;
0090
0091
0092 smath::rotateUz(p.mom, p0 );
0093
0094
0095
0096 p.pol.x = cosTheta*cosPhi ;
0097 p.pol.y = cosTheta*sinPhi ;
0098 p.pol.z = -sinTheta ;
0099
0100
0101
0102 smath::rotateUz(p.pol, p0 );
0103
0104 p.wavelength = wavelength ;
0105
0106 float fraction ;
0107 float delta ;
0108
0109 fraction_sampled( fraction, delta, rng, gs, idx, gsid );
0110
0111 float midVelocity = gs.preVelocity + fraction*( gs.postVelocity - gs.preVelocity )*0.5f ;
0112
0113 p.time = gs.time + delta / midVelocity ;
0114 p.pos = gs.pos + fraction * gs.DeltaPosition ;
0115
0116 p.zero_flags();
0117 p.set_flag(CERENKOV) ;
0118
0119 }
0120
0121
0122
0123
0124
0125
0126
0127
0128
0129
0130
0131
0132
0133
0134
0135
0136
0137
0138
0139 inline QCERENKOV_METHOD void qcerenkov::fraction_sampled(float& fraction, float& delta, RNG& rng, const scerenkov& gs, unsigned long long idx, int gsid ) const
0140 {
0141 float NumberOfPhotons ;
0142 float N ;
0143 float u ;
0144
0145 float MeanNumberOfPhotonsMax = fmaxf( gs.MeanNumberOfPhotons1, gs.MeanNumberOfPhotons2 );
0146 float DeltaN = (gs.MeanNumberOfPhotons1-gs.MeanNumberOfPhotons2) ;
0147 do
0148 {
0149 fraction = curand_uniform(&rng) ;
0150
0151 delta = fraction * gs.step_length ;
0152
0153 NumberOfPhotons = gs.MeanNumberOfPhotons1 - fraction * DeltaN ;
0154
0155 u = curand_uniform(&rng) ;
0156
0157 N = u * MeanNumberOfPhotonsMax ;
0158
0159 } while (N > NumberOfPhotons);
0160
0161
0162
0163 }
0164
0165
0166
0167
0168
0169
0170
0171
0172
0173
0174
0175
0176
0177
0178
0179
0180
0181
0182
0183
0184
0185
0186
0187
0188
0189
0190
0191
0192
0193
0194
0195
0196
0197
0198
0199
0200
0201
0202
0203
0204
0205
0206
0207
0208
0209
0210
0211
0212
0213
0214
0215
0216
0217
0218
0219
0220
0221
0222
0223
0224
0225
0226
0227
0228
0229
0230
0231
0232
0233
0234
0235
0236
0237
0238
0239
0240
0241
0242
0243
0244
0245
0246
0247
0248
0249
0250
0251
0252
0253
0254
0255
0256
0257
0258
0259
0260
0261
0262
0263
0264
0265
0266
0267
0268
0269
0270
0271
0272
0273
0274
0275
0276
0277
0278
0279
0280
0281
0282
0283
0284
0285 inline QCERENKOV_METHOD void qcerenkov::wavelength_sampled_bndtex(float& wavelength, float& cosTheta, float& sin2Theta, RNG& rng, const scerenkov& gs, unsigned long long idx, int gsid ) const
0286 {
0287
0288 float u0 ;
0289 float u1 ;
0290 float w ;
0291 float sampledRI ;
0292 float u_maxSin2 ;
0293
0294 unsigned count = 0 ;
0295
0296 do {
0297 u0 = curand_uniform(&rng) ;
0298
0299 w = gs.Wmin + u0*(gs.Wmax - gs.Wmin) ;
0300
0301 wavelength = gs.Wmin*gs.Wmax/w ;
0302
0303 float4 props = bnd->boundary_lookup(wavelength, gs.matline, 0u);
0304
0305 sampledRI = props.x ;
0306
0307
0308
0309 cosTheta = gs.BetaInverse / sampledRI ;
0310
0311 sin2Theta = fmaxf( 0.f, (1.f - cosTheta)*(1.f + cosTheta));
0312
0313 u1 = curand_uniform(&rng) ;
0314
0315 u_maxSin2 = u1*gs.maxSin2 ;
0316
0317 count += 1 ;
0318
0319 } while ( u_maxSin2 > sin2Theta && count < 100 );
0320
0321 #if !defined(PRODUCTION) && defined(DEBUG_PIDX)
0322 if(count > 50)
0323 printf("//qcerenkov::wavelength_sampled_bndtex idx %6lld sampledRI %7.3f cosTheta %7.3f sin2Theta %7.3f wavelength %7.3f count %d matline %d \n",
0324 idx , sampledRI, cosTheta, sin2Theta, wavelength, count, gs.matline );
0325 #endif
0326
0327 }
0328
0329
0330
0331
0332
0333
0334
0335
0336
0337
0338 template<typename T>
0339 inline QCERENKOV_METHOD void qcerenkov::wavelength_sampled_enprop(float& f_wavelength, float& f_cosTheta, float& f_sin2Theta, RNG& rng, const scerenkov& gs, unsigned long long idx, int gsid ) const
0340 {
0341 T u0 ;
0342 T u1 ;
0343 T energy ;
0344 T sampledRI ;
0345 T cosTheta ;
0346 T sin2Theta ;
0347 T u_mxs2_s2 ;
0348
0349 T one(1.) ;
0350 T zero(0.) ;
0351
0352 T pmin = gs.Pmin() ;
0353 T pmax = gs.Pmax() ;
0354
0355 unsigned loop = 0u ;
0356
0357 do {
0358
0359 u0 = scurand<T>::uniform(&rng) ;
0360
0361 energy = pmin + u0*(pmax - pmin) ;
0362
0363 sampledRI = prop->interpolate( 0u, energy );
0364
0365 cosTheta = gs.BetaInverse / sampledRI ;
0366
0367 sin2Theta = (one - cosTheta)*(one + cosTheta);
0368
0369 u1 = scurand<T>::uniform(&rng) ;
0370
0371 u_mxs2_s2 = u1*gs.maxSin2 - sin2Theta ;
0372
0373 loop += 1 ;
0374
0375 if( idx == base->pidx )
0376 {
0377 printf("//qcerenkov::cerenkov_generate_enprop idx %d loop %3d u0 %10.5f ri %10.5f ct %10.5f s2 %10.5f u_mxs2_s2 %10.5f \n", idx, loop, u0, sampledRI, cosTheta, sin2Theta, u_mxs2_s2 );
0378 }
0379
0380
0381 } while ( u_mxs2_s2 > zero );
0382
0383 f_wavelength = smath::hc_eVnm/energy ;
0384 f_cosTheta = cosTheta ;
0385 f_sin2Theta = sin2Theta ;
0386 }
0387
0388 #endif
0389
0390
0391