File indexing completed on 2026-04-09 07:49:11
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025 #if defined(__CUDACC__) || defined(__CUDABE__)
0026 #define QSIM_METHOD __device__
0027 #else
0028 #define QSIM_METHOD
0029 #endif
0030
0031 #include "OpticksGenstep.h"
0032 #include "OpticksPhoton.h"
0033
0034 #include "sflow.h"
0035 #include "sqat4.h"
0036 #include "sc4u.h"
0037 #include "sxyz.h"
0038 #include "sphoton.h"
0039
0040 #include "storch.h"
0041 #include "scarrier.h"
0042 #include "sevent.h"
0043 #include "sstate.h"
0044 #include "smatsur.h"
0045
0046
0047 #ifndef PRODUCTION
0048 #include "srec.h"
0049 #include "sseq.h"
0050 #include "stag.h"
0051 #ifdef DEBUG_LOGF
0052 #define KLUDGE_FASTMATH_LOGF(u) (u < 0.998f ? __logf(u) : __logf(u) - 0.46735790f*1e-7f )
0053 #endif
0054 #endif
0055
0056 #include "sctx.h"
0057
0058 #include "qrng.h"
0059 #include "qbase.h"
0060 #include "qprop.h"
0061 #include "qmultifilm.h"
0062 #include "qbnd.h"
0063 #include "qscint.h"
0064 #include "qcerenkov.h"
0065 #include "qpmt.h"
0066 #include "tcomplex.h"
0067
0068
0069 struct qcerenkov ;
0070
0071 struct qsim
0072 {
0073 qbase* base ;
0074 sevent* evt ;
0075 qrng<RNG>* rng ;
0076 qbnd* bnd ;
0077 qmultifilm* multifilm;
0078 qcerenkov* cerenkov ;
0079 qscint* scint ;
0080 qpmt<float>* pmt ;
0081
0082 #if defined(__CUDACC__) || defined(__CUDABE__)
0083 #else
0084 qsim();
0085 #endif
0086
0087 QSIM_METHOD void generate_photon_dummy( sphoton& p, RNG& rng, const quad6& gs, unsigned long long photon_id, unsigned genstep_id ) const ;
0088 QSIM_METHOD static float3 uniform_sphere(const float u0, const float u1);
0089 QSIM_METHOD static float RandGaussQ_shoot( RNG& rng, float mean, float stdDev );
0090 QSIM_METHOD static void SmearNormal_SigmaAlpha( RNG& rng, float3* smeared_normal, const float3* direction, const float3* normal, float sigma_alpha, const sctx& ctx );
0091 QSIM_METHOD static void SmearNormal_Polish( RNG& rng, float3* smeared_normal, const float3* direction, const float3* normal, float polish , const sctx& ctx );
0092
0093 #if defined(__CUDACC__) || defined(__CUDABE__) || defined( MOCK_CURAND ) || defined(MOCK_CUDA)
0094 QSIM_METHOD static float3 uniform_sphere(RNG& rng);
0095 #endif
0096
0097 #if defined(__CUDACC__) || defined(__CUDABE__)
0098 QSIM_METHOD float4 multifilm_lookup(unsigned pmtType, float nm, float aoi);
0099 #endif
0100
0101 #if defined(__CUDACC__) || defined(__CUDABE__) || defined( MOCK_CURAND ) || defined(MOCK_CUDA)
0102 QSIM_METHOD static void lambertian_direction(float3* dir, const float3* normal, float orient, RNG& rng, sctx& ctx );
0103 QSIM_METHOD static void random_direction_marsaglia(float3* dir, RNG& rng, sctx& ctx );
0104 QSIM_METHOD void rayleigh_scatter(RNG& rng, sctx& ctx );
0105 QSIM_METHOD int propagate_to_boundary( unsigned& flag, RNG& rng, sctx& ctx );
0106 #endif
0107
0108 #if defined(__CUDACC__) || defined(__CUDABE__) || defined( MOCK_CURAND ) || defined(MOCK_CUDA)
0109 QSIM_METHOD int propagate_at_boundary( unsigned& flag, RNG& rng, sctx& ctx, float theTransmittance=-1.f ) const ;
0110 QSIM_METHOD int propagate_at_boundary_with_T( unsigned& flag, RNG& rng, sctx& ctx, float theTransmittance ) const ;
0111 #endif
0112
0113 #if defined(__CUDACC__) || defined(__CUDABE__)
0114 QSIM_METHOD int propagate_at_surface_MultiFilm(unsigned& flag, RNG& rng, sctx& ctx );
0115 #endif
0116
0117 #if defined(__CUDACC__) || defined(__CUDABE__) || defined( MOCK_CURAND ) || defined(MOCK_CUDA)
0118 QSIM_METHOD int propagate_at_surface( unsigned& flag, RNG& rng, sctx& ctx );
0119 QSIM_METHOD int propagate_at_surface_Detect( unsigned& flag, RNG& rng, sctx& ctx ) const ;
0120 #if defined( WITH_CUSTOM4 )
0121 QSIM_METHOD int propagate_at_surface_CustomART( unsigned& flag, RNG& rng, sctx& ctx ) const ;
0122 #endif
0123 #endif
0124
0125 #if defined(__CUDACC__) || defined(__CUDABE__) || defined( MOCK_CURAND ) || defined(MOCK_CUDA)
0126 QSIM_METHOD void reflect_diffuse( RNG& rng, sctx& ctx );
0127 QSIM_METHOD void reflect_specular( RNG& rng, sctx& ctx );
0128
0129 QSIM_METHOD void fake_propagate( sphoton& p, const quad2* mock_prd, RNG& rng, unsigned long long idx );
0130 QSIM_METHOD int propagate(const int bounce, RNG& rng, sctx& ctx );
0131
0132 QSIM_METHOD void hemisphere_polarized( unsigned polz, bool inwards, RNG& rng, sctx& ctx );
0133 QSIM_METHOD void generate_photon_simtrace( quad4& p, RNG& rng, const quad6& gs, unsigned long long photon_id, unsigned genstep_id ) const ;
0134 QSIM_METHOD void generate_photon_simtrace_frame( quad4& p, RNG& rng, const quad6& gs, unsigned long long photon_id, unsigned genstep_id ) const ;
0135 QSIM_METHOD void generate_photon( sphoton& p, RNG& rng, const quad6& gs, unsigned long long photon_id, unsigned genstep_id ) const ;
0136 #endif
0137 };
0138
0139
0140 #if defined(__CUDACC__) || defined(__CUDABE__)
0141 #else
0142 inline qsim::qsim()
0143 :
0144 base(nullptr),
0145 evt(nullptr),
0146 rng(nullptr),
0147 bnd(nullptr),
0148 multifilm(nullptr),
0149 cerenkov(nullptr),
0150 scint(nullptr),
0151 pmt(nullptr)
0152 {
0153 }
0154 #endif
0155
0156 inline QSIM_METHOD void qsim::generate_photon_dummy(sphoton& p_, RNG& rng, const quad6& gs, unsigned long long photon_id, unsigned genstep_id ) const
0157 {
0158 quad4& p = (quad4&)p_ ;
0159 #ifndef PRODUCTION
0160 printf("//qsim::generate_photon_dummy photon_id %3lld genstep_id %3d gs.q0.i ( gencode:%3d %3d %3d %3d ) \n",
0161 photon_id,
0162 genstep_id,
0163 gs.q0.i.x,
0164 gs.q0.i.y,
0165 gs.q0.i.z,
0166 gs.q0.i.w
0167 );
0168 #endif
0169 p.q0.i.x = 1 ; p.q0.i.y = 2 ; p.q0.i.z = 3 ; p.q0.i.w = 4 ;
0170 p.q1.i.x = 1 ; p.q1.i.y = 2 ; p.q1.i.z = 3 ; p.q1.i.w = 4 ;
0171 p.q2.i.x = 1 ; p.q2.i.y = 2 ; p.q2.i.z = 3 ; p.q2.i.w = 4 ;
0172 p.q3.i.x = 1 ; p.q3.i.y = 2 ; p.q3.i.z = 3 ; p.q3.i.w = 4 ;
0173
0174 p.set_flag(TORCH);
0175 }
0176
0177 inline QSIM_METHOD float3 qsim::uniform_sphere(const float u0, const float u1)
0178 {
0179 float phi = u0*2.f*M_PIf;
0180 float cosTheta = 2.f*u1 - 1.f ;
0181 float sinTheta = sqrtf(1.f-cosTheta*cosTheta);
0182 return make_float3(cosf(phi)*sinTheta, sinf(phi)*sinTheta, cosTheta);
0183 }
0184
0185
0186 #if defined(__CUDACC__) || defined(__CUDABE__) || defined( MOCK_CURAND ) || defined(MOCK_CUDA)
0187
0188
0189
0190
0191
0192 inline QSIM_METHOD float3 qsim::uniform_sphere(RNG& rng)
0193 {
0194 float phi = curand_uniform(&rng)*2.f*M_PIf;
0195 float cosTheta = 2.f*curand_uniform(&rng) - 1.f ;
0196 float sinTheta = sqrtf(1.f-cosTheta*cosTheta);
0197 return make_float3(cosf(phi)*sinTheta, sinf(phi)*sinTheta, cosTheta);
0198 }
0199
0200
0201
0202
0203
0204
0205
0206
0207
0208
0209
0210
0211
0212
0213 inline QSIM_METHOD float qsim::RandGaussQ_shoot( RNG& rng, float mean, float stdDev )
0214 {
0215 float u2 = 2.f*curand_uniform(&rng) ;
0216 float v = -M_SQRT2f*erfcinvf(u2)*stdDev + mean ;
0217
0218 return v ;
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 inline QSIM_METHOD void qsim::SmearNormal_SigmaAlpha(
0255 RNG& rng,
0256 float3* smeared_normal,
0257 const float3* direction,
0258 const float3* normal,
0259 float sigma_alpha,
0260 const sctx& ctx
0261 )
0262 {
0263 #if !defined(PRODUCTION) && defined(MOCK_CUDA_DEBUG)
0264 bool dump = ctx.pidx == -1 ;
0265 #endif
0266
0267 if(sigma_alpha == 0.f)
0268 {
0269 *smeared_normal = *normal ;
0270 return ;
0271 }
0272 float f_max = fminf(1.f,4.f*sigma_alpha);
0273
0274 #if !defined(PRODUCTION) && defined(MOCK_CUDA_DEBUG)
0275 if(dump) printf("//qsim::SmearNormal_SigmaAlpha.MOCK_CUDA_DEBUG sigma_alpha %10.5f f_max %10.5f \n", sigma_alpha, f_max );
0276 #endif
0277
0278 float alpha, sin_alpha, phi, u0, u1, u2 ;
0279 bool reject_alpha ;
0280 bool reject_dir ;
0281
0282 do {
0283 do {
0284
0285 u0 = curand_uniform(&rng) ;
0286 alpha = -M_SQRT2f*erfcinvf(2.f*u0)*sigma_alpha ;
0287
0288 sin_alpha = sinf(alpha);
0289 u1 = curand_uniform(&rng) ;
0290 reject_alpha = alpha >= M_PIf/2.f || (u1*f_max > sin_alpha) ;
0291
0292 #if !defined(PRODUCTION) && defined(MOCK_CUDA_DEBUG)
0293 if(dump) printf("//qsim::SmearNormal_SigmaAlpha.MOCK_CUDA_DEBUG u0 %10.5f alpha %10.5f sin_alpha %10.5f u1 %10.5f u1*f_max %10.5f (u1*f_max > sin_alpha) %d reject_alpha %d \n",
0294 u0, alpha, sin_alpha, u1, u1*f_max, (u1*f_max > sin_alpha), reject_alpha );
0295
0296 #endif
0297
0298 } while( reject_alpha ) ;
0299
0300 u2 = curand_uniform(&rng) ;
0301 phi = u2*M_PIf*2.f ;
0302
0303 smeared_normal->x = sin_alpha * cosf(phi) ;
0304 smeared_normal->y = sin_alpha * sinf(phi) ;
0305 smeared_normal->z = cosf(alpha) ;
0306
0307 smath::rotateUz(*smeared_normal, *normal);
0308 reject_dir = dot(*smeared_normal, *direction ) >= 0.f ;
0309
0310
0311 #if !defined(PRODUCTION) && defined(MOCK_CUDA_DEBUG)
0312 if(dump) printf("//qsim::SmearNormal_SigmaAlpha.MOCK_CUDA_DEBUG u2 %10.5f phi %10.5f smeared_normal ( %10.5f, %10.5f, %10.5f) reject_dir %d \n",
0313 u2, phi, smeared_normal->x, smeared_normal->y, smeared_normal->z, reject_dir );
0314 #endif
0315
0316
0317 } while( reject_dir ) ;
0318 }
0319
0320
0321
0322
0323
0324
0325
0326
0327
0328 inline QSIM_METHOD void qsim::SmearNormal_Polish(
0329 RNG& rng,
0330 float3* smeared_normal,
0331 const float3* direction,
0332 const float3* normal,
0333 float polish,
0334 const sctx& ctx
0335 )
0336 {
0337 #if !defined(PRODUCTION) && defined(MOCK_CUDA_DEBUG)
0338 bool dump = ctx.pidx == -1 ;
0339 #endif
0340
0341 if(polish == 1.f)
0342 {
0343 *smeared_normal = *normal ;
0344 return ;
0345 }
0346
0347 float u0, u1, u2 ;
0348 float3 smear ;
0349 bool reject_mag ;
0350 bool reject_dir ;
0351
0352 do {
0353 do {
0354 u0 = curand_uniform(&rng);
0355 u1 = curand_uniform(&rng) ;
0356 u2 = curand_uniform(&rng) ;
0357 smear.x = 2.f*u0 - 1.f ;
0358 smear.y = 2.f*u1 - 1.f ;
0359 smear.z = 2.f*u2 - 1.f ;
0360 reject_mag = length(smear) > 1.f ;
0361 }
0362 while( reject_mag );
0363
0364 *smeared_normal = *normal + (1.f-polish)*smear;
0365 reject_dir = dot(*smeared_normal, *direction) >= 0.f ;
0366 }
0367 while( reject_dir );
0368 *smeared_normal = normalize(*smeared_normal);
0369 }
0370
0371
0372
0373
0374
0375 #endif
0376
0377 #if defined(__CUDACC__) || defined(__CUDABE__)
0378
0379
0380
0381
0382
0383
0384 inline QSIM_METHOD float4 qsim::multifilm_lookup(unsigned pmtType, float nm, float aoi)
0385 {
0386 float4 value = multifilm->lookup(pmtType, nm, aoi);
0387 return value;
0388 }
0389
0390 #endif
0391
0392 #if defined(__CUDACC__) || defined(__CUDABE__) || defined(MOCK_CURAND) || defined(MOCK_CUDA)
0393
0394
0395
0396
0397
0398
0399
0400
0401
0402
0403
0404
0405
0406
0407
0408
0409
0410
0411
0412
0413
0414
0415
0416
0417
0418
0419
0420
0421
0422
0423
0424
0425
0426
0427
0428
0429
0430 inline QSIM_METHOD void qsim::lambertian_direction(float3* dir, const float3* normal, float orient, RNG& rng, sctx& ctx )
0431 {
0432 #if !defined(PRODUCTION) && defined(DEBUG_PIDX)
0433 unsigned long long PIDX = 0xffffffffff ;
0434 if(ctx.pidx == PIDX )
0435 {
0436 printf("//qsim.lambertian_direction.head pidx %7lld : normal = np.array([%10.5f,%10.5f,%10.5f]) ; orient = %10.5f \n",
0437 ctx.pidx, normal->x, normal->y, normal->z, orient );
0438 }
0439 #endif
0440
0441 float ndotv ;
0442 int count = 0 ;
0443 float u ;
0444 do
0445 {
0446 count++ ;
0447 random_direction_marsaglia(dir, rng, ctx);
0448 ndotv = dot( *dir, *normal )*orient ;
0449 if( ndotv < 0.f )
0450 {
0451 *dir = -1.f*(*dir) ;
0452 ndotv = -1.f*ndotv ;
0453 }
0454
0455
0456
0457 u = curand_uniform(&rng) ;
0458
0459 #if !defined(PRODUCTION) && defined(DEBUG_PIDX)
0460
0461 if(ctx.pidx == PIDX)
0462 {
0463 printf("//qsim.lambertian_direction.loop pidx %7lld : dir = np.array([%10.5f,%10.5f,%10.5f]) ; count = %d ; ndotv = %10.5f ; u = %10.5f \n",
0464 ctx.pidx, dir->x, dir->y, dir->z, count, ndotv, u );
0465
0466 }
0467 #endif
0468 }
0469 while (!(u < ndotv) && (count < 1024)) ;
0470
0471
0472
0473 #if !defined(PRODUCTION) && defined(DEBUG_PIDX)
0474 if(ctx.pidx == PIDX)
0475 {
0476 printf("//qsim.lambertian_direction.tail pidx %7lld : dir = np.array([%10.5f,%10.5f,%10.5f]) ; count = %d ; ndotv = %10.5f \n",
0477 ctx.pidx, dir->x, dir->y, dir->z, count, ndotv );
0478
0479 }
0480 #endif
0481
0482
0483 }
0484
0485
0486
0487
0488
0489
0490
0491
0492
0493
0494
0495
0496
0497
0498
0499
0500
0501
0502
0503
0504
0505
0506
0507
0508
0509
0510
0511
0512
0513
0514
0515
0516
0517
0518
0519
0520
0521
0522
0523
0524
0525
0526
0527
0528
0529
0530
0531
0532
0533
0534
0535
0536
0537
0538
0539
0540
0541
0542
0543
0544
0545
0546
0547
0548
0549
0550
0551 inline QSIM_METHOD void qsim::random_direction_marsaglia(float3* dir, RNG& rng, sctx& ctx )
0552 {
0553
0554 float u0, u1 ;
0555 float u, v, b, a ;
0556 do
0557 {
0558 u0 = curand_uniform(&rng);
0559 u1 = curand_uniform(&rng);
0560
0561 u = 2.f*u0 - 1.f ;
0562 v = 2.f*u1 - 1.f ;
0563 b = u*u + v*v ;
0564 }
0565 while( b > 1.f ) ;
0566
0567 a = 2.f*sqrtf( 1.f - b );
0568
0569 dir->x = a*u ;
0570 dir->y = a*v ;
0571 dir->z = 2.f*b - 1.f ;
0572 }
0573
0574
0575
0576
0577
0578
0579
0580
0581
0582
0583
0584
0585
0586
0587
0588
0589
0590
0591
0592
0593
0594
0595
0596
0597
0598
0599
0600
0601 inline QSIM_METHOD void qsim::rayleigh_scatter(RNG& rng, sctx& ctx )
0602 {
0603 sphoton& p = ctx.p ;
0604 float3 direction ;
0605 float3 polarization ;
0606
0607 bool looping(true) ;
0608 do
0609 {
0610 float u0 = curand_uniform(&rng) ;
0611 float u1 = curand_uniform(&rng) ;
0612 float u2 = curand_uniform(&rng) ;
0613 float u3 = curand_uniform(&rng) ;
0614 float u4 = curand_uniform(&rng) ;
0615
0616 #if !defined(PRODUCTION) && defined(DEBUG_TAG)
0617 stagr& tagr = ctx.tagr ;
0618 tagr.add(stag_sc, u0);
0619 tagr.add(stag_sc, u1);
0620 tagr.add(stag_sc, u2);
0621 tagr.add(stag_sc, u3);
0622 tagr.add(stag_sc, u4);
0623 #endif
0624 float cosTheta = u0 ;
0625 float sinTheta = sqrtf(1.0f-u0*u0);
0626 if(u1 < 0.5f ) cosTheta = -cosTheta ;
0627
0628
0629 float sinPhi ;
0630 float cosPhi ;
0631
0632 #if defined(MOCK_CURAND ) || defined(MOCK_CUDA)
0633
0634 float phi = 2.f*M_PIf*u2 ;
0635 sinPhi = sinf(phi);
0636 cosPhi = cosf(phi);
0637 #else
0638 sincosf(2.f*M_PIf*u2,&sinPhi,&cosPhi);
0639 #endif
0640
0641 direction.x = sinTheta * cosPhi;
0642 direction.y = sinTheta * sinPhi;
0643 direction.z = cosTheta ;
0644
0645 smath::rotateUz(direction, p.mom );
0646
0647 float constant = -dot(direction, p.pol );
0648
0649 polarization.x = p.pol.x + constant*direction.x ;
0650 polarization.y = p.pol.y + constant*direction.y ;
0651 polarization.z = p.pol.z + constant*direction.z ;
0652
0653 if(dot(polarization, polarization) == 0.f )
0654 {
0655
0656 #if defined( MOCK_CURAND ) || defined(MOCK_CUDA)
0657
0658 phi = 2.f*M_PIf*u3 ;
0659 sinPhi = sinf(phi);
0660 cosPhi = cosf(phi);
0661 #else
0662 sincosf(2.f*M_PIf*u3,&sinPhi,&cosPhi);
0663 #endif
0664
0665 polarization.x = cosPhi ;
0666 polarization.y = sinPhi ;
0667 polarization.z = 0.f ;
0668
0669 smath::rotateUz(polarization, direction);
0670 }
0671 else
0672 {
0673
0674
0675 if(u3 < 0.5f) polarization = -polarization ;
0676 }
0677 polarization = normalize(polarization);
0678
0679
0680
0681 float doCosTheta = dot(polarization, p.pol ) ;
0682 float doCosTheta2 = doCosTheta*doCosTheta ;
0683 looping = doCosTheta2 < u4 ;
0684
0685 } while ( looping ) ;
0686
0687 p.mom = direction ;
0688 p.pol = polarization ;
0689 }
0690
0691
0692
0693
0694
0695
0696
0697
0698
0699
0700
0701
0702
0703
0704
0705
0706
0707
0708
0709
0710
0711
0712
0713
0714
0715
0716
0717
0718 inline QSIM_METHOD int qsim::propagate_to_boundary(unsigned& flag, RNG& rng, sctx& ctx)
0719 {
0720 sphoton& p = ctx.p ;
0721 const sstate& s = ctx.s ;
0722
0723 const float& absorption_length = s.material1.y ;
0724 const float& scattering_length = s.material1.z ;
0725 const float& reemission_prob = s.material1.w ;
0726 const float& group_velocity = s.m1group2.x ;
0727 const float& distance_to_boundary = ctx.prd->q0.f.w ;
0728
0729
0730 #if !defined(PRODUCTION) && defined(DEBUG_TAG)
0731 float u_to_sci = curand_uniform(&rng) ;
0732 float u_to_bnd = curand_uniform(&rng) ;
0733 #endif
0734 float u_scattering = curand_uniform(&rng) ;
0735 float u_absorption = curand_uniform(&rng) ;
0736
0737 #if !defined(PRODUCTION) && defined(DEBUG_TAG)
0738 stagr& tagr = ctx.tagr ;
0739 tagr.add( stag_to_sci, u_to_sci);
0740 tagr.add( stag_to_bnd, u_to_bnd);
0741 tagr.add( stag_to_sca, u_scattering);
0742 tagr.add( stag_to_abs, u_absorption);
0743 #endif
0744
0745
0746 #if !defined(PRODUCTION) && defined(DEBUG_LOGF)
0747
0748 float scattering_distance = -scattering_length*KLUDGE_FASTMATH_LOGF(u_scattering);
0749 float absorption_distance = -absorption_length*KLUDGE_FASTMATH_LOGF(u_absorption);
0750 #else
0751 float scattering_distance = -scattering_length*logf(u_scattering);
0752 float absorption_distance = -absorption_length*logf(u_absorption);
0753 #endif
0754
0755 #if !defined(PRODUCTION) && defined(DEBUG_PIDX)
0756
0757 if(ctx.pidx == base->pidx)
0758 {
0759 printf("//qsim.propagate_to_boundary.head pidx %7lld : u_absorption %10.8f logf(u_absorption) %10.8f absorption_length %10.4f absorption_distance %10.6f \n",
0760 ctx.pidx, u_absorption, logf(u_absorption), absorption_length, absorption_distance );
0761
0762 printf("//qsim.propagate_to_boundary.head pidx %7lld : post = np.array([%10.5f,%10.5f,%10.5f,%10.5f]) \n",
0763 ctx.pidx, p.pos.x, p.pos.y, p.pos.z, p.time );
0764
0765 printf("//qsim.propagate_to_boundary.head pidx %7lld : distance_to_boundary %10.4f absorption_distance %10.4f scattering_distance %10.4f \n",
0766 ctx.pidx, distance_to_boundary, absorption_distance, scattering_distance );
0767
0768 printf("//qsim.propagate_to_boundary.head pidx %7lld : u_scattering %10.4f u_absorption %10.4f \n",
0769 ctx.pidx, u_scattering, u_absorption );
0770
0771 }
0772 #endif
0773
0774
0775
0776
0777
0778 if (absorption_distance <= scattering_distance)
0779 {
0780 if (absorption_distance <= distance_to_boundary)
0781 {
0782 p.time += absorption_distance/group_velocity ;
0783 p.pos += absorption_distance*(p.mom) ;
0784
0785
0786 #if !defined(PRODUCTION) && defined(DEBUG_PIDX)
0787 float absorb_time_delta = absorption_distance/group_velocity ;
0788 if( ctx.pidx == base->pidx )
0789 {
0790 printf("//qsim.propagate_to_boundary.body.BULK_ABSORB pidx %7lld : post = np.array([%10.5f,%10.5f,%10.5f,%10.5f]) ; absorb_time_delta = %10.8f \n",
0791 ctx.pidx, p.pos.x, p.pos.y, p.pos.z, p.time, absorb_time_delta );
0792
0793 }
0794 #endif
0795
0796 float u_reemit = reemission_prob == 0.f ? 2.f : curand_uniform(&rng);
0797
0798
0799 #if !defined(PRODUCTION) && defined(DEBUG_TAG)
0800 if( u_reemit != 2.f ) tagr.add( stag_to_ree, u_reemit) ;
0801 #endif
0802
0803
0804 if (u_reemit < reemission_prob)
0805 {
0806 float u_re_wavelength = curand_uniform(&rng);
0807 float u_re_mom_ph = curand_uniform(&rng);
0808 float u_re_mom_ct = curand_uniform(&rng);
0809 float u_re_pol_ph = curand_uniform(&rng);
0810 float u_re_pol_ct = curand_uniform(&rng);
0811
0812 p.wavelength = scint->wavelength(u_re_wavelength);
0813 p.mom = uniform_sphere(u_re_mom_ph, u_re_mom_ct);
0814 p.pol = normalize(cross(uniform_sphere(u_re_pol_ph, u_re_pol_ct), p.mom));
0815
0816 #if !defined(PRODUCTION) && defined(DEBUG_TAG)
0817 tagr.add( stag_re_wl, u_re_wavelength);
0818 tagr.add( stag_re_mom_ph, u_re_mom_ph);
0819 tagr.add( stag_re_mom_ct, u_re_mom_ct);
0820 tagr.add( stag_re_pol_ph, u_re_pol_ph);
0821 tagr.add( stag_re_pol_ct, u_re_pol_ct);
0822 #endif
0823
0824 flag = BULK_REEMIT ;
0825 return CONTINUE;
0826 }
0827 else
0828 {
0829 flag = BULK_ABSORB ;
0830 return BREAK;
0831 }
0832 }
0833
0834 }
0835 else
0836 {
0837 if (scattering_distance <= distance_to_boundary)
0838 {
0839 p.time += scattering_distance/group_velocity ;
0840 p.pos += scattering_distance*(p.mom) ;
0841
0842 rayleigh_scatter(rng, ctx);
0843
0844 flag = BULK_SCATTER;
0845
0846 return CONTINUE;
0847 }
0848
0849 }
0850
0851
0852
0853 p.pos += distance_to_boundary*(p.mom) ;
0854 p.time += distance_to_boundary/group_velocity ;
0855
0856 #if !defined(PRODUCTION) && defined(DEBUG_PIDX)
0857 float sail_time_delta = distance_to_boundary/group_velocity ;
0858 if( ctx.pidx == base->pidx ) printf("//qsim.propagate_to_boundary.tail.SAIL pidx %7lld : post = np.array([%10.5f,%10.5f,%10.5f,%10.5f]) ; sail_time_delta = %10.5f \n",
0859 ctx.pidx, p.pos.x, p.pos.y, p.pos.z, p.time, sail_time_delta );
0860 #endif
0861
0862 return BOUNDARY ;
0863 }
0864 #endif
0865 #if defined(__CUDACC__) || defined(__CUDABE__) || defined( MOCK_CURAND ) || defined(MOCK_CUDA)
0866
0867
0868
0869
0870
0871
0872
0873
0874
0875
0876
0877
0878
0879
0880
0881
0882
0883
0884
0885
0886
0887
0888
0889
0890
0891
0892
0893
0894
0895
0896
0897
0898
0899
0900
0901
0902
0903
0904
0905
0906
0907
0908
0909
0910
0911
0912
0913
0914
0915
0916
0917
0918
0919
0920
0921
0922
0923
0924
0925
0926
0927
0928
0929
0930
0931
0932
0933
0934
0935
0936
0937
0938
0939
0940
0941
0942
0943
0944
0945
0946
0947
0948
0949
0950
0951
0952
0953
0954
0955
0956
0957
0958
0959
0960
0961
0962
0963
0964
0965
0966
0967
0968
0969
0970
0971
0972
0973
0974
0975
0976
0977
0978
0979
0980
0981
0982
0983
0984
0985
0986
0987
0988
0989
0990
0991
0992
0993
0994
0995
0996
0997
0998 inline QSIM_METHOD int qsim::propagate_at_boundary(unsigned& flag, RNG& rng, sctx& ctx, float theTransmittance ) const
0999 {
1000 #if !defined(PRODUCTION) && defined(DEBUG_PIDX)
1001 if(ctx.pidx == base->pidx)
1002 printf("//propagate_at_boundary.DEBUG_PIDX ctx.pidx %7lld base %p base.pidx %7lld \n", ctx.pidx, base, base->pidx );
1003 #endif
1004
1005 #if !defined(PRODUCTION) && defined(DEBUG_TAG)
1006 if(ctx.pidx == base->pidx)
1007 printf("//propagate_at_boundary.DEBUG_TAG ctx.pidx %7lld base %p base.pidx %7lld \n", ctx.pidx, base, base->pidx );
1008 #endif
1009
1010
1011 sphoton& p = ctx.p ;
1012 const sstate& s = ctx.s ;
1013
1014 const float& n1 = s.material1.x ;
1015 const float& n2 = s.material2.x ;
1016 const float eta = n1/n2 ;
1017
1018 const float3* normal = (float3*)&ctx.prd->q0.f.x ;
1019
1020 const float _c1 = -dot(p.mom, *normal );
1021 const float3 oriented_normal = _c1 < 0.f ? -(*normal) : (*normal) ;
1022 const float3 trans = cross(p.mom, oriented_normal) ;
1023 const float trans_length = length(trans) ;
1024 const bool normal_incidence = trans_length < 1e-6f ;
1025 const float3 A_trans = normal_incidence ? p.pol : trans/trans_length ;
1026 const float E1_perp = dot(p.pol, A_trans);
1027
1028 const float c1 = fabs(_c1) ;
1029
1030 #if !defined(PRODUCTION) && defined(DEBUG_PIDX)
1031 if(ctx.pidx == base->pidx)
1032 {
1033 printf("//qsim.propagate_at_boundary.head pidx %7lld : theTransmittance = %10.8f \n", ctx.pidx, theTransmittance );
1034 printf("//qsim.propagate_at_boundary.head pidx %7lld : nrm = np.array([%10.8f,%10.8f,%10.8f]) ; lnrm = %10.8f \n",
1035 ctx.pidx, oriented_normal.x, oriented_normal.y, oriented_normal.z, length(oriented_normal) );
1036 printf("//qsim.propagate_at_boundary.head pidx %7lld : pos = np.array([%10.5f,%10.5f,%10.5f]) ; lpos = %10.8f \n",
1037 ctx.pidx, p.pos.x, p.pos.y, p.pos.z, length(p.pos) );
1038 printf("//qsim.propagate_at_boundary.head pidx %7lld : mom0 = np.array([%10.8f,%10.8f,%10.8f]) ; lmom0 = %10.8f \n",
1039 ctx.pidx, p.mom.x, p.mom.y, p.mom.z, length(p.mom) );
1040 printf("//qsim.propagate_at_boundary.head pidx %7lld : pol0 = np.array([%10.8f,%10.8f,%10.8f]) ; lpol0 = %10.8f \n",
1041 ctx.pidx, p.pol.x, p.pol.y, p.pol.z, length(p.pol) );
1042 printf("//qsim.propagate_at_boundary.head pidx %7lld : n1,n2,eta = (%10.8f,%10.8f,%10.8f) \n", ctx.pidx, n1, n2, eta );
1043 printf("//qsim.propagate_at_boundary.head pidx %7lld : c1 = %10.8f ; normal_incidence = %d \n", ctx.pidx, c1, normal_incidence );
1044 }
1045 #endif
1046
1047 const float c2c2 = 1.f - eta*eta*(1.f - c1 * c1 ) ;
1048 bool tir = c2c2 < 0.f ;
1049 const float EdotN = dot(p.pol, oriented_normal ) ;
1050 const float c2 = tir ? 0.f : sqrtf(c2c2) ;
1051 const float n1c1 = n1*c1 ;
1052 const float n2c2 = n2*c2 ;
1053 const float n2c1 = n2*c1 ;
1054 const float n1c2 = n1*c2 ;
1055
1056 const float2 E1 = normal_incidence ? make_float2( 0.f, 1.f) : make_float2( E1_perp , length( p.pol - (E1_perp*A_trans) ) );
1057 const float2 E2_t = make_float2( 2.f*n1c1*E1.x/(n1c1+n2c2), 2.f*n1c1*E1.y/(n2c1+n1c2) ) ;
1058 const float2 E2_r = make_float2( E2_t.x - E1.x , (n2*E2_t.y/n1) - E1.y ) ;
1059 const float2 RR = normalize(E2_r) ;
1060 const float2 TT = normalize(E2_t) ;
1061 const float TransCoeff = theTransmittance >= 0.f ?
1062 theTransmittance
1063 :
1064 ( tir || n1c1 == 0.f ? 0.f : n2c2*dot(E2_t,E2_t)/n1c1 )
1065 ;
1066
1067
1068
1069
1070
1071
1072 #if !defined(PRODUCTION) && defined(DEBUG_PIDX)
1073 if(ctx.pidx == base->pidx)
1074 {
1075 printf("//qsim.propagate_at_boundary.body pidx %7lld : TransCoeff = %10.8f ; n1c1 = %10.8f ; n2c2 = %10.8f \n",
1076 ctx.pidx, TransCoeff, n1c1, n2c2 );
1077
1078 printf("//qsim.propagate_at_boundary.body pidx %7lld : E2_t = np.array([%10.8f,%10.8f]) ; lE2_t = %10.8f \n",
1079 ctx.pidx, E2_t.x, E2_t.y, length(E2_t) );
1080
1081 printf("//qsim.propagate_at_boundary.body pidx %7lld : A_trans = np.array([%10.8f,%10.8f,%10.8f]) ; lA_trans = %10.8f \n",
1082 ctx.pidx, A_trans.x, A_trans.y, A_trans.z, length(A_trans) );
1083
1084 }
1085 #endif
1086
1087
1088 #if !defined(PRODUCTION) && defined(DEBUG_TAG)
1089 const float u_boundary_burn = curand_uniform(&rng) ;
1090 #endif
1091 const float u_reflect = curand_uniform(&rng) ;
1092 bool reflect = u_reflect > TransCoeff ;
1093
1094 #if !defined(PRODUCTION) && defined(DEBUG_TAG)
1095 stagr& tagr = ctx.tagr ;
1096 tagr.add( stag_at_burn_sf_sd, u_boundary_burn);
1097 tagr.add( stag_at_ref, u_reflect);
1098 #endif
1099
1100 #if !defined(PRODUCTION) && defined(DEBUG_PIDX)
1101 if(ctx.pidx == base->pidx)
1102 {
1103 printf("//qsim.propagate_at_boundary.body pidx %7lld : u_reflect %10.4f TransCoeff %10.4f reflect %d \n",
1104 ctx.pidx, u_reflect, TransCoeff, reflect );
1105
1106 printf("//qsim.propagate_at_boundary.body pidx %7lld : mom0 = np.array([%10.8f,%10.8f,%10.8f]) ; lmom0 = %10.8f \n",
1107 ctx.pidx, p.mom.x, p.mom.y, p.mom.z, length(p.mom) ) ;
1108
1109 printf("//qsim.propagate_at_boundary.body pidx %7lld : pos = np.array([%10.5f,%10.5f,%10.5f]) ; lpos = %10.8f \n",
1110 ctx.pidx, p.pos.x, p.pos.y, p.pos.z, length(p.pos) );
1111
1112 printf("//qsim.propagate_at_boundary.body pidx %7lld : nrm = np.array([%10.8f,%10.8f,%10.8f]) ; lnrm = %10.8f \n",
1113 ctx.pidx, oriented_normal.x, oriented_normal.y, oriented_normal.z, length(oriented_normal) ) ;
1114
1115 printf("//qsim.propagate_at_boundary.body pidx %7lld : n1 = %10.8f ; n2 = %10.8f ; eta = %10.8f \n",
1116 ctx.pidx, n1, n2, eta );
1117
1118 printf("//qsim.propagate_at_boundary.body pidx %7lld : c1 = %10.8f ; eta_c1 = %10.8f ; c2 = %10.8f ; eta_c1__c2 = %10.8f \n",
1119 ctx.pidx, c1, eta*c1, c2, (eta*c1 - c2) );
1120
1121 }
1122 #endif
1123
1124 p.mom = reflect
1125 ?
1126 p.mom + 2.0f*c1*oriented_normal
1127 :
1128 eta*(p.mom) + (eta*c1 - c2)*oriented_normal
1129 ;
1130
1131
1132
1133
1134
1135
1136 const float3 A_paral = normalize(cross(p.mom, A_trans));
1137
1138 p.pol = normal_incidence ?
1139 ( reflect ? p.pol*(n2>n1? -1.f:1.f) : p.pol )
1140 :
1141 ( reflect ?
1142 ( tir ? -p.pol + 2.f*EdotN*oriented_normal : RR.x*A_trans + RR.y*A_paral )
1143
1144 :
1145 TT.x*A_trans + TT.y*A_paral
1146
1147 )
1148 ;
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163 #if !defined(PRODUCTION) && defined(DEBUG_PIDX)
1164 if(ctx.pidx == base->pidx)
1165 {
1166 printf("//qsim.propagate_at_boundary.tail pidx %7lld : reflect %d tir %d TransCoeff %10.4f u_reflect %10.4f \n", ctx.pidx, reflect, tir, TransCoeff, u_reflect );
1167 printf("//qsim.propagate_at_boundary.tail pidx %7lld : mom1 = np.array([%10.8f,%10.8f,%10.8f]) ; lmom1 = %10.8f \n",
1168 ctx.pidx, p.mom.x, p.mom.y, p.mom.z, length(p.mom) );
1169 printf("//qsim.propagate_at_boundary.tail pidx %7lld : pol1 = np.array([%10.8f,%10.8f,%10.8f]) ; lpol1 = %10.8f \n",
1170 ctx.pidx, p.pol.x, p.pol.y, p.pol.z, length(p.pol) );
1171 }
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183 #endif
1184
1185 flag = reflect ? BOUNDARY_REFLECT : BOUNDARY_TRANSMIT ;
1186
1187
1188 #if !defined(PRODUCTION) && defined(DEBUG_TAG)
1189 if( flag == BOUNDARY_REFLECT )
1190 {
1191 const float u_br_align_0 = curand_uniform(&rng) ;
1192 const float u_br_align_1 = curand_uniform(&rng) ;
1193 const float u_br_align_2 = curand_uniform(&rng) ;
1194 const float u_br_align_3 = curand_uniform(&rng) ;
1195
1196
1197 tagr.add( stag_to_sci, u_br_align_0 );
1198 tagr.add( stag_to_bnd, u_br_align_1 );
1199 tagr.add( stag_to_sca, u_br_align_2 );
1200 tagr.add( stag_to_abs, u_br_align_3 );
1201 }
1202 #endif
1203
1204 return CONTINUE ;
1205 }
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224 inline QSIM_METHOD int qsim::propagate_at_boundary_with_T(unsigned& flag, RNG& rng, sctx& ctx, float theTransmittance ) const
1225 {
1226 sphoton& p = ctx.p ;
1227 const sstate& s = ctx.s ;
1228
1229 const float& n1 = s.material1.x ;
1230 const float& n2 = s.material2.x ;
1231 const float eta = n1/n2 ;
1232
1233 const float3* normal = (float3*)&ctx.prd->q0.f.x ;
1234
1235 const float _c1 = -dot(p.mom, *normal );
1236 const float3 oriented_normal = _c1 < 0.f ? -(*normal) : (*normal) ;
1237 const float3 trans = cross(p.mom, oriented_normal) ;
1238 const float trans_length = length(trans) ;
1239 const bool normal_incidence = trans_length < 1e-6f ;
1240 const float3 A_trans = normal_incidence ? p.pol : trans/trans_length ;
1241 const float E1_perp = dot(p.pol, A_trans);
1242
1243 const float c1 = fabs(_c1) ;
1244
1245 const float c2c2 = 1.f - eta*eta*(1.f - c1 * c1 ) ;
1246 bool tir = c2c2 < 0.f ;
1247 const float EdotN = dot(p.pol, oriented_normal ) ;
1248 const float c2 = tir ? 0.f : sqrtf(c2c2) ;
1249 const float n1c1 = n1*c1 ;
1250 const float n2c2 = n2*c2 ;
1251 const float n2c1 = n2*c1 ;
1252 const float n1c2 = n1*c2 ;
1253
1254 const float2 E1 = normal_incidence ? make_float2( 0.f, 1.f) : make_float2( E1_perp , length( p.pol - (E1_perp*A_trans) ) );
1255 const float2 E2_t = make_float2( 2.f*n1c1*E1.x/(n1c1+n2c2), 2.f*n1c1*E1.y/(n2c1+n1c2) ) ;
1256 const float2 E2_r = make_float2( E2_t.x - E1.x , (n2*E2_t.y/n1) - E1.y ) ;
1257 const float2 RR = normalize(E2_r) ;
1258 const float2 TT = normalize(E2_t) ;
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269 const float& TransCoeff = theTransmittance ;
1270
1271 const float u_reflect = curand_uniform(&rng) ;
1272 bool reflect = u_reflect > TransCoeff ;
1273
1274 p.mom = reflect
1275 ?
1276 p.mom + 2.0f*c1*oriented_normal
1277 :
1278 eta*(p.mom) + (eta*c1 - c2)*oriented_normal
1279 ;
1280
1281
1282 const float3 A_paral = normalize(cross(p.mom, A_trans));
1283
1284 p.pol = normal_incidence ?
1285 ( reflect ? p.pol*(n2>n1? -1.f:1.f) : p.pol )
1286 :
1287 ( reflect ?
1288 ( tir ? -p.pol + 2.f*EdotN*oriented_normal : RR.x*A_trans + RR.y*A_paral )
1289
1290 :
1291 TT.x*A_trans + TT.y*A_paral
1292
1293 )
1294 ;
1295
1296 flag = reflect ? BOUNDARY_REFLECT : BOUNDARY_TRANSMIT ;
1297
1298
1299 return CONTINUE ;
1300 }
1301
1302 #endif
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537 #if defined(__CUDACC__) || defined(__CUDABE__)
1538 inline QSIM_METHOD int qsim::propagate_at_surface_MultiFilm(unsigned& flag, RNG& rng, sctx& ctx )
1539 {
1540
1541 const float one = 1.0f;
1542 const sphoton& p = ctx.p ;
1543 const float3* normal = (float3*)&ctx.prd->q0.f.x ;
1544 int lpmtid = ctx.prd->identity() - 1 ;
1545
1546 float minus_cos_theta = dot(p.mom, *normal);
1547 int pmtcat = pmt->get_lpmtcat_from_lpmtid(lpmtid);
1548 float wv_nm = p.wavelength;
1549
1550 float4 RsTsRpTp = multifilm->lookup(pmtcat, wv_nm, minus_cos_theta);
1551
1552
1553 const float c1 = fabs(minus_cos_theta) ;
1554 const float s1 = sqrtf(one -c1*c1);
1555
1556 float EsEs = s1 > 0.f ? dot(p.pol, cross( p.mom, *normal))/s1 : 0.f ;
1557 EsEs *= EsEs;
1558
1559
1560 float3 ART ;
1561 ART.z = RsTsRpTp.y*EsEs + RsTsRpTp.w*(one - EsEs);
1562 ART.y = RsTsRpTp.x*EsEs + RsTsRpTp.z*(one - EsEs);
1563 ART.x = one - (ART.y+ART.z);
1564
1565 const float& A = ART.x ;
1566 const float& T = ART.z ;
1567
1568
1569 float4 RsTsRpTpNormal = multifilm->lookup(pmtcat, wv_nm, -one );
1570
1571
1572 float3 ART_normal;
1573 ART_normal.z = 0.5f*(RsTsRpTpNormal.y + RsTsRpTpNormal.w);
1574 ART_normal.y = 0.5f*(RsTsRpTpNormal.x + RsTsRpTpNormal.z);
1575 ART_normal.x = one -(ART_normal.y + ART_normal.z) ;
1576
1577 const float& An = ART_normal.x ;
1578 const float energy_eV = qpmt<float>::hc_eVnm/wv_nm ;
1579 const float qe_scale = pmt->get_qescale_from_lpmtid(lpmtid);
1580 const float qe_shape = pmt->get_lpmtcat_qe(pmtcat, energy_eV);
1581
1582 const float _qe = minus_cos_theta > 0.f ? 0.f : qe_scale * qe_shape;
1583
1584 const float& theAbsorption = A;
1585 const float& theTransmittance = T/(one-A);
1586 const float& theEfficiency = _qe/An;
1587
1588 float u_theAbsorption = curand_uniform(&rng);
1589 int action = u_theAbsorption < theAbsorption ? BREAK : CONTINUE ;
1590
1591 if( action == BREAK )
1592 {
1593 float u_theEfficiency = curand_uniform(&rng) ;
1594 flag = u_theEfficiency < theEfficiency ? SURFACE_DETECT : SURFACE_ABSORB ;
1595 }
1596 else
1597 {
1598 propagate_at_boundary( flag, rng, ctx, theTransmittance );
1599 }
1600
1601
1602
1603
1604 return action ;
1605
1606 }
1607
1608 #endif
1609
1610
1611 #if defined(__CUDACC__) || defined(__CUDABE__) || defined( MOCK_CURAND ) || defined(MOCK_CUDA)
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677 inline QSIM_METHOD int qsim::propagate_at_surface(unsigned& flag, RNG& rng, sctx& ctx)
1678 {
1679 const sstate& s = ctx.s ;
1680 const float& detect = s.surface.x ;
1681 const float& absorb = s.surface.y ;
1682
1683 const float& reflect_diffuse_ = s.surface.w ;
1684
1685 float u_surface = curand_uniform(&rng);
1686
1687 #if !defined(PRODUCTION) && defined(DEBUG_TAG)
1688 stagr& tagr = ctx.tagr ;
1689 float u_surface_burn = curand_uniform(&rng);
1690 tagr.add( stag_at_burn_sf_sd, u_surface);
1691 tagr.add( stag_sf_burn, u_surface_burn);
1692 #endif
1693
1694
1695 int action = u_surface < absorb + detect ? BREAK : CONTINUE ;
1696
1697 if( action == BREAK )
1698 {
1699 #if defined(WITH_CUSTOM4)
1700 int pmtid = ctx.prd->identity() - 1 ;
1701 float qe = 1.f ;
1702 float u_qe = curand_uniform(&rng);
1703 if( s_pmt::is_spmtid(pmtid) )
1704 {
1705 const float energy_eV = qpmt<float>::hc_eVnm/ctx.p.wavelength ;
1706 float qe_shape = pmt->s_qeshape_prop->interpolate( 0, energy_eV );
1707 float qe_scale = pmt->get_s_qescale_from_spmtid(pmtid);
1708 qe = qe_shape*qe_scale ;
1709 #if !defined(PRODUCTION) && defined(DEBUG_PIDX)
1710 if(ctx.pidx == base->pidx)
1711 printf("//qsim.propagate_at_surface.BREAK.is_spmtid pidx %7lld : pmtid %d energy_eV %7.3f qe_shape %7.3f qe_scale %7.3f qe %7.3f detect %7.3f absorb %7.3f reflect_specular %7.3f reflect_diffuse %7.3f \n" ,
1712 ctx.pidx, pmtid, energy_eV, qe_shape, qe_scale, qe, detect, absorb, s.surface.z, reflect_diffuse_ );
1713 #endif
1714 }
1715 flag = u_surface < absorb ?
1716 SURFACE_ABSORB
1717 :
1718 ( u_qe < qe ? EFFICIENCY_COLLECT : EFFICIENCY_CULL )
1719 ;
1720 #else
1721 flag = u_surface < absorb ?
1722 SURFACE_ABSORB
1723 :
1724 SURFACE_DETECT
1725 ;
1726 #endif
1727
1728 #if !defined(PRODUCTION) && defined(DEBUG_PIDX)
1729 if(ctx.pidx == base->pidx)
1730 printf("//qsim.propagate_at_surface.SA/SD.BREAK pidx %7lld : flag %d \n" , ctx.pidx, flag );
1731 #endif
1732 }
1733 else
1734 {
1735 flag = u_surface < absorb + detect + reflect_diffuse_ ? SURFACE_DREFLECT : SURFACE_SREFLECT ;
1736 switch(flag)
1737 {
1738 case SURFACE_DREFLECT: reflect_diffuse( rng, ctx) ; break ;
1739 case SURFACE_SREFLECT: reflect_specular(rng, ctx) ; break ;
1740 }
1741 #if !defined(PRODUCTION) && defined(DEBUG_PIDX)
1742 if(ctx.pidx == base->pidx)
1743 printf("//qsim.propagate_at_surface.DR/SR.CONTINUE pidx %7lld : flag %d \n" , ctx.pidx, flag );
1744 #endif
1745 }
1746 return action ;
1747 }
1748
1749
1750 inline QSIM_METHOD int qsim::propagate_at_surface_Detect(unsigned& flag, RNG& rng, sctx& ctx) const
1751 {
1752 float u_surface_burn = curand_uniform(&rng);
1753 flag = SURFACE_DETECT ;
1754 return BREAK ;
1755 }
1756
1757
1758 #if defined(WITH_CUSTOM4)
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
1780
1781
1782
1783 inline QSIM_METHOD int qsim::propagate_at_surface_CustomART(unsigned& flag, RNG& rng, sctx& ctx) const
1784 {
1785
1786 sphoton& p = ctx.p ;
1787 const float3* normal = (float3*)&ctx.prd->q0.f.x ;
1788 int lpmtid = ctx.prd->identity() - 1 ;
1789 const float lposcost = ctx.prd->lposcost() ;
1790
1791
1792 float minus_cos_theta = dot(p.mom, *normal);
1793 float dot_pol_cross_mom_nrm = dot(p.pol,cross(p.mom,*normal)) ;
1794
1795 #if !defined(PRODUCTION) && defined(DEBUG_PIDX)
1796 if( ctx.pidx_debug )
1797 {
1798 float3 cross_mom_nrm = cross(p.mom, *normal) ;
1799 printf("//qsim::propagate_at_surface_CustomART pidx %7lld : mom = np.array([%10.8f,%10.8f,%10.8f]) ; lmom = %10.8f \n",
1800 ctx.pidx, p.mom.x, p.mom.y, p.mom.z, length(p.mom) );
1801 printf("//qsim::propagate_at_surface_CustomART pidx %7lld : pol = np.array([%10.8f,%10.8f,%10.8f]) ; lpol = %10.8f \n",
1802 ctx.pidx, p.pol.x, p.pol.y, p.pol.z, length(p.pol) );
1803 printf("//qsim::propagate_at_surface_CustomART pidx %7lld : nrm = np.array([%10.8f,%10.8f,%10.8f]) ; lnrm = %10.8f \n",
1804 ctx.pidx, normal->x, normal->y, normal->z, length(*normal) );
1805 printf("//qsim::propagate_at_surface_CustomART pidx %7lld : cross_mom_nrm = np.array([%10.8f,%10.8f,%10.8f]) ; lcross_mom_nrm = %10.8f \n",
1806 ctx.pidx, cross_mom_nrm.x, cross_mom_nrm.y, cross_mom_nrm.z, length(cross_mom_nrm) );
1807 printf("//qsim::propagate_at_surface_CustomART pidx %7lld : dot_pol_cross_mom_nrm = %10.8f \n", ctx.pidx, dot_pol_cross_mom_nrm );
1808 printf("//qsim::propagate_at_surface_CustomART pidx %7lld : minus_cos_theta = %10.8f \n", ctx.pidx, minus_cos_theta );
1809 printf("//qsim::propagate_at_surface_CustomART pidx %7lld : lposcost = %10.8f (expect 0->1)\n", ctx.pidx, lposcost );
1810 }
1811 #endif
1812
1813
1814
1815
1816 if(lpmtid < s_pmt::OFFSET_CD_LPMT || lpmtid >= s_pmt::OFFSET_WP_WAL_PMT_END )
1817 {
1818 flag = NAN_ABORT ;
1819 #if !defined(PRODUCTION) && defined(DEBUG_PIDX)
1820 printf("//qsim::propagate_at_surface_CustomART pidx %7lld lpmtid %d : ERROR UNEXPECTED LPMTID : NAN_ABORT \n", ctx.pidx, lpmtid );
1821 #endif
1822 return BREAK ;
1823 }
1824
1825 #if !defined(PRODUCTION) && defined(DEBUG_PIDX)
1826 if( ctx.pidx_debug )
1827 printf("//qsim::propagate_at_surface_CustomART pidx %7lld lpmtid %d wl %8.4f mct %8.4f dpcmn %8.4f pmt %p pre-ATQC \n",
1828 ctx.pidx, lpmtid, p.wavelength, minus_cos_theta, dot_pol_cross_mom_nrm, pmt );
1829 #endif
1830
1831 float ATQC[4] = {} ;
1832
1833 #if !defined(PRODUCTION) && defined(DEBUG_PIDX)
1834 if(lpmtid > -1 && pmt != nullptr) pmt->get_lpmtid_ATQC(ATQC, lpmtid, p.wavelength, minus_cos_theta, dot_pol_cross_mom_nrm, lposcost, ctx.pidx, ctx.pidx_debug );
1835 #else
1836 if(lpmtid > -1 && pmt != nullptr) pmt->get_lpmtid_ATQC(ATQC, lpmtid, p.wavelength, minus_cos_theta, dot_pol_cross_mom_nrm, lposcost );
1837 #endif
1838
1839
1840
1841 #if !defined(PRODUCTION) && defined(DEBUG_PIDX)
1842 if( ctx.pidx_debug )
1843 printf("//qsim::propagate_at_surface_CustomART pidx %7lld lpmtid %d wl %8.4f mct %8.4f dpcmn %8.4f lpc %8.4f ATQC ( %8.4f %8.4f %8.4f %8.4f ) \n",
1844 ctx.pidx, lpmtid, p.wavelength, minus_cos_theta, dot_pol_cross_mom_nrm, lposcost, ATQC[0], ATQC[1], ATQC[2], ATQC[3] );
1845 #endif
1846
1847
1848 const float& theAbsorption = ATQC[0];
1849 const float& theTransmittance = ATQC[1];
1850 const float& theEfficiency = ATQC[2];
1851 const float& collectionEfficiency = ATQC[3];
1852
1853 float u_theAbsorption = curand_uniform(&rng);
1854 int action = u_theAbsorption < theAbsorption ? BREAK : CONTINUE ;
1855
1856
1857 #if !defined(PRODUCTION) && defined(DEBUG_PIDX)
1858 if( ctx.pidx_debug )
1859 printf("//qsim.propagate_at_surface_CustomART pidx %7lld lpmtid %d ATQC ( %8.4f %8.4f %8.4f %8.4f ) u_theAbsorption %7.3f action %d \n",
1860 ctx.pidx, lpmtid, ATQC[0], ATQC[1], ATQC[2], ATQC[3], u_theAbsorption, action );
1861 #endif
1862
1863 if( action == BREAK )
1864 {
1865 float u_theEfficiency = curand_uniform(&rng) ;
1866 float u_collectionEfficiency = curand_uniform(&rng);
1867
1868 flag = u_theEfficiency < theEfficiency ?
1869 ( u_collectionEfficiency < collectionEfficiency ? EFFICIENCY_COLLECT : EFFICIENCY_CULL )
1870 :
1871 SURFACE_ABSORB
1872 ;
1873
1874
1875
1876 #if !defined(PRODUCTION) && defined(DEBUG_PIDX)
1877 if( ctx.pidx_debug )
1878 printf("//qsim.propagate_at_surface_CustomART.BREAK.SD/SA EC/EX pidx %7lld lpmtid %d ATQC ( %8.4f %8.4f %8.4f %8.4f ) u_theEfficiency %8.4f theEfficiency %8.4f flag %d \n",
1879 ctx.pidx, lpmtid, ATQC[0],ATQC[1], ATQC[2],ATQC[3], u_theEfficiency, theEfficiency, flag );
1880 #endif
1881
1882 }
1883 else
1884 {
1885
1886 #if !defined(PRODUCTION) && defined(DEBUG_PIDX)
1887 if( ctx.pidx_debug )
1888 printf("//qsim.propagate_at_surface_CustomART.CONTINUE pidx %7lld lpmtid %d ATQC ( %7.3f %7.3f %7.3f %7.3f ) theTransmittance %7.3f \n",
1889 ctx.pidx, lpmtid, ATQC[0], ATQC[1], ATQC[2], ATQC[3], theTransmittance );
1890 #endif
1891
1892 propagate_at_boundary( flag, rng, ctx, theTransmittance );
1893 }
1894 return action ;
1895 }
1896 #endif
1897
1898 #endif
1899
1900
1901 #if defined(__CUDACC__) || defined(__CUDABE__) || defined(MOCK_CURAND) || defined(MOCK_CUDA)
1902
1903
1904
1905
1906
1907
1908
1909
1910
1911
1912
1913
1914
1915
1916
1917
1918
1919
1920
1921
1922
1923
1924
1925
1926
1927
1928
1929
1930
1931
1932
1933
1934
1935
1936
1937
1938
1939
1940
1941
1942
1943
1944
1945
1946
1947
1948
1949
1950
1951
1952
1953
1954
1955
1956
1957
1958
1959
1960
1961
1962
1963
1964
1965
1966
1967
1968
1969
1970
1971
1972
1973
1974
1975
1976
1977 inline QSIM_METHOD void qsim::reflect_diffuse( RNG& rng, sctx& ctx )
1978 {
1979 sphoton& p = ctx.p ;
1980
1981 float3 old_mom = p.mom ;
1982
1983 const float3* normal = ctx.prd->normal() ;
1984
1985
1986 const float orient = dot( old_mom, *normal ) > 0.f ? -1.f : 1.f ;
1987
1988 lambertian_direction( &p.mom, normal, orient, rng, ctx );
1989
1990
1991 float3 facet_normal = normalize( p.mom - old_mom );
1992 const float EdotN = dot( p.pol, facet_normal );
1993 p.pol = -1.f*(p.pol) + 2.f*EdotN*facet_normal ;
1994
1995 #if !defined(PRODUCTION) && defined(DEBUG_PIDX)
1996 if(ctx.pidx == base->pidx)
1997 {
1998 printf("//qsim.reflect_diffuse pidx %7lld : old_mom = np.array([%10.5f,%10.5f,%10.5f]) \n",
1999 ctx.pidx, old_mom.x, old_mom.y, old_mom.z ) ;
2000
2001 printf("//qsim.reflect_diffuse pidx %7lld : normal0 = np.array([%10.5f,%10.5f,%10.5f]) \n",
2002 ctx.pidx, normal->x, normal->y, normal->z ) ;
2003
2004 printf("//qsim.reflect_diffuse pidx %7lld : p.mom = np.array([%10.5f,%10.5f,%10.5f]) \n",
2005 ctx.pidx, p.mom.x, p.mom.y, p.mom.z ) ;
2006
2007 printf("//qsim.reflect_diffuse pidx %7lld : facet_normal = np.array([%10.5f,%10.5f,%10.5f]) \n",
2008 ctx.pidx, facet_normal.x, facet_normal.y, facet_normal.z ) ;
2009 }
2010 #endif
2011
2012 }
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
2027
2028
2029
2030 inline QSIM_METHOD void qsim::reflect_specular( RNG& rng, sctx& ctx )
2031 {
2032 sphoton& p = ctx.p ;
2033 const float3* normal = ctx.prd->normal() ;
2034
2035 #if !defined(PRODUCTION) && defined(DEBUG_PIDX)
2036 if(ctx.pidx == base->pidx)
2037 {
2038 printf("//qsim.reflect_specular.head pidx %7lld : normal0 = np.array([%10.5f,%10.5f,%10.5f]) \n",
2039 ctx.pidx, normal->x, normal->y, normal->z ) ;
2040
2041 printf("//qsim.reflect_specular.head pidx %7lld : mom0 = np.array([%10.5f,%10.5f,%10.5f]) \n",
2042 ctx.pidx, p.mom.x, p.mom.y, p.mom.z ) ;
2043
2044 printf("//qsim.reflect_specular.head pidx %7lld : pol0 = np.array([%10.5f,%10.5f,%10.5f]) \n",
2045 ctx.pidx, p.pol.x, p.pol.y, p.pol.z ) ;
2046 }
2047 #endif
2048
2049 #ifdef WITH_ORIENT
2050
2051 const float orient = 1.f ;
2052
2053
2054
2055 const float PdotN = dot( p.mom, *normal )*orient ;
2056 p.mom = p.mom - 2.f*PdotN*(*normal)*orient ;
2057
2058 const float EdotN = dot( p.pol, *normal )*orient ;
2059 p.pol = -1.f*(p.pol) + 2.f*EdotN*(*normal)*orient ;
2060 #else
2061
2062 const float PdotN = dot( p.mom, *normal ) ;
2063 p.mom = p.mom - 2.f*PdotN*(*normal) ;
2064
2065 const float EdotN = dot( p.pol, *normal ) ;
2066 p.pol = -1.f*(p.pol) + 2.f*EdotN*(*normal) ;
2067 #endif
2068
2069 #if !defined(PRODUCTION) && defined(DEBUG_PIDX)
2070 if(ctx.pidx == base->pidx)
2071 {
2072 printf("//qsim.reflect_specular.tail pidx %7lld : mom1 = np.array([%10.5f,%10.5f,%10.5f]) ; PdotN = %10.5f ; EdotN = %10.5f \n",
2073 ctx.pidx, p.mom.x, p.mom.y, p.mom.z, PdotN, EdotN ) ;
2074
2075 printf("//qsim.reflect_specular.tail pidx %7lld : pol1 = np.array([%10.5f,%10.5f,%10.5f]) \n",
2076 ctx.pidx, p.pol.x, p.pol.y, p.pol.z ) ;
2077
2078 }
2079 #endif
2080
2081
2082 }
2083
2084
2085
2086
2087
2088
2089
2090
2091
2092
2093
2094
2095
2096
2097
2098
2099
2100
2101
2102
2103
2104
2105
2106
2107
2108
2109
2110
2111
2112
2113
2114
2115
2116
2117
2118
2119
2120
2121
2122
2123 inline QSIM_METHOD void qsim::fake_propagate( sphoton& p, const quad2* mock_prd, RNG& rng, unsigned long long idx )
2124 {
2125 p.set_flag(TORCH);
2126
2127 qsim* sim = this ;
2128
2129 sctx ctx = {} ;
2130 ctx.p = p ;
2131 ctx.evt = evt ;
2132 ctx.pidx = idx ;
2133
2134 int command = START ;
2135 int bounce = 0 ;
2136 #ifndef PRODUCTION
2137 ctx.point(bounce);
2138 #endif
2139
2140 while( bounce < evt->max_bounce )
2141 {
2142 ctx.prd = mock_prd + (evt->max_bounce*idx+bounce) ;
2143 if( ctx.prd->boundary() == 0xffffu ) break ;
2144 #ifndef PRODUCTION
2145 ctx.trace(bounce);
2146 #endif
2147
2148 #if !defined(PRODUCTION) && defined(DEBUG_PIDX)
2149 if(idx == base->pidx)
2150 printf("//qsim.fake_propagate pidx %7lld bounce %d evt.max_bounce %d prd.q0.f.xyzw (%10.4f %10.4f %10.4f %10.4f) \n",
2151 idx, bounce, evt->max_bounce, ctx.prd->q0.f.x, ctx.prd->q0.f.y, ctx.prd->q0.f.z, ctx.prd->q0.f.w );
2152 #endif
2153 command = sim->propagate(bounce, rng, ctx );
2154 bounce++;
2155 #ifndef PRODUCTION
2156 ctx.point(bounce);
2157 #endif
2158 if(command == BREAK) break ;
2159 }
2160 #ifndef PRODUCTION
2161 ctx.end();
2162 #endif
2163 evt->photon[idx] = ctx.p ;
2164 }
2165
2166
2167
2168
2169
2170
2171
2172
2173
2174
2175
2176
2177
2178
2179
2180
2181
2182
2183
2184
2185
2186
2187
2188
2189
2190
2191
2192
2193
2194
2195
2196
2197
2198
2199
2200
2201
2202
2203
2204
2205
2206
2207
2208
2209
2210
2211
2212
2213
2214
2215
2216
2217
2218 inline QSIM_METHOD int qsim::propagate(const int bounce, RNG& rng, sctx& ctx )
2219 {
2220 const unsigned boundary = ctx.prd->boundary() ;
2221 const unsigned identity = ctx.prd->identity() ;
2222 const unsigned iindex = ctx.prd->iindex() ;
2223 const float lposcost = ctx.prd->lposcost() ;
2224
2225 const float3* normal = ctx.prd->normal();
2226 float cosTheta = dot(ctx.p.mom, *normal ) ;
2227
2228 #if !defined(PRODUCTION) && defined(DEBUG_PIDX)
2229 if( ctx.pidx == base->pidx )
2230 {
2231 printf("\n//qsim.propagate.head pidx %7lld : ctx.evt.index %d evt.index %d \n", ctx.pidx, ctx.evt->index, evt->index );
2232
2233 printf("\n//qsim.propagate.head pidx %7lld : bnc %d boundary %d cosTheta %10.8f \n", ctx.pidx, bounce, boundary, cosTheta );
2234
2235 printf("//qsim.propagate.head pidx %7lld : mom = np.array([%10.8f,%10.8f,%10.8f]) ; lmom = %10.8f \n",
2236 ctx.pidx, ctx.p.mom.x, ctx.p.mom.y, ctx.p.mom.z, length(ctx.p.mom) ) ;
2237
2238 printf("//qsim.propagate.head pidx %7lld : pos = np.array([%10.5f,%10.5f,%10.5f]) ; lpos = %10.8f \n",
2239 ctx.pidx, ctx.p.pos.x, ctx.p.pos.y, ctx.p.pos.z, length(ctx.p.pos) ) ;
2240
2241 printf("//qsim.propagate.head pidx %7lld : nrm = np.array([(%10.8f,%10.8f,%10.8f]) ; lnrm = %10.8f \n",
2242 ctx.pidx, normal->x, normal->y, normal->z, length(*normal) );
2243
2244 }
2245 #endif
2246
2247
2248 ctx.p.set_prd(boundary, identity, cosTheta, iindex );
2249
2250 bnd->fill_state(ctx.s, boundary, ctx.p.wavelength, cosTheta, ctx.pidx, base->pidx );
2251
2252 unsigned flag = 0 ;
2253
2254 int command = propagate_to_boundary( flag, rng, ctx );
2255
2256
2257
2258
2259
2260
2261
2262
2263
2264 #if !defined(PRODUCTION) && defined(DEBUG_PIDX)
2265 if( ctx.pidx == base->pidx )
2266 printf("//qsim.propagate.body pidx %7lld bounce %d command %d flag %d s.optical.x %d s.optical.y %d \n",
2267 ctx.pidx, bounce, command, flag, ctx.s.optical.x, ctx.s.optical.y );
2268 #endif
2269
2270 if( command == BOUNDARY )
2271 {
2272 const int& ems = ctx.s.optical.y ;
2273
2274 #if !defined(PRODUCTION) && defined(DEBUG_PIDX)
2275 if( ctx.pidx == base->pidx )
2276 {
2277 #if defined(WITH_CUSTOM4)
2278 printf("//qsim.propagate.body.WITH_CUSTOM4 pidx %7lld BOUNDARY ems %d lposcost %7.3f \n", ctx.pidx, ems, lposcost );
2279 #else
2280 printf("//qsim.propagate.body.NOT:WITH_CUSTOM4 pidx %7lld BOUNDARY ems %d lposcost %7.3f \n", ctx.pidx, ems, lposcost);
2281 #endif
2282 }
2283 #endif
2284
2285 if( ems == smatsur_NoSurface )
2286 {
2287 command = propagate_at_boundary( flag, rng, ctx ) ;
2288 }
2289 else if( ems == smatsur_Surface )
2290 {
2291 command = propagate_at_surface( flag, rng, ctx ) ;
2292 }
2293 else if( lposcost < 0.f )
2294 {
2295 #if !defined(PRODUCTION) && defined(DEBUG_PIDX)
2296 if( ctx.pidx == base->pidx )
2297 printf("//qsim.propagate.body (lposcost < 0.f) pidx %7lld bounce %d command %d flag %d ems %d \n",
2298 ctx.pidx, bounce, command, flag, ems );
2299 #endif
2300 command = propagate_at_surface( flag, rng, ctx ) ;
2301 }
2302 else if( ems == smatsur_Surface_zplus_sensor_A )
2303 {
2304 command = propagate_at_surface_Detect( flag, rng, ctx ) ;
2305 }
2306 else if( ems == smatsur_Surface_zplus_sensor_CustomART )
2307 {
2308 #if defined(WITH_CUSTOM4)
2309 command = propagate_at_surface_CustomART( flag, rng, ctx ) ;
2310
2311
2312 #endif
2313 }
2314 }
2315 ctx.p.set_flag(flag);
2316
2317
2318
2319
2320 #if !defined(PRODUCTION) && defined(DEBUG_PIDX)
2321 if( ctx.pidx == base->pidx )
2322 printf("//qsim.propagate.tail pidx %7lld bounce %d command %d flag %d ctx.s.optical.y(ems) %d \n",
2323 ctx.pidx, bounce, command, flag, ctx.s.optical.y );
2324 #endif
2325
2326 return command ;
2327 }
2328
2329
2330
2331
2332
2333
2334
2335
2336
2337
2338
2339
2340
2341
2342
2343
2344
2345
2346
2347
2348
2349
2350
2351
2352
2353
2354
2355
2356
2357
2358
2359
2360
2361
2362
2363
2364
2365
2366
2367
2368
2369
2370
2371
2372
2373
2374
2375
2376
2377
2378
2379
2380
2381 inline QSIM_METHOD void qsim::hemisphere_polarized( unsigned polz, bool inwards, RNG& rng, sctx& ctx )
2382 {
2383 sphoton& p = ctx.p ;
2384 const float3* normal = ctx.prd->normal() ;
2385
2386
2387
2388 float u_hemipol_phi = curand_uniform(&rng) ;
2389 float phi = u_hemipol_phi*2.f*M_PIf;
2390 float cosTheta = curand_uniform(&rng) ;
2391
2392 #if !defined(PRODUCTION) && defined(DEBUG_TAG)
2393 stagr& tagr = ctx.tagr ;
2394 tagr.add( stag_hp_ph, u_hemipol_phi );
2395 tagr.add( stag_hp_ph, cosTheta );
2396 #endif
2397
2398 float sinTheta = sqrtf(1.f-cosTheta*cosTheta);
2399
2400 p.mom.x = cosf(phi)*sinTheta ;
2401 p.mom.y = sinf(phi)*sinTheta ;
2402 p.mom.z = cosTheta ;
2403
2404 smath::rotateUz( p.mom, (*normal) * ( inwards ? -1.f : 1.f ));
2405
2406
2407
2408
2409 const float3 transverse = normalize(cross(p.mom, (*normal) * ( inwards ? -1.f : 1.f ) )) ;
2410 const float3 within = normalize( cross(p.mom, transverse) );
2411
2412 switch(polz)
2413 {
2414 case 0: p.pol = transverse ; break ;
2415 case 1: p.pol = within ; break ;
2416 case 2: p.pol = normalize( 0.5f*transverse + (1.f-0.5f)*within ) ; break ;
2417 }
2418 }
2419
2420
2421
2422
2423
2424
2425
2426
2427
2428
2429
2430
2431
2432
2433
2434
2435
2436
2437
2438
2439
2440
2441
2442
2443
2444
2445
2446
2447
2448
2449 inline QSIM_METHOD void qsim::generate_photon_simtrace(quad4& p, RNG& rng, const quad6& gs, unsigned long long photon_id, unsigned genstep_id ) const
2450 {
2451 const int& gencode = gs.q0.i.x ;
2452 switch(gencode)
2453 {
2454 case OpticksGenstep_FRAME: generate_photon_simtrace_frame(p, rng, gs, photon_id, genstep_id ); break ;
2455 case OpticksGenstep_INPUT_PHOTON_SIMTRACE: { p = (quad4&)evt->simtrace[photon_id] ; } ; break ;
2456 }
2457 }
2458
2459 inline QSIM_METHOD void qsim::generate_photon_simtrace_frame(quad4& p, RNG& rng, const quad6& gs, unsigned long long photon_id, unsigned genstep_id ) const
2460 {
2461 C4U gsid ;
2462
2463
2464 int gridaxes = gs.q0.i.y ;
2465 gsid.u = gs.q0.i.z ;
2466
2467
2468 p.q0.f.x = gs.q1.f.x ;
2469 p.q0.f.y = gs.q1.f.y ;
2470 p.q0.f.z = gs.q1.f.z ;
2471 p.q0.f.w = 1.f ;
2472
2473
2474
2475 float u0 = curand_uniform(&rng);
2476 float sinPhi, cosPhi;
2477 #if defined(MOCK_CURAND) || defined(MOCK_CUDA)
2478 __sincosf(2.f*M_PIf*u0,&sinPhi,&cosPhi);
2479 #else
2480 sincosf(2.f*M_PIf*u0,&sinPhi,&cosPhi);
2481 #endif
2482
2483 float u1 = curand_uniform(&rng);
2484 float cosTheta = 2.f*u1 - 1.f ;
2485 float sinTheta = sqrtf(1.f-cosTheta*cosTheta) ;
2486
2487
2488
2489
2490
2491 switch( gridaxes )
2492 {
2493 case YZ: { p.q1.f.x = 0.f ; p.q1.f.y = cosPhi ; p.q1.f.z = sinPhi ; p.q1.f.w = 0.f ; } ; break ;
2494 case XZ: { p.q1.f.x = cosPhi ; p.q1.f.y = 0.f ; p.q1.f.z = sinPhi ; p.q1.f.w = 0.f ; } ; break ;
2495 case XY: { p.q1.f.x = cosPhi ; p.q1.f.y = sinPhi ; p.q1.f.z = 0.f ; p.q1.f.w = 0.f ; } ; break ;
2496 case XYZ: { p.q1.f.x = sinTheta*cosPhi ;
2497 p.q1.f.y = sinTheta*sinPhi ;
2498 p.q1.f.z = cosTheta ;
2499 p.q1.f.w = 0.f ; } ; break ;
2500 }
2501
2502
2503 qat4 qt(gs) ;
2504 qt.right_multiply_inplace( p.q0.f, 1.f );
2505 qt.right_multiply_inplace( p.q1.f, 0.f );
2506
2507
2508 unsigned char ucj = (photon_id < 255 ? photon_id : 255 ) ;
2509 gsid.c4.w = ucj ;
2510 p.q3.u.w = gsid.u ;
2511 }
2512
2513
2514
2515
2516
2517
2518
2519
2520
2521 inline QSIM_METHOD void qsim::generate_photon(sphoton& p, RNG& rng, const quad6& gs, unsigned long long photon_id, unsigned genstep_id ) const
2522 {
2523 const int& gencode = gs.q0.i.x ;
2524 switch(gencode)
2525 {
2526 case OpticksGenstep_CARRIER: scarrier::generate( p, rng, gs, photon_id, genstep_id) ; break ;
2527 case OpticksGenstep_TORCH: storch::generate( p, rng, gs, photon_id, genstep_id ) ; break ;
2528
2529 case OpticksGenstep_G4Cerenkov_modified:
2530 case OpticksGenstep_CERENKOV:
2531 cerenkov->generate( p, rng, gs, photon_id, genstep_id ) ; break ;
2532
2533 case OpticksGenstep_DsG4Scintillation_r4695:
2534 case OpticksGenstep_SCINTILLATION:
2535 scint->generate( p, rng, gs, photon_id, genstep_id ) ; break ;
2536
2537 case OpticksGenstep_INPUT_PHOTON: { p = evt->photon[photon_id] ; p.set_flag(TORCH) ; } ; break ;
2538 default: generate_photon_dummy( p, rng, gs, photon_id, genstep_id) ; break ;
2539 }
2540 p.set_index(photon_id) ;
2541 }
2542 #endif
2543