Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-09-15 08:26:13

0001 // SPDX-License-Identifier: LGPL-3.0-or-later
0002 // Copyright (C) 2024, Wouter Deconinck
0003 
0004 #include <DD4hep/DetElement.h>
0005 #include <DD4hep/Detector.h>
0006 #include <DD4hep/Handle.h>
0007 #include <DD4hep/IDDescriptor.h>
0008 #include <DD4hep/Objects.h>
0009 #include <DD4hep/Readout.h>
0010 #include <DD4hep/Segmentations.h>
0011 #include <DD4hep/Shapes.h>
0012 #include <DD4hep/VolumeManager.h>
0013 #include <DD4hep/Volumes.h>
0014 #include <DD4hep/detail/DetectorInterna.h>
0015 #include <DD4hep/detail/SegmentationsInterna.h>
0016 #include <DDSegmentation/CartesianGridXY.h>
0017 #include <DDSegmentation/MultiSegmentation.h>
0018 #include <Math/GenVector/Cartesian3D.h>
0019 #include <Math/GenVector/DisplacementVector3D.h>
0020 #include <TGeoMaterial.h>
0021 #include <TGeoMedium.h>
0022 #include <algorithms/geo.h>
0023 #include <algorithms/interfaces/ActsSvc.h>
0024 #include <algorithms/interfaces/UniqueIDGenSvc.h>
0025 #include <algorithms/random.h>
0026 #include <algorithms/service.h>
0027 #include <catch2/generators/catch_generators_random.hpp>
0028 #include <catch2/interfaces/catch_interfaces_reporter.hpp>
0029 #include <catch2/reporters/catch_reporter_event_listener.hpp>
0030 #include <catch2/reporters/catch_reporter_registrars.hpp>
0031 #include <services/evaluator/EvaluatorSvc.h>
0032 #include <services/particle/ParticleSvc.h>
0033 #include <services/pid_lut/PIDLookupTableSvc.h>
0034 #include <cstddef>
0035 #include <cstdint>
0036 #include <functional>
0037 #include <memory>
0038 #include <string>
0039 #include <utility>
0040 
0041 #include "algorithms/tracking/ActsGeometryProvider.h"
0042 class algorithmsInitListener : public Catch::EventListenerBase {
0043 public:
0044   using Catch::EventListenerBase::EventListenerBase;
0045 
0046   std::unique_ptr<const dd4hep::Detector> m_detector{nullptr};
0047   std::shared_ptr<ActsGeometryProvider> m_actsGeoProvider{nullptr};
0048 
0049   void testRunStarting(Catch::TestRunInfo const& /*testRunInfo*/) override {
0050     auto detector = dd4hep::Detector::make_unique("");
0051     detector->addConstant(dd4hep::Constant("MockCalorimeter_ID", "1"));
0052     dd4hep::Readout readout(std::string("MockCalorimeterHits"));
0053     dd4hep::IDDescriptor id_desc("MockCalorimeterHits", "system:8,layer:8,x:8,y:8");
0054     readout.setIDDescriptor(id_desc);
0055     detector->add(id_desc);
0056     detector->add(readout);
0057 
0058     detector->addConstant(dd4hep::Constant("MockTracker_ID", "2"));
0059     dd4hep::Readout readoutTracker(std::string("MockTrackerHits"));
0060     dd4hep::IDDescriptor id_desc_tracker("MockTrackerHits", "system:8,layer:8,x:8,y:8");
0061     //Create segmentation with 1x1 mm pixels
0062     dd4hep::Segmentation segmentation("CartesianGridXY", "TrackerHitsSeg",
0063                                       id_desc_tracker.decoder());
0064     readoutTracker.setIDDescriptor(id_desc_tracker);
0065     readoutTracker.setSegmentation(segmentation);
0066     detector->add(id_desc_tracker);
0067     detector->add(readoutTracker);
0068 
0069     dd4hep::Readout readoutSilicon(std::string("MockSiliconHits"));
0070     dd4hep::IDDescriptor id_desc_Silicon("MockSiliconHits",
0071                                          "system:8,layer:4,module:12,sensor:10,x:40:-8,y:-16");
0072     //Create segmentation with 1x1 mm pixels
0073     dd4hep::Segmentation segmentation_Silicon("CartesianGridXY", "SiliconHitsSeg",
0074                                               id_desc_tracker.decoder());
0075     readoutSilicon.setIDDescriptor(id_desc_Silicon);
0076     readoutSilicon.setSegmentation(segmentation_Silicon);
0077     detector->add(id_desc_Silicon);
0078     detector->add(readoutSilicon);
0079 
0080     // Mock MPGD readout with full geometry registered in the VolumeManager.
0081     // MPGDTrackerDigi requires a MultiSegmentation discriminating on "strip",
0082     // with CartesianGridXY sub-segmentations for p-strip (key=1) and n-strip (key=2).
0083     dd4hep::Readout readoutMPGD(std::string("MockMPGDHits"));
0084     dd4hep::IDDescriptor id_desc_mpgd(
0085         "MockMPGDHits", "system:8,layer:4,module:12,sensor:24:4,strip:28:4,x:32:-16,y:-16");
0086     {
0087       // Build MultiSegmentation at the DDSegmentation level, then wrap it.
0088       auto* multiSeg = new dd4hep::DDSegmentation::MultiSegmentation(
0089           "system:8,layer:4,module:12,sensor:24:4,strip:28:4,x:32:-16,y:-16");
0090       // Set the discriminator field to "strip" (must be done via the registered parameter).
0091       multiSeg->parameter("key")->setValue("strip");
0092 
0093       // Sub-segmentation for p-strip (strip field value = 1)
0094       auto* pSeg = new dd4hep::DDSegmentation::CartesianGridXY(
0095           "system:8,layer:4,module:12,sensor:24:4,strip:28:4,x:32:-16,y:-16");
0096       pSeg->setGridSizeX(1.0); // 1 mm pitch
0097       pSeg->setGridSizeY(1.0);
0098       multiSeg->addSubsegmentation(1, 1, pSeg);
0099 
0100       // Sub-segmentation for n-strip (strip field value = 2)
0101       auto* nSeg = new dd4hep::DDSegmentation::CartesianGridXY(
0102           "system:8,layer:4,module:12,sensor:24:4,strip:28:4,x:32:-16,y:-16");
0103       nSeg->setGridSizeX(1.0);
0104       nSeg->setGridSizeY(1.0);
0105       multiSeg->addSubsegmentation(2, 2, nSeg);
0106 
0107       // Wrap in a dd4hep::SegmentationObject and set decoder
0108       auto* segObj = new dd4hep::SegmentationObject(multiSeg);
0109       multiSeg->setDecoder(id_desc_mpgd.decoder());
0110 
0111       dd4hep::Segmentation segmentation_MPGD(segObj);
0112       readoutMPGD.setIDDescriptor(id_desc_mpgd);
0113       readoutMPGD.setSegmentation(segmentation_MPGD);
0114     }
0115     detector->add(id_desc_mpgd);
0116     detector->add(readoutMPGD);
0117 
0118     // World constants must be defined before Detector::init().
0119     detector->add(dd4hep::Constant("world_x", "1000.0"));
0120     detector->add(dd4hep::Constant("world_y", "1000.0"));
0121     detector->add(dd4hep::Constant("world_z", "1000.0"));
0122     // Add to actual Evaluator global state
0123     dd4hep::_toDictionary("world_x", "1000.0");
0124     dd4hep::_toDictionary("world_y", "1000.0");
0125     dd4hep::_toDictionary("world_z", "1000.0");
0126 
0127     auto* matVac = new TGeoMaterial("Vacuum", 0, 0, 0);
0128     auto* matAir = new TGeoMaterial("Air", 0, 0, 0);
0129     new TGeoMedium("Vacuum", 1, matVac);
0130     new TGeoMedium("Air", 2, matAir);
0131 
0132     detector->init();
0133 
0134     // SD name must match the top-level DetElement name ("MockMPGD").
0135     dd4hep::SensitiveDetector sd("MockMPGD", "tracker");
0136     sd.setReadout(readoutMPGD);
0137     detector->add(sd);
0138 
0139     // Hierarchy: world → envelope ("system") → module ("layer","module") → sensor ("strip")
0140     // The algorithm expects 3 subvolumes per module:
0141     //   strip=0 (reference/drift volume), strip=1 (p-strip), strip=2 (n-strip)
0142     // The strip=0 volume is the "reference subvolume" used for coordinate transforms.
0143     dd4hep::Box sensorShape("sensor_shape", 5.0, 5.0, 0.025);
0144     dd4hep::Volume sensorVol("MockMPGDSensor", sensorShape, detector->air());
0145     sensorVol.setSensitiveDetector(sd);
0146 
0147     // Reference (drift) volume sits between the two strip layers.
0148     dd4hep::Box refShape("ref_shape", 5.0, 5.0, 0.025);
0149     dd4hep::Volume refVol("MockMPGDRef", refShape, detector->air());
0150     refVol.setSensitiveDetector(sd);
0151 
0152     dd4hep::Box moduleShape("module_shape", 5.0, 5.0, 0.15);
0153     dd4hep::Box envShape("env_shape", 10.0, 10.0, 5.0);
0154     dd4hep::Volume envVol("MockMPGDEnvelope", envShape, detector->air());
0155 
0156     dd4hep::Volume worldVol     = detector->worldVolume();
0157     dd4hep::DetElement worldDet = detector->world();
0158     dd4hep::DetElement det(worldDet, "MockMPGD", 3);
0159 
0160     // Required for VolumeManager to accumulate parent volume IDs.
0161     det.object<dd4hep::DetElement::Object>().flag |=
0162         dd4hep::DetElement::Object::HAVE_SENSITIVE_DETECTOR;
0163 
0164     const int nModules = 2; // module 0 and module 1
0165     int deID           = 0;
0166 
0167     for (int imod = 0; imod < nModules; imod++) {
0168       dd4hep::Volume moduleVol("MockMPGDModule_" + std::to_string(imod), moduleShape,
0169                                detector->air());
0170 
0171       // Place reference volume (strip=0) at the center of the module.
0172       dd4hep::PlacedVolume refPV = moduleVol.placeVolume(refVol, dd4hep::Position(0, 0, 0));
0173       refPV.addPhysVolID("strip", 0);
0174 
0175       // Place p-strip (strip=1) and n-strip (strip=2) on either side.
0176       dd4hep::PlacedVolume stripPVs[2];
0177       const int stripIDs[] = {1, 2};
0178       for (int is = 0; is < 2; is++) {
0179         double zChild = (is == 0) ? -0.05 : +0.05;
0180         stripPVs[is]  = moduleVol.placeVolume(sensorVol, dd4hep::Position(0, 0, zChild));
0181         stripPVs[is].addPhysVolID("strip", stripIDs[is]);
0182       }
0183 
0184       dd4hep::PlacedVolume mpv = envVol.placeVolume(moduleVol, dd4hep::Position(0, 0, imod * 0.5));
0185       mpv.addPhysVolID("layer", 0);
0186       mpv.addPhysVolID("module", imod);
0187 
0188       std::string modName = "module_" + std::to_string(imod);
0189       dd4hep::DetElement modDE(det, modName, deID++);
0190       modDE.setPlacement(mpv);
0191 
0192       // Each sensitive placement needs its own DetElement for VolumeManager registration.
0193       // The reference volume (strip=0) is the "module-level" reference used by the algorithm.
0194       std::string refName = modName + "_strip0";
0195       dd4hep::DetElement refDE(modDE, refName, deID++);
0196       refDE.setPlacement(refPV);
0197 
0198       for (int is = 0; is < 2; is++) {
0199         std::string sensName = modName + "_strip" + std::to_string(stripIDs[is]);
0200         dd4hep::DetElement sensDE(modDE, sensName, deID++);
0201         sensDE.setPlacement(stripPVs[is]);
0202       }
0203     }
0204 
0205     dd4hep::PlacedVolume envPV = worldVol.placeVolume(envVol);
0206     envPV.addPhysVolID("system", 3);
0207     det.setPlacement(envPV);
0208 
0209     detector->endDocument();
0210 
0211     // NONE flag avoids auto-scanning; addSubdetector passes the correct Readout.
0212     dd4hep::VolumeManager vm(*detector, "tracking", detector->world(), dd4hep::Readout(),
0213                              dd4hep::VolumeManager::NONE);
0214     vm.addSubdetector(det, readoutMPGD);
0215 
0216     m_detector = std::move(detector);
0217 
0218     auto& serviceSvc              = algorithms::ServiceSvc::instance();
0219     [[maybe_unused]] auto& geoSvc = algorithms::GeoSvc::instance();
0220     serviceSvc.setInit<algorithms::GeoSvc>([this](auto&& g) { g.init(this->m_detector.get()); });
0221 
0222     // Initialize ActsSvc with a minimal ActsGeometryProvider
0223     m_actsGeoProvider              = std::make_shared<ActsGeometryProvider>();
0224     [[maybe_unused]] auto& actsSvc = algorithms::ActsSvc::instance();
0225     serviceSvc.setInit<algorithms::ActsSvc>([this](auto&& g) { g.init(this->m_actsGeoProvider); });
0226 
0227     [[maybe_unused]] auto& randomSvc = algorithms::RandomSvc::instance();
0228     auto seed                        = Catch::Generators::Detail::getSeed();
0229     serviceSvc.setInit<algorithms::RandomSvc>([seed](auto&& r) {
0230       r.setProperty("seed", static_cast<std::size_t>(seed));
0231       r.init();
0232     });
0233 
0234     auto& evaluatorSvc = eicrecon::EvaluatorSvc::instance();
0235     serviceSvc.add<eicrecon::EvaluatorSvc>(&evaluatorSvc);
0236 
0237     auto& lutSvc = eicrecon::PIDLookupTableSvc::instance();
0238     serviceSvc.add<eicrecon::PIDLookupTableSvc>(&lutSvc);
0239 
0240     auto& particleSvc = algorithms::ParticleSvc::instance();
0241     serviceSvc.add<algorithms::ParticleSvc>(&particleSvc);
0242 
0243     auto& uniqueIDSvc = algorithms::UniqueIDGenSvc::instance();
0244     serviceSvc.add<algorithms::UniqueIDGenSvc>(&uniqueIDSvc);
0245 
0246     serviceSvc.init();
0247   }
0248 };
0249 
0250 CATCH_REGISTER_LISTENER(algorithmsInitListener)