Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-04-09 07:49:07

0001 /**
0002 QSimTest.cc
0003 =============
0004 
0005 NB QSimTest.cc uses many QSim.cc methods that are purely for testing
0006 Many of those testing methods used extern linked methods
0007 implemented in QSim.cu which do CUDA launches.
0008 
0009 Arguably this layout mixes too closely the purely testing methods
0010 with the actual code being tested.
0011 
0012 **/
0013 
0014 #include <sstream>
0015 #include <csignal>
0016 
0017 #include <cuda_runtime.h>
0018 #include "OPTICKS_LOG.hh"
0019 
0020 #include "SEventConfig.hh"
0021 #include "scuda.h"
0022 #include "squad.h"
0023 #include "ssys.h"
0024 #include "spath.h"
0025 
0026 #include "SSim.hh"
0027 #include "SBnd.h"
0028 #include "SPrd.h"
0029 
0030 #include "SEvt.hh"
0031 #include "NP.hh"
0032 #include "sstate.h"
0033 
0034 #include "QRng.hh"
0035 #include "QBnd.hh"
0036 #include "QProp.hh"
0037 #include "QSim.hh"
0038 #include "QSimLaunch.hh"
0039 #include "QEvt.hh"
0040 
0041 #include "QDebug.hh"
0042 #include "qdebug.h"
0043 
0044 #include "SEvent.hh"
0045 
0046 
0047 
0048 struct QSimTest
0049 {
0050     static constexpr const unsigned M = 1000000 ;
0051     static const char* FOLD ;
0052     static const plog::Severity LEVEL ;
0053     static unsigned Num(int argc, char** argv);
0054 
0055     const SPrd* sprd ;
0056     QSim* qs ;
0057     unsigned type ;  // QSimLaunch type
0058     unsigned num ;
0059     const char* subfold ;
0060     int rc ;
0061 
0062     QSimTest(unsigned type, unsigned num, const SPrd* sprd );
0063     void main();
0064 
0065     static const bool rng_sequence_PRECOOKED ;
0066     void rng_sequence(unsigned ni, int ni_tranche_size);
0067 
0068 
0069     void boundary_lookup_all();
0070     void boundary_lookup_line(const char* material, float x0, float x1, unsigned nx );
0071 
0072     template<typename T>
0073     void prop_lookup( int iprop, T x0, T x1, unsigned nx );
0074 
0075     void multifilm_lookup_all();
0076 
0077     void wavelength() ;
0078     void RandGaussQ_shoot();
0079 
0080     void dbg_gs_generate();
0081 
0082 
0083     void generate_photon();
0084     void getStateNames(std::vector<std::string>& names, int num_state) const ;
0085 
0086     void fill_state(unsigned version);
0087     void save_state( const char* subfold, const float* data, int num_state  );
0088 
0089     void photon_launch_generate();
0090     void photon_launch_mutate();
0091 
0092     static void  EventConfig(unsigned type, const SPrd* prd);  // must be run after SEvt is instanciated
0093     void fake_propagate();
0094 
0095     void quad_launch_generate();
0096 
0097 
0098 };
0099 
0100 /**
0101 QSimTest::LEVEL
0102 ----------------
0103 
0104 Inhibiting logging  within executables does not work ...
0105 
0106 **/
0107 
0108 const plog::Severity QSimTest::LEVEL = SLOG::EnvLevel("QSimTest", "INFO");
0109 
0110 
0111 
0112 QSimTest::QSimTest(unsigned type_, unsigned num_, const SPrd* sprd_)
0113     :
0114     sprd(sprd_),
0115     qs(QSim::Create()),
0116     type(type_),
0117     num(num_),
0118     subfold(QSimLaunch::Name(type)),
0119     rc(0)
0120 {
0121 }
0122 
0123 
0124 /**
0125 QSimTest::rng_sequence
0126 -------------------------
0127 
0128 Default ni and ni_tranche_size_ are 1M and 100k which corresponds to 10 tranche launches
0129 to generate the 256M randoms.
0130 
0131 Default dir is $TMP/QSimTest/rng_sequence leading to npy paths like::
0132 
0133     /tmp/blyth/opticks/QSimTest/rng_sequence/rng_sequence_f_ni1000000_nj16_nk16_tranche100000/rng_sequence_f_ni100000_nj16_nk16_ioffset000000.npy
0134 
0135 As default ni of 1M taking too much space on /tmp/QSimTest/rng_sequence arranged to delete the FOLD after ana at bash level::
0136 
0137     977M    rng_sequence
0138 
0139 **/
0140 
0141 
0142 const bool QSimTest::rng_sequence_PRECOOKED = ssys::getenvbool("QSimTest__rng_sequence_PRECOOKED") ;
0143 
0144 void QSimTest::rng_sequence(unsigned ni, int ni_tranche_size_)
0145 {
0146     unsigned nj = 16 ;
0147     unsigned nk = 16 ;
0148     unsigned ni_tranche_size = ni_tranche_size_ > 0 ? ni_tranche_size_ : ni ;
0149 
0150     const char* udir = rng_sequence_PRECOOKED ? "$HOME/.opticks/precooked/QSimTest/rng_sequence" : "$FOLD" ;
0151     LOG(info) << " idir " << udir ;
0152 
0153 
0154     LOG_IF(error, rng_sequence_PRECOOKED)
0155         << " QSimTest__rng_sequence_PRECOOKED envvar triggers directory override " << std::endl
0156         << " default  [" << "$FOLD" << "] " << std::endl
0157         << " override [" << udir << "]"
0158         ;
0159 
0160     qs->rng_sequence<float>(udir, ni, nj, nk, ni_tranche_size );
0161 }
0162 
0163 
0164 
0165 
0166 /**
0167 QSimTest::boundary_lookup_all
0168 -------------------------------
0169 
0170 Does lookups at every texel of the 2d float4 boundary texture
0171 
0172 **/
0173 
0174 void QSimTest::boundary_lookup_all()
0175 {
0176     unsigned width = qs->getBoundaryTexWidth();
0177     unsigned height = qs->getBoundaryTexHeight();
0178     const NP* src = qs->getBoundaryTexSrc();
0179 
0180 
0181     bool height_expect = height % 8 == 0 ;
0182     assert( height_expect );
0183     if(!height_expect) std::raise(SIGINT);
0184 
0185     unsigned num_bnd = height/8 ;
0186     NP* l = qs->boundary_lookup_all( width, height );
0187 
0188     bool l_expect = l->has_shape( num_bnd, 4, 2, width, 4 ) ;
0189     assert( l_expect );
0190     if(!l_expect ) std::raise(SIGINT) ;
0191 
0192     l->save("$FOLD/lookup_all.npy" );
0193     src->save("$FOLD/lookup_all_src.npy" );
0194 }
0195 
0196 /**
0197 QSimTest::boundary_lookup_line
0198 -------------------------------
0199 
0200 Single material property lookups across domain of wavelength values
0201 
0202 **/
0203 void QSimTest::boundary_lookup_line(const char* material, float x0 , float x1, unsigned nx )
0204 {
0205     LOG(info);
0206 
0207     unsigned line = qs->bnd->sbn->getMaterialLine(material);
0208     if( line == ~0u )
0209     {
0210         LOG(fatal) << " material not in boundary tex " << material ;
0211         assert(0);
0212     }
0213 
0214     LOG(info) << " material " << material << " line " << line ;
0215     unsigned k = 0 ;    // 0 or 1 picking the property float4 group to collect
0216 
0217     NP* x = NP::Linspace<float>(x0,x1,nx);
0218     float* xx = x->values<float>();
0219 
0220     NP* l = qs->boundary_lookup_line( xx, nx, line, k );
0221 
0222     l->save("$FOLD/lookup_line.npy" );
0223     x->save("$FOLD/lookup_line_wavelength.npy");
0224 }
0225 
0226 /**
0227 QSimTest::prop_lookup
0228 ----------------------
0229 
0230 Testing QProp/qprop::interpolate machinery for on device interpolated property access
0231 very simular to traditional Geant4 interpolation, without the need for textures.
0232 
0233 Multiple launches are done by QSim::prop_lookup_onebyone
0234 
0235 **/
0236 
0237 template<typename T>
0238 void QSimTest::prop_lookup( int iprop, T x0, T x1, unsigned nx )
0239 {
0240     unsigned tot_prop = qs->prop->ni ;
0241     const NP* pp = qs->prop->a ;
0242 
0243     std::vector<unsigned> pids ;
0244     if( iprop == -1 )
0245     {
0246         for(unsigned i=0 ; i < tot_prop ; i++ ) pids.push_back(i);
0247     }
0248     else
0249     {
0250         pids.push_back(iprop);
0251     }
0252 
0253     unsigned num_prop = pids.size() ;
0254 
0255     LOG(info)
0256         << " tot_prop " << tot_prop
0257         << " iprop " << iprop
0258         << " pids.size " << pids.size()
0259         << " num_prop " << num_prop
0260         << " pp " << pp->desc()
0261         ;
0262 
0263 
0264     NP* yy = NP::Make<T>(num_prop, nx) ;
0265     NP* x = NP::Linspace<T>(x0,x1,nx);
0266 
0267     qs->prop_lookup_onebyone( yy->values<T>(), x->cvalues<T>(), nx, pids ) ;
0268 
0269     const char* reldir = sizeof(T) == 8 ? "double" : "float" ;
0270 
0271     pp->save("$FOLD", reldir, "prop_lookup_pp.npy" );
0272     x->save("$FOLD", reldir, "prop_lookup_x.npy" );
0273     yy->save("$FOLD", reldir, "prop_lookup_yy.npy" );
0274 }
0275 
0276 
0277 
0278 
0279 
0280 void QSimTest::multifilm_lookup_all(){
0281 
0282     /*
0283      test_texture.npy :  (height, width,2,4)
0284 
0285       2*4 : means quad2 type:
0286       pmtType , wv_nm , aoi , undefined;
0287       R_s,      T_s ,   R_p,  T_p      ;
0288      */
0289     NP * sample = NP::Load("/tmp/debug_multi_film_table/","test_texture.npy");
0290 
0291     assert(sample);
0292     quad2 * h_quad2_sample = (quad2*)sample->values<float>();
0293 
0294 
0295     unsigned height= sample->shape[0];
0296     unsigned width = sample->shape[1];
0297     unsigned num_sample = height*width;
0298     std::cout<<"  width  = "<< width
0299              <<"  height = "<< height
0300              <<"  num_sample ="<< num_sample
0301              <<std::endl;
0302 
0303     assert( height*width == num_sample);
0304     // convert float to quad2
0305 
0306     quad2 h_quad2_result[num_sample];
0307     qs->multifilm_lookup_all(  h_quad2_sample ,  h_quad2_result ,  width,  height );
0308 
0309     assert(h_quad2_result);
0310     NP * result = NP::Make<float>(height,width , 4);
0311     float4* output = (float4*) result->values<float>();
0312     // convert quad2 to float
0313 
0314     for(unsigned i = 0 ; i < height ; i++){
0315         for(unsigned j = 0 ; j < width ; j++ ){
0316             unsigned index = i*width + j;
0317             output[index].x = h_quad2_result[index].q1.f.x;
0318             output[index].y = h_quad2_result[index].q1.f.y;
0319             output[index].z = h_quad2_result[index].q1.f.z;
0320             output[index].w = h_quad2_result[index].q1.f.w;
0321         }
0322     }
0323     result->save("$FOLD/multifilm_lut_result.npy");
0324 }
0325 
0326 
0327 
0328 void QSimTest::wavelength()
0329 {
0330     NP* w = nullptr ;
0331 
0332     std::stringstream ss ;
0333     ss << "wavelength" ; ;
0334     if( type == WAVELENGTH_SCINTILLATION )
0335     {
0336         unsigned hd_factor(~0u) ;
0337         w = qs->scint_wavelength( num, hd_factor );  // hd_factor is an output argument
0338         assert( hd_factor == 0 || hd_factor == 10 || hd_factor == 20 );
0339         ss << "_scint_hd" << hd_factor ;
0340 
0341         char scintTexFilterMode = qs->getScintTexFilterMode() ;
0342         if(scintTexFilterMode == 'P') ss << "_cudaFilterModePoint" ;
0343     }
0344     else if( type == WAVELENGTH_CERENKOV )
0345     {
0346         //w = qs->cerenkov_wavelength_rejection_sampled(num);  // MOVED TO QSim_dbg.cu
0347         assert(0);
0348         ss << "_cerenkov" ;
0349     }
0350 
0351     ss << "_" << num << ".npy" ;
0352     std::string s = ss.str();
0353     const char* name = s.c_str();
0354 
0355     float* ww = w->values<float>();
0356     qs->dump_wavelength( ww, num );
0357 
0358     LOG(info) << " name " << name ;
0359     w->save("$FOLD", name );
0360 }
0361 
0362 
0363 
0364 void QSimTest::RandGaussQ_shoot()
0365 {
0366     NP* v = qs->RandGaussQ_shoot(num)  ;
0367     v->save("$FOLD/RandGaussQ_shoot.npy" );
0368 }
0369 
0370 
0371 
0372 void QSimTest::dbg_gs_generate()
0373 {
0374     NP* p = qs->dbg_gs_generate(num, type);
0375 
0376     p->save("$FOLD/p.npy");
0377 
0378     if( type == SCINT_GENERATE )
0379     {
0380         qs->dbg->save_scint_gs("$FOLD");
0381     }
0382     else if( type == CERENKOV_GENERATE )
0383     {
0384         qs->dbg->save_cerenkov_gs("$FOLD");
0385     }
0386     else
0387     {
0388         LOG(fatal) << "unexpected type " << type << " subfold " << subfold ;
0389     }
0390 }
0391 
0392 
0393 
0394 void QSimTest::generate_photon()
0395 {
0396     const char* gs_config = ssys::getenvvar("GS_CONFIG", "torch" );
0397 
0398     LOG(info) << "[ gs_config " << gs_config ;
0399     const NP* gs = SEvent::MakeDemoGenstep(gs_config);
0400 
0401     SEvt* evt = SEvt::Create(SEvt::EGPU) ;
0402     assert(evt);
0403 
0404     evt->addGenstep(gs);
0405     unsigned num_photon_after_SEvt__addGenstep = qs->qev->getNumPhoton();
0406 
0407 
0408     NP* igs = evt->makeGenstepArrayFromVector();
0409     qs->qev->setGenstepUpload_NP(igs);
0410     unsigned num_photon_after_QEvt__setGenstep = qs->qev->getNumPhoton();
0411 
0412 
0413     LOG(info)
0414        << "\n"
0415        << " gs_config " << gs_config
0416        << " gs " << ( gs ? gs->sstr() : "-" )
0417        << "\n"
0418        << " num_photon_after_SEvt__addGenstep "
0419        <<   num_photon_after_SEvt__addGenstep
0420        << "\n"
0421        << " num_photon_after_QEvt__setGenstep "
0422        <<   num_photon_after_QEvt__setGenstep
0423        << "\n"
0424        ;
0425 
0426 
0427     qs->generate_photon();
0428 
0429 
0430 
0431     NP* p = qs->qev->gatherPhoton();
0432     p->save("$FOLD/p.npy");
0433 
0434     LOG(info) << "]" ;
0435 }
0436 
0437 
0438 
0439 /**
0440 QSimTest::fill_state
0441 -----------------------
0442 
0443 Doing this for all boundaries with -0.5 and +0.5 for cosTheta will cover
0444 all states at a particular wavelength
0445 
0446 **/
0447 
0448 void QSimTest::fill_state(unsigned version)
0449 {
0450     LOG(info) << "[" ;
0451 
0452     unsigned num_state = qs->bnd->sbn->getNumBoundary() ;
0453 
0454     if( version == 0 )
0455     {
0456         std::vector<quad6> s(num_state) ;
0457         qs->fill_state_0( s.data(), s.size() );
0458         save_state("fill_state_0", (float*)s.data(), num_state );
0459     }
0460     else if( version == 1 )
0461     {
0462         std::vector<sstate> s(num_state) ;
0463         qs->fill_state_1( s.data(), s.size() );
0464         save_state("fill_state_1", (float*)s.data(), num_state );
0465     }
0466     LOG(info) << "]" ;
0467 }
0468 
0469 
0470 void QSimTest::save_state( const char* subfold, const float* data, int num_state  )
0471 {
0472     std::vector<std::string> names ;
0473     getStateNames(names, num_state);
0474 
0475     NP* a = NP::Make<float>( num_state, 6, 4 ); // (6,4) item dimension corresponds to the 6 quads of quad6
0476     a->read( data );
0477     a->set_names(names);
0478     a->save("$FOLD/state.npy");
0479 }
0480 
0481 
0482 void QSimTest::getStateNames(std::vector<std::string>& names, int num_state) const
0483 {
0484     int* idx = new int[num_state] ;
0485     for(int i=0 ; i < num_state ; i++) idx[i] = i ;
0486     qs->bnd->sbn->getBoundarySpec(names, idx, num_state );
0487     delete [] idx ;
0488 }
0489 
0490 void QSimTest::photon_launch_generate()
0491 {
0492     assert( QSimLaunch::IsMutate(type)==false );
0493     NP* p = qs->photon_launch_generate(num, type );
0494     p->save("$FOLD/p.npy");
0495     qs->dbg->save("$FOLD");
0496 }
0497 
0498 
0499 
0500 
0501 
0502 
0503 
0504 
0505 
0506 
0507 
0508 
0509 
0510 
0511 /**
0512 QSimTest::EventConfig
0513 -----------------------
0514 
0515 This is invoked from the QSimTest main  immediately
0516 prior to SEvt EGPU instanciation.
0517 
0518 For the FAKE_PROPAGATE test the SEventConfig settings
0519 are adjusted to configure the QEvt GPU buffers.
0520 This must be done prior to QEvt::init which happens
0521 when QSim is instanciated.
0522 
0523 **/
0524 
0525 void QSimTest::EventConfig(unsigned type, const SPrd* prd )  // static
0526 {
0527     SEvt* sev = SEvt::Get_EGPU();
0528     LOG_IF(fatal, sev != nullptr ) << "QSimTest::EventConfig must be done prior to instanciating SEvt, eg for fake_propagate bounce consistency " ;
0529     assert(sev == nullptr);
0530 
0531     LOG(LEVEL) << "[ " <<  QSimLaunch::Name(type) ;
0532     if( type == FAKE_PROPAGATE )
0533     {
0534         LOG(LEVEL) << prd->desc() ;
0535         int maxbounce = prd->getNumBounce();
0536 
0537         SEventConfig::SetMaxBounce(maxbounce);
0538         SEventConfig::SetEventMode("DebugLite");
0539         SEventConfig::Initialize();
0540 
0541         SEventConfig::SetMaxGenstep(1);    // FAKE_PROPAGATE starts from input photons but uses a single placeholder genstep
0542 
0543         unsigned mx = 1000000 ;
0544         SEventConfig::SetMaxPhoton(mx);   // used for QEvt buffer sizing
0545         SEventConfig::SetMaxSlot(mx);
0546         // greatly reduced MaxSlot as debug arrays in use
0547 
0548         LOG(LEVEL) << " SEventConfig::Desc " << SEventConfig::Desc() ;
0549     }
0550     LOG(LEVEL) << "] " <<  QSimLaunch::Name(type) ;
0551 }
0552 
0553 
0554 /**
0555 QSimTest::fake_propagate
0556 ----------------------------------------
0557 
0558 NB QSimTest::EventConfig does FAKE_PROPAGATE specific SEventConfig setup of event maxima
0559 
0560 **/
0561 
0562 void QSimTest::fake_propagate()
0563 {
0564     assert( QSimLaunch::IsMutate(type)==true );
0565     LOG(info) << "[" ;
0566     LOG(info) << " SEventConfig::Desc " << SEventConfig::Desc() ;
0567 
0568     NP* p = sphoton::make_ephoton_array(num);
0569 
0570     SEvt* sev = SEvt::Get_EGPU();
0571     assert( sev );
0572     sev->setInputPhoton(p);
0573     sev->setFramePlaceholder() ;
0574 
0575     int bounce_max = SEventConfig::MaxBounce();
0576     NP* prd = sprd->fake_prd(num, bounce_max);
0577 
0578     LOG(info)
0579         << " num " << num
0580         << " p " << ( p ? p->sstr() : "-" )
0581         << " bounce_max " << bounce_max
0582         << " prd " << ( prd ? prd->sstr() : "-" )
0583         ;
0584 
0585     // sev->add_array("prd0", prd );
0586     // its too soon to add array here, must be after the QEvt::setGenstep
0587     // which calls SEvt/clear (done in QSim::fake_propagate)
0588 
0589     int eventID = 0 ;
0590 
0591     sev->beginOfEvent(eventID) ;  // this tees up input photon gensteps
0592 
0593     qs->fake_propagate( prd, type );
0594 
0595     sev->endOfEvent(eventID) ;    // saves and clears
0596 
0597     LOG(info) << "]" ;
0598 }
0599 
0600 
0601 
0602 
0603 
0604 
0605 
0606 void QSimTest::quad_launch_generate()
0607 {
0608     assert( QSimLaunch::IsMutate(type)==false );
0609     NP* q = qs->quad_launch_generate(num, type );
0610     q->set_meta<std::string>("source", "QSimTest.sh");
0611     q->save("$FOLD/q.npy");
0612 }
0613 
0614 
0615 
0616 /**
0617 QSimTest::photon_launch_mutate
0618 --------------------------------
0619 
0620 How should/could this use QEvt/sevent ?
0621 
0622 **/
0623 
0624 void QSimTest::photon_launch_mutate()
0625 {
0626     assert( QSimLaunch::IsMutate(type)==true );
0627 
0628     unsigned src = QSimLaunch::MutateSource(type);
0629     const char* src_subfold = QSimLaunch::Name(src);
0630     assert( src_subfold );
0631 
0632     unsigned num_photon = num ;
0633     NP* a = NP::Load("$BASE", src_subfold,  "p.npy" );
0634 
0635     // U::Resolve does not support "$FOLD/.." so use "$BASE"
0636     // and plant that in QSimTest.sh
0637 
0638     if( a == nullptr )
0639     {
0640         const char* a_path = U::Resolve("$BASE", src_subfold,  "p.npy" );
0641         LOG(fatal)
0642              << "failed to NP::Load photons from "
0643              << " src_subfold [" << ( src_subfold ? src_subfold : "-" ) << "]"
0644              << " a_path [" << ( a_path ? a_path : "-" ) << "]"
0645              << std::endl
0646              << " YOU PROBABLY NEED TO RUN ANOTHER TEST FIRST TO GENERATE THE PHOTONS "
0647              ;
0648         rc = 101 ;
0649         return ;
0650     }
0651 
0652     unsigned num_photon_loaded = a->shape[0] ;
0653     bool num_photon_consistent = num_photon_loaded == num_photon ;
0654 
0655     LOG(info)
0656         << "\n"
0657         << " a.sstr " << a->sstr() << "\n"
0658         << " from src_subfold " << src_subfold << "\n"
0659         << " a.lpath " << a->get_lpath() << "\n"
0660         << " num_photon_loaded " << num_photon_loaded << "\n"
0661         << " num_photon_loaded/M " << num_photon_loaded/M  << "\n"
0662         << " num_photon " << num_photon << "\n"
0663         << " num_photon/M " << num_photon/M << "\n"
0664         << " num_photon_consistent " << ( num_photon_consistent ? "YES" : "NO " ) << "\n"
0665         ;
0666 
0667     assert( num_photon_consistent );
0668     if(!num_photon_consistent) std::raise(SIGINT);
0669 
0670     sphoton* photons = (sphoton*)a->bytes() ;
0671     qs->photon_launch_mutate( photons, num_photon, type );
0672 
0673 
0674 
0675     a->save("$FOLD/p.npy");
0676 
0677     qs->dbg->save("$FOLD");
0678 }
0679 
0680 
0681 unsigned QSimTest::Num(int argc, char** argv)
0682 {
0683     unsigned M1   = 1000000u ; // 1 million
0684     unsigned num_default = ssys::getenvunsigned("NUM", M1 )  ;
0685     unsigned num = argc > 1 ? std::atoi(argv[1]) : num_default ;
0686     return num ;
0687 }
0688 
0689 void QSimTest::main()
0690 {
0691     unsigned K100 =  100000u ; // default 100k usable with any GPU
0692     int ni_tranche_size = ssys::getenvint("NI_TRANCHE_SIZE", K100 );
0693     int print_id = ssys::getenvint("PINDEX", -1 );
0694     const char* subfold = QSimLaunch::Name(type) ;
0695     assert( subfold );
0696 
0697     LOG(info)
0698         << " num " << num
0699         << " type " << type
0700         << " subfold " << subfold
0701         << " ni_tranche_size " << ni_tranche_size
0702         << " print_id " << print_id
0703         ;
0704 
0705     switch(type)
0706     {
0707         case RNG_SEQUENCE:                  rng_sequence(num, ni_tranche_size)                ; break ;
0708 
0709         case WAVELENGTH_SCINTILLATION:
0710         case WAVELENGTH_CERENKOV:
0711                                             wavelength()                               ; break ;
0712 
0713         case RANDGAUSSQ_SHOOT:
0714                                             RandGaussQ_shoot()                         ; break ;
0715 
0716         case SCINT_GENERATE:
0717         case CERENKOV_GENERATE:
0718                                              dbg_gs_generate()               ; break ;
0719 
0720         case CERENKOV_GENERATE_ENPROP_FLOAT:
0721         case CERENKOV_GENERATE_ENPROP_DOUBLE:
0722         case CERENKOV_GENERATE_EXPT :
0723                                               assert(0)                       ;   break ;
0724 
0725         case GENERATE_PHOTON_G:
0726         case GENTORCH:
0727                                             generate_photon();                         ; break ;
0728 
0729         case BOUNDARY_LOOKUP_ALL:           boundary_lookup_all()                          ; break ;
0730         case BOUNDARY_LOOKUP_WATER:         boundary_lookup_line("Water", 80., 800., 721)  ; break ;
0731         case BOUNDARY_LOOKUP_LS:            boundary_lookup_line("LS",    80., 800., 721)  ; break ;
0732 
0733         case PROP_LOOKUP_Y:                 prop_lookup(-1, -1.f,16.f,1701)                ; break ;
0734         case MULTIFILM_LOOKUP:              multifilm_lookup_all()                     ; break ;
0735 
0736         case FILL_STATE_0:                  fill_state(0)                              ; break ;
0737         case FILL_STATE_1:                  fill_state(1)                              ; break ;
0738 
0739         // hmm some conflation here between running from duplicated p0 ephoton and actual photon generation such as scint/cerenkov
0740 
0741         case PROPAGATE_TO_BOUNDARY:         num=8 ; photon_launch_generate()          ; break ;
0742         case PROPAGATE_AT_SURFACE:          num=8 ; photon_launch_generate()          ; break ;
0743 
0744         case RAYLEIGH_SCATTER_ALIGN:
0745         case PROPAGATE_AT_BOUNDARY:
0746         case PROPAGATE_AT_BOUNDARY_NORMAL_INCIDENCE:
0747                                                  assert(0) ; break ;  // TODO: review these tests and revive them
0748         case REFLECT_DIFFUSE:
0749         case REFLECT_SPECULAR:
0750                                                  photon_launch_generate()  ; break ;
0751         case HEMISPHERE_S_POLARIZED:
0752         case HEMISPHERE_P_POLARIZED:
0753         case HEMISPHERE_X_POLARIZED:
0754                                                  photon_launch_generate()       ; break ;
0755         case PROPAGATE_AT_BOUNDARY_S_POLARIZED:
0756         case PROPAGATE_AT_BOUNDARY_P_POLARIZED:
0757         case PROPAGATE_AT_BOUNDARY_X_POLARIZED:
0758         case PROPAGATE_AT_MULTIFILM_S_POLARIZED:
0759         case PROPAGATE_AT_MULTIFILM_P_POLARIZED:
0760         case PROPAGATE_AT_MULTIFILM_X_POLARIZED:
0761                                                  photon_launch_mutate()         ; break ;
0762         case QGEN_RANDOM_DIRECTION_MARSAGLIA:
0763         case QGEN_LAMBERTIAN_DIRECTION:
0764         case QGEN_SMEAR_NORMAL_SIGMA_ALPHA:
0765         case QGEN_SMEAR_NORMAL_POLISH:
0766                                                  quad_launch_generate()       ; break ;
0767         case FAKE_PROPAGATE:
0768                                                 fake_propagate()              ; break ;
0769 
0770         default :
0771                                                LOG(fatal) << "unimplemented" << std::endl ; break ;
0772     }
0773 }
0774 
0775 
0776 
0777 int main(int argc, char** argv)
0778 {
0779     OPTICKS_LOG(argc, argv);
0780 
0781     const char* TEST = ssys::getenvvar("TEST", "hemisphere_s_polarized");
0782     LOG(info) << "[ TEST " << TEST ;
0783 
0784 
0785     int type = QSimLaunch::Type(TEST);
0786     unsigned num = QSimTest::Num(argc, argv);
0787 
0788     LOG(info) << "[SSim::Load" ;
0789     SSim* sim = SSim::Load();
0790     LOG(info) << "]SSim::Load" ;
0791     assert(sim);
0792 
0793 
0794     QSim::UploadComponents(sim);   // instanciates things like QBnd : NORMALLY FIRST GPU ACCESS
0795     const SPrd* prd = sim->get_sprd() ;
0796 
0797     LOG_IF(error, prd->rc != 0 )
0798         << " SPrd::rc NON-ZERO " << prd->rc
0799         << " NOT ALL CONFIGURED BOUNDARIES ARE IN THE GEOMETRY "
0800         << "\nprd.desc\n"
0801         << prd->desc()
0802         << "\nsim.desc\n"
0803         << sim->desc()
0804         ;
0805     if(prd->rc != 0 ) return 0 ; // avoid test fail when using geometry without expected boundaries
0806 
0807 
0808     QSimTest::EventConfig(type, prd );  // must be after QBnd instanciation and before SEvt instanciation
0809 
0810     [[maybe_unused]] SEvt* ev = SEvt::Create_EGPU() ;
0811     assert(ev);
0812 
0813 
0814     QSimTest qst(type, num, prd)  ;
0815     qst.main();
0816 
0817     cudaDeviceSynchronize();
0818 
0819     LOG(info) << "] TEST " << TEST << " qst.rc " << qst.rc ;
0820     return qst.rc  ;
0821 }