Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-05-15 07:41:49

0001 #include "OpticsRun.hh"
0002 
0003 #include <DD4hep/InstanceCount.h>
0004 #include <DDG4/Factories.h>
0005 #include <DDG4/Geant4Kernel.h>
0006 
0007 #include <G4Material.hh>
0008 #include <G4MaterialPropertiesTable.hh>
0009 #include <G4Run.hh>
0010 
0011 #include <chrono>
0012 
0013 #include <G4CXOpticks.hh>
0014 #include <SEventConfig.hh>
0015 #include <SEvt.hh>
0016 #include <SSim.hh>
0017 
0018 #include "DD4hepSensorIdentifier.hh"
0019 
0020 namespace ddeicopticks
0021 {
0022 
0023 //---------------------------------------------------------------------------//
0024 /*!
0025  * Add Geant4 10.x property name aliases for Opticks compatibility.
0026  *
0027  * Opticks GPU code looks up scintillation spectra by Geant4 10.x names
0028  * (FASTCOMPONENT, SLOWCOMPONENT) while DD4hep + Geant4 11.x uses
0029  * SCINTILLATIONCOMPONENT1/2. This adds the old names pointing to the
0030  * same data so both sides find what they need.
0031  */
0032 static void addOpticksPropertyAliases()
0033 {
0034     static const std::pair<const char *, const char *> aliases[] = {
0035         {"SCINTILLATIONCOMPONENT1", "FASTCOMPONENT"},
0036         {"SCINTILLATIONCOMPONENT2", "SLOWCOMPONENT"},
0037     };
0038 
0039     auto const *matTable = G4Material::GetMaterialTable();
0040     for (auto const *mat : *matTable)
0041     {
0042         auto *mpt = mat->GetMaterialPropertiesTable();
0043         if (!mpt)
0044             continue;
0045 
0046         for (auto const &[g4_11_name, g4_10_name] : aliases)
0047         {
0048             auto *prop = mpt->GetProperty(g4_11_name);
0049             if (prop && !mpt->GetProperty(g4_10_name))
0050             {
0051                 bool createNewKey = true;
0052                 mpt->AddProperty(g4_10_name, prop, createNewKey);
0053             }
0054         }
0055     }
0056 }
0057 
0058 //---------------------------------------------------------------------------//
0059 OpticsRun::OpticsRun(dd4hep::sim::Geant4Context *ctxt, std::string const &name)
0060     : dd4hep::sim::Geant4RunAction(ctxt, name)
0061 {
0062     dd4hep::InstanceCount::increment(this);
0063     declareProperty("SaveGeometry", save_geometry_);
0064 }
0065 
0066 //---------------------------------------------------------------------------//
0067 OpticsRun::~OpticsRun()
0068 {
0069     dd4hep::InstanceCount::decrement(this);
0070 }
0071 
0072 //---------------------------------------------------------------------------//
0073 void OpticsRun::begin(G4Run const *run)
0074 {
0075     G4VPhysicalVolume *world = context()->world();
0076     if (!world)
0077     {
0078         except("OpticsRun: world volume is null at begin-of-run");
0079         return;
0080     }
0081 
0082     info("Initializing G4CXOpticks geometry (run #%d)", run->GetRunID());
0083 
0084     // Add Geant4 10.x scintillation property aliases for Opticks GPU
0085     addOpticksPropertyAliases();
0086 
0087     SEvt::CreateOrReuse(SEvt::EGPU);
0088 
0089     // Register DD4hep-aware sensor identifier before geometry translation.
0090     // Unlike the default which requires GLOBAL_SENSOR_BOUNDARY_LIST env var,
0091     // this checks G4VSensitiveDetector directly on volumes.
0092     static DD4hepSensorIdentifier dd4hep_sid;
0093     G4CXOpticks::SetSensorIdentifier(&dd4hep_sid);
0094 
0095     bool hasDevice = SEventConfig::HasDevice();
0096     info("HasDevice=%s, IntegrationMode=%d", hasDevice ? "YES" : "NO", SEventConfig::IntegrationMode());
0097     G4CXOpticks::SetGeometry(world);
0098 
0099     if (save_geometry_)
0100     {
0101         info("Saving Opticks geometry to disk");
0102         G4CXOpticks::SaveGeometry();
0103     }
0104 
0105     // Log boundary count
0106     {
0107         const SSim *sim = SSim::Get();
0108         if (sim && sim->get_bnd())
0109             info("Boundary table: %zu boundaries", sim->get_bnd()->names.size());
0110     }
0111 
0112     info("G4CXOpticks geometry initialized successfully");
0113 }
0114 
0115 //---------------------------------------------------------------------------//
0116 void OpticsRun::end(G4Run const *run)
0117 {
0118     // Flush any remaining batched gensteps (from PhotonThreshold mode)
0119     SEvt *sev = SEvt::Get_EGPU();
0120     if (sev)
0121     {
0122         int64_t num_genstep = sev->getNumGenstepFromGenstep();
0123         int64_t num_photon = sev->getNumPhotonFromGenstep();
0124         if (num_genstep > 0)
0125         {
0126             G4CXOpticks *gx = G4CXOpticks::Get();
0127             if (gx)
0128             {
0129                 int eventID = run->GetNumberOfEvent() > 0 ? run->GetNumberOfEvent() - 1 : 0;
0130                 info("Flushing %lld remaining photons from %lld gensteps", static_cast<long long>(num_photon),
0131                      static_cast<long long>(num_genstep));
0132 
0133                 auto t0 = std::chrono::high_resolution_clock::now();
0134                 gx->simulate(eventID, /*reset=*/false);
0135                 auto t1 = std::chrono::high_resolution_clock::now();
0136                 double ms = std::chrono::duration<double, std::milli>(t1 - t0).count();
0137 
0138                 unsigned num_hit = sev->getNumHit();
0139                 info("OPTICKS_GPU_TIME event=%d ms=%.3f photons=%lld hits=%u", eventID, ms,
0140                      static_cast<long long>(num_photon), num_hit);
0141 
0142                 sev->endOfEvent(eventID);
0143                 gx->reset(eventID);
0144             }
0145         }
0146     }
0147 
0148     info("Finalizing G4CXOpticks (run #%d)", run->GetRunID());
0149     G4CXOpticks::Finalize();
0150 }
0151 
0152 //---------------------------------------------------------------------------//
0153 } // namespace ddeicopticks
0154 
0155 DECLARE_GEANT4ACTION_NS(ddeicopticks, OpticsRun)